Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1702)

Unified Diff: content/public/android/junit/src/org/chromium/content/browser/installedapp/InstalledAppProviderTest.java

Issue 2706403014: Add Android implementation of navigator.getInstalledRelatedApps. (Closed)
Patch Set: Rebase. Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/public/android/junit/src/org/chromium/content/browser/installedapp/InstalledAppProviderTest.java
diff --git a/content/public/android/junit/src/org/chromium/content/browser/installedapp/InstalledAppProviderTest.java b/content/public/android/junit/src/org/chromium/content/browser/installedapp/InstalledAppProviderTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..583c868c4561a5eaf33d24aece78e7629cfc8a7a
--- /dev/null
+++ b/content/public/android/junit/src/org/chromium/content/browser/installedapp/InstalledAppProviderTest.java
@@ -0,0 +1,767 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.content.browser.installedapp;
+
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.AssetManager;
+import android.content.res.Resources;
+import android.os.Bundle;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.res.builder.DefaultPackageManager;
+
+import org.chromium.base.test.util.Feature;
+import org.chromium.installedapp.mojom.InstalledAppProvider;
+import org.chromium.installedapp.mojom.RelatedApplication;
+import org.chromium.testing.local.LocalRobolectricTestRunner;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.HashMap;
+
+/**
+ * Ensure that the InstalledAppProvider returns the correct apps.
+ */
+@RunWith(LocalRobolectricTestRunner.class)
+@Config(manifest = Config.NONE)
+public class InstalledAppProviderTest {
+ private static final String ASSET_STATEMENTS_KEY =
+ InstalledAppProviderImpl.ASSET_STATEMENTS_KEY;
+ private static final String RELATION_HANDLE_ALL_URLS =
+ "delegate_permission/common.handle_all_urls";
+ private static final String NAMESPACE_WEB =
+ InstalledAppProviderImpl.ASSET_STATEMENT_NAMESPACE_WEB;
+ private static final String PLATFORM_ANDROID =
+ InstalledAppProviderImpl.RELATED_APP_PLATFORM_ANDROID;
+ private static final String PLATFORM_OTHER = "itunes";
+ // Note: Android package name and origin deliberately unrelated (there is no requirement that
+ // they be the same).
+ private static final String PACKAGE_NAME_1 = "com.app1.package";
+ private static final String PACKAGE_NAME_2 = "com.app2.package";
+ private static final String PACKAGE_NAME_3 = "com.app3.package";
+ private static final String URL_UNRELATED = "https://appstore.example.com/app1";
+ private static final String ORIGIN = "https://example.com:8000";
+ private static final String URL_ON_ORIGIN =
+ "https://example.com:8000/path/to/page.html?key=value#fragment";
+ private static final String ORIGIN_SYNTAX_ERROR = "https:{";
+ private static final String ORIGIN_MISSING_SCHEME = "path/only";
+ private static final String ORIGIN_MISSING_HOST = "file:///path/piece";
+ private static final String ORIGIN_MISSING_PORT = "http://example.com";
+ private static final String ORIGIN_DIFFERENT_SCHEME = "http://example.com:8000";
+ private static final String ORIGIN_DIFFERENT_HOST = "https://example.org:8000";
+ private static final String ORIGIN_DIFFERENT_PORT = "https://example.com:8001";
+
+ private FakePackageManager mPackageManager;
+ private FakeFrameUrlDelegate mFrameUrlDelegate;
+ private InstalledAppProviderImpl mInstalledAppProvider;
+
+ /**
+ * FakePackageManager allows for the "installation" of Android package names and setting up
+ * Resources for installed packages.
+ */
+ private static class FakePackageManager extends DefaultPackageManager {
+ private final HashMap<String, Bundle> mMetaDataMap;
+ private final HashMap<String, Resources> mResourceMap;
+
+ public FakePackageManager() {
+ super();
+ mMetaDataMap = new HashMap<String, Bundle>();
+ mResourceMap = new HashMap<String, Resources>();
+ }
+
+ @Override
+ public ApplicationInfo getApplicationInfo(String packageName, int flags)
+ throws NameNotFoundException {
+ if (packageName == null) throw new NullPointerException();
+
+ Bundle metaData = mMetaDataMap.get(packageName);
+ if (metaData == null) throw new NameNotFoundException(packageName);
+
+ // Create an application with this metadata (but only if |flags| allows). Doing it this
+ // way (rather than simply storing the ApplicationInfo in a map) ensures that the
+ // |flags| is set correctly.
+ ApplicationInfo appInfo = new ApplicationInfo();
+ appInfo.packageName = packageName;
+ if ((flags & PackageManager.GET_META_DATA) != 0) {
+ appInfo.metaData = metaData;
+ }
+ return appInfo;
+ }
+
+ @Override
+ public Resources getResourcesForApplication(ApplicationInfo app)
+ throws NameNotFoundException {
+ if (app == null) throw new NullPointerException();
+
+ Resources result = mResourceMap.get(app.packageName);
+ if (result == null) throw new NameNotFoundException(app.packageName);
+
+ return result;
+ }
+
+ public void setMetaDataAndResourcesForTest(
+ String packageName, Bundle metaData, Resources resources) {
+ mMetaDataMap.put(packageName, metaData);
+ mResourceMap.put(packageName, resources);
+ }
+ }
+
+ /**
+ * Fakes the Resources object, allowing lookup of a single String value.
+ *
+ * Note: The real Resources object defines a mapping to many values. This fake object only
+ * allows a single value in the mapping, and it must be a String (which is all that is required
+ * for these tests).
+ */
+ private static class FakeResources extends Resources {
+ private final int mId;
+ private final String mValue;
+
+ // Do not warn about deprecated call to Resources(); the documentation says code is not
+ // supposed to create its own Resources object, but we are using it to fake out the
+ // Resources, and there is no other way to do that.
+ @SuppressWarnings("deprecation")
+ public FakeResources(int identifier, String value) {
+ super(new AssetManager(), null, null);
+ mId = identifier;
+ mValue = value;
+ }
+
+ @Override
+ public int getIdentifier(String name, String defType, String defPackage) {
+ if (name == null) throw new NullPointerException();
+
+ // There is *no guarantee* (in the Digital Asset Links spec) about what the string
+ // resource should be called ("asset_statements" is just an example). Therefore,
+ // getIdentifier cannot be used to get the asset statements string. Always fail the
+ // lookup here, to ensure the implementation isn't relying on any particular hard-coded
+ // string.
+ return 0;
+ }
+
+ @Override
+ public String getString(int id) {
+ if (id != mId) {
+ throw new Resources.NotFoundException("id 0x" + Integer.toHexString(id));
+ }
+
+ return mValue;
+ }
+ }
+
+ private static final class FakeFrameUrlDelegate
+ implements InstalledAppProviderImpl.FrameUrlDelegate {
+ private URI mFrameUrl;
+
+ public FakeFrameUrlDelegate(String frameUrl) {
+ setFrameUrl(frameUrl);
+ }
+
+ public void setFrameUrl(String frameUrl) {
+ if (frameUrl == null) {
+ mFrameUrl = null;
+ return;
+ }
+
+ try {
+ mFrameUrl = new URI(frameUrl);
+ } catch (URISyntaxException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ @Override
+ public URI getUrl() {
+ return mFrameUrl;
+ }
+ }
+
+ /**
+ * Creates a metaData bundle with a single resource-id key.
+ */
+ private static Bundle createMetaData(String metaDataName, int metaDataResourceId) {
+ Bundle metaData = new Bundle();
+ metaData.putInt(metaDataName, metaDataResourceId);
+ return metaData;
+ }
+
+ /**
+ * Sets a resource with a single key-value pair in an Android package's manifest.
+ *
+ * The value is always a string.
+ */
+ private void setStringResource(String packageName, String key, String value) {
+ int identifier = 0x1234;
+ Bundle metaData = createMetaData(key, identifier);
+ FakeResources resources = new FakeResources(identifier, value);
+ mPackageManager.setMetaDataAndResourcesForTest(packageName, metaData, resources);
+ }
+
+ /**
+ * Creates a valid Android asset statement string.
+ */
+ private String createAssetStatement(String platform, String relation, String url) {
+ return String.format(
+ "{\"relation\": [\"%s\"], \"target\": {\"namespace\": \"%s\", \"site\": \"%s\"}}",
+ relation, platform, url);
+ }
+
+ /**
+ * Sets an asset statement to an Android package's manifest (in the fake package manager).
+ *
+ * Only one asset statement can be set for a given package (if this is called twice on the same
+ * package, overwrites the previous asset statement).
+ *
+ * This corresponds to a Statement List in the Digital Asset Links spec v1.
+ */
+ private void setAssetStatement(
+ String packageName, String platform, String relation, String url) {
+ String statements = "[" + createAssetStatement(platform, relation, url) + "]";
+ setStringResource(packageName, ASSET_STATEMENTS_KEY, statements);
+ }
+
+ /**
+ * Creates a RelatedApplication to put in the web app manifest.
+ */
+ private RelatedApplication createRelatedApplication(String platform, String id, String url) {
+ RelatedApplication application = new RelatedApplication();
+ application.platform = platform;
+ application.id = id;
+ application.url = url;
+ return application;
+ }
+
+ /**
+ * Calls filterInstalledApps with the given inputs, and tests that the expected result is
+ * returned.
+ */
+ private void verifyInstalledApps(RelatedApplication[] manifestRelatedApps,
+ final RelatedApplication[] expectedInstalledRelatedApps) {
+ mInstalledAppProvider.filterInstalledApps(
+ manifestRelatedApps, new InstalledAppProvider.FilterInstalledAppsResponse() {
+ @Override
+ public void call(RelatedApplication[] installedRelatedApps) {
+ Assert.assertEquals(
+ expectedInstalledRelatedApps.length, installedRelatedApps.length);
+
+ for (int i = 0; i < installedRelatedApps.length; i++) {
+ Assert.assertEquals(
+ expectedInstalledRelatedApps[i], installedRelatedApps[i]);
+ }
+ }
+ });
+ }
+
+ @Before
+ public void setUp() {
+ mPackageManager = new FakePackageManager();
+ RuntimeEnvironment.setRobolectricPackageManager(mPackageManager);
+ mFrameUrlDelegate = new FakeFrameUrlDelegate(URL_ON_ORIGIN);
+ mInstalledAppProvider =
+ new InstalledAppProviderImpl(mFrameUrlDelegate, RuntimeEnvironment.application);
+ }
+
+ /**
+ * Origin of the page using the API is missing certain parts of the URI.
+ */
+ @Test
+ @Feature({"InstalledApp"})
+ public void testOriginMissingParts() {
+ RelatedApplication manifestRelatedApps[] = new RelatedApplication[] {
+ createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_1, null)};
+ setAssetStatement(PACKAGE_NAME_1, NAMESPACE_WEB, RELATION_HANDLE_ALL_URLS, ORIGIN);
+ RelatedApplication[] expectedInstalledRelatedApps = new RelatedApplication[] {};
+
+ mFrameUrlDelegate.setFrameUrl(ORIGIN_MISSING_SCHEME);
+ verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps);
+
+ mFrameUrlDelegate.setFrameUrl(ORIGIN_MISSING_HOST);
+ verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps);
+ }
+
+ /**
+ * No related Android apps.
+ *
+ * An Android app relates to the web app, but not mutual.
+ */
+ @Test
+ @Feature({"InstalledApp"})
+ public void testNoRelatedApps() {
+ // The web manifest has no related apps.
+ RelatedApplication manifestRelatedApps[] = new RelatedApplication[] {};
+
+ // One Android app is installed named |PACKAGE_NAME_1|. It has a related web app with origin
+ // |ORIGIN|.
+ setAssetStatement(PACKAGE_NAME_1, NAMESPACE_WEB, RELATION_HANDLE_ALL_URLS, ORIGIN);
+
+ RelatedApplication[] expectedInstalledRelatedApps = new RelatedApplication[] {};
+ verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps);
+ }
+
+ /**
+ * One related Android app with no id (package name).
+ *
+ * An Android app relates to the web app, but not mutual.
+ */
+ @Test
+ @Feature({"InstalledApp"})
+ public void testOneRelatedAppNoId() {
+ RelatedApplication manifestRelatedApps[] =
+ new RelatedApplication[] {createRelatedApplication(PLATFORM_ANDROID, null, null)};
+
+ setAssetStatement(PACKAGE_NAME_1, NAMESPACE_WEB, RELATION_HANDLE_ALL_URLS, ORIGIN);
+
+ RelatedApplication[] expectedInstalledRelatedApps = new RelatedApplication[] {};
+ verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps);
+ }
+
+ /**
+ * One related app (from a non-Android platform).
+ *
+ * An Android app with the same id relates to the web app. This should be ignored since the
+ * manifest doesn't mention the Android app.
+ */
+ @Test
+ @Feature({"InstalledApp"})
+ public void testOneRelatedNonAndroidApp() {
+ RelatedApplication manifestRelatedApps[] = new RelatedApplication[] {
+ createRelatedApplication(PLATFORM_OTHER, PACKAGE_NAME_1, null)};
+
+ setAssetStatement(PACKAGE_NAME_1, NAMESPACE_WEB, RELATION_HANDLE_ALL_URLS, ORIGIN);
+
+ RelatedApplication[] expectedInstalledRelatedApps = new RelatedApplication[] {};
+ verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps);
+ }
+
+ /**
+ * One related Android app; Android app is not installed.
+ *
+ * Another Android app relates to the web app, but not mutual.
+ */
+ @Test
+ @Feature({"InstalledApp"})
+ public void testOneRelatedAppNotInstalled() {
+ // The web manifest has a related Android app named |PACKAGE_NAME_1|.
+ RelatedApplication manifestRelatedApps[] = new RelatedApplication[] {
+ createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_1, null)};
+
+ // One Android app is installed named |PACKAGE_NAME_2|. It has a related web app with origin
+ // |ORIGIN|.
+ setAssetStatement(PACKAGE_NAME_2, NAMESPACE_WEB, RELATION_HANDLE_ALL_URLS, ORIGIN);
+
+ RelatedApplication[] expectedInstalledRelatedApps = new RelatedApplication[] {};
+ verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps);
+ }
+
+ /**
+ * Android app manifest has an asset_statements key, but the resource it links to is missing.
+ */
+ @Test
+ @Feature({"InstalledApp"})
+ public void testOneRelatedAppBrokenAssetStatementsResource() {
+ RelatedApplication manifestRelatedApps[] = new RelatedApplication[] {
+ createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_1, null)};
+
+ Bundle metaData = createMetaData(ASSET_STATEMENTS_KEY, 0x1234);
+ String statements =
+ "[" + createAssetStatement(NAMESPACE_WEB, RELATION_HANDLE_ALL_URLS, ORIGIN) + "]";
+ FakeResources resources = new FakeResources(0x4321, statements);
+ mPackageManager.setMetaDataAndResourcesForTest(PACKAGE_NAME_1, metaData, resources);
+ RelatedApplication[] expectedInstalledRelatedApps = new RelatedApplication[] {};
+ verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps);
+ }
+
+ /**
+ * One related Android app; Android app is not mutually related (has no asset_statements).
+ */
+ @Test
+ @Feature({"InstalledApp"})
+ public void testOneRelatedAppNoAssetStatements() {
+ RelatedApplication manifestRelatedApps[] = new RelatedApplication[] {
+ createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_1, null)};
+
+ setStringResource(PACKAGE_NAME_1, null, null);
+ RelatedApplication[] expectedInstalledRelatedApps = new RelatedApplication[] {};
+ verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps);
+ }
+
+ /**
+ * One related Android app; Android app is related to other origins.
+ *
+ * Tests three cases:
+ * - The Android app is related to a web app with a different scheme.
+ * - The Android app is related to a web app with a different host.
+ * - The Android app is related to a web app with a different port.
+ */
+ @Test
+ @Feature({"InstalledApp"})
+ public void testOneRelatedAppRelatedToDifferentOrigins() {
+ RelatedApplication manifestRelatedApps[] = new RelatedApplication[] {
+ createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_1, null)};
+
+ setAssetStatement(
+ PACKAGE_NAME_1, NAMESPACE_WEB, RELATION_HANDLE_ALL_URLS, ORIGIN_DIFFERENT_SCHEME);
+ RelatedApplication[] expectedInstalledRelatedApps = new RelatedApplication[] {};
+ verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps);
+
+ setAssetStatement(
+ PACKAGE_NAME_1, NAMESPACE_WEB, RELATION_HANDLE_ALL_URLS, ORIGIN_DIFFERENT_HOST);
+ verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps);
+
+ setAssetStatement(
+ PACKAGE_NAME_1, NAMESPACE_WEB, RELATION_HANDLE_ALL_URLS, ORIGIN_DIFFERENT_PORT);
+ verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps);
+ }
+
+ /**
+ * One related Android app; Android app is installed and mutually related.
+ */
+ @Test
+ @Feature({"InstalledApp"})
+ public void testOneInstalledRelatedApp() {
+ RelatedApplication manifestRelatedApps[] = new RelatedApplication[] {
+ createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_1, null)};
+
+ setAssetStatement(PACKAGE_NAME_1, NAMESPACE_WEB, RELATION_HANDLE_ALL_URLS, ORIGIN);
+
+ RelatedApplication[] expectedInstalledRelatedApps = manifestRelatedApps;
+ verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps);
+ }
+
+ /**
+ * Change the frame URL and ensure the app relates to the new URL, not the old one.
+ *
+ * This simulates navigating the frame while keeping the same Mojo service open.
+ */
+ @Test
+ @Feature({"InstalledApp"})
+ public void testDynamicallyChangingUrl() {
+ RelatedApplication manifestRelatedApps[] = new RelatedApplication[] {
+ createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_1, null)};
+
+ setAssetStatement(
+ PACKAGE_NAME_1, NAMESPACE_WEB, RELATION_HANDLE_ALL_URLS, ORIGIN_DIFFERENT_SCHEME);
+
+ // Should be empty, since Android app does not relate to this frame's origin.
+ RelatedApplication[] expectedInstalledRelatedApps = new RelatedApplication[] {};
+ verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps);
+
+ // Simulate a navigation to a different origin.
+ mFrameUrlDelegate.setFrameUrl(ORIGIN_DIFFERENT_SCHEME);
+
+ // Now the result should include the Android app that relates to the new origin.
+ expectedInstalledRelatedApps = manifestRelatedApps;
+ verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps);
+
+ // Simulate the native RenderFrameHost disappearing.
+ mFrameUrlDelegate.setFrameUrl(null);
+
+ expectedInstalledRelatedApps = new RelatedApplication[] {};
+ verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps);
+ }
+
+ /**
+ * One related Android app (installed and mutually related), with a non-null URL field.
+ */
+ @Test
+ @Feature({"InstalledApp"})
+ public void testInstalledRelatedAppWithUrl() {
+ RelatedApplication manifestRelatedApps[] = new RelatedApplication[] {
+ createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_1, URL_UNRELATED)};
+
+ setAssetStatement(PACKAGE_NAME_1, NAMESPACE_WEB, RELATION_HANDLE_ALL_URLS, ORIGIN);
+
+ RelatedApplication[] expectedInstalledRelatedApps = manifestRelatedApps;
+ verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps);
+ }
+
+ /**
+ * One related Android app; Android app is related to multiple origins.
+ */
+ @Test
+ @Feature({"InstalledApp"})
+ public void testMultipleAssetStatements() {
+ RelatedApplication manifestRelatedApps[] = new RelatedApplication[] {
+ createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_1, null)};
+
+ // Create an asset_statements field with multiple statements. The second one matches the web
+ // app.
+ String statements = "["
+ + createAssetStatement(
+ NAMESPACE_WEB, RELATION_HANDLE_ALL_URLS, ORIGIN_DIFFERENT_HOST)
+ + ", " + createAssetStatement(NAMESPACE_WEB, RELATION_HANDLE_ALL_URLS, ORIGIN)
+ + "]";
+ setStringResource(PACKAGE_NAME_1, ASSET_STATEMENTS_KEY, statements);
+
+ RelatedApplication[] expectedInstalledRelatedApps = manifestRelatedApps;
+ verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps);
+ }
+
+ /**
+ * A JSON syntax error in the Android app's asset statement.
+ */
+ @Test
+ @Feature({"InstalledApp"})
+ public void testAssetStatementSyntaxError() {
+ RelatedApplication manifestRelatedApps[] = new RelatedApplication[] {
+ createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_1, null)};
+
+ String statements = "[{\"target\" {}}]";
+ setStringResource(PACKAGE_NAME_1, ASSET_STATEMENTS_KEY, statements);
+
+ RelatedApplication[] expectedInstalledRelatedApps = new RelatedApplication[] {};
+ verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps);
+ }
+
+ /**
+ * The Android app's asset statement is not an array.
+ */
+ @Test
+ @Feature({"InstalledApp"})
+ public void testAssetStatementNotArray() {
+ RelatedApplication manifestRelatedApps[] = new RelatedApplication[] {
+ createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_1, null)};
+
+ String statement = createAssetStatement(NAMESPACE_WEB, RELATION_HANDLE_ALL_URLS, ORIGIN);
+ setStringResource(PACKAGE_NAME_1, ASSET_STATEMENTS_KEY, statement);
+
+ RelatedApplication[] expectedInstalledRelatedApps = new RelatedApplication[] {};
+ verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps);
+ }
+
+ /**
+ * The Android app's asset statement array contains non-objects.
+ */
+ @Test
+ @Feature({"InstalledApp"})
+ public void testAssetStatementArrayNoObjects() {
+ RelatedApplication manifestRelatedApps[] = new RelatedApplication[] {
+ createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_1, null)};
+
+ String statements = "["
+ + createAssetStatement(NAMESPACE_WEB, RELATION_HANDLE_ALL_URLS, ORIGIN) + ", 4]";
+ setStringResource(PACKAGE_NAME_1, ASSET_STATEMENTS_KEY, statements);
+
+ // Expect it to ignore the integer and successfully parse the valid object.
+ RelatedApplication[] expectedInstalledRelatedApps = manifestRelatedApps;
+ verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps);
+ }
+
+ /**
+ * Android app has no "relation" in the asset statement.
+ *
+ * Currently, the relation string (in the Android package's asset statement) is ignored, so the
+ * app is still returned as "installed".
+ */
+ @Test
+ @Feature({"InstalledApp"})
+ public void testAssetStatementNoRelation() {
+ RelatedApplication manifestRelatedApps[] = new RelatedApplication[] {
+ createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_1, null)};
+
+ String statements = String.format(
+ "[{\"target\": {\"namespace\": \"%s\", \"site\": \"%s\"}}]", NAMESPACE_WEB, ORIGIN);
+ setStringResource(PACKAGE_NAME_1, ASSET_STATEMENTS_KEY, statements);
+
+ // TODO(mgiuca): [Spec issue] Should we require a specific relation string, rather than any
+ // or no relation?
+ RelatedApplication[] expectedInstalledRelatedApps = manifestRelatedApps;
+ verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps);
+ }
+
+ /**
+ * Android app is related with a non-standard relation.
+ *
+ * Currently, the relation string (in the Android package's asset statement) is ignored, so any
+ * will do. Is this desirable, or do we want to require a specific relation string?
+ */
+ @Test
+ @Feature({"InstalledApp"})
+ public void testAssetStatementNonStandardRelation() {
+ RelatedApplication manifestRelatedApps[] = new RelatedApplication[] {
+ createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_1, null)};
+
+ setAssetStatement(PACKAGE_NAME_1, NAMESPACE_WEB, "nonstandard/relation", ORIGIN);
+
+ // TODO(mgiuca): [Spec issue] Should we require a specific relation string, rather than any
+ // or no relation?
+ RelatedApplication[] expectedInstalledRelatedApps = manifestRelatedApps;
+ verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps);
+ }
+
+ /**
+ * Android app has no "target" in the asset statement.
+ */
+ @Test
+ @Feature({"InstalledApp"})
+ public void testAssetStatementNoTarget() {
+ RelatedApplication manifestRelatedApps[] = new RelatedApplication[] {
+ createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_1, null)};
+
+ String statements = String.format("[{\"relation\": [\"%s\"]}]", RELATION_HANDLE_ALL_URLS);
+ setStringResource(PACKAGE_NAME_1, ASSET_STATEMENTS_KEY, statements);
+
+ RelatedApplication[] expectedInstalledRelatedApps = new RelatedApplication[] {};
+ verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps);
+ }
+
+ /**
+ * Android app has no "namespace" in the asset statement.
+ */
+ @Test
+ @Feature({"InstalledApp"})
+ public void testAssetStatementNoNamespace() {
+ RelatedApplication manifestRelatedApps[] = new RelatedApplication[] {
+ createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_1, null)};
+
+ String statements =
+ String.format("[{\"relation\": [\"%s\"], \"target\": {\"site\": \"%s\"}}]",
+ RELATION_HANDLE_ALL_URLS, ORIGIN);
+ setStringResource(PACKAGE_NAME_1, ASSET_STATEMENTS_KEY, statements);
+
+ RelatedApplication[] expectedInstalledRelatedApps = new RelatedApplication[] {};
+ verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps);
+ }
+
+ /**
+ * Android app is related, but not to the web namespace.
+ */
+ @Test
+ @Feature({"InstalledApp"})
+ public void testNonWebAssetStatement() {
+ RelatedApplication manifestRelatedApps[] = new RelatedApplication[] {
+ createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_1, null)};
+
+ setAssetStatement(PACKAGE_NAME_1, "play", RELATION_HANDLE_ALL_URLS, ORIGIN);
+
+ RelatedApplication[] expectedInstalledRelatedApps = new RelatedApplication[] {};
+ verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps);
+ }
+
+ /**
+ * Android app has no "site" in the asset statement.
+ */
+ @Test
+ @Feature({"InstalledApp"})
+ public void testAssetStatementNoSite() {
+ RelatedApplication manifestRelatedApps[] = new RelatedApplication[] {
+ createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_1, null)};
+
+ String statements =
+ String.format("[{\"relation\": [\"%s\"], \"target\": {\"namespace\": \"%s\"}}]",
+ RELATION_HANDLE_ALL_URLS, NAMESPACE_WEB);
+ setStringResource(PACKAGE_NAME_1, ASSET_STATEMENTS_KEY, statements);
+
+ RelatedApplication[] expectedInstalledRelatedApps = new RelatedApplication[] {};
+ verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps);
+ }
+
+ /**
+ * Android app has a syntax error in the "site" field of the asset statement.
+ */
+ @Test
+ @Feature({"InstalledApp"})
+ public void testAssetStatementSiteSyntaxError() {
+ RelatedApplication manifestRelatedApps[] = new RelatedApplication[] {
+ createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_1, null)};
+
+ setAssetStatement(
+ PACKAGE_NAME_1, NAMESPACE_WEB, RELATION_HANDLE_ALL_URLS, ORIGIN_SYNTAX_ERROR);
+
+ RelatedApplication[] expectedInstalledRelatedApps = new RelatedApplication[] {};
+ verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps);
+ }
+
+ /**
+ * Android app has a "site" field missing certain parts of the URI (scheme, host, port).
+ */
+ @Test
+ @Feature({"InstalledApp"})
+ public void testAssetStatementSiteMissingParts() {
+ RelatedApplication manifestRelatedApps[] = new RelatedApplication[] {
+ createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_1, null)};
+
+ setAssetStatement(
+ PACKAGE_NAME_1, NAMESPACE_WEB, RELATION_HANDLE_ALL_URLS, ORIGIN_MISSING_SCHEME);
+ RelatedApplication[] expectedInstalledRelatedApps = new RelatedApplication[] {};
+ verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps);
+
+ setAssetStatement(
+ PACKAGE_NAME_1, NAMESPACE_WEB, RELATION_HANDLE_ALL_URLS, ORIGIN_MISSING_HOST);
+ verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps);
+
+ setAssetStatement(
+ PACKAGE_NAME_1, NAMESPACE_WEB, RELATION_HANDLE_ALL_URLS, ORIGIN_MISSING_PORT);
+ verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps);
+ }
+
+ /**
+ * One related Android app; Android app is related with a path part in the "site" field.
+ *
+ * The path part shouldn't really be there (according to the Digital Asset Links spec), but if
+ * it is, we are lenient and just ignore it (matching only the origin).
+ */
+ @Test
+ @Feature({"InstalledApp"})
+ public void testAssetStatementSiteHasPath() {
+ RelatedApplication manifestRelatedApps[] = new RelatedApplication[] {
+ createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_1, null)};
+
+ String site = ORIGIN + "/path";
+ setAssetStatement(PACKAGE_NAME_1, NAMESPACE_WEB, RELATION_HANDLE_ALL_URLS, site);
+
+ RelatedApplication[] expectedInstalledRelatedApps = manifestRelatedApps;
+ verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps);
+ }
+
+ /**
+ * One related Android app; Android app is installed and mutually related.
+ *
+ * Another Android app relates to the web app, but not mutual.
+ */
+ @Test
+ @Feature({"InstalledApp"})
+ public void testExtraInstalledApp() {
+ RelatedApplication manifestRelatedApps[] = new RelatedApplication[] {
+ createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_1, null)};
+
+ setAssetStatement(PACKAGE_NAME_1, NAMESPACE_WEB, RELATION_HANDLE_ALL_URLS, ORIGIN);
+ setAssetStatement(PACKAGE_NAME_2, NAMESPACE_WEB, RELATION_HANDLE_ALL_URLS, ORIGIN);
+
+ RelatedApplication[] expectedInstalledRelatedApps = manifestRelatedApps;
+ verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps);
+ }
+
+ /**
+ * Two related Android apps; Android apps both installed and mutually related.
+ *
+ * Web app also related to an app with the same name on another platform, and another Android
+ * app which is not installed.
+ */
+ @Test
+ @Feature({"InstalledApp"})
+ public void testMultipleInstalledRelatedApps() {
+ RelatedApplication[] manifestRelatedApps = new RelatedApplication[] {
+ createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_1, null),
+ createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_2, null),
+ createRelatedApplication(PLATFORM_OTHER, PACKAGE_NAME_2, null),
+ createRelatedApplication(PLATFORM_ANDROID, PACKAGE_NAME_3, null)};
+
+ setAssetStatement(PACKAGE_NAME_2, NAMESPACE_WEB, RELATION_HANDLE_ALL_URLS, ORIGIN);
+ setAssetStatement(PACKAGE_NAME_3, NAMESPACE_WEB, RELATION_HANDLE_ALL_URLS, ORIGIN);
+
+ RelatedApplication[] expectedInstalledRelatedApps =
+ new RelatedApplication[] {manifestRelatedApps[1], manifestRelatedApps[3]};
+ verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps);
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698