/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook

import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import androidx.test.core.app.ApplicationProvider
import com.facebook.internal.Utility
import java.util.Date
import org.assertj.core.api.Assertions.assertThat
import org.json.JSONObject
import org.junit.Assert
import org.junit.Before
import org.junit.Test
import org.mockito.Matchers
import org.mockito.kotlin.any
import org.mockito.kotlin.whenever
import org.powermock.api.mockito.PowerMockito
import org.powermock.api.support.membermodification.MemberModifier
import org.powermock.core.classloader.annotations.PrepareForTest

@PrepareForTest(Utility::class, FacebookSdk::class, LocalBroadcastManager::class)
class AccessTokenTest : FacebookPowerMockTestCase() {

  private val mockTokenString = "A token of my esteem"
  private val mockAppID = "1234"
  private val mockUserID = "1000"

  @Before
  fun before() {
    MemberModifier.stub<Any>(
            PowerMockito.method(Utility::class.java, "awaitGetGraphMeRequestWithCache"))
        .toReturn(JSONObject().put("id", mockUserID))

    PowerMockito.mockStatic(FacebookSdk::class.java)
    whenever(FacebookSdk.isInitialized()).thenReturn(true)
    whenever(FacebookSdk.getApplicationId()).thenReturn(mockAppID)
    whenever(FacebookSdk.getApplicationContext())
        .thenReturn(ApplicationProvider.getApplicationContext())
    PowerMockito.mockStatic(LocalBroadcastManager::class.java)
    val mockLocalBroadcastManager = PowerMockito.mock(LocalBroadcastManager::class.java)
    whenever(LocalBroadcastManager.getInstance(Matchers.isA(Context::class.java)))
        .thenReturn(mockLocalBroadcastManager)
  }

  @Test
  fun `test empty token throws`() {
    try {
      val token =
          AccessToken(
              "",
              "1234",
              "1000",
              arrayListOf("something"),
              arrayListOf("something_else"),
              arrayListOf("something_else_e"),
              AccessTokenSource.CLIENT_TOKEN,
              Date(),
              Date(),
              Date())
      Assert.fail()
    } catch (e: IllegalArgumentException) {}
  }

  @Test
  fun `test empty userId throws`() {
    try {
      val token =
          AccessToken(
              "a token",
              "1234",
              "",
              arrayListOf("something"),
              arrayListOf("something_else"),
              arrayListOf("something_else_e"),
              AccessTokenSource.CLIENT_TOKEN,
              Date(),
              Date(),
              Date())
      Assert.fail()
    } catch (e: IllegalArgumentException) {}
  }

  @Test
  fun `test empty application Id throws`() {
    try {
      val token =
          AccessToken(
              "a token",
              "",
              "0000",
              arrayListOf("something"),
              arrayListOf("something_else"),
              arrayListOf("something_else_e"),
              AccessTokenSource.CLIENT_TOKEN,
              Date(),
              Date(),
              Date())
      Assert.fail()
    } catch (e: IllegalArgumentException) {}
  }

  @Test
  fun `test create from refresh failure`() {
    val accessToken =
        AccessToken(
            "a token",
            "1234",
            "1000",
            arrayListOf("stream_publish"),
            null,
            null,
            AccessTokenSource.WEB_VIEW,
            null,
            null,
            null)
    val token = "AnImaginaryTokenValue"
    val bundle = Bundle()
    bundle.putString("access_token", "AnImaginaryTokenValue")
    bundle.putString("expires_in", "60")
    try {
      AccessToken.createFromRefresh(accessToken, bundle)
      Assert.fail("Expected exception")
    } catch (ex: FacebookException) {
      Assert.assertEquals("Invalid token source: " + AccessTokenSource.WEB_VIEW, ex.message)
    }
  }

  @Test
  fun `test cache roundtrip`() {
    val permissions: Set<String> = hashSetOf("stream_publish", "go_outside_and_play")
    val declinedPermissions: Set<String> = hashSetOf("no you may not", "no soup for you")
    val expiredPermissions: Set<String> = hashSetOf("expired", "oh no")
    val token = "AnImaginaryTokenValue"
    val later = FacebookTestUtility.nowPlusSeconds(60)
    val earlier = FacebookTestUtility.nowPlusSeconds(-60)
    val applicationId = "1234"
    val bundle = Bundle()
    LegacyTokenHelper.putToken(bundle, token)
    LegacyTokenHelper.putExpirationDate(bundle, later)
    LegacyTokenHelper.putSource(bundle, AccessTokenSource.FACEBOOK_APPLICATION_WEB)
    LegacyTokenHelper.putLastRefreshDate(bundle, earlier)
    LegacyTokenHelper.putPermissions(bundle, permissions)
    LegacyTokenHelper.putDeclinedPermissions(bundle, declinedPermissions)
    LegacyTokenHelper.putExpiredPermissions(bundle, expiredPermissions)
    LegacyTokenHelper.putApplicationId(bundle, applicationId)
    val accessToken = AccessToken.createFromLegacyCache(bundle)
    Assert.assertNotNull(accessToken)
    checkNotNull(accessToken)
    FacebookTestUtility.assertSameCollectionContents(permissions, accessToken.permissions)
    Assert.assertEquals(token, accessToken.token)
    Assert.assertEquals(AccessTokenSource.FACEBOOK_APPLICATION_WEB, accessToken.source)
    assertThat(accessToken.isExpired).isFalse
    val cache = AccessTokenTestHelper.toLegacyCacheBundle(accessToken)
    FacebookTestUtility.assertEqualContentsWithoutOrder(bundle, cache)
  }

  @Test
  fun `test from cache with missing application Id`() {
    val token = "AnImaginaryTokenValue"
    val applicationId = "1234"
    val bundle = Bundle()
    LegacyTokenHelper.putToken(bundle, token)
    // no app id
    PowerMockito.mockStatic(FacebookSdk::class.java)
    whenever(FacebookSdk.isInitialized()).thenReturn(true)
    whenever(FacebookSdk.getApplicationId()).thenReturn(applicationId)
    whenever(FacebookSdk.getAutoLogAppEventsEnabled()).thenReturn(false)
    whenever(FacebookSdk.getApplicationContext())
        .thenReturn(ApplicationProvider.getApplicationContext())
    val accessToken = AccessToken.createFromLegacyCache(bundle)
    Assert.assertNotNull(accessToken)
    checkNotNull(accessToken)
    Assert.assertEquals(applicationId, accessToken.applicationId)
  }

  @Test
  fun `test cache push get`() {
    val bundle = Bundle()
    for (token in arrayOf("", "A completely random token value")) {
      LegacyTokenHelper.putToken(bundle, token)
      Assert.assertEquals(token, LegacyTokenHelper.getToken(bundle))
    }
    for (date in arrayOf(Date(42), Date())) {
      LegacyTokenHelper.putExpirationDate(bundle, date)
      Assert.assertEquals(date, LegacyTokenHelper.getExpirationDate(bundle))
      LegacyTokenHelper.putLastRefreshDate(bundle, date)
      Assert.assertEquals(date, LegacyTokenHelper.getLastRefreshDate(bundle))
    }
    for (milliseconds in longArrayOf(0, -1, System.currentTimeMillis())) {
      LegacyTokenHelper.putExpirationMilliseconds(bundle, milliseconds)
      Assert.assertEquals(milliseconds, LegacyTokenHelper.getExpirationMilliseconds(bundle))
      LegacyTokenHelper.putLastRefreshMilliseconds(bundle, milliseconds)
      Assert.assertEquals(milliseconds, LegacyTokenHelper.getLastRefreshMilliseconds(bundle))
    }
    for (source in AccessTokenSource.values()) {
      LegacyTokenHelper.putSource(bundle, source)
      Assert.assertEquals(source, LegacyTokenHelper.getSource(bundle))
    }
    val normalList = listOf("", "Another completely random token value")
    val emptyList: List<String> = emptyList<String>()
    val normalArrayList = HashSet(normalList)
    val emptyArrayList = HashSet<String>()
    val permissionLists = listOf(normalList, emptyList, normalArrayList, emptyArrayList)
    for (list in permissionLists) {
      LegacyTokenHelper.putPermissions(bundle, list)
      FacebookTestUtility.assertSameCollectionContents(
          list, LegacyTokenHelper.getPermissions(bundle))
    }
    normalArrayList.add(null)
  }

  @Test
  fun `test create from native linking intent with user id`() {
    val intent = Intent()
    val tokenString = "a token"
    val userId = "1234"
    val applicationId = "1000"
    intent.putExtra(AccessToken.ACCESS_TOKEN_KEY, tokenString)
    intent.putExtra(AccessToken.USER_ID_KEY, userId)
    intent.putExtra(AccessToken.EXPIRES_IN_KEY, "0")
    var capturedAccessToken: AccessToken? = null
    AccessToken.createFromNativeLinkingIntent(
        intent,
        applicationId,
        object : AccessToken.AccessTokenCreationCallback {
          override fun onSuccess(token: AccessToken?) {
            capturedAccessToken = token
          }

          override fun onError(error: FacebookException?) = Unit
        })
    Assert.assertNotNull(capturedAccessToken)
    val accessToken = checkNotNull(capturedAccessToken)
    Assert.assertEquals(tokenString, accessToken.token)
    Assert.assertEquals(userId, accessToken.userId)
    Assert.assertEquals(applicationId, accessToken.applicationId)
    Assert.assertEquals(AccessTokenSource.FACEBOOK_APPLICATION_WEB, accessToken.source)
  }

  @Test
  fun `test create from native linking intent without user id`() {
    val intent = Intent()
    val tokenString = "a token"
    val userId = "1234"
    val applicationId = "1000"
    var capturedGraphRequestCallback: Utility.GraphMeRequestWithCacheCallback? = null
    PowerMockito.mockStatic(Utility::class.java)
    whenever(Utility.getGraphMeRequestWithCacheAsync(any(), any())).thenAnswer {
      capturedGraphRequestCallback = it.arguments[1] as Utility.GraphMeRequestWithCacheCallback?
      Unit
    }
    whenever(Utility.getBundleLongAsDate(any(), any(), any())).thenCallRealMethod()
    intent.putExtra(AccessToken.ACCESS_TOKEN_KEY, tokenString)
    intent.putExtra(AccessToken.EXPIRES_IN_KEY, "0")
    var capturedAccessToken: AccessToken? = null
    AccessToken.createFromNativeLinkingIntent(
        intent,
        applicationId,
        object : AccessToken.AccessTokenCreationCallback {
          override fun onSuccess(token: AccessToken?) {
            capturedAccessToken = token
          }

          override fun onError(error: FacebookException?) = Unit
        })

    Assert.assertNotNull(capturedGraphRequestCallback)
    val userInfo = JSONObject()
    userInfo.put("id", userId)
    capturedGraphRequestCallback?.onSuccess(userInfo)
    Assert.assertNotNull(capturedAccessToken)
    val accessToken = checkNotNull(capturedAccessToken)
    Assert.assertEquals(tokenString, accessToken.token)
    Assert.assertEquals(userId, accessToken.userId)
    Assert.assertEquals(applicationId, accessToken.applicationId)
    Assert.assertEquals(AccessTokenSource.FACEBOOK_APPLICATION_WEB, accessToken.source)
  }

  @Test
  fun `test create from empty intent`() {
    val intent = Intent()
    var capturedError: FacebookException? = null
    AccessToken.createFromNativeLinkingIntent(
        intent,
        "1234",
        object : AccessToken.AccessTokenCreationCallback {
          override fun onSuccess(token: AccessToken?) = Unit

          override fun onError(error: FacebookException?) {
            capturedError = error
          }
        })
    Assert.assertNotNull(capturedError)
  }

  @Test
  fun `test roundtrip JSONObject`() {
    val accessToken =
        AccessToken(
            "a token",
            "1234",
            "1000",
            listOf("permission_1", "permission_2"),
            listOf("declined permission_1", "declined permission_2"),
            listOf("expired permission_1", "expired permission_2"),
            AccessTokenSource.WEB_VIEW,
            Date(2_015, 3, 3),
            Date(2_015, 1, 1),
            Date(2_015, 3, 3))
    val jsonObject = accessToken.toJSONObject()
    val deserializedAccessToken = AccessToken.createFromJSONObject(jsonObject)
    Assert.assertEquals(accessToken, deserializedAccessToken)
  }

