TestContentProvider.java revision c01ec9664a26a603d90b067d1ca7ca39950eb025
1c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay/*
2c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * Copyright (C) 2017 The Android Open Source Project
3c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay *
4c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * Licensed under the Apache License, Version 2.0 (the "License");
5c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * you may not use this file except in compliance with the License.
6c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * You may obtain a copy of the License at
7c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay *
8c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay *      http://www.apache.org/licenses/LICENSE-2.0
9c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay *
10c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * Unless required by applicable law or agreed to in writing, software
11c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * distributed under the License is distributed on an "AS IS" BASIS,
12c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * See the License for the specific language governing permissions and
14c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * limitations under the License.
15c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay */
16c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
17c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKaypackage android.support.content;
18c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
19c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKayimport static junit.framework.Assert.assertEquals;
20c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
21c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKayimport android.content.ContentProvider;
22c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKayimport android.content.ContentResolver;
23c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKayimport android.content.ContentValues;
24c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKayimport android.database.AbstractWindowedCursor;
25c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKayimport android.database.Cursor;
26c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKayimport android.database.CursorWindow;
27c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKayimport android.database.MatrixCursor;
28c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKayimport android.database.MatrixCursor.RowBuilder;
29c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKayimport android.net.Uri;
30c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKayimport android.os.Bundle;
31c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKayimport android.os.CancellationSignal;
32c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKayimport android.support.annotation.Nullable;
33c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKayimport android.support.annotation.VisibleForTesting;
34c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
35c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay/**
36c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * A stub data paging provider used for testing of paging support.
37c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * Ignores client supplied projections.
38c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay */
39c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKaypublic final class TestContentProvider extends ContentProvider {
40c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
41c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    public static final String AUTHORITY = "android.support.content.test.testpagingprovider";
42c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
43c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    public static final String UNPAGED_PATH = "/un-paged";
44c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    public static final String PAGED_PATH = "/paged";
45c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    public static final String PAGED_WINDOWED_PATH = PAGED_PATH + "/windowed";
46c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
47c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    public static final Uri UNPAGED_URI = new Uri.Builder()
48c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            .scheme("content")
49c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            .authority(AUTHORITY)
50c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            .path(UNPAGED_PATH)
51c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            .build();
52c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    public static final Uri PAGED_URI = new Uri.Builder()
53c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            .scheme("content")
54c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            .authority(AUTHORITY)
55c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            .path(PAGED_PATH)
56c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            .build();
57c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    public static final Uri PAGED_WINDOWED_URI = new Uri.Builder()
58c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            .scheme("content")
59c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            .authority(AUTHORITY)
60c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            .path(PAGED_WINDOWED_PATH)
61c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            .build();
62c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
63c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    public static final String COLUMN_POS = "ColumnPos";
64c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    public static final String COLUMN_A = "ColumnA";
65c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    public static final String COLUMN_B = "ColumnB";
66c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    public static final String COLUMN_C = "ColumnC";
67c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    public static final String COLUMN_D = "ColumnD";
68c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    public static final String[] PROJECTION = {
69c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            COLUMN_POS,
70c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            COLUMN_A,
71c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            COLUMN_B,
72c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            COLUMN_C,
73c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            COLUMN_D
74c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    };
75c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
76c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    @VisibleForTesting
77c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    public static final String RECORD_COUNT = "test-record-count";
78c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
79c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    @VisibleForTesting
80c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    public static final int DEFAULT_RECORD_COUNT = 567;
81c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
82c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    private static final String TAG = "TestPagingProvider";
83c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
84c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    @Override
85c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    public boolean onCreate() {
86c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        return true;
87c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    }
88c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
89c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    @Override
90c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    public Cursor query(
91c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            Uri uri, @Nullable String[] projection, String selection, String[] selectionArgs,
92c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            String sortOrder) {
93c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        return query(uri, projection, null, null);
94c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    }
95c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
96c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    @Override
97c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    public Cursor query(Uri uri, String[] ignored, Bundle queryArgs,
98c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            CancellationSignal cancellationSignal) {
99c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
100c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        queryArgs = queryArgs != null ? queryArgs : Bundle.EMPTY;
101c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
102c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        int recordCount = getIntValue(RECORD_COUNT, queryArgs, uri, DEFAULT_RECORD_COUNT);
103c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        if (recordCount < 0) {
104c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            throw new RuntimeException("Recordset size must be >= 0");
105c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        }
106c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
107c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        Cursor cursor = null;
108c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        switch (uri.getPath()) {
109c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            case UNPAGED_PATH:
110c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                cursor = buildUnpagedResults(recordCount);
111c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                break;
112c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            case PAGED_PATH:
113c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                cursor = buildPagedResults(uri, queryArgs, recordCount);
114c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                break;
115c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            case PAGED_WINDOWED_PATH:
116c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                cursor = buildPagedWindowedResults(uri, queryArgs, recordCount);
117c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                break;
118c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            default:
119c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                throw new IllegalArgumentException("Unrecognized path: " + uri.getPath());
120c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        }
121c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
122c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        cursor.setNotificationUri(getContext().getContentResolver(), uri);
123c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
124c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        return cursor;
125c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    }
126c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
127c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    /**
128c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay     * Return a int value specified in Bundle key, Uri query arg, or fallback default value.
129c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay     */
130c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    private static int getIntValue(String key, Bundle queryArgs, Uri uri, int defaultValue) {
131c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        int value = queryArgs.getInt(key, Integer.MIN_VALUE);
132c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        if (value != Integer.MIN_VALUE) {
133c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            return value;
134c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        }
135c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
136c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        @Nullable String argValue = uri.getQueryParameter(key);
137c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        if (argValue != null) {
138c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            try {
139c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                return Integer.parseInt(argValue);
140c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            } catch (NumberFormatException ignored) {
141c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            }
142c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        }
143c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
144c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        return defaultValue;
145c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    }
146c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
147c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    private MatrixCursor buildPagedResults(Uri uri, Bundle queryArgs, int recordsetSize) {
148c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        int offset = getIntValue(ContentResolver.QUERY_ARG_OFFSET, queryArgs, uri, 0);
149c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        int limit = getIntValue(ContentResolver.QUERY_ARG_LIMIT, queryArgs, uri, recordsetSize);
150c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
151c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        MatrixCursor c = createInMemoryCursor();
152c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        Bundle extras = c.getExtras();
153c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
154c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        // Calculate the number of items to include in the cursor.
155c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        int numItems = constrain(recordsetSize - offset, 0, limit);
156c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
157c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        // Build the paged result set.
158c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        for (int i = offset; i < offset + numItems; i++) {
159c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            fillRow(c.newRow(), i);
160c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        }
161c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
162c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        extras.putStringArray(ContentResolver.EXTRA_HONORED_ARGS, new String[] {
163c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                ContentResolver.QUERY_ARG_OFFSET,
164c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                ContentResolver.QUERY_ARG_LIMIT
165c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        });
166c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        extras.putInt(ContentResolver.EXTRA_TOTAL_COUNT, recordsetSize);
167c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        return c;
168c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    }
169c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
170c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    private AbstractWindowedCursor buildPagedWindowedResults(
171c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            Uri uri, Bundle queryArgs, int recordsetSize) {
172c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        int offset = getIntValue(ContentResolver.QUERY_ARG_OFFSET, queryArgs, uri, 0);
173c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        int limit = getIntValue(ContentResolver.QUERY_ARG_LIMIT, queryArgs, uri, recordsetSize);
174c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
175c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        int windowSize = limit - 1;
176c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
177c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        TestWindowedCursor c = new TestWindowedCursor(PROJECTION, recordsetSize);
178c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        CursorWindow window = c.getWindow();
179c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        window.setNumColumns(PROJECTION.length);
180c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
181c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        Bundle extras = c.getExtras();
182c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
183c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        // Build the unpaged result set.
184c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        for (int row = 0; row < windowSize; row++) {
185c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            if (!window.allocRow()) {
186c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                break;
187c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            }
188c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            if (!fillRow(window, row)) {
189c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                window.freeLastRow();
190c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                break;
191c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            }
192c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        }
193c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
194c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        extras.putStringArray(ContentResolver.EXTRA_HONORED_ARGS, new String[] {
195c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                ContentResolver.QUERY_ARG_OFFSET,
196c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                ContentResolver.QUERY_ARG_LIMIT
197c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        });
198c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        extras.putInt(ContentResolver.EXTRA_TOTAL_COUNT, recordsetSize);
199c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        return c;
200c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    }
201c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
202c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    private MatrixCursor buildUnpagedResults(int recordsetSize) {
203c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        MatrixCursor c = createInMemoryCursor();
204c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
205c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        // Build the unpaged result set.
206c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        for (int i = 0; i < recordsetSize; i++) {
207c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            fillRow(c.newRow(), i);
208c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        }
209c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
210c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        return c;
211c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    }
212c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
213c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    /**
214c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay     * Returns data type of the given object's value.
215c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay     *<p>
216c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay     * Returned values are
217c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay     * <ul>
218c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay     *   <li>{@link Cursor#FIELD_TYPE_NULL}</li>
219c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay     *   <li>{@link Cursor#FIELD_TYPE_INTEGER}</li>
220c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay     *   <li>{@link Cursor#FIELD_TYPE_FLOAT}</li>
221c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay     *   <li>{@link Cursor#FIELD_TYPE_STRING}</li>
222c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay     *   <li>{@link Cursor#FIELD_TYPE_BLOB}</li>
223c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay     *</ul>
224c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay     *</p>
225c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay     */
226c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    public static int getTypeOfObject(Object obj) {
227c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        if (obj == null) {
228c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            return Cursor.FIELD_TYPE_NULL;
229c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        } else if (obj instanceof byte[]) {
230c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            return Cursor.FIELD_TYPE_BLOB;
231c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        } else if (obj instanceof Float || obj instanceof Double) {
232c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            return Cursor.FIELD_TYPE_FLOAT;
233c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        } else if (obj instanceof Long || obj instanceof Integer
234c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                || obj instanceof Short || obj instanceof Byte) {
235c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            return Cursor.FIELD_TYPE_INTEGER;
236c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        } else {
237c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            return Cursor.FIELD_TYPE_STRING;
238c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        }
239c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    }
240c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
241c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    private MatrixCursor createInMemoryCursor() {
242c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        MatrixCursor c = new MatrixCursor(PROJECTION);
243c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        Bundle extras = new Bundle();
244c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        c.setExtras(extras);
245c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        return c;
246c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    }
247c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
248c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    private void fillRow(RowBuilder row, int rowId) {
249c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        row.add(createCellValue(rowId, 0));
250c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        row.add(createCellValue(rowId, 1));
251c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        row.add(createCellValue(rowId, 2));
252c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        row.add(createCellValue(rowId, 3));
253c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        row.add(createCellValue(rowId, 4));
254c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    }
255c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
256c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    /**
257c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay     * @return true if the row was successfully populated. If false, caller should freeLastRow.
258c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay     */
259c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    private static boolean fillRow(CursorWindow window, int row) {
260c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        if (!window.putLong((int) createCellValue(row, 0), row, 0)) {
261c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            return false;
262c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        }
263c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        for (int i = 1; i < PROJECTION.length; i++) {
264c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            if (!window.putString((String) createCellValue(row, i), row, i)) {
265c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                return false;
266c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            }
267c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        }
268c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        return true;
269c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    }
270c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
271c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    private static Object createCellValue(int row, int col) {
272c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        switch(col) {
273c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            case 0:
274c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                return row;
275c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            case 1:
276c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                return "--aaa--" + row;
277c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            case 2:
278c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                return "**bbb**" + row;
279c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            case 3:
280c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                return ("^^ccc^^" + row);
281c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            case 4:
282c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                return "##ddd##" + row;
283c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            default:
284c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                throw new IllegalArgumentException("Unsupported column: " + col);
285c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        }
286c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    }
287c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
288c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    /**
289c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay     * Asserts that the value at the current cursor position x column
290c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay     * is expected test data for the supplied row.
291c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay     *
292c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay     * <p>Cursor must be pre-positioned.
293c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay     *
294c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay     * @param cursor must be prepositioned to the row to be tested.
295c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay     * @param row row value expected to be reflected in cell. This can be different
296c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay     *            than the cursor position due to paging.
297c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay     * @param column
298c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay     */
299c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    @VisibleForTesting
300c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    public static void assertExpectedCellValue(Cursor cursor, int row, int column) {
301c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        int type = cursor.getType(column);
302c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        switch(type) {
303c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            case Cursor.FIELD_TYPE_NULL:
304c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                throw new UnsupportedOperationException("Not implemented.");
305c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            case Cursor.FIELD_TYPE_INTEGER:
306c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                assertEquals(createCellValue(row, column), cursor.getInt(column));
307c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                break;
308c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            case Cursor.FIELD_TYPE_FLOAT:
309c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                assertEquals(createCellValue(row, column), cursor.getDouble(column));
310c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                break;
311c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            case Cursor.FIELD_TYPE_BLOB:
312c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                assertEquals(createCellValue(row, column), cursor.getBlob(column));
313c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                break;
314c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            case Cursor.FIELD_TYPE_STRING:
315c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                assertEquals(createCellValue(row, column), cursor.getString(column));
316c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                break;
317c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            default:
318c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                throw new UnsupportedOperationException("Unknown column type: " + type);
319c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        }
320c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    }
321c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
322c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    @Override
323c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    public String getType(Uri uri) {
324c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        throw new UnsupportedOperationException();
325c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    }
326c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
327c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    @Override
328c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    public Uri insert(Uri uri, ContentValues values) {
329c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        throw new UnsupportedOperationException();
330c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    }
331c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
332c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    @Override
333c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    public int delete(Uri uri, String selection, String[] selectionArgs) {
334c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        throw new UnsupportedOperationException();
335c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    }
336c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
337c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    @Override
338c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
339c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        throw new UnsupportedOperationException();
340c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    }
341c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
342c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    private static int constrain(int amount, int low, int high) {
343c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        return amount < low ? low : (amount > high ? high : amount);
344c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    }
345c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
346c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    /**
347c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay     * Returns a Uri that includes paging information embedded in the URI.
348c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay     * This allows a test client to force paged results when running on older SDKs...
349c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay     * pre Android O SDKs lacking the ContentResolver#query w/ Bundle override
350c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay     * necessary for paging.
351c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay     */
352c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    public static Uri forcePagingSpec(Uri uri, int offset, int limit) {
353c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        assert (uri.getPath().equals(TestContentProvider.PAGED_PATH)
354c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                || uri.getPath().equals(TestContentProvider.PAGED_WINDOWED_PATH));
355c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        return uri.buildUpon()
356c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                .appendQueryParameter(ContentResolver.QUERY_ARG_OFFSET, String.valueOf(offset))
357c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                .appendQueryParameter(ContentResolver.QUERY_ARG_LIMIT, String.valueOf(limit))
358c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                .build();
359c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    }
360c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
361c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    public static Uri forceRecordCount(Uri uri, int recordCount) {
362c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        return uri.buildUpon()
363c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                .appendQueryParameter(RECORD_COUNT, String.valueOf(recordCount))
364c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                .build();
365c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    }
366c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
367c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    private static final class TestWindowedCursor extends AbstractWindowedCursor {
368c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
369c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        private final String[] mProjection;
370c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        private final int mCount;
371c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        private final Bundle mExtras;
372c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
373c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        TestWindowedCursor(String[] projection, int count) {
374c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            mProjection = projection;
375c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            mCount = count;
376c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            mExtras = new Bundle();
377c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
378c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            setWindow(new CursorWindow("stevie"));
379c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        }
380c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
381c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        @Override
382c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        public Bundle getExtras() {
383c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            return mExtras;
384c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        }
385c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
386c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        @Override
387c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        public int getCount() {
388c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            return mCount;
389c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        }
390c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
391c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        @Override
392c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        public String[] getColumnNames() {
393c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            return mProjection;
394c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        }
395c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    }
396c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay}
397