1 /*
2  * Copyright (C) 2011 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 package com.android.vcard.tests;
17 
18 import com.android.vcard.VCardConfig;
19 import com.android.vcard.VCardConstants;
20 import com.android.vcard.VCardEntry;
21 import com.android.vcard.VCardEntry.AndroidCustomData;
22 import com.android.vcard.VCardEntry.AnniversaryData;
23 import com.android.vcard.VCardEntry.BirthdayData;
24 import com.android.vcard.VCardEntry.EmailData;
25 import com.android.vcard.VCardEntry.EntryElement;
26 import com.android.vcard.VCardEntry.EntryLabel;
27 import com.android.vcard.VCardEntry.ImData;
28 import com.android.vcard.VCardEntry.NameData;
29 import com.android.vcard.VCardEntry.NicknameData;
30 import com.android.vcard.VCardEntry.NoteData;
31 import com.android.vcard.VCardEntry.OrganizationData;
32 import com.android.vcard.VCardEntry.PhoneData;
33 import com.android.vcard.VCardEntry.PhotoData;
34 import com.android.vcard.VCardEntry.PostalData;
35 import com.android.vcard.VCardEntry.SipData;
36 import com.android.vcard.VCardEntryConstructor;
37 import com.android.vcard.VCardEntryHandler;
38 import com.android.vcard.VCardInterpreter;
39 import com.android.vcard.VCardProperty;
40 
41 import android.content.ContentProviderOperation;
42 import android.content.ContentResolver;
43 import android.provider.ContactsContract.CommonDataKinds.Email;
44 import android.provider.ContactsContract.CommonDataKinds.Im;
45 import android.provider.ContactsContract.CommonDataKinds.Organization;
46 import android.provider.ContactsContract.CommonDataKinds.Phone;
47 import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
48 import android.provider.ContactsContract.CommonDataKinds.SipAddress;
49 import android.test.AndroidTestCase;
50 
51 import java.util.ArrayList;
52 import java.util.Arrays;
53 import java.util.HashMap;
54 import java.util.List;
55 import java.util.Map;
56 
57 public class VCardEntryTests extends AndroidTestCase {
58     private class MockVCardEntryHandler implements VCardEntryHandler {
59         private List<VCardEntry> mEntries = new ArrayList<VCardEntry>();
60         private boolean mOnStartCalled;
61         private boolean mOnEndCalled;
62 
63         @Override
onStart()64         public void onStart() {
65             assertFalse(mOnStartCalled);
66             mOnStartCalled = true;
67         }
68 
69         @Override
onEntryCreated(VCardEntry entry)70         public void onEntryCreated(VCardEntry entry) {
71             assertTrue(mOnStartCalled);
72             assertFalse(mOnEndCalled);
73             mEntries.add(entry);
74         }
75 
76         @Override
onEnd()77         public void onEnd() {
78             assertTrue(mOnStartCalled);
79             assertFalse(mOnEndCalled);
80             mOnEndCalled = true;
81         }
82 
getEntries()83         public List<VCardEntry> getEntries() {
84             return mEntries;
85         }
86     }
87 
88     /**
89      * Tests VCardEntry and related clasess can handle nested classes given
90      * {@link VCardInterpreter} is called appropriately.
91      *
92      * This test manually calls VCardInterpreter's callback mechanism and checks
93      * {@link VCardEntryConstructor} constructs {@link VCardEntry} per given calls.
94      *
95      * Intended vCard is as follows:
96      * <code>
97      * BEGIN:VCARD
98      * N:test1
99      * BEGIN:VCARD
100      * N:test2
101      * END:VCARD
102      * TEL:1
103      * END:VCARD
104      * </code>
105      */
testNestHandling()106     public void testNestHandling() {
107         VCardEntryConstructor entryConstructor = new VCardEntryConstructor();
108         MockVCardEntryHandler entryHandler = new MockVCardEntryHandler();
109         entryConstructor.addEntryHandler(entryHandler);
110 
111         entryConstructor.onVCardStarted();
112         entryConstructor.onEntryStarted();
113         VCardProperty property = new VCardProperty();
114         property.setName(VCardConstants.PROPERTY_N);
115         property.setValues("test1");
116         entryConstructor.onPropertyCreated(property);
117 
118         entryConstructor.onEntryStarted();  // begin nest
119         property = new VCardProperty();
120         property.setName(VCardConstants.PROPERTY_N);
121         property.setValues("test2");
122         entryConstructor.onPropertyCreated(property);
123         entryConstructor.onEntryEnded();  // end nest
124 
125         property = new VCardProperty();
126         property.setName(VCardConstants.PROPERTY_TEL);
127         property.setValues("1");
128         entryConstructor.onPropertyCreated(property);
129         entryConstructor.onEntryEnded();
130         entryConstructor.onVCardEnded();
131 
132         List<VCardEntry> entries = entryHandler.getEntries();
133         assertEquals(2, entries.size());
134         VCardEntry parent = entries.get(1);
135         VCardEntry child = entries.get(0);
136         assertEquals("test1", parent.getDisplayName());
137         assertEquals("test2", child.getDisplayName());
138         List<VCardEntry.PhoneData> phoneList = parent.getPhoneList();
139         assertNotNull(phoneList);
140         assertEquals(1, phoneList.size());
141         assertEquals("1", phoneList.get(0).getNumber());
142     }
143 
144     private class MockEntryElementIterator implements VCardEntry.EntryElementIterator {
145         private boolean mStartCalled;
146         private boolean mEndCalled;
147         private EntryLabel mLabel;
148         private final Map<EntryLabel, EntryElement> mExpectedElements =
149                 new HashMap<EntryLabel, EntryElement>();
150 
addExpectedElement(EntryElement elem)151         public void addExpectedElement(EntryElement elem) {
152             mExpectedElements.put(elem.getEntryLabel(), elem);
153         }
154 
155         @Override
onIterationStarted()156         public void onIterationStarted() {
157             assertFalse(mStartCalled);
158             assertFalse(mEndCalled);
159             assertNull(mLabel);
160             mStartCalled = true;
161         }
162 
163         @Override
onIterationEnded()164         public void onIterationEnded() {
165             assertTrue(mStartCalled);
166             assertFalse(mEndCalled);
167             assertNull(mLabel);
168             assertTrue("Expected Elements remaining: " +
169                     Arrays.toString(mExpectedElements.values().toArray()),
170                     mExpectedElements.isEmpty());
171         }
172 
173         @Override
onElementGroupStarted(EntryLabel label)174         public void onElementGroupStarted(EntryLabel label) {
175             assertTrue(mStartCalled);
176             assertFalse(mEndCalled);
177             assertNull(mLabel);
178             mLabel = label;
179         }
180 
181         @Override
onElementGroupEnded()182         public void onElementGroupEnded() {
183             assertTrue(mStartCalled);
184             assertFalse(mEndCalled);
185             assertNotNull(mLabel);
186             mLabel = null;
187         }
188 
189         @Override
onElement(EntryElement elem)190         public boolean onElement(EntryElement elem) {
191             EntryElement expectedElem = mExpectedElements.remove(elem.getEntryLabel());
192             assertNotNull("Unexpected elem: " + elem.toString(), expectedElem);
193             assertEquals(expectedElem, elem);
194             return true;
195         }
196     }
197 
198     /**
199      * Tests every element in VCardEntry is iterated by
200      * {@link VCardEntry#iterateAllData(com.android.vcard.VCardEntry.EntryElementIterator)}.
201      */
testEntryElementIterator()202     public void testEntryElementIterator() {
203         VCardEntry entry = new VCardEntry();
204         MockEntryElementIterator iterator = new MockEntryElementIterator();
205 
206         VCardProperty property = new VCardProperty();
207         property.setName("N");
208         property.setValues("family", "given", "middle", "prefix", "suffix");
209         entry.addProperty(property);
210         NameData nameData = new NameData();
211         nameData.setFamily("family");
212         nameData.setGiven("given");
213         nameData.setMiddle("middle");
214         nameData.setPrefix("prefix");
215         nameData.setSuffix("suffix");
216         iterator.addExpectedElement(nameData);
217 
218         property = new VCardProperty();
219         property.setName("TEL");
220         property.setParameter("TYPE", "HOME");
221         property.setValues("1");
222         entry.addProperty(property);
223         PhoneData phoneData = new PhoneData("1", Phone.TYPE_HOME, null, false);
224         iterator.addExpectedElement(phoneData);
225 
226         property = new VCardProperty();
227         property.setName("EMAIL");
228         property.setParameter("TYPE", "WORK");
229         property.setValues("email");
230         entry.addProperty(property);
231         EmailData emailData = new EmailData("email", Email.TYPE_WORK, null, false);
232         iterator.addExpectedElement(emailData);
233 
234         property = new VCardProperty();
235         property.setName("ADR");
236         property.setParameter("TYPE", "HOME");
237         property.setValues(null, null, "street");
238         entry.addProperty(property);
239         PostalData postalData = new PostalData(null, null, "street", null, null, null,
240                 null, StructuredPostal.TYPE_HOME, null, false,
241                 VCardConfig.VCARD_TYPE_DEFAULT);
242         iterator.addExpectedElement(postalData);
243 
244         property = new VCardProperty();
245         property.setName("ORG");
246         property.setValues("organization", "depertment");
247         entry.addProperty(property);
248         OrganizationData organizationData = new OrganizationData(
249                 "organization", "depertment", null, null, Organization.TYPE_WORK, false);
250         iterator.addExpectedElement(organizationData);
251 
252         property = new VCardProperty();
253         property.setName("X-GOOGLE-TALK");
254         property.setParameter("TYPE", "WORK");
255         property.setValues("googletalk");
256         entry.addProperty(property);
257         ImData imData = new ImData(
258                 Im.PROTOCOL_GOOGLE_TALK, null, "googletalk", Im.TYPE_WORK, false);
259         iterator.addExpectedElement(imData);
260 
261         property = new VCardProperty();
262         property.setName("PHOTO");
263         property.setParameter("TYPE", "PNG");
264         byte[] photoBytes = new byte[] {1};
265         property.setByteValue(photoBytes);
266         entry.addProperty(property);
267         PhotoData photoData = new PhotoData("PNG", photoBytes, false);
268         iterator.addExpectedElement(photoData);
269 
270         property = new VCardProperty();
271         property.setName("X-SIP");
272         property.setValues("sipdata");
273         entry.addProperty(property);
274         SipData sipData = new SipData("sip:sipdata", SipAddress.TYPE_OTHER, null, false);
275         iterator.addExpectedElement(sipData);
276 
277         property = new VCardProperty();
278         property.setName("NICKNAME");
279         property.setValues("nickname");
280         entry.addProperty(property);
281         NicknameData nicknameData = new NicknameData("nickname");
282         iterator.addExpectedElement(nicknameData);
283 
284         property = new VCardProperty();
285         property.setName("NOTE");
286         property.setValues("note");
287         entry.addProperty(property);
288         NoteData noteData = new NoteData("note");
289         iterator.addExpectedElement(noteData);
290 
291         property = new VCardProperty();
292         property.setName("BDAY");
293         property.setValues("birthday");
294         entry.addProperty(property);
295         BirthdayData birthdayData = new BirthdayData("birthday");
296         iterator.addExpectedElement(birthdayData);
297 
298         property = new VCardProperty();
299         property.setName("ANNIVERSARY");
300         property.setValues("anniversary");
301         entry.addProperty(property);
302         AnniversaryData anniversaryData = new AnniversaryData("anniversary");
303         iterator.addExpectedElement(anniversaryData);
304 
305         property = new VCardProperty();
306         property.setName("X-ANDROID-CUSTOM");
307         property.setValues("mime;value");
308         entry.addProperty(property);
309         AndroidCustomData androidCustom = new AndroidCustomData("mime", Arrays.asList("value"));
310         iterator.addExpectedElement(androidCustom);
311 
312         entry.iterateAllData(iterator);
313     }
314 
testToString()315     public void testToString() {
316         VCardEntry entry = new VCardEntry();
317         VCardProperty property = new VCardProperty();
318         property.setName("N");
319         property.setValues("Family", "Given", "Middle", "Prefix", "Suffix");
320         entry.addProperty(property);
321         entry.consolidateFields();
322 
323         String result = entry.toString();
324         assertNotNull(result);
325 
326         assertTrue(result.contains(String.valueOf(entry.hashCode())));
327         assertTrue(result.contains(VCardEntry.EntryLabel.NAME.toString()));
328         assertTrue(result.contains("Family"));
329         assertTrue(result.contains("Given"));
330         assertTrue(result.contains("Middle"));
331         assertTrue(result.contains("Prefix"));
332         assertTrue(result.contains("Suffix"));
333     }
334 
335     /**
336      * Tests that VCardEntry emits correct insert operation for name field.
337      */
testConstructInsertOperationsInsertName()338     public void testConstructInsertOperationsInsertName() {
339         VCardEntry entry = new VCardEntry();
340         VCardProperty property = new VCardProperty();
341         property.setName("N");
342         property.setValues("Family", "Given", "Middle", "Prefix", "Suffix");
343         entry.addProperty(property);
344         entry.consolidateFields();
345 
346         NameData nameData = entry.getNameData();
347         assertEquals("Family", nameData.getFamily());
348         assertEquals("Given", nameData.getGiven());
349         assertEquals("Middle", nameData.getMiddle());
350         assertEquals("Prefix", nameData.getPrefix());
351         assertEquals("Suffix", nameData.getSuffix());
352 
353         ContentResolver resolver = getContext().getContentResolver();
354         ArrayList<ContentProviderOperation> operationList =
355                 new ArrayList<ContentProviderOperation>();
356         entry.constructInsertOperations(resolver, operationList);
357 
358         // Need too many details for testing these. Just check basics.
359         // TODO: introduce nice-to-test mechanism here.
360         assertEquals(2, operationList.size());
361         assertEquals(ContentProviderOperation.TYPE_INSERT, operationList.get(0).getType());
362         assertEquals(ContentProviderOperation.TYPE_INSERT, operationList.get(1).getType());
363     }
364 
365     /**
366      * Tests that VCardEntry refrains from emitting unnecessary insert operation.
367      */
testConstructInsertOperationsEmptyData()368     public void testConstructInsertOperationsEmptyData() {
369         VCardEntry entry = new VCardEntry();
370         ContentResolver resolver = getContext().getContentResolver();
371         ArrayList<ContentProviderOperation> operationList =
372                 new ArrayList<ContentProviderOperation>();
373         entry.constructInsertOperations(resolver, operationList);
374         assertEquals(0, operationList.size());
375     }
376 
377     // TODO: add bunch of test for constructInsertOperations..
378 }