/** * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. * * You are hereby granted a non-exclusive, worldwide, royalty-free license to use, * copy, modify, and distribute this software in source code or binary form for use * in connection with the web services and APIs provided by Facebook. * * As with any software that integrates with the Facebook platform, your use of * this software is subject to the Facebook Developer Principles and Policies * [http://developers.facebook.com/policy/]. This copyright notice shall be * included in all copies or substantial portions of the software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package com.facebook.login; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; import com.facebook.AccessToken; import com.facebook.FacebookActivity; import com.facebook.FacebookException; import com.facebook.FacebookOperationCanceledException; import com.facebook.FacebookSdk; import com.facebook.TestUtils; import com.facebook.internal.FetchedAppSettings; import com.facebook.internal.FetchedAppSettingsManager; import com.facebook.internal.Utility; import com.facebook.internal.Validate; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.powermock.core.classloader.annotations.PrepareForTest; import java.util.ArrayList; import java.util.Date; import java.util.List; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.powermock.api.mockito.PowerMockito.mockStatic; import static org.powermock.api.mockito.PowerMockito.when; @PrepareForTest({ LoginClient.class, Validate.class, Utility.class, FacebookSdk.class, AccessToken.class, FetchedAppSettings.class, FetchedAppSettingsManager.class }) public class CustomTabLoginMethodHandlerTest extends LoginHandlerTestCase { private final static String SIGNED_REQUEST_STR = "ggarbage.eyJhbGdvcml0aG0iOiJITUFDSEEyNTYiLCJ" + "jb2RlIjoid2h5bm90IiwiaXNzdWVkX2F0IjoxNDIyNTAyMDkyLCJ1c2VyX2lkIjoiMTIzIn0"; private final static String CHROME_PACKAGE = "com.android.chrome"; private final static String DEV_PACKAGE = "com.chrome.dev"; private final static String BETA_PACKAGE = "com.chrome.beta"; private CustomTabLoginMethodHandler handler; private LoginClient.Request request; @Before public void setUp() { handler = new CustomTabLoginMethodHandler(mockLoginClient); request = createRequest(); } @Test public void testCustomTabHandlesSuccess() { final Bundle bundle = new Bundle(); bundle.putString("access_token", ACCESS_TOKEN); bundle.putString("expires_in", String.format("%d", EXPIRES_IN_DELTA)); bundle.putString("code", "Something else"); bundle.putString("signed_request", SIGNED_REQUEST_STR); handler.onComplete(request, bundle, null); final ArgumentCaptor<LoginClient.Result> resultArgumentCaptor = ArgumentCaptor.forClass(LoginClient.Result.class); verify(mockLoginClient, times(1)).completeAndValidate(resultArgumentCaptor.capture()); final LoginClient.Result result = resultArgumentCaptor.getValue(); assertNotNull(result); assertEquals(LoginClient.Result.Code.SUCCESS, result.code); final AccessToken token = result.token; assertNotNull(token); assertEquals(ACCESS_TOKEN, token.getToken()); assertDateDiffersWithinDelta(new Date(), token.getExpires(), EXPIRES_IN_DELTA * 1000, 1000); TestUtils.assertSamePermissions(PERMISSIONS, token.getPermissions()); } @Test public void testCustomTabHandlesCancel() { handler.onComplete(request, null, new FacebookOperationCanceledException()); final ArgumentCaptor<LoginClient.Result> resultArgumentCaptor = ArgumentCaptor.forClass(LoginClient.Result.class); verify(mockLoginClient, times(1)).completeAndValidate(resultArgumentCaptor.capture()); final LoginClient.Result result = resultArgumentCaptor.getValue(); assertNotNull(result); assertEquals(LoginClient.Result.Code.CANCEL, result.code); assertNull(result.token); assertNotNull(result.errorMessage); } @Test public void testCustomTabHandlesError() { handler.onComplete(request, null, new FacebookException(ERROR_MESSAGE)); final ArgumentCaptor<LoginClient.Result> resultArgumentCaptor = ArgumentCaptor.forClass(LoginClient.Result.class); verify(mockLoginClient, times(1)).completeAndValidate(resultArgumentCaptor.capture()); final LoginClient.Result result = resultArgumentCaptor.getValue(); assertNotNull(result); assertEquals(LoginClient.Result.Code.ERROR, result.code); assertNull(result.token); assertNotNull(result.errorMessage); assertEquals(ERROR_MESSAGE, result.errorMessage); } @Test public void testTryAuthorizeNeedsRedirectActivity() { mockTryAuthorize(); mockChromeCustomTabsSupported(true, CHROME_PACKAGE); mockCustomTabsAllowed(true); mockCustomTabRedirectActivity(true); assertTrue(handler.tryAuthorize(request)); mockCustomTabsAllowed(false); assertFalse(handler.tryAuthorize(request)); } @Test public void testTryAuthorizeWithChromePackage() { mockTryAuthorize(); mockCustomTabsAllowed(true); mockCustomTabRedirectActivity(true); mockChromeCustomTabsSupported(true, CHROME_PACKAGE); assertTrue(handler.tryAuthorize(request)); } @Test public void testTryAuthorizeWithChromeBetaPackage() { mockTryAuthorize(); mockCustomTabsAllowed(true); mockCustomTabRedirectActivity(true); mockChromeCustomTabsSupported(true, BETA_PACKAGE); assertTrue(handler.tryAuthorize(request)); } @Test public void testTryAuthorizeWithChromeDevPackage() { mockTryAuthorize(); mockCustomTabsAllowed(true); mockCustomTabRedirectActivity(true); mockChromeCustomTabsSupported(true, DEV_PACKAGE); assertTrue(handler.tryAuthorize(request)); } @Test public void testTryAuthorizeWithoutChromePackage() { mockTryAuthorize(); mockCustomTabsAllowed(true); mockCustomTabRedirectActivity(true); mockChromeCustomTabsSupported(true, "not.chrome.package"); assertFalse(handler.tryAuthorize(request)); } private void mockTryAuthorize() { mockStatic(FacebookSdk.class); when(FacebookSdk.isInitialized()).thenReturn(true); mockStatic(AccessToken.class); when(AccessToken.getCurrentAccessToken()).thenReturn(null); Fragment fragment = mock(LoginFragment.class); when(mockLoginClient.getFragment()).thenReturn(fragment); } private void mockChromeCustomTabsSupported(final boolean supported, final String packageName) { final List<ResolveInfo> resolveInfos = new ArrayList<>(); ResolveInfo resolveInfo = new ResolveInfo(); ServiceInfo serviceInfo = new ServiceInfo(); serviceInfo.packageName = packageName; resolveInfo.serviceInfo = serviceInfo; if (supported) { resolveInfos.add(resolveInfo); } final PackageManager packageManager = mock(PackageManager.class); when(packageManager.queryIntentServices(any(Intent.class), anyInt())) .thenReturn(resolveInfos); activity = mock(FacebookActivity.class); when(mockLoginClient.getActivity()).thenReturn(activity); when(activity.getPackageManager()).thenReturn(packageManager); } private void mockCustomTabRedirectActivity(final boolean hasActivity) { mockStatic(Validate.class); when(Validate.hasCustomTabRedirectActivity(any(Context.class))).thenReturn(hasActivity); } private void mockCustomTabsAllowed(final boolean allowed) { final FetchedAppSettings settings = mock(FetchedAppSettings.class); when(settings.getCustomTabsEnabled()).thenReturn(allowed); mockStatic(FetchedAppSettingsManager.class); when(FetchedAppSettingsManager.getAppSettingsWithoutQuery(anyString())).thenReturn(settings); } }