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