Home | History | Annotate | Download | only in shadows
      1 package org.robolectric.shadows;
      2 
      3 import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR2;
      4 import static android.os.Build.VERSION_CODES.LOLLIPOP;
      5 import static android.os.Build.VERSION_CODES.LOLLIPOP_MR1;
      6 import static com.google.common.truth.Truth.assertThat;
      7 import static org.junit.Assert.fail;
      8 import static org.robolectric.Shadows.shadowOf;
      9 
     10 import android.accounts.Account;
     11 import android.accounts.AccountManager;
     12 import android.accounts.AccountManagerCallback;
     13 import android.accounts.AccountManagerFuture;
     14 import android.accounts.AuthenticatorDescription;
     15 import android.accounts.AuthenticatorException;
     16 import android.accounts.OnAccountsUpdateListener;
     17 import android.accounts.OperationCanceledException;
     18 import android.app.Activity;
     19 import android.content.Context;
     20 import android.content.Intent;
     21 import android.os.Bundle;
     22 import android.os.Handler;
     23 import androidx.test.core.app.ApplicationProvider;
     24 import androidx.test.ext.junit.runners.AndroidJUnit4;
     25 import java.io.IOException;
     26 import org.junit.Before;
     27 import org.junit.Test;
     28 import org.junit.runner.RunWith;
     29 import org.robolectric.Robolectric;
     30 import org.robolectric.annotation.Config;
     31 import org.robolectric.util.Scheduler;
     32 
     33 @RunWith(AndroidJUnit4.class)
     34 public class ShadowAccountManagerTest {
     35   private AccountManager am;
     36   private Scheduler scheduler;
     37   private Activity activity;
     38 
     39   @Before
     40   public void setUp() throws Exception {
     41     am = AccountManager.get(ApplicationProvider.getApplicationContext());
     42     scheduler = Robolectric.getForegroundThreadScheduler();
     43     activity = new Activity();
     44   }
     45 
     46   @Test
     47   public void testGet() {
     48     assertThat(am).isNotNull();
     49     assertThat(am).isSameAs(AccountManager.get(ApplicationProvider.getApplicationContext()));
     50 
     51     AccountManager activityAM = AccountManager.get(ApplicationProvider.getApplicationContext());
     52     assertThat(activityAM).isNotNull();
     53     assertThat(activityAM).isSameAs(am);
     54   }
     55 
     56   @Test
     57   public void testGetAccounts() {
     58     assertThat(am.getAccounts()).isNotNull();
     59     assertThat(am.getAccounts().length).isEqualTo(0);
     60 
     61     Account a1 = new Account("name_a", "type_a");
     62     shadowOf(am).addAccount(a1);
     63     assertThat(am.getAccounts()).isNotNull();
     64     assertThat(am.getAccounts().length).isEqualTo(1);
     65     assertThat(am.getAccounts()[0]).isSameAs(a1);
     66 
     67     Account a2 = new Account("name_b", "type_b");
     68     shadowOf(am).addAccount(a2);
     69     assertThat(am.getAccounts()).isNotNull();
     70     assertThat(am.getAccounts().length).isEqualTo(2);
     71     assertThat(am.getAccounts()[1]).isSameAs(a2);
     72   }
     73 
     74   @Test
     75   public void getAccountsByType_nullTypeReturnsAllAccounts() {
     76     shadowOf(am).addAccount(new Account("name_1", "type_1"));
     77     shadowOf(am).addAccount(new Account("name_2", "type_2"));
     78     shadowOf(am).addAccount(new Account("name_3", "type_3"));
     79 
     80     assertThat(am.getAccountsByType(null)).asList().containsAllIn(am.getAccounts());
     81   }
     82 
     83   @Test
     84   public void testGetAccountsByType() {
     85     assertThat(am.getAccountsByType("name_a")).isNotNull();
     86     assertThat(am.getAccounts().length).isEqualTo(0);
     87 
     88     Account a1 = new Account("name_a", "type_a");
     89     shadowOf(am).addAccount(a1);
     90     Account[] accounts = am.getAccountsByType("type_a");
     91     assertThat(accounts).isNotNull();
     92     assertThat(accounts.length).isEqualTo(1);
     93     assertThat(accounts[0]).isSameAs(a1);
     94 
     95     Account a2 = new Account("name_b", "type_b");
     96     shadowOf(am).addAccount(a2);
     97     accounts = am.getAccountsByType("type_a");
     98     assertThat(accounts).isNotNull();
     99     assertThat(accounts.length).isEqualTo(1);
    100     assertThat(accounts[0]).isSameAs(a1);
    101 
    102     Account a3 = new Account("name_c", "type_a");
    103     shadowOf(am).addAccount(a3);
    104     accounts = am.getAccountsByType("type_a");
    105     assertThat(accounts).isNotNull();
    106     assertThat(accounts.length).isEqualTo(2);
    107     assertThat(accounts[0]).isSameAs(a1);
    108     assertThat(accounts[1]).isSameAs(a3);
    109   }
    110 
    111   @Test
    112   public void addAuthToken() {
    113     Account account = new Account("name", "type");
    114     shadowOf(am).addAccount(account);
    115 
    116     am.setAuthToken(account, "token_type_1", "token1");
    117     am.setAuthToken(account, "token_type_2", "token2");
    118 
    119     assertThat(am.peekAuthToken(account, "token_type_1")).isEqualTo("token1");
    120     assertThat(am.peekAuthToken(account, "token_type_2")).isEqualTo("token2");
    121   }
    122 
    123   @Test
    124   public void setAuthToken_shouldNotAddTokenIfAccountNotPresent() {
    125     Account account = new Account("name", "type");
    126     am.setAuthToken(account, "token_type_1", "token1");
    127     assertThat(am.peekAuthToken(account, "token_type_1")).isNull();
    128   }
    129 
    130   @Test
    131   public void testAddAccountExplicitly_noPasswordNoExtras() {
    132     Account account = new Account("name", "type");
    133     boolean accountAdded = am.addAccountExplicitly(account, null, null);
    134 
    135     assertThat(accountAdded).isTrue();
    136     assertThat(am.getAccountsByType("type").length).isEqualTo(1);
    137     assertThat(am.getAccountsByType("type")[0].name).isEqualTo("name");
    138 
    139     boolean accountAddedTwice = am.addAccountExplicitly(account, null, null);
    140     assertThat(accountAddedTwice).isFalse();
    141 
    142     account = new Account("another_name", "type");
    143     accountAdded = am.addAccountExplicitly(account, null, null);
    144     assertThat(accountAdded).isTrue();
    145     assertThat(am.getAccountsByType("type").length).isEqualTo(2);
    146     assertThat(am.getAccountsByType("type")[0].name).isEqualTo("name");
    147     assertThat(am.getAccountsByType("type")[1].name).isEqualTo("another_name");
    148     assertThat(am.getPassword(account)).isNull();
    149 
    150     try {
    151       am.addAccountExplicitly(null, null, null);
    152       fail("An illegal argument exception should have been thrown when trying to add a null account");
    153     } catch (IllegalArgumentException iae) {
    154       // NOP
    155     }
    156   }
    157 
    158   @Test
    159   public void testAddAccountExplicitly_withPassword() {
    160     Account account = new Account("name", "type");
    161     boolean accountAdded = am.addAccountExplicitly(account, "passwd", null);
    162 
    163     assertThat(accountAdded).isTrue();
    164     assertThat(am.getPassword(account)).isEqualTo("passwd");
    165   }
    166 
    167   @Test
    168   public void testAddAccountExplicitly_withExtras() {
    169     Account account = new Account("name", "type");
    170     Bundle extras = new Bundle();
    171     extras.putString("key123", "value123");
    172     boolean accountAdded = am.addAccountExplicitly(account, null, extras);
    173 
    174     assertThat(accountAdded).isTrue();
    175     assertThat(am.getUserData(account, "key123")).isEqualTo("value123");
    176     assertThat(am.getUserData(account, "key456")).isNull();
    177   }
    178 
    179   @Test
    180   public void testAddAccountExplicitly_notifiesListenersIfSuccessful() {
    181     TestOnAccountsUpdateListener listener = new TestOnAccountsUpdateListener();
    182     am.addOnAccountsUpdatedListener(listener, null, false);
    183     assertThat(listener.getInvocationCount()).isEqualTo(0);
    184 
    185     Account account = new Account("name", "type");
    186     boolean accountAdded = am.addAccountExplicitly(account, "passwd", null);
    187 
    188     assertThat(accountAdded).isTrue();
    189     assertThat(listener.getInvocationCount()).isEqualTo(1);
    190   }
    191 
    192   @Test
    193   public void testAddAccountExplicitly_doesNotNotifyListenersIfUnsuccessful() {
    194     Account account = new Account("name", "type");
    195     boolean accountAdded = am.addAccountExplicitly(account, "passwd", null);
    196     assertThat(accountAdded).isTrue();
    197 
    198     TestOnAccountsUpdateListener listener = new TestOnAccountsUpdateListener();
    199     am.addOnAccountsUpdatedListener(listener, null, false);
    200     assertThat(listener.getInvocationCount()).isEqualTo(0);
    201 
    202     // This account is added already, so it'll fail
    203     boolean accountAdded2 = am.addAccountExplicitly(account, "passwd", null);
    204     assertThat(accountAdded2).isFalse();
    205     assertThat(listener.getInvocationCount()).isEqualTo(0);
    206   }
    207 
    208   @Test
    209   public void testGetSetUserData_addToInitiallyEmptyExtras() {
    210     Account account = new Account("name", "type");
    211     boolean accountAdded = am.addAccountExplicitly(account, null, null);
    212 
    213     assertThat(accountAdded).isTrue();
    214 
    215     am.setUserData(account, "key123", "value123");
    216     assertThat(am.getUserData(account, "key123")).isEqualTo("value123");
    217   }
    218 
    219   @Test
    220   public void testGetSetUserData_overwrite() {
    221     Account account = new Account("name", "type");
    222     boolean accountAdded = am.addAccountExplicitly(account, null, null);
    223 
    224     assertThat(accountAdded).isTrue();
    225 
    226     am.setUserData(account, "key123", "value123");
    227     assertThat(am.getUserData(account, "key123")).isEqualTo("value123");
    228 
    229     am.setUserData(account, "key123", "value456");
    230     assertThat(am.getUserData(account, "key123")).isEqualTo("value456");
    231   }
    232 
    233   @Test
    234   public void testGetSetUserData_remove() {
    235     Account account = new Account("name", "type");
    236     boolean accountAdded = am.addAccountExplicitly(account, null, null);
    237 
    238     assertThat(accountAdded).isTrue();
    239 
    240     am.setUserData(account, "key123", "value123");
    241     assertThat(am.getUserData(account, "key123")).isEqualTo("value123");
    242 
    243     am.setUserData(account, "key123", null);
    244     assertThat(am.getUserData(account, "key123")).isNull();
    245   }
    246 
    247   @Test
    248   public void testGetSetPassword_setInAccountInitiallyWithNoPassword() {
    249     Account account = new Account("name", "type");
    250     boolean accountAdded = am.addAccountExplicitly(account, null, null);
    251 
    252     assertThat(accountAdded).isTrue();
    253     assertThat(am.getPassword(account)).isNull();
    254 
    255     am.setPassword(account, "passwd");
    256     assertThat(am.getPassword(account)).isEqualTo("passwd");
    257   }
    258 
    259   @Test
    260   public void testGetSetPassword_overwrite() {
    261     Account account = new Account("name", "type");
    262     boolean accountAdded = am.addAccountExplicitly(account, "passwd1", null);
    263 
    264     assertThat(accountAdded).isTrue();
    265     assertThat(am.getPassword(account)).isEqualTo("passwd1");
    266 
    267     am.setPassword(account, "passwd2");
    268     assertThat(am.getPassword(account)).isEqualTo("passwd2");
    269   }
    270 
    271   @Test
    272   public void testGetSetPassword_remove() {
    273     Account account = new Account("name", "type");
    274     boolean accountAdded = am.addAccountExplicitly(account, "passwd1", null);
    275 
    276     assertThat(accountAdded).isTrue();
    277     assertThat(am.getPassword(account)).isEqualTo("passwd1");
    278 
    279     am.setPassword(account, null);
    280     assertThat(am.getPassword(account)).isNull();
    281   }
    282 
    283   @Test
    284   public void testBlockingGetAuthToken() throws AuthenticatorException, OperationCanceledException, IOException {
    285     Account account = new Account("name", "type");
    286     shadowOf(am).addAccount(account);
    287 
    288     am.setAuthToken(account, "token_type_1", "token1");
    289     am.setAuthToken(account, "token_type_2", "token2");
    290 
    291     assertThat(am.blockingGetAuthToken(account, "token_type_1", false)).isEqualTo("token1");
    292     assertThat(am.blockingGetAuthToken(account, "token_type_2", false)).isEqualTo("token2");
    293 
    294     try {
    295       am.blockingGetAuthToken(null, "token_type_1", false);
    296       fail("blockingGetAuthToken() should throw an illegal argument exception if the account is null");
    297     } catch (IllegalArgumentException iae) {
    298       // Expected
    299     }
    300     try {
    301       am.blockingGetAuthToken(account, null, false);
    302       fail("blockingGetAuthToken() should throw an illegal argument exception if the auth token type is null");
    303     } catch (IllegalArgumentException iae) {
    304       // Expected
    305     }
    306 
    307     Account account1 = new Account("unknown", "type");
    308     assertThat(am.blockingGetAuthToken(account1, "token_type_1", false)).isNull();
    309   }
    310 
    311   @Test
    312   public void removeAccount_throwsIllegalArgumentException_whenPassedNullAccount() {
    313     Account account = new Account("name", "type");
    314     shadowOf(am).addAccount(account);
    315 
    316     try {
    317       am.removeAccount(null, null, null);
    318       fail("removeAccount() should throw an illegal argument exception if the account is null");
    319     } catch (IllegalArgumentException iae) {
    320       // Expected
    321     }
    322   }
    323 
    324   @Test
    325   public void removeAccount_doesNotRemoveAccountOfDifferentName() throws Exception {
    326     Account account = new Account("name", "type");
    327     shadowOf(am).addAccount(account);
    328 
    329     Account wrongAccount = new Account("wrong_name", "type");
    330     AccountManagerFuture<Boolean> future = am.removeAccount(wrongAccount, null, null);
    331     assertThat(future.getResult()).isFalse();
    332     assertThat(am.getAccountsByType("type")).isNotEmpty();
    333   }
    334 
    335   @Test
    336   public void removeAccount_does() throws Exception {
    337     Account account = new Account("name", "type");
    338     shadowOf(am).addAccount(account);
    339 
    340     TestAccountManagerCallback<Boolean> testAccountManagerCallback = new TestAccountManagerCallback<>();
    341     AccountManagerFuture<Boolean> future = am.removeAccount(account, testAccountManagerCallback, null);
    342     assertThat(future.getResult()).isTrue();
    343     assertThat(am.getAccountsByType("type")).isEmpty();
    344 
    345     assertThat(testAccountManagerCallback.accountManagerFuture).isNotNull();
    346   }
    347 
    348   @Test
    349   public void removeAccount_notifiesListenersIfSuccessful() {
    350     Account account = new Account("name", "type");
    351     am.addAccountExplicitly(account, "passwd", null);
    352 
    353     TestOnAccountsUpdateListener listener = new TestOnAccountsUpdateListener();
    354     am.addOnAccountsUpdatedListener(listener, null, false);
    355     assertThat(listener.getInvocationCount()).isEqualTo(0);
    356 
    357     am.removeAccount(account, null, null);
    358 
    359     assertThat(listener.getInvocationCount()).isEqualTo(1);
    360   }
    361 
    362   @Test
    363   public void removeAccount_doesNotNotifyIfUnuccessful() {
    364     Account account = new Account("name", "type");
    365 
    366     TestOnAccountsUpdateListener listener = new TestOnAccountsUpdateListener();
    367     am.addOnAccountsUpdatedListener(listener, null, false);
    368     assertThat(listener.getInvocationCount()).isEqualTo(0);
    369 
    370     // The account has not been added
    371     am.removeAccount(account, null, null);
    372 
    373     assertThat(listener.getInvocationCount()).isEqualTo(0);
    374   }
    375 
    376   private static class TestOnAccountsUpdateListener implements OnAccountsUpdateListener {
    377     private int invocationCount = 0;
    378 
    379     @Override
    380     public void onAccountsUpdated(Account[] accounts) {
    381       invocationCount++;
    382     }
    383 
    384     public int getInvocationCount() {
    385       return invocationCount;
    386     }
    387   }
    388 
    389   @Test
    390   public void testAccountsUpdateListener() {
    391     TestOnAccountsUpdateListener listener = new TestOnAccountsUpdateListener();
    392     am.addOnAccountsUpdatedListener(listener, null, false);
    393     assertThat(listener.getInvocationCount()).isEqualTo(0);
    394 
    395     Account account = new Account("name", "type");
    396     shadowOf(am).addAccount(account);
    397     assertThat(listener.getInvocationCount()).isEqualTo(1);
    398   }
    399 
    400   @Test
    401   public void testAccountsUpdateListener_duplicate() {
    402     TestOnAccountsUpdateListener listener = new TestOnAccountsUpdateListener();
    403     am.addOnAccountsUpdatedListener(listener, null, false);
    404     am.addOnAccountsUpdatedListener(listener, null, false);
    405     assertThat(listener.getInvocationCount()).isEqualTo(0);
    406 
    407     Account account = new Account("name", "type");
    408     shadowOf(am).addAccount(account);
    409     assertThat(listener.getInvocationCount()).isEqualTo(1);
    410   }
    411 
    412   @Test
    413   public void testAccountsUpdateListener_updateImmediately() {
    414     TestOnAccountsUpdateListener listener = new TestOnAccountsUpdateListener();
    415     am.addOnAccountsUpdatedListener(listener, null, true);
    416     assertThat(listener.getInvocationCount()).isEqualTo(1);
    417   }
    418 
    419   @Test
    420   public void testAccountsUpdateListener_listenerNotInvokedAfterRemoval() {
    421     TestOnAccountsUpdateListener listener = new TestOnAccountsUpdateListener();
    422     am.addOnAccountsUpdatedListener(listener, null, false);
    423     assertThat(listener.getInvocationCount()).isEqualTo(0);
    424 
    425     Account account = new Account("name", "type");
    426     shadowOf(am).addAccount(account);
    427 
    428     assertThat(listener.getInvocationCount()).isEqualTo(1);
    429 
    430     am.removeOnAccountsUpdatedListener(listener);
    431 
    432     shadowOf(am).addAccount(account);
    433 
    434     assertThat(listener.getInvocationCount()).isEqualTo(1);
    435   }
    436 
    437   @Test
    438   public void testAddAuthenticator() {
    439     shadowOf(am).addAuthenticator("type");
    440     AuthenticatorDescription[] result = am.getAuthenticatorTypes();
    441     assertThat(result.length).isEqualTo(1);
    442     assertThat(result[0].type).isEqualTo("type");
    443   }
    444 
    445   @Test
    446   public void invalidateAuthToken_noAccount() {
    447     am.invalidateAuthToken("type1", "token1");
    448   }
    449 
    450   @Test
    451   public void invalidateAuthToken_noToken() {
    452     Account account1 = new Account("name", "type1");
    453     shadowOf(am).addAccount(account1);
    454     am.invalidateAuthToken("type1", "token1");
    455   }
    456 
    457   @Test
    458   public void invalidateAuthToken_multipleAccounts() {
    459     Account account1 = new Account("name", "type1");
    460     shadowOf(am).addAccount(account1);
    461 
    462     Account account2 = new Account("name", "type2");
    463     shadowOf(am).addAccount(account2);
    464 
    465     am.setAuthToken(account1, "token_type_1", "token1");
    466     am.setAuthToken(account2, "token_type_1", "token1");
    467 
    468     assertThat(am.peekAuthToken(account1, "token_type_1")).isEqualTo("token1");
    469     assertThat(am.peekAuthToken(account2, "token_type_1")).isEqualTo("token1");
    470 
    471     // invalidate token for type1 account
    472     am.invalidateAuthToken("type1", "token1");
    473     assertThat(am.peekAuthToken(account1, "token_type_1")).isNull();
    474     assertThat(am.peekAuthToken(account2, "token_type_1")).isEqualTo("token1");
    475 
    476     // invalidate token for type2 account
    477     am.invalidateAuthToken("type2", "token1");
    478     assertThat(am.peekAuthToken(account1, "token_type_1")).isNull();
    479     assertThat(am.peekAuthToken(account2, "token_type_1")).isNull();
    480   }
    481 
    482   @Test
    483   public void invalidateAuthToken_multipleTokens() {
    484     Account account = new Account("name", "type1");
    485     shadowOf(am).addAccount(account);
    486 
    487     am.setAuthToken(account, "token_type_1", "token1");
    488     am.setAuthToken(account, "token_type_2", "token2");
    489 
    490     assertThat(am.peekAuthToken(account, "token_type_1")).isEqualTo("token1");
    491     assertThat(am.peekAuthToken(account, "token_type_2")).isEqualTo("token2");
    492 
    493     // invalidate token1
    494     am.invalidateAuthToken("type1", "token1");
    495     assertThat(am.peekAuthToken(account, "token_type_1")).isNull();
    496     assertThat(am.peekAuthToken(account, "token_type_2")).isEqualTo("token2");
    497 
    498     // invalidate token2
    499     am.invalidateAuthToken("type1", "token2");
    500     assertThat(am.peekAuthToken(account, "token_type_1")).isNull();
    501     assertThat(am.peekAuthToken(account, "token_type_2")).isNull();
    502   }
    503 
    504   @Test
    505   public void invalidateAuthToken_multipleTokenTypesSameToken() {
    506     Account account = new Account("name", "type1");
    507     shadowOf(am).addAccount(account);
    508 
    509     am.setAuthToken(account, "token_type_1", "token1");
    510     am.setAuthToken(account, "token_type_2", "token1");
    511 
    512     assertThat(am.peekAuthToken(account, "token_type_1")).isEqualTo("token1");
    513     assertThat(am.peekAuthToken(account, "token_type_2")).isEqualTo("token1");
    514 
    515     // invalidate token1
    516     am.invalidateAuthToken("type1", "token1");
    517     assertThat(am.peekAuthToken(account, "token_type_1")).isNull();
    518     assertThat(am.peekAuthToken(account, "token_type_2")).isNull();
    519   }
    520 
    521   @Test
    522   public void addAccount_noActivitySpecified() throws Exception {
    523     shadowOf(am).addAuthenticator("google.com");
    524 
    525     AccountManagerFuture<Bundle> result = am.addAccount("google.com", "auth_token_type", null, null, null, null, null);
    526 
    527     Bundle resultBundle = result.getResult();
    528 
    529     assertThat((Intent) resultBundle.getParcelable(AccountManager.KEY_INTENT)).isNotNull();
    530   }
    531 
    532   @Test
    533   public void addAccount_activitySpecified() throws Exception {
    534     shadowOf(am).addAuthenticator("google.com");
    535 
    536     AccountManagerFuture<Bundle> result = am.addAccount("google.com", "auth_token_type", null, null, activity, null, null);
    537     Bundle resultBundle = result.getResult();
    538 
    539     assertThat(resultBundle.getString(AccountManager.KEY_ACCOUNT_TYPE)).isEqualTo("google.com");
    540     assertThat(resultBundle.getString(AccountManager.KEY_ACCOUNT_NAME)).isEqualTo("some_user (at) gmail.com");
    541   }
    542 
    543   @Test
    544   public void addAccount_shouldCallCallback() throws Exception {
    545     shadowOf(am).addAuthenticator("google.com");
    546 
    547     TestAccountManagerCallback<Bundle> callback = new TestAccountManagerCallback<>();
    548     AccountManagerFuture<Bundle> result = am.addAccount("google.com", "auth_token_type", null, null, activity, callback, new Handler());
    549 
    550     assertThat(callback.hasBeenCalled()).isFalse();
    551     assertThat(result.isDone()).isFalse();
    552 
    553     shadowOf(am).addAccount(new Account("thebomb (at) google.com", "google.com"));
    554     assertThat(result.isDone()).isTrue();
    555     assertThat(callback.accountManagerFuture).isNotNull();
    556 
    557     Bundle resultBundle = callback.getResult();
    558     assertThat(resultBundle.getString(AccountManager.KEY_ACCOUNT_TYPE)).isEqualTo("google.com");
    559     assertThat(resultBundle.getString(AccountManager.KEY_ACCOUNT_NAME)).isEqualTo("thebomb (at) google.com");
    560   }
    561 
    562   @Test
    563   public void addAccount_whenSchedulerPaused_shouldCallCallbackAfterSchedulerUnpaused() throws Exception {
    564     scheduler.pause();
    565     shadowOf(am).addAuthenticator("google.com");
    566 
    567     TestAccountManagerCallback<Bundle> callback = new TestAccountManagerCallback<>();
    568     am.addAccount("google.com", "auth_token_type", null, null, activity, callback, new Handler());
    569     assertThat(callback.hasBeenCalled()).isFalse();
    570 
    571     shadowOf(am).addAccount(new Account("thebomb (at) google.com", "google.com"));
    572 
    573     scheduler.unPause();
    574     assertThat(callback.hasBeenCalled()).isTrue();
    575 
    576     Bundle resultBundle = callback.getResult();
    577     assertThat(resultBundle.getString(AccountManager.KEY_ACCOUNT_TYPE)).isEqualTo("google.com");
    578     assertThat(resultBundle.getString(AccountManager.KEY_ACCOUNT_NAME)).isEqualTo("thebomb (at) google.com");
    579   }
    580 
    581   @Test
    582   public void addAccount_noAuthenticatorDefined() throws Exception {
    583     AccountManagerFuture<Bundle> future = am.addAccount("unknown_account_type", "auth_token_type", null, null, activity, null, null);
    584     try {
    585       future.getResult();
    586       fail("addAccount() should throw an authenticator exception if no authenticator was registered for this account type");
    587     } catch(AuthenticatorException e) {
    588       // Expected
    589     }
    590     assertThat(future.isDone()).isTrue();
    591   }
    592 
    593   @Test
    594   public void addAccount_withOptionsShouldSupportGetNextAddAccountOptions() throws Exception {
    595     assertThat(shadowOf(am).getNextAddAccountOptions()).isNull();
    596 
    597     shadowOf(am).addAuthenticator("google.com");
    598 
    599     Bundle expectedAddAccountOptions = new Bundle();
    600     expectedAddAccountOptions.putString("option", "value");
    601 
    602     am.addAccount("google.com", "auth_token_type", null, expectedAddAccountOptions, activity, null, null);
    603 
    604     Bundle actualAddAccountOptions = shadowOf(am).getNextAddAccountOptions();
    605     assertThat(shadowOf(am).getNextAddAccountOptions()).isNull();
    606     assertThat(actualAddAccountOptions).isEqualTo(expectedAddAccountOptions);
    607   }
    608 
    609   @Test
    610   public void addAccount_withOptionsShouldSupportPeekNextAddAccountOptions() throws Exception {
    611     assertThat(shadowOf(am).peekNextAddAccountOptions()).isNull();
    612 
    613     shadowOf(am).addAuthenticator("google.com");
    614 
    615     Bundle expectedAddAccountOptions = new Bundle();
    616     expectedAddAccountOptions.putString("option", "value");
    617     am.addAccount("google.com", "auth_token_type", null, expectedAddAccountOptions, activity, null, null);
    618 
    619     Bundle actualAddAccountOptions = shadowOf(am).peekNextAddAccountOptions();
    620     assertThat(shadowOf(am).peekNextAddAccountOptions()).isNotNull();
    621     assertThat(actualAddAccountOptions).isEqualTo(expectedAddAccountOptions);
    622   }
    623 
    624   @Test
    625   public void addAccount_withNoAuthenticatorForType_throwsExceptionInGetResult() throws Exception {
    626     assertThat(shadowOf(am).peekNextAddAccountOptions()).isNull();
    627 
    628     AccountManagerFuture<Bundle> futureResult = am.addAccount("google.com", "auth_token_type", null, null, activity, null, null);
    629     try {
    630       futureResult.getResult();
    631       fail("should have thrown");
    632     } catch (AuthenticatorException expected) { }
    633   }
    634 
    635   @Test
    636   @Config(minSdk = LOLLIPOP)
    637   public void addPreviousAccount() {
    638     Account account = new Account("name_a", "type_a");
    639     shadowOf(am).setPreviousAccountName(account, "old_name");
    640     assertThat(am.getPreviousName(account)).isEqualTo("old_name");
    641   }
    642 
    643   @Test
    644   public void testGetAsSystemService() throws Exception {
    645     AccountManager systemService =
    646         (AccountManager)
    647             ApplicationProvider.getApplicationContext().getSystemService(Context.ACCOUNT_SERVICE);
    648     assertThat(systemService).isNotNull();
    649     assertThat(am).isEqualTo(systemService);
    650   }
    651 
    652   @Test
    653   public void getAuthToken_withActivity_returnsCorrectToken() throws Exception {
    654     Account account = new Account("name", "google.com");
    655     shadowOf(am).addAccount(account);
    656     shadowOf(am).addAuthenticator("google.com");
    657 
    658     am.setAuthToken(account, "auth_token_type", "token1");
    659 
    660     TestAccountManagerCallback<Bundle> callback = new TestAccountManagerCallback<>();
    661     AccountManagerFuture<Bundle> future = am.getAuthToken(account,
    662         "auth_token_type",
    663         new Bundle(),
    664         activity,
    665         callback,
    666         new Handler());
    667 
    668     assertThat(future.isDone()).isTrue();
    669     assertThat(future.getResult().getString(AccountManager.KEY_ACCOUNT_NAME)).isEqualTo(account.name);
    670     assertThat(future.getResult().getString(AccountManager.KEY_ACCOUNT_TYPE)).isEqualTo(account.type);
    671     assertThat(future.getResult().getString(AccountManager.KEY_AUTHTOKEN)).isEqualTo("token1");
    672 
    673     assertThat(callback.hasBeenCalled()).isTrue();
    674   }
    675 
    676   @Test
    677   public void getAuthToken_withActivity_returnsAuthIntent() throws Exception {
    678     Account account = new Account("name", "google.com");
    679     shadowOf(am).addAccount(account);
    680     shadowOf(am).addAuthenticator("google.com");
    681 
    682     TestAccountManagerCallback<Bundle> callback = new TestAccountManagerCallback<>();
    683     AccountManagerFuture<Bundle> future = am.getAuthToken(account,
    684         "auth_token_type",
    685         new Bundle(),
    686         activity,
    687         callback,
    688         new Handler());
    689 
    690     assertThat(future.isDone()).isTrue();
    691     assertThat(future.getResult().getString(AccountManager.KEY_ACCOUNT_NAME))
    692         .isEqualTo(account.name);
    693     assertThat(future.getResult().getString(AccountManager.KEY_ACCOUNT_TYPE))
    694         .isEqualTo(account.type);
    695     assertThat(future.getResult().getString(AccountManager.KEY_AUTHTOKEN)).isNull();
    696     assertThat((Intent) future.getResult().getParcelable(AccountManager.KEY_INTENT)).isNotNull();
    697 
    698     assertThat(callback.hasBeenCalled()).isTrue();
    699   }
    700 
    701   @Test
    702   public void getAuthToken_withNotifyAuthFailureSetToFalse_returnsCorrectToken() throws Exception {
    703     Account account = new Account("name", "google.com");
    704     shadowOf(am).addAccount(account);
    705     shadowOf(am).addAuthenticator("google.com");
    706 
    707     am.setAuthToken(account, "auth_token_type", "token1");
    708 
    709     TestAccountManagerCallback<Bundle> callback = new TestAccountManagerCallback<>();
    710     AccountManagerFuture<Bundle> future =
    711         am.getAuthToken(
    712             account,
    713             "auth_token_type",
    714             new Bundle(),
    715             /* notifyAuthFailure= */ false,
    716             callback,
    717             new Handler());
    718 
    719     assertThat(future.isDone()).isTrue();
    720     assertThat(future.getResult().getString(AccountManager.KEY_ACCOUNT_NAME))
    721         .isEqualTo(account.name);
    722     assertThat(future.getResult().getString(AccountManager.KEY_ACCOUNT_TYPE))
    723         .isEqualTo(account.type);
    724     assertThat(future.getResult().getString(AccountManager.KEY_AUTHTOKEN)).isEqualTo("token1");
    725 
    726     assertThat(callback.hasBeenCalled()).isTrue();
    727   }
    728 
    729   @Test
    730   public void getAuthToken_withNotifyAuthFailureSetToFalse_returnsAuthIntent() throws Exception {
    731     Account account = new Account("name", "google.com");
    732     shadowOf(am).addAccount(account);
    733     shadowOf(am).addAuthenticator("google.com");
    734 
    735     TestAccountManagerCallback<Bundle> callback = new TestAccountManagerCallback<>();
    736     AccountManagerFuture<Bundle> future =
    737         am.getAuthToken(
    738             account,
    739             "auth_token_type",
    740             new Bundle(),
    741             /* notifyAuthFailure= */ false,
    742             callback,
    743             new Handler());
    744 
    745     assertThat(future.isDone()).isTrue();
    746     assertThat(future.getResult().getString(AccountManager.KEY_ACCOUNT_NAME))
    747         .isEqualTo(account.name);
    748     assertThat(future.getResult().getString(AccountManager.KEY_ACCOUNT_TYPE))
    749         .isEqualTo(account.type);
    750     assertThat(future.getResult().getString(AccountManager.KEY_AUTHTOKEN)).isNull();
    751     assertThat((Intent) future.getResult().getParcelable(AccountManager.KEY_INTENT)).isNotNull();
    752 
    753     assertThat(callback.hasBeenCalled()).isTrue();
    754   }
    755 
    756   @Test
    757   public void getHasFeatures_returnsTrueWhenAllFeaturesSatisfied() throws Exception {
    758     Account account = new Account("name", "google.com");
    759     shadowOf(am).addAccount(account);
    760     shadowOf(am).setFeatures(account, new String[] { "FEATURE_1", "FEATURE_2" });
    761 
    762     TestAccountManagerCallback<Boolean> callback = new TestAccountManagerCallback<>();
    763     AccountManagerFuture<Boolean> future = am.hasFeatures(account, new String[] { "FEATURE_1", "FEATURE_2" }, callback, new Handler());
    764 
    765     assertThat(future.isDone()).isTrue();
    766     assertThat(future.getResult().booleanValue()).isEqualTo(true);
    767 
    768     assertThat(callback.hasBeenCalled()).isTrue();
    769   }
    770 
    771   @Test
    772   public void getHasFeatures_returnsFalseWhenAllFeaturesNotSatisfied() throws Exception {
    773     Account account = new Account("name", "google.com");
    774     shadowOf(am).addAccount(account);
    775     shadowOf(am).setFeatures(account, new String[] { "FEATURE_1" });
    776 
    777     TestAccountManagerCallback<Boolean> callback = new TestAccountManagerCallback<>();
    778     AccountManagerFuture<Boolean> future = am.hasFeatures(account, new String[] { "FEATURE_1", "FEATURE_2" }, callback, new Handler());
    779 
    780     assertThat(future.isDone()).isTrue();
    781     assertThat(future.getResult().booleanValue()).isEqualTo(false);
    782     assertThat(callback.hasBeenCalled()).isTrue();
    783   }
    784 
    785   @Test
    786   public void getAccountsByTypeAndFeatures() throws Exception {
    787 
    788     Account accountWithCorrectTypeAndFeatures = new Account("account_1", "google.com");
    789     shadowOf(am).addAccount(accountWithCorrectTypeAndFeatures);
    790     shadowOf(am).setFeatures(accountWithCorrectTypeAndFeatures, new String[] { "FEATURE_1", "FEATURE_2" });
    791 
    792     Account accountWithCorrectTypeButNotFeatures = new Account("account_2", "google.com");
    793     shadowOf(am).addAccount(accountWithCorrectTypeButNotFeatures);
    794     shadowOf(am).setFeatures(accountWithCorrectTypeButNotFeatures, new String[] { "FEATURE_1" });
    795 
    796     Account accountWithCorrectFeaturesButNotType = new Account("account_3", "facebook.com");
    797     shadowOf(am).addAccount(accountWithCorrectFeaturesButNotType);
    798     shadowOf(am).setFeatures(accountWithCorrectFeaturesButNotType, new String[] { "FEATURE_1", "FEATURE_2" });
    799 
    800 
    801     TestAccountManagerCallback<Account[]> callback = new TestAccountManagerCallback<>();
    802 
    803     AccountManagerFuture<Account[]> future = am.getAccountsByTypeAndFeatures("google.com", new String[] { "FEATURE_1", "FEATURE_2" }, callback, new Handler());
    804 
    805     assertThat(future.isDone()).isTrue();
    806     assertThat(future.getResult()).asList().containsExactly(accountWithCorrectTypeAndFeatures);
    807 
    808     assertThat(callback.hasBeenCalled()).isTrue();
    809   }
    810 
    811   @Test
    812   public void getAccountsByTypeAndFeatures_returnsAllAccountsForNullFeature() throws Exception {
    813 
    814     Account accountWithCorrectTypeAndFeatures = new Account("account_1", "google.com");
    815     shadowOf(am).addAccount(accountWithCorrectTypeAndFeatures);
    816     shadowOf(am).setFeatures(
    817         accountWithCorrectTypeAndFeatures, new String[] { "FEATURE_1", "FEATURE_2" });
    818 
    819     Account accountWithCorrectTypeButNotFeatures = new Account("account_2", "google.com");
    820     shadowOf(am).addAccount(accountWithCorrectTypeButNotFeatures);
    821     shadowOf(am).setFeatures(accountWithCorrectTypeButNotFeatures, new String[] { "FEATURE_1" });
    822 
    823     Account accountWithCorrectFeaturesButNotType = new Account("account_3", "facebook.com");
    824     shadowOf(am).addAccount(accountWithCorrectFeaturesButNotType);
    825     shadowOf(am).setFeatures(
    826         accountWithCorrectFeaturesButNotType, new String[] { "FEATURE_1", "FEATURE_2" });
    827 
    828 
    829     TestAccountManagerCallback<Account[]> callback = new TestAccountManagerCallback<>();
    830 
    831     AccountManagerFuture<Account[]> future =
    832         am.getAccountsByTypeAndFeatures("google.com", null, callback, new Handler());
    833 
    834     assertThat(future.isDone()).isTrue();
    835     assertThat(future.getResult()).asList()
    836         .containsExactly(accountWithCorrectTypeAndFeatures, accountWithCorrectTypeButNotFeatures);
    837 
    838     assertThat(callback.hasBeenCalled()).isTrue();
    839   }
    840 
    841   @Test
    842   @Config(minSdk = JELLY_BEAN_MR2)
    843   public void getAccountsByTypeForPackage() {
    844     Account[] accountsByTypeForPackage = am.getAccountsByTypeForPackage(null, "org.somepackage");
    845 
    846     assertThat(accountsByTypeForPackage).isEmpty();
    847 
    848     Account accountVisibleToPackage = new Account("user (at) gmail.com", "gmail.com");
    849     shadowOf(am).addAccount(accountVisibleToPackage, "org.somepackage");
    850 
    851     accountsByTypeForPackage = am.getAccountsByTypeForPackage("other_type", "org.somepackage");
    852     assertThat(accountsByTypeForPackage).isEmpty();
    853 
    854     accountsByTypeForPackage = am.getAccountsByTypeForPackage("gmail.com", "org.somepackage");
    855     assertThat(accountsByTypeForPackage).asList().containsExactly(accountVisibleToPackage);
    856 
    857     accountsByTypeForPackage = am.getAccountsByTypeForPackage(null, "org.somepackage");
    858     assertThat(accountsByTypeForPackage).asList().containsExactly(accountVisibleToPackage);
    859   }
    860 
    861   @Test
    862   @Config(minSdk = LOLLIPOP_MR1)
    863   public void removeAccountExplicitly() {
    864     assertThat(am.removeAccountExplicitly(new Account("non_existant_account (at) gmail.com", "gmail.com"))).isFalse();
    865     assertThat(am.removeAccountExplicitly(null)).isFalse();
    866 
    867     Account account = new Account("name (at) gmail.com", "gmail.com");
    868     shadowOf(am).addAccount(account);
    869 
    870     assertThat(am.removeAccountExplicitly(account)).isTrue();
    871   }
    872 
    873   @Test
    874   public void removeAllAccounts() throws Exception {
    875 
    876     Account account = new Account("name (at) gmail.com", "gmail.com");
    877     shadowOf(am).addAccount(account);
    878 
    879     assertThat(am.getAccounts()).isNotEmpty();
    880 
    881     shadowOf(am).removeAllAccounts();
    882 
    883     assertThat(am.getAccounts()).isEmpty();
    884   }
    885 
    886   @Test
    887   public void testSetAuthenticationErrorOnNextResponse()
    888       throws AuthenticatorException, IOException, OperationCanceledException {
    889 
    890     shadowOf(am).setAuthenticationErrorOnNextResponse(true);
    891 
    892     try {
    893       am.getAccountsByTypeAndFeatures(null, null, null, null).getResult();
    894       fail("should have thrown");
    895     } catch (AuthenticatorException expected) {
    896       // Expected
    897     }
    898 
    899     am.getAccountsByTypeAndFeatures(null, null, null, null).getResult();
    900   }
    901 
    902   private static class TestAccountManagerCallback<T> implements AccountManagerCallback<T> {
    903     private AccountManagerFuture<T> accountManagerFuture;
    904 
    905     @Override
    906     public void run(AccountManagerFuture<T> accountManagerFuture) {
    907       this.accountManagerFuture = accountManagerFuture;
    908     }
    909 
    910     boolean hasBeenCalled() {
    911       return accountManagerFuture != null;
    912     }
    913 
    914     T getResult() throws Exception {
    915       return accountManagerFuture.getResult();
    916     }
    917   }
    918 }
    919