Skip to content

Commit ae417a5

Browse files
committed
feat: add tests framework
Signed-off-by: Lennoard <lennoardrai@gmail.com>
1 parent a4eea53 commit ae417a5

File tree

5 files changed

+125
-4
lines changed

5 files changed

+125
-4
lines changed

app/build.gradle.kts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ android {
1717
applicationId = AppConfig.appId
1818
minSdk = AppConfig.minSdkVersion
1919
targetSdk = AppConfig.targetSdkVersion
20-
versionCode = 20
21-
versionName = "3.0.1"
20+
versionCode = 21
21+
versionName = "3.0.2"
2222
vectorDrawables.useSupportLibrary = true
2323
androidResources {
2424
localeFilters += listOf("en", "de", "pt-rBR", "tr")

data/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,6 @@ dependencies {
6363
ksp(libs.androidx.room.compiler)
6464

6565
testImplementation(libs.junit)
66+
testImplementation(libs.mockk.android)
67+
testImplementation(libs.kotlinx.coroutines.test)
6668
}

data/src/main/java/com/androidvip/sysctlgui/data/repository/DocumentationRepositoryImpl.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import com.androidvip.sysctlgui.domain.models.KernelParam
55
import com.androidvip.sysctlgui.domain.models.ParamDocumentation
66
import com.androidvip.sysctlgui.domain.repository.AppPrefs
77
import com.androidvip.sysctlgui.domain.repository.DocumentationRepository
8-
import kotlinx.coroutines.withTimeout
98
import kotlinx.coroutines.withTimeoutOrNull
109

1110
/**
@@ -36,6 +35,6 @@ class DocumentationRepositoryImpl(
3635
}
3736

3837
companion object {
39-
private const val REQUEST_TIMEOUT_MS = 3000L
38+
internal const val REQUEST_TIMEOUT_MS = 3000L
4039
}
4140
}
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
package com.androidvip.sysctlgui.data.repository
2+
3+
import com.androidvip.sysctlgui.data.source.DocumentationDataSource
4+
import com.androidvip.sysctlgui.domain.models.KernelParam
5+
import com.androidvip.sysctlgui.domain.models.ParamDocumentation
6+
import io.mockk.called
7+
import io.mockk.coEvery
8+
import io.mockk.coVerify
9+
import io.mockk.mockk
10+
import io.mockk.verify
11+
import kotlinx.coroutines.delay
12+
import kotlinx.coroutines.test.runTest
13+
import org.junit.Assert
14+
import org.junit.Before
15+
import org.junit.Test
16+
17+
class DocumentationRepositoryImplTest {
18+
private val offlineDataSource: DocumentationDataSource = mockk(relaxed = true)
19+
private val onlineDataSource: DocumentationDataSource = mockk(relaxed = true)
20+
private lateinit var repository: DocumentationRepositoryImpl
21+
22+
private val testParam = KernelParam(
23+
name = "vm.swappiness",
24+
path = "/proc/sys/vm/swappiness",
25+
value = "100"
26+
)
27+
28+
private val expectedDocumentation = ParamDocumentation(
29+
title = "Swappiness",
30+
documentationText = "Controls swappiness",
31+
url = "https://docs.kernel.org/admin-guide/sysctl/vm.html#swappiness"
32+
)
33+
34+
@Before
35+
fun setUp() {
36+
repository = DocumentationRepositoryImpl(offlineDataSource, onlineDataSource)
37+
}
38+
39+
@Test
40+
fun `getDocumentation when online is true and online source succeeds then return online documentation`() =
41+
runTest {
42+
// Given
43+
coEvery { onlineDataSource.getDocumentation(testParam) } returns expectedDocumentation
44+
45+
// When
46+
val result = repository.getDocumentation(testParam, online = true)
47+
48+
// Then
49+
coVerify(exactly = 1) { onlineDataSource.getDocumentation(testParam) }
50+
verify { offlineDataSource wasNot called }
51+
52+
Assert.assertEquals(expectedDocumentation, result)
53+
}
54+
55+
@Test
56+
fun `getDocumentation when online is true and online source times out then return offline documentation`() = runTest {
57+
// Given
58+
coEvery { onlineDataSource.getDocumentation(testParam) } coAnswers {
59+
delay(DocumentationRepositoryImpl.REQUEST_TIMEOUT_MS + 100)
60+
null
61+
}
62+
63+
coEvery { onlineDataSource.getDocumentation(testParam) } returns null
64+
coEvery { offlineDataSource.getDocumentation(testParam) } returns expectedDocumentation
65+
66+
// When
67+
val result = repository.getDocumentation(testParam, online = true)
68+
69+
// Then
70+
coVerify(exactly = 1) { onlineDataSource.getDocumentation(testParam) }
71+
coVerify(exactly = 1) { offlineDataSource.getDocumentation(testParam) }
72+
Assert.assertEquals(expectedDocumentation, result)
73+
}
74+
75+
@Test
76+
fun `getDocumentation when online is false then return offline documentation`() = runTest {
77+
// Given
78+
coEvery { offlineDataSource.getDocumentation(testParam) } returns expectedDocumentation
79+
80+
// When
81+
val result = repository.getDocumentation(testParam, online = false)
82+
83+
// Then
84+
coVerify(exactly = 1) { offlineDataSource.getDocumentation(testParam) }
85+
verify { onlineDataSource wasNot called }
86+
Assert.assertEquals(expectedDocumentation, result)
87+
}
88+
89+
@Test
90+
fun `getDocumentation when online is true and both sources return null then return null`() = runTest {
91+
// Given
92+
coEvery { onlineDataSource.getDocumentation(testParam) } returns null
93+
coEvery { offlineDataSource.getDocumentation(testParam) } returns null
94+
95+
// When
96+
val result = repository.getDocumentation(testParam, online = true)
97+
98+
// Then
99+
coVerify(exactly = 1) { onlineDataSource.getDocumentation(testParam) }
100+
coVerify(exactly = 1) { offlineDataSource.getDocumentation(testParam) }
101+
Assert.assertNull(result)
102+
}
103+
104+
@Test
105+
fun `getDocumentation when online is false and offline source returns null then return null`() = runTest {
106+
// Given
107+
coEvery { offlineDataSource.getDocumentation(testParam) } returns null
108+
109+
// When
110+
val result = repository.getDocumentation(testParam, online = false)
111+
112+
// Then
113+
coVerify(exactly = 1) { offlineDataSource.getDocumentation(testParam) }
114+
verify { onlineDataSource wasNot called }
115+
Assert.assertNull(result)
116+
}
117+
}

gradle/libs.versions.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ composeBom = "2025.07.00"
1717
appcompat = "1.7.1"
1818
materialIconsCoreCompose = "1.7.8"
1919
material = "1.12.0"
20+
mockkAndroid = "1.14.5"
2021
multidex = "2.0.1"
2122
navigationCompose = "2.9.3"
2223
preference = "1.2.1"
@@ -39,6 +40,7 @@ androidx-navigation-compose = { module = "androidx.navigation:navigation-compose
3940
androidx-preference = { module = "androidx.preference:preference", version.ref = "preference" }
4041
androidx-window = { module = "androidx.window:window", version.ref = "window" }
4142
androidx-work-runtime-ktx = { module = "androidx.work:work-runtime-ktx", version.ref = "workRuntimeKtx" }
43+
kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinxCoroutinesAndroid" }
4244
libsu-core = { module = "com.github.topjohnwu.libsu:core", version.ref = "libsu" }
4345
libsu-nio = { module = "com.github.topjohnwu.libsu:nio", version.ref = "libsu" }
4446
jsoup = { module = "org.jsoup:jsoup", version.ref = "jsoup" }
@@ -73,6 +75,7 @@ ktor-client-android = { module = "io.ktor:ktor-client-android", version.ref = "k
7375
ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" }
7476
ktor-client-logging = { module = "io.ktor:ktor-client-logging", version.ref = "ktor" }
7577
material = { module = "com.google.android.material:material", version.ref = "material" }
78+
mockk-android = { module = "io.mockk:mockk-android", version.ref = "mockkAndroid" }
7679

7780
[bundles]
7881
ktor-clients = ["ktor-client-core", "ktor-client-android", "ktor-client-logging"]

0 commit comments

Comments
 (0)