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