Skip to content

Commit bb0e6b1

Browse files
committed
added first query provider test
1 parent 6d1ed42 commit bb0e6b1

File tree

5 files changed

+134
-58
lines changed

5 files changed

+134
-58
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package com.example.android.architecture.blueprints.todoapp.data;
2+
3+
import android.content.ContentValues;
4+
import android.database.Cursor;
5+
import android.test.AndroidTestCase;
6+
7+
import com.example.android.architecture.blueprints.todoapp.data.source.local.TasksPersistenceContract;
8+
9+
import java.util.Map;
10+
import java.util.Set;
11+
import java.util.UUID;
12+
13+
public class ProviderUtilities extends AndroidTestCase{
14+
15+
static ContentValues createTasksValues() {
16+
ContentValues weatherValues = new ContentValues();
17+
weatherValues.put(TasksPersistenceContract.TaskEntry.COLUMN_NAME_ENTRY_ID, UUID.randomUUID().toString());
18+
weatherValues.put(TasksPersistenceContract.TaskEntry.COLUMN_NAME_TITLE, "Title1");
19+
weatherValues.put(TasksPersistenceContract.TaskEntry.COLUMN_NAME_DESCRIPTION, "Description1");
20+
weatherValues.put(TasksPersistenceContract.TaskEntry.COLUMN_NAME_COMPLETED, 0);
21+
22+
weatherValues.put(TasksPersistenceContract.TaskEntry.COLUMN_NAME_ENTRY_ID, UUID.randomUUID().toString());
23+
weatherValues.put(TasksPersistenceContract.TaskEntry.COLUMN_NAME_TITLE, "Title2");
24+
weatherValues.put(TasksPersistenceContract.TaskEntry.COLUMN_NAME_DESCRIPTION, "Description2");
25+
weatherValues.put(TasksPersistenceContract.TaskEntry.COLUMN_NAME_COMPLETED, 0);
26+
27+
return weatherValues;
28+
}
29+
30+
static void assertCursorEmpty(Cursor valueCursor) {
31+
assertFalse("Non Empty cursor returned", valueCursor.moveToFirst());
32+
}
33+
34+
static void assertCursorHasData(String error, Cursor valueCursor, ContentValues expectedValues) {
35+
assertTrue("Empty cursor returned. " + error, valueCursor.moveToFirst());
36+
validateCurrentRecord(error, valueCursor, expectedValues);
37+
valueCursor.close();
38+
}
39+
40+
static void validateCurrentRecord(String error, Cursor valueCursor, ContentValues expectedValues) {
41+
Set<Map.Entry<String, Object>> valueSet = expectedValues.valueSet();
42+
for (Map.Entry<String, Object> entry : valueSet) {
43+
String columnName = entry.getKey();
44+
int idx = valueCursor.getColumnIndex(columnName);
45+
assertFalse("Column '" + columnName + "' not found. " + error, idx == -1);
46+
String expectedValue = entry.getValue().toString();
47+
assertEquals("Value '" + entry.getValue().toString() +
48+
"' did not match the expected value '" +
49+
expectedValue + "'. " + error, expectedValue, valueCursor.getString(idx));
50+
}
51+
}
52+
53+
}

todoapp/app/src/androidTest/java/com/example/android/architecture/blueprints/todoapp/data/TasksProviderTest.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,19 @@
33
import android.content.ComponentName;
44
import android.content.pm.PackageManager;
55
import android.content.pm.ProviderInfo;
6+
import android.database.Cursor;
67
import android.support.test.InstrumentationRegistry;
78
import android.support.test.runner.AndroidJUnit4;
89
import android.test.AndroidTestCase;
910

11+
import com.example.android.architecture.blueprints.todoapp.data.source.TasksDataSource;
1012
import com.example.android.architecture.blueprints.todoapp.data.source.TasksProvider;
13+
import com.example.android.architecture.blueprints.todoapp.data.source.local.TasksLocalDataSource;
1114
import com.example.android.architecture.blueprints.todoapp.data.source.local.TasksPersistenceContract;
15+
import com.example.android.architecture.blueprints.todoapp.data.source.remote.TasksRemoteDataSource;
16+
import com.google.common.collect.Lists;
17+
18+
import java.util.List;
1219

1320
import org.junit.Before;
1421
import org.junit.Test;
@@ -17,12 +24,33 @@
1724
@RunWith(AndroidJUnit4.class)
1825
public class TasksProviderTest extends AndroidTestCase {
1926

27+
TasksDataSource mTasksRemoteDataSource;
28+
TasksLocalDataSource mTasksLocalDataSource;
29+
30+
private static List<Task> REMOTE_TASKS = Lists.newArrayList(
31+
new Task("Title1", "Description1"),
32+
new Task("Title2", "Description2")
33+
);
34+
2035
@Before
2136
public void setUp() throws Exception {
2237
setContext(InstrumentationRegistry.getTargetContext());
38+
mTasksLocalDataSource = TasksLocalDataSource.getInstance(mContext);
39+
mTasksRemoteDataSource = TasksRemoteDataSource.getInstance();
40+
41+
deleteAllTasks();
42+
2343
super.setUp();
2444
}
2545

46+
private void deleteAllTasks() {
47+
mContext.getContentResolver().delete(
48+
TasksPersistenceContract.BASE_CONTENT_URI,
49+
null,
50+
null
51+
);
52+
}
53+
2654
/*
2755
This test checks to make sure that the content provider is registered correctly.
2856
*/
@@ -72,4 +100,19 @@ public void testGetType() {
72100
);
73101
}
74102

