diff --git a/.travis.yml b/.travis.yml index d7b6f859..3ba4be2e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,7 @@ before_install: - ln -s $ANDROID_HOME/tools/emulator-arm $ANDROID_HOME/tools/emulator install: echo -script: mvn clean install +script: mvn clean install -P ci notifications: email: false diff --git a/RapidFTR-Android/src/main/java/com/rapidftr/dao/ChildDAO.java b/RapidFTR-Android/src/main/java/com/rapidftr/dao/ChildDAO.java index 567c6863..d652a21d 100644 --- a/RapidFTR-Android/src/main/java/com/rapidftr/dao/ChildDAO.java +++ b/RapidFTR-Android/src/main/java/com/rapidftr/dao/ChildDAO.java @@ -4,7 +4,6 @@ import android.database.Cursor; import com.google.inject.Inject; import com.google.inject.name.Named; -import com.rapidftr.database.DatabaseHelper; import com.rapidftr.database.DatabaseSession; import com.rapidftr.model.Child; import lombok.Cleanup; @@ -19,24 +18,27 @@ public class ChildDAO implements Closeable { - private final String userName; - private final DatabaseHelper helper; - private final DatabaseSession session; + protected final String userName; + protected final DatabaseSession session; @Inject - public ChildDAO(@Named("USER_NAME") String userName, DatabaseHelper helper) { + public ChildDAO(@Named("USER_NAME") String userName, DatabaseSession session) { this.userName = userName; - this.helper = helper; - this.session = helper.openSession(); + this.session = session; } - public void clearAll() { - session.delete("CHILDREN", " = ?", new String[]{userName}); + public Child get(String id) throws JSONException { + @Cleanup Cursor cursor = session.rawQuery("SELECT child_json FROM children WHERE id = ? AND child_owner = ?", new String[]{id, userName}); + return cursor.moveToNext() ? new Child(cursor.getString(0)) : null; } + public int size() { + @Cleanup Cursor cursor = session.rawQuery("SELECT COUNT(1) FROM children WHERE child_owner = ?", new String[]{userName}); + return cursor.moveToNext() ? cursor.getInt(0) : 0; + } - public List getAllChildren() throws JSONException { - @Cleanup Cursor cursor = session.rawQuery("SELECT * FROM CHILDREN WHERE OWNER_USERNAME=? ORDER BY CHILD_ID", new String[]{userName}); + public List all() throws JSONException { + @Cleanup Cursor cursor = session.rawQuery("SELECT child_json FROM children WHERE child_owner = ? ORDER BY id", new String[]{userName}); List children = new ArrayList(); while (cursor.moveToNext()) { @@ -47,18 +49,22 @@ public List getAllChildren() throws JSONException { } public void create(Child child) throws JSONException { + if (!userName.equals(child.getOwner())) + throw new IllegalArgumentException(); + ContentValues values = new ContentValues(); values.put(DB_CHILD_OWNER, child.getOwner()); values.put(DB_CHILD_ID, child.getId()); values.put(DB_CHILD_CONTENT, child.toString()); - session.insert("CHILDREN", null, values); + long id = session.insert("CHILDREN", null, values); + if (id <= 0) + throw new IllegalArgumentException(); } @Override public void close() throws IOException { session.close(); - helper.close(); } } diff --git a/RapidFTR-Android/src/main/java/com/rapidftr/database/DatabaseHelper.java b/RapidFTR-Android/src/main/java/com/rapidftr/database/DatabaseHelper.java index 240c8046..e9f8f8e5 100644 --- a/RapidFTR-Android/src/main/java/com/rapidftr/database/DatabaseHelper.java +++ b/RapidFTR-Android/src/main/java/com/rapidftr/database/DatabaseHelper.java @@ -9,6 +9,6 @@ public interface DatabaseHelper extends Closeable { public static final String DB_CHILD_CONTENT = "child_json"; public static final String DB_CHILD_OWNER = "child_owner"; - DatabaseSession openSession(); + public DatabaseSession getSession(); } diff --git a/RapidFTR-Android/src/main/java/com/rapidftr/database/DatabaseSession.java b/RapidFTR-Android/src/main/java/com/rapidftr/database/DatabaseSession.java index 66c20af5..186a30ce 100644 --- a/RapidFTR-Android/src/main/java/com/rapidftr/database/DatabaseSession.java +++ b/RapidFTR-Android/src/main/java/com/rapidftr/database/DatabaseSession.java @@ -7,9 +7,10 @@ public interface DatabaseSession extends Closeable { - public int delete(String table, String whereClause, String[] whereArgs); public Cursor rawQuery(String sql, String[] selectionArgs); public void execSQL(String sql); public long insert(String table, String nullColumnHack, ContentValues values); + public Cursor query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit); + public int delete(String table, String whereClause, String[] whereArgs); } diff --git a/RapidFTR-Android/src/main/java/com/rapidftr/database/FluentInsert.java b/RapidFTR-Android/src/main/java/com/rapidftr/database/FluentInsert.java new file mode 100644 index 00000000..da7179ff --- /dev/null +++ b/RapidFTR-Android/src/main/java/com/rapidftr/database/FluentInsert.java @@ -0,0 +1,25 @@ +package com.rapidftr.database; + +import android.content.ContentValues; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor(suppressConstructorProperties = true) +public class FluentInsert { + + public interface Interface { + public FluentInsert insert(); + } + + protected ContentValues values; + protected final DatabaseSession session; + + public FluentInsert set(String column, String value) { + values.put(column, value); + return this; + } + + public long insertInto(String table) { + return session.insert(table, null, values); + } + +} diff --git a/RapidFTR-Android/src/main/java/com/rapidftr/database/FluentSelect.java b/RapidFTR-Android/src/main/java/com/rapidftr/database/FluentSelect.java new file mode 100644 index 00000000..500795ae --- /dev/null +++ b/RapidFTR-Android/src/main/java/com/rapidftr/database/FluentSelect.java @@ -0,0 +1,68 @@ +package com.rapidftr.database; + +import android.database.Cursor; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.ArrayList; +import java.util.List; + +@RequiredArgsConstructor(suppressConstructorProperties = true) +public class FluentSelect { + + public interface Interface { + public FluentSelect select(); + } + + protected String table; + protected List columns = new ArrayList(); + protected StringBuffer selection; + protected List selectionArgs = new ArrayList(); + protected StringBuffer orderBy; + protected String limit; + + protected final DatabaseSession session; + protected @Getter Cursor cursor; + + public FluentSelect from(String table) { + this.table = table; + return this; + } + + public FluentSelect select(String column) { + this.columns.add(column); + return this; + } + + public FluentSelect where(String criteria, String arg) { + this.selection.append("(").append(criteria).append(")"); + this.selectionArgs.add(arg); + return this; + } + + public FluentSelect and(String criteria, String arg) { + this.selection.append(" AND "); + return this.where(criteria, arg); + } + + public FluentSelect or(String criteria, String arg) { + this.selection.append(" OR "); + return this.where(criteria, arg); + } + + public FluentSelect orderBy(String orderBy, boolean asc) { + this.orderBy.append(orderBy).append(asc ? " ASC" : " DESC"); + return this; + } + + public FluentSelect limit(String limit) { + this.limit = limit; + return this; + } + + public FluentSelect execute() { + this.cursor = session.query(table, columns.toArray(new String[columns.size()]), selection.toString(), selectionArgs.toArray(new String[selectionArgs.size()]), null, null, orderBy.toString(), limit); + return this; + } + +} diff --git a/RapidFTR-Android/src/main/java/com/rapidftr/database/SQLCipherHelper.java b/RapidFTR-Android/src/main/java/com/rapidftr/database/SQLCipherHelper.java index 1c4e50a4..37e23dda 100644 --- a/RapidFTR-Android/src/main/java/com/rapidftr/database/SQLCipherHelper.java +++ b/RapidFTR-Android/src/main/java/com/rapidftr/database/SQLCipherHelper.java @@ -3,12 +3,12 @@ import android.content.Context; import com.google.inject.Inject; import com.google.inject.name.Named; +import lombok.Getter; import net.sqlcipher.database.SQLiteDatabase; import net.sqlcipher.database.SQLiteOpenHelper; public class SQLCipherHelper extends SQLiteOpenHelper implements DatabaseHelper { - public static final String DB_NAME = "rapidftr.db"; public static final int DB_VERSION = 1; public static final String DB_CHILD_TABLE = "children"; @@ -16,7 +16,6 @@ public class SQLCipherHelper extends SQLiteOpenHelper implements DatabaseHelper public static final String DB_CHILD_CONTENT = "child_json"; public static final String DB_CHILD_OWNER = "child_owner"; - // Database creation sql statement public static final String DATABASE_CREATE = "create table " + DB_CHILD_TABLE + "(" + DB_CHILD_ID + " text primary key, " @@ -24,19 +23,14 @@ public class SQLCipherHelper extends SQLiteOpenHelper implements DatabaseHelper + DB_CHILD_OWNER + " text not null" + ");"; - private final String dbKey; + protected @Getter final DatabaseSession session; @Inject - public SQLCipherHelper(@Named("DB_KEY") String dbKey, Context context) { - super(context, DB_NAME, null, DB_VERSION); - net.sqlcipher.database.SQLiteDatabase.loadLibs(context); + public SQLCipherHelper(@Named("DB_NAME") String dbName, @Named("DB_KEY") String dbKey, Context context) { + super(context, dbName, null, DB_VERSION); + SQLiteDatabase.loadLibs(context); - this.dbKey = dbKey; - } - - @Override - public DatabaseSession openSession() { - return null; + this.session = new SQLCipherSession(getWritableDatabase(dbKey)); } @Override @@ -48,4 +42,10 @@ public void onCreate(SQLiteDatabase database) { public void onUpgrade(SQLiteDatabase database, int i, int i1) { } + @Override + public void close() { + super.close(); + SQLiteDatabase.releaseMemory(); + } + } diff --git a/RapidFTR-Android/src/main/java/com/rapidftr/database/SQLCipherSession.java b/RapidFTR-Android/src/main/java/com/rapidftr/database/SQLCipherSession.java index 3d19f7e3..72a9710a 100644 --- a/RapidFTR-Android/src/main/java/com/rapidftr/database/SQLCipherSession.java +++ b/RapidFTR-Android/src/main/java/com/rapidftr/database/SQLCipherSession.java @@ -4,10 +4,10 @@ import lombok.RequiredArgsConstructor; import net.sqlcipher.database.SQLiteDatabase; -@RequiredArgsConstructor +@RequiredArgsConstructor(suppressConstructorProperties = true) public class SQLCipherSession implements DatabaseSession { @Delegate(types = DatabaseSession.class) - private final SQLiteDatabase database; + protected final SQLiteDatabase database; } diff --git a/RapidFTR-Android/src/main/java/com/rapidftr/forms/FormField.java b/RapidFTR-Android/src/main/java/com/rapidftr/forms/FormField.java index 3221e6ab..d8f29010 100644 --- a/RapidFTR-Android/src/main/java/com/rapidftr/forms/FormField.java +++ b/RapidFTR-Android/src/main/java/com/rapidftr/forms/FormField.java @@ -1,10 +1,8 @@ package com.rapidftr.forms; +import lombok.*; import org.codehaus.jackson.annotate.JsonIgnoreProperties; import org.codehaus.jackson.annotate.JsonProperty; -import lombok.Getter; -import lombok.Setter; -import lombok.EqualsAndHashCode; import java.util.List; @@ -12,6 +10,8 @@ @Getter @Setter @EqualsAndHashCode +@NoArgsConstructor +@AllArgsConstructor(suppressConstructorProperties = true) public class FormField { @JsonProperty("name") diff --git a/RapidFTR-Android/src/main/java/com/rapidftr/forms/FormSection.java b/RapidFTR-Android/src/main/java/com/rapidftr/forms/FormSection.java index f68f2bda..e35a1daa 100644 --- a/RapidFTR-Android/src/main/java/com/rapidftr/forms/FormSection.java +++ b/RapidFTR-Android/src/main/java/com/rapidftr/forms/FormSection.java @@ -1,8 +1,6 @@ package com.rapidftr.forms; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.Setter; +import lombok.*; import org.codehaus.jackson.annotate.JsonIgnoreProperties; import org.codehaus.jackson.annotate.JsonProperty; @@ -13,6 +11,8 @@ @Getter @Setter @EqualsAndHashCode +@NoArgsConstructor +@AllArgsConstructor(suppressConstructorProperties = true) public class FormSection implements Comparable { private String name; @@ -32,4 +32,8 @@ public int compareTo(FormSection other) { return Integer.valueOf(this.order).compareTo(otherOrder); } + public String toString() { + return name; + } + } diff --git a/RapidFTR-Android/src/main/java/com/rapidftr/forms/HighlightInfo.java b/RapidFTR-Android/src/main/java/com/rapidftr/forms/HighlightInfo.java index ebe32a78..a151c0b0 100644 --- a/RapidFTR-Android/src/main/java/com/rapidftr/forms/HighlightInfo.java +++ b/RapidFTR-Android/src/main/java/com/rapidftr/forms/HighlightInfo.java @@ -1,14 +1,14 @@ package com.rapidftr.forms; -import lombok.Getter; -import lombok.Setter; -import lombok.EqualsAndHashCode; +import lombok.*; import org.codehaus.jackson.annotate.JsonIgnoreProperties; @JsonIgnoreProperties(ignoreUnknown = true) @Getter @Setter @EqualsAndHashCode +@NoArgsConstructor +@AllArgsConstructor(suppressConstructorProperties = true) public class HighlightInfo{ private String order; diff --git a/RapidFTR-Android/src/main/java/com/rapidftr/model/Child.java b/RapidFTR-Android/src/main/java/com/rapidftr/model/Child.java index 0e42f070..cb86b15c 100644 --- a/RapidFTR-Android/src/main/java/com/rapidftr/model/Child.java +++ b/RapidFTR-Android/src/main/java/com/rapidftr/model/Child.java @@ -1,9 +1,12 @@ package com.rapidftr.model; +import com.google.common.base.Strings; +import org.codehaus.jackson.map.ObjectMapper; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; +import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.UUID; @@ -15,12 +18,13 @@ public class Child extends JSONObject { public static final String[] INTERNAL_FIELDS = { ID_FIELD, OWNER_FIELD }; public static final SimpleDateFormat UUID_DATE_FORMAT = new SimpleDateFormat("yyyyMMdd"); + public static final ObjectMapper JSON_MAPPER = new ObjectMapper(); public Child() { } public Child(String content) throws JSONException { - super(content == null ? "{}" : content); + super(Strings.nullToEmpty(content).trim().length() == 0 ? "{}" : content); } public Child(String id, String owner, String content) throws JSONException { @@ -98,4 +102,13 @@ public boolean isValid() { return count > 0; } + + public boolean equals(Object other) { + try { + return (other != null && other instanceof JSONObject) ? JSON_MAPPER.readTree(toString()).equals(JSON_MAPPER.readTree(other.toString())) : false; + } catch (IOException e) { + return false; + } + } + } diff --git a/RapidFTR-Android/src/main/java/com/rapidftr/utils/ApplicationInjector.java b/RapidFTR-Android/src/main/java/com/rapidftr/utils/ApplicationInjector.java index 4aa12685..6d61c4d5 100644 --- a/RapidFTR-Android/src/main/java/com/rapidftr/utils/ApplicationInjector.java +++ b/RapidFTR-Android/src/main/java/com/rapidftr/utils/ApplicationInjector.java @@ -5,9 +5,14 @@ import com.google.inject.Provides; import com.google.inject.name.Named; import com.rapidftr.RapidFtrApplication; +import com.rapidftr.database.DatabaseHelper; +import com.rapidftr.database.DatabaseSession; +import com.rapidftr.database.SQLCipherHelper; public class ApplicationInjector extends AbstractModule { + public static final String DB_NAME = "rapidftr"; + @Override protected void configure() { bind(Context.class).to(RapidFtrApplication.class); @@ -23,9 +28,24 @@ public String getDBKey(RapidFtrApplication application) { return application.getDbKey(); } + @Provides @Named("DB_NAME") + public String getDBName() { + return DB_NAME; + } + @Provides public RapidFtrApplication getRapidFTRApplication() { return RapidFtrApplication.getInstance(); } + @Provides + public DatabaseHelper getDatabaseHelper(@Named("DB_NAME") String dbName, @Named("DB_KEY") String dbKey, Context context) { + return new SQLCipherHelper(dbName, dbKey, context); + } + + @Provides + public DatabaseSession getDatabaseSession(DatabaseHelper helper) { + return helper.getSession(); + } + } diff --git a/RapidFTR-Android/src/test/java/com/rapidftr/CustomTestRunner.java b/RapidFTR-Android/src/test/java/com/rapidftr/CustomTestRunner.java index c8187b8b..03181aa4 100644 --- a/RapidFTR-Android/src/test/java/com/rapidftr/CustomTestRunner.java +++ b/RapidFTR-Android/src/test/java/com/rapidftr/CustomTestRunner.java @@ -4,11 +4,6 @@ import org.junit.runners.model.InitializationError; import org.mockito.MockitoAnnotations; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; - public class CustomTestRunner extends RobolectricTestRunner { public CustomTestRunner(Class testClass) throws InitializationError { @@ -21,22 +16,4 @@ protected void bindShadowClasses() { super.bindShadowClasses(); } - @SuppressWarnings("unchecked") - public static T duck(final Object obj, final Class t) { - return (T) Proxy.newProxyInstance(t.getClassLoader(), new Class[]{t}, - new InvocationHandler() { - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - try { - return obj.getClass() - .getMethod(method.getName(), method.getParameterTypes()) - .invoke(obj, args); - } catch (NoSuchMethodException nsme) { - throw new NoSuchMethodError(nsme.getMessage()); - } catch (InvocationTargetException ite) { - throw ite.getTargetException(); - } - } - }); - } - } diff --git a/RapidFTR-Android/src/test/java/com/rapidftr/dao/ChildDAOTest.java b/RapidFTR-Android/src/test/java/com/rapidftr/dao/ChildDAOTest.java index 38eba834..a87de4bf 100644 --- a/RapidFTR-Android/src/test/java/com/rapidftr/dao/ChildDAOTest.java +++ b/RapidFTR-Android/src/test/java/com/rapidftr/dao/ChildDAOTest.java @@ -1,20 +1,110 @@ package com.rapidftr.dao; import com.rapidftr.CustomTestRunner; +import com.rapidftr.database.DatabaseSession; import com.rapidftr.database.ShadowSQLiteHelper; +import com.rapidftr.model.Child; +import org.json.JSONException; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import java.io.IOException; +import java.util.List; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.core.IsEqual.equalTo; +import static org.hamcrest.core.IsNot.not; +import static org.hamcrest.core.IsNull.nullValue; +import static org.junit.Assert.assertThat; +import static org.junit.matchers.JUnitMatchers.hasItem; +import static org.junit.matchers.JUnitMatchers.hasItems; @RunWith(CustomTestRunner.class) public class ChildDAOTest { - private ChildDAO dao; + public DatabaseSession session; + public ChildDAO dao; + + @Before + public void setupSession() { + session = new ShadowSQLiteHelper().getSession(); + } + + @Test + public void testCreateChildRecord() throws JSONException { + ChildDAO dao = new ChildDAO("some_user", session); + dao.create(new Child("id1", "some_user", null)); + assertThat(dao.size(), equalTo(1)); + } + + @Test + public void testCreateShouldNotSaveOtherUserRecords() throws Exception { + ChildDAO dao = new ChildDAO("user1", session); + try { + dao.create(new Child("id1", "user2", null)); + throw new Exception(); + } catch (IllegalArgumentException e) { } + } + + @Test + public void testShouldNotCreateChildRecordIfIDExists() throws Exception { + ChildDAO dao = new ChildDAO("user1", session); + dao.create(new Child("id1", "user1", null)); + try { + dao.create(new Child("id1", "user1", null)); + throw new Exception(); + } catch (IllegalArgumentException e) { } + } + + @Test + public void testGetCorrectlyDeserializesData() throws JSONException, IOException { + ChildDAO dao = new ChildDAO("some_user", session); + + Child child1 = new Child("id1", "some_user", "{ \"test1\" : \"value1\", \"test2\" : 0, \"test3\" : [ \"1\", 2, \"3\" ] }"); + dao.create(child1); + + Child child2 = dao.get("id1"); + assertThat(child1, equalTo(child2)); + } + + @Test + public void testGetOnlyReturnsOwnRecords() throws JSONException { + ChildDAO dao1 = new ChildDAO("user1", session); + dao1.create(new Child("id1", "user1", null)); + + ChildDAO dao2 = new ChildDAO("user2", session); + dao2.create(new Child("id2", "user2", null)); + + assertThat(dao1.get("id2"), is(nullValue())); + assertThat(dao2.get("id1"), is(nullValue())); + } @Test - public void testOne() throws IOException { - dao = new ChildDAO("user1", new ShadowSQLiteHelper()); + public void testReturnsAllRecords() throws JSONException { + ChildDAO dao1 = new ChildDAO("user1", session); + Child child1 = new Child("id1", "user1", null); + Child child2 = new Child("id2", "user1", null); + dao1.create(child1); + dao1.create(child2); + + List children = dao1.all(); + assertThat(children.size(), equalTo(2)); + assertThat(children, hasItems(child1, child2)); + } + + @Test + public void testAllOnlyReturnsOwnRecords() throws JSONException { + ChildDAO dao1 = new ChildDAO("user1", session); + Child child1 = new Child("id1", "user1", null); + dao1.create(child1); + + ChildDAO dao2 = new ChildDAO("user2", session); + Child child2 = new Child("id2", "user2", null); + dao2.create(child2); + + assertThat(dao1.all(), not(hasItem(child2))); + assertThat(dao2.all(), not(hasItem(child1))); } } diff --git a/RapidFTR-Android/src/test/java/com/rapidftr/database/ChildDAOTest.java b/RapidFTR-Android/src/test/java/com/rapidftr/database/ChildDAOTest.java deleted file mode 100644 index 76f8600e..00000000 --- a/RapidFTR-Android/src/test/java/com/rapidftr/database/ChildDAOTest.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.rapidftr.database; - -import android.test.ActivityInstrumentationTestCase2; -import com.rapidftr.CustomTestRunner; -import com.rapidftr.activity.MainActivity; -import com.rapidftr.dao.ChildDAO; -import com.rapidftr.model.Child; -import org.json.JSONException; -import org.junit.Ignore; -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.util.List; - -@Ignore -@RunWith(CustomTestRunner.class) -public class ChildDAOTest extends ActivityInstrumentationTestCase2 { - - private DatabaseHelper helper; - - public ChildDAOTest() { - super(MainActivity.class); - helper = new SQLCipherHelper("SampleDBKey", getActivity()); - } - - @Test - public void shouldStoreAndRetrieveChildRecord() throws JSONException { - ChildDAO storage = new ChildDAO("some_user", helper); - Child child1 = new Child("id1", "user1", "child1"); - Child child2 = new Child("id2", "user2", "child2"); - - storage.clearAll(); - storage.create(child1); - storage.create(child2); - - List children = storage.getAllChildren(); - assertEquals(2, children.size()); - assertEquals("child1", children.get(0)); - assertEquals("child2", children.get(1)); - } - - @Test - public void shouldNotSeeRecordsFromOtherUsers() throws JSONException { - ChildDAO storage = new ChildDAO("user1", helper); - storage.clearAll(); - - ChildDAO otherStorage = new ChildDAO("user2", helper); - otherStorage.clearAll(); - - storage.create(new Child("id3", "user3", "child3")); - assertTrue(otherStorage.getAllChildren().isEmpty()); - } - - @Test - public void shouldClearAllShouldOnlyDeleteRecordsForCurrentUser() throws JSONException { - ChildDAO storage = new ChildDAO("user1", helper); - storage.clearAll(); - - ChildDAO otherStorage = new ChildDAO("user2", helper); - otherStorage.clearAll(); - - storage.create(new Child("id5", "user5", "child5")); - otherStorage.clearAll(); - - assertFalse(storage.getAllChildren().isEmpty()); - } - -} diff --git a/RapidFTR-Android/src/test/java/com/rapidftr/database/DatabaseSessionIntegrationTest.java b/RapidFTR-Android/src/test/java/com/rapidftr/database/DatabaseSessionIntegrationTest.java deleted file mode 100644 index 933bd2c5..00000000 --- a/RapidFTR-Android/src/test/java/com/rapidftr/database/DatabaseSessionIntegrationTest.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.rapidftr.database; - -import android.content.ContentValues; -import android.database.Cursor; -import android.test.ActivityInstrumentationTestCase2; -import com.rapidftr.activity.LoginActivity; -import lombok.Cleanup; -import org.junit.Ignore; - -@Ignore -public class DatabaseSessionIntegrationTest extends ActivityInstrumentationTestCase2 { - - private DatabaseHelper dbHelper; - - public DatabaseSessionIntegrationTest() { - super(LoginActivity.class); - } - - @Override - public void setUp() throws Exception { - dbHelper = new SQLCipherHelper("SampleDBKey", getActivity()); - } - - @Override - public void tearDown() throws Exception { - @Cleanup DatabaseSession SQLite = dbHelper.openSession(); - SQLite.execSQL("DROP TABLE CHILDREN"); - dbHelper.close(); - } - - public void testCreateTableAndAccessIt() throws Exception { - @Cleanup DatabaseSession SQLite = dbHelper.openSession(); - SQLite.execSQL("CREATE TABLE CHILDREN (CHILD_NAME VARCHAR(255),CHILD_ID VARCHAR(255))"); - - ContentValues values = new ContentValues(); - values.put("CHILD_NAME", "child name"); - values.put("CHILD_ID", "1234"); - SQLite.insert("CHILDREN", null, values); - - Cursor cursor = SQLite.rawQuery("SELECT CHILD_NAME FROM CHILDREN WHERE CHILD_ID=?", new String[]{"1234"}); - while (cursor.moveToNext()) { - assertEquals(cursor.getString(0), "child name"); - } - } - -} diff --git a/RapidFTR-Android/src/test/java/com/rapidftr/database/ShadowSQLiteHelper.java b/RapidFTR-Android/src/test/java/com/rapidftr/database/ShadowSQLiteHelper.java index 0a6fe5f6..fcd63d97 100644 --- a/RapidFTR-Android/src/test/java/com/rapidftr/database/ShadowSQLiteHelper.java +++ b/RapidFTR-Android/src/test/java/com/rapidftr/database/ShadowSQLiteHelper.java @@ -1,14 +1,20 @@ package com.rapidftr.database; + import android.app.Activity; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import lombok.Delegate; +import lombok.Getter; import lombok.RequiredArgsConstructor; +/* + * Stub SQLite Helper class which uses an in-memory database provided by Robolectric + * Database is freshly created Whenever "getWritableDatabase" or "getReadableDatabase" is called + */ public class ShadowSQLiteHelper extends SQLiteOpenHelper implements DatabaseHelper { - @RequiredArgsConstructor + @RequiredArgsConstructor(suppressConstructorProperties = true) public static class ShadowSQLiteSession implements DatabaseSession { @Delegate(types = DatabaseSession.class) @@ -16,17 +22,11 @@ public static class ShadowSQLiteSession implements DatabaseSession { } - public ShadowSQLiteHelper() { - super(new Activity(), "mydb", null, 1); - } - - @Override - public DatabaseSession openSession() { - return new ShadowSQLiteSession(getWritableDatabase()); - } + private @Getter DatabaseSession session; - @Override - public void close() { + public ShadowSQLiteHelper() { + super(new Activity(), "test_database", null, 1); + session = new ShadowSQLiteSession(getWritableDatabase()); } @Override diff --git a/RapidFTR-Android/src/test/java/com/rapidftr/model/ChildTest.java b/RapidFTR-Android/src/test/java/com/rapidftr/model/ChildTest.java index 84c5425c..21e6628b 100644 --- a/RapidFTR-Android/src/test/java/com/rapidftr/model/ChildTest.java +++ b/RapidFTR-Android/src/test/java/com/rapidftr/model/ChildTest.java @@ -24,8 +24,8 @@ public class ChildTest { @Test - public void shouldCreateEmptyChild() throws JSONException { - Child child = new Child(null); + public void shouldCreateChildWithBlankContent() throws JSONException { + new Child(" "); } @Test diff --git a/RapidFTR-AndroidTests/assets/icudt46l.zip b/RapidFTR-AndroidTests/assets/icudt46l.zip new file mode 100644 index 00000000..91dc7f71 Binary files /dev/null and b/RapidFTR-AndroidTests/assets/icudt46l.zip differ diff --git a/RapidFTR-AndroidTests/pom.xml b/RapidFTR-AndroidTests/pom.xml index 5269b478..26ac8354 100644 --- a/RapidFTR-AndroidTests/pom.xml +++ b/RapidFTR-AndroidTests/pom.xml @@ -13,6 +13,10 @@ rapidftr-android-parent + + ${project.basedir}/../RapidFTR-Android/libs + + junit @@ -21,6 +25,28 @@ compile + + sqlcipher + sqlcipher + 1.0 + system + ${sqlcipher.dir}/sqlcipher.jar + + + guava + guava + 1.0 + system + ${sqlcipher.dir}/guava-r09.jar + + + commons-codec + commons-codec + 1.0 + system + ${sqlcipher.dir}/commons-codec.jar + + com.jayway.android.robotium robotium-solo diff --git a/RapidFTR-AndroidTests/src/main/java/com/rapidftr/activity/LoginActivityIntegrationTest.java b/RapidFTR-AndroidTests/src/main/java/com/rapidftr/activity/LoginActivityIntegrationTest.java index 3819a1ee..882c6ea0 100644 --- a/RapidFTR-AndroidTests/src/main/java/com/rapidftr/activity/LoginActivityIntegrationTest.java +++ b/RapidFTR-AndroidTests/src/main/java/com/rapidftr/activity/LoginActivityIntegrationTest.java @@ -11,7 +11,7 @@ public class LoginActivityIntegrationTest extends ActivityInstrumentationTestCas public LoginPage loginPage; public LoginActivityIntegrationTest() { - super("com.rapidftr.activity", LoginActivity.class); + super(LoginActivity.class); } @Override diff --git a/RapidFTR-AndroidTests/src/main/java/com/rapidftr/database/DatabaseSessionIntegrationTest.java b/RapidFTR-AndroidTests/src/main/java/com/rapidftr/database/DatabaseSessionIntegrationTest.java new file mode 100644 index 00000000..018bd9b9 --- /dev/null +++ b/RapidFTR-AndroidTests/src/main/java/com/rapidftr/database/DatabaseSessionIntegrationTest.java @@ -0,0 +1,76 @@ +package com.rapidftr.database; + +import android.content.ContentValues; +import android.database.Cursor; +import android.test.ActivityInstrumentationTestCase2; +import com.jayway.android.robotium.solo.Solo; +import com.rapidftr.activity.LoginActivity; +import lombok.Cleanup; +import net.sqlcipher.database.SQLiteException; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.Assert.assertThat; + +public class DatabaseSessionIntegrationTest extends ActivityInstrumentationTestCase2 { + + public Solo solo; + public DatabaseHelper helper; + public DatabaseSession session; + + public DatabaseSessionIntegrationTest() { + super(LoginActivity.class); + } + + @Override + public void setUp() throws Exception { + solo = new Solo(getInstrumentation(), getActivity()); + helper = new SQLCipherHelper("test_db", "test_key", getActivity()); + session = helper.getSession(); + + session.execSQL("DELETE FROM children"); + } + + @Override + public void tearDown() throws Exception { + session.close(); + helper.close(); + solo.finishOpenedActivities(); + } + + public void testRawQueryCountAs0() { + @Cleanup Cursor cursor = session.rawQuery("select count(1) from children", new String[]{}); + cursor.moveToNext(); + assertThat(cursor.getInt(0), equalTo(0)); + } + + public void testInsertNewChildRecord() { + ContentValues values = new ContentValues(); + values.put(DatabaseHelper.DB_CHILD_ID, "id1"); + values.put(DatabaseHelper.DB_CHILD_OWNER, "owner1"); + values.put(DatabaseHelper.DB_CHILD_CONTENT, "content1"); + + long id = session.insert("children", null, values); + assertTrue(id > 0); + } + + public void testDeleteExistingChildRecord() { + testInsertNewChildRecord(); + + int deleted = session.delete("children", "id = ?", new String[] { "id1" }); + assertTrue(deleted == 1); + } + + public void testExecSQLDeleteAllFromChildren() { + testInsertNewChildRecord(); + session.execSQL("DELETE FROM children"); + testRawQueryCountAs0(); + } + + public void testEncryption() { + try { + helper = new SQLCipherHelper("test_db", "wrong_password", getActivity()); + fail(); + } catch (SQLiteException e) { } + } + +}