Skip to content

Commit 12b4787

Browse files
committed
Complete refactoring of GpxImport backend code
Refactored to use Flows and moving tests that need XmlPullParser to androidTest to get rid of robolectric
1 parent 86d3703 commit 12b4787

File tree

15 files changed

+541
-453
lines changed

15 files changed

+541
-453
lines changed

app/build.gradle.kts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ android {
4545
isShrinkResources = false
4646
// don't use proguard-android-optimize.txt, it is too aggressive, it is more trouble than it is worth
4747
proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro")
48+
testProguardFile("test-proguard-rules.pro")
4849
}
4950
getByName("release") {
5051
signingConfig = signingConfigs.getByName("release")
@@ -116,12 +117,13 @@ dependencies {
116117
testImplementation("org.mockito:mockito-inline:$mockitoVersion")
117118
testImplementation("org.assertj:assertj-core:3.23.1")
118119
testImplementation(kotlin("test"))
119-
testImplementation("org.robolectric:robolectric:4.12.2")
120+
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.1")
120121

121122
androidTestImplementation("androidx.test:runner:1.5.2")
122123
androidTestImplementation("androidx.test:rules:1.5.0")
123124
androidTestImplementation("org.mockito:mockito-android:$mockitoVersion")
124125
androidTestImplementation("org.assertj:assertj-core:3.23.1")
126+
androidTestImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.1")
125127
androidTestImplementation(kotlin("test"))
126128

127129
// dependency injection

app/src/test/java/de/westnordost/streetcomplete/data/import/GpxImportParseTest.kt renamed to app/src/androidTest/java/de/westnordost/streetcomplete/data/import/GpxImportParseTest.kt

Lines changed: 61 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
package de.westnordost.streetcomplete.data.import
22

33
import de.westnordost.streetcomplete.data.osm.mapdata.LatLon
4-
import org.junit.runner.RunWith
5-
import org.robolectric.RobolectricTestRunner
4+
import kotlinx.coroutines.flow.toList
5+
import kotlinx.coroutines.runBlocking
66
import kotlin.test.Test
77
import kotlin.test.assertEquals
88
import kotlin.test.assertFails
99

10-
@RunWith(RobolectricTestRunner::class)
1110
class GpxImportParseTest {
1211
@Test
13-
fun `successfully parses minimal sample track`() {
12+
fun successfullyParsesMinimalSampleTrack() = runBlocking {
1413
val originalTrackPoints = arrayListOf(
1514
TrackPoint("22.22", "172.3"),
1615
TrackPoint("39.11111", "-179.999"),
@@ -20,13 +19,17 @@ class GpxImportParseTest {
2019
TrackPoint("-72.0", "0.3"),
2120
)
2221

23-
val inputGpx = minimalGpxBuilder(originalTrackPoints)
22+
val inputGpx =
23+
minimalGpxBuilder(originalTrackPoints)
2424

25-
assertSuccess(originalTrackPoints, parseGpx(inputGpx))
25+
assertSuccess(
26+
originalTrackPoints,
27+
parseGpx(inputGpx)
28+
)
2629
}
2730

2831
@Test
29-
fun `concatenates multiple track segments`() {
32+
fun concatenatesMultipleTrackSegments() = runBlocking {
3033
val trackPointsSegment1 = arrayListOf(
3134
TrackPoint("-56.0", "0.0"),
3235
TrackPoint("57.57", "172.3")
@@ -53,11 +56,14 @@ class GpxImportParseTest {
5356
append("</gpx>")
5457
}
5558

56-
assertSuccess(trackPointsSegment1 + trackPointsSegment2, parseGpx(inputGpx))
59+
assertSuccess(
60+
trackPointsSegment1 + trackPointsSegment2,
61+
parseGpx(inputGpx)
62+
)
5763
}
5864

5965
@Test
60-
fun `process multiple tracks and segments`() {
66+
fun processesMultipleTracksAndSegments() = runBlocking {
6167
val trackPoints1 = arrayListOf(
6268
TrackPoint("-12.33", "0.0"),
6369
TrackPoint("74.1", "-122.34")
@@ -95,21 +101,32 @@ class GpxImportParseTest {
95101
append("</gpx>")
96102
}
97103

98-
assertSuccess(trackPoints1 + trackPoints2 + trackPoints3, parseGpx(inputGpx))
104+
assertSuccess(
105+
trackPoints1 + trackPoints2 + trackPoints3,
106+
parseGpx(inputGpx)
107+
)
99108
}
100109

101110
@Test
102-
fun `throws on invalid trackPoints`() {
111+
fun throwsOnInvalidTrackPoints(): Unit = runBlocking {
103112
assertFails {
104-
parseGpx(minimalGpxBuilder(listOf(TrackPoint("99.0", "-12.1"))))
113+
parseGpx(
114+
minimalGpxBuilder(
115+
listOf(TrackPoint("99.0", "-12.1"))
116+
)
117+
)
105118
}
106119
assertFails {
107-
parseGpx(minimalGpxBuilder(listOf(TrackPoint("-11.5", "-181.0"))))
120+
parseGpx(
121+
minimalGpxBuilder(
122+
listOf(TrackPoint("-11.5", "-181.0"))
123+
)
124+
)
108125
}
109126
}
110127

111128
@Test
112-
fun `throws on non-gpx files`() {
129+
fun throwsOnNonGpxFiles(): Unit = runBlocking {
113130
val nonGpxXml = """
114131
<xml>
115132
</xml>
@@ -120,7 +137,7 @@ class GpxImportParseTest {
120137
}
121138

122139
@Test
123-
fun `Exhausting outer before inner sequence yields no elements`() {
140+
fun exhaustingOuterBeforeInnerFlowYieldsNoElements() = runBlocking {
124141
val inputGpx = minimalGpxBuilder(
125142
arrayListOf(
126143
TrackPoint("-39.654", "180"),
@@ -129,28 +146,28 @@ class GpxImportParseTest {
129146
)
130147

131148
// exhausting outer first
132-
val incorrectlyRetrievedSegments = parseGpxFile(inputGpx.byteInputStream()).toList();
149+
val incorrectlyRetrievedSegments = parseGpxFile(inputGpx.byteInputStream()).toList()
133150
assertEquals(
134151
1, incorrectlyRetrievedSegments.size,
135152
"Exhausting outer first fails to retrieve the track segment"
136153
)
137154
assertEquals(
138-
0, incorrectlyRetrievedSegments.first().count(),
155+
emptyList(), incorrectlyRetrievedSegments.first().toList(),
139156
"Exhausting outer first unexpectedly yields track points"
140157
)
141158

142159
// exhausting inner first
143-
val correctlyRetrievedSegments =
144-
parseGpxFile(inputGpx.byteInputStream()).flatMap { it.toList() }
160+
val correctlyRetrievedSegments = parseGpx(inputGpx)
145161
assertEquals(
146-
2, correctlyRetrievedSegments.count(),
162+
2, correctlyRetrievedSegments.size,
147163
"Exhausting inner first fails to retrieve track points"
148164
)
149165
}
150166

151167
@Test
152-
fun `handles additional data gracefully`() {
153-
val originalTrackPoints = arrayListOf(TrackPoint("88", "-19"))
168+
fun handlesAdditionalDataGracefully() = runBlocking {
169+
val originalTrackPoints =
170+
arrayListOf(TrackPoint("88", "-19"))
154171

155172
val inputGpx = buildString {
156173
append("<gpx version='1.1' xmlns='http://www.topografix.com/GPX/1/1'>")
@@ -167,28 +184,31 @@ class GpxImportParseTest {
167184
append("</gpx>")
168185
}
169186

170-
assertSuccess(originalTrackPoints, parseGpx(inputGpx))
187+
assertSuccess(
188+
originalTrackPoints,
189+
parseGpx(inputGpx)
190+
)
171191
}
172-
}
173192

174-
private fun assertSuccess(
175-
originalTrackPoints: List<TrackPoint>,
176-
parseResult: List<LatLon>,
177-
) {
178-
assertEquals(
179-
originalTrackPoints.size, parseResult.size,
180-
"Not all trackPoints are retrieved"
181-
)
182-
originalTrackPoints.map{it.toLatLon()}.zip(parseResult).forEach { pair ->
183-
assertEquals(
184-
expected = pair.component1().latitude,
185-
actual = pair.component2().latitude,
186-
"Latitudes don't match"
187-
)
193+
private fun assertSuccess(
194+
originalTrackPoints: List<TrackPoint>,
195+
parseResult: List<LatLon>,
196+
) {
188197
assertEquals(
189-
expected = pair.component1().longitude,
190-
actual = pair.component2().longitude,
191-
"Longitudes don't match"
198+
originalTrackPoints.size, parseResult.size,
199+
"Not all trackPoints are retrieved"
192200
)
201+
originalTrackPoints.map { it.toLatLon() }.zip(parseResult).forEach { pair ->
202+
assertEquals(
203+
expected = pair.component1().latitude,
204+
actual = pair.component2().latitude,
205+
"Latitudes don't match"
206+
)
207+
assertEquals(
208+
expected = pair.component1().longitude,
209+
actual = pair.component2().longitude,
210+
"Longitudes don't match"
211+
)
212+
}
193213
}
194214
}

0 commit comments

Comments
 (0)