ContactEditorUtilsTest.java revision 3e435f0e724cb3e88efce15f760e59b9bc08f0d3
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
17package com.android.contacts.editor;
18
19import com.android.contacts.editor.ContactEditorUtils;
20import com.android.contacts.model.AccountType;
21import com.android.contacts.model.AccountWithDataSet;
22import com.android.contacts.tests.mocks.MockAccountTypeManager;
23import com.google.common.collect.Sets;
24
25import android.content.Context;
26import android.test.AndroidTestCase;
27import android.test.MoreAsserts;
28import android.test.suitebuilder.annotation.SmallTest;
29
30import java.util.Collection;
31import java.util.Set;
32
33/**
34 * Test case for {@link ContactEditorUtils}.
35 *
36 * adb shell am instrument -w -e class com.android.contacts.editor.ContactEditorUtilsTest \
37       com.android.contacts.tests/android.test.InstrumentationTestRunner
38 */
39@SmallTest
40public class ContactEditorUtilsTest extends AndroidTestCase {
41    private MockAccountTypeManager mAccountTypes;
42    private ContactEditorUtils mTarget;
43
44    private static final MockAccountType TYPE1 = new MockAccountType("type1", null, true);
45    private static final MockAccountType TYPE2 = new MockAccountType("type2", null, true);
46    private static final MockAccountType TYPE2EX = new MockAccountType("type2", "ext", true);
47
48    // Only type 3 is "readonly".
49    private static final MockAccountType TYPE3 = new MockAccountType("type3", null, false);
50
51    private static final AccountWithDataSet ACCOUNT_1_A = new AccountWithDataSet(
52            "a", TYPE1.accountType, TYPE1.dataSet);
53    private static final AccountWithDataSet ACCOUNT_1_B = new AccountWithDataSet(
54            "b", TYPE1.accountType, TYPE1.dataSet);
55
56    private static final AccountWithDataSet ACCOUNT_2_A = new AccountWithDataSet(
57            "a", TYPE2.accountType, TYPE2.dataSet);
58    private static final AccountWithDataSet ACCOUNT_2EX_A = new AccountWithDataSet(
59            "a", TYPE2EX.accountType, TYPE2EX.dataSet);
60
61    private static final AccountWithDataSet ACCOUNT_3_C = new AccountWithDataSet(
62            "c", TYPE3.accountType, TYPE3.dataSet);
63
64    @Override
65    protected void setUp() throws Exception {
66        // Initialize with 0 types, 0 accounts.
67        mAccountTypes = new MockAccountTypeManager(new AccountType[] {},
68                new AccountWithDataSet[] {});
69        mTarget = new ContactEditorUtils(getContext(), mAccountTypes);
70
71        // Clear the preferences.
72        mTarget.cleanupForTest();
73    }
74
75    private void setAccountTypes(AccountType... types) {
76        mAccountTypes.mTypes = types;
77    }
78
79    private void setAccounts(AccountWithDataSet... accounts) {
80        mAccountTypes.mAccounts = accounts;
81    }
82
83    public void testGetWritableAccountTypeStrings() {
84        String[] types;
85
86        // 0 writable types
87        setAccountTypes();
88
89        types = mTarget.getWritableAccountTypeStrings();
90        MoreAsserts.assertEquals(types, new String[0]);
91
92        // 1 writable type
93        setAccountTypes(TYPE1);
94
95        types = mTarget.getWritableAccountTypeStrings();
96        MoreAsserts.assertEquals(Sets.newHashSet(TYPE1.accountType), Sets.newHashSet(types));
97
98        // 2 writable types
99        setAccountTypes(TYPE1, TYPE2EX);
100
101        types = mTarget.getWritableAccountTypeStrings();
102        MoreAsserts.assertEquals(Sets.newHashSet(TYPE1.accountType, TYPE2EX.accountType),
103                Sets.newHashSet(types));
104
105        // 3 writable types + 1 readonly type
106        setAccountTypes(TYPE1, TYPE2, TYPE2EX, TYPE3);
107
108        types = mTarget.getWritableAccountTypeStrings();
109        MoreAsserts.assertEquals(
110                Sets.newHashSet(TYPE1.accountType, TYPE2.accountType, TYPE2EX.accountType),
111                Sets.newHashSet(types));
112    }
113
114    /**
115     * Test for
116     * - {@link ContactEditorUtils#saveDefaultAndAllAccounts}
117     * - {@link ContactEditorUtils#getDefaultAccount}
118     * - {@link ContactEditorUtils#getSavedAccounts()}
119     */
120    public void testSaveDefaultAndAllAccounts() {
121        // Use these account types here.
122        setAccountTypes(TYPE1, TYPE2);
123
124        // If none has been saved, it should return an empty list.
125        assertEquals(0, mTarget.getSavedAccounts().size());
126
127        // Save 0 accounts.
128        mAccountTypes.mAccounts = new AccountWithDataSet[]{};
129        mTarget.saveDefaultAndAllAccounts(null);
130        assertNull(mTarget.getDefaultAccount());
131        MoreAsserts.assertEquals(
132                Sets.newHashSet(mAccountTypes.mAccounts),
133                toSet(mTarget.getSavedAccounts()));
134
135        // 1 account
136        mAccountTypes.mAccounts = new AccountWithDataSet[]{ACCOUNT_1_A};
137        mTarget.saveDefaultAndAllAccounts(ACCOUNT_1_A);
138        assertEquals(ACCOUNT_1_A, mTarget.getDefaultAccount());
139        MoreAsserts.assertEquals(
140                Sets.newHashSet(mAccountTypes.mAccounts),
141                toSet(mTarget.getSavedAccounts()));
142
143        // 2 accounts
144        mAccountTypes.mAccounts = new AccountWithDataSet[]{ACCOUNT_1_A, ACCOUNT_1_B};
145        mTarget.saveDefaultAndAllAccounts(ACCOUNT_1_B);
146        assertEquals(ACCOUNT_1_B, mTarget.getDefaultAccount());
147        MoreAsserts.assertEquals(
148                Sets.newHashSet(mAccountTypes.mAccounts),
149                toSet(mTarget.getSavedAccounts()));
150
151        // 2 accounts, and save null as the default.  Even though there are accounts, the saved
152        // account list should be empty in this case.
153        mTarget.saveDefaultAndAllAccounts(null);
154        assertNull(mTarget.getDefaultAccount());
155        assertEquals(0, mTarget.getSavedAccounts().size());
156    }
157
158    public void testIsAccountValid() {
159        // Use these account types here.
160        setAccountTypes(TYPE1, TYPE2);
161
162        // 0 accounts
163        mAccountTypes.mAccounts = new AccountWithDataSet[]{};
164        assertFalse(mTarget.isValidAccount(ACCOUNT_1_A));
165        assertTrue(mTarget.isValidAccount(null)); // null is always valid
166
167        // 2 accounts
168        mAccountTypes.mAccounts = new AccountWithDataSet[]{ACCOUNT_1_A, ACCOUNT_2_A};
169        assertTrue(mTarget.isValidAccount(ACCOUNT_1_A));
170        assertTrue(mTarget.isValidAccount(ACCOUNT_2_A));
171        assertFalse(mTarget.isValidAccount(ACCOUNT_2EX_A));
172        assertTrue(mTarget.isValidAccount(null)); // null is always valid
173    }
174
175    /**
176     * Tests for {@link ContactEditorUtils#shouldShowAccountChangedNotification()}, starting with
177     * 0 accounts.
178     */
179    public void testShouldShowAccountChangedNotification_0Accounts() {
180        // There's always at least one writable type...
181        setAccountTypes(TYPE1);
182
183        // First launch -- always true.
184        assertTrue(mTarget.shouldShowAccountChangedNotification());
185
186        // We show the notification here, and user clicked "add account"
187        setAccounts(ACCOUNT_1_A);
188
189        // Now we open the contact editor with the new account.
190
191        // When closing the editor, we save the default account.
192        mTarget.saveDefaultAndAllAccounts(ACCOUNT_1_A);
193
194        // Next time the user creates a contact, we don't show the notification.
195        assertFalse(mTarget.shouldShowAccountChangedNotification());
196
197        // User added a new writable account, ACCOUNT_1_B.
198        setAccounts(ACCOUNT_1_A, ACCOUNT_1_B);
199
200        // Now we show the notification again.
201        assertTrue(mTarget.shouldShowAccountChangedNotification());
202
203        // User saved a new contact.  We update the account list and the default account.
204        mTarget.saveDefaultAndAllAccounts(ACCOUNT_1_B);
205
206        // User created another contact.  Now we don't show the notification.
207        assertFalse(mTarget.shouldShowAccountChangedNotification());
208
209        // User installed a new contact sync adapter...
210
211        // Added a new account type: TYPE2, and the TYPE2EX extension.
212        setAccountTypes(TYPE1, TYPE2, TYPE2EX);
213        // Add new accounts: ACCOUNT_2_A, ACCOUNT_2EX_A.
214        setAccounts(ACCOUNT_1_A, ACCOUNT_1_B, ACCOUNT_2_A, ACCOUNT_2EX_A);
215
216        // New account means another notification.
217        assertTrue(mTarget.shouldShowAccountChangedNotification());
218
219        // User saves a new contact, with a different default account.
220        mTarget.saveDefaultAndAllAccounts(ACCOUNT_2_A);
221
222        // Next time user creates a contact, no notification.
223        assertFalse(mTarget.shouldShowAccountChangedNotification());
224
225        // Remove ACCOUNT_2EX_A.
226        setAccountTypes(TYPE1, TYPE2, TYPE2EX);
227        setAccounts(ACCOUNT_1_A, ACCOUNT_1_B, ACCOUNT_2_A);
228
229        // ACCOUNT_2EX_A was not default, so no notification either.
230        assertFalse(mTarget.shouldShowAccountChangedNotification());
231
232        // Remove ACCOUNT_1_B, which is default.
233        setAccountTypes(TYPE1, TYPE2, TYPE2EX);
234        setAccounts(ACCOUNT_1_A, ACCOUNT_1_B);
235
236        // Now we show the notification.
237        assertTrue(mTarget.shouldShowAccountChangedNotification());
238    }
239
240    /**
241     * Tests for {@link ContactEditorUtils#shouldShowAccountChangedNotification()}, starting with
242     * 1 accounts.
243     */
244    public void testShouldShowAccountChangedNotification_1Account() {
245        setAccountTypes(TYPE1, TYPE2);
246        setAccounts(ACCOUNT_1_A);
247
248        // First launch -- always true.
249        assertTrue(mTarget.shouldShowAccountChangedNotification());
250
251        // User saves a new contact.
252        mTarget.saveDefaultAndAllAccounts(ACCOUNT_1_A);
253
254        // Next time, no notification.
255        assertFalse(mTarget.shouldShowAccountChangedNotification());
256
257        // The rest is the same...
258    }
259
260    /**
261     * Tests for {@link ContactEditorUtils#shouldShowAccountChangedNotification()}, starting with
262     * 0 accounts, and the user selected "local only".
263     */
264    public void testShouldShowAccountChangedNotification_0Account_localOnly() {
265        // There's always at least one writable type...
266        setAccountTypes(TYPE1);
267
268        // First launch -- always true.
269        assertTrue(mTarget.shouldShowAccountChangedNotification());
270
271        // We show the notification here, and user clicked "keep local" and saved an contact.
272        mTarget.saveDefaultAndAllAccounts(null);
273
274        // Now there are no accounts, and default account is null.
275
276        // The user created another contact, but this we shouldn't show the notification.
277        assertFalse(mTarget.shouldShowAccountChangedNotification());
278    }
279
280    public void testShouldShowAccountChangedNotification_sanity_check() {
281        // Prepare 1 account and save it as the default.
282        setAccountTypes(TYPE1);
283        setAccounts(ACCOUNT_1_A);
284
285        mTarget.saveDefaultAndAllAccounts(ACCOUNT_1_A);
286
287        // Right after a save, the dialog shouldn't show up.
288        assertFalse(mTarget.shouldShowAccountChangedNotification());
289
290        // Remove the default account to emulate broken preferences.
291        mTarget.removeDefaultAccountForTest();
292        assertTrue(mTarget.shouldShowAccountChangedNotification());
293    }
294
295    private static <T> Set<T> toSet(Collection<T> collection) {
296        Set<T> ret = Sets.newHashSet();
297        ret.addAll(collection);
298        return ret;
299    }
300
301    private static class MockAccountType extends AccountType {
302        private boolean mAreContactsWritable;
303
304        public MockAccountType(String accountType, String dataSet, boolean areContactsWritable) {
305            this.accountType = accountType;
306            this.dataSet = dataSet;
307            mAreContactsWritable = areContactsWritable;
308        }
309
310        @Override
311        public boolean areContactsWritable() {
312            return mAreContactsWritable;
313        }
314
315        @Override
316        public boolean isGroupMembershipEditable() {
317            return true;
318        }
319    }
320}
321