diff --git a/CHANGELOG.md b/CHANGELOG.md index a4a5cc0fc..00986730a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ # Changelog ## Unreleased -(empty) +### Changed +* When inserting arrays at multiple carets, the number of elements per array is now independently chosen for each array. + ([#450](https://github.com/FWDekker/intellij-randomness/issues/450)) ## 3.0.0 -- 2023-11-17 diff --git a/src/main/kotlin/com/fwdekker/randomness/array/ArrayDecorator.kt b/src/main/kotlin/com/fwdekker/randomness/array/ArrayDecorator.kt index cbf93b4b3..4f3223358 100644 --- a/src/main/kotlin/com/fwdekker/randomness/array/ArrayDecorator.kt +++ b/src/main/kotlin/com/fwdekker/randomness/array/ArrayDecorator.kt @@ -32,9 +32,19 @@ data class ArrayDecorator( override fun generateUndecoratedStrings(count: Int): List { - val partsPerString = random.nextInt(minCount, maxCount + 1) - return generator(count * partsPerString) - .chunked(partsPerString) { it.joinToString(if (separatorEnabled) separator.replace("\\n", "\n") else "") } + val partsPerString = List(count) { random.nextInt(minCount, maxCount + 1) } + val parts = generator(partsPerString.sum()) + + return partsPerString + .fold(Pair(parts, emptyList())) { (remainingParts, createdStrings), nextPartCount -> + val nextString = + remainingParts + .take(nextPartCount) + .joinToString(if (separatorEnabled) separator.replace("\\n", "\n") else "") + + Pair(remainingParts.drop(nextPartCount), createdStrings + nextString) + } + .second } diff --git a/src/test/kotlin/com/fwdekker/randomness/array/ArrayDecoratorTest.kt b/src/test/kotlin/com/fwdekker/randomness/array/ArrayDecoratorTest.kt index 018e45bdb..8d3f007a7 100644 --- a/src/test/kotlin/com/fwdekker/randomness/array/ArrayDecoratorTest.kt +++ b/src/test/kotlin/com/fwdekker/randomness/array/ArrayDecoratorTest.kt @@ -7,6 +7,7 @@ import com.fwdekker.randomness.testhelpers.shouldValidateAsBundle import io.kotest.core.spec.style.FunSpec import io.kotest.data.row import io.kotest.datatest.withData +import io.kotest.matchers.collections.shouldHaveAtLeastSize import io.kotest.matchers.ints.shouldBeInRange import io.kotest.matchers.shouldBe @@ -24,59 +25,69 @@ object ArrayDecoratorTest : FunSpec({ "returns default input if disabled" to row( ArrayDecorator(enabled = false, minCount = 3), - "[i0]", + "{i0}", ), "returns a single value" to row( ArrayDecorator(enabled = true, minCount = 1, maxCount = 1), - "[[i0]]", + "[{i0}]", ), "returns a fixed number of values" to row( ArrayDecorator(enabled = true, minCount = 3, maxCount = 3), - "[[i0], [i1], [i2]]", + "[{i0}, {i1}, {i2}]", ), "returns array with multi-char separator" to row( ArrayDecorator(enabled = true, separator = ";;"), - "[[i0];;[i1];;[i2]]", + "[{i0};;{i1};;{i2}]", ), "retains leading whitespace in separator" to row( ArrayDecorator(enabled = true, separator = ", "), - "[[i0], [i1], [i2]]", + "[{i0}, {i1}, {i2}]", ), "converts escaped 'n' in separator to newline" to row( ArrayDecorator(enabled = true, separator = """\n"""), - "[[i0]\n[i1]\n[i2]]", + "[{i0}\n{i1}\n{i2}]", ), "applies affix decorator" to row( ArrayDecorator(enabled = true, affixDecorator = AffixDecorator(enabled = true, "(@)")), - "([i0], [i1], [i2])", + "({i0}, {i1}, {i2})", ), ) ) { (scheme, output) -> - scheme.generator = { count -> List(count) { "[i$it]" } } + scheme.generator = { count -> List(count) { "{i$it}" } } scheme.generateStrings()[0] shouldBe output } - test("generates the desired number of entries") { + test("generates the desired number of parts in each string") { val scheme = ArrayDecorator(enabled = true, minCount = 3, maxCount = 8) - scheme.generator = { count -> List(count) { "[i$it]" } } + scheme.generator = { count -> List(count) { "{i$it}" } } - scheme.generateStrings(count = 50).map { string -> string.count { it == ',' } + 1 } + scheme.generateStrings(count = 50) + .map { string -> string.count { it == ',' } + 1 } .forEach { it shouldBeInRange 3..8 } } - test("appropriately chunks generator outputs") { + test("generates an independently random number of parts per string") { + val scheme = ArrayDecorator(enabled = true, minCount = 1, maxCount = 8) + scheme.generator = { count -> List(count) { "{i$it}" } } + + scheme.generateStrings(count = 50) + .map { string -> string.count { it == ',' } + 1 } + .distinct() shouldHaveAtLeastSize 2 + } + + test("appropriately splits parts into strings") { val scheme = ArrayDecorator(enabled = true) - var i = 0 - scheme.generator = { count -> List(count) { "[i${i++}]" } } + var partIdx = 0 + scheme.generator = { count -> List(count) { "{i${partIdx++}}" } } - scheme.generateStrings(count = 2) shouldBe listOf("[[i0], [i1], [i2]]", "[[i3], [i4], [i5]]") + scheme.generateStrings(count = 2) shouldBe listOf("[{i0}, {i1}, {i2}]", "[{i3}, {i4}, {i5}]") } } @@ -97,7 +108,7 @@ object ArrayDecoratorTest : FunSpec({ row(ArrayDecorator(affixDecorator = AffixDecorator(descriptor = """\""")), ""), ) ) { (scheme, validation) -> - scheme.generator = { count -> List(count) { "[i$it]" } } + scheme.generator = { count -> List(count) { "{i$it}" } } scheme shouldValidateAsBundle validation }