package com.nononsenseapps.notepad.test; import java.util.ArrayList; import java.util.Calendar; import java.util.HashMap; import java.util.List; import com.nononsenseapps.notepad.data.model.sql.Task; import com.nononsenseapps.notepad.data.model.sql.TaskList; import com.nononsenseapps.notepad.data.model.gtasks.GoogleTask; import com.nononsenseapps.notepad.data.model.gtasks.GoogleTaskList; import com.nononsenseapps.notepad.data.remote.gtasks.GoogleTaskSync; import android.database.Cursor; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; import android.util.Log; import android.util.Pair; import static com.nononsenseapps.notepad.data.local.sql.DatabaseHandler.resetTestDatabase; import static com.nononsenseapps.notepad.data.local.sql.DatabaseHandler.setEmptyTestDatabase; import static com.nononsenseapps.notepad.data.local.sql.DatabaseHandler.setFreshTestDatabase; import static com.nononsenseapps.notepad.data.local.sql.DatabaseHandler.setTestDatabase; public class GTaskSyncTest extends AndroidTestCase { String balle = "balle"; String balleRemote = "balleremote"; String account = "balleman"; ArrayList<TaskList> localLists; ArrayList<GoogleTaskList> remoteListsInDB; ArrayList<GoogleTaskList> remoteListsSubset; HashMap<TaskList, ArrayList<Task>> localTasks; HashMap<GoogleTaskList, ArrayList<GoogleTask>> remoteTasksInDB; HashMap<GoogleTaskList, ArrayList<GoogleTask>> remoteTasksSubSet; int remoteOnlyCount = 2; int localOnlyCount = 1; int localListNewestCount = 0; int remoteListNewestCount = 0; int localTaskNewestCount = 0; int remoteTaskNewestCount = 0; @Override public void setUp() throws Exception { localListNewestCount = 0; remoteListNewestCount = 0; // Delete all existing lists setEmptyTestDatabase(getContext(), getClass().getName()); // First insert some lists and remote stuff localLists = new ArrayList<TaskList>(); remoteListsInDB = new ArrayList<GoogleTaskList>(); remoteListsSubset = new ArrayList<GoogleTaskList>(); localTasks = new HashMap<TaskList, ArrayList<Task>>(); remoteTasksInDB = new HashMap<GoogleTaskList, ArrayList<GoogleTask>>(); remoteTasksSubSet = new HashMap<GoogleTaskList, ArrayList<GoogleTask>>(); int max = 8; for (int i = 0; i < max; i++) { GoogleTaskList gl = null; TaskList l = new TaskList(); l.title = balle + i; // In the past l.save(mContext, 5L); localLists.add(l); localTasks.put(l, new ArrayList<Task>()); if (i < (max - localOnlyCount)) { gl = new GoogleTaskList(l, account); // 0 2 4 6 if (i % 2 == 0) { gl.updated = l.updated - 1; // localListNewestCount++; } else { gl.updated = l.updated + 1; // remoteListNewestCount++; } gl.remoteId = l.title; gl.save(mContext); remoteListsInDB.add(gl); remoteTasksInDB.put(gl, new ArrayList<GoogleTask>()); remoteTasksSubSet.put(gl, new ArrayList<GoogleTask>()); // 0 2 if (i < 4) { remoteListsSubset.add(gl); if (i % 2 == 0) { localListNewestCount++; } else { remoteListNewestCount++; } } } addTasks(l, gl); } // Simulate remote only items GoogleTaskList gl = new GoogleTaskList(account); gl.title = balleRemote; gl.updated = Calendar.getInstance().getTimeInMillis(); gl.remoteId = balle + "999"; remoteListsSubset.add(gl); remoteListNewestCount++; gl = new GoogleTaskList(account); gl.title = balleRemote; gl.updated = Calendar.getInstance().getTimeInMillis(); gl.remoteId = balle + "998"; remoteListsSubset.add(gl); remoteListNewestCount++; remoteOnlyCount = 2; } void addTasks(final TaskList l, final GoogleTaskList gl) { // All lists look the same so ok to overwrite these values if (gl != null) { localTaskNewestCount = 0; remoteTaskNewestCount = 0; } // Always add some local tasks int taskCount = 8; int remoteCount = taskCount - localOnlyCount; int remoteSubCount = remoteCount - 3; for (int i = 0; i < taskCount; i++) { Task t = new Task(); t.dblist = l._id; t.title = balle + i; t.note = balle + i; t.save(mContext); localTasks.get(l).add(t); if (gl != null && i < remoteCount) { GoogleTask gt = new GoogleTask(t, account); gt.remoteId = l.title + balleRemote + i; if (i < remoteSubCount) { gt.updated = t.updated + 1; remoteTasksSubSet.get(gl).add(gt); remoteTaskNewestCount++; } else { localTaskNewestCount++; gt.updated = t.updated - 1; } gt.save(mContext); remoteTasksInDB.get(gl).add(gt); } } if (gl != null) { // add two remote only GoogleTask gt = new GoogleTask(account); gt.title = balleRemote + "991"; gt.notes = balleRemote + "991"; gt.remoteId = balleRemote + "991"; // gt.listdbid = l._id; gt.updated = Calendar.getInstance().getTimeInMillis(); remoteTaskNewestCount++; remoteTasksSubSet.get(gl).add(gt); gt = new GoogleTask(account); gt.title = balleRemote + "992"; gt.notes = balleRemote + "992"; gt.remoteId = balleRemote + "992"; gt.updated = 0L; // gt.listdbid = l._id; remoteTaskNewestCount++; remoteTasksSubSet.get(gl).add(gt); } } @Override public void tearDown() throws Exception { // remote items that were inserted resetTestDatabase(getContext(), getClass().getName()); } @SmallTest public void testBasic() { GoogleTaskList gl = new GoogleTaskList(account); gl.updated = 9L; gl.remoteId = "bobman"; gl.dbid = 99L; gl.save(mContext); assertTrue("save did not succeed", gl._id > 0); final Cursor cc = mContext.getContentResolver().query( GoogleTaskList.URI, GoogleTaskList.Columns.FIELDS, null, null, null); try { assertNotNull(cc); assertTrue("Simple Cursor can not be empty!", cc.getCount() > 0); boolean found = false; while (cc.moveToNext()) { GoogleTaskList gll = new GoogleTaskList(cc); if (gll.remoteId.equals("bobman")) { found = true; break; } } assertTrue("List was not returned in simple case!", found); } finally { if (cc != null) cc.close(); } final Cursor c = mContext.getContentResolver().query( GoogleTaskList.URI, GoogleTaskList.Columns.FIELDS, GoogleTaskList.Columns.ACCOUNT + " IS ? AND " + GoogleTaskList.Columns.SERVICE + " IS ?", new String[] { account, GoogleTaskList.SERVICENAME }, null); try { assertNotNull(c); assertTrue("Cursor can not be empty!", c.getCount() > 0); boolean found = false; while (c.moveToNext()) { GoogleTaskList gll = new GoogleTaskList(c); if (gll.remoteId.equals("bobman")) { found = true; break; } } assertTrue("List was not returned!", found); } finally { if (c != null) c.close(); } gl.delete(mContext); } @SmallTest public void testLogic() { final Cursor c = mContext.getContentResolver().query( GoogleTaskList.URI, GoogleTaskList.Columns.FIELDS, GoogleTaskList.Columns.ACCOUNT + " IS ? AND " + GoogleTaskList.Columns.SERVICE + " IS ?", new String[] { account, GoogleTaskList.SERVICENAME }, null); try { assertNotNull(c); assertEquals("Cursor of remote lists not expected size", remoteListsInDB.size(), c.getCount()); } finally { if (c != null) c.close(); } } @SmallTest public void testMergeLists() { // Verify that merge works GoogleTaskSync.mergeListsWithLocalDB(mContext, account, remoteListsSubset); assertEquals("mergeLists result does not equal real result!", remoteListsInDB.size() + remoteOnlyCount, remoteListsSubset.size()); } @SmallTest public void testMergeTasks() { final TaskList tl = localLists.get(0); final GoogleTaskList gl = remoteListsInDB.get(0); List<GoogleTask> remoteTasks = remoteTasksSubSet.get(gl); GoogleTaskSync.mergeTasksWithLocalDB(mContext, account, remoteTasks, tl._id); Log.d("nononsenseapps gtasktest", "remoteTasks size: " + remoteTasks.size()); assertEquals("mergeTasks did not equal expected size!", remoteTasksInDB .get(gl).size() + remoteOnlyCount, remoteTasks.size()); int remoteCount = 0; for (GoogleTask gt : remoteTasks) { // See that all has local id, except the two remote only if (gt.remoteId.contains("99")) { remoteCount++; } else { assertNotNull("Local id was not set", gt.dbid); assertTrue("Local id was not set", gt.dbid > 0); } // And that list is set! assertTrue("List id was not set", gt.listdbid > 0); Log.d("nononsenseapps gtasktest", gt.remoteId); } assertEquals("Only two tasks were remote only!", remoteOnlyCount, remoteCount); } @SmallTest public void testSyncListsLocally() { int initialSize = remoteListsSubset.size(); // Two is remote only, one old and one new GoogleTaskSync.mergeListsWithLocalDB(mContext, account, remoteListsSubset); List<Pair<TaskList, GoogleTaskList>> pairs = GoogleTaskSync .synchronizeListsLocally(mContext, remoteListsSubset); assertNotNull(pairs); // for (Pair<TaskList, GoogleTaskList> pair : pairs) { // if (pair.first == null) { // Log.d("nononsenseapps gtasktest", "r: " + pair.second.title); // } // else if (pair.second == null) { // Log.d("nononsenseapps gtasktest", "l: " + pair.first.title); // } // else // Log.d("nononsenseapps gtasktest", "l: " + pair.first.title // + ", r: " + pair.second.title); // } assertEquals("Resulting list seems to have wrong size", initialSize + localOnlyCount, pairs.size()); int remoteNewestCount = 0; int localNewestCount = 0; int remoteNullCount = 0; int localNullCount = 0; for (Pair<TaskList, GoogleTaskList> pair : pairs) { if (pair.first == null) { assertNotNull(pair.second); localNullCount++; } else if (pair.second == null) { assertNotNull(pair.first); remoteNullCount++; } else { assertEquals("Titles should be the same", pair.first.title, pair.second.title); assertEquals("local id should be set", (Long) pair.first._id, pair.second.dbid); // REverse check to avoid .equals fuckup if (pair.first.updated > pair.second.updated) { localNewestCount++; } else { remoteNewestCount++; assertEquals("Update time should be the same", pair.second.updated, pair.first.updated); } } } // assertTrue("Only one item was supposed to be remote and deleted locally", // localNullCount == remoteOnlyCount); assertTrue("Expected only one 'new local list'", remoteNullCount == 1); assertTrue(localNewestCount > 0); assertTrue(remoteNewestCount > 0); assertEquals("lUpdate time incorrect", localListNewestCount, localNewestCount); // Plus one for remote only object which creates new list assertEquals("rUpdate time incorrect", remoteListNewestCount, remoteNewestCount); } @SmallTest public void testSyncTasksLocally() { // TODO final TaskList tl = localLists.get(0); final GoogleTaskList gl = remoteListsInDB.get(0); List<GoogleTask> remoteTasks = remoteTasksSubSet.get(gl); GoogleTaskSync.mergeTasksWithLocalDB(mContext, account, remoteTasks, tl._id); List<Pair<Task, GoogleTask>> pairs = GoogleTaskSync .synchronizeTasksLocally(mContext, remoteTasks, new Pair<TaskList, GoogleTaskList>(tl, gl)); assertNotNull(pairs); assertEquals("Synced pairs have wrong length", localOnlyCount + localTaskNewestCount, pairs.size()); int remoteNewestCount = 0; int localNewestCount = 0; int remoteNullCount = 0; int localNullCount = 0; for (Pair<Task, GoogleTask> pair : pairs) { if (pair.first == null) { assertNotNull(pair.second); localNullCount++; } else if (pair.second == null) { assertNotNull(pair.first); remoteNullCount++; } else { assertEquals("Titles should be the same", pair.first.title, pair.second.title); assertEquals("local id should be set", (Long) pair.first._id, pair.second.dbid); assertEquals("list id should be set", (Long) pair.first.dblist, pair.second.listdbid); if (pair.first.updated > pair.second.updated){ localNewestCount++; Log.d("nononsenseapps gtasksync", "local newest: " + pair.first.title + " : " + pair.second.title); } else { remoteNewestCount++; assertEquals("Update time should be the same", pair.second.updated, pair.first.updated); assertEquals("Title should be the same", pair.second.title, pair.first.title); assertEquals("Note should be the same", pair.second.notes, pair.first.note); assertNotNull("Title is not allowed to be null", pair.first.title); Log.d("nononsenseapps gtasksync", "remote newest: " + pair.first.title + " : " + pair.second.title); } } } // assertTrue("Only one item was supposed to be remote and deletedlocally: " // + localNullCount, localNullCount == localOnlyCount); assertEquals("Not expected 'new local task' count: " + remoteNullCount, localTasks.get(tl).size() - remoteTasksInDB.get(gl).size(), remoteNullCount); Log.d("nononsenseapps gtasksync", "localnewest: " + localTaskNewestCount + " vs " + localNewestCount); Log.d("nononsenseapps gtasksync", "remotenewest: " + remoteTaskNewestCount + " vs " + remoteNewestCount); assertTrue("local count", localNewestCount > 0); assertEquals("remote count", 0, remoteNewestCount); assertEquals("lUpdate time incorrect", localTaskNewestCount, localNewestCount); assertEquals("rUpdate time incorrect", 0, remoteNewestCount); } @SmallTest public void testSyncTasksLocallyCompleteBug() { // TODO // Complete status should be transferred correclty, // localcomplete, remote not // localcomplete, remote complete // local not, remote not // localcomplete, remote complete } }