1package com.peachpasswords.shared23import kotlinx.coroutines.CoroutineScope4import kotlinx.coroutines.test.StandardTestDispatcher5import kotlinx.coroutines.test.advanceTimeBy6import kotlinx.coroutines.test.runCurrent7import kotlinx.coroutines.test.runTest8import org.junit.Assert.assertEquals9import org.junit.Assert.assertFalse10import org.junit.Assert.assertTrue11import org.junit.Test12131415161718@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)19class PeachClipboardTest {2021 @Test fun clears_after_delay_when_value_unchanged() = runTest {22 var clipboard: String? = "s3cret"23 PeachClipboard.scheduleClear(24 scope = CoroutineScope(StandardTestDispatcher(testScheduler)),25 expected = "s3cret",26 readCurrent = { clipboard },27 clear = { clipboard = "" },28 )29 advanceTimeBy(PeachClipboard.CLEAR_DELAY_MS - 1_000); runCurrent()30 assertEquals("not cleared before the window elapses", "s3cret", clipboard)31 advanceTimeBy(2_000); runCurrent()32 assertEquals("cleared once the 30s window elapses", "", clipboard)33 }3435 @Test fun does_not_clear_when_user_copied_something_else() = runTest {36 var clipboard: String? = "s3cret"37 var cleared = false38 PeachClipboard.scheduleClear(39 scope = CoroutineScope(StandardTestDispatcher(testScheduler)),40 expected = "s3cret",41 readCurrent = { clipboard },42 clear = { cleared = true },43 )44 clipboard = "user typed this after copying" 45 advanceTimeBy(PeachClipboard.CLEAR_DELAY_MS + 1_000); runCurrent()46 assertFalse("must never wipe what the user copied afterwards", cleared)47 assertEquals("user typed this after copying", clipboard)48 }4950 @Test fun clears_when_the_clipboard_cannot_be_read() = runTest {51 52 53 54 var cleared = false55 PeachClipboard.scheduleClear(56 scope = CoroutineScope(StandardTestDispatcher(testScheduler)),57 expected = "s3cret",58 readCurrent = { null },59 clear = { cleared = true },60 )61 advanceTimeBy(PeachClipboard.CLEAR_DELAY_MS + 1_000); runCurrent()62 assertTrue("a denied read must still clear our value", cleared)63 }6465 @Test fun superseded_copy_is_left_to_its_own_timer() = runTest {66 var cleared = false67 PeachClipboard.scheduleClear(68 scope = CoroutineScope(StandardTestDispatcher(testScheduler)),69 expected = "s3cret",70 readCurrent = { "newer peach copy" },71 clear = { cleared = true },72 superseded = { true },73 )74 advanceTimeBy(PeachClipboard.CLEAR_DELAY_MS + 1_000); runCurrent()75 assertFalse("an older timer must not fire after a newer copy", cleared)76 }7778 @Test fun thirty_second_default_matches_browser() {79 assertTrue(PeachClipboard.CLEAR_DELAY_MS == 30_000L)80 }8182 @Test fun copy_feedback_bus_pulses_monotonically() {83 val before = CopyFeedbackBus.pulses.value84 CopyFeedbackBus.pulse()85 CopyFeedbackBus.pulse()8687 assertEquals(before + 2, CopyFeedbackBus.pulses.value)88 }89}