Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Geo): Add Kotlin Geo Facade #2155

Merged
merged 5 commits into from Dec 7, 2022
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 11 additions & 0 deletions .idea/codeStyles/Project.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Expand Up @@ -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
Expand All @@ -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()
Expand Down
@@ -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<MapStyle>

/**
* 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
}
@@ -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<MapStyle> = 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) }
)
}
}
@@ -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<GeoCategoryBehavior>()
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<Consumer<Collection<MapStyle>>>()
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<Consumer<GeoException>>()
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<Consumer<MapStyle>>()
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<Consumer<GeoException>>()
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<Consumer<MapStyleDescriptor>>()
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<Consumer<MapStyleDescriptor>>()
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<Consumer<GeoException>>()
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 {
mattcreaser marked this conversation as resolved.
Show resolved Hide resolved
val callback = thirdArg<Consumer<GeoSearchResult>>()
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<Consumer<GeoSearchResult>>()
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<Consumer<GeoException>>()
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<Consumer<GeoSearchResult>>()
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<Consumer<GeoSearchResult>>()
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<Consumer<GeoException>>()
callback.accept(error)
}
geo.searchByCoordinates(position)
}
}