Skip to content

Commit 675dd5e

Browse files
authored
πŸ”€ Merge pull request #410 from vinceglb/platformfile-serialization
✨ Add @serialization support to PlatformFile
2 parents 2264c14 + 77d8181 commit 675dd5e

File tree

21 files changed

+294
-41
lines changed

21 files changed

+294
-41
lines changed

β€Žfilekit-core/build.gradle.ktsβ€Ž

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget
44
plugins {
55
alias(libs.plugins.androidLibrary)
66
alias(libs.plugins.kotlinMultiplatform)
7+
alias(libs.plugins.kotlinSerialization)
78
alias(libs.plugins.vanniktech.mavenPublish)
89
}
910

@@ -55,6 +56,9 @@ kotlin {
5556

5657
// Kotlinx IO
5758
api(libs.kotlinx.io)
59+
60+
// Kotlinx Serialization
61+
implementation(libs.kotlinx.serialization.core)
5862
}
5963

6064
commonTest.dependencies {
@@ -69,6 +73,9 @@ kotlin {
6973
}
7074
}
7175
val nonWebTest by creating { dependsOn(commonTest.get()) }
76+
nonWebTest.dependencies {
77+
implementation(libs.kotlinx.serialization.json)
78+
}
7279

7380
val jvmAndNativeMain by creating { dependsOn(nonWebMain) }
7481

@@ -80,7 +87,12 @@ kotlin {
8087
implementation(libs.androidx.exifinterface)
8188
}
8289
}
83-
androidUnitTest.get().dependsOn(nonWebTest)
90+
androidUnitTest {
91+
dependsOn(nonWebTest)
92+
dependencies {
93+
implementation(libs.test.android.robolectric)
94+
}
95+
}
8496
jvmMain.get().dependsOn(jvmAndNativeMain)
8597
jvmTest.get().dependsOn(nonWebTest)
8698
nativeMain.get().dependsOn(jvmAndNativeMain)

β€Žfilekit-core/src/androidMain/kotlin/io/github/vinceglb/filekit/PlatformFile.android.ktβ€Ž

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,14 @@ import kotlinx.io.asSink
2121
import kotlinx.io.asSource
2222
import kotlinx.io.files.Path
2323
import kotlinx.io.files.SystemFileSystem
24+
import kotlinx.serialization.Serializable
2425
import java.io.File
2526
import java.nio.file.Files
2627
import java.nio.file.attribute.BasicFileAttributes
2728
import kotlin.time.ExperimentalTime
2829
import kotlin.time.Instant
2930

