From 099867d131a0bc8664ddb6a012773b918d0a2606 Mon Sep 17 00:00:00 2001 From: Alex Baker Date: Fri, 10 Jan 2014 15:24:38 -0600 Subject: [PATCH] First robolectric db test --- astrid/src/main/AndroidManifest.xml | 5 +- .../java/com/todoroo/astrid/dao/Database.java | 3 - .../java/com/todoroo/astrid/dao/TaskDao.java | 29 ++++------ .../service/AstridDependencyInjector.java | 4 ++ .../todoroo/astrid/widget/TasksWidget.java | 37 ++++++++----- .../src/main/java/org/tasks/Broadcaster.java | 16 ++++++ .../RobolectricTestDependencyInjector.java | 38 +++++++++++++ ...odorooRobolectricTestCaseWithInjector.java | 32 +++++++++++ .../com/todoroo/astrid/model/TaskTest.java | 55 +++++++++++++++++++ astrid/src/test/java/org/tasks/Freeze.java | 6 ++ .../java/org/tasks/RemoteModelHelpers.java | 53 ++++++++++++++++++ 11 files changed, 242 insertions(+), 36 deletions(-) create mode 100644 astrid/src/main/java/org/tasks/Broadcaster.java create mode 100644 astrid/src/test/java/com/todoroo/andlib/service/RobolectricTestDependencyInjector.java create mode 100644 astrid/src/test/java/com/todoroo/andlib/test/TodorooRobolectricTestCaseWithInjector.java create mode 100644 astrid/src/test/java/com/todoroo/astrid/model/TaskTest.java create mode 100644 astrid/src/test/java/org/tasks/RemoteModelHelpers.java diff --git a/astrid/src/main/AndroidManifest.xml b/astrid/src/main/AndroidManifest.xml index a21608e8a..629aaaf9c 100644 --- a/astrid/src/main/AndroidManifest.xml +++ b/astrid/src/main/AndroidManifest.xml @@ -5,8 +5,8 @@ --> + android:versionName="4.6.12" + android:versionCode="326"> @@ -215,6 +215,7 @@ + { @Autowired private Database database; + @Autowired + private Broadcaster broadcaster; + public TaskDao() { super(Task.class); DependencyInjectionService.getInstance().inject(this); @@ -330,7 +332,7 @@ public class TaskDao extends RemoteModelDao { * TaskApiDao in that it runs hooks that need to be run from within * Astrid. Order matters here! */ - public static void afterSave(Task task, ContentValues values) { + private void afterSave(Task task, ContentValues values) { if(values == null) { return; } @@ -357,19 +359,16 @@ public class TaskDao extends RemoteModelDao { * @param task task that was saved * @param values values that were updated */ - public static void broadcastTaskSave(Task task, ContentValues values) { + private void broadcastTaskSave(Task task, ContentValues values) { if(TaskApiDao.insignificantChange(values)) { return; } if(values.containsKey(Task.COMPLETION_DATE.name) && task.isCompleted()) { - Context context = ContextManager.getContext(); - if(context != null) { - Intent broadcastIntent; - broadcastIntent = new Intent(AstridApiConstants.BROADCAST_EVENT_TASK_COMPLETED); - broadcastIntent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, task.getId()); - context.sendOrderedBroadcast(broadcastIntent, null); - } + Intent broadcastIntent; + broadcastIntent = new Intent(AstridApiConstants.BROADCAST_EVENT_TASK_COMPLETED); + broadcastIntent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, task.getId()); + broadcaster.sendOrderedBroadcast(broadcastIntent); } broadcastTaskChanged(); @@ -378,12 +377,8 @@ public class TaskDao extends RemoteModelDao { /** * Send broadcast when task list changes. Widgets should update. */ - public static void broadcastTaskChanged() { - Context context = ContextManager.getContext(); - if(context != null) { - Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_EVENT_TASK_LIST_UPDATED); - context.sendOrderedBroadcast(broadcastIntent, null); - } + private void broadcastTaskChanged() { + broadcaster.sendOrderedBroadcast(new Intent(AstridApiConstants.BROADCAST_EVENT_TASK_LIST_UPDATED)); } /** diff --git a/astrid/src/main/java/com/todoroo/astrid/service/AstridDependencyInjector.java b/astrid/src/main/java/com/todoroo/astrid/service/AstridDependencyInjector.java index 7b65bf22f..2bb60ea3c 100644 --- a/astrid/src/main/java/com/todoroo/astrid/service/AstridDependencyInjector.java +++ b/astrid/src/main/java/com/todoroo/astrid/service/AstridDependencyInjector.java @@ -26,6 +26,8 @@ import com.todoroo.astrid.gtasks.sync.GtasksSyncService; import com.todoroo.astrid.tags.TagService; import com.todoroo.astrid.utility.Constants; +import org.tasks.Broadcaster; + /** * Astrid application dependency injector loads classes in Astrid with the * appropriate instantiated objects necessary for their operation. For @@ -82,6 +84,8 @@ public class AstridDependencyInjector extends AbstractDependencyInjector { // com.todoroo.astrid.tags injectables.put("tagService", TagService.class); + injectables.put("broadcaster", Broadcaster.class); + // these make reference to fields defined above injectables.put("errorReporters", new ErrorReporter[] { new AndroidLogReporter(), diff --git a/astrid/src/main/java/com/todoroo/astrid/widget/TasksWidget.java b/astrid/src/main/java/com/todoroo/astrid/widget/TasksWidget.java index eac8bcf65..3baa75f8d 100644 --- a/astrid/src/main/java/com/todoroo/astrid/widget/TasksWidget.java +++ b/astrid/src/main/java/com/todoroo/astrid/widget/TasksWidget.java @@ -29,6 +29,8 @@ import com.todoroo.astrid.utility.AstridPreferences; import org.tasks.R; import org.tasks.widget.WidgetHelper; +import static com.todoroo.astrid.api.AstridApiConstants.BROADCAST_EVENT_TASK_LIST_UPDATED; + public class TasksWidget extends AppWidgetProvider { static { @@ -54,20 +56,27 @@ public class TasksWidget extends AppWidgetProvider { @Override public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals(COMPLETE_TASK)) { - Task task = taskService.fetchById(intent.getLongExtra(TaskEditFragment.TOKEN_ID, 0), Task.ID, Task.COMPLETION_DATE); - taskService.setComplete(task, !task.isCompleted()); - } else if(intent.getAction().equals(EDIT_TASK)) { - if(AstridPreferences.useTabletLayout(context)) { - intent.setClass(context, TaskListActivity.class); - } else { - intent.setClass(context, TaskEditActivity.class); - } - intent.setFlags(WidgetHelper.flags); - intent.putExtra(TaskEditFragment.OVERRIDE_FINISH_ANIM, false); - context.startActivity(intent); - } else { - super.onReceive(context, intent); + switch(intent.getAction()) { + case COMPLETE_TASK: + Task task = taskService.fetchById(intent.getLongExtra(TaskEditFragment.TOKEN_ID, 0), Task.ID, Task.COMPLETION_DATE); + taskService.setComplete(task, !task.isCompleted()); + break; + case EDIT_TASK: + if(AstridPreferences.useTabletLayout(context)) { + intent.setClass(context, TaskListActivity.class); + } else { + intent.setClass(context, TaskEditActivity.class); + } + intent.setFlags(WidgetHelper.flags); + intent.putExtra(TaskEditFragment.OVERRIDE_FINISH_ANIM, false); + context.startActivity(intent); + + break; + case BROADCAST_EVENT_TASK_LIST_UPDATED: + updateWidgets(context); + break; + default: + super.onReceive(context, intent); } } diff --git a/astrid/src/main/java/org/tasks/Broadcaster.java b/astrid/src/main/java/org/tasks/Broadcaster.java new file mode 100644 index 000000000..11c5e242d --- /dev/null +++ b/astrid/src/main/java/org/tasks/Broadcaster.java @@ -0,0 +1,16 @@ +package org.tasks; + +import android.content.Context; +import android.content.Intent; + +import com.todoroo.andlib.service.ContextManager; + +public class Broadcaster { + + public void sendOrderedBroadcast(Intent intent) { + Context context = ContextManager.getContext(); + if(context != null) { + context.sendOrderedBroadcast(intent, null); + } + } +} diff --git a/astrid/src/test/java/com/todoroo/andlib/service/RobolectricTestDependencyInjector.java b/astrid/src/test/java/com/todoroo/andlib/service/RobolectricTestDependencyInjector.java new file mode 100644 index 000000000..c82f76633 --- /dev/null +++ b/astrid/src/test/java/com/todoroo/andlib/service/RobolectricTestDependencyInjector.java @@ -0,0 +1,38 @@ +package com.todoroo.andlib.service; + +public class RobolectricTestDependencyInjector extends AbstractDependencyInjector { + + private String name; + + public RobolectricTestDependencyInjector(String name) { + this.name = name; + } + + public void addInjectable(String field, Object injection) { + injectables.put(field, injection); + } + + @Override + public String toString() { + return "TestDI:" + name; + } + + // --- static stuff + + /** + * Install TestDependencyInjector above other injectors + */ + public synchronized static RobolectricTestDependencyInjector initialize(String name) { + RobolectricTestDependencyInjector instance = new RobolectricTestDependencyInjector(name); + DependencyInjectionService.getInstance().addInjector(instance); + return instance; + } + + /** + * Remove an installed TestDependencyInjector + */ + public static void deinitialize(RobolectricTestDependencyInjector instance) { + DependencyInjectionService.getInstance().removeInjector(instance); + } + +} diff --git a/astrid/src/test/java/com/todoroo/andlib/test/TodorooRobolectricTestCaseWithInjector.java b/astrid/src/test/java/com/todoroo/andlib/test/TodorooRobolectricTestCaseWithInjector.java new file mode 100644 index 000000000..3a6936b0e --- /dev/null +++ b/astrid/src/test/java/com/todoroo/andlib/test/TodorooRobolectricTestCaseWithInjector.java @@ -0,0 +1,32 @@ +package com.todoroo.andlib.test; + +import com.todoroo.andlib.service.RobolectricTestDependencyInjector; + +import org.tasks.Broadcaster; + +import static org.mockito.Mockito.mock; + +abstract public class TodorooRobolectricTestCaseWithInjector extends TodorooRobolectricTestCase { + + protected RobolectricTestDependencyInjector testInjector; + + protected void addInjectables() { + } + + @Override + public void setUp() throws Exception { + testInjector = RobolectricTestDependencyInjector.initialize("test"); + testInjector.addInjectable("broadcaster", mock(Broadcaster.class)); + addInjectables(); + + super.setUp(); + } + + @Override + public void tearDown() throws Exception { + super.tearDown(); + + RobolectricTestDependencyInjector.deinitialize(testInjector); + } + +} diff --git a/astrid/src/test/java/com/todoroo/astrid/model/TaskTest.java b/astrid/src/test/java/com/todoroo/astrid/model/TaskTest.java new file mode 100644 index 000000000..47672307e --- /dev/null +++ b/astrid/src/test/java/com/todoroo/astrid/model/TaskTest.java @@ -0,0 +1,55 @@ +package com.todoroo.astrid.model; + +import com.todoroo.andlib.data.Property; +import com.todoroo.andlib.test.TodorooRobolectricTestCaseWithInjector; +import com.todoroo.astrid.data.Task; +import com.todoroo.astrid.service.TaskService; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.tasks.Snippet; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.tasks.Freeze.freezeClock; +import static org.tasks.RemoteModelHelpers.compareRemoteModel; +import static org.tasks.RemoteModelHelpers.asQueryProperties; +import static org.tasks.date.DateTimeUtils.currentTimeMillis; + +@RunWith(RobolectricTestRunner.class) +public class TaskTest extends TodorooRobolectricTestCaseWithInjector { + + private TaskService taskService; + + @Before + public void before() { + taskService = new TaskService(); + } + + @Test + public void newTaskHasNoCreationDate() { + assertFalse(new Task().containsValue(Task.CREATION_DATE)); + } + + @Test + public void savedTaskHasCreationDate() { + freezeClock().thawAfter(new Snippet() {{ + Task task = new Task(); + taskService.save(task); + assertEquals(currentTimeMillis(), (long) task.getValue(Task.CREATION_DATE)); + }}); + } + + @Test + public void readTaskFromDb() { + Task task = new Task(); + taskService.save(task); + Property[] properties = asQueryProperties(Task.TABLE, task.getDatabaseValues()); + final Task fromDb = taskService.fetchById(task.getId(), properties); + compareRemoteModel(task, fromDb); + } + + +} diff --git a/astrid/src/test/java/org/tasks/Freeze.java b/astrid/src/test/java/org/tasks/Freeze.java index deb1e345c..8c7e419aa 100644 --- a/astrid/src/test/java/org/tasks/Freeze.java +++ b/astrid/src/test/java/org/tasks/Freeze.java @@ -5,8 +5,14 @@ import org.joda.time.DateTimeUtils; import java.util.Date; +import static org.tasks.date.DateTimeUtils.currentTimeMillis; + public class Freeze { + public static Freeze freezeClock() { + return freezeAt(currentTimeMillis()); + } + public static Freeze freezeAt(Date date) { return freezeAt(date.getTime()); } diff --git a/astrid/src/test/java/org/tasks/RemoteModelHelpers.java b/astrid/src/test/java/org/tasks/RemoteModelHelpers.java new file mode 100644 index 000000000..2448d8908 --- /dev/null +++ b/astrid/src/test/java/org/tasks/RemoteModelHelpers.java @@ -0,0 +1,53 @@ +package org.tasks; + +import android.annotation.SuppressLint; +import android.content.ContentValues; + +import com.todoroo.andlib.data.Property; +import com.todoroo.andlib.data.Table; +import com.todoroo.astrid.data.RemoteModel; + +import java.util.Set; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +@SuppressLint("NewApi") +public class RemoteModelHelpers { + public static Property[] asQueryProperties(Table table, ContentValues contentValues) { + Set keys = contentValues.keySet(); + Property[] result = new Property[keys.size()]; + int index = 0; + for(String key : keys) { + result[index++] = new Property.StringProperty(table, key); + } + return result; + } + + public static void compareRemoteModel(RemoteModel expected, RemoteModel actual) { + compareContentValues(expected.getSetValues(), actual.getSetValues()); + compareContentValues(expected.getDatabaseValues(), actual.getDatabaseValues()); + } + + private static void compareContentValues(ContentValues expected, ContentValues actual) { + if(expected == null && actual == null) { + return; + } + if(expected == null || actual == null) { + fail(); + } + for(String key : expected.keySet()) { + Object entry = expected.get(key); + if(entry instanceof Integer) { + assertEquals(entry, actual.getAsInteger(key)); + } else if(entry instanceof String) { + assertEquals(entry, actual.getAsString(key)); + } else if(entry instanceof Long) { + assertEquals(entry, actual.getAsLong(key)); + } else { + fail("Unhandled property type: " + entry.getClass()); + } + } + } + +}