diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index 74709d9df5..6be996f999 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -1,6 +1,14 @@ + + \ No newline at end of file diff --git a/core-kotlin/src/main/java/com/amplifyframework/kotlin/core/Amplify.kt b/core-kotlin/src/main/java/com/amplifyframework/kotlin/core/Amplify.kt index 4e50124de5..9d1ecb9b43 100644 --- a/core-kotlin/src/main/java/com/amplifyframework/kotlin/core/Amplify.kt +++ b/core-kotlin/src/main/java/com/amplifyframework/kotlin/core/Amplify.kt @@ -24,6 +24,7 @@ import com.amplifyframework.core.plugin.Plugin import com.amplifyframework.kotlin.api.KotlinApiFacade import com.amplifyframework.kotlin.auth.KotlinAuthFacade import com.amplifyframework.kotlin.datastore.KotlinDataStoreFacade +import com.amplifyframework.kotlin.geo.KotlinGeoFacade import com.amplifyframework.kotlin.hub.KotlinHubFacade import com.amplifyframework.kotlin.predictions.KotlinPredictionsFacade import com.amplifyframework.kotlin.storage.KotlinStorageFacade @@ -41,6 +42,7 @@ class Amplify { val Analytics = AnalyticsCategory() val API = KotlinApiFacade() val Auth = KotlinAuthFacade() + val Geo = KotlinGeoFacade() val Logging = LoggingCategory() val Storage = KotlinStorageFacade() val Hub = KotlinHubFacade() diff --git a/core-kotlin/src/main/java/com/amplifyframework/kotlin/geo/Geo.kt b/core-kotlin/src/main/java/com/amplifyframework/kotlin/geo/Geo.kt new file mode 100644 index 0000000000..fffe28e056 --- /dev/null +++ b/core-kotlin/src/main/java/com/amplifyframework/kotlin/geo/Geo.kt @@ -0,0 +1,74 @@ +/* + * Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.amplifyframework.kotlin.geo + +import com.amplifyframework.geo.models.Coordinates +import com.amplifyframework.geo.models.MapStyle +import com.amplifyframework.geo.models.MapStyleDescriptor +import com.amplifyframework.geo.options.GeoSearchByCoordinatesOptions +import com.amplifyframework.geo.options.GeoSearchByTextOptions +import com.amplifyframework.geo.options.GetMapStyleDescriptorOptions +import com.amplifyframework.geo.result.GeoSearchResult + +interface Geo { + /** + * Gets a collection of maps and their corresponding styles. + * + * @return A collection of all available [MapStyle]. + */ + suspend fun getAvailableMaps(): Collection + + /** + * Gets the default map and style from available maps. + * + * @return The default [MapStyle]. + */ + suspend fun getDefaultMap(): MapStyle + + /** + * Uses given options to get map style descriptor JSON. + * + * @param options Options to specify for this operation. + * @return The [MapStyleDescriptor] matching the given options. + */ + suspend fun getMapStyleDescriptor( + options: GetMapStyleDescriptorOptions = GetMapStyleDescriptorOptions.defaults() + ): MapStyleDescriptor + + /** + * Searches for locations that match text query. + * + * @param query Search query text. + * @param options Search options to use. + * @return The [GeoSearchResult] for the query and options. + */ + suspend fun searchByText( + query: String, + options: GeoSearchByTextOptions = GeoSearchByTextOptions.defaults() + ): GeoSearchResult + + /** + * Searches for location with given set of coordinates. + * + * @param position Coordinates to look-up. + * @param options Search options to use. + * @return The [GeoSearchResult] for the position and options. + */ + suspend fun searchByCoordinates( + position: Coordinates, + options: GeoSearchByCoordinatesOptions = GeoSearchByCoordinatesOptions.defaults() + ): GeoSearchResult +} diff --git a/core-kotlin/src/main/java/com/amplifyframework/kotlin/geo/KotlinGeoFacade.kt b/core-kotlin/src/main/java/com/amplifyframework/kotlin/geo/KotlinGeoFacade.kt new file mode 100644 index 0000000000..e30163a931 --- /dev/null +++ b/core-kotlin/src/main/java/com/amplifyframework/kotlin/geo/KotlinGeoFacade.kt @@ -0,0 +1,76 @@ +/* + * Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.amplifyframework.kotlin.geo + +import com.amplifyframework.core.Amplify +import com.amplifyframework.geo.GeoCategoryBehavior +import com.amplifyframework.geo.models.Coordinates +import com.amplifyframework.geo.models.MapStyle +import com.amplifyframework.geo.options.GeoSearchByCoordinatesOptions +import com.amplifyframework.geo.options.GeoSearchByTextOptions +import com.amplifyframework.geo.options.GetMapStyleDescriptorOptions +import kotlin.coroutines.resume +import kotlin.coroutines.resumeWithException +import kotlin.coroutines.suspendCoroutine + +class KotlinGeoFacade(private val delegate: GeoCategoryBehavior = Amplify.Geo) : Geo { + override suspend fun getAvailableMaps(): Collection = suspendCoroutine { continuation -> + delegate.getAvailableMaps( + { continuation.resume(it) }, + { continuation.resumeWithException(it) } + ) + } + + override suspend fun getDefaultMap() = suspendCoroutine { continuation -> + delegate.getDefaultMap( + { continuation.resume(it) }, + { continuation.resumeWithException(it) } + ) + } + + override suspend fun getMapStyleDescriptor(options: GetMapStyleDescriptorOptions) = + suspendCoroutine { continuation -> + delegate.getMapStyleDescriptor( + options, + { continuation.resume(it) }, + { continuation.resumeWithException(it) } + ) + } + + override suspend fun searchByText( + query: String, + options: GeoSearchByTextOptions + ) = suspendCoroutine { continuation -> + delegate.searchByText( + query, + options, + { continuation.resume(it) }, + { continuation.resumeWithException(it) } + ) + } + + override suspend fun searchByCoordinates( + position: Coordinates, + options: GeoSearchByCoordinatesOptions + ) = suspendCoroutine { continuation -> + delegate.searchByCoordinates( + position, + options, + { continuation.resume(it) }, + { continuation.resumeWithException(it) } + ) + } +} diff --git a/core-kotlin/src/test/java/com/amplifyframework/kotlin/geo/KotlinGeoFacadeTest.kt b/core-kotlin/src/test/java/com/amplifyframework/kotlin/geo/KotlinGeoFacadeTest.kt new file mode 100644 index 0000000000..0efb5516bb --- /dev/null +++ b/core-kotlin/src/test/java/com/amplifyframework/kotlin/geo/KotlinGeoFacadeTest.kt @@ -0,0 +1,190 @@ +/* + * Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.amplifyframework.kotlin.geo + +import com.amplifyframework.core.Consumer +import com.amplifyframework.geo.GeoCategoryBehavior +import com.amplifyframework.geo.GeoException +import com.amplifyframework.geo.models.Coordinates +import com.amplifyframework.geo.models.MapStyle +import com.amplifyframework.geo.models.MapStyleDescriptor +import com.amplifyframework.geo.options.GeoSearchByCoordinatesOptions +import com.amplifyframework.geo.options.GeoSearchByTextOptions +import com.amplifyframework.geo.options.GetMapStyleDescriptorOptions +import com.amplifyframework.geo.result.GeoSearchResult +import io.mockk.every +import io.mockk.mockk +import junit.framework.Assert.assertSame +import kotlinx.coroutines.runBlocking +import org.junit.Test + +/** + * Unit tests for the [KotlinGeoFacade] class. + */ +internal class KotlinGeoFacadeTest { + private val delegate = mockk() + private val geo = KotlinGeoFacade(delegate) + + @Test + fun `gets available maps`() = runBlocking { + val maps = listOf( + MapStyle("a", "b"), + MapStyle("c", "d") + ) + every { delegate.getAvailableMaps(any(), any()) } answers { + val callback = firstArg>>() + callback.accept(maps) + } + val result = geo.getAvailableMaps() + assertSame(maps, result) + } + + @Test(expected = GeoException::class) + fun `throws available map error`(): Unit = runBlocking { + val error = GeoException("message", "suggestion") + every { delegate.getAvailableMaps(any(), any()) } answers { + val callback = secondArg>() + callback.accept(error) + } + geo.getAvailableMaps() + } + + @Test + fun `gets default map`() = runBlocking { + val map = MapStyle("name", "style") + every { delegate.getDefaultMap(any(), any()) } answers { + val callback = firstArg>() + callback.accept(map) + } + val result = geo.getDefaultMap() + assertSame(map, result) + } + + @Test(expected = GeoException::class) + fun `throws default map error`(): Unit = runBlocking { + val error = GeoException("message", "suggestion") + every { delegate.getDefaultMap(any(), any()) } answers { + val callback = secondArg>() + callback.accept(error) + } + geo.getDefaultMap() + } + + @Test + fun `returns map style descriptor`() = runBlocking { + val descriptor = MapStyleDescriptor("") + every { delegate.getMapStyleDescriptor(any(), any(), any()) } answers { + val callback = secondArg>() + callback.accept(descriptor) + } + val result = geo.getMapStyleDescriptor() + assertSame(descriptor, result) + } + + @Test + fun `returns map style descriptor with options`() = runBlocking { + val descriptor = MapStyleDescriptor("") + val options = GetMapStyleDescriptorOptions.builder().mapName("map").build() + every { delegate.getMapStyleDescriptor(options, any(), any()) } answers { + val callback = secondArg>() + callback.accept(descriptor) + } + val result = geo.getMapStyleDescriptor(options) + assertSame(descriptor, result) + } + + @Test(expected = GeoException::class) + fun `throws map style descriptor error`(): Unit = runBlocking { + val error = GeoException("message", "suggestion") + every { delegate.getMapStyleDescriptor(any(), any(), any()) } answers { + val callback = lastArg>() + callback.accept(error) + } + geo.getMapStyleDescriptor() + } + + @Test + fun `returns search by text result`() = runBlocking { + val query = "query" + val searchResult = GeoSearchResult.withPlaces(emptyList()) + every { delegate.searchByText(query, any(), any(), any()) } answers { + val callback = thirdArg>() + callback.accept(searchResult) + } + val result = geo.searchByText(query) + assertSame(searchResult, result) + } + + @Test + fun `returns search by text result with options`() = runBlocking { + val query = "query" + val options = GeoSearchByTextOptions.builder().maxResults(4).build() + val searchResult = GeoSearchResult.withPlaces(emptyList()) + every { delegate.searchByText(query, options, any(), any()) } answers { + val callback = thirdArg>() + callback.accept(searchResult) + } + val result = geo.searchByText(query, options) + assertSame(searchResult, result) + } + + @Test(expected = GeoException::class) + fun `throws search by text error`(): Unit = runBlocking { + val query = "query" + val error = GeoException("message", "suggestion") + every { delegate.searchByText(query, any(), any(), any()) } answers { + val callback = lastArg>() + callback.accept(error) + } + geo.searchByText(query) + } + + @Test + fun `returns search by coordinates result`() = runBlocking { + val position = Coordinates() + val searchResult = GeoSearchResult.withPlaces(emptyList()) + every { delegate.searchByCoordinates(position, any(), any(), any()) } answers { + val callback = thirdArg>() + callback.accept(searchResult) + } + val result = geo.searchByCoordinates(position) + assertSame(searchResult, result) + } + + @Test + fun `returns search by coordinates result with options`() = runBlocking { + val position = Coordinates() + val options = GeoSearchByCoordinatesOptions.builder().maxResults(3).build() + val searchResult = GeoSearchResult.withPlaces(emptyList()) + every { delegate.searchByCoordinates(position, options, any(), any()) } answers { + val callback = thirdArg>() + callback.accept(searchResult) + } + val result = geo.searchByCoordinates(position, options) + assertSame(searchResult, result) + } + + @Test(expected = GeoException::class) + fun `throws search by coordinates error`(): Unit = runBlocking { + val position = Coordinates() + val error = GeoException("message", "suggestion") + every { delegate.searchByCoordinates(position, any(), any(), any()) } answers { + val callback = lastArg>() + callback.accept(error) + } + geo.searchByCoordinates(position) + } +}