Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.widget.cts;
     18 
     19 import static org.junit.Assert.assertEquals;
     20 import static org.junit.Assert.assertFalse;
     21 import static org.junit.Assert.assertNotNull;
     22 import static org.junit.Assert.assertNull;
     23 import static org.junit.Assert.assertSame;
     24 import static org.junit.Assert.assertTrue;
     25 import static org.junit.Assert.fail;
     26 
     27 import android.content.Context;
     28 import android.content.res.Resources.Theme;
     29 import android.database.ContentObserver;
     30 import android.database.Cursor;
     31 import android.database.DataSetObserver;
     32 import android.database.sqlite.SQLiteDatabase;
     33 import android.os.Looper;
     34 import android.support.test.InstrumentationRegistry;
     35 import android.support.test.annotation.UiThreadTest;
     36 import android.support.test.filters.MediumTest;
     37 import android.support.test.runner.AndroidJUnit4;
     38 import android.view.LayoutInflater;
     39 import android.view.View;
     40 import android.view.ViewGroup;
     41 import android.widget.CursorAdapter;
     42 import android.widget.Filter;
     43 import android.widget.FilterQueryProvider;
     44 import android.widget.TextView;
     45 
     46 import com.android.compatibility.common.util.PollingCheck;
     47 import com.android.compatibility.common.util.TestThread;
     48 
     49 import org.junit.After;
     50 import org.junit.Before;
     51 import org.junit.Test;
     52 import org.junit.runner.RunWith;
     53 
     54 import java.io.File;
     55 
     56 /**
     57  * Test {@link CursorAdapter}.
     58  */
     59 @MediumTest
     60 @RunWith(AndroidJUnit4.class)
     61 public class CursorAdapterTest {
     62     private static final long TEST_TIME_OUT = 5000;
     63     private static final int NUMBER_INDEX = 1;
     64     private static final String FIRST_NUMBER = "123";
     65     private static final String SECOND_NUMBER = "5555";
     66     private static final int FIRST_ITEM_ID = 1;
     67     private static final int SECOND_ITEM_ID = 2;
     68     private static final String[] NUMBER_PROJECTION = new String[] {
     69         "_id",             // 0
     70         "number"           // 1
     71     };
     72     private SQLiteDatabase mDatabase;
     73     private File mDatabaseFile;
     74     private Cursor mCursor;
     75     private ViewGroup mParent;
     76     private MockCursorAdapter mMockCursorAdapter;
     77     private Context mContext;
     78 
     79     @Before
     80     public void setup() {
     81         mContext = InstrumentationRegistry.getTargetContext();
     82         File dbDir = mContext.getDir("tests", Context.MODE_PRIVATE);
     83         mDatabaseFile = new File(dbDir, "database_test.db");
     84         if (mDatabaseFile.exists()) {
     85             mDatabaseFile.delete();
     86         }
     87         mDatabase = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile.getPath(), null);
     88         assertNotNull(mDatabase);
     89         mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, number TEXT);");
     90         mDatabase.execSQL("INSERT INTO test (number) VALUES ('" + FIRST_NUMBER + "');");
     91         mDatabase.execSQL("INSERT INTO test (number) VALUES ('" + SECOND_NUMBER + "');");
     92         mCursor = mDatabase.query("test", NUMBER_PROJECTION, null, null, null, null, null);
     93         assertNotNull(mCursor);
     94 
     95         final LayoutInflater inflater = LayoutInflater.from(mContext);
     96         mParent = (ViewGroup) inflater.inflate(R.layout.cursoradapter_host, null);
     97         assertNotNull(mParent);
     98     }
     99 
    100     @After
    101     public void teardown() {
    102         if (null != mCursor) {
    103             mCursor.close();
    104             mCursor = null;
    105         }
    106         mDatabase.close();
    107         mDatabaseFile.delete();
    108     }
    109 
    110     @UiThreadTest
    111     @Test
    112     public void testConstructor() {
    113         new MockCursorAdapter(mContext, mCursor);
    114 
    115         new MockCursorAdapter(null, null);
    116 
    117         new MockCursorAdapter(mContext, mCursor, true);
    118 
    119         new MockCursorAdapter(null, null, false);
    120     }
    121 
    122     @UiThreadTest
    123     @Test
    124     public void testInit() {
    125         MockCursorAdapter cursorAdapter = new MockCursorAdapter(null, null, false);
    126         cursorAdapter.init(null, null, false);
    127         assertNull(cursorAdapter.getContext());
    128         assertNull(cursorAdapter.getCursor());
    129         assertFalse(cursorAdapter.getAutoRequery());
    130         assertFalse(cursorAdapter.getDataValid());
    131         assertEquals(-1, cursorAdapter.getRowIDColumn());
    132 
    133         // add context
    134         cursorAdapter.init(mContext, null, false);
    135         assertSame(mContext, cursorAdapter.getContext());
    136         assertNull(cursorAdapter.getCursor());
    137         assertFalse(cursorAdapter.getAutoRequery());
    138         assertFalse(cursorAdapter.getDataValid());
    139         assertEquals(-1, cursorAdapter.getRowIDColumn());
    140 
    141         // add autoRequery
    142         cursorAdapter.init(mContext, null, true);
    143         assertSame(mContext, cursorAdapter.getContext());
    144         assertNull(cursorAdapter.getCursor());
    145         assertTrue(cursorAdapter.getAutoRequery());
    146         assertFalse(cursorAdapter.getDataValid());
    147         assertEquals(-1, cursorAdapter.getRowIDColumn());
    148 
    149         // add cursor
    150         cursorAdapter.init(mContext, mCursor, true);
    151         assertSame(mContext, cursorAdapter.getContext());
    152         assertSame(mCursor, cursorAdapter.getCursor());
    153         assertTrue(cursorAdapter.getAutoRequery());
    154         assertTrue(cursorAdapter.getDataValid());
    155         assertEquals(0, cursorAdapter.getRowIDColumn());
    156         try {
    157             mCursor.registerContentObserver(cursorAdapter.getContentObserver());
    158             fail("the ContentObserver has not been registered");
    159         } catch (IllegalStateException e) {
    160         }
    161         try {
    162             mCursor.registerDataSetObserver(cursorAdapter.getDataSetObserver());
    163             fail("the DataSetObserver has not been registered");
    164         } catch (IllegalStateException e) {
    165         }
    166     }
    167 
    168     @UiThreadTest
    169     @Test
    170     public void testGetCount() {
    171         CursorAdapter cursorAdapter = new MockCursorAdapter(mContext, null);
    172         assertEquals(0, cursorAdapter.getCount());
    173 
    174         cursorAdapter.changeCursor(mCursor);
    175         assertEquals(mCursor.getCount(), cursorAdapter.getCount());
    176     }
    177 
    178     @UiThreadTest
    179     @Test
    180     public void testAccessCursor() {
    181         CursorAdapter cursorAdapter = new MockCursorAdapter(mContext, null);
    182         assertNull(cursorAdapter.getCursor());
    183 
    184         cursorAdapter.changeCursor(mCursor);
    185         assertSame(mCursor, cursorAdapter.getCursor());
    186 
    187         cursorAdapter.changeCursor(null);
    188         assertNull(cursorAdapter.getCursor());
    189     }
    190 
    191     @UiThreadTest
    192     @Test
    193     public void testConvertToString() {
    194         CursorAdapter cursorAdapter = new MockCursorAdapter(mContext, null);
    195         assertEquals("", cursorAdapter.convertToString(null));
    196 
    197         assertEquals(mCursor.toString(), cursorAdapter.convertToString(mCursor));
    198     }
    199 
    200     @UiThreadTest
    201     @Test
    202     public void testHasStableIds() {
    203         CursorAdapter cursorAdapter = new MockCursorAdapter(mContext, mCursor);
    204         assertTrue(cursorAdapter.hasStableIds());
    205 
    206         cursorAdapter  = new MockCursorAdapter(null, null);
    207         assertTrue(cursorAdapter.hasStableIds());
    208     }
    209 
    210     @UiThreadTest
    211     @Test
    212     public void testGetView() {
    213         TextView textView = new TextView(mContext);
    214         textView.setText("getView test");
    215 
    216         MockCursorAdapter cursorAdapter = new MockCursorAdapter(mContext, null);
    217         // null cursor
    218         assertFalse(cursorAdapter.getDataValid());
    219         try {
    220             cursorAdapter.getView(0, textView, mParent);
    221             fail("does not throw IllegalStateException when cursor is invalid");
    222         } catch (IllegalStateException e) {
    223         }
    224 
    225         cursorAdapter = new MockCursorAdapter(mContext, mCursor);
    226         try {
    227             cursorAdapter.getView(100, textView, mParent);
    228             fail("does not throw IllegalStateException when position is out of bound");
    229         } catch (IllegalStateException e) {
    230         }
    231 
    232         // null convertView
    233         TextView retView = (TextView) cursorAdapter.getView(0, null, mParent);
    234         assertNotNull(retView);
    235         assertEquals(FIRST_NUMBER, retView.getText().toString());
    236 
    237         // convertView is not null
    238         retView = (TextView) cursorAdapter.getView(1, textView, mParent);
    239         assertNotNull(retView);
    240         assertEquals(SECOND_NUMBER, retView.getText().toString());
    241     }
    242 
    243     @UiThreadTest
    244     @Test
    245     public void testNewDropDownView() {
    246         CursorAdapter cursorAdapter = new MockCursorAdapter(mContext, mCursor);
    247         // null cursor
    248         assertNull(cursorAdapter.newDropDownView(mContext, null, mParent));
    249 
    250         TextView textView = (TextView) cursorAdapter.newDropDownView(mContext, mCursor, mParent);
    251         assertEquals(FIRST_NUMBER, textView.getText().toString());
    252     }
    253 
    254     @UiThreadTest
    255     @Test
    256     public void testGetDropDownView() {
    257         MockCursorAdapter cursorAdapter = new MockCursorAdapter(mContext, null);
    258         // null cursor
    259         assertFalse(cursorAdapter.getDataValid());
    260         TextView textView = new TextView(mContext);
    261         textView.setText("getDropDownView test");
    262 
    263         assertNull(cursorAdapter.getDropDownView(0, textView, mParent));
    264 
    265         // null convertView
    266         cursorAdapter = new MockCursorAdapter(mContext, mCursor);
    267         TextView retView = (TextView) cursorAdapter.getDropDownView(0, null, mParent);
    268         assertNotNull(retView);
    269         assertEquals(FIRST_NUMBER, retView.getText().toString());
    270 
    271         // convertView is not null
    272         retView = (TextView) cursorAdapter.getDropDownView(1, textView, mParent);
    273         assertNotNull(retView);
    274         assertEquals(SECOND_NUMBER, retView.getText().toString());
    275     }
    276 
    277     @UiThreadTest
    278     @Test
    279     public void testAccessDropDownViewTheme() {
    280         CursorAdapter cursorAdapter = new MockCursorAdapter(mContext, null);
    281         Theme theme = mContext.getResources().newTheme();
    282         cursorAdapter.setDropDownViewTheme(theme);
    283         assertSame(theme, cursorAdapter.getDropDownViewTheme());
    284     }
    285 
    286     @UiThreadTest
    287     @Test
    288     public void testGetFilter() {
    289         CursorAdapter cursorAdapter = new MockCursorAdapter(mContext, mCursor);
    290         Filter filter = cursorAdapter.getFilter();
    291         assertNotNull(filter);
    292     }
    293 
    294     @UiThreadTest
    295     @Test
    296     public void testGetItem() {
    297         CursorAdapter cursorAdapter = new MockCursorAdapter(mContext, null);
    298         // cursor is null
    299         assertNull(cursorAdapter.getItem(0));
    300 
    301         cursorAdapter = new MockCursorAdapter(mContext, mCursor);
    302         Cursor c = (Cursor) cursorAdapter.getItem(0);
    303         assertNotNull(c);
    304         assertEquals(0, c.getPosition());
    305         assertEquals(FIRST_NUMBER, c.getString(NUMBER_INDEX));
    306 
    307         c = (Cursor) cursorAdapter.getItem(1);
    308         assertNotNull(c);
    309         assertEquals(1, c.getPosition());
    310         assertEquals(SECOND_NUMBER, c.getString(NUMBER_INDEX));
    311     }
    312 
    313     @UiThreadTest
    314     @Test
    315     public void testGetItemId() {
    316         CursorAdapter cursorAdapter = new MockCursorAdapter(mContext, null);
    317         // cursor is null
    318         assertEquals(0, cursorAdapter.getItemId(0));
    319 
    320         cursorAdapter = new MockCursorAdapter(mContext, mCursor);
    321         assertEquals(FIRST_ITEM_ID, cursorAdapter.getItemId(0));
    322 
    323         assertEquals(SECOND_ITEM_ID, cursorAdapter.getItemId(1));
    324 
    325         // position is out of bound
    326         assertEquals(0, cursorAdapter.getItemId(2));
    327     }
    328 
    329     @UiThreadTest
    330     @Test
    331     public void testAccessFilterQueryProvider() {
    332         CursorAdapter cursorAdapter = new MockCursorAdapter(mContext, mCursor);
    333         FilterQueryProvider filterProvider = new MockFilterQueryProvider();
    334         assertNotNull(filterProvider);
    335 
    336         assertNull(cursorAdapter.getFilterQueryProvider());
    337 
    338         cursorAdapter.setFilterQueryProvider(filterProvider);
    339         assertSame(filterProvider, cursorAdapter.getFilterQueryProvider());
    340     }
    341 
    342     @UiThreadTest
    343     @Test
    344     public void testRunQueryOnBackgroundThread() {
    345         CursorAdapter cursorAdapter = new MockCursorAdapter(mContext, mCursor);
    346         final String constraint = "constraint";
    347 
    348         // FilterQueryProvider is null, return mCursor
    349         assertSame(mCursor, cursorAdapter.runQueryOnBackgroundThread(constraint));
    350 
    351         FilterQueryProvider filterProvider = new MockFilterQueryProvider();
    352         assertNotNull(filterProvider);
    353         cursorAdapter.setFilterQueryProvider(filterProvider);
    354         assertNull(cursorAdapter.runQueryOnBackgroundThread(constraint));
    355     }
    356 
    357     @Test
    358     public void testOnContentChanged() throws Throwable {
    359         new TestThread(() -> {
    360             Looper.prepare();
    361             mMockCursorAdapter = new MockCursorAdapter(mContext, mCursor);
    362         }).runTest(TEST_TIME_OUT);
    363         assertFalse(mMockCursorAdapter.hasContentChanged());
    364         // insert a new row
    365         mDatabase.execSQL("INSERT INTO test (number) VALUES ('" + FIRST_NUMBER + "');");
    366         new PollingCheck(TEST_TIME_OUT) {
    367             @Override
    368             protected boolean check() {
    369                 return mMockCursorAdapter.hasContentChanged();
    370             }
    371         };
    372     }
    373 
    374     private final class MockCursorAdapter extends CursorAdapter {
    375         private Context mContext;
    376         private boolean mAutoRequery;
    377 
    378         private boolean mContentChanged = false;
    379 
    380         public MockCursorAdapter(Context context, Cursor c) {
    381             super(context, c);
    382 
    383             mContext = context;
    384             mAutoRequery = false;
    385         }
    386 
    387         public MockCursorAdapter(Context context, Cursor c, boolean autoRequery) {
    388             super(context, c, autoRequery);
    389 
    390             mContext = context;
    391             mAutoRequery = autoRequery;
    392         }
    393 
    394         public Context getContext() {
    395             return mContext;
    396         }
    397 
    398         public boolean getAutoRequery() {
    399             return mAutoRequery;
    400         }
    401 
    402         public boolean getDataValid() {
    403             return mDataValid;
    404         }
    405 
    406         public int getRowIDColumn() {
    407             return mRowIDColumn;
    408         }
    409 
    410         public ContentObserver getContentObserver() {
    411             return mChangeObserver;
    412         }
    413 
    414         public DataSetObserver getDataSetObserver() {
    415             return mDataSetObserver;
    416         }
    417 
    418         @Override
    419         public void init(Context context, Cursor c, boolean autoRequery) {
    420             super.init(context, c, autoRequery);
    421 
    422             mContext = context;
    423             mAutoRequery = autoRequery;
    424         }
    425 
    426         @Override
    427         public void bindView(View view, Context context, Cursor cursor) {
    428             if (null == context || null == cursor || null == view) {
    429                 return;
    430             }
    431 
    432             if (view instanceof TextView) {
    433                 String number = cursor.getString(NUMBER_INDEX);
    434                 TextView textView = (TextView) view;
    435                 textView.setText(number);
    436             }
    437         }
    438 
    439         @Override
    440         public View newView(Context context, Cursor cursor, ViewGroup parent) {
    441             if (null == context || null == cursor || null == parent) {
    442                 return null;
    443             }
    444 
    445             if (cursor.moveToFirst()) {
    446                 String number = cursor.getString(NUMBER_INDEX);
    447                 TextView textView = new TextView(context);
    448                 textView.setText(number);
    449                 return textView;
    450             }
    451             return null;
    452         }
    453 
    454         @Override
    455         protected void onContentChanged() {
    456             super.onContentChanged();
    457             mContentChanged = true;
    458         }
    459 
    460         public boolean hasContentChanged() {
    461             return mContentChanged;
    462         }
    463     }
    464 
    465     private final class MockFilterQueryProvider implements FilterQueryProvider {
    466         public Cursor runQuery(CharSequence constraint) {
    467             return null;
    468         }
    469     }
    470 }
    471