Skip to content

Commit

Permalink
support varargs formatter, fixes #70
Browse files Browse the repository at this point in the history
  • Loading branch information
jangalinski committed Jul 21, 2022
1 parent 1b38b5c commit 9cd5f65
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 0 deletions.
9 changes: 9 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
<jgiven.version>1.2.2</jgiven.version>
<spring-boot.version>2.3.7.RELEASE</spring-boot.version>

<!-- TEST -->
<assertj.version>3.23.1</assertj.version>
</properties>

<dependencyManagement>
Expand Down Expand Up @@ -63,6 +65,13 @@
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>${assertj.version}</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package io.toolisticon.testing.jgiven.format

import com.tngtech.jgiven.annotation.Format
import com.tngtech.jgiven.format.ArgumentFormatter
import com.tngtech.jgiven.format.PrintfFormatter
import kotlin.annotation.AnnotationRetention.RUNTIME
import kotlin.annotation.AnnotationTarget.*


/**
* Varargs step parameters annotated with this annotation will be put into quotes (" ") in reports.
*/
@MustBeDocumented
@Format(value = VarargsFormatter::class, args = ["\"%s\""])
@Target(FIELD, VALUE_PARAMETER, ANNOTATION_CLASS)
@Retention(RUNTIME)
annotation class VarargsQuoted

/**
* Argument formatter for varargs delegating to [PrintfFormatter]
*/
class VarargsFormatter @JvmOverloads constructor(private val delimiter: String = ", ") : ArgumentFormatter<Any?> {
companion object {
fun anyToList(instance: Any?): List<Any?>? {
if (instance == null || !instance::class.java.isArray) {
return null
}

// deal with the various primitive array (int[],...) wrappers in kotlin.
return when (instance) {
is IntArray -> instance.toList()
is ByteArray -> instance.toList()
is CharArray -> instance.toList()
is ShortArray -> instance.toList()
is LongArray -> instance.toList()
is DoubleArray -> instance.toList()
is FloatArray -> instance.toList()
is BooleanArray -> instance.toList()
else -> (instance as Array<*>).toList()
}
}
}

private val formatter = PrintfFormatter()

override fun format(argumentToFormat: Any?, vararg formatterArguments: String): String {
val argumentList = anyToList(argumentToFormat)

return argumentList
?.joinToString(separator = delimiter) { formatter.format(it, *formatterArguments) }
?: formatter.format(argumentToFormat, *formatterArguments)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.tngtech.jgiven.Stage
import com.tngtech.jgiven.annotation.ScenarioState
import com.tngtech.jgiven.annotation.ScenarioState.Resolution.NAME
import com.tngtech.jgiven.junit5.SimpleScenarioTest
import io.toolisticon.testing.jgiven.format.VarargsQuoted
import org.junit.jupiter.api.Test
import kotlin.test.assertEquals

Expand All @@ -25,6 +26,18 @@ internal class CalculatorExampleTest : SimpleScenarioTest<CalculatorStage>() {
THEN
.`the sum is $`(11)
}

@Test
fun `calculator adds two numbers as varargs`() {
GIVEN
.`numbers are $`(5, 4)

WHEN
.`both numbers are added`()

THEN
.`the sum is $`(9)
}
}

@JGivenKotlinStage
Expand All @@ -39,6 +52,14 @@ class CalculatorStage : Stage<CalculatorStage>() {
@ScenarioState(resolution = NAME)
var sum: Int = 0

/**
* Sets both numbers via vararg, use to verify Vararg formatter.
*/
fun `numbers are $`(@VarargsQuoted vararg nums: Int) = step {
require(nums.size == 2) { "need to pass two numbers" }
`the first number is $`(nums[0]).`the second number is $`(nums[1])
}

fun `the first number is $`(n: Int) = step {
this.firstNumber = n
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package io.toolisticon.testing.jgiven.format

import io.toolisticon.testing.jgiven.format.VarargsFormatter.Companion.anyToList
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.junit.jupiter.api.Nested
import org.junit.jupiter.api.Test


internal class VarargsFormatterTest {

private var formatter: VarargsFormatter = VarargsFormatter()


@Test
fun `format a single value`() {
assertThat(formatter.format("value", "\"%s\"")).isEqualTo("\"value\"")
}

@Test
fun `format single array values`() {
val varargs = arrayOf("value")
assertThat(formatter.format(varargs, "\"%s\"")).isEqualTo("\"value\"")
}

@Test
fun `format multiple array values`() {
val varargs = arrayOf<Any>("value1", 1L)
assertThat(formatter.format(varargs, "\"%s\"")).isEqualTo("\"value1\", \"1\"")
}

@Test
fun `fail without formatterArguments`() {
val varargs = arrayOf("value")

assertThatThrownBy { formatter.format(varargs) }
.isInstanceOf(ArrayIndexOutOfBoundsException::class.java)
}

@Test
fun `format null value`() {
val varargs: Array<String>? = null
assertThat(formatter.format(varargs, "\"%s\"")).isEqualTo("\"null\"")
}

@Nested
inner class AnyToList {


@Test
fun `null to null`() {
assertThat(anyToList(null)).isNull()
}

@Test
fun `non-array to null`() {
assertThat(anyToList("")).isNull()
}

@Test
fun `int to list`() {
val list: List<Any?> = requireNotNull(anyToList(varargInt(1, 2, 3)))

assertThat(list).containsExactly(1, 2, 3)
}

@Test
fun `boolean to list`() {
val list = requireNotNull(anyToList(varargBoolean(true, false, null)))

assertThat(list).containsExactly(true, false, null)
}
}

private fun varargInt(vararg v: Int): Any? = v as Any?
private fun varargBoolean(vararg v: Boolean?): Any? = v as Any?
}

0 comments on commit 9cd5f65

Please sign in to comment.