@@ -2,18 +2,24 @@ package net.thunderbird.feature.account.avatar.data.datasource
22
33import assertk.assertThat
44import assertk.assertions.isEqualTo
5+ import assertk.assertions.isNotEqualTo
56import assertk.assertions.isNotNull
67import assertk.assertions.isNull
78import com.eygraber.uri.toKmpUri
89import kotlin.test.BeforeTest
910import kotlin.test.Test
11+ import kotlin.time.Duration.Companion.milliseconds
12+ import kotlin.time.ExperimentalTime
13+ import kotlin.time.Instant
1014import kotlinx.coroutines.test.runTest
1115import net.thunderbird.core.file.DirectoryProvider
16+ import net.thunderbird.core.testing.TestClock
1217import net.thunderbird.feature.account.AccountIdFactory
1318import net.thunderbird.feature.account.avatar.data.AvatarDataContract
1419import org.junit.Rule
1520import org.junit.rules.TemporaryFolder
1621
22+ @OptIn(ExperimentalTime ::class )
1723class LocalAvatarImageDataSourceTest {
1824
1925 @JvmField
@@ -22,37 +28,57 @@ class LocalAvatarImageDataSourceTest {
2228
2329 private lateinit var directoryProvider: DirectoryProvider
2430 private lateinit var fileManager: CapturingFileManager
31+ private lateinit var clock: TestClock
2532 private lateinit var testSubject: LocalAvatarImageDataSource
2633
2734 @BeforeTest
2835 fun setUp () {
2936 val appDir = folder.newFolder(" app" )
3037 directoryProvider = FakeDirectoryProvider (appDir.absolutePath.toKmpUri())
3138 fileManager = CapturingFileManager ()
32- testSubject = LocalAvatarImageDataSource (fileManager, directoryProvider)
39+ clock = TestClock (Instant .fromEpochMilliseconds(1_000 ))
40+ testSubject = LocalAvatarImageDataSource (fileManager, directoryProvider, clock)
3341 }
3442
3543 @Test
36- fun `update should copy image to expected path and return destination uri` () = runTest {
44+ fun `update should copy image to expected path and return versioned destination uri` () = runTest {
3745 // Arrange
3846 val accountId = AccountIdFactory .create()
3947 val source = " file:///external/picked/image.jpg" .toKmpUri()
4048 val expectedDir = directoryProvider.getFilesDir().buildUpon()
4149 .appendPath(AvatarDataContract .DataSource .LocalAvatarImage .DIRECTORY_NAME )
4250 .build()
4351 val expectedDest = expectedDir.buildUpon().appendPath(" $accountId .jpg" ).build()
52+ val expectedVersioned = expectedDest.buildUpon().appendQueryParameter(" v" , " 1000" ).build()
4453
4554 // Act
4655 val returned = testSubject.update(accountId, source)
4756
4857 // Assert
49- assertThat(returned).isEqualTo(expectedDest )
58+ assertThat(returned).isEqualTo(expectedVersioned )
5059 assertThat(fileManager.lastCreatedDir).isEqualTo(expectedDir)
5160 assertThat(fileManager.lastCopySource).isEqualTo(source)
5261 assertThat(fileManager.lastCopyDestination).isEqualTo(expectedDest)
5362 assertThat(fileManager.lastDeleted).isNull()
5463 }
5564
65+ @Test
66+ fun `successive updates should return different URIs` () = runTest {
67+ // Arrange
68+ val accountId = AccountIdFactory .create()
69+ val source = " file:///external/picked/image.jpg" .toKmpUri()
70+
71+ // Act
72+ val uri1 = testSubject.update(accountId, source)
73+ clock.advanceTimeBy(1 .milliseconds)
74+ val uri2 = testSubject.update(accountId, source)
75+
76+ // Assert
77+ assertThat(uri1).isNotEqualTo(uri2)
78+ // Base paths should be the same
79+ assertThat(uri1.buildUpon().clearQuery().build()).isEqualTo(uri2.buildUpon().clearQuery().build())
80+ }
81+
5682 @Test
5783 fun `delete should remove expected avatar path` () = runTest {
5884 // Arrange
0 commit comments