Fix foundation classes for vCard importer/exporter.

A lot of tests are not actually tested =(

Change-Id: Iea873573e8aced9660be9bf8d7900d85c9c68380
diff --git a/java/com/android/vcard/VCardInterpreterCollection.java b/java/com/android/vcard/VCardInterpreterCollection.java
index 4a40d93..adf577e 100644
--- a/java/com/android/vcard/VCardInterpreterCollection.java
+++ b/java/com/android/vcard/VCardInterpreterCollection.java
@@ -25,7 +25,7 @@
  */
 public final class VCardInterpreterCollection implements VCardInterpreter {
     private final Collection<VCardInterpreter> mInterpreterCollection;
-    
+
     public VCardInterpreterCollection(Collection<VCardInterpreter> interpreterCollection) {
         mInterpreterCollection = interpreterCollection;
     }
diff --git a/java/com/android/vcard/VCardParserImpl_V30.java b/java/com/android/vcard/VCardParserImpl_V30.java
index 9e5cde2..9fefe89 100644
--- a/java/com/android/vcard/VCardParserImpl_V30.java
+++ b/java/com/android/vcard/VCardParserImpl_V30.java
@@ -194,17 +194,79 @@
      *  param-name    = iana-token / x-name
      *  param-value   = ptext / quoted-string
      *  quoted-string = DQUOTE QSAFE-CHAR DQUOTE
+     *  QSAFE-CHAR    = WSP / %x21 / %x23-7E / NON-ASCII
+     *                ; Any character except CTLs, DQUOTE
+     *
+     *  QSAFE-CHAR must not contain DQUOTE, including escaped one (\").
      */
     @Override
-    protected void handleType(final String ptypevalues) {
-        String[] ptypeArray = ptypevalues.split(",");
-        mInterpreter.propertyParamType("TYPE");
-        for (String value : ptypeArray) {
-            int length = value.length();
-            if (length >= 2 && value.startsWith("\"") && value.endsWith("\"")) {
-                mInterpreter.propertyParamValue(value.substring(1, value.length() - 1));
-            } else {
-                mInterpreter.propertyParamValue(value);
+    protected void handleType(final String paramvalues) {
+        if (mInterpreter != null) {
+            mInterpreter.propertyParamType("TYPE");
+
+            // "comma,separated:inside.dquote",pref
+            //   -->
+            // - comma,separated:inside.dquote
+            // - pref
+            //
+            // Note: Though there's a code, we don't need to take much care of
+            // wrongly-added quotes like the example above, as they induce
+            // parse errors at the top level (when splitting a line into parts).
+            StringBuilder builder = null;  // Delay initialization.
+            boolean insideDquote = false;
+            final int length = paramvalues.length();
+            for (int i = 0; i < length; i = paramvalues.offsetByCodePoints(i, 1)) {
+                final int codePoint = paramvalues.codePointAt(i);
+                if (codePoint == '"') {
+                    if (insideDquote) {
+                        // End of Dquote.
+                        mInterpreter.propertyParamValue(builder.toString());
+                        builder = null;
+                        insideDquote = false;
+                    } else {
+                        if (builder != null) {
+                            if (builder.length() > 0) {
+                                // e.g.
+                                // pref"quoted"
+                                Log.w(LOG_TAG, "Unexpected Dquote inside property.");
+                            } else {
+                                // e.g.
+                                // pref,"quoted"
+                                // "quoted",pref
+                                mInterpreter.propertyParamValue(builder.toString());
+                            }
+                        }
+                        insideDquote = true;
+                    }
+                } else if (codePoint == ',' && !insideDquote) {
+                    if (builder == null) {
+                        Log.w(LOG_TAG, "Comma is used before actual string comes. (" +
+                                paramvalues + ")");
+                    } else {
+                        mInterpreter.propertyParamValue(builder.toString());
+                        builder = null;
+                    }
+                } else {
+                    // To stop creating empty StringBuffer at the end of parameter,
+                    // we delay creating this object until this point.
+                    if (builder == null) {
+                        builder = new StringBuilder();
+                    }
+                    builder.appendCodePoint(codePoint);
+                }
+            }
+            if (insideDquote) {
+                // e.g.
+                // "non-quote-at-end
+                Log.d(LOG_TAG, "Dangling Dquote.");
+            }
+            if (builder != null) {
+                if (builder.length() == 0) {
+                    Log.w(LOG_TAG, "Unintended behavior. We must not see empty StringBuilder " +
+                            "at the end of parameter value parsing.");
+                } else {
+                    mInterpreter.propertyParamValue(builder.toString());
+                }
             }
         }
     }
diff --git a/tests/res/raw/v30_comma_separated.vcf b/tests/res/raw/v30_comma_separated.vcf
index bd4c889..f1baf88 100644
--- a/tests/res/raw/v30_comma_separated.vcf
+++ b/tests/res/raw/v30_comma_separated.vcf
@@ -1,5 +1,5 @@
 BEGIN:VCARD

 VERSION:3.0

 N;TYPE=PREF,HOME:F;G;M;;

-TEL;TYPE="COMMA,SEPARATED",PREF:1

+TEL;TYPE="COMMA,SEPARATED:INSIDE.DQUOTE",PREF:1

 END:VCARD

diff --git a/tests/src/com/android/vcard/tests/VCardImporterTests.java b/tests/src/com/android/vcard/tests/VCardImporterTests.java
index 0cddf7b..fcff4fc 100644
--- a/tests/src/com/android/vcard/tests/VCardImporterTests.java
+++ b/tests/src/com/android/vcard/tests/VCardImporterTests.java
@@ -408,7 +408,7 @@
 
     public void testV21SimpleCase1_Parsing() {
         mVerifier.initForImportTest(V21, R.raw.v21_simple_1);
-        mVerifier.addPropertyNodesVerifierElem()
+        mVerifier.addPropertyNodesVerifierElemWithoutVersion()  // no "VERSION:2.1" line.
                 .addExpectedNodeWithOrder("N", "Ando;Roid;", Arrays.asList("Ando", "Roid", ""));
     }
 
@@ -457,7 +457,6 @@
     public void testV21BackslashCase_Parsing() {
         mVerifier.initForImportTest(V21, R.raw.v21_backslash);
         mVerifier.addPropertyNodesVerifierElem()
-                .addExpectedNodeWithOrder("VERSION", "2.1")
                 .addExpectedNodeWithOrder("N", ";A;B\\;C\\;;D;:E;\\\\;",
                         Arrays.asList("", "A;B\\", "C\\;", "D", ":E", "\\\\", ""))
                 .addExpectedNodeWithOrder("FN", "A;B\\C\\;D:E\\\\");
@@ -552,7 +551,6 @@
     public void testV21ComplicatedCase_Parsing() {
         mVerifier.initForImportTest(V21, R.raw.v21_complicated);
         mVerifier.addPropertyNodesVerifierElem()
-                .addExpectedNodeWithOrder("VERSION", "2.1")
                 .addExpectedNodeWithOrder("N", "Gump;Forrest;Hoge;Pos;Tao",
                         Arrays.asList("Gump", "Forrest", "Hoge", "Pos", "Tao"))
                 .addExpectedNodeWithOrder("FN", "Joe Due")
@@ -697,7 +695,6 @@
     public void testV30Simple_Parsing() {
         mVerifier.initForImportTest(V30, R.raw.v30_simple);
         mVerifier.addPropertyNodesVerifierElem()
-                .addExpectedNodeWithOrder("VERSION", "3.0")
                 .addExpectedNodeWithOrder("FN", "And Roid")
                 .addExpectedNodeWithOrder("N", "And;Roid;;;",
                         Arrays.asList("And", "Roid", "", "", ""))
@@ -737,7 +734,6 @@
         // Do not need to handle it as multiple values.
         mVerifier.initForImportTest(VCardConfig.VCARD_TYPE_V21_JAPANESE, R.raw.v21_japanese_1);
         mVerifier.addPropertyNodesVerifierElem()
-                .addExpectedNodeWithOrder("VERSION", "2.1", null, null, null, null, null)
                 .addExpectedNodeWithOrder("N", "\u5B89\u85E4\u30ED\u30A4\u30C9;;;;",
                         Arrays.asList("\u5B89\u85E4\u30ED\u30A4\u30C9", "", "", "", ""),
                         null, mContentValuesForSJis, null, null)
@@ -798,7 +794,6 @@
     public void testV21Japanese2_Parsing() {
         mVerifier.initForImportTest(VCardConfig.VCARD_TYPE_V21_JAPANESE, R.raw.v21_japanese_2);
         mVerifier.addPropertyNodesVerifierElem()
-                .addExpectedNodeWithOrder("VERSION", "2.1")
                 .addExpectedNodeWithOrder("N", "\u5B89\u85E4;\u30ED\u30A4\u30C9\u0031;;;",
                         Arrays.asList("\u5B89\u85E4", "\u30ED\u30A4\u30C9\u0031",
                                 "", "", ""),
@@ -856,7 +851,6 @@
     public void testV21MultipleEntryCase_Parse() {
         mVerifier.initForImportTest(VCardConfig.VCARD_TYPE_V21_JAPANESE, R.raw.v21_multiple_entry);
         mVerifier.addPropertyNodesVerifierElem()
-                .addExpectedNodeWithOrder("VERSION", "2.1")
                 .addExpectedNodeWithOrder("N", "\u5B89\u85E4\u30ED\u30A4\u30C9\u0033;;;;",
                         Arrays.asList("\u5B89\u85E4\u30ED\u30A4\u30C9\u0033", "", "", "", ""),
                         null, mContentValuesForSJis, null, null)
@@ -869,7 +863,6 @@
                 .addExpectedNodeWithOrder("TEL", "11", new TypeSet("X-NEC-SCHOOL"))
                 .addExpectedNodeWithOrder("TEL", "12", new TypeSet("FAX", "HOME"));
         mVerifier.addPropertyNodesVerifierElem()
-                .addExpectedNodeWithOrder("VERSION", "2.1")
                 .addExpectedNodeWithOrder("N", "\u5B89\u85E4\u30ED\u30A4\u30C9\u0034;;;;",
                         Arrays.asList("\u5B89\u85E4\u30ED\u30A4\u30C9\u0034", "", "", "", ""),
                         null, mContentValuesForSJis, null, null)
@@ -882,7 +875,6 @@
                 .addExpectedNodeWithOrder("TEL", "15", new TypeSet("X-NEC-FAMILY"))
                 .addExpectedNodeWithOrder("TEL", "16", new TypeSet("X-NEC-GIRL"));
         mVerifier.addPropertyNodesVerifierElem()
-                .addExpectedNodeWithOrder("VERSION", "2.1")
                 .addExpectedNodeWithOrder("N", "\u5B89\u85E4\u30ED\u30A4\u30C9\u0035;;;;",
                         Arrays.asList("\u5B89\u85E4\u30ED\u30A4\u30C9\u0035", "", "", "", ""),
                         null, mContentValuesForSJis, null, null)
@@ -971,7 +963,6 @@
         ContentValues contentValuesForValue = new ContentValues();
         contentValuesForValue.put("VALUE", "DATE");
         mVerifier.addPropertyNodesVerifierElem()
-                .addExpectedNodeWithOrder("VERSION", "2.1")
                 .addExpectedNodeWithOrder("N", Arrays.asList("Example", "", "", "", ""))
                 .addExpectedNodeWithOrder("FN", "Example")
                 .addExpectedNodeWithOrder("ANNIVERSARY", "20091010", contentValuesForValue)
@@ -1007,7 +998,6 @@
     public void testPagerV30_Parse() {
         mVerifier.initForImportTest(V30, R.raw.v30_pager);
         mVerifier.addPropertyNodesVerifierElem()
-                .addExpectedNodeWithOrder("VERSION", "3.0")
                 .addExpectedNodeWithOrder("N", Arrays.asList("F", "G", "M", "", ""))
                 .addExpectedNodeWithOrder("TEL", "6101231234@pagersample.com",
                         new TypeSet("WORK", "MSG", "PAGER"));
@@ -1029,7 +1019,6 @@
     public void testMultiBytePropV30_Parse() {
         mVerifier.initForImportTest(V30, R.raw.v30_multibyte_param);
         mVerifier.addPropertyNodesVerifierElem()
-                .addExpectedNodeWithOrder("VERSION", "3.0")
                 .addExpectedNodeWithOrder("N", Arrays.asList("F", "G", "M", "", ""))
                 .addExpectedNodeWithOrder("TEL", "1", new TypeSet("\u8D39"));
     }
@@ -1051,10 +1040,9 @@
     public void testCommaSeparatedParamsV30_Parse() {
         mVerifier.initForImportTest(V30, R.raw.v30_comma_separated);
         mVerifier.addPropertyNodesVerifierElem()
-                .addExpectedNodeWithOrder("VERSION", "3.0")
                 .addExpectedNodeWithOrder("N", Arrays.asList("F", "G", "M", "", ""),
                         new TypeSet("PREF", "HOME"))
                 .addExpectedNodeWithOrder("TEL", "1",
-                        new TypeSet("COMMA,SEPARATED", "PREF"));
+                        new TypeSet("COMMA,SEPARATED:INSIDE.DQUOTE", "PREF"));
     }
 }
diff --git a/tests/src/com/android/vcard/tests/test_utils/ContentValuesVerifier.java b/tests/src/com/android/vcard/tests/test_utils/ContentValuesVerifier.java
index d83f28a..57dbf32 100644
--- a/tests/src/com/android/vcard/tests/test_utils/ContentValuesVerifier.java
+++ b/tests/src/com/android/vcard/tests/test_utils/ContentValuesVerifier.java
@@ -18,62 +18,22 @@
 import android.test.AndroidTestCase;
 
 import com.android.vcard.VCardEntry;
-import com.android.vcard.VCardEntryConstructor;
 import com.android.vcard.VCardEntryHandler;
-import com.android.vcard.VCardParser;
-import com.android.vcard.VCardUtils;
-import com.android.vcard.exception.VCardException;
 
-import java.io.IOException;
-import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.List;
 
 public class ContentValuesVerifier implements VCardEntryHandler {
-    private AndroidTestCase mTestCase;
     private List<ContentValuesVerifierElem> mContentValuesVerifierElemList =
         new ArrayList<ContentValuesVerifierElem>();
     private int mIndex;
 
     public ContentValuesVerifierElem addElem(AndroidTestCase androidTestCase) {
-        mTestCase = androidTestCase;
         ContentValuesVerifierElem importVerifier = new ContentValuesVerifierElem(androidTestCase);
         mContentValuesVerifierElemList.add(importVerifier);
         return importVerifier;
     }
 
-    public void verify(int resId, int vcardType) throws IOException, VCardException {
-        verify(mTestCase.getContext().getResources().openRawResource(resId), vcardType);
-    }
-
-    public void verify(int resId, int vcardType, final VCardParser vCardParser)
-            throws IOException, VCardException {
-        verify(mTestCase.getContext().getResources().openRawResource(resId),
-                vcardType, vCardParser);
-    }
-
-
-    public void verify(InputStream is, int vcardType) throws IOException, VCardException {
-        final VCardParser vCardParser = VCardUtils.getAppropriateParser(vcardType);
-        verify(is, vcardType, vCardParser);
-    }
-
-    public void verify(InputStream is, int vcardType, final VCardParser vCardParser)
-            throws IOException, VCardException {
-        VCardEntryConstructor builder = new VCardEntryConstructor(vcardType, null);
-        builder.addEntryHandler(this);
-        try {
-            vCardParser.parse(is, builder);
-        } finally {
-            if (is != null) {
-                try {
-                    is.close();
-                } catch (IOException e) {
-                }
-            }
-        }
-    }
-
     public void onStart() {
         for (ContentValuesVerifierElem elem : mContentValuesVerifierElemList) {
             elem.onParsingStart();
diff --git a/tests/src/com/android/vcard/tests/test_utils/PropertyNodesVerifier.java b/tests/src/com/android/vcard/tests/test_utils/PropertyNodesVerifier.java
index 9c4a46f..ce24d04 100644
--- a/tests/src/com/android/vcard/tests/test_utils/PropertyNodesVerifier.java
+++ b/tests/src/com/android/vcard/tests/test_utils/PropertyNodesVerifier.java
@@ -43,8 +43,7 @@
         return elem;
     }
 
-    public void verify(int resId, int vcardType)
-            throws IOException, VCardException {
+    public void verify(int resId, int vcardType) throws IOException, VCardException {
         verify(mAndroidTestCase.getContext().getResources().openRawResource(resId), vcardType);
     }
 
diff --git a/tests/src/com/android/vcard/tests/test_utils/PropertyNodesVerifierElem.java b/tests/src/com/android/vcard/tests/test_utils/PropertyNodesVerifierElem.java
index e4a275c..b6a4138 100644
--- a/tests/src/com/android/vcard/tests/test_utils/PropertyNodesVerifierElem.java
+++ b/tests/src/com/android/vcard/tests/test_utils/PropertyNodesVerifierElem.java
@@ -118,7 +118,7 @@
         if (propValue == null && propValueList != null) {
             propValue = concatinateListWithSemiColon(propValueList);
         }
-        PropertyNode propertyNode = new PropertyNode(propName,
+        final PropertyNode propertyNode = new PropertyNode(propName,
                 propValue, propValueList, propValue_bytes,
                 paramMap, paramMap_TYPE, propGroupSet);
         List<PropertyNode> expectedNodeList = mOrderedNodeMap.get(propName);
@@ -197,8 +197,9 @@
         for (PropertyNode actualNode : vnode.propList) {
             verifyNode(actualNode.propName, actualNode);
         }
+
         if (!mOrderedNodeMap.isEmpty() || !mUnorderedNodeList.isEmpty()) {
-            List<String> expectedProps = new ArrayList<String>();
+            final List<String> expectedProps = new ArrayList<String>();
             for (List<PropertyNode> nodes : mOrderedNodeMap.values()) {
                 for (PropertyNode node : nodes) {
                     if (!expectedProps.contains(node.propName)) {
@@ -217,12 +218,13 @@
     }
 
     private void verifyNode(final String propName, final PropertyNode actualNode) {
-        List<PropertyNode> expectedNodeList = mOrderedNodeMap.get(propName);
+        final List<PropertyNode> expectedNodeList = mOrderedNodeMap.get(propName);
         final int size = (expectedNodeList != null ? expectedNodeList.size() : 0);
         if (size > 0) {
             for (int i = 0; i < size; i++) {
-                PropertyNode expectedNode = expectedNodeList.get(i);
-                List<PropertyNode> expectedButDifferentValueList = new ArrayList<PropertyNode>();
+                final PropertyNode expectedNode = expectedNodeList.get(i);
+                final List<PropertyNode> expectedButDifferentValueList =
+                        new ArrayList<PropertyNode>();
                 if (expectedNode.propName.equals(propName)) {
                     if (expectedNode.equals(actualNode)) {
                         expectedNodeList.remove(i);
diff --git a/tests/src/com/android/vcard/tests/test_utils/VCardVerifier.java b/tests/src/com/android/vcard/tests/test_utils/VCardVerifier.java
index cabda2a..e5de13f 100644
--- a/tests/src/com/android/vcard/tests/test_utils/VCardVerifier.java
+++ b/tests/src/com/android/vcard/tests/test_utils/VCardVerifier.java
@@ -33,6 +33,8 @@
 import com.android.vcard.VCardUtils;
 import com.android.vcard.exception.VCardException;
 
+import junit.framework.TestCase;
+
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -70,14 +72,14 @@
             return true;
         }
         public boolean onEntryCreated(String vcard) {
-            verifyOneVCard(vcard);
+            verifyOneVCardForExport(vcard);
             return true;
         }
         public void onTerminate() {
         }
     }
 
-    private final AndroidTestCase mTestCase;
+    private final AndroidTestCase mAndroidTestCase;
     private final VCardVerifierInternal mVCardVerifierInternal;
     private int mVCardType;
     private boolean mIsDoCoMo;
@@ -96,8 +98,8 @@
     private String mCharset;
 
     // Called by VCardTestsBase
-    public VCardVerifier(AndroidTestCase testCase) {
-        mTestCase = testCase;
+    public VCardVerifier(AndroidTestCase androidTestCase) {
+        mAndroidTestCase = androidTestCase;
         mVCardVerifierInternal = new VCardVerifierInternal();
         mExportTestResolver = null;
         mInputStream = null;
@@ -125,7 +127,7 @@
         if (mInitialized) {
             AndroidTestCase.fail("Already initialized");
         }
-        mExportTestResolver = new ExportTestResolver(mTestCase);
+        mExportTestResolver = new ExportTestResolver(mAndroidTestCase);
         mVCardType = vcardType;
         mIsDoCoMo = VCardConfig.isDoCoMo(vcardType);
         mInitialized = true;
@@ -137,7 +139,7 @@
     }
 
     private void setInputResourceId(int resId) {
-        InputStream inputStream = mTestCase.getContext().getResources().openRawResource(resId);
+        InputStream inputStream = mAndroidTestCase.getContext().getResources().openRawResource(resId);
         if (inputStream == null) {
             AndroidTestCase.fail("Wrong resId: " + resId);
         }
@@ -163,15 +165,18 @@
         return mExportTestResolver.addInputContactEntry();
     }
 
-    public PropertyNodesVerifierElem addPropertyNodesVerifierElem() {
+    public PropertyNodesVerifierElem addPropertyNodesVerifierElemWithoutVersion() {
         if (!mInitialized) {
             AndroidTestCase.fail("Not initialized");
         }
         if (mPropertyNodesVerifier == null) {
-            mPropertyNodesVerifier = new PropertyNodesVerifier(mTestCase);
+            mPropertyNodesVerifier = new PropertyNodesVerifier(mAndroidTestCase);
         }
-        PropertyNodesVerifierElem elem =
-                mPropertyNodesVerifier.addPropertyNodesVerifierElem();
+        return mPropertyNodesVerifier.addPropertyNodesVerifierElem();
+    }
+    
+    public PropertyNodesVerifierElem addPropertyNodesVerifierElem() {
+        final PropertyNodesVerifierElem elem = addPropertyNodesVerifierElemWithoutVersion();
         final String versionString;
         if (VCardConfig.isVersion21(mVCardType)) {
             versionString = "2.1";
@@ -205,7 +210,7 @@
             AndroidTestCase.fail("Not initialized");
         }
         if (mLineVerifier == null) {
-            mLineVerifier = new LineVerifier(mTestCase, mVCardType);
+            mLineVerifier = new LineVerifier(mAndroidTestCase, mVCardType);
         }
         return mLineVerifier.addLineVerifierElem();
     }
@@ -218,43 +223,55 @@
             mContentValuesVerifier = new ContentValuesVerifier();
         }
 
-        return mContentValuesVerifier.addElem(mTestCase);
+        return mContentValuesVerifier.addElem(mAndroidTestCase);
     }
 
-    private void verifyOneVCard(final String vcard) {
-        Log.d(LOG_TAG, vcard);
-        final VCardInterpreter builder;
+    /**
+     * Sets up sub-verifiers correctly and try parse given vCard as InputStream.
+     * Errors around InputStream must be handled outside this method.
+     *
+     * Used both from {@link #verifyForImportTest()} and from {@link #verifyForExportTest()}.
+     */
+    private void verifyWithInputStream(InputStream is) throws IOException {
+        final VCardInterpreter interpreter;
         if (mContentValuesVerifier != null) {
             final VNodeBuilder vnodeBuilder = mPropertyNodesVerifier;
             final VCardEntryConstructor vcardDataBuilder =
                     new VCardEntryConstructor(mVCardType);
             vcardDataBuilder.addEntryHandler(mContentValuesVerifier);
             if (mPropertyNodesVerifier != null) {
-                builder = new VCardInterpreterCollection(Arrays.asList(
+                interpreter = new VCardInterpreterCollection(Arrays.asList(
                         mPropertyNodesVerifier, vcardDataBuilder));
             } else {
-                builder = vnodeBuilder;
+                interpreter = vnodeBuilder;
             }
         } else {
             if (mPropertyNodesVerifier != null) {
-                builder = mPropertyNodesVerifier;
+                interpreter = mPropertyNodesVerifier;
             } else {
-                return;
+                interpreter = null;
             }
         }
 
-        InputStream is = null;
         try {
             // Note: we must not specify charset toward vCard parsers. This code checks whether
             // those parsers are able to encode given binary without any extra information for
             // charset.
             final VCardParser parser = VCardUtils.getAppropriateParser(mVCardType);
-            is = new ByteArrayInputStream(vcard.getBytes(mCharset));
-            parser.parse(is, builder);
-        } catch (IOException e) {
-            AndroidTestCase.fail("Unexpected IOException: " + e.getMessage());
+            parser.parse(is, interpreter);
         } catch (VCardException e) {
             AndroidTestCase.fail("Unexpected VCardException: " + e.getMessage());
+        }
+    }
+
+    private void verifyOneVCardForExport(final String vcard) {
+        Log.d(LOG_TAG, vcard);
+        InputStream is = null;
+        try {
+            is = new ByteArrayInputStream(vcard.getBytes(mCharset));
+            verifyWithInputStream(is);
+        } catch (IOException e) {
+            AndroidTestCase.fail("Unexpected IOException: " + e.getMessage());
         } finally {
             if (is != null) {
                 try {
@@ -268,33 +285,41 @@
 
     public void verify() {
         if (!mInitialized) {
-            AndroidTestCase.fail("Not initialized.");
+            TestCase.fail("Not initialized.");
         }
         if (mVerified) {
-            AndroidTestCase.fail("verify() was called twice.");
+            TestCase.fail("verify() was called twice.");
         }
+
         if (mInputStream != null) {
-            try {
-                verifyForImportTest();
-            } catch (IOException e) {
-                AndroidTestCase.fail("IOException was thrown: " + e.getMessage());
-            } catch (VCardException e) {
-                AndroidTestCase.fail("VCardException was thrown: " + e.getMessage());
+            if (mExportTestResolver != null){
+                TestCase.fail("There are two input sources.");
             }
+            verifyForImportTest();
         } else if (mExportTestResolver != null){
             verifyForExportTest();
         } else {
-            AndroidTestCase.fail("No input is determined");
+            TestCase.fail("No input is determined");
         }
         mVerified = true;
     }
 
-    private void verifyForImportTest() throws IOException, VCardException {
+    private void verifyForImportTest() {
         if (mLineVerifier != null) {
             AndroidTestCase.fail("Not supported now.");
         }
-        if (mContentValuesVerifier != null) {
-            mContentValuesVerifier.verify(mInputStream, mVCardType);
+
+        try {
+            verifyWithInputStream(mInputStream);
+        } catch (IOException e) {
+            AndroidTestCase.fail("IOException was thrown: " + e.getMessage());
+        } finally {
+            if (mInputStream != null) {
+                try {
+                    mInputStream.close();
+                } catch (IOException e) {
+                }
+            }
         }
     }