Home | History | Annotate | Download | only in account
      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 
     17 package com.android.contacts.common.model.account;
     18 
     19 import android.content.Context;
     20 import android.provider.ContactsContract.CommonDataKinds.Email;
     21 import android.provider.ContactsContract.CommonDataKinds.Event;
     22 import android.provider.ContactsContract.CommonDataKinds.Im;
     23 import android.provider.ContactsContract.CommonDataKinds.Note;
     24 import android.provider.ContactsContract.CommonDataKinds.Organization;
     25 import android.provider.ContactsContract.CommonDataKinds.Photo;
     26 import android.provider.ContactsContract.CommonDataKinds.Relation;
     27 import android.provider.ContactsContract.CommonDataKinds.SipAddress;
     28 import android.provider.ContactsContract.CommonDataKinds.StructuredName;
     29 import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
     30 import android.provider.ContactsContract.CommonDataKinds.Website;
     31 import android.test.AndroidTestCase;
     32 import android.test.suitebuilder.annotation.SmallTest;
     33 import android.util.Log;
     34 
     35 import com.android.contacts.common.model.dataitem.DataKind;
     36 import com.android.contacts.common.unittest.R;
     37 import com.google.common.base.Objects;
     38 
     39 import java.util.List;
     40 
     41 /**
     42  * Test case for {@link com.android.contacts.common.model.account.ExternalAccountType}.
     43  *
     44  * adb shell am instrument -w -e class com.android.contacts.model.ExternalAccountTypeTest \
     45        com.android.contacts.tests/android.test.InstrumentationTestRunner
     46  */
     47 @SmallTest
     48 public class ExternalAccountTypeTest extends AndroidTestCase {
     49     public void testResolveExternalResId() {
     50         final Context c = getContext();
     51         // In this test we use the test package itself as an external package.
     52         final String packageName = getTestContext().getPackageName();
     53 
     54         // Resource name empty.
     55         assertEquals(-1, ExternalAccountType.resolveExternalResId(c, null, packageName, ""));
     56         assertEquals(-1, ExternalAccountType.resolveExternalResId(c, "", packageName, ""));
     57 
     58         // Name doesn't begin with '@'
     59         assertEquals(-1, ExternalAccountType.resolveExternalResId(c, "x", packageName, ""));
     60 
     61         // Invalid resource name
     62         assertEquals(-1, ExternalAccountType.resolveExternalResId(c, "@", packageName, ""));
     63         assertEquals(-1, ExternalAccountType.resolveExternalResId(c, "@a", packageName, ""));
     64         assertEquals(-1, ExternalAccountType.resolveExternalResId(c, "@a/b", packageName, ""));
     65 
     66         // Valid resource name
     67         assertEquals(R.string.test_string, ExternalAccountType.resolveExternalResId(c,
     68                 "@string/test_string", packageName, ""));
     69     }
     70 
     71     /**
     72      * Initialize with an invalid package name and see if type type will *not* be initialized.
     73      */
     74     public void testNoPackage() {
     75         final ExternalAccountType type = new ExternalAccountType(getContext(),
     76                 "!!!no such package name!!!", false);
     77         assertFalse(type.isInitialized());
     78     }
     79 
     80     /**
     81      * Initialize with the name of an existing package, which has no contacts.xml metadata.
     82      */
     83     /*
     84     public void testNoMetadata() {
     85         // Use the main application package, which does exist, but has no contacts.xml in it.
     86         String packageName = getContext().getPackageName();
     87         Log.e("TEST", packageName);
     88         final ExternalAccountType type = new ExternalAccountType(getContext(),
     89                 packageName, false);
     90         assertTrue(type.isInitialized());
     91     }
     92     */
     93 
     94     /**
     95      * Initialize with the test package itself and see if EditSchema is correctly parsed.
     96      */
     97     public void testEditSchema() {
     98         final ExternalAccountType type = new ExternalAccountType(getContext(),
     99                 getTestContext().getPackageName(), false);
    100 
    101         assertTrue(type.isInitialized());
    102 
    103         // Let's just check if the DataKinds are registered.
    104         assertNotNull(type.getKindForMimetype(StructuredName.CONTENT_ITEM_TYPE));
    105         assertNotNull(type.getKindForMimetype(DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME));
    106         assertNotNull(type.getKindForMimetype(DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME));
    107         assertNotNull(type.getKindForMimetype(Email.CONTENT_ITEM_TYPE));
    108         assertNotNull(type.getKindForMimetype(StructuredPostal.CONTENT_ITEM_TYPE));
    109         assertNotNull(type.getKindForMimetype(Im.CONTENT_ITEM_TYPE));
    110         assertNotNull(type.getKindForMimetype(Organization.CONTENT_ITEM_TYPE));
    111         assertNotNull(type.getKindForMimetype(Photo.CONTENT_ITEM_TYPE));
    112         assertNotNull(type.getKindForMimetype(Note.CONTENT_ITEM_TYPE));
    113         assertNotNull(type.getKindForMimetype(Website.CONTENT_ITEM_TYPE));
    114         assertNotNull(type.getKindForMimetype(SipAddress.CONTENT_ITEM_TYPE));
    115         assertNotNull(type.getKindForMimetype(Event.CONTENT_ITEM_TYPE));
    116         assertNotNull(type.getKindForMimetype(Relation.CONTENT_ITEM_TYPE));
    117     }
    118 
    119     /**
    120      * Initialize with "contacts_fallback.xml" and compare the DataKinds to those of
    121      * {@link com.android.contacts.common.model.account.FallbackAccountType}.
    122      */
    123     public void testEditSchema_fallback() {
    124         final ExternalAccountType type = new ExternalAccountType(getContext(),
    125                 getTestContext().getPackageName(), false,
    126                 getTestContext().getResources().getXml(R.xml.contacts_fallback)
    127                 );
    128 
    129         assertTrue(type.isInitialized());
    130 
    131         // Create a fallback type with the same resource package name, and compare all the data
    132         // kinds to its.
    133         final AccountType reference = FallbackAccountType.createWithPackageNameForTest(
    134                 getContext(), type.resourcePackageName);
    135 
    136         assertsDataKindEquals(reference.getSortedDataKinds(), type.getSortedDataKinds());
    137     }
    138 
    139     public void testEditSchema_mustHaveChecks() {
    140         checkEditSchema_mustHaveChecks(R.xml.missing_contacts_base, true);
    141         checkEditSchema_mustHaveChecks(R.xml.missing_contacts_photo, false);
    142         checkEditSchema_mustHaveChecks(R.xml.missing_contacts_name, false);
    143         checkEditSchema_mustHaveChecks(R.xml.missing_contacts_name_attr1, false);
    144         checkEditSchema_mustHaveChecks(R.xml.missing_contacts_name_attr2, false);
    145         checkEditSchema_mustHaveChecks(R.xml.missing_contacts_name_attr3, false);
    146         checkEditSchema_mustHaveChecks(R.xml.missing_contacts_name_attr4, false);
    147         checkEditSchema_mustHaveChecks(R.xml.missing_contacts_name_attr5, false);
    148         checkEditSchema_mustHaveChecks(R.xml.missing_contacts_name_attr6, false);
    149         checkEditSchema_mustHaveChecks(R.xml.missing_contacts_name_attr7, false);
    150     }
    151 
    152     private void checkEditSchema_mustHaveChecks(int xmlResId, boolean expectInitialized) {
    153         final ExternalAccountType type = new ExternalAccountType(getContext(),
    154                 getTestContext().getPackageName(), false,
    155                 getTestContext().getResources().getXml(xmlResId)
    156                 );
    157 
    158         assertEquals(expectInitialized, type.isInitialized());
    159     }
    160 
    161     /**
    162      * Initialize with "contacts_readonly.xml" and see if all data kinds are correctly registered.
    163      */
    164     public void testReadOnlyDefinition() {
    165         final ExternalAccountType type = new ExternalAccountType(getContext(),
    166                 getTestContext().getPackageName(), false,
    167                 getTestContext().getResources().getXml(R.xml.contacts_readonly)
    168                 );
    169         assertTrue(type.isInitialized());
    170 
    171         // Shouldn't have a "null" mimetype.
    172         assertTrue(type.getKindForMimetype(null) == null);
    173 
    174         // 3 kinds are defined in XML and 4 are added by default.
    175         assertEquals(4 + 3, type.getSortedDataKinds().size());
    176 
    177         // Check for the default kinds.
    178         assertNotNull(type.getKindForMimetype(StructuredName.CONTENT_ITEM_TYPE));
    179         assertNotNull(type.getKindForMimetype(DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME));
    180         assertNotNull(type.getKindForMimetype(DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME));
    181         assertNotNull(type.getKindForMimetype(Photo.CONTENT_ITEM_TYPE));
    182 
    183         // Check for type specific kinds.
    184         DataKind kind = type.getKindForMimetype("vnd.android.cursor.item/a.b.c");
    185         assertNotNull(kind);
    186         // No check for icon -- we actually just ignore it.
    187         assertEquals("data1", ((BaseAccountType.SimpleInflater) kind.actionHeader)
    188                 .getColumnNameForTest());
    189         assertEquals("data2", ((BaseAccountType.SimpleInflater) kind.actionBody)
    190                 .getColumnNameForTest());
    191 
    192         kind = type.getKindForMimetype("vnd.android.cursor.item/d.e.f");
    193         assertNotNull(kind);
    194         assertEquals("data3", ((BaseAccountType.SimpleInflater) kind.actionHeader)
    195                 .getColumnNameForTest());
    196         assertEquals("data4", ((BaseAccountType.SimpleInflater) kind.actionBody)
    197                 .getColumnNameForTest());
    198 
    199         kind = type.getKindForMimetype("vnd.android.cursor.item/xyz");
    200         assertNotNull(kind);
    201         assertEquals("data5", ((BaseAccountType.SimpleInflater) kind.actionHeader)
    202                 .getColumnNameForTest());
    203         assertEquals("data6", ((BaseAccountType.SimpleInflater) kind.actionBody)
    204                 .getColumnNameForTest());
    205     }
    206 
    207     private static void assertsDataKindEquals(List<DataKind> expectedKinds,
    208             List<DataKind> actualKinds) {
    209         final int count = Math.max(actualKinds.size(), expectedKinds.size());
    210         for (int i = 0; i < count; i++) {
    211             String actual =  actualKinds.size() > i ? actualKinds.get(i).toString() : "(n/a)";
    212             String expected =  expectedKinds.size() > i ? expectedKinds.get(i).toString() : "(n/a)";
    213 
    214             // Because assertEquals()'s output is not very friendly when comparing two similar
    215             // strings, we manually do the check.
    216             if (!Objects.equal(actual, expected)) {
    217                 final int commonPrefixEnd = findCommonPrefixEnd(actual, expected);
    218                 fail("Kind #" + i
    219                         + "\n[Actual]\n" + insertMarkerAt(actual, commonPrefixEnd)
    220                         + "\n[Expected]\n" + insertMarkerAt(expected, commonPrefixEnd));
    221             }
    222         }
    223     }
    224 
    225     private static int findCommonPrefixEnd(String s1, String s2) {
    226         int i = 0;
    227         for (;;) {
    228             final boolean s1End = (s1.length() <= i);
    229             final boolean s2End = (s2.length() <= i);
    230             if (s1End || s2End) {
    231                 return i;
    232             }
    233             if (s1.charAt(i) != s2.charAt(i)) {
    234                 return i;
    235             }
    236             i++;
    237         }
    238     }
    239 
    240     private static String insertMarkerAt(String s, int position) {
    241         final String MARKER = "***";
    242         if (position > s.length()) {
    243             return s + MARKER;
    244         } else {
    245             return new StringBuilder(s).insert(position, MARKER).toString();
    246         }
    247     }
    248 }
    249