// Copyright (c) Microsoft Corporation.
// All rights reserved.
//
// This code is licensed under the MIT License.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package com.microsoft.aad.adal;

import static com.microsoft.aad.adal.AuthenticationConstants.Broker.BROKER_ACCOUNT_TYPE;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AccountManagerCallback;
import android.accounts.AccountManagerFuture;
import android.accounts.AuthenticatorDescription;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.Signature;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.util.Base64;

import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;

import com.microsoft.identity.common.adal.internal.AuthenticationConstants;
import com.microsoft.identity.common.internal.broker.BrokerValidator;
import com.microsoft.identity.common.internal.broker.PackageHelper;

import junit.framework.Assert;

import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatchers;
import org.mockito.Mockito;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Locale;
import java.util.UUID;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

@RunWith(AndroidJUnit4.class)
public class BrokerProxyTests {

    static final String TEST_AUTHORITY = "https://login.windows.net/common/";

    private static final String TAG = "BrokerProxyTests";

    public static final String TEST_AUTHORITY_ADFS = "https://fs.ade2eadfs30.com/adfs";

    private byte[] mTestSignature;

    private String mTestTag;

    @Before
    @SuppressLint("PackageManagerGetSignatures")
    public void setUp() throws Exception {
        System.setProperty(
                "dexmaker.dexcache",
                androidx.test.platform.app.InstrumentationRegistry
                        .getInstrumentation()
                        .getTargetContext()
                        .getCacheDir()
                        .getPath()
        );

        System.setProperty(
                "org.mockito.android.target",
                ApplicationProvider
                        .getApplicationContext()
                        .getCacheDir()
                        .getPath()
        );

        // ADAL is set to this signature for now
        PackageInfo info =
                androidx.test.platform.app.InstrumentationRegistry.getInstrumentation()
                        .getContext()
                        .getPackageManager()
                        .getPackageInfo(
                                androidx.test.platform.app.InstrumentationRegistry.getInstrumentation()
                                        .getContext().getPackageName(),
                                PackageHelper.getPackageManagerSignaturesFlag()
                        );

        // Broker App can be signed with multiple certificates. It will look
        // all of them
        // until it finds the correct one for ADAL broker.
        for (Signature signature : PackageHelper.getSignatures(info)) {
            mTestSignature = signature.toByteArray();
            MessageDigest md = MessageDigest.getInstance("SHA-512");
            md.update(mTestSignature);
            mTestTag = Base64.encodeToString(md.digest(), Base64.NO_WRAP);
            break;
        }

        AuthenticationSettings.INSTANCE.setBrokerSignature(mTestTag);
        AuthenticationSettings.INSTANCE
                .setBrokerPackageName(AuthenticationConstants.Broker.COMPANY_PORTAL_APP_PACKAGE_NAME);
        Logger.d(TAG, "mTestSignature is set");
    }

    @After
    public void tearDown() throws Exception {
        AuthenticationSettings.INSTANCE.setUseBroker(false);
    }

    @Test
    public void testCanSwitchToBrokerInvalidPackage() throws NameNotFoundException {
        final String brokerPackage = "wrong";
        final Signature signature = new Signature(mTestSignature);
        final FileMockContext context = new FileMockContext(androidx.test.platform.app.InstrumentationRegistry.getInstrumentation().getContext());
        context.setMockedPackageManager(getMockedPackageManagerWithBrokerAccountServiceDisabled(
                signature, brokerPackage, false));
        context.setMockedAccountManager(getMockedAccountManager(BROKER_ACCOUNT_TYPE, brokerPackage));

        AuthenticationSettings.INSTANCE.setUseBroker(true);
        final BrokerProxy brokerProxy = new BrokerProxy(context);
        assertEquals(BrokerProxy.SwitchToBroker.CANNOT_SWITCH_TO_BROKER, brokerProxy.canSwitchToBroker(TEST_AUTHORITY));
    }