31+
@Serializable(with = PlatformFileSerializer::class)
3032
public actual data class PlatformFile(
3133
val androidFile: AndroidFile
3234
) {
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package io.github.vinceglb.filekit
2+
3+
import android.net.Uri
4+
import kotlinx.serialization.json.Json
5+
import org.junit.runner.RunWith
6+
import org.robolectric.RobolectricTestRunner
7+
import org.robolectric.annotation.Config
8+
import kotlin.test.Test
9+
import kotlin.test.assertEquals
10+
import kotlin.test.assertIs
11+
12+
@RunWith(RobolectricTestRunner::class)
13+
@Config(sdk = [36])
14+
class PlatformFileAndroidSerializationTest {
15+
private val json = Json { encodeDefaults = true }
16+
17+
@Test
18+
fun serializeAndDeserializeUriBackedPlatformFile() {
19+
val uri = Uri.parse("content://example.provider/document/12345")
20+
val platformFile = PlatformFile(uri)
21+
22+
val encoded = json.encodeToString(platformFile)
23+
val decoded = json.decodeFromString<PlatformFile>(encoded)
24+
25+
assertEquals(platformFile.path, decoded.path)
26+
assertEquals(uri.toString(), decoded.toString())
27+
assertIs<AndroidFile.UriWrapper>(value = decoded.androidFile)
28+
}
29+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package io.github.vinceglb.filekit
2+
3+
import io.github.vinceglb.filekit.mimeType.MimeType
4+
import org.junit.runner.RunWith
5+
import org.robolectric.RobolectricTestRunner
6+
import org.robolectric.annotation.Config
7+
import kotlin.test.Test
8+
import kotlin.test.assertEquals
9+
10+
@RunWith(RobolectricTestRunner::class)
11+
@Config(sdk = [36])
12+
class PlatformFileAndroidTest {
13+
private val resourceDirectory = FileKit.projectDir / "src/nonWebTest/resources"
14+
private val textFile = resourceDirectory / "hello.txt"
15+
private val imageFile = resourceDirectory / "compose-logo.png"
16+
private val emptyFile = resourceDirectory / "empty-file"
17+
private val notExistingFile = resourceDirectory / "not-existing-file.pdf"
18+
19+
@Test
20+
fun testPlatformMimeType() {
21+
assertEquals(
22+
expected = MimeType.parse("text/plain"),
23+
actual = textFile.mimeType()
24+
)
25+
assertEquals(
26+
expected = MimeType.parse("image/png"),
27+
actual = imageFile.mimeType()
28+
)
29+
assertEquals(
30+
expected = null,
31+
actual = emptyFile.mimeType()
32+
)
33+
assertEquals(
34+
expected = MimeType.parse("application/pdf"),
35+
actual = notExistingFile.mimeType()
36+
)
37+
assertEquals(
38+
expected = null,
39+
actual = resourceDirectory.mimeType()
40+
)
41+
}
42+
}

β€Žfilekit-core/src/appleMain/kotlin/io/github/vinceglb/filekit/PlatformFile.apple.ktβ€Ž

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import kotlinx.coroutines.IO
2323
import kotlinx.coroutines.withContext
2424
import kotlinx.io.files.Path
2525
import kotlinx.io.files.SystemFileSystem
26+
import kotlinx.serialization.Serializable
2627
import platform.CoreFoundation.CFRelease
2728
import platform.CoreFoundation.CFStringCreateWithCString
2829
import platform.CoreFoundation.CFStringGetCString
@@ -46,6 +47,7 @@ import platform.UniformTypeIdentifiers.UTType
4647
import kotlin.time.ExperimentalTime
4748
import kotlin.time.Instant
4849

50+
@Serializable(with = PlatformFileSerializer::class)
4951
public actual data class PlatformFile(
5052
val nsUrl: NSURL,
5153
) {
@@ -220,16 +222,6 @@ public actual suspend fun PlatformFile.bookmarkData(): BookmarkData = withContex
220222
}
221223
}
222224

223-
internal actual suspend fun PlatformFile.prepareDestinationForWrite(
224-
source: PlatformFile
225-
): PlatformFile = withScopedAccess {
226-
if (isDirectory()) {
227-
PlatformFile(toKotlinxIoPath() / source.name)
228-
} else {
229-
this
230-
}
231-
}
232-
233225
public actual fun PlatformFile.releaseBookmark() {}
234226

235227
@OptIn(ExperimentalForeignApi::class, BetaInteropApi::class)

β€Žfilekit-core/src/commonMain/kotlin/io/github/vinceglb/filekit/PlatformFile.ktβ€Ž

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package io.github.vinceglb.filekit
22

33
import io.github.vinceglb.filekit.mimeType.MimeType
4+
import kotlinx.serialization.Serializable
45

6+
@Serializable(with = PlatformFileSerializer::class)
57
public expect class PlatformFile {
68
override fun toString(): String
79
public companion object
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package io.github.vinceglb.filekit
2+
3+
import kotlinx.serialization.KSerializer
4+
import kotlinx.serialization.descriptors.SerialDescriptor
5+
import kotlinx.serialization.encoding.Decoder
6+
import kotlinx.serialization.encoding.Encoder
7+
8+
public expect object PlatformFileSerializer : KSerializer<PlatformFile> {
9+
override val descriptor: SerialDescriptor
10+
override fun serialize(encoder: Encoder, value: PlatformFile)
11+
override fun deserialize(decoder: Decoder): PlatformFile
12+
}

β€Žfilekit-core/src/jsMain/kotlin/io/github/vinceglb/filekit/PlatformFile.js.ktβ€Ž

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import io.github.vinceglb.filekit.exceptions.FileKitException
44
import io.github.vinceglb.filekit.mimeType.MimeType
55
import kotlinx.coroutines.Dispatchers
66
import kotlinx.coroutines.withContext
7+
import kotlinx.serialization.Serializable
78
import org.khronos.webgl.ArrayBuffer
89
import org.khronos.webgl.Uint8Array
910
import org.khronos.webgl.get
@@ -13,6 +14,7 @@ import kotlin.coroutines.resume
1314
import kotlin.coroutines.resumeWithException
1415
import kotlin.coroutines.suspendCoroutine
1516

17+
@Serializable(with = PlatformFileSerializer::class)
1618
public actual data class PlatformFile(
1719
val file: File,
1820
) {
@@ -70,4 +72,3 @@ public actual suspend fun PlatformFile.readBytes(): ByteArray = withContext(Disp
7072
public actual fun PlatformFile.mimeType(): MimeType? =
7173
takeIf { file.type.isNotBlank() }
7274
?.let { MimeType.parse(file.type) }
73-
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package io.github.vinceglb.filekit
2+
3+
import kotlinx.serialization.KSerializer
4+
import kotlinx.serialization.descriptors.PrimitiveKind
5+
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
6+
import kotlinx.serialization.descriptors.SerialDescriptor
7+
import kotlinx.serialization.encoding.Decoder
8+
import kotlinx.serialization.encoding.Encoder
9+
10+
private const val unsupportedMessage = "PlatformFile serialization is not supported on JS targets"
11+
12+
public actual object PlatformFileSerializer : KSerializer<PlatformFile> {
13+
actual override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor(
14+
serialName = "io.github.vinceglb.filekit.PlatformFile",
15+
kind = PrimitiveKind.STRING
16+
)
17+
18+
actual override fun deserialize(decoder: Decoder): PlatformFile {
19+
error(unsupportedMessage)
20+
}
21+
22+
actual override fun serialize(encoder: Encoder, value: PlatformFile) {
23+
error(unsupportedMessage)
24+
}
25+
}

β€Žfilekit-core/src/jsTest/kotlin/io/github/vinceglb/filekit/utils/CreateTestFile.js.ktβ€Ž

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package io.github.vinceglb.filekit.utils
22

33
import io.github.vinceglb.filekit.PlatformFile
44
import org.w3c.files.File
5+
import org.w3c.files.FilePropertyBag
56

67
actual fun createTestFile(
78
name: String,
@@ -11,6 +12,7 @@ actual fun createTestFile(
1112
val file = File(
1213
fileBits = bytes.toBitsArray(),
1314
fileName = name,
15+
options = FilePropertyBag(type = "text/plain"),
1416
)
1517
return PlatformFile(file)
1618
}

0 commit comments

Comments
Β (0)