summaryrefslogtreecommitdiff
path: root/android
diff options
context:
space:
mode:
authorBrad Leege <bleege@gmail.com>2015-09-16 16:47:36 -0400
committerBrad Leege <bleege@gmail.com>2015-09-16 16:47:36 -0400
commit341c95957c1a785813e7c15e57f8aee8a8c23318 (patch)
tree9c4539d2f05dc350b36e77623868a6c57f58f07e /android
parentadfd66e8bbcf5ca03641ab60492054adc96ad4c5 (diff)
parentfee31b05b9e698f8755a867f7c219d7b7de987c4 (diff)
downloadqtlocation-mapboxgl-341c95957c1a785813e7c15e57f8aee8a8c23318.tar.gz
Merge branch '2317-espresso' of git://github.com/zugaldia/mapbox-gl-native into zugaldia-2317-espresso
Diffstat (limited to 'android')
-rw-r--r--android/java/MapboxGLAndroidSDKTestApp/README.md81
-rw-r--r--android/java/MapboxGLAndroidSDKTestApp/build.gradle11
-rw-r--r--android/java/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxgl/testapp/BaseTest.java46
-rw-r--r--android/java/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxgl/testapp/MainActivityScreenTest.java66
-rw-r--r--android/java/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxgl/testapp/MainActivityTest.java291
-rw-r--r--android/java/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxgl/testapp/SecondMapActivityTest.java41
-rw-r--r--android/java/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxgl/testapp/utils/ScreenshotUtil.java130
-rw-r--r--android/java/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml1
-rw-r--r--android/java/MapboxGLAndroidSDKTestApp/src/test/java/BoundingBoxTest.java15
-rw-r--r--android/java/MapboxGLAndroidSDKTestApp/src/test/java/CoordinateRegionTest.java54
-rw-r--r--android/java/MapboxGLAndroidSDKTestApp/src/test/java/CoordinateSpanTest.java48
-rw-r--r--android/java/MapboxGLAndroidSDKTestApp/src/test/java/LatLngTest.java98
-rw-r--r--android/java/MapboxGLAndroidSDKTestApp/src/test/java/LatLngZoomTest.java15
-rw-r--r--android/java/MapboxGLAndroidSDKTestApp/src/test/java/ProjectedMetersTest.java15
14 files changed, 912 insertions, 0 deletions
diff --git a/android/java/MapboxGLAndroidSDKTestApp/README.md b/android/java/MapboxGLAndroidSDKTestApp/README.md
new file mode 100644
index 0000000000..646f29c4b4
--- /dev/null
+++ b/android/java/MapboxGLAndroidSDKTestApp/README.md
@@ -0,0 +1,81 @@
+# Mapbox GL Test App
+
+## Testing
+
+### Running Espresso tests on a device
+
+This test project comes with all the required Android Testing Support Library dependencies
+in the Gradle file. Tests are under the `app/src/androidTest` folder.
+
+Note that before running your tests, you might want to turn off animations on your test device.
+It's a known issue that leaving system animations turned on in a test device
+(window animation scale, transition animation scale, animator duration scale)
+might cause unexpected results, or may lead tests to fail.
+
+To create a new run configuration:
+* Click on Run -> Edit Configurations...
+* Click on the plus sign and then on "Android Tests"
+* Give a name to the configuration, e.g. `TestAppTests`
+* Choose the `MapboxGLAndroidSDKTestApp` module
+* Choose `android.support.test.runner.AndroidJUnitRunner` as the instrumentation runner
+* Click OK to save the new configuration
+
+You can now run this configuration from the main toolbar dropdown menu.
+
+### Running Espresso tests on AWS Device Farm
+
+On a terminal, within `mapbox-gl-native/android/java`,
+run the tests (`cC` stands for `connectedCheck`):
+
+```
+$ ./gradlew cC -p MapboxGLAndroidSDKTestApp
+```
+
+Then:
+* Go to your AWS Console and choose Device Farm.
+* Create a new project, e.g. `MapboxGLAndroidSDKTestApp`
+* On step 1, upload the APK in `mapbox-gl-native/android/java/MapboxGLAndroidSDKTestApp/build/outputs/apk/MapboxGLAndroidSDKTestApp-debug-unaligned.apk`
+* On step 2, choose Instrumentation, test filter is `com.mapbox.mapboxgl.testapp.MainActivityTest` and upload the APK in `mapbox-gl-native/android/java/MapboxGLAndroidSDKTestApp/build/outputs/apk/MapboxGLAndroidSDKTestApp-debug-androidTest-unaligned.apk`
+* On step 3, choose a device pool. E.g. Top Devices
+* On step 4, customize your device state (if needed)
+* Finally, confirm the configuration and run the tests.
+
+On Step 2, you can also separate by commas different classes: `com.mapbox.mapboxgl.testapp.MainActivityTest,com.mapbox.mapboxgl.testapp.MainActivityScreenTest`
+
+If you have no tests for your app, or want to test some random user behaviour,
+you can just choose "Built-in: Fuzz" in step 2.
+
+### Running pure JUnit tests
+
+These tests run on a local JVM on your development machine and they are extremely fast to run
+(as compared to Espresso). These tests are located under `src/test/java`. To run them you switch
+to the Unit Tests build variant, then right click the corresponding test class or method
+and select "Run ...".
+
+You can also have a run configuration:
+* Click on Run -> Edit Configurations...
+* Click on "Junit Tests"
+* Give a name to the configuration, e.g. `JUnit tests`
+* As "Test Kind", choose "All in directory"
+* As folder, choose the following folder: `mapbox-gl-native/android/java/MapboxGLAndroidSDKTestApp/src/test/java`
+* Click OK to save the new configuration
+
+You can also run the tests from the command line with:
+
+```
+$ ./gradlew test --continue -p MapboxGLAndroidSDKTestApp
+```
+
+### Running the UI/Application Exerciser Monkey
+
+Similar to the "Built-in: Fuzz" test mentioned above, Android provides
+[Monkey](http://developer.android.com/tools/help/monkey.html),
+"a program that runs on your emulator or device and generates pseudo-random streams of user events
+such as clicks, touches, or gestures, as well as a number of system-level events."
+
+To exercise Monkey on the test app, install the package on the device (e.g. via Android Studio)
+and then:
+
+```
+$ adb shell monkey -p com.mapbox.mapboxgl.testapp -v 500
+```
diff --git a/android/java/MapboxGLAndroidSDKTestApp/build.gradle b/android/java/MapboxGLAndroidSDKTestApp/build.gradle
index 172f31d0fc..98c26912ff 100644
--- a/android/java/MapboxGLAndroidSDKTestApp/build.gradle
+++ b/android/java/MapboxGLAndroidSDKTestApp/build.gradle
@@ -51,6 +51,9 @@ android {
targetSdkVersion 23
versionCode 4
versionName "0.1.3"
+
+ // Specify AndroidJUnitRunner as the default test instrumentation runner
+ testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
compileOptions {
@@ -61,6 +64,7 @@ android {
packagingOptions {
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/NOTICE.txt'
+ exclude 'LICENSE.txt'
}
lintOptions {
@@ -89,6 +93,13 @@ dependencies {
compile('com.crashlytics.sdk.android:crashlytics:2.5.1@aar') {
transitive = true;
}
+
+ // Testing dependencies
+ testCompile 'junit:junit:4.12'
+ testCompile 'org.mockito:mockito-core:1.+'
+ androidTestCompile 'com.android.support.test:runner:0.4'
+ androidTestCompile 'com.android.support.test:rules:0.4'
+ androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.1'
}
checkstyle {
diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxgl/testapp/BaseTest.java b/android/java/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxgl/testapp/BaseTest.java
new file mode 100644
index 0000000000..f3ae2018c0
--- /dev/null
+++ b/android/java/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxgl/testapp/BaseTest.java
@@ -0,0 +1,46 @@
+package com.mapbox.mapboxgl.testapp;
+
+import android.app.Activity;
+import android.support.test.InstrumentationRegistry;
+import android.test.ActivityInstrumentationTestCase2;
+
+import com.mapbox.mapboxgl.testapp.utils.ScreenshotUtil;
+
+import org.junit.Before;
+
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.assertion.ViewAssertions.matches;
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+
+/**
+ * Base Espresso class for all tests, helps working with ActivityInstrumentationTestCase2
+ */
+public class BaseTest {
+
+ /*
+ * Shortcuts for common UI tests
+ */
+
+ protected void checkViewIsDisplayed(int id) {
+ onView(withId(id))
+ .check(matches(isDisplayed()));
+ }
+
+ /*
+ * Screenshots logic
+ */
+
+ protected void takeNamedScreenshot(final Activity activity, final String name) {
+
+ // Screenshots need to be taken on the UI thread
+ activity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ ScreenshotUtil.take(activity, name);
+ }
+ });
+
+ }
+
+}
diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxgl/testapp/MainActivityScreenTest.java b/android/java/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxgl/testapp/MainActivityScreenTest.java
new file mode 100644
index 0000000000..80dc0aa774
--- /dev/null
+++ b/android/java/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxgl/testapp/MainActivityScreenTest.java
@@ -0,0 +1,66 @@
+package com.mapbox.mapboxgl.testapp;
+
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.action.ViewActions.click;
+import static android.support.test.espresso.action.ViewActions.doubleClick;
+import static android.support.test.espresso.matcher.ViewMatchers.withContentDescription;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static android.support.test.espresso.matcher.ViewMatchers.withText;
+
+/**
+ * Tests on MainActivity with screenshots
+ */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class MainActivityScreenTest extends BaseTest {
+
+ private final static String HOME_BUTTON_STRING = "Navigate up";
+
+ @Rule
+ public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule<>(
+ MainActivity.class);
+
+ private MainActivity mActivity = null;
+
+ @Before
+ public void setActivity() {
+ mActivity = mActivityRule.getActivity();
+ }
+
+ @Test
+ public void testSanity() {
+ checkViewIsDisplayed(R.id.mainMapView);
+ }
+
+ /*
+ * Take a screenshot of Mapbox Streets to monitor #1649
+ */
+
+ @Test
+ public void testMapboxStreetsBlackAndWhite() {
+ // Click home and switch to Mapbox streets
+ onView(withContentDescription(HOME_BUTTON_STRING))
+ .perform(click());
+ onView(withText(R.string.styleMapboxStreets))
+ .perform(click());
+
+ // Zoom in
+ onView(withId(R.id.mainMapView))
+ .perform(doubleClick());
+ onView(withId(R.id.mainMapView))
+ .perform(doubleClick());
+
+ // Standard screenshot
+ takeNamedScreenshot(mActivity, "testMapboxStreetsBlackAndWhite");
+ }
+
+}
diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxgl/testapp/MainActivityTest.java b/android/java/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxgl/testapp/MainActivityTest.java
new file mode 100644
index 0000000000..b880176fe6
--- /dev/null
+++ b/android/java/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxgl/testapp/MainActivityTest.java
@@ -0,0 +1,291 @@
+package com.mapbox.mapboxgl.testapp;
+
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.action.ViewActions.click;
+import static android.support.test.espresso.action.ViewActions.doubleClick;
+import static android.support.test.espresso.action.ViewActions.longClick;
+import static android.support.test.espresso.action.ViewActions.swipeDown;
+import static android.support.test.espresso.action.ViewActions.swipeLeft;
+import static android.support.test.espresso.action.ViewActions.swipeRight;
+import static android.support.test.espresso.action.ViewActions.swipeUp;
+import static android.support.test.espresso.assertion.ViewAssertions.matches;
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static android.support.test.espresso.matcher.ViewMatchers.withContentDescription;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static android.support.test.espresso.matcher.ViewMatchers.withText;
+import static org.hamcrest.Matchers.not;
+
+/**
+ * Tests on MainActivity
+ */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class MainActivityTest extends BaseTest {
+
+ private final static String HOME_BUTTON_STRING = "Navigate up";
+
+ @Rule
+ public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule<>(
+ MainActivity.class);
+
+ private MainActivity mActivity = null;
+
+ @Before
+ public void setActivity() {
+ mActivity = mActivityRule.getActivity();
+ }
+
+ /*
+ * Note that we need to keep the `test` prefix if we want to be able to run these
+ * tests on AWS Device Farm, annotations are not enough:
+ * https://github.com/awslabs/aws-device-farm-sample-app-for-android/issues/5#issuecomment-138258444
+ */
+
+ @Test
+ public void testSanity() {
+ onView(withId(R.id.mainMapView))
+ .check(matches(isDisplayed()));
+ }
+
+ /*
+ * Check UI ids are visible
+ */
+
+ @Test
+ public void testDrawerLayoutIsDisplayed() {
+ onView(withId(R.id.drawer_layout))
+ .check(matches(isDisplayed()));
+ }
+
+ @Test
+ public void testToolbarIsDisplayed() {
+ onView(withId(R.id.toolbar))
+ .check(matches(isDisplayed()));
+ }
+
+ @Test
+ public void testContentFrameIsDisplayed() {
+ onView(withId(R.id.content_frame))
+ .check(matches(isDisplayed()));
+ }
+
+ @Test
+ public void testViewFpsIsDisplayed() {
+ // By default, R.id.view_fps is not displayed
+ onView(withId(R.id.view_fps))
+ .check(matches(not(isDisplayed())));
+ }
+
+ @Test
+ public void testLocationFABIsDisplayed() {
+ onView(withId(R.id.locationFAB))
+ .check(matches(isDisplayed()));
+ }
+
+ @Test
+ public void testNavViewIsNotDisplayed() {
+ // By default, nav_view not displayed
+ onView(withId(R.id.nav_view))
+ .check(matches(not(isDisplayed())));
+ }
+
+ @Test
+ public void testNavViewIsDisplayed() {
+ // However, it's displayed when we click the home icon
+ onView(withContentDescription(HOME_BUTTON_STRING))
+ .perform(click());
+ onView(withId(R.id.nav_view))
+ .check(matches(isDisplayed()));
+ }
+
+ /*
+ * Some more tests on the map view (clicks, gestures)
+ */
+
+ @Test
+ public void testClickMap() {
+ onView(withId(R.id.mainMapView))
+ .perform(click())
+ .check(matches(isDisplayed()));
+ }
+
+ @Test
+ public void testDoubleClickMap() {
+ onView(withId(R.id.mainMapView))
+ .perform(doubleClick())
+ .check(matches(isDisplayed()));
+ }
+
+ @Test
+ public void testLongClickMap() {
+ onView(withId(R.id.mainMapView))
+ .perform(longClick())
+ .check(matches(isDisplayed()));
+ }
+
+ @Test
+ public void testSwipeLeftMap() {
+ onView(withId(R.id.mainMapView))
+ .perform(swipeLeft())
+ .check(matches(isDisplayed()));
+ }
+
+ @Test
+ public void testSwipeRightMap() {
+ onView(withId(R.id.mainMapView))
+ .perform(swipeRight())
+ .check(matches(isDisplayed()));
+ }
+
+ @Test
+ public void testSwipeDownMap() {
+ onView(withId(R.id.mainMapView))
+ .perform(swipeDown())
+ .check(matches(isDisplayed()));
+ }
+
+ @Test
+ public void testSwipeUpMap() {
+ onView(withId(R.id.mainMapView))
+ .perform(swipeUp())
+ .check(matches(isDisplayed()));
+ }
+
+ /*
+ * Test the main drawer options
+ */
+
+ @Test
+ public void testNavViewActionDebug() {
+ onView(withContentDescription(HOME_BUTTON_STRING))
+ .perform(click());
+ onView(withText(R.string.action_debug))
+ .perform(click());
+
+ // Clicking the item closes the drawer
+ onView(withId(R.id.nav_view))
+ .check(matches(not(isDisplayed())));
+ }
+
+ @Test
+ public void testNavViewActionPointAnnotations() {
+ onView(withContentDescription(HOME_BUTTON_STRING))
+ .perform(click());
+ onView(withText(R.string.action_point_annotations))
+ .perform(click());
+
+ // Clicking the item closes the drawer
+ onView(withId(R.id.nav_view))
+ .check(matches(not(isDisplayed())));
+ }
+
+ @Test
+ public void testNavViewActionCompass() {
+ onView(withContentDescription(HOME_BUTTON_STRING))
+ .perform(click());
+ onView(withText(R.string.action_compass))
+ .perform(click());
+
+ // Clicking the item closes the drawer
+ onView(withId(R.id.nav_view))
+ .check(matches(not(isDisplayed())));
+ }
+
+ @Test
+ public void testNavViewStyleMapboxStreets() {
+ onView(withContentDescription(HOME_BUTTON_STRING))
+ .perform(click());
+ onView(withText(R.string.styleMapboxStreets))
+ .perform(click());
+
+ // Clicking the item closes the drawer
+ onView(withId(R.id.nav_view))
+ .check(matches(not(isDisplayed())));
+ }
+
+ @Test
+ public void testNavViewStyleEmerald() {
+ onView(withContentDescription(HOME_BUTTON_STRING))
+ .perform(click());
+ onView(withText(R.string.styleEmerald))
+ .perform(click());
+
+ // Clicking the item closes the drawer
+ onView(withId(R.id.nav_view))
+ .check(matches(not(isDisplayed())));
+ }
+
+ @Test
+ public void testNavViewStyleLight() {
+ onView(withContentDescription(HOME_BUTTON_STRING))
+ .perform(click());
+ onView(withText(R.string.styleLight))
+ .perform(click());
+
+ // Clicking the item closes the drawer
+ onView(withId(R.id.nav_view))
+ .check(matches(not(isDisplayed())));
+ }
+
+ @Test
+ public void testNavViewStyleDark() {
+ onView(withContentDescription(HOME_BUTTON_STRING))
+ .perform(click());
+ onView(withText(R.string.styleDark))
+ .perform(click());
+
+ // Clicking the item closes the drawer
+ onView(withId(R.id.nav_view))
+ .check(matches(not(isDisplayed())));
+ }
+
+ @Test
+ public void testNavViewStyleSatellite() {
+ onView(withContentDescription(HOME_BUTTON_STRING))
+ .perform(click());
+ onView(withText(R.string.styleSatellite))
+ .perform(click());
+
+ // Clicking the item closes the drawer
+ onView(withId(R.id.nav_view))
+ .check(matches(not(isDisplayed())));
+ }
+
+ /*
+ * We can also check the map inner elements are visible
+ */
+
+ @Test
+ public void testMapIconContentDescription() {
+ // Mapbox logo
+ onView(withContentDescription(mActivity.getResources()
+ .getString(R.string.mapboxIconContentDescription)))
+ .check(matches(isDisplayed()));
+ }
+
+ @Test
+ public void testMapCompassContentDescription() {
+ // Map compass
+ onView(withContentDescription(mActivity.getResources()
+ .getString(R.string.compassContentDescription)))
+ .check(matches(isDisplayed()));
+ }
+
+ @Test
+ public void testMapAttributionsIconContentDescription() {
+ // Attribution icon
+ onView(withContentDescription(mActivity.getResources()
+ .getString(R.string.attributionsIconContentDescription)))
+ .check(matches(isDisplayed()));
+ }
+
+}
diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxgl/testapp/SecondMapActivityTest.java b/android/java/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxgl/testapp/SecondMapActivityTest.java
new file mode 100644
index 0000000000..593b0b2ee2
--- /dev/null
+++ b/android/java/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxgl/testapp/SecondMapActivityTest.java
@@ -0,0 +1,41 @@
+package com.mapbox.mapboxgl.testapp;
+
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.assertion.ViewAssertions.matches;
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+
+/**
+ * Tests on SecondMapActivity.
+ */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class SecondMapActivityTest extends BaseTest {
+
+ @Rule
+ public ActivityTestRule<SecondMapActivity> mActivityRule = new ActivityTestRule<>(
+ SecondMapActivity.class);
+
+ private SecondMapActivity mActivity = null;
+
+ @Before
+ public void setActivity() {
+ mActivity = mActivityRule.getActivity();
+ }
+
+ @Test
+ public void testSanity() {
+ onView(withId(R.id.secondMapView))
+ .check(matches(isDisplayed()));
+ }
+
+}
diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxgl/testapp/utils/ScreenshotUtil.java b/android/java/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxgl/testapp/utils/ScreenshotUtil.java
new file mode 100644
index 0000000000..258a389237
--- /dev/null
+++ b/android/java/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxgl/testapp/utils/ScreenshotUtil.java
@@ -0,0 +1,130 @@
+package com.mapbox.mapboxgl.testapp.utils;
+
+import android.app.Activity;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.os.Environment;
+import android.util.Log;
+import android.view.TextureView;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+/**
+ * The built-in Fuzz Suite on AWS Device Farm takes screenshots after every test. However,
+ * this doesn't happen with Espresso unless we manually do it. This class fixes it.
+ */
+public class ScreenshotUtil {
+
+ private static final String LOG_TAG = ScreenshotUtil.class.getName();
+
+ // Where to store the files. This path is required by AWS Device Farm:
+ // http://docs.aws.amazon.com/devicefarm/latest/developerguide/test-types-android-instrumentation.html#test-types-android-instrumentation-screenshots
+ private static final String SCREENSHOT_FOLDER = "test-screenshots";
+
+ // Image type and quality
+ private static final String DEFAULT_IMAGE_EXTENSION = ".png";
+ private static final Bitmap.CompressFormat DEFAULT_IMAGE_FORMAT = Bitmap.CompressFormat.PNG;
+ private static final int DEFAULT_IMAGE_QUALITY = 100;
+
+ public static void take(Activity activity, String testName) {
+
+ // Check if storage is available
+ if (!isExternalStorageWritable()) {
+ Log.d(LOG_TAG, "External storage is not available.");
+ return;
+ }
+
+ // Get a bitmap from the activity root view. When the drawing cache is enabled,
+ // the next call to getDrawingCache() will draw the view in a bitmap.
+ View rootView = activity.getWindow().getDecorView().getRootView();
+ rootView.setDrawingCacheEnabled(true);
+ Bitmap bitmap = Bitmap.createBitmap(rootView.getDrawingCache());
+ rootView.setDrawingCacheEnabled(false);
+
+ // Add the SurfaceView bit (see getAllTextureViews() below)
+ List<TextureView> tilingViews = getAllTextureViews(rootView);
+ if (tilingViews.size() > 0) {
+ Canvas canvas = new Canvas(bitmap);
+ for (TextureView TextureView : tilingViews) {
+ Bitmap b = TextureView.getBitmap(TextureView.getWidth(), TextureView.getHeight());
+ int[] location = new int[2];
+ TextureView.getLocationInWindow(location);
+ int[] location2 = new int[2];
+ TextureView.getLocationOnScreen(location2);
+ canvas.drawBitmap(b, location[0], location[1], null);
+ }
+ }
+
+ // Save the bitmap in external storage
+ String uniqueAbsolutePath = getUniqueAbsolutePath(testName);
+ File outputFile = new File(uniqueAbsolutePath);
+ OutputStream outputStream = null;
+ try {
+ outputStream = new FileOutputStream(outputFile);
+ bitmap.compress(DEFAULT_IMAGE_FORMAT, DEFAULT_IMAGE_QUALITY, outputStream);
+ outputStream.flush();
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ if (outputStream != null) {
+ try {
+ outputStream.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ /*
+ * The classic way of taking a screenshot (above) doesn't work with TextureView, this fixes it:
+ * http://stackoverflow.com/questions/19704060/screen-capture-textureview-is-black-using-drawingcache
+ */
+
+ public static List<TextureView> getAllTextureViews(View view)
+ {
+ List<TextureView> tilingViews = new ArrayList<TextureView>();
+ if (view instanceof TextureView) {
+ tilingViews.add((TextureView)view);
+ } else if(view instanceof ViewGroup) {
+ ViewGroup viewGroup = (ViewGroup)view;
+ for (int i = 0; i < viewGroup.getChildCount(); i++) {
+ tilingViews.addAll(getAllTextureViews(viewGroup.getChildAt(i)));
+ }
+ }
+
+ return tilingViews;
+ }
+
+ /*
+ * Utils
+ */
+
+ public static boolean isExternalStorageWritable() {
+ // Checks if external storage is available for read and write
+ String state = Environment.getExternalStorageState();
+ return Environment.MEDIA_MOUNTED.equals(state);
+ }
+
+ private static String getUniqueAbsolutePath(String testName) {
+ // A screenshot after every test vs. manual tests
+ String filename = UUID.randomUUID().toString() + DEFAULT_IMAGE_EXTENSION;
+ if (testName != null && !testName.isEmpty()) {
+ filename = testName + DEFAULT_IMAGE_EXTENSION;
+ }
+
+ String externalPath = Environment.getExternalStorageDirectory().toString();
+ String path = externalPath + File.separator + SCREENSHOT_FOLDER + File.separator + filename;
+ Log.d(LOG_TAG, "Screenshot path: " + path);
+ return path;
+ }
+
+}
diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml b/android/java/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml
index 5e07c105a2..f91c57e7ee 100644
--- a/android/java/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml
+++ b/android/java/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml
@@ -26,4 +26,5 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
</manifest>
diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/test/java/BoundingBoxTest.java b/android/java/MapboxGLAndroidSDKTestApp/src/test/java/BoundingBoxTest.java
new file mode 100644
index 0000000000..a94bbc7732
--- /dev/null
+++ b/android/java/MapboxGLAndroidSDKTestApp/src/test/java/BoundingBoxTest.java
@@ -0,0 +1,15 @@
+import com.mapbox.mapboxgl.geometry.BoundingBox;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertNotNull;
+
+public class BoundingBoxTest {
+
+ @Test
+ public void testSanity() {
+ BoundingBox boundingBox = new BoundingBox(0.0, 0.0, 0.0, 0.0);
+ assertNotNull("boundingBox should not be null", boundingBox);
+ }
+
+}
diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/test/java/CoordinateRegionTest.java b/android/java/MapboxGLAndroidSDKTestApp/src/test/java/CoordinateRegionTest.java
new file mode 100644
index 0000000000..9672d9da54
--- /dev/null
+++ b/android/java/MapboxGLAndroidSDKTestApp/src/test/java/CoordinateRegionTest.java
@@ -0,0 +1,54 @@
+import com.mapbox.mapboxgl.geometry.CoordinateRegion;
+import com.mapbox.mapboxgl.geometry.CoordinateSpan;
+import com.mapbox.mapboxgl.geometry.LatLng;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+public class CoordinateRegionTest {
+
+ @Test
+ public void testSanity() {
+ LatLng center = new LatLng(1.2, 3.4, 5.6);
+ CoordinateSpan span = new CoordinateSpan(9.8, 7.6);
+ CoordinateRegion coordinateRegion = new CoordinateRegion(center, span);
+ assertNotNull("coordinateRegion should not be null", coordinateRegion);
+ }
+
+ @Test
+ public void testCenterConstructor() {
+ LatLng center = new LatLng(1.2, 3.4, 5.6);
+ CoordinateSpan span = new CoordinateSpan(9.8, 7.6);
+ CoordinateRegion coordinateRegion = new CoordinateRegion(center, span);
+ assertEquals("center should match", coordinateRegion.getCenter(), center);
+ }
+
+ @Test
+ public void testSpanConstructor() {
+ LatLng center = new LatLng(1.2, 3.4, 5.6);
+ CoordinateSpan span = new CoordinateSpan(9.8, 7.6);
+ CoordinateRegion coordinateRegion = new CoordinateRegion(center, span);
+ assertEquals("span should match", coordinateRegion.getSpan(), span);
+ }
+
+ @Test
+ public void testCenterMethod() {
+ LatLng center = new LatLng(1.2, 3.4, 5.6);
+ CoordinateSpan span = new CoordinateSpan(9.8, 7.6);
+ CoordinateRegion coordinateRegion = new CoordinateRegion(null, span);
+ coordinateRegion.setCenter(center);
+ assertEquals("center should match", coordinateRegion.getCenter(), center);
+ }
+
+ @Test
+ public void testSpanMethod() {
+ LatLng center = new LatLng(1.2, 3.4, 5.6);
+ CoordinateSpan span = new CoordinateSpan(9.8, 7.6);
+ CoordinateRegion coordinateRegion = new CoordinateRegion(center, null);
+ coordinateRegion.setSpan(span);
+ assertEquals("span should match", coordinateRegion.getSpan(), span);
+ }
+
+}
diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/test/java/CoordinateSpanTest.java b/android/java/MapboxGLAndroidSDKTestApp/src/test/java/CoordinateSpanTest.java
new file mode 100644
index 0000000000..0ccb766248
--- /dev/null
+++ b/android/java/MapboxGLAndroidSDKTestApp/src/test/java/CoordinateSpanTest.java
@@ -0,0 +1,48 @@
+import com.mapbox.mapboxgl.geometry.CoordinateSpan;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+public class CoordinateSpanTest {
+
+ private static final double DELTA = 1e-15;
+
+ @Test
+ public void testSanity() {
+ CoordinateSpan coordinateSpan = new CoordinateSpan(0.0, 0.0);
+ assertNotNull("coordinateSpan should not be null", coordinateSpan);
+ }
+
+ @Test
+ public void testLatitudeConstructor() {
+ double latitude = 1.23;
+ CoordinateSpan coordinateSpan = new CoordinateSpan(latitude, 0.0);
+ assertEquals("latitude in constructor", coordinateSpan.getLatitudeSpan(), latitude, DELTA);
+ }
+
+ @Test
+ public void testLongitudeConstructor() {
+ double longitude = 1.23;
+ CoordinateSpan coordinateSpan = new CoordinateSpan(0.0, longitude);
+ assertEquals("latitude in constructor", coordinateSpan.getLongitudeSpan(), longitude, DELTA);
+ }
+
+ @Test
+ public void testLatitudeMethod() {
+ double latitude = 1.23;
+ CoordinateSpan coordinateSpan = new CoordinateSpan(0.0, 0.0);
+ coordinateSpan.setLatitudeSpan(latitude);
+ assertEquals("latitude in constructor", coordinateSpan.getLatitudeSpan(), latitude, DELTA);
+ }
+
+ @Test
+ public void testLongitudeMethod() {
+ double longitude = 1.23;
+ CoordinateSpan coordinateSpan = new CoordinateSpan(0.0, 0.0);
+ coordinateSpan.setLongitudeSpan(longitude);
+ assertEquals("latitude in constructor", coordinateSpan.getLongitudeSpan(), longitude, DELTA);
+ }
+
+}
diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/test/java/LatLngTest.java b/android/java/MapboxGLAndroidSDKTestApp/src/test/java/LatLngTest.java
new file mode 100644
index 0000000000..a3065789b0
--- /dev/null
+++ b/android/java/MapboxGLAndroidSDKTestApp/src/test/java/LatLngTest.java
@@ -0,0 +1,98 @@
+import android.location.Location;
+
+import com.mapbox.mapboxgl.geometry.LatLng;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class LatLngTest {
+
+ private static final double DELTA = 1e-15;
+
+ @Test
+ public void testSanity() {
+ LatLng latLng = new LatLng(0.0, 0.0);
+ assertNotNull("latLng should not be null", latLng);
+ }
+
+ @Test
+ public void testLatitudeConstructor() {
+ double latitude = 1.2;
+ LatLng latLng = new LatLng(latitude, 3.4);
+ assertEquals("latitude should match", latLng.getLatitude(), latitude, DELTA);
+ }
+
+ @Test
+ public void testLongitudeConstructor() {
+ double longitude = 3.4;
+ LatLng latLng = new LatLng(1.2, longitude);
+ assertEquals("longitude should match", latLng.getLongitude(), longitude, DELTA);
+ }
+
+ @Test
+ public void testAltitudeConstructor() {
+ LatLng latLng1 = new LatLng(1.2, 3.4);
+ assertEquals("altitude default value", latLng1.getAltitude(), 0.0, DELTA);
+
+ double altitude = 5.6;
+ LatLng latLng2 = new LatLng(1.2, 3.4, altitude);
+ assertEquals("altitude default value", latLng2.getAltitude(), altitude, DELTA);
+ }
+
+ /*
+ * A sample test where Mockito is necessary
+ */
+
+ @Test
+ public void testLocationProvider() {
+ double latitude = 1.2;
+ double longitude = 3.4;
+ double altitude = 5.6;
+
+ // Mock the location class
+ Location locationMocked = mock(Location.class);
+ when(locationMocked.getLatitude()).thenReturn(latitude);
+ when(locationMocked.getLongitude()).thenReturn(longitude);
+ when(locationMocked.getAltitude()).thenReturn(altitude);
+
+ // Test the constructor
+ LatLng latLng = new LatLng(locationMocked);
+ assertEquals("latitude should match", latLng.getLatitude(), latitude, DELTA);
+ assertEquals("longitude should match", latLng.getLongitude(), longitude, DELTA);
+ assertEquals("altitude should match", latLng.getAltitude(), altitude, DELTA);
+ }
+
+ @Test
+ public void testHashCode() {
+ double latitude = 1.2;
+ double longitude = 3.4;
+ double altitude = 5.6;
+ LatLng latLng = new LatLng(latitude, longitude, altitude);
+ assertEquals("hash code should match", latLng.hashCode(), -151519232);
+ }
+
+ @Test
+ public void testToString() {
+ double latitude = 1.2;
+ double longitude = 3.4;
+ double altitude = 5.6;
+ LatLng latLng = new LatLng(latitude, longitude, altitude);
+ assertEquals("string should match",
+ latLng.toString(),
+ "LatLng [longitude=3.4, latitude=1.2, altitude=5.6]");
+ }
+
+ @Test
+ public void testDistanceTo() {
+ LatLng latLng1 = new LatLng(0.0, 0.0);
+ LatLng latLng2 = new LatLng(1.0, 1.0);
+ assertEquals("distances should match",
+ latLng1.distanceTo(latLng2),
+ 157425.53710839353, DELTA);
+ }
+
+}
diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/test/java/LatLngZoomTest.java b/android/java/MapboxGLAndroidSDKTestApp/src/test/java/LatLngZoomTest.java
new file mode 100644
index 0000000000..7b6dfbde7f
--- /dev/null
+++ b/android/java/MapboxGLAndroidSDKTestApp/src/test/java/LatLngZoomTest.java
@@ -0,0 +1,15 @@
+import com.mapbox.mapboxgl.geometry.LatLngZoom;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertNotNull;
+
+public class LatLngZoomTest {
+
+ @Test
+ public void testSanity() {
+ LatLngZoom latLngZoom = new LatLngZoom(0.0, 0.0, 0.0);
+ assertNotNull("latLngZoom should not be null", latLngZoom);
+ }
+
+}
diff --git a/android/java/MapboxGLAndroidSDKTestApp/src/test/java/ProjectedMetersTest.java b/android/java/MapboxGLAndroidSDKTestApp/src/test/java/ProjectedMetersTest.java
new file mode 100644
index 0000000000..39655bdf30
--- /dev/null
+++ b/android/java/MapboxGLAndroidSDKTestApp/src/test/java/ProjectedMetersTest.java
@@ -0,0 +1,15 @@
+import com.mapbox.mapboxgl.geometry.ProjectedMeters;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertNotNull;
+
+public class ProjectedMetersTest {
+
+ @Test
+ public void testSanity() {
+ ProjectedMeters projectedMeters = new ProjectedMeters(0.0, 0.0);
+ assertNotNull("projectedMeters should not be null", projectedMeters);
+ }
+
+}