Skip to content

Commit d3c3025

Browse files
authored
feat(Geo): Add Kotlin Geo Facade (#2155)
* Add Kotlin Geo Facade * Add return docs to the function comments * Add tests to verify options are passed
1 parent ba2fc74 commit d3c3025

File tree

5 files changed

+353
-0
lines changed

5 files changed

+353
-0
lines changed

.idea/codeStyles/Project.xml

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

core-kotlin/src/main/java/com/amplifyframework/kotlin/core/Amplify.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import com.amplifyframework.core.plugin.Plugin
2424
import com.amplifyframework.kotlin.api.KotlinApiFacade
2525
import com.amplifyframework.kotlin.auth.KotlinAuthFacade
2626
import com.amplifyframework.kotlin.datastore.KotlinDataStoreFacade
27+
import com.amplifyframework.kotlin.geo.KotlinGeoFacade
2728
import com.amplifyframework.kotlin.hub.KotlinHubFacade
2829
import com.amplifyframework.kotlin.predictions.KotlinPredictionsFacade
2930
import com.amplifyframework.kotlin.storage.KotlinStorageFacade
@@ -41,6 +42,7 @@ class Amplify {
4142
val Analytics = AnalyticsCategory()
4243
val API = KotlinApiFacade()
4344
val Auth = KotlinAuthFacade()
45+
val Geo = KotlinGeoFacade()
4446
val Logging = LoggingCategory()
4547
val Storage = KotlinStorageFacade()
4648
val Hub = KotlinHubFacade()
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package com.amplifyframework.kotlin.geo
17+
18+
import com.amplifyframework.geo.models.Coordinates
19+
import com.amplifyframework.geo.models.MapStyle
20+
import com.amplifyframework.geo.models.MapStyleDescriptor
21+
import com.amplifyframework.geo.options.GeoSearchByCoordinatesOptions
22+
import com.amplifyframework.geo.options.GeoSearchByTextOptions
23+
import com.amplifyframework.geo.options.GetMapStyleDescriptorOptions
24+
import com.amplifyframework.geo.result.GeoSearchResult
25+
26+
interface Geo {
27+
/**
28+
* Gets a collection of maps and their corresponding styles.
29+
*
30+
* @return A collection of all available [MapStyle].
31+
*/
32+
suspend fun getAvailableMaps(): Collection<MapStyle>
33+
34+
/**
35+
* Gets the default map and style from available maps.
36+
*
37+
* @return The default [MapStyle].
38+
*/
39+
suspend fun getDefaultMap(): MapStyle
40+
41+
/**
42+
* Uses given options to get map style descriptor JSON.
43+
*
44+
* @param options Options to specify for this operation.
45+
* @return The [MapStyleDescriptor] matching the given options.
46+
*/
47+
suspend fun getMapStyleDescriptor(
48+
options: GetMapStyleDescriptorOptions = GetMapStyleDescriptorOptions.defaults()
49+
): MapStyleDescriptor
50+
51+
/**
52+
* Searches for locations that match text query.
53+
*
54+
* @param query Search query text.
55+
* @param options Search options to use.
56+
* @return The [GeoSearchResult] for the query and options.
57+
*/
58+
suspend fun searchByText(
59+
query: String,
60+
options: GeoSearchByTextOptions = GeoSearchByTextOptions.defaults()
61+
): GeoSearchResult
62+
63+
/**
64+
* Searches for location with given set of coordinates.
65+
*
66+
* @param position Coordinates to look-up.
67+
* @param options Search options to use.
68+
* @return The [GeoSearchResult] for the position and options.
69+
*/
70+
suspend fun searchByCoordinates(
71+
position: Coordinates,
72+
options: GeoSearchByCoordinatesOptions = GeoSearchByCoordinatesOptions.defaults()
73+
): GeoSearchResult
74+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
* Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package com.amplifyframework.kotlin.geo
17+
18+
import com.amplifyframework.core.Amplify
19+
import com.amplifyframework.geo.GeoCategoryBehavior
20+
import com.amplifyframework.geo.models.Coordinates
21+
import com.amplifyframework.geo.models.MapStyle
22+
import com.amplifyframework.geo.options.GeoSearchByCoordinatesOptions
23+
import com.amplifyframework.geo.options.GeoSearchByTextOptions
24+
import com.amplifyframework.geo.options.GetMapStyleDescriptorOptions
25+
import kotlin.coroutines.resume
26+
import kotlin.coroutines.resumeWithException
27+
import kotlin.coroutines.suspendCoroutine
28+
29+
class KotlinGeoFacade(private val delegate: GeoCategoryBehavior = Amplify.Geo) : Geo {
30+
override suspend fun getAvailableMaps(): Collection<MapStyle> = suspendCoroutine { continuation ->
31+
delegate.getAvailableMaps(
32+
{ continuation.resume(it) },
33+
{ continuation.resumeWithException(it) }
34+
)
35+
}
36+
37+
override suspend fun getDefaultMap() = suspendCoroutine { continuation ->
38+
delegate.getDefaultMap(
39+
{ continuation.resume(it) },
40+
{ continuation.resumeWithException(it) }
41+
)
42+
}
43+
44+
override suspend fun getMapStyleDescriptor(options: GetMapStyleDescriptorOptions) =
45+
suspendCoroutine { continuation ->
46+
delegate.getMapStyleDescriptor(
47+
options,
48+
{ continuation.resume(it) },
49+
{ continuation.resumeWithException(it) }
50+
)
51+
}
52+
53+
override suspend fun searchByText(
54+
query: String,
55+
options: GeoSearchByTextOptions
56+
) = suspendCoroutine { continuation ->
57+
delegate.searchByText(
58+
query,
59+
options,
60+
{ continuation.resume(it) },
61+
{ continuation.resumeWithException(it) }
62+
)
63+
}
64+
65+
override suspend fun searchByCoordinates(
66+
position: Coordinates,
67+
options: GeoSearchByCoordinatesOptions
68+
) = suspendCoroutine { continuation ->
69+
delegate.searchByCoordinates(
70+
position,
71+
options,
72+
{ continuation.resume(it) },
73+
{ continuation.resumeWithException(it) }
74+
)
75+
}
76+
}
Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
/*
2+
* Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package com.amplifyframework.kotlin.geo
17+
18+
import com.amplifyframework.core.Consumer
19+
import com.amplifyframework.geo.GeoCategoryBehavior
20+
import com.amplifyframework.geo.GeoException
21+
import com.amplifyframework.geo.models.Coordinates
22+
import com.amplifyframework.geo.models.MapStyle
23+
import com.amplifyframework.geo.models.MapStyleDescriptor
24+
import com.amplifyframework.geo.options.GeoSearchByCoordinatesOptions
25+
import com.amplifyframework.geo.options.GeoSearchByTextOptions
26+
import com.amplifyframework.geo.options.GetMapStyleDescriptorOptions
27+
import com.amplifyframework.geo.result.GeoSearchResult
28+
import io.mockk.every
29+
import io.mockk.mockk
30+
import junit.framework.Assert.assertSame
31+
import kotlinx.coroutines.runBlocking
32+
import org.junit.Test
33+
34+
/**
35+
* Unit tests for the [KotlinGeoFacade] class.
36+
*/
37+
internal class KotlinGeoFacadeTest {
38+
private val delegate = mockk<GeoCategoryBehavior>()
39+
private val geo = KotlinGeoFacade(delegate)
40+
41+
@Test
42+
fun `gets available maps`() = runBlocking {
43+
val maps = listOf(
44+
MapStyle("a", "b"),
45+
MapStyle("c", "d")
46+
)
47+
every { delegate.getAvailableMaps(any(), any()) } answers {
48+
val callback = firstArg<Consumer<Collection<MapStyle>>>()
49+
callback.accept(maps)
50+
}
51+
val result = geo.getAvailableMaps()
52+
assertSame(maps, result)
53+
}
54+
55+
@Test(expected = GeoException::class)
56+
fun `throws available map error`(): Unit = runBlocking {
57+
val error = GeoException("message", "suggestion")
58+
every { delegate.getAvailableMaps(any(), any()) } answers {
59+
val callback = secondArg<Consumer<GeoException>>()
60+
callback.accept(error)
61+
}
62+
geo.getAvailableMaps()
63+
}
64+
65+
@Test
66+
fun `gets default map`() = runBlocking {
67+
val map = MapStyle("name", "style")
68+
every { delegate.getDefaultMap(any(), any()) } answers {
69+
val callback = firstArg<Consumer<MapStyle>>()
70+
callback.accept(map)
71+
}
72+
val result = geo.getDefaultMap()
73+
assertSame(map, result)
74+
}
75+
76+
@Test(expected = GeoException::class)
77+
fun `throws default map error`(): Unit = runBlocking {
78+
val error = GeoException("message", "suggestion")
79+
every { delegate.getDefaultMap(any(), any()) } answers {
80+
val callback = secondArg<Consumer<GeoException>>()
81+
callback.accept(error)
82+
}
83+
geo.getDefaultMap()
84+
}
85+
86+
@Test
87+
fun `returns map style descriptor`() = runBlocking {
88+
val descriptor = MapStyleDescriptor("")
89+
every { delegate.getMapStyleDescriptor(any(), any(), any()) } answers {
90+
val callback = secondArg<Consumer<MapStyleDescriptor>>()
91+
callback.accept(descriptor)
92+
}
93+
val result = geo.getMapStyleDescriptor()
94+
assertSame(descriptor, result)
95+
}
96+
97+
@Test
98+
fun `returns map style descriptor with options`() = runBlocking {
99+
val descriptor = MapStyleDescriptor("")
100+
val options = GetMapStyleDescriptorOptions.builder().mapName("map").build()
101+
every { delegate.getMapStyleDescriptor(options, any(), any()) } answers {
102+
val callback = secondArg<Consumer<MapStyleDescriptor>>()
103+
callback.accept(descriptor)
104+
}
105+
val result = geo.getMapStyleDescriptor(options)
106+
assertSame(descriptor, result)
107+
}
108+
109+
@Test(expected = GeoException::class)
110+
fun `throws map style descriptor error`(): Unit = runBlocking {
111+
val error = GeoException("message", "suggestion")
112+
every { delegate.getMapStyleDescriptor(any(), any(), any()) } answers {
113+
val callback = lastArg<Consumer<GeoException>>()
114+
callback.accept(error)
115+
}
116+
geo.getMapStyleDescriptor()
117+
}
118+
119+
@Test
120+
fun `returns search by text result`() = runBlocking {
121+
val query = "query"
122+
val searchResult = GeoSearchResult.withPlaces(emptyList())
123+
every { delegate.searchByText(query, any(), any(), any()) } answers {
124+
val callback = thirdArg<Consumer<GeoSearchResult>>()
125+
callback.accept(searchResult)
126+
}
127+
val result = geo.searchByText(query)
128+
assertSame(searchResult, result)
129+
}
130+
131+
@Test
132+
fun `returns search by text result with options`() = runBlocking {
133+
val query = "query"
134+
val options = GeoSearchByTextOptions.builder().maxResults(4).build()
135+
val searchResult = GeoSearchResult.withPlaces(emptyList())
136+
every { delegate.searchByText(query, options, any(), any()) } answers {
137+
val callback = thirdArg<Consumer<GeoSearchResult>>()
138+
callback.accept(searchResult)
139+
}
140+
val result = geo.searchByText(query, options)
141+
assertSame(searchResult, result)
142+
}
143+
144+
@Test(expected = GeoException::class)
145+
fun `throws search by text error`(): Unit = runBlocking {
146+
val query = "query"
147+
val error = GeoException("message", "suggestion")
148+
every { delegate.searchByText(query, any(), any(), any()) } answers {
149+
val callback = lastArg<Consumer<GeoException>>()
150+
callback.accept(error)
151+
}
152+
geo.searchByText(query)
153+
}
154+
155+
@Test
156+
fun `returns search by coordinates result`() = runBlocking {
157+
val position = Coordinates()
158+
val searchResult = GeoSearchResult.withPlaces(emptyList())
159+
every { delegate.searchByCoordinates(position, any(), any(), any()) } answers {
160+
val callback = thirdArg<Consumer<GeoSearchResult>>()
161+
callback.accept(searchResult)
162+
}
163+
val result = geo.searchByCoordinates(position)
164+
assertSame(searchResult, result)
165+
}
166+
167+
@Test
168+
fun `returns search by coordinates result with options`() = runBlocking {
169+
val position = Coordinates()
170+
val options = GeoSearchByCoordinatesOptions.builder().maxResults(3).build()
171+
val searchResult = GeoSearchResult.withPlaces(emptyList())
172+
every { delegate.searchByCoordinates(position, options, any(), any()) } answers {
173+
val callback = thirdArg<Consumer<GeoSearchResult>>()
174+
callback.accept(searchResult)
175+
}
176+
val result = geo.searchByCoordinates(position, options)
177+
assertSame(searchResult, result)
178+
}
179+
180+
@Test(expected = GeoException::class)
181+
fun `throws search by coordinates error`(): Unit = runBlocking {
182+
val position = Coordinates()
183+
val error = GeoException("message", "suggestion")
184+
every { delegate.searchByCoordinates(position, any(), any(), any()) } answers {
185+
val callback = lastArg<Consumer<GeoException>>()
186+
callback.accept(error)
187+
}
188+
geo.searchByCoordinates(position)
189+
}
190+
}

0 commit comments

Comments
 (0)