Skip to content

Commit 8b5140e

Browse files
authored
feat: annotated string resolver
1 parent 7e36015 commit 8b5140e

7 files changed

Lines changed: 134 additions & 4 deletions

File tree

android/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ detekt { autoCorrect = true }
3333
dependencies {
3434
api(projects.core)
3535

36-
testImplementation(libs.androidx.compose.ui)
36+
implementation(libs.androidx.compose.ui)
3737
testImplementation(libs.junit)
3838
testImplementation(libs.kotlin.test)
3939
testImplementation(libs.robolectric)

android/src/main/java/dev/appoutlet/some/android/AndroidResolverProvider.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import dev.appoutlet.some.android.resolver.SizeFResolver
1111
import dev.appoutlet.some.android.resolver.SizeResolver
1212
import dev.appoutlet.some.android.resolver.UriResolver
1313
import dev.appoutlet.some.android.resolver.UserHandleResolver
14+
import dev.appoutlet.some.android.resolver.compose.AnnotatedStringResolver
1415
import dev.appoutlet.some.core.Resolver
1516
import dev.appoutlet.some.core.ResolverProvider
1617
import dev.appoutlet.some.core.StrategyProvider
@@ -19,8 +20,7 @@ import kotlin.random.Random
1920
/**
2021
* Contributes Android-specific resolvers discovered through `ServiceLoader`.
2122
*
22-
* The returned resolvers extend the shared `some-core` chain with support for common Android framework
23-
* value types such as `Uri`, geometry classes, `Bundle`, `Pair`, `UserHandle`, and `Color`.
23+
* The returned resolvers extend the shared `some-core` chain with Android-specific type support.
2424
*/
2525
class AndroidResolverProvider : ResolverProvider {
2626
/**
@@ -44,7 +44,8 @@ class AndroidResolverProvider : ResolverProvider {
4444
SizeFResolver(random),
4545
PairResolver(random),
4646
UserHandleResolver(random),
47-
ColorResolver(random)
47+
ColorResolver(random),
48+
AnnotatedStringResolver(random)
4849
)
4950
}
5051
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package dev.appoutlet.some.android.resolver.compose
2+
3+
import androidx.compose.ui.text.AnnotatedString
4+
import dev.appoutlet.some.core.Resolver
5+
import dev.appoutlet.some.core.ResolverChain
6+
import kotlin.random.Random
7+
import kotlin.reflect.KType
8+
import kotlin.reflect.typeOf
9+
10+
private const val MIN_TEXT_LENGTH = 1
11+
private const val MAX_TEXT_LENGTH = 20
12+
13+
/**
14+
* Resolves [AnnotatedString] types with randomized non-blank text content.
15+
*
16+
* @param random Random source used when generating text.
17+
*/
18+
class AnnotatedStringResolver(
19+
private val random: Random
20+
) : Resolver {
21+
override fun canResolve(type: KType): Boolean = type == typeOf<AnnotatedString>()
22+
23+
override fun resolve(type: KType, chain: ResolverChain): Any {
24+
return AnnotatedString(generateText())
25+
}
26+
27+
private fun generateText(): String {
28+
val length = random.nextInt(MIN_TEXT_LENGTH, MAX_TEXT_LENGTH + 1)
29+
val chars = CharArray(length) { ('a'..'z').random(random) }
30+
return String(chars)
31+
}
32+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package dev.appoutlet.some.android
2+
3+
import dev.appoutlet.some.android.resolver.BundleResolver
4+
import dev.appoutlet.some.android.resolver.ColorResolver
5+
import dev.appoutlet.some.android.resolver.PairResolver
6+
import dev.appoutlet.some.android.resolver.PointFResolver
7+
import dev.appoutlet.some.android.resolver.PointResolver
8+
import dev.appoutlet.some.android.resolver.RectFResolver
9+
import dev.appoutlet.some.android.resolver.RectResolver
10+
import dev.appoutlet.some.android.resolver.SizeFResolver
11+
import dev.appoutlet.some.android.resolver.SizeResolver
12+
import dev.appoutlet.some.android.resolver.UriResolver
13+
import dev.appoutlet.some.android.resolver.UserHandleResolver
14+
import dev.appoutlet.some.android.resolver.compose.AnnotatedStringResolver
15+
import dev.appoutlet.some.config.DefaultStrategyProvider
16+
import org.junit.Assert.assertEquals
17+
import org.junit.Test
18+
import kotlin.random.Random
19+
20+
class AndroidResolverProviderTest {
21+
@Test
22+
fun `createResolvers returns the full Android resolver list`() {
23+
val resolvers = AndroidResolverProvider().createResolvers(DefaultStrategyProvider(), Random.Default)
24+
25+
assertEquals(
26+
listOf(
27+
UriResolver::class,
28+
BundleResolver::class,
29+
RectResolver::class,
30+
RectFResolver::class,
31+
PointResolver::class,
32+
PointFResolver::class,
33+
SizeResolver::class,
34+
SizeFResolver::class,
35+
PairResolver::class,
36+
UserHandleResolver::class,
37+
ColorResolver::class,
38+
AnnotatedStringResolver::class
39+
),
40+
resolvers.map { it::class }
41+
)
42+
}
43+
}

android/src/test/java/dev/appoutlet/some/android/AndroidServiceLoaderTest.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package dev.appoutlet.some.android
22

33
import android.graphics.Point
4+
import androidx.compose.ui.text.AnnotatedString
45
import dev.appoutlet.some.some
56
import org.junit.Assert.assertTrue
67
import org.junit.Test
@@ -17,4 +18,10 @@ class AndroidServiceLoaderTest {
1718
val result: Any = some<Point>()
1819
assertTrue(result is Point)
1920
}
21+
22+
@Test
23+
fun `top-level some resolves AnnotatedString through AndroidResolverProvider`() {
24+
val result: AnnotatedString = some()
25+
assertTrue("Generated AnnotatedString text should not be blank", result.text.isNotBlank())
26+
}
2027
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package dev.appoutlet.some.android.resolver.compose
2+
3+
import androidx.compose.ui.text.AnnotatedString
4+
import dev.appoutlet.some.config.NullableStrategy
5+
import dev.appoutlet.some.core.ResolverChain
6+
import org.junit.Assert.assertFalse
7+
import org.junit.Assert.assertTrue
8+
import org.junit.Test
9+
import kotlin.random.Random
10+
import kotlin.reflect.typeOf
11+
12+
class AnnotatedStringResolverTest {
13+
@Test
14+
fun `AnnotatedStringResolver generates AnnotatedString values`() {
15+
val resolver = AnnotatedStringResolver(Random.Default)
16+
val result = resolver.resolve(typeOf<AnnotatedString>(), testChain)
17+
assertTrue(result is AnnotatedString)
18+
}
19+
20+
@Test
21+
fun `AnnotatedStringResolver generates non-blank text`() {
22+
val resolver = AnnotatedStringResolver(Random.Default)
23+
24+
repeat(20) {
25+
val result = resolver.resolve(typeOf<AnnotatedString>(), testChain) as AnnotatedString
26+
assertTrue("Generated AnnotatedString text should not be blank", result.text.isNotBlank())
27+
}
28+
}
29+
30+
@Test
31+
fun `AnnotatedStringResolver canResolve detects AnnotatedString type`() {
32+
val resolver = AnnotatedStringResolver(Random.Default)
33+
assertTrue(resolver.canResolve(typeOf<AnnotatedString>()))
34+
}
35+
36+
@Test
37+
fun `AnnotatedStringResolver rejects non-AnnotatedString types`() {
38+
val resolver = AnnotatedStringResolver(Random.Default)
39+
assertFalse(resolver.canResolve(typeOf<String>()))
40+
assertFalse(resolver.canResolve(typeOf<Int>()))
41+
}
42+
43+
companion object {
44+
private val testChain = ResolverChain(emptyList(), NullableStrategy.NullOnCircularReference)
45+
}
46+
}

docs/android/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ Today, the Android module adds these Android-specific types:
5151
| `android.os.Bundle` | `some<Bundle>()` | One random value each for `String`, `Int`, `Long`, `Float`, `Double`, and `Boolean` |
5252
| `android.os.UserHandle` | `some<UserHandle>()` | API 24+; generated from a random non-system UID |
5353
| `android.graphics.Color` | `some<Color>()` | API 26+; generated from random RGB channel values |
54+
| `androidx.compose.ui.text.AnnotatedString` | `some<AnnotatedString>()` | Non-blank plain text without span styles |
5455

5556
## Platform constraints
5657

0 commit comments

Comments
 (0)