103+
@Test
104+
public void getTasks_returnsEmptyWhenFirstQueried() {
105+
Cursor tasksCursor = mContext.getContentResolver().query(
106+
TasksPersistenceContract.BASE_CONTENT_URI,
107+
null,
108+
null,
109+
null,
110+
null
111+
);
112+
113+
// Make sure we get the correct cursor out of the database
114+
ProviderUtilities.assertCursorEmpty(tasksCursor);
115+
116+
}
117+
75118
}

todoapp/app/src/main/java/com/example/android/architecture/blueprints/todoapp/data/source/TasksInteractor.java

Lines changed: 20 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
import com.example.android.architecture.blueprints.todoapp.data.source.local.TasksPersistenceContract;
1313
import com.example.android.architecture.blueprints.todoapp.tasks.TasksFilterType;
1414

15-
public class TasksInteractor implements LoaderManager.LoaderCallbacks<Cursor> {
15+
public class TasksInteractor {
1616

1717
private static TasksInteractor INSTANCE;
1818

@@ -26,8 +26,6 @@ public class TasksInteractor implements LoaderManager.LoaderCallbacks<Cursor> {
2626
private final LoaderManager mLoaderManager;
2727
private final ContentResolver mContentResolver;
2828

29-
private GetTasksCallback callback;
30-
3129
public static TasksInteractor getInstance(LoaderProvider mLoaderProvider, LoaderManager mLoaderManager, ContentResolver mContentResolver) {
3230
if (INSTANCE == null) {
3331
INSTANCE = new TasksInteractor(mLoaderProvider, mLoaderManager, mContentResolver);
@@ -42,24 +40,21 @@ private TasksInteractor(LoaderProvider mLoaderProvider, LoaderManager mLoaderMan
4240
}
4341

4442
public void getTasks(final Bundle extras, final GetTasksCallback callback) {
45-
this.callback = callback;
4643
if (mLoaderManager.getLoader(TASKS_LOADER) == null) {
47-
mLoaderManager.initLoader(TASKS_LOADER, extras, new GetTasksLoaderCallback(callback));
44+
mLoaderManager.initLoader(TASKS_LOADER, extras, new TasksCursorLoaderCallback(callback));
4845
} else {
49-
mLoaderManager.restartLoader(TASKS_LOADER, extras, new GetTasksLoaderCallback(callback));
46+
mLoaderManager.restartLoader(TASKS_LOADER, extras, new TasksCursorLoaderCallback(callback));
5047
}
5148
}
5249

5350
public void getTask(String taskId, GetTasksCallback callback) {
54-
this.callback = callback;
55-
5651
Bundle bundle = new Bundle();
5752
bundle.putSerializable(TasksInteractor.KEY_TASK_ID, taskId);
5853

5954
if (mLoaderManager.getLoader(TASK_LOADER) == null) {
60-
mLoaderManager.initLoader(TASK_LOADER, bundle, this);
55+
mLoaderManager.initLoader(TASK_LOADER, bundle, new TasksCursorLoaderCallback(callback));
6156
} else {
62-
mLoaderManager.restartLoader(TASK_LOADER, bundle, this);
57+
mLoaderManager.restartLoader(TASK_LOADER, bundle, new TasksCursorLoaderCallback(callback));
6358
}
6459
}
6560

@@ -122,57 +117,37 @@ public void deleteTask(Task deletedTask) {
122117
mContentResolver.delete(TasksPersistenceContract.TaskEntry.buildTasksUri(), selection, selectionArgs);
123118
}
124119

125-
@Override
126-
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
127-
switch (id) {
128-
case TASKS_LOADER:
129-
TasksFilterType tasksFilterType = (TasksFilterType) args.getSerializable(KEY_TASK_FILTER);
130-
return mLoaderProvider.createFilteredTasksLoader(tasksFilterType);
131-
case TASK_LOADER:
132-
String taskId = args.getString(KEY_TASK_ID);
133-
return mLoaderProvider.createTaskLoader(taskId);
134-
default:
135-
throw new IllegalArgumentException("Loader Id not recognised");
136-
}
137-
138-
}
139-
140-
@Override
141-
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
142-
if (data != null) {
143-
callback.onDataLoaded(data);
144-
} else {
145-
callback.onDataNotAvailable();
146-
}
147-
}
148-
149-
@Override
150-
public void onLoaderReset(Loader<Cursor> loader) {
151-
152-
}
153-
154120
public interface GetTasksCallback {
155121
void onDataLoaded(Cursor data);
156122

157123
void onDataNotAvailable();
158124
}
159125

160-
private class GetTasksLoaderCallback implements LoaderManager.LoaderCallbacks<Cursor> {
126+
private class TasksCursorLoaderCallback implements LoaderManager.LoaderCallbacks<Cursor> {
161127
private final GetTasksCallback callback;
162128

163-
public GetTasksLoaderCallback(GetTasksCallback callback) {
129+
public TasksCursorLoaderCallback(GetTasksCallback callback) {
164130
this.callback = callback;
165131
}
166132

167133
@Override
168134
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
169-
TasksFilterType tasksFilterType = (TasksFilterType) args.getSerializable(KEY_TASK_FILTER);
170-
return mLoaderProvider.createFilteredTasksLoader(tasksFilterType);
135+
switch (id) {
136+
case TASKS_LOADER:
137+
TasksFilterType tasksFilterType = (TasksFilterType) args.getSerializable(KEY_TASK_FILTER);
138+
return mLoaderProvider.createFilteredTasksLoader(tasksFilterType);
139+
case TASK_LOADER:
140+
String taskId = args.getString(KEY_TASK_ID);
141+
return mLoaderProvider.createTaskLoader(taskId);
142+
default:
143+
throw new IllegalArgumentException("Loader Id not recognised");
144+
}
145+
171146
}
172147

173148
@Override
174149
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
175-
if (data != null) {
150+
if (data != null && data.moveToFirst()) {
176151
callback.onDataLoaded(data);
177152
} else {
178153
callback.onDataNotAvailable();
@@ -183,6 +158,7 @@ public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
183158
public void onLoaderReset(Loader<Cursor> loader) {
184159

185160
}
161+
186162
}
187163

188164
}

todoapp/app/src/main/java/com/example/android/architecture/blueprints/todoapp/data/source/TasksProvider.java

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,12 @@ public Uri insert(Uri uri, ContentValues values) {
6666
public int delete(Uri uri, String selection, String[] selectionArgs) {
6767
int rowsDeleted;
6868

69-
if (selectionArgs.equals("1")) {
69+
if (null == selection) {
70+
mTasksRemoteDataSource.deleteAllTasks();
71+
rowsDeleted = mTasksLocalDataSource.deleteAllTasks();
72+
clearCache();
73+
74+
} else if (selectionArgs.equals("1")) {
7075
mTasksRemoteDataSource.clearCompletedTasks();
7176
rowsDeleted = mTasksLocalDataSource.clearCompletedTasks(selection, selectionArgs);
7277

@@ -77,7 +82,7 @@ public int delete(Uri uri, String selection, String[] selectionArgs) {
7782
it.remove();
7883
}
7984
}
80-
} else if (selectionArgs.length == 1) {
85+
} else {
8186
String taskId = selectionArgs[0];
8287
mTasksRemoteDataSource.deleteTask(taskId);
8388
rowsDeleted = mTasksLocalDataSource.deleteTask(selectionArgs);
@@ -89,11 +94,6 @@ public int delete(Uri uri, String selection, String[] selectionArgs) {
8994
it.remove();
9095
}
9196
}
92-
93-
} else {
94-
mTasksRemoteDataSource.deleteAllTasks();
95-
rowsDeleted = mTasksLocalDataSource.deleteAllTasks();
96-
mCachedTasks.clear();
9797
}
9898

9999
if (selection == null || rowsDeleted != 0) {
@@ -188,9 +188,9 @@ private MatrixCursor getCachedTasks(String selection, String[] selectionArgs) {
188188
Map.Entry pair = (Map.Entry) it.next();
189189
Task cachedTask = (Task) pair.getValue();
190190

191-
if (selection != null){
191+
if (selection != null) {
192192
boolean taskStateFilter = selectionArgs[0].equals("1");
193-
if (cachedTask.isCompleted() == taskStateFilter){
193+
if (cachedTask.isCompleted() == taskStateFilter) {
194194
matrixCursor.addRow(new Object[]{
195195
cachedTask.getInternalId(),
196196
cachedTask.getId(),
@@ -237,6 +237,14 @@ private void saveTasksInLocalDataSource(List<Task> tasks) {
237237
}
238238
}
239239

240+
private void clearCache(){
241+
if (mCachedTasks == null) {
242+
mCachedTasks = new LinkedHashMap<>();
243+
} else {
244+
mCachedTasks.clear();
245+
}
246+
}
247+
240248
private static UriMatcher buildUriMatcher() {
241249
final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
242250
final String authority = TasksPersistenceContract.CONTENT_AUTHORITY;

todoapp/app/src/main/java/com/example/android/architecture/blueprints/todoapp/taskdetail/TaskDetailPresenter.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -110,11 +110,7 @@ private void showTask(Cursor data) {
110110

111111
@Override
112112
public void onDataLoaded(Cursor data) {
113-
if (data != null && data.moveToLast()) {
114-
showTask(data);
115-
} else {
116-
mTaskDetailView.showMissingTask();
117-
}
113+
showTask(data);
118114
}
119115

120116
@Override

0 commit comments

Comments
 (0)