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.List;
import co.smartreceipts.android.model.Category;
import co.smartreceipts.android.model.factory.CategoryBuilderFactory;
import co.smartreceipts.android.persistence.DatabaseHelper;
import co.smartreceipts.android.persistence.database.defaults.TableDefaultsCustomizer;
import co.smartreceipts.android.persistence.database.operations.DatabaseOperationMetadata;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@RunWith(RobolectricTestRunner.class)
public class CategoriesTableTest {
private static final String NAME1 = "name1";
private static final String NAME2 = "name2";
private static final String CODE1 = "code1";
private static final String CODE2 = "code2";
// Class under test
CategoriesTable mCategoriesTable;
@Mock
SQLiteDatabase mSQLiteDatabase;
@Mock
TableDefaultsCustomizer mTableDefaultsCustomizer;
@Captor
ArgumentCaptor<String> mSqlCaptor;
SQLiteOpenHelper mSQLiteOpenHelper;
Category mCategory1;
Category mCategory2;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
mSQLiteOpenHelper = new TestSQLiteOpenHelper(RuntimeEnvironment.application);
mCategoriesTable = new CategoriesTable(mSQLiteOpenHelper);
// Now create the table and insert some defaults
mCategoriesTable.onCreate(mSQLiteOpenHelper.getWritableDatabase(), mTableDefaultsCustomizer);
mCategory1 = mCategoriesTable.insert(new CategoryBuilderFactory().setName(NAME1).setCode(CODE1).build(), new DatabaseOperationMetadata()).blockingGet();
mCategory2 = mCategoriesTable.insert(new CategoryBuilderFactory().setName(NAME2).setCode(CODE2).build(), new DatabaseOperationMetadata()).blockingGet();
assertNotNull(mCategory1);
assertNotNull(mCategory2);
}
@After
public void tearDown() {
mSQLiteOpenHelper.getWritableDatabase().execSQL("DROP TABLE IF EXISTS " + mCategoriesTable.getTableName());
}
@Test
public void getTableName() {
assertEquals("categories", mCategoriesTable.getTableName());
}
@Test
public void onCreate() {
final TableDefaultsCustomizer customizer = mock(TableDefaultsCustomizer.class);
mCategoriesTable.onCreate(mSQLiteDatabase, customizer);
verify(mSQLiteDatabase).execSQL(mSqlCaptor.capture());
verify(customizer).insertCategoryDefaults(mCategoriesTable);
assertTrue(mSqlCaptor.getValue().contains("CREATE TABLE categories"));
assertTrue(mSqlCaptor.getValue().contains("name TEXT PRIMARY KEY"));
assertTrue(mSqlCaptor.getValue().contains("code TEXT"));
assertTrue(mSqlCaptor.getValue().contains("breakdown BOOLEAN"));
assertTrue(mSqlCaptor.getValue().contains("drive_sync_id TEXT"));
assertTrue(mSqlCaptor.getValue().contains("drive_is_synced BOOLEAN DEFAULT 0"));
assertTrue(mSqlCaptor.getValue().contains("drive_marked_for_deletion BOOLEAN DEFAULT 0"));
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);
mCategoriesTable.onUpgrade(mSQLiteDatabase, oldVersion, newVersion, customizer);
verify(mSQLiteDatabase, atLeastOnce()).execSQL(mSqlCaptor.capture());
verify(customizer, never()).insertCategoryDefaults(mCategoriesTable);
assertTrue(mSqlCaptor.getAllValues().get(0).equals("ALTER TABLE categories ADD breakdown BOOLEAN DEFAULT 1"));
assertEquals(mSqlCaptor.getAllValues().get(1), "ALTER TABLE " + mCategoriesTable.getTableName() + " ADD drive_sync_id TEXT");
assertEquals(mSqlCaptor.getAllValues().get(2), "ALTER TABLE " + mCategoriesTable.getTableName() + " ADD drive_is_synced BOOLEAN DEFAULT 0");
assertEquals(mSqlCaptor.getAllValues().get(3), "ALTER TABLE " + mCategoriesTable.getTableName() + " ADD drive_marked_for_deletion BOOLEAN DEFAULT 0");
assertEquals(mSqlCaptor.getAllValues().get(4), "ALTER TABLE " + mCategoriesTable.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);
mCategoriesTable.onUpgrade(mSQLiteDatabase, oldVersion, newVersion, customizer);
verify(mSQLiteDatabase, atLeastOnce()).execSQL(mSqlCaptor.capture());
verify(customizer, never()).insertCategoryDefaults(mCategoriesTable);
assertEquals(mSqlCaptor.getAllValues().get(0), "ALTER TABLE " + mCategoriesTable.getTableName() + " ADD drive_sync_id TEXT");
assertEquals(mSqlCaptor.getAllValues().get(1), "ALTER TABLE " + mCategoriesTable.getTableName() + " ADD drive_is_synced BOOLEAN DEFAULT 0");
assertEquals(mSqlCaptor.getAllValues().get(2), "ALTER TABLE " + mCategoriesTable.getTableName() + " ADD drive_marked_for_deletion BOOLEAN DEFAULT 0");
assertEquals(mSqlCaptor.getAllValues().get(3), "ALTER TABLE " + mCategoriesTable.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);
mCategoriesTable.onUpgrade(mSQLiteDatabase, oldVersion, newVersion, customizer);
verify(mSQLiteDatabase, never()).execSQL(mSqlCaptor.capture());
verify(customizer, never()).insertCategoryDefaults(mCategoriesTable);
}
@Test
public void get() {
final List<Category> categories = mCategoriesTable.get().blockingGet();
assertEquals(categories, Arrays.asList(mCategory1, mCategory2));
}
@Test
public void getMaintainsAlphabeticalSortingOrder() {
final Category zCategory = mCategoriesTable.insert(new CategoryBuilderFactory().setName("zz").setCode("zz").build(), new DatabaseOperationMetadata()).blockingGet();
final Category aCategory = mCategoriesTable.insert(new CategoryBuilderFactory().setName("aa").setCode("aa").build(), new DatabaseOperationMetadata()).blockingGet();
final List<Category> categories = mCategoriesTable.get().blockingGet();
assertEquals(categories, Arrays.asList(aCategory, mCategory1, mCategory2, zCategory));
}
@Test
public void findByPrimaryKey() {
mCategoriesTable.findByPrimaryKey(mCategory1.getName())
.test()
.assertNoErrors()
.assertResult(mCategory1);
}
@Test
public void findByPrimaryMissingKey() {
mCategoriesTable.findByPrimaryKey("xxx")
.test()
.assertError(Exception.class);
}
@Test
public void insert() {
final String name = "abc";
final String code = "abc";
final Category insertCategory = new CategoryBuilderFactory().setName(name).setCode(code).build();
assertEquals(insertCategory, mCategoriesTable.insert(insertCategory, new DatabaseOperationMetadata()).blockingGet());
final List<Category> categories = mCategoriesTable.get().blockingGet();
assertEquals(categories, Arrays.asList(insertCategory, mCategory1, mCategory2));
}
@Test
public void update() {
final String name = "NewName";
final String code = "NewCode";
final Category updateCategory = new CategoryBuilderFactory().setName(name).setCode(code).build();
assertEquals(updateCategory, mCategoriesTable.update(mCategory1, updateCategory, new DatabaseOperationMetadata()).blockingGet());
final List<Category> categories = mCategoriesTable.get().blockingGet();
assertTrue(categories.contains(updateCategory));
assertTrue(categories.contains(mCategory2));
}
@Test
public void delete() {
final List<Category> oldCategories = mCategoriesTable.get().blockingGet();
assertTrue(oldCategories.contains(mCategory1));
assertTrue(oldCategories.contains(mCategory2));
assertEquals(mCategory1, mCategoriesTable.delete(mCategory1, new DatabaseOperationMetadata()).blockingGet());
assertEquals(mCategory2, mCategoriesTable.delete(mCategory2, new DatabaseOperationMetadata()).blockingGet());
final List<Category> newCategories = mCategoriesTable.get().blockingGet();
assertTrue(newCategories.isEmpty());
}
}