From 9f260d3fcdf7aeca1d07664d23412e6fbfe3710f Mon Sep 17 00:00:00 2001 From: Dale Hawkins <107309+dkhawk@users.noreply.github.com> Date: Tue, 15 Sep 2026 15:48:17 -0600 Subject: [PATCH] test(widgets): add JVM unit and composable tests for ScaleBar --- maps-compose-widgets/build.gradle.kts | 21 +++ .../src/debug/AndroidManifest.xml | 23 ++++ .../android/compose/widgets/ScaleBarTest.kt | 125 ++++++++++++++++++ 3 files changed, 169 insertions(+) create mode 100644 maps-compose-widgets/src/debug/AndroidManifest.xml create mode 100644 maps-compose-widgets/src/test/java/com/google/maps/android/compose/widgets/ScaleBarTest.kt diff --git a/maps-compose-widgets/build.gradle.kts b/maps-compose-widgets/build.gradle.kts index c3812eb1..a12c56f6 100644 --- a/maps-compose-widgets/build.gradle.kts +++ b/maps-compose-widgets/build.gradle.kts @@ -58,6 +58,12 @@ android { enableAndroidTestCoverage = true } } + + testOptions { + unitTests { + isIncludeAndroidResources = true + } + } } kotlin { @@ -96,9 +102,24 @@ dependencies { api(libs.maps.ktx.utils) testImplementation(libs.test.junit) + testImplementation(libs.robolectric) + testImplementation(libs.truth) + testImplementation(libs.mockk) + testImplementation(libs.androidx.test.compose.ui) + testImplementation(libs.androidx.activity.compose) + testImplementation(libs.androidx.test.core) + testImplementation(libs.kotlinx.coroutines.test) + testImplementation(libs.maps.robolectric.shadows) + androidTestImplementation(platform(libs.androidx.compose.bom)) androidTestImplementation(libs.androidx.test.espresso) androidTestImplementation(libs.androidx.test.junit.ktx) androidTestImplementation(libs.mockk.android) androidTestImplementation(libs.truth) } + +tasks.withType().configureEach { + javaLauncher.set(javaToolchains.launcherFor { + languageVersion.set(JavaLanguageVersion.of(21)) + }) +} diff --git a/maps-compose-widgets/src/debug/AndroidManifest.xml b/maps-compose-widgets/src/debug/AndroidManifest.xml new file mode 100644 index 00000000..b106adac --- /dev/null +++ b/maps-compose-widgets/src/debug/AndroidManifest.xml @@ -0,0 +1,23 @@ + + + + + + + diff --git a/maps-compose-widgets/src/test/java/com/google/maps/android/compose/widgets/ScaleBarTest.kt b/maps-compose-widgets/src/test/java/com/google/maps/android/compose/widgets/ScaleBarTest.kt new file mode 100644 index 00000000..0d9ed7dd --- /dev/null +++ b/maps-compose-widgets/src/test/java/com/google/maps/android/compose/widgets/ScaleBarTest.kt @@ -0,0 +1,125 @@ +/* + * 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.google.maps.android.compose.widgets + +import android.graphics.Point +import androidx.activity.ComponentActivity +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.test.junit4.AndroidComposeTestRule +import androidx.compose.ui.test.junit4.createAndroidComposeRule +import androidx.compose.ui.unit.Density +import androidx.compose.ui.unit.dp +import androidx.test.ext.junit.rules.ActivityScenarioRule +import com.google.android.gms.maps.Projection +import com.google.android.gms.maps.model.CameraPosition +import com.google.android.gms.maps.model.LatLng +import com.google.android.maps.robolectric.annotation.EnableMapsShadows +import com.google.common.truth.Truth.assertThat +import com.google.maps.android.compose.CameraPositionState +import com.google.maps.android.ktx.utils.sphericalDistance +import io.mockk.every +import io.mockk.mockk +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config + +// [START maps_compose_widgets_scale_bar_test] +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [34]) +@EnableMapsShadows +internal class ScaleBarTest { + + @get:Rule + internal val composeTestRule: AndroidComposeTestRule, ComponentActivity> = + createAndroidComposeRule() + + @Test + internal fun testCalculateDistance_computesExpectedCanvasDistance(): Unit { + val projection = mockk(relaxed = true) + val density = Density(1f, 1f) + val width = 100.dp + + val startPoint = Point(0, 0) + val endPoint = Point(width.value.toInt(), 0) + + val startLatLng = LatLng(0.0, 0.0) + val endLatLng = LatLng(0.0, 0.001) + + every { projection.fromScreenLocation(startPoint) } returns startLatLng + every { projection.fromScreenLocation(endPoint) } returns endLatLng + + val expectedDistance = startLatLng.sphericalDistance(endLatLng) + val expectedResult = (expectedDistance * 8 / 9).toInt() + + val result = calculateDistance(projection, width, density) + + assertThat(result).isEqualTo(expectedResult) + } + + @Test + internal fun testUnitConversions_toFeetAndToMiles(): Unit { + val meters = 1609.344 // 1 mile in meters + val feet = meters.toFeet() + assertThat(feet).isWithin(1.0).of(5280.0) + + val miles = feet.toMiles() + assertThat(miles).isWithin(0.01).of(1.0) + } + + @Test + internal fun testScaleBar_rendersWithoutCrashing(): Unit { + val cameraState = CameraPositionState( + position = CameraPosition.fromLatLngZoom(LatLng(37.7749, -122.4194), 12f) + ) + + composeTestRule.setContent { + ScaleBar( + cameraPositionState = cameraState, + width = 80.dp, + height = 50.dp, + textColor = Color.Black, + lineColor = Color.Blue, + shadowColor = Color.White + ) + } + + composeTestRule.waitForIdle() + } + + @Test + internal fun testDisappearingScaleBar_rendersAndRespondsToCameraPosition(): Unit { + val cameraState = CameraPositionState( + position = CameraPosition.fromLatLngZoom(LatLng(37.7749, -122.4194), 10f) + ) + + composeTestRule.setContent { + DisappearingScaleBar( + cameraPositionState = cameraState, + visibilityDurationMillis = 500 + ) + } + + composeTestRule.waitForIdle() + + // Update camera position to trigger visibility LaunchedEffect + cameraState.position = CameraPosition.fromLatLngZoom(LatLng(37.7749, -122.4194), 14f) + composeTestRule.waitForIdle() + } +} +// [END maps_compose_widgets_scale_bar_test]