diff --git a/.github/workflows/gradle-build.yaml b/.github/workflows/gradle-build.yaml index 21693f9..c1d1550 100644 --- a/.github/workflows/gradle-build.yaml +++ b/.github/workflows/gradle-build.yaml @@ -4,27 +4,47 @@ on: [push, pull_request] jobs: build: - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up JDK - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'microsoft' java-version: '17' - name: Cache Gradle packages - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: | ~/.gradle/caches ~/.gradle/wrapper key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} - restore-keys: | - ${{ runner.os }}-gradle- + restore-keys: ${{ runner.os }}-gradle- + - name: Cache Kotlin Native + uses: actions/cache@v4 + with: + path: ~/.konan + key: ${{ runner.os }}-konan-${{ hashFiles('**/*.gradle.kts') }} + restore-keys: ${{ runner.os }}-konan- - name: Build with Gradle - run: ./gradlew --no-daemon assemble check + run: | + if [ "$RUNNER_OS" == "Linux" ]; then + ./gradlew --no-daemon jvmJar jsBrowserDistribution linkReleaseExecutableLinuxX64 jvmTest jsTest linuxX64Test + elif [ "$RUNNER_OS" == "macOS" ]; then + ./gradlew --no-daemon linkReleaseExecutableMacosX64 macosX64Test + elif [ "$RUNNER_OS" == "Windows" ]; then + ./gradlew --no-daemon linkReleaseExecutableMingwX64 mingwX64Test + else + echo "Unknown OS: $RUNNER_OS" + exit 1 + fi + shell: bash - name: Publish snapshot + if: runner.os == 'Linux' env: OSSRH_DEPLOY_USERNAME: ${{ secrets.OSSRH_DEPLOY_USERNAME }} OSSRH_DEPLOY_PASSWORD: ${{ secrets.OSSRH_DEPLOY_PASSWORD }} @@ -32,8 +52,10 @@ jobs: PGP_KEY_ID: ${{ secrets.PGP_KEY_ID }} PGP_PASSPHRASE: ${{ secrets.PGP_PASSPHRASE }} run: ./publish-snapshot.sh - - name: Archive browser distribution zip - uses: actions/upload-artifact@v3 + - name: Archive distributed artifacts + uses: actions/upload-artifact@v4 with: - name: browser-distribution - path: build/zip/kotwords-browser-distribution-*.zip + name: kotwords-build-${{ runner.os }} + path: | + build/zip/kotwords-browser-distribution-*.zip + build/bin/**/releaseExecutable/kotwords.* diff --git a/build.gradle.kts b/build.gradle.kts index 5c9c80c..a0bb894 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,3 +1,5 @@ +import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi +import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpack plugins { @@ -28,6 +30,20 @@ kotlin { binaries.executable() } + mingwX64() + linuxX64() + macosX64() + + targets.all { + if (this is KotlinNativeTarget) { + binaries.executable { + entryPoint = "com.jeffpdavidson.kotwords.cli.main" + } + } + } + + applyDefaultHierarchyTemplate() + sourceSets { all { languageSettings { @@ -47,7 +63,8 @@ kotlin { implementation("com.github.ajalt.colormath:colormath:3.3.3") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3") - // TODO: Migrate to kotlinx-datetime if parsing/formatting support is added. + // TODO: Migrate to kotlinx-datetime when it can be done without breaking ksoup. + // Ensure any size hit to the JS bundle is acceptable. implementation("com.soywiz.korlibs.klock:klock:4.0.10") } } @@ -57,6 +74,7 @@ kotlin { implementation("org.jetbrains.kotlin:kotlin-test-annotations-common") implementation("org.jetbrains.kotlin:kotlin-test-common") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3") + implementation("io.github.pdvrieze.xmlutil:testutil:0.86.3") } languageSettings { @@ -102,24 +120,29 @@ kotlin { optIn("kotlinx.coroutines.ExperimentalCoroutinesApi") } } - } - targets.configureEach { - compilations.configureEach { - compilerOptions.configure { - freeCompilerArgs.add("-Xexpect-actual-classes") + val nativeMain by getting { + dependencies { + implementation("com.soywiz.korlibs.korio:korio:4.0.10") + implementation("com.fleeksoft.ksoup:ksoup:0.1.2") + implementation("net.thauvin.erik.urlencoder:urlencoder-lib:1.4.0") } } } + + @OptIn(ExperimentalKotlinGradlePluginApi::class) + compilerOptions { + freeCompilerArgs.add("-Xexpect-actual-classes") + } } tasks { - // Omit .web package from documentation + // Omit .web and .cli package from documentation dokkaHtml.configure { dokkaSourceSets { configureEach { perPackageOption { - matchingRegex.set("""com.jeffpdavidson\.kotwords\.web.*""") + matchingRegex.set("""com.jeffpdavidson\.kotwords\.(?:web|cli).*""") suppress.set(true) } } diff --git a/gradle.properties b/gradle.properties index 894492d..5292fdc 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1,2 @@ -org.gradle.jvmargs=-Xmx2000m \ No newline at end of file +org.gradle.jvmargs=-Xmx2000m +kotlin.native.ignoreDisabledTargets=true \ No newline at end of file diff --git a/src/commonMain/kotlin/com/jeffpdavidson/kotwords/formats/AcrossLite.kt b/src/commonMain/kotlin/com/jeffpdavidson/kotwords/formats/AcrossLite.kt index 39070fe..13411e4 100644 --- a/src/commonMain/kotlin/com/jeffpdavidson/kotwords/formats/AcrossLite.kt +++ b/src/commonMain/kotlin/com/jeffpdavidson/kotwords/formats/AcrossLite.kt @@ -130,6 +130,7 @@ class AcrossLite(private val binaryData: ByteArray) : DelegatingPuzzleable() { // Skip the null terminator. skip(1) } + "RTBL" -> { val data = readNullTerminatedString(Charset.CP_1252) data.split(';').filterNot { it.isEmpty() }.forEach { @@ -137,6 +138,7 @@ class AcrossLite(private val binaryData: ByteArray) : DelegatingPuzzleable() { rebusTable[parts[0].trim().toInt()] = parts[1] } } + "RUSR" -> { // Handle invalid/empty RUSR sections gracefully. if (sectionLength == 0.toShort()) { @@ -152,6 +154,7 @@ class AcrossLite(private val binaryData: ByteArray) : DelegatingPuzzleable() { } } } + "GEXT" -> { for (y in 0 until height) { for (x in 0 until width) { @@ -164,6 +167,7 @@ class AcrossLite(private val binaryData: ByteArray) : DelegatingPuzzleable() { // Skip the null terminator. skip(1) } + else -> { // Skip section + null terminator. skip(sectionLength + 1L) diff --git a/src/commonMain/kotlin/com/jeffpdavidson/kotwords/formats/Encodings.kt b/src/commonMain/kotlin/com/jeffpdavidson/kotwords/formats/Encodings.kt index 2a8d7cf..0835e2f 100644 --- a/src/commonMain/kotlin/com/jeffpdavidson/kotwords/formats/Encodings.kt +++ b/src/commonMain/kotlin/com/jeffpdavidson/kotwords/formats/Encodings.kt @@ -12,4 +12,55 @@ internal expect object Encodings { fun decodeHtmlEntities(string: String): String fun unescape(string: String): String +} + +/** Unicode values corresponding to bytes 0x80-0x9F in CP1252. */ +private val CP1252_DECODE_TABLE = listOf( + '\u20ac', '\u0081', '\u201a', '\u0192', '\u201e', '\u2026', '\u2020', '\u2021', + '\u02c6', '\u2030', '\u0160', '\u2039', '\u0152', '\u008d', '\u017d', '\u008f', + '\u0090', '\u2018', '\u2019', '\u201c', '\u201d', '\u2022', '\u2013', '\u2014', + '\u02dc', '\u2122', '\u0161', '\u203a', '\u0153', '\u009d', '\u017e', '\u0178', +) + +/** Map from supported CP1252 unicode values to their byte value in CP1252. */ +private val CP1252_ENCODE_TABLE = CP1252_DECODE_TABLE.withIndex().associate { it.value to it.index } + +internal fun Encodings.commonDecodeCp1252(bytes: ByteArray): String { + return bytes.map { byte -> + val intValue = byte.toInt() and 0xFF + if (intValue in 0x00..0x7F || intValue in 0xA0..0xFF) { + // ISO-8859-1 characters map directly. + intValue.toChar() + } else { + // Between 0x80 and 0x9F - look up the value in the table. + CP1252_DECODE_TABLE[intValue - 0x80] + } + }.joinToString("") +} + +internal fun Encodings.commonEncodeCp1252(string: String): ByteArray { + return string.map { ch -> + if (ch.code in 0x00..0x7F || ch.code in 0xA0..0xFF) { + // ISO-8859-1 characters map directly. + ch.code.toByte() + } else { + val cp1252Byte = CP1252_ENCODE_TABLE[ch] + if (cp1252Byte != null) { + // One of the supported CP1252 characters. + (0x80 + cp1252Byte).toByte() + } else { + // Unsupported value - use default '?' character. + '?'.code.toByte() + } + } + }.toByteArray() +} + +private val UNESCAPE_PATTERN = "%u([0-9A-Fa-f]{4})|%([0-9A-Fa-f]{2})".toRegex() + +internal fun Encodings.commonUnescape(string: String): String { + return UNESCAPE_PATTERN.replace(string) { result -> + val code = result.groupValues[1].ifEmpty { result.groupValues[2] } + code.toInt(16).toChar().toString() + } } \ No newline at end of file diff --git a/src/commonMain/kotlin/com/jeffpdavidson/kotwords/formats/Ipuz.kt b/src/commonMain/kotlin/com/jeffpdavidson/kotwords/formats/Ipuz.kt index d1681aa..c4064b2 100644 --- a/src/commonMain/kotlin/com/jeffpdavidson/kotwords/formats/Ipuz.kt +++ b/src/commonMain/kotlin/com/jeffpdavidson/kotwords/formats/Ipuz.kt @@ -53,6 +53,7 @@ class Ipuz(private val json: String) : Puzzleable() { is IpuzJson.StyleRef -> { ipuz.styles.getOrElse(style.style) { IpuzJson.StyleSpec() } } + is IpuzJson.StyleSpec -> style } val cellType = when { @@ -483,6 +484,7 @@ internal data class IpuzJson @OptIn(ExperimentalSerializationApi::class) constru put("number", element[0].jsonPrimitive) put("clue", element[1].jsonPrimitive) } + is JsonObject -> element } } diff --git a/src/commonMain/kotlin/com/jeffpdavidson/kotwords/formats/Jpz.kt b/src/commonMain/kotlin/com/jeffpdavidson/kotwords/formats/Jpz.kt index 47c8fa0..ea31a1b 100644 --- a/src/commonMain/kotlin/com/jeffpdavidson/kotwords/formats/Jpz.kt +++ b/src/commonMain/kotlin/com/jeffpdavidson/kotwords/formats/Jpz.kt @@ -9,7 +9,6 @@ import kotlinx.serialization.modules.SerializersModule import kotlinx.serialization.modules.polymorphic import kotlinx.serialization.modules.subclass import nl.adaptivity.xmlutil.XmlDeclMode -import nl.adaptivity.xmlutil.XmlException import nl.adaptivity.xmlutil.core.XmlVersion import nl.adaptivity.xmlutil.serialization.XML import nl.adaptivity.xmlutil.serialization.XmlElement diff --git a/src/commonMain/kotlin/com/jeffpdavidson/kotwords/formats/Pdf.kt b/src/commonMain/kotlin/com/jeffpdavidson/kotwords/formats/Pdf.kt index 5f136d1..a893c36 100644 --- a/src/commonMain/kotlin/com/jeffpdavidson/kotwords/formats/Pdf.kt +++ b/src/commonMain/kotlin/com/jeffpdavidson/kotwords/formats/Pdf.kt @@ -245,6 +245,7 @@ object Pdf { val backgroundColor = when { square.backgroundColor.isNotBlank() -> getAdjustedColor(RGB(square.backgroundColor), blackSquareLightnessAdjustment) + square.cellType == Puzzle.CellType.BLOCK && !puzzle.diagramless -> gridBlackColor else -> RGB("#ffffff") } @@ -492,6 +493,7 @@ object Pdf { ) } } + is TextNode -> { val currentFont = getFont(fontFamily, nodeState.boldTagLevel, nodeState.italicTagLevel) val currentScript = getScript(nodeState.subTagLevel, nodeState.supTagLevel) @@ -727,6 +729,7 @@ object Pdf { currentLinePosition += getTextWidth(element.text, currentFont, currentFontSize) } } + is RichTextElement.NewLine -> { val offset = (if (i == lastNewLineIndex) nextFontSize else fontSize) * LINE_SPACING if (render) { @@ -736,6 +739,7 @@ object Pdf { } positionY -= offset } + is RichTextElement.SetFormat -> { if (render) { val newFont = element.format.font diff --git a/src/commonMain/kotlin/com/jeffpdavidson/kotwords/formats/PuzzleMe.kt b/src/commonMain/kotlin/com/jeffpdavidson/kotwords/formats/PuzzleMe.kt index 3222b93..9bde797 100644 --- a/src/commonMain/kotlin/com/jeffpdavidson/kotwords/formats/PuzzleMe.kt +++ b/src/commonMain/kotlin/com/jeffpdavidson/kotwords/formats/PuzzleMe.kt @@ -37,6 +37,7 @@ class PuzzleMe(val json: String) : DelegatingPuzzleable() { data.cellInfos.find { it.isCircled } != null -> { cellInfoMap.filterValues { it.isCircled }.keys } + else -> { data.backgroundShapeBoxes.filter { it.size == 2 }.map { it[0] to it[1] } } diff --git a/src/commonMain/kotlin/com/jeffpdavidson/kotwords/formats/json/xwordinfo/XWordInfoAcrosticJson.kt b/src/commonMain/kotlin/com/jeffpdavidson/kotwords/formats/json/xwordinfo/XWordInfoAcrosticJson.kt index 26ccebc..02686db 100644 --- a/src/commonMain/kotlin/com/jeffpdavidson/kotwords/formats/json/xwordinfo/XWordInfoAcrosticJson.kt +++ b/src/commonMain/kotlin/com/jeffpdavidson/kotwords/formats/json/xwordinfo/XWordInfoAcrosticJson.kt @@ -1,6 +1,5 @@ package com.jeffpdavidson.kotwords.formats.json.xwordinfo -import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable internal object XWordInfoAcrosticJson { diff --git a/src/commonMain/kotlin/com/jeffpdavidson/kotwords/model/Acrostic.kt b/src/commonMain/kotlin/com/jeffpdavidson/kotwords/model/Acrostic.kt index 2d48f7c..f1a8860 100644 --- a/src/commonMain/kotlin/com/jeffpdavidson/kotwords/model/Acrostic.kt +++ b/src/commonMain/kotlin/com/jeffpdavidson/kotwords/model/Acrostic.kt @@ -88,6 +88,7 @@ data class Acrostic( quoteWord.add(Puzzle.Coordinate(x = x, y = y)) cell } + ' ' -> Puzzle.Cell(cellType = Puzzle.CellType.BLOCK) else -> { // Replace hyphen with en-dash for aesthetics. @@ -250,6 +251,7 @@ data class Acrostic( in 'A'..'Z' -> { solutionWords.add(ch to wordIndex) } + ' ' -> wordIndex++ } } diff --git a/src/commonMain/kotlin/com/jeffpdavidson/kotwords/model/HeartsAndArrows.kt b/src/commonMain/kotlin/com/jeffpdavidson/kotwords/model/HeartsAndArrows.kt index f9142c7..fbb0b7e 100644 --- a/src/commonMain/kotlin/com/jeffpdavidson/kotwords/model/HeartsAndArrows.kt +++ b/src/commonMain/kotlin/com/jeffpdavidson/kotwords/model/HeartsAndArrows.kt @@ -2,8 +2,6 @@ package com.jeffpdavidson.kotwords.model import com.jeffpdavidson.kotwords.formats.Puzzleable import kotlinx.serialization.Serializable -import kotlin.math.floor -import kotlin.math.roundToInt @Serializable data class HeartsAndArrows( diff --git a/src/commonMain/kotlin/com/jeffpdavidson/kotwords/model/RowsGarden.kt b/src/commonMain/kotlin/com/jeffpdavidson/kotwords/model/RowsGarden.kt index 94a0a1b..d6b503c 100644 --- a/src/commonMain/kotlin/com/jeffpdavidson/kotwords/model/RowsGarden.kt +++ b/src/commonMain/kotlin/com/jeffpdavidson/kotwords/model/RowsGarden.kt @@ -51,9 +51,11 @@ data class RowsGarden( } letters.chunked(3).joinToString(separator = "...", prefix = "...", postfix = "...") } + validWidthLong -> { letters.chunked(3).joinToString(separator = "...") } + else -> { throw IllegalArgumentException("Outer row length must be $validWidthShort or $validWidthLong") } diff --git a/src/commonMain/kotlin/com/jeffpdavidson/kotwords/model/SpellWeaving.kt b/src/commonMain/kotlin/com/jeffpdavidson/kotwords/model/SpellWeaving.kt index 0db77ed..f45edb9 100644 --- a/src/commonMain/kotlin/com/jeffpdavidson/kotwords/model/SpellWeaving.kt +++ b/src/commonMain/kotlin/com/jeffpdavidson/kotwords/model/SpellWeaving.kt @@ -112,18 +112,21 @@ data class SpellWeaving( } return position.copy(x = position.x + 1, direction = Direction.RIGHT) } + Direction.DOWN -> { if (isPointInGrid(position.x, position.y + 1, middleRowLength)) { return position.copy(y = position.y + 1) } return position.copy(x = position.x - 1, direction = Direction.LEFT) } + Direction.RIGHT -> { if (isPointInGrid(position.x + 1, position.y, middleRowLength)) { return position.copy(x = position.x + 1) } return position.copy(y = position.y + 1, direction = Direction.DOWN) } + Direction.LEFT -> { if (isPointInGrid(position.x - 1, position.y, middleRowLength)) { return position.copy(x = position.x - 1) diff --git a/src/commonTest/kotlin/com/jeffpdavidson/kotwords/TestRunner.kt b/src/commonTest/kotlin/com/jeffpdavidson/kotwords/TestRunner.kt index ad45f46..5682aaf 100644 --- a/src/commonTest/kotlin/com/jeffpdavidson/kotwords/TestRunner.kt +++ b/src/commonTest/kotlin/com/jeffpdavidson/kotwords/TestRunner.kt @@ -6,4 +6,8 @@ import kotlin.reflect.KClass expect suspend fun readBinaryResource(clazz: KClass, resourceName: String): ByteArray /** Read the given resource as a String. */ -expect suspend fun readStringResource(clazz: KClass, resourceName: String): String \ No newline at end of file +expect suspend fun readStringResource(clazz: KClass, resourceName: String): String + +/** Annotation to skip a test for native targets. */ +@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) +expect annotation class IgnoreNative() \ No newline at end of file diff --git a/src/commonTest/kotlin/com/jeffpdavidson/kotwords/formats/NewYorkTimesTest.kt b/src/commonTest/kotlin/com/jeffpdavidson/kotwords/formats/NewYorkTimesTest.kt index f413ba8..e8ffb7a 100644 --- a/src/commonTest/kotlin/com/jeffpdavidson/kotwords/formats/NewYorkTimesTest.kt +++ b/src/commonTest/kotlin/com/jeffpdavidson/kotwords/formats/NewYorkTimesTest.kt @@ -1,8 +1,10 @@ package com.jeffpdavidson.kotwords.formats +import com.jeffpdavidson.kotwords.IgnoreNative import com.jeffpdavidson.kotwords.model.assertPuzzleEquals import com.jeffpdavidson.kotwords.readBinaryResource import com.jeffpdavidson.kotwords.readStringResource +import io.github.pdvrieze.xmlutil.testutil.assertXmlEquals import kotlinx.coroutines.test.runTest import kotlin.test.Test import kotlin.test.assertEquals @@ -38,21 +40,21 @@ class NewYorkTimesTest { fun toPuzzle() = runTest { val json = readStringResource(NewYorkTimesTest::class, "nyt/test.json") val puzzle = NewYorkTimes.fromPluribusJson(json).asPuzzle() - assertEquals(readStringResource(NewYorkTimesTest::class, "nyt/test.jpz"), puzzle.asJpz().toXmlString()) + assertXmlEquals(readStringResource(NewYorkTimesTest::class, "nyt/test.jpz"), puzzle.asJpz().toXmlString()) } @Test fun toPuzzle_api() = runTest { val json = readStringResource(NewYorkTimesTest::class, "nyt/test-api.json") val puzzle = NewYorkTimes.fromApiJson(json, "daily").asPuzzle() - assertEquals(readStringResource(NewYorkTimesTest::class, "nyt/test.jpz"), puzzle.asJpz().toXmlString()) + assertXmlEquals(readStringResource(NewYorkTimesTest::class, "nyt/test.jpz"), puzzle.asJpz().toXmlString()) } @Test fun toPuzzle_bgImage_noFetcher() = runTest { val json = readStringResource(NewYorkTimesTest::class, "nyt/test-bgimage.json") val puzzle = NewYorkTimes.fromPluribusJson(json).asPuzzle() - assertEquals( + assertXmlEquals( readStringResource(NewYorkTimesTest::class, "nyt/test-bgimage-nofetcher.jpz"), puzzle.asJpz().toXmlString() ) @@ -62,13 +64,14 @@ class NewYorkTimesTest { fun toPuzzle_bgImage_api_noFetcher() = runTest { val json = readStringResource(NewYorkTimesTest::class, "nyt/test-bgimage-api.json") val puzzle = NewYorkTimes.fromApiJson(json, "daily").asPuzzle() - assertEquals( + assertXmlEquals( readStringResource(NewYorkTimesTest::class, "nyt/test-bgimage-nofetcher.jpz"), puzzle.asJpz().toXmlString() ) } @Test + @IgnoreNative // Depends on image support fun toPuzzle_bgImage_api() = runTest { val puzzle = NewYorkTimes.fromApiJson( readStringResource(NewYorkTimesTest::class, "nyt/test-bgimage-api.json"), diff --git a/src/commonTest/kotlin/com/jeffpdavidson/kotwords/formats/PdfTest.kt b/src/commonTest/kotlin/com/jeffpdavidson/kotwords/formats/PdfTest.kt index 3e29f24..ecc1f40 100644 --- a/src/commonTest/kotlin/com/jeffpdavidson/kotwords/formats/PdfTest.kt +++ b/src/commonTest/kotlin/com/jeffpdavidson/kotwords/formats/PdfTest.kt @@ -1,11 +1,13 @@ package com.jeffpdavidson.kotwords.formats +import com.jeffpdavidson.kotwords.IgnoreNative import com.jeffpdavidson.kotwords.formats.Pdf.splitTextToLines import com.jeffpdavidson.kotwords.readBinaryResource import kotlinx.coroutines.test.runTest import kotlin.test.Test import kotlin.test.assertEquals +@IgnoreNative // Depends on PDF support class PdfTest { @Test fun asPdf() = runTest { diff --git a/src/commonTest/kotlin/com/jeffpdavidson/kotwords/formats/PuzzleMeTest.kt b/src/commonTest/kotlin/com/jeffpdavidson/kotwords/formats/PuzzleMeTest.kt index 61bd1d0..0ae6913 100644 --- a/src/commonTest/kotlin/com/jeffpdavidson/kotwords/formats/PuzzleMeTest.kt +++ b/src/commonTest/kotlin/com/jeffpdavidson/kotwords/formats/PuzzleMeTest.kt @@ -1,5 +1,6 @@ package com.jeffpdavidson.kotwords.formats +import com.jeffpdavidson.kotwords.IgnoreNative import com.jeffpdavidson.kotwords.model.assertPuzzleEquals import com.jeffpdavidson.kotwords.readBinaryResource import com.jeffpdavidson.kotwords.readStringResource @@ -135,6 +136,7 @@ class PuzzleMeTest { } @Test + @IgnoreNative // Depends on image support fun toPuzzle_bgImage() = runTest { val puzzleMe = PuzzleMe(readStringResource(PuzzleMeTest::class, "puzzleme/test-bgimage.json")) assertPuzzleEquals( diff --git a/src/commonTest/kotlin/com/jeffpdavidson/kotwords/formats/RowsGardenTest.kt b/src/commonTest/kotlin/com/jeffpdavidson/kotwords/formats/RowsGardenTest.kt index f997d6a..ef5043e 100644 --- a/src/commonTest/kotlin/com/jeffpdavidson/kotwords/formats/RowsGardenTest.kt +++ b/src/commonTest/kotlin/com/jeffpdavidson/kotwords/formats/RowsGardenTest.kt @@ -2,9 +2,9 @@ package com.jeffpdavidson.kotwords.formats import com.jeffpdavidson.kotwords.readBinaryResource import com.jeffpdavidson.kotwords.readStringResource +import io.github.pdvrieze.xmlutil.testutil.assertXmlEquals import kotlinx.coroutines.test.runTest import kotlin.test.Test -import kotlin.test.assertEquals class RowsGardenTest { @@ -19,7 +19,7 @@ class RowsGardenTest { ).asPuzzle() val expected = readStringResource(RowsGardenTest::class, "rows-garden/rows-garden.jpz") - assertEquals( + assertXmlEquals( expected, puzzle.asJpz( appletSettings = CrosswordCompilerApplet.AppletSettings( cursorColor = "#00b100", @@ -42,7 +42,7 @@ class RowsGardenTest { ).asPuzzle() val expected = readStringResource(RowsGardenTest::class, "rows-garden/rows-garden-mini.jpz") - assertEquals( + assertXmlEquals( expected, puzzle.asJpz( appletSettings = CrosswordCompilerApplet.AppletSettings( cursorColor = "#00b100", diff --git a/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/AcrosticTest.kt b/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/AcrosticTest.kt index 7f6681a..3aeb36e 100644 --- a/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/AcrosticTest.kt +++ b/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/AcrosticTest.kt @@ -2,6 +2,7 @@ package com.jeffpdavidson.kotwords.model import com.jeffpdavidson.kotwords.formats.CrosswordCompilerApplet import com.jeffpdavidson.kotwords.readStringResource +import io.github.pdvrieze.xmlutil.testutil.assertXmlEquals import kotlinx.coroutines.test.runTest import kotlin.test.Test import kotlin.test.assertEquals @@ -10,7 +11,7 @@ import kotlin.test.fail class AcrosticTest { @Test fun asJpz() = runTest { - assertEquals( + assertXmlEquals( readStringResource(AcrosticTest::class, "acrostic/acrostic.jpz"), acrostic.asPuzzle().asJpz( appletSettings = CrosswordCompilerApplet.AppletSettings( @@ -24,7 +25,7 @@ class AcrosticTest { @Test fun asJpz_withAttribution() = runTest { - assertEquals( + assertXmlEquals( readStringResource(AcrosticTest::class, "acrostic/acrostic-attribution.jpz"), acrostic.copy(includeAttribution = true).asPuzzle().asJpz( appletSettings = CrosswordCompilerApplet.AppletSettings( diff --git a/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/AroundTheBendTest.kt b/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/AroundTheBendTest.kt index a43fdb2..9f4c242 100644 --- a/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/AroundTheBendTest.kt +++ b/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/AroundTheBendTest.kt @@ -2,9 +2,9 @@ package com.jeffpdavidson.kotwords.model import com.jeffpdavidson.kotwords.formats.CrosswordCompilerApplet import com.jeffpdavidson.kotwords.readStringResource +import io.github.pdvrieze.xmlutil.testutil.assertXmlEquals import kotlinx.coroutines.test.runTest import kotlin.test.Test -import kotlin.test.assertEquals class AroundTheBendTest { @Test @@ -30,7 +30,7 @@ class AroundTheBendTest { val puzzle = aroundTheBend.asPuzzle() val expected = readStringResource(AroundTheBendTest::class, "around-the-bend/around-the-bend.jpz") - assertEquals( + assertXmlEquals( expected, puzzle.asJpz( appletSettings = CrosswordCompilerApplet.AppletSettings( cursorColor = "#00b100", diff --git a/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/CodedTest.kt b/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/CodedTest.kt index 1e903a2..77dcabe 100644 --- a/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/CodedTest.kt +++ b/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/CodedTest.kt @@ -1,9 +1,9 @@ package com.jeffpdavidson.kotwords.model import com.jeffpdavidson.kotwords.readStringResource +import io.github.pdvrieze.xmlutil.testutil.assertXmlEquals import kotlinx.coroutines.test.runTest import kotlin.test.Test -import kotlin.test.assertEquals class CodedTest { @Test @@ -30,6 +30,6 @@ class CodedTest { ) val expected = readStringResource(CodedTest::class, "coded/coded.jpz") - assertEquals(expected, coded.asPuzzle().asJpz().toXmlString()) + assertXmlEquals(expected, coded.asPuzzle().asJpz().toXmlString()) } } \ No newline at end of file diff --git a/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/CrosswordTest.kt b/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/CrosswordTest.kt index 947a660..eaddd35 100644 --- a/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/CrosswordTest.kt +++ b/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/CrosswordTest.kt @@ -3,6 +3,7 @@ package com.jeffpdavidson.kotwords.model import com.jeffpdavidson.kotwords.formats.JpzFile import com.jeffpdavidson.kotwords.readBinaryResource import com.jeffpdavidson.kotwords.readStringResource +import io.github.pdvrieze.xmlutil.testutil.assertXmlEquals import kotlinx.coroutines.test.runTest import kotlin.test.Test import kotlin.test.assertEquals @@ -136,7 +137,7 @@ class CrosswordTest { hasHtmlClues = true, ) - assertEquals( + assertXmlEquals( readStringResource(CrosswordTest::class, "jpz/test-barred.jpz"), crossword.asPuzzle().asJpz().toXmlString(), ) diff --git a/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/CrosswordleTest.kt b/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/CrosswordleTest.kt index 2ed9826..e4faeb1 100644 --- a/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/CrosswordleTest.kt +++ b/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/CrosswordleTest.kt @@ -1,9 +1,9 @@ package com.jeffpdavidson.kotwords.model import com.jeffpdavidson.kotwords.readStringResource +import io.github.pdvrieze.xmlutil.testutil.assertXmlEquals import kotlinx.coroutines.test.runTest import kotlin.test.Test -import kotlin.test.assertEquals class CrosswordleTest { @Test @@ -39,6 +39,6 @@ class CrosswordleTest { val puzzle = crosswordle.asPuzzle() val expected = readStringResource(CrosswordleTest::class, "crosswordle.jpz") - assertEquals(expected, puzzle.asJpz().toXmlString()) + assertXmlEquals(expected, puzzle.asJpz().toXmlString()) } } \ No newline at end of file diff --git a/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/EightTracksTest.kt b/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/EightTracksTest.kt index 698cdd7..bbdde70 100644 --- a/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/EightTracksTest.kt +++ b/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/EightTracksTest.kt @@ -2,9 +2,9 @@ package com.jeffpdavidson.kotwords.model import com.jeffpdavidson.kotwords.formats.CrosswordCompilerApplet import com.jeffpdavidson.kotwords.readStringResource +import io.github.pdvrieze.xmlutil.testutil.assertXmlEquals import kotlinx.coroutines.test.runTest import kotlin.test.Test -import kotlin.test.assertEquals class EightTracksTest { @Test @@ -25,7 +25,7 @@ class EightTracksTest { val puzzle = eightTracks.asPuzzle() val expected = readStringResource(EightTracks::class, "eight-tracks/annotations.jpz") - assertEquals( + assertXmlEquals( expected, puzzle.asJpz( appletSettings = CrosswordCompilerApplet.AppletSettings( cursorColor = "#00b100", @@ -54,7 +54,7 @@ class EightTracksTest { val puzzle = eightTracks.asPuzzle() val expected = readStringResource(EightTracks::class, "eight-tracks/no-annotations.jpz") - assertEquals( + assertXmlEquals( expected, puzzle.asJpz( appletSettings = CrosswordCompilerApplet.AppletSettings( cursorColor = "#00b100", diff --git a/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/HeartsAndArrowsTest.kt b/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/HeartsAndArrowsTest.kt index 384902f..facd5ef 100644 --- a/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/HeartsAndArrowsTest.kt +++ b/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/HeartsAndArrowsTest.kt @@ -1,9 +1,8 @@ package com.jeffpdavidson.kotwords.model -import com.jeffpdavidson.kotwords.formats.CrosswordCompilerApplet import com.jeffpdavidson.kotwords.formats.Ipuz import com.jeffpdavidson.kotwords.readStringResource -import com.jeffpdavidson.kotwords.util.trimmedLines +import io.github.pdvrieze.xmlutil.testutil.assertXmlEquals import kotlinx.coroutines.test.runTest import kotlin.test.Test import kotlin.test.assertEquals @@ -13,7 +12,7 @@ class HeartsAndArrowsTest { fun jpzGeneration() = runTest { val puzzle = PUZZLE.asPuzzle() val expected = readStringResource(HeartsAndArrowsTest::class, "hearts-and-arrows/hearts-and-arrows.jpz") - assertEquals(expected, puzzle.asJpz().toXmlString()) + assertXmlEquals(expected, puzzle.asJpz().toXmlString()) } @Test diff --git a/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/HelterSkelterTest.kt b/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/HelterSkelterTest.kt index 22e0107..8e9da9a 100644 --- a/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/HelterSkelterTest.kt +++ b/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/HelterSkelterTest.kt @@ -1,14 +1,14 @@ package com.jeffpdavidson.kotwords.model import com.jeffpdavidson.kotwords.readStringResource +import io.github.pdvrieze.xmlutil.testutil.assertXmlEquals import kotlinx.coroutines.test.runTest import kotlin.test.Test -import kotlin.test.assertEquals class HelterSkelterTest { @Test fun asPuzzle() = runTest { - assertEquals( + assertXmlEquals( readStringResource(HelterSkelterTest::class, "helter-skelter/helter-skelter.jpz"), helterSkelter.asPuzzle().asJpz().toXmlString(), ) @@ -16,7 +16,7 @@ class HelterSkelterTest { @Test fun asPuzzle_withoutVectors() = runTest { - assertEquals( + assertXmlEquals( readStringResource(HelterSkelterTest::class, "helter-skelter/helter-skelter.jpz"), helterSkelter.copy(answerVectors = listOf()).asPuzzle().asJpz().toXmlString(), ) @@ -24,7 +24,7 @@ class HelterSkelterTest { @Test fun asPuzzle_extendToEdges() = runTest { - assertEquals( + assertXmlEquals( readStringResource(HelterSkelterTest::class, "helter-skelter/helter-skelter-extend-to-edges.jpz"), helterSkelter.copy(extendToEdges = true).asPuzzle().asJpz().toXmlString(), ) diff --git a/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/JellyRollTest.kt b/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/JellyRollTest.kt index 9dab672..22768b2 100644 --- a/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/JellyRollTest.kt +++ b/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/JellyRollTest.kt @@ -2,9 +2,9 @@ package com.jeffpdavidson.kotwords.model import com.jeffpdavidson.kotwords.formats.CrosswordCompilerApplet import com.jeffpdavidson.kotwords.readStringResource +import io.github.pdvrieze.xmlutil.testutil.assertXmlEquals import kotlinx.coroutines.test.runTest import kotlin.test.Test -import kotlin.test.assertEquals class JellyRollTest { @Test @@ -27,7 +27,7 @@ class JellyRollTest { val puzzle = jellyRoll.asPuzzle() val expected = readStringResource(JellyRollTest::class, "jelly-roll/jelly-roll.jpz") - assertEquals( + assertXmlEquals( expected, puzzle.asJpz( appletSettings = CrosswordCompilerApplet.AppletSettings( cursorColor = "#00b100", @@ -58,7 +58,7 @@ class JellyRollTest { val puzzle = jellyRoll.asPuzzle() val expected = readStringResource(JellyRollTest::class, "jelly-roll/jelly-roll-combined.jpz") - assertEquals( + assertXmlEquals( expected, puzzle.asJpz( appletSettings = CrosswordCompilerApplet.AppletSettings( cursorColor = "#00b100", @@ -89,7 +89,7 @@ class JellyRollTest { val puzzle = jellyRoll.asPuzzle() val expected = readStringResource(JellyRollTest::class, "jelly-roll/jelly-roll-nonsquare.jpz") - assertEquals( + assertXmlEquals( expected, puzzle.asJpz( appletSettings = CrosswordCompilerApplet.AppletSettings( cursorColor = "#00b100", diff --git a/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/LabyrinthTest.kt b/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/LabyrinthTest.kt index 8262d85..6e0e4f9 100644 --- a/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/LabyrinthTest.kt +++ b/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/LabyrinthTest.kt @@ -2,9 +2,9 @@ package com.jeffpdavidson.kotwords.model import com.jeffpdavidson.kotwords.formats.CrosswordCompilerApplet import com.jeffpdavidson.kotwords.readStringResource +import io.github.pdvrieze.xmlutil.testutil.assertXmlEquals import kotlinx.coroutines.test.runTest import kotlin.test.Test -import kotlin.test.assertEquals class LabyrinthTest { @Test @@ -31,7 +31,7 @@ class LabyrinthTest { val puzzle = labyrinth.asPuzzle() val expected = readStringResource(LabyrinthTest::class, "labyrinth/labyrinth.jpz") - assertEquals( + assertXmlEquals( expected, puzzle.asJpz( appletSettings = CrosswordCompilerApplet.AppletSettings( cursorColor = "#00b100", diff --git a/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/MarchingBandsTest.kt b/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/MarchingBandsTest.kt index 3365524..2c355bf 100644 --- a/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/MarchingBandsTest.kt +++ b/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/MarchingBandsTest.kt @@ -1,5 +1,6 @@ package com.jeffpdavidson.kotwords.model +import com.jeffpdavidson.kotwords.IgnoreNative import com.jeffpdavidson.kotwords.formats.CrosswordCompilerApplet import com.jeffpdavidson.kotwords.formats.ImageComparator import com.jeffpdavidson.kotwords.formats.ImageComparator.assertPdfEquals @@ -8,16 +9,16 @@ import com.jeffpdavidson.kotwords.formats.PdfTest import com.jeffpdavidson.kotwords.formats.getNotoSerifFontFamily import com.jeffpdavidson.kotwords.readBinaryResource import com.jeffpdavidson.kotwords.readStringResource +import io.github.pdvrieze.xmlutil.testutil.assertXmlEquals import kotlinx.coroutines.test.runTest import kotlin.test.Test -import kotlin.test.assertEquals class MarchingBandsTest { @Test fun jpzGeneration() = runTest { val puzzle = MARCHING_BANDS.asPuzzle() val expected = readStringResource(MarchingBandsTest::class, "marching-bands/marching-bands.jpz") - assertEquals( + assertXmlEquals( expected, puzzle.asJpz( appletSettings = CrosswordCompilerApplet.AppletSettings( cursorColor = "#00b100", @@ -32,7 +33,7 @@ class MarchingBandsTest { fun jpzGeneration_withoutRowNumbers() = runTest { val puzzle = MARCHING_BANDS.copy(includeRowNumbers = false).asPuzzle() val expected = readStringResource(MarchingBandsTest::class, "marching-bands/marching-bands-without-rows.jpz") - assertEquals( + assertXmlEquals( expected, puzzle.asJpz( appletSettings = CrosswordCompilerApplet.AppletSettings( cursorColor = "#00b100", @@ -44,6 +45,7 @@ class MarchingBandsTest { } @Test + @IgnoreNative // Depends on PDF support fun pdfGeneration() = runTest { assertPdfEquals( readBinaryResource(ImageComparator::class, "marching-bands/marching-bands.pdf"), diff --git a/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/PatchworkTest.kt b/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/PatchworkTest.kt index 5222534..03c2b6f 100644 --- a/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/PatchworkTest.kt +++ b/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/PatchworkTest.kt @@ -2,6 +2,7 @@ package com.jeffpdavidson.kotwords.model import com.jeffpdavidson.kotwords.formats.Ipuz import com.jeffpdavidson.kotwords.readStringResource +import io.github.pdvrieze.xmlutil.testutil.assertXmlEquals import kotlinx.coroutines.test.runTest import kotlin.test.Test import kotlin.test.assertEquals @@ -11,7 +12,7 @@ class PatchworkTest { fun jpzGeneration() = runTest { val puzzle = PATCHWORK.asPuzzle() val expected = readStringResource(PatchworkTest::class, "patchwork/patchwork.jpz") - assertEquals(expected, puzzle.asJpz().toXmlString()) + assertXmlEquals(expected, puzzle.asJpz().toXmlString()) } @Test diff --git a/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/SnakeCharmerTest.kt b/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/SnakeCharmerTest.kt index 9ef8cfd..d5e9715 100644 --- a/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/SnakeCharmerTest.kt +++ b/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/SnakeCharmerTest.kt @@ -2,9 +2,9 @@ package com.jeffpdavidson.kotwords.model import com.jeffpdavidson.kotwords.formats.CrosswordCompilerApplet import com.jeffpdavidson.kotwords.readStringResource +import io.github.pdvrieze.xmlutil.testutil.assertXmlEquals import kotlinx.coroutines.test.runTest import kotlin.test.Test -import kotlin.test.assertEquals class SnakeCharmerTest { @Test @@ -21,7 +21,7 @@ class SnakeCharmerTest { val puzzle = snakeCharmer.asPuzzle() val expected = readStringResource(SnakeCharmerTest::class, "snake-charmer/snake-charmer.jpz") - assertEquals( + assertXmlEquals( expected, puzzle.asJpz( appletSettings = CrosswordCompilerApplet.AppletSettings( cursorColor = "#00b100", diff --git a/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/SpellWeavingTest.kt b/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/SpellWeavingTest.kt index 9c8a8c5..7b17d6d 100644 --- a/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/SpellWeavingTest.kt +++ b/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/SpellWeavingTest.kt @@ -2,9 +2,9 @@ package com.jeffpdavidson.kotwords.model import com.jeffpdavidson.kotwords.formats.CrosswordCompilerApplet import com.jeffpdavidson.kotwords.readStringResource +import io.github.pdvrieze.xmlutil.testutil.assertXmlEquals import kotlinx.coroutines.test.runTest import kotlin.test.Test -import kotlin.test.assertEquals class SpellWeavingTest { @Test @@ -20,7 +20,7 @@ class SpellWeavingTest { val puzzle = spellWeaving.asPuzzle() val expected = readStringResource(SpellWeavingTest::class, "spell-weaving/spell-weaving.jpz") - assertEquals( + assertXmlEquals( expected, puzzle.asJpz( appletSettings = CrosswordCompilerApplet.AppletSettings( cursorColor = "#00b100", diff --git a/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/SpiralTest.kt b/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/SpiralTest.kt index 233dd9f..cb3504f 100644 --- a/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/SpiralTest.kt +++ b/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/SpiralTest.kt @@ -2,9 +2,9 @@ package com.jeffpdavidson.kotwords.model import com.jeffpdavidson.kotwords.formats.CrosswordCompilerApplet import com.jeffpdavidson.kotwords.readStringResource +import io.github.pdvrieze.xmlutil.testutil.assertXmlEquals import kotlinx.coroutines.test.runTest import kotlin.test.Test -import kotlin.test.assertEquals class SpiralTest { @Test @@ -22,7 +22,7 @@ class SpiralTest { val puzzle = spiral.asPuzzle() val expected = readStringResource(SpiralTest::class, "spiral/spiral.jpz") - assertEquals( + assertXmlEquals( expected, puzzle.asJpz( appletSettings = CrosswordCompilerApplet.AppletSettings( cursorColor = "#00b100", @@ -48,7 +48,7 @@ class SpiralTest { val puzzle = spiral.asPuzzle() val expected = readStringResource(SpiralTest::class, "spiral/spiral-nonsquare.jpz") - assertEquals( + assertXmlEquals( expected, puzzle.asJpz( appletSettings = CrosswordCompilerApplet.AppletSettings( cursorColor = "#00b100", @@ -75,7 +75,7 @@ class SpiralTest { val puzzle = spiral.asPuzzle() val expected = readStringResource(SpiralTest::class, "spiral/spiral-rectangular.jpz") - assertEquals( + assertXmlEquals( expected, puzzle.asJpz( appletSettings = CrosswordCompilerApplet.AppletSettings( cursorColor = "#00b100", @@ -102,6 +102,6 @@ class SpiralTest { val puzzle = spiral.asPuzzle() val expected = readStringResource(SpiralTest::class, "spiral/spiral-chunked.jpz") - assertEquals(expected, puzzle.asJpz().toXmlString()) + assertXmlEquals(expected, puzzle.asJpz().toXmlString()) } } \ No newline at end of file diff --git a/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/TwistsAndTurnsTest.kt b/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/TwistsAndTurnsTest.kt index fd38f95..e8b9c95 100644 --- a/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/TwistsAndTurnsTest.kt +++ b/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/TwistsAndTurnsTest.kt @@ -1,20 +1,21 @@ package com.jeffpdavidson.kotwords.model +import com.jeffpdavidson.kotwords.IgnoreNative import com.jeffpdavidson.kotwords.formats.CrosswordCompilerApplet import com.jeffpdavidson.kotwords.formats.ImageComparator.assertPdfEquals import com.jeffpdavidson.kotwords.formats.getNotoSerifFontFamily import com.jeffpdavidson.kotwords.readBinaryResource import com.jeffpdavidson.kotwords.readStringResource +import io.github.pdvrieze.xmlutil.testutil.assertXmlEquals import kotlinx.coroutines.test.runTest import kotlin.test.Test -import kotlin.test.assertEquals // TODO: Expand test coverage class TwistsAndTurnsTest { @Test fun jpzGeneration() = runTest { val expected = readStringResource(TwistsAndTurnsTest::class, "twists-and-turns/twists-and-turns.jpz") - assertEquals( + assertXmlEquals( expected, puzzle.asPuzzle().asJpz( appletSettings = CrosswordCompilerApplet.AppletSettings( cursorColor = "#00b100", @@ -26,6 +27,7 @@ class TwistsAndTurnsTest { } @Test + @IgnoreNative // Depends on PDF support fun pdfGeneration_unsortedTwists() = runTest { val expected = readBinaryResource(TwistsAndTurnsTest::class, "twists-and-turns/unsorted-twists.pdf") assertPdfEquals( @@ -41,6 +43,7 @@ class TwistsAndTurnsTest { } @Test + @IgnoreNative // Depends on PDF support fun pdfGeneration_sortedTwists() = runTest { val expected = readBinaryResource(TwistsAndTurnsTest::class, "twists-and-turns/sorted-twists.pdf") assertPdfEquals( diff --git a/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/TwoToneTest.kt b/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/TwoToneTest.kt index 1877449..496e564 100644 --- a/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/TwoToneTest.kt +++ b/src/commonTest/kotlin/com/jeffpdavidson/kotwords/model/TwoToneTest.kt @@ -2,9 +2,9 @@ package com.jeffpdavidson.kotwords.model import com.jeffpdavidson.kotwords.formats.CrosswordCompilerApplet import com.jeffpdavidson.kotwords.readStringResource +import io.github.pdvrieze.xmlutil.testutil.assertXmlEquals import kotlinx.coroutines.test.runTest import kotlin.test.Test -import kotlin.test.assertEquals class TwoToneTest { @Test @@ -26,7 +26,7 @@ class TwoToneTest { val puzzle = twoTone.asPuzzle() val expected = readStringResource(TwoToneTest::class, "two-tone/two-tone.jpz") - assertEquals( + assertXmlEquals( expected, puzzle.asJpz( appletSettings = CrosswordCompilerApplet.AppletSettings( cursorColor = "#00b100", @@ -56,7 +56,7 @@ class TwoToneTest { val puzzle = twoTone.asPuzzle() val expected = readStringResource(TwoToneTest::class, "two-tone/two-tone-nonsquare.jpz") - assertEquals( + assertXmlEquals( expected, puzzle.asJpz( appletSettings = CrosswordCompilerApplet.AppletSettings( cursorColor = "#00b100", diff --git a/src/jsMain/kotlin/com/jeffpdavidson/kotwords/formats/Encodings.kt b/src/jsMain/kotlin/com/jeffpdavidson/kotwords/formats/Encodings.kt index 990553a..8edae3e 100644 --- a/src/jsMain/kotlin/com/jeffpdavidson/kotwords/formats/Encodings.kt +++ b/src/jsMain/kotlin/com/jeffpdavidson/kotwords/formats/Encodings.kt @@ -6,46 +6,13 @@ import org.w3c.dom.HTMLTextAreaElement internal external fun decodeURIComponent(encodedURI: String): String internal actual object Encodings { - /** Unicode values corresponding to bytes 0x80-0x9F in CP1252. */ - private val CP1252_DECODE_TABLE = listOf( - '\u20ac', '\u0081', '\u201a', '\u0192', '\u201e', '\u2026', '\u2020', '\u2021', - '\u02c6', '\u2030', '\u0160', '\u2039', '\u0152', '\u008d', '\u017d', '\u008f', - '\u0090', '\u2018', '\u2019', '\u201c', '\u201d', '\u2022', '\u2013', '\u2014', - '\u02dc', '\u2122', '\u0161', '\u203a', '\u0153', '\u009d', '\u017e', '\u0178', - ) - - /** Map from supported CP1252 unicode values to their byte value in CP1252. */ - private val CP1252_ENCODE_TABLE = CP1252_DECODE_TABLE.withIndex().associate { it.value to it.index } actual fun decodeCp1252(bytes: ByteArray): String { - return bytes.map { byte -> - val intValue = byte.toInt() and 0xFF - if (intValue in 0x00..0x7F || intValue in 0xA0..0xFF) { - // ISO-8859-1 characters map directly. - intValue.toChar() - } else { - // Between 0x80 and 0x9F - look up the value in the table. - CP1252_DECODE_TABLE[intValue - 0x80] - } - }.joinToString("") + return commonDecodeCp1252(bytes) } actual fun encodeCp1252(string: String): ByteArray { - return string.map { ch -> - if (ch.code in 0x00..0x7F || ch.code in 0xA0..0xFF) { - // ISO-8859-1 characters map directly. - ch.code.toByte() - } else { - val cp1252Byte = CP1252_ENCODE_TABLE[ch] - if (cp1252Byte != null) { - // One of the supported CP1252 characters. - (0x80 + cp1252Byte).toByte() - } else { - // Unsupported value - use default '?' character. - '?'.code.toByte() - } - } - }.toByteArray() + return commonEncodeCp1252(string) } actual fun decodeUrl(url: String): String = decodeURIComponent(url) diff --git a/src/jsMain/kotlin/com/jeffpdavidson/kotwords/formats/PdfDocument.kt b/src/jsMain/kotlin/com/jeffpdavidson/kotwords/formats/PdfDocument.kt index 260f6fd..183c825 100644 --- a/src/jsMain/kotlin/com/jeffpdavidson/kotwords/formats/PdfDocument.kt +++ b/src/jsMain/kotlin/com/jeffpdavidson/kotwords/formats/PdfDocument.kt @@ -87,6 +87,7 @@ actual class PdfDocument { } pdf.embedStandardFont(standardFont) } + is PdfFont.TtfFont -> { pdf.embedFont(font.fontData.toArrayBuffer(), newEmbedFontOptions(subset = true)).await() } diff --git a/src/jsMain/kotlin/com/jeffpdavidson/kotwords/js/PdfLib.kt b/src/jsMain/kotlin/com/jeffpdavidson/kotwords/js/PdfLib.kt index 78b1e49..0cfce01 100644 --- a/src/jsMain/kotlin/com/jeffpdavidson/kotwords/js/PdfLib.kt +++ b/src/jsMain/kotlin/com/jeffpdavidson/kotwords/js/PdfLib.kt @@ -43,18 +43,18 @@ internal external class PDFFont { internal external class PDFImage internal external sealed class PageSizes { - object Letter: PageSizes + object Letter : PageSizes } internal external sealed class StandardFonts { - object Courier: StandardFonts - object CourierBold: StandardFonts - object CourierBoldOblique: StandardFonts - object CourierOblique: StandardFonts - object TimesRoman: StandardFonts - object TimesRomanBold: StandardFonts - object TimesRomanBoldItalic: StandardFonts - object TimesRomanItalic: StandardFonts + object Courier : StandardFonts + object CourierBold : StandardFonts + object CourierBoldOblique : StandardFonts + object CourierOblique : StandardFonts + object TimesRoman : StandardFonts + object TimesRomanBold : StandardFonts + object TimesRomanBoldItalic : StandardFonts + object TimesRomanItalic : StandardFonts } internal external interface EmbedFontOptions { diff --git a/src/jsMain/kotlin/com/jeffpdavidson/kotwords/web/CrosswordForm.kt b/src/jsMain/kotlin/com/jeffpdavidson/kotwords/web/CrosswordForm.kt index 3e2f435..72519eb 100644 --- a/src/jsMain/kotlin/com/jeffpdavidson/kotwords/web/CrosswordForm.kt +++ b/src/jsMain/kotlin/com/jeffpdavidson/kotwords/web/CrosswordForm.kt @@ -121,6 +121,7 @@ class CrosswordForm { solution = "", borderDirections = borders.getOrElse(x to y) { setOf() }, ) + else -> Puzzle.Cell( solution = col, borderDirections = borders.getOrElse(x to y) { setOf() }, diff --git a/src/jsMain/kotlin/com/jeffpdavidson/kotwords/web/PatchworkForm.kt b/src/jsMain/kotlin/com/jeffpdavidson/kotwords/web/PatchworkForm.kt index 211154d..de045ec 100644 --- a/src/jsMain/kotlin/com/jeffpdavidson/kotwords/web/PatchworkForm.kt +++ b/src/jsMain/kotlin/com/jeffpdavidson/kotwords/web/PatchworkForm.kt @@ -6,7 +6,6 @@ import com.jeffpdavidson.kotwords.model.Puzzle import com.jeffpdavidson.kotwords.util.trimmedLines import com.jeffpdavidson.kotwords.web.html.FormFields import com.jeffpdavidson.kotwords.web.html.Html -import kotlinx.html.js.onChangeFunction @JsExport @KotwordsInternal diff --git a/src/jsMain/kotlin/com/jeffpdavidson/kotwords/web/PuzzleFileForm.kt b/src/jsMain/kotlin/com/jeffpdavidson/kotwords/web/PuzzleFileForm.kt index b950526..485bf1a 100644 --- a/src/jsMain/kotlin/com/jeffpdavidson/kotwords/web/PuzzleFileForm.kt +++ b/src/jsMain/kotlin/com/jeffpdavidson/kotwords/web/PuzzleFileForm.kt @@ -314,6 +314,7 @@ internal class PuzzleFileForm( else -> it.value } } + is HTMLTextAreaElement -> it.value else -> throw IllegalStateException("") } @@ -354,6 +355,7 @@ internal class PuzzleFileForm( event.initEvent("input", bubbles = true, cancelable = true) element.dispatchEvent(event) } + is HTMLTextAreaElement -> element.value = value as String } } diff --git a/src/jsTest/kotlin/com/jeffpdavidson/kotwords/JsTestRunner.kt b/src/jsTest/kotlin/com/jeffpdavidson/kotwords/JsTestRunner.kt index 21b2635..4e7a1fb 100644 --- a/src/jsTest/kotlin/com/jeffpdavidson/kotwords/JsTestRunner.kt +++ b/src/jsTest/kotlin/com/jeffpdavidson/kotwords/JsTestRunner.kt @@ -11,3 +11,6 @@ actual suspend fun readBinaryResource(clazz: KClass, resourceName: actual suspend fun readStringResource(clazz: KClass, resourceName: String): String = Http.getString("$BASE_RESOURCE_PATH/$resourceName") + +@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) +actual annotation class IgnoreNative \ No newline at end of file diff --git a/src/jvmMain/kotlin/com/jeffpdavidson/kotwords/formats/Encodings.kt b/src/jvmMain/kotlin/com/jeffpdavidson/kotwords/formats/Encodings.kt index 6a95d34..cc0129b 100644 --- a/src/jvmMain/kotlin/com/jeffpdavidson/kotwords/formats/Encodings.kt +++ b/src/jvmMain/kotlin/com/jeffpdavidson/kotwords/formats/Encodings.kt @@ -7,7 +7,6 @@ import java.nio.charset.StandardCharsets import java.nio.charset.UnsupportedCharsetException internal actual object Encodings { - private val UNESCAPE_PATTERN = "%u([0-9A-Fa-f]{4})|%([0-9A-Fa-f]{2})".toRegex() private val WINDOWS_1252_CHARSET = try { Charset.forName("windows-1252") } catch (e: UnsupportedCharsetException) { @@ -29,9 +28,6 @@ internal actual object Encodings { Parser.unescapeEntities(string, /* inAttribute= */ false) actual fun unescape(string: String): String { - return UNESCAPE_PATTERN.replace(string) { result -> - val code = result.groupValues[1].ifEmpty { result.groupValues[2] } - code.toInt(16).toChar().toString() - } + return commonUnescape(string) } } \ No newline at end of file diff --git a/src/jvmMain/kotlin/com/jeffpdavidson/kotwords/formats/PdfDocument.kt b/src/jvmMain/kotlin/com/jeffpdavidson/kotwords/formats/PdfDocument.kt index aaae526..70fadb7 100644 --- a/src/jvmMain/kotlin/com/jeffpdavidson/kotwords/formats/PdfDocument.kt +++ b/src/jvmMain/kotlin/com/jeffpdavidson/kotwords/formats/PdfDocument.kt @@ -122,6 +122,7 @@ actual class PdfDocument { BuiltInFontName.COURIER_ITALIC -> PDType1Font(Standard14Fonts.FontName.COURIER_OBLIQUE) BuiltInFontName.COURIER_BOLD_ITALIC -> PDType1Font(Standard14Fonts.FontName.COURIER_BOLD_OBLIQUE) + BuiltInFontName.TIMES_ROMAN -> PDType1Font(Standard14Fonts.FontName.TIMES_ROMAN) BuiltInFontName.TIMES_BOLD -> PDType1Font(Standard14Fonts.FontName.TIMES_BOLD) BuiltInFontName.TIMES_ITALIC -> PDType1Font(Standard14Fonts.FontName.TIMES_ITALIC) @@ -129,6 +130,7 @@ actual class PdfDocument { } } } + is PdfFont.TtfFont -> { loadedTtfFonts.getOrPut(fontName to fontStyle) { PDType0Font.load(document, ByteArrayInputStream(fontData)) diff --git a/src/jvmTest/kotlin/com/jeffpdavidson/kotwords/JvmTestRunner.kt b/src/jvmTest/kotlin/com/jeffpdavidson/kotwords/JvmTestRunner.kt index 05dc04e..63f7e30 100644 --- a/src/jvmTest/kotlin/com/jeffpdavidson/kotwords/JvmTestRunner.kt +++ b/src/jvmTest/kotlin/com/jeffpdavidson/kotwords/JvmTestRunner.kt @@ -18,3 +18,6 @@ private fun getResourceAsStream(clazz: KClass, resourceName: String return clazz.java.classLoader.getResourceAsStream(resourceName) ?: throw IllegalArgumentException("Error loading resource $resourceName") } + +@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) +actual annotation class IgnoreNative \ No newline at end of file diff --git a/src/nativeMain/kotlin/com/jeffpdavidson/kotwords/cli/Main.kt b/src/nativeMain/kotlin/com/jeffpdavidson/kotwords/cli/Main.kt new file mode 100644 index 0000000..ed05d61 --- /dev/null +++ b/src/nativeMain/kotlin/com/jeffpdavidson/kotwords/cli/Main.kt @@ -0,0 +1,6 @@ +package com.jeffpdavidson.kotwords.cli + +fun main() { + // TODO: Implement me. + println("Hello world") +} \ No newline at end of file diff --git a/src/nativeMain/kotlin/com/jeffpdavidson/kotwords/formats/Encodings.kt b/src/nativeMain/kotlin/com/jeffpdavidson/kotwords/formats/Encodings.kt new file mode 100644 index 0000000..d168060 --- /dev/null +++ b/src/nativeMain/kotlin/com/jeffpdavidson/kotwords/formats/Encodings.kt @@ -0,0 +1,27 @@ +package com.jeffpdavidson.kotwords.formats + +import com.fleeksoft.ksoup.parser.Parser +import net.thauvin.erik.urlencoder.UrlEncoderUtil + +internal actual object Encodings { + // TODO: Explore using platform.iconv* for CP1252 conversion. + actual fun decodeCp1252(bytes: ByteArray): String { + return commonDecodeCp1252(bytes) + } + + actual fun encodeCp1252(string: String): ByteArray { + return commonEncodeCp1252(string) + } + + actual fun decodeUrl(url: String): String { + return UrlEncoderUtil.decode(url) + } + + actual fun decodeHtmlEntities(string: String): String { + return Parser.unescapeEntities(string, inAttribute = false) + } + + actual fun unescape(string: String): String { + return commonUnescape(string) + } +} \ No newline at end of file diff --git a/src/nativeMain/kotlin/com/jeffpdavidson/kotwords/formats/ParsedImage.kt b/src/nativeMain/kotlin/com/jeffpdavidson/kotwords/formats/ParsedImage.kt new file mode 100644 index 0000000..5bbca6f --- /dev/null +++ b/src/nativeMain/kotlin/com/jeffpdavidson/kotwords/formats/ParsedImage.kt @@ -0,0 +1,40 @@ +package com.jeffpdavidson.kotwords.formats + +import okio.Closeable + +internal actual class ParsedImage : Closeable { + actual val width: Int + get() = TODO("Not yet implemented") + actual val height: Int + get() = TODO("Not yet implemented") + + actual fun containsVisiblePixels(): Boolean { + TODO("Not yet implemented") + } + + actual fun crop( + width: Int, + height: Int, + x: Int, + y: Int + ): ParsedImage { + TODO("Not yet implemented") + } + + actual suspend fun toPngBytes(): ByteArray { + TODO("Not yet implemented") + } + + actual companion object { + actual suspend fun parse( + format: ParsedImageFormat, + data: ByteArray + ): ParsedImage { + TODO("Not yet implemented") + } + } + + override fun close() { + TODO("Not yet implemented") + } +} \ No newline at end of file diff --git a/src/nativeMain/kotlin/com/jeffpdavidson/kotwords/formats/PdfDocument.kt b/src/nativeMain/kotlin/com/jeffpdavidson/kotwords/formats/PdfDocument.kt new file mode 100644 index 0000000..e62b5d7 --- /dev/null +++ b/src/nativeMain/kotlin/com/jeffpdavidson/kotwords/formats/PdfDocument.kt @@ -0,0 +1,95 @@ +package com.jeffpdavidson.kotwords.formats + +import com.jeffpdavidson.kotwords.model.Puzzle + +actual class PdfDocument { + actual val width: Float + get() = TODO("Not yet implemented") + actual val height: Float + get() = TODO("Not yet implemented") + + actual fun beginText() { + TODO("Not yet implemented") + } + + actual fun endText() { + TODO("Not yet implemented") + } + + actual fun newLineAtOffset(offsetX: Float, offsetY: Float) { + TODO("Not yet implemented") + } + + actual suspend fun setFont(font: PdfFont, size: Float) { + TODO("Not yet implemented") + } + + actual suspend fun getTextWidth( + text: String, + font: PdfFont, + size: Float + ): Float { + TODO("Not yet implemented") + } + + actual suspend fun drawText(text: String) { + TODO("Not yet implemented") + } + + actual fun setLineWidth(width: Float) { + TODO("Not yet implemented") + } + + actual fun setStrokeColor(r: Float, g: Float, b: Float) { + TODO("Not yet implemented") + } + + actual fun setFillColor(r: Float, g: Float, b: Float) { + TODO("Not yet implemented") + } + + actual fun drawLine(x1: Float, y1: Float, x2: Float, y2: Float) { + TODO("Not yet implemented") + } + + actual fun drawRect( + x: Float, + y: Float, + width: Float, + height: Float, + stroke: Boolean, + fill: Boolean + ) { + TODO("Not yet implemented") + } + + actual fun drawCircle( + x: Float, + y: Float, + radius: Float, + stroke: Boolean, + fill: Boolean + ) { + TODO("Not yet implemented") + } + + actual suspend fun drawImage( + x: Float, + y: Float, + width: Float, + height: Float, + image: Puzzle.Image.Data + ) { + TODO("Not yet implemented") + } + + actual suspend fun toByteArray(): ByteArray { + TODO("Not yet implemented") + } + + actual companion object { + actual suspend fun create(): PdfDocument { + TODO("Not yet implemented") + } + } +} \ No newline at end of file diff --git a/src/nativeMain/kotlin/com/jeffpdavidson/kotwords/formats/Xml.kt b/src/nativeMain/kotlin/com/jeffpdavidson/kotwords/formats/Xml.kt new file mode 100644 index 0000000..5be8c59 --- /dev/null +++ b/src/nativeMain/kotlin/com/jeffpdavidson/kotwords/formats/Xml.kt @@ -0,0 +1,37 @@ +package com.jeffpdavidson.kotwords.formats + +import com.fleeksoft.ksoup.Ksoup +import com.fleeksoft.ksoup.parser.Parser + +// TODO: Determine if this could reasonably replace the JS/JVM implementations as well. +private open class ElementImpl(private val ksoupElement: com.fleeksoft.ksoup.nodes.Element) : Element { + override val tag: String = ksoupElement.tagName().uppercase() + override val data: String = ksoupElement.data() + override val text: String = ksoupElement.text() + override val children: List = ksoupElement.childNodes().mapNotNull { node -> + when (node) { + is com.fleeksoft.ksoup.nodes.TextNode -> TextNode(node.text()) + is com.fleeksoft.ksoup.nodes.Element -> ElementImpl(node) + else -> null + } + } + + override fun attr(key: String): String = ksoupElement.attr(key) + + override fun select(selector: String): Iterable = + ksoupElement.select(selector).map { ElementImpl(it) } + + override fun selectFirst(selector: String): Element? { + return ElementImpl(ksoupElement.selectFirst(selector) ?: return null) + } +} + +internal actual object Xml { + actual fun parse(html: String, baseUri: String?, format: DocumentFormat): Element { + val parser = when (format) { + DocumentFormat.HTML -> Parser.htmlParser() + DocumentFormat.XML -> Parser.xmlParser() + } + return ElementImpl(Ksoup.parse(html, baseUri ?: "", parser)) + } +} \ No newline at end of file diff --git a/src/nativeMain/kotlin/com/jeffpdavidson/kotwords/formats/Zip.kt b/src/nativeMain/kotlin/com/jeffpdavidson/kotwords/formats/Zip.kt new file mode 100644 index 0000000..b1e3ad6 --- /dev/null +++ b/src/nativeMain/kotlin/com/jeffpdavidson/kotwords/formats/Zip.kt @@ -0,0 +1,27 @@ +package com.jeffpdavidson.kotwords.formats + +import korlibs.io.file.std.MemoryVfs +import korlibs.io.file.std.createZipFromTree +import korlibs.io.file.std.openAsZip +import korlibs.io.stream.openAsync + +internal actual object Zip { + actual suspend fun zip(filename: String, data: ByteArray): ByteArray { + return MemoryVfs(mapOf(filename to data.openAsync())).createZipFromTree() + } + + actual suspend fun unzip(data: ByteArray): ByteArray { + val fs = try { + data.openAsync().openAsZip() + } catch (e: IllegalArgumentException) { + throw InvalidZipException("Error unzipping data", e) + } + val files = fs.listRecursiveSimple() + files.forEach { file -> + if (file.isFile()) { + return file.readBytes() + } + } + throw InvalidZipException("No file entry in ZIP file") + } +} \ No newline at end of file diff --git a/src/nativeTest/kotlin/com/jeffpdavidson/kotwords/TestRunner.kt b/src/nativeTest/kotlin/com/jeffpdavidson/kotwords/TestRunner.kt new file mode 100644 index 0000000..c46b7f1 --- /dev/null +++ b/src/nativeTest/kotlin/com/jeffpdavidson/kotwords/TestRunner.kt @@ -0,0 +1,24 @@ +package com.jeffpdavidson.kotwords + +import okio.FileSystem +import okio.Path.Companion.toPath +import kotlin.reflect.KClass + +// TODO: Handle sourceSet-specific resources + +actual suspend fun readBinaryResource( + clazz: KClass, + resourceName: String +): ByteArray { + return FileSystem.SYSTEM.read("src/commonTest/resources/$resourceName".toPath()) { + readByteArray() + } +} + +actual suspend fun readStringResource(clazz: KClass, resourceName: String): String { + return FileSystem.SYSTEM.read("src/commonTest/resources/$resourceName".toPath()) { + readUtf8() + } +} + +actual typealias IgnoreNative = kotlin.test.Ignore \ No newline at end of file diff --git a/src/nativeTest/kotlin/com/jeffpdavidson/kotwords/formats/ImageComparator.kt b/src/nativeTest/kotlin/com/jeffpdavidson/kotwords/formats/ImageComparator.kt new file mode 100644 index 0000000..ccdbc28 --- /dev/null +++ b/src/nativeTest/kotlin/com/jeffpdavidson/kotwords/formats/ImageComparator.kt @@ -0,0 +1,11 @@ +package com.jeffpdavidson.kotwords.formats + +actual object ImageComparator { + actual suspend fun assertPdfEquals(expected: ByteArray, actual: ByteArray) { + TODO("Not yet implemented") + } + + actual suspend fun assertPngEquals(expected: ByteArray, actual: ByteArray) { + TODO("Not yet implemented") + } +} \ No newline at end of file