diff --git a/.github/workflows/reusable-check.yml b/.github/workflows/reusable-check.yml
index ce24c1b66..75557fe00 100644
--- a/.github/workflows/reusable-check.yml
+++ b/.github/workflows/reusable-check.yml
@@ -294,8 +294,6 @@ jobs:
tasks+=(
"app:connectedFdroidDebugAndroidTest"
"app:connectedGoogleDebugAndroidTest"
- "core:barcode:connectedFdroidDebugAndroidTest"
- "core:barcode:connectedGoogleDebugAndroidTest"
)
fi
diff --git a/core/barcode/build.gradle.kts b/core/barcode/build.gradle.kts
index 0be6e2fa7..c2533dd3c 100644
--- a/core/barcode/build.gradle.kts
+++ b/core/barcode/build.gradle.kts
@@ -53,8 +53,5 @@ dependencies {
testRuntimeOnly(libs.junit.vintage.engine)
testImplementation(libs.robolectric)
testImplementation(libs.androidx.compose.ui.test.junit4)
-
- androidTestImplementation(libs.androidx.test.ext.junit)
- androidTestImplementation(libs.androidx.compose.ui.test.junit4)
debugImplementation(libs.androidx.compose.ui.test.manifest)
}
diff --git a/core/barcode/src/androidTest/kotlin/org/meshtastic/core/barcode/BarcodeScannerTest.kt b/core/barcode/src/androidTest/kotlin/org/meshtastic/core/barcode/BarcodeScannerTest.kt
deleted file mode 100644
index 6e36ca79a..000000000
--- a/core/barcode/src/androidTest/kotlin/org/meshtastic/core/barcode/BarcodeScannerTest.kt
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (c) 2025-2026 Meshtastic LLC
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.meshtastic.core.barcode
-
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-class BarcodeScannerTest {
- @Test
- fun placeholder() {
- // Placeholder for AndroidTest
- }
-}
diff --git a/core/common/src/androidHostTest/kotlin/org/meshtastic/core/common/util/CommonUriTest.kt b/core/common/src/androidHostTest/kotlin/org/meshtastic/core/common/util/CommonUriTest.kt
deleted file mode 100644
index fc8c8d04e..000000000
--- a/core/common/src/androidHostTest/kotlin/org/meshtastic/core/common/util/CommonUriTest.kt
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2026 Meshtastic LLC
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.meshtastic.core.common.util
-
-import org.junit.runner.RunWith
-import org.robolectric.RobolectricTestRunner
-import org.robolectric.annotation.Config
-import kotlin.test.Test
-import kotlin.test.assertEquals
-import kotlin.test.assertTrue
-
-@RunWith(RobolectricTestRunner::class)
-@Config(sdk = [34])
-class CommonUriTest {
-
- @Test
- fun testParse() {
- val uri = CommonUri.parse("https://meshtastic.org/path/to/page?param1=value1¶m2=true#fragment")
- assertEquals("meshtastic.org", uri.host)
- assertEquals("fragment", uri.fragment)
- assertEquals(listOf("path", "to", "page"), uri.pathSegments)
- assertEquals("value1", uri.getQueryParameter("param1"))
- assertTrue(uri.getBooleanQueryParameter("param2", false))
- }
-
- @Test
- fun testBooleanParameters() {
- val uri = CommonUri.parse("meshtastic://test?t1=true&t2=1&t3=yes&f1=false&f2=0")
- assertTrue(uri.getBooleanQueryParameter("t1", false))
- assertTrue(uri.getBooleanQueryParameter("t2", false))
- assertTrue(uri.getBooleanQueryParameter("t3", false))
- assertTrue(!uri.getBooleanQueryParameter("f1", true))
- assertTrue(!uri.getBooleanQueryParameter("f2", true))
- }
-}
diff --git a/core/database/build.gradle.kts b/core/database/build.gradle.kts
index 6f5ae71ed..4ebdfbb92 100644
--- a/core/database/build.gradle.kts
+++ b/core/database/build.gradle.kts
@@ -57,10 +57,8 @@ kotlin {
dependencies {
implementation(libs.androidx.sqlite.bundled)
implementation(libs.androidx.room.testing)
- implementation(libs.androidx.test.core)
implementation(libs.androidx.test.ext.junit)
implementation(libs.junit)
- implementation(libs.robolectric)
}
}
val androidDeviceTest by getting {
diff --git a/core/database/src/androidHostTest/kotlin/org/meshtastic/core/database/model/NodeTest.kt b/core/database/src/androidHostTest/kotlin/org/meshtastic/core/database/model/NodeTest.kt
deleted file mode 100644
index 163e03b9e..000000000
--- a/core/database/src/androidHostTest/kotlin/org/meshtastic/core/database/model/NodeTest.kt
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2025-2026 Meshtastic LLC
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.meshtastic.core.model
-
-import org.meshtastic.proto.HardwareModel
-import kotlin.test.Test
-import kotlin.test.assertEquals
-
-class NodeTest {
-
- @Test
- fun `createFallback produces expected node data`() {
- val nodeNum = 0x12345678
- val prefix = "Node"
- val node = Node.createFallback(nodeNum, prefix)
-
- assertEquals(nodeNum, node.num)
- assertEquals("!12345678", node.user.id)
- assertEquals("Node 5678", node.user.long_name)
- assertEquals("5678", node.user.short_name)
- assertEquals(HardwareModel.UNSET, node.user.hw_model)
- }
-
- @Test
- fun `createFallback pads short IDs with zeros`() {
- val nodeNum = 0x1
- val prefix = "Node"
- val node = Node.createFallback(nodeNum, prefix)
-
- assertEquals(nodeNum, node.num)
- assertEquals("!00000001", node.user.id)
- assertEquals("Node 0001", node.user.long_name)
- assertEquals("0001", node.user.short_name)
- }
-}
diff --git a/core/database/src/androidHostTest/kotlin/org/meshtastic/core/database/DatabaseManagerEvictionTest.kt b/core/database/src/commonTest/kotlin/org/meshtastic/core/database/DatabaseManagerEvictionTest.kt
similarity index 100%
rename from core/database/src/androidHostTest/kotlin/org/meshtastic/core/database/DatabaseManagerEvictionTest.kt
rename to core/database/src/commonTest/kotlin/org/meshtastic/core/database/DatabaseManagerEvictionTest.kt
diff --git a/core/model/build.gradle.kts b/core/model/build.gradle.kts
index 4726457fd..4e01fc223 100644
--- a/core/model/build.gradle.kts
+++ b/core/model/build.gradle.kts
@@ -52,13 +52,6 @@ kotlin {
api(libs.androidx.annotation)
api(libs.androidx.core.ktx)
}
- val androidHostTest by getting {
- dependencies {
- implementation(libs.junit)
- implementation(libs.robolectric)
- implementation(libs.androidx.test.ext.junit)
- }
- }
val androidDeviceTest by getting {
dependencies {
implementation(libs.androidx.test.ext.junit)
diff --git a/core/service/build.gradle.kts b/core/service/build.gradle.kts
index 2e0b6965d..1c6b56346 100644
--- a/core/service/build.gradle.kts
+++ b/core/service/build.gradle.kts
@@ -60,8 +60,6 @@ kotlin {
val androidHostTest by getting {
dependencies {
implementation(projects.core.testing)
- implementation(libs.robolectric)
- implementation(libs.androidx.test.core)
implementation(libs.androidx.test.ext.junit)
implementation(libs.androidx.work.testing)
}
diff --git a/core/service/src/test/kotlin/org/meshtastic/core/service/IMeshServiceContractTest.kt b/core/service/src/androidHostTest/kotlin/org/meshtastic/core/service/IMeshServiceContractTest.kt
similarity index 88%
rename from core/service/src/test/kotlin/org/meshtastic/core/service/IMeshServiceContractTest.kt
rename to core/service/src/androidHostTest/kotlin/org/meshtastic/core/service/IMeshServiceContractTest.kt
index a2c02427e..c37f63fb4 100644
--- a/core/service/src/test/kotlin/org/meshtastic/core/service/IMeshServiceContractTest.kt
+++ b/core/service/src/androidHostTest/kotlin/org/meshtastic/core/service/IMeshServiceContractTest.kt
@@ -16,12 +16,17 @@
*/
package org.meshtastic.core.service
+import org.junit.runner.RunWith
import org.meshtastic.core.service.testing.FakeIMeshService
+import org.robolectric.RobolectricTestRunner
+import org.robolectric.annotation.Config
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
/** Test to verify that the AIDL contract is correctly implemented by our test harness. */
+@RunWith(RobolectricTestRunner::class)
+@Config(sdk = [34])
class IMeshServiceContractTest {
@Test
diff --git a/core/service/src/test/kotlin/org/meshtastic/core/service/ServiceClientTest.kt b/core/service/src/test/kotlin/org/meshtastic/core/service/ServiceClientTest.kt
deleted file mode 100644
index 4548fe931..000000000
--- a/core/service/src/test/kotlin/org/meshtastic/core/service/ServiceClientTest.kt
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (c) 2026 Meshtastic LLC
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.meshtastic.core.service
-
-import android.content.ComponentName
-import android.content.Context
-import android.content.Intent
-import android.content.ServiceConnection
-import android.os.IBinder
-import android.os.IInterface
-import dev.mokkery.MockMode
-import dev.mokkery.every
-import dev.mokkery.matcher.any
-import dev.mokkery.matcher.capture.Capture
-import dev.mokkery.matcher.capture.capture
-import dev.mokkery.mock
-import dev.mokkery.verify
-import dev.mokkery.verify.exactly
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.runTest
-import java.util.concurrent.CountDownLatch
-import java.util.concurrent.TimeUnit
-import kotlin.concurrent.thread
-import kotlin.test.Test
-import kotlin.test.assertFailsWith
-import kotlin.test.assertNotNull
-import kotlin.test.assertNull
-import kotlin.test.fail
-
-@OptIn(ExperimentalCoroutinesApi::class)
-class ServiceClientTest {
-
- interface MyInterface : IInterface
-
- private val stubFactory: (IBinder) -> MyInterface = { _ -> mock() }
- private val client = ServiceClient(stubFactory)
- private val context = mock(MockMode.autofill)
- private val intent = mock()
- private val binder = mock()
-
- @Test
- fun `connect binds service successfully`() = runTest {
- val slot = Capture.slot()
- every { context.bindService(any(), capture(slot), any()) } returns true
-
- client.connect(context, intent, 0)
-
- verify { context.bindService(intent, any(), 0) }
-
- // Simulate connection
- try {
- slot.get().onServiceConnected(ComponentName("pkg", "cls"), binder)
- assertNotNull(client.serviceP)
- } catch (e: NoSuchElementException) {
- fail("ServiceConnection was not captured")
- }
- }
-
- @Test
- fun `connect retries on failure`() = runTest {
- val slot = Capture.slot()
- // First attempt fails, second succeeds
- every { context.bindService(any(), capture(slot), any()) } sequentially
- {
- returns(false)
- returns(true)
- }
-
- client.connect(context, intent, 0)
-
- verify(exactly(2)) { context.bindService(intent, any(), 0) }
- }
-
- @Test
- fun `connect throws exception after two failures`() = runTest {
- every { context.bindService(any(), any(), any()) } returns false
- assertFailsWith { client.connect(context, intent, 0) }
- }
-
- @Test
- fun `waitConnect blocks until connected`() {
- val slot = Capture.slot()
- every { context.bindService(any(), capture(slot), any()) } returns true
-
- // Run connect in a coroutine scope (it's suspend)
- runTest { client.connect(context, intent, 0) }
-
- val latch = CountDownLatch(1)
- thread {
- client.waitConnect()
- latch.countDown()
- }
-
- // Verify it's blocked (wait a bit)
- if (latch.await(100, TimeUnit.MILLISECONDS)) {
- fail("waitConnect should block until connected")
- }
-
- // Simulate connection
- try {
- slot.get().onServiceConnected(ComponentName("pkg", "cls"), binder)
- } catch (e: NoSuchElementException) {
- fail("ServiceConnection was not captured")
- }
-
- // Verify it unblocks
- if (!latch.await(1, TimeUnit.SECONDS)) {
- fail("waitConnect should unblock after connection")
- }
-
- assertNotNull(client.serviceP)
- }
-
- @Test
- fun `close unbinds service`() = runTest {
- val slot = Capture.slot()
- every { context.bindService(any(), capture(slot), any()) } returns true
-
- client.connect(context, intent, 0)
-
- try {
- client.close()
- verify { context.unbindService(slot.get()) }
- assertNull(client.serviceP)
- } catch (e: NoSuchElementException) {
- fail("ServiceConnection was not captured")
- }
- }
-}
diff --git a/core/ui/src/androidHostTest/kotlin/org/meshtastic/core/ui/timezone/ZoneIdExtensionsTest.kt b/core/ui/src/androidHostTest/kotlin/org/meshtastic/core/ui/timezone/ZoneIdExtensionsTest.kt
deleted file mode 100644
index 6d055886a..000000000
--- a/core/ui/src/androidHostTest/kotlin/org/meshtastic/core/ui/timezone/ZoneIdExtensionsTest.kt
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (c) 2025-2026 Meshtastic LLC
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.meshtastic.core.ui.timezone
-
-import kotlinx.datetime.TimeZone
-import org.meshtastic.core.model.util.toPosixString
-import kotlin.test.Test
-import kotlin.test.assertEquals
-
-class ZoneIdExtensionsTest {
-
- @Test
- fun `test POSIX string generation`() {
- val zoneMap =
- mapOf(
- "US/Hawaii" to "HST10",
- "US/Alaska" to "AKST9AKDT,M3.2.0,M11.1.0",
- "US/Pacific" to "PST8PDT,M3.2.0,M11.1.0",
- "US/Arizona" to "MST7",
- "US/Mountain" to "MST7MDT,M3.2.0,M11.1.0",
- "US/Central" to "CST6CDT,M3.2.0,M11.1.0",
- "US/Eastern" to "EST5EDT,M3.2.0,M11.1.0",
- "America/Sao_Paulo" to "BRT3",
- "UTC" to "UTC0",
- "Europe/London" to "GMT0BST,M3.5.0/1,M10.5.0",
- "Europe/Lisbon" to "WET0WEST,M3.5.0/1,M10.5.0",
- "Europe/Budapest" to "CET-1CEST,M3.5.0,M10.5.0/3",
- "Europe/Kiev" to "EET-2EEST,M3.5.0/3,M10.5.0/4",
- "Africa/Cairo" to "EET-2EEST,M4.5.5/0,M10.5.5/0",
- "Asia/Kolkata" to "IST-5:30",
- "Asia/Hong_Kong" to "HKT-8",
- "Asia/Tokyo" to "JST-9",
- "Australia/Perth" to "AWST-8",
- "Australia/Adelaide" to "ACST-9:30ACDT,M10.1.0,M4.1.0/3",
- "Australia/Sydney" to "AEST-10AEDT,M10.1.0,M4.1.0/3",
- "Pacific/Auckland" to "NZST-12NZDT,M9.5.0,M4.1.0/3",
- )
-
- zoneMap.forEach { (tz, expected) -> assertEquals(expected, TimeZone.of(tz).toPosixString()) }
- }
-}
diff --git a/feature/connections/build.gradle.kts b/feature/connections/build.gradle.kts
index 9ac1a69ba..f6fb40ae8 100644
--- a/feature/connections/build.gradle.kts
+++ b/feature/connections/build.gradle.kts
@@ -49,12 +49,5 @@ kotlin {
}
androidMain.dependencies { implementation(libs.usb.serial.android) }
-
- val androidHostTest by getting {
- dependencies {
- implementation(libs.androidx.test.core)
- implementation(libs.robolectric)
- }
- }
}
}
diff --git a/feature/firmware/build.gradle.kts b/feature/firmware/build.gradle.kts
index cf8d08e8b..8fee603bf 100644
--- a/feature/firmware/build.gradle.kts
+++ b/feature/firmware/build.gradle.kts
@@ -58,16 +58,9 @@ kotlin {
androidMain.dependencies { implementation(libs.markdown.renderer.android) }
- commonTest.dependencies {
- implementation(projects.core.testing)
- implementation(libs.turbine)
- }
-
val androidHostTest by getting {
dependencies {
implementation(libs.junit)
- implementation(libs.robolectric)
- implementation(libs.turbine)
implementation(libs.kotlinx.coroutines.test)
implementation(libs.androidx.compose.ui.test.junit4)
implementation(libs.androidx.test.ext.junit)
diff --git a/feature/intro/build.gradle.kts b/feature/intro/build.gradle.kts
index e93ce2924..fe05a2b43 100644
--- a/feature/intro/build.gradle.kts
+++ b/feature/intro/build.gradle.kts
@@ -42,9 +42,7 @@ kotlin {
val androidHostTest by getting {
dependencies {
implementation(libs.junit)
- implementation(libs.robolectric)
implementation(project.dependencies.platform(libs.androidx.compose.bom))
- implementation(libs.androidx.test.core)
implementation(libs.kotlinx.coroutines.test)
implementation(libs.androidx.compose.ui.test.junit4)
}
diff --git a/feature/map/build.gradle.kts b/feature/map/build.gradle.kts
index e417843e1..fff9fe21b 100644
--- a/feature/map/build.gradle.kts
+++ b/feature/map/build.gradle.kts
@@ -47,10 +47,8 @@ kotlin {
val androidHostTest by getting {
dependencies {
implementation(libs.junit)
- implementation(libs.robolectric)
implementation(project.dependencies.platform(libs.androidx.compose.bom))
implementation(libs.kotlinx.coroutines.test)
- implementation(libs.androidx.test.core)
}
}
}
diff --git a/feature/messaging/build.gradle.kts b/feature/messaging/build.gradle.kts
index e6634e0a1..e06b417b7 100644
--- a/feature/messaging/build.gradle.kts
+++ b/feature/messaging/build.gradle.kts
@@ -56,12 +56,6 @@ kotlin {
androidMain.dependencies { implementation(libs.androidx.work.runtime.ktx) }
- val androidHostTest by getting {
- dependencies {
- implementation(libs.androidx.work.testing)
- implementation(libs.androidx.test.core)
- implementation(libs.robolectric)
- }
- }
+ val androidHostTest by getting { dependencies { implementation(libs.androidx.work.testing) } }
}
}
diff --git a/feature/messaging/src/androidHostTest/kotlin/org/meshtastic/feature/messaging/HomoglyphCharacterTransformTest.kt b/feature/messaging/src/commonTest/kotlin/org/meshtastic/feature/messaging/HomoglyphCharacterTransformTest.kt
similarity index 89%
rename from feature/messaging/src/androidHostTest/kotlin/org/meshtastic/feature/messaging/HomoglyphCharacterTransformTest.kt
rename to feature/messaging/src/commonTest/kotlin/org/meshtastic/feature/messaging/HomoglyphCharacterTransformTest.kt
index f75031fa8..30ec27f16 100644
--- a/feature/messaging/src/androidHostTest/kotlin/org/meshtastic/feature/messaging/HomoglyphCharacterTransformTest.kt
+++ b/feature/messaging/src/commonTest/kotlin/org/meshtastic/feature/messaging/HomoglyphCharacterTransformTest.kt
@@ -27,8 +27,8 @@ class HomoglyphCharacterTransformTest {
fun `optimizeUtf8StringWithHomoglyphs shrinks binary size of cyrillic text containing some homoglyphs`() {
val testString = "Мештастик - это проект с открытым исходным кодом"
val transformedTestString = HomoglyphCharacterStringTransformer.optimizeUtf8StringWithHomoglyphs(testString)
- val testStringBytes = testString.toByteArray(charset = Charsets.UTF_8)
- val transformedTestStringBytes = transformedTestString.toByteArray(charset = Charsets.UTF_8)
+ val testStringBytes = testString.encodeToByteArray()
+ val transformedTestStringBytes = transformedTestString.encodeToByteArray()
val transformedStringBinarySizeShrinked = transformedTestStringBytes.size < testStringBytes.size
assertTrue(transformedStringBinarySizeShrinked)
}
@@ -37,8 +37,8 @@ class HomoglyphCharacterTransformTest {
fun `optimizeUtf8StringWithHomoglyphs shrinks binary size in half of cyrillic text containing only homoglyphs`() {
val testString = "Косуха"
val transformedTestString = HomoglyphCharacterStringTransformer.optimizeUtf8StringWithHomoglyphs(testString)
- val testStringBytes = testString.toByteArray(charset = Charsets.UTF_8)
- val transformedTestStringBytes = transformedTestString.toByteArray(charset = Charsets.UTF_8)
+ val testStringBytes = testString.encodeToByteArray()
+ val transformedTestStringBytes = transformedTestString.encodeToByteArray()
assertEquals(transformedTestStringBytes.size, testStringBytes.size / 2)
}
diff --git a/feature/node/build.gradle.kts b/feature/node/build.gradle.kts
index 2e408d341..6195fb13b 100644
--- a/feature/node/build.gradle.kts
+++ b/feature/node/build.gradle.kts
@@ -66,8 +66,6 @@ kotlin {
val androidHostTest by getting {
dependencies {
implementation(libs.junit)
- implementation(libs.robolectric)
- implementation(libs.turbine)
implementation(libs.kotlinx.coroutines.test)
implementation(libs.androidx.compose.ui.test.junit4)
implementation(libs.androidx.test.ext.junit)
diff --git a/feature/node/src/test/kotlin/org/meshtastic/feature/node/metrics/BaseMetricScreenTest.kt b/feature/node/src/test/kotlin/org/meshtastic/feature/node/metrics/BaseMetricScreenTest.kt
deleted file mode 100644
index 99572b3a9..000000000
--- a/feature/node/src/test/kotlin/org/meshtastic/feature/node/metrics/BaseMetricScreenTest.kt
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (c) 2026 Meshtastic LLC
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.meshtastic.feature.node.metrics
-
-import androidx.compose.material3.Text
-import androidx.compose.ui.test.assertIsDisplayed
-import androidx.compose.ui.test.junit4.createComposeRule
-import androidx.compose.ui.test.onNodeWithTag
-import androidx.compose.ui.test.onNodeWithText
-import androidx.compose.ui.test.performClick
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.meshtastic.core.model.TelemetryType
-import org.meshtastic.core.resources.Res
-import org.meshtastic.core.resources.device_metrics_log
-import org.meshtastic.core.ui.theme.AppTheme
-import org.robolectric.RobolectricTestRunner
-import org.robolectric.annotation.Config
-import kotlin.test.assertTrue
-
-@RunWith(RobolectricTestRunner::class)
-@Config(sdk = [34])
-class BaseMetricScreenTest {
-
- @get:Rule val composeTestRule = createComposeRule()
-
- @Test
- fun baseMetricScreen_displaysTitleAndNodeName() {
- val nodeName = "Test Node 123"
- val testData = listOf("Item 1", "Item 2")
-
- composeTestRule.setContent {
- AppTheme {
- BaseMetricScreen(
- onNavigateUp = {},
- telemetryType = TelemetryType.DEVICE,
- titleRes = Res.string.device_metrics_log,
- nodeName = nodeName,
- data = testData,
- timeProvider = { 0.0 },
- chartPart = { _, _, _, _ -> Text("Chart Placeholder") },
- listPart = { _, _, _, _ -> Text("List Placeholder") },
- )
- }
- }
-
- // Verify Node Name is displayed (MainAppBar title)
- composeTestRule.onNodeWithText(nodeName).assertIsDisplayed()
-
- // Verify Placeholders are displayed
- composeTestRule.onNodeWithText("Chart Placeholder").assertIsDisplayed()
- composeTestRule.onNodeWithText("List Placeholder").assertIsDisplayed()
- }
-
- @Test
- fun baseMetricScreen_refreshButtonTriggersCallback() {
- var refreshClicked = false
- val testData = emptyList()
-
- composeTestRule.setContent {
- AppTheme {
- BaseMetricScreen(
- onNavigateUp = {},
- telemetryType = TelemetryType.DEVICE,
- titleRes = Res.string.device_metrics_log,
- nodeName = "Node",
- data = testData,
- timeProvider = { 0.0 },
- onRequestTelemetry = { refreshClicked = true },
- chartPart = { _, _, _, _ -> },
- listPart = { _, _, _, _ -> },
- )
- }
- }
-
- composeTestRule.onNodeWithTag("refresh_button").performClick()
-
- assertTrue("Refresh callback should be triggered", refreshClicked)
- }
-}
diff --git a/feature/settings/build.gradle.kts b/feature/settings/build.gradle.kts
index 5419e3276..4b868fbc4 100644
--- a/feature/settings/build.gradle.kts
+++ b/feature/settings/build.gradle.kts
@@ -57,17 +57,12 @@ kotlin {
implementation(libs.androidx.appcompat)
}
- commonTest.dependencies {
- implementation(project(":core:testing"))
- implementation(project(":core:datastore"))
- }
+ commonTest.dependencies { implementation(project(":core:datastore")) }
val androidHostTest by getting {
dependencies {
implementation(project(":core:datastore"))
implementation(libs.junit)
- implementation(libs.robolectric)
- implementation(libs.turbine)
implementation(libs.kotlinx.coroutines.test)
implementation(libs.androidx.compose.ui.test.junit4)
implementation(libs.androidx.compose.ui.test.manifest)
diff --git a/feature/settings/src/androidHostTest/kotlin/org/meshtastic/feature/settings/debugging/DebugFiltersTest.kt b/feature/settings/src/androidHostTest/kotlin/org/meshtastic/feature/settings/debugging/DebugFiltersTest.kt
deleted file mode 100644
index aeef9129d..000000000
--- a/feature/settings/src/androidHostTest/kotlin/org/meshtastic/feature/settings/debugging/DebugFiltersTest.kt
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (c) 2025-2026 Meshtastic LLC
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.meshtastic.feature.settings.debugging
-
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.padding
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.setValue
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.test.assertIsDisplayed
-import androidx.compose.ui.test.junit4.v2.createComposeRule
-import androidx.compose.ui.test.onNodeWithContentDescription
-import androidx.compose.ui.test.onNodeWithText
-import androidx.compose.ui.test.performClick
-import androidx.compose.ui.test.performTextInput
-import androidx.compose.ui.unit.dp
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.platform.app.InstrumentationRegistry
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.meshtastic.core.resources.Res
-import org.meshtastic.core.resources.debug_active_filters
-import org.meshtastic.core.resources.debug_filters
-import org.meshtastic.core.resources.getString
-import org.meshtastic.feature.settings.debugging.DebugViewModel.UiMeshLog
-import org.robolectric.annotation.Config
-
-@RunWith(AndroidJUnit4::class)
-@Config(sdk = [34])
-class DebugFiltersTest {
-
- @get:Rule val composeTestRule = createComposeRule()
-
- @Test
- fun debugFilterBar_showsFilterButtonAndMenu() {
- val filterLabel = getString(Res.string.debug_filters)
- composeTestRule.setContent {
- var filterTexts by remember { mutableStateOf(listOf()) }
- var customFilterText by remember { mutableStateOf("") }
- val presetFilters = listOf("Error", "Warning", "Info")
- val logs =
- listOf(
- UiMeshLog(
- uuid = "1",
- messageType = "Info",
- formattedReceivedDate = "2024-01-01 12:00:00",
- logMessage = "Sample log message",
- ),
- )
- DebugFilterBar(
- filterTexts = filterTexts,
- onFilterTextsChange = { filterTexts = it },
- customFilterText = customFilterText,
- onCustomFilterTextChange = { customFilterText = it },
- presetFilters = presetFilters,
- logs = logs,
- )
- }
- // The filter button should be visible
- composeTestRule.onNodeWithText(filterLabel).assertIsDisplayed()
- }
-
- @Test
- fun debugFilterBar_addCustomFilter_displaysActiveFilter() {
- val context = InstrumentationRegistry.getInstrumentation().targetContext
- val activeFiltersLabel = getString(Res.string.debug_active_filters)
- composeTestRule.setContent {
- var filterTexts by remember { mutableStateOf(listOf()) }
- var customFilterText by remember { mutableStateOf("") }
- Column(modifier = Modifier.padding(16.dp)) {
- DebugActiveFilters(
- filterTexts = filterTexts,
- onFilterTextsChange = { filterTexts = it },
- filterMode = FilterMode.OR,
- onFilterModeChange = {},
- )
- DebugCustomFilterInput(
- customFilterText = customFilterText,
- onCustomFilterTextChange = { customFilterText = it },
- filterTexts = filterTexts,
- onFilterTextsChange = { filterTexts = it },
- )
- }
- }
- with(composeTestRule) {
- // Add a custom filter
- onNodeWithText("Add custom filter").performTextInput("MyFilter")
- onNodeWithContentDescription("Add filter").performClick()
- // The active filters label and the filter chip should be visible
- onNodeWithText(activeFiltersLabel).assertIsDisplayed()
- onNodeWithText("MyFilter").assertIsDisplayed()
- }
- }
-
- @Test
- fun debugActiveFilters_clearAllFilters_removesFilters() {
- val activeFiltersLabel = getString(Res.string.debug_active_filters)
- composeTestRule.setContent {
- var filterTexts by remember { mutableStateOf(listOf("A", "B")) }
- DebugActiveFilters(
- filterTexts = filterTexts,
- onFilterTextsChange = { filterTexts = it },
- filterMode = FilterMode.OR,
- onFilterModeChange = {},
- )
- }
- // The active filters label and chips should be visible
- composeTestRule.onNodeWithText(activeFiltersLabel).assertIsDisplayed()
- composeTestRule.onNodeWithText("A").assertIsDisplayed()
- composeTestRule.onNodeWithText("B").assertIsDisplayed()
- // Click the clear all filters button
- composeTestRule.onNodeWithContentDescription("Clear all filters").performClick()
- // The filter chips should no longer be visible
- composeTestRule.onNodeWithText("A").assertDoesNotExist()
- composeTestRule.onNodeWithText("B").assertDoesNotExist()
- }
-}
diff --git a/feature/settings/src/test/kotlin/org/meshtastic/feature/settings/HomoglyphSettingTest.kt b/feature/settings/src/test/kotlin/org/meshtastic/feature/settings/HomoglyphSettingTest.kt
deleted file mode 100644
index 8ffb10fae..000000000
--- a/feature/settings/src/test/kotlin/org/meshtastic/feature/settings/HomoglyphSettingTest.kt
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (c) 2026 Meshtastic LLC
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.meshtastic.feature.settings
-
-import android.content.res.Configuration
-import androidx.compose.runtime.CompositionLocalProvider
-import androidx.compose.ui.platform.LocalConfiguration
-import androidx.compose.ui.test.assertIsDisplayed
-import androidx.compose.ui.test.junit4.v2.createComposeRule
-import androidx.compose.ui.test.onNodeWithText
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.meshtastic.core.resources.Res
-import org.meshtastic.core.resources.getString
-import org.meshtastic.core.resources.use_homoglyph_characters_encoding
-import org.meshtastic.feature.settings.component.HomoglyphSetting
-import org.robolectric.RobolectricTestRunner
-import org.robolectric.annotation.Config
-import java.util.Locale
-
-@RunWith(RobolectricTestRunner::class)
-@Config(sdk = [34])
-class HomoglyphSettingTest {
-
- @get:Rule val composeTestRule = createComposeRule()
-
- @Test
- fun homoglyphSetting_isVisible_forRussianLocale() {
- val russianConfig = Configuration().apply { setLocale(Locale.forLanguageTag("ru")) }
-
- composeTestRule.setContent {
- CompositionLocalProvider(LocalConfiguration provides russianConfig) {
- HomoglyphSetting(homoglyphEncodingEnabled = false, onToggle = {})
- }
- }
-
- val expectedText = getString(Res.string.use_homoglyph_characters_encoding)
- composeTestRule.onNodeWithText(expectedText).assertIsDisplayed()
- }
-
- @Test
- fun homoglyphSetting_isNotVisible_forEnglishLocale() {
- val englishConfig = Configuration().apply { setLocale(Locale.forLanguageTag("en")) }
-
- composeTestRule.setContent {
- CompositionLocalProvider(LocalConfiguration provides englishConfig) {
- HomoglyphSetting(homoglyphEncodingEnabled = false, onToggle = {})
- }
- }
-
- val expectedText = getString(Res.string.use_homoglyph_characters_encoding)
- composeTestRule.onNodeWithText(expectedText).assertDoesNotExist()
- }
-}