VCardExporterTests.java revision 95e66b00988bc16ecc17df31e47c873b2554b8cc
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.testutils.ContactEntry;
21import com.android.vcard.tests.testutils.PropertyNodesVerifierElem;
22import com.android.vcard.tests.testutils.PropertyNodesVerifierElem.TypeSet;
23import com.android.vcard.tests.testutils.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        if (VCardConfig.isVersion40(vcardType)) {
412            mVerifier.addPropertyNodesVerifierElemWithEmptyName()
413                    .addExpectedNode("TEL", "tel:1", new TypeSet("HOME"));
414        } else {
415            mVerifier.addPropertyNodesVerifierElemWithEmptyName()
416                    .addExpectedNode("TEL", "1", new TypeSet("HOME"));
417        }
418    }
419
420    public void testPhoneBasicV21() {
421        testPhoneBasicCommon(V21);
422    }
423
424    public void testPhoneBasicV30() {
425        testPhoneBasicCommon(V30);
426    }
427
428    public void testPhoneBasicV40() {
429        testPhoneBasicCommon(V40);
430    }
431
432    public void testPhoneRefrainFormatting() {
433        mVerifier.initForExportTest(V21 | VCardConfig.FLAG_REFRAIN_PHONE_NUMBER_FORMATTING);
434        mVerifier.addInputEntry().addContentValues(Phone.CONTENT_ITEM_TYPE)
435                .put(Phone.NUMBER, "1234567890(abcdefghijklmnopqrstuvwxyz)")
436                .put(Phone.TYPE, Phone.TYPE_HOME);
437        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
438                .addExpectedNode("TEL", "1234567890(abcdefghijklmnopqrstuvwxyz)",
439                        new TypeSet("HOME"));
440    }
441
442    /**
443     * Tests that vCard composer emits corresponding type param which we expect.
444     */
445    private void testPhoneVariousTypeSupport(int vcardType) {
446        mVerifier.initForExportTest(vcardType);
447        ContactEntry entry = mVerifier.addInputEntry();
448        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
449                .put(Phone.NUMBER, "10")
450                .put(Phone.TYPE, Phone.TYPE_HOME);
451        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
452                .put(Phone.NUMBER, "20")
453                .put(Phone.TYPE, Phone.TYPE_WORK);
454        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
455                .put(Phone.NUMBER, "30")
456                .put(Phone.TYPE, Phone.TYPE_FAX_HOME);
457        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
458                .put(Phone.NUMBER, "40")
459                .put(Phone.TYPE, Phone.TYPE_FAX_WORK);
460        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
461                .put(Phone.NUMBER, "50")
462                .put(Phone.TYPE, Phone.TYPE_MOBILE);
463        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
464                .put(Phone.NUMBER, "60")
465                .put(Phone.TYPE, Phone.TYPE_PAGER);
466        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
467                .put(Phone.NUMBER, "70")
468                .put(Phone.TYPE, Phone.TYPE_OTHER);
469        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
470                .put(Phone.NUMBER, "80")
471                .put(Phone.TYPE, Phone.TYPE_CAR);
472        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
473                .put(Phone.NUMBER, "90")
474                .put(Phone.TYPE, Phone.TYPE_COMPANY_MAIN);
475        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
476                .put(Phone.NUMBER, "100")
477                .put(Phone.TYPE, Phone.TYPE_ISDN);
478        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
479                .put(Phone.NUMBER, "110")
480                .put(Phone.TYPE, Phone.TYPE_MAIN);
481        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
482                .put(Phone.NUMBER, "120")
483                .put(Phone.TYPE, Phone.TYPE_OTHER_FAX);
484        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
485                .put(Phone.NUMBER, "130")
486                .put(Phone.TYPE, Phone.TYPE_TELEX);
487        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
488                .put(Phone.NUMBER, "140")
489                .put(Phone.TYPE, Phone.TYPE_WORK_MOBILE);
490        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
491                .put(Phone.NUMBER, "150")
492                .put(Phone.TYPE, Phone.TYPE_WORK_PAGER);
493        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
494                .put(Phone.NUMBER, "160")
495                .put(Phone.TYPE, Phone.TYPE_MMS);
496
497        if (VCardConfig.isVersion40(vcardType)) {
498            // Currently pager type has special logic...
499            mVerifier.addPropertyNodesVerifierElemWithEmptyName()
500                    .addExpectedNode("TEL", "tel:10", new TypeSet("HOME"))
501                    .addExpectedNode("TEL", "tel:20", new TypeSet("WORK"))
502                    .addExpectedNode("TEL", "tel:30", new TypeSet("HOME", "FAX"))
503                    .addExpectedNode("TEL", "tel:40", new TypeSet("WORK", "FAX"))
504                    .addExpectedNode("TEL", "tel:50", new TypeSet("CELL"))
505                    .addExpectedNode("TEL", "60", new TypeSet("PAGER"))
506                    .addExpectedNode("TEL", "tel:70", new TypeSet("VOICE"))
507                    .addExpectedNode("TEL", "tel:80", new TypeSet("CAR"))
508                    .addExpectedNode("TEL", "tel:90", new TypeSet("WORK", "PREF"))
509                    .addExpectedNode("TEL", "tel:100", new TypeSet("ISDN"))
510                    .addExpectedNode("TEL", "tel:110", new TypeSet("PREF"))
511                    .addExpectedNode("TEL", "tel:120", new TypeSet("FAX"))
512                    .addExpectedNode("TEL", "tel:130", new TypeSet("TLX"))
513                    .addExpectedNode("TEL", "tel:140", new TypeSet("WORK", "CELL"))
514                    .addExpectedNode("TEL", "tel:150", new TypeSet("WORK", "PAGER"))
515                    .addExpectedNode("TEL", "tel:160", new TypeSet("MSG"));
516        } else {
517            mVerifier.addPropertyNodesVerifierElemWithEmptyName()
518                    .addExpectedNode("TEL", "10", new TypeSet("HOME"))
519                    .addExpectedNode("TEL", "20", new TypeSet("WORK"))
520                    .addExpectedNode("TEL", "30", new TypeSet("HOME", "FAX"))
521                    .addExpectedNode("TEL", "40", new TypeSet("WORK", "FAX"))
522                    .addExpectedNode("TEL", "50", new TypeSet("CELL"))
523                    .addExpectedNode("TEL", "60", new TypeSet("PAGER"))
524                    .addExpectedNode("TEL", "70", new TypeSet("VOICE"))
525                    .addExpectedNode("TEL", "80", new TypeSet("CAR"))
526                    .addExpectedNode("TEL", "90", new TypeSet("WORK", "PREF"))
527                    .addExpectedNode("TEL", "100", new TypeSet("ISDN"))
528                    .addExpectedNode("TEL", "110", new TypeSet("PREF"))
529                    .addExpectedNode("TEL", "120", new TypeSet("FAX"))
530                    .addExpectedNode("TEL", "130", new TypeSet("TLX"))
531                    .addExpectedNode("TEL", "140", new TypeSet("WORK", "CELL"))
532                    .addExpectedNode("TEL", "150", new TypeSet("WORK", "PAGER"))
533                    .addExpectedNode("TEL", "160", new TypeSet("MSG"));
534        }
535    }
536
537    public void testPhoneVariousTypeSupportV21() {
538        testPhoneVariousTypeSupport(V21);
539    }
540
541    public void testPhoneVariousTypeSupportV30() {
542        testPhoneVariousTypeSupport(V30);
543    }
544
545    public void testPhoneVariousTypeSupportV40() {
546        testPhoneVariousTypeSupport(V40);
547    }
548
549    /**
550     * Tests that "PREF"s are emitted appropriately.
551     */
552    private void testPhonePrefHandlingCommon(int vcardType) {
553        mVerifier.initForExportTest(vcardType);
554        ContactEntry entry = mVerifier.addInputEntry();
555        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
556                .put(Phone.NUMBER, "1")
557                .put(Phone.TYPE, Phone.TYPE_HOME);
558        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
559                .put(Phone.NUMBER, "2")
560                .put(Phone.TYPE, Phone.TYPE_WORK)
561                .put(Phone.IS_PRIMARY, 1);
562        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
563                .put(Phone.NUMBER, "3")
564                .put(Phone.TYPE, Phone.TYPE_FAX_HOME)
565                .put(Phone.IS_PRIMARY, 1);
566        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
567                .put(Phone.NUMBER, "4")
568                .put(Phone.TYPE, Phone.TYPE_FAX_WORK);
569
570        if (VCardConfig.isVersion40(vcardType)) {
571            mVerifier.addPropertyNodesVerifierElemWithEmptyName()
572                    .addExpectedNode("TEL", "tel:4", new TypeSet("WORK", "FAX"))
573                    .addExpectedNode("TEL", "tel:3", new TypeSet("HOME", "FAX", "PREF"))
574                    .addExpectedNode("TEL", "tel:2", new TypeSet("WORK", "PREF"))
575                    .addExpectedNode("TEL", "tel:1", new TypeSet("HOME"));
576        } else {
577            mVerifier.addPropertyNodesVerifierElemWithEmptyName()
578                    .addExpectedNode("TEL", "4", new TypeSet("WORK", "FAX"))
579                    .addExpectedNode("TEL", "3", new TypeSet("HOME", "FAX", "PREF"))
580                    .addExpectedNode("TEL", "2", new TypeSet("WORK", "PREF"))
581                    .addExpectedNode("TEL", "1", new TypeSet("HOME"));
582        }
583    }
584
585    public void testPhonePrefHandlingV21() {
586        testPhonePrefHandlingCommon(V21);
587    }
588
589    public void testPhonePrefHandlingV30() {
590        testPhonePrefHandlingCommon(V30);
591    }
592
593    public void testPhonePrefHandlingV40() {
594        testPhonePrefHandlingCommon(V40);
595    }
596
597    private void testMiscPhoneTypeHandling(int vcardType) {
598        mVerifier.initForExportTest(vcardType);
599        ContactEntry entry = mVerifier.addInputEntry();
600        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
601                .put(Phone.NUMBER, "1")
602                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
603                .put(Phone.LABEL, "Modem");
604        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
605                .put(Phone.NUMBER, "2")
606                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
607                .put(Phone.LABEL, "MSG");
608        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
609                .put(Phone.NUMBER, "3")
610                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
611                .put(Phone.LABEL, "BBS");
612        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
613                .put(Phone.NUMBER, "4")
614                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
615                .put(Phone.LABEL, "VIDEO");
616        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
617                .put(Phone.NUMBER, "5")
618                .put(Phone.TYPE, Phone.TYPE_CUSTOM);
619        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
620                .put(Phone.NUMBER, "6")
621                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
622                .put(Phone.LABEL, "_AUTO_CELL");  // The old indicator for the type mobile.
623        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
624                .put(Phone.NUMBER, "7")
625                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
626                .put(Phone.LABEL, "\u643A\u5E2F");  // Mobile phone in Japanese Kanji
627        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
628                .put(Phone.NUMBER, "8")
629                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
630                .put(Phone.LABEL, "invalid");
631        PropertyNodesVerifierElem elem = mVerifier.addPropertyNodesVerifierElemWithEmptyName();
632        if (VCardConfig.isVersion40(vcardType)) {
633            // vCard 4.0 (rev.13) does not allow bare number but URI.
634            elem.addExpectedNode("TEL", "tel:1", new TypeSet("Modem"))
635                    .addExpectedNode("TEL", "tel:2", new TypeSet("MSG"))
636                    .addExpectedNode("TEL", "tel:3", new TypeSet("BBS"))
637                    .addExpectedNode("TEL", "tel:4", new TypeSet("VIDEO"))
638                    .addExpectedNode("TEL", "tel:5", new TypeSet("VOICE"))
639                    .addExpectedNode("TEL", "tel:6", new TypeSet("CELL"))
640                    .addExpectedNode("TEL", "tel:7", new TypeSet("CELL"))
641                    .addExpectedNode("TEL", "tel:8", new TypeSet("invalid"));
642        } else if (VCardConfig.isVersion30(vcardType)) {
643            // vCard 3.0 accepts "invalid". Also stop using toUpper()
644            elem.addExpectedNode("TEL", "1", new TypeSet("Modem"))
645                    .addExpectedNode("TEL", "2", new TypeSet("MSG"))
646                    .addExpectedNode("TEL", "3", new TypeSet("BBS"))
647                    .addExpectedNode("TEL", "4", new TypeSet("VIDEO"))
648                    .addExpectedNode("TEL", "5", new TypeSet("VOICE"))
649                    .addExpectedNode("TEL", "6", new TypeSet("CELL"))
650                    .addExpectedNode("TEL", "7", new TypeSet("CELL"))
651                    .addExpectedNode("TEL", "8", new TypeSet("invalid"));
652        } else {
653            elem.addExpectedNode("TEL", "1", new TypeSet("MODEM"))
654                    .addExpectedNode("TEL", "2", new TypeSet("MSG"))
655                    .addExpectedNode("TEL", "3", new TypeSet("BBS"))
656                    .addExpectedNode("TEL", "4", new TypeSet("VIDEO"))
657                    .addExpectedNode("TEL", "5", new TypeSet("VOICE"))
658                    .addExpectedNode("TEL", "6", new TypeSet("CELL"))
659                    .addExpectedNode("TEL", "7", new TypeSet("CELL"))
660                    .addExpectedNode("TEL", "8", new TypeSet("X-invalid"));
661        }
662    }
663
664    public void testPhoneTypeHandlingV21() {
665        testMiscPhoneTypeHandling(V21);
666    }
667
668    public void testPhoneTypeHandlingV30() {
669        testMiscPhoneTypeHandling(V30);
670    }
671
672    public void testPhoneTypeHandlingV40() {
673        testMiscPhoneTypeHandling(V40);
674    }
675
676    private void testEmailBasicCommon(int vcardType) {
677        mVerifier.initForExportTest(vcardType);
678        mVerifier.addInputEntry().addContentValues(Email.CONTENT_ITEM_TYPE)
679                .put(Email.DATA, "sample@example.com");
680        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
681            .addExpectedNode("EMAIL", "sample@example.com");
682    }
683
684    public void testEmailBasicV21() {
685        testEmailBasicCommon(V21);
686    }
687
688    public void testEmailBasicV30() {
689        testEmailBasicCommon(V30);
690    }
691
692    public void testEmailBasicV40() {
693        testEmailBasicCommon(V40);
694    }
695
696    private void testEmailVariousTypeSupportCommon(int vcardType) {
697        mVerifier.initForExportTest(vcardType);
698        ContactEntry entry = mVerifier.addInputEntry();
699        entry.addContentValues(Email.CONTENT_ITEM_TYPE)
700                .put(Email.DATA, "type_home@example.com")
701                .put(Email.TYPE, Email.TYPE_HOME);
702        entry.addContentValues(Email.CONTENT_ITEM_TYPE)
703                .put(Email.DATA, "type_work@example.com")
704                .put(Email.TYPE, Email.TYPE_WORK);
705        entry.addContentValues(Email.CONTENT_ITEM_TYPE)
706                .put(Email.DATA, "type_mobile@example.com")
707                .put(Email.TYPE, Email.TYPE_MOBILE);
708        entry.addContentValues(Email.CONTENT_ITEM_TYPE)
709                .put(Email.DATA, "type_other@example.com")
710                .put(Email.TYPE, Email.TYPE_OTHER);
711        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
712                .addExpectedNode("EMAIL", "type_home@example.com", new TypeSet("HOME"))
713                .addExpectedNode("EMAIL", "type_work@example.com", new TypeSet("WORK"))
714                .addExpectedNode("EMAIL", "type_mobile@example.com", new TypeSet("CELL"))
715                .addExpectedNode("EMAIL", "type_other@example.com");
716    }
717
718    public void testEmailVariousTypeSupportV21() {
719        testEmailVariousTypeSupportCommon(V21);
720    }
721
722    public void testEmailVariousTypeSupportV30() {
723        testEmailVariousTypeSupportCommon(V30);
724    }
725
726    public void testEmailVariousTypeSupportV40() {
727        testEmailVariousTypeSupportCommon(V40);
728    }
729
730    private void testEmailPrefHandlingCommon(int vcardType) {
731        mVerifier.initForExportTest(vcardType);
732        ContactEntry entry = mVerifier.addInputEntry();
733        entry.addContentValues(Email.CONTENT_ITEM_TYPE)
734                .put(Email.DATA, "type_home@example.com")
735                .put(Email.TYPE, Email.TYPE_HOME)
736                .put(Email.IS_PRIMARY, 1);
737        entry.addContentValues(Email.CONTENT_ITEM_TYPE)
738                .put(Email.DATA, "type_notype@example.com")
739                .put(Email.IS_PRIMARY, 1);
740
741        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
742                .addExpectedNode("EMAIL", "type_notype@example.com", new TypeSet("PREF"))
743                .addExpectedNode("EMAIL", "type_home@example.com", new TypeSet("HOME", "PREF"));
744    }
745
746    public void testEmailPrefHandlingV21() {
747        testEmailPrefHandlingCommon(V21);
748    }
749
750    public void testEmailPrefHandlingV30() {
751        testEmailPrefHandlingCommon(V30);
752    }
753
754    public void testEmailPrefHandlingV40() {
755        testEmailPrefHandlingCommon(V40);
756    }
757
758    private void testPostalAddressCommon(int vcardType) {
759        mVerifier.initForExportTest(vcardType);
760        mVerifier.addInputEntry().addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
761                .put(StructuredPostal.POBOX, "Pobox")
762                .put(StructuredPostal.NEIGHBORHOOD, "Neighborhood")
763                .put(StructuredPostal.STREET, "Street")
764                .put(StructuredPostal.CITY, "City")
765                .put(StructuredPostal.REGION, "Region")
766                .put(StructuredPostal.POSTCODE, "100")
767                .put(StructuredPostal.COUNTRY, "Country")
768                .put(StructuredPostal.FORMATTED_ADDRESS, "Formatted Address")
769                .put(StructuredPostal.TYPE, StructuredPostal.TYPE_WORK);
770        // adr-value    = 0*6(text-value ";") text-value
771        //              ; PO Box, Extended Address, Street, Locality, Region, Postal Code,
772        //              ; Country Name
773        //
774        // The NEIGHBORHOOD field is appended after the CITY field.
775        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
776                .addExpectedNode("ADR",
777                        Arrays.asList("Pobox", "", "Street", "City Neighborhood",
778                                "Region", "100", "Country"), new TypeSet("WORK"));
779    }
780
781    public void testPostalAddressV21() {
782        testPostalAddressCommon(V21);
783    }
784
785    public void testPostalAddressV30() {
786        testPostalAddressCommon(V30);
787    }
788
789    public void testPostalAddressV40() {
790        testPostalAddressCommon(V40);
791    }
792
793    private void testPostalAddressNonNeighborhood(int vcardType) {
794        mVerifier.initForExportTest(vcardType);
795        mVerifier.addInputEntry().addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
796                .put(StructuredPostal.CITY, "City");
797        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
798                .addExpectedNode("ADR",
799                        Arrays.asList("", "", "", "City", "", "", ""), new TypeSet("HOME"));
800    }
801
802    public void testPostalAddressNonNeighborhoodV21() {
803        testPostalAddressNonNeighborhood(V21);
804    }
805
806    public void testPostalAddressNonNeighborhoodV30() {
807        testPostalAddressNonNeighborhood(V30);
808    }
809
810    public void testPostalAddressNonNeighborhoodV40() {
811        testPostalAddressNonNeighborhood(V40);
812    }
813
814    private void testPostalAddressNonCity(int vcardType) {
815        mVerifier.initForExportTest(vcardType);
816        mVerifier.addInputEntry().addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
817                .put(StructuredPostal.NEIGHBORHOOD, "Neighborhood");
818        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
819                .addExpectedNode("ADR",
820                        Arrays.asList("", "", "", "Neighborhood", "", "", ""), new TypeSet("HOME"));
821    }
822
823    public void testPostalAddressNonCityV21() {
824        testPostalAddressNonCity(V21);
825    }
826
827    public void testPostalAddressNonCityV30() {
828        testPostalAddressNonCity(V30);
829    }
830
831    public void testPostalAddressNonCityV40() {
832        testPostalAddressNonCity(V40);
833    }
834
835    private void testPostalOnlyWithFormattedAddressCommon(int vcardType) {
836        mVerifier.initForExportTest(vcardType);
837        mVerifier.addInputEntry().addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
838                .put(StructuredPostal.REGION, "")  // Must be ignored.
839                .put(StructuredPostal.FORMATTED_ADDRESS,
840                "Formatted address CA 123-334 United Statue");
841        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
842                .addExpectedNodeWithOrder("ADR", ";Formatted address CA 123-334 United Statue;;;;;",
843                        Arrays.asList("", "Formatted address CA 123-334 United Statue",
844                                "", "", "", "", ""), new TypeSet("HOME"));
845    }
846
847    public void testPostalOnlyWithFormattedAddressV21() {
848        testPostalOnlyWithFormattedAddressCommon(V21);
849    }
850
851    public void testPostalOnlyWithFormattedAddressV30() {
852        testPostalOnlyWithFormattedAddressCommon(V30);
853    }
854
855    public void testPostalOnlyWithFormattedAddressV40() {
856        testPostalOnlyWithFormattedAddressCommon(V40);
857    }
858
859    /**
860     * Tests that the vCard composer honors formatted data when it is available
861     * even when it is partial.
862     */
863    private void testPostalWithBothStructuredAndFormattedCommon(int vcardType) {
864        mVerifier.initForExportTest(vcardType);
865        mVerifier.addInputEntry().addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
866                .put(StructuredPostal.POBOX, "Pobox")
867                .put(StructuredPostal.COUNTRY, "Country")
868                .put(StructuredPostal.FORMATTED_ADDRESS,
869                        "Formatted address CA 123-334 United Statue");  // Should be ignored
870        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
871                .addExpectedNode("ADR", "Pobox;;;;;;Country",
872                        Arrays.asList("Pobox", "", "", "", "", "", "Country"),
873                        new TypeSet("HOME"));
874    }
875
876    public void testPostalWithBothStructuredAndFormattedV21() {
877        testPostalWithBothStructuredAndFormattedCommon(V21);
878    }
879
880    public void testPostalWithBothStructuredAndFormattedV30() {
881        testPostalWithBothStructuredAndFormattedCommon(V30);
882    }
883
884    public void testPostalWithBothStructuredAndFormattedV40() {
885        testPostalWithBothStructuredAndFormattedCommon(V40);
886    }
887
888    private void testOrganizationCommon(int vcardType) {
889        mVerifier.initForExportTest(vcardType);
890        ContactEntry entry = mVerifier.addInputEntry();
891        entry.addContentValues(Organization.CONTENT_ITEM_TYPE)
892                .put(Organization.COMPANY, "CompanyX")
893                .put(Organization.DEPARTMENT, "DepartmentY")
894                .put(Organization.TITLE, "TitleZ")
895                .put(Organization.JOB_DESCRIPTION, "Description Rambda")  // Ignored.
896                .put(Organization.OFFICE_LOCATION, "Mountain View")  // Ignored.
897                .put(Organization.PHONETIC_NAME, "PhoneticName!")  // Ignored
898                .put(Organization.SYMBOL, "(^o^)/~~");  // Ignore him (her).
899        entry.addContentValues(Organization.CONTENT_ITEM_TYPE)
900                .putNull(Organization.COMPANY)
901                .put(Organization.DEPARTMENT, "DepartmentXX")
902                .putNull(Organization.TITLE);
903        entry.addContentValues(Organization.CONTENT_ITEM_TYPE)
904                .put(Organization.COMPANY, "CompanyXYZ")
905                .putNull(Organization.DEPARTMENT)
906                .put(Organization.TITLE, "TitleXYZYX");
907        // Currently we do not use group but depend on the order.
908        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
909                .addExpectedNodeWithOrder("ORG", "CompanyX;DepartmentY",
910                        Arrays.asList("CompanyX", "DepartmentY"))
911                .addExpectedNodeWithOrder("TITLE", "TitleZ")
912                .addExpectedNodeWithOrder("ORG", "DepartmentXX")
913                .addExpectedNodeWithOrder("ORG", "CompanyXYZ")
914                .addExpectedNodeWithOrder("TITLE", "TitleXYZYX");
915    }
916
917    public void testOrganizationV21() {
918        testOrganizationCommon(V21);
919    }
920
921    public void testOrganizationV30() {
922        testOrganizationCommon(V30);
923    }
924
925    public void testOrganizationV40() {
926        testOrganizationCommon(V40);
927    }
928
929    private void testImVariousTypeSupportCommon(int vcardType) {
930        mVerifier.initForExportTest(vcardType);
931        ContactEntry entry = mVerifier.addInputEntry();
932        entry.addContentValues(Im.CONTENT_ITEM_TYPE)
933                .put(Im.PROTOCOL, Im.PROTOCOL_AIM)
934                .put(Im.DATA, "aim");
935        entry.addContentValues(Im.CONTENT_ITEM_TYPE)
936                .put(Im.PROTOCOL, Im.PROTOCOL_MSN)
937                .put(Im.DATA, "msn");
938        entry.addContentValues(Im.CONTENT_ITEM_TYPE)
939                .put(Im.PROTOCOL, Im.PROTOCOL_YAHOO)
940                .put(Im.DATA, "yahoo");
941        entry.addContentValues(Im.CONTENT_ITEM_TYPE)
942                .put(Im.PROTOCOL, Im.PROTOCOL_SKYPE)
943                .put(Im.DATA, "skype");
944        entry.addContentValues(Im.CONTENT_ITEM_TYPE)
945                .put(Im.PROTOCOL, Im.PROTOCOL_QQ)
946                .put(Im.DATA, "qq");
947        entry.addContentValues(Im.CONTENT_ITEM_TYPE)
948                .put(Im.PROTOCOL, Im.PROTOCOL_GOOGLE_TALK)
949                .put(Im.DATA, "google talk");
950        entry.addContentValues(Im.CONTENT_ITEM_TYPE)
951                .put(Im.PROTOCOL, Im.PROTOCOL_ICQ)
952                .put(Im.DATA, "icq");
953        entry.addContentValues(Im.CONTENT_ITEM_TYPE)
954                .put(Im.PROTOCOL, Im.PROTOCOL_JABBER)
955                .put(Im.DATA, "jabber");
956        entry.addContentValues(Im.CONTENT_ITEM_TYPE)
957                .put(Im.PROTOCOL, Im.PROTOCOL_NETMEETING)
958                .put(Im.DATA, "netmeeting");
959
960        // No determined way to express unknown type...
961        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
962                .addExpectedNode("X-JABBER", "jabber")
963                .addExpectedNode("X-ICQ", "icq")
964                .addExpectedNode("X-GOOGLE-TALK", "google talk")
965                .addExpectedNode("X-QQ", "qq")
966                .addExpectedNode("X-SKYPE-USERNAME", "skype")
967                .addExpectedNode("X-YAHOO", "yahoo")
968                .addExpectedNode("X-MSN", "msn")
969                .addExpectedNode("X-NETMEETING", "netmeeting")
970                .addExpectedNode("X-AIM", "aim");
971    }
972
973    public void testImBasiV21() {
974        testImVariousTypeSupportCommon(V21);
975    }
976
977    public void testImBasicV30() {
978        testImVariousTypeSupportCommon(V30);
979    }
980
981    public void testImBasicV40() {
982        testImVariousTypeSupportCommon(V40);
983    }
984
985    private void testImPrefHandlingCommon(int vcardType) {
986        mVerifier.initForExportTest(vcardType);
987        ContactEntry entry = mVerifier.addInputEntry();
988        entry.addContentValues(Im.CONTENT_ITEM_TYPE)
989                .put(Im.PROTOCOL, Im.PROTOCOL_AIM)
990                .put(Im.DATA, "aim1");
991        entry.addContentValues(Im.CONTENT_ITEM_TYPE)
992                .put(Im.PROTOCOL, Im.PROTOCOL_AIM)
993                .put(Im.DATA, "aim2")
994                .put(Im.TYPE, Im.TYPE_HOME)
995                .put(Im.IS_PRIMARY, 1);
996
997        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
998                .addExpectedNode("X-AIM", "aim1")
999                .addExpectedNode("X-AIM", "aim2", new TypeSet("HOME", "PREF"));
1000    }
1001
1002    public void testImPrefHandlingV21() {
1003        testImPrefHandlingCommon(V21);
1004    }
1005
1006    public void testImPrefHandlingV30() {
1007        testImPrefHandlingCommon(V30);
1008    }
1009
1010    public void testImPrefHandlingV40() {
1011        testImPrefHandlingCommon(V40);
1012    }
1013
1014    private void testWebsiteCommon(int vcardType) {
1015        mVerifier.initForExportTest(vcardType);
1016        ContactEntry entry = mVerifier.addInputEntry();
1017        entry.addContentValues(Website.CONTENT_ITEM_TYPE)
1018                .put(Website.URL, "http://website.example.android.com/index.html")
1019                .put(Website.TYPE, Website.TYPE_BLOG);
1020        entry.addContentValues(Website.CONTENT_ITEM_TYPE)
1021                .put(Website.URL, "ftp://ftp.example.android.com/index.html")
1022                .put(Website.TYPE, Website.TYPE_FTP);
1023
1024        // We drop TYPE information since vCard (especially 3.0) does not allow us to emit it.
1025        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
1026                .addExpectedNode("URL", "ftp://ftp.example.android.com/index.html")
1027                .addExpectedNode("URL", "http://website.example.android.com/index.html");
1028    }
1029
1030    public void testWebsiteV21() {
1031        testWebsiteCommon(V21);
1032    }
1033
1034    public void testWebsiteV30() {
1035        testWebsiteCommon(V30);
1036    }
1037
1038    public void testWebsiteV40() {
1039        testWebsiteCommon(V40);
1040    }
1041
1042    private String getAndroidPropValue(final String mimeType, String value, Integer type) {
1043        return getAndroidPropValue(mimeType, value, type, null);
1044    }
1045
1046    private String getAndroidPropValue(final String mimeType, String value,
1047            Integer type, String label) {
1048        return (mimeType + ";" + value + ";"
1049                + (type != null ? type : "") + ";"
1050                + (label != null ? label : "") + ";;;;;;;;;;;;");
1051    }
1052
1053    private void testEventCommon(int vcardType) {
1054        mVerifier.initForExportTest(vcardType);
1055        ContactEntry entry = mVerifier.addInputEntry();
1056        entry.addContentValues(Event.CONTENT_ITEM_TYPE)
1057                .put(Event.TYPE, Event.TYPE_ANNIVERSARY)
1058                .put(Event.START_DATE, "1982-06-16");
1059        entry.addContentValues(Event.CONTENT_ITEM_TYPE)
1060                .put(Event.TYPE, Event.TYPE_BIRTHDAY)
1061                .put(Event.START_DATE, "2008-10-22");
1062        entry.addContentValues(Event.CONTENT_ITEM_TYPE)
1063                .put(Event.TYPE, Event.TYPE_OTHER)
1064                .put(Event.START_DATE, "2018-03-12");
1065        entry.addContentValues(Event.CONTENT_ITEM_TYPE)
1066                .put(Event.TYPE, Event.TYPE_CUSTOM)
1067                .put(Event.LABEL, "The last day")
1068                .put(Event.START_DATE, "When the Tower of Hanoi with 64 rings is completed.");
1069        entry.addContentValues(Event.CONTENT_ITEM_TYPE)
1070                .put(Event.TYPE, Event.TYPE_BIRTHDAY)
1071                .put(Event.START_DATE, "2009-05-19");  // Should be ignored.
1072        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
1073                .addExpectedNode("BDAY", "2008-10-22")
1074                .addExpectedNode("X-ANDROID-CUSTOM",
1075                        getAndroidPropValue(
1076                                Event.CONTENT_ITEM_TYPE, "1982-06-16", Event.TYPE_ANNIVERSARY))
1077                .addExpectedNode("X-ANDROID-CUSTOM",
1078                        getAndroidPropValue(
1079                                Event.CONTENT_ITEM_TYPE, "2018-03-12", Event.TYPE_OTHER))
1080                .addExpectedNode("X-ANDROID-CUSTOM",
1081                        getAndroidPropValue(
1082                                Event.CONTENT_ITEM_TYPE,
1083                                "When the Tower of Hanoi with 64 rings is completed.",
1084                                Event.TYPE_CUSTOM, "The last day"));
1085    }
1086
1087    public void testEventV21() {
1088        testEventCommon(V21);
1089    }
1090
1091    public void testEventV30() {
1092        testEventCommon(V30);
1093    }
1094
1095    public void testEventV40() {
1096        testEventCommon(V40);
1097    }
1098
1099    private void testNoteCommon(int vcardType) {
1100        mVerifier.initForExportTest(vcardType);
1101        ContactEntry entry = mVerifier.addInputEntry();
1102        entry.addContentValues(Note.CONTENT_ITEM_TYPE)
1103                .put(Note.NOTE, "note1");
1104        entry.addContentValues(Note.CONTENT_ITEM_TYPE)
1105                .put(Note.NOTE, "note2")
1106                .put(Note.IS_PRIMARY, 1);  // Just ignored.
1107        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
1108                .addExpectedNodeWithOrder("NOTE", "note1")
1109                .addExpectedNodeWithOrder("NOTE", "note2");
1110    }
1111
1112    public void testNoteV21() {
1113        testNoteCommon(V21);
1114    }
1115
1116    public void testNoteV30() {
1117        testNoteCommon(V30);
1118    }
1119
1120    public void testNoteV40() {
1121        testNoteCommon(V40);
1122    }
1123
1124    private void testPhotoCommon(int vcardType) {
1125        final boolean useB =
1126            (VCardConfig.isVersion30(vcardType) || VCardConfig.isVersion40(vcardType));
1127        mVerifier.initForExportTest(vcardType);
1128        ContactEntry entry = mVerifier.addInputEntry();
1129        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
1130                .put(StructuredName.FAMILY_NAME, "PhotoTest");
1131        entry.addContentValues(Photo.CONTENT_ITEM_TYPE)
1132                .put(Photo.PHOTO, sPhotoByteArray);
1133
1134        ContentValues contentValuesForPhoto = new ContentValues();
1135        contentValuesForPhoto.put("ENCODING", (useB ? "b" : "BASE64"));
1136        mVerifier.addPropertyNodesVerifierElem()
1137                .addExpectedNode("FN", "PhotoTest")
1138                .addExpectedNode("N", "PhotoTest;;;;",
1139                        Arrays.asList("PhotoTest", "", "", "", ""))
1140                .addExpectedNodeWithOrder("PHOTO", null, null, sPhotoByteArray,
1141                        contentValuesForPhoto, new TypeSet("JPEG"), null);
1142    }
1143
1144    public void testPhotoV21() {
1145        testPhotoCommon(V21);
1146    }
1147
1148    public void testPhotoV30() {
1149        testPhotoCommon(V30);
1150    }
1151
1152    public void testPhotoV40() {
1153        testPhotoCommon(V40);
1154    }
1155
1156    private void testRelationCommon(int vcardType) {
1157        mVerifier.initForExportTest(vcardType);
1158        mVerifier.addInputEntry().addContentValues(Relation.CONTENT_ITEM_TYPE)
1159                .put(Relation.TYPE, Relation.TYPE_MOTHER)
1160                .put(Relation.NAME, "Ms. Mother");
1161        mVerifier.addContentValuesVerifierElem().addExpected(Relation.CONTENT_ITEM_TYPE)
1162                .put(Relation.TYPE, Relation.TYPE_MOTHER)
1163                .put(Relation.NAME, "Ms. Mother");
1164    }
1165
1166    public void testRelationV21() {
1167        testRelationCommon(V21);
1168    }
1169
1170    public void testRelationV30() {
1171        testRelationCommon(V30);
1172    }
1173
1174    public void testV30HandleEscape() {
1175        mVerifier.initForExportTest(V30);
1176        mVerifier.addInputEntry().addContentValues(StructuredName.CONTENT_ITEM_TYPE)
1177                .put(StructuredName.FAMILY_NAME, "\\")
1178                .put(StructuredName.GIVEN_NAME, ";")
1179                .put(StructuredName.MIDDLE_NAME, ",")
1180                .put(StructuredName.PREFIX, "\n")
1181                .put(StructuredName.DISPLAY_NAME, "[<{Unescaped:Asciis}>]");
1182        // Verifies the vCard String correctly escapes each character which must be escaped.
1183        mVerifier.addLineVerifierElem()
1184                .addExpected("N:\\\\;\\;;\\,;\\n;")
1185                .addExpected("FN:[<{Unescaped:Asciis}>]");
1186        mVerifier.addPropertyNodesVerifierElem()
1187                .addExpectedNode("FN", "[<{Unescaped:Asciis}>]")
1188                .addExpectedNode("N", Arrays.asList("\\", ";", ",", "\n", ""));
1189    }
1190
1191    /**
1192     * There's no "NICKNAME" property in vCard 2.1, while there is in vCard 3.0.
1193     * We use Android-specific "X-ANDROID-CUSTOM" property.
1194     * This test verifies the functionality.
1195     */
1196    public void testNickNameV21() {
1197        mVerifier.initForExportTest(V21);
1198        mVerifier.addInputEntry().addContentValues(Nickname.CONTENT_ITEM_TYPE)
1199                .put(Nickname.NAME, "Nicky");
1200        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
1201                .addExpectedNode("X-ANDROID-CUSTOM",
1202                        Nickname.CONTENT_ITEM_TYPE + ";Nicky;;;;;;;;;;;;;;");
1203        mVerifier.addContentValuesVerifierElem().addExpected(Nickname.CONTENT_ITEM_TYPE)
1204                .put(Nickname.NAME, "Nicky");
1205    }
1206
1207    public void testTolerateBrokenPhoneNumberEntryV21() {
1208        mVerifier.initForExportTest(V21);
1209        ContactEntry entry = mVerifier.addInputEntry();
1210        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
1211                .put(Phone.TYPE, Phone.TYPE_HOME)
1212                .put(Phone.NUMBER, "111-222-3333 (Miami)\n444-5555-666 (Tokyo)\n"
1213                        + "777-888-9999 (Chicago)\n111-222-3333 (Miami)");
1214        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
1215                .addExpectedNode("TEL", "111-222-3333", new TypeSet("HOME"))
1216                .addExpectedNode("TEL", "444-555-5666", new TypeSet("HOME"))
1217                .addExpectedNode("TEL", "777-888-9999", new TypeSet("HOME"));
1218    }
1219
1220    private void testPickUpNonEmptyContentValuesCommon(int vcardType) {
1221        mVerifier.initForExportTest(vcardType);
1222        ContactEntry entry = mVerifier.addInputEntry();
1223        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
1224                .put(StructuredName.IS_PRIMARY, 1);  // Empty name. Should be ignored.
1225        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
1226                .put(StructuredName.FAMILY_NAME, "family1")  // Not primary. Should be ignored.
1227                .put(StructuredName.DISPLAY_NAME, "display");
1228        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
1229                .put(StructuredName.IS_PRIMARY, 1)
1230                .put(StructuredName.FAMILY_NAME, "family2")  // This entry is what we want.
1231                .put(StructuredName.DISPLAY_NAME, "display");
1232        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
1233                .put(StructuredName.IS_PRIMARY, 1)
1234                .put(StructuredName.FAMILY_NAME, "family3")
1235                .put(StructuredName.DISPLAY_NAME, "display");
1236        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
1237                .put(StructuredName.FAMILY_NAME, "family4")
1238                .put(StructuredName.DISPLAY_NAME, "display");
1239        mVerifier.addPropertyNodesVerifierElem()
1240                .addExpectedNode("N", Arrays.asList("family2", "", "", "", ""))
1241                .addExpectedNode("FN", "display");
1242    }
1243
1244    public void testPickUpNonEmptyContentValuesV21() {
1245        testPickUpNonEmptyContentValuesCommon(V21);
1246    }
1247
1248    public void testPickUpNonEmptyContentValuesV30() {
1249        testPickUpNonEmptyContentValuesCommon(V30);
1250    }
1251
1252    public void testPickUpNonEmptyContentValuesV40() {
1253        testPickUpNonEmptyContentValuesCommon(V40);
1254    }
1255
1256    public void testUseMultiByteTypeV30() {
1257        mVerifier.initForExportTest(V30);
1258        final ContactEntry entry = mVerifier.addInputEntry();
1259        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
1260                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
1261                .put(Phone.LABEL, "\u96FB\u8A71")
1262                .put(Phone.NUMBER, "1");
1263        mVerifier.addLineVerifierElem()
1264                .addExpected("N:")
1265                .addExpected("FN:")
1266                .addExpected("TEL;TYPE=\u96FB\u8A71:1");
1267        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
1268                .addExpectedNode("TEL", "1", new TypeSet("\u96FB\u8A71"));
1269    }
1270
1271    public void testSipAddressV21() {
1272        mVerifier.initForExportTest(V21);
1273        final ContactEntry entry = mVerifier.addInputEntry();
1274        entry.addContentValues(SipAddress.CONTENT_ITEM_TYPE)
1275                .put(SipAddress.SIP_ADDRESS, "gold");
1276        mVerifier.addLineVerifierElem()
1277                .addExpected("X-SIP:gold");
1278        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
1279                .addExpectedNode("X-SIP", "gold");
1280    }
1281
1282    public void testSipAddressV30() {
1283        mVerifier.initForExportTest(V30);
1284        final ContactEntry entry = mVerifier.addInputEntry();
1285        entry.addContentValues(SipAddress.CONTENT_ITEM_TYPE)
1286                .put(SipAddress.SIP_ADDRESS, "android@example.com");
1287        mVerifier.addLineVerifierElem()
1288                .addExpected("N:")
1289                .addExpected("FN:")
1290                .addExpected("IMPP:sip:android@example.com");
1291        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
1292                .addExpectedNode("IMPP", "sip:android@example.com");
1293    }
1294
1295    public void testPauseAndWaitConversionV30() {
1296        mVerifier.initForExportTest(V30);
1297        final ContactEntry entry = mVerifier.addInputEntry();
1298        // Insert numbers with PAUSE (',' internally, 'p' for outside) and
1299        // WAIT (';' internally, 'w' for outside)
1300        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
1301                .put(Phone.TYPE, Phone.TYPE_HOME)
1302                .put(Phone.NUMBER, "111,222;333");
1303        mVerifier.addLineVerifierElem()
1304                .addExpected("N:")
1305                .addExpected("FN:")
1306                .addExpected("TEL;TYPE=HOME:111p222w333");
1307        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
1308                .addExpectedNode("TEL", "111p222w333", new TypeSet("HOME"));
1309    }
1310
1311    public void testSipAddressV40() {
1312        mVerifier.initForExportTest(V40);
1313        final ContactEntry entry = mVerifier.addInputEntry();
1314        entry.addContentValues(SipAddress.CONTENT_ITEM_TYPE)
1315                .put(SipAddress.SIP_ADDRESS, "android@example.com");
1316        mVerifier.addLineVerifierElem()
1317                .addExpected("FN:")
1318                .addExpected("TEL:sip:android@example.com");
1319        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
1320                .addExpectedNode("TEL", "sip:android@example.com");
1321    }
1322}
1323