diff options
Diffstat (limited to 'mobile/android/tests/browser/junit3')
20 files changed, 1429 insertions, 0 deletions
diff --git a/mobile/android/tests/browser/junit3/AndroidManifest.xml.in b/mobile/android/tests/browser/junit3/AndroidManifest.xml.in new file mode 100644 index 000000000..1775c2433 --- /dev/null +++ b/mobile/android/tests/browser/junit3/AndroidManifest.xml.in @@ -0,0 +1,23 @@ +#filter substitution +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="org.mozilla.gecko.browser.tests" + sharedUserId="@MOZ_ANDROID_SHARED_ID@" + android:versionCode="1" + android:versionName="1.0" > + + <uses-sdk android:minSdkVersion="8" + android:targetSdkVersion="@ANDROID_TARGET_SDK@" /> + + <application + android:debuggable="true" + android:icon="@drawable/icon" + android:label="@ANDROID_BROWSER_APP_DISPLAYNAME@"> + <uses-library android:name="android.test.runner" /> + </application> + + <instrumentation + android:label="@string/app_name" + android:name="org.mozilla.gecko.harness.BrowserInstrumentationTestRunner" + android:targetPackage="@ANDROID_BROWSER_TARGET_PACKAGE_NAME@" /> +</manifest> diff --git a/mobile/android/tests/browser/junit3/Makefile.in b/mobile/android/tests/browser/junit3/Makefile.in new file mode 100644 index 000000000..299b4d280 --- /dev/null +++ b/mobile/android/tests/browser/junit3/Makefile.in @@ -0,0 +1,13 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +ANDROID_EXTRA_JARS += \ + browser-junit3.jar \ + $(NULL) + +ANDROID_MANIFEST_FILE := $(CURDIR)/AndroidManifest.xml + +include $(topsrcdir)/config/rules.mk + +tools:: $(ANDROID_APK_NAME).apk diff --git a/mobile/android/tests/browser/junit3/instrumentation.ini b/mobile/android/tests/browser/junit3/instrumentation.ini new file mode 100644 index 000000000..5f61d938f --- /dev/null +++ b/mobile/android/tests/browser/junit3/instrumentation.ini @@ -0,0 +1,9 @@ +[DEFAULT] +subsuite = browser + +[src/org/mozilla/tests/browser/junit3/TestDistribution.java] +[src/org/mozilla/tests/browser/junit3/TestGeckoSharedPrefs.java] +[src/org/mozilla/tests/browser/junit3/TestImageDownloader.java] +[src/org/mozilla/tests/browser/junit3/TestJarReader.java] +[src/org/mozilla/tests/browser/junit3/TestRawResource.java] +[src/org/mozilla/tests/browser/junit3/TestSuggestedSites.java] diff --git a/mobile/android/tests/browser/junit3/moz.build b/mobile/android/tests/browser/junit3/moz.build new file mode 100644 index 000000000..577664508 --- /dev/null +++ b/mobile/android/tests/browser/junit3/moz.build @@ -0,0 +1,55 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +DEFINES['ANDROID_PACKAGE_NAME'] = CONFIG['ANDROID_PACKAGE_NAME'] + +ANDROID_APK_NAME = 'browser-junit3-debug' +ANDROID_APK_PACKAGE = 'org.mozilla.gecko.browser.tests' + +jar = add_java_jar('browser-junit3') +jar.sources += [ + 'src/org/mozilla/tests/browser/junit3/harness/BrowserInstrumentationTestRunner.java', + 'src/org/mozilla/tests/browser/junit3/harness/BrowserTestListener.java', + 'src/org/mozilla/tests/browser/junit3/TestDistribution.java', + 'src/org/mozilla/tests/browser/junit3/TestGeckoBackgroundThread.java', + 'src/org/mozilla/tests/browser/junit3/TestGeckoMenu.java', + 'src/org/mozilla/tests/browser/junit3/TestGeckoProfilesProvider.java', + 'src/org/mozilla/tests/browser/junit3/TestGeckoSharedPrefs.java', + 'src/org/mozilla/tests/browser/junit3/TestImageDownloader.java', + 'src/org/mozilla/tests/browser/junit3/TestJarReader.java', + 'src/org/mozilla/tests/browser/junit3/TestRawResource.java', + 'src/org/mozilla/tests/browser/junit3/TestSuggestedSites.java', +] +jar.generated_sources = [] # None yet -- try to keep it this way. +jar.javac_flags += ['-Xlint:all'] + +jar.extra_jars += [ + CONFIG['ANDROID_SUPPORT_V4_AAR_LIB'], + CONFIG['ANDROID_RECYCLERVIEW_V7_AAR_LIB'], + TOPOBJDIR + '/mobile/android/base/constants.jar', + TOPOBJDIR + '/mobile/android/base/gecko-R.jar', + TOPOBJDIR + '/mobile/android/base/gecko-browser.jar', + TOPOBJDIR + '/mobile/android/base/gecko-mozglue.jar', + TOPOBJDIR + '/mobile/android/base/gecko-thirdparty.jar', + TOPOBJDIR + '/mobile/android/base/gecko-util.jar', + TOPOBJDIR + '/mobile/android/base/gecko-view.jar', + TOPOBJDIR + '/mobile/android/base/services.jar', + TOPOBJDIR + '/mobile/android/base/sync-thirdparty.jar', +] + +if CONFIG['MOZ_ANDROID_MLS_STUMBLER']: + jar.extra_jars += [ + TOPOBJDIR + '/mobile/android/stumbler/stumbler.jar', + ] + +ANDROID_INSTRUMENTATION_MANIFESTS += ['instrumentation.ini'] + +DEFINES['ANDROID_BROWSER_TARGET_PACKAGE_NAME'] = CONFIG['ANDROID_PACKAGE_NAME'] +DEFINES['ANDROID_BROWSER_APP_DISPLAYNAME'] = '%s Browser Tests' % CONFIG['MOZ_APP_DISPLAYNAME'] +DEFINES['MOZ_ANDROID_SHARED_ID'] = CONFIG['MOZ_ANDROID_SHARED_ID'] +OBJDIR_PP_FILES.mobile.android.tests.browser.junit3 += [ + 'AndroidManifest.xml.in', +] diff --git a/mobile/android/tests/browser/junit3/res/drawable-hdpi/icon.png b/mobile/android/tests/browser/junit3/res/drawable-hdpi/icon.png Binary files differnew file mode 100644 index 000000000..e83438eee --- /dev/null +++ b/mobile/android/tests/browser/junit3/res/drawable-hdpi/icon.png diff --git a/mobile/android/tests/browser/junit3/res/drawable-ldpi/icon.png b/mobile/android/tests/browser/junit3/res/drawable-ldpi/icon.png Binary files differnew file mode 100644 index 000000000..0483c95e9 --- /dev/null +++ b/mobile/android/tests/browser/junit3/res/drawable-ldpi/icon.png diff --git a/mobile/android/tests/browser/junit3/res/drawable-mdpi/icon.png b/mobile/android/tests/browser/junit3/res/drawable-mdpi/icon.png Binary files differnew file mode 100644 index 000000000..86b4dee54 --- /dev/null +++ b/mobile/android/tests/browser/junit3/res/drawable-mdpi/icon.png diff --git a/mobile/android/tests/browser/junit3/res/layout/main.xml b/mobile/android/tests/browser/junit3/res/layout/main.xml new file mode 100644 index 000000000..db8893bd9 --- /dev/null +++ b/mobile/android/tests/browser/junit3/res/layout/main.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" > + + <TextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/app_name" /> + +</LinearLayout> diff --git a/mobile/android/tests/browser/junit3/res/values/strings.xml b/mobile/android/tests/browser/junit3/res/values/strings.xml new file mode 100644 index 000000000..a3faebab6 --- /dev/null +++ b/mobile/android/tests/browser/junit3/res/values/strings.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + + <string name="app_name">Gecko Browser Tests</string> + +</resources> diff --git a/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestDistribution.java b/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestDistribution.java new file mode 100644 index 000000000..9cabb346c --- /dev/null +++ b/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestDistribution.java @@ -0,0 +1,37 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.tests.browser.junit3; + +import android.test.InstrumentationTestCase; +import org.mozilla.gecko.distribution.ReferrerDescriptor; + +public class TestDistribution extends InstrumentationTestCase { + private static final String TEST_REFERRER_STRING = "utm_source=campsource&utm_medium=campmed&utm_term=term%2Bhere&utm_content=content&utm_campaign=name"; + private static final String TEST_MALFORMED_REFERRER_STRING = "utm_source=campsource&utm_medium=campmed&utm_term=term%2"; + + public void testReferrerParsing() { + ReferrerDescriptor good = new ReferrerDescriptor(TEST_REFERRER_STRING); + assertEquals("campsource", good.source); + assertEquals("campmed", good.medium); + assertEquals("term+here", good.term); + assertEquals("content", good.content); + assertEquals("name", good.campaign); + + // Uri.Builder is permissive. + ReferrerDescriptor bad = new ReferrerDescriptor(TEST_MALFORMED_REFERRER_STRING); + assertEquals("campsource", bad.source); + assertEquals("campmed", bad.medium); + assertFalse("term+here".equals(bad.term)); + assertNull(bad.content); + assertNull(bad.campaign); + + ReferrerDescriptor ugly = new ReferrerDescriptor(null); + assertNull(ugly.source); + assertNull(ugly.medium); + assertNull(ugly.term); + assertNull(ugly.content); + assertNull(ugly.campaign); + } +} diff --git a/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestGeckoBackgroundThread.java b/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestGeckoBackgroundThread.java new file mode 100644 index 000000000..cbf9dffe3 --- /dev/null +++ b/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestGeckoBackgroundThread.java @@ -0,0 +1,56 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.tests.browser.junit3; + +import android.test.InstrumentationTestCase; +import org.mozilla.gecko.util.ThreadUtils; + +public class TestGeckoBackgroundThread extends InstrumentationTestCase { + + private boolean finishedTest; + private boolean ranFirstRunnable; + + public void testGeckoBackgroundThread() throws InterruptedException { + + final Thread testThread = Thread.currentThread(); + + ThreadUtils.postToBackgroundThread(new Runnable() { + @Override + public void run() { + // Must *not* be on thread that posted the Runnable. + assertFalse(ThreadUtils.isOnThread(testThread)); + + // Must be on background thread. + assertTrue(ThreadUtils.isOnBackgroundThread()); + + ranFirstRunnable = true; + } + }); + + // Post a second Runnable to make sure it still runs on the background thread, + // and it only runs after the first Runnable has run. + ThreadUtils.postToBackgroundThread(new Runnable() { + @Override + public void run() { + // Must still be on background thread. + assertTrue(ThreadUtils.isOnBackgroundThread()); + + // This Runnable must be run after the first Runnable had finished. + assertTrue(ranFirstRunnable); + + synchronized (TestGeckoBackgroundThread.this) { + finishedTest = true; + TestGeckoBackgroundThread.this.notify(); + } + } + }); + + synchronized (this) { + while (!finishedTest) { + wait(); + } + } + } +} diff --git a/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestGeckoMenu.java b/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestGeckoMenu.java new file mode 100644 index 000000000..15be26004 --- /dev/null +++ b/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestGeckoMenu.java @@ -0,0 +1,72 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.tests.browser.junit3; + +import android.test.InstrumentationTestCase; +import org.mozilla.gecko.AppConstants; +import org.mozilla.gecko.menu.GeckoMenu; +import org.mozilla.gecko.util.ThreadUtils; + +public class TestGeckoMenu extends InstrumentationTestCase { + + private volatile Exception exception; + private void setException(Exception e) { + this.exception = e; + } + + public void testMenuThreading() throws InterruptedException { + final GeckoMenu menu = new GeckoMenu(getInstrumentation().getTargetContext()); + final Object semaphore = new Object(); + + ThreadUtils.postToUiThread(new Runnable() { + @Override + public void run() { + try { + menu.add("test1"); + } catch (Exception e) { + setException(e); + } + + synchronized (semaphore) { + semaphore.notify(); + } + } + }); + synchronized (semaphore) { + semaphore.wait(); + } + + // No exception thrown if called on UI thread. + assertNull(exception); + + new Thread(new Runnable() { + @Override + public void run() { + try { + menu.add("test2"); + } catch (Exception e) { + setException(e); + } + + synchronized (semaphore) { + semaphore.notify(); + } + } + }).start(); + + synchronized (semaphore) { + semaphore.wait(); + } + + if (AppConstants.RELEASE_OR_BETA) { + // No exception thrown: release build. + assertNull(exception); + return; + } + + assertNotNull(exception); + assertEquals(exception.getClass(), IllegalThreadStateException.class); + } +} diff --git a/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestGeckoProfilesProvider.java b/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestGeckoProfilesProvider.java new file mode 100644 index 000000000..2b1da3295 --- /dev/null +++ b/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestGeckoProfilesProvider.java @@ -0,0 +1,50 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.tests.browser.junit3; + +import android.content.ContentResolver; +import android.database.Cursor; +import android.net.Uri; +import android.os.RemoteException; +import android.test.InstrumentationTestCase; +import org.mozilla.gecko.db.BrowserContract; + +import java.io.File; +import java.util.HashMap; +import java.util.Map; + +public class TestGeckoProfilesProvider extends InstrumentationTestCase { + private static final String[] NAME_AND_PATH = new String[] { BrowserContract.Profiles.NAME, BrowserContract.Profiles.PATH }; + + /** + * Ensure that the default profile is found in the results from the provider. + */ + public void testQueryDefault() throws RemoteException { + final ContentResolver contentResolver = getInstrumentation().getContext().getContentResolver(); + final Uri uri = BrowserContract.PROFILES_AUTHORITY_URI.buildUpon().appendPath("profiles").build(); + final Cursor c = contentResolver.query(uri, NAME_AND_PATH, null, null, null); + assertNotNull(c); + try { + assertTrue(c.moveToFirst()); + assertTrue(c.getCount() > 0); + Map<String, String> profiles = new HashMap<String, String>(); + while (!c.isAfterLast()) { + final String name = c.getString(0); + final String path = c.getString(1); + profiles.put(name, path); + c.moveToNext(); + } + + assertTrue(profiles.containsKey("default")); + final String path = profiles.get("default"); + assertTrue(path.endsWith(".default")); // It's the right profile... + assertTrue(path.startsWith("/data/")); // ... in the 'data' dir... + assertTrue(path.contains("/mozilla/")); // ... in the 'mozilla' dir. + assertTrue(new File(path).exists()); + } finally { + c.close(); + } + } +} diff --git a/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestGeckoSharedPrefs.java b/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestGeckoSharedPrefs.java new file mode 100644 index 000000000..9e35cab35 --- /dev/null +++ b/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestGeckoSharedPrefs.java @@ -0,0 +1,153 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +package org.mozilla.tests.browser.junit3; + +import android.content.Context; +import android.content.SharedPreferences; +import android.content.SharedPreferences.Editor; +import android.preference.PreferenceManager; +import android.test.InstrumentationTestCase; +import android.test.RenamingDelegatingContext; +import org.mozilla.gecko.GeckoProfile; +import org.mozilla.gecko.GeckoSharedPrefs; +import org.mozilla.gecko.GeckoSharedPrefs.Flags; + +import java.util.Arrays; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.Set; + +/** + * Test GeckoSharedPrefs migrations. + */ +public class TestGeckoSharedPrefs extends InstrumentationTestCase { + + private static class TestContext extends RenamingDelegatingContext { + private static final String PREFIX = "TestGeckoSharedPrefs-"; + + private final Set<String> usedPrefs; + + public TestContext(Context context) { + super(context, PREFIX); + usedPrefs = Collections.synchronizedSet(new HashSet<String>()); + } + + @Override + public SharedPreferences getSharedPreferences(String name, int mode) { + usedPrefs.add(name); + return super.getSharedPreferences(PREFIX + name, mode); + } + + public void clearUsedPrefs() { + for (String prefsName : usedPrefs) { + getSharedPreferences(prefsName, 0).edit().clear().commit(); + } + + usedPrefs.clear(); + } + } + + private static final EnumSet<Flags> disableMigrations = EnumSet.of(Flags.DISABLE_MIGRATIONS); + + private TestContext context; + + protected void setUp() { + context = new TestContext(getInstrumentation().getTargetContext()); + } + + protected void tearDown() { + context.clearUsedPrefs(); + GeckoSharedPrefs.reset(); + } + + public void testDisableMigrations() { + // Version is 0 before any migration + assertEquals(0, GeckoSharedPrefs.getVersion(context)); + + // Get prefs with migrations disabled + GeckoSharedPrefs.forApp(context, disableMigrations); + GeckoSharedPrefs.forProfile(context, disableMigrations); + GeckoSharedPrefs.forProfileName(context, "someProfile", disableMigrations); + + // Version should still be 0 + assertEquals(0, GeckoSharedPrefs.getVersion(context)); + } + + public void testPrefsVersion() { + // Version is 0 before any migration + assertEquals(0, GeckoSharedPrefs.getVersion(context)); + + // Trigger migration by getting a SharedPreferences instance + GeckoSharedPrefs.forApp(context); + + // Version should be current after migration + assertEquals(GeckoSharedPrefs.PREFS_VERSION, GeckoSharedPrefs.getVersion(context)); + } + + public void testMigrateFromPreferenceManager() { + SharedPreferences appPrefs = GeckoSharedPrefs.forApp(context, disableMigrations); + assertTrue(appPrefs.getAll().isEmpty()); + final Editor appEditor = appPrefs.edit(); + + SharedPreferences profilePrefs = GeckoSharedPrefs.forProfileName(context, GeckoProfile.DEFAULT_PROFILE, disableMigrations); + assertTrue(profilePrefs.getAll().isEmpty()); + final Editor profileEditor = profilePrefs.edit(); + + final SharedPreferences pmPrefs = PreferenceManager.getDefaultSharedPreferences(context); + assertTrue(pmPrefs.getAll().isEmpty()); + Editor pmEditor = pmPrefs.edit(); + + // Insert a key for each type to exercise the + // migration path a bit more thoroughly. + pmEditor.putInt("int_key", 23); + pmEditor.putLong("long_key", 23L); + pmEditor.putString("string_key", "23"); + pmEditor.putFloat("float_key", 23.3f); + + final String[] profileKeys = { + "string_profile", + "int_profile" + }; + + // Insert keys that are expected to be moved to the + // PROFILE scope. + pmEditor.putString(profileKeys[0], "24"); + pmEditor.putInt(profileKeys[1], 24); + + // Commit changes to PreferenceManager + pmEditor.commit(); + assertEquals(6, pmPrefs.getAll().size()); + + // Perform actual migration with the given editors + pmEditor = GeckoSharedPrefs.migrateFromPreferenceManager(context, appEditor, + profileEditor, Arrays.asList(profileKeys)); + + // Commit changes applied during the migration + appEditor.commit(); + profileEditor.commit(); + pmEditor.commit(); + + // PreferenceManager should have no keys + assertTrue(pmPrefs.getAll().isEmpty()); + + // App should have all keys except the profile ones + assertEquals(4, appPrefs.getAll().size()); + + // Ensure app scope doesn't have any of the profile keys + for (int i = 0; i < profileKeys.length; i++) { + assertFalse(appPrefs.contains(profileKeys[i])); + } + + // Check app keys + assertEquals(23, appPrefs.getInt("int_key", 0)); + assertEquals(23L, appPrefs.getLong("long_key", 0L)); + assertEquals("23", appPrefs.getString("string_key", "")); + assertEquals(23.3f, appPrefs.getFloat("float_key", 0)); + + assertEquals(2, profilePrefs.getAll().size()); + assertEquals("24", profilePrefs.getString(profileKeys[0], "")); + assertEquals(24, profilePrefs.getInt(profileKeys[1], 0)); + } +} diff --git a/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestImageDownloader.java b/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestImageDownloader.java new file mode 100644 index 000000000..e0cf9bc63 --- /dev/null +++ b/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestImageDownloader.java @@ -0,0 +1,205 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +package org.mozilla.tests.browser.junit3; + +import android.content.Context; +import android.content.SharedPreferences; +import android.content.res.Resources; +import android.net.Uri; +import android.test.InstrumentationTestCase; +import android.test.RenamingDelegatingContext; +import android.test.mock.MockResources; +import android.util.DisplayMetrics; +import org.mozilla.gecko.distribution.Distribution; +import org.mozilla.gecko.home.ImageLoader.ImageDownloader; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class TestImageDownloader extends InstrumentationTestCase { + private static class TestContext extends RenamingDelegatingContext { + private static final String PREFIX = "TestImageDownloader-"; + + private final Resources resources; + private final Set<String> usedPrefs; + + public TestContext(Context context) { + super(context, PREFIX); + resources = new TestResources(); + usedPrefs = Collections.synchronizedSet(new HashSet<String>()); + } + + @Override + public Resources getResources() { + return resources; + } + + @Override + public SharedPreferences getSharedPreferences(String name, int mode) { + usedPrefs.add(name); + return super.getSharedPreferences(PREFIX + name, mode); + } + + public void clearUsedPrefs() { + for (String prefsName : usedPrefs) { + getSharedPreferences(prefsName, 0).edit().clear().commit(); + } + + usedPrefs.clear(); + } + } + + private static class TestResources extends MockResources { + private final DisplayMetrics metrics; + + public TestResources() { + metrics = new DisplayMetrics(); + } + + @Override + public DisplayMetrics getDisplayMetrics() { + return metrics; + } + + public void setDensityDpi(int densityDpi) { + metrics.densityDpi = densityDpi; + } + } + + private static class TestDistribution extends Distribution { + final List<String> accessedFiles; + + public TestDistribution(Context context) { + super(context); + accessedFiles = new ArrayList<String>(); + } + + @Override + public File getDistributionFile(String name) { + accessedFiles.add(name); + + // Return null to ensure the ImageDownloader will go + // through a complete density lookup for each filename. + return null; + } + + public List<String> getAccessedFiles() { + return Collections.unmodifiableList(accessedFiles); + } + + public void resetAccessedFiles() { + accessedFiles.clear(); + } + } + + private TestContext context; + private TestResources resources; + private TestDistribution distribution; + private ImageDownloader downloader; + + protected void setUp() { + context = new TestContext(getInstrumentation().getTargetContext()); + resources = (TestResources) context.getResources(); + distribution = new TestDistribution(context); + downloader = new ImageDownloader(context, distribution); + } + + protected void tearDown() { + context.clearUsedPrefs(); + } + + private void triggerLoad(Uri uri) { + try { + downloader.load(uri, false); + } catch (IOException e) { + // Ignore any IO exceptions. + } + } + + private void checkAccessedFiles(String[] filenames) { + List<String> accessedFiles = distribution.getAccessedFiles(); + + for (int i = 0; i < filenames.length; i++) { + assertEquals(filenames[i], accessedFiles.get(i)); + } + } + + private void checkAccessedFilesForUri(Uri uri, int densityDpi, String[] filenames) { + resources.setDensityDpi(densityDpi); + triggerLoad(uri); + checkAccessedFiles(filenames); + distribution.resetAccessedFiles(); + } + + public void testAccessedFiles() { + // Filename only. + checkAccessedFilesForUri(Uri.parse("gecko.distribution://file"), + DisplayMetrics.DENSITY_MEDIUM, + new String[] { + "mdpi/file.png", + "xhdpi/file.png", + "hdpi/file.png" + }); + + // Directory and filename. + checkAccessedFilesForUri(Uri.parse("gecko.distribution://dir/file"), + DisplayMetrics.DENSITY_MEDIUM, + new String[] { + "dir/mdpi/file.png", + "dir/xhdpi/file.png", + "dir/hdpi/file.png" + }); + + // Sub-directories and filename. + checkAccessedFilesForUri(Uri.parse("gecko.distribution://dir/subdir/file"), + DisplayMetrics.DENSITY_MEDIUM, + new String[] { + "dir/subdir/mdpi/file.png", + "dir/subdir/xhdpi/file.png", + "dir/subdir/hdpi/file.png" + }); + } + + public void testDensityLookup() { + Uri uri = Uri.parse("gecko.distribution://file"); + + // Medium density + checkAccessedFilesForUri(uri, + DisplayMetrics.DENSITY_MEDIUM, + new String[] { + "mdpi/file.png", + "xhdpi/file.png", + "hdpi/file.png" + }); + + checkAccessedFilesForUri(uri, + DisplayMetrics.DENSITY_HIGH, + new String[] { + "hdpi/file.png", + "xxhdpi/file.png", + "xhdpi/file.png" + }); + + checkAccessedFilesForUri(uri, + DisplayMetrics.DENSITY_XHIGH, + new String[] { + "xhdpi/file.png", + "xxhdpi/file.png", + "mdpi/file.png" + }); + + + checkAccessedFilesForUri(uri, + DisplayMetrics.DENSITY_XXHIGH, + new String[] { + "xxhdpi/file.png", + "hdpi/file.png" + }); + } +} diff --git a/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestJarReader.java b/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestJarReader.java new file mode 100644 index 000000000..125ffe933 --- /dev/null +++ b/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestJarReader.java @@ -0,0 +1,124 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +package org.mozilla.tests.browser.junit3; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.Stack; + +import android.test.InstrumentationTestCase; +import org.mozilla.gecko.AppConstants; +import org.mozilla.gecko.util.FileUtils; +import org.mozilla.gecko.util.GeckoJarReader; + +import android.content.Context; + +/** + * A basic jar reader test. Tests reading a png from fennec's apk, as well as + * loading some invalid jar urls. + */ +public class TestJarReader extends InstrumentationTestCase { + public void testJarReader() { + final Context context = getInstrumentation().getTargetContext().getApplicationContext(); + String appPath = getInstrumentation().getTargetContext().getPackageResourcePath(); + assertNotNull(appPath); + + // Test reading a file from a jar url that looks correct. + String url = "jar:file://" + appPath + "!/" + AppConstants.OMNIJAR_NAME; + InputStream stream = GeckoJarReader.getStream(context, "jar:" + url + "!/chrome/chrome/content/branding/favicon32.png"); + assertNotNull(stream); + + // Test looking for an non-existent file in a jar. + url = "jar:file://" + appPath + "!/" + AppConstants.OMNIJAR_NAME; + stream = GeckoJarReader.getStream(context, "jar:" + url + "!/chrome/chrome/content/branding/nonexistent_file.png"); + assertNull(stream); + + // Test looking for a file that doesn't exist in the APK. + url = "jar:file://" + appPath + "!/" + "BAD" + AppConstants.OMNIJAR_NAME; + stream = GeckoJarReader.getStream(context, "jar:" + url + "!/chrome/chrome/content/branding/favicon32.png"); + assertNull(stream); + + // Test looking for a file that doesn't exist in the APK. + // Bug 1174922, prefixed string / length error. + url = "jar:file://" + appPath + "!/" + AppConstants.OMNIJAR_NAME + "BAD"; + stream = GeckoJarReader.getStream(context, "jar:" + url + "!/chrome/chrome/content/branding/favicon32.png"); + assertNull(stream); + + // Test looking for an jar with an invalid url. + url = "jar:file://" + appPath + "!" + "!/" + AppConstants.OMNIJAR_NAME; + stream = GeckoJarReader.getStream(context, "jar:" + url + "!/chrome/chrome/content/branding/nonexistent_file.png"); + assertNull(stream); + + // Test looking for a file that doesn't exist on disk. + url = "jar:file://" + appPath + "BAD" + "!/" + AppConstants.OMNIJAR_NAME; + stream = GeckoJarReader.getStream(context, "jar:" + url + "!/chrome/chrome/content/branding/favicon32.png"); + assertNull(stream); + } + + protected void assertExtractStream(String url) throws IOException { + final File file = GeckoJarReader.extractStream(getInstrumentation().getTargetContext(), url, getInstrumentation().getContext().getCacheDir(), ".test"); + assertNotNull(file); + try { + assertTrue(file.getName().endsWith("test")); + final String contents = FileUtils.readStringFromFile(file); + assertNotNull(contents); + assertTrue(contents.length() > 0); + } finally { + file.delete(); + } + } + + public void testExtractStream() throws IOException { + String appPath = getInstrumentation().getTargetContext().getPackageResourcePath(); + assertNotNull(appPath); + + // We don't have a lot of good files to choose from. package-name.txt isn't included in Gradle APKs. + assertExtractStream("jar:file://" + appPath + "!/resources.arsc"); + + final String url = GeckoJarReader.getJarURL(getInstrumentation().getTargetContext(), "chrome.manifest"); + assertExtractStream(url); + + // Now use an extracted copy of chrome.manifest to test further. + final File file = GeckoJarReader.extractStream(getInstrumentation().getTargetContext(), url, getInstrumentation().getContext().getCacheDir(), ".test"); + assertNotNull(file); + try { + assertExtractStream("file://" + file.getAbsolutePath()); // file:// URI. + assertExtractStream(file.getAbsolutePath()); // Vanilla path. + } finally { + file.delete(); + } + } + + protected void assertExtractStreamFails(String url) throws IOException { + final File file = GeckoJarReader.extractStream(getInstrumentation().getTargetContext(), url, getInstrumentation().getContext().getCacheDir(), ".test"); + assertNull(file); + } + + public void testExtractStreamFailureCases() throws IOException { + String appPath = getInstrumentation().getTargetContext().getPackageResourcePath(); + assertNotNull(appPath); + + // First, a bad APK. + assertExtractStreamFails("jar:file://" + appPath + "BAD!/resources.arsc"); + + // Second, a bad file in the APK. + assertExtractStreamFails("jar:file://" + appPath + "!/BADresources.arsc"); + + // Now a bad file in the omnijar. + final String badUrl = GeckoJarReader.getJarURL(getInstrumentation().getTargetContext(), "BADchrome.manifest"); + assertExtractStreamFails(badUrl); + + // Now use an extracted copy of chrome.manifest to test further. + final String goodUrl = GeckoJarReader.getJarURL(getInstrumentation().getTargetContext(), "chrome.manifest"); + final File file = GeckoJarReader.extractStream(getInstrumentation().getTargetContext(), goodUrl, getInstrumentation().getContext().getCacheDir(), ".test"); + assertNotNull(file); + try { + assertExtractStreamFails("file://" + file.getAbsolutePath() + "BAD"); // Bad file:// URI. + assertExtractStreamFails(file.getAbsolutePath() + "BAD"); //Bad vanilla path. + } finally { + file.delete(); + } + } +} diff --git a/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestRawResource.java b/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestRawResource.java new file mode 100644 index 000000000..8e27cbe9c --- /dev/null +++ b/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestRawResource.java @@ -0,0 +1,66 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +package org.mozilla.tests.browser.junit3; + +import android.content.Context; +import android.content.res.Resources; +import android.test.InstrumentationTestCase; +import android.test.mock.MockContext; +import android.test.mock.MockResources; +import org.mozilla.gecko.util.RawResource; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * Tests whether RawResource.getAsString() produces the right String + * result after reading the returned raw resource's InputStream. + */ +public class TestRawResource extends InstrumentationTestCase { + private static final int RAW_RESOURCE_ID = 1; + private static final String RAW_CONTENTS = "RAW"; + + private static class TestContext extends MockContext { + private final Resources resources; + + public TestContext() { + resources = new TestResources(); + } + + @Override + public Resources getResources() { + return resources; + } + } + + /** + * Browser instrumentation tests can't have access to test-only + * resources (bug 994135) yet so we mock the access to resources + * for now. + */ + private static class TestResources extends MockResources { + @Override + public InputStream openRawResource(int id) { + if (id == RAW_RESOURCE_ID) { + return new ByteArrayInputStream(RAW_CONTENTS.getBytes()); + } + + return null; + } + } + + public void testGet() { + Context context = new TestContext(); + String result; + + try { + result = RawResource.getAsString(context, RAW_RESOURCE_ID); + } catch (IOException e) { + result = null; + } + + assertEquals(RAW_CONTENTS, result); + } +} diff --git a/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestSuggestedSites.java b/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestSuggestedSites.java new file mode 100644 index 000000000..c29c369d6 --- /dev/null +++ b/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestSuggestedSites.java @@ -0,0 +1,473 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +package org.mozilla.tests.browser.junit3; + +import android.content.ContentResolver; +import android.content.Context; +import android.content.SharedPreferences; +import android.content.res.Resources; +import android.database.ContentObserver; +import android.database.Cursor; +import android.net.Uri; +import android.os.SystemClock; +import android.test.InstrumentationTestCase; +import android.test.RenamingDelegatingContext; +import android.test.mock.MockResources; +import org.json.JSONArray; +import org.json.JSONObject; +import org.mozilla.gecko.R; +import org.mozilla.gecko.GeckoSharedPrefs; +import org.mozilla.gecko.Locales; +import org.mozilla.gecko.db.BrowserContract; +import org.mozilla.gecko.db.SuggestedSites; +import org.mozilla.gecko.distribution.Distribution; +import org.mozilla.gecko.preferences.GeckoPreferences; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +public class TestSuggestedSites extends InstrumentationTestCase { + private static class TestContext extends RenamingDelegatingContext { + private static final String PREFIX = "TestSuggestedSites-"; + + private final Resources resources; + private final Set<String> usedPrefs; + + public TestContext(Context context) { + super(context, PREFIX); + resources = new TestResources(); + usedPrefs = Collections.synchronizedSet(new HashSet<String>()); + } + + @Override + public Resources getResources() { + return resources; + } + + @Override + public SharedPreferences getSharedPreferences(String name, int mode) { + usedPrefs.add(name); + return super.getSharedPreferences(PREFIX + name, mode); + } + + public void clearUsedPrefs() { + for (String prefsName : usedPrefs) { + getSharedPreferences(prefsName, 0).edit().clear().commit(); + } + + usedPrefs.clear(); + } + } + + private static class TestResources extends MockResources { + private String suggestedSites; + + @Override + public InputStream openRawResource(int id) { + if (id == R.raw.suggestedsites && suggestedSites != null) { + return new ByteArrayInputStream(suggestedSites.getBytes()); + } + + return null; + } + + public void setSuggestedSitesResource(String suggestedSites) { + this.suggestedSites = suggestedSites; + } + } + + private static class TestDistribution extends Distribution { + private final Map<Locale, File> filesPerLocale; + + public TestDistribution(Context context) { + super(context); + this.filesPerLocale = new HashMap<Locale, File>(); + } + + @Override + public File getDistributionFile(String name) { + for (Locale locale : filesPerLocale.keySet()) { + if (name.startsWith("suggestedsites/locales/" + Locales.getLanguageTag(locale))) { + return filesPerLocale.get(locale); + } + } + + return null; + } + + @Override + public boolean exists() { + return true; + } + + public void setFileForLocale(Locale locale, File file) { + filesPerLocale.put(locale, file); + } + + public void start() { + doInit(); + } + } + + class TestObserver extends ContentObserver { + private final CountDownLatch changeLatch; + + public TestObserver(CountDownLatch changeLatch) { + super(null); + this.changeLatch = changeLatch; + } + + @Override + public void onChange(boolean selfChange) { + changeLatch.countDown(); + } + } + + private static final int DEFAULT_LIMIT = 6; + + private static final String DIST_PREFIX = "dist"; + + private TestContext context; + private TestResources resources; + private List<File> tempFiles; + + private String generateSites(int n) { + return generateSites(n, ""); + } + + private String generateSites(int n, String prefix) { + JSONArray sites = new JSONArray(); + + try { + for (int i = 0; i < n; i++) { + JSONObject site = new JSONObject(); + site.put("url", prefix + "url" + i); + site.put("title", prefix + "title" + i); + site.put("imageurl", prefix + "imageUrl" + i); + site.put("bgcolor", prefix + "bgColor" + i); + + sites.put(site); + } + } catch (Exception e) { + return ""; + } + + return sites.toString(); + } + + private File createDistSuggestedSitesFile(int n) { + FileOutputStream fos = null; + + try { + File distFile = File.createTempFile("distrosites", ".json", + context.getCacheDir()); + + fos = new FileOutputStream(distFile); + fos.write(generateSites(n, DIST_PREFIX).getBytes()); + + return distFile; + } catch (IOException e) { + fail("Failed to create temp suggested sites file"); + } finally { + if (fos != null) { + try { + fos.close(); + } catch (IOException e) { + // Ignore. + } + } + } + + return null; + } + + private void checkCursorCount(String content, int expectedCount) { + checkCursorCount(content, expectedCount, DEFAULT_LIMIT); + } + + private void checkCursorCount(String content, int expectedCount, int limit) { + resources.setSuggestedSitesResource(content); + Cursor c = new SuggestedSites(context).get(limit); + assertEquals(expectedCount, c.getCount()); + c.close(); + } + + protected void setUp() { + context = new TestContext(getInstrumentation().getTargetContext()); + resources = (TestResources) context.getResources(); + tempFiles = new ArrayList<File>(); + } + + protected void tearDown() { + context.clearUsedPrefs(); + for (File f : tempFiles) { + f.delete(); + } + } + + public void testCount() { + // Empty array = empty cursor + checkCursorCount(generateSites(0), 0); + + // 2 items = cursor with 2 rows + checkCursorCount(generateSites(2), 2); + + // 10 items with lower limit = cursor respects limit + checkCursorCount(generateSites(10), 3, 3); + } + + public void testEmptyCursor() { + // Null resource = empty cursor + checkCursorCount(null, 0); + + // Empty string = empty cursor + checkCursorCount("", 0); + + // Invalid json string = empty cursor + checkCursorCount("{ broken: }", 0); + } + + public void testCursorContent() { + resources.setSuggestedSitesResource(generateSites(3)); + + Cursor c = new SuggestedSites(context).get(DEFAULT_LIMIT); + assertEquals(3, c.getCount()); + + c.moveToPosition(-1); + while (c.moveToNext()) { + int position = c.getPosition(); + + String url = c.getString(c.getColumnIndexOrThrow(BrowserContract.SuggestedSites.URL)); + assertEquals("url" + position, url); + + String title = c.getString(c.getColumnIndexOrThrow(BrowserContract.SuggestedSites.TITLE)); + assertEquals("title" + position, title); + } + + c.close(); + } + + public void testExcludeUrls() { + resources.setSuggestedSitesResource(generateSites(6)); + + List<String> excludedUrls = new ArrayList<String>(3); + excludedUrls.add("url1"); + excludedUrls.add("url3"); + excludedUrls.add("url5"); + + List<String> includedUrls = new ArrayList<String>(3); + includedUrls.add("url0"); + includedUrls.add("url2"); + includedUrls.add("url4"); + + Cursor c = new SuggestedSites(context).get(DEFAULT_LIMIT, excludedUrls); + + c.moveToPosition(-1); + while (c.moveToNext()) { + String url = c.getString(c.getColumnIndexOrThrow(BrowserContract.SuggestedSites.URL)); + assertFalse(excludedUrls.contains(url)); + assertTrue(includedUrls.contains(url)); + } + + c.close(); + } + + public void testHiddenSites() { + resources.setSuggestedSitesResource(generateSites(6)); + + List<String> visibleUrls = new ArrayList<String>(3); + visibleUrls.add("url3"); + visibleUrls.add("url4"); + visibleUrls.add("url5"); + + List<String> hiddenUrls = new ArrayList<String>(3); + hiddenUrls.add("url0"); + hiddenUrls.add("url1"); + hiddenUrls.add("url2"); + + // Add mocked hidden sites to SharedPreferences. + StringBuilder hiddenUrlBuilder = new StringBuilder(); + for (String s : hiddenUrls) { + hiddenUrlBuilder.append(" "); + hiddenUrlBuilder.append(Uri.encode(s)); + } + + final String hiddenPref = hiddenUrlBuilder.toString(); + GeckoSharedPrefs.forProfile(context).edit() + .putString(SuggestedSites.PREF_SUGGESTED_SITES_HIDDEN, hiddenPref) + .commit(); + + Cursor c = new SuggestedSites(context).get(DEFAULT_LIMIT); + assertEquals(Math.min(3, DEFAULT_LIMIT), c.getCount()); + + c.moveToPosition(-1); + while (c.moveToNext()) { + String url = c.getString(c.getColumnIndexOrThrow(BrowserContract.SuggestedSites.URL)); + assertFalse(hiddenUrls.contains(url)); + assertTrue(visibleUrls.contains(url)); + } + + c.close(); + } + + public void testImageUrlAndBgColor() { + final int count = 3; + resources.setSuggestedSitesResource(generateSites(count)); + + SuggestedSites suggestedSites = new SuggestedSites(context); + + // Suggested sites hasn't been loaded yet. + for (int i = 0; i < count; i++) { + String url = "url" + i; + assertFalse(suggestedSites.contains(url)); + assertNull(suggestedSites.getImageUrlForUrl(url)); + assertNull(suggestedSites.getBackgroundColorForUrl(url)); + } + + Cursor c = suggestedSites.get(DEFAULT_LIMIT); + c.moveToPosition(-1); + + // We should have cached results after the get() call. + while (c.moveToNext()) { + String url = c.getString(c.getColumnIndexOrThrow(BrowserContract.SuggestedSites.URL)); + assertTrue(suggestedSites.contains(url)); + assertEquals("imageUrl" + c.getPosition(), + suggestedSites.getImageUrlForUrl(url)); + assertEquals("bgColor" + c.getPosition(), + suggestedSites.getBackgroundColorForUrl(url)); + } + c.close(); + + // No valid values for unknown URLs. + assertFalse(suggestedSites.contains("foo")); + assertNull(suggestedSites.getImageUrlForUrl("foo")); + assertNull(suggestedSites.getBackgroundColorForUrl("foo")); + } + + public void testLocaleChanges() { + resources.setSuggestedSitesResource(generateSites(3)); + + SuggestedSites suggestedSites = new SuggestedSites(context); + + // Initial load with predefined locale + Cursor c = suggestedSites.get(DEFAULT_LIMIT, Locale.UK); + assertEquals(3, c.getCount()); + c.close(); + + resources.setSuggestedSitesResource(generateSites(5)); + + // Second load with same locale should return same results + // even though the contents of the resource have changed. + c = suggestedSites.get(DEFAULT_LIMIT, Locale.UK); + assertEquals(3, c.getCount()); + c.close(); + + // Changing the locale forces the cached list to be refreshed. + c = suggestedSites.get(DEFAULT_LIMIT, Locale.US); + assertEquals(5, c.getCount()); + c.close(); + } + + public void testDistribution() { + final int DIST_COUNT = 2; + final int DEFAULT_COUNT = 3; + + File sitesFile = new File(context.getCacheDir(), + "suggestedsites-" + SystemClock.uptimeMillis() + ".json"); + tempFiles.add(sitesFile); + assertFalse(sitesFile.exists()); + + File distFile = createDistSuggestedSitesFile(DIST_COUNT); + tempFiles.add(distFile); + assertTrue(distFile.exists()); + + final CountDownLatch changeLatch = new CountDownLatch(1); + + // Watch for change notifications on suggested sites. + ContentResolver cr = context.getContentResolver(); + ContentObserver observer = new TestObserver(changeLatch); + cr.registerContentObserver(BrowserContract.SuggestedSites.CONTENT_URI, + false, observer); + + // Init distribution with the mock file. + TestDistribution distribution = new TestDistribution(context); + distribution.setFileForLocale(Locale.getDefault(), distFile); + distribution.start(); + + // Init suggested sites with default values. + resources.setSuggestedSitesResource(generateSites(DEFAULT_COUNT)); + SuggestedSites suggestedSites = + new SuggestedSites(context, distribution, sitesFile); + + // The initial query will not contain the distribution sites + // yet. This will happen asynchronously once the distribution + // is installed. + Cursor c1 = null; + try { + c1 = suggestedSites.get(DEFAULT_LIMIT); + assertEquals(DEFAULT_COUNT, c1.getCount()); + } finally { + if (c1 != null) { + c1.close(); + } + } + + try { + assertTrue(changeLatch.await(5, TimeUnit.SECONDS)); + } catch (InterruptedException ie) { + fail("No change notification after fetching distribution file"); + } + + // Target file should exist after distribution is deployed. + assertTrue(sitesFile.exists()); + cr.unregisterContentObserver(observer); + + Cursor c2 = null; + try { + c2 = suggestedSites.get(DEFAULT_LIMIT); + + // The next query should contain the distribution contents. + assertEquals(DIST_COUNT + DEFAULT_COUNT, c2.getCount()); + + // The first items should be from the distribution + for (int i = 0; i < DIST_COUNT; i++) { + c2.moveToPosition(i); + + String url = c2.getString(c2.getColumnIndexOrThrow(BrowserContract.SuggestedSites.URL)); + assertEquals(DIST_PREFIX + "url" + i, url); + + String title = c2.getString(c2.getColumnIndexOrThrow(BrowserContract.SuggestedSites.TITLE)); + assertEquals(DIST_PREFIX + "title" + i, title); + } + + // The remaining items should be the default ones + for (int i = 0; i < c2.getCount() - DIST_COUNT; i++) { + c2.moveToPosition(i + DIST_COUNT); + + String url = c2.getString(c2.getColumnIndexOrThrow(BrowserContract.SuggestedSites.URL)); + assertEquals("url" + i, url); + + String title = c2.getString(c2.getColumnIndexOrThrow(BrowserContract.SuggestedSites.TITLE)); + assertEquals("title" + i, title); + } + } finally { + if (c2 != null) { + c2.close(); + } + } + } +} diff --git a/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/harness/BrowserInstrumentationTestRunner.java b/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/harness/BrowserInstrumentationTestRunner.java new file mode 100644 index 000000000..36c60d92e --- /dev/null +++ b/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/harness/BrowserInstrumentationTestRunner.java @@ -0,0 +1,33 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +package org.mozilla.tests.browser.junit3.harness; + +import android.os.Bundle; +import android.test.AndroidTestRunner; +import android.test.InstrumentationTestRunner; +import android.util.Log; + +/** + * A test runner that installs a special test listener. + * <p> + * In future, this listener will turn JUnit 3 test events into log messages in + * the format that Mochitest parsers understand. + */ +public class BrowserInstrumentationTestRunner extends InstrumentationTestRunner { + private static final String LOG_TAG = "BInstTestRunner"; + + @Override + public void onCreate(Bundle arguments) { + Log.d(LOG_TAG, "onCreate"); + super.onCreate(arguments); + } + + @Override + protected AndroidTestRunner getAndroidTestRunner() { + Log.d(LOG_TAG, "getAndroidTestRunner"); + AndroidTestRunner testRunner = super.getAndroidTestRunner(); + testRunner.addTestListener(new BrowserTestListener()); + return testRunner; + } +} diff --git a/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/harness/BrowserTestListener.java b/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/harness/BrowserTestListener.java new file mode 100644 index 000000000..026d5065f --- /dev/null +++ b/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/harness/BrowserTestListener.java @@ -0,0 +1,42 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +package org.mozilla.tests.browser.junit3.harness; + +import android.util.Log; +import junit.framework.AssertionFailedError; +import junit.framework.Test; +import junit.framework.TestListener; + +/** + * BrowserTestListener turns JUnit 3 test events into log messages in the format + * that Mochitest parsers understand. + * <p> + * The idea is that, on infrastructure, we'll be able to use the same test + * parsing code for Browser JUnit 3 tests as we do for Robocop tests. + * <p> + * In future, that is! + */ +public class BrowserTestListener implements TestListener { + public static final String LOG_TAG = "BTestListener"; + + @Override + public void startTest(Test test) { + Log.d(LOG_TAG, "startTest: " + test); + } + + @Override + public void endTest(Test test) { + Log.d(LOG_TAG, "endTest: " + test); + } + + @Override + public void addFailure(Test test, AssertionFailedError t) { + Log.d(LOG_TAG, "addFailure: " + test); + } + + @Override + public void addError(Test test, Throwable t) { + Log.d(LOG_TAG, "addError: " + test); + } +} |