    @Test
    public void testCanSwitchToBrokerInvalidAuthenticatorType() throws NameNotFoundException {
        final String authenticatorType = "invalid";
        final String brokerPackage = AuthenticationConstants.Broker.COMPANY_PORTAL_APP_PACKAGE_NAME;
        final Signature signature = new Signature(mTestSignature);

        AuthenticationSettings.INSTANCE.setUseBroker(true);
        final FileMockContext context = new FileMockContext(androidx.test.platform.app.InstrumentationRegistry.getInstrumentation().getContext());
        context.setMockedPackageManager(getMockedPackageManagerWithBrokerAccountServiceDisabled(
                signature, brokerPackage, false));
        context.setMockedAccountManager(getMockedAccountManager(authenticatorType, brokerPackage));
        final BrokerProxy brokerProxy = new BrokerProxy(context);

        // assert
        assertEquals(BrokerProxy.SwitchToBroker.CANNOT_SWITCH_TO_BROKER, brokerProxy.canSwitchToBroker(TEST_AUTHORITY));
    }

    @Test
    public void testCanSwitchToBrokerInvalidSignature() throws NameNotFoundException {
        String authenticatorType = BROKER_ACCOUNT_TYPE;
        String brokerPackage = AuthenticationConstants.Broker.COMPANY_PORTAL_APP_PACKAGE_NAME;
        Signature signature = new Signature("74657374696e67");

        AuthenticationSettings.INSTANCE.setUseBroker(true);
        final FileMockContext context = new FileMockContext(androidx.test.platform.app.InstrumentationRegistry.getInstrumentation().getContext());
        context.setMockedPackageManager(getMockedPackageManagerWithBrokerAccountServiceDisabled(
                signature, brokerPackage, false));
        context.setMockedAccountManager(getMockedAccountManager(authenticatorType, brokerPackage));

        final BrokerProxy brokerProxy = new BrokerProxy(context);
        assertEquals(BrokerProxy.SwitchToBroker.CANNOT_SWITCH_TO_BROKER, brokerProxy.canSwitchToBroker(TEST_AUTHORITY));
    }

    @Test
    public void testCannotSwitchToBrokerWhenADFS()
            throws ClassNotFoundException, NoSuchMethodException, InstantiationException,
            IllegalAccessException, InvocationTargetException, NoSuchFieldException, NameNotFoundException {
        String authenticatorType = BROKER_ACCOUNT_TYPE;
        String brokerPackage = AuthenticationConstants.Broker.COMPANY_PORTAL_APP_PACKAGE_NAME;
        Signature signature = new Signature(mTestSignature);

        final AccountManager mockedAccountManager = getMockedAccountManager(authenticatorType, brokerPackage);
        final PackageManager mockedPackageManager = getMockedPackageManagerWithBrokerAccountServiceDisabled(signature, brokerPackage, true);
        when(mockedPackageManager.queryIntentActivities(any(Intent.class), anyInt())).thenReturn(Collections.<ResolveInfo>emptyList());

        final Account[] accts = getAccountList("valid", authenticatorType);
        when(mockedAccountManager.getAccountsByType(anyString())).thenReturn(accts);

        final FileMockContext context = new FileMockContext(androidx.test.platform.app.InstrumentationRegistry.getInstrumentation().getContext());
        context.setMockedAccountManager(mockedAccountManager);
        context.setMockedPackageManager(mockedPackageManager);

        AuthenticationSettings.INSTANCE.setUseBroker(true);
        final BrokerProxy brokerProxy = new BrokerProxy(context);
        assertEquals(BrokerProxy.SwitchToBroker.CANNOT_SWITCH_TO_BROKER, brokerProxy.canSwitchToBroker(TEST_AUTHORITY_ADFS));
    }

