am f035b477: Make test compontent support multiple vCard input.

Merge commit 'f035b47774aabf7397aec5c5459ac9860ad63bab' into eclair-mr2-plus-aosp

* commit 'f035b47774aabf7397aec5c5459ac9860ad63bab':
  Make test compontent support multiple vCard input.
diff --git a/core/java/android/pim/vcard/VCardComposer.java b/core/java/android/pim/vcard/VCardComposer.java
index aff3831..b8f4cfd 100644
--- a/core/java/android/pim/vcard/VCardComposer.java
+++ b/core/java/android/pim/vcard/VCardComposer.java
@@ -392,7 +392,9 @@
      * Must call before {{@link #init()}.
      */
     public void addHandler(OneEntryHandler handler) {
-        mHandlerList.add(handler);
+        if (handler != null) {
+            mHandlerList.add(handler);
+        }
     }
 
     /**
@@ -1865,11 +1867,11 @@
         switch (typeAsPrimitive) {
         case Phone.TYPE_HOME:
             parameterList.addAll(
-                    Arrays.asList(Constants.PARAM_TYPE_HOME, Constants.PARAM_TYPE_VOICE));
+                    Arrays.asList(Constants.PARAM_TYPE_HOME));
             break;
         case Phone.TYPE_WORK:
             parameterList.addAll(
-                    Arrays.asList(Constants.PARAM_TYPE_WORK, Constants.PARAM_TYPE_VOICE));
+                    Arrays.asList(Constants.PARAM_TYPE_WORK));
             break;
         case Phone.TYPE_FAX_HOME:
             parameterList.addAll(
diff --git a/tests/AndroidTests/src/com/android/unit_tests/vcard/PropertyNodesVerifier.java b/tests/AndroidTests/src/com/android/unit_tests/vcard/PropertyNodesVerifier.java
index a0d6d16..933ff2a 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/vcard/PropertyNodesVerifier.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/PropertyNodesVerifier.java
@@ -17,14 +17,73 @@
 package com.android.unit_tests.vcard;
 
 import android.content.ContentValues;
+import android.pim.vcard.VCardConfig;
+import android.pim.vcard.VCardParser;
+import android.pim.vcard.VCardParser_V21;
+import android.pim.vcard.VCardParser_V30;
+import android.pim.vcard.exception.VCardException;
+import android.test.AndroidTestCase;
+import android.util.Log;
 
+import junit.framework.TestCase;
+
+import java.io.IOException;
+import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 
-import junit.framework.TestCase;
+public class PropertyNodesVerifier extends VNodeBuilder {
+    private final List<PropertyNodesVerifierElem> mPropertyNodesVerifierElemList;
+    private final AndroidTestCase mAndroidTestCase;
+    private int mIndex;
+
+    public PropertyNodesVerifier(AndroidTestCase testCase) {
+        mPropertyNodesVerifierElemList = new ArrayList<PropertyNodesVerifierElem>();
+        mAndroidTestCase = testCase;
+    }
+
+    public PropertyNodesVerifierElem addPropertyNodesVerifierElem() {
+        PropertyNodesVerifierElem elem = new PropertyNodesVerifierElem(mAndroidTestCase);
+        mPropertyNodesVerifierElemList.add(elem);
+        return elem;
+    }
+
+    public void verify(int resId, int vCardType)
+            throws IOException, VCardException {
+        verify(mAndroidTestCase.getContext().getResources().openRawResource(resId), vCardType);
+    }
+
+    public void verify(InputStream is, int vCardType) throws IOException, VCardException {
+        final VCardParser vCardParser;
+        if (VCardConfig.isV30(vCardType)) {
+            vCardParser = new VCardParser_V30(true);  // use StrictParsing
+        } else {
+            vCardParser = new VCardParser_V21();
+        }
+        try {
+            vCardParser.parse(is, this);
+        } finally {
+            if (is != null) {
+                try {
+                    is.close();
+                } catch (IOException e) {
+                }
+            }
+        }
+    }
+
+    @Override
+    public void endRecord() {
+        super.endRecord();
+        mAndroidTestCase.assertTrue(mIndex < mPropertyNodesVerifierElemList.size());
+        mAndroidTestCase.assertTrue(mIndex < vNodeList.size());
+        mPropertyNodesVerifierElemList.get(mIndex).verify(vNodeList.get(mIndex));
+        mIndex++;
+    }
+}
 
 /**
  * Utility class which verifies input VNode.
@@ -34,7 +93,7 @@
  * If the node does not exist in the "ordered list", the class refers to
  * "unorderd expected property set" and checks the node is expected somewhere.
  */
-public class PropertyNodesVerifier {
+class PropertyNodesVerifierElem {
     public static class TypeSet extends HashSet<String> {
         public TypeSet(String ... array) {
             super(Arrays.asList(array));
@@ -53,7 +112,7 @@
     private final ArrayList<PropertyNode> mUnorderedNodeList;
     private final TestCase mTestCase;
 
-    public PropertyNodesVerifier(TestCase testCase) {
+    public PropertyNodesVerifierElem(TestCase testCase) {
         mOrderedNodeMap = new HashMap<String, List<PropertyNode>>();
         mUnorderedNodeList = new ArrayList<PropertyNode>();
         mTestCase = testCase;
@@ -61,16 +120,16 @@
 
     // WithOrder
 
-    public PropertyNodesVerifier addNodeWithOrder(String propName, String propValue) {
+    public PropertyNodesVerifierElem addNodeWithOrder(String propName, String propValue) {
         return addNodeWithOrder(propName, propValue, null, null, null, null, null);
     }
 
-    public PropertyNodesVerifier addNodeWithOrder(String propName, String propValue,
+    public PropertyNodesVerifierElem addNodeWithOrder(String propName, String propValue,
             List<String> propValueList) {
         return addNodeWithOrder(propName, propValue, propValueList, null, null, null, null);
     }
 
-    public PropertyNodesVerifier addNodeWithOrder(String propName, List<String> propValueList) {
+    public PropertyNodesVerifierElem addNodeWithOrder(String propName, List<String> propValueList) {
         StringBuffer buffer = new StringBuffer();
         boolean first = true;
         for (String propValueElem : propValueList) {
@@ -85,18 +144,18 @@
                 null, null, null, null);
     }
 
-    public PropertyNodesVerifier addNodeWithOrder(String propName, String propValue,
+    public PropertyNodesVerifierElem addNodeWithOrder(String propName, String propValue,
             TypeSet paramMap_TYPE) {
         return addNodeWithOrder(propName, propValue, null, null, null, paramMap_TYPE, null);
     }
 
-    public PropertyNodesVerifier addNodeWithOrder(String propName, String propValue,
+    public PropertyNodesVerifierElem addNodeWithOrder(String propName, String propValue,
             List<String> propValueList, TypeSet paramMap_TYPE) {
         return addNodeWithOrder(propName, propValue, propValueList, null, null,
                 paramMap_TYPE, null);
     }
 
-    public PropertyNodesVerifier addNodeWithOrder(String propName, String propValue,
+    public PropertyNodesVerifierElem addNodeWithOrder(String propName, String propValue,
             List<String> propValueList, byte[] propValue_bytes,
             ContentValues paramMap, TypeSet paramMap_TYPE, GroupSet propGroupSet) {
         PropertyNode propertyNode = new PropertyNode(propName,
@@ -113,16 +172,16 @@
 
     // WithoutOrder
 
-    public PropertyNodesVerifier addNodeWithoutOrder(String propName, String propValue) {
+    public PropertyNodesVerifierElem addNodeWithoutOrder(String propName, String propValue) {
         return addNodeWithoutOrder(propName, propValue, null, null, null, null, null);
     }
 
-    public PropertyNodesVerifier addNodeWithoutOrder(String propName, String propValue,
+    public PropertyNodesVerifierElem addNodeWithoutOrder(String propName, String propValue,
             List<String> propValueList) {
         return addNodeWithoutOrder(propName, propValue, propValueList, null, null, null, null);
     }
 
-    public PropertyNodesVerifier addNodeWithoutOrder(String propName, List<String> propValueList) {
+    public PropertyNodesVerifierElem addNodeWithoutOrder(String propName, List<String> propValueList) {
         StringBuffer buffer = new StringBuffer();
         boolean first = true;
         for (String propValueElem : propValueList) {
@@ -137,18 +196,18 @@
                 null, null, null, null);
     }
 
-    public PropertyNodesVerifier addNodeWithoutOrder(String propName, String propValue,
+    public PropertyNodesVerifierElem addNodeWithoutOrder(String propName, String propValue,
             TypeSet paramMap_TYPE) {
         return addNodeWithoutOrder(propName, propValue, null, null, null, paramMap_TYPE, null);
     }
 
-    public PropertyNodesVerifier addNodeWithoutOrder(String propName, String propValue,
+    public PropertyNodesVerifierElem addNodeWithoutOrder(String propName, String propValue,
             List<String> propValueList, TypeSet paramMap_TYPE) {
         return addNodeWithoutOrder(propName, propValue, propValueList, null, null,
                 paramMap_TYPE, null);
     }
 
-    public PropertyNodesVerifier addNodeWithoutOrder(String propName, String propValue,
+    public PropertyNodesVerifierElem addNodeWithoutOrder(String propName, String propValue,
             List<String> propValueList, byte[] propValue_bytes,
             ContentValues paramMap, TypeSet paramMap_TYPE, GroupSet propGroupSet) {
         mUnorderedNodeList.add(new PropertyNode(propName, propValue,
@@ -185,8 +244,7 @@
         if (size > 0) {
             for (int i = 0; i < size; i++) {
                 PropertyNode expectedNode = expectedNodeList.get(i);
-                List<PropertyNode> expectedButDifferentValueList =
-                    new ArrayList<PropertyNode>();
+                List<PropertyNode> expectedButDifferentValueList = new ArrayList<PropertyNode>();
                 if (expectedNode.propName.equals(propName)) {
                     if (expectedNode.equals(actualNode)) {
                         expectedNodeList.remove(i);
diff --git a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardExporterTests.java b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardExporterTests.java
index b2cc008..727d33b 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardExporterTests.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardExporterTests.java
@@ -17,7 +17,6 @@
 package com.android.unit_tests.vcard;
 
 import android.content.ContentValues;
-import android.pim.vcard.VCardComposer;
 import android.pim.vcard.VCardConfig;
 import android.provider.ContactsContract.CommonDataKinds.Email;
 import android.provider.ContactsContract.CommonDataKinds.Event;
@@ -31,7 +30,7 @@
 import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
 import android.provider.ContactsContract.CommonDataKinds.Website;
 
-import com.android.unit_tests.vcard.PropertyNodesVerifier.TypeSet;
+import com.android.unit_tests.vcard.PropertyNodesVerifierElem.TypeSet;
 
 import java.util.Arrays;
 
@@ -44,42 +43,24 @@
     private static final byte[] sPhotoByteArray =
         VCardImporterTests.sPhotoByteArrayForComplicatedCase;
 
-    private void verifyOneComposition(ExportTestResolver resolver,
-            VCardVerificationHandler handler, int version) {
-        final boolean isV30 = (version == V30);
-
-        final int vcardType = (isV30 ? VCardConfig.VCARD_TYPE_V30_GENERIC_UTF8
-                : VCardConfig.VCARD_TYPE_V21_GENERIC_UTF8);
-        VCardComposer composer = new VCardComposer(new CustomMockContext(resolver), vcardType);
-        composer.addHandler(handler);
-        if (!composer.init(VCardComposer.CONTACTS_TEST_CONTENT_URI, null, null, null)) {
-            fail("init() failed. Reason: " + composer.getErrorReason());
-        }
-        assertFalse(composer.isAfterLast());
-        assertTrue(composer.createOneEntry());
-        assertTrue(composer.isAfterLast());
-        composer.terminate();
-    }
-
     public void testSimpleV21() {
         ExportTestResolver resolver = new ExportTestResolver();
-        resolver.buildInput(StructuredName.CONTENT_ITEM_TYPE)
+        resolver.buildContactEntry().buildData(StructuredName.CONTENT_ITEM_TYPE)
                 .put(StructuredName.FAMILY_NAME, "Ando")
                 .put(StructuredName.GIVEN_NAME, "Roid");
 
-        VCardVerificationHandler handler = new VCardVerificationHandler(this, V21);
-        handler.addPropertyNodesVerifier()
+        VCardVerifier verifier = new VCardVerifier(resolver, V21);
+        verifier.addPropertyNodesVerifierElem()
                 .addNodeWithoutOrder("FN", "Roid Ando")
                 .addNodeWithoutOrder("N", "Ando;Roid;;;", Arrays.asList("Ando", "Roid", "", "", ""));
-
-        verifyOneComposition(resolver, handler, V21);
+        verifier.verify();
     }
 
     private void testStructuredNameBasic(int version) {
-        final boolean isV30 = (version == V30);
+        final boolean isV30 = VCardConfig.isV30(version);
         ExportTestResolver resolver = new ExportTestResolver();
 
-        resolver.buildInput(StructuredName.CONTENT_ITEM_TYPE)
+        resolver.buildContactEntry().buildData(StructuredName.CONTENT_ITEM_TYPE)
                 .put(StructuredName.FAMILY_NAME, "AppropriateFamilyName")
                 .put(StructuredName.GIVEN_NAME, "AppropriateGivenName")
                 .put(StructuredName.MIDDLE_NAME, "AppropriateMiddleName")
@@ -89,8 +70,8 @@
                 .put(StructuredName.PHONETIC_GIVEN_NAME, "AppropriatePhoneticGiven")
                 .put(StructuredName.PHONETIC_MIDDLE_NAME, "AppropriatePhoneticMiddle");
 
-        VCardVerificationHandler handler = new VCardVerificationHandler(this, version);
-        PropertyNodesVerifier verifier = handler.addPropertyNodesVerifier()
+        VCardVerifier verifier = new VCardVerifier(resolver, version);
+        PropertyNodesVerifierElem elem = verifier.addPropertyNodesVerifierElem()
                 .addNodeWithOrder("N",
                         "AppropriateFamilyName;AppropriateGivenName;AppropriateMiddleName;"
                         + "AppropriatePrefix;AppropriateSuffix",
@@ -104,12 +85,12 @@
                 .addNodeWithoutOrder("X-PHONETIC-LAST-NAME", "AppropriatePhoneticFamily");
 
         if (isV30) {
-            verifier.addNodeWithoutOrder("SORT-STRING",
+            elem.addNodeWithoutOrder("SORT-STRING",
                     "AppropriatePhoneticGiven AppropriatePhoneticMiddle "
                     + "AppropriatePhoneticFamily");
         }
 
-        verifyOneComposition(resolver, handler, version);
+        verifier.verify();
     }
 
     public void testStructuredNameBasicV21() {
@@ -130,7 +111,8 @@
         final boolean isV30 = (version == V30);
         ExportTestResolver resolver = new ExportTestResolver();
 
-        resolver.buildInput(StructuredName.CONTENT_ITEM_TYPE)
+        ContactEntry entry = resolver.buildContactEntry();
+        entry.buildData(StructuredName.CONTENT_ITEM_TYPE)
                 .put(StructuredName.FAMILY_NAME, "DoNotEmitFamilyName1")
                 .put(StructuredName.GIVEN_NAME, "DoNotEmitGivenName1")
                 .put(StructuredName.MIDDLE_NAME, "DoNotEmitMiddleName1")
@@ -141,7 +123,7 @@
                 .put(StructuredName.PHONETIC_MIDDLE_NAME, "DoNotEmitPhoneticMiddle1");
 
         // With "IS_PRIMARY=1". This is what we should use.
-        resolver.buildInput(StructuredName.CONTENT_ITEM_TYPE)
+        entry.buildData(StructuredName.CONTENT_ITEM_TYPE)
                 .put(StructuredName.FAMILY_NAME, "AppropriateFamilyName")
                 .put(StructuredName.GIVEN_NAME, "AppropriateGivenName")
                 .put(StructuredName.MIDDLE_NAME, "AppropriateMiddleName")
@@ -153,7 +135,7 @@
                 .put(StructuredName.IS_PRIMARY, 1);
 
         // With "IS_PRIMARY=1", but we should ignore this time, since this is second, not first.
-        resolver.buildInput(StructuredName.CONTENT_ITEM_TYPE)
+        entry.buildData(StructuredName.CONTENT_ITEM_TYPE)
                 .put(StructuredName.FAMILY_NAME, "DoNotEmitFamilyName2")
                 .put(StructuredName.GIVEN_NAME, "DoNotEmitGivenName2")
                 .put(StructuredName.MIDDLE_NAME, "DoNotEmitMiddleName2")
@@ -164,8 +146,8 @@
                 .put(StructuredName.PHONETIC_MIDDLE_NAME, "DoNotEmitPhoneticMiddle2")
                 .put(StructuredName.IS_PRIMARY, 1);
 
-        VCardVerificationHandler handler = new VCardVerificationHandler(this, version);
-        PropertyNodesVerifier verifier = handler.addPropertyNodesVerifier()
+        VCardVerifier verifier = new VCardVerifier(resolver, version);
+        PropertyNodesVerifierElem elem = verifier.addPropertyNodesVerifierElem()
                 .addNodeWithOrder("N",
                         "AppropriateFamilyName;AppropriateGivenName;AppropriateMiddleName;"
                         + "AppropriatePrefix;AppropriateSuffix",
@@ -179,12 +161,12 @@
                 .addNodeWithoutOrder("X-PHONETIC-LAST-NAME", "AppropriatePhoneticFamily");
 
         if (isV30) {
-            verifier.addNodeWithoutOrder("SORT-STRING",
+            elem.addNodeWithoutOrder("SORT-STRING",
                     "AppropriatePhoneticGiven AppropriatePhoneticMiddle "
                     + "AppropriatePhoneticFamily");
         }
 
-        verifyOneComposition(resolver, handler, version);
+        verifier.verify();
     }
 
     public void testStructuredNameUsePrimaryV21() {
@@ -203,7 +185,8 @@
         final boolean isV30 = (version == V30);
         ExportTestResolver resolver = new ExportTestResolver();
 
-        resolver.buildInput(StructuredName.CONTENT_ITEM_TYPE)
+        ContactEntry entry = resolver.buildContactEntry();
+        entry.buildData(StructuredName.CONTENT_ITEM_TYPE)
                 .put(StructuredName.FAMILY_NAME, "DoNotEmitFamilyName1")
                 .put(StructuredName.GIVEN_NAME, "DoNotEmitGivenName1")
                 .put(StructuredName.MIDDLE_NAME, "DoNotEmitMiddleName1")
@@ -214,7 +197,7 @@
                 .put(StructuredName.PHONETIC_MIDDLE_NAME, "DoNotEmitPhoneticMiddle1");
 
         // With "IS_PRIMARY=1", but we should ignore this time.
-        resolver.buildInput(StructuredName.CONTENT_ITEM_TYPE)
+        entry.buildData(StructuredName.CONTENT_ITEM_TYPE)
                 .put(StructuredName.FAMILY_NAME, "DoNotEmitFamilyName2")
                 .put(StructuredName.GIVEN_NAME, "DoNotEmitGivenName2")
                 .put(StructuredName.MIDDLE_NAME, "DoNotEmitMiddleName2")
@@ -226,7 +209,7 @@
                 .put(StructuredName.IS_PRIMARY, 1);
 
         // With "IS_SUPER_PRIMARY=1". This is what we should use.
-        resolver.buildInput(StructuredName.CONTENT_ITEM_TYPE)
+        entry.buildData(StructuredName.CONTENT_ITEM_TYPE)
                 .put(StructuredName.FAMILY_NAME, "AppropriateFamilyName")
                 .put(StructuredName.GIVEN_NAME, "AppropriateGivenName")
                 .put(StructuredName.MIDDLE_NAME, "AppropriateMiddleName")
@@ -237,7 +220,7 @@
                 .put(StructuredName.PHONETIC_MIDDLE_NAME, "AppropriatePhoneticMiddle")
                 .put(StructuredName.IS_SUPER_PRIMARY, 1);
 
-        resolver.buildInput(StructuredName.CONTENT_ITEM_TYPE)
+        entry.buildData(StructuredName.CONTENT_ITEM_TYPE)
                 .put(StructuredName.FAMILY_NAME, "DoNotEmitFamilyName3")
                 .put(StructuredName.GIVEN_NAME, "DoNotEmitGivenName3")
                 .put(StructuredName.MIDDLE_NAME, "DoNotEmitMiddleName3")
@@ -248,8 +231,8 @@
                 .put(StructuredName.PHONETIC_MIDDLE_NAME, "DoNotEmitPhoneticMiddle3")
                 .put(StructuredName.IS_PRIMARY, 1);
 
-        VCardVerificationHandler handler = new VCardVerificationHandler(this, version);
-        PropertyNodesVerifier verifier = handler.addPropertyNodesVerifier()
+        VCardVerifier verifier = new VCardVerifier(resolver, version);
+        PropertyNodesVerifierElem elem = verifier.addPropertyNodesVerifierElem()
                 .addNodeWithOrder("N",
                         "AppropriateFamilyName;AppropriateGivenName;AppropriateMiddleName;"
                         + "AppropriatePrefix;AppropriateSuffix",
@@ -263,12 +246,12 @@
                 .addNodeWithoutOrder("X-PHONETIC-LAST-NAME", "AppropriatePhoneticFamily");
 
         if (isV30) {
-            verifier.addNodeWithoutOrder("SORT-STRING",
+            elem.addNodeWithoutOrder("SORT-STRING",
                     "AppropriatePhoneticGiven AppropriatePhoneticMiddle"
                     + " AppropriatePhoneticFamily");
         }
 
-        verifyOneComposition(resolver, handler, version);
+        verifier.verify();
     }
 
     public void testStructuredNameUseSuperPrimaryV21() {
@@ -281,28 +264,28 @@
 
     public void testNickNameV30() {
         ExportTestResolver resolver = new ExportTestResolver();
-        resolver.buildInput(Nickname.CONTENT_ITEM_TYPE)
+        resolver.buildContactEntry().buildData(Nickname.CONTENT_ITEM_TYPE)
                 .put(Nickname.NAME, "Nicky");
 
-        VCardVerificationHandler handler = new VCardVerificationHandler(this, V30);
-        handler.addPropertyVerifierWithEmptyName()
+        VCardVerifier verifier = new VCardVerifier(resolver, V30);
+        verifier.addPropertyNodesVerifierWithEmptyName()
             .addNodeWithOrder("NICKNAME", "Nicky");
 
-        verifyOneComposition(resolver, handler, V30);
+        verifier.verify();
     }
 
     private void testPhoneBasicCommon(int version) {
         ExportTestResolver resolver = new ExportTestResolver();
 
-        resolver.buildInput(Phone.CONTENT_ITEM_TYPE)
+        resolver.buildContactEntry().buildData(Phone.CONTENT_ITEM_TYPE)
                 .put(Phone.NUMBER, "1")
                 .put(Phone.TYPE, Phone.TYPE_HOME);
 
-        VCardVerificationHandler handler = new VCardVerificationHandler(this, version);
-        handler.addPropertyVerifierWithEmptyName()
-                .addNodeWithoutOrder("TEL", "1", new TypeSet("HOME", "VOICE"));
+        VCardVerifier verifier = new VCardVerifier(resolver, version);
+        verifier.addPropertyNodesVerifierWithEmptyName()
+                .addNodeWithoutOrder("TEL", "1", new TypeSet("HOME"));
 
-        verifyOneComposition(resolver, handler, version);
+        verifier.verify();
     }
 
     public void testPhoneBasicV21() {
@@ -319,72 +302,58 @@
     private void testPhoneVariousTypeSupport(int version) {
         ExportTestResolver resolver = new ExportTestResolver();
 
-        resolver.buildInput(Phone.CONTENT_ITEM_TYPE)
+        ContactEntry entry = resolver.buildContactEntry();
+        entry.buildData(Phone.CONTENT_ITEM_TYPE)
                 .put(Phone.NUMBER, "10")
                 .put(Phone.TYPE, Phone.TYPE_HOME);
-
-        resolver.buildInput(Phone.CONTENT_ITEM_TYPE)
+        entry.buildData(Phone.CONTENT_ITEM_TYPE)
                 .put(Phone.NUMBER, "20")
                 .put(Phone.TYPE, Phone.TYPE_WORK);
-
-        resolver.buildInput(Phone.CONTENT_ITEM_TYPE)
+        entry.buildData(Phone.CONTENT_ITEM_TYPE)
                 .put(Phone.NUMBER, "30")
                 .put(Phone.TYPE, Phone.TYPE_FAX_HOME);
-
-        resolver.buildInput(Phone.CONTENT_ITEM_TYPE)
+        entry.buildData(Phone.CONTENT_ITEM_TYPE)
                 .put(Phone.NUMBER, "40")
                 .put(Phone.TYPE, Phone.TYPE_FAX_WORK);
-
-        resolver.buildInput(Phone.CONTENT_ITEM_TYPE)
+        entry.buildData(Phone.CONTENT_ITEM_TYPE)
                 .put(Phone.NUMBER, "50")
                 .put(Phone.TYPE, Phone.TYPE_MOBILE);
-
-        resolver.buildInput(Phone.CONTENT_ITEM_TYPE)
+        entry.buildData(Phone.CONTENT_ITEM_TYPE)
                 .put(Phone.NUMBER, "60")
                 .put(Phone.TYPE, Phone.TYPE_PAGER);
-
-        resolver.buildInput(Phone.CONTENT_ITEM_TYPE)
+        entry.buildData(Phone.CONTENT_ITEM_TYPE)
                 .put(Phone.NUMBER, "70")
                 .put(Phone.TYPE, Phone.TYPE_OTHER);
-
-        resolver.buildInput(Phone.CONTENT_ITEM_TYPE)
+        entry.buildData(Phone.CONTENT_ITEM_TYPE)
                 .put(Phone.NUMBER, "80")
                 .put(Phone.TYPE, Phone.TYPE_CAR);
-
-        resolver.buildInput(Phone.CONTENT_ITEM_TYPE)
+        entry.buildData(Phone.CONTENT_ITEM_TYPE)
                 .put(Phone.NUMBER, "90")
                 .put(Phone.TYPE, Phone.TYPE_COMPANY_MAIN);
-
-        resolver.buildInput(Phone.CONTENT_ITEM_TYPE)
+        entry.buildData(Phone.CONTENT_ITEM_TYPE)
                 .put(Phone.NUMBER, "100")
                 .put(Phone.TYPE, Phone.TYPE_ISDN);
-
-        resolver.buildInput(Phone.CONTENT_ITEM_TYPE)
+        entry.buildData(Phone.CONTENT_ITEM_TYPE)
                 .put(Phone.NUMBER, "110")
                 .put(Phone.TYPE, Phone.TYPE_MAIN);
-
-        resolver.buildInput(Phone.CONTENT_ITEM_TYPE)
+        entry.buildData(Phone.CONTENT_ITEM_TYPE)
                 .put(Phone.NUMBER, "120")
                 .put(Phone.TYPE, Phone.TYPE_OTHER_FAX);
-
-        resolver.buildInput(Phone.CONTENT_ITEM_TYPE)
+        entry.buildData(Phone.CONTENT_ITEM_TYPE)
                 .put(Phone.NUMBER, "130")
                 .put(Phone.TYPE, Phone.TYPE_TELEX);
-
-        resolver.buildInput(Phone.CONTENT_ITEM_TYPE)
+        entry.buildData(Phone.CONTENT_ITEM_TYPE)
                 .put(Phone.NUMBER, "140")
                 .put(Phone.TYPE, Phone.TYPE_WORK_MOBILE);
-
-        resolver.buildInput(Phone.CONTENT_ITEM_TYPE)
+        entry.buildData(Phone.CONTENT_ITEM_TYPE)
                 .put(Phone.NUMBER, "150")
                 .put(Phone.TYPE, Phone.TYPE_WORK_PAGER);
-
-        resolver.buildInput(Phone.CONTENT_ITEM_TYPE)
+        entry.buildData(Phone.CONTENT_ITEM_TYPE)
                 .put(Phone.NUMBER, "160")
                 .put(Phone.TYPE, Phone.TYPE_MMS);
 
-        VCardVerificationHandler handler = new VCardVerificationHandler(this, version);
-        handler.addPropertyVerifierWithEmptyName()
+        VCardVerifier verifier = new VCardVerifier(resolver, version);
+        verifier.addPropertyNodesVerifierWithEmptyName()
                 .addNodeWithoutOrder("TEL", "10", new TypeSet("HOME"))
                 .addNodeWithoutOrder("TEL", "20", new TypeSet("WORK"))
                 .addNodeWithoutOrder("TEL", "30", new TypeSet("HOME", "FAX"))
@@ -398,9 +367,10 @@
                 .addNodeWithoutOrder("TEL", "110", new TypeSet("PREF"))
                 .addNodeWithoutOrder("TEL", "120", new TypeSet("FAX"))
                 .addNodeWithoutOrder("TEL", "130", new TypeSet("TLX"))
-                .addNodeWithoutOrder("TEL", "140", new TypeSet("WORK", "MOBILE"))
+                .addNodeWithoutOrder("TEL", "140", new TypeSet("WORK", "CELL"))
                 .addNodeWithoutOrder("TEL", "150", new TypeSet("WORK", "PAGER"))
                 .addNodeWithoutOrder("TEL", "160", new TypeSet("MSG"));
+        verifier.verify();
     }
 
     public void testPhoneVariousTypeSupportV21() {
@@ -416,33 +386,29 @@
      */
     private void testPhonePrefHandlingCommon(int version) {
         ExportTestResolver resolver = new ExportTestResolver();
-
-        resolver.buildInput(Phone.CONTENT_ITEM_TYPE)
+        ContactEntry entry = resolver.buildContactEntry();
+        entry.buildData(Phone.CONTENT_ITEM_TYPE)
                 .put(Phone.NUMBER, "1")
                 .put(Phone.TYPE, Phone.TYPE_HOME);
-
-        resolver.buildInput(Phone.CONTENT_ITEM_TYPE)
+        entry.buildData(Phone.CONTENT_ITEM_TYPE)
                 .put(Phone.NUMBER, "2")
                 .put(Phone.TYPE, Phone.TYPE_WORK)
                 .put(Phone.IS_PRIMARY, 1);
-
-        resolver.buildInput(Phone.CONTENT_ITEM_TYPE)
+        entry.buildData(Phone.CONTENT_ITEM_TYPE)
                 .put(Phone.NUMBER, "3")
                 .put(Phone.TYPE, Phone.TYPE_FAX_HOME)
                 .put(Phone.IS_PRIMARY, 1);
-
-        resolver.buildInput(Phone.CONTENT_ITEM_TYPE)
+        entry.buildData(Phone.CONTENT_ITEM_TYPE)
                 .put(Phone.NUMBER, "4")
                 .put(Phone.TYPE, Phone.TYPE_FAX_WORK);
 
-        VCardVerificationHandler handler = new VCardVerificationHandler(this, version);
-        handler.addPropertyVerifierWithEmptyName()
+        VCardVerifier verifier = new VCardVerifier(resolver, version);
+        verifier.addPropertyNodesVerifierWithEmptyName()
                 .addNodeWithoutOrder("TEL", "4", new TypeSet("WORK", "FAX"))
                 .addNodeWithoutOrder("TEL", "3", new TypeSet("HOME", "FAX", "PREF"))
-                .addNodeWithoutOrder("TEL", "2", new TypeSet("WORK", "VOICE", "PREF"))
-                .addNodeWithoutOrder("TEL", "1", new TypeSet("HOME", "VOICE"));
-
-        verifyOneComposition(resolver, handler, version);
+                .addNodeWithoutOrder("TEL", "2", new TypeSet("WORK", "PREF"))
+                .addNodeWithoutOrder("TEL", "1", new TypeSet("HOME"));
+        verifier.verify();
     }
 
     public void testPhonePrefHandlingV21() {
@@ -455,15 +421,15 @@
 
     private void testEmailBasicCommon(int version) {
         ExportTestResolver resolver = new ExportTestResolver();
-        resolver.buildInput(Email.CONTENT_ITEM_TYPE)
+        resolver.buildContactEntry().buildData(Email.CONTENT_ITEM_TYPE)
                 .put(Email.DATA, "sample@example.com");
 
-        VCardVerificationHandler handler = new VCardVerificationHandler(this, version);
+        VCardVerifier verifier = new VCardVerifier(resolver, version);
 
-        handler.addPropertyVerifierWithEmptyName()
+        verifier.addPropertyNodesVerifierWithEmptyName()
             .addNodeWithoutOrder("EMAIL", "sample@example.com");
 
-        verifyOneComposition(resolver, handler, version);
+        verifier.verify();
     }
 
     public void testEmailBasicV21() {
@@ -477,31 +443,29 @@
     private void testEmailVariousTypeSupportCommon(int version) {
         ExportTestResolver resolver = new ExportTestResolver();
 
-        resolver.buildInput(Email.CONTENT_ITEM_TYPE)
+        ContactEntry entry = resolver.buildContactEntry();
+        entry.buildData(Email.CONTENT_ITEM_TYPE)
                 .put(Email.DATA, "type_home@example.com")
                 .put(Email.TYPE, Email.TYPE_HOME);
-
-        resolver.buildInput(Email.CONTENT_ITEM_TYPE)
+        entry.buildData(Email.CONTENT_ITEM_TYPE)
                 .put(Email.DATA, "type_work@example.com")
                 .put(Email.TYPE, Email.TYPE_WORK);
-
-        resolver.buildInput(Email.CONTENT_ITEM_TYPE)
+        entry.buildData(Email.CONTENT_ITEM_TYPE)
                 .put(Email.DATA, "type_mobile@example.com")
                 .put(Email.TYPE, Email.TYPE_MOBILE);
-
-        resolver.buildInput(Email.CONTENT_ITEM_TYPE)
+        entry.buildData(Email.CONTENT_ITEM_TYPE)
                 .put(Email.DATA, "type_other@example.com")
                 .put(Email.TYPE, Email.TYPE_OTHER);
 
-        VCardVerificationHandler handler = new VCardVerificationHandler(this, version);
+        VCardVerifier verifier = new VCardVerifier(resolver, version);
 
-        handler.addPropertyVerifierWithEmptyName()
+        verifier.addPropertyNodesVerifierWithEmptyName()
                 .addNodeWithoutOrder("EMAIL", "type_home@example.com", new TypeSet("HOME"))
                 .addNodeWithoutOrder("EMAIL", "type_work@example.com", new TypeSet("WORK"))
                 .addNodeWithoutOrder("EMAIL", "type_mobile@example.com", new TypeSet("CELL"))
                 .addNodeWithoutOrder("EMAIL", "type_other@example.com");
 
-        verifyOneComposition(resolver, handler, version);
+        verifier.verify();
     }
 
     public void testEmailVariousTypeSupportV21() {
@@ -515,22 +479,22 @@
     private void testEmailPrefHandlingCommon(int version) {
         ExportTestResolver resolver = new ExportTestResolver();
 
-        resolver.buildInput(Email.CONTENT_ITEM_TYPE)
+        ContactEntry entry = resolver.buildContactEntry();
+        entry.buildData(Email.CONTENT_ITEM_TYPE)
                 .put(Email.DATA, "type_home@example.com")
                 .put(Email.TYPE, Email.TYPE_HOME)
                 .put(Email.IS_PRIMARY, 1);
-
-        resolver.buildInput(Email.CONTENT_ITEM_TYPE)
+        entry.buildData(Email.CONTENT_ITEM_TYPE)
                 .put(Email.DATA, "type_notype@example.com")
                 .put(Email.IS_PRIMARY, 1);
 
-        VCardVerificationHandler handler = new VCardVerificationHandler(this, version);
+        VCardVerifier verifier = new VCardVerifier(resolver, version);
 
-        handler.addPropertyVerifierWithEmptyName()
+        verifier.addPropertyNodesVerifierWithEmptyName()
                 .addNodeWithoutOrder("EMAIL", "type_notype@example.com", new TypeSet("PREF"))
                 .addNodeWithoutOrder("EMAIL", "type_home@example.com", new TypeSet("HOME", "PREF"));
 
-        verifyOneComposition(resolver, handler, version);
+        verifier.verify();
     }
 
     public void testEmailPrefHandlingV21() {
@@ -547,7 +511,7 @@
         // adr-value    = 0*6(text-value ";") text-value
         //              ; PO Box, Extended Address, Street, Locality, Region, Postal Code,
         //              ; Country Name
-        resolver.buildInput(StructuredPostal.CONTENT_ITEM_TYPE)
+        resolver.buildContactEntry().buildData(StructuredPostal.CONTENT_ITEM_TYPE)
                 .put(StructuredPostal.POBOX, "Pobox")
                 .put(StructuredPostal.NEIGHBORHOOD, "Neighborhood")
                 .put(StructuredPostal.STREET, "Street")
@@ -555,13 +519,13 @@
                 .put(StructuredPostal.REGION, "Region")
                 .put(StructuredPostal.POSTCODE, "100")
                 .put(StructuredPostal.COUNTRY, "Country");
-        VCardVerificationHandler handler = new VCardVerificationHandler(this, version);
-        handler.addPropertyVerifierWithEmptyName()
+        VCardVerifier verifier = new VCardVerifier(resolver, version);
+        verifier.addPropertyNodesVerifierWithEmptyName()
                 .addNodeWithoutOrder("ADR", "Pobox;Neighborhood;Street;City;Region;100;Country",
                         Arrays.asList("Pobox", "Neighborhood", "Street", "City",
                                 "Region", "100", "Country"), new TypeSet("HOME"));
 
-        verifyOneComposition(resolver, handler, version);
+        verifier.verify();
     }
 
     public void testPostalOnlyWithStructuredDataV21() {
@@ -575,17 +539,17 @@
     private void testPostalOnlyWithFormattedAddressCommon(int version) {
         ExportTestResolver resolver = new ExportTestResolver();
 
-        resolver.buildInput(StructuredPostal.CONTENT_ITEM_TYPE)
+        resolver.buildContactEntry().buildData(StructuredPostal.CONTENT_ITEM_TYPE)
                 .put(StructuredPostal.FORMATTED_ADDRESS,
                 "Formatted address CA 123-334 United Statue");
 
-        VCardVerificationHandler handler = new VCardVerificationHandler(this, version);
-        handler.addPropertyVerifierWithEmptyName()
+        VCardVerifier verifier = new VCardVerifier(resolver, version);
+        verifier.addPropertyNodesVerifierWithEmptyName()
                 .addNodeWithOrder("ADR", ";Formatted address CA 123-334 United Statue;;;;;",
                         Arrays.asList("", "Formatted address CA 123-334 United Statue",
                                 "", "", "", "", ""), new TypeSet("HOME"));
 
-        verifyOneComposition(resolver, handler, version);
+        verifier.verify();
     }
 
     public void testPostalOnlyWithFormattedAddressV21() {
@@ -603,19 +567,19 @@
     private void testPostalWithBothStructuredAndFormattedCommon(int version) {
         ExportTestResolver resolver = new ExportTestResolver();
 
-        resolver.buildInput(StructuredPostal.CONTENT_ITEM_TYPE)
+        resolver.buildContactEntry().buildData(StructuredPostal.CONTENT_ITEM_TYPE)
                 .put(StructuredPostal.POBOX, "Pobox")
                 .put(StructuredPostal.COUNTRY, "Country")
                 .put(StructuredPostal.FORMATTED_ADDRESS,
                         "Formatted address CA 123-334 United Statue");  // Should be ignored
 
-        VCardVerificationHandler handler = new VCardVerificationHandler(this, version);
-        handler.addPropertyVerifierWithEmptyName()
+        VCardVerifier verifier = new VCardVerifier(resolver, version);
+        verifier.addPropertyNodesVerifierWithEmptyName()
                 .addNodeWithoutOrder("ADR", "Pobox;;;;;;Country",
                         Arrays.asList("Pobox", "", "", "", "", "", "Country"),
                         new TypeSet("HOME"));
 
-        verifyOneComposition(resolver, handler, version);
+        verifier.verify();
     }
 
     public void testPostalWithBothStructuredAndFormattedV21() {
@@ -628,7 +592,8 @@
 
     private void testOrganizationCommon(int version) {
         ExportTestResolver resolver = new ExportTestResolver();
-        resolver.buildInput(Organization.CONTENT_ITEM_TYPE)
+        ContactEntry entry = resolver.buildContactEntry();
+        entry.buildData(Organization.CONTENT_ITEM_TYPE)
                 .put(Organization.COMPANY, "CompanyX")
                 .put(Organization.DEPARTMENT, "DepartmentY")
                 .put(Organization.TITLE, "TitleZ")
@@ -637,20 +602,20 @@
                 .put(Organization.PHONETIC_NAME, "PhoneticName!")  // Ignored
                 .put(Organization.SYMBOL, "(^o^)/~~");  // Ignore him (her).
 
-        resolver.buildInput(Organization.CONTENT_ITEM_TYPE)
+        entry.buildData(Organization.CONTENT_ITEM_TYPE)
                 .putNull(Organization.COMPANY)
                 .put(Organization.DEPARTMENT, "DepartmentXX")
                 .putNull(Organization.TITLE);
 
-        resolver.buildInput(Organization.CONTENT_ITEM_TYPE)
+        entry.buildData(Organization.CONTENT_ITEM_TYPE)
                 .put(Organization.COMPANY, "CompanyXYZ")
                 .putNull(Organization.DEPARTMENT)
                 .put(Organization.TITLE, "TitleXYZYX");
 
-        VCardVerificationHandler handler = new VCardVerificationHandler(this, version);
+        VCardVerifier verifier = new VCardVerifier(resolver, version);
 
         // Currently we do not use group but depend on the order.
-        handler.addPropertyVerifierWithEmptyName()
+        verifier.addPropertyNodesVerifierWithEmptyName()
                 .addNodeWithOrder("ORG", "CompanyX;DepartmentY",
                         Arrays.asList("CompanyX", "DepartmentY"))
                 .addNodeWithOrder("TITLE", "TitleZ")
@@ -658,7 +623,7 @@
                 .addNodeWithOrder("ORG", "CompanyXYZ")
                 .addNodeWithOrder("TITLE", "TitleXYZYX");
 
-        verifyOneComposition(resolver, handler, version);
+        verifier.verify();
     }
 
     public void testOrganizationV21() {
@@ -672,46 +637,47 @@
     private void testImVariousTypeSupportCommon(int version) {
         ExportTestResolver resolver = new ExportTestResolver();
 
-        resolver.buildInput(Im.CONTENT_ITEM_TYPE)
+        ContactEntry entry = resolver.buildContactEntry();
+        entry.buildData(Im.CONTENT_ITEM_TYPE)
                 .put(Im.PROTOCOL, Im.PROTOCOL_AIM)
                 .put(Im.DATA, "aim");
 
-        resolver.buildInput(Im.CONTENT_ITEM_TYPE)
+        entry.buildData(Im.CONTENT_ITEM_TYPE)
                 .put(Im.PROTOCOL, Im.PROTOCOL_MSN)
                 .put(Im.DATA, "msn");
 
-        resolver.buildInput(Im.CONTENT_ITEM_TYPE)
+        entry.buildData(Im.CONTENT_ITEM_TYPE)
                 .put(Im.PROTOCOL, Im.PROTOCOL_YAHOO)
                 .put(Im.DATA, "yahoo");
 
-        resolver.buildInput(Im.CONTENT_ITEM_TYPE)
+        entry.buildData(Im.CONTENT_ITEM_TYPE)
                 .put(Im.PROTOCOL, Im.PROTOCOL_SKYPE)
                 .put(Im.DATA, "skype");
 
-        resolver.buildInput(Im.CONTENT_ITEM_TYPE)
+        entry.buildData(Im.CONTENT_ITEM_TYPE)
                 .put(Im.PROTOCOL, Im.PROTOCOL_QQ)
                 .put(Im.DATA, "qq");
 
-        resolver.buildInput(Im.CONTENT_ITEM_TYPE)
+        entry.buildData(Im.CONTENT_ITEM_TYPE)
                 .put(Im.PROTOCOL, Im.PROTOCOL_GOOGLE_TALK)
                 .put(Im.DATA, "google talk");
 
-        resolver.buildInput(Im.CONTENT_ITEM_TYPE)
+        entry.buildData(Im.CONTENT_ITEM_TYPE)
                 .put(Im.PROTOCOL, Im.PROTOCOL_ICQ)
                 .put(Im.DATA, "icq");
 
-        resolver.buildInput(Im.CONTENT_ITEM_TYPE)
+        entry.buildData(Im.CONTENT_ITEM_TYPE)
                 .put(Im.PROTOCOL, Im.PROTOCOL_JABBER)
                 .put(Im.DATA, "jabber");
 
-        resolver.buildInput(Im.CONTENT_ITEM_TYPE)
+        entry.buildData(Im.CONTENT_ITEM_TYPE)
                 .put(Im.PROTOCOL, Im.PROTOCOL_NETMEETING)
                 .put(Im.DATA, "netmeeting");
 
         // No determined way to express unknown type...
 
-        VCardVerificationHandler handler = new VCardVerificationHandler(this, version);
-        handler.addPropertyVerifierWithEmptyName()
+        VCardVerifier verifier = new VCardVerifier(resolver, version);
+        verifier.addPropertyNodesVerifierWithEmptyName()
                 .addNodeWithoutOrder("X-JABBER", "jabber")
                 .addNodeWithoutOrder("X-ICQ", "icq")
                 .addNodeWithoutOrder("X-GOOGLE-TALK", "google talk")
@@ -722,7 +688,7 @@
                 .addNodeWithoutOrder("X-NETMEETING", "netmeeting")
                 .addNodeWithoutOrder("X-AIM", "aim");
 
-        verifyOneComposition(resolver, handler, version);
+        verifier.verify();
     }
 
     public void testImBasiV21() {
@@ -736,22 +702,23 @@
     private void testImPrefHandlingCommon(int version) {
         ExportTestResolver resolver = new ExportTestResolver();
 
-        resolver.buildInput(Im.CONTENT_ITEM_TYPE)
+        ContactEntry entry = resolver.buildContactEntry();
+        entry.buildData(Im.CONTENT_ITEM_TYPE)
                 .put(Im.PROTOCOL, Im.PROTOCOL_AIM)
                 .put(Im.DATA, "aim1");
 
-        resolver.buildInput(Im.CONTENT_ITEM_TYPE)
+        entry.buildData(Im.CONTENT_ITEM_TYPE)
                 .put(Im.PROTOCOL, Im.PROTOCOL_AIM)
                 .put(Im.DATA, "aim2")
                 .put(Im.TYPE, Im.TYPE_HOME)
                 .put(Im.IS_PRIMARY, 1);
 
-        VCardVerificationHandler handler = new VCardVerificationHandler(this, version);
-        handler.addPropertyVerifierWithEmptyName()
+        VCardVerifier verifier = new VCardVerifier(resolver, version);
+        verifier.addPropertyNodesVerifierWithEmptyName()
                 .addNodeWithoutOrder("X-AIM", "aim1")
                 .addNodeWithoutOrder("X-AIM", "aim2", new TypeSet("HOME", "PREF"));
 
-        verifyOneComposition(resolver, handler, version);
+        verifier.verify();
     }
 
     public void testImPrefHandlingV21() {
@@ -765,21 +732,21 @@
     private void testWebsiteCommon(int version) {
         ExportTestResolver resolver = new ExportTestResolver();
 
-        resolver.buildInput(Website.CONTENT_ITEM_TYPE)
+        ContactEntry entry = resolver.buildContactEntry();
+        entry.buildData(Website.CONTENT_ITEM_TYPE)
                 .put(Website.URL, "http://website.example.android.com/index.html")
                 .put(Website.TYPE, Website.TYPE_BLOG);
 
-        resolver.buildInput(Website.CONTENT_ITEM_TYPE)
+        entry.buildData(Website.CONTENT_ITEM_TYPE)
                 .put(Website.URL, "ftp://ftp.example.android.com/index.html")
                 .put(Website.TYPE, Website.TYPE_FTP);
 
         // We drop TYPE information since vCard (especially 3.0) does not allow us to emit it.
-        VCardVerificationHandler handler = new VCardVerificationHandler(this, version);
-        handler.addPropertyVerifierWithEmptyName()
+        VCardVerifier verifier = new VCardVerifier(resolver, version);
+        verifier.addPropertyNodesVerifierWithEmptyName()
                 .addNodeWithoutOrder("URL", "ftp://ftp.example.android.com/index.html")
                 .addNodeWithoutOrder("URL", "http://website.example.android.com/index.html");
-
-        verifyOneComposition(resolver, handler, version);
+        verifier.verify();
     }
 
     public void testWebsiteV21() {
@@ -793,32 +760,29 @@
     private void testEventCommon(int version) {
         ExportTestResolver resolver = new ExportTestResolver();
 
-        resolver.buildInput(Event.CONTENT_ITEM_TYPE)
+        ContactEntry entry = resolver.buildContactEntry();
+        entry.buildData(Event.CONTENT_ITEM_TYPE)
                 .put(Event.TYPE, Event.TYPE_ANNIVERSARY)
                 .put(Event.START_DATE, "1982-06-16");
-
-        resolver.buildInput(Event.CONTENT_ITEM_TYPE)
+        entry.buildData(Event.CONTENT_ITEM_TYPE)
                 .put(Event.TYPE, Event.TYPE_BIRTHDAY)
                 .put(Event.START_DATE, "2008-10-22");
-
-        resolver.buildInput(Event.CONTENT_ITEM_TYPE)
+        entry.buildData(Event.CONTENT_ITEM_TYPE)
                 .put(Event.TYPE, Event.TYPE_OTHER)
                 .put(Event.START_DATE, "2018-03-12");
-
-        resolver.buildInput(Event.CONTENT_ITEM_TYPE)
+        entry.buildData(Event.CONTENT_ITEM_TYPE)
                 .put(Event.TYPE, Event.TYPE_CUSTOM)
                 .put(Event.LABEL, "The last day")
                 .put(Event.START_DATE, "When the Tower of Hanoi with 64 rings is completed.");
-
-        resolver.buildInput(Event.CONTENT_ITEM_TYPE)
+        entry.buildData(Event.CONTENT_ITEM_TYPE)
                 .put(Event.TYPE, Event.TYPE_BIRTHDAY)
                 .put(Event.START_DATE, "2009-05-19");
 
-        VCardVerificationHandler handler = new VCardVerificationHandler(this, version);
-        handler.addPropertyVerifierWithEmptyName()
+        VCardVerifier verifier = new VCardVerifier(resolver, version);
+        verifier.addPropertyNodesVerifierWithEmptyName()
                 .addNodeWithoutOrder("BDAY", "2008-10-22");
 
-        verifyOneComposition(resolver, handler, version);
+        verifier.verify();
     }
 
     public void testEventV21() {
@@ -832,19 +796,19 @@
     private void testNoteCommon(int version) {
         ExportTestResolver resolver = new ExportTestResolver();
 
-        resolver.buildInput(Note.CONTENT_ITEM_TYPE)
+        ContactEntry entry = resolver.buildContactEntry();
+        entry.buildData(Note.CONTENT_ITEM_TYPE)
                 .put(Note.NOTE, "note1");
-
-        resolver.buildInput(Note.CONTENT_ITEM_TYPE)
+        entry.buildData(Note.CONTENT_ITEM_TYPE)
                 .put(Note.NOTE, "note2")
                 .put(Note.IS_PRIMARY, 1);  // Just ignored.
 
-        VCardVerificationHandler handler = new VCardVerificationHandler(this, version);
-        handler.addPropertyVerifierWithEmptyName()
+        VCardVerifier verifier = new VCardVerifier(resolver, version);
+        verifier.addPropertyNodesVerifierWithEmptyName()
                 .addNodeWithOrder("NOTE", "note1")
                 .addNodeWithOrder("NOTE", "note2");
 
-        verifyOneComposition(resolver, handler, version);
+        verifier.verify();
     }
 
     public void testNoteV21() {
@@ -858,23 +822,23 @@
     private void testPhotoCommon(int version) {
         final boolean isV30 = version == V30;
         ExportTestResolver resolver = new ExportTestResolver();
-        resolver.buildInput(StructuredName.CONTENT_ITEM_TYPE)
+        ContactEntry entry = resolver.buildContactEntry();
+        entry.buildData(StructuredName.CONTENT_ITEM_TYPE)
                 .put(StructuredName.FAMILY_NAME, "PhotoTest");
-
-        resolver.buildInput(Photo.CONTENT_ITEM_TYPE)
+        entry.buildData(Photo.CONTENT_ITEM_TYPE)
                 .put(Photo.PHOTO, sPhotoByteArray);
 
         ContentValues contentValuesForPhoto = new ContentValues();
         contentValuesForPhoto.put("ENCODING", (isV30 ? "b" : "BASE64"));
-        VCardVerificationHandler handler = new VCardVerificationHandler(this, version);
-        handler.addPropertyNodesVerifier()
+        VCardVerifier verifier = new VCardVerifier(resolver, version);
+        verifier.addPropertyNodesVerifierElem()
                 .addNodeWithoutOrder("FN", "PhotoTest")
                 .addNodeWithoutOrder("N", "PhotoTest;;;;",
                         Arrays.asList("PhotoTest", "", "", "", ""))
                 .addNodeWithOrder("PHOTO", null, null, sPhotoByteArray,
                         contentValuesForPhoto, new TypeSet("JPEG"), null);
 
-        verifyOneComposition(resolver, handler, version);
+        verifier.verify();
     }
 
     public void testPhotoV21() {
@@ -888,21 +852,22 @@
     public void testV30HandleEscape() {
         final int version = V30;
         ExportTestResolver resolver = new ExportTestResolver();
-        resolver.buildInput(StructuredName.CONTENT_ITEM_TYPE)
+        resolver.buildContactEntry().buildData(StructuredName.CONTENT_ITEM_TYPE)
                 .put(StructuredName.FAMILY_NAME, "\\")
                 .put(StructuredName.GIVEN_NAME, ";")
                 .put(StructuredName.MIDDLE_NAME, ",")
                 .put(StructuredName.PREFIX, "\n")
                 .put(StructuredName.DISPLAY_NAME, "[<{Unescaped:Asciis}>]");
-        VCardVerificationHandler handler = new VCardVerificationHandler(this, version);
+        VCardVerifier verifier = new VCardVerifier(resolver, version);
         // Verifies the vCard String correctly escapes each character which must be escaped.
-        handler.addExpectedLine("N:\\\\;\\;;\\,;\\n;")
-                .addExpectedLine("FN:[<{Unescaped:Asciis}>]");
-        handler.addPropertyNodesVerifier()
+        verifier.addLineVerifier()
+                .addExpected("N:\\\\;\\;;\\,;\\n;")
+                .addExpected("FN:[<{Unescaped:Asciis}>]");
+        verifier.addPropertyNodesVerifierElem()
                 .addNodeWithoutOrder("FN", "[<{Unescaped:Asciis}>]")
                 .addNodeWithoutOrder("N", Arrays.asList("\\", ";", ",", "\n", ""));
 
-        verifyOneComposition(resolver, handler, version);
+        verifier.verify();
     }
 
     /**
@@ -912,18 +877,16 @@
      */
     public void testNickNameV21() {
         ExportTestResolver resolver = new ExportTestResolver();
-        resolver.buildInput(Nickname.CONTENT_ITEM_TYPE)
+        resolver.buildContactEntry().buildData(Nickname.CONTENT_ITEM_TYPE)
                 .put(Nickname.NAME, "Nicky");
 
-        VCardVerificationHandler handler = new VCardVerificationHandler(this, V21);
-        handler.addPropertyVerifierWithEmptyName()
+        VCardVerifier verifier = new VCardVerifier(resolver, V21);
+        verifier.addPropertyNodesVerifierWithEmptyName()
                 .addNodeWithOrder("X-ANDROID-CUSTOM",
                         Nickname.CONTENT_ITEM_TYPE + ";Nicky;;;;;;;;;;;;;;");
-
-        handler.addContentValuesVerifier()
-                .buildExpected(Nickname.CONTENT_ITEM_TYPE)
+        verifier.addImportVerifier()
+                .addExpected(Nickname.CONTENT_ITEM_TYPE)
                         .put(Nickname.NAME, "Nicky");
-
-        verifyOneComposition(resolver, handler, V21);
+        verifier.verify();
     }
 }
diff --git a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardImporterTests.java b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardImporterTests.java
index 0a20310..1aa334a 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardImporterTests.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardImporterTests.java
@@ -19,7 +19,6 @@
 import android.content.ContentValues;
 import android.pim.vcard.VCardConfig;
 import android.pim.vcard.VCardParser_V21;
-import android.pim.vcard.VCardParser_V30;
 import android.pim.vcard.exception.VCardException;
 import android.provider.ContactsContract.Data;
 import android.provider.ContactsContract.CommonDataKinds.Email;
@@ -33,7 +32,7 @@
 import android.provider.ContactsContract.CommonDataKinds.Website;
 
 import com.android.unit_tests.R;
-import com.android.unit_tests.vcard.PropertyNodesVerifier.TypeSet;
+import com.android.unit_tests.vcard.PropertyNodesVerifierElem.TypeSet;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -410,53 +409,52 @@
     }
 
     public void testV21SimpleCase1_Parsing() throws IOException, VCardException {
-        VCardParser_V21 parser = new VCardParser_V21();
-        VNodeBuilder builder = new VNodeBuilder();
-        InputStream is = getContext().getResources().openRawResource(R.raw.v21_simple_1);
-        assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
-        is.close();
-        assertEquals(1, builder.vNodeList.size());
-        PropertyNodesVerifier verifier = new PropertyNodesVerifier(this)
+        PropertyNodesVerifier verifier = new PropertyNodesVerifier(this);
+        verifier.addPropertyNodesVerifierElem()
                 .addNodeWithOrder("N", "Ando;Roid;", Arrays.asList("Ando", "Roid", ""));
-        verifier.verify(builder.vNodeList.get(0));
+        verifier.verify(R.raw.v21_simple_1, V21);
     }
 
     public void testV21SimpleCase1_Type_Generic() throws IOException, VCardException {
-        ContentValuesVerifier verifier = new ContentValuesVerifier();
-        verifier.buildExpected(StructuredName.CONTENT_ITEM_TYPE)
-                .put(StructuredName.FAMILY_NAME, "Ando")
-                .put(StructuredName.GIVEN_NAME, "Roid")
-                .put(StructuredName.DISPLAY_NAME, "Roid Ando");
+        ImportVerifier verifier = new ImportVerifier();
+        verifier.addImportVerifierElem()
+                .addExpected(StructuredName.CONTENT_ITEM_TYPE)
+                        .put(StructuredName.FAMILY_NAME, "Ando")
+                        .put(StructuredName.GIVEN_NAME, "Roid")
+                        .put(StructuredName.DISPLAY_NAME, "Roid Ando");
         verifier.verify(R.raw.v21_simple_1, VCardConfig.VCARD_TYPE_V21_GENERIC_UTF8);
     }
 
     public void testV21SimpleCase1_Type_Japanese() throws IOException, VCardException {
-        ContentValuesVerifier verifier = new ContentValuesVerifier();
-        verifier.buildExpected(StructuredName.CONTENT_ITEM_TYPE)
-                .put(StructuredName.FAMILY_NAME, "Ando")
-                .put(StructuredName.GIVEN_NAME, "Roid")
-                // If name-related strings only contains printable Ascii,
-                // the order is remained to be US's:
-                // "Prefix Given Middle Family Suffix"
-                .put(StructuredName.DISPLAY_NAME, "Roid Ando");
+        ImportVerifier verifier = new ImportVerifier();
+        verifier.addImportVerifierElem()
+                .addExpected(StructuredName.CONTENT_ITEM_TYPE)
+                        .put(StructuredName.FAMILY_NAME, "Ando")
+                        .put(StructuredName.GIVEN_NAME, "Roid")
+                        // If name-related strings only contains printable Ascii,
+                        // the order is remained to be US's:
+                        // "Prefix Given Middle Family Suffix"
+                        .put(StructuredName.DISPLAY_NAME, "Roid Ando");
         verifier.verify(R.raw.v21_simple_1, VCardConfig.VCARD_TYPE_V21_JAPANESE_SJIS);
     }
 
     public void testV21SimpleCase2() throws IOException, VCardException {
-        ContentValuesVerifier verifier = new ContentValuesVerifier();
-        verifier.buildExpected(StructuredName.CONTENT_ITEM_TYPE)
-                .put(StructuredName.DISPLAY_NAME, "Ando Roid");
+        ImportVerifier verifier = new ImportVerifier();
+        verifier.addImportVerifierElem()
+                .addExpected(StructuredName.CONTENT_ITEM_TYPE)
+                        .put(StructuredName.DISPLAY_NAME, "Ando Roid");
         verifier.verify(R.raw.v21_simple_2, VCardConfig.VCARD_TYPE_V21_GENERIC_UTF8);
     }
 
     public void testV21SimpleCase3() throws IOException, VCardException {
-        ContentValuesVerifier verifier = new ContentValuesVerifier();
-        verifier.buildExpected(StructuredName.CONTENT_ITEM_TYPE)
-                .put(StructuredName.FAMILY_NAME, "Ando")
-                .put(StructuredName.GIVEN_NAME, "Roid")
-                // "FN" field should be prefered since it should contain the original order
-                // intended by the author of the file.
-                .put(StructuredName.DISPLAY_NAME, "Ando Roid");
+        ImportVerifier verifier = new ImportVerifier();
+        verifier.addImportVerifierElem()
+                .addExpected(StructuredName.CONTENT_ITEM_TYPE)
+                        .put(StructuredName.FAMILY_NAME, "Ando")
+                        .put(StructuredName.GIVEN_NAME, "Roid")
+                        // "FN" field should be prefered since it should contain the original
+                        // order intended by the author of the file.
+                        .put(StructuredName.DISPLAY_NAME, "Ando Roid");
         verifier.verify(R.raw.v21_simple_3, VCardConfig.VCARD_TYPE_V21_GENERIC_UTF8);
     }
 
@@ -464,18 +462,13 @@
      * Tests ';' is properly handled by VCardParser implementation.
      */
     public void testV21BackslashCase_Parsing() throws IOException, VCardException {
-        VCardParser_V21 parser = new VCardParser_V21();
-        VNodeBuilder builder = new VNodeBuilder();
-        InputStream is = getContext().getResources().openRawResource(R.raw.v21_backslash);
-        assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
-        is.close();
-        assertEquals(1, builder.vNodeList.size());
-        PropertyNodesVerifier verifier = new PropertyNodesVerifier(this)
+        PropertyNodesVerifier verifier = new PropertyNodesVerifier(this);
+        verifier.addPropertyNodesVerifierElem()
                 .addNodeWithOrder("VERSION", "2.1")
                 .addNodeWithOrder("N", ";A;B\\;C\\;;D;:E;\\\\;",
                         Arrays.asList("", "A;B\\", "C\\;", "D", ":E", "\\\\", ""))
                 .addNodeWithOrder("FN", "A;B\\C\\;D:E\\\\");
-        verifier.verify(builder.vNodeList.get(0));
+        verifier.verify(R.raw.v21_backslash, V21);
     }
 
     /**
@@ -483,23 +476,25 @@
      * inserts name related data.
      */
     public void testV21BackslashCase() throws IOException, VCardException {
-        ContentValuesVerifier verifier = new ContentValuesVerifier();
-        verifier.buildExpected(StructuredName.CONTENT_ITEM_TYPE)
-                // FAMILY_NAME is empty and removed in this test...
-                .put(StructuredName.GIVEN_NAME, "A;B\\")
-                .put(StructuredName.MIDDLE_NAME, "C\\;")
-                .put(StructuredName.PREFIX, "D")
-                .put(StructuredName.SUFFIX, ":E")
-                .put(StructuredName.DISPLAY_NAME, "A;B\\C\\;D:E\\\\");
+        ImportVerifier verifier = new ImportVerifier();
+        verifier.addImportVerifierElem()
+                .addExpected(StructuredName.CONTENT_ITEM_TYPE)
+                        // FAMILY_NAME is empty and removed in this test...
+                        .put(StructuredName.GIVEN_NAME, "A;B\\")
+                        .put(StructuredName.MIDDLE_NAME, "C\\;")
+                        .put(StructuredName.PREFIX, "D")
+                        .put(StructuredName.SUFFIX, ":E")
+                        .put(StructuredName.DISPLAY_NAME, "A;B\\C\\;D:E\\\\");
         verifier.verify(R.raw.v21_backslash, VCardConfig.VCARD_TYPE_V21_GENERIC_UTF8);
     }
 
     public void testOrgBeforTitle() throws IOException, VCardException {
-        ContentValuesVerifier verifier = new ContentValuesVerifier();
-        verifier.buildExpected(StructuredName.CONTENT_ITEM_TYPE)
+        ImportVerifier verifier = new ImportVerifier();
+        ImportVerifierElem elem = verifier.addImportVerifierElem();
+        elem.addExpected(StructuredName.CONTENT_ITEM_TYPE)
                 .put(StructuredName.DISPLAY_NAME, "Normal Guy");
 
-        verifier.buildExpected(Organization.CONTENT_ITEM_TYPE)
+        elem.addExpected(Organization.CONTENT_ITEM_TYPE)
                 .put(Organization.COMPANY, "Company")
                 .put(Organization.DEPARTMENT, "Organization Devision Room Sheet No.")
                 .put(Organization.TITLE, "Excellent Janitor")
@@ -508,11 +503,12 @@
     }
 
     public void testTitleBeforOrg() throws IOException, VCardException {
-        ContentValuesVerifier verifier = new ContentValuesVerifier();
-        verifier.buildExpected(StructuredName.CONTENT_ITEM_TYPE)
+        ImportVerifier verifier = new ImportVerifier();
+        ImportVerifierElem elem = verifier.addImportVerifierElem();
+        elem.addExpected(StructuredName.CONTENT_ITEM_TYPE)
                 .put(StructuredName.DISPLAY_NAME, "Nice Guy");
 
-        verifier.buildExpected(Organization.CONTENT_ITEM_TYPE)
+        elem.addExpected(Organization.CONTENT_ITEM_TYPE)
                 .put(Organization.COMPANY, "Marverous")
                 .put(Organization.DEPARTMENT, "Perfect Great Good Bad Poor")
                 .put(Organization.TITLE, "Cool Title")
@@ -525,45 +521,46 @@
      * The data contain three cases: one "PREF", no "PREF" and multiple "PREF", in each type.
      */
     public void testV21PrefToIsPrimary() throws IOException, VCardException {
-        ContentValuesVerifier verifier = new ContentValuesVerifier();
-        verifier.buildExpected(StructuredName.CONTENT_ITEM_TYPE)
+        ImportVerifier verifier = new ImportVerifier();
+        ImportVerifierElem elem = verifier.addImportVerifierElem();
+        elem.addExpected(StructuredName.CONTENT_ITEM_TYPE)
                 .put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE)
                 .put(StructuredName.DISPLAY_NAME, "Smith");
 
-        verifier.buildExpected(Phone.CONTENT_ITEM_TYPE)
+        elem.addExpected(Phone.CONTENT_ITEM_TYPE)
                 .put(Phone.NUMBER, "1")
                 .put(Phone.TYPE, Phone.TYPE_HOME);
 
-        verifier.buildExpected(Phone.CONTENT_ITEM_TYPE)
+        elem.addExpected(Phone.CONTENT_ITEM_TYPE)
                 .put(Phone.NUMBER, "2")
                 .put(Phone.TYPE, Phone.TYPE_WORK)
                 .put(Phone.IS_PRIMARY, 1);
 
-        verifier.buildExpected(Phone.CONTENT_ITEM_TYPE)
+        elem.addExpected(Phone.CONTENT_ITEM_TYPE)
                 .put(Phone.NUMBER, "3")
                 .put(Phone.TYPE, Phone.TYPE_ISDN);
 
-        verifier.buildExpected(Email.CONTENT_ITEM_TYPE)
+        elem.addExpected(Email.CONTENT_ITEM_TYPE)
                 .put(Email.DATA, "test@example.com")
                 .put(Email.TYPE, Email.TYPE_HOME)
                 .put(Email.IS_PRIMARY, 1);
 
-        verifier.buildExpected(Email.CONTENT_ITEM_TYPE)
+        elem.addExpected(Email.CONTENT_ITEM_TYPE)
                 .put(Email.DATA, "test2@examination.com")
                 .put(Email.TYPE, Email.TYPE_MOBILE)
                 .put(Email.IS_PRIMARY, 1);
 
-        verifier.buildExpected(Organization.CONTENT_ITEM_TYPE)
+        elem.addExpected(Organization.CONTENT_ITEM_TYPE)
                 .put(Organization.COMPANY, "Company")
                 .put(Organization.TITLE, "Engineer")
                 .put(Organization.TYPE, Organization.TYPE_WORK);
 
-        verifier.buildExpected(Organization.CONTENT_ITEM_TYPE)
+        elem.addExpected(Organization.CONTENT_ITEM_TYPE)
                 .put(Organization.COMPANY, "Mystery")
                 .put(Organization.TITLE, "Blogger")
                 .put(Organization.TYPE, Organization.TYPE_WORK);
 
-        verifier.buildExpected(Organization.CONTENT_ITEM_TYPE)
+        elem.addExpected(Organization.CONTENT_ITEM_TYPE)
                 .put(Organization.COMPANY, "Poetry")
                 .put(Organization.TITLE, "Poet")
                 .put(Organization.TYPE, Organization.TYPE_WORK);
@@ -574,17 +571,12 @@
      * Tests all the properties in a complicated vCard are correctly parsed by the VCardParser.
      */
     public void testV21ComplicatedCase_Parsing() throws IOException, VCardException {
-        VCardParser_V21 parser = new VCardParser_V21();
-        VNodeBuilder builder = new VNodeBuilder();
-        InputStream is = getContext().getResources().openRawResource(R.raw.v21_complicated);
-        assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
-        is.close();
-        assertEquals(1, builder.vNodeList.size());
         ContentValues contentValuesForQP = new ContentValues();
         contentValuesForQP.put("ENCODING", "QUOTED-PRINTABLE");
         ContentValues contentValuesForPhoto = new ContentValues();
         contentValuesForPhoto.put("ENCODING", "BASE64");
-        PropertyNodesVerifier verifier = new PropertyNodesVerifier(this)
+        PropertyNodesVerifier verifier = new PropertyNodesVerifier(this);
+        verifier.addPropertyNodesVerifierElem()
                 .addNodeWithOrder("VERSION", "2.1")
                 .addNodeWithOrder("N", "Gump;Forrest;Hoge;Pos;Tao",
                         Arrays.asList("Gump", "Forrest", "Hoge", "Pos", "Tao"))
@@ -631,7 +623,7 @@
                 .addNodeWithOrder("GEO", "35.6563854,139.6994233")
                 .addNodeWithOrder("URL", "http://www.example.com/")
                 .addNodeWithOrder("REV", "20080424T195243Z");
-        verifier.verify(builder.vNodeList.get(0));
+        verifier.verify(R.raw.v21_complicated, V21);
     }
 
     /**
@@ -639,8 +631,9 @@
      * into ContentResolver.
      */
     public void testV21ComplicatedCase() throws IOException, VCardException {
-        ContentValuesVerifier verifier = new ContentValuesVerifier();
-        verifier.buildExpected(StructuredName.CONTENT_ITEM_TYPE)
+        ImportVerifier verifier = new ImportVerifier();
+        ImportVerifierElem elem = verifier.addImportVerifierElem();
+        elem.addExpected(StructuredName.CONTENT_ITEM_TYPE)
                 .put(StructuredName.FAMILY_NAME, "Gump")
                 .put(StructuredName.GIVEN_NAME, "Forrest")
                 .put(StructuredName.MIDDLE_NAME, "Hoge")
@@ -648,36 +641,36 @@
                 .put(StructuredName.SUFFIX, "Tao")
                 .put(StructuredName.DISPLAY_NAME, "Joe Due");
         
-        verifier.buildExpected(Organization.CONTENT_ITEM_TYPE)
+        elem.addExpected(Organization.CONTENT_ITEM_TYPE)
                 .put(Organization.TYPE, Organization.TYPE_WORK)
                 .put(Organization.COMPANY, "Gump Shrimp Co.")
                 .put(Organization.DEPARTMENT, "Sales Dept.;Manager Fish keeper")
                 .put(Organization.TITLE, "Shrimp Man");
 
-        verifier.buildExpected(Phone.CONTENT_ITEM_TYPE)
+        elem.addExpected(Phone.CONTENT_ITEM_TYPE)
                 .put(Phone.TYPE, Phone.TYPE_WORK)
                 // Phone number is expected to be formated with NAMP format in default.
                 .put(Phone.NUMBER, "111-555-1212");
 
-        verifier.buildExpected(Phone.CONTENT_ITEM_TYPE)
+        elem.addExpected(Phone.CONTENT_ITEM_TYPE)
                 .put(Phone.TYPE, Phone.TYPE_HOME)
                 .put(Phone.NUMBER, "404-555-1212");
 
-        verifier.buildExpected(Phone.CONTENT_ITEM_TYPE)
+        elem.addExpected(Phone.CONTENT_ITEM_TYPE)
                 .put(Phone.TYPE, Phone.TYPE_MOBILE)
                 .put(Phone.NUMBER, "031-111-1111");
 
-        verifier.buildExpected(Phone.CONTENT_ITEM_TYPE)
+        elem.addExpected(Phone.CONTENT_ITEM_TYPE)
                 .put(Phone.TYPE, Phone.TYPE_CUSTOM)
                 .put(Phone.LABEL, "VIDEO")
                 .put(Phone.NUMBER, "032-222-2222");
 
-        verifier.buildExpected(Phone.CONTENT_ITEM_TYPE)
+        elem.addExpected(Phone.CONTENT_ITEM_TYPE)
                 .put(Phone.TYPE, Phone.TYPE_CUSTOM)
                 .put(Phone.LABEL, "VOICE")
                 .put(Phone.NUMBER, "033-333-3333");
 
-        verifier.buildExpected(StructuredPostal.CONTENT_ITEM_TYPE)
+        elem.addExpected(StructuredPostal.CONTENT_ITEM_TYPE)
                 .put(StructuredPostal.TYPE, StructuredPostal.TYPE_WORK)
                 .put(StructuredPostal.COUNTRY, "United States of America")
                 .put(StructuredPostal.POSTCODE, "30314")
@@ -687,7 +680,7 @@
                 .put(StructuredPostal.FORMATTED_ADDRESS,
                         "100 Waters Edge Baytown LA 30314 United States of America");
 
-        verifier.buildExpected(StructuredPostal.CONTENT_ITEM_TYPE)
+        elem.addExpected(StructuredPostal.CONTENT_ITEM_TYPE)
                 .put(StructuredPostal.TYPE, StructuredPostal.TYPE_HOME)
                 .put(StructuredPostal.COUNTRY, "United States of America")
                 .put(StructuredPostal.POSTCODE, "30314")
@@ -697,46 +690,41 @@
                 .put(StructuredPostal.FORMATTED_ADDRESS,
                         "42 Plantation St. Baytown LA 30314 United States of America");
 
-        verifier.buildExpected(Email.CONTENT_ITEM_TYPE)
+        elem.addExpected(Email.CONTENT_ITEM_TYPE)
                 // "TYPE=INTERNET" -> TYPE_CUSTOM + the label "INTERNET"
                 .put(Email.TYPE, Email.TYPE_CUSTOM)
                 .put(Email.LABEL, "INTERNET")
                 .put(Email.DATA, "forrestgump@walladalla.com")
                 .put(Email.IS_PRIMARY, 1);
 
-        verifier.buildExpected(Email.CONTENT_ITEM_TYPE)
+        elem.addExpected(Email.CONTENT_ITEM_TYPE)
                 .put(Email.TYPE, Email.TYPE_MOBILE)
                 .put(Email.DATA, "cell@example.com");
 
-        verifier.buildExpected(Note.CONTENT_ITEM_TYPE)
+        elem.addExpected(Note.CONTENT_ITEM_TYPE)
                 .put(Note.NOTE, "The following note is the example from RFC 2045.");
 
-        verifier.buildExpected(Note.CONTENT_ITEM_TYPE)
+        elem.addExpected(Note.CONTENT_ITEM_TYPE)
                 .put(Note.NOTE,
                         "Now's the time for all folk to come to the aid of their country.");
 
-        verifier.buildExpected(Photo.CONTENT_ITEM_TYPE)
+        elem.addExpected(Photo.CONTENT_ITEM_TYPE)
                 // No information about its image format can be inserted.
                 .put(Photo.PHOTO, sPhotoByteArrayForComplicatedCase);
 
-        verifier.buildExpected(Event.CONTENT_ITEM_TYPE)
+        elem.addExpected(Event.CONTENT_ITEM_TYPE)
                 .put(Event.START_DATE, "19800101")
                 .put(Event.TYPE, Event.TYPE_BIRTHDAY);
 
-        verifier.buildExpected(Website.CONTENT_ITEM_TYPE)
+        elem.addExpected(Website.CONTENT_ITEM_TYPE)
                 .put(Website.URL, "http://www.example.com/")
                 .put(Website.TYPE, Website.TYPE_HOMEPAGE);
         verifier.verify(R.raw.v21_complicated, VCardConfig.VCARD_TYPE_V21_GENERIC_UTF8);
     }
 
     public void testV30Simple_Parsing() throws IOException, VCardException {
-        VCardParser_V21 parser = new VCardParser_V30();
-        VNodeBuilder builder = new VNodeBuilder();
-        InputStream is = getContext().getResources().openRawResource(R.raw.v30_simple);
-        assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
-        is.close();
-        assertEquals(1, builder.vNodeList.size());
-        PropertyNodesVerifier verifier = new PropertyNodesVerifier(this)
+        PropertyNodesVerifier verifier = new PropertyNodesVerifier(this);
+        verifier.addPropertyNodesVerifierElem()
                 .addNodeWithOrder("VERSION", "3.0")
                 .addNodeWithOrder("FN", "And Roid")
                 .addNodeWithOrder("N", "And;Roid;;;", Arrays.asList("And", "Roid", "", "", ""))
@@ -749,24 +737,22 @@
                 .addNodeWithOrder("X-GN", "group0")
                 .addNodeWithOrder("X-REDUCTION", "0")
                 .addNodeWithOrder("REV", "20081031T065854Z");
-        verifier.verify(builder.vNodeList.get(0));
+        verifier.verify(R.raw.v30_simple, V30);
     }
 
     public void testV30Simple() throws IOException, VCardException {
-        ContentValuesVerifier verifier = new ContentValuesVerifier();
-
-        verifier.buildExpected(StructuredName.CONTENT_ITEM_TYPE)
+        ImportVerifier verifier = new ImportVerifier();
+        ImportVerifierElem elem = verifier.addImportVerifierElem();
+        elem.addExpected(StructuredName.CONTENT_ITEM_TYPE)
                 .put(StructuredName.FAMILY_NAME, "And")
                 .put(StructuredName.GIVEN_NAME, "Roid")
                 .put(StructuredName.DISPLAY_NAME, "And Roid")
                 .put(StructuredName.PHONETIC_GIVEN_NAME, "android");
-
-        verifier.buildExpected(Organization.CONTENT_ITEM_TYPE)
+        elem.addExpected(Organization.CONTENT_ITEM_TYPE)
                 .put(Organization.COMPANY, "Open")
                 .put(Organization.DEPARTMENT, "Handset  Alliance")
                 .put(Organization.TYPE, Organization.TYPE_WORK);
-
-        verifier.buildExpected(Phone.CONTENT_ITEM_TYPE)
+        elem.addExpected(Phone.CONTENT_ITEM_TYPE)
                 .put(Phone.TYPE, Phone.TYPE_CUSTOM)
                 .put(Phone.LABEL, "VOICE")
                 .put(Phone.NUMBER, "030-000-0000")
@@ -775,18 +761,13 @@
     }
 
     public void testV21Japanese1_Parsing() throws IOException, VCardException {
-        VCardParser_V21 parser = new VCardParser_V21();
-        VNodeBuilder builder = new VNodeBuilder();
-        InputStream is = getContext().getResources().openRawResource(R.raw.v21_japanese_1);
-        assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
-        is.close();
-        assertEquals(1, builder.vNodeList.size());
-        ContentValues contentValuesForShiftJis = new ContentValues();
-        contentValuesForShiftJis.put("CHARSET", "SHIFT_JIS");
         // Though Japanese careers append ";;;;" at the end of the value of "SOUND",
         // vCard 2.1/3.0 specification does not allow multiple values.
         // Do not need to handle it as multiple values.
-        PropertyNodesVerifier verifier = new PropertyNodesVerifier(this)
+        ContentValues contentValuesForShiftJis = new ContentValues();
+        contentValuesForShiftJis.put("CHARSET", "SHIFT_JIS");
+        PropertyNodesVerifier verifier = new PropertyNodesVerifier(this);
+        verifier.addPropertyNodesVerifierElem()
                 .addNodeWithOrder("VERSION", "2.1", null, null, null, null, null)
                 .addNodeWithOrder("N", "\u5B89\u85E4\u30ED\u30A4\u30C9;;;;",
                         Arrays.asList("\u5B89\u85E4\u30ED\u30A4\u30C9", "", "", "", ""),
@@ -797,13 +778,14 @@
                         new TypeSet("X-IRMC-N"), null)
                 .addNodeWithOrder("TEL", "0300000000", null, null, null,
                         new TypeSet("VOICE", "PREF"), null);
-        verifier.verify(builder.vNodeList.get(0));
+        verifier.verify(R.raw.v21_japanese_1, VCardConfig.VCARD_TYPE_V21_JAPANESE_SJIS);
     }
 
     private void testV21Japanese1Common(int resId, int vcardType, boolean japanese)
             throws IOException, VCardException {
-        ContentValuesVerifier verifier = new ContentValuesVerifier();
-        verifier.buildExpected(StructuredName.CONTENT_ITEM_TYPE)
+        ImportVerifier verifier = new ImportVerifier();
+        ImportVerifierElem elem = verifier.addImportVerifierElem();
+        elem.addExpected(StructuredName.CONTENT_ITEM_TYPE)
                 .put(StructuredName.FAMILY_NAME, "\u5B89\u85E4\u30ED\u30A4\u30C9")
                 .put(StructuredName.DISPLAY_NAME, "\u5B89\u85E4\u30ED\u30A4\u30C9")
                 // While vCard parser does not split "SOUND" property values,
@@ -811,7 +793,7 @@
                 .put(StructuredName.PHONETIC_FAMILY_NAME,
                         "\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E");
 
-        verifier.buildExpected(Phone.CONTENT_ITEM_TYPE)
+        elem.addExpected(Phone.CONTENT_ITEM_TYPE)
                 // Phone number formatting is different.
                 .put(Phone.NUMBER, (japanese ? "03-0000-0000" : "030-000-0000"))
                 .put(Phone.TYPE, Phone.TYPE_CUSTOM)
@@ -849,18 +831,13 @@
     }
 
     public void testV21Japanese2_Parsing() throws IOException, VCardException {
-        VCardParser_V21 parser = new VCardParser_V21();
-        VNodeBuilder builder = new VNodeBuilder();
-        InputStream is = getContext().getResources().openRawResource(R.raw.v21_japanese_2);
-        assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
-        is.close();
-        assertEquals(1, builder.vNodeList.size());
         ContentValues contentValuesForShiftJis = new ContentValues();
         contentValuesForShiftJis.put("CHARSET", "SHIFT_JIS");
         ContentValues contentValuesForQPAndSJ = new ContentValues();
         contentValuesForQPAndSJ.put("ENCODING", "QUOTED-PRINTABLE");
         contentValuesForQPAndSJ.put("CHARSET", "SHIFT_JIS");
-        PropertyNodesVerifier verifier = new PropertyNodesVerifier(this)
+        PropertyNodesVerifier verifier = new PropertyNodesVerifier(this);
+        verifier.addPropertyNodesVerifierElem()
                 .addNodeWithOrder("VERSION", "2.1")
                 .addNodeWithOrder("N", "\u5B89\u85E4;\u30ED\u30A4\u30C9\u0031;;;",
                         Arrays.asList("\u5B89\u85E4", "\u30ED\u30A4\u30C9\u0031",
@@ -885,12 +862,12 @@
                         null, contentValuesForQPAndSJ, new TypeSet("HOME"), null)
                 .addNodeWithOrder("NOTE", "\u30E1\u30E2", null, null,
                         contentValuesForQPAndSJ, null, null);
-        verifier.verify(builder.vNodeList.get(0));
+        verifier.verify(R.raw.v21_japanese_2, VCardConfig.VCARD_TYPE_V21_JAPANESE_SJIS);
     }
 
     public void testV21Japanese2_Type_Generic_Utf8() throws IOException, VCardException {
-        ContentValuesVerifier verifier = new ContentValuesVerifier();
-        verifier.buildExpected(StructuredName.CONTENT_ITEM_TYPE)
+        ImportVerifierElem verifier = new ImportVerifierElem();
+        verifier.addExpected(StructuredName.CONTENT_ITEM_TYPE)
                 .put(StructuredName.FAMILY_NAME, "\u5B89\u85E4")
                 .put(StructuredName.GIVEN_NAME, "\u30ED\u30A4\u30C9\u0031")
                 .put(StructuredName.DISPLAY_NAME,
@@ -900,7 +877,7 @@
                 .put(StructuredName.PHONETIC_FAMILY_NAME, "\uFF71\uFF9D\uFF84\uFF9E\uFF73")
                 .put(StructuredName.PHONETIC_GIVEN_NAME, "\uFF9B\uFF72\uFF84\uFF9E\u0031");
 
-        verifier.buildExpected(StructuredPostal.CONTENT_ITEM_TYPE)
+        verifier.addExpected(StructuredPostal.CONTENT_ITEM_TYPE)
                 .put(StructuredPostal.POSTCODE, "150-8512")
                 .put(StructuredPostal.NEIGHBORHOOD,
                         "\u6771\u4EAC\u90FD\u6E0B\u8C37\u533A\u685C" +
@@ -913,21 +890,16 @@
                         "\u30EB\u30EA\u30A2\u30F3\u30BF\u30EF\u30FC" +
                         "\u0036\u968E 150-8512")
                 .put(StructuredPostal.TYPE, StructuredPostal.TYPE_HOME);
-        verifier.buildExpected(Note.CONTENT_ITEM_TYPE)
+        verifier.addExpected(Note.CONTENT_ITEM_TYPE)
                 .put(Note.NOTE, "\u30E1\u30E2");
         verifier.verify(R.raw.v21_japanese_2, VCardConfig.VCARD_TYPE_V21_GENERIC_UTF8);
     }
 
-    public void testV21MultipleEntryCase() throws IOException, VCardException {
-        VCardParser_V21 parser = new VCardParser_V21();
-        VNodeBuilder builder = new VNodeBuilder();
-        InputStream is = getContext().getResources().openRawResource(R.raw.v21_multiple_entry);
-        assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
-        is.close();
-        assertEquals(3, builder.vNodeList.size());
+    public void testV21MultipleEntryCase_Parse() throws IOException, VCardException {
         ContentValues contentValuesForShiftJis = new ContentValues();
         contentValuesForShiftJis.put("CHARSET", "SHIFT_JIS");
-        PropertyNodesVerifier verifier = new PropertyNodesVerifier(this)
+        PropertyNodesVerifier verifier = new PropertyNodesVerifier(this);
+        verifier.addPropertyNodesVerifierElem()
                 .addNodeWithOrder("VERSION", "2.1")
                 .addNodeWithOrder("N", "\u5B89\u85E4\u30ED\u30A4\u30C9\u0033;;;;",
                         Arrays.asList("\u5B89\u85E4\u30ED\u30A4\u30C9\u0033", "", "", "", ""),
@@ -940,9 +912,8 @@
                 .addNodeWithOrder("TEL", "10", new TypeSet("X-NEC-HOTEL"))
                 .addNodeWithOrder("TEL", "11", new TypeSet("X-NEC-SCHOOL"))
                 .addNodeWithOrder("TEL", "12", new TypeSet("FAX", "HOME"));
-        verifier.verify(builder.vNodeList.get(0));
-        
-        verifier = new PropertyNodesVerifier(this)
+
+        verifier.addPropertyNodesVerifierElem()
                 .addNodeWithOrder("VERSION", "2.1")
                 .addNodeWithOrder("N", "\u5B89\u85E4\u30ED\u30A4\u30C9\u0034;;;;",
                         Arrays.asList("\u5B89\u85E4\u30ED\u30A4\u30C9\u0034", "", "", "", ""),
@@ -955,8 +926,8 @@
                 .addNodeWithOrder("TEL", "14", new TypeSet("PAGER"))
                 .addNodeWithOrder("TEL", "15", new TypeSet("X-NEC-FAMILY"))
                 .addNodeWithOrder("TEL", "16", new TypeSet("X-NEC-GIRL"));
-        verifier.verify(builder.vNodeList.get(1));
-        verifier = new PropertyNodesVerifier(this)
+
+        verifier.addPropertyNodesVerifierElem()
                 .addNodeWithOrder("VERSION", "2.1")
                 .addNodeWithOrder("N", "\u5B89\u85E4\u30ED\u30A4\u30C9\u0035;;;;",
                         Arrays.asList("\u5B89\u85E4\u30ED\u30A4\u30C9\u0035", "", "", "", ""),
@@ -969,6 +940,77 @@
                 .addNodeWithOrder("TEL", "18", new TypeSet("X-NEC-FRIEND"))
                 .addNodeWithOrder("TEL", "19", new TypeSet("X-NEC-PHS"))
                 .addNodeWithOrder("TEL", "20", new TypeSet("X-NEC-RESTAURANT"));
-        verifier.verify(builder.vNodeList.get(2));
+        verifier.verify(R.raw.v21_multiple_entry, VCardConfig.VCARD_TYPE_V21_JAPANESE_SJIS);
+    }
+
+    public void testV21MultipleEntryCase() throws IOException, VCardException {
+        ImportVerifier verifier = new ImportVerifier();
+        ImportVerifierElem elem = verifier.addImportVerifierElem();
+        elem.addExpected(StructuredName.CONTENT_ITEM_TYPE)
+                .put(StructuredName.FAMILY_NAME, "\u5B89\u85E4\u30ED\u30A4\u30C9\u0033")
+                .put(StructuredName.DISPLAY_NAME, "\u5B89\u85E4\u30ED\u30A4\u30C9\u0033")
+                .put(StructuredName.PHONETIC_FAMILY_NAME,
+                        "\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E\u0033");
+        elem.addExpected(Phone.CONTENT_ITEM_TYPE)
+                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
+                .put(Phone.LABEL, "NEC-SECRET")
+                .put(Phone.NUMBER, "9");
+        elem.addExpected(Phone.CONTENT_ITEM_TYPE)
+                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
+                .put(Phone.LABEL, "NEC-HOTEL")
+                .put(Phone.NUMBER, "10");
+        elem.addExpected(Phone.CONTENT_ITEM_TYPE)
+                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
+                .put(Phone.LABEL, "NEC-SCHOOL")
+                .put(Phone.NUMBER, "11");
+        elem.addExpected(Phone.CONTENT_ITEM_TYPE)
+                .put(Phone.TYPE, Phone.TYPE_FAX_HOME)
+                .put(Phone.NUMBER, "12");
+
+        elem = verifier.addImportVerifierElem();
+        elem.addExpected(StructuredName.CONTENT_ITEM_TYPE)
+                .put(StructuredName.FAMILY_NAME, "\u5B89\u85E4\u30ED\u30A4\u30C9\u0034")
+                .put(StructuredName.DISPLAY_NAME, "\u5B89\u85E4\u30ED\u30A4\u30C9\u0034")
+                .put(StructuredName.PHONETIC_FAMILY_NAME,
+                        "\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E\u0034");
+        elem.addExpected(Phone.CONTENT_ITEM_TYPE)
+                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
+                .put(Phone.LABEL, "MODEM")
+                .put(Phone.NUMBER, "13");
+        elem.addExpected(Phone.CONTENT_ITEM_TYPE)
+                .put(Phone.TYPE, Phone.TYPE_PAGER)
+                .put(Phone.NUMBER, "14");
+        elem.addExpected(Phone.CONTENT_ITEM_TYPE)
+                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
+                .put(Phone.LABEL, "NEC-FAMILY")
+                .put(Phone.NUMBER, "15");
+        elem.addExpected(Phone.CONTENT_ITEM_TYPE)
+                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
+                .put(Phone.LABEL, "NEC-GIRL")
+                .put(Phone.NUMBER, "16");
+
+        elem = verifier.addImportVerifierElem();
+        elem.addExpected(StructuredName.CONTENT_ITEM_TYPE)
+                .put(StructuredName.FAMILY_NAME, "\u5B89\u85E4\u30ED\u30A4\u30C9\u0035")
+                .put(StructuredName.DISPLAY_NAME, "\u5B89\u85E4\u30ED\u30A4\u30C9\u0035")
+                .put(StructuredName.PHONETIC_FAMILY_NAME,
+                        "\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E\u0035");
+        elem.addExpected(Phone.CONTENT_ITEM_TYPE)
+                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
+                .put(Phone.LABEL, "NEC-BOY")
+                .put(Phone.NUMBER, "17");
+        elem.addExpected(Phone.CONTENT_ITEM_TYPE)
+                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
+                .put(Phone.LABEL, "NEC-FRIEND")
+                .put(Phone.NUMBER, "18");
+        elem.addExpected(Phone.CONTENT_ITEM_TYPE)
+                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
+                .put(Phone.LABEL, "NEC-PHS")
+                .put(Phone.NUMBER, "19");
+        elem.addExpected(Phone.CONTENT_ITEM_TYPE)
+                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
+                .put(Phone.LABEL, "NEC-RESTAURANT")
+                .put(Phone.NUMBER, "20");
+        verifier.verify(R.raw.v21_multiple_entry, VCardConfig.VCARD_TYPE_V21_JAPANESE_SJIS);
     }
 }
diff --git a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardTestsBase.java b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardTestsBase.java
index 08d1722..9ec6e05 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardTestsBase.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardTestsBase.java
@@ -33,7 +33,11 @@
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
+import android.pim.vcard.ContactStruct;
 import android.pim.vcard.EntryCommitter;
+import android.pim.vcard.EntryHandler;
+import android.pim.vcard.VCardBuilder;
+import android.pim.vcard.VCardBuilderCollection;
 import android.pim.vcard.VCardComposer;
 import android.pim.vcard.VCardConfig;
 import android.pim.vcard.VCardDataBuilder;
@@ -62,6 +66,7 @@
 import android.test.mock.MockContext;
 import android.test.mock.MockCursor;
 import android.text.TextUtils;
+import android.util.Log;
 
 import junit.framework.TestCase;
 
@@ -177,24 +182,24 @@
  * Please do not add each unit test here.
  */
 /* package */ class VCardTestsBase extends AndroidTestCase {
-    public static final int V21 = 0;
-    public static final int V30 = 1;
+    public static final int V21 = VCardConfig.VCARD_TYPE_V21_GENERIC_UTF8;
+    public static final int V30 = VCardConfig.VCARD_TYPE_V30_GENERIC_UTF8;
 
-    public class ImportVerificationResolver extends MockContentResolver {
-        ImportVerificationProvider mVerificationProvider = new ImportVerificationProvider();
+    public class ImportTestResolver extends MockContentResolver {
+        ImportTestProvider mProvider = new ImportTestProvider();
         @Override
         public ContentProviderResult[] applyBatch(String authority,
                 ArrayList<ContentProviderOperation> operations) {
             equalsString(authority, RawContacts.CONTENT_URI.toString());
-            return mVerificationProvider.applyBatch(operations);
+            return mProvider.applyBatch(operations);
         }
 
         public void addExpectedContentValues(ContentValues expectedContentValues) {
-            mVerificationProvider.addExpectedContentValues(expectedContentValues);
+            mProvider.addExpectedContentValues(expectedContentValues);
         }
 
         public void verify() {
-            mVerificationProvider.verify();
+            mProvider.verify();
         }
     }
 
@@ -208,10 +213,10 @@
                 Relation.CONTENT_ITEM_TYPE, Event.CONTENT_ITEM_TYPE,
                 GroupMembership.CONTENT_ITEM_TYPE));
 
-    public class ImportVerificationProvider extends MockContentProvider {
+    public class ImportTestProvider extends MockContentProvider {
         final Map<String, Collection<ContentValues>> mMimeTypeToExpectedContentValues;
 
-        public ImportVerificationProvider() {
+        public ImportTestProvider() {
             mMimeTypeToExpectedContentValues =
                 new HashMap<String, Collection<ContentValues>>();
             for (String acceptanbleMimeType : sKnownMimeTypeSet) {
@@ -303,11 +308,11 @@
                     }
                     boolean checked = false;
                     for (ContentValues expectedContentValues : contentValuesCollection) {
-                        /* for testing
+                        /*for testing
                         Log.d("@@@", "expected: "
                                 + convertToEasilyReadableString(expectedContentValues));
                         Log.d("@@@", "actual  : "
-                                + convertToEasilyReadableString(actualContentValues)); */
+                                + convertToEasilyReadableString(actualContentValues));*/
                         if (equalsForContentValues(expectedContentValues,
                                 actualContentValues)) {
                             assertTrue(contentValuesCollection.remove(expectedContentValues));
@@ -346,15 +351,16 @@
         }
     }
 
-    public class ContentValuesVerifier {
-        private final ImportVerificationResolver mResolver;
-        // private final String mCharset;
+    class ImportVerifierElem {
+        private final ImportTestResolver mResolver;
+        private final EntryHandler mHandler;
 
-        public ContentValuesVerifier() {
-            mResolver = new ImportVerificationResolver();
+        public ImportVerifierElem() {
+            mResolver = new ImportTestResolver();
+            mHandler = new EntryCommitter(mResolver);
         }
 
-        public ContentValuesBuilder buildExpected(String mimeType) {
+        public ContentValuesBuilder addExpected(String mimeType) {
             ContentValues contentValues = new ContentValues();
             contentValues.put(Data.MIMETYPE, mimeType);
             mResolver.addExpectedContentValues(contentValues);
@@ -366,8 +372,7 @@
             verify(getContext().getResources().openRawResource(resId), vCardType);
         }
 
-        public void verify(InputStream is, int vCardType)
-                throws IOException, VCardException {
+        public void verify(InputStream is, int vCardType) throws IOException, VCardException {
             final VCardParser vCardParser;
             if (VCardConfig.isV30(vCardType)) {
                 vCardParser = new VCardParser_V30(true);  // use StrictParsing
@@ -375,8 +380,8 @@
                 vCardParser = new VCardParser_V21();
             }
             VCardDataBuilder builder =
-                new VCardDataBuilder(null, null, false, vCardType, null);
-            builder.addEntryHandler(new EntryCommitter(mResolver));
+                    new VCardDataBuilder(null, null, false, vCardType, null);
+            builder.addEntryHandler(mHandler);
             try {
                 vCardParser.parse(is, builder);
             } finally {
@@ -387,8 +392,81 @@
                     }
                 }
             }
+            verifyResolver();
+        }
+
+        public void verifyResolver() {
             mResolver.verify();
         }
+
+        public void onParsingStart() {
+            mHandler.onParsingStart();
+        }
+
+        public void onEntryCreated(ContactStruct entry) {
+            mHandler.onEntryCreated(entry);
+        }
+
+        public void onParsingEnd() {
+            mHandler.onParsingEnd();
+        }
+    }
+
+    class ImportVerifier implements EntryHandler {
+        private List<ImportVerifierElem> mImportVerifierElemList =
+            new ArrayList<ImportVerifierElem>();
+        private int mIndex;
+
+        public ImportVerifierElem addImportVerifierElem() {
+            ImportVerifierElem importVerifier = new ImportVerifierElem();
+            mImportVerifierElemList.add(importVerifier);
+            return importVerifier;
+        }
+
+        public void verify(int resId, int vCardType) throws IOException, VCardException {
+            verify(getContext().getResources().openRawResource(resId), vCardType);
+        }
+
+        public void verify(InputStream is, int vCardType) throws IOException, VCardException {
+            final VCardParser vCardParser;
+            if (VCardConfig.isV30(vCardType)) {
+                vCardParser = new VCardParser_V30(true);  // use StrictParsing
+            } else {
+                vCardParser = new VCardParser_V21();
+            }
+            VCardDataBuilder builder =
+                new VCardDataBuilder(null, null, false, vCardType, null);
+            builder.addEntryHandler(this);
+            try {
+                vCardParser.parse(is, builder);
+            } finally {
+                if (is != null) {
+                    try {
+                        is.close();
+                    } catch (IOException e) {
+                    }
+                }
+            }
+        }
+
+        public void onParsingStart() {
+            for (ImportVerifierElem elem : mImportVerifierElemList) {
+                elem.onParsingStart();
+            }
+        }
+
+        public void onEntryCreated(ContactStruct entry) {
+            assertTrue(mIndex < mImportVerifierElemList.size());
+            mImportVerifierElemList.get(mIndex).onEntryCreated(entry);
+            mIndex++;
+        }
+
+        public void onParsingEnd() {
+            for (ImportVerifierElem elem : mImportVerifierElemList) {
+                elem.onParsingEnd();
+                elem.verifyResolver();
+            }
+        }
     }
 
     public class ExportTestResolver extends MockContentResolver {
@@ -398,24 +476,23 @@
             addProvider(RawContacts.CONTENT_URI.getAuthority(), mProvider);
         }
 
-        public ContentValuesBuilder buildInput(String mimeType) {
-            return mProvider.buildData(mimeType);
+        public ContactEntry buildContactEntry() {
+            return mProvider.buildInputEntry();
         }
     }
 
     public static class MockEntityIterator implements EntityIterator {
-        Collection<Entity> mEntityCollection;
+        List<Entity> mEntityList;
         Iterator<Entity> mIterator;
 
-        // TODO: Support multiple vCard entries.
-        public MockEntityIterator(Collection<ContentValues> contentValuesCollection) {
-            mEntityCollection = new ArrayList<Entity>();
+        public MockEntityIterator(List<ContentValues> contentValuesList) {
+            mEntityList = new ArrayList<Entity>();
             Entity entity = new Entity(new ContentValues());
-            for (ContentValues contentValues : contentValuesCollection) {
-                entity.addSubValue(Data.CONTENT_URI, contentValues);
+            for (ContentValues contentValues : contentValuesList) {
+                    entity.addSubValue(Data.CONTENT_URI, contentValues);
             }
-            mEntityCollection.add(entity);
-            mIterator = mEntityCollection.iterator();
+            mEntityList.add(entity);
+            mIterator = mEntityList.iterator();
         }
 
         public boolean hasNext() {
@@ -427,15 +504,20 @@
         }
 
         public void reset() {
-            mIterator = mEntityCollection.iterator();
+            mIterator = mEntityList.iterator();
         }
 
         public void close() {
         }
     }
 
-    public class ExportTestProvider extends MockContentProvider {
-        List<ContentValues> mContentValuesList = new ArrayList<ContentValues>();
+    /**
+     * Represents one contact, which should contain multiple ContentValues like
+     * StructuredName, Email, etc.
+     */
+    static class ContactEntry {
+        private final List<ContentValues> mContentValuesList = new ArrayList<ContentValues>();
+
         public ContentValuesBuilder buildData(String mimeType) {
             ContentValues contentValues = new ContentValues();
             contentValues.put(Data.MIMETYPE, mimeType);
@@ -443,28 +525,50 @@
             return new ContentValuesBuilder(contentValues);
         }
 
-        @Override
-        public EntityIterator queryEntities(Uri uri, String selection, String[] selectionArgs,
-                String sortOrder) {
-            assert(uri != null);
-            assert(ContentResolver.SCHEME_CONTENT.equals(uri.getScheme()));
-            final String authority = uri.getAuthority();
-            assert(RawContacts.CONTENT_URI.getAuthority().equals(authority));
+        public List<ContentValues> getList() {
+            return mContentValuesList;
+        }
+    }
 
-            return new MockEntityIterator(mContentValuesList);
+    class ExportTestProvider extends MockContentProvider {
+        ArrayList<ContactEntry> mContactEntryList = new ArrayList<ContactEntry>();
+
+        public ContactEntry buildInputEntry() {
+            ContactEntry contactEntry = new ContactEntry();
+            mContactEntryList.add(contactEntry);
+            return contactEntry;
         }
 
         @Override
-        public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+        public EntityIterator queryEntities(Uri uri, String selection, String[] selectionArgs,
                 String sortOrder) {
-            assert(VCardComposer.CONTACTS_TEST_CONTENT_URI.equals(uri));
-            // Support multiple rows.
+            assertTrue(uri != null);
+            assertTrue(ContentResolver.SCHEME_CONTENT.equals(uri.getScheme()));
+            final String authority = uri.getAuthority();
+            assertTrue(RawContacts.CONTENT_URI.getAuthority().equals(authority));
+            assertTrue((Data.CONTACT_ID + "=?").equals(selection));
+            assertEquals(1, selectionArgs.length);
+            int id = Integer.parseInt(selectionArgs[0]);
+            assertTrue(id >= 0 && id < mContactEntryList.size());
+
+            return new MockEntityIterator(mContactEntryList.get(id).getList());
+        }
+
+        @Override
+        public Cursor query(Uri uri, String[] projection,
+                String selection, String[] selectionArgs, String sortOrder) {
+            assertTrue(VCardComposer.CONTACTS_TEST_CONTENT_URI.equals(uri));
+            // In this test, following arguments are not supported.
+            assertNull(selection);
+            assertNull(selectionArgs);
+            assertNull(sortOrder);
+
             return new MockCursor() {
                 int mCurrentPosition = -1;
 
                 @Override
                 public int getCount() {
-                    return 1;
+                    return mContactEntryList.size();
                 }
 
                 @Override
@@ -475,7 +579,7 @@
 
                 @Override
                 public boolean moveToNext() {
-                    if (mCurrentPosition == 0 || mCurrentPosition == -1) {
+                    if (mCurrentPosition < mContactEntryList.size()) {
                         mCurrentPosition++;
                         return true;
                     } else {
@@ -490,7 +594,7 @@
 
                 @Override
                 public boolean isAfterLast() {
-                    return mCurrentPosition > 0;
+                    return mCurrentPosition >= mContactEntryList.size();
                 }
 
                 @Override
@@ -502,7 +606,9 @@
                 @Override
                 public int getInt(int columnIndex) {
                     assertEquals(0, columnIndex);
-                    return 0;
+                    assertTrue(mCurrentPosition >= 0
+                            && mCurrentPosition < mContactEntryList.size());
+                    return mCurrentPosition;
                 }
 
                 @Override
@@ -517,130 +623,252 @@
         }
     }
 
-    public class VCardVerificationHandler implements VCardComposer.OneEntryHandler {
-        final private TestCase mTestCase;
-        final private List<PropertyNodesVerifier> mPropertyNodesVerifierList;
-        final private boolean mIsV30;
-        // To allow duplication, use list instead of set.
-        // TODO: support multiple vCard entries.
-        final private List<String> mExpectedLineList;
-        final private List<ContentValuesVerifier> mContentValuesVerifierList;
-        final private int mVCardType;
-        int mCount;
+    class LineVerifierElem {
+        private final List<String> mExpectedLineList = new ArrayList<String>();
+        private final boolean mIsV30;
 
-        public VCardVerificationHandler(final TestCase testCase, final int version) {
-            mTestCase = testCase;
-            mPropertyNodesVerifierList = new ArrayList<PropertyNodesVerifier>();
-            mIsV30 = (version == V30);
-            mExpectedLineList = new ArrayList<String>();
-            mContentValuesVerifierList = new ArrayList<ContentValuesVerifier>();
-            mVCardType = (version == V30 ? VCardConfig.VCARD_TYPE_V30_GENERIC_UTF8
-                    : VCardConfig.VCARD_TYPE_V21_GENERIC_UTF8);
-            mCount = 1;
+        public LineVerifierElem(boolean isV30) {
+            mIsV30 = isV30;
         }
 
-        public PropertyNodesVerifier addPropertyNodesVerifier() {
-            PropertyNodesVerifier verifier = new PropertyNodesVerifier(mTestCase);
-            mPropertyNodesVerifierList.add(verifier);
-            verifier.addNodeWithOrder("VERSION", mIsV30 ? "3.0" : "2.1");
-            return verifier;
-        }
-
-        public PropertyNodesVerifier addPropertyVerifierWithEmptyName() {
-            PropertyNodesVerifier verifier = addPropertyNodesVerifier();
-            if (mIsV30) {
-                verifier.addNodeWithOrder("N", "").addNodeWithOrder("FN", "");
+        public LineVerifierElem addExpected(final String line) {
+            if (!TextUtils.isEmpty(line)) {
+                mExpectedLineList.add(line);
             }
-            return verifier;
-        }
-
-        public ContentValuesVerifier addContentValuesVerifier() {
-            ContentValuesVerifier verifier = new ContentValuesVerifier();
-            mContentValuesVerifierList.add(verifier);
-            return verifier;
-        }
-
-        public VCardVerificationHandler addExpectedLine(String line) {
-            mExpectedLineList.add(line);
             return this;
         }
 
-        public boolean onInit(final Context context) {
-            return true;
-        }
-
-        public boolean onEntryCreated(final String vcard) {
-            if (!mExpectedLineList.isEmpty()) {
-                verifyLines(vcard);
-            }
-            verifyNodes(vcard);
-            return true;
-        }
-
-        private void verifyLines(final String vcard) {
+        public void verify(final String vcard) {
             final String[] lineArray = vcard.split("\\r?\\n");
             final int length = lineArray.length;
+            final TestCase testCase = VCardTestsBase.this;
+            boolean beginExists = false;
+            boolean endExists = false;
+            boolean versionExists = false;
+
             for (int i = 0; i < length; i++) {
                 final String line = lineArray[i];
-                // TODO: support multiple vcard entries.
-                if ("BEGIN:VCARD".equals(line) || "END:VCARD".equals(line) ||
-                        (mIsV30 ? "VERSION:3.0" : "VERSION:2.1").equals(line)) {
+                if (TextUtils.isEmpty(line)) {
                     continue;
                 }
+
+                if ("BEGIN:VCARD".equalsIgnoreCase(line)) {
+                    if (beginExists) {
+                        testCase.fail("Multiple \"BEGIN:VCARD\" line found");
+                    } else {
+                        beginExists = true;
+                        continue;
+                    }
+                } else if ("END:VCARD".equalsIgnoreCase(line)) {
+                    if (endExists) {
+                        testCase.fail("Multiple \"END:VCARD\" line found");
+                    } else {
+                        endExists = true;
+                        continue;
+                    }
+                } else if (
+                        (mIsV30 ? "VERSION:3.0" : "VERSION:2.1").equalsIgnoreCase(line)) {
+                    if (versionExists) {
+                        testCase.fail("Multiple VERSION line + found");
+                    } else {
+                        versionExists = true;
+                        continue;
+                    }
+                }
+
+                if (!beginExists) {
+                    testCase.fail(
+                            "Property other than BEGIN came before BEGIN property: " + line);
+                } else if (endExists) {
+                    testCase.fail("Property other than END came after END property: " + line);
+                }
+
                 final int index = mExpectedLineList.indexOf(line);
                 if (index >= 0) {
                     mExpectedLineList.remove(index);
                 } else {
-                    mTestCase.fail("Unexpected line: " + line);
+                    testCase.fail("Unexpected line: " + line);
                 }
             }
+
             if (!mExpectedLineList.isEmpty()) {
                 StringBuffer buffer = new StringBuffer();
                 for (String expectedLine : mExpectedLineList) {
                     buffer.append(expectedLine);
                     buffer.append("\n");
                 }
-                mTestCase.fail("Expected line(s) not found:" + buffer.toString());
+
+                testCase.fail("Expected line(s) not found:" + buffer.toString());
             }
         }
+    }
 
-        private void verifyNodes(final String vcard) {
-            if (mPropertyNodesVerifierList.size() == 0) {
-                mTestCase.fail("Too many vCard entries seems to be inserted(No."
-                        + mCount + " of the entries (No.1 is the first entry))");
+    class LineVerifier implements VCardComposer.OneEntryHandler {
+        private final ArrayList<LineVerifierElem> mLineVerifierElemList;
+        private final boolean mIsV30;
+        private int index;
+
+        public LineVerifier(final boolean isV30) {
+            mLineVerifierElemList = new ArrayList<LineVerifierElem>();
+            mIsV30 = isV30;
+        }
+
+        public LineVerifierElem addLineVerifierElem() {
+            LineVerifierElem lineVerifier = new LineVerifierElem(mIsV30);
+            mLineVerifierElemList.add(lineVerifier);
+            return lineVerifier;
+        }
+
+        public void verify(String vcard) {
+            if (index >= mLineVerifierElemList.size()) {
+                VCardTestsBase.this.fail("Insufficient number of LineVerifier (" + index + ")");
             }
-            PropertyNodesVerifier propertyNodesVerifier =
-                    mPropertyNodesVerifierList.get(0);
-            mPropertyNodesVerifierList.remove(0);
-            VCardParser parser = (mIsV30 ? new VCardParser_V30(true) : new VCardParser_V21());
-            VNodeBuilder builder = new VNodeBuilder();
-            InputStream is;
-            try {
-                is = new ByteArrayInputStream(vcard.getBytes("UTF-8"));
-                mTestCase.assertEquals(true, parser.parse(is, null, builder));
-                is.close();
-                mTestCase.assertEquals(1, builder.vNodeList.size());
-                propertyNodesVerifier.verify(builder.vNodeList.get(0));
-                if (!mContentValuesVerifierList.isEmpty()) {
-                    ContentValuesVerifier contentValuesVerifier =
-                            mContentValuesVerifierList.get(0);
-                    is = new ByteArrayInputStream(vcard.getBytes("UTF-8"));
-                    contentValuesVerifier.verify(is, mVCardType);
-                    is.close();
-                }
-            } catch (IOException e) {
-                mTestCase.fail("Unexpected IOException: " + e.getMessage());
-            } catch (VCardException e) {
-                mTestCase.fail("Unexpected VCardException: " + e.getMessage());
-            } finally {
-                mCount++;
-            }
+
+            LineVerifierElem lineVerifier = mLineVerifierElemList.get(index);
+            lineVerifier.verify(vcard);
+
+            index++;
+        }
+
+        public boolean onEntryCreated(String vcard) {
+            verify(vcard);
+            return true;
+        }
+
+        public boolean onInit(Context context) {
+            return true;
         }
 
         public void onTerminate() {
         }
     }
 
+    class VCardVerifier {
+        private class VCardVerifierInternal implements VCardComposer.OneEntryHandler {
+            public boolean onInit(Context context) {
+                return true;
+            }
+            public boolean onEntryCreated(String vcard) {
+                verifyOneVCard(vcard);
+                return true;
+            }
+            public void onTerminate() {
+            }
+        }
+
+        private final VCardVerifierInternal mVCardVerifierInternal;
+        private final ExportTestResolver mResolver;
+        private final int mVCardType;
+        private final boolean mIsV30;
+
+        // To allow duplication, use list instead of set.
+        // When null, we don't need to do the verification.
+        private PropertyNodesVerifier mPropertyNodesVerifier;
+        private LineVerifier mLineVerificationHandler;
+        private ImportVerifier mImportVerifier;
+
+        public VCardVerifier(ExportTestResolver resolver, int vcardType) {
+            mVCardVerifierInternal = new VCardVerifierInternal();
+            mResolver = resolver;
+            mIsV30 = VCardConfig.isV30(vcardType);
+            mVCardType = vcardType;
+        }
+
+        public PropertyNodesVerifierElem addPropertyNodesVerifierElem() {
+            if (mPropertyNodesVerifier == null) {
+                mPropertyNodesVerifier = new PropertyNodesVerifier(VCardTestsBase.this);
+            }
+            PropertyNodesVerifierElem elem =
+                    mPropertyNodesVerifier.addPropertyNodesVerifierElem();
+            elem.addNodeWithOrder("VERSION", (mIsV30 ? "3.0" : "2.1"));
+
+            return elem;
+        }
+
+        public PropertyNodesVerifierElem addPropertyNodesVerifierWithEmptyName() {
+            PropertyNodesVerifierElem elem = addPropertyNodesVerifierElem();
+            if (mIsV30) {
+                elem.addNodeWithOrder("N", "").addNodeWithOrder("FN", "");
+            }
+            return elem;
+        }
+
+        public LineVerifierElem addLineVerifier() {
+            if (mLineVerificationHandler == null) {
+                mLineVerificationHandler = new LineVerifier(mIsV30);
+            }
+            return mLineVerificationHandler.addLineVerifierElem();
+        }
+
+        public ImportVerifierElem addImportVerifier() {
+            if (mImportVerifier == null) {
+                mImportVerifier = new ImportVerifier();
+            }
+
+            return mImportVerifier.addImportVerifierElem();
+        }
+
+        private void verifyOneVCard(final String vcard) {
+            final VCardBuilder builder;
+            if (mImportVerifier != null) {
+                final VNodeBuilder vnodeBuilder = mPropertyNodesVerifier;
+                final VCardDataBuilder vcardDataBuilder = new VCardDataBuilder();
+                vcardDataBuilder.addEntryHandler(mImportVerifier);
+                if (mPropertyNodesVerifier != null) {
+                    builder = new VCardBuilderCollection(Arrays.asList(
+                            vcardDataBuilder, mPropertyNodesVerifier));
+                } else {
+                    builder = vnodeBuilder;
+                }
+            } else {
+                if (mPropertyNodesVerifier != null) {
+                    builder = mPropertyNodesVerifier;
+                } else {
+                    return;
+                }
+            }
+
+            final VCardParser parser =
+                    (mIsV30 ? new VCardParser_V30(true) : new VCardParser_V21());
+            final TestCase testCase = VCardTestsBase.this;
+
+            InputStream is = null;
+            try {
+                is = new ByteArrayInputStream(vcard.getBytes("UTF-8"));
+                testCase.assertEquals(true, parser.parse(is, null, builder));
+            } catch (IOException e) {
+                testCase.fail("Unexpected IOException: " + e.getMessage());
+            } catch (VCardException e) {
+                testCase.fail("Unexpected VCardException: " + e.getMessage());
+            } finally {
+                if (is != null) {
+                    try {
+                        is.close();
+                    } catch (IOException e) {
+                    }
+                }
+            }
+        }
+
+        public void verify() {
+            VCardComposer composer =
+                    new VCardComposer(new CustomMockContext(mResolver), mVCardType);
+            composer.addHandler(mLineVerificationHandler);
+            composer.addHandler(mVCardVerifierInternal);
+            if (!composer.init(VCardComposer.CONTACTS_TEST_CONTENT_URI, null, null, null)) {
+                fail("init() failed. Reason: " + composer.getErrorReason());
+            }
+            assertFalse(composer.isAfterLast());
+            try {
+                while (!composer.isAfterLast()) {
+                    assertTrue(composer.createOneEntry());
+                }
+            } finally {
+                composer.terminate();
+            }
+        }
+    }
+
     /**
      * Utility method to print ContentValues whose content is printed with sorted keys.
      */
@@ -683,6 +911,7 @@
         } else if (expected == null || actual == null || expected.size() != actual.size()) {
             return false;
         }
+
         for (Entry<String, Object> entry : expected.valueSet()) {
             final String key = entry.getKey();
             final Object value = entry.getValue();