VCardExporterTests.java revision 2bf85a1a15a3175119ab8415fc590fd5fe3d0752
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        if (VCardConfig.isVersion30(vcardType)) {
444            // vCard 3.0 accepts "invalid". Also stop using toUpper()
445            elem.addExpectedNode("TEL", "1", new TypeSet("Modem"))
446                    .addExpectedNode("TEL", "2", new TypeSet("MSG"))
447                    .addExpectedNode("TEL", "3", new TypeSet("BBS"))
448                    .addExpectedNode("TEL", "4", new TypeSet("VIDEO"))
449                    .addExpectedNode("TEL", "5", new TypeSet("VOICE"))
450                    .addExpectedNode("TEL", "6", new TypeSet("CELL"))
451                    .addExpectedNode("TEL", "7", new TypeSet("CELL"))
452                    .addExpectedNode("TEL", "8", new TypeSet("invalid"));
453        } else {
454            elem.addExpectedNode("TEL", "1", new TypeSet("MODEM"))
455                    .addExpectedNode("TEL", "2", new TypeSet("MSG"))
456                    .addExpectedNode("TEL", "3", new TypeSet("BBS"))
457                    .addExpectedNode("TEL", "4", new TypeSet("VIDEO"))
458                    .addExpectedNode("TEL", "5", new TypeSet("VOICE"))
459                    .addExpectedNode("TEL", "6", new TypeSet("CELL"))
460                    .addExpectedNode("TEL", "7", new TypeSet("CELL"))
461                    .addExpectedNode("TEL", "8", new TypeSet("X-invalid"));
462        }
463    }
464
465    public void testPhoneTypeHandlingV21() {
466        testMiscPhoneTypeHandling(V21);
467    }
468
469    public void testPhoneTypeHandlingV30() {
470        testMiscPhoneTypeHandling(V30);
471    }
472
473    private void testEmailBasicCommon(int vcardType) {
474        mVerifier.initForExportTest(vcardType);
475        mVerifier.addInputEntry().addContentValues(Email.CONTENT_ITEM_TYPE)
476                .put(Email.DATA, "sample@example.com");
477        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
478            .addExpectedNode("EMAIL", "sample@example.com");
479    }
480
481    public void testEmailBasicV21() {
482        testEmailBasicCommon(V21);
483    }
484
485    public void testEmailBasicV30() {
486        testEmailBasicCommon(V30);
487    }
488
489    private void testEmailVariousTypeSupportCommon(int vcardType) {
490        mVerifier.initForExportTest(vcardType);
491        ContactEntry entry = mVerifier.addInputEntry();
492        entry.addContentValues(Email.CONTENT_ITEM_TYPE)
493                .put(Email.DATA, "type_home@example.com")
494                .put(Email.TYPE, Email.TYPE_HOME);
495        entry.addContentValues(Email.CONTENT_ITEM_TYPE)
496                .put(Email.DATA, "type_work@example.com")
497                .put(Email.TYPE, Email.TYPE_WORK);
498        entry.addContentValues(Email.CONTENT_ITEM_TYPE)
499                .put(Email.DATA, "type_mobile@example.com")
500                .put(Email.TYPE, Email.TYPE_MOBILE);
501        entry.addContentValues(Email.CONTENT_ITEM_TYPE)
502                .put(Email.DATA, "type_other@example.com")
503                .put(Email.TYPE, Email.TYPE_OTHER);
504        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
505                .addExpectedNode("EMAIL", "type_home@example.com", new TypeSet("HOME"))
506                .addExpectedNode("EMAIL", "type_work@example.com", new TypeSet("WORK"))
507                .addExpectedNode("EMAIL", "type_mobile@example.com", new TypeSet("CELL"))
508                .addExpectedNode("EMAIL", "type_other@example.com");
509    }
510
511    public void testEmailVariousTypeSupportV21() {
512        testEmailVariousTypeSupportCommon(V21);
513    }
514
515    public void testEmailVariousTypeSupportV30() {
516        testEmailVariousTypeSupportCommon(V30);
517    }
518
519    private void testEmailPrefHandlingCommon(int vcardType) {
520        mVerifier.initForExportTest(vcardType);
521        ContactEntry entry = mVerifier.addInputEntry();
522        entry.addContentValues(Email.CONTENT_ITEM_TYPE)
523                .put(Email.DATA, "type_home@example.com")
524                .put(Email.TYPE, Email.TYPE_HOME)
525                .put(Email.IS_PRIMARY, 1);
526        entry.addContentValues(Email.CONTENT_ITEM_TYPE)
527                .put(Email.DATA, "type_notype@example.com")
528                .put(Email.IS_PRIMARY, 1);
529
530        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
531                .addExpectedNode("EMAIL", "type_notype@example.com", new TypeSet("PREF"))
532                .addExpectedNode("EMAIL", "type_home@example.com", new TypeSet("HOME", "PREF"));
533    }
534
535    public void testEmailPrefHandlingV21() {
536        testEmailPrefHandlingCommon(V21);
537    }
538
539    public void testEmailPrefHandlingV30() {
540        testEmailPrefHandlingCommon(V30);
541    }
542
543    private void testPostalAddressCommon(int vcardType) {
544        mVerifier.initForExportTest(vcardType);
545        mVerifier.addInputEntry().addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
546                .put(StructuredPostal.POBOX, "Pobox")
547                .put(StructuredPostal.NEIGHBORHOOD, "Neighborhood")
548                .put(StructuredPostal.STREET, "Street")
549                .put(StructuredPostal.CITY, "City")
550                .put(StructuredPostal.REGION, "Region")
551                .put(StructuredPostal.POSTCODE, "100")
552                .put(StructuredPostal.COUNTRY, "Country")
553                .put(StructuredPostal.FORMATTED_ADDRESS, "Formatted Address")
554                .put(StructuredPostal.TYPE, StructuredPostal.TYPE_WORK);
555        // adr-value    = 0*6(text-value ";") text-value
556        //              ; PO Box, Extended Address, Street, Locality, Region, Postal Code,
557        //              ; Country Name
558        //
559        // The NEIGHBORHOOD field is appended after the CITY field.
560        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
561                .addExpectedNode("ADR",
562                        Arrays.asList("Pobox", "", "Street", "City Neighborhood",
563                                "Region", "100", "Country"), new TypeSet("WORK"));
564    }
565
566    public void testPostalAddressV21() {
567        testPostalAddressCommon(V21);
568    }
569
570    public void testPostalAddressV30() {
571        testPostalAddressCommon(V30);
572    }
573
574    private void testPostalAddressNonNeighborhood(int vcardType) {
575        mVerifier.initForExportTest(vcardType);
576        mVerifier.addInputEntry().addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
577                .put(StructuredPostal.CITY, "City");
578        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
579                .addExpectedNode("ADR",
580                        Arrays.asList("", "", "", "City", "", "", ""), new TypeSet("HOME"));
581    }
582
583    public void testPostalAddressNonNeighborhoodV21() {
584        testPostalAddressNonNeighborhood(V21);
585    }
586
587    public void testPostalAddressNonNeighborhoodV30() {
588        testPostalAddressNonNeighborhood(V30);
589    }
590
591    private void testPostalAddressNonCity(int vcardType) {
592        mVerifier.initForExportTest(vcardType);
593        mVerifier.addInputEntry().addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
594                .put(StructuredPostal.NEIGHBORHOOD, "Neighborhood");
595        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
596                .addExpectedNode("ADR",
597                        Arrays.asList("", "", "", "Neighborhood", "", "", ""), new TypeSet("HOME"));
598    }
599
600    public void testPostalAddressNonCityV21() {
601        testPostalAddressNonCity(V21);
602    }
603
604    public void testPostalAddressNonCityV30() {
605        testPostalAddressNonCity(V30);
606    }
607
608    private void testPostalOnlyWithFormattedAddressCommon(int vcardType) {
609        mVerifier.initForExportTest(vcardType);
610        mVerifier.addInputEntry().addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
611                .put(StructuredPostal.REGION, "")  // Must be ignored.
612                .put(StructuredPostal.FORMATTED_ADDRESS,
613                "Formatted address CA 123-334 United Statue");
614        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
615                .addExpectedNodeWithOrder("ADR", ";Formatted address CA 123-334 United Statue;;;;;",
616                        Arrays.asList("", "Formatted address CA 123-334 United Statue",
617                                "", "", "", "", ""), new TypeSet("HOME"));
618    }
619
620    public void testPostalOnlyWithFormattedAddressV21() {
621        testPostalOnlyWithFormattedAddressCommon(V21);
622    }
623
624    public void testPostalOnlyWithFormattedAddressV30() {
625        testPostalOnlyWithFormattedAddressCommon(V30);
626    }
627
628    /**
629     * Tests that the vCard composer honors formatted data when it is available
630     * even when it is partial.
631     */
632    private void testPostalWithBothStructuredAndFormattedCommon(int vcardType) {
633        mVerifier.initForExportTest(vcardType);
634        mVerifier.addInputEntry().addContentValues(StructuredPostal.CONTENT_ITEM_TYPE)
635                .put(StructuredPostal.POBOX, "Pobox")
636                .put(StructuredPostal.COUNTRY, "Country")
637                .put(StructuredPostal.FORMATTED_ADDRESS,
638                        "Formatted address CA 123-334 United Statue");  // Should be ignored
639        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
640                .addExpectedNode("ADR", "Pobox;;;;;;Country",
641                        Arrays.asList("Pobox", "", "", "", "", "", "Country"),
642                        new TypeSet("HOME"));
643    }
644
645    public void testPostalWithBothStructuredAndFormattedV21() {
646        testPostalWithBothStructuredAndFormattedCommon(V21);
647    }
648
649    public void testPostalWithBothStructuredAndFormattedV30() {
650        testPostalWithBothStructuredAndFormattedCommon(V30);
651    }
652
653    private void testOrganizationCommon(int vcardType) {
654        mVerifier.initForExportTest(vcardType);
655        ContactEntry entry = mVerifier.addInputEntry();
656        entry.addContentValues(Organization.CONTENT_ITEM_TYPE)
657                .put(Organization.COMPANY, "CompanyX")
658                .put(Organization.DEPARTMENT, "DepartmentY")
659                .put(Organization.TITLE, "TitleZ")
660                .put(Organization.JOB_DESCRIPTION, "Description Rambda")  // Ignored.
661                .put(Organization.OFFICE_LOCATION, "Mountain View")  // Ignored.
662                .put(Organization.PHONETIC_NAME, "PhoneticName!")  // Ignored
663                .put(Organization.SYMBOL, "(^o^)/~~");  // Ignore him (her).
664        entry.addContentValues(Organization.CONTENT_ITEM_TYPE)
665                .putNull(Organization.COMPANY)
666                .put(Organization.DEPARTMENT, "DepartmentXX")
667                .putNull(Organization.TITLE);
668        entry.addContentValues(Organization.CONTENT_ITEM_TYPE)
669                .put(Organization.COMPANY, "CompanyXYZ")
670                .putNull(Organization.DEPARTMENT)
671                .put(Organization.TITLE, "TitleXYZYX");
672        // Currently we do not use group but depend on the order.
673        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
674                .addExpectedNodeWithOrder("ORG", "CompanyX;DepartmentY",
675                        Arrays.asList("CompanyX", "DepartmentY"))
676                .addExpectedNodeWithOrder("TITLE", "TitleZ")
677                .addExpectedNodeWithOrder("ORG", "DepartmentXX")
678                .addExpectedNodeWithOrder("ORG", "CompanyXYZ")
679                .addExpectedNodeWithOrder("TITLE", "TitleXYZYX");
680    }
681
682    public void testOrganizationV21() {
683        testOrganizationCommon(V21);
684    }
685
686    public void testOrganizationV30() {
687        testOrganizationCommon(V30);
688    }
689
690    private void testImVariousTypeSupportCommon(int vcardType) {
691        mVerifier.initForExportTest(vcardType);
692        ContactEntry entry = mVerifier.addInputEntry();
693        entry.addContentValues(Im.CONTENT_ITEM_TYPE)
694                .put(Im.PROTOCOL, Im.PROTOCOL_AIM)
695                .put(Im.DATA, "aim");
696        entry.addContentValues(Im.CONTENT_ITEM_TYPE)
697                .put(Im.PROTOCOL, Im.PROTOCOL_MSN)
698                .put(Im.DATA, "msn");
699        entry.addContentValues(Im.CONTENT_ITEM_TYPE)
700                .put(Im.PROTOCOL, Im.PROTOCOL_YAHOO)
701                .put(Im.DATA, "yahoo");
702        entry.addContentValues(Im.CONTENT_ITEM_TYPE)
703                .put(Im.PROTOCOL, Im.PROTOCOL_SKYPE)
704                .put(Im.DATA, "skype");
705        entry.addContentValues(Im.CONTENT_ITEM_TYPE)
706                .put(Im.PROTOCOL, Im.PROTOCOL_QQ)
707                .put(Im.DATA, "qq");
708        entry.addContentValues(Im.CONTENT_ITEM_TYPE)
709                .put(Im.PROTOCOL, Im.PROTOCOL_GOOGLE_TALK)
710                .put(Im.DATA, "google talk");
711        entry.addContentValues(Im.CONTENT_ITEM_TYPE)
712                .put(Im.PROTOCOL, Im.PROTOCOL_ICQ)
713                .put(Im.DATA, "icq");
714        entry.addContentValues(Im.CONTENT_ITEM_TYPE)
715                .put(Im.PROTOCOL, Im.PROTOCOL_JABBER)
716                .put(Im.DATA, "jabber");
717        entry.addContentValues(Im.CONTENT_ITEM_TYPE)
718                .put(Im.PROTOCOL, Im.PROTOCOL_NETMEETING)
719                .put(Im.DATA, "netmeeting");
720
721        // No determined way to express unknown type...
722        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
723                .addExpectedNode("X-JABBER", "jabber")
724                .addExpectedNode("X-ICQ", "icq")
725                .addExpectedNode("X-GOOGLE-TALK", "google talk")
726                .addExpectedNode("X-QQ", "qq")
727                .addExpectedNode("X-SKYPE-USERNAME", "skype")
728                .addExpectedNode("X-YAHOO", "yahoo")
729                .addExpectedNode("X-MSN", "msn")
730                .addExpectedNode("X-NETMEETING", "netmeeting")
731                .addExpectedNode("X-AIM", "aim");
732    }
733
734    public void testImBasiV21() {
735        testImVariousTypeSupportCommon(V21);
736    }
737
738    public void testImBasicV30() {
739        testImVariousTypeSupportCommon(V30);
740    }
741
742    private void testImPrefHandlingCommon(int vcardType) {
743        mVerifier.initForExportTest(vcardType);
744        ContactEntry entry = mVerifier.addInputEntry();
745        entry.addContentValues(Im.CONTENT_ITEM_TYPE)
746                .put(Im.PROTOCOL, Im.PROTOCOL_AIM)
747                .put(Im.DATA, "aim1");
748        entry.addContentValues(Im.CONTENT_ITEM_TYPE)
749                .put(Im.PROTOCOL, Im.PROTOCOL_AIM)
750                .put(Im.DATA, "aim2")
751                .put(Im.TYPE, Im.TYPE_HOME)
752                .put(Im.IS_PRIMARY, 1);
753
754        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
755                .addExpectedNode("X-AIM", "aim1")
756                .addExpectedNode("X-AIM", "aim2", new TypeSet("HOME", "PREF"));
757    }
758
759    public void testImPrefHandlingV21() {
760        testImPrefHandlingCommon(V21);
761    }
762
763    public void testImPrefHandlingV30() {
764        testImPrefHandlingCommon(V30);
765    }
766
767    private void testWebsiteCommon(int vcardType) {
768        mVerifier.initForExportTest(vcardType);
769        ContactEntry entry = mVerifier.addInputEntry();
770        entry.addContentValues(Website.CONTENT_ITEM_TYPE)
771                .put(Website.URL, "http://website.example.android.com/index.html")
772                .put(Website.TYPE, Website.TYPE_BLOG);
773        entry.addContentValues(Website.CONTENT_ITEM_TYPE)
774                .put(Website.URL, "ftp://ftp.example.android.com/index.html")
775                .put(Website.TYPE, Website.TYPE_FTP);
776
777        // We drop TYPE information since vCard (especially 3.0) does not allow us to emit it.
778        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
779                .addExpectedNode("URL", "ftp://ftp.example.android.com/index.html")
780                .addExpectedNode("URL", "http://website.example.android.com/index.html");
781    }
782
783    public void testWebsiteV21() {
784        testWebsiteCommon(V21);
785    }
786
787    public void testWebsiteV30() {
788        testWebsiteCommon(V30);
789    }
790
791    private String getAndroidPropValue(final String mimeType, String value, Integer type) {
792        return getAndroidPropValue(mimeType, value, type, null);
793    }
794
795    private String getAndroidPropValue(final String mimeType, String value,
796            Integer type, String label) {
797        return (mimeType + ";" + value + ";"
798                + (type != null ? type : "") + ";"
799                + (label != null ? label : "") + ";;;;;;;;;;;;");
800    }
801
802    private void testEventCommon(int vcardType) {
803        mVerifier.initForExportTest(vcardType);
804        ContactEntry entry = mVerifier.addInputEntry();
805        entry.addContentValues(Event.CONTENT_ITEM_TYPE)
806                .put(Event.TYPE, Event.TYPE_ANNIVERSARY)
807                .put(Event.START_DATE, "1982-06-16");
808        entry.addContentValues(Event.CONTENT_ITEM_TYPE)
809                .put(Event.TYPE, Event.TYPE_BIRTHDAY)
810                .put(Event.START_DATE, "2008-10-22");
811        entry.addContentValues(Event.CONTENT_ITEM_TYPE)
812                .put(Event.TYPE, Event.TYPE_OTHER)
813                .put(Event.START_DATE, "2018-03-12");
814        entry.addContentValues(Event.CONTENT_ITEM_TYPE)
815                .put(Event.TYPE, Event.TYPE_CUSTOM)
816                .put(Event.LABEL, "The last day")
817                .put(Event.START_DATE, "When the Tower of Hanoi with 64 rings is completed.");
818        entry.addContentValues(Event.CONTENT_ITEM_TYPE)
819                .put(Event.TYPE, Event.TYPE_BIRTHDAY)
820                .put(Event.START_DATE, "2009-05-19");  // Should be ignored.
821        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
822                .addExpectedNode("BDAY", "2008-10-22")
823                .addExpectedNode("X-ANDROID-CUSTOM",
824                        getAndroidPropValue(
825                                Event.CONTENT_ITEM_TYPE, "1982-06-16", Event.TYPE_ANNIVERSARY))
826                .addExpectedNode("X-ANDROID-CUSTOM",
827                        getAndroidPropValue(
828                                Event.CONTENT_ITEM_TYPE, "2018-03-12", Event.TYPE_OTHER))
829                .addExpectedNode("X-ANDROID-CUSTOM",
830                        getAndroidPropValue(
831                                Event.CONTENT_ITEM_TYPE,
832                                "When the Tower of Hanoi with 64 rings is completed.",
833                                Event.TYPE_CUSTOM, "The last day"));
834    }
835
836    public void testEventV21() {
837        testEventCommon(V21);
838    }
839
840    public void testEventV30() {
841        testEventCommon(V30);
842    }
843
844    private void testNoteCommon(int vcardType) {
845        mVerifier.initForExportTest(vcardType);
846        ContactEntry entry = mVerifier.addInputEntry();
847        entry.addContentValues(Note.CONTENT_ITEM_TYPE)
848                .put(Note.NOTE, "note1");
849        entry.addContentValues(Note.CONTENT_ITEM_TYPE)
850                .put(Note.NOTE, "note2")
851                .put(Note.IS_PRIMARY, 1);  // Just ignored.
852        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
853                .addExpectedNodeWithOrder("NOTE", "note1")
854                .addExpectedNodeWithOrder("NOTE", "note2");
855    }
856
857    public void testNoteV21() {
858        testNoteCommon(V21);
859    }
860
861    public void testNoteV30() {
862        testNoteCommon(V30);
863    }
864
865    private void testPhotoCommon(int vcardType) {
866        final boolean isV30 = vcardType == V30;
867        mVerifier.initForExportTest(vcardType);
868        ContactEntry entry = mVerifier.addInputEntry();
869        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
870                .put(StructuredName.FAMILY_NAME, "PhotoTest");
871        entry.addContentValues(Photo.CONTENT_ITEM_TYPE)
872                .put(Photo.PHOTO, sPhotoByteArray);
873
874        ContentValues contentValuesForPhoto = new ContentValues();
875        contentValuesForPhoto.put("ENCODING", (isV30 ? "b" : "BASE64"));
876        mVerifier.addPropertyNodesVerifierElem()
877                .addExpectedNode("FN", "PhotoTest")
878                .addExpectedNode("N", "PhotoTest;;;;",
879                        Arrays.asList("PhotoTest", "", "", "", ""))
880                .addExpectedNodeWithOrder("PHOTO", null, null, sPhotoByteArray,
881                        contentValuesForPhoto, new TypeSet("JPEG"), null);
882    }
883
884    public void testPhotoV21() {
885        testPhotoCommon(V21);
886    }
887
888    public void testPhotoV30() {
889        testPhotoCommon(V30);
890    }
891
892    private void testRelationCommon(int vcardType) {
893        mVerifier.initForExportTest(vcardType);
894        mVerifier.addInputEntry().addContentValues(Relation.CONTENT_ITEM_TYPE)
895                .put(Relation.TYPE, Relation.TYPE_MOTHER)
896                .put(Relation.NAME, "Ms. Mother");
897        mVerifier.addContentValuesVerifierElem().addExpected(Relation.CONTENT_ITEM_TYPE)
898                .put(Relation.TYPE, Relation.TYPE_MOTHER)
899                .put(Relation.NAME, "Ms. Mother");
900    }
901
902    public void testRelationV21() {
903        testRelationCommon(V21);
904    }
905
906    public void testRelationV30() {
907        testRelationCommon(V30);
908    }
909
910    public void testV30HandleEscape() {
911        mVerifier.initForExportTest(V30);
912        mVerifier.addInputEntry().addContentValues(StructuredName.CONTENT_ITEM_TYPE)
913                .put(StructuredName.FAMILY_NAME, "\\")
914                .put(StructuredName.GIVEN_NAME, ";")
915                .put(StructuredName.MIDDLE_NAME, ",")
916                .put(StructuredName.PREFIX, "\n")
917                .put(StructuredName.DISPLAY_NAME, "[<{Unescaped:Asciis}>]");
918        // Verifies the vCard String correctly escapes each character which must be escaped.
919        mVerifier.addLineVerifierElem()
920                .addExpected("N:\\\\;\\;;\\,;\\n;")
921                .addExpected("FN:[<{Unescaped:Asciis}>]");
922        mVerifier.addPropertyNodesVerifierElem()
923                .addExpectedNode("FN", "[<{Unescaped:Asciis}>]")
924                .addExpectedNode("N", Arrays.asList("\\", ";", ",", "\n", ""));
925    }
926
927    /**
928     * There's no "NICKNAME" property in vCard 2.1, while there is in vCard 3.0.
929     * We use Android-specific "X-ANDROID-CUSTOM" property.
930     * This test verifies the functionality.
931     */
932    public void testNickNameV21() {
933        mVerifier.initForExportTest(V21);
934        mVerifier.addInputEntry().addContentValues(Nickname.CONTENT_ITEM_TYPE)
935                .put(Nickname.NAME, "Nicky");
936        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
937                .addExpectedNode("X-ANDROID-CUSTOM",
938                        Nickname.CONTENT_ITEM_TYPE + ";Nicky;;;;;;;;;;;;;;");
939        mVerifier.addContentValuesVerifierElem().addExpected(Nickname.CONTENT_ITEM_TYPE)
940                .put(Nickname.NAME, "Nicky");
941    }
942
943    public void testTolerateBrokenPhoneNumberEntryV21() {
944        mVerifier.initForExportTest(V21);
945        ContactEntry entry = mVerifier.addInputEntry();
946        entry.addContentValues(Phone.CONTENT_ITEM_TYPE)
947                .put(Phone.TYPE, Phone.TYPE_HOME)
948                .put(Phone.NUMBER, "111-222-3333 (Miami)\n444-5555-666 (Tokyo);"
949                        + "777-888-9999 (Chicago);111-222-3333 (Miami)");
950        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
951                .addExpectedNode("TEL", "111-222-3333", new TypeSet("HOME"))
952                .addExpectedNode("TEL", "444-555-5666", new TypeSet("HOME"))
953                .addExpectedNode("TEL", "777-888-9999", new TypeSet("HOME"));
954    }
955
956    private void testPickUpNonEmptyContentValuesCommon(int vcardType) {
957        mVerifier.initForExportTest(vcardType);
958        ContactEntry entry = mVerifier.addInputEntry();
959        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
960                .put(StructuredName.IS_PRIMARY, 1);  // Empty name. Should be ignored.
961        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
962                .put(StructuredName.FAMILY_NAME, "family1");  // Not primary. Should be ignored.
963        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
964                .put(StructuredName.IS_PRIMARY, 1)
965                .put(StructuredName.FAMILY_NAME, "family2");  // This entry is what we want.
966        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
967                .put(StructuredName.IS_PRIMARY, 1)
968                .put(StructuredName.FAMILY_NAME, "family3");
969        entry.addContentValues(StructuredName.CONTENT_ITEM_TYPE)
970                .put(StructuredName.FAMILY_NAME, "family4");
971        mVerifier.addPropertyNodesVerifierElem()
972                .addExpectedNode("N", Arrays.asList("family2", "", "", "", ""))
973                .addExpectedNode("FN", "family2");
974    }
975
976    public void testPickUpNonEmptyContentValuesV21() {
977        testPickUpNonEmptyContentValuesCommon(V21);
978    }
979
980    public void testPickUpNonEmptyContentValuesV30() {
981        testPickUpNonEmptyContentValuesCommon(V30);
982    }
983}
984