From 38e2055b3f4b751134a4716c6f346c80724700ad Mon Sep 17 00:00:00 2001
From: ialokim <ialokim@mailbox.org>
Date: Wed, 16 Nov 2022 12:49:11 +0100
Subject: [PATCH] separate automatedScreenshots from test in gradle tasks and
 directories

---
 briar-desktop/build.gradle.kts                |  22 +++
 .../briar/desktop/ScreenshotTest.kt           | 126 ++++++++++++++++++
 .../briarproject/briar/desktop/ui/BriarUi.kt  |  23 ++--
 .../desktop/viewmodel/ViewModelProvider.kt    |   2 +
 .../briar/desktop/BriarDesktopTestApp.kt      |   3 +
 .../briar/desktop/RunWithTemporaryAccount.kt  |   2 -
 .../briar/desktop/ScreenshotTest.kt           |  65 ---------
 7 files changed, 168 insertions(+), 75 deletions(-)
 create mode 100644 briar-desktop/src/automatedScreenshots/kotlin/org/briarproject/briar/desktop/ScreenshotTest.kt
 delete mode 100644 briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/ScreenshotTest.kt

diff --git a/briar-desktop/build.gradle.kts b/briar-desktop/build.gradle.kts
index de8841fed0..bf12f8ba11 100644
--- a/briar-desktop/build.gradle.kts
+++ b/briar-desktop/build.gradle.kts
@@ -139,6 +139,28 @@ tasks.test {
     useJUnit()
 }
 
