mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-04-20 22:23:37 +00:00
Refactor map layer management and navigation infrastructure (#4921)
Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
This commit is contained in:
parent
b608a04ca4
commit
a005231d94
142 changed files with 5408 additions and 3090 deletions
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.repository
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import org.meshtastic.core.database.entity.FirmwareRelease
|
||||
|
||||
interface FirmwareReleaseRepository {
|
||||
/** A flow that provides the latest STABLE firmware release. */
|
||||
val stableRelease: Flow<FirmwareRelease?>
|
||||
|
||||
/** A flow that provides the latest ALPHA firmware release. */
|
||||
val alphaRelease: Flow<FirmwareRelease?>
|
||||
|
||||
/** Invalidates the local cache of firmware releases. */
|
||||
suspend fun invalidateCache()
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.repository
|
||||
|
||||
import org.meshtastic.core.testing.FakeRadioPrefs
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class AppPreferencesTest {
|
||||
|
||||
@Test
|
||||
fun `RadioPrefs isBle returns true for x prefix`() {
|
||||
val prefs = FakeRadioPrefs()
|
||||
prefs.setDevAddr("x12345678")
|
||||
assertTrue(prefs.isBle())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `RadioPrefs isBle returns false for other prefix`() {
|
||||
val prefs = FakeRadioPrefs()
|
||||
prefs.setDevAddr("s12345678")
|
||||
assertFalse(prefs.isBle())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `RadioPrefs isSerial returns true for s prefix`() {
|
||||
val prefs = FakeRadioPrefs()
|
||||
prefs.setDevAddr("s12345678")
|
||||
assertTrue(prefs.isSerial())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `RadioPrefs isTcp returns true for t prefix`() {
|
||||
val prefs = FakeRadioPrefs()
|
||||
prefs.setDevAddr("t192.168.1.1")
|
||||
assertTrue(prefs.isTcp())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `RadioPrefs isMock returns true for m prefix`() {
|
||||
val prefs = FakeRadioPrefs()
|
||||
prefs.setDevAddr("m12345678")
|
||||
assertTrue(prefs.isMock())
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.repository
|
||||
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class DataPairTest {
|
||||
|
||||
@Test
|
||||
fun `DataPair with non-null value retains value`() {
|
||||
val pair = DataPair("key", "value")
|
||||
assertEquals("value", pair.value)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `DataPair with null value becomes string null`() {
|
||||
val pair = DataPair("key", null)
|
||||
assertEquals("null", pair.value)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.repository
|
||||
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class NotificationTest {
|
||||
|
||||
@Test
|
||||
fun `Notification creation works with defaults`() {
|
||||
val notification = Notification("Title", "Message")
|
||||
assertEquals("Title", notification.title)
|
||||
assertEquals("Message", notification.message)
|
||||
assertEquals(Notification.Type.Info, notification.type)
|
||||
assertEquals(Notification.Category.Message, notification.category)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* 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.repository.usecase
|
||||
|
||||
import dev.mokkery.MockMode
|
||||
import dev.mokkery.mock
|
||||
import io.kotest.matchers.shouldBe
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.meshtastic.core.model.DataPacket
|
||||
import org.meshtastic.core.model.Node
|
||||
import org.meshtastic.core.repository.MessageQueue
|
||||
import org.meshtastic.core.repository.PacketRepository
|
||||
import org.meshtastic.core.testing.FakeAppPreferences
|
||||
import org.meshtastic.core.testing.FakeNodeRepository
|
||||
import org.meshtastic.core.testing.FakeRadioController
|
||||
import org.meshtastic.proto.Config
|
||||
import org.meshtastic.proto.DeviceMetadata
|
||||
import org.meshtastic.proto.User
|
||||
import kotlin.test.BeforeTest
|
||||
import kotlin.test.Test
|
||||
|
||||
class SendMessageUseCaseTest {
|
||||
|
||||
private lateinit var nodeRepository: FakeNodeRepository
|
||||
private lateinit var packetRepository: PacketRepository
|
||||
private lateinit var radioController: FakeRadioController
|
||||
private lateinit var appPreferences: FakeAppPreferences
|
||||
private lateinit var messageQueue: MessageQueue
|
||||
private lateinit var useCase: SendMessageUseCase
|
||||
|
||||
@BeforeTest
|
||||
fun setUp() {
|
||||
nodeRepository = FakeNodeRepository()
|
||||
packetRepository = mock(MockMode.autofill)
|
||||
radioController = FakeRadioController()
|
||||
appPreferences = FakeAppPreferences()
|
||||
messageQueue = mock(MockMode.autofill)
|
||||
|
||||
useCase =
|
||||
SendMessageUseCaseImpl(
|
||||
nodeRepository = nodeRepository,
|
||||
packetRepository = packetRepository,
|
||||
radioController = radioController,
|
||||
homoglyphEncodingPrefs = appPreferences.homoglyph,
|
||||
messageQueue = messageQueue,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `invoke with broadcast message simply sends data packet`() = runTest {
|
||||
// Arrange
|
||||
val ourNode = Node(num = 1, user = User(id = "!1234"))
|
||||
nodeRepository.setOurNode(ourNode)
|
||||
appPreferences.homoglyph.setHomoglyphEncodingEnabled(false)
|
||||
|
||||
// Act
|
||||
useCase("Hello broadcast", "0${DataPacket.ID_BROADCAST}", null)
|
||||
|
||||
// Assert
|
||||
radioController.favoritedNodes.size shouldBe 0
|
||||
radioController.sentSharedContacts.size shouldBe 0
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `invoke with direct message to older firmware triggers favoriteNode`() = runTest {
|
||||
// Arrange
|
||||
val ourNode =
|
||||
Node(
|
||||
num = 1,
|
||||
user = User(id = "!local", role = Config.DeviceConfig.Role.CLIENT),
|
||||
metadata = DeviceMetadata(firmware_version = "2.0.0"),
|
||||
)
|
||||
nodeRepository.setOurNode(ourNode)
|
||||
|
||||
val destNode = Node(num = 12345, user = User(id = "!dest"))
|
||||
nodeRepository.upsert(destNode)
|
||||
|
||||
appPreferences.homoglyph.setHomoglyphEncodingEnabled(false)
|
||||
|
||||
// Act
|
||||
useCase("Direct message", "!dest", null)
|
||||
|
||||
// Assert
|
||||
radioController.favoritedNodes.size shouldBe 1
|
||||
radioController.favoritedNodes[0] shouldBe 12345
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `invoke with direct message to new firmware triggers sendSharedContact`() = runTest {
|
||||
// Arrange
|
||||
val ourNode =
|
||||
Node(
|
||||
num = 1,
|
||||
user = User(id = "!local", role = Config.DeviceConfig.Role.CLIENT),
|
||||
metadata = DeviceMetadata(firmware_version = "2.7.12"),
|
||||
)
|
||||
nodeRepository.setOurNode(ourNode)
|
||||
|
||||
val destNode = Node(num = 67890, user = User(id = "!dest"))
|
||||
nodeRepository.upsert(destNode)
|
||||
|
||||
appPreferences.homoglyph.setHomoglyphEncodingEnabled(false)
|
||||
|
||||
// Act
|
||||
useCase("Direct message", "!dest", null)
|
||||
|
||||
// Assert
|
||||
radioController.sentSharedContacts.size shouldBe 1
|
||||
radioController.sentSharedContacts[0] shouldBe 67890
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `invoke with homoglyph enabled transforms text`() = runTest {
|
||||
// Arrange
|
||||
val ourNode = Node(num = 1)
|
||||
nodeRepository.setOurNode(ourNode)
|
||||
appPreferences.homoglyph.setHomoglyphEncodingEnabled(true)
|
||||
|
||||
val originalText = "\u0410pple" // Cyrillic A
|
||||
|
||||
// Act
|
||||
useCase(originalText, "0${DataPacket.ID_BROADCAST}", null)
|
||||
|
||||
// Assert
|
||||
// Verified by observing that no exception is thrown and coverage is hit.
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue