Loading packages/SystemUI/multivalentTests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java +2 −2 Original line number Diff line number Diff line Loading @@ -142,7 +142,7 @@ public class PluginInstanceTest extends SysuiTestCase { mPluginInstanceFactory.create( mContext, mAppInfo, wrongVersionTestPluginComponentName, TestPlugin.class, mPluginListener); LogAssertKt.assertLogsWtf(()-> { LogAssertKt.assertRunnableLogsWtf(()-> { mPluginInstance.onCreate(); }); assertTrue(mPluginInstance.hasError()); Loading Loading @@ -195,7 +195,7 @@ public class PluginInstanceTest extends SysuiTestCase { mPluginInstance.onCreate(); assertFalse(mPluginInstance.hasError()); LogAssertKt.assertLogsWtf(()-> { LogAssertKt.assertRunnableLogsWtf(()-> { Object result = mPluginInstance.getPlugin().methodThrowsError(); assertNotNull(result); // Wrapper function should return non-null; }); Loading packages/SystemUI/multivalentTests/src/com/android/systemui/util/wakelock/WakeLockTest.java +1 −1 Original line number Diff line number Diff line Loading @@ -93,6 +93,6 @@ public class WakeLockTest extends SysuiTestCase { @Test public void prodBuild_wakeLock_releaseWithoutAcquire_noThrow() { // shouldn't throw an exception on production builds LogAssertKt.assertLogsWtf(() -> mWakeLock.release(WHY)); LogAssertKt.assertRunnableLogsWtf(() -> mWakeLock.release(WHY)); } } packages/SystemUI/tests/src/com/android/systemui/recents/LauncherProxyServiceTest.kt +2 −1 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ import com.android.systemui.dump.DumpManager import com.android.systemui.keyguard.KeyguardUnlockAnimationController import com.android.systemui.keyguard.WakefulnessLifecycle import com.android.systemui.keyguard.ui.view.InWindowLauncherUnlockAnimationManager import com.android.systemui.log.assertLogsWtf import com.android.systemui.model.sysUiState import com.android.systemui.navigationbar.NavigationBarController import com.android.systemui.navigationbar.NavigationModeController Loading Loading @@ -221,7 +222,7 @@ class LauncherProxyServiceTest : SysuiTestCase() { `when`(processWrapper.isSystemUser).thenReturn(false) `when`(userManager.isVisibleBackgroundUsersSupported()).thenReturn(false) val spyContext = spy(context) val ops = createLauncherProxyService(spyContext) val ops = assertLogsWtf { createLauncherProxyService(spyContext) }.result ops.startConnectionToCurrentUser() verify(spyContext, times(0)).bindServiceAsUser(any(), any(), anyInt(), any()) } Loading packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java +10 −11 Original line number Diff line number Diff line Loading @@ -77,7 +77,6 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.plugga import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifStabilityManager; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable; import com.android.systemui.statusbar.notification.collection.notifcollection.CollectionReadyForBuildListener; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationTestHelper; import com.android.systemui.statusbar.notification.shared.NotificationBundleUi; import com.android.systemui.util.time.FakeSystemClock; Loading Loading @@ -1795,7 +1794,7 @@ public class ShadeListBuilderTest extends SysuiTestCase { invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS); // THEN an exception is NOT thrown directly, but a WTF IS logged. LogAssertKt.assertLogsWtfs(() -> { LogAssertKt.assertRunnableLogsWtfs(() -> { dispatchBuild(); runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2); }); Loading @@ -1818,7 +1817,7 @@ public class ShadeListBuilderTest extends SysuiTestCase { addNotif(0, PACKAGE_2); invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 1); LogAssertKt.assertLogsWtfs(() -> { LogAssertKt.assertRunnableLogsWtfs(() -> { Assert.assertThrows(IllegalStateException.class, () -> { dispatchBuild(); runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2); Loading @@ -1844,13 +1843,13 @@ public class ShadeListBuilderTest extends SysuiTestCase { addNotif(0, PACKAGE_2); invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS); LogAssertKt.assertLogsWtfs(() -> { LogAssertKt.assertRunnableLogsWtfs(() -> { dispatchBuild(); runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2); }); invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS); LogAssertKt.assertLogsWtfs(() -> { LogAssertKt.assertRunnableLogsWtfs(() -> { // Note: dispatchBuild itself triggers a non-reentrant pipeline run. dispatchBuild(); runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2); Loading @@ -1874,7 +1873,7 @@ public class ShadeListBuilderTest extends SysuiTestCase { addNotif(0, PACKAGE_1); invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS); LogAssertKt.assertLogsWtfs(() -> { LogAssertKt.assertRunnableLogsWtfs(() -> { dispatchBuild(); runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2); }); Loading @@ -1897,7 +1896,7 @@ public class ShadeListBuilderTest extends SysuiTestCase { addNotif(0, PACKAGE_1); invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 1); LogAssertKt.assertLogsWtfs(() -> { LogAssertKt.assertRunnableLogsWtfs(() -> { Assert.assertThrows(IllegalStateException.class, () -> { dispatchBuild(); runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2); Loading @@ -1922,7 +1921,7 @@ public class ShadeListBuilderTest extends SysuiTestCase { addNotif(0, PACKAGE_2); invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS); LogAssertKt.assertLogsWtfs(() -> { LogAssertKt.assertRunnableLogsWtfs(() -> { dispatchBuild(); runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2); }); Loading @@ -1945,7 +1944,7 @@ public class ShadeListBuilderTest extends SysuiTestCase { addNotif(0, PACKAGE_2); invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 1); LogAssertKt.assertLogsWtfs(() -> { LogAssertKt.assertRunnableLogsWtfs(() -> { Assert.assertThrows(IllegalStateException.class, () -> { dispatchBuild(); runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2); Loading @@ -1970,7 +1969,7 @@ public class ShadeListBuilderTest extends SysuiTestCase { addNotif(0, PACKAGE_2); invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS); LogAssertKt.assertLogsWtfs(() -> { LogAssertKt.assertRunnableLogsWtfs(() -> { dispatchBuild(); runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2); }); Loading @@ -1993,7 +1992,7 @@ public class ShadeListBuilderTest extends SysuiTestCase { addNotif(0, PACKAGE_2); invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 1); LogAssertKt.assertLogsWtfs(() -> { LogAssertKt.assertRunnableLogsWtfs(() -> { Assert.assertThrows(IllegalStateException.class, () -> { dispatchBuild(); runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2); Loading packages/SystemUI/tests/utils/src/com/android/systemui/log/LogAssert.kt +64 −50 Original line number Diff line number Diff line Loading @@ -13,89 +13,103 @@ * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.log import android.util.Log import android.util.Log.TerribleFailureHandler import junit.framework.Assert import com.google.common.truth.Truth.assertWithMessage import java.util.concurrent.Callable /** Asserts that the given block does not make a call to Log.wtf */ fun assertDoesNotLogWtf( /** Asserts that [notLoggingBlock] does not make a call to [Log.wtf] */ fun <T> assertDoesNotLogWtf( message: String = "Expected Log.wtf not to be called", notLoggingBlock: () -> Unit, ) { notLoggingBlock: () -> T, ): T { var caught: TerribleFailureLog? = null val newHandler = TerribleFailureHandler { tag, failure, system -> caught = TerribleFailureLog(tag, failure, system) } val oldHandler = Log.setWtfHandler(newHandler) val result = try { notLoggingBlock() } finally { Log.setWtfHandler(oldHandler) } caught?.let { throw AssertionError("$message: $it", it.failure) } return result } fun assertDoesNotLogWtf( message: String = "Expected Log.wtf not to be called", notLoggingRunnable: Runnable, ) = assertDoesNotLogWtf(message = message) { notLoggingRunnable.run() } /** * Assert that the given block makes a call to Log.wtf * * @return the details of the log */ fun assertLogsWtf( /** Assert that [loggingBlock] makes a call to [Log.wtf] */ @JvmOverloads fun <T> assertLogsWtf( message: String = "Expected Log.wtf to be called", allowMultiple: Boolean = false, loggingBlock: () -> Unit, ): TerribleFailureLog { var caught: TerribleFailureLog? = null var count = 0 loggingBlock: () -> T, ): WtfBlockResult<T> { val caught = mutableListOf<TerribleFailureLog>() val newHandler = TerribleFailureHandler { tag, failure, system -> if (caught == null) { caught = TerribleFailureLog(tag, failure, system) } count++ caught.add(TerribleFailureLog(tag, failure, system)) } val oldHandler = Log.setWtfHandler(newHandler) val result = try { loggingBlock() } finally { Log.setWtfHandler(oldHandler) } Assert.assertNotNull(message, caught) if (!allowMultiple && count != 1) { Assert.fail("Unexpectedly caught Log.Wtf $count times; expected only 1. First: $caught") assertWithMessage(message).that(caught).isNotEmpty() if (!allowMultiple) { assertWithMessage("Unexpectedly caught Log.Wtf multiple times").that(caught).hasSize(1) } return caught!! return WtfBlockResult(caught, result) } /** Assert that [loggingCallable] makes a call to [Log.wtf] */ @JvmOverloads fun assertLogsWtf( fun <T> assertLogsWtf( message: String = "Expected Log.wtf to be called", allowMultiple: Boolean = false, loggingRunnable: Runnable, ): TerribleFailureLog = assertLogsWtf(message = message, allowMultiple = allowMultiple) { loggingRunnable.run() } loggingCallable: Callable<T>, ): WtfBlockResult<T> = assertLogsWtf(message = message, allowMultiple = allowMultiple, loggingCallable::call) fun assertLogsWtfs( /** Assert that [loggingBlock] makes at least one call to [Log.wtf] */ @JvmOverloads fun <T> assertLogsWtfs( message: String = "Expected Log.wtf to be called once or more", loggingBlock: () -> Unit, ): TerribleFailureLog = assertLogsWtf(message, allowMultiple = true, loggingBlock) loggingBlock: () -> T, ): WtfBlockResult<T> = assertLogsWtf(message, allowMultiple = true, loggingBlock) /** Assert that [loggingCallable] makes at least one call to [Log.wtf] */ @JvmOverloads fun assertLogsWtfs( fun <T> assertLogsWtfs( message: String = "Expected Log.wtf to be called once or more", loggingRunnable: Runnable, ): TerribleFailureLog = assertLogsWtfs(message) { loggingRunnable.run() } loggingCallable: Callable<T>, ): WtfBlockResult<T> = assertLogsWtf(message, allowMultiple = true, loggingCallable) /** The data passed to [TerribleFailureHandler.onTerribleFailure] */ data class TerribleFailureLog( val tag: String, val failure: Log.TerribleFailure, val system: Boolean val system: Boolean, ) /** The [Log.wtf] logs and return value of the block */ data class WtfBlockResult<T>(val logs: List<TerribleFailureLog>, val result: T) /** Assert that [loggingRunnable] makes a call to [Log.wtf] */ @JvmOverloads fun assertRunnableLogsWtf( message: String = "Expected Log.wtf to be called", allowMultiple: Boolean = false, loggingRunnable: Runnable, ): WtfBlockResult<Unit> = assertLogsWtf(message = message, allowMultiple = allowMultiple) { loggingRunnable.run() } /** Assert that [loggingRunnable] makes at least one call to [Log.wtf] */ @JvmOverloads fun assertRunnableLogsWtfs( message: String = "Expected Log.wtf to be called once or more", loggingRunnable: Runnable, ): WtfBlockResult<Unit> = assertRunnableLogsWtf(message, allowMultiple = true, loggingRunnable) Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java +2 −2 Original line number Diff line number Diff line Loading @@ -142,7 +142,7 @@ public class PluginInstanceTest extends SysuiTestCase { mPluginInstanceFactory.create( mContext, mAppInfo, wrongVersionTestPluginComponentName, TestPlugin.class, mPluginListener); LogAssertKt.assertLogsWtf(()-> { LogAssertKt.assertRunnableLogsWtf(()-> { mPluginInstance.onCreate(); }); assertTrue(mPluginInstance.hasError()); Loading Loading @@ -195,7 +195,7 @@ public class PluginInstanceTest extends SysuiTestCase { mPluginInstance.onCreate(); assertFalse(mPluginInstance.hasError()); LogAssertKt.assertLogsWtf(()-> { LogAssertKt.assertRunnableLogsWtf(()-> { Object result = mPluginInstance.getPlugin().methodThrowsError(); assertNotNull(result); // Wrapper function should return non-null; }); Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/util/wakelock/WakeLockTest.java +1 −1 Original line number Diff line number Diff line Loading @@ -93,6 +93,6 @@ public class WakeLockTest extends SysuiTestCase { @Test public void prodBuild_wakeLock_releaseWithoutAcquire_noThrow() { // shouldn't throw an exception on production builds LogAssertKt.assertLogsWtf(() -> mWakeLock.release(WHY)); LogAssertKt.assertRunnableLogsWtf(() -> mWakeLock.release(WHY)); } }
packages/SystemUI/tests/src/com/android/systemui/recents/LauncherProxyServiceTest.kt +2 −1 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ import com.android.systemui.dump.DumpManager import com.android.systemui.keyguard.KeyguardUnlockAnimationController import com.android.systemui.keyguard.WakefulnessLifecycle import com.android.systemui.keyguard.ui.view.InWindowLauncherUnlockAnimationManager import com.android.systemui.log.assertLogsWtf import com.android.systemui.model.sysUiState import com.android.systemui.navigationbar.NavigationBarController import com.android.systemui.navigationbar.NavigationModeController Loading Loading @@ -221,7 +222,7 @@ class LauncherProxyServiceTest : SysuiTestCase() { `when`(processWrapper.isSystemUser).thenReturn(false) `when`(userManager.isVisibleBackgroundUsersSupported()).thenReturn(false) val spyContext = spy(context) val ops = createLauncherProxyService(spyContext) val ops = assertLogsWtf { createLauncherProxyService(spyContext) }.result ops.startConnectionToCurrentUser() verify(spyContext, times(0)).bindServiceAsUser(any(), any(), anyInt(), any()) } Loading
packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java +10 −11 Original line number Diff line number Diff line Loading @@ -77,7 +77,6 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.plugga import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifStabilityManager; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable; import com.android.systemui.statusbar.notification.collection.notifcollection.CollectionReadyForBuildListener; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationTestHelper; import com.android.systemui.statusbar.notification.shared.NotificationBundleUi; import com.android.systemui.util.time.FakeSystemClock; Loading Loading @@ -1795,7 +1794,7 @@ public class ShadeListBuilderTest extends SysuiTestCase { invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS); // THEN an exception is NOT thrown directly, but a WTF IS logged. LogAssertKt.assertLogsWtfs(() -> { LogAssertKt.assertRunnableLogsWtfs(() -> { dispatchBuild(); runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2); }); Loading @@ -1818,7 +1817,7 @@ public class ShadeListBuilderTest extends SysuiTestCase { addNotif(0, PACKAGE_2); invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 1); LogAssertKt.assertLogsWtfs(() -> { LogAssertKt.assertRunnableLogsWtfs(() -> { Assert.assertThrows(IllegalStateException.class, () -> { dispatchBuild(); runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2); Loading @@ -1844,13 +1843,13 @@ public class ShadeListBuilderTest extends SysuiTestCase { addNotif(0, PACKAGE_2); invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS); LogAssertKt.assertLogsWtfs(() -> { LogAssertKt.assertRunnableLogsWtfs(() -> { dispatchBuild(); runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2); }); invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS); LogAssertKt.assertLogsWtfs(() -> { LogAssertKt.assertRunnableLogsWtfs(() -> { // Note: dispatchBuild itself triggers a non-reentrant pipeline run. dispatchBuild(); runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2); Loading @@ -1874,7 +1873,7 @@ public class ShadeListBuilderTest extends SysuiTestCase { addNotif(0, PACKAGE_1); invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS); LogAssertKt.assertLogsWtfs(() -> { LogAssertKt.assertRunnableLogsWtfs(() -> { dispatchBuild(); runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2); }); Loading @@ -1897,7 +1896,7 @@ public class ShadeListBuilderTest extends SysuiTestCase { addNotif(0, PACKAGE_1); invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 1); LogAssertKt.assertLogsWtfs(() -> { LogAssertKt.assertRunnableLogsWtfs(() -> { Assert.assertThrows(IllegalStateException.class, () -> { dispatchBuild(); runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2); Loading @@ -1922,7 +1921,7 @@ public class ShadeListBuilderTest extends SysuiTestCase { addNotif(0, PACKAGE_2); invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS); LogAssertKt.assertLogsWtfs(() -> { LogAssertKt.assertRunnableLogsWtfs(() -> { dispatchBuild(); runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2); }); Loading @@ -1945,7 +1944,7 @@ public class ShadeListBuilderTest extends SysuiTestCase { addNotif(0, PACKAGE_2); invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 1); LogAssertKt.assertLogsWtfs(() -> { LogAssertKt.assertRunnableLogsWtfs(() -> { Assert.assertThrows(IllegalStateException.class, () -> { dispatchBuild(); runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2); Loading @@ -1970,7 +1969,7 @@ public class ShadeListBuilderTest extends SysuiTestCase { addNotif(0, PACKAGE_2); invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS); LogAssertKt.assertLogsWtfs(() -> { LogAssertKt.assertRunnableLogsWtfs(() -> { dispatchBuild(); runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2); }); Loading @@ -1993,7 +1992,7 @@ public class ShadeListBuilderTest extends SysuiTestCase { addNotif(0, PACKAGE_2); invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 1); LogAssertKt.assertLogsWtfs(() -> { LogAssertKt.assertRunnableLogsWtfs(() -> { Assert.assertThrows(IllegalStateException.class, () -> { dispatchBuild(); runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2); Loading
packages/SystemUI/tests/utils/src/com/android/systemui/log/LogAssert.kt +64 −50 Original line number Diff line number Diff line Loading @@ -13,89 +13,103 @@ * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.log import android.util.Log import android.util.Log.TerribleFailureHandler import junit.framework.Assert import com.google.common.truth.Truth.assertWithMessage import java.util.concurrent.Callable /** Asserts that the given block does not make a call to Log.wtf */ fun assertDoesNotLogWtf( /** Asserts that [notLoggingBlock] does not make a call to [Log.wtf] */ fun <T> assertDoesNotLogWtf( message: String = "Expected Log.wtf not to be called", notLoggingBlock: () -> Unit, ) { notLoggingBlock: () -> T, ): T { var caught: TerribleFailureLog? = null val newHandler = TerribleFailureHandler { tag, failure, system -> caught = TerribleFailureLog(tag, failure, system) } val oldHandler = Log.setWtfHandler(newHandler) val result = try { notLoggingBlock() } finally { Log.setWtfHandler(oldHandler) } caught?.let { throw AssertionError("$message: $it", it.failure) } return result } fun assertDoesNotLogWtf( message: String = "Expected Log.wtf not to be called", notLoggingRunnable: Runnable, ) = assertDoesNotLogWtf(message = message) { notLoggingRunnable.run() } /** * Assert that the given block makes a call to Log.wtf * * @return the details of the log */ fun assertLogsWtf( /** Assert that [loggingBlock] makes a call to [Log.wtf] */ @JvmOverloads fun <T> assertLogsWtf( message: String = "Expected Log.wtf to be called", allowMultiple: Boolean = false, loggingBlock: () -> Unit, ): TerribleFailureLog { var caught: TerribleFailureLog? = null var count = 0 loggingBlock: () -> T, ): WtfBlockResult<T> { val caught = mutableListOf<TerribleFailureLog>() val newHandler = TerribleFailureHandler { tag, failure, system -> if (caught == null) { caught = TerribleFailureLog(tag, failure, system) } count++ caught.add(TerribleFailureLog(tag, failure, system)) } val oldHandler = Log.setWtfHandler(newHandler) val result = try { loggingBlock() } finally { Log.setWtfHandler(oldHandler) } Assert.assertNotNull(message, caught) if (!allowMultiple && count != 1) { Assert.fail("Unexpectedly caught Log.Wtf $count times; expected only 1. First: $caught") assertWithMessage(message).that(caught).isNotEmpty() if (!allowMultiple) { assertWithMessage("Unexpectedly caught Log.Wtf multiple times").that(caught).hasSize(1) } return caught!! return WtfBlockResult(caught, result) } /** Assert that [loggingCallable] makes a call to [Log.wtf] */ @JvmOverloads fun assertLogsWtf( fun <T> assertLogsWtf( message: String = "Expected Log.wtf to be called", allowMultiple: Boolean = false, loggingRunnable: Runnable, ): TerribleFailureLog = assertLogsWtf(message = message, allowMultiple = allowMultiple) { loggingRunnable.run() } loggingCallable: Callable<T>, ): WtfBlockResult<T> = assertLogsWtf(message = message, allowMultiple = allowMultiple, loggingCallable::call) fun assertLogsWtfs( /** Assert that [loggingBlock] makes at least one call to [Log.wtf] */ @JvmOverloads fun <T> assertLogsWtfs( message: String = "Expected Log.wtf to be called once or more", loggingBlock: () -> Unit, ): TerribleFailureLog = assertLogsWtf(message, allowMultiple = true, loggingBlock) loggingBlock: () -> T, ): WtfBlockResult<T> = assertLogsWtf(message, allowMultiple = true, loggingBlock) /** Assert that [loggingCallable] makes at least one call to [Log.wtf] */ @JvmOverloads fun assertLogsWtfs( fun <T> assertLogsWtfs( message: String = "Expected Log.wtf to be called once or more", loggingRunnable: Runnable, ): TerribleFailureLog = assertLogsWtfs(message) { loggingRunnable.run() } loggingCallable: Callable<T>, ): WtfBlockResult<T> = assertLogsWtf(message, allowMultiple = true, loggingCallable) /** The data passed to [TerribleFailureHandler.onTerribleFailure] */ data class TerribleFailureLog( val tag: String, val failure: Log.TerribleFailure, val system: Boolean val system: Boolean, ) /** The [Log.wtf] logs and return value of the block */ data class WtfBlockResult<T>(val logs: List<TerribleFailureLog>, val result: T) /** Assert that [loggingRunnable] makes a call to [Log.wtf] */ @JvmOverloads fun assertRunnableLogsWtf( message: String = "Expected Log.wtf to be called", allowMultiple: Boolean = false, loggingRunnable: Runnable, ): WtfBlockResult<Unit> = assertLogsWtf(message = message, allowMultiple = allowMultiple) { loggingRunnable.run() } /** Assert that [loggingRunnable] makes at least one call to [Log.wtf] */ @JvmOverloads fun assertRunnableLogsWtfs( message: String = "Expected Log.wtf to be called once or more", loggingRunnable: Runnable, ): WtfBlockResult<Unit> = assertRunnableLogsWtf(message, allowMultiple = true, loggingRunnable)