Skip to content

Commit

Permalink
Fix ParameterizeFailedError count including skipped iterations
Browse files Browse the repository at this point in the history
When a parameter is declared with empty arguments causing the iteration
to be skipped, that iteration would still count towards the total when
reported in a `ParameterizeFailedError` despite it not finishing. When
used for writing tests, this means it would look like some cases didn't
fail, since the "fail/total" result wouldn't look like 100% failures.

This change also expose the number of successful/skipped iterations in
the `onComplete` API now that they're being tracked.
  • Loading branch information
BenWoodworth committed Sep 18, 2024
1 parent 30adb30 commit 2b667c9
Show file tree
Hide file tree
Showing 14 changed files with 142 additions and 29 deletions.
2 changes: 2 additions & 0 deletions api/parameterize.api
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ public final class com/benwoodworth/parameterize/ParameterizeConfiguration$OnCom
public final fun getFailureCount ()J
public final fun getIterationCount ()J
public final fun getRecordedFailures ()Ljava/util/List;
public final fun getSkipCount ()J
public final fun getSuccessCount ()J
public final fun invoke (Lcom/benwoodworth/parameterize/ParameterizeFailedError$Companion;)Lcom/benwoodworth/parameterize/ParameterizeFailedError;
}

Expand Down
4 changes: 4 additions & 0 deletions api/parameterize.klib.api
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ final class com.benwoodworth.parameterize/ParameterizeConfiguration { // com.ben
final fun <get-iterationCount>(): kotlin/Long // com.benwoodworth.parameterize/ParameterizeConfiguration.OnCompleteScope.iterationCount.<get-iterationCount>|<get-iterationCount>(){}[0]
final val recordedFailures // com.benwoodworth.parameterize/ParameterizeConfiguration.OnCompleteScope.recordedFailures|{}recordedFailures[0]
final fun <get-recordedFailures>(): kotlin.collections/List<com.benwoodworth.parameterize/ParameterizeFailure> // com.benwoodworth.parameterize/ParameterizeConfiguration.OnCompleteScope.recordedFailures.<get-recordedFailures>|<get-recordedFailures>(){}[0]
final val skipCount // com.benwoodworth.parameterize/ParameterizeConfiguration.OnCompleteScope.skipCount|{}skipCount[0]
final fun <get-skipCount>(): kotlin/Long // com.benwoodworth.parameterize/ParameterizeConfiguration.OnCompleteScope.skipCount.<get-skipCount>|<get-skipCount>(){}[0]
final val successCount // com.benwoodworth.parameterize/ParameterizeConfiguration.OnCompleteScope.successCount|{}successCount[0]
final fun <get-successCount>(): kotlin/Long // com.benwoodworth.parameterize/ParameterizeConfiguration.OnCompleteScope.successCount.<get-successCount>|<get-successCount>(){}[0]

final fun (com.benwoodworth.parameterize/ParameterizeFailedError.Companion).invoke(): com.benwoodworth.parameterize/ParameterizeFailedError // com.benwoodworth.parameterize/ParameterizeConfiguration.OnCompleteScope.invoke|invoke@com.benwoodworth.parameterize.ParameterizeFailedError.Companion(){}[0]
}
Expand Down
18 changes: 16 additions & 2 deletions src/commonMain/kotlin/ParameterizeConfiguration.kt
Original file line number Diff line number Diff line change
Expand Up @@ -214,10 +214,18 @@ public class ParameterizeConfiguration internal constructor(
/** @see Builder.onComplete */
public class OnCompleteScope internal constructor(
/**
* The total number of iterations completed.
* The total number of iterations, including [skips][skipCount] and [failures][failureCount].
*/
public val iterationCount: Long,

/**
* The number of skipped iterations.
*
* A [parameterize] iteration will be skipped when a [parameter] is declared without any
* [arguments][ParameterizeScope.Parameter.arguments].
*/
public val skipCount: Long,

/**
* The number of failing iterations.
*/
Expand All @@ -235,8 +243,14 @@ public class ParameterizeConfiguration internal constructor(
/** @see OnFailureScope.recordFailure */
public val recordedFailures: List<ParameterizeFailure>
) {
/**
* The number of successful iterations, completed without [skipping][skipCount] or [failing][failureCount].
*/
public val successCount: Long
get() = iterationCount - skipCount - failureCount

/** @see ParameterizeFailedError */
public operator fun ParameterizeFailedError.Companion.invoke(): ParameterizeFailedError =
ParameterizeFailedError(recordedFailures, failureCount, iterationCount, completedEarly)
ParameterizeFailedError(recordedFailures, successCount, failureCount, completedEarly)
}
}
6 changes: 3 additions & 3 deletions src/commonMain/kotlin/ParameterizeFailedError.kt
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,17 @@ import com.benwoodworth.parameterize.ParameterizeConfiguration.OnCompleteScope
*/
public expect class ParameterizeFailedError internal constructor(
recordedFailures: List<ParameterizeFailure>,
successCount: Long,
failureCount: Long,
iterationCount: Long,
completedEarly: Boolean
) : AssertionError {
// TODO: Use context receiver instead of companion + pseudo constructor
/** @suppress */
public companion object;

internal val recordedFailures: List<ParameterizeFailure>
internal val successCount: Long
internal val failureCount: Long
internal val iterationCount: Long
internal val completedEarly: Boolean

/** @suppress */
Expand Down Expand Up @@ -88,7 +88,7 @@ internal inline val ParameterizeFailedError.commonMessage
append("Failed ")
append(failureCount)
append('/')
append(iterationCount)
append(successCount + failureCount)

if (completedEarly) {
append('+')
Expand Down
2 changes: 1 addition & 1 deletion src/commonMain/kotlin/ParameterizeIterator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ internal class ParameterizeIterator(

@PublishedApi
internal fun handleFailure(failure: Throwable): Unit = when {
failure is ParameterizeContinue -> {}
failure is ParameterizeContinue -> parameterizeState.handleContinue()

failure is ParameterizeException && failure.parameterizeState === parameterizeState -> {
afterEach() // Since nextIteration() won't be called again to finalize the iteration
Expand Down
6 changes: 6 additions & 0 deletions src/commonMain/kotlin/ParameterizeState.kt
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ internal class ParameterizeState {
private var lastParameterWithNextArgument: ParameterState? = null

private var iterationCount = 0L
private var skipCount = 0L
private var failureCount = 0L
private val recordedFailures = mutableListOf<ParameterizeFailure>()

Expand Down Expand Up @@ -111,6 +112,10 @@ internal class ParameterizeState {
}
}

fun handleContinue() {
skipCount++
}

/**
* Get a list of used arguments for reporting a failure.
*/
Expand Down Expand Up @@ -153,6 +158,7 @@ internal class ParameterizeState {

val scope = OnCompleteScope(
iterationCount,
skipCount,
failureCount,
completedEarly = hasNextArgumentCombination,
recordedFailures,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,91 @@ class ParameterizeConfigurationSpec_onComplete {
}
}

@Test
fun iteration_count_should_be_correct_with_skips() {
var expectedIterationCount = 0L

testParameterize(
onComplete = {
assertEquals(expectedIterationCount, iterationCount)
}
) {
val iteration by parameter(0..100)

expectedIterationCount++

if (iteration % 3 == 0 && iteration % 7 == 0) {
val skipWithEmptyParameter by parameterOf<Unit>()
}
}
}

@Test
fun skip_count_should_be_correct() {
var expectedSkipCount = 0L

testParameterize(
onComplete = {
assertEquals(expectedSkipCount, skipCount)
}
) {
val iteration by parameter(0..100)

if (iteration % 3 == 0 && iteration % 7 == 0) {
expectedSkipCount++
val skipWithEmptyParameter by parameterOf<Unit>()
}
}
}

@Test
fun skip_count_should_be_correct_with_break() {
var expectedSkipCount = 0L

testParameterize(
onFailure = {
breakEarly = true
},
onComplete = {
assertEquals(expectedSkipCount, skipCount)
}
) {
val iteration by parameter(0..100)

if (iteration % 3 == 0 && iteration % 7 == 0) {
expectedSkipCount++
val skipWithEmptyParameter by parameterOf<Unit>()
}

if (iteration == 50) {
fail()
}
}
}

@Test
fun success_count_should_be_correct_with_skips_and_failures() {
var expectedSuccessCount = 0L

testParameterize(
onComplete = {
assertEquals(expectedSuccessCount, successCount)
}
) {
val iteration by parameter(0..100)

if (iteration % 3 == 0) {
val skipWithEmptyParameter by parameterOf<Unit>()
}

if (iteration % 7 == 0) {
fail()
}

expectedSuccessCount++
}
}

@Test
fun failure_count_should_be_correct() {
var expectedFailureCount = 0L
Expand Down Expand Up @@ -240,12 +325,14 @@ class ParameterizeConfigurationSpec_onComplete {
"base values" to OnCompleteScope(
recordedFailures = emptyList(),
failureCount = 1,
skipCount = 1,
iterationCount = 1,
completedEarly = false
),
"changed values" to OnCompleteScope(
recordedFailures = listOf(ParameterizeFailure(Throwable(), emptyList())),
failureCount = 2,
skipCount = 2,
iterationCount = 2,
completedEarly = true
)
Expand All @@ -255,8 +342,8 @@ class ParameterizeConfigurationSpec_onComplete {
}

assertEquals(scope.recordedFailures, error.recordedFailures, error::recordedFailures.name)
assertEquals(scope.successCount, error.successCount, error::successCount.name)
assertEquals(scope.failureCount, error.failureCount, error::failureCount.name)
assertEquals(scope.iterationCount, error.iterationCount, error::iterationCount.name)
assertEquals(scope.completedEarly, error.completedEarly, error::completedEarly.name)
}
}
30 changes: 15 additions & 15 deletions src/commonTest/kotlin/ParameterizeFailedErrorSpec.kt
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ class ParameterizeFailedErrorSpec {
fun message_should_have_failure_count_and_total() {
val error = ParameterizeFailedError(
emptyList(),
successCount = 4,
failureCount = 3,
iterationCount = 7,
completedEarly = false
)

Expand All @@ -52,8 +52,8 @@ class ParameterizeFailedErrorSpec {
fun message_total_when_completed_early_should_have_a_plus_after_the_total() {
val error = ParameterizeFailedError(
emptyList(),
successCount = 4,
failureCount = 3,
iterationCount = 7,
completedEarly = true
)

Expand All @@ -70,8 +70,8 @@ class ParameterizeFailedErrorSpec {

val error = ParameterizeFailedError(
failures.map { ParameterizeFailure(it, emptyList()) },
successCount = 4,
failureCount = 3,
iterationCount = 7,
completedEarly = false
)

Expand All @@ -97,8 +97,8 @@ class ParameterizeFailedErrorSpec {

val error = ParameterizeFailedError(
failures.map { ParameterizeFailure(it, emptyList()) },
successCount = 4,
failureCount = 3,
iterationCount = 7,
completedEarly = false
)

Expand All @@ -123,8 +123,8 @@ class ParameterizeFailedErrorSpec {

val error = ParameterizeFailedError(
failures.map { ParameterizeFailure(it, emptyList()) },
successCount = 4,
failureCount = 3,
iterationCount = 7,
completedEarly = false
)

Expand All @@ -147,8 +147,8 @@ class ParameterizeFailedErrorSpec {

val error = ParameterizeFailedError(
failures.map { ParameterizeFailure(it, emptyList()) },
successCount = 6,
failureCount = 1,
iterationCount = 7,
completedEarly = false
)

Expand All @@ -165,8 +165,8 @@ class ParameterizeFailedErrorSpec {
fun message_failure_list_should_end_with_an_ellipsis_if_not_all_failures_were_recorded() {
val error = ParameterizeFailedError(
List(2) { i -> ParameterizeFailure(Throwable("Failure $i"), emptyList()) },
successCount = 4,
failureCount = 3,
iterationCount = 7,
completedEarly = false
)

Expand All @@ -190,8 +190,8 @@ class ParameterizeFailedErrorSpec {

val error = ParameterizeFailedError(
failures.mapIndexed { index, it -> ParameterizeFailure(it, arguments.take(index)) },
successCount = 4,
failureCount = 3,
iterationCount = 7,
completedEarly = false
)

Expand All @@ -216,8 +216,8 @@ class ParameterizeFailedErrorSpec {

val error = ParameterizeFailedError(
failures.map { ParameterizeFailure(it, arguments) },
successCount = 4,
failureCount = 3,
iterationCount = 7,
completedEarly = false
)

Expand All @@ -231,8 +231,8 @@ class ParameterizeFailedErrorSpec {
fun recorded_failure_message_with_no_arguments_should_say_failed_with_no_arguments() {
val error = ParameterizeFailedError(
listOf(ParameterizeFailure(Throwable(), emptyList())),
successCount = 0,
failureCount = 1,
iterationCount = 1,
completedEarly = false
)

Expand All @@ -245,8 +245,8 @@ class ParameterizeFailedErrorSpec {
fun recorded_failure_message_with_one_used_parameter_should_list_its_argument() {
val error = ParameterizeFailedError(
listOf(ParameterizeFailure(Throwable(), arguments.take(1))),
successCount = 0,
failureCount = 1,
iterationCount = 1,
completedEarly = false
)

Expand All @@ -265,8 +265,8 @@ class ParameterizeFailedErrorSpec {
fun recorded_failure_message_with_two_used_parameters_should_list_their_arguments() {
val error = ParameterizeFailedError(
listOf(ParameterizeFailure(Throwable(), arguments)),
successCount = 0,
failureCount = 1,
iterationCount = 1,
completedEarly = false
)

Expand All @@ -286,8 +286,8 @@ class ParameterizeFailedErrorSpec {
fun stack_trace_without_recorded_failures_should_not_be_cleared() {
val error = ParameterizeFailedError(
listOf(),
successCount = 0,
failureCount = 1,
iterationCount = 1,
completedEarly = false
)

Expand All @@ -301,8 +301,8 @@ class ParameterizeFailedErrorSpec {

val error = ParameterizeFailedError(
listOf(ParameterizeFailure(failure, arguments)),
successCount = 0,
failureCount = 1,
iterationCount = 1,
completedEarly = false
)

Expand All @@ -316,8 +316,8 @@ class ParameterizeFailedErrorSpec {

val error = ParameterizeFailedError(
listOf(ParameterizeFailure(failure, arguments)),
successCount = 0,
failureCount = 1,
iterationCount = 1,
completedEarly = false
)

Expand Down
2 changes: 1 addition & 1 deletion src/jsMain/kotlin/ParameterizeFailedError.js.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ package com.benwoodworth.parameterize

public actual class ParameterizeFailedError internal actual constructor(
internal actual val recordedFailures: List<ParameterizeFailure>,
internal actual val successCount: Long,
internal actual val failureCount: Long,
internal actual val iterationCount: Long,
internal actual val completedEarly: Boolean
) : AssertionError() {
public actual companion object;
Expand Down
Loading

0 comments on commit 2b667c9

Please sign in to comment.