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