Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions map-sample/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,29 @@
* limitations under the License.
*/

import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.powerassert.gradle.PowerAssertCompilationFilter

plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.power.assert)
alias(libs.plugins.maps.secrets)
}

@OptIn(ExperimentalKotlinGradlePluginApi::class)
powerAssert {
functions = listOf(
"kotlin.assert",
"kotlin.require",
"kotlin.check",
"com.google.maps.android.robolectric.powerassert.assertGeo",
"com.google.maps.android.robolectric.powerassert.assertMap",
"com.google.maps.android.robolectric.powerassert.assertMarker",
)
compilationFilter = PowerAssertCompilationFilter.ALL
}

android {
namespace = "com.example.mapdemo"
compileSdk = 37
Expand All @@ -41,6 +57,21 @@ android {
// for all Navigation SDK supported languages.
androidResources.localeFilters += "en"
multiDexEnabled = true
manifestPlaceholders["MAPS_API_KEY"] = "DEFAULT_API_KEY"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}

testOptions {
unitTests {
isIncludeAndroidResources = true
isReturnDefaultValues = true
all {
it.systemProperty(
"maps.golden.record",
System.getProperty("maps.golden.record") ?: "false",
)
}
}
}

buildTypes {
Expand Down Expand Up @@ -112,6 +143,29 @@ dependencies {
annotationProcessor(libs.glide.compiler)

coreLibraryDesugaring(libs.desugar.jdk.libs)

// Unit tests: JUnit, Kotlin Power-Assert, Google Truth, Robolectric, and android-maps-testing
testImplementation(libs.junit)
testImplementation(libs.truth)
testImplementation(libs.robolectric)
testImplementation(libs.androidx.test.core)
testImplementation(libs.androidx.test.ext.junit)
testImplementation(libs.kotlinx.coroutines.test)
testImplementation(libs.mockito.core)
testImplementation(libs.maps.testing.robolectric)
testImplementation(libs.maps.testing.golden)

// Instrumented & visual tests
androidTestImplementation(libs.junit)
androidTestImplementation(libs.truth)
androidTestImplementation(libs.androidx.test.core)
androidTestImplementation(libs.androidx.test.ext.junit)
androidTestImplementation(libs.androidx.test.runner)
androidTestImplementation(libs.androidx.test.rules)
androidTestImplementation(libs.androidx.test.espresso.core)
androidTestImplementation(libs.androidx.uiautomator)
androidTestImplementation(libs.maps.testing.golden)
androidTestImplementation(libs.maps.testing.visual)
}

secrets {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* Copyright 2026 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.example.mapdemo;

import static com.google.common.truth.Truth.assertThat;

import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.widget.ListView;
import android.widget.ToggleButton;
import androidx.test.core.app.ActivityScenario;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import java.util.HashSet;
import java.util.Set;
import org.junit.Test;
import org.junit.runner.RunWith;

/**
* Connected-device instrumentation smoke tests for {@code map-sample} using <b>Google Truth</b>.
*
* <p>Sits near the top of the testing pyramid to verify that:
*
* <ol>
* <li>Every demo activity listed in {@link DemoDetailsList#DEMOS} is registered in {@code
* AndroidManifest.xml} on the target device.
* <li>{@link MainActivity} launches cleanly, populates the full catalog adapter, and toggles the
* Maps vs. Navigation flavor switch without error.
* </ol>
*/
@RunWith(AndroidJUnit4.class)
public class MapSampleSmokeTest {

@Test
public void manifest_registersAll46DemoActivitiesFromDemoDetailsList() throws Exception {
Context context = ApplicationProvider.getApplicationContext();
PackageInfo packageInfo =
context
.getPackageManager()
.getPackageInfo(context.getPackageName(), PackageManager.GET_ACTIVITIES);

Set<String> registeredActivities = new HashSet<>();
if (packageInfo.activities != null) {
for (ActivityInfo info : packageInfo.activities) {
registeredActivities.add(info.name);
}
}

assertThat(DemoDetailsList.DEMOS).hasLength(47);
for (DemoDetails demo : DemoDetailsList.DEMOS) {
assertThat(registeredActivities).contains(demo.activityClass.getName());
}
}

@Test
public void mainActivity_launchesAndTogglesNavigationFlavorSwitch() {
try (ActivityScenario<MainActivity> scenario = ActivityScenario.launch(MainActivity.class)) {
scenario.onActivity(
activity -> {
ListView demoListView = activity.findViewById(R.id.demoListView);
assertThat(demoListView).isNotNull();
assertThat(demoListView.getAdapter().getCount()).isEqualTo(DemoDetailsList.DEMOS.length);
ToggleButton flavorToggle = activity.findViewById(R.id.view_source_toggle_btn);
assertThat(flavorToggle).isNotNull();
assertThat(flavorToggle.isChecked()).isFalse();

flavorToggle.performClick();
assertThat(flavorToggle.isChecked()).isTrue();
});
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright 2026 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.example.mapdemo

import androidx.test.core.app.ActivityScenario
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.maps.android.testing.visual.BaseVisualTest
import kotlinx.coroutines.runBlocking
import org.junit.Test
import org.junit.runner.RunWith

/**
* Top-of-pyramid multimodal AI visual and hybrid golden test for `map-sample`.
*
* Extends [BaseVisualTest] from `com.google.maps.android:maps-testing-visual` to verify the visual
* presentation of the `MainActivity` demo catalog and flavor toggle switch via
* `verifyScreenshotWithGoldenFallback`.
*/
@RunWith(AndroidJUnit4::class)
class MapSampleVisualTest : BaseVisualTest() {

@Test
fun mainActivity_rendersMapDemoCatalogWithFlavorToggle() = runBlocking {
ActivityScenario.launch(MainActivity::class.java).use {
val screenshotBitmap = captureScreenshot("map_sample_main_catalog.png")
verifyScreenshotWithGoldenFallback(
testName = "map_sample_main_catalog",
screenshotBitmap = screenshotBitmap,
prompt =
"Verify that the Map Demo catalog list is displayed with a flavor switch at the top " +
"and entries such as Basic Map and Camera, and reply PASSED if all criteria are met.",
tolerancePercent = 2.0,
)
}
}
}
Loading
Loading