VCardExporterTests.java revision 5db8b7baeffb35191032789cb0b0d643b78f0120
1/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.vcard.tests;
18
19import com.android.vcard.VCardConfig;
20import com.android.vcard.tests.test_utils.ContactEntry;
21import com.android.vcard.tests.test_utils.PropertyNodesVerifierElem;
22import com.android.vcard.tests.test_utils.PropertyNodesVerifierElem.TypeSet;
23import com.android.vcard.tests.test_utils.VCardTestsBase;
24
25import android.content.ContentValues;
26import android.provider.ContactsContract.CommonDataKinds.Email;
27import android.provider.ContactsContract.CommonDataKinds.Event;
28import android.provider.ContactsContract.CommonDataKinds.Im;
29import android.provider.ContactsContract.CommonDataKinds.Nickname;
30import android.provider.ContactsContract.CommonDataKinds.Note;
31import android.provider.ContactsContract.CommonDataKinds.Organization;
32import android.provider.ContactsContract.CommonDataKinds.Phone;
33import android.provider.ContactsContract.CommonDataKinds.Photo;
34import android.provider.ContactsContract.CommonDataKinds.Relation;
35import android.provider.ContactsContract.CommonDataKinds.SipAddress;
36import android.provider.ContactsContract.CommonDataKinds.StructuredName;
37import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
38import android.provider.ContactsContract.CommonDataKinds.Website;
39
40import java.util.Arrays;
41
42/**
43 * Tests for the code related to vCard exporter, inculding vCard composer.
44 * This test class depends on vCard importer code, so if tests for vCard importer fail,
45 * the result of this class will not be reliable.
46 */
47public class VCardExporterTests extends VCardTestsBase {
48    private static final byte[] sPhotoByteArray =
49        VCardImporterTests.sPhotoByteArrayForComplicatedCase;
50
51    public void testSimpleV21() {
52        mVerifier.initForExportTest(V21);
53        mVerifier.addInputEntry().addContentValues(StructuredName.CONTENT_ITEM_TYPE)
54                .put(StructuredName.FAMILY_NAME, "Ando")
55                .put(StructuredName.GIVEN_NAME, "Roid");
56        mVerifier.addPropertyNodesVerifierElem()
57                .addExpectedNode("FN", "Roid Ando")
58                .addExpectedNode("N", "Ando;Roid;;;",
59                        Arrays.asList("Ando", "Roid", "", "", ""));
60    }
61
62    private void testStructuredNameBasic(int vcardType) {
63        mVerifier.initForExportTest(vcardType);
64        mVerifier.addInputEntry().addContentValues(StructuredName.CONTENT_ITEM_TYPE)
65                .put(StructuredName.FAMILY_NAME, "AppropriateFamilyName")
66                .put(StructuredName.GIVEN_NAME, "AppropriateGivenName")
67                .put(StructuredName.MIDDLE_NAME, "AppropriateMiddleName")
68                .put(StructuredName.PREFIX, "AppropriatePrefix")
69                .put(StructuredName.SUFFIX, "AppropriateSuffix")
70                .put(StructuredName.DISPLAY_NAME, "DISPLAY NAME");
71
72        mVerifier.addPropertyNodesVerifierElem()
73                .addExpectedNodeWithOrder("N",
74                        "AppropriateFamilyName;AppropriateGivenName;AppropriateMiddleName;"
75                        + "AppropriatePrefix;AppropriateSuffix",
76                        Arrays.asList("AppropriateFamilyName", "AppropriateGivenName",
77                                "AppropriateMiddleName", "AppropriatePrefix", "AppropriateSuffix"))
78                .addExpectedNodeWithOrder("FN", "DISPLAY NAME");
79    }
80
81    public void testStructuredNameBasicV21() {
82        testStructuredNameBasic(V21);
83    }
84
85    public void testStructuredNameBasicV30() {
86        testStructuredNameBasic(V30);
87    }
88
89    public void testStructuredNameBasicV40() {
90        testStructuredNameBasic(V40);
91    }
92
93    /**
94     * Test that only "primary" StructuredName is emitted, so that our vCard file
95     * will not confuse the external importer, assuming there may be some importer
96     * which presume that there's only one property toward each of  "N", "FN", etc.
97     * Note that more than one "N", "FN", etc. properties are acceptable in vCard spec.
98     */
99    private void testStructuredNameUsePrimaryCommon(int vcardType) {
100        mVerifier.initForExportTest(vcardType);
101        final ContactEntry entry = mVerifier.addInputEntry();
102        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
103                .put(StructuredName.FAMILY_NAME, "DoNotEmitFamilyName1")
104                .put(StructuredName.GIVEN_NAME, "DoNotEmitGivenName1")
105                .put(StructuredName.MIDDLE_NAME, "DoNotEmitMiddleName1")
106                .put(StructuredName.PREFIX, "DoNotEmitPrefix1")
107                .put(StructuredName.SUFFIX, "DoNotEmitSuffix1")
108                .put(StructuredName.DISPLAY_NAME, "DoNotEmitDisplayName1");
109
110        // With "IS_PRIMARY=1". This is what we should use.
111        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
112                .put(StructuredName.FAMILY_NAME, "AppropriateFamilyName")
113                .put(StructuredName.GIVEN_NAME, "AppropriateGivenName")
114                .put(StructuredName.MIDDLE_NAME, "AppropriateMiddleName")
115                .put(StructuredName.PREFIX, "AppropriatePrefix")
116                .put(StructuredName.SUFFIX, "AppropriateSuffix")
117                .put(StructuredName.DISPLAY_NAME, "AppropriateDisplayName")
118                .put(StructuredName.IS_PRIMARY, 1);
119
120        // With "IS_PRIMARY=1", but we should ignore this time, since this is second, not first.
121        // vCard 2.1 does not specify anything about the number of N properties. We choose not
122        // emitting this property.
123        // vCard 3.0 does (There must be one N property)
124        // vCard 4.0 (rev13) does (cardinality (0, 1)).
125        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
126                .put(StructuredName.FAMILY_NAME, "DoNotEmitFamilyName2")
127                .put(StructuredName.GIVEN_NAME, "DoNotEmitGivenName2")
128                .put(StructuredName.MIDDLE_NAME, "DoNotEmitMiddleName2")
129                .put(StructuredName.PREFIX, "DoNotEmitPrefix2")
130                .put(StructuredName.SUFFIX, "DoNotEmitSuffix2")
131                .put(StructuredName.DISPLAY_NAME, "DoNotEmitDisplayName2")
132                .put(StructuredName.IS_PRIMARY, 1);
133
134       mVerifier.addPropertyNodesVerifierElem()
135                .addExpectedNodeWithOrder("N",
136                        "AppropriateFamilyName;AppropriateGivenName;AppropriateMiddleName;"
137                        + "AppropriatePrefix;AppropriateSuffix",
138                        Arrays.asList("AppropriateFamilyName", "AppropriateGivenName",
139                                "AppropriateMiddleName", "AppropriatePrefix", "AppropriateSuffix"))
140                .addExpectedNodeWithOrder("FN", "AppropriateDisplayName");
141    }
142
143    public void testStructuredNameUsePrimaryV21() {
144        testStructuredNameUsePrimaryCommon(V21);
145    }
146
147    public void testStructuredNameUsePrimaryV30() {
148        testStructuredNameUsePrimaryCommon(V30);
149    }
150
151    public void testStructuredNameUsePrimaryV40() {
152        testStructuredNameUsePrimaryCommon(V40);
153    }
154
155    /**
156     * Tests that only "super primary" StructuredName is emitted.
157     * See also the comment in {@link #testStructuredNameUsePrimaryCommon(int)}.
158     */
159    private void testStructuredNameUseSuperPrimaryCommon(int vcardType) {
160        mVerifier.initForExportTest(vcardType);
161        final ContactEntry entry = mVerifier.addInputEntry();
162        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
163                .put(StructuredName.FAMILY_NAME, "DoNotEmitFamilyName1")
164                .put(StructuredName.GIVEN_NAME, "DoNotEmitGivenName1")
165                .put(StructuredName.MIDDLE_NAME, "DoNotEmitMiddleName1")
166                .put(StructuredName.PREFIX, "DoNotEmitPrefix1")
167                .put(StructuredName.SUFFIX, "DoNotEmitSuffix1")
168                .put(StructuredName.DISPLAY_NAME, "DoNotEmitDisplay1");
169
170        // With "IS_PRIMARY=1", but we should ignore this time.
171        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
172                .put(StructuredName.FAMILY_NAME, "DoNotEmitFamilyName2")
173                .put(StructuredName.GIVEN_NAME, "DoNotEmitGivenName2")
174                .put(StructuredName.MIDDLE_NAME, "DoNotEmitMiddleName2")
175                .put(StructuredName.PREFIX, "DoNotEmitPrefix2")
176                .put(StructuredName.SUFFIX, "DoNotEmitSuffix2")
177                .put(StructuredName.DISPLAY_NAME, "DoNotEmitDisplay2")
178                .put(StructuredName.IS_PRIMARY, 1);
179
180        // With "IS_SUPER_PRIMARY=1". This is what we should use.
181        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
182                .put(StructuredName.FAMILY_NAME, "AppropriateFamilyName")
183                .put(StructuredName.GIVEN_NAME, "AppropriateGivenName")
184                .put(StructuredName.MIDDLE_NAME, "AppropriateMiddleName")
185                .put(StructuredName.PREFIX, "AppropriatePrefix")
186                .put(StructuredName.SUFFIX, "AppropriateSuffix")
187                .put(StructuredName.DISPLAY_NAME, "AppropriateDisplayName")
188                .put(StructuredName.IS_SUPER_PRIMARY, 1);
189
190        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
191                .put(StructuredName.FAMILY_NAME, "DoNotEmitFamilyName3")
192                .put(StructuredName.GIVEN_NAME, "DoNotEmitGivenName3")
193                .put(StructuredName.MIDDLE_NAME, "DoNotEmitMiddleName3")
194                .put(StructuredName.PREFIX, "DoNotEmitPrefix3")
195                .put(StructuredName.SUFFIX, "DoNotEmitSuffix3")
196                .put(StructuredName.DISPLAY_NAME, "DoNotEmitDisplay3")
197                .put(StructuredName.IS_PRIMARY, 1);
198
199        final PropertyNodesVerifierElem elem = mVerifier.addPropertyNodesVerifierElem();
200        elem.addExpectedNodeWithOrder("N",
201                "AppropriateFamilyName;AppropriateGivenName;AppropriateMiddleName;"
202                + "AppropriatePrefix;AppropriateSuffix",
203                Arrays.asList("AppropriateFamilyName", "AppropriateGivenName",
204                        "AppropriateMiddleName", "AppropriatePrefix", "AppropriateSuffix"));
205
206        elem.addExpectedNodeWithOrder("FN", "AppropriateDisplayName");
207    }
208
209    public void testStructuredNameUseSuperPrimaryV21() {
210        testStructuredNameUseSuperPrimaryCommon(V21);
211    }
212
213    public void testStructuredNameUseSuperPrimaryV30() {
214        testStructuredNameUseSuperPrimaryCommon(V30);
215    }
216
217    public void testStructuredNameUseSuperPrimaryV40() {
218        testStructuredNameUseSuperPrimaryCommon(V40);
219    }
220
221    /**
222     * Tests phonetic names field are handled correctly.
223     *
224     * vCard 2.1 does not have any field corresponding to them.
225     * vCard 3.0 has SORT-STRING property, which does not support multiple values inside it.
226     * vCard 4.0 (rev13) has SORT-AS parameter, which has three values (family, given, middle)
227     * inside it.
228     */
229    private void testStructuredNamePhoneticNameCommon(int vcardType) {
230        mVerifier.initForExportTest(vcardType);
231        final ContactEntry entry = mVerifier.addInputEntry();
232        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
233                .put(StructuredName.FAMILY_NAME, "AppropriateFamilyName")
234                .put(StructuredName.GIVEN_NAME, "AppropriateGivenName")
235                .put(StructuredName.MIDDLE_NAME, "AppropriateMiddleName")
236                .put(StructuredName.PREFIX, "AppropriatePrefix")
237                .put(StructuredName.SUFFIX, "AppropriateSuffix")
238                .put(StructuredName.DISPLAY_NAME, "AppropriateDisplayName")
239                .put(StructuredName.PHONETIC_FAMILY_NAME, "AppropriatePhoneticFamily")
240                .put(StructuredName.PHONETIC_GIVEN_NAME, "AppropriatePhoneticGiven")
241                .put(StructuredName.PHONETIC_MIDDLE_NAME, "AppropriatePhoneticMiddle");
242
243        final PropertyNodesVerifierElem elem = mVerifier.addPropertyNodesVerifierElem();
244        if (VCardConfig.isVersion40(vcardType)) {
245            final ContentValues contentValues = new ContentValues();
246            contentValues.put("SORT-AS",
247                    "AppropriateFamilyName;AppropriateGivenName;AppropriateMiddleName");
248            // vCard 4.0 (rev13) now uses SORT-AS parameter, which is not compatible with
249            // either 2.1 nor 3.0.
250            elem.addExpectedNodeWithOrder("N",
251                    "AppropriateFamilyName;AppropriateGivenName;AppropriateMiddleName;"
252                    + "AppropriatePrefix;AppropriateSuffix",
253                    Arrays.asList("AppropriateFamilyName", "AppropriateGivenName",
254                            "AppropriateMiddleName", "AppropriatePrefix", "AppropriateSuffix"),
255                    contentValues);
256        } else {
257            elem.addExpectedNodeWithOrder("N",
258                    "AppropriateFamilyName;AppropriateGivenName;AppropriateMiddleName;"
259                    + "AppropriatePrefix;AppropriateSuffix",
260                    Arrays.asList("AppropriateFamilyName", "AppropriateGivenName",
261                            "AppropriateMiddleName", "AppropriatePrefix", "AppropriateSuffix"));
262            if (VCardConfig.isVersion30(vcardType)) {
263                elem.addExpectedNode("SORT-STRING",
264                        "AppropriatePhoneticGiven AppropriatePhoneticMiddle"
265                        + " AppropriatePhoneticFamily");
266            }
267        }
268
269        elem.addExpectedNodeWithOrder("FN", "AppropriateDisplayName")
270            .addExpectedNode("X-PHONETIC-FIRST-NAME", "AppropriatePhoneticGiven")
271            .addExpectedNode("X-PHONETIC-MIDDLE-NAME", "AppropriatePhoneticMiddle")
272            .addExpectedNode("X-PHONETIC-LAST-NAME", "AppropriatePhoneticFamily");
273    }
274
275    public void testStructuredNamePhoneticNameV21() {
276        testStructuredNamePhoneticNameCommon(V21);
277    }
278
279    public void testStructuredNamePhoneticNameV30() {
280        testStructuredNamePhoneticNameCommon(V30);
281    }
282
283    public void testStructuredNamePhoneticNameV40() {
284        testStructuredNamePhoneticNameCommon(V40);
285    }
286
287    // TODO: need to add test cases confirming escaping, empty values, etc.
288
289    /**
290     * Confirms all the other sides of the handling is correctly interpreted at one time.
291     *
292     * A kind of regression test for StructuredName handling.
293     */
294    private void testStructuredNameComplicatedCommon(int vcardType) {
295        mVerifier.initForExportTest(vcardType);
296        final ContactEntry entry = mVerifier.addInputEntry();
297        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
298                .put(StructuredName.FAMILY_NAME, "DoNotEmitFamilyName1")
299                .put(StructuredName.GIVEN_NAME, "DoNotEmitGivenName1")
300                .put(StructuredName.MIDDLE_NAME, "DoNotEmitMiddleName1")
301                .put(StructuredName.PREFIX, "DoNotEmitPrefix1")
302                .put(StructuredName.SUFFIX, "DoNotEmitSuffix1")
303                .put(StructuredName.PHONETIC_FAMILY_NAME, "DoNotEmitPhoneticFamily1")
304                .put(StructuredName.PHONETIC_GIVEN_NAME, "DoNotEmitPhoneticGiven1")
305                .put(StructuredName.PHONETIC_MIDDLE_NAME, "DoNotEmitPhoneticMiddle1");
306
307        // With "IS_PRIMARY=1", but we should ignore this time.
308        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
309                .put(StructuredName.FAMILY_NAME, "DoNotEmitFamilyName2")
310                .put(StructuredName.GIVEN_NAME, "DoNotEmitGivenName2")
311                .put(StructuredName.MIDDLE_NAME, "DoNotEmitMiddleName2")
312                .put(StructuredName.PREFIX, "DoNotEmitPrefix2")
313                .put(StructuredName.SUFFIX, "DoNotEmitSuffix2")
314                .put(StructuredName.PHONETIC_FAMILY_NAME, "DoNotEmitPhoneticFamily2")
315                .put(StructuredName.PHONETIC_GIVEN_NAME, "DoNotEmitPhoneticGiven2")
316                .put(StructuredName.PHONETIC_MIDDLE_NAME, "DoNotEmitPhoneticMiddle2")
317                .put(StructuredName.IS_PRIMARY, 1);
318
319        // With "IS_SUPER_PRIMARY=1". This is what we should use.
320        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
321                .put(StructuredName.FAMILY_NAME, "AppropriateFamilyName")
322                .put(StructuredName.GIVEN_NAME, "AppropriateGivenName")
323                .put(StructuredName.MIDDLE_NAME, "AppropriateMiddleName")
324                .put(StructuredName.PREFIX, "AppropriatePrefix")
325                .put(StructuredName.SUFFIX, "AppropriateSuffix")
326                .put(StructuredName.PHONETIC_FAMILY_NAME, "AppropriatePhoneticFamily")
327                .put(StructuredName.PHONETIC_GIVEN_NAME, "AppropriatePhoneticGiven")
328                .put(StructuredName.PHONETIC_MIDDLE_NAME, "AppropriatePhoneticMiddle")
329                .put(StructuredName.IS_SUPER_PRIMARY, 1);
330
331        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
332                .put(StructuredName.FAMILY_NAME, "DoNotEmitFamilyName3")
333                .put(StructuredName.GIVEN_NAME, "DoNotEmitGivenName3")
334                .put(StructuredName.MIDDLE_NAME, "DoNotEmitMiddleName3")
335                .put(StructuredName.PREFIX, "DoNotEmitPrefix3")
336                .put(StructuredName.SUFFIX, "DoNotEmitSuffix3")
337                .put(StructuredName.PHONETIC_FAMILY_NAME, "DoNotEmitPhoneticFamily3")
338                .put(StructuredName.PHONETIC_GIVEN_NAME, "DoNotEmitPhoneticGiven3")
339                .put(StructuredName.PHONETIC_MIDDLE_NAME, "DoNotEmitPhoneticMiddle3")
340                .put(StructuredName.IS_PRIMARY, 1);
341
342        final PropertyNodesVerifierElem elem = mVerifier.addPropertyNodesVerifierElem();
343        if (VCardConfig.isVersion40(vcardType)) {
344            final ContentValues contentValues = new ContentValues();
345            contentValues.put("SORT-AS",
346                    "AppropriateFamilyName;AppropriateGivenName;AppropriateMiddleName");
347            // vCard 4.0 (rev13) now uses SORT-AS parameter, which is not compatible with
348            // either 2.1 nor 3.0.
349            elem.addExpectedNodeWithOrder("N",
350                    "AppropriateFamilyName;AppropriateGivenName;AppropriateMiddleName;"
351                    + "AppropriatePrefix;AppropriateSuffix",
352                    Arrays.asList("AppropriateFamilyName", "AppropriateGivenName",
353                            "AppropriateMiddleName", "AppropriatePrefix", "AppropriateSuffix"),
354                    contentValues);
355        } else {
356            elem.addExpectedNodeWithOrder("N",
357                    "AppropriateFamilyName;AppropriateGivenName;AppropriateMiddleName;"
358                    + "AppropriatePrefix;AppropriateSuffix",
359                    Arrays.asList("AppropriateFamilyName", "AppropriateGivenName",
360                            "AppropriateMiddleName", "AppropriatePrefix", "AppropriateSuffix"));
361            if (VCardConfig.isVersion30(vcardType)) {
362                elem.addExpectedNode("SORT-STRING",
363                        "AppropriatePhoneticGiven AppropriatePhoneticMiddle"
364                        + " AppropriatePhoneticFamily");
365            }
366        }
367
368        elem.addExpectedNodeWithOrder("FN",
369                "AppropriatePrefix AppropriateGivenName "
370                + "AppropriateMiddleName AppropriateFamilyName AppropriateSuffix")
371            .addExpectedNode("X-PHONETIC-FIRST-NAME", "AppropriatePhoneticGiven")
372            .addExpectedNode("X-PHONETIC-MIDDLE-NAME", "AppropriatePhoneticMiddle")
373            .addExpectedNode("X-PHONETIC-LAST-NAME", "AppropriatePhoneticFamily");
374    }
375
376    public void testStructuredNameComplicatedV21() {
377        testStructuredNameComplicatedCommon(V21);
378    }
379
380    public void testStructuredNameComplicatedV30() {
381        testStructuredNameComplicatedCommon(V30);
382    }
383
384    public void testStructuredNameComplicatedV40() {
385        testStructuredNameComplicatedCommon(V40);
386    }
387
388    public void testNickNameV30() {
389        mVerifier.initForExportTest(V30);
390        mVerifier.addInputEntry().addContentValues(Nickname.CONTENT_ITEM_TYPE)
391                .put(Nickname.NAME, "Nicky");
392
393        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
394            .addExpectedNodeWithOrder("NICKNAME", "Nicky");
395    }
396
397    public void testNickNameV40() {
398        mVerifier.initForExportTest(V40);
399        mVerifier.addInputEntry().addContentValues(Nickname.CONTENT_ITEM_TYPE)
400                .put(Nickname.NAME, "Nicky");
401
402        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
403            .addExpectedNodeWithOrder("NICKNAME", "Nicky");
404    }
405
406    private void testPhoneBasicCommon(int vcardType) {
407        mVerifier.initForExportTest(vcardType);
408        mVerifier.addInputEntry().addContentValues(Phone.CONTENT_ITEM_TYPE)
409                .put(Phone.NUMBER, "1")
410                .put(Phone.TYPE, Phone.TYPE_HOME);
411        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
412                .addExpectedNode("TEL", "1", new TypeSet("HOME"));
413    }
414
415    public void testPhoneBasicV21() {
416        testPhoneBasicCommon(V21);
417    }
418
419    public void testPhoneBasicV30() {
420        testPhoneBasicCommon(V30);
421    }
422
423    public void testPhoneBasicV40() {
424        testPhoneBasicCommon(V40);
425    }
426
427    public void testPhoneRefrainFormatting() {
428        mVerifier.initForExportTest(V21 | VCardConfig.FLAG_REFRAIN_PHONE_NUMBER_FORMATTING);
429        mVerifier.addInputEntry().addContentValues(Phone.CONTENT_ITEM_TYPE)
430                .put(Phone.NUMBER, "1234567890(abcdefghijklmnopqrstuvwxyz)")
431                .put(Phone.TYPE, Phone.TYPE_HOME);
432        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
433                .addExpectedNode("TEL", "1234567890(abcdefghijklmnopqrstuvwxyz)",
434                        new TypeSet("HOME"));
435    }
436
437    /**
438     * Tests that vCard composer emits corresponding type param which we expect.
439     */
440    private void testPhoneVariousTypeSupport(int vcardType) {
441        mVerifier.initForExportTest(vcardType);
442        ContactEntry entry = mVerifier.addInputEntry();
443        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
444                .put(Phone.NUMBER, "10")
445                .put(Phone.TYPE, Phone.TYPE_HOME);
446        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
447                .put(Phone.NUMBER, "20")
448                .put(Phone.TYPE, Phone.TYPE_WORK);
449        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
450                .put(Phone.NUMBER, "30")
451                .put(Phone.TYPE, Phone.TYPE_FAX_HOME);
452        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
453                .put(Phone.NUMBER, "40")
454                .put(Phone.TYPE, Phone.TYPE_FAX_WORK);
455        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
456                .put(Phone.NUMBER, "50")
457                .put(Phone.TYPE, Phone.TYPE_MOBILE);
458        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
459                .put(Phone.NUMBER, "60")
460                .put(Phone.TYPE, Phone.TYPE_PAGER);
461        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
462                .put(Phone.NUMBER, "70")
463                .put(Phone.TYPE, Phone.TYPE_OTHER);
464        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
465                .put(Phone.NUMBER, "80")
466                .put(Phone.TYPE, Phone.TYPE_CAR);
467        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
468                .put(Phone.NUMBER, "90")
469                .put(Phone.TYPE, Phone.TYPE_COMPANY_MAIN);
470        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
471                .put(Phone.NUMBER, "100")
472                .put(Phone.TYPE, Phone.TYPE_ISDN);
473        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
474                .put(Phone.NUMBER, "110")
475                .put(Phone.TYPE, Phone.TYPE_MAIN);
476        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
477                .put(Phone.NUMBER, "120")
478                .put(Phone.TYPE, Phone.TYPE_OTHER_FAX);
479        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
480                .put(Phone.NUMBER, "130")
481                .put(Phone.TYPE, Phone.TYPE_TELEX);
482        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
483                .put(Phone.NUMBER, "140")
484                .put(Phone.TYPE, Phone.TYPE_WORK_MOBILE);
485        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
486                .put(Phone.NUMBER, "150")
487                .put(Phone.TYPE, Phone.TYPE_WORK_PAGER);
488        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
489                .put(Phone.NUMBER, "160")
490                .put(Phone.TYPE, Phone.TYPE_MMS);
491
492        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
493                .addExpectedNode("TEL", "10", new TypeSet("HOME"))
494                .addExpectedNode("TEL", "20", new TypeSet("WORK"))
495                .addExpectedNode("TEL", "30", new TypeSet("HOME", "FAX"))
496                .addExpectedNode("TEL", "40", new TypeSet("WORK", "FAX"))
497                .addExpectedNode("TEL", "50", new TypeSet("CELL"))
498                .addExpectedNode("TEL", "60", new TypeSet("PAGER"))
499                .addExpectedNode("TEL", "70", new TypeSet("VOICE"))
500                .addExpectedNode("TEL", "80", new TypeSet("CAR"))
501                .addExpectedNode("TEL", "90", new TypeSet("WORK", "PREF"))
502                .addExpectedNode("TEL", "100", new TypeSet("ISDN"))
503                .addExpectedNode("TEL", "110", new TypeSet("PREF"))
504                .addExpectedNode("TEL", "120", new TypeSet("FAX"))
505                .addExpectedNode("TEL", "130", new TypeSet("TLX"))
506                .addExpectedNode("TEL", "140", new TypeSet("WORK", "CELL"))
507                .addExpectedNode("TEL", "150", new TypeSet("WORK", "PAGER"))
508                .addExpectedNode("TEL", "160", new TypeSet("MSG"));
509    }
510
511    public void testPhoneVariousTypeSupportV21() {
512        testPhoneVariousTypeSupport(V21);
513    }
514
515    public void testPhoneVariousTypeSupportV30() {
516        testPhoneVariousTypeSupport(V30);
517    }
518
519    public void testPhoneVariousTypeSupportV40() {
520        testPhoneVariousTypeSupport(V40);
521    }
522
523    /**
524     * Tests that "PREF"s are emitted appropriately.
525     */
526    private void testPhonePrefHandlingCommon(int vcardType) {
527        mVerifier.initForExportTest(vcardType);
528        ContactEntry entry = mVerifier.addInputEntry();
529        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
530                .put(Phone.NUMBER, "1")
531                .put(Phone.TYPE, Phone.TYPE_HOME);
532        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
533                .put(Phone.NUMBER, "2")
534                .put(Phone.TYPE, Phone.TYPE_WORK)
535                .put(Phone.IS_PRIMARY, 1);
536        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
537                .put(Phone.NUMBER, "3")
538                .put(Phone.TYPE, Phone.TYPE_FAX_HOME)
539                .put(Phone.IS_PRIMARY, 1);
540        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
541                .put(Phone.NUMBER, "4")
542                .put(Phone.TYPE, Phone.TYPE_FAX_WORK);
543
544        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
545                .addExpectedNode("TEL", "4", new TypeSet("WORK", "FAX"))
546                .addExpectedNode("TEL", "3", new TypeSet("HOME", "FAX", "PREF"))
547                .addExpectedNode("TEL", "2", new TypeSet("WORK", "PREF"))
548                .addExpectedNode("TEL", "1", new TypeSet("HOME"));
549    }
550
551    public void testPhonePrefHandlingV21() {
552        testPhonePrefHandlingCommon(V21);
553    }
554
555    public void testPhonePrefHandlingV30() {
556        testPhonePrefHandlingCommon(V30);
557    }
558
559    public void testPhonePrefHandlingV40() {
560        testPhonePrefHandlingCommon(V40);
561    }
562
563    private void testMiscPhoneTypeHandling(int vcardType) {
564        mVerifier.initForExportTest(vcardType);
565        ContactEntry entry = mVerifier.addInputEntry();
566        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
567                .put(Phone.NUMBER, "1")
568                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
569                .put(Phone.LABEL, "Modem");
570        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
571                .put(Phone.NUMBER, "2")
572                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
573                .put(Phone.LABEL, "MSG");
574        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
575                .put(Phone.NUMBER, "3")
576                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
577                .put(Phone.LABEL, "BBS");
578        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
579                .put(Phone.NUMBER, "4")
580                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
581                .put(Phone.LABEL, "VIDEO");
582        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
583                .put(Phone.NUMBER, "5")
584                .put(Phone.TYPE, Phone.TYPE_CUSTOM);
585        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
586                .put(Phone.NUMBER, "6")
587                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
588                .put(Phone.LABEL, "_AUTO_CELL");  // The old indicator for the type mobile.
589        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
590                .put(Phone.NUMBER, "7")
591                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
592                .put(Phone.LABEL, "\u643A\u5E2F");  // Mobile phone in Japanese Kanji
593        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
594                .put(Phone.NUMBER, "8")
595                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
596                .put(Phone.LABEL, "invalid");
597        PropertyNodesVerifierElem elem = mVerifier.addPropertyNodesVerifierElemWithEmptyName();
598        if (VCardConfig.isVersion30(vcardType) || VCardConfig.isVersion40(vcardType)) {
599            // vCard 3.0 accepts "invalid". Also stop using toUpper()
600            elem.addExpectedNode("TEL", "1", new TypeSet("Modem"))
601                    .addExpectedNode("TEL", "2", new TypeSet("MSG"))
602                    .addExpectedNode("TEL", "3", new TypeSet("BBS"))
603                    .addExpectedNode("TEL", "4", new TypeSet("VIDEO"))
604                    .addExpectedNode("TEL", "5", new TypeSet("VOICE"))
605                    .addExpectedNode("TEL", "6", new TypeSet("CELL"))
606                    .addExpectedNode("TEL", "7", new TypeSet("CELL"))
607                    .addExpectedNode("TEL", "8", new TypeSet("invalid"));
608        } else {
609            elem.addExpectedNode("TEL", "1", new TypeSet("MODEM"))
610                    .addExpectedNode("TEL", "2", new TypeSet("MSG"))
611                    .addExpectedNode("TEL", "3", new TypeSet("BBS"))
612                    .addExpectedNode("TEL", "4", new TypeSet("VIDEO"))
613                    .addExpectedNode("TEL", "5", new TypeSet("VOICE"))
614                    .addExpectedNode("TEL", "6", new TypeSet("CELL"))
615                    .addExpectedNode("TEL", "7", new TypeSet("CELL"))
616                    .addExpectedNode("TEL", "8", new TypeSet("X-invalid"));
617        }
618    }
619
620    public void testPhoneTypeHandlingV21() {
621        testMiscPhoneTypeHandling(V21);
622    }
623
624    public void testPhoneTypeHandlingV30() {
625        testMiscPhoneTypeHandling(V30);
626    }
627
628    public void testPhoneTypeHandlingV40() {
629        testMiscPhoneTypeHandling(V40);
630    }
631
632    private void testEmailBasicCommon(int vcardType) {
633        mVerifier.initForExportTest(vcardType);
634        mVerifier.addInputEntry().addContentValues(Email.CONTENT_ITEM_TYPE)
635                .put(Email.DATA, "sample@example.com");
636        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
637            .addExpectedNode("EMAIL", "sample@example.com");
638    }
639
640    public void testEmailBasicV21() {
641        testEmailBasicCommon(V21);
642    }
643
644    public void testEmailBasicV30() {
645        testEmailBasicCommon(V30);
646    }
647
648    public void testEmailBasicV40() {
649        testEmailBasicCommon(V40);
650    }
651
652    private void testEmailVariousTypeSupportCommon(int vcardType) {
653        mVerifier.initForExportTest(vcardType);
654        ContactEntry entry = mVerifier.addInputEntry();
655        entry.addContentValues(Email.CONTENT_ITEM_TYPE)
656                .put(Email.DATA, "type_home@example.com")
657                .put(Email.TYPE, Email.TYPE_HOME);
658        entry.addContentValues(Email.CONTENT_ITEM_TYPE)
659                .put(Email.DATA, "type_work@example.com")
660                .put(Email.TYPE, Email.TYPE_WORK);
661        entry.addContentValues(Email.CONTENT_ITEM_TYPE)
662                .put(Email.DATA, "type_mobile@example.com")
663                .put(Email.TYPE, Email.TYPE_MOBILE);
664        entry.addContentValues(Email.CONTENT_ITEM_TYPE)
665                .put(Email.DATA, "type_other@example.com")
666                .put(Email.TYPE, Email.TYPE_OTHER);
667        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
668                .addExpectedNode("EMAIL", "type_home@example.com", new TypeSet("HOME"))
669                .addExpectedNode("EMAIL", "type_work@example.com", new TypeSet("WORK"))
670                .addExpectedNode("EMAIL", "type_mobile@example.com", new TypeSet("CELL"))
671                .addExpectedNode("EMAIL", "type_other@example.com");
672    }
673
674    public void testEmailVariousTypeSupportV21() {
675        testEmailVariousTypeSupportCommon(V21);
676    }
677
678    public void testEmailVariousTypeSupportV30() {
679        testEmailVariousTypeSupportCommon(V30);
680    }
681
682    public void testEmailVariousTypeSupportV40() {
683        testEmailVariousTypeSupportCommon(V40);
684    }
685
686    private void testEmailPrefHandlingCommon(int vcardType) {
687        mVerifier.initForExportTest(vcardType);
688        ContactEntry entry = mVerifier.addInputEntry();
689        entry.addContentValues(Email.CONTENT_ITEM_TYPE)
690                .put(Email.DATA, "type_home@example.com")
691                .put(Email.TYPE, Email.TYPE_HOME)
692                .put(Email.IS_PRIMARY, 1);
693        entry.addContentValues(Email.CONTENT_ITEM_TYPE)
694                .put(Email.DATA, "type_notype@example.com")
695                .put(Email.IS_PRIMARY, 1);
696
697        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
698                .addExpectedNode("EMAIL", "type_notype@example.com", new TypeSet("PREF"))
699                .addExpectedNode("EMAIL", "type_home@example.com", new TypeSet("HOME", "PREF"));
700    }
701
702    public void testEmailPrefHandlingV21() {
703        testEmailPrefHandlingCommon(V21);
704    }
705
706    public void testEmailPrefHandlingV30() {
707        testEmailPrefHandlingCommon(V30);
708    }
709
710    public void testEmailPrefHandlingV40() {
711        testEmailPrefHandlingCommon(V40);
712    }
713
714    private void testPostalAddressCommon(int vcardType) {
715        mVerifier.initForExportTest(vcardType);
716        mVerifier.addInputEntry().addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
717                .put(StructuredPostal.POBOX, "Pobox")
718                .put(StructuredPostal.NEIGHBORHOOD, "Neighborhood")
719                .put(StructuredPostal.STREET, "Street")
720                .put(StructuredPostal.CITY, "City")
721                .put(StructuredPostal.REGION, "Region")
722                .put(StructuredPostal.POSTCODE, "100")
723                .put(StructuredPostal.COUNTRY, "Country")
724                .put(StructuredPostal.FORMATTED_ADDRESS, "Formatted Address")
725                .put(StructuredPostal.TYPE, StructuredPostal.TYPE_WORK);
726        // adr-value    = 0*6(text-value ";") text-value
727        //              ; PO Box, Extended Address, Street, Locality, Region, Postal Code,
728        //              ; Country Name
729        //
730        // The NEIGHBORHOOD field is appended after the CITY field.
731        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
732                .addExpectedNode("ADR",
733                        Arrays.asList("Pobox", "", "Street", "City Neighborhood",
734                                "Region", "100", "Country"), new TypeSet("WORK"));
735    }
736
737    public void testPostalAddressV21() {
738        testPostalAddressCommon(V21);
739    }
740
741    public void testPostalAddressV30() {
742        testPostalAddressCommon(V30);
743    }
744
745    public void testPostalAddressV40() {
746        testPostalAddressCommon(V40);
747    }
748
749    private void testPostalAddressNonNeighborhood(int vcardType) {
750        mVerifier.initForExportTest(vcardType);
751        mVerifier.addInputEntry().addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
752                .put(StructuredPostal.CITY, "City");
753        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
754                .addExpectedNode("ADR",
755                        Arrays.asList("", "", "", "City", "", "", ""), new TypeSet("HOME"));
756    }
757
758    public void testPostalAddressNonNeighborhoodV21() {
759        testPostalAddressNonNeighborhood(V21);
760    }
761
762    public void testPostalAddressNonNeighborhoodV30() {
763        testPostalAddressNonNeighborhood(V30);
764    }
765
766    public void testPostalAddressNonNeighborhoodV40() {
767        testPostalAddressNonNeighborhood(V40);
768    }
769
770    private void testPostalAddressNonCity(int vcardType) {
771        mVerifier.initForExportTest(vcardType);
772        mVerifier.addInputEntry().addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
773                .put(StructuredPostal.NEIGHBORHOOD, "Neighborhood");
774        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
775                .addExpectedNode("ADR",
776                        Arrays.asList("", "", "", "Neighborhood", "", "", ""), new TypeSet("HOME"));
777    }
778
779    public void testPostalAddressNonCityV21() {
780        testPostalAddressNonCity(V21);
781    }
782
783    public void testPostalAddressNonCityV30() {
784        testPostalAddressNonCity(V30);
785    }
786
787    public void testPostalAddressNonCityV40() {
788        testPostalAddressNonCity(V40);
789    }
790
791    private void testPostalOnlyWithFormattedAddressCommon(int vcardType) {
792        mVerifier.initForExportTest(vcardType);
793        mVerifier.addInputEntry().addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
794                .put(StructuredPostal.REGION, "")  // Must be ignored.
795                .put(StructuredPostal.FORMATTED_ADDRESS,
796                "Formatted address CA 123-334 United Statue");
797        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
798                .addExpectedNodeWithOrder("ADR", ";Formatted address CA 123-334 United Statue;;;;;",
799                        Arrays.asList("", "Formatted address CA 123-334 United Statue",
800                                "", "", "", "", ""), new TypeSet("HOME"));
801    }
802
803    public void testPostalOnlyWithFormattedAddressV21() {
804        testPostalOnlyWithFormattedAddressCommon(V21);
805    }
806
807    public void testPostalOnlyWithFormattedAddressV30() {
808        testPostalOnlyWithFormattedAddressCommon(V30);
809    }
810
811    public void testPostalOnlyWithFormattedAddressV40() {
812        testPostalOnlyWithFormattedAddressCommon(V40);
813    }
814
815    /**
816     * Tests that the vCard composer honors formatted data when it is available
817     * even when it is partial.
818     */
819    private void testPostalWithBothStructuredAndFormattedCommon(int vcardType) {
820        mVerifier.initForExportTest(vcardType);
821        mVerifier.addInputEntry().addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
822                .put(StructuredPostal.POBOX, "Pobox")
823                .put(StructuredPostal.COUNTRY, "Country")
824                .put(StructuredPostal.FORMATTED_ADDRESS,
825                        "Formatted address CA 123-334 United Statue");  // Should be ignored
826        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
827                .addExpectedNode("ADR", "Pobox;;;;;;Country",
828                        Arrays.asList("Pobox", "", "", "", "", "", "Country"),
829                        new TypeSet("HOME"));
830    }
831
832    public void testPostalWithBothStructuredAndFormattedV21() {
833        testPostalWithBothStructuredAndFormattedCommon(V21);
834    }
835
836    public void testPostalWithBothStructuredAndFormattedV30() {
837        testPostalWithBothStructuredAndFormattedCommon(V30);
838    }
839
840    public void testPostalWithBothStructuredAndFormattedV40() {
841        testPostalWithBothStructuredAndFormattedCommon(V40);
842    }
843
844    private void testOrganizationCommon(int vcardType) {
845        mVerifier.initForExportTest(vcardType);
846        ContactEntry entry = mVerifier.addInputEntry();
847        entry.addContentValues(Organization.CONTENT_ITEM_TYPE)
848                .put(Organization.COMPANY, "CompanyX")
849                .put(Organization.DEPARTMENT, "DepartmentY")
850                .put(Organization.TITLE, "TitleZ")
851                .put(Organization.JOB_DESCRIPTION, "Description Rambda")  // Ignored.
852                .put(Organization.OFFICE_LOCATION, "Mountain View")  // Ignored.
853                .put(Organization.PHONETIC_NAME, "PhoneticName!")  // Ignored
854                .put(Organization.SYMBOL, "(^o^)/~~");  // Ignore him (her).
855        entry.addContentValues(Organization.CONTENT_ITEM_TYPE)
856                .putNull(Organization.COMPANY)
857                .put(Organization.DEPARTMENT, "DepartmentXX")
858                .putNull(Organization.TITLE);
859        entry.addContentValues(Organization.CONTENT_ITEM_TYPE)
860                .put(Organization.COMPANY, "CompanyXYZ")
861                .putNull(Organization.DEPARTMENT)
862                .put(Organization.TITLE, "TitleXYZYX");
863        // Currently we do not use group but depend on the order.
864        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
865                .addExpectedNodeWithOrder("ORG", "CompanyX;DepartmentY",
866                        Arrays.asList("CompanyX", "DepartmentY"))
867                .addExpectedNodeWithOrder("TITLE", "TitleZ")
868                .addExpectedNodeWithOrder("ORG", "DepartmentXX")
869                .addExpectedNodeWithOrder("ORG", "CompanyXYZ")
870                .addExpectedNodeWithOrder("TITLE", "TitleXYZYX");
871    }
872
873    public void testOrganizationV21() {
874        testOrganizationCommon(V21);
875    }
876
877    public void testOrganizationV30() {
878        testOrganizationCommon(V30);
879    }
880
881    public void testOrganizationV40() {
882        testOrganizationCommon(V40);
883    }
884
885    private void testImVariousTypeSupportCommon(int vcardType) {
886        mVerifier.initForExportTest(vcardType);
887        ContactEntry entry = mVerifier.addInputEntry();
888        entry.addContentValues(Im.CONTENT_ITEM_TYPE)
889                .put(Im.PROTOCOL, Im.PROTOCOL_AIM)
890                .put(Im.DATA, "aim");
891        entry.addContentValues(Im.CONTENT_ITEM_TYPE)
892                .put(Im.PROTOCOL, Im.PROTOCOL_MSN)
893                .put(Im.DATA, "msn");
894        entry.addContentValues(Im.CONTENT_ITEM_TYPE)
895                .put(Im.PROTOCOL, Im.PROTOCOL_YAHOO)
896                .put(Im.DATA, "yahoo");
897        entry.addContentValues(Im.CONTENT_ITEM_TYPE)
898                .put(Im.PROTOCOL, Im.PROTOCOL_SKYPE)
899                .put(Im.DATA, "skype");
900        entry.addContentValues(Im.CONTENT_ITEM_TYPE)
901                .put(Im.PROTOCOL, Im.PROTOCOL_QQ)
902                .put(Im.DATA, "qq");
903        entry.addContentValues(Im.CONTENT_ITEM_TYPE)
904                .put(Im.PROTOCOL, Im.PROTOCOL_GOOGLE_TALK)
905                .put(Im.DATA, "google talk");
906        entry.addContentValues(Im.CONTENT_ITEM_TYPE)
907                .put(Im.PROTOCOL, Im.PROTOCOL_ICQ)
908                .put(Im.DATA, "icq");
909        entry.addContentValues(Im.CONTENT_ITEM_TYPE)
910                .put(Im.PROTOCOL, Im.PROTOCOL_JABBER)
911                .put(Im.DATA, "jabber");
912        entry.addContentValues(Im.CONTENT_ITEM_TYPE)
913                .put(Im.PROTOCOL, Im.PROTOCOL_NETMEETING)
914                .put(Im.DATA, "netmeeting");
915
916        // No determined way to express unknown type...
917        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
918                .addExpectedNode("X-JABBER", "jabber")
919                .addExpectedNode("X-ICQ", "icq")
920                .addExpectedNode("X-GOOGLE-TALK", "google talk")
921                .addExpectedNode("X-QQ", "qq")
922                .addExpectedNode("X-SKYPE-USERNAME", "skype")
923                .addExpectedNode("X-YAHOO", "yahoo")
924                .addExpectedNode("X-MSN", "msn")
925                .addExpectedNode("X-NETMEETING", "netmeeting")
926                .addExpectedNode("X-AIM", "aim");
927    }
928
929    public void testImBasiV21() {
930        testImVariousTypeSupportCommon(V21);
931    }
932
933    public void testImBasicV30() {
934        testImVariousTypeSupportCommon(V30);
935    }
936
937    public void testImBasicV40() {
938        testImVariousTypeSupportCommon(V40);
939    }
940
941    private void testImPrefHandlingCommon(int vcardType) {
942        mVerifier.initForExportTest(vcardType);
943        ContactEntry entry = mVerifier.addInputEntry();
944        entry.addContentValues(Im.CONTENT_ITEM_TYPE)
945                .put(Im.PROTOCOL, Im.PROTOCOL_AIM)
946                .put(Im.DATA, "aim1");
947        entry.addContentValues(Im.CONTENT_ITEM_TYPE)
948                .put(Im.PROTOCOL, Im.PROTOCOL_AIM)
949                .put(Im.DATA, "aim2")
950                .put(Im.TYPE, Im.TYPE_HOME)
951                .put(Im.IS_PRIMARY, 1);
952
953        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
954                .addExpectedNode("X-AIM", "aim1")
955                .addExpectedNode("X-AIM", "aim2", new TypeSet("HOME", "PREF"));
956    }
957
958    public void testImPrefHandlingV21() {
959        testImPrefHandlingCommon(V21);
960    }
961
962    public void testImPrefHandlingV30() {
963        testImPrefHandlingCommon(V30);
964    }
965
966    public void testImPrefHandlingV40() {
967        testImPrefHandlingCommon(V40);
968    }
969
970    private void testWebsiteCommon(int vcardType) {
971        mVerifier.initForExportTest(vcardType);
972        ContactEntry entry = mVerifier.addInputEntry();
973        entry.addContentValues(Website.CONTENT_ITEM_TYPE)
974                .put(Website.URL, "http://website.example.android.com/index.html")
975                .put(Website.TYPE, Website.TYPE_BLOG);
976        entry.addContentValues(Website.CONTENT_ITEM_TYPE)
977                .put(Website.URL, "ftp://ftp.example.android.com/index.html")
978                .put(Website.TYPE, Website.TYPE_FTP);
979
980        // We drop TYPE information since vCard (especially 3.0) does not allow us to emit it.
981        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
982                .addExpectedNode("URL", "ftp://ftp.example.android.com/index.html")
983                .addExpectedNode("URL", "http://website.example.android.com/index.html");
984    }
985
986    public void testWebsiteV21() {
987        testWebsiteCommon(V21);
988    }
989
990    public void testWebsiteV30() {
991        testWebsiteCommon(V30);
992    }
993
994    public void testWebsiteV40() {
995        testWebsiteCommon(V40);
996    }
997
998    private String getAndroidPropValue(final String mimeType, String value, Integer type) {
999        return getAndroidPropValue(mimeType, value, type, null);
1000    }
1001
1002    private String getAndroidPropValue(final String mimeType, String value,
1003            Integer type, String label) {
1004        return (mimeType + ";" + value + ";"
1005                + (type != null ? type : "") + ";"
1006                + (label != null ? label : "") + ";;;;;;;;;;;;");
1007    }
1008
1009    private void testEventCommon(int vcardType) {
1010        mVerifier.initForExportTest(vcardType);
1011        ContactEntry entry = mVerifier.addInputEntry();
1012        entry.addContentValues(Event.CONTENT_ITEM_TYPE)
1013                .put(Event.TYPE, Event.TYPE_ANNIVERSARY)
1014                .put(Event.START_DATE, "1982-06-16");
1015        entry.addContentValues(Event.CONTENT_ITEM_TYPE)
1016                .put(Event.TYPE, Event.TYPE_BIRTHDAY)
1017                .put(Event.START_DATE, "2008-10-22");
1018        entry.addContentValues(Event.CONTENT_ITEM_TYPE)
1019                .put(Event.TYPE, Event.TYPE_OTHER)
1020                .put(Event.START_DATE, "2018-03-12");
1021        entry.addContentValues(Event.CONTENT_ITEM_TYPE)
1022                .put(Event.TYPE, Event.TYPE_CUSTOM)
1023                .put(Event.LABEL, "The last day")
1024                .put(Event.START_DATE, "When the Tower of Hanoi with 64 rings is completed.");
1025        entry.addContentValues(Event.CONTENT_ITEM_TYPE)
1026                .put(Event.TYPE, Event.TYPE_BIRTHDAY)
1027                .put(Event.START_DATE, "2009-05-19");  // Should be ignored.
1028        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
1029                .addExpectedNode("BDAY", "2008-10-22")
1030                .addExpectedNode("X-ANDROID-CUSTOM",
1031                        getAndroidPropValue(
1032                                Event.CONTENT_ITEM_TYPE, "1982-06-16", Event.TYPE_ANNIVERSARY))
1033                .addExpectedNode("X-ANDROID-CUSTOM",
1034                        getAndroidPropValue(
1035                                Event.CONTENT_ITEM_TYPE, "2018-03-12", Event.TYPE_OTHER))
1036                .addExpectedNode("X-ANDROID-CUSTOM",
1037                        getAndroidPropValue(
1038                                Event.CONTENT_ITEM_TYPE,
1039                                "When the Tower of Hanoi with 64 rings is completed.",
1040                                Event.TYPE_CUSTOM, "The last day"));
1041    }
1042
1043    public void testEventV21() {
1044        testEventCommon(V21);
1045    }
1046
1047    public void testEventV30() {
1048        testEventCommon(V30);
1049    }
1050
1051    public void testEventV40() {
1052        testEventCommon(V40);
1053    }
1054
1055    private void testNoteCommon(int vcardType) {
1056        mVerifier.initForExportTest(vcardType);
1057        ContactEntry entry = mVerifier.addInputEntry();
1058        entry.addContentValues(Note.CONTENT_ITEM_TYPE)
1059                .put(Note.NOTE, "note1");
1060        entry.addContentValues(Note.CONTENT_ITEM_TYPE)
1061                .put(Note.NOTE, "note2")
1062                .put(Note.IS_PRIMARY, 1);  // Just ignored.
1063        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
1064                .addExpectedNodeWithOrder("NOTE", "note1")
1065                .addExpectedNodeWithOrder("NOTE", "note2");
1066    }
1067
1068    public void testNoteV21() {
1069        testNoteCommon(V21);
1070    }
1071
1072    public void testNoteV30() {
1073        testNoteCommon(V30);
1074    }
1075
1076    public void testNoteV40() {
1077        testNoteCommon(V40);
1078    }
1079
1080    private void testPhotoCommon(int vcardType) {
1081        final boolean useB =
1082            (VCardConfig.isVersion30(vcardType) || VCardConfig.isVersion40(vcardType));
1083        mVerifier.initForExportTest(vcardType);
1084        ContactEntry entry = mVerifier.addInputEntry();
1085        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
1086                .put(StructuredName.FAMILY_NAME, "PhotoTest");
1087        entry.addContentValues(Photo.CONTENT_ITEM_TYPE)
1088                .put(Photo.PHOTO, sPhotoByteArray);
1089
1090        ContentValues contentValuesForPhoto = new ContentValues();
1091        contentValuesForPhoto.put("ENCODING", (useB ? "b" : "BASE64"));
1092        mVerifier.addPropertyNodesVerifierElem()
1093                .addExpectedNode("FN", "PhotoTest")
1094                .addExpectedNode("N", "PhotoTest;;;;",
1095                        Arrays.asList("PhotoTest", "", "", "", ""))
1096                .addExpectedNodeWithOrder("PHOTO", null, null, sPhotoByteArray,
1097                        contentValuesForPhoto, new TypeSet("JPEG"), null);
1098    }
1099
1100    public void testPhotoV21() {
1101        testPhotoCommon(V21);
1102    }
1103
1104    public void testPhotoV30() {
1105        testPhotoCommon(V30);
1106    }
1107
1108    public void testPhotoV40() {
1109        testPhotoCommon(V40);
1110    }
1111
1112    private void testRelationCommon(int vcardType) {
1113        mVerifier.initForExportTest(vcardType);
1114        mVerifier.addInputEntry().addContentValues(Relation.CONTENT_ITEM_TYPE)
1115                .put(Relation.TYPE, Relation.TYPE_MOTHER)
1116                .put(Relation.NAME, "Ms. Mother");
1117        mVerifier.addContentValuesVerifierElem().addExpected(Relation.CONTENT_ITEM_TYPE)
1118                .put(Relation.TYPE, Relation.TYPE_MOTHER)
1119                .put(Relation.NAME, "Ms. Mother");
1120    }
1121
1122    public void testRelationV21() {
1123        testRelationCommon(V21);
1124    }
1125
1126    public void testRelationV30() {
1127        testRelationCommon(V30);
1128    }
1129
1130    public void testV30HandleEscape() {
1131        mVerifier.initForExportTest(V30);
1132        mVerifier.addInputEntry().addContentValues(StructuredName.CONTENT_ITEM_TYPE)
1133                .put(StructuredName.FAMILY_NAME, "\\")
1134                .put(StructuredName.GIVEN_NAME, ";")
1135                .put(StructuredName.MIDDLE_NAME, ",")
1136                .put(StructuredName.PREFIX, "\n")
1137                .put(StructuredName.DISPLAY_NAME, "[<{Unescaped:Asciis}>]");
1138        // Verifies the vCard String correctly escapes each character which must be escaped.
1139        mVerifier.addLineVerifierElem()
1140                .addExpected("N:\\\\;\\;;\\,;\\n;")
1141                .addExpected("FN:[<{Unescaped:Asciis}>]");
1142        mVerifier.addPropertyNodesVerifierElem()
1143                .addExpectedNode("FN", "[<{Unescaped:Asciis}>]")
1144                .addExpectedNode("N", Arrays.asList("\\", ";", ",", "\n", ""));
1145    }
1146
1147    /**
1148     * There's no "NICKNAME" property in vCard 2.1, while there is in vCard 3.0.
1149     * We use Android-specific "X-ANDROID-CUSTOM" property.
1150     * This test verifies the functionality.
1151     */
1152    public void testNickNameV21() {
1153        mVerifier.initForExportTest(V21);
1154        mVerifier.addInputEntry().addContentValues(Nickname.CONTENT_ITEM_TYPE)
1155                .put(Nickname.NAME, "Nicky");
1156        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
1157                .addExpectedNode("X-ANDROID-CUSTOM",
1158                        Nickname.CONTENT_ITEM_TYPE + ";Nicky;;;;;;;;;;;;;;");
1159        mVerifier.addContentValuesVerifierElem().addExpected(Nickname.CONTENT_ITEM_TYPE)
1160                .put(Nickname.NAME, "Nicky");
1161    }
1162
1163    public void testTolerateBrokenPhoneNumberEntryV21() {
1164        mVerifier.initForExportTest(V21);
1165        ContactEntry entry = mVerifier.addInputEntry();
1166        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
1167                .put(Phone.TYPE, Phone.TYPE_HOME)
1168                .put(Phone.NUMBER, "111-222-3333 (Miami)\n444-5555-666 (Tokyo);"
1169                        + "777-888-9999 (Chicago);111-222-3333 (Miami)");
1170        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
1171                .addExpectedNode("TEL", "111-222-3333", new TypeSet("HOME"))
1172                .addExpectedNode("TEL", "444-555-5666", new TypeSet("HOME"))
1173                .addExpectedNode("TEL", "777-888-9999", new TypeSet("HOME"));
1174    }
1175
1176    private void testPickUpNonEmptyContentValuesCommon(int vcardType) {
1177        mVerifier.initForExportTest(vcardType);
1178        ContactEntry entry = mVerifier.addInputEntry();
1179        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
1180                .put(StructuredName.IS_PRIMARY, 1);  // Empty name. Should be ignored.
1181        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
1182                .put(StructuredName.FAMILY_NAME, "family1")  // Not primary. Should be ignored.
1183                .put(StructuredName.DISPLAY_NAME, "display");
1184        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
1185                .put(StructuredName.IS_PRIMARY, 1)
1186                .put(StructuredName.FAMILY_NAME, "family2")  // This entry is what we want.
1187                .put(StructuredName.DISPLAY_NAME, "display");
1188        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
1189                .put(StructuredName.IS_PRIMARY, 1)
1190                .put(StructuredName.FAMILY_NAME, "family3")
1191                .put(StructuredName.DISPLAY_NAME, "display");
1192        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
1193                .put(StructuredName.FAMILY_NAME, "family4")
1194                .put(StructuredName.DISPLAY_NAME, "display");
1195        mVerifier.addPropertyNodesVerifierElem()
1196                .addExpectedNode("N", Arrays.asList("family2", "", "", "", ""))
1197                .addExpectedNode("FN", "display");
1198    }
1199
1200    public void testPickUpNonEmptyContentValuesV21() {
1201        testPickUpNonEmptyContentValuesCommon(V21);
1202    }
1203
1204    public void testPickUpNonEmptyContentValuesV30() {
1205        testPickUpNonEmptyContentValuesCommon(V30);
1206    }
1207
1208    public void testPickUpNonEmptyContentValuesV40() {
1209        testPickUpNonEmptyContentValuesCommon(V40);
1210    }
1211
1212    public void testUseMultiByteTypeV30() {
1213        mVerifier.initForExportTest(V30);
1214        final ContactEntry entry = mVerifier.addInputEntry();
1215        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
1216                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
1217                .put(Phone.LABEL, "\u96FB\u8A71")
1218                .put(Phone.NUMBER, "1");
1219        mVerifier.addLineVerifierElem()
1220                .addExpected("N:")
1221                .addExpected("FN:")
1222                .addExpected("TEL;TYPE=\u96FB\u8A71:1");
1223        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
1224                .addExpectedNode("TEL", "1", new TypeSet("\u96FB\u8A71"));
1225    }
1226
1227    public void testSipAddressV21() {
1228        mVerifier.initForExportTest(V21);
1229        final ContactEntry entry = mVerifier.addInputEntry();
1230        entry.addContentValues(SipAddress.CONTENT_ITEM_TYPE)
1231                .put(SipAddress.SIP_ADDRESS, "gold");
1232        mVerifier.addLineVerifierElem()
1233                .addExpected("X-SIP:gold");
1234        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
1235                .addExpectedNode("X-SIP", "gold");
1236    }
1237
1238    public void testSipAddressV30() {
1239        mVerifier.initForExportTest(V30);
1240        final ContactEntry entry = mVerifier.addInputEntry();
1241        entry.addContentValues(SipAddress.CONTENT_ITEM_TYPE)
1242                .put(SipAddress.SIP_ADDRESS, "android@example.com");
1243        mVerifier.addLineVerifierElem()
1244                .addExpected("N:")
1245                .addExpected("FN:")
1246                .addExpected("IMPP:sip:android@example.com");
1247        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
1248                .addExpectedNode("IMPP", "sip:android@example.com");
1249    }
1250
1251    public void testSipAddressV40() {
1252        mVerifier.initForExportTest(V40);
1253        final ContactEntry entry = mVerifier.addInputEntry();
1254        entry.addContentValues(SipAddress.CONTENT_ITEM_TYPE)
1255                .put(SipAddress.SIP_ADDRESS, "android@example.com");
1256        mVerifier.addLineVerifierElem()
1257                .addExpected("FN:")
1258                .addExpected("IMPP:sip:android@example.com");
1259        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
1260                .addExpectedNode("IMPP", "sip:android@example.com");
1261    }
1262}
1263