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