package org.robolectric.shadows;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.app.Activity;
import android.app.Application;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
import org.robolectric.TestRunners;

import java.io.IOException;

import static org.fest.assertions.api.Assertions.assertThat;
import static org.fest.assertions.api.Assertions.fail;
import static org.junit.Assert.assertSame;

@RunWith(TestRunners.WithDefaults.class)
public class AccountManagerTest {
  Application app;

  @Before
  public void setUp() throws Exception {
    app = Robolectric.application;
  }

  @Test
  public void testGet() {
    AccountManager appAM = AccountManager.get(app);
    assertThat(appAM).isNotNull();
    assertSame(AccountManager.get(app), appAM);

    Activity a = new Activity();
    assertThat(AccountManager.get(a)).isNotNull();
    assertThat(AccountManager.get(a)).isNotSameAs(appAM);
  }

  @Test
  public void testGetAccounts() {
    AccountManager am = AccountManager.get(app);
    assertThat(am.getAccounts()).isNotNull();
    assertThat(am.getAccounts().length).isEqualTo(0);

    Account a1 = new Account("name_a", "type_a");
    Robolectric.shadowOf(am).addAccount(a1);
    assertThat(am.getAccounts()).isNotNull();
    assertThat(am.getAccounts().length).isEqualTo(1);
    assertThat(am.getAccounts()[0]).isSameAs(a1);

    Account a2 = new Account("name_b", "type_b");
    Robolectric.shadowOf(am).addAccount(a2);
    assertThat(am.getAccounts()).isNotNull();
    assertThat(am.getAccounts().length).isEqualTo(2);
    assertThat(am.getAccounts()[1]).isSameAs(a2);
  }

  @Test
  public void testGetAccountsByType() {
    AccountManager am = AccountManager.get(app);
    assertThat(am.getAccountsByType("name_a")).isNotNull();
    assertThat(am.getAccounts().length).isEqualTo(0);

    Account a1 = new Account("name_a", "type_a");
    Robolectric.shadowOf(am).addAccount(a1);
    Account[] accounts = am.getAccountsByType("type_a");
    assertThat(accounts).isNotNull();
    assertThat(accounts.length).isEqualTo(1);
    assertThat(accounts[0]).isSameAs(a1);

    Account a2 = new Account("name_b", "type_b");
    Robolectric.shadowOf(am).addAccount(a2);
    accounts = am.getAccountsByType("type_a");
    assertThat(accounts).isNotNull();
    assertThat(accounts.length).isEqualTo(1);
    assertThat(accounts[0]).isSameAs(a1);

    Account a3 = new Account("name_c", "type_a");
    Robolectric.shadowOf(am).addAccount(a3);
    accounts = am.getAccountsByType("type_a");
    assertThat(accounts).isNotNull();
    assertThat(accounts.length).isEqualTo(2);
    assertThat(accounts[0]).isSameAs(a1);
    assertThat(accounts[1]).isSameAs(a3);
  }

  @Test
  public void addAuthToken() {
    AccountManager am = AccountManager.get(app);
    Account account = new Account("name", "type");
    Robolectric.shadowOf(am).addAccount(account);

    am.setAuthToken(account, "token_type_1", "token1");
    am.setAuthToken(account, "token_type_2", "token2");

    assertThat(am.peekAuthToken(account, "token_type_1")).isEqualTo("token1");
    assertThat(am.peekAuthToken(account, "token_type_2")).isEqualTo("token2");
  }

  @Test
  public void setAuthToken_shouldNotAddTokenIfAccountNotPresent() {
    AccountManager am = AccountManager.get(app);
    Account account = new Account("name", "type");
    am.setAuthToken(account, "token_type_1", "token1");

    assertThat(am.peekAuthToken(account, "token_type_1")).isNull();
  }

  @Test
  public void testAddAccountExplicitly() {
    AccountManager am = AccountManager.get(app);
    Account account = new Account("name", "type");
    am.addAccountExplicitly(account, null, null);

    assertThat(am.getAccountsByType("type").length).isEqualTo(1);
    assertThat(am.getAccountsByType("type")[0].name).isEqualTo("name");

    boolean accountAddedTwice = am.addAccountExplicitly(account, null, null);
    assertThat(accountAddedTwice).isFalse();

//    boolean nullAccountAdded = am.addAccountExplicitly(null, null, null);
//    assertThat(nullAccountAdded).isFalse();

    try {
      am.addAccountExplicitly(null, null, null);
      fail("An illegal argument exception should have been thrown when trying to add a null account");
    } catch (IllegalArgumentException iae) {
      // NOP
    }
  }

  @Test
  public void testBlockingGetAuthToken() throws AuthenticatorException, OperationCanceledException, IOException {
    AccountManager am = AccountManager.get(app);
    Account account = new Account("name", "type");
    Robolectric.shadowOf(am).addAccount(account);

    am.setAuthToken(account, "token_type_1", "token1");
    am.setAuthToken(account, "token_type_2", "token2");

    assertThat(am.blockingGetAuthToken(account, "token_type_1", false)).isEqualTo("token1");
    assertThat(am.blockingGetAuthToken(account, "token_type_2", false)).isEqualTo("token2");

    try {
      am.blockingGetAuthToken(null, "token_type_1", false);
      fail("blockingGetAuthToken() should throw an illegal argument exception if the account is null");
    } catch (IllegalArgumentException iae) {
      // NOP
    }
    try {
      am.blockingGetAuthToken(account, null, false);
      fail("blockingGetAuthToken() should throw an illegal argument exception if the auth token type is null");
    } catch (IllegalArgumentException iae) {
      // NOP
    }

    Account account1 = new Account("unknown", "type");
    assertThat(am.blockingGetAuthToken(account1, "token_type_1", false)).isNull();
  }
}

@@ -4111,40 +4111,62 @@
 );%0A%0A
-//
     
-boolean nullAccountAdded =
+account = new Account(%22another_name%22, %22type%22);%0A   
  am.
@@ -4178,36 +4178,39 @@
 countExplicitly(
-null
+account
 , null, null);%0A/
@@ -4208,18 +4208,16 @@
  null);%0A
-//
     asse
@@ -4227,34 +4227,208 @@
 hat(
-nullAccountAdded).isFalse(
+am.getAccountsByType(%22type%22).length).isEqualTo(2);%0A    assertThat(am.getAccountsByType(%22type%22)%5B0%5D.name).isEqualTo(%22name%22);%0A    assertThat(am.getAccountsByType(%22type%22)%5B1%5D.name).isEqualTo(%22another_name%22
 );%0A%0A

Add one more test to check that two different accounts of the same type are added correctly