First robolectric db test

pull/73/head
Alex Baker 12 years ago
parent b92702dec8
commit 099867d131

@ -5,8 +5,8 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.tasks"
android:versionName="4.6.11"
android:versionCode="325">
android:versionName="4.6.12"
android:versionCode="326">
<!-- widgets, alarms, and services will break if Astrid is installed on SD card -->
<!-- android:installLocation="internalOnly"> -->
@ -215,6 +215,7 @@
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="com.todoroo.astrid.widget.TasksWidget.COMPLETE_TASK"/>
<action android:name="com.todoroo.astrid.widget.TasksWidget.EDIT_TASK"/>
<action android:name="org.tasks.TASK_LIST_UPDATED"/>
</intent-filter>
<meta-data
android:name="android.appwidget.provider"

@ -13,7 +13,6 @@ import com.todoroo.andlib.data.AbstractDatabase;
import com.todoroo.andlib.data.AbstractModel;
import com.todoroo.andlib.data.Property;
import com.todoroo.andlib.data.Table;
import com.todoroo.andlib.service.ContextManager;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.StoreObject;
import com.todoroo.astrid.data.TagData;
@ -24,7 +23,6 @@ import com.todoroo.astrid.data.TaskListMetadata;
import com.todoroo.astrid.data.UserActivity;
import com.todoroo.astrid.provider.Astrid2TaskProvider;
import com.todoroo.astrid.provider.Astrid3ContentProvider;
import com.todoroo.astrid.widget.TasksWidget;
/**
* Database wrapper
@ -71,7 +69,6 @@ public class Database extends AbstractDatabase {
public void onDatabaseUpdated() {
Astrid2TaskProvider.notifyDatabaseModification();
Astrid3ContentProvider.notifyDatabaseModification();
TasksWidget.updateWidgets(ContextManager.getContext());
}
});
}

@ -6,14 +6,12 @@
package com.todoroo.astrid.dao;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.sqlite.SQLiteConstraintException;
import com.todoroo.andlib.data.Property;
import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.ContextManager;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Functions;
@ -27,6 +25,7 @@ import com.todoroo.astrid.data.TaskApiDao;
import com.todoroo.astrid.reminders.Notifications;
import com.todoroo.astrid.reminders.ReminderService;
import org.tasks.Broadcaster;
import org.tasks.R;
/**
@ -43,6 +42,9 @@ public class TaskDao extends RemoteModelDao<Task> {
@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<Task> {
* 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<Task> {
* @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<Task> {
/**
* 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));
}
/**

@ -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(),

@ -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);
}
}

@ -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);
}
}
}

@ -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);
}
}

@ -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);
}
}

@ -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);
}
}

@ -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());
}

@ -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<String> 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());
}
}
}
}
Loading…
Cancel
Save