Added parameterized tests

This commit is contained in:
Erik C. Thauvin 2023-01-01 23:05:17 -08:00
parent 59d53ebe01
commit 5f84e96b11
4 changed files with 132 additions and 81 deletions

View file

@ -26,7 +26,7 @@ val deployDir = "deploy"
val gitHub = "ethauvin/${rootProject.name}" val gitHub = "ethauvin/${rootProject.name}"
val mavenUrl = "https://github.com/$gitHub" val mavenUrl = "https://github.com/$gitHub"
val publicationName = "mavenJava" val publicationName = "mavenJava"
val myClassName = "net.thauvin.erik.urlencoder.UrlEncoder" val myClassName = "$group.${rootProject.name}.$mavenName"
repositories { repositories {
mavenCentral() mavenCentral()
@ -34,7 +34,8 @@ repositories {
} }
dependencies { dependencies {
testImplementation(kotlin("test")) // testImplementation("com.willowtreeapps.assertk:assertk-jvm:0.25")
testImplementation("org.junit.jupiter:junit-jupiter:5.9.0")
} }
base { base {
@ -79,6 +80,10 @@ tasks {
kotlinOptions.jvmTarget = java.targetCompatibility.toString() kotlinOptions.jvmTarget = java.targetCompatibility.toString()
} }
test {
useJUnitPlatform()
}
withType<Test> { withType<Test> {
testLogging { testLogging {
exceptionFormat = TestExceptionFormat.FULL exceptionFormat = TestExceptionFormat.FULL

View file

@ -2,6 +2,7 @@
<SmellBaseline> <SmellBaseline>
<ManuallySuppressedIssues/> <ManuallySuppressedIssues/>
<CurrentIssues> <CurrentIssues>
<ID>ComplexCondition:UrlEncoder.kt$UrlEncoder$hasOption &amp;&amp; args.size == 2 || !hasOption &amp;&amp; args.size == 1</ID>
<ID>MagicNumber:UrlEncoder.kt$UrlEncoder$0x80</ID> <ID>MagicNumber:UrlEncoder.kt$UrlEncoder$0x80</ID>
<ID>MagicNumber:UrlEncoder.kt$UrlEncoder$0xFF</ID> <ID>MagicNumber:UrlEncoder.kt$UrlEncoder$0xFF</ID>
<ID>MagicNumber:UrlEncoder.kt$UrlEncoder$16</ID> <ID>MagicNumber:UrlEncoder.kt$UrlEncoder$16</ID>

View file

@ -1,6 +1,6 @@
/* /*
* Copyright 2001-2022 Geert Bevin (gbevin[remove] at uwyn dot com) * Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Copyright 2022 Erik C. Thauvin (erik@thauvin.net) * Copyright 2023 Erik C. Thauvin (erik@thauvin.net)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -134,10 +134,9 @@ object UrlEncoder {
*/ */
@JvmStatic @JvmStatic
fun encode(source: String, allow: String): String { fun encode(source: String, allow: String): String {
if (source.isBlank()) { if (source.isEmpty()) {
return source return source
} }
var out: StringBuilder? = null var out: StringBuilder? = null
var ch: Char var ch: Char
var i = 0 var i = 0
@ -145,6 +144,7 @@ object UrlEncoder {
ch = source[i] ch = source[i]
if (ch.isUnreserved() || allow.indexOf(ch) != -1) { if (ch.isUnreserved() || allow.indexOf(ch) != -1) {
out?.append(ch) out?.append(ch)
println(out)
i++ i++
} else { } else {
if (out == null) { if (out == null) {
@ -205,10 +205,10 @@ object UrlEncoder {
internal fun processMain(args: Array<String>): MainResult { internal fun processMain(args: Array<String>): MainResult {
val result = MainResult() val result = MainResult()
if (args.isNotEmpty() && args[0].isNotBlank() && args.size <= 2) { if (args.isNotEmpty() && args[0].isNotEmpty()) {
val hasDecode = args[0] == "-d" val hasDecode = (args[0] == "-d")
val hasOption = hasDecode || args[0] == "-e" val hasOption = (hasDecode || args[0] == "-e")
if (!hasOption || args.size == 2) { if (hasOption && args.size == 2 || !hasOption && args.size == 1) {
val arg = if (hasOption) args[1] else args[0] val arg = if (hasOption) args[1] else args[0]
if (hasDecode) { if (hasDecode) {
result.output = decode(arg) result.output = decode(arg)

View file

@ -1,6 +1,6 @@
/* /*
* Copyright 2001-2022 Geert Bevin (gbevin[remove] at uwyn dot com) * Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Copyright 2022 Erik C. Thauvin (erik@thauvin.net) * Copyright 2023 Erik C. Thauvin (erik@thauvin.net)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -21,91 +21,136 @@ import net.thauvin.erik.urlencoder.UrlEncoder.decode
import net.thauvin.erik.urlencoder.UrlEncoder.encode import net.thauvin.erik.urlencoder.UrlEncoder.encode
import net.thauvin.erik.urlencoder.UrlEncoder.processMain import net.thauvin.erik.urlencoder.UrlEncoder.processMain
import net.thauvin.erik.urlencoder.UrlEncoder.usage import net.thauvin.erik.urlencoder.UrlEncoder.usage
import org.junit.Test import org.junit.jupiter.api.Assertions.assertEquals
import kotlin.test.assertEquals import org.junit.jupiter.api.Assertions.assertSame
import kotlin.test.assertFailsWith import org.junit.jupiter.api.Assertions.assertThrows
import kotlin.test.assertSame import org.junit.jupiter.api.Assertions.assertTrue
import kotlin.test.assertTrue import org.junit.jupiter.api.Test
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.Arguments
import org.junit.jupiter.params.provider.Arguments.arguments
import org.junit.jupiter.params.provider.MethodSource
import org.junit.jupiter.params.provider.ValueSource
import java.util.stream.Stream
class UrlEncoderTest { class UrlEncoderTest {
private val invalid = arrayOf("sdkjfh%", "sdkjfh%6", "sdkjfh%xx", "sdfjfh%-1")
private val same = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVQXYZ0123456789-_.~" private val same = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVQXYZ0123456789-_.~"
private val validMap = mapOf(
"a test &" to "a%20test%20%26", companion object {
"!abcdefghijklmnopqrstuvwxyz%%ABCDEFGHIJKLMNOPQRSTUVQXYZ0123456789-_.~=" to @JvmStatic
"%21abcdefghijklmnopqrstuvwxyz%25%25ABCDEFGHIJKLMNOPQRSTUVQXYZ0123456789-_.~%3D", fun invalid() = arrayOf("sdkjfh%", "sdkjfh%6", "sdkjfh%xx", "sdfjfh%-1")
"%#okékÉȢ smile!😁" to "%25%23ok%C3%A9k%C3%89%C8%A2%20smile%21%F0%9F%98%81"
@JvmStatic
fun validMap(): Stream<Arguments> = Stream.of(
arguments("a test &", "a%20test%20%26"),
arguments(
"!abcdefghijklmnopqrstuvwxyz%%ABCDEFGHIJKLMNOPQRSTUVQXYZ0123456789-_.~=",
"%21abcdefghijklmnopqrstuvwxyz%25%25ABCDEFGHIJKLMNOPQRSTUVQXYZ0123456789-_.~%3D"
),
arguments("%#okékÉȢ smile!😁", "%25%23ok%C3%A9k%C3%89%C8%A2%20smile%21%F0%9F%98%81"),
arguments(
"\uD808\uDC00\uD809\uDD00\uD808\uDF00\uD808\uDD00", "%F0%92%80%80%F0%92%94%80%F0%92%8C%80%F0%92%84%80"
) )
)
}
@ParameterizedTest(name = "decode({0}) should be {1}")
@MethodSource("validMap")
fun `Decode Multiple URLs`(expected: String, source: String) {
assertEquals(expected, decode(source))
}
@ParameterizedTest(name = "decode({0})")
@MethodSource("invalid")
fun `Decode with Exceptions`(source: String) {
assertThrows(IllegalArgumentException::class.java, { decode(source) }, "decode($source)")
}
@Test @Test
fun testDecode() { fun `Decode when none needed`() {
assertEquals("", decode(""))
assertSame(same, decode(same)) assertSame(same, decode(same))
validMap.forEach { assertEquals("", decode(""), "decode('')")
assertEquals(it.key, decode(it.value)) assertEquals(" ", decode(" "), "decode(' ')")
}
invalid.forEach {
assertFailsWith<IllegalArgumentException>(
message = it,
block = { decode(it) }
)
} }
@ParameterizedTest(name = "encode({0}) should be {1}")
@MethodSource("validMap")
fun `Encode Multiple URLs`(source: String, expected: String) {
assertEquals(expected, encode(source))
} }
@Test @Test
fun testEncode() { fun `Encode Empty or Blank`() {
assertEquals("", encode("")) assertTrue(encode("", "").isEmpty(), "encode('','')")
assertEquals("", encode(""), "encode('')")
assertEquals("%20", encode(" "), "encode('')")
}
@Test
fun `Encode when none needed`() {
assertSame(same, encode(same)) assertSame(same, encode(same))
assertSame(same, encode(same, "")) assertSame(same, encode(same, ""), "with empty allow")
assertTrue(encode("").isEmpty())
validMap.forEach {
assertEquals(it.value, encode(it.key))
}
assertEquals("?test=a%20test", encode("?test=a test", '=', '?'))
assertEquals("?test=a%20test", encode("?test=a test", "=?"))
assertEquals("aaa", encode("aaa", 'a'))
} }
@Test @Test
fun testMainDecode() { fun `Encode with allow arg`() {
var result: UrlEncoder.MainResult assertEquals("?test=a%20test", encode("?test=a test", '=', '?'), "encode(x, =, ?)")
validMap.forEach { assertEquals("?test=a%20test", encode("?test=a test", "=?"), "encode(x, =?)")
result = processMain(arrayOf("-d", it.value)) assertEquals("aaa", encode("aaa", 'a'), "encode(aaa, a)")
assertEquals(result.output, it.key, it.key) assertEquals(" ", encode(" ", ' '), "encode(' ', ' ')")
assertEquals(result.status, 0, it.key)
} }
@ParameterizedTest(name = "processMain(-d {1}) should be {0}")
@MethodSource("validMap")
fun `Main Decode`(expected: String, source: String) {
val result: UrlEncoder.MainResult = processMain(arrayOf("-d", source))
assertEquals(expected, result.output)
assertEquals(0, result.status, "processMain(-d $source).status")
} }
@ParameterizedTest(name = "processMain(-d {0})")
@MethodSource("invalid")
fun `Main Decode with Exceptions`(source: String) {
assertThrows(IllegalArgumentException::class.java, { processMain(arrayOf("-d", source)) }, source)
}
@ParameterizedTest(name = "processMain(-e {0})")
@MethodSource("validMap")
fun `Main Encode`(source: String, expected: String) {
val result = processMain(arrayOf(source))
assertEquals(expected, result.output)
assertEquals(0, result.status, "processMain(-e $source).status")
}
@ParameterizedTest(name = "processMain(-e {0})")
@MethodSource("validMap")
fun `Main Encode with option`(source: String, expected: String) {
val result = processMain(arrayOf("-e", source))
assertEquals(expected, result.output)
assertEquals(0, result.status, "processMain(-e $source).status")
}
@Test @Test
fun testMainEncode() { fun `Main Usage with Empty args`() {
var result: UrlEncoder.MainResult assertEquals(usage, processMain(arrayOf(" ", " ")).output, "processMain(' ', ' ')")
validMap.forEach { assertEquals(usage, processMain(arrayOf("foo", " ")).output, "processMain('foo', ' ')")
result = processMain(arrayOf("-e", it.key)) assertEquals(usage, processMain(arrayOf(" ", "foo")).output, "processMain(' ', 'foo')")
assertEquals(it.value, result.output, "-e ${it.key}") assertEquals(usage, processMain(arrayOf("-d ", "")).output, "processMain('-d', '')")
assertEquals(0, result.status, "-e ${it.key}") assertEquals("%20", processMain(arrayOf("-e", " ")).output, "processMain('-e', ' ')")
assertEquals(" ", processMain(arrayOf("-d", " ")).output, "processMain('-d', ' ')")
result = processMain(arrayOf(it.key))
assertEquals(it.value, result.output, it.value)
assertEquals(0, result.status, it.value)
} }
invalid.forEach { @ParameterizedTest
assertFailsWith<IllegalArgumentException>( @ValueSource(strings = ["", "-d", "-e"])
message = it, fun `Main Usage with invalid arg`(arg: String) {
block = { processMain(arrayOf("-d", it)) } val result = processMain(arrayOf(arg))
)
}
}
@Test
fun testMainUsage() {
var result: UrlEncoder.MainResult
assertEquals(usage, processMain(arrayOf("foo", "bar", "test")).output, "too many args")
for (arg in arrayOf("", " ", "-d", "-e")) {
result = processMain(arrayOf(arg))
assertEquals(usage, result.output, "processMain('$arg')") assertEquals(usage, result.output, "processMain('$arg')")
assertEquals(1, result.status, "processMain('$arg')") assertEquals(1, result.status, "processMain('$arg').status")
} }
@Test
fun `Main Usage with too many args`() {
assertEquals(usage, processMain(arrayOf("foo", "bar", "test")).output, "too many args")
} }
} }