@Test
  public void testGetDistinctKeys_LessThanInclusiveAscending() {
    ConnectionManager connectionManager = temporaryInMemoryDatabase.getConnectionManager(true);
    SQLiteIndex<String, Car, Integer> offHeapIndex =
        SQLiteIndex.onAttribute(
            Car.MODEL,
            Car.CAR_ID,
            new SimpleAttribute<Integer, Car>() {
              @Override
              public Car getValue(Integer carId, QueryOptions queryOptions) {
                return CarFactory.createCar(carId);
              }
            },
            connectionManager);
    offHeapIndex.addAll(CarFactory.createCollectionOfCars(10), QueryFactory.noQueryOptions());
    List<String> expected, actual;

    expected =
        Arrays.asList(
            "Accord", "Avensis", "Civic", "Focus", "Fusion", "Hilux", "Insight", "M6", "Prius");
    actual =
        Lists.newArrayList(
            offHeapIndex.getDistinctKeys(null, true, "Prius", true, noQueryOptions()));
    assertEquals(expected, actual);
  }
  @Test
  public void testInit_NonEmptyCollection() throws Exception {

    // Mock
    ConnectionManager connectionManager = mock(ConnectionManager.class);
    Connection connection = mock(Connection.class);
    Connection connection1 = mock(Connection.class);
    Statement statement = mock(Statement.class);
    PreparedStatement preparedStatement = mock(PreparedStatement.class);

    when(connection1.prepareStatement("INSERT OR IGNORE INTO " + TABLE_NAME + " values(?, ?);"))
        .thenReturn(preparedStatement);
    when(connectionManager.getConnection(any(SQLiteIndex.class)))
        .thenReturn(connection)
        .thenReturn(connection1);
    when(connectionManager.isApplyUpdateForIndexEnabled(any(SQLiteIndex.class))).thenReturn(true);
    when(connection.createStatement()).thenReturn(statement);
    when(preparedStatement.executeBatch()).thenReturn(new int[] {2});

    // The objects to add
    Set<Car> initWithObjects = new HashSet<Car>(2);
    initWithObjects.add(
        new Car(1, "Ford", "Focus", Car.Color.BLUE, 5, 9000.50, Arrays.asList("abs", "gps")));
    initWithObjects.add(
        new Car(2, "Honda", "Civic", Car.Color.RED, 5, 5000.00, Arrays.asList("airbags")));

    SQLiteIndex<String, Car, Integer> carFeaturesOffHeapIndex =
        new SQLiteIndex<String, Car, Integer>(
            Car.FEATURES, OBJECT_TO_ID, ID_TO_OBJECT, connectionManager);

    carFeaturesOffHeapIndex.init(initWithObjects, new QueryOptions());

    // Verify
    verify(statement, times(1))
        .executeUpdate(
            "CREATE TABLE IF NOT EXISTS "
                + TABLE_NAME
                + " (objectKey INTEGER, value TEXT, PRIMARY KEY (objectKey, value)) WITHOUT ROWID;");
    verify(statement, times(1))
        .executeUpdate(
            "CREATE INDEX IF NOT EXISTS " + INDEX_NAME + " ON " + TABLE_NAME + " (value);");
    verify(statement, times(2)).close();
    verify(connection, times(1)).close();

    verify(preparedStatement, times(2)).setObject(1, 1);
    verify(preparedStatement, times(1)).setObject(1, 2);
    verify(preparedStatement, times(1)).setObject(2, "abs");
    verify(preparedStatement, times(1)).setObject(2, "gps");
    verify(preparedStatement, times(1)).setObject(2, "airbags");
    verify(preparedStatement, times(3)).addBatch();
    verify(preparedStatement, times(1)).executeBatch();
    verify(preparedStatement, times(1)).close();
    verify(connection1, times(1)).close();
  }
  @Test
  public void testGetConnectionManager_Standalone() {

    ConnectionManager connectionManager = mock(ConnectionManager.class);

    SQLiteIndex<String, Car, Integer> carFeaturesOffHeapIndex =
        new SQLiteIndex<String, Car, Integer>(
            Car.FEATURES, OBJECT_TO_ID, ID_TO_OBJECT, connectionManager);

    assertEquals(
        connectionManager, carFeaturesOffHeapIndex.getConnectionManager(new QueryOptions()));
  }
  @Test
  public void testGetConnectionManager_NonStandalone() {

    ConnectionManager connectionManager = mock(ConnectionManager.class);
    QueryOptions queryOptions = mock(QueryOptions.class);
    when(queryOptions.get(ConnectionManager.class)).thenReturn(connectionManager);

    SQLiteIndex<String, Car, Integer> carFeaturesOffHeapIndex =
        new SQLiteIndex<String, Car, Integer>(Car.FEATURES, OBJECT_TO_ID, ID_TO_OBJECT, null);

    assertEquals(connectionManager, carFeaturesOffHeapIndex.getConnectionManager(queryOptions));
  }
  @Test
  public void testInit_EmptyCollection() throws Exception {

    // Mock
    ConnectionManager connectionManager = mock(ConnectionManager.class);

    SQLiteIndex<String, Car, Integer> carFeaturesOffHeapIndex =
        new SQLiteIndex<String, Car, Integer>(
            Car.FEATURES, OBJECT_TO_ID, ID_TO_OBJECT, connectionManager);

    carFeaturesOffHeapIndex.init(Collections.<Car>emptySet(), new QueryOptions());
    verify(connectionManager, times(0)).getConnection(any(SQLiteIndex.class));
  }
  @Test
  public void testNotifyObjectsRemoved() throws Exception {

    // Mock
    ConnectionManager connectionManager = mock(ConnectionManager.class);
    Connection connection = mock(Connection.class);
    Connection connection1 = mock(Connection.class);
    Statement statement = mock(Statement.class);
    PreparedStatement preparedStatement = mock(PreparedStatement.class);

    // Behaviour
    when(connectionManager.getConnection(any(SQLiteIndex.class)))
        .thenReturn(connection)
        .thenReturn(connection1);
    when(connectionManager.isApplyUpdateForIndexEnabled(any(SQLiteIndex.class))).thenReturn(true);
    when(connection.createStatement()).thenReturn(statement);
    when(connection1.prepareStatement("DELETE FROM " + TABLE_NAME + " WHERE objectKey = ?;"))
        .thenReturn(preparedStatement);
    when(preparedStatement.executeBatch()).thenReturn(new int[] {1});

    // The objects to add
    Set<Car> removedObjects = new HashSet<Car>(2);
    removedObjects.add(
        new Car(1, "Ford", "Focus", Car.Color.BLUE, 5, 9000.50, Arrays.asList("abs", "gps")));
    removedObjects.add(
        new Car(2, "Honda", "Civic", Car.Color.RED, 5, 5000.00, Arrays.asList("airbags")));

    @SuppressWarnings({"unchecked", "unused"})
    SQLiteIndex<String, Car, Integer> carFeaturesOffHeapIndex =
        new SQLiteIndex<String, Car, Integer>(
            Car.FEATURES, OBJECT_TO_ID, ID_TO_OBJECT, connectionManager);

    carFeaturesOffHeapIndex.removeAll(removedObjects, new QueryOptions());

    // Verify
    verify(statement, times(1))
        .executeUpdate(
            "CREATE TABLE IF NOT EXISTS "
                + TABLE_NAME
                + " (objectKey INTEGER, value TEXT, PRIMARY KEY (objectKey, value)) WITHOUT ROWID;");
    verify(statement, times(1))
        .executeUpdate(
            "CREATE INDEX IF NOT EXISTS " + INDEX_NAME + " ON " + TABLE_NAME + " (value);");
    verify(connection, times(1)).close();

    verify(preparedStatement, times(1)).setObject(1, 1);
    verify(preparedStatement, times(1)).setObject(1, 2);
    verify(preparedStatement, times(2)).addBatch();
    verify(preparedStatement, times(1)).executeBatch();
    verify(connection1, times(1)).close();
  }
  @Test
  public void testNewNonStandalone() throws Exception {

    SQLiteIndex<String, Car, Integer> carFeaturesOffHeapIndex =
        SQLiteIndex.onAttribute(Car.FEATURES, OBJECT_TO_ID, ID_TO_OBJECT);

    assertNotNull(carFeaturesOffHeapIndex);
  }
  @Test
  public void testNotifyObjectsCleared() throws Exception {

    // Mock
    ConnectionManager connectionManager = mock(ConnectionManager.class);
    Connection connection = mock(Connection.class);
    Connection connection1 = mock(Connection.class);
    Statement statement = mock(Statement.class);
    Statement statement1 = mock(Statement.class);

    // Behaviour
    when(connectionManager.getConnection(any(SQLiteIndex.class)))
        .thenReturn(connection)
        .thenReturn(connection1);
    when(connectionManager.isApplyUpdateForIndexEnabled(any(SQLiteIndex.class))).thenReturn(true);
    when(connection.createStatement()).thenReturn(statement);
    when(connection1.createStatement()).thenReturn(statement1);

    @SuppressWarnings({"unchecked", "unused"})
    SQLiteIndex<String, Car, Integer> carFeaturesOffHeapIndex =
        new SQLiteIndex<String, Car, Integer>(
            Car.FEATURES, OBJECT_TO_ID, ID_TO_OBJECT, connectionManager);

    carFeaturesOffHeapIndex.clear(new QueryOptions());

    // Verify
    verify(statement, times(1))
        .executeUpdate(
            "CREATE TABLE IF NOT EXISTS "
                + TABLE_NAME
                + " (objectKey INTEGER, value TEXT, PRIMARY KEY (objectKey, value)) WITHOUT ROWID;");
    verify(statement, times(1))
        .executeUpdate(
            "CREATE INDEX IF NOT EXISTS " + INDEX_NAME + " ON " + TABLE_NAME + " (value);");
    verify(connection, times(1)).close();

    verify(statement1, times(1)).executeUpdate("DELETE FROM " + TABLE_NAME + ";");
    verify(connection1, times(1)).close();
  }
  @Test
  public void testObjectKeyIterable() {

    Iterable<Integer> objectKeys = SQLiteIndex.objectKeyIterable(data, Car.CAR_ID, null);
    Assert.assertNotNull(objectKeys);

    Iterator<Integer> objectKeysIterator = objectKeys.iterator();
    Assert.assertNotNull(objectKeysIterator);
    assertTrue(objectKeysIterator.hasNext());
    assertEquals(new Integer(1), objectKeysIterator.next());
    assertTrue(objectKeysIterator.hasNext());
    assertEquals(new Integer(2), objectKeysIterator.next());
    assertTrue(objectKeysIterator.hasNext());
    assertEquals(new Integer(3), objectKeysIterator.next());
    assertTrue(objectKeysIterator.hasNext());
    assertEquals(new Integer(4), objectKeysIterator.next());
    assertTrue(objectKeysIterator.hasNext());
    assertEquals(new Integer(5), objectKeysIterator.next());
    assertFalse(objectKeysIterator.hasNext());
  }
  @Test
  public void testRowIterable() {

    Iterable<DBQueries.Row<Integer, String>> rows =
        SQLiteIndex.rowIterable(data, Car.CAR_ID, Car.FEATURES, null);
    Assert.assertNotNull(rows);

    Iterator<DBQueries.Row<Integer, String>> rowsIterator = rows.iterator();
    Assert.assertNotNull(rowsIterator);
    assertTrue(rowsIterator.hasNext());
    assertEquals(new DBQueries.Row<Integer, String>(1, "abs"), rowsIterator.next());
    assertTrue(rowsIterator.hasNext());
    assertEquals(new DBQueries.Row<Integer, String>(1, "gps"), rowsIterator.next());
    assertTrue(rowsIterator.hasNext());
    assertEquals(new DBQueries.Row<Integer, String>(2, "airbags"), rowsIterator.next());
    assertTrue(rowsIterator.hasNext());
    assertEquals(new DBQueries.Row<Integer, String>(3, "abs"), rowsIterator.next());
    assertTrue(rowsIterator.hasNext());
    assertEquals(new DBQueries.Row<Integer, String>(5, "gps"), rowsIterator.next());
    assertFalse(rowsIterator.hasNext());
  }