    @Test
    @Ignore
    public void testCanSwitchToBrokerNoAccountChooserActivity() throws NameNotFoundException {
        String authenticatorType = BROKER_ACCOUNT_TYPE;
        String brokerPackage = AuthenticationConstants.Broker.COMPANY_PORTAL_APP_PACKAGE_NAME;
        Signature signature = new Signature(mTestSignature);

        final AccountManager mockedAccountManager = getMockedAccountManager(authenticatorType, brokerPackage);
        final PackageManager mockedPackageManager = getMockedPackageManagerWithBrokerAccountServiceDisabled(signature, brokerPackage, true);
        when(mockedPackageManager.queryIntentActivities(any(Intent.class), anyInt())).thenReturn(Collections.<ResolveInfo>emptyList());

        final Account[] accts = getAccountList("valid", authenticatorType);
        when(mockedAccountManager.getAccountsByType(anyString())).thenReturn(accts);

        final FileMockContext context = new FileMockContext(androidx.test.platform.app.InstrumentationRegistry.getInstrumentation().getContext());
        context.setMockedAccountManager(mockedAccountManager);
        context.setMockedPackageManager(mockedPackageManager);

        AuthenticationSettings.INSTANCE.setUseBroker(true);
        final BrokerProxy brokerProxy = new BrokerProxy(context);
        assertEquals(BrokerProxy.SwitchToBroker.CAN_SWITCH_TO_BROKER, brokerProxy.canSwitchToBroker(TEST_AUTHORITY));
    }

    @Test
    @Ignore
    public void testCanSwitchToBrokerWithAccountChooser() throws NameNotFoundException {
        String authenticatorType = BROKER_ACCOUNT_TYPE;
        String brokerPackage = AuthenticationConstants.Broker.COMPANY_PORTAL_APP_PACKAGE_NAME;
        Signature signature = new Signature(mTestSignature);

        final AccountManager mockedAccountManager = getMockedAccountManager(authenticatorType, brokerPackage);
        final PackageManager mockedPackageManager = getMockedPackageManagerWithBrokerAccountServiceDisabled(signature, brokerPackage, true);
        mockIntentActivityQuery(mockedPackageManager);

        final FileMockContext context = new FileMockContext(androidx.test.platform.app.InstrumentationRegistry.getInstrumentation().getContext());
        context.setMockedAccountManager(mockedAccountManager);
        context.setMockedPackageManager(mockedPackageManager);

        AuthenticationSettings.INSTANCE.setUseBroker(true);
        final BrokerProxy brokerProxy = new BrokerProxy(context);
        assertEquals(BrokerProxy.SwitchToBroker.CAN_SWITCH_TO_BROKER, brokerProxy.canSwitchToBroker(TEST_AUTHORITY));
    }

    @Test
    public void testCanSwitchToBrokerValidSkip()
            throws ClassNotFoundException, NoSuchMethodException, InstantiationException,
            IllegalAccessException, InvocationTargetException, NoSuchFieldException, NameNotFoundException {
        String authenticatorType = BROKER_ACCOUNT_TYPE;
        String brokerPackage = AuthenticationConstants.Broker.COMPANY_PORTAL_APP_PACKAGE_NAME;
        Signature signature = new Signature(mTestSignature);

        final AccountManager mockedAccountManager = getMockedAccountManager(authenticatorType, brokerPackage);
        final PackageManager mockedPackageManager = getMockedPackageManagerWithBrokerAccountServiceDisabled(signature, brokerPackage, true);
        when(mockedPackageManager.queryIntentActivities(any(Intent.class), anyInt())).thenReturn(null);

        final Account[] accts = getAccountList("valid", authenticatorType);
        when(mockedAccountManager.getAccountsByType(anyString())).thenReturn(accts);

        final FileMockContext context = new FileMockContext(androidx.test.platform.app.InstrumentationRegistry.getInstrumentation().getContext());
        context.setMockedAccountManager(mockedAccountManager);
        context.setMockedPackageManager(mockedPackageManager);

        final BrokerProxy brokerProxy = new BrokerProxy(context);
        AuthenticationSettings.INSTANCE.setUseBroker(false);

        assertEquals(BrokerProxy.SwitchToBroker.CANNOT_SWITCH_TO_BROKER, brokerProxy.canSwitchToBroker(TEST_AUTHORITY));
    }

