From a253cd2f265d02d835d2462ae36c005e96907587 Mon Sep 17 00:00:00 2001 From: Denver Coneybeare Date: Wed, 11 Dec 2024 17:09:54 +0000 Subject: [PATCH] Go back to just making FirebaseDataConnect.logLevel a MutableStateFlow --- firebase-dataconnect/CHANGELOG.md | 7 +- firebase-dataconnect/api.txt | 26 +-- .../firebase-dataconnect.gradle.kts | 1 - firebase-dataconnect/gradle.properties | 2 +- .../dataconnect/DataConnectLogging.kt | 150 ------------------ .../dataconnect/FirebaseDataConnect.kt | 26 ++- .../{DataConnectLoggingImpl.kt => Logger.kt} | 45 +----- .../dataconnect/DataConnectLoggingUnitTest.kt | 72 --------- .../FirebaseDataConnectUnitTest.kt | 53 ------- .../core/DataConnectLoggingImplUnitTest.kt | 99 ------------ .../testutil/DataConnectLogLevelRule.kt | 11 +- 11 files changed, 27 insertions(+), 465 deletions(-) delete mode 100644 firebase-dataconnect/src/main/kotlin/com/google/firebase/dataconnect/DataConnectLogging.kt rename firebase-dataconnect/src/main/kotlin/com/google/firebase/dataconnect/core/{DataConnectLoggingImpl.kt => Logger.kt} (67%) delete mode 100644 firebase-dataconnect/src/test/kotlin/com/google/firebase/dataconnect/DataConnectLoggingUnitTest.kt delete mode 100644 firebase-dataconnect/src/test/kotlin/com/google/firebase/dataconnect/FirebaseDataConnectUnitTest.kt delete mode 100644 firebase-dataconnect/src/test/kotlin/com/google/firebase/dataconnect/core/DataConnectLoggingImplUnitTest.kt diff --git a/firebase-dataconnect/CHANGELOG.md b/firebase-dataconnect/CHANGELOG.md index a7dff935eb0..07a93ef2117 100644 --- a/firebase-dataconnect/CHANGELOG.md +++ b/firebase-dataconnect/CHANGELOG.md @@ -1,8 +1,7 @@ # Unreleased -* [feature] `FirebaseDataConnect.logging` added, to provide more advanced - control and access to the logcat logging facilities, such as a `Flow` to - collect the log level changes, `push()` to set and restore the log level, - and `withLevel()` to run a block with a specific log level. +* [changed] `FirebaseDataConnect.logLevel` type changed from `LogLevel` to + `MutableStateFlow`. This enables apps to "collect" the flow to, + for example, update a UI component when the log level changes. ([#6586](https://github.com/firebase/firebase-android-sdk/pull/6586)) # 16.0.0-beta03 diff --git a/firebase-dataconnect/api.txt b/firebase-dataconnect/api.txt index 59638bb76ef..96e5c1e4601 100644 --- a/firebase-dataconnect/api.txt +++ b/firebase-dataconnect/api.txt @@ -42,28 +42,6 @@ package com.google.firebase.dataconnect { ctor public DataConnectException(@NonNull String message, @Nullable Throwable cause = null); } - public interface DataConnectLogging { - method @NonNull public kotlinx.coroutines.flow.Flow getFlow(); - method @NonNull public com.google.firebase.dataconnect.LogLevel getLevel(); - method @NonNull public com.google.firebase.dataconnect.DataConnectLogging.LogLevelStackFrame push(@NonNull com.google.firebase.dataconnect.LogLevel level); - method public void setLevel(@NonNull com.google.firebase.dataconnect.LogLevel); - property @NonNull public abstract kotlinx.coroutines.flow.Flow flow; - property @NonNull public abstract com.google.firebase.dataconnect.LogLevel level; - } - - public static interface DataConnectLogging.LogLevelStackFrame extends java.lang.AutoCloseable { - method public void close(); - method @NonNull public com.google.firebase.dataconnect.LogLevel getNewLevel(); - method @NonNull public com.google.firebase.dataconnect.LogLevel getOriginalLevel(); - method @Nullable public suspend Object suspendingClose(@NonNull kotlin.coroutines.Continuation); - property @NonNull public abstract com.google.firebase.dataconnect.LogLevel newLevel; - property @NonNull public abstract com.google.firebase.dataconnect.LogLevel originalLevel; - } - - public final class DataConnectLoggingKt { - method public static inline T withLevel(@NonNull com.google.firebase.dataconnect.DataConnectLogging, @NonNull com.google.firebase.dataconnect.LogLevel level, @NonNull kotlin.jvm.functions.Function0 block); - } - public final class DataConnectSettings { ctor public DataConnectSettings(@NonNull String host = "firebasedataconnect.googleapis.com", boolean sslEnabled = true); method @NonNull public String getHost(); @@ -134,9 +112,7 @@ package com.google.firebase.dataconnect { public final class FirebaseDataConnectKt { method @NonNull public static com.google.firebase.dataconnect.FirebaseDataConnect getInstance(@NonNull com.google.firebase.dataconnect.FirebaseDataConnect.Companion, @NonNull com.google.firebase.FirebaseApp app, @NonNull com.google.firebase.dataconnect.ConnectorConfig config, @NonNull com.google.firebase.dataconnect.DataConnectSettings settings = com.google.firebase.dataconnect.DataConnectSettings()); method @NonNull public static com.google.firebase.dataconnect.FirebaseDataConnect getInstance(@NonNull com.google.firebase.dataconnect.FirebaseDataConnect.Companion, @NonNull com.google.firebase.dataconnect.ConnectorConfig config, @NonNull com.google.firebase.dataconnect.DataConnectSettings settings = com.google.firebase.dataconnect.DataConnectSettings()); - method @Deprecated @NonNull public static com.google.firebase.dataconnect.LogLevel getLogLevel(@NonNull com.google.firebase.dataconnect.FirebaseDataConnect.Companion); - method @NonNull public static com.google.firebase.dataconnect.DataConnectLogging getLogging(@NonNull com.google.firebase.dataconnect.FirebaseDataConnect.Companion); - method @Deprecated public static void setLogLevel(@NonNull com.google.firebase.dataconnect.FirebaseDataConnect.Companion, @NonNull com.google.firebase.dataconnect.LogLevel); + method @NonNull public static kotlinx.coroutines.flow.MutableStateFlow getLogLevel(@NonNull com.google.firebase.dataconnect.FirebaseDataConnect.Companion); } @kotlinx.serialization.Serializable(with=LocalDateSerializer::class) public final class LocalDate { diff --git a/firebase-dataconnect/firebase-dataconnect.gradle.kts b/firebase-dataconnect/firebase-dataconnect.gradle.kts index 84a42ab3c7b..87ffe572916 100644 --- a/firebase-dataconnect/firebase-dataconnect.gradle.kts +++ b/firebase-dataconnect/firebase-dataconnect.gradle.kts @@ -125,7 +125,6 @@ dependencies { testImplementation(libs.mockk) testImplementation(libs.testonly.three.ten.abp) testImplementation(libs.robolectric) - testImplementation(libs.turbine) androidTestImplementation(project(":firebase-dataconnect:androidTestutil")) androidTestImplementation(project(":firebase-dataconnect:connectors")) diff --git a/firebase-dataconnect/gradle.properties b/firebase-dataconnect/gradle.properties index 73f95247b1b..61e7407c387 100644 --- a/firebase-dataconnect/gradle.properties +++ b/firebase-dataconnect/gradle.properties @@ -1,2 +1,2 @@ -version=16.0.0-beta99 +version=16.0.0-beta04 latestReleasedVersion=16.0.0-beta03 diff --git a/firebase-dataconnect/src/main/kotlin/com/google/firebase/dataconnect/DataConnectLogging.kt b/firebase-dataconnect/src/main/kotlin/com/google/firebase/dataconnect/DataConnectLogging.kt deleted file mode 100644 index 7abfba1740f..00000000000 --- a/firebase-dataconnect/src/main/kotlin/com/google/firebase/dataconnect/DataConnectLogging.kt +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright 2024 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.dataconnect - -import kotlinx.coroutines.flow.Flow - -/** - * The logcat logging facilities provided by the Firebase Data Connect SDK. - * - * The most common use of this interface is simply setting [level] to [LogLevel.DEBUG] to enable - * debug logging. - * - * ### Obtaining Instances - * - * To obtain an instance of [DataConnectLogging] call [FirebaseDataConnect.Companion.logging]. - * - * ### Safe for Concurrent Use - * - * All methods and properties of [DataConnectLogging] are thread-safe and may be safely called - * and/or accessed concurrently from multiple threads and/or coroutines. - * - * ### Not Stable for Inheritance - * - * The [DataConnectLogging] interface is _not_ stable for inheritance in third-party libraries, as - * new methods might be added to this interface or contracts of the existing methods can be changed. - */ -public interface DataConnectLogging { - - /** - * The log level use by all [FirebaseDataConnect] instances. - * - * The default log level is [LogLevel.WARN]. Setting this to [LogLevel.DEBUG] will enable debug - * logging, which is especially useful when reporting issues to Google or investigating problems - * yourself. Setting it to [LogLevel.NONE] will disable all logging. - */ - public var level: LogLevel - - /** A [Flow] that can be used to observe changes to [state]. */ - public val flow: Flow - - /** - * The state of the logging facilities. - * - * A caller may wish to save the value of this property into a local variable, make some changes - * to the public properties of [DataConnectLogging] (for example, change [level]), run some code, - * then restore the original state by calling [DataConnectLogging.State.restore]. - * - * For an example in Firebase Data Connect's own Android test suite, see https://goo.gle/3ZuRug5. - */ - public val state: StateT - - /** - * A snapshot of the state of the logging facilities, that can be later restored. - * - * ### Safe for Concurrent Use - * - * All methods and properties of [State] are thread-safe and may be safely called and/or accessed - * concurrently from multiple threads and/or coroutines. - * - * ### Not Stable for Inheritance - * - * The [State] interface is _not_ stable for inheritance in third-party libraries, as new methods - * might be added to this interface or contracts of the existing methods can be changed. - * - * @see state - */ - public interface State { - - /** The log level. */ - public val level: LogLevel - - /** Restores the state from this object into the [DataConnectLogging] that created it. */ - public fun restore() - - /** - * Compares this object with another object for equality. - * - * @param other The object to compare to this for equality. - * @return true if, and only if, the other object is an instance of the same implementation of - * [State] whose public properties compare equal using the `==` operator to the corresponding - * properties of this object. - */ - override fun equals(other: Any?): Boolean - - /** - * Calculates and returns the hash code for this object. - * - * The hash code is _not_ guaranteed to be stable across application restarts. - * - * @return the hash code for this object, that incorporates the values of this object's public - * properties. - */ - override fun hashCode(): Int - - /** - * Returns a string representation of this object, useful for debugging. - * - * The string representation is _not_ guaranteed to be stable and may change without notice at - * any time. Therefore, the only recommended usage of the returned string is debugging and/or - * logging. Namely, parsing the returned string or storing the returned string in non-volatile - * storage should generally be avoided in order to be robust in case that the string - * representation changes. - * - * @return a string representation of this object, which includes the class name and the values - * of all public properties. - */ - override fun toString(): String - } -} - -/** - * Sets the log level to the given level, runs the given block, then restores the log level to its - * original value. - * - * The given block is called exactly once and is called in-place. Using the experimental - * [kotlin.contracts.contract], this could be expressed as: - * ``` - * contract { - * callsInPlace(block, InvocationKind.EXACTLY_ONCE) - * } - * ``` - * - * @param level the log level to have in effect when the given block is executed. - * @param block the code to execute with the given log level set; it will be invoked exactly once - * inline. - * @return whatever the given block returns. - */ -public inline fun DataConnectLogging<*>.withLevel(level: LogLevel, block: () -> T): T { - val savedState = state - this.level = level - return try { - block() - } finally { - savedState.restore() - } -} diff --git a/firebase-dataconnect/src/main/kotlin/com/google/firebase/dataconnect/FirebaseDataConnect.kt b/firebase-dataconnect/src/main/kotlin/com/google/firebase/dataconnect/FirebaseDataConnect.kt index 37fd12c688b..a1e1d60943b 100644 --- a/firebase-dataconnect/src/main/kotlin/com/google/firebase/dataconnect/FirebaseDataConnect.kt +++ b/firebase-dataconnect/src/main/kotlin/com/google/firebase/dataconnect/FirebaseDataConnect.kt @@ -20,9 +20,10 @@ import android.annotation.SuppressLint import com.google.firebase.Firebase import com.google.firebase.FirebaseApp import com.google.firebase.app -import com.google.firebase.dataconnect.core.DataConnectLoggingImpl import com.google.firebase.dataconnect.core.FirebaseDataConnectFactory +import com.google.firebase.dataconnect.core.LoggerGlobals import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.serialization.DeserializationStrategy import kotlinx.serialization.SerializationStrategy import kotlinx.serialization.modules.SerializersModule @@ -61,8 +62,8 @@ import kotlinx.serialization.modules.SerializersModule * Data Connect service) call [FirebaseDataConnect.useEmulator]. To create [QueryRef] and * [MutationRef] instances for running queries and mutations, call [FirebaseDataConnect.query] and * [FirebaseDataConnect.mutation], respectively. To enable debug logging, which is especially useful - * when reporting issues to Google, set [DataConnectLogging.level] in - * [FirebaseDataConnect.Companion.logging] to [LogLevel.DEBUG]. + * when reporting issues to Google, set [FirebaseDataConnect.Companion.logLevel] to [LogLevel.DEBUG] + * . * * ### Integration with Kotlin Coroutines and Serialization * @@ -381,20 +382,13 @@ public fun FirebaseDataConnect.Companion.getInstance( /** * The log level used by all [FirebaseDataConnect] instances. * + * As a [MutableStateFlow], the log level can be changed by assigning [MutableStateFlow.value]. + * Also, the flow can be "collected" as a means of observing the log level, which may be useful in + * the case that a user interface shows a UI element, such as a checkbox, to represent whether debug + * logging is enabled. + * * The default log level is [LogLevel.WARN]. Setting this to [LogLevel.DEBUG] will enable debug * logging, which is especially useful when reporting issues to Google or investigating problems * yourself. Setting it to [LogLevel.NONE] will disable all logging. */ -@Deprecated( - message = "Will be removed when Data Connect graduates from beta", - replaceWith = ReplaceWith("logging.level", "com.google.firebase.dataconnect.logging") -) -public var FirebaseDataConnect.Companion.logLevel: LogLevel - get() = logging.level - set(level) { - logging.level = level - } - -/** The logcat logging facilities used by all [FirebaseDataConnect] instances. */ -public val FirebaseDataConnect.Companion.logging: DataConnectLogging<*> - get() = DataConnectLoggingImpl +public val FirebaseDataConnect.Companion.logLevel: MutableStateFlow get() = LoggerGlobals.logLevel diff --git a/firebase-dataconnect/src/main/kotlin/com/google/firebase/dataconnect/core/DataConnectLoggingImpl.kt b/firebase-dataconnect/src/main/kotlin/com/google/firebase/dataconnect/core/Logger.kt similarity index 67% rename from firebase-dataconnect/src/main/kotlin/com/google/firebase/dataconnect/core/DataConnectLoggingImpl.kt rename to firebase-dataconnect/src/main/kotlin/com/google/firebase/dataconnect/core/Logger.kt index e8f0a284e8e..c5e70fa6e43 100644 --- a/firebase-dataconnect/src/main/kotlin/com/google/firebase/dataconnect/core/DataConnectLoggingImpl.kt +++ b/firebase-dataconnect/src/main/kotlin/com/google/firebase/dataconnect/core/Logger.kt @@ -18,42 +18,11 @@ package com.google.firebase.dataconnect.core import android.util.Log import com.google.firebase.dataconnect.BuildConfig -import com.google.firebase.dataconnect.DataConnectLogging import com.google.firebase.dataconnect.LogLevel import com.google.firebase.dataconnect.core.LoggerGlobals.LOG_TAG -import com.google.firebase.dataconnect.core.LoggerGlobals.Logger import com.google.firebase.util.nextAlphanumericString -import kotlin.random.Random import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.asSharedFlow - -internal object DataConnectLoggingImpl : DataConnectLogging { - - private val _state = MutableStateFlow(StateImpl(level = LogLevel.WARN)) - - override val flow = _state.asSharedFlow() - - override val state - get() = _state.value - - override var level: LogLevel - get() = _state.value.level - set(newLevel) { - while (true) { - val oldState = _state.value - val newState = oldState.copy(level = newLevel) - if (_state.compareAndSet(oldState, newState)) { - break - } - } - } - - data class StateImpl(override val level: LogLevel) : DataConnectLogging.State { - override fun restore() { - _state.value = this - } - } -} +import kotlin.random.Random internal interface Logger { val name: String @@ -90,22 +59,22 @@ private class LoggerImpl(override val name: String) : Logger { internal object LoggerGlobals { const val LOG_TAG = "FirebaseDataConnect" - private val logLevel: LogLevel by DataConnectLoggingImpl::level + val logLevel = MutableStateFlow(LogLevel.WARN) inline fun Logger.debug(message: () -> Any?) { - if (logLevel <= LogLevel.DEBUG) debug("${message()}") + if (logLevel.value <= LogLevel.DEBUG) debug("${message()}") } fun Logger.debug(message: String) { - if (logLevel <= LogLevel.DEBUG) log(null, LogLevel.DEBUG, message) + if (logLevel.value <= LogLevel.DEBUG) log(null, LogLevel.DEBUG, message) } inline fun Logger.warn(message: () -> Any?) { - if (logLevel <= LogLevel.WARN) warn("${message()}") + if (logLevel.value <= LogLevel.WARN) warn("${message()}") } inline fun Logger.warn(exception: Throwable?, message: () -> Any?) { - if (logLevel <= LogLevel.WARN) warn(exception, "${message()}") + if (logLevel.value <= LogLevel.WARN) warn(exception, "${message()}") } fun Logger.warn(message: String) { @@ -113,7 +82,7 @@ internal object LoggerGlobals { } fun Logger.warn(exception: Throwable?, message: String) { - if (logLevel <= LogLevel.WARN) log(exception, LogLevel.WARN, message) + if (logLevel.value <= LogLevel.WARN) log(exception, LogLevel.WARN, message) } fun Logger(name: String): Logger = LoggerImpl(name) diff --git a/firebase-dataconnect/src/test/kotlin/com/google/firebase/dataconnect/DataConnectLoggingUnitTest.kt b/firebase-dataconnect/src/test/kotlin/com/google/firebase/dataconnect/DataConnectLoggingUnitTest.kt deleted file mode 100644 index 75dd93b9bd2..00000000000 --- a/firebase-dataconnect/src/test/kotlin/com/google/firebase/dataconnect/DataConnectLoggingUnitTest.kt +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2024 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.google.firebase.dataconnect - -import io.kotest.assertions.assertSoftly -import io.kotest.assertions.withClue -import io.kotest.matchers.shouldBe -import io.kotest.matchers.types.shouldBeSameInstanceAs -import io.kotest.property.Arb -import io.kotest.property.arbitrary.enum -import io.kotest.property.arbitrary.string -import io.kotest.property.checkAll -import java.util.concurrent.atomic.AtomicInteger -import kotlinx.coroutines.test.runTest -import org.junit.Test - -class DataConnectLoggingUnitTest { - - @Test - fun `withLevel() should set and restore the log level`() = runTest { - val arb = Arb.enum() - checkAll(arb, arb) { level1, level2 -> - FirebaseDataConnect.logging.level = level1 - - FirebaseDataConnect.logging.withLevel(level2) { - withClue("inside withLevel") { FirebaseDataConnect.logging.level shouldBe level2 } - } - - withClue("after withLevel") { FirebaseDataConnect.logging.level shouldBe level1 } - } - } - - @Test - fun `withLevel() should return the object returned from the block`() = runTest { - checkAll(Arb.enum(), Arb.string()) { level, string -> - val returnValue = FirebaseDataConnect.logging.withLevel(level) { string } - - returnValue shouldBeSameInstanceAs string - } - } - - @Test - fun `withLevel() should call the given block exactly once inline`() = runTest { - checkAll(Arb.enum()) { level -> - val invocationCount = AtomicInteger(0) - val thread1 = Thread.currentThread() - val thread2 = - FirebaseDataConnect.logging.withLevel(level) { - invocationCount.incrementAndGet() - Thread.currentThread() - } - - assertSoftly { - thread1 shouldBe thread2 - invocationCount.get() shouldBe 1 - } - } - } -} diff --git a/firebase-dataconnect/src/test/kotlin/com/google/firebase/dataconnect/FirebaseDataConnectUnitTest.kt b/firebase-dataconnect/src/test/kotlin/com/google/firebase/dataconnect/FirebaseDataConnectUnitTest.kt deleted file mode 100644 index b9175eab4fa..00000000000 --- a/firebase-dataconnect/src/test/kotlin/com/google/firebase/dataconnect/FirebaseDataConnectUnitTest.kt +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2024 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.google.firebase.dataconnect - -import io.kotest.matchers.shouldBe -import io.kotest.property.Arb -import io.kotest.property.arbitrary.enum -import io.kotest.property.checkAll -import kotlinx.coroutines.test.runTest -import org.junit.Test - -class FirebaseDataConnectUnitTest { - - @Test - @Suppress("DEPRECATION") - fun `logLevel set and get`() = runTest { - checkAll(Arb.enum()) { newLevel -> - FirebaseDataConnect.logLevel = newLevel - FirebaseDataConnect.logLevel shouldBe newLevel - } - } - - @Test - @Suppress("DEPRECATION") - fun `logLevel set should forward to logging dot level`() = runTest { - checkAll(Arb.enum()) { newLevel -> - FirebaseDataConnect.logLevel = newLevel - FirebaseDataConnect.logging.level shouldBe newLevel - } - } - - @Test - @Suppress("DEPRECATION") - fun `logLevel get should retrieve from logging dot level`() = runTest { - checkAll(Arb.enum()) { newLevel -> - FirebaseDataConnect.logging.level = newLevel - FirebaseDataConnect.logLevel shouldBe newLevel - } - } -} diff --git a/firebase-dataconnect/src/test/kotlin/com/google/firebase/dataconnect/core/DataConnectLoggingImplUnitTest.kt b/firebase-dataconnect/src/test/kotlin/com/google/firebase/dataconnect/core/DataConnectLoggingImplUnitTest.kt deleted file mode 100644 index 846b4e1dd28..00000000000 --- a/firebase-dataconnect/src/test/kotlin/com/google/firebase/dataconnect/core/DataConnectLoggingImplUnitTest.kt +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright 2024 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.firebase.dataconnect.core - -import app.cash.turbine.test -import com.google.firebase.dataconnect.LogLevel -import com.google.firebase.dataconnect.core.DataConnectLoggingImpl.StateImpl -import io.kotest.assertions.withClue -import io.kotest.matchers.shouldBe -import io.kotest.property.Arb -import io.kotest.property.arbitrary.enum -import io.kotest.property.arbitrary.map -import io.kotest.property.checkAll -import kotlinx.coroutines.test.runTest -import org.junit.Test - -class DataConnectLoggingImplUnitTest { - - @Test - fun `level property, setting and getting`() = runTest { - checkAll(Arb.enum()) { newLevel -> - DataConnectLoggingImpl.level = newLevel - DataConnectLoggingImpl.level shouldBe newLevel - } - } - - @Test - fun `flow property, collecting`() = runTest { - DataConnectLoggingImpl.flow.test { - withClue("initial item") { awaitItem().level shouldBe DataConnectLoggingImpl.level } - - checkAll(Arb.enum()) { newLevel -> - val levelChanged = DataConnectLoggingImpl.level != newLevel - DataConnectLoggingImpl.level = newLevel - if (levelChanged) { - awaitItem().level shouldBe newLevel - } - } - } - } - - @Test - fun `state property, should be the current state`() = runTest { - val arb = Arb.enum() - checkAll(arb, arb) { level1, level2 -> - DataConnectLoggingImpl.level = level1 - withClue("state1") { DataConnectLoggingImpl.state.level shouldBe level1 } - DataConnectLoggingImpl.level = level2 - withClue("state1") { DataConnectLoggingImpl.state.level shouldBe level2 } - } - } - - @Test - fun `StateImpl level property, equals value given to constructor`() = runTest { - checkAll(Arb.enum()) { level -> - val state = StateImpl(level) - state.level shouldBe level - } - } - - @Test - fun `StateImpl restore(), should restore level`() = runTest { - checkAll(Arb.stateImpl()) { state: StateImpl -> - state.restore() - DataConnectLoggingImpl.level shouldBe state.level - } - } - - @Test - fun `StateImpl restore(), should restore on each invocation`() = runTest { - checkAll(Arb.stateImpl(), Arb.enum()) { state: StateImpl, newLevel -> - state.restore() - withClue("restore1") { DataConnectLoggingImpl.level shouldBe state.level } - - DataConnectLoggingImpl.level = newLevel - state.restore() - withClue("restore2") { DataConnectLoggingImpl.level shouldBe state.level } - } - } - - private companion object { - - fun Arb.Companion.stateImpl(): Arb = Arb.enum().map { StateImpl(it) } - } -} diff --git a/firebase-dataconnect/testutil/src/main/kotlin/com/google/firebase/dataconnect/testutil/DataConnectLogLevelRule.kt b/firebase-dataconnect/testutil/src/main/kotlin/com/google/firebase/dataconnect/testutil/DataConnectLogLevelRule.kt index ed47de65a4e..91a78ff51f1 100644 --- a/firebase-dataconnect/testutil/src/main/kotlin/com/google/firebase/dataconnect/testutil/DataConnectLogLevelRule.kt +++ b/firebase-dataconnect/testutil/src/main/kotlin/com/google/firebase/dataconnect/testutil/DataConnectLogLevelRule.kt @@ -15,10 +15,9 @@ */ package com.google.firebase.dataconnect.testutil -import com.google.firebase.dataconnect.DataConnectLogging import com.google.firebase.dataconnect.FirebaseDataConnect import com.google.firebase.dataconnect.LogLevel -import com.google.firebase.dataconnect.logging +import com.google.firebase.dataconnect.logLevel import org.junit.rules.ExternalResource /** @@ -28,14 +27,14 @@ import org.junit.rules.ExternalResource class DataConnectLogLevelRule(val logLevelDuringTest: LogLevel = LogLevel.DEBUG) : ExternalResource() { - private lateinit var savedLoggingState: DataConnectLogging.State + private lateinit var logLevelBefore: LogLevel override fun before() { - savedLoggingState = FirebaseDataConnect.logging.state - FirebaseDataConnect.logging.level = logLevelDuringTest + logLevelBefore = FirebaseDataConnect.logLevel.value + logLevelDuringTest.also { FirebaseDataConnect.logLevel.value = it } } override fun after() { - savedLoggingState.restore() + FirebaseDataConnect.logLevel.value = logLevelBefore } }