ankidroid / Anki-Android

AnkiDroid: Anki flashcards on Android. Your secret trick to achieve superhuman information retention.
GNU General Public License v3.0
7.93k stars 2.16k forks source link

test: fail on unhandled exception #16281

Closed david-allison closed 2 weeks ago

david-allison commented 2 weeks ago

Purpose / Description

Previously, an unhandled exception would hang, now it fails

Fixes

Approach

Assert no unhandled exceptions are thrown

How Has This Been Tested?

https://github.com/ankidroid/Anki-Android/actions/runs/8859797884

WhiteboardDefaultForegroundColorTest > [1] > testDefaultForegroundColor[1] FAILED
    java.lang.IllegalStateException: unhandled exception
        at com.ichi2.testutils.FailOnUnhandledExceptionRule$apply$1.evaluate(FailOnUnhandledExceptionRule.kt:64)
        at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
        at org.robolectric.RobolectricTestRunner$HelperTestRunner$1.evaluate(RobolectricTestRunner.java:588)
        at org.robolectric.internal.SandboxTestRunner$2.lambda$evaluate$2(SandboxTestRunner.java:290)
        at org.robolectric.internal.bytecode.Sandbox.lambda$runOnMainThread$0(Sandbox.java:101)
        at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
        at java.base/java.lang.Thread.run(Thread.java:1583)

        Caused by:
        net.ankiweb.rsdroid.exceptions.BackendInvalidInputException$BackendCollectionAlreadyOpenException: CollectionAlreadyOpen
            at net.ankiweb.rsdroid.exceptions.BackendInvalidInputException$Companion.fromInvalidInputError(BackendInvalidInputException.kt:34)
            at net.ankiweb.rsdroid.BackendException$Companion.fromError(BackendException.kt:114)
            at net.ankiweb.rsdroid.BackendKt.unpackResult(Backend.kt:271)
            at net.ankiweb.rsdroid.BackendKt.access$unpackResult(Backend.kt:1)
            at net.ankiweb.rsdroid.Backend$runMethodRaw$1.invoke(Backend.kt:118)
            at net.ankiweb.rsdroid.Backend$runMethodRaw$1.invoke(Backend.kt:117)
            at net.ankiweb.rsdroid.Backend.withBackend(Backend.kt:131)
            at net.ankiweb.rsdroid.Backend.runMethodRaw(Backend.kt:117)
            at anki.backend.GeneratedBackend.openCollectionRaw(GeneratedBackend.kt:102)
            at anki.backend.GeneratedBackend.openCollection(GeneratedBackend.kt:109)
            at net.ankiweb.rsdroid.Backend.openCollection(Backend.kt:98)
            at net.ankiweb.rsdroid.Backend.openCollection(Backend.kt:57)
            at com.ichi2.libanki.Storage.openDB$AnkiDroid_playDebug(Storage.kt:52)
            at com.ichi2.libanki.Collection.reopen(Collection.kt:206)
            at com.ichi2.libanki.Collection.reopen$default(Collection.kt:203)
            at com.ichi2.libanki.Collection.<init>(Collection.kt:138)
            at com.ichi2.libanki.Storage.collection(Storage.kt:40)
            at com.ichi2.anki.CollectionManager.ensureOpenInner(CollectionManager.kt:230)
            at com.ichi2.anki.CollectionManager.access$ensureOpenInner(CollectionManager.kt:39)
            at com.ichi2.anki.CollectionManager$withCol$2.invoke(CollectionManager.kt:101)
            at com.ichi2.anki.CollectionManager$withCol$2.invoke(CollectionManager.kt:100)
            at com.ichi2.anki.CollectionManager$withQueue$2.invokeSuspend(CollectionManager.kt:86)
            at app//kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
            at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:104)
            at kotlinx.coroutines.EventLoop.processUnconfinedEvent(EventLoop.common.kt:65)
            at kotlinx.coroutines.internal.DispatchedContinuationKt.resumeCancellableWith(DispatchedContinuation.kt:[371](https://github.com/ankidroid/Anki-Android/actions/runs/8859797884/job/24330353482?pr=16281#step:8:373))
            at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable(Cancellable.kt:26)
            at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable$default(Cancellable.kt:21)
            at kotlinx.coroutines.CoroutineStart.invoke(CoroutineStart.kt:88)
            at kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt:123)
            at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch(Builders.common.kt:52)
            at kotlinx.coroutines.BuildersKt.launch(Unknown Source)
            at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch$default(Builders.common.kt:43)
            at kotlinx.coroutines.BuildersKt.launch$default(Unknown Source)
            at com.ichi2.anki.Reviewer.addFlags(Reviewer.kt:659)
            at com.ichi2.anki.Reviewer.onCreateOptionsMenu(Reviewer.kt:676)
            at android.app.Activity.$$robo$$android_app_Activity$onCreatePanelMenu(Activity.java:4343)
            at android.app.Activity.onCreatePanelMenu(Activity.java)
            at androidx.activity.ComponentActivity.onCreatePanelMenu(ComponentActivity.java:520)
            at androidx.appcompat.view.WindowCallbackWrapper.onCreatePanelMenu(WindowCallbackWrapper.java:94)
            at androidx.appcompat.app.AppCompatDelegateImpl$AppCompatWindowCallback.onCreatePanelMenu(AppCompatDelegateImpl.java:3442)
            at androidx.appcompat.app.ToolbarActionBar.populateOptionsMenu(ToolbarActionBar.java:458)
            at androidx.appcompat.app.ToolbarActionBar$1.run(ToolbarActionBar.java:58)
            at android.os.Handler.$$robo$$android_os_Handler$handleCallback(Handler.java:942)
            at android.os.Handler.handleCallback(Handler.java)
            at android.os.Handler.$$robo$$android_os_Handler$dispatchMessage(Handler.java:99)
            at android.os.Handler.dispatchMessage(Handler.java)
            at org.robolectric.shadows.ShadowPausedLooper$IdlingRunnable.doRun(ShadowPausedLooper.java:573)
            at org.robolectric.shadows.ShadowPausedLooper$ControlRunnable.run(ShadowPausedLooper.java:536)
            at org.robolectric.shadows.ShadowPausedLooper.executeOnLooper(ShadowPausedLooper.java:629)
            at org.robolectric.shadows.ShadowPausedLooper.idle(ShadowPausedLooper.java:104)
            at org.robolectric.shadows.ShadowPausedLooper.idleIfPaused(ShadowPausedLooper.java:177)
            at org.robolectric.android.controller.ActivityController.visible(ActivityController.java:232)
            at com.ichi2.anki.RobolectricTest$Companion.startActivityNormallyOpenCollectionWithIntent(RobolectricTest.kt:284)
            at com.ichi2.anki.RobolectricTest.startActivityNormallyOpenCollectionWithIntent(RobolectricTest.kt)
            at com.ichi2.anki.RobolectricTest.startActivityNormallyOpenCollectionWithIntent$AnkiDroid_playDebugUnitTest(RobolectricTest.kt:342)
            at com.ichi2.anki.WhiteboardDefaultForegroundColorTest.getForegroundColor(WhiteboardDefaultForegroundColorTest.kt:43)
            at com.ichi2.anki.WhiteboardDefaultForegroundColorTest.testDefaultForegroundColor(WhiteboardDefaultForegroundColorTest.kt:38)
TemplatePreviewerViewModelTest > getCurrentTabIndex returns the correct tab if the first cloze isn't 1 and ord isn't 0 FAILED
    kotlinx.coroutines.test.UncaughtExceptionsBeforeTest: There were uncaught exceptions before the test started. Please avoid this, as such exceptions are also reported in a platform-dependent manner so that they are not lost.
        at kotlinx.coroutines.test.TestScopeImpl.enter(TestScope.kt:239)
        at kotlinx.coroutines.test.TestBuildersKt__TestBuildersKt.runTest-8Mi8wO0(TestBuilders.kt:309)
        at kotlinx.coroutines.test.TestBuildersKt.runTest-8Mi8wO0(Unknown Source)
        at kotlinx.coroutines.test.TestBuildersKt__TestBuildersKt.runTest-8Mi8wO0(TestBuilders.kt:168)
        at kotlinx.coroutines.test.TestBuildersKt.runTest-8Mi8wO0(Unknown Source)
        at com.ichi2.testutils.TestClass.runTest(TestClass.kt:238)
        at com.ichi2.testutils.TestClass.runTest$default(TestClass.kt:227)
        at com.ichi2.anki.previewer.TemplatePreviewerViewModelTest.runClozeTest(TemplatePreviewerViewModelTest.kt:61)
        at com.ichi2.anki.previewer.TemplatePreviewerViewModelTest.getCurrentTabIndex returns the correct tab if the first cloze isn't 1 and ord isn't 0(TemplatePreviewerViewModelTest.kt:38)

Checklist

david-allison commented 2 weeks ago

Actually... we should do better with that stack trace

david-allison commented 2 weeks ago

ActivityStartupUnderBackupTest > [CardViewerActivity] > activityHandlesRestoreBackup[CardViewerActivity] FAILED
    java.lang.IllegalArgumentException: FailOnUnhandledExceptionRule must be applied after AnkiDroidApp.onCreate
        at com.ichi2.testutils.FailOnUnhandledExceptionRule$apply$1.evaluate(FailOnUnhandledExceptionRule.kt:45)
        at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
        at org.robolectric.RobolectricTestRunner$HelperTestRunner$1.evaluate(RobolectricTestRunner.java:588)
        at org.robolectric.internal.SandboxTestRunner$2.lambda$evaluate$2(SandboxTestRunner.java:290)
        at org.robolectric.internal.bytecode.Sandbox.lambda$runOnMainThread$0(Sandbox.java:101)
        at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
        at java.base/java.lang.Thread.run(Thread.java:1583)
david-allison commented 2 weeks ago

Much better!

``` WhiteboardDefaultForegroundColorTest > [1] > testDefaultForegroundColor[1] FAILED java.lang.IllegalStateException: unhandled exception at com.ichi2.testutils.FailOnUnhandledExceptionRule$apply$1.evaluate(FailOnUnhandledExceptionRule.kt:64) at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306) at org.robolectric.RobolectricTestRunner$HelperTestRunner$1.evaluate(RobolectricTestRunner.java:588) at org.robolectric.internal.SandboxTestRunner$2.lambda$evaluate$2(SandboxTestRunner.java:290) at org.robolectric.internal.bytecode.Sandbox.lambda$runOnMainThread$0(Sandbox.java:101) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642) at java.base/java.lang.Thread.run(Thread.java:1583) Caused by: net.ankiweb.rsdroid.exceptions.BackendInvalidInputException$BackendCollectionAlreadyOpenException: CollectionAlreadyOpen at net.ankiweb.rsdroid.exceptions.BackendInvalidInputException$Companion.fromInvalidInputError(BackendInvalidInputException.kt:34) at net.ankiweb.rsdroid.BackendException$Companion.fromError(BackendException.kt:114) at net.ankiweb.rsdroid.BackendKt.unpackResult(Backend.kt:271) at net.ankiweb.rsdroid.BackendKt.access$unpackResult(Backend.kt:1) at net.ankiweb.rsdroid.Backend$runMethodRaw$1.invoke(Backend.kt:118) at net.ankiweb.rsdroid.Backend$runMethodRaw$1.invoke(Backend.kt:117) at net.ankiweb.rsdroid.Backend.withBackend(Backend.kt:131) at net.ankiweb.rsdroid.Backend.runMethodRaw(Backend.kt:117) at anki.backend.GeneratedBackend.openCollectionRaw(GeneratedBackend.kt:102) at anki.backend.GeneratedBackend.openCollection(GeneratedBackend.kt:109) at net.ankiweb.rsdroid.Backend.openCollection(Backend.kt:98) at net.ankiweb.rsdroid.Backend.openCollection(Backend.kt:57) at com.ichi2.libanki.Storage.openDB$AnkiDroid_playDebug(Storage.kt:52) at com.ichi2.libanki.Collection.reopen(Collection.kt:206) at com.ichi2.libanki.Collection.reopen$default(Collection.kt:203) at com.ichi2.libanki.Collection.(Collection.kt:138) at com.ichi2.libanki.Storage.collection(Storage.kt:40) at com.ichi2.anki.CollectionManager.ensureOpenInner(CollectionManager.kt:230) at com.ichi2.anki.CollectionManager.access$ensureOpenInner(CollectionManager.kt:39) at com.ichi2.anki.CollectionManager$withCol$2.invoke(CollectionManager.kt:101) at com.ichi2.anki.CollectionManager$withCol$2.invoke(CollectionManager.kt:100) at com.ichi2.anki.CollectionManager$withQueue$2.invokeSuspend(CollectionManager.kt:86) at app//kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:104) at kotlinx.coroutines.EventLoop.processUnconfinedEvent(EventLoop.common.kt:65) at kotlinx.coroutines.internal.DispatchedContinuationKt.resumeCancellableWith(DispatchedContinuation.kt:[371](https://github.com/ankidroid/Anki-Android/actions/runs/8859797884/job/24330353482?pr=16281#step:8:373)) at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable(Cancellable.kt:26) at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable$default(Cancellable.kt:21) at kotlinx.coroutines.CoroutineStart.invoke(CoroutineStart.kt:88) at kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt:123) at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch(Builders.common.kt:52) at kotlinx.coroutines.BuildersKt.launch(Unknown Source) at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch$default(Builders.common.kt:43) at kotlinx.coroutines.BuildersKt.launch$default(Unknown Source) at com.ichi2.anki.Reviewer.addFlags(Reviewer.kt:659) at com.ichi2.anki.Reviewer.onCreateOptionsMenu(Reviewer.kt:676) at android.app.Activity.$$robo$$android_app_Activity$onCreatePanelMenu(Activity.java:4343) at android.app.Activity.onCreatePanelMenu(Activity.java) at androidx.activity.ComponentActivity.onCreatePanelMenu(ComponentActivity.java:520) at androidx.appcompat.view.WindowCallbackWrapper.onCreatePanelMenu(WindowCallbackWrapper.java:94) at androidx.appcompat.app.AppCompatDelegateImpl$AppCompatWindowCallback.onCreatePanelMenu(AppCompatDelegateImpl.java:3442) at androidx.appcompat.app.ToolbarActionBar.populateOptionsMenu(ToolbarActionBar.java:458) at androidx.appcompat.app.ToolbarActionBar$1.run(ToolbarActionBar.java:58) at android.os.Handler.$$robo$$android_os_Handler$handleCallback(Handler.java:942) at android.os.Handler.handleCallback(Handler.java) at android.os.Handler.$$robo$$android_os_Handler$dispatchMessage(Handler.java:99) at android.os.Handler.dispatchMessage(Handler.java) at org.robolectric.shadows.ShadowPausedLooper$IdlingRunnable.doRun(ShadowPausedLooper.java:573) at org.robolectric.shadows.ShadowPausedLooper$ControlRunnable.run(ShadowPausedLooper.java:536) at org.robolectric.shadows.ShadowPausedLooper.executeOnLooper(ShadowPausedLooper.java:629) at org.robolectric.shadows.ShadowPausedLooper.idle(ShadowPausedLooper.java:104) at org.robolectric.shadows.ShadowPausedLooper.idleIfPaused(ShadowPausedLooper.java:177) at org.robolectric.android.controller.ActivityController.visible(ActivityController.java:232) at com.ichi2.anki.RobolectricTest$Companion.startActivityNormallyOpenCollectionWithIntent(RobolectricTest.kt:284) at com.ichi2.anki.RobolectricTest.startActivityNormallyOpenCollectionWithIntent(RobolectricTest.kt) at com.ichi2.anki.RobolectricTest.startActivityNormallyOpenCollectionWithIntent$AnkiDroid_playDebugUnitTest(RobolectricTest.kt:342) at com.ichi2.anki.WhiteboardDefaultForegroundColorTest.getForegroundColor(WhiteboardDefaultForegroundColorTest.kt:43) at com.ichi2.anki.WhiteboardDefaultForegroundColorTest.testDefaultForegroundColor(WhiteboardDefaultForegroundColorTest.kt:38) ```