mirror of
https://github.com/aljazceru/Android-nRF-Toolbox.git
synced 2025-12-20 07:54:20 +01:00
Make test with service working
This commit is contained in:
@@ -29,37 +29,32 @@
|
|||||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package no.nordicsemi.android.uart
|
package no.nordicsemi.android.nrftoolbox
|
||||||
|
|
||||||
import android.content.Context
|
import android.app.Application
|
||||||
import androidx.room.Room
|
import dagger.hilt.android.HiltAndroidApp
|
||||||
import dagger.Module
|
import no.nordicsemi.android.analytics.AppAnalytics
|
||||||
import dagger.Provides
|
import no.nordicsemi.android.analytics.AppOpenEvent
|
||||||
import dagger.hilt.InstallIn
|
import no.nordicsemi.android.gls.UartServer
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import javax.inject.Inject
|
||||||
import dagger.hilt.components.SingletonComponent
|
|
||||||
import no.nordicsemi.android.uart.db.ConfigurationsDao
|
|
||||||
import no.nordicsemi.android.uart.db.ConfigurationsDatabase
|
|
||||||
import no.nordicsemi.android.uart.db.MIGRATION_1_2
|
|
||||||
import javax.inject.Singleton
|
|
||||||
|
|
||||||
@Module
|
@HiltAndroidApp
|
||||||
@InstallIn(SingletonComponent::class)
|
class NrfToolboxApplication : Application() {
|
||||||
class HiltModule {
|
|
||||||
|
|
||||||
@Provides
|
@Inject
|
||||||
@Singleton
|
lateinit var analytics: AppAnalytics
|
||||||
internal fun provideDB(@ApplicationContext context: Context): ConfigurationsDatabase {
|
|
||||||
return Room.databaseBuilder(
|
@Inject
|
||||||
context,
|
lateinit var glsServer: UartServer
|
||||||
ConfigurationsDatabase::class.java, "toolbox_uart.db"
|
|
||||||
).addMigrations(MIGRATION_1_2).build()
|
@Inject
|
||||||
|
lateinit var uartServer: UartServer
|
||||||
|
|
||||||
|
override fun onCreate() {
|
||||||
|
super.onCreate()
|
||||||
|
|
||||||
|
analytics.logEvent(AppOpenEvent)
|
||||||
|
|
||||||
|
uartServer.start(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
internal fun provideDao(db: ConfigurationsDatabase): ConfigurationsDao {
|
|
||||||
return db.dao()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -35,7 +35,6 @@ import android.app.Application
|
|||||||
import dagger.hilt.android.HiltAndroidApp
|
import dagger.hilt.android.HiltAndroidApp
|
||||||
import no.nordicsemi.android.analytics.AppAnalytics
|
import no.nordicsemi.android.analytics.AppAnalytics
|
||||||
import no.nordicsemi.android.analytics.AppOpenEvent
|
import no.nordicsemi.android.analytics.AppOpenEvent
|
||||||
import no.nordicsemi.android.gls.GlsServer
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@HiltAndroidApp
|
@HiltAndroidApp
|
||||||
@@ -44,14 +43,9 @@ class NrfToolboxApplication : Application() {
|
|||||||
@Inject
|
@Inject
|
||||||
lateinit var analytics: AppAnalytics
|
lateinit var analytics: AppAnalytics
|
||||||
|
|
||||||
@Inject
|
|
||||||
lateinit var glsServer: GlsServer
|
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
|
|
||||||
analytics.logEvent(AppOpenEvent)
|
analytics.logEvent(AppOpenEvent)
|
||||||
|
|
||||||
glsServer.start(this)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -31,41 +31,11 @@
|
|||||||
|
|
||||||
package no.nordicsemi.android.service
|
package no.nordicsemi.android.service
|
||||||
|
|
||||||
import android.bluetooth.BluetoothDevice
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
|
||||||
import no.nordicsemi.android.kotlin.ble.core.ServerDevice
|
import no.nordicsemi.android.kotlin.ble.core.ServerDevice
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
const val DEVICE_DATA = "device-data"
|
const val DEVICE_DATA = "device-data"
|
||||||
|
|
||||||
class ServiceManager @Inject constructor(
|
interface ServiceManager {
|
||||||
@ApplicationContext
|
|
||||||
private val context: Context
|
|
||||||
) {
|
|
||||||
|
|
||||||
fun <T> startService(service: Class<T>, device: ServerDevice) {
|
fun <T> startService(service: Class<T>, device: ServerDevice)
|
||||||
val intent = Intent(context, service).apply {
|
|
||||||
putExtra(DEVICE_DATA, device)
|
|
||||||
}
|
|
||||||
context.startService(intent)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T> startService(service: Class<T>, device: BluetoothDevice) {
|
|
||||||
val intent = Intent(context, service).apply {
|
|
||||||
putExtra(DEVICE_DATA, device)
|
|
||||||
}
|
|
||||||
context.startService(intent)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T> startService(service: Class<T>) {
|
|
||||||
val intent = Intent(context, service)
|
|
||||||
context.startService(intent)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T> stopService(service: Class<T>) {
|
|
||||||
val intent = Intent(context, service)
|
|
||||||
context.stopService(intent)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package no.nordicsemi.android.service
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import dagger.Module
|
||||||
|
import dagger.Provides
|
||||||
|
import dagger.hilt.InstallIn
|
||||||
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
|
import dagger.hilt.components.SingletonComponent
|
||||||
|
|
||||||
|
@Module
|
||||||
|
@InstallIn(SingletonComponent::class)
|
||||||
|
class ServiceManagerHiltModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
fun createServiceManager(
|
||||||
|
@ApplicationContext
|
||||||
|
context: Context,
|
||||||
|
): ServiceManager {
|
||||||
|
return ServiceManagerImpl(context)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package no.nordicsemi.android.service
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
|
import no.nordicsemi.android.kotlin.ble.core.ServerDevice
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class ServiceManagerImpl @Inject constructor(
|
||||||
|
@ApplicationContext
|
||||||
|
private val context: Context
|
||||||
|
): ServiceManager {
|
||||||
|
|
||||||
|
override fun <T> startService(service: Class<T>, device: ServerDevice) {
|
||||||
|
val intent = Intent(context, service).apply {
|
||||||
|
putExtra(DEVICE_DATA, device)
|
||||||
|
}
|
||||||
|
context.startService(intent)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -35,6 +35,10 @@ plugins {
|
|||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "no.nordicsemi.android.ui"
|
namespace = "no.nordicsemi.android.ui"
|
||||||
|
|
||||||
|
testOptions {
|
||||||
|
unitTests.isIncludeAndroidResources = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
|||||||
@@ -6,12 +6,11 @@ import dagger.Provides
|
|||||||
import dagger.hilt.InstallIn
|
import dagger.hilt.InstallIn
|
||||||
import dagger.hilt.components.SingletonComponent
|
import dagger.hilt.components.SingletonComponent
|
||||||
import no.nordicsemi.android.common.logger.NordicBlekLogger
|
import no.nordicsemi.android.common.logger.NordicBlekLogger
|
||||||
import no.nordicsemi.android.common.logger.BlekLogger
|
|
||||||
import no.nordicsemi.android.common.logger.BlekLoggerAndLauncher
|
import no.nordicsemi.android.common.logger.BlekLoggerAndLauncher
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
@InstallIn(SingletonComponent::class)
|
@InstallIn(SingletonComponent::class)
|
||||||
class HiltModule {
|
class NordicLoggerFactoryHiltModule {
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
fun createLogger(): NordicLoggerFactory {
|
fun createLogger(): NordicLoggerFactory {
|
||||||
@@ -119,8 +119,6 @@ internal class GLSViewModel @Inject constructor(
|
|||||||
private val highestSequenceNumber
|
private val highestSequenceNumber
|
||||||
get() = state.value.glsServiceData.records.keys.maxByOrNull { it.sequenceNumber }?.sequenceNumber ?: -1
|
get() = state.value.glsServiceData.records.keys.maxByOrNull { it.sequenceNumber }?.sequenceNumber ?: -1
|
||||||
|
|
||||||
fun test() = 2
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
navigationManager.navigateTo(ScannerDestinationId, ParcelUuid(GLS_SERVICE_UUID))
|
navigationManager.navigateTo(ScannerDestinationId, ParcelUuid(GLS_SERVICE_UUID))
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ import no.nordicsemi.android.ui.view.NordicLoggerFactory
|
|||||||
import no.nordicsemi.android.ui.view.StringConst
|
import no.nordicsemi.android.ui.view.StringConst
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
import org.junit.Assert.assertEquals
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Assert.assertTrue
|
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
@@ -121,11 +120,6 @@ internal class GLSViewModelTest {
|
|||||||
every { NordicBlekLogger.create(any(), any(), any(), any()) } returns mockk()
|
every { NordicBlekLogger.create(any(), any(), any(), any()) } returns mockk()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
fun addition_isCorrect() {
|
|
||||||
assertEquals(2, viewModel.test())
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `when connection fails return disconnected`() = runTest {
|
fun `when connection fails return disconnected`() = runTest {
|
||||||
val disconnectedState = GattConnectionStateWithStatus(
|
val disconnectedState = GattConnectionStateWithStatus(
|
||||||
|
|||||||
@@ -38,6 +38,10 @@ plugins {
|
|||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "no.nordicsemi.android.uart"
|
namespace = "no.nordicsemi.android.uart"
|
||||||
|
|
||||||
|
testOptions {
|
||||||
|
unitTests.isIncludeAndroidResources = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wire {
|
wire {
|
||||||
@@ -54,6 +58,8 @@ dependencies {
|
|||||||
implementation(libs.nordic.blek.client)
|
implementation(libs.nordic.blek.client)
|
||||||
implementation(libs.nordic.blek.profile)
|
implementation(libs.nordic.blek.profile)
|
||||||
implementation(libs.nordic.blek.core)
|
implementation(libs.nordic.blek.core)
|
||||||
|
implementation(libs.nordic.blek.server)
|
||||||
|
implementation(libs.nordic.blek.advertiser)
|
||||||
|
|
||||||
implementation(libs.room.runtime)
|
implementation(libs.room.runtime)
|
||||||
implementation(libs.room.ktx)
|
implementation(libs.room.ktx)
|
||||||
@@ -81,6 +87,21 @@ dependencies {
|
|||||||
implementation(libs.androidx.activity.compose)
|
implementation(libs.androidx.activity.compose)
|
||||||
implementation(libs.androidx.lifecycle.service)
|
implementation(libs.androidx.lifecycle.service)
|
||||||
|
|
||||||
|
// For Robolectric tests.
|
||||||
|
testImplementation("com.google.dagger:hilt-android-testing:2.44")
|
||||||
|
// ...with Kotlin.
|
||||||
|
kaptTest("com.google.dagger:hilt-android-compiler:2.46.1")
|
||||||
|
|
||||||
|
testImplementation("androidx.test:rules:1.5.0")
|
||||||
|
|
||||||
|
testImplementation(libs.junit4)
|
||||||
|
testImplementation(libs.test.mockk)
|
||||||
|
testImplementation(libs.androidx.test.ext)
|
||||||
|
testImplementation(libs.kotlinx.coroutines.test)
|
||||||
|
testImplementation(libs.test.slf4j.simple)
|
||||||
|
testImplementation(libs.test.robolectric)
|
||||||
|
testImplementation(libs.kotlin.junit)
|
||||||
|
|
||||||
implementation("org.simpleframework:simple-xml:2.7.1") {
|
implementation("org.simpleframework:simple-xml:2.7.1") {
|
||||||
exclude(group = "stax", module = "stax-api")
|
exclude(group = "stax", module = "stax-api")
|
||||||
exclude(group = "xpp3", module = "xpp3")
|
exclude(group = "xpp3", module = "xpp3")
|
||||||
|
|||||||
@@ -0,0 +1,184 @@
|
|||||||
|
package no.nordicsemi.android.gls
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.Context
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.flow.filter
|
||||||
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
import kotlinx.coroutines.flow.mapNotNull
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import no.nordicsemi.android.kotlin.ble.advertiser.BleAdvertiser
|
||||||
|
import no.nordicsemi.android.kotlin.ble.core.MockServerDevice
|
||||||
|
import no.nordicsemi.android.kotlin.ble.core.advertiser.BleAdvertiseConfig
|
||||||
|
import no.nordicsemi.android.kotlin.ble.core.data.BleGattPermission
|
||||||
|
import no.nordicsemi.android.kotlin.ble.core.data.BleGattProperty
|
||||||
|
import no.nordicsemi.android.kotlin.ble.profile.gls.RecordAccessControlPointInputParser
|
||||||
|
import no.nordicsemi.android.kotlin.ble.server.main.BleGattServer
|
||||||
|
import no.nordicsemi.android.kotlin.ble.server.main.service.BleGattServerServiceType
|
||||||
|
import no.nordicsemi.android.kotlin.ble.server.main.service.BleServerGattCharacteristic
|
||||||
|
import no.nordicsemi.android.kotlin.ble.server.main.service.BleServerGattCharacteristicConfig
|
||||||
|
import no.nordicsemi.android.kotlin.ble.server.main.service.BleServerGattServiceConfig
|
||||||
|
import no.nordicsemi.android.kotlin.ble.server.main.service.BluetoothGattServerConnection
|
||||||
|
import no.nordicsemi.android.uart.repository.BATTERY_LEVEL_CHARACTERISTIC_UUID
|
||||||
|
import no.nordicsemi.android.uart.repository.BATTERY_SERVICE_UUID
|
||||||
|
import no.nordicsemi.android.uart.repository.UART_RX_CHARACTERISTIC_UUID
|
||||||
|
import no.nordicsemi.android.uart.repository.UART_SERVICE_UUID
|
||||||
|
import no.nordicsemi.android.uart.repository.UART_TX_CHARACTERISTIC_UUID
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
private const val STANDARD_DELAY = 1000L
|
||||||
|
|
||||||
|
@SuppressLint("MissingPermission")
|
||||||
|
@Singleton
|
||||||
|
class UartServer @Inject constructor(
|
||||||
|
private val scope: CoroutineScope
|
||||||
|
) {
|
||||||
|
|
||||||
|
lateinit var server: BleGattServer
|
||||||
|
|
||||||
|
lateinit var glsCharacteristic: BleServerGattCharacteristic
|
||||||
|
lateinit var glsContextCharacteristic: BleServerGattCharacteristic
|
||||||
|
lateinit var racpCharacteristic: BleServerGattCharacteristic
|
||||||
|
lateinit var batteryLevelCharacteristic: BleServerGattCharacteristic
|
||||||
|
|
||||||
|
private var lastRequest = byteArrayOf()
|
||||||
|
|
||||||
|
val YOUNGEST_RECORD = byteArrayOf(0x07, 0x00, 0x00, 0xDC.toByte(), 0x07, 0x01, 0x01, 0x0C, 0x1E, 0x05, 0x00, 0x00, 0x26, 0xD2.toByte(), 0x11)
|
||||||
|
val OLDEST_RECORD = byteArrayOf(0x07, 0x04, 0x00, 0xDC.toByte(), 0x07, 0x01, 0x01, 0x0C, 0x1E, 0x11, 0x00, 0x00, 0x82.toByte(), 0xD2.toByte(), 0x11)
|
||||||
|
|
||||||
|
val records = listOf(
|
||||||
|
YOUNGEST_RECORD,
|
||||||
|
byteArrayOf(0x07, 0x01, 0x00, 0xDC.toByte(), 0x07, 0x01, 0x01, 0x0C, 0x1E, 0x08, 0x00, 0x00, 0x3D, 0xD2.toByte(), 0x11),
|
||||||
|
byteArrayOf(0x07, 0x02, 0x00, 0xDC.toByte(), 0x07, 0x01, 0x01, 0x0C, 0x1E, 0x0B, 0x00, 0x00, 0x54, 0xD2.toByte(), 0x11),
|
||||||
|
byteArrayOf(0x07, 0x03, 0x00, 0xDC.toByte(), 0x07, 0x01, 0x01, 0x0C, 0x1E, 0x0E, 0x00, 0x00, 0x6B, 0xD2.toByte(), 0x11),
|
||||||
|
OLDEST_RECORD
|
||||||
|
)
|
||||||
|
|
||||||
|
val racp = byteArrayOf(0x06, 0x00, 0x01, 0x01)
|
||||||
|
|
||||||
|
fun start(
|
||||||
|
context: Context,
|
||||||
|
device: MockServerDevice = MockServerDevice(
|
||||||
|
name = "GLS Server",
|
||||||
|
address = "55:44:33:22:11"
|
||||||
|
),
|
||||||
|
) = scope.launch {
|
||||||
|
val rxCharacteristic = BleServerGattCharacteristicConfig(
|
||||||
|
UART_RX_CHARACTERISTIC_UUID,
|
||||||
|
listOf(BleGattProperty.PROPERTY_NOTIFY),
|
||||||
|
listOf()
|
||||||
|
)
|
||||||
|
|
||||||
|
val txCharacteristic = BleServerGattCharacteristicConfig(
|
||||||
|
UART_TX_CHARACTERISTIC_UUID,
|
||||||
|
listOf(BleGattProperty.PROPERTY_INDICATE, BleGattProperty.PROPERTY_WRITE),
|
||||||
|
listOf(BleGattPermission.PERMISSION_WRITE)
|
||||||
|
)
|
||||||
|
|
||||||
|
val uartService = BleServerGattServiceConfig(
|
||||||
|
UART_SERVICE_UUID,
|
||||||
|
BleGattServerServiceType.SERVICE_TYPE_PRIMARY,
|
||||||
|
listOf(rxCharacteristic, txCharacteristic)
|
||||||
|
)
|
||||||
|
|
||||||
|
val batteryLevelCharacteristic = BleServerGattCharacteristicConfig(
|
||||||
|
BATTERY_LEVEL_CHARACTERISTIC_UUID,
|
||||||
|
listOf(BleGattProperty.PROPERTY_READ, BleGattProperty.PROPERTY_NOTIFY),
|
||||||
|
listOf(BleGattPermission.PERMISSION_READ)
|
||||||
|
)
|
||||||
|
|
||||||
|
val batteryService = BleServerGattServiceConfig(
|
||||||
|
BATTERY_SERVICE_UUID,
|
||||||
|
BleGattServerServiceType.SERVICE_TYPE_PRIMARY,
|
||||||
|
listOf(batteryLevelCharacteristic)
|
||||||
|
)
|
||||||
|
|
||||||
|
server = BleGattServer.create(
|
||||||
|
context = context,
|
||||||
|
config = arrayOf(uartService, batteryService),
|
||||||
|
mock = device
|
||||||
|
)
|
||||||
|
|
||||||
|
val advertiser = BleAdvertiser.create(context)
|
||||||
|
advertiser.advertise(config = BleAdvertiseConfig(), mock = device).launchIn(scope)
|
||||||
|
|
||||||
|
launch {
|
||||||
|
server.connections
|
||||||
|
.mapNotNull { it.values.firstOrNull() }
|
||||||
|
.collect { setUpConnection(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun stopServer() {
|
||||||
|
server.stopServer()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setUpConnection(connection: BluetoothGattServerConnection) {
|
||||||
|
// val glsService = connection.services.findService(GLS_SERVICE_UUID)!!
|
||||||
|
// glsCharacteristic = glsService.findCharacteristic(GLUCOSE_MEASUREMENT_CHARACTERISTIC)!!
|
||||||
|
// glsContextCharacteristic = glsService.findCharacteristic(GLUCOSE_MEASUREMENT_CONTEXT_CHARACTERISTIC)!!
|
||||||
|
// racpCharacteristic = glsService.findCharacteristic(RACP_CHARACTERISTIC)!!
|
||||||
|
|
||||||
|
val batteryService = connection.services.findService(BATTERY_SERVICE_UUID)!!
|
||||||
|
batteryLevelCharacteristic = batteryService.findCharacteristic(BATTERY_LEVEL_CHARACTERISTIC_UUID)!!
|
||||||
|
|
||||||
|
|
||||||
|
// startGlsService(connection)
|
||||||
|
// startBatteryService(connection)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun startGlsService(connection: BluetoothGattServerConnection) {
|
||||||
|
racpCharacteristic.value
|
||||||
|
.filter { it.isNotEmpty() }
|
||||||
|
.onEach { lastRequest = it }
|
||||||
|
.launchIn(scope)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun continueWithResponse() {
|
||||||
|
sendResponse(lastRequest)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun sendResponse(request: ByteArray) {
|
||||||
|
if (request.contentEquals(RecordAccessControlPointInputParser.reportNumberOfAllStoredRecords().value)) {
|
||||||
|
sendAll(glsCharacteristic)
|
||||||
|
racpCharacteristic.setValue(racp)
|
||||||
|
} else if (request.contentEquals(RecordAccessControlPointInputParser.reportLastStoredRecord().value)) {
|
||||||
|
sendLast(glsCharacteristic)
|
||||||
|
racpCharacteristic.setValue(racp)
|
||||||
|
} else if (request.contentEquals(RecordAccessControlPointInputParser.reportFirstStoredRecord().value)) {
|
||||||
|
sendFirst(glsCharacteristic)
|
||||||
|
racpCharacteristic.setValue(racp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun sendFirst(characteristics: BleServerGattCharacteristic) {
|
||||||
|
characteristics.setValue(records.first())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun sendLast(characteristics: BleServerGattCharacteristic) {
|
||||||
|
characteristics.setValue(records.last())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun sendAll(characteristics: BleServerGattCharacteristic) = scope.launch {
|
||||||
|
records.forEach {
|
||||||
|
characteristics.setValue(it)
|
||||||
|
delay(100)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun startBatteryService(connection: BluetoothGattServerConnection) {
|
||||||
|
scope.launch {
|
||||||
|
repeat(100) {
|
||||||
|
batteryLevelCharacteristic.setValue(byteArrayOf(0x61))
|
||||||
|
delay(STANDARD_DELAY)
|
||||||
|
batteryLevelCharacteristic.setValue(byteArrayOf(0x60))
|
||||||
|
delay(STANDARD_DELAY)
|
||||||
|
batteryLevelCharacteristic.setValue(byteArrayOf(0x5F))
|
||||||
|
delay(STANDARD_DELAY)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package no.nordicsemi.android.uart
|
||||||
|
|
||||||
|
import dagger.Module
|
||||||
|
import dagger.Provides
|
||||||
|
import dagger.hilt.InstallIn
|
||||||
|
import dagger.hilt.components.SingletonComponent
|
||||||
|
import no.nordicsemi.android.uart.db.ConfigurationsDao
|
||||||
|
import no.nordicsemi.android.uart.db.ConfigurationsDatabase
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Module
|
||||||
|
@InstallIn(SingletonComponent::class)
|
||||||
|
class DaoHiltModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
internal fun provideDao(db: ConfigurationsDatabase): ConfigurationsDao {
|
||||||
|
return db.dao()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package no.nordicsemi.android.uart
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.room.Room
|
||||||
|
import dagger.Module
|
||||||
|
import dagger.Provides
|
||||||
|
import dagger.hilt.InstallIn
|
||||||
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
|
import dagger.hilt.components.SingletonComponent
|
||||||
|
import no.nordicsemi.android.uart.db.ConfigurationsDatabase
|
||||||
|
import no.nordicsemi.android.uart.db.MIGRATION_1_2
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Module
|
||||||
|
@InstallIn(SingletonComponent::class)
|
||||||
|
class DbHiltModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
internal fun provideDB(@ApplicationContext context: Context): ConfigurationsDatabase {
|
||||||
|
return Room.databaseBuilder(
|
||||||
|
context,
|
||||||
|
ConfigurationsDatabase::class.java, "toolbox_uart.db"
|
||||||
|
).addMigrations(MIGRATION_1_2).build()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -39,7 +39,6 @@ import kotlinx.coroutines.flow.asStateFlow
|
|||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import no.nordicsemi.android.common.core.simpleSharedFlow
|
import no.nordicsemi.android.common.core.simpleSharedFlow
|
||||||
import no.nordicsemi.android.common.logger.BlekLoggerAndLauncher
|
import no.nordicsemi.android.common.logger.BlekLoggerAndLauncher
|
||||||
import no.nordicsemi.android.common.logger.NordicBlekLogger
|
|
||||||
import no.nordicsemi.android.kotlin.ble.core.ServerDevice
|
import no.nordicsemi.android.kotlin.ble.core.ServerDevice
|
||||||
import no.nordicsemi.android.kotlin.ble.core.data.GattConnectionState
|
import no.nordicsemi.android.kotlin.ble.core.data.GattConnectionState
|
||||||
import no.nordicsemi.android.kotlin.ble.core.data.GattConnectionStateWithStatus
|
import no.nordicsemi.android.kotlin.ble.core.data.GattConnectionStateWithStatus
|
||||||
@@ -52,6 +51,7 @@ import no.nordicsemi.android.uart.data.UARTRecord
|
|||||||
import no.nordicsemi.android.uart.data.UARTRecordType
|
import no.nordicsemi.android.uart.data.UARTRecordType
|
||||||
import no.nordicsemi.android.uart.data.UARTServiceData
|
import no.nordicsemi.android.uart.data.UARTServiceData
|
||||||
import no.nordicsemi.android.uart.data.parseWithNewLineChar
|
import no.nordicsemi.android.uart.data.parseWithNewLineChar
|
||||||
|
import no.nordicsemi.android.ui.view.NordicLoggerFactory
|
||||||
import no.nordicsemi.android.ui.view.StringConst
|
import no.nordicsemi.android.ui.view.StringConst
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
@@ -62,7 +62,8 @@ class UARTRepository @Inject internal constructor(
|
|||||||
private val context: Context,
|
private val context: Context,
|
||||||
private val serviceManager: ServiceManager,
|
private val serviceManager: ServiceManager,
|
||||||
private val configurationDataSource: ConfigurationDataSource,
|
private val configurationDataSource: ConfigurationDataSource,
|
||||||
private val stringConst: StringConst
|
private val stringConst: StringConst,
|
||||||
|
private val loggerFactory: NordicLoggerFactory
|
||||||
) {
|
) {
|
||||||
private var logger: BlekLoggerAndLauncher? = null
|
private var logger: BlekLoggerAndLauncher? = null
|
||||||
|
|
||||||
@@ -97,7 +98,7 @@ class UARTRepository @Inject internal constructor(
|
|||||||
private fun shouldClean() = !isOnScreen && !isServiceRunning
|
private fun shouldClean() = !isOnScreen && !isServiceRunning
|
||||||
|
|
||||||
fun launch(device: ServerDevice) {
|
fun launch(device: ServerDevice) {
|
||||||
logger = NordicBlekLogger.create(context, stringConst.APP_NAME, "UART", device.address)
|
logger = loggerFactory.createNordicLogger(context, stringConst.APP_NAME, "UART", device.address)
|
||||||
_data.value = _data.value.copy(deviceName = device.name)
|
_data.value = _data.value.copy(deviceName = device.name)
|
||||||
serviceManager.startService(UARTService::class.java, device)
|
serviceManager.startService(UARTService::class.java, device)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,11 +56,11 @@ import java.util.*
|
|||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
val UART_SERVICE_UUID: UUID = UUID.fromString("6E400001-B5A3-F393-E0A9-E50E24DCCA9E")
|
val UART_SERVICE_UUID: UUID = UUID.fromString("6E400001-B5A3-F393-E0A9-E50E24DCCA9E")
|
||||||
private val UART_RX_CHARACTERISTIC_UUID = UUID.fromString("6E400002-B5A3-F393-E0A9-E50E24DCCA9E")
|
internal val UART_RX_CHARACTERISTIC_UUID = UUID.fromString("6E400002-B5A3-F393-E0A9-E50E24DCCA9E")
|
||||||
private val UART_TX_CHARACTERISTIC_UUID = UUID.fromString("6E400003-B5A3-F393-E0A9-E50E24DCCA9E")
|
internal val UART_TX_CHARACTERISTIC_UUID = UUID.fromString("6E400003-B5A3-F393-E0A9-E50E24DCCA9E")
|
||||||
|
|
||||||
private val BATTERY_SERVICE_UUID = UUID.fromString("0000180F-0000-1000-8000-00805f9b34fb")
|
internal val BATTERY_SERVICE_UUID = UUID.fromString("0000180F-0000-1000-8000-00805f9b34fb")
|
||||||
private val BATTERY_LEVEL_CHARACTERISTIC_UUID = UUID.fromString("00002A19-0000-1000-8000-00805f9b34fb")
|
internal val BATTERY_LEVEL_CHARACTERISTIC_UUID = UUID.fromString("00002A19-0000-1000-8000-00805f9b34fb")
|
||||||
|
|
||||||
@SuppressLint("MissingPermission")
|
@SuppressLint("MissingPermission")
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ import no.nordicsemi.android.uart.view.OnRunMacro
|
|||||||
import no.nordicsemi.android.uart.view.OpenLogger
|
import no.nordicsemi.android.uart.view.OpenLogger
|
||||||
import no.nordicsemi.android.uart.view.UARTViewEvent
|
import no.nordicsemi.android.uart.view.UARTViewEvent
|
||||||
import no.nordicsemi.android.uart.view.UARTViewState
|
import no.nordicsemi.android.uart.view.UARTViewState
|
||||||
|
import no.nordicsemi.android.ui.view.NordicLoggerFactory
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
@@ -84,7 +85,8 @@ internal class UARTViewModel @Inject constructor(
|
|||||||
private val repository: UARTRepository,
|
private val repository: UARTRepository,
|
||||||
private val navigationManager: Navigator,
|
private val navigationManager: Navigator,
|
||||||
private val dataSource: UARTPersistentDataSource,
|
private val dataSource: UARTPersistentDataSource,
|
||||||
private val analytics: AppAnalytics
|
private val analytics: AppAnalytics,
|
||||||
|
private val loggerFactory: NordicLoggerFactory
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
private val _state = MutableStateFlow(UARTViewState())
|
private val _state = MutableStateFlow(UARTViewState())
|
||||||
@@ -126,7 +128,7 @@ internal class UARTViewModel @Inject constructor(
|
|||||||
.launchIn(viewModelScope)
|
.launchIn(viewModelScope)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleResult(result: NavigationResult<ServerDevice>) {
|
internal fun handleResult(result: NavigationResult<ServerDevice>) {
|
||||||
when (result) {
|
when (result) {
|
||||||
is NavigationResult.Cancelled -> navigationManager.navigateUp()
|
is NavigationResult.Cancelled -> navigationManager.navigateUp()
|
||||||
is NavigationResult.Success -> onDeviceSelected(result.value)
|
is NavigationResult.Success -> onDeviceSelected(result.value)
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package no.nordicsemi.android.gls
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import dagger.Module
|
||||||
|
import dagger.Provides
|
||||||
|
import dagger.hilt.components.SingletonComponent
|
||||||
|
import dagger.hilt.testing.TestInstallIn
|
||||||
|
import no.nordicsemi.android.common.logger.BlekLoggerAndLauncher
|
||||||
|
import no.nordicsemi.android.ui.view.NordicLoggerFactory
|
||||||
|
import no.nordicsemi.android.ui.view.NordicLoggerFactoryHiltModule
|
||||||
|
|
||||||
|
@Module
|
||||||
|
@TestInstallIn(
|
||||||
|
components = [SingletonComponent::class],
|
||||||
|
replaces = [NordicLoggerFactoryHiltModule::class]
|
||||||
|
)
|
||||||
|
class NordicLoggerFactoryTestModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
fun createLogger(): NordicLoggerFactory {
|
||||||
|
return object : NordicLoggerFactory {
|
||||||
|
override fun createNordicLogger(
|
||||||
|
context: Context,
|
||||||
|
profile: String?,
|
||||||
|
key: String,
|
||||||
|
name: String?,
|
||||||
|
): BlekLoggerAndLauncher {
|
||||||
|
return object : BlekLoggerAndLauncher {
|
||||||
|
override fun launch() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun log(priority: Int, log: String) {
|
||||||
|
println(log)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package no.nordicsemi.android.gls
|
||||||
|
|
||||||
|
import android.content.ComponentName
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import dagger.Module
|
||||||
|
import dagger.Provides
|
||||||
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
|
import dagger.hilt.components.SingletonComponent
|
||||||
|
import dagger.hilt.testing.TestInstallIn
|
||||||
|
import no.nordicsemi.android.kotlin.ble.core.MockServerDevice
|
||||||
|
import no.nordicsemi.android.kotlin.ble.core.ServerDevice
|
||||||
|
import no.nordicsemi.android.service.DEVICE_DATA
|
||||||
|
import no.nordicsemi.android.service.ServiceManager
|
||||||
|
import no.nordicsemi.android.service.ServiceManagerHiltModule
|
||||||
|
import no.nordicsemi.android.uart.repository.UARTService
|
||||||
|
import org.robolectric.Robolectric
|
||||||
|
import org.robolectric.android.controller.ServiceController
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Module
|
||||||
|
@TestInstallIn(
|
||||||
|
components = [SingletonComponent::class],
|
||||||
|
replaces = [ServiceManagerHiltModule::class]
|
||||||
|
)
|
||||||
|
class ServiceManagerTestModule {
|
||||||
|
|
||||||
|
private val componentName = ComponentName("org.robolectric", UARTService::class.java.name)
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
internal fun provideDevice(): MockServerDevice {
|
||||||
|
return MockServerDevice(
|
||||||
|
name = "GLS Server",
|
||||||
|
address = "55:44:33:22:11"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
internal fun provideServiceController(
|
||||||
|
@ApplicationContext context: Context,
|
||||||
|
device: MockServerDevice
|
||||||
|
): ServiceController<UARTService> {
|
||||||
|
return Robolectric.buildService(UARTService::class.java, Intent(context, UARTService::class.java).apply {
|
||||||
|
putExtra(DEVICE_DATA, device)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
internal fun provideServiceManager(controller: ServiceController<UARTService>): ServiceManager {
|
||||||
|
return object : ServiceManager {
|
||||||
|
override fun <T> startService(service: Class<T>, device: ServerDevice) {
|
||||||
|
controller.create().startCommand(3, 4).get()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package no.nordicsemi.android.gls
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.room.Room
|
||||||
|
import dagger.Module
|
||||||
|
import dagger.Provides
|
||||||
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
|
import dagger.hilt.components.SingletonComponent
|
||||||
|
import dagger.hilt.testing.TestInstallIn
|
||||||
|
import no.nordicsemi.android.uart.DbHiltModule
|
||||||
|
import no.nordicsemi.android.uart.db.ConfigurationsDatabase
|
||||||
|
import no.nordicsemi.android.uart.db.MIGRATION_1_2
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Module
|
||||||
|
@TestInstallIn(
|
||||||
|
components = [SingletonComponent::class],
|
||||||
|
replaces = [DbHiltModule::class]
|
||||||
|
)
|
||||||
|
class TestDbHiltModule {
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
internal fun provideDB(@ApplicationContext context: Context): ConfigurationsDatabase {
|
||||||
|
return Room.inMemoryDatabaseBuilder(
|
||||||
|
context,
|
||||||
|
ConfigurationsDatabase::class.java
|
||||||
|
).addMigrations(MIGRATION_1_2).build()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package no.nordicsemi.android.gls
|
||||||
|
|
||||||
|
import dagger.Module
|
||||||
|
import dagger.hilt.components.SingletonComponent
|
||||||
|
import dagger.hilt.testing.TestInstallIn
|
||||||
|
|
||||||
|
//@Module
|
||||||
|
//@TestInstallIn(
|
||||||
|
// components = [SingletonComponent::class],
|
||||||
|
// replaces = [AnalyticsModule::class]
|
||||||
|
//)
|
||||||
|
//class TestHiltModule {
|
||||||
|
//}
|
||||||
@@ -0,0 +1,208 @@
|
|||||||
|
package no.nordicsemi.android.gls
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.test.rule.ServiceTestRule
|
||||||
|
import dagger.hilt.android.testing.BindValue
|
||||||
|
import dagger.hilt.android.testing.HiltAndroidRule
|
||||||
|
import dagger.hilt.android.testing.HiltAndroidTest
|
||||||
|
import dagger.hilt.android.testing.HiltTestApplication
|
||||||
|
import dagger.hilt.android.testing.UninstallModules
|
||||||
|
import io.mockk.every
|
||||||
|
import io.mockk.impl.annotations.MockK
|
||||||
|
import io.mockk.impl.annotations.RelaxedMockK
|
||||||
|
import io.mockk.junit4.MockKRule
|
||||||
|
import io.mockk.mockk
|
||||||
|
import io.mockk.mockkObject
|
||||||
|
import io.mockk.mockkStatic
|
||||||
|
import io.mockk.spyk
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
||||||
|
import kotlinx.coroutines.test.advanceUntilIdle
|
||||||
|
import kotlinx.coroutines.test.resetMain
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import kotlinx.coroutines.test.setMain
|
||||||
|
import no.nordicsemi.android.analytics.AppAnalytics
|
||||||
|
import no.nordicsemi.android.common.logger.NordicBlekLogger
|
||||||
|
import no.nordicsemi.android.common.navigation.NavigationResult
|
||||||
|
import no.nordicsemi.android.common.navigation.Navigator
|
||||||
|
import no.nordicsemi.android.common.navigation.di.NavigationModule
|
||||||
|
import no.nordicsemi.android.kotlin.ble.client.main.ClientScope
|
||||||
|
import no.nordicsemi.android.kotlin.ble.core.MockServerDevice
|
||||||
|
import no.nordicsemi.android.kotlin.ble.core.data.BleGattConnectionStatus
|
||||||
|
import no.nordicsemi.android.kotlin.ble.core.data.GattConnectionState
|
||||||
|
import no.nordicsemi.android.kotlin.ble.core.data.GattConnectionStateWithStatus
|
||||||
|
import no.nordicsemi.android.kotlin.ble.server.main.ServerScope
|
||||||
|
import no.nordicsemi.android.uart.data.UARTPersistentDataSource
|
||||||
|
import no.nordicsemi.android.uart.repository.UARTRepository
|
||||||
|
import no.nordicsemi.android.uart.view.DisconnectEvent
|
||||||
|
import no.nordicsemi.android.uart.viewmodel.UARTViewModel
|
||||||
|
import no.nordicsemi.android.ui.view.NordicLoggerFactory
|
||||||
|
import no.nordicsemi.android.ui.view.StringConst
|
||||||
|
import org.junit.After
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Rule
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.robolectric.RobolectricTestRunner
|
||||||
|
import org.robolectric.annotation.Config
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Example local unit test, which will execute on the development machine (host).
|
||||||
|
*
|
||||||
|
* See [testing documentation](http://d.android.com/tools/testing).
|
||||||
|
*/
|
||||||
|
@HiltAndroidTest
|
||||||
|
@Config(application = HiltTestApplication::class)
|
||||||
|
@UninstallModules(NavigationModule::class)
|
||||||
|
@RunWith(RobolectricTestRunner::class)
|
||||||
|
internal class UARTViewModelTest {
|
||||||
|
|
||||||
|
@get:Rule
|
||||||
|
val mockkRule = MockKRule(this)
|
||||||
|
|
||||||
|
@get:Rule
|
||||||
|
val serviceRule = ServiceTestRule()
|
||||||
|
|
||||||
|
@get:Rule
|
||||||
|
var hiltRule = HiltAndroidRule(this)
|
||||||
|
|
||||||
|
@BindValue
|
||||||
|
@JvmField
|
||||||
|
val analyticsService: Navigator = mockk(relaxed = true)
|
||||||
|
|
||||||
|
@RelaxedMockK
|
||||||
|
lateinit var analytics: AppAnalytics
|
||||||
|
|
||||||
|
@MockK
|
||||||
|
lateinit var stringConst: StringConst
|
||||||
|
|
||||||
|
@RelaxedMockK
|
||||||
|
lateinit var context: Context
|
||||||
|
|
||||||
|
@RelaxedMockK
|
||||||
|
lateinit var logger: NordicBlekLogger
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var repository: UARTRepository
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var dataSource: UARTPersistentDataSource
|
||||||
|
|
||||||
|
lateinit var viewModel: UARTViewModel
|
||||||
|
|
||||||
|
lateinit var uartServer: UartServer
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var device: MockServerDevice
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
hiltRule.inject()
|
||||||
|
Dispatchers.setMain(UnconfinedTestDispatcher())
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
fun release() {
|
||||||
|
Dispatchers.resetMain()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun before() {
|
||||||
|
viewModel = UARTViewModel(repository, mockk(relaxed = true), dataSource, mockk(relaxed = true), object :
|
||||||
|
NordicLoggerFactory {
|
||||||
|
override fun createNordicLogger(
|
||||||
|
context: Context,
|
||||||
|
profile: String?,
|
||||||
|
key: String,
|
||||||
|
name: String?,
|
||||||
|
): NordicBlekLogger {
|
||||||
|
return logger
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
runBlocking {
|
||||||
|
mockkStatic("no.nordicsemi.android.kotlin.ble.client.main.ClientScopeKt")
|
||||||
|
every { ClientScope } returns CoroutineScope(UnconfinedTestDispatcher())
|
||||||
|
mockkStatic("no.nordicsemi.android.kotlin.ble.server.main.ServerScopeKt")
|
||||||
|
every { ServerScope } returns CoroutineScope(UnconfinedTestDispatcher())
|
||||||
|
every { stringConst.APP_NAME } returns "Test"
|
||||||
|
|
||||||
|
uartServer = UartServer(CoroutineScope(UnconfinedTestDispatcher()))
|
||||||
|
uartServer.start(spyk(), device)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun prepareLogger() {
|
||||||
|
mockkObject(NordicBlekLogger.Companion)
|
||||||
|
every { NordicBlekLogger.create(any(), any(), any(), any()) } returns mockk()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `when connected should return state connected`() = runTest {
|
||||||
|
val connectedState = GattConnectionStateWithStatus(
|
||||||
|
GattConnectionState.STATE_CONNECTED,
|
||||||
|
BleGattConnectionStatus.SUCCESS
|
||||||
|
)
|
||||||
|
viewModel.handleResult(NavigationResult.Success(device))
|
||||||
|
|
||||||
|
advanceUntilIdle()
|
||||||
|
|
||||||
|
assertEquals(connectedState, viewModel.state.value.uartManagerState.connectionState)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `when disconnected should return state connected`() = runTest {
|
||||||
|
val disconnectedState = GattConnectionStateWithStatus(
|
||||||
|
GattConnectionState.STATE_DISCONNECTED,
|
||||||
|
BleGattConnectionStatus.SUCCESS
|
||||||
|
)
|
||||||
|
viewModel.handleResult(NavigationResult.Success(device))
|
||||||
|
viewModel.onEvent(DisconnectEvent)
|
||||||
|
|
||||||
|
advanceUntilIdle()
|
||||||
|
|
||||||
|
assertEquals(disconnectedState, viewModel.state.value.uartManagerState.connectionState)
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// @Test
|
||||||
|
// fun `when request last record then change status and get 1 record`() = runTest {
|
||||||
|
// viewModel.handleResult(NavigationResult.Success(device))
|
||||||
|
// advanceUntilIdle() //Needed because of delay() in waitForBonding()
|
||||||
|
// assertEquals(RequestStatus.IDLE, viewModel.state.value.glsServiceData.requestStatus)
|
||||||
|
//
|
||||||
|
// viewModel.onEvent(OnWorkingModeSelected(WorkingMode.LAST))
|
||||||
|
// assertEquals(RequestStatus.PENDING, viewModel.state.value.glsServiceData.requestStatus)
|
||||||
|
//
|
||||||
|
// glsServer.continueWithResponse() //continue server breakpoint
|
||||||
|
//
|
||||||
|
// assertEquals(RequestStatus.SUCCESS, viewModel.state.value.glsServiceData.requestStatus)
|
||||||
|
// assertEquals(1, viewModel.state.value.glsServiceData.records.size)
|
||||||
|
//
|
||||||
|
// val parsedResponse = GlucoseMeasurementParser.parse(glsServer.OLDEST_RECORD)
|
||||||
|
// assertEquals(parsedResponse, viewModel.state.value.glsServiceData.records.keys.first())
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Test
|
||||||
|
// fun `when request all record then change status and get 5 records`() = runTest {
|
||||||
|
// viewModel.handleResult(NavigationResult.Success(device))
|
||||||
|
// advanceUntilIdle() //Needed because of delay() in waitForBonding()
|
||||||
|
// assertEquals(RequestStatus.IDLE, viewModel.state.value.glsServiceData.requestStatus)
|
||||||
|
//
|
||||||
|
// viewModel.onEvent(OnWorkingModeSelected(WorkingMode.ALL))
|
||||||
|
// assertEquals(RequestStatus.PENDING, viewModel.state.value.glsServiceData.requestStatus)
|
||||||
|
//
|
||||||
|
// glsServer.continueWithResponse() //continue server breakpoint
|
||||||
|
// advanceUntilIdle() //We have to use because of delay() in sendAll()
|
||||||
|
//
|
||||||
|
// assertEquals(RequestStatus.SUCCESS, viewModel.state.value.glsServiceData.requestStatus)
|
||||||
|
// assertEquals(5, viewModel.state.value.glsServiceData.records.size)
|
||||||
|
//
|
||||||
|
// val expectedRecords = glsServer.records.map { GlucoseMeasurementParser.parse(it) }
|
||||||
|
// assertContentEquals(expectedRecords, viewModel.state.value.glsServiceData.records.keys)
|
||||||
|
// }
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user