    @Test
    public void testGetCurrentUser() throws NameNotFoundException {
        final String authenticatorType = BROKER_ACCOUNT_TYPE;
        final String brokerPackage = AuthenticationConstants.Broker.COMPANY_PORTAL_APP_PACKAGE_NAME;
        AuthenticationSettings.INSTANCE.setBrokerSignature(mTestTag);

        Account[] accts = getAccountList("currentUserName", authenticatorType);
        final AccountManager mockedAccountManager = getMockedAccountManager(authenticatorType, brokerPackage);
        when(mockedAccountManager.getAccountsByType(anyString())).thenReturn(accts);

        final FileMockContext context = new FileMockContext(androidx.test.platform.app.InstrumentationRegistry.getInstrumentation().getContext());
        context.setMockedAccountManager(mockedAccountManager);
        context.setMockedPackageManager(getMockedPackageManagerWithBrokerAccountServiceDisabled(mock(Signature.class),
                AuthenticationConstants.Broker.COMPANY_PORTAL_APP_PACKAGE_NAME, true));

        // action
        final BrokerProxy brokerProxy = new BrokerProxy(context);
        final String result = brokerProxy.getCurrentUser();

        // assert
        assertEquals("Username is not equal", "currentUserName", result);
    }

    @Test
    public void testGetBrokerUsers() throws NameNotFoundException, OperationCanceledException, AuthenticatorException,
            IOException {
        final String authenticatorType = BROKER_ACCOUNT_TYPE;
        final String brokerPackage = AuthenticationConstants.Broker.COMPANY_PORTAL_APP_PACKAGE_NAME;
        final Signature signature = new Signature(mTestSignature);
        AuthenticationSettings.INSTANCE.setBrokerSignature(mTestTag);

        final AccountManager mockedAccountManager = getMockedAccountManager(authenticatorType, brokerPackage);
        Account[] accounts = getAccountList("currentUserName", authenticatorType);
        when(mockedAccountManager.getAccountsByType(anyString())).thenReturn(accounts);

        final AccountManagerFuture<Bundle> mockResult = mock(AccountManagerFuture.class);
        final Bundle testBundle = new Bundle();
        testBundle.putString(AuthenticationConstants.Broker.ACCOUNT_USERINFO_USERID, "userid");
        testBundle.putString(AuthenticationConstants.Broker.ACCOUNT_USERINFO_GIVEN_NAME, "given_name");
        testBundle.putString(AuthenticationConstants.Broker.ACCOUNT_USERINFO_FAMILY_NAME, "family_name");
        testBundle.putString(AuthenticationConstants.Broker.ACCOUNT_USERINFO_IDENTITY_PROVIDER, "idp");
        testBundle.putString(AuthenticationConstants.Broker.ACCOUNT_USERINFO_USERID_DISPLAYABLE, "displayableid_upn");
        when(mockResult.getResult()).thenReturn(testBundle);

        final Bundle bundle = new Bundle();
        bundle.putBoolean("com.microsoft.workaccount.user.info", true);
        when(mockedAccountManager.updateCredentials(eq(accounts[0]), eq(AuthenticationConstants.Broker.AUTHTOKEN_TYPE),
                any(Bundle.class), (Activity) eq(null), (AccountManagerCallback) eq(null), (Handler) eq(null)))
                .thenReturn(mockResult);

        final FileMockContext context = new FileMockContext(androidx.test.platform.app.InstrumentationRegistry.getInstrumentation().getContext());
        context.setMockedAccountManager(mockedAccountManager);
        context.setMockedPackageManager(getMockedPackageManagerWithBrokerAccountServiceDisabled(mock(Signature.class),
                AuthenticationConstants.Broker.COMPANY_PORTAL_APP_PACKAGE_NAME, true));

        // action
        final BrokerProxy brokerProxy = new BrokerProxy(context);
        final UserInfo[] result = brokerProxy.getBrokerUsers();

        // assert
        assertNotNull("It returns one user", result);
        assertEquals("displayableid_upn", result[0].getDisplayableId());
    }

