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