diff --git a/AGENTS.md b/AGENTS.md index 942859bc..55928abd 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -4,7 +4,7 @@ "some" is a Kotlin test data generation library that creates random instances of data classes, sealed classes/interfaces, collections, and primitive types. It uses a resolver chain pattern -where each TypeResolver handles specific types. +where each Resolver handles specific types. **Tech Stack:** - Kotlin (JVM) diff --git a/README.md b/README.md index fb2af95a..906b8346 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ val user = some() - **Universal type support** — Works with data classes, sealed classes/interfaces, object singletons, value classes, generics, and all standard collections. If Kotlin can represent it, Some can generate it. - **Nested and recursive structures** — Handles deeply nested data classes, circular references, and recursive sealed class hierarchies without infinite loops. - **Fine-grained control** — Override how specific fields are generated: control nullable probability, string format, collection sizes, register custom type factories for types, or use property factories for individual fields. -- **Extensible** — Ship custom `TypeResolverProvider` implementations discovered via `ServiceLoader` to add support for domain-specific, third-party, or internal application types — with custom strategies and no consumer configuration required. +- **Extensible** — Ship custom `ResolverProvider` implementations discovered via `ServiceLoader` to add support for domain-specific, third-party, or internal application types — with custom strategies and no consumer configuration required. - **Deterministic by choice** — Set a seed for reproducible test data across runs, or default to random for variation. ## Installation diff --git a/android/build.gradle.kts b/android/build.gradle.kts index 5d7fbf2c..f4bd4028 100644 --- a/android/build.gradle.kts +++ b/android/build.gradle.kts @@ -32,7 +32,9 @@ detekt { autoCorrect = true } dependencies { implementation(projects.core) + testImplementation(libs.androidx.compose.ui) testImplementation(libs.junit) + testImplementation(libs.kotlin.test) detektPlugins(libs.detekt.formatting) -} \ No newline at end of file +} diff --git a/android/src/main/java/dev/appoutlet/some/android/AndroidResolverProvider.kt b/android/src/main/java/dev/appoutlet/some/android/AndroidResolverProvider.kt index 7640b3a1..dff7f432 100644 --- a/android/src/main/java/dev/appoutlet/some/android/AndroidResolverProvider.kt +++ b/android/src/main/java/dev/appoutlet/some/android/AndroidResolverProvider.kt @@ -1,15 +1,15 @@ package dev.appoutlet.some.android +import dev.appoutlet.some.core.Resolver +import dev.appoutlet.some.core.ResolverProvider import dev.appoutlet.some.core.StrategyProvider -import dev.appoutlet.some.core.TypeResolver -import dev.appoutlet.some.core.TypeResolverProvider import kotlin.random.Random -class AndroidResolverProvider : TypeResolverProvider { +class AndroidResolverProvider : ResolverProvider { override fun createResolvers( strategyProvider: StrategyProvider, random: Random - ): List { + ): List { return emptyList() } } diff --git a/android/src/main/resources/META-INF/services/dev.appoutlet.some.core.ResolverProvider b/android/src/main/resources/META-INF/services/dev.appoutlet.some.core.ResolverProvider new file mode 100644 index 00000000..9048b9f4 --- /dev/null +++ b/android/src/main/resources/META-INF/services/dev.appoutlet.some.core.ResolverProvider @@ -0,0 +1 @@ +dev.appoutlet.some.android.AndroidResolverProvider \ No newline at end of file diff --git a/android/src/test/java/dev/appoutlet/some/android/AndroidServiceLoaderTest.kt b/android/src/test/java/dev/appoutlet/some/android/AndroidServiceLoaderTest.kt new file mode 100644 index 00000000..773a4bde --- /dev/null +++ b/android/src/test/java/dev/appoutlet/some/android/AndroidServiceLoaderTest.kt @@ -0,0 +1,13 @@ +package dev.appoutlet.some.android + +import dev.appoutlet.some.some +import org.junit.Assert.assertTrue +import org.junit.Test + +class AndroidServiceLoaderTest { + @Test + fun `top-level some also works with AndroidTypeResolverProvider`() { + val result: String = some() + assertTrue("Generated string should not be empty", result.isNotEmpty()) + } +} diff --git a/core/src/main/kotlin/dev/appoutlet/some/Some.kt b/core/src/main/kotlin/dev/appoutlet/some/Some.kt index d074b305..0ba1b500 100644 --- a/core/src/main/kotlin/dev/appoutlet/some/Some.kt +++ b/core/src/main/kotlin/dev/appoutlet/some/Some.kt @@ -4,8 +4,8 @@ import dev.appoutlet.some.config.NullableStrategy import dev.appoutlet.some.config.SomeConfig import dev.appoutlet.some.config.SomeConfigBuilder import dev.appoutlet.some.config.buildSomeConfig +import dev.appoutlet.some.core.Resolver import dev.appoutlet.some.core.ResolverChain -import dev.appoutlet.some.core.TypeResolver import kotlin.random.Random import kotlin.reflect.typeOf @@ -19,7 +19,7 @@ import kotlin.reflect.typeOf * @param config Configuration used by this generator. */ class Some( - val resolvers: List, + val resolvers: List, val random: Random, val config: SomeConfig ) { @@ -83,7 +83,7 @@ val defaultConfig: SomeConfig by lazy { SomeConfig() } /** * Lazily-created default resolver chain used by top-level [some]. */ -val defaultResolvers: List by lazy { defaultConfig.buildResolvers() } +val defaultResolvers: List by lazy { defaultConfig.buildResolvers() } /** * Generates a fixture value using the default configuration. diff --git a/core/src/main/kotlin/dev/appoutlet/some/config/SomeConfig.kt b/core/src/main/kotlin/dev/appoutlet/some/config/SomeConfig.kt index 7d7c429e..631dd6f7 100644 --- a/core/src/main/kotlin/dev/appoutlet/some/config/SomeConfig.kt +++ b/core/src/main/kotlin/dev/appoutlet/some/config/SomeConfig.kt @@ -1,9 +1,9 @@ package dev.appoutlet.some.config import dev.appoutlet.some.core.FixtureContext +import dev.appoutlet.some.core.Resolver +import dev.appoutlet.some.core.ResolverProvider import dev.appoutlet.some.core.StrategyProvider -import dev.appoutlet.some.core.TypeResolver -import dev.appoutlet.some.core.TypeResolverProvider import dev.appoutlet.some.logging.logger import dev.appoutlet.some.resolver.ArrayResolver import dev.appoutlet.some.resolver.BigDecimalResolver @@ -12,7 +12,7 @@ import dev.appoutlet.some.resolver.BooleanResolver import dev.appoutlet.some.resolver.ByteResolver import dev.appoutlet.some.resolver.CharResolver import dev.appoutlet.some.resolver.ClassResolver -import dev.appoutlet.some.resolver.CustomTypeFactoryResolver +import dev.appoutlet.some.resolver.CustomFactoryResolver import dev.appoutlet.some.resolver.DoubleResolver import dev.appoutlet.some.resolver.EnumResolver import dev.appoutlet.some.resolver.FloatResolver @@ -92,7 +92,7 @@ data class SomeConfig( * * Resolver order defines precedence: the first resolver that supports a type is used. * - * 1. [CustomTypeFactoryResolver] is first so explicit user factories override everything. + * 1. [CustomFactoryResolver] is first so explicit user factories override everything. * 2. [NullableResolver] handles nullable wrappers before any concrete type resolver. * 3. Third-party resolvers discovered via [java.util.ServiceLoader] come next, allowing external libraries to * override built-in behavior for basic types. @@ -104,9 +104,9 @@ data class SomeConfig( * This keeps resolver construction free of strategy-specific knowledge. * * @param random Random source shared by resolvers that generate randomized values. - * @return The ordered [TypeResolver] list for this configuration. + * @return The ordered [Resolver] list for this configuration. */ - fun buildResolvers(random: Random = buildRandom()): List { + fun buildResolvers(random: Random = buildRandom()): List { val builtInResolvers = listOf( ObjectResolver(), EnumResolver(random), @@ -143,13 +143,13 @@ data class SomeConfig( val discoveredResolvers = discoverResolvers(strategyProvider, random) return listOf( - CustomTypeFactoryResolver(strategyProvider, typeFactories, random), + CustomFactoryResolver(strategyProvider, typeFactories, random), NullableResolver(strategyProvider, random), ) + discoveredResolvers + builtInResolvers + ClassResolver(strategyProvider, propertyFactories, random) } /** - * Discovers additional [TypeResolver]s from third-party libraries via [java.util.ServiceLoader]. + * Discovers additional [Resolver]s from third-party libraries via [java.util.ServiceLoader]. * * Failures during discovery or provider instantiation are swallowed so the library always falls back to the * built-in resolver chain. @@ -162,9 +162,9 @@ data class SomeConfig( private fun discoverResolvers( strategyProvider: StrategyProvider, random: Random, - ): List { - val loader = ServiceLoader.load(TypeResolverProvider::class.java) - val providers = mutableListOf() + ): List { + val loader = ServiceLoader.load(ResolverProvider::class.java) + val providers = mutableListOf() val iterator = loader.iterator() while (iterator.hasNext()) { diff --git a/core/src/main/kotlin/dev/appoutlet/some/core/TypeResolver.kt b/core/src/main/kotlin/dev/appoutlet/some/core/Resolver.kt similarity index 94% rename from core/src/main/kotlin/dev/appoutlet/some/core/TypeResolver.kt rename to core/src/main/kotlin/dev/appoutlet/some/core/Resolver.kt index ba026af7..a4b5259f 100644 --- a/core/src/main/kotlin/dev/appoutlet/some/core/TypeResolver.kt +++ b/core/src/main/kotlin/dev/appoutlet/some/core/Resolver.kt @@ -5,7 +5,7 @@ import kotlin.reflect.KType /** * Resolves a requested [KType] into a generated value. */ -interface TypeResolver { +interface Resolver { /** * Returns whether this resolver can generate a value for [type]. */ diff --git a/core/src/main/kotlin/dev/appoutlet/some/core/ResolverChain.kt b/core/src/main/kotlin/dev/appoutlet/some/core/ResolverChain.kt index b2f0ba8e..b3898810 100644 --- a/core/src/main/kotlin/dev/appoutlet/some/core/ResolverChain.kt +++ b/core/src/main/kotlin/dev/appoutlet/some/core/ResolverChain.kt @@ -15,7 +15,7 @@ import kotlin.reflect.KType * @param nullableStrategy Strategy used when a circular reference is detected for a nullable type. */ class ResolverChain( - val resolvers: List, + val resolvers: List, nullableStrategy: NullableStrategy?, ) { private val nullableStrategy = nullableStrategy ?: NullableStrategy.default diff --git a/core/src/main/kotlin/dev/appoutlet/some/core/TypeResolverProvider.kt b/core/src/main/kotlin/dev/appoutlet/some/core/ResolverProvider.kt similarity index 82% rename from core/src/main/kotlin/dev/appoutlet/some/core/TypeResolverProvider.kt rename to core/src/main/kotlin/dev/appoutlet/some/core/ResolverProvider.kt index 4ce0f58a..a91efccb 100644 --- a/core/src/main/kotlin/dev/appoutlet/some/core/TypeResolverProvider.kt +++ b/core/src/main/kotlin/dev/appoutlet/some/core/ResolverProvider.kt @@ -3,17 +3,17 @@ package dev.appoutlet.some.core import kotlin.random.Random /** - * Service-provider interface for contributing [TypeResolver]s to the fixture generation chain. + * Service-provider interface for contributing [Resolver]s to the fixture generation chain. * * Implementations are discovered at runtime via [java.util.ServiceLoader]. Third-party libraries * can ship their own provider to extend `Some` without requiring users to write configuration. * * Contributed resolvers are inserted between [NullableResolver][dev.appoutlet.some.resolver.NullableResolver] * and the built-in resolvers, giving them priority over built-in type handling while still allowing - * user-registered type factories ([CustomTypeFactoryResolver][dev.appoutlet.some.resolver.CustomTypeFactoryResolver]) + * user-registered type factories ([CustomTypeFactoryResolver][dev.appoutlet.some.resolver.CustomFactoryResolver]) * to take precedence. */ -interface TypeResolverProvider { +interface ResolverProvider { /** * Creates resolvers to be contributed to the fixture generation chain. * @@ -24,5 +24,5 @@ interface TypeResolverProvider { fun createResolvers( strategyProvider: StrategyProvider, random: Random, - ): List + ): List } diff --git a/core/src/main/kotlin/dev/appoutlet/some/resolver/ArrayResolver.kt b/core/src/main/kotlin/dev/appoutlet/some/resolver/ArrayResolver.kt index e79d9357..d14c1b19 100644 --- a/core/src/main/kotlin/dev/appoutlet/some/resolver/ArrayResolver.kt +++ b/core/src/main/kotlin/dev/appoutlet/some/resolver/ArrayResolver.kt @@ -1,9 +1,9 @@ package dev.appoutlet.some.resolver import dev.appoutlet.some.config.CollectionStrategy +import dev.appoutlet.some.core.Resolver import dev.appoutlet.some.core.ResolverChain import dev.appoutlet.some.core.StrategyProvider -import dev.appoutlet.some.core.TypeResolver import dev.appoutlet.some.core.get import kotlin.random.Random import kotlin.reflect.KClass @@ -18,7 +18,7 @@ import kotlin.reflect.KType class ArrayResolver( strategyProvider: StrategyProvider, private val random: Random -) : TypeResolver { +) : Resolver { private val collectionStrategy = strategyProvider.get() ?: CollectionStrategy.default override fun canResolve(type: KType): Boolean { diff --git a/core/src/main/kotlin/dev/appoutlet/some/resolver/BigDecimalResolver.kt b/core/src/main/kotlin/dev/appoutlet/some/resolver/BigDecimalResolver.kt index 32c0af71..a089509c 100644 --- a/core/src/main/kotlin/dev/appoutlet/some/resolver/BigDecimalResolver.kt +++ b/core/src/main/kotlin/dev/appoutlet/some/resolver/BigDecimalResolver.kt @@ -1,13 +1,13 @@ package dev.appoutlet.some.resolver +import dev.appoutlet.some.core.Resolver import dev.appoutlet.some.core.ResolverChain -import dev.appoutlet.some.core.TypeResolver import java.math.BigDecimal import kotlin.random.Random import kotlin.reflect.KType import kotlin.reflect.typeOf -class BigDecimalResolver(val random: Random) : TypeResolver { +class BigDecimalResolver(val random: Random) : Resolver { override fun canResolve(type: KType): Boolean { return type == typeOf() } diff --git a/core/src/main/kotlin/dev/appoutlet/some/resolver/BigIntegerResolver.kt b/core/src/main/kotlin/dev/appoutlet/some/resolver/BigIntegerResolver.kt index 37334a69..9cad341c 100644 --- a/core/src/main/kotlin/dev/appoutlet/some/resolver/BigIntegerResolver.kt +++ b/core/src/main/kotlin/dev/appoutlet/some/resolver/BigIntegerResolver.kt @@ -1,13 +1,13 @@ package dev.appoutlet.some.resolver +import dev.appoutlet.some.core.Resolver import dev.appoutlet.some.core.ResolverChain -import dev.appoutlet.some.core.TypeResolver import java.math.BigInteger import kotlin.random.Random import kotlin.reflect.KType import kotlin.reflect.typeOf -class BigIntegerResolver(val random: Random) : TypeResolver { +class BigIntegerResolver(val random: Random) : Resolver { override fun canResolve(type: KType): Boolean { return type == typeOf() } diff --git a/core/src/main/kotlin/dev/appoutlet/some/resolver/BooleanResolver.kt b/core/src/main/kotlin/dev/appoutlet/some/resolver/BooleanResolver.kt index ba3d1640..2528b511 100644 --- a/core/src/main/kotlin/dev/appoutlet/some/resolver/BooleanResolver.kt +++ b/core/src/main/kotlin/dev/appoutlet/some/resolver/BooleanResolver.kt @@ -1,12 +1,12 @@ package dev.appoutlet.some.resolver +import dev.appoutlet.some.core.Resolver import dev.appoutlet.some.core.ResolverChain -import dev.appoutlet.some.core.TypeResolver import kotlin.random.Random import kotlin.reflect.KType import kotlin.reflect.typeOf -class BooleanResolver(val random: Random) : TypeResolver { +class BooleanResolver(val random: Random) : Resolver { override fun canResolve(type: KType): Boolean = type == typeOf() override fun resolve(type: KType, chain: ResolverChain): Any { diff --git a/core/src/main/kotlin/dev/appoutlet/some/resolver/ByteResolver.kt b/core/src/main/kotlin/dev/appoutlet/some/resolver/ByteResolver.kt index c7962193..b5e9069d 100644 --- a/core/src/main/kotlin/dev/appoutlet/some/resolver/ByteResolver.kt +++ b/core/src/main/kotlin/dev/appoutlet/some/resolver/ByteResolver.kt @@ -1,12 +1,12 @@ package dev.appoutlet.some.resolver +import dev.appoutlet.some.core.Resolver import dev.appoutlet.some.core.ResolverChain -import dev.appoutlet.some.core.TypeResolver import kotlin.random.Random import kotlin.reflect.KType import kotlin.reflect.typeOf -class ByteResolver(val random: Random) : TypeResolver { +class ByteResolver(val random: Random) : Resolver { override fun canResolve(type: KType): Boolean = type == typeOf() override fun resolve(type: KType, chain: ResolverChain): Any { diff --git a/core/src/main/kotlin/dev/appoutlet/some/resolver/CharResolver.kt b/core/src/main/kotlin/dev/appoutlet/some/resolver/CharResolver.kt index cf3bf76c..e76428b8 100644 --- a/core/src/main/kotlin/dev/appoutlet/some/resolver/CharResolver.kt +++ b/core/src/main/kotlin/dev/appoutlet/some/resolver/CharResolver.kt @@ -1,12 +1,12 @@ package dev.appoutlet.some.resolver +import dev.appoutlet.some.core.Resolver import dev.appoutlet.some.core.ResolverChain -import dev.appoutlet.some.core.TypeResolver import kotlin.random.Random import kotlin.reflect.KType import kotlin.reflect.typeOf -class CharResolver(val random: Random) : TypeResolver { +class CharResolver(val random: Random) : Resolver { override fun canResolve(type: KType): Boolean = type == typeOf() override fun resolve(type: KType, chain: ResolverChain): Any { diff --git a/core/src/main/kotlin/dev/appoutlet/some/resolver/ClassResolver.kt b/core/src/main/kotlin/dev/appoutlet/some/resolver/ClassResolver.kt index 55087b8f..26cc2155 100644 --- a/core/src/main/kotlin/dev/appoutlet/some/resolver/ClassResolver.kt +++ b/core/src/main/kotlin/dev/appoutlet/some/resolver/ClassResolver.kt @@ -2,9 +2,9 @@ package dev.appoutlet.some.resolver import dev.appoutlet.some.config.DefaultValueStrategy import dev.appoutlet.some.core.FixtureContext +import dev.appoutlet.some.core.Resolver import dev.appoutlet.some.core.ResolverChain import dev.appoutlet.some.core.StrategyProvider -import dev.appoutlet.some.core.TypeResolver import dev.appoutlet.some.core.get import dev.appoutlet.some.exception.SomeCircularReferenceException import dev.appoutlet.some.exception.SomeInstantiationException @@ -48,7 +48,7 @@ class ClassResolver( private val strategyProvider: StrategyProvider, private val propertyFactories: Map, String>, FixtureContext.() -> Any?> = emptyMap(), private val random: Random = Random.Default, -) : TypeResolver { +) : Resolver { private val logger by logger() private val defaultValueStrategy = strategyProvider.get() ?: DefaultValueStrategy.default diff --git a/core/src/main/kotlin/dev/appoutlet/some/resolver/CustomTypeFactoryResolver.kt b/core/src/main/kotlin/dev/appoutlet/some/resolver/CustomFactoryResolver.kt similarity index 96% rename from core/src/main/kotlin/dev/appoutlet/some/resolver/CustomTypeFactoryResolver.kt rename to core/src/main/kotlin/dev/appoutlet/some/resolver/CustomFactoryResolver.kt index e6d16ab2..6780fa2c 100644 --- a/core/src/main/kotlin/dev/appoutlet/some/resolver/CustomTypeFactoryResolver.kt +++ b/core/src/main/kotlin/dev/appoutlet/some/resolver/CustomFactoryResolver.kt @@ -1,9 +1,9 @@ package dev.appoutlet.some.resolver import dev.appoutlet.some.core.FixtureContext +import dev.appoutlet.some.core.Resolver import dev.appoutlet.some.core.ResolverChain import dev.appoutlet.some.core.StrategyProvider -import dev.appoutlet.some.core.TypeResolver import kotlin.random.Random import kotlin.reflect.KClass import kotlin.reflect.KType @@ -22,11 +22,11 @@ import kotlin.reflect.KType * @param typeFactories Map of classes to user-provided type factory functions. * @param random Random source exposed to type factories through [FixtureContext]. */ -class CustomTypeFactoryResolver( +class CustomFactoryResolver( private val strategyProvider: StrategyProvider, private val typeFactories: Map, FixtureContext.() -> Any?>, private val random: Random, -) : TypeResolver { +) : Resolver { /** * Returns whether [type] has a registered type factory. * diff --git a/core/src/main/kotlin/dev/appoutlet/some/resolver/DoubleResolver.kt b/core/src/main/kotlin/dev/appoutlet/some/resolver/DoubleResolver.kt index d12b64ab..3d6a9c8a 100644 --- a/core/src/main/kotlin/dev/appoutlet/some/resolver/DoubleResolver.kt +++ b/core/src/main/kotlin/dev/appoutlet/some/resolver/DoubleResolver.kt @@ -1,12 +1,12 @@ package dev.appoutlet.some.resolver +import dev.appoutlet.some.core.Resolver import dev.appoutlet.some.core.ResolverChain -import dev.appoutlet.some.core.TypeResolver import kotlin.random.Random import kotlin.reflect.KType import kotlin.reflect.typeOf -class DoubleResolver(val random: Random) : TypeResolver { +class DoubleResolver(val random: Random) : Resolver { override fun canResolve(type: KType): Boolean = type == typeOf() override fun resolve(type: KType, chain: ResolverChain): Any { diff --git a/core/src/main/kotlin/dev/appoutlet/some/resolver/EnumResolver.kt b/core/src/main/kotlin/dev/appoutlet/some/resolver/EnumResolver.kt index ae795e61..40b16623 100644 --- a/core/src/main/kotlin/dev/appoutlet/some/resolver/EnumResolver.kt +++ b/core/src/main/kotlin/dev/appoutlet/some/resolver/EnumResolver.kt @@ -1,12 +1,12 @@ package dev.appoutlet.some.resolver +import dev.appoutlet.some.core.Resolver import dev.appoutlet.some.core.ResolverChain -import dev.appoutlet.some.core.TypeResolver import kotlin.random.Random import kotlin.reflect.KClass import kotlin.reflect.KType -class EnumResolver(val random: Random) : TypeResolver { +class EnumResolver(val random: Random) : Resolver { override fun canResolve(type: KType): Boolean { val kClass = type.classifier as? KClass<*> ?: return false return kClass.java.isEnum diff --git a/core/src/main/kotlin/dev/appoutlet/some/resolver/FloatResolver.kt b/core/src/main/kotlin/dev/appoutlet/some/resolver/FloatResolver.kt index 1b830593..6da28d26 100644 --- a/core/src/main/kotlin/dev/appoutlet/some/resolver/FloatResolver.kt +++ b/core/src/main/kotlin/dev/appoutlet/some/resolver/FloatResolver.kt @@ -1,12 +1,12 @@ package dev.appoutlet.some.resolver +import dev.appoutlet.some.core.Resolver import dev.appoutlet.some.core.ResolverChain -import dev.appoutlet.some.core.TypeResolver import kotlin.random.Random import kotlin.reflect.KType import kotlin.reflect.typeOf -class FloatResolver(val random: Random) : TypeResolver { +class FloatResolver(val random: Random) : Resolver { override fun canResolve(type: KType): Boolean = type == typeOf() override fun resolve(type: KType, chain: ResolverChain): Any { diff --git a/core/src/main/kotlin/dev/appoutlet/some/resolver/IntResolver.kt b/core/src/main/kotlin/dev/appoutlet/some/resolver/IntResolver.kt index 2b4adcc0..31ceeb45 100644 --- a/core/src/main/kotlin/dev/appoutlet/some/resolver/IntResolver.kt +++ b/core/src/main/kotlin/dev/appoutlet/some/resolver/IntResolver.kt @@ -1,14 +1,14 @@ package dev.appoutlet.some.resolver +import dev.appoutlet.some.core.Resolver import dev.appoutlet.some.core.ResolverChain -import dev.appoutlet.some.core.TypeResolver import kotlin.random.Random import kotlin.reflect.KType import kotlin.reflect.typeOf class IntResolver( private val random: Random -) : TypeResolver { +) : Resolver { override fun canResolve(type: KType): Boolean = type == typeOf() override fun resolve(type: KType, chain: ResolverChain): Any { diff --git a/core/src/main/kotlin/dev/appoutlet/some/resolver/JavaDurationResolver.kt b/core/src/main/kotlin/dev/appoutlet/some/resolver/JavaDurationResolver.kt index 5513e7e2..a3e73656 100644 --- a/core/src/main/kotlin/dev/appoutlet/some/resolver/JavaDurationResolver.kt +++ b/core/src/main/kotlin/dev/appoutlet/some/resolver/JavaDurationResolver.kt @@ -1,13 +1,13 @@ package dev.appoutlet.some.resolver +import dev.appoutlet.some.core.Resolver import dev.appoutlet.some.core.ResolverChain -import dev.appoutlet.some.core.TypeResolver import java.time.Duration import kotlin.random.Random import kotlin.reflect.KType import kotlin.reflect.typeOf -class JavaDurationResolver(val random: Random) : TypeResolver { +class JavaDurationResolver(val random: Random) : Resolver { override fun canResolve(type: KType): Boolean { return type == typeOf() } diff --git a/core/src/main/kotlin/dev/appoutlet/some/resolver/JavaInstantResolver.kt b/core/src/main/kotlin/dev/appoutlet/some/resolver/JavaInstantResolver.kt index 4e9419f9..b3782097 100644 --- a/core/src/main/kotlin/dev/appoutlet/some/resolver/JavaInstantResolver.kt +++ b/core/src/main/kotlin/dev/appoutlet/some/resolver/JavaInstantResolver.kt @@ -1,13 +1,13 @@ package dev.appoutlet.some.resolver +import dev.appoutlet.some.core.Resolver import dev.appoutlet.some.core.ResolverChain -import dev.appoutlet.some.core.TypeResolver import java.time.Instant import kotlin.random.Random import kotlin.reflect.KType import kotlin.reflect.typeOf -class JavaInstantResolver(val random: Random) : TypeResolver { +class JavaInstantResolver(val random: Random) : Resolver { override fun canResolve(type: KType): Boolean { return type == typeOf() } diff --git a/core/src/main/kotlin/dev/appoutlet/some/resolver/JavaUuidResolver.kt b/core/src/main/kotlin/dev/appoutlet/some/resolver/JavaUuidResolver.kt index 51d67b75..ae973eb0 100644 --- a/core/src/main/kotlin/dev/appoutlet/some/resolver/JavaUuidResolver.kt +++ b/core/src/main/kotlin/dev/appoutlet/some/resolver/JavaUuidResolver.kt @@ -1,12 +1,12 @@ package dev.appoutlet.some.resolver +import dev.appoutlet.some.core.Resolver import dev.appoutlet.some.core.ResolverChain -import dev.appoutlet.some.core.TypeResolver import java.util.UUID import kotlin.reflect.KType import kotlin.reflect.typeOf -class JavaUuidResolver : TypeResolver { +class JavaUuidResolver : Resolver { override fun canResolve(type: KType): Boolean { return type == typeOf() } diff --git a/core/src/main/kotlin/dev/appoutlet/some/resolver/JavaZonedDateTimeResolver.kt b/core/src/main/kotlin/dev/appoutlet/some/resolver/JavaZonedDateTimeResolver.kt index d2454764..1192b16f 100644 --- a/core/src/main/kotlin/dev/appoutlet/some/resolver/JavaZonedDateTimeResolver.kt +++ b/core/src/main/kotlin/dev/appoutlet/some/resolver/JavaZonedDateTimeResolver.kt @@ -1,7 +1,7 @@ package dev.appoutlet.some.resolver +import dev.appoutlet.some.core.Resolver import dev.appoutlet.some.core.ResolverChain -import dev.appoutlet.some.core.TypeResolver import java.time.Instant import java.time.ZoneId import java.time.ZonedDateTime @@ -17,7 +17,7 @@ import kotlin.reflect.typeOf * * @param random The random source used for generation. */ -class JavaZonedDateTimeResolver(private val random: Random) : TypeResolver { +class JavaZonedDateTimeResolver(private val random: Random) : Resolver { private val zoneIds by lazy { ZoneId.getAvailableZoneIds().toList() } override fun canResolve(type: KType): Boolean { diff --git a/core/src/main/kotlin/dev/appoutlet/some/resolver/KotlinDurationResolver.kt b/core/src/main/kotlin/dev/appoutlet/some/resolver/KotlinDurationResolver.kt index 8f9ead76..38fa08de 100644 --- a/core/src/main/kotlin/dev/appoutlet/some/resolver/KotlinDurationResolver.kt +++ b/core/src/main/kotlin/dev/appoutlet/some/resolver/KotlinDurationResolver.kt @@ -1,7 +1,7 @@ package dev.appoutlet.some.resolver +import dev.appoutlet.some.core.Resolver import dev.appoutlet.some.core.ResolverChain -import dev.appoutlet.some.core.TypeResolver import kotlin.random.Random import kotlin.reflect.KType import kotlin.reflect.typeOf @@ -9,7 +9,7 @@ import kotlin.time.Duration import kotlin.time.Duration.Companion.days import kotlin.time.Duration.Companion.seconds -class KotlinDurationResolver(val random: Random) : TypeResolver { +class KotlinDurationResolver(val random: Random) : Resolver { override fun canResolve(type: KType): Boolean { return type == typeOf() } diff --git a/core/src/main/kotlin/dev/appoutlet/some/resolver/KotlinInstantResolver.kt b/core/src/main/kotlin/dev/appoutlet/some/resolver/KotlinInstantResolver.kt index eb903a00..c2d3e419 100644 --- a/core/src/main/kotlin/dev/appoutlet/some/resolver/KotlinInstantResolver.kt +++ b/core/src/main/kotlin/dev/appoutlet/some/resolver/KotlinInstantResolver.kt @@ -1,13 +1,13 @@ package dev.appoutlet.some.resolver +import dev.appoutlet.some.core.Resolver import dev.appoutlet.some.core.ResolverChain -import dev.appoutlet.some.core.TypeResolver import kotlin.random.Random import kotlin.reflect.KType import kotlin.reflect.typeOf import kotlin.time.Instant -class KotlinInstantResolver(val random: Random) : TypeResolver { +class KotlinInstantResolver(val random: Random) : Resolver { override fun canResolve(type: KType): Boolean { return type == typeOf() } diff --git a/core/src/main/kotlin/dev/appoutlet/some/resolver/KotlinUuidResolver.kt b/core/src/main/kotlin/dev/appoutlet/some/resolver/KotlinUuidResolver.kt index a80670a5..736e22a5 100644 --- a/core/src/main/kotlin/dev/appoutlet/some/resolver/KotlinUuidResolver.kt +++ b/core/src/main/kotlin/dev/appoutlet/some/resolver/KotlinUuidResolver.kt @@ -1,14 +1,14 @@ package dev.appoutlet.some.resolver +import dev.appoutlet.some.core.Resolver import dev.appoutlet.some.core.ResolverChain -import dev.appoutlet.some.core.TypeResolver import kotlin.reflect.KType import kotlin.reflect.typeOf import kotlin.uuid.ExperimentalUuidApi import kotlin.uuid.Uuid @OptIn(ExperimentalUuidApi::class) -class KotlinUuidResolver : TypeResolver { +class KotlinUuidResolver : Resolver { override fun canResolve(type: KType): Boolean { return type == typeOf() } diff --git a/core/src/main/kotlin/dev/appoutlet/some/resolver/ListResolver.kt b/core/src/main/kotlin/dev/appoutlet/some/resolver/ListResolver.kt index da27e059..bbe65cda 100644 --- a/core/src/main/kotlin/dev/appoutlet/some/resolver/ListResolver.kt +++ b/core/src/main/kotlin/dev/appoutlet/some/resolver/ListResolver.kt @@ -1,9 +1,9 @@ package dev.appoutlet.some.resolver import dev.appoutlet.some.config.CollectionStrategy +import dev.appoutlet.some.core.Resolver import dev.appoutlet.some.core.ResolverChain import dev.appoutlet.some.core.StrategyProvider -import dev.appoutlet.some.core.TypeResolver import dev.appoutlet.some.core.get import kotlin.random.Random import kotlin.reflect.KClass @@ -21,7 +21,7 @@ import kotlin.reflect.typeOf class ListResolver( strategyProvider: StrategyProvider, private val random: Random -) : TypeResolver { +) : Resolver { private val collectionStrategy = strategyProvider.get() ?: CollectionStrategy.default override fun canResolve(type: KType): Boolean { diff --git a/core/src/main/kotlin/dev/appoutlet/some/resolver/LocalDateResolver.kt b/core/src/main/kotlin/dev/appoutlet/some/resolver/LocalDateResolver.kt index 8e390332..de6c500e 100644 --- a/core/src/main/kotlin/dev/appoutlet/some/resolver/LocalDateResolver.kt +++ b/core/src/main/kotlin/dev/appoutlet/some/resolver/LocalDateResolver.kt @@ -1,14 +1,14 @@ package dev.appoutlet.some.resolver +import dev.appoutlet.some.core.Resolver import dev.appoutlet.some.core.ResolverChain -import dev.appoutlet.some.core.TypeResolver import java.time.LocalDate import java.time.Year import kotlin.random.Random import kotlin.reflect.KType import kotlin.reflect.typeOf -class LocalDateResolver(val random: Random) : TypeResolver { +class LocalDateResolver(val random: Random) : Resolver { override fun canResolve(type: KType): Boolean { return type == typeOf() } diff --git a/core/src/main/kotlin/dev/appoutlet/some/resolver/LocalDateTimeResolver.kt b/core/src/main/kotlin/dev/appoutlet/some/resolver/LocalDateTimeResolver.kt index 7905dc5f..393cf14b 100644 --- a/core/src/main/kotlin/dev/appoutlet/some/resolver/LocalDateTimeResolver.kt +++ b/core/src/main/kotlin/dev/appoutlet/some/resolver/LocalDateTimeResolver.kt @@ -1,7 +1,7 @@ package dev.appoutlet.some.resolver +import dev.appoutlet.some.core.Resolver import dev.appoutlet.some.core.ResolverChain -import dev.appoutlet.some.core.TypeResolver import java.time.LocalDate import java.time.LocalDateTime import java.time.Year @@ -12,7 +12,7 @@ import kotlin.reflect.typeOf private const val HOURS_IN_DAY = 24 private const val MINUTES_IN_HOUR = 60 -class LocalDateTimeResolver(val random: Random) : TypeResolver { +class LocalDateTimeResolver(val random: Random) : Resolver { override fun canResolve(type: KType): Boolean { return type == typeOf() } diff --git a/core/src/main/kotlin/dev/appoutlet/some/resolver/LongResolver.kt b/core/src/main/kotlin/dev/appoutlet/some/resolver/LongResolver.kt index 602c0a56..fc13ef43 100644 --- a/core/src/main/kotlin/dev/appoutlet/some/resolver/LongResolver.kt +++ b/core/src/main/kotlin/dev/appoutlet/some/resolver/LongResolver.kt @@ -1,12 +1,12 @@ package dev.appoutlet.some.resolver +import dev.appoutlet.some.core.Resolver import dev.appoutlet.some.core.ResolverChain -import dev.appoutlet.some.core.TypeResolver import kotlin.random.Random import kotlin.reflect.KType import kotlin.reflect.typeOf -class LongResolver(val random: Random) : TypeResolver { +class LongResolver(val random: Random) : Resolver { override fun canResolve(type: KType): Boolean = type == typeOf() override fun resolve(type: KType, chain: ResolverChain): Any { diff --git a/core/src/main/kotlin/dev/appoutlet/some/resolver/MapResolver.kt b/core/src/main/kotlin/dev/appoutlet/some/resolver/MapResolver.kt index 009225f0..185a0ce6 100644 --- a/core/src/main/kotlin/dev/appoutlet/some/resolver/MapResolver.kt +++ b/core/src/main/kotlin/dev/appoutlet/some/resolver/MapResolver.kt @@ -1,9 +1,9 @@ package dev.appoutlet.some.resolver import dev.appoutlet.some.config.CollectionStrategy +import dev.appoutlet.some.core.Resolver import dev.appoutlet.some.core.ResolverChain import dev.appoutlet.some.core.StrategyProvider -import dev.appoutlet.some.core.TypeResolver import dev.appoutlet.some.core.get import kotlin.random.Random import kotlin.reflect.KClass @@ -21,7 +21,7 @@ import kotlin.reflect.typeOf class MapResolver( strategyProvider: StrategyProvider, private val random: Random -) : TypeResolver { +) : Resolver { private val collectionStrategy = strategyProvider.get() ?: CollectionStrategy.default override fun canResolve(type: KType): Boolean { diff --git a/core/src/main/kotlin/dev/appoutlet/some/resolver/NullableResolver.kt b/core/src/main/kotlin/dev/appoutlet/some/resolver/NullableResolver.kt index a5c2294a..fb01e138 100644 --- a/core/src/main/kotlin/dev/appoutlet/some/resolver/NullableResolver.kt +++ b/core/src/main/kotlin/dev/appoutlet/some/resolver/NullableResolver.kt @@ -1,9 +1,9 @@ package dev.appoutlet.some.resolver import dev.appoutlet.some.config.NullableStrategy +import dev.appoutlet.some.core.Resolver import dev.appoutlet.some.core.ResolverChain import dev.appoutlet.some.core.StrategyProvider -import dev.appoutlet.some.core.TypeResolver import dev.appoutlet.some.core.get import kotlin.random.Random import kotlin.reflect.KType @@ -23,7 +23,7 @@ import kotlin.reflect.full.createType class NullableResolver( strategyProvider: StrategyProvider, private val random: Random -) : TypeResolver { +) : Resolver { private val nullableStrategy = strategyProvider.get() ?: NullableStrategy.default override fun canResolve(type: KType): Boolean = type.isMarkedNullable diff --git a/core/src/main/kotlin/dev/appoutlet/some/resolver/NumberResolver.kt b/core/src/main/kotlin/dev/appoutlet/some/resolver/NumberResolver.kt index 308c6a46..decefd9c 100644 --- a/core/src/main/kotlin/dev/appoutlet/some/resolver/NumberResolver.kt +++ b/core/src/main/kotlin/dev/appoutlet/some/resolver/NumberResolver.kt @@ -1,7 +1,7 @@ package dev.appoutlet.some.resolver +import dev.appoutlet.some.core.Resolver import dev.appoutlet.some.core.ResolverChain -import dev.appoutlet.some.core.TypeResolver import kotlin.random.Random import kotlin.reflect.KType import kotlin.reflect.typeOf @@ -28,7 +28,7 @@ private val numberTypes = listOf( */ class NumberResolver( private val random: Random -) : TypeResolver { +) : Resolver { /** * Returns `true` when [type] is exactly [Number]. diff --git a/core/src/main/kotlin/dev/appoutlet/some/resolver/ObjectResolver.kt b/core/src/main/kotlin/dev/appoutlet/some/resolver/ObjectResolver.kt index 274cb6b4..3baaa553 100644 --- a/core/src/main/kotlin/dev/appoutlet/some/resolver/ObjectResolver.kt +++ b/core/src/main/kotlin/dev/appoutlet/some/resolver/ObjectResolver.kt @@ -1,11 +1,11 @@ package dev.appoutlet.some.resolver +import dev.appoutlet.some.core.Resolver import dev.appoutlet.some.core.ResolverChain -import dev.appoutlet.some.core.TypeResolver import kotlin.reflect.KClass import kotlin.reflect.KType -class ObjectResolver : TypeResolver { +class ObjectResolver : Resolver { override fun canResolve(type: KType): Boolean { val kClass = type.classifier as? KClass<*> ?: return false return kClass.objectInstance != null diff --git a/core/src/main/kotlin/dev/appoutlet/some/resolver/OptionalResolver.kt b/core/src/main/kotlin/dev/appoutlet/some/resolver/OptionalResolver.kt index 082b9aac..984332a0 100644 --- a/core/src/main/kotlin/dev/appoutlet/some/resolver/OptionalResolver.kt +++ b/core/src/main/kotlin/dev/appoutlet/some/resolver/OptionalResolver.kt @@ -1,9 +1,9 @@ package dev.appoutlet.some.resolver import dev.appoutlet.some.config.NullableStrategy +import dev.appoutlet.some.core.Resolver import dev.appoutlet.some.core.ResolverChain import dev.appoutlet.some.core.StrategyProvider -import dev.appoutlet.some.core.TypeResolver import dev.appoutlet.some.core.get import dev.appoutlet.some.exception.SomeCircularReferenceException import dev.appoutlet.some.logging.logger @@ -27,7 +27,7 @@ import kotlin.reflect.full.isSubclassOf class OptionalResolver( strategyProvider: StrategyProvider, private val random: Random -) : TypeResolver { +) : Resolver { private val logger by logger() /** diff --git a/core/src/main/kotlin/dev/appoutlet/some/resolver/SealedClassResolver.kt b/core/src/main/kotlin/dev/appoutlet/some/resolver/SealedClassResolver.kt index e83b457e..0332aa42 100644 --- a/core/src/main/kotlin/dev/appoutlet/some/resolver/SealedClassResolver.kt +++ b/core/src/main/kotlin/dev/appoutlet/some/resolver/SealedClassResolver.kt @@ -1,13 +1,13 @@ package dev.appoutlet.some.resolver +import dev.appoutlet.some.core.Resolver import dev.appoutlet.some.core.ResolverChain -import dev.appoutlet.some.core.TypeResolver import kotlin.random.Random import kotlin.reflect.KClass import kotlin.reflect.KType import kotlin.reflect.full.createType -class SealedClassResolver(val random: Random) : TypeResolver { +class SealedClassResolver(val random: Random) : Resolver { override fun canResolve(type: KType): Boolean { val kClass = type.classifier as? KClass<*> ?: return false return kClass.isSealed diff --git a/core/src/main/kotlin/dev/appoutlet/some/resolver/SetResolver.kt b/core/src/main/kotlin/dev/appoutlet/some/resolver/SetResolver.kt index 0ef81468..0a33af72 100644 --- a/core/src/main/kotlin/dev/appoutlet/some/resolver/SetResolver.kt +++ b/core/src/main/kotlin/dev/appoutlet/some/resolver/SetResolver.kt @@ -1,9 +1,9 @@ package dev.appoutlet.some.resolver import dev.appoutlet.some.config.CollectionStrategy +import dev.appoutlet.some.core.Resolver import dev.appoutlet.some.core.ResolverChain import dev.appoutlet.some.core.StrategyProvider -import dev.appoutlet.some.core.TypeResolver import dev.appoutlet.some.core.get import kotlin.random.Random import kotlin.reflect.KClass @@ -21,7 +21,7 @@ import kotlin.reflect.typeOf class SetResolver( strategyProvider: StrategyProvider, private val random: Random -) : TypeResolver { +) : Resolver { private val collectionStrategy = strategyProvider.get() ?: CollectionStrategy.default override fun canResolve(type: KType): Boolean { diff --git a/core/src/main/kotlin/dev/appoutlet/some/resolver/ShortResolver.kt b/core/src/main/kotlin/dev/appoutlet/some/resolver/ShortResolver.kt index ae97d07e..51303c95 100644 --- a/core/src/main/kotlin/dev/appoutlet/some/resolver/ShortResolver.kt +++ b/core/src/main/kotlin/dev/appoutlet/some/resolver/ShortResolver.kt @@ -1,12 +1,12 @@ package dev.appoutlet.some.resolver +import dev.appoutlet.some.core.Resolver import dev.appoutlet.some.core.ResolverChain -import dev.appoutlet.some.core.TypeResolver import kotlin.random.Random import kotlin.reflect.KType import kotlin.reflect.typeOf -class ShortResolver(val random: Random) : TypeResolver { +class ShortResolver(val random: Random) : Resolver { override fun canResolve(type: KType): Boolean = type == typeOf() override fun resolve(type: KType, chain: ResolverChain): Any { diff --git a/core/src/main/kotlin/dev/appoutlet/some/resolver/StringResolver.kt b/core/src/main/kotlin/dev/appoutlet/some/resolver/StringResolver.kt index 42edabdd..35d63f87 100644 --- a/core/src/main/kotlin/dev/appoutlet/some/resolver/StringResolver.kt +++ b/core/src/main/kotlin/dev/appoutlet/some/resolver/StringResolver.kt @@ -1,9 +1,9 @@ package dev.appoutlet.some.resolver import dev.appoutlet.some.config.StringStrategy +import dev.appoutlet.some.core.Resolver import dev.appoutlet.some.core.ResolverChain import dev.appoutlet.some.core.StrategyProvider -import dev.appoutlet.some.core.TypeResolver import dev.appoutlet.some.core.get import kotlin.random.Random import kotlin.reflect.KType @@ -21,7 +21,7 @@ import kotlin.uuid.Uuid class StringResolver( strategyProvider: StrategyProvider, private val random: Random -) : TypeResolver { +) : Resolver { private val stringStrategy = strategyProvider.get() ?: StringStrategy.default override fun canResolve(type: KType): Boolean = type == typeOf() diff --git a/core/src/main/kotlin/dev/appoutlet/some/resolver/ValueClassResolver.kt b/core/src/main/kotlin/dev/appoutlet/some/resolver/ValueClassResolver.kt index cc5bb866..438d682b 100644 --- a/core/src/main/kotlin/dev/appoutlet/some/resolver/ValueClassResolver.kt +++ b/core/src/main/kotlin/dev/appoutlet/some/resolver/ValueClassResolver.kt @@ -1,12 +1,12 @@ package dev.appoutlet.some.resolver +import dev.appoutlet.some.core.Resolver import dev.appoutlet.some.core.ResolverChain -import dev.appoutlet.some.core.TypeResolver import kotlin.reflect.KClass import kotlin.reflect.KType import kotlin.reflect.full.primaryConstructor -class ValueClassResolver : TypeResolver { +class ValueClassResolver : Resolver { override fun canResolve(type: KType): Boolean { val kClass = type.classifier as? KClass<*> ?: return false return kClass.isValue diff --git a/core/src/test/kotlin/dev/appoutlet/some/ServiceLoaderDiscoveryTest.kt b/core/src/test/kotlin/dev/appoutlet/some/ServiceLoaderDiscoveryTest.kt index f05c9b12..d19791b3 100644 --- a/core/src/test/kotlin/dev/appoutlet/some/ServiceLoaderDiscoveryTest.kt +++ b/core/src/test/kotlin/dev/appoutlet/some/ServiceLoaderDiscoveryTest.kt @@ -2,12 +2,12 @@ package dev.appoutlet.some import dev.appoutlet.some.config.SomeConfig import dev.appoutlet.some.resolver.ClassResolver -import dev.appoutlet.some.resolver.CustomTypeFactoryResolver +import dev.appoutlet.some.resolver.CustomFactoryResolver import dev.appoutlet.some.resolver.NullableResolver import dev.appoutlet.some.resolver.ObjectResolver import dev.appoutlet.some.resolver.StringResolver import dev.appoutlet.some.test.DiscoveredType -import dev.appoutlet.some.test.TestTypeResolver +import dev.appoutlet.some.test.TestResolver import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertTrue @@ -40,15 +40,15 @@ class ServiceLoaderDiscoveryTest { val resolvers = SomeConfig().buildResolvers() val resolverClasses = resolvers.map { it::class } - assertTrue(resolverClasses.first() == CustomTypeFactoryResolver::class) + assertTrue(resolverClasses.first() == CustomFactoryResolver::class) assertTrue(resolverClasses.last() == ClassResolver::class) - assertTrue(TestTypeResolver::class in resolverClasses) + assertTrue(TestResolver::class in resolverClasses) val nullableResolverIndex = resolverClasses.indexOf(NullableResolver::class) val objectResolverIndex = resolverClasses.indexOf(ObjectResolver::class) val stringResolverIndex = resolverClasses.indexOf(StringResolver::class) val classResolverIndex = resolverClasses.indexOf(ClassResolver::class) - val discoveredIndex = resolverClasses.indexOf(TestTypeResolver::class) + val discoveredIndex = resolverClasses.indexOf(TestResolver::class) assertTrue(nullableResolverIndex < discoveredIndex) assertTrue(discoveredIndex < objectResolverIndex) diff --git a/core/src/test/kotlin/dev/appoutlet/some/resolver/CustomTypeFactoryResolverTest.kt b/core/src/test/kotlin/dev/appoutlet/some/resolver/CustomTypeFactoryResolverTest.kt index a7e7c14f..61065337 100644 --- a/core/src/test/kotlin/dev/appoutlet/some/resolver/CustomTypeFactoryResolverTest.kt +++ b/core/src/test/kotlin/dev/appoutlet/some/resolver/CustomTypeFactoryResolverTest.kt @@ -14,7 +14,7 @@ data class CustomFactoryClass(val value: String) class CustomTypeFactoryResolverTest { @Test fun `CustomTypeFactoryResolver canResolve detects registered types`() { - val resolver = CustomTypeFactoryResolver( + val resolver = CustomFactoryResolver( DefaultStrategyProvider(), mapOf(CustomFactoryClass::class to { CustomFactoryClass("test") }), Random.Default @@ -24,7 +24,7 @@ class CustomTypeFactoryResolverTest { @Test fun `CustomTypeFactoryResolver canResolve rejects unregistered types`() { - val resolver = CustomTypeFactoryResolver( + val resolver = CustomFactoryResolver( DefaultStrategyProvider(), mapOf(CustomFactoryClass::class to { CustomFactoryClass("test") }), Random.Default @@ -35,7 +35,7 @@ class CustomTypeFactoryResolverTest { @Test fun `CustomTypeFactoryResolver resolve returns factory result`() { - val resolver = CustomTypeFactoryResolver( + val resolver = CustomFactoryResolver( DefaultStrategyProvider(), mapOf(CustomFactoryClass::class to { CustomFactoryClass("from-factory") }), Random.Default diff --git a/core/src/test/kotlin/dev/appoutlet/some/test/FailingLoadTypeResolverProvider.kt b/core/src/test/kotlin/dev/appoutlet/some/test/FailingLoadResolverProvider.kt similarity index 67% rename from core/src/test/kotlin/dev/appoutlet/some/test/FailingLoadTypeResolverProvider.kt rename to core/src/test/kotlin/dev/appoutlet/some/test/FailingLoadResolverProvider.kt index 2807971e..d11ade63 100644 --- a/core/src/test/kotlin/dev/appoutlet/some/test/FailingLoadTypeResolverProvider.kt +++ b/core/src/test/kotlin/dev/appoutlet/some/test/FailingLoadResolverProvider.kt @@ -1,20 +1,20 @@ package dev.appoutlet.some.test import com.fueledbycaffeine.autoservice.AutoService +import dev.appoutlet.some.core.Resolver +import dev.appoutlet.some.core.ResolverProvider import dev.appoutlet.some.core.StrategyProvider -import dev.appoutlet.some.core.TypeResolver -import dev.appoutlet.some.core.TypeResolverProvider import kotlin.random.Random /** - * Test [TypeResolverProvider] that fails during class instantiation (init block). + * Test [ResolverProvider] that fails during class instantiation (init block). * * Simulates a class-loading failure (e.g., NoClassDefFoundError from a missing optional dependency) * that would cause [java.util.ServiceLoader.iterator.next] to throw. Used to verify that a faulty * provider does not discard other valid providers discovered in the same iteration. */ @AutoService -class FailingLoadTypeResolverProvider : TypeResolverProvider { +class FailingLoadResolverProvider : ResolverProvider { init { error("Simulated class loading failure") } @@ -22,5 +22,5 @@ class FailingLoadTypeResolverProvider : TypeResolverProvider { override fun createResolvers( strategyProvider: StrategyProvider, random: Random, - ): List = throw UnsupportedOperationException() + ): List = throw UnsupportedOperationException() } diff --git a/core/src/test/kotlin/dev/appoutlet/some/test/FailingTypeResolverProvider.kt b/core/src/test/kotlin/dev/appoutlet/some/test/FailingResolverProvider.kt similarity index 66% rename from core/src/test/kotlin/dev/appoutlet/some/test/FailingTypeResolverProvider.kt rename to core/src/test/kotlin/dev/appoutlet/some/test/FailingResolverProvider.kt index b9cd644e..b95faf3a 100644 --- a/core/src/test/kotlin/dev/appoutlet/some/test/FailingTypeResolverProvider.kt +++ b/core/src/test/kotlin/dev/appoutlet/some/test/FailingResolverProvider.kt @@ -1,20 +1,20 @@ package dev.appoutlet.some.test import com.fueledbycaffeine.autoservice.AutoService +import dev.appoutlet.some.core.Resolver +import dev.appoutlet.some.core.ResolverProvider import dev.appoutlet.some.core.StrategyProvider -import dev.appoutlet.some.core.TypeResolver -import dev.appoutlet.some.core.TypeResolverProvider import kotlin.random.Random /** - * Test [TypeResolverProvider] that throws during resolver creation. + * Test [ResolverProvider] that throws during resolver creation. * * Used to verify that `SomeConfig.buildResolvers()` gracefully skips misbehaving providers. */ @AutoService -class FailingTypeResolverProvider : TypeResolverProvider { +class FailingResolverProvider : ResolverProvider { override fun createResolvers( strategyProvider: StrategyProvider, random: Random, - ): List = error("Simulated provider failure") + ): List = error("Simulated provider failure") } diff --git a/core/src/test/kotlin/dev/appoutlet/some/test/TestTypeResolverProvider.kt b/core/src/test/kotlin/dev/appoutlet/some/test/TestResolverProvider.kt similarity index 62% rename from core/src/test/kotlin/dev/appoutlet/some/test/TestTypeResolverProvider.kt rename to core/src/test/kotlin/dev/appoutlet/some/test/TestResolverProvider.kt index b76dbf63..fe2fb2ff 100644 --- a/core/src/test/kotlin/dev/appoutlet/some/test/TestTypeResolverProvider.kt +++ b/core/src/test/kotlin/dev/appoutlet/some/test/TestResolverProvider.kt @@ -1,34 +1,34 @@ package dev.appoutlet.some.test import com.fueledbycaffeine.autoservice.AutoService +import dev.appoutlet.some.core.Resolver import dev.appoutlet.some.core.ResolverChain +import dev.appoutlet.some.core.ResolverProvider import dev.appoutlet.some.core.StrategyProvider -import dev.appoutlet.some.core.TypeResolver -import dev.appoutlet.some.core.TypeResolverProvider import kotlin.random.Random import kotlin.reflect.KType import kotlin.reflect.typeOf /** - * Test type handled by the discovered [TestTypeResolverProvider]. + * Test type handled by the discovered [TestResolverProvider]. */ data class DiscoveredType(val value: String) /** - * Test [TypeResolverProvider] registered via `autoservice-ir` to verify ServiceLoader discovery. + * Test [ResolverProvider] registered via `autoservice-ir` to verify ServiceLoader discovery. */ @AutoService -class TestTypeResolverProvider : TypeResolverProvider { +class TestResolverProvider : ResolverProvider { override fun createResolvers( strategyProvider: StrategyProvider, random: Random, - ): List = listOf(TestTypeResolver()) + ): List = listOf(TestResolver()) } /** * Resolver that handles [DiscoveredType] for discovery tests. */ -class TestTypeResolver : TypeResolver { +class TestResolver : Resolver { override fun canResolve(type: KType): Boolean = type == typeOf() override fun resolve(type: KType, chain: ResolverChain): Any? = DiscoveredType("discovered") diff --git a/docs/custom-resolvers.md b/docs/custom-resolvers.md index 80df0af2..cf968537 100644 --- a/docs/custom-resolvers.md +++ b/docs/custom-resolvers.md @@ -3,19 +3,19 @@ icon: lucide/puzzle --- # Custom Resolvers -Some discovers custom `TypeResolver` implementations at runtime through Java's `ServiceLoader` mechanism. This lets you extend Some with support for domain-specific, third-party, or internal application types **without requiring every consumer to write configuration code**. +Some discovers custom `Resolver` implementations at runtime through Java's `ServiceLoader` mechanism. This lets you extend Some with support for domain-specific, third-party, or internal application types **without requiring every consumer to write configuration code**. If you only need to override how a single type is generated in your own tests, a [custom factory](custom-factories.md) is simpler. Use a custom resolver when you are **building a library** that others will depend on, **adding support for internal types in your own application**, or when the type needs its own resolution logic that delegates to the resolver chain. ## How it works -Some defines a service-provider interface called `TypeResolverProvider`. When fixture generation starts, Some calls `ServiceLoader.load(TypeResolverProvider::class.java)` to discover all implementations on the classpath. Each provider returns a list of [TypeResolver] instances that are inserted into the resolver chain. +Some defines a service-provider interface called `ResolverProvider`. When fixture generation starts, Some calls `ServiceLoader.load(ResolverProvider::class.java)` to discover all implementations on the classpath. Each provider returns a list of [Resolver] instances that are inserted into the resolver chain. The resolver chain order is: 1. **Custom type factories** — explicit user factories registered with `factory()`. 2. **Nullable resolver** — handles nullable wrappers before concrete types. -3. **Discovered resolvers** — contributed by `TypeResolverProvider` implementations. +3. **Discovered resolvers** — contributed by `ResolverProvider` implementations. 4. **Built-in resolvers** — standard types like `String`, `Int`, `List`, etc. 5. **Class resolver** — fallback for data classes and other constructable types. @@ -23,19 +23,19 @@ Because discovered resolvers sit between nullable handling and built-in resolver Misbehaving providers are silently skipped. If a provider throws during discovery or resolver creation, Some continues with the remaining providers and built-in chain. -## Implementing a TypeResolverProvider +## Implementing a ResolverProvider ### 1. Create a resolver -A resolver implements the `TypeResolver` interface with two methods: +A resolver implements the `Resolver` interface with two methods: ```kotlin import dev.appoutlet.some.core.ResolverChain -import dev.appoutlet.some.core.TypeResolver +import dev.appoutlet.some.core.Resolver import kotlin.reflect.KType import kotlin.reflect.typeOf -class UrlResolver : TypeResolver { +class UrlResolver : Resolver { override fun canResolve(type: KType): Boolean = type == typeOf() @@ -55,14 +55,14 @@ Resolvers that need strategies receive a `StrategyProvider` via the provider. Re ```kotlin import dev.appoutlet.some.config.StringStrategy import dev.appoutlet.some.core.StrategyProvider -import dev.appoutlet.some.core.TypeResolver +import dev.appoutlet.some.core.Resolver import dev.appoutlet.some.core.get import kotlin.random.Random class UrlResolver( strategyProvider: StrategyProvider, private val random: Random, -) : TypeResolver { +) : Resolver { private val stringStrategy = strategyProvider.get() ?: StringStrategy.default // ... @@ -75,15 +75,15 @@ The provider is the entry point that Some discovers via `ServiceLoader`. It rece ```kotlin import dev.appoutlet.some.core.StrategyProvider -import dev.appoutlet.some.core.TypeResolver -import dev.appoutlet.some.core.TypeResolverProvider +import dev.appoutlet.some.core.Resolver +import dev.appoutlet.some.core.ResolverProvider import kotlin.random.Random -class UrlResolverProvider : TypeResolverProvider { +class UrlResolverProvider : ResolverProvider { override fun createResolvers( strategyProvider: StrategyProvider, random: Random, - ): List = listOf(UrlResolver(strategyProvider, random)) + ): List = listOf(UrlResolver(strategyProvider, random)) } ``` @@ -92,7 +92,7 @@ class UrlResolverProvider : TypeResolverProvider { Create a file at: ``` -META-INF/services/dev.appoutlet.some.core.TypeResolverProvider +META-INF/services/dev.appoutlet.some.core.ResolverProvider ``` containing the fully qualified class name of your provider: @@ -109,10 +109,10 @@ If you use the [autoservice-ir](https://github.com/joshfriend/autoservice-ir) co ```kotlin import com.fueledbycaffeine.autoservice.AutoService -import dev.appoutlet.some.core.TypeResolverProvider +import dev.appoutlet.some.core.ResolverProvider @AutoService -class UrlResolverProvider : TypeResolverProvider { +class UrlResolverProvider : ResolverProvider { // ... } ``` @@ -135,7 +135,7 @@ package com.example.some import dev.appoutlet.some.core.ResolverChain import dev.appoutlet.some.core.StrategyProvider -import dev.appoutlet.some.core.TypeResolver +import dev.appoutlet.some.core.Resolver import dev.appoutlet.some.config.StringStrategy import dev.appoutlet.some.core.get import kotlin.random.Random @@ -145,7 +145,7 @@ import kotlin.reflect.typeOf class UrlResolver( private val strategyProvider: StrategyProvider, private val random: Random, -) : TypeResolver { +) : Resolver { private val stringStrategy = strategyProvider.get() ?: StringStrategy.default override fun canResolve(type: KType): Boolean = type == typeOf() @@ -165,15 +165,15 @@ class UrlResolver( package com.example.some import dev.appoutlet.some.core.StrategyProvider -import dev.appoutlet.some.core.TypeResolver -import dev.appoutlet.some.core.TypeResolverProvider +import dev.appoutlet.some.core.Resolver +import dev.appoutlet.some.core.ResolverProvider import kotlin.random.Random -class UrlResolverProvider : TypeResolverProvider { +class UrlResolverProvider : ResolverProvider { override fun createResolvers( strategyProvider: StrategyProvider, random: Random, - ): List = listOf(UrlResolver(strategyProvider, random)) + ): List = listOf(UrlResolver(strategyProvider, random)) } ``` @@ -191,7 +191,7 @@ Resolvers can delegate nested type resolution to `chain.resolve(type)`. This is ```kotlin data class Email(val address: String) -class EmailResolver : TypeResolver { +class EmailResolver : Resolver { override fun canResolve(type: KType): Boolean = type == typeOf() override fun resolve(type: KType, chain: ResolverChain): Any { @@ -235,7 +235,7 @@ Then retrieve it in your resolver through the `StrategyProvider`: class UrlResolver( strategyProvider: StrategyProvider, private val random: Random, -) : TypeResolver { +) : Resolver { private val urlStrategy = strategyProvider.get() ?: UrlStrategy.default override fun canResolve(type: KType): Boolean = type == typeOf() @@ -264,6 +264,6 @@ When no strategy is registered, the resolver falls back to `UrlStrategy.default` ## Error handling -If a `TypeResolverProvider` throws during discovery or resolver creation, Some catches the error and continues with the remaining providers. The built-in resolver chain is always available as a fallback. This means your application will still work even if an extension fails to load. +If a `ResolverProvider` throws during discovery or resolver creation, Some catches the error and continues with the remaining providers. The built-in resolver chain is always available as a fallback. This means your application will still work even if an extension fails to load. -[TypeResolver]: ../reference/latest/index.html \ No newline at end of file +[Resolver]: ../reference/latest/index.html \ No newline at end of file diff --git a/docs/index.md b/docs/index.md index d68acc8c..9379d076 100644 --- a/docs/index.md +++ b/docs/index.md @@ -63,7 +63,7 @@ Writing tests means creating test data — lots of it. Constructing data classes - **Universal type support** — Works with data classes, sealed classes/interfaces, object singletons, value classes, generics, and all standard collections. If Kotlin can represent it, Some can generate it. - **Nested and recursive structures** — Handles deeply nested data classes, circular references, and recursive sealed class hierarchies without infinite loops. - **Fine-grained control** — Override how specific fields are generated: control nullable probability, string format, collection sizes, register custom type factories for types, or use property factories for individual fields. -- **Extensible** — Ship custom `TypeResolverProvider` implementations discovered via `ServiceLoader` to add support for domain-specific, third-party, or internal application types — with custom strategies and no consumer configuration required. +- **Extensible** — Ship custom `ResolverProvider` implementations discovered via `ServiceLoader` to add support for domain-specific, third-party, or internal application types — with custom strategies and no consumer configuration required. - **Deterministic by choice** — Set a seed for reproducible test data across runs, or default to random for variation. ## Quick start diff --git a/docs/supported-types.md b/docs/supported-types.md index 14b3461e..a7b37fd4 100644 --- a/docs/supported-types.md +++ b/docs/supported-types.md @@ -65,4 +65,4 @@ someSetup { See [Type and Property Factories](custom-factories.md) for more. -For library authors or application developers who want to bundle resolver logic for a custom type, see [Custom Resolvers](custom-resolvers.md) to learn about `TypeResolverProvider`. +For library authors or application developers who want to bundle resolver logic for a custom type, see [Custom Resolvers](custom-resolvers.md) to learn about `ResolverProvider`. diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7e6d563d..67581fc7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,6 @@ [versions] agp = "9.2.1" +androidxCompose = "1.11.3" autoserviceIr = "0.1.5" detekt = "1.23.8" dokka = "2.2.0" @@ -9,6 +10,7 @@ kotlin = "2.4.0" mavenPublish = "0.36.0" [libraries] +androidx-compose-ui = { module = "androidx.compose.ui:ui", version.ref = "androidxCompose" } detekt-formatting = { module = "io.gitlab.arturbosch.detekt:detekt-formatting", version.ref = "detekt" } dokka-versioning = { module = "org.jetbrains.dokka:versioning-plugin", version.ref = "dokka" } junit = { group = "junit", name = "junit", version.ref = "junit" }