From 7edf0ff04a08da5ecfccb6c6bb3ebbfe19504171 Mon Sep 17 00:00:00 2001 From: Jake Wharton Date: Mon, 24 Feb 2025 09:01:28 -0500 Subject: [PATCH] Decouple test TerminalReader from TestTty (#731) --- .../mosaic/terminal/BaseTerminalParserTest.kt | 5 +- .../mosaic/terminal/TestTerminalReader.kt | 18 ++++++++ .../jakewharton/mosaic/terminal/TestTty.kt | 8 ++-- .../jakewharton/mosaic/terminal/TtyTest.kt | 7 ++- .../jakewharton/mosaic/terminal/TestTty.kt | 32 ++++++------- .../jakewharton/mosaic/terminal/TestTty.kt | 46 +++++++++---------- 6 files changed, 68 insertions(+), 48 deletions(-) create mode 100644 mosaic-terminal/src/commonTest/kotlin/com/jakewharton/mosaic/terminal/TestTerminalReader.kt diff --git a/mosaic-terminal/src/commonTest/kotlin/com/jakewharton/mosaic/terminal/BaseTerminalParserTest.kt b/mosaic-terminal/src/commonTest/kotlin/com/jakewharton/mosaic/terminal/BaseTerminalParserTest.kt index 3f1d71f47..b0cca7b14 100644 --- a/mosaic-terminal/src/commonTest/kotlin/com/jakewharton/mosaic/terminal/BaseTerminalParserTest.kt +++ b/mosaic-terminal/src/commonTest/kotlin/com/jakewharton/mosaic/terminal/BaseTerminalParserTest.kt @@ -11,8 +11,9 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.test.runTest abstract class BaseTerminalParserTest { - internal val testTty = TestTty() - internal val reader = testTty.terminalReader() + private val testTerminalReader = TestTerminalReader() + internal val testTty = testTerminalReader.testTty + internal val reader = testTerminalReader.terminalReader private val runLoop = GlobalScope.launch(Dispatchers.IO) { reader.runParseLoop() } diff --git a/mosaic-terminal/src/commonTest/kotlin/com/jakewharton/mosaic/terminal/TestTerminalReader.kt b/mosaic-terminal/src/commonTest/kotlin/com/jakewharton/mosaic/terminal/TestTerminalReader.kt new file mode 100644 index 000000000..b7a69e97e --- /dev/null +++ b/mosaic-terminal/src/commonTest/kotlin/com/jakewharton/mosaic/terminal/TestTerminalReader.kt @@ -0,0 +1,18 @@ +package com.jakewharton.mosaic.terminal + +import com.jakewharton.mosaic.terminal.event.Event +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.channels.Channel.Factory.UNLIMITED + +internal fun TestTerminalReader(): TestTerminalReader { + val events = Channel(UNLIMITED) + val platformEventHandler = PlatformEventHandler(events, emitDebugEvents = false) + val testTty = TestTty.create(platformEventHandler) + val reader = TerminalReader(testTty.tty, events, emitDebugEvents = false) + return TestTerminalReader(testTty, reader) +} + +internal class TestTerminalReader( + val testTty: TestTty, + val terminalReader: TerminalReader, +) diff --git a/mosaic-terminal/src/commonTest/kotlin/com/jakewharton/mosaic/terminal/TestTty.kt b/mosaic-terminal/src/commonTest/kotlin/com/jakewharton/mosaic/terminal/TestTty.kt index 937df8ba9..72ac5450b 100644 --- a/mosaic-terminal/src/commonTest/kotlin/com/jakewharton/mosaic/terminal/TestTty.kt +++ b/mosaic-terminal/src/commonTest/kotlin/com/jakewharton/mosaic/terminal/TestTty.kt @@ -1,11 +1,11 @@ package com.jakewharton.mosaic.terminal -internal expect fun TestTty(): TestTty - internal expect class TestTty : AutoCloseable { - val tty: Tty + companion object { + fun create(callback: Tty.Callback): TestTty + } - fun terminalReader(emitDebugEvents: Boolean = false): TerminalReader + val tty: Tty // TODO Take ByteString once it migrates to stdlib, // or if Sink/RawSink migrates expose that as a val. diff --git a/mosaic-terminal/src/commonTest/kotlin/com/jakewharton/mosaic/terminal/TtyTest.kt b/mosaic-terminal/src/commonTest/kotlin/com/jakewharton/mosaic/terminal/TtyTest.kt index efec572dd..d04d05a91 100644 --- a/mosaic-terminal/src/commonTest/kotlin/com/jakewharton/mosaic/terminal/TtyTest.kt +++ b/mosaic-terminal/src/commonTest/kotlin/com/jakewharton/mosaic/terminal/TtyTest.kt @@ -14,7 +14,12 @@ import kotlinx.coroutines.delay import kotlinx.coroutines.launch class TtyTest { - private val testTty = TestTty() + private val testTty = TestTty.create(object : Tty.Callback { + override fun onFocus(focused: Boolean) {} + override fun onKey() {} + override fun onMouse() {} + override fun onResize(columns: Int, rows: Int, width: Int, height: Int) {} + }) private val tty = testTty.tty @AfterTest fun after() { diff --git a/mosaic-terminal/src/jvmTest/kotlin/com/jakewharton/mosaic/terminal/TestTty.kt b/mosaic-terminal/src/jvmTest/kotlin/com/jakewharton/mosaic/terminal/TestTty.kt index 165db100b..741a92a22 100644 --- a/mosaic-terminal/src/jvmTest/kotlin/com/jakewharton/mosaic/terminal/TestTty.kt +++ b/mosaic-terminal/src/jvmTest/kotlin/com/jakewharton/mosaic/terminal/TestTty.kt @@ -8,28 +8,26 @@ import com.jakewharton.mosaic.terminal.event.Event import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.Channel.Factory.UNLIMITED -internal actual fun TestTty(): TestTty { - val events = Channel(UNLIMITED) - val callbackPtr = ttyCallbackInit(PlatformEventHandler(events, emitDebugEvents = false)) - if (callbackPtr != 0L) { - val testTtyPtr = testTtyInit(callbackPtr) - if (testTtyPtr != 0L) { - val ttyPtr = testTtyGetTty(testTtyPtr) - val tty = Tty(ttyPtr, callbackPtr) - return TestTty(testTtyPtr, events, tty) - } - ttyCallbackFree(callbackPtr) - } - throw OutOfMemoryError() -} - internal actual class TestTty( private var testTtyPtr: Long, private val events: Channel, actual val tty: Tty, ) : AutoCloseable { - actual fun terminalReader(emitDebugEvents: Boolean): TerminalReader { - return TerminalReader(tty, events, emitDebugEvents) + actual companion object { + actual fun create(callback: Tty.Callback): TestTty { + val events = Channel(UNLIMITED) + val callbackPtr = ttyCallbackInit(PlatformEventHandler(events, emitDebugEvents = false)) + if (callbackPtr != 0L) { + val testTtyPtr = testTtyInit(callbackPtr) + if (testTtyPtr != 0L) { + val ttyPtr = testTtyGetTty(testTtyPtr) + val tty = Tty(ttyPtr, callbackPtr) + return TestTty(testTtyPtr, events, tty) + } + ttyCallbackFree(callbackPtr) + } + throw OutOfMemoryError() + } } actual fun write(buffer: ByteArray) { diff --git a/mosaic-terminal/src/nativeTest/kotlin/com/jakewharton/mosaic/terminal/TestTty.kt b/mosaic-terminal/src/nativeTest/kotlin/com/jakewharton/mosaic/terminal/TestTty.kt index 4f3ed814f..f9a1940e2 100644 --- a/mosaic-terminal/src/nativeTest/kotlin/com/jakewharton/mosaic/terminal/TestTty.kt +++ b/mosaic-terminal/src/nativeTest/kotlin/com/jakewharton/mosaic/terminal/TestTty.kt @@ -12,35 +12,33 @@ import kotlinx.cinterop.usePinned import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.Channel.Factory.UNLIMITED -internal actual fun TestTty(): TestTty { - val events = Channel(UNLIMITED) - - val callback = PlatformEventHandler(events, emitDebugEvents = false) - val callbackRef = StableRef.create(callback) - val callbackPtr = callbackRef.toNativeAllocationIn(nativeHeap).ptr - - val testTtyPtr = testTty_init(callbackPtr).useContents { - testTty?.let { return@useContents it } - - nativeHeap.free(callbackPtr) - callbackRef.dispose() - - check(error == 0U) { "Unable to create test tty: $error" } - throw OutOfMemoryError() - } - - val ttyPtr = testTty_getTty(testTtyPtr)!! - val tty = Tty(ttyPtr, callbackPtr, callbackRef) - return TestTty(testTtyPtr, events, tty) -} - internal actual class TestTty( private var ptr: CPointer?, private val events: Channel, actual val tty: Tty, ) : AutoCloseable { - actual fun terminalReader(emitDebugEvents: Boolean): TerminalReader { - return TerminalReader(tty, events, emitDebugEvents) + actual companion object { + actual fun create(callback: Tty.Callback): TestTty { + val events = Channel(UNLIMITED) + + val callback = PlatformEventHandler(events, emitDebugEvents = false) + val callbackRef = StableRef.create(callback) + val callbackPtr = callbackRef.toNativeAllocationIn(nativeHeap).ptr + + val testTtyPtr = testTty_init(callbackPtr).useContents { + testTty?.let { return@useContents it } + + nativeHeap.free(callbackPtr) + callbackRef.dispose() + + check(error == 0U) { "Unable to create test tty: $error" } + throw OutOfMemoryError() + } + + val ttyPtr = testTty_getTty(testTtyPtr)!! + val tty = Tty(ttyPtr, callbackPtr, callbackRef) + return TestTty(testTtyPtr, events, tty) + } } actual fun write(buffer: ByteArray) {