/** * 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.messenger; import android.app.Activity; import android.content.ContentResolver; import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.database.MatrixCursor; import android.net.Uri; import android.os.Bundle; import com.facebook.FacebookSdk; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.robolectric.Robolectric; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; import java.util.Arrays; import static org.junit.Assert.*; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.*; /** * Tests for {@link com.facebook.messenger.MessengerUtils} */ @RunWith(RobolectricTestRunner.class) @Config(emulateSdk = 18, manifest = Config.NONE) public class MessengerUtilsTest { private Activity mMockActivity; private PackageManager mMockPackageManager; private ContentResolver mMockContentResolver; @Before public void setup() { mMockActivity = mock(Activity.class); mMockPackageManager = mock(PackageManager.class); mMockContentResolver = mock(ContentResolver.class); when(mMockActivity.getPackageManager()).thenReturn(mMockPackageManager); when(mMockActivity.getContentResolver()).thenReturn(mMockContentResolver); FacebookSdk.sdkInitialize(Robolectric.application); FacebookSdk.setApplicationId("200"); } @Test public void testMessengerIsInstalled() throws Exception { setupPackageManagerForMessenger(true); assertTrue(MessengerUtils.hasMessengerInstalled(mMockActivity)); } @Test public void testMessengerNotInstalled() throws Exception { setupPackageManagerForMessenger(false); assertFalse(MessengerUtils.hasMessengerInstalled(mMockActivity)); } @Test public void testShareToMessengerWith20150314Protocol() throws Exception { setupPackageManagerForMessenger(true); setupContentResolverForProtocolVersions(20150314); Uri uri = Uri.parse("file:///foo.jpeg"); Uri externalUri = Uri.parse("http://example.com/foo.jpeg"); ShareToMessengerParams params = ShareToMessengerParams .newBuilder(uri, "image/jpeg") .setMetaData("{}") .setExternalUri(externalUri) .build(); MessengerUtils.shareToMessenger(mMockActivity, 1, params); // Expect it to have launched messenger with the right intent. ArgumentCaptor<Intent> intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class); verify(mMockActivity).startActivityForResult( intentArgumentCaptor.capture(), eq(1)); Intent intent = intentArgumentCaptor.getValue(); assertEquals(Intent.ACTION_SEND, intent.getAction()); assertEquals(Intent.FLAG_GRANT_READ_URI_PERMISSION, intent.getFlags()); assertEquals("com.facebook.orca", intent.getPackage()); assertEquals(uri, intent.getParcelableExtra(Intent.EXTRA_STREAM)); assertEquals("image/jpeg", intent.getType()); assertEquals("200", intent.getStringExtra("com.facebook.orca.extra.APPLICATION_ID")); assertEquals(20150314, intent.getIntExtra("com.facebook.orca.extra.PROTOCOL_VERSION", -1)); assertEquals("{}", intent.getStringExtra("com.facebook.orca.extra.METADATA")); assertEquals(externalUri, intent.getParcelableExtra("com.facebook.orca.extra.EXTERNAL_URI")); } @Test public void testShareToMessengerWithNoProtocol() throws Exception { setupPackageManagerForMessenger(true); setupContentResolverForProtocolVersions(/* empty */); Uri uri = Uri.parse("file:///foo.jpeg"); Uri externalUri = Uri.parse("http://example.com/foo.jpeg"); ShareToMessengerParams params = ShareToMessengerParams .newBuilder(uri, "image/jpeg") .setMetaData("{}") .setExternalUri(externalUri) .build(); MessengerUtils.shareToMessenger(mMockActivity, 1, params); // Expect it to have gone to the play store. ArgumentCaptor<Intent> intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class); verify(mMockActivity).startActivity(intentArgumentCaptor.capture()); Intent intent = intentArgumentCaptor.getValue(); assertEquals(Intent.ACTION_VIEW, intent.getAction()); assertEquals(Uri.parse("market://details?id=com.facebook.orca"), intent.getData()); } @Test public void testGetMessengerThreadParamsForIntentWith20150314Protocol() throws Exception { // Simulate an intent that Messenger would send. Intent intent = new Intent(); intent.addCategory("com.facebook.orca.category.PLATFORM_THREAD_20150314"); Bundle extrasBundle = setupIntentWithAppLinkExtrasBundle(intent); extrasBundle.putString("com.facebook.orca.extra.THREAD_TOKEN", "thread_token"); extrasBundle.putString("com.facebook.orca.extra.METADATA", "{}"); extrasBundle.putString("com.facebook.orca.extra.PARTICIPANTS", "100,400,500"); extrasBundle.putBoolean("com.facebook.orca.extra.IS_REPLY", true); // Check the parsing logic. MessengerThreadParams params = MessengerUtils.getMessengerThreadParamsForIntent(intent); assertEquals(MessengerThreadParams.Origin.REPLY_FLOW, params.origin); assertEquals("thread_token", params.threadToken); assertEquals("{}", params.metadata); assertEquals(Arrays.asList("100", "400", "500"), params.participants); } @Test public void testGetMessengerThreadParamsForIntentWithUnrecognizedIntent() throws Exception { // Simulate an intent that Messenger would send. Intent intent = new Intent(); assertNull(MessengerUtils.getMessengerThreadParamsForIntent(intent)); } @Test public void testFinishShareToMessengerWith20150314Protocol() throws Exception { // Simulate an intent that Messenger would send. Intent originalIntent = new Intent(); originalIntent.addCategory("com.facebook.orca.category.PLATFORM_THREAD_20150314"); Bundle extrasBundle = setupIntentWithAppLinkExtrasBundle(originalIntent); extrasBundle.putString("com.facebook.orca.extra.THREAD_TOKEN", "thread_token"); extrasBundle.putString("com.facebook.orca.extra.METADATA", "{}"); extrasBundle.putString("com.facebook.orca.extra.PARTICIPANTS", "100,400,500"); when(mMockActivity.getIntent()).thenReturn(originalIntent); // Setup the data the app will send back to messenger. Uri uri = Uri.parse("file:///foo.jpeg"); Uri externalUri = Uri.parse("http://example.com/foo.jpeg"); ShareToMessengerParams params = ShareToMessengerParams .newBuilder(uri, "image/jpeg") .setMetaData("{}") .setExternalUri(externalUri) .build(); // Call finishShareToMessenger and verify the results. MessengerUtils.finishShareToMessenger(mMockActivity, params); ArgumentCaptor<Intent> intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class); verify(mMockActivity).setResult(eq(Activity.RESULT_OK), intentArgumentCaptor.capture()); verify(mMockActivity).finish(); Intent intent = intentArgumentCaptor.getValue(); assertNotNull(intent); assertEquals(Intent.FLAG_GRANT_READ_URI_PERMISSION, intent.getFlags()); assertEquals(20150314, intent.getIntExtra("com.facebook.orca.extra.PROTOCOL_VERSION", -1)); assertEquals("thread_token", intent.getStringExtra("com.facebook.orca.extra.THREAD_TOKEN")); assertEquals(uri, intent.getData()); assertEquals("image/jpeg", intent.getType()); assertEquals("200", intent.getStringExtra("com.facebook.orca.extra.APPLICATION_ID")); assertEquals("{}", intent.getStringExtra("com.facebook.orca.extra.METADATA")); assertEquals(externalUri, intent.getParcelableExtra("com.facebook.orca.extra.EXTERNAL_URI")); } @Test public void testFinishShareToMessengerWithUnexpectedIntent() throws Exception { // Simulate an intent that Messenger would send. Intent originalIntent = new Intent(); when(mMockActivity.getIntent()).thenReturn(originalIntent); // Setup the data the app will send back to messenger. Uri uri = Uri.parse("file:///foo.jpeg"); Uri externalUri = Uri.parse("http://example.com/foo.jpeg"); ShareToMessengerParams params = ShareToMessengerParams .newBuilder(uri, "image/jpeg") .setMetaData("{}") .setExternalUri(externalUri) .build(); // Call finishShareToMessenger and verify the results. MessengerUtils.finishShareToMessenger(mMockActivity, params); verify(mMockActivity).setResult(Activity.RESULT_CANCELED, null); verify(mMockActivity).finish(); } /** * Sets up the PackageManager to return what we expect depending on whether messenger is * installed. * * @param isInstalled true to simulate that messenger is installed */ private void setupPackageManagerForMessenger(boolean isInstalled) throws Exception { if (isInstalled) { when(mMockPackageManager.getPackageInfo("com.facebook.orca", 0)) .thenReturn(new PackageInfo()); } else { when(mMockPackageManager.getPackageInfo("com.facebook.orca", 0)) .thenThrow(new PackageManager.NameNotFoundException()); } } /** * Sets up the Messenger content resolver to reply that it supports the specified versions. * * @param versions the versions that it should support */ private void setupContentResolverForProtocolVersions(int... versions) { MatrixCursor matrixCursor = new MatrixCursor(new String[]{"version"}); for (int version : versions) { matrixCursor.addRow(new Object[]{version}); } when(mMockContentResolver.query( Uri.parse("content://com.facebook.orca.provider.MessengerPlatformProvider/versions"), new String[]{"version"}, null, null, null)) .thenReturn(matrixCursor); } /** * Adds the structure to the Intent to look like an app link and returns the Extras section * which is where the messenger parameters go. * * @param intent the intent to add to * @return the extras Bundle */ private Bundle setupIntentWithAppLinkExtrasBundle(Intent intent) { Bundle appLinksDataBundle = new Bundle(); intent.putExtra("al_applink_data", appLinksDataBundle); Bundle extrasBundle = new Bundle(); appLinksDataBundle.putBundle("extras", extrasBundle); return extrasBundle; } }