+// see https://docs.gradle.org/current/userguide/java_testing.html#sec:configuring_java_integration_tests
+sourceSets.create("automatedScreenshots") {
+    kotlin.srcDir("$projectDir/src/automatedScreenshots/kotlin")
+    resources.srcDir("$projectDir/src/automatedScreenshots/resources")
+    compileClasspath += sourceSets.main.get().output + sourceSets.test.get().output
+    runtimeClasspath += sourceSets.main.get().output + sourceSets.test.get().output
+}
+
+configurations["automatedScreenshotsImplementation"].extendsFrom(configurations.testImplementation.get())
+configurations["automatedScreenshotsRuntimeOnly"].extendsFrom(configurations.testRuntimeOnly.get())
+
+task<Test>("automatedScreenshots") {
+    testClassesDirs = sourceSets["automatedScreenshots"].output.classesDirs
+    classpath = sourceSets["automatedScreenshots"].runtimeClasspath
+}
+
+// makes `internal` visible in "automatedScreenshot"
+// see https://kotlinlang.org/docs/gradle-configure-project.html#associate-compiler-tasks
+kotlin.target.compilations.named("automatedScreenshots") {
+    associateWith(kotlin.target.compilations.getByName("test"))
+}
+
 tasks.withType<KotlinCompile> {
     kotlinOptions.jvmTarget = "11"
     kotlinOptions.freeCompilerArgs += "-opt-in=kotlin.RequiresOptIn"
diff --git a/briar-desktop/src/automatedScreenshots/kotlin/org/briarproject/briar/desktop/ScreenshotTest.kt b/briar-desktop/src/automatedScreenshots/kotlin/org/briarproject/briar/desktop/ScreenshotTest.kt
new file mode 100644
index 0000000000..a37d91cba7
--- /dev/null
+++ b/briar-desktop/src/automatedScreenshots/kotlin/org/briarproject/briar/desktop/ScreenshotTest.kt
@@ -0,0 +1,126 @@
+/*
+ * Briar Desktop
+ * Copyright (C) 2021-2022 The Briar Project
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package org.briarproject.briar.desktop
+
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.ui.awt.ComposeWindow
+import androidx.compose.ui.test.ExperimentalTestApi
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.performClick
+import androidx.compose.ui.test.runDesktopComposeUiTest
+import androidx.compose.ui.window.FrameWindowScope
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.runBlocking
+import org.briarproject.bramble.BrambleCoreEagerSingletons
+import org.briarproject.bramble.api.contact.event.ContactAddedEvent
+import org.briarproject.bramble.api.plugin.LanTcpConstants
+import org.briarproject.bramble.api.plugin.TorConstants.DEFAULT_CONTROL_PORT
+import org.briarproject.bramble.api.plugin.TorConstants.DEFAULT_SOCKS_PORT
+import org.briarproject.briar.BriarCoreEagerSingletons
+import org.briarproject.briar.desktop.TestUtils.getDataDir
+import org.briarproject.briar.desktop.contact.ContactListViewModel
+import org.briarproject.briar.desktop.ui.LocalWindowFocusState
+import org.briarproject.briar.desktop.ui.LocalWindowScope
+import org.briarproject.briar.desktop.ui.WindowFocusState
+import org.jetbrains.annotations.NonNls
+import org.jetbrains.skia.Image
+import org.junit.Test
+import java.io.FileOutputStream
+
+@OptIn(ExperimentalTestApi::class)
+class ScreenshotTest {
+    @Test
+    fun makeScreenshot() = runDesktopComposeUiTest(700, 700) {
+        // TODO: unify with interactive tests
+        val dataDir = getDataDir()
+        val app =
+            DaggerBriarDesktopTestApp.builder().desktopCoreModule(
+                DesktopCoreModule(dataDir, DEFAULT_SOCKS_PORT, DEFAULT_CONTROL_PORT)
+            ).build()
+        // We need to load the eager singletons directly after making the
+        // dependency graphs
+        BrambleCoreEagerSingletons.Helper.injectEagerSingletons(app)
+        BriarCoreEagerSingletons.Helper.injectEagerSingletons(app)
+
+        windowScope = object : FrameWindowScope {
+            override val window: ComposeWindow get() = TODO()
+        }
+        windowFocusState = WindowFocusState().apply { focused = true }
+
+        setContent {
+            CompositionLocalProvider(
+                LocalWindowScope provides windowScope,
+                LocalWindowFocusState provides windowFocusState,
+            ) {
+                app.getBriarUi().content()
+            }
+        }
+
+        captureToImage().save("before-click.png")
+        onNodeWithTag("close_expiration").performClick()
+        captureToImage().save("after-click.png")
+
+        // TODO: unify with interactive tests
+        val lifecycleManager = app.getLifecycleManager()
+        val accountManager = app.getAccountManager()
+
+        @NonNls
+        val password = "verySecret123!"
+        accountManager.createAccount("alice", password)
+
+        val dbKey = accountManager.databaseKey ?: throw AssertionError()
+        lifecycleManager.startServices(dbKey)
+        lifecycleManager.waitForStartup()
+
+        runBlocking {
+            delay(1000)
+
+            captureToImage().save("after-login.png")
+
+            app.getDeterministicTestDataCreator().createTestData(5, 20, 50, 10, 20)
+            app.getContactManager().addPendingContact("briar://aatkjq4seoualafpwh4cfckdzr4vpr4slk3bbvpxklf7y7lv4ajw6", "Faythe")
+
+            app.getEventBus().addListener { e ->
+                if (e is ContactAddedEvent) {
+                    if (app.getContactManager().getContact(e.contactId).author.name in listOf("Bob", "Chuck")) // NON-NLS
+                        app.getIoExecutor().execute {
+                            app.getConnectionRegistry().registerIncomingConnection(e.contactId, LanTcpConstants.ID) {}
+                        }
+                }
+            }
+
+            delay(1000)
+
+            val viewModel = app.getViewModelProvider().get(ContactListViewModel::class)
+            viewModel.selectContact(viewModel.contactList.value[1])
+
+            delay(1000)
+
+            captureToImage().save("after-contacts.png")
+        }
+    }
+}
+
+private fun Image.save(file: String) {
+    encodeToData()?.bytes?.let { bytes ->
+        FileOutputStream(file).use { out ->
+            out.write(bytes)
+        }
+    }
+}
diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/BriarUi.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/BriarUi.kt
index 917d5f2559..c944a6f477 100644
--- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/BriarUi.kt
+++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/BriarUi.kt
@@ -142,12 +142,6 @@ constructor(
                 var lastNotificationPrivateMessage = 0L
                 var lastNotificationForum = 0L
 
-                val eventListener = EventListener { e ->
-                    when (e) {
-                        is LifecycleEvent ->
-                            if (e.lifecycleState == RUNNING) screenState = MAIN
-                    }
-                }
                 val focusListener = object : WindowFocusListener {
                     override fun windowGainedFocus(e: WindowEvent?) {
                         focusState.focused = true
@@ -194,13 +188,11 @@ constructor(
 
                 visualNotificationProvider.init()
                 soundNotificationProvider.init()
-                eventBus.addListener(eventListener)
                 window.addWindowFocusListener(focusListener)
                 messageCounter.addListener(messageCounterListener)
 
                 onDispose {
                     messageCounter.removeListener(messageCounterListener)
-                    eventBus.removeListener(eventListener)
                     window.removeWindowFocusListener(focusListener)
                     visualNotificationProvider.uninit()
                     soundNotificationProvider.uninit()
@@ -228,6 +220,21 @@ constructor(
     @OptIn(ExperimentalFoundationApi::class)
     @Composable
     override fun content() {
+        DisposableEffect(Unit) {
+            val eventListener = EventListener { e ->
+                when (e) {
+                    is LifecycleEvent -> {
+                        if (e.lifecycleState == RUNNING) screenState = MAIN
+                    }
+                }
+            }
+            eventBus.addListener(eventListener)
+
+            onDispose {
+                eventBus.removeListener(eventListener)
+            }
+        }
+
         CompositionLocalProvider(
             LocalViewModelProvider provides viewModelProvider,
             LocalConfiguration provides configuration,
diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/viewmodel/ViewModelProvider.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/viewmodel/ViewModelProvider.kt
index 5575954f91..7f77094ea8 100644
--- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/viewmodel/ViewModelProvider.kt
+++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/viewmodel/ViewModelProvider.kt
@@ -24,8 +24,10 @@ originally licensed under the Apache License, Version 2.0
 package org.briarproject.briar.desktop.viewmodel
 
 import javax.inject.Inject
+import javax.inject.Singleton
 import kotlin.reflect.KClass
 
+@Singleton
 class ViewModelProvider
 @Inject
 constructor(
diff --git a/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/BriarDesktopTestApp.kt b/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/BriarDesktopTestApp.kt
index 9557b64d13..f3888c693b 100644
--- a/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/BriarDesktopTestApp.kt
+++ b/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/BriarDesktopTestApp.kt
@@ -40,6 +40,7 @@ import org.briarproject.briar.api.test.TestDataCreator
 import org.briarproject.briar.desktop.testdata.DeterministicTestDataCreator
 import org.briarproject.briar.desktop.threading.BriarExecutors
 import org.briarproject.briar.desktop.ui.BriarUi
+import org.briarproject.briar.desktop.viewmodel.ViewModelProvider
 import java.util.concurrent.Executor
 import javax.inject.Singleton
 
@@ -87,4 +88,6 @@ internal interface BriarDesktopTestApp : BrambleCoreEagerSingletons, BriarCoreEa
     fun getForumManager(): ForumManager
 
     fun getForumSharingManager(): ForumSharingManager
+
+    fun getViewModelProvider(): ViewModelProvider
 }
diff --git a/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/RunWithTemporaryAccount.kt b/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/RunWithTemporaryAccount.kt
index 7b50b7493b..c39d64c9bf 100644
--- a/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/RunWithTemporaryAccount.kt
+++ b/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/RunWithTemporaryAccount.kt
@@ -21,7 +21,6 @@
 package org.briarproject.briar.desktop
 
 import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.window.application
 import mu.KotlinLogging
 import org.briarproject.bramble.BrambleCoreEagerSingletons
@@ -48,7 +47,6 @@ internal class RunWithTemporaryAccount(
         private val LOG = KotlinLogging.logger {}
     }
 
-    @OptIn(ExperimentalComposeUiApi::class)
     fun run() {
         LogUtils.setupLogging(ALL)
 
diff --git a/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/ScreenshotTest.kt b/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/ScreenshotTest.kt
deleted file mode 100644
index b24d4cb7fe..0000000000
--- a/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/ScreenshotTest.kt
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Briar Desktop
- * Copyright (C) 2021-2022 The Briar Project
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-package org.briarproject.briar.desktop
-
-import androidx.compose.ui.test.ExperimentalTestApi
-import androidx.compose.ui.test.onNodeWithTag
-import androidx.compose.ui.test.performClick
-import androidx.compose.ui.test.runDesktopComposeUiTest
-import org.briarproject.bramble.BrambleCoreEagerSingletons
-import org.briarproject.bramble.api.plugin.TorConstants.DEFAULT_CONTROL_PORT
-import org.briarproject.bramble.api.plugin.TorConstants.DEFAULT_SOCKS_PORT
-import org.briarproject.briar.BriarCoreEagerSingletons
-import org.briarproject.briar.desktop.TestUtils.getDataDir
-import org.jetbrains.skia.Image
-import org.junit.Test
-import java.io.FileOutputStream
-
-@OptIn(ExperimentalTestApi::class)
-class ScreenshotTest {
-    @Test
-    fun makeScreenshot() = runDesktopComposeUiTest(700, 500) {
-        val dataDir = getDataDir()
-        val app =
-            DaggerBriarDesktopTestApp.builder().desktopCoreModule(
-                DesktopCoreModule(dataDir, DEFAULT_SOCKS_PORT, DEFAULT_CONTROL_PORT)
-            ).build()
-        // We need to load the eager singletons directly after making the
-        // dependency graphs
-        BrambleCoreEagerSingletons.Helper.injectEagerSingletons(app)
-        BriarCoreEagerSingletons.Helper.injectEagerSingletons(app)
-
-        val ui = app.getBriarUi()
-
-        setContent {
-            ui.content()
-        }
-        captureToImage().save("before-click.png")
-        onNodeWithTag("close_expiration").performClick()
-        captureToImage().save("after-click.png")
-    }
-}
-
-private fun Image.save(file: String) {
-    encodeToData()?.bytes?.let { bytes ->
-        FileOutputStream(file).use { out ->
-            out.write(bytes)
-        }
-    }
-}
-- 
GitLab