Skip to content

Commit 84d60d6

Browse files
Skobeltsynclaude
andcommitted
test(#885): cover GenerableSupportKt Float-input coercion + List/nested types
14 new tests targeting the NO_COVERAGE clusters from #885: coerceToInt — Float input (was lines 340-345 untouched): - in-range whole-number Float → coerce successfully - fractional Float → reject (return null) - out-of-range Float (1e10) → reject - NaN, +Infinity, -Infinity → reject - Short and Byte inputs → coerce (line 334 fallthrough) coerceToLong — Float input (was lines 366-371 untouched): - same six cases as above for Long with appropriate bounds - Short/Byte fallthrough (line 360) promptTypeName — List<T> recursion + nested-Generable simpleName: - `List<String>` field renders type as "List<String>" (line 215-217) - nested @generable field renders as its simpleName (line 219) PIT delta on agents_engine.generation.GenerableSupportKt: - NO_COVERAGE: 24 → 14 (10 mutants newly covered) - promptTypeName: fully covered (6 → 0 NO_COVERAGE) - coerceToInt: 5 → 2 NO_COVERAGE - coerceToLong: 4 → 2 NO_COVERAGE Remaining 14 NO_COVERAGE are in sealed-class path (sealedJsonSchema, sealedPromptFragment, dataClassPromptFragment) and coerceValue wrapper — out of scope for this ticket; tracked under #889 catch-all. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 565d06f commit 84d60d6

1 file changed

Lines changed: 126 additions & 0 deletions

File tree

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
package agents_engine.generation
2+
3+
import kotlin.test.Test
4+
import kotlin.test.assertEquals
5+
import kotlin.test.assertNotNull
6+
import kotlin.test.assertNull
7+
import kotlin.test.assertTrue
8+
9+
// Tests for #885 — coverage gaps in GenerableSupport identified by PIT NO_COVERAGE.
10+
//
11+
// Three areas:
12+
// 1. coerceToInt — Float input branches (lines 340-345)
13+
// 2. coerceToLong — Float input branches (lines 366-371)
14+
// 3. promptTypeName — List<T> recursion and KClass<*> simpleName fallback (lines 215-219)
15+
//
16+
// Reuses IntBox / LongBox fixtures from CoerceValueOverflowTest (in the same
17+
// package and source set).
18+
19+
class GenerableSupportCoverageTest {
20+
21+
// coerceToInt — Float input
22+
23+
@Test
24+
fun `Int field accepts in-range whole-number Float`() {
25+
val r = IntBox::class.constructFromMap(mapOf("n" to 42.0f))
26+
assertNotNull(r)
27+
assertEquals(42, r!!.n)
28+
}
29+
30+
@Test
31+
fun `Int field rejects fractional Float`() {
32+
assertNull(IntBox::class.constructFromMap(mapOf("n" to 1.5f)))
33+
}
34+
35+
@Test
36+
fun `Int field rejects out-of-range Float`() {
37+
// 1e10 > Int.MAX_VALUE (~2.1e9)
38+
assertNull(IntBox::class.constructFromMap(mapOf("n" to 1.0e10f)))
39+
}
40+
41+
@Test
42+
fun `Int field rejects NaN Float`() {
43+
assertNull(IntBox::class.constructFromMap(mapOf("n" to Float.NaN)))
44+
}
45+
46+
@Test
47+
fun `Int field rejects Infinity Float`() {
48+
assertNull(IntBox::class.constructFromMap(mapOf("n" to Float.POSITIVE_INFINITY)))
49+
assertNull(IntBox::class.constructFromMap(mapOf("n" to Float.NEGATIVE_INFINITY)))
50+
}
51+
52+
@Test
53+
fun `Int field accepts Short input`() {
54+
val r = IntBox::class.constructFromMap(mapOf("n" to 7.toShort()))
55+
assertNotNull(r)
56+
assertEquals(7, r!!.n)
57+
}
58+
59+
@Test
60+
fun `Int field accepts Byte input`() {
61+
val r = IntBox::class.constructFromMap(mapOf("n" to 5.toByte()))
62+
assertNotNull(r)
63+
assertEquals(5, r!!.n)
64+
}
65+
66+
// coerceToLong — Float input
67+
68+
@Test
69+
fun `Long field accepts in-range whole-number Float`() {
70+
val r = LongBox::class.constructFromMap(mapOf("n" to 1000.0f))
71+
assertNotNull(r)
72+
assertEquals(1000L, r!!.n)
73+
}
74+
75+
@Test
76+
fun `Long field rejects fractional Float`() {
77+
assertNull(LongBox::class.constructFromMap(mapOf("n" to 1.5f)))
78+
}
79+
80+
@Test
81+
fun `Long field rejects NaN Float`() {
82+
assertNull(LongBox::class.constructFromMap(mapOf("n" to Float.NaN)))
83+
}
84+
85+
@Test
86+
fun `Long field rejects Infinity Float`() {
87+
assertNull(LongBox::class.constructFromMap(mapOf("n" to Float.POSITIVE_INFINITY)))
88+
assertNull(LongBox::class.constructFromMap(mapOf("n" to Float.NEGATIVE_INFINITY)))
89+
}
90+
91+
@Test
92+
fun `Long field accepts Short input`() {
93+
val r = LongBox::class.constructFromMap(mapOf("n" to 7.toShort()))
94+
assertNotNull(r)
95+
assertEquals(7L, r!!.n)
96+
}
97+
98+
@Test
99+
fun `Long field accepts Byte input`() {
100+
val r = LongBox::class.constructFromMap(mapOf("n" to 5.toByte()))
101+
assertNotNull(r)
102+
assertEquals(5L, r!!.n)
103+
}
104+
105+
// promptTypeName — List<T> branch and nested-Generable branch
106+
107+
@Test
108+
fun `promptFragment renders List of primitives as List of T`() {
109+
// TaggedResult is from GenerableTest.kt: data class TaggedResult(@Guide val tags: List<String>, val count: Int)
110+
val out = TaggedResult::class.promptFragment()
111+
assertTrue(
112+
out.contains("<List<String>"),
113+
"List<String> should render as List<String> type name; got:\n$out",
114+
)
115+
}
116+
117+
@Test
118+
fun `promptFragment renders nested Generable as its simpleName`() {
119+
// NestedResult is from GenerableTest.kt: data class NestedResult(@Guide val inner: ScoreResult, val label: String)
120+
val out = NestedResult::class.promptFragment()
121+
assertTrue(
122+
out.contains("ScoreResult"),
123+
"Nested @Generable should render with its simpleName; got:\n$out",
124+
)
125+
}
126+
}

0 commit comments

Comments
 (0)