From fca7e3b3b4d9edb39f9bbcabfbab164a2e0bd848 Mon Sep 17 00:00:00 2001 From: SOR <3272194354@qq.com> Date: Sun, 20 Sep 2026 16:51:28 +0800 Subject: [PATCH] full basic functions --- .../sor2171/puzzles/annotation/SkipCompile.kt | 5 ++ .../sor2171/puzzles/service/PuzzleNote.kt | 33 +++++++++++ .../puzzles/service/RandomGenerator.kt | 57 +++++++++++++++++++ .../sor2171/puzzles/utils/CatalogStructure.kt | 47 +++++++++++++++ .../sor2171/puzzles/utils/CompileDetector.kt | 24 ++++++++ .../io/github/sor2171/puzzles/Catalog.kt | 14 +++++ .../github/sor2171/puzzles/alphabet/First.kt | 29 ++++++++++ .../extend/TestLifecycleLoggerExtension.kt | 22 +++++++ .../sor2171/puzzles/extra/FirstExtra.kt | 8 +++ .../io/github/sor2171/puzzles/hyper/Second.kt | 11 ++++ .../org.junit.jupiter.api.extension.Extension | 1 + src/test/resources/junit-platform.properties | 1 + 12 files changed, 252 insertions(+) create mode 100644 src/main/kotlin/io/github/sor2171/puzzles/annotation/SkipCompile.kt create mode 100644 src/main/kotlin/io/github/sor2171/puzzles/service/PuzzleNote.kt create mode 100644 src/main/kotlin/io/github/sor2171/puzzles/service/RandomGenerator.kt create mode 100644 src/main/kotlin/io/github/sor2171/puzzles/utils/CatalogStructure.kt create mode 100644 src/main/kotlin/io/github/sor2171/puzzles/utils/CompileDetector.kt create mode 100644 src/test/kotlin/io/github/sor2171/puzzles/Catalog.kt create mode 100644 src/test/kotlin/io/github/sor2171/puzzles/alphabet/First.kt create mode 100644 src/test/kotlin/io/github/sor2171/puzzles/extend/TestLifecycleLoggerExtension.kt create mode 100644 src/test/kotlin/io/github/sor2171/puzzles/extra/FirstExtra.kt create mode 100644 src/test/kotlin/io/github/sor2171/puzzles/hyper/Second.kt create mode 100644 src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension create mode 100644 src/test/resources/junit-platform.properties diff --git a/src/main/kotlin/io/github/sor2171/puzzles/annotation/SkipCompile.kt b/src/main/kotlin/io/github/sor2171/puzzles/annotation/SkipCompile.kt new file mode 100644 index 0000000..0c12cfc --- /dev/null +++ b/src/main/kotlin/io/github/sor2171/puzzles/annotation/SkipCompile.kt @@ -0,0 +1,5 @@ +package io.github.sor2171.puzzles.annotation + +@Target(AnnotationTarget.FILE) +@Retention(AnnotationRetention.SOURCE) +annotation class SkipCompile(val skip: Boolean = true) \ No newline at end of file diff --git a/src/main/kotlin/io/github/sor2171/puzzles/service/PuzzleNote.kt b/src/main/kotlin/io/github/sor2171/puzzles/service/PuzzleNote.kt new file mode 100644 index 0000000..afec00c --- /dev/null +++ b/src/main/kotlin/io/github/sor2171/puzzles/service/PuzzleNote.kt @@ -0,0 +1,33 @@ +package io.github.sor2171.puzzles.service + +import io.github.sor2171.puzzles.utils.CompileDetector + +class PuzzleNote( + className: String, + vararg notes: PuzzleNote? = arrayOf(null) +) { + val className = CompileDetector.getColoredName(className) + val notes = notes + + override fun toString(): String { + val sb = StringBuilder() + + sb.append(className) + + if (notes.size > 1) { + for (i in 1 until notes.size) { + sb.append("\n │") + notes[i]?.let { note -> + sb.append("\n ├── ").append(note.className) + } + } + } + + val nextNote = notes.firstOrNull() + if (nextNote != null) { + sb.append("\n │\n").append(nextNote.toString()) + } + + return sb.toString() + } +} \ No newline at end of file diff --git a/src/main/kotlin/io/github/sor2171/puzzles/service/RandomGenerator.kt b/src/main/kotlin/io/github/sor2171/puzzles/service/RandomGenerator.kt new file mode 100644 index 0000000..e099312 --- /dev/null +++ b/src/main/kotlin/io/github/sor2171/puzzles/service/RandomGenerator.kt @@ -0,0 +1,57 @@ +package io.github.sor2171.puzzles.service + +import kotlin.random.Random +import kotlin.reflect.KClass + +class RandomGenerator(vararg keys: Pair>) { + val variableMap = mutableMapOf() + + init { + keys.forEach { (name, type) -> + variableMap[name] = when (type) { + String::class -> randomString() + + Byte::class -> Random.nextInt( + Byte.MIN_VALUE.toInt(), + Byte.MAX_VALUE.toInt() + 1 + ).toByte() + + Short::class -> Random.nextInt( + Short.MIN_VALUE.toInt(), + Short.MAX_VALUE.toInt() + 1 + ).toShort() + + Int::class -> Random.nextInt() + + Long::class -> Random.nextLong() + // [0.0, 1.0) + + Float::class -> Random.nextFloat() + + Double::class -> Random.nextDouble() + + UByte::class -> Random.nextInt(0, UByte.MAX_VALUE.toInt() + 1).toUByte() + UShort::class -> Random.nextInt(0, UShort.MAX_VALUE.toInt() + 1).toUShort() + UInt::class -> Random.nextInt().toUInt() + ULong::class -> Random.nextLong().toULong() + + else -> error("不支持的类型: ${type.qualifiedName}") + } + } + } + + private fun randomString(length: Int = Random.nextInt(5, 16)): String { + val chars = ('a'..'z') + ('A'..'Z').toList() + ('0'..'9').toList() + return buildString(length) { + repeat(length) { + append(chars[Random.nextInt(chars.size)]) + } + } + } + + operator fun get(key: String) = variableMap[key] + + operator fun set(key: String, value: Any) { + variableMap[key] = value + } +} \ No newline at end of file diff --git a/src/main/kotlin/io/github/sor2171/puzzles/utils/CatalogStructure.kt b/src/main/kotlin/io/github/sor2171/puzzles/utils/CatalogStructure.kt new file mode 100644 index 0000000..907929c --- /dev/null +++ b/src/main/kotlin/io/github/sor2171/puzzles/utils/CatalogStructure.kt @@ -0,0 +1,47 @@ +package io.github.sor2171.puzzles.utils + +import io.github.sor2171.puzzles.service.PuzzleNote + +object CatalogStructure { + enum class Classification { + ALPHABET, + HYPER, + EXTRA; + + override fun toString(): String { + return super.toString().lowercase() + } + } + + val puzzlesArray = arrayOf( + arrayOf( + "${Classification.ALPHABET}.First", + "${Classification.EXTRA}.FirstExtra", + ), + arrayOf( + "${Classification.HYPER}.Second", + ) + ) + + val firstPuzzleNote: PuzzleNote + get() { + var nextMainNote: PuzzleNote? = null + + for (i in puzzlesArray.indices.reversed()) { + val array = puzzlesArray[i] + + val children = Array(array.size) { index -> + if (index == 0) { + nextMainNote + } else { + PuzzleNote(array[index]) + } + } + + nextMainNote = PuzzleNote(array[0], *children) + } + return nextMainNote!! + } + + fun printAllMessage() = println(firstPuzzleNote) +} \ No newline at end of file diff --git a/src/main/kotlin/io/github/sor2171/puzzles/utils/CompileDetector.kt b/src/main/kotlin/io/github/sor2171/puzzles/utils/CompileDetector.kt new file mode 100644 index 0000000..4fe7171 --- /dev/null +++ b/src/main/kotlin/io/github/sor2171/puzzles/utils/CompileDetector.kt @@ -0,0 +1,24 @@ +package io.github.sor2171.puzzles.utils + +object CompileDetector { + const val ANSI_GREEN = "\u001b[32m" + const val ANSI_RESET = "\u001b[0m" + + fun detect(fullName: String): Boolean { + return try { + Class.forName(fullName) + true + } catch (_: ClassNotFoundException) { + false + } + } + + fun fullName(className: String): String = + "io.github.sor2171.puzzles.$className" + + fun getColoredName(className: String): String { + val fullName = fullName(className) + return if (detect(fullName)) "$ANSI_GREEN$className$ANSI_RESET" + else className + } +} \ No newline at end of file diff --git a/src/test/kotlin/io/github/sor2171/puzzles/Catalog.kt b/src/test/kotlin/io/github/sor2171/puzzles/Catalog.kt new file mode 100644 index 0000000..38c47ba --- /dev/null +++ b/src/test/kotlin/io/github/sor2171/puzzles/Catalog.kt @@ -0,0 +1,14 @@ +package io.github.sor2171.puzzles + +import io.github.sor2171.puzzles.utils.CatalogStructure +import org.junit.jupiter.api.Test + +/** + * 运行该测试类即可查询此 Kotlin Puzzle 的详细信息。 + */ +class Catalog { + @Test + fun getCatalog() { + CatalogStructure.printAllMessage() + } +} \ No newline at end of file diff --git a/src/test/kotlin/io/github/sor2171/puzzles/alphabet/First.kt b/src/test/kotlin/io/github/sor2171/puzzles/alphabet/First.kt new file mode 100644 index 0000000..3c16c32 --- /dev/null +++ b/src/test/kotlin/io/github/sor2171/puzzles/alphabet/First.kt @@ -0,0 +1,29 @@ +@file:SkipCompile(skip = false) + +package io.github.sor2171.puzzles.alphabet + +import io.github.sor2171.puzzles.annotation.SkipCompile +import io.github.sor2171.puzzles.service.RandomGenerator +import org.junit.jupiter.api.Test + +class First { + val randoms = RandomGenerator( + "a" to Int::class, + "b" to Double::class, + ) + + @Test + fun puzzle() { + // write start 1 + val a = randoms["a"] + // write end 1 + + assert( a == randoms["a"]) + + // write start 2 + val b = randoms["b"] + // write end 2 + + assert( b == randoms["b"]) + } +} \ No newline at end of file diff --git a/src/test/kotlin/io/github/sor2171/puzzles/extend/TestLifecycleLoggerExtension.kt b/src/test/kotlin/io/github/sor2171/puzzles/extend/TestLifecycleLoggerExtension.kt new file mode 100644 index 0000000..ba36072 --- /dev/null +++ b/src/test/kotlin/io/github/sor2171/puzzles/extend/TestLifecycleLoggerExtension.kt @@ -0,0 +1,22 @@ +package io.github.sor2171.puzzles.extend + +import org.junit.jupiter.api.extension.AfterAllCallback +import org.junit.jupiter.api.extension.BeforeAllCallback +import org.junit.jupiter.api.extension.ExtensionContext + +class TestLifecycleLoggerExtension : BeforeAllCallback, AfterAllCallback { + + override fun beforeAll(context: ExtensionContext) { + val testClassName = context.requiredTestClass.simpleName + println() + println("=== [START] $testClassName ===") + println() + } + + override fun afterAll(context: ExtensionContext) { + val testClassName = context.requiredTestClass.simpleName + println() + println("=== [ END ] $testClassName ===") + println() + } +} \ No newline at end of file diff --git a/src/test/kotlin/io/github/sor2171/puzzles/extra/FirstExtra.kt b/src/test/kotlin/io/github/sor2171/puzzles/extra/FirstExtra.kt new file mode 100644 index 0000000..c44e902 --- /dev/null +++ b/src/test/kotlin/io/github/sor2171/puzzles/extra/FirstExtra.kt @@ -0,0 +1,8 @@ +@file:SkipCompile(skip = true) + +package io.github.sor2171.puzzles.extra + +import io.github.sor2171.puzzles.annotation.SkipCompile + +class FirstExtra { +} \ No newline at end of file diff --git a/src/test/kotlin/io/github/sor2171/puzzles/hyper/Second.kt b/src/test/kotlin/io/github/sor2171/puzzles/hyper/Second.kt new file mode 100644 index 0000000..8b8cd5b --- /dev/null +++ b/src/test/kotlin/io/github/sor2171/puzzles/hyper/Second.kt @@ -0,0 +1,11 @@ +@file:SkipCompile(skip = true) + +package io.github.sor2171.puzzles.hyper + +import io.github.sor2171.puzzles.annotation.SkipCompile +import org.junit.jupiter.api.Test + +class Second { + @Test + fun () {} +} \ No newline at end of file diff --git a/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension b/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension new file mode 100644 index 0000000..f7bc063 --- /dev/null +++ b/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension @@ -0,0 +1 @@ +io.github.sor2171.puzzles.extend.TestLifecycleLoggerExtension \ No newline at end of file diff --git a/src/test/resources/junit-platform.properties b/src/test/resources/junit-platform.properties new file mode 100644 index 0000000..6efc0d5 --- /dev/null +++ b/src/test/resources/junit-platform.properties @@ -0,0 +1 @@ +junit.jupiter.extensions.autodetection.enabled=true