package co.smartreceipts.android.persistence.database.tables; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import java.util.Arrays; import java.util.Collections; import java.util.List; import co.smartreceipts.android.model.Column; import co.smartreceipts.android.model.ColumnDefinitions; import co.smartreceipts.android.model.Receipt; import co.smartreceipts.android.model.impl.columns.BlankColumn; import co.smartreceipts.android.model.impl.columns.receipts.ReceiptCategoryNameColumn; import co.smartreceipts.android.model.impl.columns.receipts.ReceiptNameColumn; import co.smartreceipts.android.model.impl.columns.receipts.ReceiptPriceColumn; import co.smartreceipts.android.persistence.DatabaseHelper; import co.smartreceipts.android.persistence.database.defaults.TableDefaultsCustomizer; import co.smartreceipts.android.persistence.database.operations.DatabaseOperationMetadata; import co.smartreceipts.android.sync.model.SyncState; import co.smartreceipts.android.sync.model.impl.DefaultSyncState; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @RunWith(RobolectricTestRunner.class) public class CSVTableTest { // Class Under Test CSVTable mCSVTable; @Mock ColumnDefinitions<Receipt> mReceiptColumnDefinitions; @Mock SQLiteDatabase mSQLiteDatabase; @Mock TableDefaultsCustomizer mTableDefaultsCustomizer; SQLiteOpenHelper mSQLiteOpenHelper; @Captor ArgumentCaptor<String> mSqlCaptor; Column<Receipt> mColumn1; Column<Receipt> mColumn2; Column<Receipt> mDefaultColumn; @Before public void setup() { MockitoAnnotations.initMocks(this); mSQLiteOpenHelper = new TestSQLiteOpenHelper(RuntimeEnvironment.application); mCSVTable = new CSVTable(mSQLiteOpenHelper, mReceiptColumnDefinitions); mDefaultColumn = new BlankColumn<>(-1, "", new DefaultSyncState()); when(mReceiptColumnDefinitions.getDefaultInsertColumn()).thenReturn(mDefaultColumn); when(mReceiptColumnDefinitions.getColumn(anyInt(), eq(""), any(SyncState.class))).thenReturn(mDefaultColumn); // Now create the table and insert some defaults mCSVTable.onCreate(mSQLiteOpenHelper.getWritableDatabase(), mTableDefaultsCustomizer); mColumn1 = mCSVTable.insert(new ReceiptNameColumn(-1, "Name", new DefaultSyncState()), new DatabaseOperationMetadata()).blockingGet(); mColumn2 = mCSVTable.insert(new ReceiptPriceColumn(-1, "Price", new DefaultSyncState()), new DatabaseOperationMetadata()).blockingGet(); assertNotNull(mColumn1); assertNotNull(mColumn2); } @After public void tearDown() { mSQLiteOpenHelper.getWritableDatabase().execSQL("DROP TABLE IF EXISTS " + mCSVTable.getTableName()); } @Test public void getTableName() { assertEquals("csvcolumns", mCSVTable.getTableName()); } @Test public void onCreate() { final TableDefaultsCustomizer customizer = mock(TableDefaultsCustomizer.class); mCSVTable.onCreate(mSQLiteDatabase, customizer); verify(mSQLiteDatabase).execSQL(mSqlCaptor.capture()); verify(customizer).insertCSVDefaults(mCSVTable); assertTrue(mSqlCaptor.getValue().contains("CREATE TABLE csvcolumns")); assertTrue(mSqlCaptor.getValue().contains("id INTEGER PRIMARY KEY AUTOINCREMENT")); assertTrue(mSqlCaptor.getValue().contains("type TEXT")); assertTrue(mSqlCaptor.getValue().contains("drive_sync_id TEXT")); assertTrue(mSqlCaptor.getValue().contains("drive_is_synced BOOLEAN")); assertTrue(mSqlCaptor.getValue().contains("drive_marked_for_deletion BOOLEAN")); assertTrue(mSqlCaptor.getValue().contains("last_local_modification_time DATE")); } @Test public void onUpgradeFromV2() { final int oldVersion = 2; final int newVersion = DatabaseHelper.DATABASE_VERSION; final TableDefaultsCustomizer customizer = mock(TableDefaultsCustomizer.class); mCSVTable.onUpgrade(mSQLiteDatabase, oldVersion, newVersion, customizer); verify(mSQLiteDatabase, atLeastOnce()).execSQL(mSqlCaptor.capture()); verify(customizer).insertCSVDefaults(mCSVTable); assertTrue(mSqlCaptor.getAllValues().get(0).contains(CSVTable.TABLE_NAME)); assertTrue(mSqlCaptor.getAllValues().get(0).contains(CSVTable.COLUMN_ID)); assertTrue(mSqlCaptor.getAllValues().get(0).contains(CSVTable.COLUMN_TYPE)); assertEquals(mSqlCaptor.getAllValues().get(0), "CREATE TABLE csvcolumns (id INTEGER PRIMARY KEY AUTOINCREMENT, type TEXT);"); assertEquals(mSqlCaptor.getAllValues().get(1), "ALTER TABLE " + mCSVTable.getTableName() + " ADD drive_sync_id TEXT"); assertEquals(mSqlCaptor.getAllValues().get(2), "ALTER TABLE " + mCSVTable.getTableName() + " ADD drive_is_synced BOOLEAN DEFAULT 0"); assertEquals(mSqlCaptor.getAllValues().get(3), "ALTER TABLE " + mCSVTable.getTableName() + " ADD drive_marked_for_deletion BOOLEAN DEFAULT 0"); assertEquals(mSqlCaptor.getAllValues().get(4), "ALTER TABLE " + mCSVTable.getTableName() + " ADD last_local_modification_time DATE"); } @Test public void onUpgradeFromV14() { final int oldVersion = 14; final int newVersion = DatabaseHelper.DATABASE_VERSION; final TableDefaultsCustomizer customizer = mock(TableDefaultsCustomizer.class); mCSVTable.onUpgrade(mSQLiteDatabase, oldVersion, newVersion, customizer); verify(mSQLiteDatabase, atLeastOnce()).execSQL(mSqlCaptor.capture()); verify(customizer, never()).insertCSVDefaults(mCSVTable); assertEquals(mSqlCaptor.getAllValues().get(0), "ALTER TABLE " + mCSVTable.getTableName() + " ADD drive_sync_id TEXT"); assertEquals(mSqlCaptor.getAllValues().get(1), "ALTER TABLE " + mCSVTable.getTableName() + " ADD drive_is_synced BOOLEAN DEFAULT 0"); assertEquals(mSqlCaptor.getAllValues().get(2), "ALTER TABLE " + mCSVTable.getTableName() + " ADD drive_marked_for_deletion BOOLEAN DEFAULT 0"); assertEquals(mSqlCaptor.getAllValues().get(3), "ALTER TABLE " + mCSVTable.getTableName() + " ADD last_local_modification_time DATE"); } @Test public void onUpgradeAlreadyOccurred() { final int oldVersion = DatabaseHelper.DATABASE_VERSION; final int newVersion = DatabaseHelper.DATABASE_VERSION; final TableDefaultsCustomizer customizer = mock(TableDefaultsCustomizer.class); mCSVTable.onUpgrade(mSQLiteDatabase, oldVersion, newVersion, customizer); verify(mSQLiteDatabase, never()).execSQL(mSqlCaptor.capture()); verify(customizer, never()).insertCSVDefaults(mCSVTable); } @Test public void get() { final List<Column<Receipt>> columns = mCSVTable.get().blockingGet(); assertEquals(columns, Arrays.asList(mColumn1, mColumn2)); } @Test public void findByPrimaryKey() { mCSVTable.findByPrimaryKey(mColumn1.getId()) .test() .assertNoErrors() .assertResult(mColumn1); } @Test public void findByPrimaryMissingKey() { mCSVTable.findByPrimaryKey(-1) .test() .assertError(Exception.class); } @Test public void insert() { final String name = "Code"; final Column<Receipt> column = mCSVTable.insert(new ReceiptCategoryNameColumn(-1, name, new DefaultSyncState()), new DatabaseOperationMetadata()).blockingGet(); assertNotNull(column); assertEquals(name, column.getName()); final List<Column<Receipt>> columns = mCSVTable.get().blockingGet(); assertEquals(columns, Arrays.asList(mColumn1, mColumn2, column)); } @Test public void insertDefaultColumn() { final Column<Receipt> column = mCSVTable.insertDefaultColumn().blockingGet(); assertNotNull(column); assertEquals(column, mDefaultColumn); final List<Column<Receipt>> columns = mCSVTable.get().blockingGet(); assertEquals(Arrays.asList(mColumn1, mColumn2, column), columns); } @Test public void update() { final String name = "Code"; final Column<Receipt> column = mCSVTable.update(mColumn1, new ReceiptCategoryNameColumn(-1, name, new DefaultSyncState()), new DatabaseOperationMetadata()) .blockingGet(); assertNotNull(column); assertEquals(name, column.getName()); final List<Column<Receipt>> columns = mCSVTable.get().blockingGet(); assertEquals(columns, Arrays.asList(column, mColumn2)); } @Test public void delete() { assertEquals(mColumn1, mCSVTable.delete(mColumn1, new DatabaseOperationMetadata()).blockingGet()); assertEquals(mCSVTable.get().blockingGet(), Collections.singletonList(mColumn2)); } @Test public void deleteLast() { final DatabaseOperationMetadata databaseOperationMetadata = new DatabaseOperationMetadata(); assertTrue(mCSVTable.deleteLast(databaseOperationMetadata).blockingGet()); assertEquals(mCSVTable.get().blockingGet(), Collections.singletonList(mColumn1)); assertTrue(mCSVTable.deleteLast(databaseOperationMetadata).blockingGet()); assertEquals(mCSVTable.get().blockingGet(), Collections.emptyList()); assertFalse(mCSVTable.deleteLast(databaseOperationMetadata).blockingGet()); } }