diff --git a/build.gradle.kts b/build.gradle.kts index 5dfc6ac..97cba33 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,7 +6,7 @@ plugins { } group = "com.mapk" -version = "0.11" +version = "0.12" java { sourceCompatibility = JavaVersion.VERSION_1_8 diff --git a/src/main/kotlin/com/mapk/core/ArgumentAdaptor.kt b/src/main/kotlin/com/mapk/core/ArgumentAdaptor.kt index 1887633..b011f1c 100644 --- a/src/main/kotlin/com/mapk/core/ArgumentAdaptor.kt +++ b/src/main/kotlin/com/mapk/core/ArgumentAdaptor.kt @@ -13,7 +13,7 @@ class ArgumentAdaptor(private val requiredParameters: Map) { override val isOptional: Boolean, override val name: String, override val requiredClazz: KClass - ) : ArgumentBinder(annotations), - ValueParameter { + ) : ArgumentBinder(annotations), ValueParameter { override fun bindArgument(adaptor: ArgumentAdaptor, valueArray: Array): Boolean { return if (adaptor.isInitialized(name)) { valueArray[index] = adaptor.readout(name) diff --git a/src/main/kotlin/com/mapk/core/internal/ArgumentBucket.kt b/src/main/kotlin/com/mapk/core/internal/ArgumentBucket.kt index 82f8457..fa7d1b1 100644 --- a/src/main/kotlin/com/mapk/core/internal/ArgumentBucket.kt +++ b/src/main/kotlin/com/mapk/core/internal/ArgumentBucket.kt @@ -17,8 +17,7 @@ internal class ArgumentBucket( override var value: Any? ) : Map.Entry - private val initializationStatusManager = - InitializationStatusManager(initializationStatus) + private val initializationStatusManager = InitializationStatusManager(initializationStatus) val isInitialized: Boolean override val size: Int @@ -32,9 +31,7 @@ internal class ArgumentBucket( size = initializationStatusManager.count } - override fun containsKey(key: KParameter): Boolean { - return initializationStatusManager.isInitialized(key.index) - } + override fun containsKey(key: KParameter): Boolean = initializationStatusManager.isInitialized(key.index) override fun containsValue(value: Any?): Boolean = valueArray.any { Objects.equals(value, it) } diff --git a/src/main/kotlin/com/mapk/core/internal/BucketGenerator.kt b/src/main/kotlin/com/mapk/core/internal/BucketGenerator.kt index 2b87e1c..b73b2de 100644 --- a/src/main/kotlin/com/mapk/core/internal/BucketGenerator.kt +++ b/src/main/kotlin/com/mapk/core/internal/BucketGenerator.kt @@ -36,20 +36,20 @@ internal class BucketGenerator( } fun generate(adaptor: ArgumentAdaptor): ArgumentBucket = - ArgumentBucket( - parameters, originalValueArray.clone(), originalInitializationStatus.clone(), binders, adaptor - ) + ArgumentBucket(parameters, originalValueArray.clone(), originalInitializationStatus.clone(), binders, adaptor) } private fun KParameter.toArgumentBinder(parameterNameConverter: ParameterNameConverter): ArgumentBinder { val name = getAliasOrName()!! return findAnnotation()?.let { annotation -> - // 名前の変換処理、結合が必要な場合はインスタンスを持ってきて対応する + // 名前の変換処理 val converter: ParameterNameConverter = if (annotation.fieldNameToPrefix) { + // 結合が必要な場合は結合機能のインスタンスを持ってきて対応する parameterNameConverter.nest(name, annotation.nameJoiner.objectInstance!!) } else { - parameterNameConverter + // プレフィックスを要求しない場合は全てsimpleでマップするように修正 + parameterNameConverter.toSimple() } ArgumentBinder.Function((type.classifier as KClass<*>).toKConstructor(converter), index, annotations) diff --git a/src/main/kotlin/com/mapk/core/internal/Functions.kt b/src/main/kotlin/com/mapk/core/internal/Functions.kt index 89f160f..47bf781 100644 --- a/src/main/kotlin/com/mapk/core/internal/Functions.kt +++ b/src/main/kotlin/com/mapk/core/internal/Functions.kt @@ -5,6 +5,7 @@ import com.mapk.annotations.KUseDefaultArgument import java.lang.IllegalArgumentException import kotlin.reflect.KParameter import kotlin.reflect.full.findAnnotation +import kotlin.reflect.jvm.jvmName /** * パラメータからエイリアスもしくはプロパティ名を取得する関数 @@ -16,9 +17,9 @@ internal fun KParameter.getAliasOrName(): String? = findAnnotation String abstract fun convert(name: String): String abstract fun nest(infix: String, nameJoiner: NameJoiner): WithPrefix + abstract fun toSimple(): Simple class Simple(override val converter: (String) -> String) : ParameterNameConverter() { override fun convert(name: String) = converter(name) - override fun nest(infix: String, nameJoiner: NameJoiner) = - WithPrefix(infix, nameJoiner, converter) + override fun nest(infix: String, nameJoiner: NameJoiner) = WithPrefix(infix, nameJoiner, converter) + override fun toSimple(): Simple = this } class WithPrefix( @@ -22,11 +23,7 @@ internal sealed class ParameterNameConverter { // 結合を伴う変換では、「双方変換 -> 結合」の順で処理を行う override fun convert(name: String) = converter(name).let { nameJoiner.join(prefix, it) } - override fun nest(infix: String, nameJoiner: NameJoiner) = - WithPrefix( - convert(infix), - nameJoiner, - converter - ) + override fun nest(infix: String, nameJoiner: NameJoiner) = WithPrefix(convert(infix), nameJoiner, converter) + override fun toSimple(): Simple = Simple(converter) } } diff --git a/src/test/kotlin/com/mapk/core/ArgumentAdaptorTest.kt b/src/test/kotlin/com/mapk/core/ArgumentAdaptorTest.kt new file mode 100644 index 0000000..f13c379 --- /dev/null +++ b/src/test/kotlin/com/mapk/core/ArgumentAdaptorTest.kt @@ -0,0 +1,96 @@ +package com.mapk.core + +import io.mockk.every +import io.mockk.mockk +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertFalse +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Nested +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows + +@DisplayName("ArgumentAdaptorのテスト") +class ArgumentAdaptorTest { + private val keys = listOf("foo", "bar", "baz") + private val adaptor: ArgumentAdaptor = keys.mapIndexed { i, argName -> + mockk> { + every { name } returns argName + every { isNullable } returns (i % 2 == 0) + } + }.associateBy { + it.name + }.let { ArgumentAdaptor(it) } + + @Nested + @DisplayName("値をバインドするテスト") + inner class PutIfAbsentTest { + @Nested + @DisplayName("Null入力") + inner class NullabilityTest { + @Test + @DisplayName("nullableかつnull入力") + fun isNullableAndNull() { + adaptor.putIfAbsent(keys[0], null) + assertTrue(adaptor.isInitialized(keys[0])) + } + + @Test + @DisplayName("non-nullかつnull入力") + fun isNonNullAndNull() { + adaptor.putIfAbsent(keys[1], null) + assertFalse(adaptor.isInitialized(keys[0])) + } + + @Test + @DisplayName("2重バインドテスト") + fun isDuplicateKey() { + adaptor.putIfAbsent(keys[0], keys[0]) + adaptor.putIfAbsent(keys[0], keys[1]) + assertEquals(keys[0], adaptor.readout(keys[0])) + } + } + } + + @Nested + @DisplayName("完全初期化チェックのテスト") + inner class IsFullInitializedTest { + @Test + @DisplayName("完全初期化していない場合") + fun isNotFullInitialized() { + adaptor.putIfAbsent(keys[0], keys[0]) + adaptor.putIfAbsent(keys[1], keys[1]) + assertFalse(adaptor.isFullInitialized()) + } + + @Test + @DisplayName("完全初期化した場合") + fun isFullInitialized() { + keys.forEach { adaptor.putIfAbsent(it, it) } + assertTrue(adaptor.isFullInitialized()) + } + } + + @Nested + @DisplayName("存在しないkeyの読み出しテスト") + inner class NotContainsKeyTest { + @Test + @DisplayName("isInitializedのテスト") + fun isInitialized() { + assertThrows { adaptor.isInitialized("hoge") } + } + + @Test + @DisplayName("putIfAbsentのテスト") + fun putIfAbsent() { + assertThrows { adaptor.putIfAbsent("hoge", "hoge") } + } + } + + @Test + @DisplayName("読み出しテスト") + fun readoutTest() { + keys.forEach { adaptor.putIfAbsent(it, it) } + keys.forEach { assertEquals(it, adaptor.readout(it)) } + } +} diff --git a/src/test/kotlin/com/mapk/core/KParameterFlattenTest.kt b/src/test/kotlin/com/mapk/core/KParameterFlattenTest.kt index 4de59a3..a3582a3 100644 --- a/src/test/kotlin/com/mapk/core/KParameterFlattenTest.kt +++ b/src/test/kotlin/com/mapk/core/KParameterFlattenTest.kt @@ -11,7 +11,8 @@ import org.junit.jupiter.api.Test @DisplayName("パラメータのフラット化テスト") class KParameterFlattenTest { - data class InnerDst1(val quxQux: Int) + data class InnerDst1(val quxQux: Int, @KParameterFlatten(fieldNameToPrefix = false) val fredFred: InnerInnerDst) + data class InnerInnerDst(val waldoWaldo: Int) data class InnerDst2(val quuxQuux: Int) data class InnerDst3(val graultGrault: String) { @KConstructor @@ -31,8 +32,14 @@ class KParameterFlattenTest { companion object { val expectedParams: Set = - linkedSetOf("fooFoo", "barBar", "bazBazQuxQux", "quuxQuux", "garplyGarply-graultGrault") - val expected: Dst = Dst(0, 1, InnerDst1(2), InnerDst2(3), InnerDst3("4")) + linkedSetOf("fooFoo", "barBar", "bazBazQuxQux", "waldoWaldo", "quuxQuux", "garplyGarply-graultGrault") + val expected: Dst = Dst( + 0, + 1, + InnerDst1(2, InnerInnerDst(3)), + InnerDst2(4), + InnerDst3("5") + ) } @Test diff --git a/src/test/kotlin/com/mapk/core/internal/ParameterNameConverterTest.kt b/src/test/kotlin/com/mapk/core/internal/ParameterNameConverterTest.kt new file mode 100644 index 0000000..66b8e91 --- /dev/null +++ b/src/test/kotlin/com/mapk/core/internal/ParameterNameConverterTest.kt @@ -0,0 +1,84 @@ +package com.mapk.core.internal + +import com.mapk.core.NameJoiner +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Nested +import org.junit.jupiter.api.Test + +@DisplayName("パラメータ名変換関連のテスト") +class ParameterNameConverterTest { + @Nested + @DisplayName("シンプルな変換機能のテスト") + inner class SimpleTest { + private val simple = ParameterNameConverter.Simple { it.toLowerCase() } + + @Test + @DisplayName("単純な変換テスト") + fun convertTest() { + val expected = "abcdef" + val actual = simple.convert("AbCdEf") + assertEquals(expected, actual) + } + + @Test + @DisplayName("ネストしたインスタンスを作るテスト") + fun nestTest() { + val nested1 = simple.nest("AbCdEf", NameJoiner.Kebab) + run { + val expected = "abcdef-ghijkl" + val actual = nested1.convert("gHiJkL") + assertEquals(expected, actual) + } + + val nested2 = nested1.nest("gHiJkL", NameJoiner.Snake) + run { + val expected = "abcdef-ghijkl_mnopqr" + val actual = nested2.convert("MNopQR") + assertEquals(expected, actual) + } + } + + @Test + @DisplayName("Simpleにした場合のテスト") + fun simple() { + val simple2 = simple.toSimple() + assertEquals(simple, simple2) + } + } + + @Nested + @DisplayName("プレフィックス付き変換機能のテスト") + inner class WithPrefixTest { + private val withPrefix = + ParameterNameConverter.WithPrefix("abcdef", NameJoiner.Snake) { it.toUpperCase() } + + @Test + @DisplayName("単純な変換テスト") + fun convertTest() { + val expected = "ABCDEF_GHIJKL" + val actual = withPrefix.convert("GhIJkL") + assertEquals(expected, actual) + } + + @Test + @DisplayName("ネストしたインスタンスを作るテスト") + fun nestTest() { + val nested = withPrefix.nest("GhIJkL", NameJoiner.Kebab) + run { + val expected = "ABCDEF_GHIJKL-MNOPQR" + val actual = nested.convert("mnOpQr") + assertEquals(expected, actual) + } + } + + @Test + @DisplayName("Simpleにした場合のテスト") + fun simple() { + val simple = withPrefix.toSimple() + val expected = "ABCDEF" + val actual = simple.convert(expected) + assertEquals(expected, actual) + } + } +}