  @Test
  fun `test JSONObject without data access or expired permissions`() {
    val accessToken =
        AccessToken(
            "a token",
            "1234",
            "1000",
            listOf("permission_1", "permission_2"),
            listOf("declined permission_1", "declined permission_2"),
            listOf(),
            AccessTokenSource.WEB_VIEW,
            Date(2_015, 3, 3),
            Date(2_015, 1, 1),
            Date(0))
    val jsonObject = accessToken.toJSONObject()
    jsonObject.remove("data_access_expiration_time")
    jsonObject.remove("expired_permissions")
    val deserializedAccessToken = AccessToken.createFromJSONObject(jsonObject)
    Assert.assertEquals(accessToken, deserializedAccessToken)
  }

  @Test
  fun `test parceling`() {
    val token = "a token"
    val appId = "1234"
    val userId = "1000"
    val permissions: Set<String?> = hashSetOf("permission_1", "permission_2")
    val declinedPermissions: Set<String?> = hashSetOf("permission_3")
    val expiredPermissions: Set<String?> = hashSetOf("permission_4")
    val source = AccessTokenSource.WEB_VIEW
    val accessToken1 =
        AccessToken(
            token,
            appId,
            userId,
            permissions,
            declinedPermissions,
            expiredPermissions,
            source,
            null,
            null,
            null)
    val accessToken2 = FacebookTestUtility.parcelAndUnparcel(accessToken1)
    checkNotNull(accessToken2)
    Assert.assertEquals(accessToken1, accessToken2)
    Assert.assertEquals(token, accessToken2.token)
    Assert.assertEquals(appId, accessToken2.applicationId)
    Assert.assertEquals(permissions, accessToken2.permissions)
    Assert.assertEquals(declinedPermissions, accessToken2.declinedPermissions)
    Assert.assertEquals(expiredPermissions, accessToken2.expiredPermissions)
    Assert.assertEquals(accessToken1.expires, accessToken2.expires)
    Assert.assertEquals(accessToken1.lastRefresh, accessToken2.lastRefresh)
    Assert.assertEquals(accessToken1.userId, accessToken2.userId)
    Assert.assertEquals(accessToken1.expires, accessToken2.expires)
    Assert.assertEquals(
        accessToken1.dataAccessExpirationTime, accessToken2.dataAccessExpirationTime)
  }

  @Test
  fun `test create from existing token defaults`() {
    val token = "A token of my esteem"
    val applicationId = "1234"
    val userId = "1000"
    val accessToken =
        AccessToken(token, applicationId, userId, null, null, null, null, null, null, null)
    Assert.assertEquals(token, accessToken.token)
    Assert.assertEquals(Date(Long.MAX_VALUE), accessToken.expires)
    Assert.assertEquals(AccessTokenSource.FACEBOOK_APPLICATION_WEB, accessToken.source)
    Assert.assertEquals(0, accessToken.permissions.size.toLong())
    Assert.assertEquals(applicationId, accessToken.applicationId)
    Assert.assertEquals(userId, accessToken.userId)
    // Allow slight variation for test execution time
    val delta = accessToken.lastRefresh.time - Date().time
    assertThat(delta).isLessThan(1_000)
  }

  @Test
  fun `test AccessToken constructor`() {
    val token = "A token of my esteem"
    val permissions: Set<String?> = hashSetOf("walk", "chew gum")
    val declinedPermissions: Set<String?> = hashSetOf("jump")
    val expiredPermissions: Set<String?> = hashSetOf("smile")
    val expires = Date(2_025, 5, 3)
    val lastRefresh = Date(2_023, 8, 15)
    val dataAccessExpirationTime = Date(2_025, 5, 3)
    val source = AccessTokenSource.WEB_VIEW
    val applicationId = "1234"
    val userId = "1000"
    val accessToken =
        AccessToken(
            token,
            applicationId,
            userId,
            permissions,
            declinedPermissions,
            expiredPermissions,
            source,
            expires,
            lastRefresh,
            dataAccessExpirationTime)
    Assert.assertEquals(token, accessToken.token)
    Assert.assertEquals(expires, accessToken.expires)
    Assert.assertEquals(lastRefresh, accessToken.lastRefresh)
    Assert.assertEquals(source, accessToken.source)
    Assert.assertEquals(permissions, accessToken.permissions)
    Assert.assertEquals(declinedPermissions, accessToken.declinedPermissions)
    Assert.assertEquals(expiredPermissions, accessToken.expiredPermissions)
    Assert.assertEquals(applicationId, accessToken.applicationId)
    Assert.assertEquals(userId, accessToken.userId)
    Assert.assertEquals(dataAccessExpirationTime, accessToken.dataAccessExpirationTime)
  }

  @Test
  fun `test access token creation with default graph domain`() {
    val accessToken =
        AccessToken(
            mockTokenString, mockAppID, mockUserID, null, null, null, null, null, null, null)
    Assert.assertEquals(accessToken.graphDomain, "facebook")
  }

  @Test
  fun `test access token creation with Instagram graph domain`() {
    val accessToken =
        AccessToken(
            mockTokenString,
            mockAppID,
            mockUserID,
            null, // permissions
            null, // declined permissions
            null, // expired permissions
            null, // token source
            null, // expiration time
            null, // last refresh
            null, // data access expiration time
            "instagram")
    Assert.assertEquals(accessToken.graphDomain, "instagram")
  }

  @Test
  fun `test is logged in with Instagram`() {
    val instagramAccessToken =
        AccessToken(
            mockTokenString,
            mockAppID,
            mockUserID,
            null, // permissions
            null, // declined permissions
            null, // expired permissions
            null, // token source
            null, // expiration time
            null, // last refresh
            null, // data access expiration time
            "instagram")
    val facebookAccessToken =
        AccessToken(
            mockTokenString,
            mockAppID,
            mockUserID,
            null, // permissions
            null, // declined permissions
            null, // expired permissions
            null, // token source
            null, // expiration time
            null, // last refresh
            null, // data access expiration time
            "facebok")

    AccessToken.setCurrentAccessToken(instagramAccessToken)
    assertThat(AccessToken.isLoggedInWithInstagram()).isTrue
    AccessToken.setCurrentAccessToken(facebookAccessToken)
    assertThat(AccessToken.isLoggedInWithInstagram()).isFalse
  }

  @Test
  fun `test default token source for Facebook domain`() {
    val token = getAccessTokenWithSpecifiedSource("facebook", null)
    Assert.assertEquals(token.source, AccessTokenSource.FACEBOOK_APPLICATION_WEB)
  }

  @Test
  fun `test application web source for Facebook domain`() {
    val token =
        getAccessTokenWithSpecifiedSource("facebook", AccessTokenSource.FACEBOOK_APPLICATION_WEB)
    Assert.assertEquals(token.source, AccessTokenSource.FACEBOOK_APPLICATION_WEB)
  }

  @Test
  fun `test chrome custom tab source for Facebook domain`() {
    val token = getAccessTokenWithSpecifiedSource("facebook", AccessTokenSource.CHROME_CUSTOM_TAB)
    Assert.assertEquals(token.source, AccessTokenSource.CHROME_CUSTOM_TAB)
  }

  @Test
  fun `test webview source for Facebook domain`() {
    val token = getAccessTokenWithSpecifiedSource("facebook", AccessTokenSource.WEB_VIEW)
    Assert.assertEquals(token.source, AccessTokenSource.WEB_VIEW)
  }

  @Test
  fun `test default token source for Gaming domain`() {
    val token = getAccessTokenWithSpecifiedSource("gaming", null)
    Assert.assertEquals(token.source, AccessTokenSource.FACEBOOK_APPLICATION_WEB)
  }

  @Test
  fun `test application web source for Gaming domain`() {
    val token =
        getAccessTokenWithSpecifiedSource("gaming", AccessTokenSource.FACEBOOK_APPLICATION_WEB)
    Assert.assertEquals(token.source, AccessTokenSource.FACEBOOK_APPLICATION_WEB)
  }

  @Test
  fun `test chrome custom tab source for Gaming domain`() {
    val token = getAccessTokenWithSpecifiedSource("gaming", AccessTokenSource.CHROME_CUSTOM_TAB)
    Assert.assertEquals(token.source, AccessTokenSource.CHROME_CUSTOM_TAB)
  }

  @Test
  fun `test webview source for Gaming domain`() {
    val token = getAccessTokenWithSpecifiedSource("gaming", AccessTokenSource.WEB_VIEW)
    Assert.assertEquals(token.source, AccessTokenSource.WEB_VIEW)
  }

  @Test
  fun `test default token source for Instagram domain`() {
    val token = getAccessTokenWithSpecifiedSource("instagram", null)
    Assert.assertEquals(token.source, AccessTokenSource.INSTAGRAM_APPLICATION_WEB)
  }

  @Test
  fun `test application web source for Instagram domain`() {
    val token =
        getAccessTokenWithSpecifiedSource("instagram", AccessTokenSource.FACEBOOK_APPLICATION_WEB)
    Assert.assertEquals(token.source, AccessTokenSource.INSTAGRAM_APPLICATION_WEB)
  }

  @Test
  fun `test chrome custom tab source for Instagram domain`() {
    val token = getAccessTokenWithSpecifiedSource("instagram", AccessTokenSource.CHROME_CUSTOM_TAB)
    Assert.assertEquals(token.source, AccessTokenSource.INSTAGRAM_CUSTOM_CHROME_TAB)
  }

  @Test
  fun `test webview source for Instagram domain`() {
    val token = getAccessTokenWithSpecifiedSource("instagram", AccessTokenSource.WEB_VIEW)
    Assert.assertEquals(token.source, AccessTokenSource.INSTAGRAM_WEB_VIEW)
  }

