public void testTrimInsertInsert() {
    final ContactsSource source = getSource();
    final Sources sources = getSources(source);
    final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
    final EditType typeHome = EntityModifier.getType(kindPhone, Phone.TYPE_HOME);

    // Try creating a contact with single empty entry
    final EntityDelta state = getEntity(null);
    final ValuesDelta values = EntityModifier.insertChild(state, kindPhone, typeHome);
    final EntitySet set = EntitySet.fromSingle(state);

    // Build diff, expecting two insert operations
    final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
    state.buildDiff(diff);
    assertEquals("Unexpected operations", 3, diff.size());
    {
      final ContentProviderOperation oper = diff.get(0);
      assertEquals("Incorrect type", TYPE_INSERT, oper.getType());
      assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
    }
    {
      final ContentProviderOperation oper = diff.get(1);
      assertEquals("Incorrect type", TYPE_INSERT, oper.getType());
      assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
    }

    // Trim empty rows and try again, expecting silence
    EntityModifier.trimEmpty(set, sources);
    diff.clear();
    state.buildDiff(diff);
    assertEquals("Unexpected operations", 0, diff.size());
  }
  public void testTrimUpdateUpdate() {
    final ContactsSource source = getSource();
    final Sources sources = getSources(source);
    final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
    final EditType typeHome = EntityModifier.getType(kindPhone, Phone.TYPE_HOME);

    // Build "before" with two phone numbers
    final ContentValues first = new ContentValues();
    first.put(Data._ID, TEST_ID);
    first.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
    first.put(kindPhone.typeColumn, typeHome.rawValue);
    first.put(Phone.NUMBER, TEST_PHONE);

    final EntityDelta state = getEntity(TEST_ID, first);
    final EntitySet set = EntitySet.fromSingle(state);

    // Build diff, expecting no changes
    final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
    state.buildDiff(diff);
    assertEquals("Unexpected operations", 0, diff.size());

    // Now update row by changing number to empty string, expecting single update
    final ValuesDelta child = state.getEntry(TEST_ID);
    child.put(Phone.NUMBER, "");
    diff.clear();
    state.buildDiff(diff);
    assertEquals("Unexpected operations", 3, diff.size());
    {
      final ContentProviderOperation oper = diff.get(0);
      assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
      assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
    }
    {
      final ContentProviderOperation oper = diff.get(1);
      assertEquals("Incorrect type", TYPE_UPDATE, oper.getType());
      assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
    }
    {
      final ContentProviderOperation oper = diff.get(2);
      assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
      assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
    }

    // Now run trim, which should turn into deleting the whole contact
    EntityModifier.trimEmpty(set, sources);
    diff.clear();
    state.buildDiff(diff);
    assertEquals("Unexpected operations", 1, diff.size());
    {
      final ContentProviderOperation oper = diff.get(0);
      assertEquals("Incorrect type", TYPE_DELETE, oper.getType());
      assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
    }
  }
  public void testTrimEmptySingle() {
    final ContactsSource source = getSource();
    final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
    final EditType typeHome = EntityModifier.getType(kindPhone, Phone.TYPE_HOME);

    // Test row that has type values, but core fields are empty
    final EntityDelta state = getEntity(TEST_ID);
    final ValuesDelta values = EntityModifier.insertChild(state, kindPhone, typeHome);

    // Build diff, expecting insert for data row and update enforcement
    final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
    state.buildDiff(diff);
    assertEquals("Unexpected operations", 3, diff.size());
    {
      final ContentProviderOperation oper = diff.get(0);
      assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
      assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
    }
    {
      final ContentProviderOperation oper = diff.get(1);
      assertEquals("Incorrect type", TYPE_INSERT, oper.getType());
      assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
    }
    {
      final ContentProviderOperation oper = diff.get(2);
      assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
      assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
    }

    // Trim empty rows and try again, expecting delete of overall contact
    EntityModifier.trimEmpty(state, source);
    diff.clear();
    state.buildDiff(diff);
    assertEquals("Unexpected operations", 1, diff.size());
    {
      final ContentProviderOperation oper = diff.get(0);
      assertEquals("Incorrect type", TYPE_DELETE, oper.getType());
      assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
    }
  }