    @Test
    @Ignore
    public void testCanSwitchToBrokerMissingBrokerPermission()
            throws ClassNotFoundException, NoSuchMethodException, InstantiationException,
            IllegalAccessException, InvocationTargetException, NoSuchFieldException, NameNotFoundException {

        final String authenticatorType = BROKER_ACCOUNT_TYPE;
        final String brokerPackage = AuthenticationConstants.Broker.COMPANY_PORTAL_APP_PACKAGE_NAME;
        final Signature signature = new Signature(mTestSignature);

        final FileMockContext context = new FileMockContext(androidx.test.platform.app.InstrumentationRegistry.getInstrumentation().getContext());
        final PackageManager mockedPackageManager = getMockedPackageManagerWithBrokerAccountServiceDisabled(
                signature, brokerPackage, false);
        mockIntentActivityQuery(mockedPackageManager);
        context.setMockedPackageManager(mockedPackageManager);

        context.setMockedAccountManager(getMockedAccountManager(authenticatorType, brokerPackage));

        AuthenticationSettings.INSTANCE.setUseBroker(true);
        final BrokerProxy brokerProxy = new BrokerProxy(context);

        // assert
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            assertEquals(BrokerProxy.SwitchToBroker.NEED_PERMISSIONS_TO_SWITCH_TO_BROKER, brokerProxy.canSwitchToBroker(TEST_AUTHORITY));
        }
    }

    @Test
    public void testCanSwitchToBrokerValidBrokerAuthenticatorInternalCall()
            throws ClassNotFoundException, NoSuchMethodException, InstantiationException,
            IllegalAccessException, InvocationTargetException, NoSuchFieldException, NameNotFoundException {

        Object brokerProxy = ReflectionUtils.getInstance("com.microsoft.aad.adal.BrokerProxy");
        String authenticatorType = BROKER_ACCOUNT_TYPE;
        String brokerPackage = AuthenticationConstants.Broker.COMPANY_PORTAL_APP_PACKAGE_NAME;
        Signature signature = new Signature(mTestSignature);
        AccountManager mockAcctManager = mock(AccountManager.class);
        AuthenticatorDescription[] descriptions = getAuthenticator(authenticatorType, brokerPackage);
        Context mockContext = getMockContext(signature, brokerPackage, brokerPackage, true);
        when(mockAcctManager.getAuthenticatorTypes()).thenReturn(descriptions);
        when(mockAcctManager.getAccountsByType(ArgumentMatchers.refEq(authenticatorType))).thenReturn(new Account[]{});
        when(mockContext.getPackageName()).thenReturn(brokerPackage);
        BrokerValidator mockBrokerValidator = mock(BrokerValidator.class);
        when(mockBrokerValidator.verifySignature(brokerPackage)).thenReturn(true);
        ReflectionUtils.setFieldValue(brokerProxy, "mContext", mockContext);
        ReflectionUtils.setFieldValue(brokerProxy, "mAcctManager", mockAcctManager);
        ReflectionUtils.setFieldValue(brokerProxy, "mBrokerValidator", mockBrokerValidator);
        AuthenticationSettings.INSTANCE.setBrokerPackageName(brokerPackage);
        AuthenticationSettings.INSTANCE.setBrokerSignature(mTestTag);

        // action
        Method m = ReflectionUtils.getTestMethod(brokerProxy, "canSwitchToBroker", String.class);
        BrokerProxy.SwitchToBroker result = (BrokerProxy.SwitchToBroker) m.invoke(brokerProxy, TEST_AUTHORITY);

        // assert
        assertEquals(BrokerProxy.SwitchToBroker.CANNOT_SWITCH_TO_BROKER, result);
    }

    @Test
    public void testGetAuthTokenInBackgroundEmptyAccts() throws NameNotFoundException {
        final AuthenticationRequest request = createAuthenticationRequest("https://login.windows.net/omercantest", "resource", "client",
                "redirect", "loginhint", PromptBehavior.Auto, "", UUID.randomUUID(), false);

        final FileMockContext context = new FileMockContext(androidx.test.platform.app.InstrumentationRegistry.getInstrumentation().getContext());
        final AccountManager mockedAccountManager = getMockedAccountManager(BROKER_ACCOUNT_TYPE,
                AuthenticationConstants.Broker.COMPANY_PORTAL_APP_PACKAGE_NAME);
        when(mockedAccountManager.getAccountsByType(anyString())).thenReturn(new Account[0]);
        context.setMockedAccountManager(mockedAccountManager);
        context.setMockedPackageManager(getMockedPackageManagerWithBrokerAccountServiceDisabled(mock(Signature.class),
                AuthenticationConstants.Broker.COMPANY_PORTAL_APP_PACKAGE_NAME, true));

        // action
        final BrokerProxy brokerProxy = new BrokerProxy(context);
        try {
            brokerProxy.getAuthTokenInBackground(request, null);
        } catch (Exception ex) {
            assertTrue("Exception type check", ex.getCause() instanceof AuthenticationException);
            assertEquals("Check error code", ADALError.BROKER_AUTHENTICATOR_BAD_ARGUMENTS,
                    ((AuthenticationException) ex.getCause()).getCode());
        }
    }

    @SuppressWarnings("unchecked")
    @Test
    public void testGetAuthTokenInBackgroundValidAccountEmptyBundle() throws NameNotFoundException, OperationCanceledException,
            AuthenticatorException, IOException, AuthenticationException {

        final String authenticatorType = BROKER_ACCOUNT_TYPE;
        final AuthenticationRequest authRequest = createAuthenticationRequest("https://login.windows.net/omercantest", "resource", "client",
                "redirect", "loginhint", PromptBehavior.Auto, "", UUID.randomUUID(), false);
        final String acctType = "loginhint";


        final FileMockContext context = new FileMockContext(androidx.test.platform.app.InstrumentationRegistry.getInstrumentation().getContext());
        final AccountManager mockedAccountManager = getMockedAccountManager(authenticatorType,
                AuthenticationConstants.Broker.COMPANY_PORTAL_APP_PACKAGE_NAME);

        final Account[] accts = getAccountList(acctType, authenticatorType);
        when(mockedAccountManager.getAccountsByType(anyString())).thenReturn(accts);

        final Bundle expected = new Bundle();
        AccountManagerFuture<Bundle> mockFuture = mock(AccountManagerFuture.class);
        when(mockFuture.getResult()).thenReturn(expected);
        when(mockedAccountManager.getAccountsByType(anyString())).thenReturn(accts);
        when(mockedAccountManager.getAuthToken(any(Account.class), anyString(), any(Bundle.class), eq(false),
                (AccountManagerCallback<Bundle>) eq(null), any(Handler.class))).thenReturn(mockFuture);

        context.setMockedAccountManager(mockedAccountManager);
        context.setMockedPackageManager(getMockedPackageManagerWithBrokerAccountServiceDisabled(mock(Signature.class),
                AuthenticationConstants.Broker.COMPANY_PORTAL_APP_PACKAGE_NAME, true));

        updateContextToSaveAccount("", "test");
        final BrokerProxy brokerProxy = new BrokerProxy(context);
        final AuthenticationResult result = brokerProxy.getAuthTokenInBackground(authRequest, null);

        // assert
        assertNull("token should return null", result.getAccessToken());
    }

    @SuppressWarnings("unchecked")
    @Test
    public void testGetAuthTokenInBackgroundPositive() throws NameNotFoundException, OperationCanceledException,
            AuthenticatorException, IOException, AuthenticationException {
        final String authenticatorType = BROKER_ACCOUNT_TYPE;
        final String acctName = "LoginHint234FDFs";
        final AuthenticationRequest authRequest = createAuthenticationRequest("https://login.windows.net/omercantest", "resource", "client",
                "redirect", acctName.toLowerCase(), PromptBehavior.Auto, "", UUID.randomUUID(), false);

        final FileMockContext context = new FileMockContext(androidx.test.platform.app.InstrumentationRegistry.getInstrumentation().getContext());
        final AccountManager mockedAccountManager = getMockedAccountManager(authenticatorType,
                AuthenticationConstants.Broker.COMPANY_PORTAL_APP_PACKAGE_NAME);

        final Account[] accts = getAccountList(acctName, authenticatorType);
        when(mockedAccountManager.getAccountsByType(anyString())).thenReturn(accts);

        final Bundle expected = new Bundle();
        expected.putString(AccountManager.KEY_AUTHTOKEN, "token123");
        AccountManagerFuture<Bundle> mockFuture = mock(AccountManagerFuture.class);
        when(mockFuture.getResult()).thenReturn(expected);
        when(mockedAccountManager.getAuthToken(any(Account.class), anyString(), any(Bundle.class), eq(false),
                (AccountManagerCallback<Bundle>) eq(null), any(Handler.class))).thenReturn(mockFuture);

        context.setMockedAccountManager(mockedAccountManager);
        context.setMockedPackageManager(getMockedPackageManagerWithBrokerAccountServiceDisabled(mock(Signature.class),
                AuthenticationConstants.Broker.COMPANY_PORTAL_APP_PACKAGE_NAME, true));

        // assert
        final BrokerProxy brokerProxy = new BrokerProxy(context);
        final AuthenticationResult result = brokerProxy.getAuthTokenInBackground(authRequest, null);
        assertEquals("token is expected", "token123", result.getAccessToken());
    }

    @SuppressWarnings("unchecked")
    @Test
    public void testGetAuthTokenInBackgroundVerifyUserInfo() throws NameNotFoundException,
            OperationCanceledException, IOException, AuthenticationException, AuthenticatorException {

        final String authenticatorType = BROKER_ACCOUNT_TYPE;
        final String acctName = "testAcct123";
        final AuthenticationRequest authRequest = createAuthenticationRequest("https://login.windows.net/omercantest", "resource", "client",
                "redirect", acctName.toLowerCase(Locale.US), PromptBehavior.Auto, "", UUID.randomUUID(), false);

        // check case sensitivity for account name
        final AccountManager mockedAccountManager = getMockedAccountManager(authenticatorType,
                AuthenticationConstants.Broker.COMPANY_PORTAL_APP_PACKAGE_NAME);
        final Account[] accounts = getAccountList(acctName, authenticatorType);
        when(mockedAccountManager.getAccountsByType(anyString())).thenReturn(accounts);

        final Bundle expected = new Bundle();
        expected.putString(AccountManager.KEY_AUTHTOKEN, "token123");
        expected.putString(AuthenticationConstants.Broker.ACCOUNT_USERINFO_USERID, acctName);
        expected.putString(AuthenticationConstants.Broker.ACCOUNT_USERINFO_GIVEN_NAME, "givenName");
        expected.putString(AuthenticationConstants.Broker.ACCOUNT_USERINFO_FAMILY_NAME, "familyName");
        expected.putString(AuthenticationConstants.Broker.ACCOUNT_USERINFO_IDENTITY_PROVIDER, "idp");
        expected.putString(AuthenticationConstants.Broker.ACCOUNT_USERINFO_USERID_DISPLAYABLE, acctName);
        final AccountManagerFuture<Bundle> mockFuture = mock(AccountManagerFuture.class);
        when(mockFuture.getResult()).thenReturn(expected);
        when(mockedAccountManager.getAuthToken(any(Account.class), anyString(), any(Bundle.class), eq(false),
                (AccountManagerCallback<Bundle>) eq(null), any(Handler.class))).thenReturn(mockFuture);

        final FileMockContext context = new FileMockContext(androidx.test.platform.app.InstrumentationRegistry.getInstrumentation().getContext());
        context.setMockedAccountManager(mockedAccountManager);
        context.setMockedPackageManager(getMockedPackageManagerWithBrokerAccountServiceDisabled(mock(Signature.class),
                AuthenticationConstants.Broker.COMPANY_PORTAL_APP_PACKAGE_NAME, true));
        updateContextToSaveAccount("", acctName);

        final BrokerProxy brokerProxy = new BrokerProxy(context);
        final AuthenticationResult result = brokerProxy.getAuthTokenInBackground(authRequest, null);

        // assert
        assertNotNull("userinfo is expected", result.getUserInfo());
        assertEquals("userid in userinfo is expected", acctName, result.getUserInfo().getUserId());
        assertEquals("givenName in userinfo is expected", "givenName", result.getUserInfo().getGivenName());
        assertEquals("familyName in userinfo is expected", "familyName", result.getUserInfo().getFamilyName());
        assertEquals("idp in userinfo is expected", "idp", result.getUserInfo().getIdentityProvider());
        assertEquals("displayable in userinfo is expected", acctName, result.getUserInfo().getDisplayableId());
    }

    @Test
    public void testGetAuthTokenInBackgroundVerifyAuthenticationResult()
            throws NameNotFoundException, OperationCanceledException,
            IOException, NoSuchFieldException, AuthenticatorException, AuthenticationException {
        final int tokenExpiresDate = 1000;

        final String authenticatorType = BROKER_ACCOUNT_TYPE;
        final String acctName = "testAcct123";
        final AuthenticationRequest authRequest = createAuthenticationRequest("https://login.windows.net/authtest", "resource", "client",
                "redirect", acctName.toLowerCase(Locale.US), PromptBehavior.Auto, "", UUID.randomUUID(), false);

        final AccountManager mockedAccountManager = getMockedAccountManager(authenticatorType,
                AuthenticationConstants.Broker.COMPANY_PORTAL_APP_PACKAGE_NAME);
        final Account[] accts = getAccountList(acctName, authenticatorType);
        when(mockedAccountManager.getAccountsByType(anyString())).thenReturn(accts);

        final Bundle expected = new Bundle();
        expected.putString(AccountManager.KEY_AUTHTOKEN, "token123");
        expected.putString(AuthenticationConstants.Broker.ACCOUNT_USERINFO_TENANTID, "testTenant");
        expected.putLong(AuthenticationConstants.Broker.ACCOUNT_EXPIREDATE, tokenExpiresDate);
        expected.putString(AuthenticationConstants.Broker.ACCOUNT_USERINFO_USERID, acctName);
        expected.putString(AuthenticationConstants.Broker.ACCOUNT_USERINFO_GIVEN_NAME, "givenName");
        expected.putString(AuthenticationConstants.Broker.ACCOUNT_USERINFO_FAMILY_NAME, "familyName");
        expected.putString(AuthenticationConstants.Broker.ACCOUNT_USERINFO_IDENTITY_PROVIDER, "idp");
        expected.putString(AuthenticationConstants.Broker.ACCOUNT_USERINFO_USERID_DISPLAYABLE, acctName);

        final AccountManagerFuture<Bundle> mockFuture = mock(AccountManagerFuture.class);
        when(mockFuture.getResult()).thenReturn(expected);