  fun getAccessTokenWithSpecifiedSource(
      graphDomain: String,
      tokenSource: AccessTokenSource?
  ): AccessToken {
    return AccessToken(
        mockTokenString,
        mockAppID,
        mockUserID,
        null, // permissions
        null, // declined permissions
        null, // expired permissions
        tokenSource,
        null, // expiration time
        null, // last refresh
        null, // data access expiration time
        graphDomain)
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook

import android.os.Bundle

object AccessTokenTestHelper {
  fun toLegacyCacheBundle(accessToken: AccessToken): Bundle {
    val bundle = Bundle()
    LegacyTokenHelper.putToken(bundle, accessToken.token)
    LegacyTokenHelper.putExpirationDate(bundle, accessToken.expires)
    LegacyTokenHelper.putPermissions(bundle, accessToken.permissions as Set<String>)
    LegacyTokenHelper.putDeclinedPermissions(bundle, accessToken.declinedPermissions as Set<String>)
    LegacyTokenHelper.putExpiredPermissions(bundle, accessToken.expiredPermissions as Set<String>)
    LegacyTokenHelper.putSource(bundle, accessToken.source)
    LegacyTokenHelper.putLastRefreshDate(bundle, accessToken.lastRefresh)
    LegacyTokenHelper.putApplicationId(bundle, accessToken.applicationId)
    return bundle
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook

import android.content.Context
import android.content.SharedPreferences
import com.facebook.internal.Utility
import com.facebook.internal.security.OidcSecurityUtil
import com.facebook.util.common.AuthenticationTokenTestUtil
import java.security.PublicKey
import org.assertj.core.api.Assertions.assertThat
import org.json.JSONObject
import org.junit.Before
import org.junit.Test
import org.mockito.kotlin.any
import org.powermock.api.mockito.PowerMockito
import org.powermock.api.support.membermodification.MemberModifier
import org.powermock.core.classloader.annotations.PrepareForTest
import org.robolectric.RuntimeEnvironment

@PrepareForTest(FacebookSdk::class, OidcSecurityUtil::class)
internal class AuthenticationTokenCacheTest : FacebookPowerMockTestCase() {
  private lateinit var sharedPreferences: SharedPreferences

  @Before
  fun before() {
    PowerMockito.mockStatic(FacebookSdk::class.java)
    PowerMockito.`when`(FacebookSdk.getApplicationId())
        .thenReturn(AuthenticationTokenTestUtil.APP_ID)

    // mock and bypass signature verification
    PowerMockito.mockStatic(OidcSecurityUtil::class.java)
    PowerMockito.`when`(OidcSecurityUtil.getRawKeyFromEndPoint(any())).thenReturn("key")
    PowerMockito.`when`(OidcSecurityUtil.getPublicKeyFromString(any()))
        .thenReturn(PowerMockito.mock(PublicKey::class.java))
    PowerMockito.`when`(OidcSecurityUtil.verify(any(), any(), any())).thenReturn(true)

    sharedPreferences =
        RuntimeEnvironment.application.getSharedPreferences(
            AuthenticationTokenManager.SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE)
    sharedPreferences.edit().clear().apply()
    MemberModifier.stub<Any>(
            PowerMockito.method(
                Utility::class.java, "awaitGetGraphMeRequestWithCache", String::class.java))
        .toReturn(JSONObject().put("id", "1000"))
  }

  @Test
  fun `test load returns null if no cached authentication token`() {
    val cache = AuthenticationTokenCache(sharedPreferences)
    val authenticationToken = cache.load()
    assertThat(authenticationToken).isNull()
  }

  @Test
  fun `test load returns null if empty authentication token`() {
    sharedPreferences
        .edit()
        .putString(AuthenticationTokenCache.CACHED_AUTHENTICATION_TOKEN_KEY, "")
        .apply()
    val cache = AuthenticationTokenCache(sharedPreferences)
    val authenticationToken = cache.load()
    assertThat(authenticationToken).isNull()
  }

  @Test
  fun `test load valid cached token`() {
    val authenticationToken = AuthenticationTokenTestUtil.getAuthenticationTokenForTest()
    sharedPreferences
        .edit()
        .putString(
            AuthenticationTokenCache.CACHED_AUTHENTICATION_TOKEN_KEY,
            authenticationToken.toJSONObject().toString())
        .apply()
    val cache = AuthenticationTokenCache(sharedPreferences)
    val loadedAuthenticationToken = cache.load()
    assertThat(loadedAuthenticationToken).isNotNull
    assertThat(authenticationToken).isEqualTo(loadedAuthenticationToken)
  }

  @Test
  fun `test AuthenticationToken save and clear`() {
    val cache = AuthenticationTokenCache(sharedPreferences)
    sharedPreferences
        .edit()
        .remove(AuthenticationTokenCache.CACHED_AUTHENTICATION_TOKEN_KEY)
        .apply()
    assertThat(cache.load()).isNull()

    // make sure save correctly
    val authenticationToken = AuthenticationTokenTestUtil.getAuthenticationTokenForTest()
    cache.save(authenticationToken)
    assertThat(authenticationToken.token).isNotEmpty
    assertThat(
            sharedPreferences.getString(
                AuthenticationTokenCache.CACHED_AUTHENTICATION_TOKEN_KEY, ""))
        .isEqualTo(authenticationToken.toJSONObject().toString())

    // clear
    cache.clear()
    assertThat(sharedPreferences.contains(AuthenticationTokenCache.CACHED_AUTHENTICATION_TOKEN_KEY))
        .isFalse
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook

import android.util.Base64
import com.facebook.util.common.AuthenticationTokenTestUtil
import org.assertj.core.api.Assertions.assertThat
import org.json.JSONException
import org.json.JSONObject
import org.junit.Before
import org.junit.Test
import org.mockito.kotlin.whenever
import org.powermock.api.mockito.PowerMockito
import org.powermock.core.classloader.annotations.PrepareForTest

@PrepareForTest(FacebookSdk::class)
class AuthenticationTokenClaimsTest : FacebookPowerMockTestCase() {

  private var claimsMap = hashMapOf<String, Any>()

  @Before
  fun before() {
    PowerMockito.mockStatic(FacebookSdk::class.java)
    whenever(FacebookSdk.getApplicationId()).thenReturn(AuthenticationTokenTestUtil.APP_ID)
    claimsMap["jti"] = "jti"
    claimsMap["sub"] = "1234"
    claimsMap["iss"] = "https://facebook.com/dialog/oauth"
    claimsMap["aud"] = AuthenticationTokenTestUtil.APP_ID
    claimsMap["nonce"] = "some nonce"
    claimsMap["exp"] = 1_516_259_022
    claimsMap["iat"] = 1_516_239_022
  }

  @Test(expected = IllegalArgumentException::class)
  fun `test missing jti throws`() {
    claimsMap.remove("jti")
    val missingJti = JSONObject(claimsMap as Map<*, *>).toString()
    val encodedClaimsString = Base64.encodeToString(missingJti.toByteArray(), Base64.URL_SAFE)
    AuthenticationTokenClaims(encodedClaimsString, AuthenticationTokenTestUtil.NONCE)
  }

  @Test(expected = IllegalArgumentException::class)
  fun `test missing iss throws`() {
    claimsMap.remove("iss")
    val missingIss = JSONObject(claimsMap as Map<*, *>).toString()
    val encodedClaimsString = Base64.encodeToString(missingIss.toByteArray(), Base64.URL_SAFE)
    AuthenticationTokenClaims(encodedClaimsString, AuthenticationTokenTestUtil.NONCE)
  }

  @Test(expected = IllegalArgumentException::class)
  fun `test missing aud throws`() {
    claimsMap.remove("aud")
    val missingAud = JSONObject(claimsMap as Map<*, *>).toString()
    val encodedClaimsString = Base64.encodeToString(missingAud.toByteArray(), Base64.URL_SAFE)
    AuthenticationTokenClaims(encodedClaimsString, AuthenticationTokenTestUtil.NONCE)
  }

  @Test(expected = IllegalArgumentException::class)
  fun `test missing nonce throws`() {
    claimsMap.remove("nonce")
    val missingNonce = JSONObject(claimsMap as Map<*, *>).toString()
    val encodedClaimsString = Base64.encodeToString(missingNonce.toByteArray(), Base64.URL_SAFE)
    AuthenticationTokenClaims(encodedClaimsString, AuthenticationTokenTestUtil.NONCE)
  }

  @Test(expected = IllegalArgumentException::class)
  fun `test nonce does not match throws`() {
    claimsMap["nonce"] = "not_nonce"
    val missingNonce = JSONObject(claimsMap as Map<*, *>).toString()
    val encodedClaimsString = Base64.encodeToString(missingNonce.toByteArray(), Base64.URL_SAFE)
    AuthenticationTokenClaims(encodedClaimsString, AuthenticationTokenTestUtil.NONCE)
  }

  @Test(expected = IllegalArgumentException::class)
  fun `test empty nonce throws`() {
    claimsMap["nonce"] = ""
    val missingNonce = JSONObject(claimsMap as Map<*, *>).toString()
    val encodedClaimsString = Base64.encodeToString(missingNonce.toByteArray(), Base64.URL_SAFE)
    AuthenticationTokenClaims(encodedClaimsString, AuthenticationTokenTestUtil.NONCE)
  }

  @Test(expected = IllegalArgumentException::class)
  fun `test missing sub throws`() {
    claimsMap.remove("sub")
    val missingSub = JSONObject(claimsMap as Map<*, *>).toString()
    val encodedClaimsString = Base64.encodeToString(missingSub.toByteArray(), Base64.URL_SAFE)
    AuthenticationTokenClaims(encodedClaimsString, AuthenticationTokenTestUtil.NONCE)
  }

  @Test(expected = JSONException::class)
  fun `test throw - invalid json format`() {
    val invalidJson = "123"
    val encodedClaimsString = Base64.encodeToString(invalidJson.toByteArray(), Base64.URL_SAFE)
    AuthenticationTokenClaims(encodedClaimsString, AuthenticationTokenTestUtil.NONCE)
  }

  @Test(expected = IllegalArgumentException::class)
  fun `test empty encode claims string throws`() {
    AuthenticationTokenClaims("", AuthenticationTokenTestUtil.NONCE)
  }

  @Test
  fun `test constructor with required encoded claims`() {
    val encodedClaims =
        AuthenticationTokenTestUtil.authenticationTokenClaimsWithRequiredFieldsOnly
            .toEnCodedString()
    val authenticationToken =
        AuthenticationTokenClaims(encodedClaims, AuthenticationTokenTestUtil.NONCE)
    assertThat(AuthenticationTokenTestUtil.authenticationTokenClaimsWithRequiredFieldsOnly.sub)
        .isEqualTo(authenticationToken.sub)
    assertThat(AuthenticationTokenTestUtil.authenticationTokenClaimsWithRequiredFieldsOnly.jti)
        .isEqualTo(authenticationToken.jti)
    assertThat(AuthenticationTokenTestUtil.authenticationTokenClaimsWithRequiredFieldsOnly.iss)
        .isEqualTo(authenticationToken.iss)
    assertThat(AuthenticationTokenTestUtil.authenticationTokenClaimsWithRequiredFieldsOnly.aud)
        .isEqualTo(authenticationToken.aud)
    assertThat(AuthenticationTokenTestUtil.authenticationTokenClaimsWithRequiredFieldsOnly.nonce)
        .isEqualTo(authenticationToken.nonce)
    assertThat(AuthenticationTokenTestUtil.authenticationTokenClaimsWithRequiredFieldsOnly.exp)
        .isEqualTo(authenticationToken.exp)
    assertThat(AuthenticationTokenTestUtil.authenticationTokenClaimsWithRequiredFieldsOnly.iat)
        .isEqualTo(authenticationToken.iat)
  }

  @Test
  fun `test roundtrip JSONObject`() {
    // test full claims
    val jsonObject = AuthenticationTokenTestUtil.AUTH_TOKEN_CLAIMS_FOR_TEST.toJSONObject()
    val deserializeClaims = AuthenticationTokenClaims.createFromJSONObject(jsonObject)
    assertThat(AuthenticationTokenTestUtil.AUTH_TOKEN_CLAIMS_FOR_TEST == deserializeClaims).isTrue

    // test claims with empty optional fields
    val jsonObjectEmptyOptionalFields =
        AuthenticationTokenTestUtil.AUTH_TOKEN_CLAIMS_WITH_EMPTY_OPTIONAL_FIELDS.toJSONObject()
    val deserializeClaimsEmptyOptionalFields =
        AuthenticationTokenClaims.createFromJSONObject(jsonObjectEmptyOptionalFields)
    assertThat(
            AuthenticationTokenTestUtil.AUTH_TOKEN_CLAIMS_WITH_EMPTY_OPTIONAL_FIELDS ==
                deserializeClaimsEmptyOptionalFields)
        .isTrue

    // test only required claims fields with others are null
    val jsonObjectRequired =
        AuthenticationTokenTestUtil.authenticationTokenClaimsWithRequiredFieldsOnly.toJSONObject()
    val deserializeClaimsRequired =
        AuthenticationTokenClaims.createFromJSONObject(jsonObjectRequired)
    assertThat(
            AuthenticationTokenTestUtil.authenticationTokenClaimsWithRequiredFieldsOnly ==
                deserializeClaimsRequired)
        .isTrue
  }

  @Test
  fun `test roundtrip decode and encode`() {
    // test full claims
    val encodedString = AuthenticationTokenTestUtil.AUTH_TOKEN_CLAIMS_FOR_TEST.toEnCodedString()
    val newAuthenticationTokenClaims =
        AuthenticationTokenClaims(encodedString, AuthenticationTokenTestUtil.NONCE)
    assertThat(
            AuthenticationTokenTestUtil.AUTH_TOKEN_CLAIMS_FOR_TEST == newAuthenticationTokenClaims)
        .isTrue

    // test only required claims fields with others are null
    val encodedStringWithRequiredFields =
        AuthenticationTokenTestUtil.authenticationTokenClaimsWithRequiredFieldsOnly
            .toEnCodedString()
    val newClaimsWithRequiredFields =
        AuthenticationTokenClaims(
            encodedStringWithRequiredFields, AuthenticationTokenTestUtil.NONCE)
    assertThat(
            AuthenticationTokenTestUtil.authenticationTokenClaimsWithRequiredFieldsOnly ==
                newClaimsWithRequiredFields)
        .isTrue
  }

  @Test
  fun `test parceling with all fields`() {
    val claims1 = AuthenticationTokenTestUtil.AUTH_TOKEN_CLAIMS_FOR_TEST
    val claims2 = FacebookTestUtility.parcelAndUnparcel(claims1)
    assertThat(claims2).isNotNull
    assertThat(claims1).isEqualTo(claims2)
  }

  @Test
  fun `test parceling with empty optional fields`() {
    val claims1 = AuthenticationTokenTestUtil.AUTH_TOKEN_CLAIMS_WITH_EMPTY_OPTIONAL_FIELDS
    val claims2 = FacebookTestUtility.parcelAndUnparcel(claims1)
    assertThat(claims2).isNotNull
    assertThat(claims1).isEqualTo(claims2)
  }

  @Test
  fun `test parceling only required fields while other are null`() {
    val claims1 = AuthenticationTokenTestUtil.authenticationTokenClaimsWithRequiredFieldsOnly
    val claims2 = FacebookTestUtility.parcelAndUnparcel(claims1)
    assertThat(claims2).isNotNull
    assertThat(claims1).isEqualTo(claims2)
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook

import android.util.Base64
import com.facebook.util.common.AuthenticationTokenTestUtil
import org.assertj.core.api.Assertions.assertThat
import org.json.JSONObject
import org.junit.Before
import org.junit.Test

class AuthenticationTokenHeaderTest : FacebookPowerMockTestCase() {
  private lateinit var headerMap: HashMap<String, String>

  @Before
  fun before() {
    headerMap = hashMapOf("alg" to "RS256", "typ" to "token_type", "kid" to "abc")
  }
  @Test(expected = IllegalArgumentException::class)
  fun `test missing alg throws`() {
    headerMap.remove("alg")
    val missingAlg = JSONObject(headerMap as Map<*, *>).toString()
    val encodedHeaderString = Base64.encodeToString(missingAlg.toByteArray(), Base64.DEFAULT)
    AuthenticationTokenHeader(encodedHeaderString)
  }

  @Test(expected = IllegalArgumentException::class)
  fun `test missing typ throws`() {
    headerMap.remove("typ")
    val missingAlg = JSONObject(headerMap as Map<*, *>).toString()
    val encodedHeaderString = Base64.encodeToString(missingAlg.toByteArray(), Base64.DEFAULT)
    AuthenticationTokenHeader(encodedHeaderString)
  }

  @Test(expected = IllegalArgumentException::class)
  fun `test missing kid throws`() {
    headerMap.remove("kid")
    val missingAlg = JSONObject(headerMap as Map<*, *>).toString()
    val encodedHeaderString = Base64.encodeToString(missingAlg.toByteArray(), Base64.DEFAULT)
    AuthenticationTokenHeader(encodedHeaderString)
  }

  @Test(expected = IllegalArgumentException::class)
  fun `test throw - invalid encoded header string which is invalid json format`() {
    AuthenticationTokenHeader("invalid")
  }

  @Test(expected = IllegalArgumentException::class)
  fun `test empty encode claims string throws`() {
    AuthenticationTokenHeader("")
  }

  @Test
  fun `test constructor with required encoded header`() {
    val authenticationHeader =
        AuthenticationTokenHeader(AuthenticationTokenTestUtil.VALID_HEADER_STRING)
    assertThat(authenticationHeader.alg).isEqualTo("RS256")
    assertThat(authenticationHeader.typ).isEqualTo("token_type")
    assertThat(authenticationHeader.kid).isEqualTo("abc")
  }

  @Test
  fun `test parceling`() {
    val idTokenHeader1 = AuthenticationTokenHeader("alg", "typ", "kid")
    val idTokenHeader2 = FacebookTestUtility.parcelAndUnparcel(idTokenHeader1)
    assertThat(idTokenHeader2).isNotNull
    assertThat(idTokenHeader1.alg).isEqualTo(idTokenHeader2?.alg)
    assertThat(idTokenHeader1.typ).isEqualTo(idTokenHeader2?.typ)
    assertThat(idTokenHeader1.kid).isEqualTo(idTokenHeader2?.kid)
  }

  @Test
  fun `test json roundtrip`() {
    val jsonObject = AuthenticationTokenTestUtil.AUTH_TOKEN_HEADER_FOR_TEST.toJSONObject()
    val deserializeHeader = AuthenticationTokenHeader(jsonObject)
    assertThat(AuthenticationTokenTestUtil.AUTH_TOKEN_HEADER_FOR_TEST).isEqualTo(deserializeHeader)
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import androidx.test.core.app.ApplicationProvider
import com.facebook.internal.Utility
import com.facebook.internal.security.OidcSecurityUtil
import com.facebook.util.common.AuthenticationTokenTestUtil
import com.facebook.util.common.mockLocalBroadcastManager
import java.security.PublicKey
import org.assertj.core.api.Assertions.assertThat
import org.junit.Before
import org.junit.Test
import org.mockito.kotlin.any
import org.mockito.kotlin.mock
import org.mockito.kotlin.never
import org.mockito.kotlin.times
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
import org.powermock.api.mockito.PowerMockito
import org.powermock.core.classloader.annotations.PrepareForTest

@PrepareForTest(
    FacebookSdk::class, AuthenticationTokenCache::class, Utility::class, OidcSecurityUtil::class)
class AuthenticationTokenManagerTest : FacebookPowerMockTestCase() {
  private lateinit var localBroadcastManager: LocalBroadcastManager
  private lateinit var authenticationTokenCache: AuthenticationTokenCache

  private fun createAuthenticationTokenManager(): AuthenticationTokenManager {
    return AuthenticationTokenManager(localBroadcastManager, authenticationTokenCache)
  }

  @Before
  fun before() {
    PowerMockito.mockStatic(FacebookSdk::class.java)
    whenever(FacebookSdk.isInitialized()).thenReturn(true)
    whenever(FacebookSdk.getApplicationContext())
        .thenReturn(ApplicationProvider.getApplicationContext())
    whenever(FacebookSdk.getApplicationId()).thenReturn(AuthenticationTokenTestUtil.APP_ID)

    // mock and bypass signature verification
    PowerMockito.mockStatic(OidcSecurityUtil::class.java)
    PowerMockito.`when`(OidcSecurityUtil.getRawKeyFromEndPoint(any())).thenReturn("key")
    PowerMockito.`when`(OidcSecurityUtil.getPublicKeyFromString(any()))
        .thenReturn(PowerMockito.mock(PublicKey::class.java))
    PowerMockito.`when`(OidcSecurityUtil.verify(any(), any(), any())).thenReturn(true)

    authenticationTokenCache = mock()
    localBroadcastManager = mockLocalBroadcastManager(ApplicationProvider.getApplicationContext())
  }

  @Test
  fun testDefaultsToNoCurrentAuthenticationToken() {
    val authenticationTokenManager = createAuthenticationTokenManager()
    assertThat(authenticationTokenManager.currentAuthenticationToken).isNull()
  }

  @Test
  fun testCanSetCurrentAuthenticationToken() {
    val authenticationTokenManager = createAuthenticationTokenManager()
    val authenticationToken = AuthenticationTokenTestUtil.getAuthenticationTokenForTest()
    authenticationTokenManager.currentAuthenticationToken = authenticationToken
    assertThat(authenticationTokenManager.currentAuthenticationToken).isEqualTo(authenticationToken)
  }

  @Test
  fun testLoadReturnsFalseIfNoCachedToken() {
    val authenticationTokenManager = createAuthenticationTokenManager()
    val result = authenticationTokenManager.loadCurrentAuthenticationToken()
    assertThat(result).isFalse
  }

  @Test
  fun testLoadReturnsTrueIfCachedToken() {
    val authenticationToken = AuthenticationTokenTestUtil.getAuthenticationTokenForTest()
    whenever(authenticationTokenCache.load()).thenReturn(authenticationToken)
    val authenticationTokenManager = createAuthenticationTokenManager()
    val result = authenticationTokenManager.loadCurrentAuthenticationToken()
    assertThat(result).isTrue
  }

  @Test
  fun testLoadSetsCurrentTokenIfCached() {
    val authenticationToken = AuthenticationTokenTestUtil.getAuthenticationTokenForTest()
    whenever(authenticationTokenCache.load()).thenReturn(authenticationToken)
    val authenticationTokenManager = createAuthenticationTokenManager()
    authenticationTokenManager.loadCurrentAuthenticationToken()
    assertThat(authenticationTokenManager.currentAuthenticationToken).isEqualTo(authenticationToken)
  }

  @Test
  fun testSaveWritesToCacheIfToken() {
    val authenticationToken = AuthenticationTokenTestUtil.getAuthenticationTokenForTest()
    val authenticationTokenManager = createAuthenticationTokenManager()
    authenticationTokenManager.currentAuthenticationToken = authenticationToken
    verify(authenticationTokenCache, times(1)).save(any())
  }

  @Test
  fun testSetEmptyTokenClearsCache() {
    val authenticationTokenManager = createAuthenticationTokenManager()
    authenticationTokenManager.currentAuthenticationToken = null
    verify(authenticationTokenCache, times(1)).clear()
  }

  @Test
  fun testLoadDoesNotSave() {
    val authenticationToken = AuthenticationTokenTestUtil.getAuthenticationTokenForTest()
    whenever(authenticationTokenCache.load()).thenReturn(authenticationToken)
    val authenticationTokenManager = createAuthenticationTokenManager()
    authenticationTokenManager.loadCurrentAuthenticationToken()
    verify(authenticationTokenCache, never()).save(any())
  }

  @Test
  fun testChangingAuthenticationTokenSendsBroadcast() {
    val authenticationTokenManager = createAuthenticationTokenManager()
    val authenticationToken = AuthenticationTokenTestUtil.getAuthenticationTokenForTest()
    authenticationTokenManager.currentAuthenticationToken = authenticationToken
    val intents = arrayOfNulls<Intent>(1)
    val broadcastReceiver: BroadcastReceiver =
        object : BroadcastReceiver() {
          override fun onReceive(context: Context, intent: Intent) {
            intents[0] = intent
          }
        }
    localBroadcastManager.registerReceiver(
        broadcastReceiver,
        IntentFilter(AuthenticationTokenManager.ACTION_CURRENT_AUTHENTICATION_TOKEN_CHANGED))
    val anotherAuthenticationToken =
        AuthenticationTokenTestUtil.getAuthenticationTokenEmptyOptionalClaimsForTest()
    authenticationTokenManager.currentAuthenticationToken = anotherAuthenticationToken
    localBroadcastManager.unregisterReceiver(broadcastReceiver)
    val intent = intents[0]
    assertThat(intent).isNotNull()
    checkNotNull(intent)
    val oldAuthenticationToken: AuthenticationToken =
        checkNotNull(
            intent.getParcelableExtra(AuthenticationTokenManager.EXTRA_OLD_AUTHENTICATION_TOKEN))
    val newAuthenticationToken: AuthenticationToken =
        checkNotNull(
            intent.getParcelableExtra(AuthenticationTokenManager.EXTRA_NEW_AUTHENTICATION_TOKEN))
    assertThat(authenticationToken.token).isEqualTo(oldAuthenticationToken.token)
    assertThat(anotherAuthenticationToken.token).isEqualTo(newAuthenticationToken.token)
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook

import android.content.Intent
import androidx.test.core.app.ApplicationProvider
import org.junit.Test
import org.mockito.kotlin.mock
import org.mockito.kotlin.never
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
import org.powermock.api.mockito.PowerMockito
import org.powermock.core.classloader.annotations.PrepareForTest
import org.powermock.reflect.Whitebox

@PrepareForTest(FacebookSdk::class)
class CurrentAccessTokenExpirationBroadcastReceiverTest : FacebookPowerMockTestCase() {
  private lateinit var mockAccessTokenManager: AccessTokenManager
  override fun setup() {
    PowerMockito.mockStatic(FacebookSdk::class.java)
    whenever(FacebookSdk.isInitialized()).thenReturn(true)
    mockAccessTokenManager = mock()
    val mockAccessTokenManagerCompanion: AccessTokenManager.Companion = mock()
    whenever(mockAccessTokenManagerCompanion.getInstance()).thenReturn(mockAccessTokenManager)
    Whitebox.setInternalState(
        AccessTokenManager::class.java, "Companion", mockAccessTokenManagerCompanion)
  }

  @Test
  fun `test on receiving current access token changed intent`() {
    val intent = Intent(AccessTokenManager.ACTION_CURRENT_ACCESS_TOKEN_CHANGED)
    val receiver = CurrentAccessTokenExpirationBroadcastReceiver()
    receiver.onReceive(ApplicationProvider.getApplicationContext(), intent)
    verify(mockAccessTokenManager).currentAccessTokenChanged()
  }

  @Test
  fun `test on receiving irrelevant intent`() {
    val intent = Intent("irrelevant action")
    val receiver = CurrentAccessTokenExpirationBroadcastReceiver()
    receiver.onReceive(ApplicationProvider.getApplicationContext(), intent)
    verify(mockAccessTokenManager, never()).currentAccessTokenChanged()
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook

import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.test.core.app.ApplicationProvider
import com.facebook.internal.NativeProtocol
import com.facebook.util.common.anyObject
import org.junit.Before
import org.junit.Test
import org.mockito.kotlin.any
import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
import org.mockito.kotlin.never
import org.mockito.kotlin.times
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
import org.powermock.api.mockito.PowerMockito
import org.powermock.core.classloader.annotations.PrepareForTest

@PrepareForTest(NativeProtocol::class)
class FacebookBroadcastReceiverTest : FacebookPowerMockTestCase() {
  // This class will make the callback methods public, which allows verifying interactions
  private class TestFacebookBroadcastReceiver : FacebookBroadcastReceiver() {
    public override fun onSuccessfulAppCall(appCallId: String, action: String, extras: Bundle) {
      // Do nothing. Only for testing.
    }

    public override fun onFailedAppCall(appCallId: String, action: String, extras: Bundle) {
      // Do nothing. Only for testing.
    }
  }

  private lateinit var receiver: TestFacebookBroadcastReceiver
  private lateinit var ctx: Context

  @Before
  fun init() {
    receiver = mock()
    whenever(receiver.onReceive(any(), any())).thenCallRealMethod()
    ctx = ApplicationProvider.getApplicationContext() as Context
  }

  @Test
  fun `test on receive successful`() {
    val intent = Intent()
    intent.putExtra(NativeProtocol.EXTRA_PROTOCOL_CALL_ID, "1337")
    intent.putExtra(NativeProtocol.EXTRA_PROTOCOL_ACTION, "action")
    PowerMockito.mockStatic(NativeProtocol::class.java)
    whenever(NativeProtocol.isErrorResult(any())).thenReturn(false)
    receiver.onReceive(ctx, intent)
    verify(receiver, times(1)).onSuccessfulAppCall(eq("1337"), eq("action"), any())
    verify(receiver, never()).onFailedAppCall(eq("1337"), eq("action"), any())
  }

  @Test
  fun `test on receive failed app call`() {
    val intent = Intent()
    intent.putExtra(NativeProtocol.EXTRA_PROTOCOL_CALL_ID, "1337")
    intent.putExtra(NativeProtocol.EXTRA_PROTOCOL_ACTION, "action")
    PowerMockito.mockStatic(NativeProtocol::class.java)
    whenever(NativeProtocol.isErrorResult(anyObject())).thenReturn(true)
    receiver.onReceive(ctx, intent)
    verify(receiver, times(1)).onFailedAppCall(eq("1337"), eq("action"), any())
    verify(receiver, never()).onSuccessfulAppCall(eq("1337"), eq("action"), any())
  }

  @Test
  fun `test on receive never called`() {
    val intent = Intent()
    intent.putExtra(NativeProtocol.EXTRA_PROTOCOL_CALL_ID, "1337")
    PowerMockito.mockStatic(NativeProtocol::class.java)
    whenever(NativeProtocol.isErrorResult(anyObject())).thenReturn(true)
    receiver.onReceive(ctx, intent)
    verify(receiver, never()).onFailedAppCall(eq("1337"), eq("action"), any())
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook

import android.net.Uri
import android.os.ParcelFileDescriptor
import android.util.Pair
import com.facebook.internal.NativeAppCallAttachmentStore
import com.facebook.internal.NativeAppCallAttachmentStore.openAttachment
import java.io.File
import java.io.FileNotFoundException
import java.io.IOException
import java.util.UUID
import kotlin.collections.ArrayList
import org.assertj.core.api.Assertions.assertThat
import org.junit.Assert
import org.junit.Before
import org.junit.Test
import org.mockito.kotlin.whenever
import org.powermock.api.mockito.PowerMockito
import org.powermock.core.classloader.annotations.PrepareForTest
import org.robolectric.RuntimeEnvironment

@PrepareForTest(NativeAppCallAttachmentStore::class)
class FacebookContentProviderTest : FacebookPowerMockTestCase() {
  private lateinit var providerUnderTest: FacebookContentProvider

  @Before
  fun before() {
    PowerMockito.mockStatic(NativeAppCallAttachmentStore::class.java)
    providerUnderTest = FacebookContentProvider()
  }

  @Test
  fun testGetAttachmentUrl() {
    val url = FacebookContentProvider.getAttachmentUrl(APP_ID, CALL_ID, ATTACHMENT_NAME)
    Assert.assertEquals(
        "content://com.facebook.app.FacebookContentProvider" +
            APP_ID +
            "/" +
            CALL_ID +
            "/" +
            ATTACHMENT_NAME,
        url)
  }

  @Test
  fun testOnCreate() {
    assertThat(providerUnderTest.onCreate()).isTrue
  }

  @Test
  fun testQuery() {
    Assert.assertNull(providerUnderTest.query(Uri.parse("/"), null, null, null, null))
  }

  @Test
  fun testGetType() {
    Assert.assertNull(providerUnderTest.getType(Uri.parse("/")))
  }

  @Test
  fun testInsert() {
    Assert.assertNull(providerUnderTest.insert(Uri.parse("/"), null))
  }

  @Test
  fun testDelete() {
    Assert.assertEquals(0, providerUnderTest.delete(Uri.parse("/"), null, null).toLong())
  }

  @Test
  fun testUpdate() {
    Assert.assertEquals(0, providerUnderTest.update(Uri.parse("/"), null, null, null).toLong())
  }

  @Test
  fun testOpenFileWithNullUri() {
    try {
      val pfd = providerUnderTest.openFile(Uri.parse("/"), "r")
      Assert.fail("expected FileNotFoundException")
    } catch (e: FileNotFoundException) {}
  }

  @Test
  fun testOpenFileWithBadPath() {
    try {
      val pfd = providerUnderTest.openFile(Uri.parse("/"), "r")
      Assert.fail("expected FileNotFoundException")
    } catch (e: FileNotFoundException) {}
  }

  @Test
  fun testOpenFileWithoutCallIdAndAttachment() {
    try {
      val pfd = providerUnderTest.openFile(Uri.parse("/foo"), "r")
      Assert.fail("expected FileNotFoundException")
    } catch (e: FileNotFoundException) {}
  }

  @Test
  fun testOpenFileWithBadCallID() {
    try {
      val pfd = providerUnderTest.openFile(Uri.parse("/foo/bar"), "r")
      Assert.fail("expected FileNotFoundException")
    } catch (e: FileNotFoundException) {}
  }

  @Test
  fun testOpenFileWithUnknownUri() {
    try {
      val pfd = getTestAttachmentParcelFileDescriptor(UUID.randomUUID())
      Assert.assertNotNull(pfd)
      pfd?.close()
      Assert.fail("expected FileNotFoundException")
    } catch (e: FileNotFoundException) {}
  }

  @Test
  fun testOpenFileWithKnownUri() {
    try {
      MockAttachmentStore.addAttachment(CALL_ID, ATTACHMENT_NAME)
      val pfd = getTestAttachmentParcelFileDescriptor(CALL_ID)
      Assert.assertNotNull(pfd)
      pfd?.close()
    } catch (e: FileNotFoundException) {
      Assert.fail("do not expected FileNotFoundException")
    }
  }

  private fun getTestAttachmentParcelFileDescriptor(callId: UUID): ParcelFileDescriptor? {
    val attachment = MockAttachmentStore.openAttachment(callId, ATTACHMENT_NAME)
    whenever(openAttachment(callId, ATTACHMENT_NAME)).thenReturn(attachment)
    val uri = Uri.parse(FacebookContentProvider.getAttachmentUrl(APP_ID, callId, ATTACHMENT_NAME))
    return providerUnderTest.openFile(uri, "r")
  }

  object MockAttachmentStore {
    private val attachments: MutableList<Pair<UUID, String>> = ArrayList()
    private const val DUMMY_FILE_NAME = "dummyfile"
    fun addAttachment(callId: UUID, attachmentName: String) {
      attachments.add(Pair(callId, attachmentName))
    }

    fun openAttachment(callId: UUID, attachmentName: String): File {
      if (attachments.contains(Pair(callId, attachmentName))) {
        val cacheDir = RuntimeEnvironment.application.cacheDir
        val dummyFile = File(cacheDir, DUMMY_FILE_NAME)
        if (!dummyFile.exists()) {
          try {
            dummyFile.createNewFile()
          } catch (e: IOException) {}
        }
        return dummyFile
      }
      throw FileNotFoundException()
    }
  }

  companion object {
    private const val APP_ID = "12345"
    private val CALL_ID = UUID.randomUUID()
    private const val ATTACHMENT_NAME = "attachMe"
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook

import org.junit.Assert.assertEquals
import org.junit.Test

class FacebookExceptionTest {
  @Test
  fun `test facebook exception`() {
    var exception = FacebookException()
    assertEquals("", exception.toString())

    exception = FacebookException("exception")
    assertEquals("exception", exception.toString())

    exception = FacebookException("%s exception", "test")
    assertEquals("test exception", exception.toString())

    val throwable = Throwable("throwable exception")
    exception = FacebookException(throwable)
    assertEquals(throwable.toString(), exception.toString())
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook

import org.junit.Assert
import org.junit.Test
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever

class FacebookGraphResponseExceptionTest : FacebookPowerMockTestCase() {
  @Test
  fun `test exception to string`() {
    val mockResponse = mock<GraphResponse>()
    val mockRequestError = mock<FacebookRequestError>()
    whenever(mockRequestError.requestStatusCode).thenReturn(404)
    whenever(mockRequestError.errorCode).thenReturn(1)
    whenever(mockRequestError.errorMessage).thenReturn("Not found")
    whenever(mockRequestError.errorType).thenReturn("an error type")
    whenever(mockResponse.error).thenReturn(mockRequestError)
    val errorMessage = "an error message"
    val exception = FacebookGraphResponseException(mockResponse, errorMessage)

    Assert.assertEquals(
        "{FacebookGraphResponseException: an error message httpResponseCode: 404, facebookErrorCode: 1, facebookErrorType: an error type, message: Not found}",
        exception.toString())
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook

import org.assertj.core.api.Assertions.assertThat
import org.json.JSONArray
import org.json.JSONObject
import org.junit.Assert
import org.junit.Before
import org.junit.Test
import org.mockito.kotlin.whenever
import org.powermock.api.mockito.PowerMockito.mockStatic
import org.powermock.core.classloader.annotations.PrepareForTest

@PrepareForTest(FacebookSdk::class)
class FacebookRequestErrorTest : FacebookPowerMockTestCase() {
  @Before
  fun before() {
    mockStatic(FacebookSdk::class.java)
    whenever(FacebookSdk.getApplicationId()).thenReturn("123456789")
  }

  @Test
  fun testClientException() {
    val errorMsg = "some error happened"
    val error = FacebookRequestError(null, FacebookException(errorMsg))
    Assert.assertEquals(errorMsg, error.errorMessage)
    Assert.assertEquals(FacebookRequestError.Category.OTHER, error.category)
    Assert.assertEquals(FacebookRequestError.INVALID_ERROR_CODE, error.errorCode)
    Assert.assertEquals(FacebookRequestError.INVALID_HTTP_STATUS_CODE, error.requestStatusCode)
  }

  @Test
  fun testSingleRequestWithoutBody() {
    val withStatusCode = JSONObject()
    withStatusCode.put("code", 400)
    val error =
        FacebookRequestError.checkResponseAndCreateError(withStatusCode, withStatusCode, null)
    Assert.assertNotNull(error)
    Assert.assertEquals(400, error?.requestStatusCode)
    Assert.assertEquals(FacebookRequestError.Category.OTHER, error?.category)
  }

  @Test
  fun testSingleErrorWithBody() {
    val originalResponse = JSONObject(ERROR_SINGLE_RESPONSE)
    val withStatusCodeAndBody = JSONObject()
    withStatusCodeAndBody.put("code", 400)
    withStatusCodeAndBody.put("body", originalResponse)
    val error =
        FacebookRequestError.checkResponseAndCreateError(
            withStatusCodeAndBody, originalResponse, null)
    Assert.assertNotNull(error)
    Assert.assertEquals(400, error?.requestStatusCode)
    Assert.assertEquals("Unknown path components: /unknown", error?.errorMessage)
    Assert.assertEquals("OAuthException", error?.errorType)
    Assert.assertEquals(2_500, error?.errorCode)
    assertThat(error?.batchRequestResult is JSONObject).isTrue
    Assert.assertEquals(FacebookRequestError.Category.OTHER, error?.category)
  }

  @Test
  fun testBatchRequest() {
    val batchResponse = JSONArray(ERROR_BATCH_RESPONSE)
    Assert.assertEquals(2, batchResponse.length())
    val firstResponse = batchResponse[0] as JSONObject
    val error = FacebookRequestError.checkResponseAndCreateError(firstResponse, batchResponse, null)
    Assert.assertNotNull(error)
    Assert.assertEquals(400, error?.requestStatusCode)
    Assert.assertEquals(
        "An active access token must be used to query information about the current user.",
        error?.errorMessage)
    Assert.assertEquals("OAuthException", error?.errorType)
    Assert.assertEquals(2_500, error?.errorCode)
    assertThat(error?.batchRequestResult is JSONArray).isTrue
    Assert.assertEquals(FacebookRequestError.Category.OTHER, error?.category)
  }

  @Test
  fun testSingleThrottledError() {
    val originalResponse = JSONObject(ERROR_SINGLE_RESPONSE_THROTTLE)
    val withStatusCodeAndBody = JSONObject()
    withStatusCodeAndBody.put("code", 403)
    withStatusCodeAndBody.put("body", originalResponse)
    val error =
        FacebookRequestError.checkResponseAndCreateError(
            withStatusCodeAndBody, originalResponse, null)
    Assert.assertNotNull(error)
    Assert.assertEquals(403, error?.requestStatusCode)
    Assert.assertEquals("Application request limit reached", error?.errorMessage)
    Assert.assertNull(error?.errorType)
    Assert.assertEquals(4, error?.errorCode)
    assertThat(error?.batchRequestResult is JSONObject).isTrue
    Assert.assertEquals(FacebookRequestError.Category.TRANSIENT, error?.category)
  }

  @Test
  fun testSingleServerError() {
    val originalResponse = JSONObject(ERROR_SINGLE_RESPONSE_SERVER)
    val withStatusCodeAndBody = JSONObject()
    withStatusCodeAndBody.put("code", 500)
    withStatusCodeAndBody.put("body", originalResponse)
    val error =
        FacebookRequestError.checkResponseAndCreateError(
            withStatusCodeAndBody, originalResponse, null)
    Assert.assertNotNull(error)
    Assert.assertEquals(500, error?.requestStatusCode)
    Assert.assertEquals("Some Server Error", error?.errorMessage)
    Assert.assertNull(error?.errorType)
    Assert.assertEquals(2, error?.errorCode)
    assertThat(error?.batchRequestResult is JSONObject).isTrue
    Assert.assertEquals(FacebookRequestError.Category.TRANSIENT, error?.category)
  }

  @Test
  fun testSinglePermissionError() {
    val originalResponse = JSONObject(ERROR_SINGLE_RESPONSE_PERMISSION)
    val withStatusCodeAndBody = JSONObject()
    withStatusCodeAndBody.put("code", 400)
    withStatusCodeAndBody.put("body", originalResponse)
    val error =
        FacebookRequestError.checkResponseAndCreateError(
            withStatusCodeAndBody, originalResponse, null)
    Assert.assertNotNull(error)
    Assert.assertEquals(400, error?.requestStatusCode)
    Assert.assertEquals("(#200) Requires extended permission: publish_actions", error?.errorMessage)
    Assert.assertEquals("OAuthException", error?.errorType)
    Assert.assertEquals(200, error?.errorCode)
    Assert.assertEquals(FacebookRequestError.INVALID_ERROR_CODE, error?.subErrorCode)
    assertThat(error?.batchRequestResult is JSONObject).isTrue
    Assert.assertEquals(FacebookRequestError.Category.OTHER, error?.category)
  }

  @Test
  fun testSingleWebLoginError() {
    val originalResponse = JSONObject(ERROR_SINGLE_RESPONSE_WEB_LOGIN)
    val withStatusCodeAndBody = JSONObject()
    withStatusCodeAndBody.put("code", 400)
    withStatusCodeAndBody.put("body", originalResponse)
    val error =
        FacebookRequestError.checkResponseAndCreateError(
            withStatusCodeAndBody, originalResponse, null)
    Assert.assertNotNull(error)
    Assert.assertEquals(400, error?.requestStatusCode)
    Assert.assertEquals("User need to login", error?.errorMessage)
    Assert.assertEquals("OAuthException", error?.errorType)
    Assert.assertEquals(102, error?.errorCode)
    Assert.assertEquals(459, error?.subErrorCode)
    assertThat(error?.batchRequestResult is JSONObject).isTrue
    Assert.assertEquals(FacebookRequestError.Category.LOGIN_RECOVERABLE, error?.category)
  }

  @Test
  fun testSingleReloginError() {
    val originalResponse = JSONObject(ERROR_SINGLE_RESPONSE_RELOGIN)
    val withStatusCodeAndBody = JSONObject()
    withStatusCodeAndBody.put("code", 400)
    withStatusCodeAndBody.put("body", originalResponse)
    val error =
        FacebookRequestError.checkResponseAndCreateError(
            withStatusCodeAndBody, originalResponse, null)
    Assert.assertNotNull(error)
    Assert.assertEquals(400, error?.requestStatusCode)
    Assert.assertEquals("User need to relogin", error?.errorMessage)
    Assert.assertEquals("OAuthException", error?.errorType)
    Assert.assertEquals(102, error?.errorCode)
    Assert.assertEquals(FacebookRequestError.INVALID_ERROR_CODE, error?.subErrorCode)
    assertThat(error?.batchRequestResult is JSONObject).isTrue
    Assert.assertEquals(FacebookRequestError.Category.LOGIN_RECOVERABLE, error?.category)
  }

  @Test
  fun testSingleReloginDeletedAppError() {
    val originalResponse = JSONObject(ERROR_SINGLE_RESPONSE_RELOGIN_DELETED_APP)
    val withStatusCodeAndBody = JSONObject()
    withStatusCodeAndBody.put("code", 400)
    withStatusCodeAndBody.put("body", originalResponse)
    val error =
        FacebookRequestError.checkResponseAndCreateError(
            withStatusCodeAndBody, originalResponse, null)
    Assert.assertNotNull(error)
    Assert.assertEquals(400, error?.requestStatusCode)
    Assert.assertEquals("User need to relogin", error?.errorMessage)
    Assert.assertEquals("OAuthException", error?.errorType)
    Assert.assertEquals(190, error?.errorCode)
    Assert.assertEquals(458, error?.subErrorCode)
    assertThat(error?.batchRequestResult is JSONObject).isTrue
    Assert.assertEquals(FacebookRequestError.Category.LOGIN_RECOVERABLE, error?.category)
  }

  companion object {
    const val ERROR_SINGLE_RESPONSE =
        "{\n" +
            "  \"error\": {\n" +
            "    \"message\": \"Unknown path components: /unknown\",\n" +
            "    \"type\": \"OAuthException\",\n" +
            "    \"code\": 2500\n" +
            "  }\n" +
            "}"
    const val ERROR_BATCH_RESPONSE =
        "[\n" +
            "  {\n" +
            "    \"headers\": [\n" +
            "      {\n" +
            "        \"value\": \"*\",\n" +
            "        \"name\": \"Access-Control-Allow-Origin\"\n" +
            "      },\n" +
            "      {\n" +
            "        \"value\": \"no-store\",\n" +
            "        \"name\": \"Cache-Control\"\n" +
            "      },\n" +
            "      {\n" +
            "        \"value\": \"close\",\n" +
            "        \"name\": \"Connection\"\n" +
            "      },\n" +
            "      {\n" +
            "        \"value\": \"text\\/javascript; charset=UTF-8\",\n" +
            "        \"name\": \"Content-Type\"\n" +
            "      },\n" +
            "      {\n" +
            "        \"value\": \"Sat, 01 Jan 2000 00:00:00 GMT\",\n" +
            "        \"name\": \"Expires\"\n" +
            "      },\n" +
            "      {\n" +
            "        \"value\": \"no-cache\",\n" +
            "        \"name\": \"Pragma\"\n" +
            "      },\n" +
            "      {\n" +
            "        \"value\": \"OAuth \\\"Facebook Platform\\\" \\\"invalid_request\\\" \\\"An active access token must be used to query information about the current user.\\\"\",\n" +
            "        \"name\": \"WWW-Authenticate\"\n" +
            "      }\n" +
            "    ],\n" +
            "    \"body\": \"{\\\"error\\\":{\\\"message\\\":\\\"An active access token must be used to query information about the current user.\\\",\\\"type\\\":\\\"OAuthException\\\",\\\"code\\\":2500}}\",\n" +
            "    \"code\": 400\n" +
            "  },\n" +
            "  {\n" +
            "    \"headers\": [\n" +
            "      {\n" +
            "        \"value\": \"*\",\n" +
            "        \"name\": \"Access-Control-Allow-Origin\"\n" +
            "      },\n" +
            "      {\n" +
            "        \"value\": \"no-store\",\n" +
            "        \"name\": \"Cache-Control\"\n" +
            "      },\n" +
            "      {\n" +
            "        \"value\": \"close\",\n" +
            "        \"name\": \"Connection\"\n" +
            "      },\n" +
            "      {\n" +
            "        \"value\": \"text\\/javascript; charset=UTF-8\",\n" +
            "        \"name\": \"Content-Type\"\n" +
            "      },\n" +
            "      {\n" +
            "        \"value\": \"Sat, 01 Jan 2000 00:00:00 GMT\",\n" +
            "        \"name\": \"Expires\"\n" +
            "      },\n" +
            "      {\n" +
            "        \"value\": \"no-cache\",\n" +
            "        \"name\": \"Pragma\"\n" +
            "      },\n" +
            "      {\n" +
            "        \"value\": \"OAuth \\\"Facebook Platform\\\" \\\"invalid_request\\\" \\\"An active access token must be used to query information about the current user.\\\"\",\n" +
            "        \"name\": \"WWW-Authenticate\"\n" +
            "      }\n" +
            "    ],\n" +
            "    \"body\": \"{\\\"error\\\":{\\\"message\\\":\\\"An active access token must be used to query information about the current user.\\\",\\\"type\\\":\\\"OAuthException\\\",\\\"code\\\":2500}}\",\n" +
            "    \"code\": 400\n" +
            "  }\n" +
            "]"
    const val ERROR_SINGLE_RESPONSE_THROTTLE =
        "{\n" +
            "  \"error\": {\n" +
            "    \"message\": \"Application request limit reached\",\n" +
            "    \"code\": 4\n" +
            "  }\n" +
            "}"
    const val ERROR_SINGLE_RESPONSE_SERVER =
        "{\n" +
            "  \"error\": {\n" +
            "    \"message\": \"Some Server Error\",\n" +
            "    \"code\": 2\n" +
            "  }\n" +
            "}"
    const val ERROR_SINGLE_RESPONSE_PERMISSION =
        "{\n" +
            "  \"error\": {\n" +
            "    \"type\": \"OAuthException\",\n" +
            "    \"message\": \"(#200) Requires extended permission: publish_actions\",\n" +
            "    \"code\": 200\n" +
            "  }\n" +
            "}"
    const val ERROR_SINGLE_RESPONSE_WEB_LOGIN =
        "{\n" +
            "  \"error\": {\n" +
            "    \"message\": \"User need to login\",\n" +
            "    \"type\": \"OAuthException\",\n" +
            "    \"code\": 102,\n" +
            "    \"error_subcode\": 459\n" +
            "  }\n" +
            "}"
    const val ERROR_SINGLE_RESPONSE_RELOGIN =
        "{\n" +
            "  \"error\": {\n" +
            "    \"message\": \"User need to relogin\",\n" +
            "    \"type\": \"OAuthException\",\n" +
            "    \"code\": 102\n" +
            "  }\n" +
            "}"
    const val ERROR_SINGLE_RESPONSE_RELOGIN_DELETED_APP =
        "{\n" +
            "  \"error\": {\n" +
            "    \"message\": \"User need to relogin\",\n" +
            "    \"type\": \"OAuthException\",\n" +
            "    \"code\": 190,\n" +
            "    \"error_subcode\": 458\n" +
            "  }\n" +
            "}"
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook

import android.content.Context
import android.content.pm.ApplicationInfo
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.content.pm.Signature
import android.os.Bundle
import android.os.ConditionVariable
import android.util.Base64
import androidx.test.core.app.ApplicationProvider
import com.facebook.internal.FetchedAppSettingsManager
import com.facebook.internal.ServerProtocol.getGraphUrlBase
import com.facebook.internal.Utility
import java.util.concurrent.Executor
import java.util.concurrent.atomic.AtomicBoolean
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.json.JSONArray
import org.json.JSONObject
import org.junit.Before
import org.junit.Test
import org.mockito.kotlin.any
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever
import org.powermock.api.support.membermodification.MemberMatcher
import org.powermock.api.support.membermodification.MemberModifier
import org.powermock.core.classloader.annotations.PrepareForTest
import org.powermock.reflect.Whitebox
import org.robolectric.RuntimeEnvironment

@PrepareForTest(FetchedAppSettingsManager::class, Utility::class, UserSettingsManager::class)
class FacebookSdkTest : FacebookPowerMockTestCase() {
  @Before
  fun before() {
    val mockPreference = MockSharedPreference()
    Whitebox.setInternalState(UserSettingsManager::class.java, "userSettingPref", mockPreference)
    Whitebox.setInternalState(UserSettingsManager::class.java, "isInitialized", AtomicBoolean(true))
    Whitebox.setInternalState(FacebookSdk::class.java, "callbackRequestCodeOffset", 0xface)
    Whitebox.setInternalState(FacebookSdk::class.java, "sdkInitialized", AtomicBoolean(false))
    MemberModifier.stub<Any?>(
            MemberMatcher.method(FetchedAppSettingsManager::class.java, "loadAppSettingsAsync"))
        .toReturn(null)
    FacebookSdk.setAutoLogAppEventsEnabled(false)
  }

  @Test
  fun testSetExecutor() {
    val condition = ConditionVariable()
    val runnable = Runnable {}
    val executor = Executor { command ->
      assertThat(command).isSameAs(runnable)
      command.run()
      condition.open()
    }
    val original = FacebookSdk.getExecutor()
    try {
      FacebookSdk.setExecutor(executor)
      FacebookSdk.getExecutor().execute(runnable)
      val success = condition.block(5_000)
      assertThat(success).isTrue
    } finally {
      FacebookSdk.setExecutor(original)
    }
  }

  @Test
  fun testFacebookDomain() {
    Whitebox.setInternalState(FacebookSdk::class.java, "sdkInitialized", AtomicBoolean(true))
    Whitebox.setInternalState(
        FacebookSdk::class.java,
        "applicationContext",
        ApplicationProvider.getApplicationContext<Context>())
    FacebookSdk.setFacebookDomain("beta.facebook.com")
    val graphUrlBase = getGraphUrlBase()
    assertThat(graphUrlBase).isEqualTo("https://graph.beta.facebook.com")
    FacebookSdk.setFacebookDomain("facebook.com")
  }

  @Test
  fun testLoadDefaults() {
    // Set to null since the value might have been set by another test
    Whitebox.setInternalState(FacebookSdk::class.java, "applicationId", null as String?)
    Whitebox.setInternalState(FacebookSdk::class.java, "sdkInitialized", AtomicBoolean(true))
    FacebookSdk.loadDefaultsFromMetadata(mockContextWithAppIdAndClientToken())
    assertThat(FacebookSdk.getApplicationId()).isEqualTo(TEST_APPLICATION_ID)
    assertThat(FacebookSdk.getClientToken()).isEqualTo(TEST_CLIENT_TOKEN)
  }

  @Test
  fun testLoadDefaultsDoesNotOverwrite() {
    Whitebox.setInternalState(FacebookSdk::class.java, "sdkInitialized", AtomicBoolean(true))
    FacebookSdk.setApplicationId("hello")
    FacebookSdk.setClientToken("world")
    FacebookSdk.loadDefaultsFromMetadata(mockContextWithAppIdAndClientToken())
    assertThat(FacebookSdk.getAutoLogAppEventsEnabled()).isFalse
    assertThat(FacebookSdk.getApplicationId()).isEqualTo("hello")
    assertThat(FacebookSdk.getClientToken()).isEqualTo("world")
  }

  @Test
  fun testRequestCodeOffsetAfterInit() {
    FacebookSdk.setApplicationId("123456789")
    FacebookSdk.setClientToken(TEST_CLIENT_TOKEN)
    FacebookSdk.sdkInitialize(RuntimeEnvironment.application)
    assertThatThrownBy { FacebookSdk.sdkInitialize(RuntimeEnvironment.application, 1_000) }
        .isInstanceOf(FacebookException::class.java)
        .hasMessage(FacebookSdk.CALLBACK_OFFSET_CHANGED_AFTER_INIT)
  }

  @Test
  fun testRequestCodeOffsetNegative() {
    FacebookSdk.setApplicationId("123456789")
    FacebookSdk.setClientToken(TEST_CLIENT_TOKEN)
    assertThatThrownBy {
          // last bit set, so negative
          FacebookSdk.sdkInitialize(RuntimeEnvironment.application, -0x5314ff4)
        }
        .isInstanceOf(FacebookException::class.java)
        .hasMessage(FacebookSdk.CALLBACK_OFFSET_NEGATIVE)
  }

  @Test
  fun testRequestCodeOffset() {
    FacebookSdk.setApplicationId("123456789")
    FacebookSdk.setClientToken(TEST_CLIENT_TOKEN)
    FacebookSdk.sdkInitialize(RuntimeEnvironment.application, 1_000)
    assertThat(FacebookSdk.getCallbackRequestCodeOffset()).isEqualTo(1_000)
  }

  @Test
  fun testRequestCodeRange() {
    FacebookSdk.setApplicationId("123456789")
    FacebookSdk.setClientToken(TEST_CLIENT_TOKEN)
    FacebookSdk.sdkInitialize(RuntimeEnvironment.application, 1_000)
    assertThat(FacebookSdk.isFacebookRequestCode(1_000)).isTrue
    assertThat(FacebookSdk.isFacebookRequestCode(1_099)).isTrue
    assertThat(FacebookSdk.isFacebookRequestCode(999)).isFalse
    assertThat(FacebookSdk.isFacebookRequestCode(1_100)).isFalse
    assertThat(FacebookSdk.isFacebookRequestCode(0)).isFalse
  }

  @Test
  fun testFullyInitialize() {
    FacebookSdk.setApplicationId("123456789")
    FacebookSdk.setClientToken(TEST_CLIENT_TOKEN)
    MemberModifier.stub<Any>(MemberMatcher.method(FacebookSdk::class.java, "getAutoInitEnabled"))
        .toReturn(true)
    FacebookSdk.sdkInitialize(RuntimeEnvironment.application)
    assertThat(FacebookSdk.isFullyInitialized()).isTrue
  }

  @Test
  fun testNotFullyInitialize() {
    FacebookSdk.setApplicationId("123456789")
    FacebookSdk.setClientToken(TEST_CLIENT_TOKEN)
    val field = FacebookSdk::class.java.getDeclaredField("isFullyInitialized")
    field.isAccessible = true
    field[null] = false
    UserSettingsManager.setAutoInitEnabled(false)
    FacebookSdk.sdkInitialize(RuntimeEnvironment.application)
    assertThat(FacebookSdk.isFullyInitialized()).isFalse
  }

  @Test
  fun `test set data processing options will update shared preferences`() {
    val expectedDataProcessingOptions = arrayOf("option1", "option2")
    val expectedDataProcessingOptionsJSONObject = JSONObject()
    expectedDataProcessingOptionsJSONObject.put(
        FacebookSdk.DATA_PROCESSION_OPTIONS, JSONArray(expectedDataProcessingOptions.toList()))
    expectedDataProcessingOptionsJSONObject.put(FacebookSdk.DATA_PROCESSION_OPTIONS_COUNTRY, 1)
    expectedDataProcessingOptionsJSONObject.put(FacebookSdk.DATA_PROCESSION_OPTIONS_STATE, 10)
    val applicationContext = mock<Context>()
    val mockSharedPreference = MockSharedPreference()
    whenever(applicationContext.getSharedPreferences(any<String>(), any<Int>()))
        .thenReturn(mockSharedPreference)
    FacebookSdk.setApplicationId(TEST_APPLICATION_ID)
    Whitebox.setInternalState(FacebookSdk::class.java, "applicationContext", applicationContext)

    FacebookSdk.setDataProcessingOptions(expectedDataProcessingOptions, 1, 10)

    assertThat(mockSharedPreference.getString(FacebookSdk.DATA_PROCESSION_OPTIONS, ""))
        .isEqualTo(expectedDataProcessingOptionsJSONObject.toString())
  }

  @Test
  fun `test set data processing options to null`() {
    val expectedDataProcessingOptionsJSONObject = JSONObject()
    expectedDataProcessingOptionsJSONObject.put(FacebookSdk.DATA_PROCESSION_OPTIONS, JSONArray())
    expectedDataProcessingOptionsJSONObject.put(FacebookSdk.DATA_PROCESSION_OPTIONS_COUNTRY, 0)
    expectedDataProcessingOptionsJSONObject.put(FacebookSdk.DATA_PROCESSION_OPTIONS_STATE, 0)
    val applicationContext = mock<Context>()
    val mockSharedPreference = MockSharedPreference()
    whenever(applicationContext.getSharedPreferences(any<String>(), any<Int>()))
        .thenReturn(mockSharedPreference)
    FacebookSdk.setApplicationId(TEST_APPLICATION_ID)
    Whitebox.setInternalState(FacebookSdk::class.java, "applicationContext", applicationContext)

    FacebookSdk.setDataProcessingOptions(null)

    assertThat(mockSharedPreference.getString(FacebookSdk.DATA_PROCESSION_OPTIONS, ""))
        .isEqualTo(expectedDataProcessingOptionsJSONObject.toString())
  }

  @Test
  fun `test get signature return a valid base64 result`() {
    Whitebox.setInternalState(FacebookSdk::class.java, "sdkInitialized", AtomicBoolean(true))
    val mockContext = mock<Context>()
    val mockPackageManager = mock<PackageManager>()
    val mockPackageInfo = mock<PackageInfo>()
    val mockSignature = mock<Signature>()
    whenever(mockContext.packageManager).thenReturn(mockPackageManager)
    whenever(mockContext.packageName).thenReturn("com.facebook.test")
    whenever(mockPackageManager.getPackageInfo(any<String>(), any())).thenReturn(mockPackageInfo)
    whenever(mockSignature.toByteArray()).thenReturn(byteArrayOf(1, 2, 3, 4))
    mockPackageInfo.signatures = arrayOf(mockSignature)

    val obtainedSignature = FacebookSdk.getApplicationSignature(mockContext)

    Base64.decode(obtainedSignature, Base64.URL_SAFE or Base64.NO_PADDING)
  }

  @Test
  fun `test get signature return null if package info is not available`() {
    Whitebox.setInternalState(FacebookSdk::class.java, "sdkInitialized", AtomicBoolean(true))
    val mockContext = mock<Context>()
    val mockPackageManager = mock<PackageManager>()
    whenever(mockContext.packageManager).thenReturn(mockPackageManager)
    whenever(mockContext.packageName).thenReturn("com.facebook.test")
    whenever(mockPackageManager.getPackageInfo(any<String>(), any()))
        .thenThrow(PackageManager.NameNotFoundException())

    assertThat(FacebookSdk.getApplicationSignature(mockContext)).isNull()
  }

  @Test(expected = FacebookException::class)
  fun `test sdk initialization will throw an exception if client token is null`() {
    Whitebox.setInternalState(FacebookSdk::class.java, "sdkInitialized", AtomicBoolean(false))
    FacebookSdk.setApplicationId(TEST_APPLICATION_ID)
    FacebookSdk.setClientToken(null)
    FacebookSdk.sdkInitialize(RuntimeEnvironment.application)
  }

  companion object {
    private const val TEST_APPLICATION_ID = "1234"
    private const val TEST_CLIENT_TOKEN = "abcd"

    private fun mockContextWithAppIdAndClientToken(): Context {
      val bundle = Bundle()
      bundle.putString(FacebookSdk.APPLICATION_ID_PROPERTY, TEST_APPLICATION_ID)
      bundle.putString(FacebookSdk.CLIENT_TOKEN_PROPERTY, TEST_CLIENT_TOKEN)
      val applicationInfo = mock<ApplicationInfo>()
      applicationInfo.metaData = bundle
      val packageManager = mock<PackageManager>()
      whenever(packageManager.getApplicationInfo("packageName", PackageManager.GET_META_DATA))
          .thenReturn(applicationInfo)
      val context = mock<Context>()
      whenever(context.packageName).thenReturn("packageName")
      whenever(context.packageManager).thenReturn(packageManager)
      return context
    }
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook

import androidx.localbroadcastmanager.content.LocalBroadcastManager
import androidx.test.core.app.ApplicationProvider
import com.facebook.AccessToken.Companion.getCurrentAccessToken
import com.facebook.AccessToken.Companion.setCurrentAccessToken
import com.facebook.internal.FacebookRequestErrorClassification
import com.facebook.internal.FetchedAppGateKeepersManager
import com.facebook.internal.Utility
import com.facebook.util.common.mockLocalBroadcastManager
import java.net.HttpURLConnection
import org.json.JSONObject
import org.junit.Assert
import org.junit.Before
import org.junit.Test
import org.mockito.kotlin.any
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever
import org.powermock.api.mockito.PowerMockito
import org.powermock.api.support.membermodification.MemberMatcher
import org.powermock.api.support.membermodification.MemberModifier
import org.powermock.core.classloader.annotations.PrepareForTest
import org.powermock.reflect.Whitebox

@PrepareForTest(
    AccessToken::class,
    AccessTokenCache::class,
    FacebookSdk::class,
    FetchedAppGateKeepersManager::class,
    GraphRequest::class,
    Utility::class,
    LocalBroadcastManager::class)
class GraphErrorTest : FacebookPowerMockTestCase() {
  @Before
  fun before() {
    MemberModifier.suppress(MemberMatcher.method(Utility::class.java, "clearFacebookCookies"))
    PowerMockito.mockStatic(FacebookSdk::class.java)
    whenever(FacebookSdk.isInitialized()).thenReturn(true)
    whenever(FacebookSdk.getApplicationContext())
        .thenReturn(ApplicationProvider.getApplicationContext())

    MemberModifier.stub<Any?>(MemberMatcher.method(AccessTokenCache::class.java, "save"))
        .toReturn(null)
    PowerMockito.mockStatic(FetchedAppGateKeepersManager::class.java)
    val mockLocalBroadcastManager = mockLocalBroadcastManager(FacebookSdk.getApplicationContext())
    PowerMockito.mockStatic(LocalBroadcastManager::class.java)
    PowerMockito.`when`(LocalBroadcastManager.getInstance(any()))
        .thenReturn(mockLocalBroadcastManager)

    val accessTokenManager = AccessTokenManager(mockLocalBroadcastManager, AccessTokenCache())
    val mockAccessTokenManagerCompanion = mock<AccessTokenManager.Companion>()
    whenever(mockAccessTokenManagerCompanion.getInstance()).thenReturn(accessTokenManager)
    Whitebox.setInternalState(
        AccessTokenManager::class.java, "Companion", mockAccessTokenManagerCompanion)
  }

  @Test
  fun testAccessTokenNotResetOnTokenExpirationError() {
    val accessToken = PowerMockito.mock(AccessToken::class.java)
    whenever(accessToken.token).thenReturn("token")
    whenever(accessToken.userId).thenReturn("user_id")
    whenever(accessToken.applicationId).thenReturn("application_id")
    MemberModifier.suppress(
        MemberMatcher.method(Utility::class.java, "isNullOrEmpty", String::class.java))
    setCurrentAccessToken(accessToken)
    val errorBody = JSONObject()
    errorBody.put("message", "Invalid OAuth access token.")
    errorBody.put("type", "OAuthException")
    errorBody.put("code", FacebookRequestErrorClassification.EC_INVALID_TOKEN)
    errorBody.put("error_subcode", FacebookRequestErrorClassification.ESC_APP_INACTIVE)
    val error = JSONObject()
    error.put("error", errorBody)
    val errorString = error.toString()
    val connection = PowerMockito.mock(HttpURLConnection::class.java)
    whenever(connection.responseCode).thenReturn(400)
    val request = PowerMockito.mock(GraphRequest::class.java)
    whenever(request.accessToken).thenReturn(accessToken)
    val batch = GraphRequestBatch(request)
    Assert.assertNotNull(getCurrentAccessToken())
    GraphResponse.createResponsesFromString(errorString, connection, batch)
    Assert.assertNotNull(getCurrentAccessToken())
  }

  @Test
  fun testAccessTokenResetOnTokenInstallError() {
    val accessToken = PowerMockito.mock(AccessToken::class.java)
    setCurrentAccessToken(accessToken)
    val errorBody = JSONObject()
    errorBody.put("message", "User has not installed the application.")
    errorBody.put("type", "OAuthException")
    errorBody.put("code", FacebookRequestErrorClassification.EC_INVALID_TOKEN)
    val error = JSONObject()
    error.put("error", errorBody)
    val errorString = error.toString()
    val connection = PowerMockito.mock(HttpURLConnection::class.java)
    whenever(connection.responseCode).thenReturn(400)
    val request = PowerMockito.mock(GraphRequest::class.java)
    whenever(request.accessToken).thenReturn(accessToken)
    val batch = GraphRequestBatch(request)
    Assert.assertNotNull(getCurrentAccessToken())
    GraphResponse.createResponsesFromString(errorString, connection, batch)
    Assert.assertNull(getCurrentAccessToken())
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook

import java.net.HttpURLConnection
import org.assertj.core.api.Assertions.assertThat
import org.junit.Test
import org.mockito.kotlin.mock
import org.mockito.kotlin.verify
import org.powermock.reflect.Whitebox

class GraphRequestAsyncTaskTest : FacebookPowerMockTestCase() {
  @Test
  fun `test creating async tasks with requests`() {
    val r1 = mock<GraphRequest>()
    val r2 = mock<GraphRequest>()
    val r3 = mock<GraphRequest>()
    val task = GraphRequestAsyncTask(r1, r2, r3)
    assertThat(task.requests[0]).isEqualTo(r1)
    assertThat(task.requests[1]).isEqualTo(r2)
    assertThat(task.requests[2]).isEqualTo(r3)
  }

  @Test
  fun `test creating async task with request batch and executing`() {
    val mockBatch = mock<GraphRequestBatch>()
    val task = GraphRequestAsyncTask(mockBatch)
    task.doInBackground()
    verify(mockBatch).executeAndWait()
  }

  @Test
  fun `test onPreExecute set handler for the requests`() {
    val task = GraphRequestAsyncTask(mock<GraphRequest>())
    task.onPreExecute()
    assertThat(task.requests.callbackHandler).isNotNull
  }

  @Test
  fun `test executing requests with existing connection`() {
    val mockGraphRequestCompanion = mock<GraphRequest.Companion>()
    Whitebox.setInternalState(GraphRequest::class.java, "Companion", mockGraphRequestCompanion)
    val connection = mock<HttpURLConnection>()
    val task = GraphRequestAsyncTask(connection, mock<GraphRequest>())
    task.doInBackground()
    verify(mockGraphRequestCompanion).executeConnectionAndWait(connection, task.requests)
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook

import java.lang.IllegalArgumentException
import org.assertj.core.api.Assertions.assertThat
import org.junit.Before
import org.junit.Test
import org.mockito.kotlin.mock
import org.mockito.kotlin.verify
import org.powermock.reflect.Whitebox

class GraphRequestBatchTest : FacebookPowerMockTestCase() {
  private lateinit var batch: GraphRequestBatch
  private lateinit var mockGraphRequestCompanion: GraphRequest.Companion
  @Before
  override fun setup() {
    super.setup()
    mockGraphRequestCompanion = mock()
    Whitebox.setInternalState(GraphRequest::class.java, "Companion", mockGraphRequestCompanion)
    batch = GraphRequestBatch()
  }

  @Test(expected = IllegalArgumentException::class)
  fun `test set timeout with invalid value`() {
    batch.timeout = -1
  }

  @Test
  fun `test set timeout with valid value`() {
    batch.timeout = 10
    assertThat(batch.timeout).isEqualTo(10)
  }

  @Test
  fun `test adding duplicate callbacks`() {
    val callback = mock<GraphRequestBatch.Callback>()
    batch.addCallback(callback)
    batch.addCallback(callback)
    assertThat(batch.callbacks.size).isEqualTo(1)
  }

  @Test
  fun `test remove callbacks`() {
    val callback = mock<GraphRequestBatch.Callback>()
    batch.addCallback(callback)
    batch.removeCallback(callback)

    assertThat(batch.callbacks.size).isEqualTo(0)
  }

  @Test
  fun `test constructor with requests`() {
    val request1 = mock<GraphRequest>()
    val request2 = mock<GraphRequest>()
    batch = GraphRequestBatch(request1, request2)
    assertThat(batch.requests[0]).isEqualTo(request1)
    assertThat(batch.requests[1]).isEqualTo(request2)
  }

  @Test
  fun `test copy constructor`() {
    val request1 = mock<GraphRequest>()
    val request2 = mock<GraphRequest>()
    val batch1 = GraphRequestBatch(request1, request2)
    val callback1 = mock<GraphRequestBatch.Callback>()
    batch1.addCallback(callback1)
    val batch2 = GraphRequestBatch(batch1)

    assertThat(batch2[0]).isEqualTo(request1)
    assertThat(batch2[1]).isEqualTo(request2)
    assertThat(batch2.callbacks[0]).isEqualTo(callback1)

    // batch 1 won't be changed after batch2 is changed
    batch2.addCallback(mock())
    batch2.add(mock())
    assertThat(batch1.size).isEqualTo(2)
    assertThat(batch1.callbacks.size).isEqualTo(1)
  }

  @Test
  fun `test execute and wait calls GraphRequest`() {
    batch.executeAndWait()
    verify(mockGraphRequestCompanion).executeBatchAndWait(batch)
  }

  @Test
  fun `test execute async calls GraphRequest`() {
    batch.executeAsync()
    verify(mockGraphRequestCompanion).executeBatchAsync(batch)
  }

  @Test
  fun `test GraphRequest from the batch`() {
    val request1 = mock<GraphRequest>()
    val request2 = mock<GraphRequest>()
    batch = GraphRequestBatch(request1, request2)
    val popRequest = batch.removeAt(0)
    assertThat(popRequest).isEqualTo(request1)
    assertThat(batch.remove(request2)).isTrue
    assertThat(batch.remove(request1)).isFalse
  }

  @Test
  fun `test clear`() {
    val request1 = mock<GraphRequest>()
    val request2 = mock<GraphRequest>()
    batch = GraphRequestBatch(request1, request2)
    batch.clear()
    assertThat(batch.size).isEqualTo(0)
  }

  @Test
  fun `test add to specific position`() {
    val request1 = mock<GraphRequest>()
    val request2 = mock<GraphRequest>()
    batch = GraphRequestBatch(request1)
    batch.add(0, request2)
    assertThat(batch[0]).isEqualTo(request2)
    assertThat(batch[1]).isEqualTo(request1)
  }
}