Refactor map layer management and navigation infrastructure (#4921)

Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
This commit is contained in:
James Rich 2026-03-25 19:29:24 -05:00 committed by GitHub
parent b608a04ca4
commit a005231d94
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
142 changed files with 5408 additions and 3090 deletions

View file

@ -17,26 +17,16 @@
package org.meshtastic.core.network.radio
import dev.mokkery.MockMode
import dev.mokkery.answering.returns
import dev.mokkery.every
import dev.mokkery.everySuspend
import dev.mokkery.matcher.any
import dev.mokkery.mock
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest
import org.meshtastic.core.ble.BleConnection
import org.meshtastic.core.ble.BleConnectionFactory
import org.meshtastic.core.ble.BleConnectionState
import org.meshtastic.core.ble.BleDevice
import org.meshtastic.core.ble.BleScanner
import org.meshtastic.core.ble.BluetoothRepository
import org.meshtastic.core.ble.BluetoothState
import org.meshtastic.core.repository.RadioInterfaceService
import org.meshtastic.core.testing.FakeBleConnection
import org.meshtastic.core.testing.FakeBleConnectionFactory
import org.meshtastic.core.testing.FakeBleDevice
import org.meshtastic.core.testing.FakeBleScanner
import org.meshtastic.core.testing.FakeBluetoothRepository
import kotlin.test.BeforeTest
import kotlin.test.Test
import kotlin.test.assertEquals
@ -45,33 +35,23 @@ import kotlin.test.assertEquals
class BleRadioInterfaceTest {
private val testScope = TestScope()
private val scanner: BleScanner = mock()
private val bluetoothRepository: BluetoothRepository = mock()
private val connectionFactory: BleConnectionFactory = mock()
private val connection: BleConnection = mock()
private val scanner = FakeBleScanner()
private val bluetoothRepository = FakeBluetoothRepository()
private val connection = FakeBleConnection()
private val connectionFactory = FakeBleConnectionFactory(connection)
private val service: RadioInterfaceService = mock(MockMode.autofill)
private val address = "00:11:22:33:44:55"
private val connectionStateFlow = MutableSharedFlow<BleConnectionState>(replay = 1)
private val bluetoothStateFlow = MutableStateFlow(BluetoothState())
@BeforeTest
fun setup() {
every { connectionFactory.create(any(), any()) } returns connection
every { connection.connectionState } returns connectionStateFlow
every { bluetoothRepository.state } returns bluetoothStateFlow.asStateFlow()
bluetoothStateFlow.value = BluetoothState(enabled = true, hasPermissions = true)
bluetoothRepository.setHasPermissions(true)
bluetoothRepository.setBluetoothEnabled(true)
}
@Test
fun `connect attempts to scan and connect via init`() = runTest {
val device: BleDevice = mock()
every { device.address } returns address
every { device.name } returns "Test Device"
every { scanner.scan(any(), any()) } returns flowOf(device)
everySuspend { connection.connectAndAwait(any(), any(), any()) } returns BleConnectionState.Connected
val device = FakeBleDevice(address = address, name = "Test Device")
scanner.emitDevice(device)
val bleInterface =
BleRadioInterface(
@ -84,8 +64,9 @@ class BleRadioInterfaceTest {
)
// init starts connect() which is async
// We can wait for the coEvery to be triggered if needed,
// but for a basic test this confirms it doesn't crash on init.
// In a real test we'd verify the connection state,
// but for now this confirms it works with the fakes.
assertEquals(address, bleInterface.address)
}
@Test

View file

@ -154,6 +154,26 @@ class StreamFrameCodecTest {
assertEquals(listOf(0xAA.toByte()), receivedPackets[0].toList())
}
@Test
fun `frameAndSend produces correct header for 1-byte payload`() = runTest {
val payload = byteArrayOf(0x42.toByte())
val sentBytes = mutableListOf<ByteArray>()
codec.frameAndSend(payload, sendBytes = { sentBytes.add(it) })
// First sent bytes are the 4-byte header, second is the payload
assertEquals(2, sentBytes.size)
val header = sentBytes[0]
assertEquals(4, header.size)
assertEquals(0x94.toByte(), header[0])
assertEquals(0xc3.toByte(), header[1])
assertEquals(0x00.toByte(), header[2])
assertEquals(0x01.toByte(), header[3])
val sentPayload = sentBytes[1]
assertEquals(payload.toList(), sentPayload.toList())
}
@Test
fun `WAKE_BYTES is four START1 bytes`() {
assertEquals(4, StreamFrameCodec.WAKE_BYTES.size)

View file

@ -1,52 +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 <https://www.gnu.org/licenses/>.
*/
package org.meshtastic.core.network.radio
import kotlinx.coroutines.test.runTest
import org.meshtastic.core.network.transport.StreamFrameCodec
import org.meshtastic.proto.Heartbeat
import org.meshtastic.proto.ToRadio
import kotlin.test.Test
import kotlin.test.assertEquals
class TCPInterfaceTest {
@Test
fun testHeartbeatFraming() = runTest {
val sentBytes = mutableListOf<ByteArray>()
val codec = StreamFrameCodec(onPacketReceived = {}, logTag = "Test")
val heartbeat = ToRadio(heartbeat = Heartbeat()).encode()
codec.frameAndSend(heartbeat, { sentBytes.add(it) })
// First sent bytes are the 4-byte header, second is the payload
assertEquals(2, sentBytes.size)
val header = sentBytes[0]
assertEquals(4, header.size)
assertEquals(0x94.toByte(), header[0])
assertEquals(0xc3.toByte(), header[1])
val payload = sentBytes[1]
assertEquals(heartbeat.toList(), payload.toList())
}
@Test
fun testServicePort() {
assertEquals(4403, TCPInterface.SERVICE_PORT)
}
}