Added main method for command line usage
This commit is contained in:
parent
ecbefa231e
commit
fad3714ae0
5 changed files with 127 additions and 18 deletions
|
@ -19,15 +19,22 @@ package net.thauvin.erik.urlencoder
|
|||
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.util.BitSet
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
/**
|
||||
* URL parameters encoding and decoding.
|
||||
*
|
||||
* - Rules determined by [RFC 3986](https://www.rfc-editor.org/rfc/rfc3986#page-13),
|
||||
*
|
||||
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
|
||||
* @author Erik C. Thauvin (erik@thauvin.net)
|
||||
*/
|
||||
object UrlEncoder {
|
||||
private val hexDigits = "0123456789ABCDEF".toCharArray()
|
||||
internal val usage = """Usage : kotlin -cp urlencoder-*.jar ${UrlEncoder::class.java.name} [-ed] text
|
||||
Encode and decode URL parameters.
|
||||
-e encode (default)
|
||||
-d decode"""
|
||||
|
||||
// see https://www.rfc-editor.org/rfc/rfc3986#page-13
|
||||
private val unreservedChars = BitSet('~'.code + 1).apply {
|
||||
|
@ -103,7 +110,7 @@ object UrlEncoder {
|
|||
}
|
||||
} else {
|
||||
if (bytesBuffer != null) {
|
||||
out?.append(String(bytesBuffer, 0, bytesPos, StandardCharsets.UTF_8))
|
||||
out!!.append(String(bytesBuffer, 0, bytesPos, StandardCharsets.UTF_8))
|
||||
bytesBuffer = null
|
||||
bytesPos = 0
|
||||
}
|
||||
|
@ -121,7 +128,9 @@ object UrlEncoder {
|
|||
|
||||
/**
|
||||
* Transforms a provided [String] object into a new string, containing only valid URL characters in the UTF-8
|
||||
* encoding. Letters, numbers, unreserved (`_-!.~'()*`) and allowed characters are left intact.
|
||||
* encoding.
|
||||
*
|
||||
* - Letters, numbers, unreserved (`_-!.~'()*`) and allowed characters are left intact.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun encode(source: String, allow: String): String {
|
||||
|
@ -167,10 +176,50 @@ object UrlEncoder {
|
|||
|
||||
/**
|
||||
* Transforms a provided [String] object into a new string, containing only valid URL characters in the UTF-8
|
||||
* encoding. Letters, numbers, unreserved (`_-!.~'()*`) and allowed characters are left intact.
|
||||
* encoding.
|
||||
*
|
||||
* - Letters, numbers, unreserved (`_-!.~'()*`) and allowed characters are left intact.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun encode(source: String, vararg allow: Char): String {
|
||||
return encode(source, String(allow))
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes and decodes URLs from the command line.
|
||||
*
|
||||
* - `kotlin -cp urlencoder-*.jar net.thauvin.erik.urlencoder.UrlEncoder`
|
||||
*/
|
||||
@JvmStatic
|
||||
fun main(args: Array<String>) {
|
||||
val result = processMain(args)
|
||||
if (result.status == 1) {
|
||||
System.err.println(result.output)
|
||||
} else {
|
||||
println(result.output)
|
||||
}
|
||||
exitProcess(result.status)
|
||||
}
|
||||
|
||||
internal data class MainResult(var output: String = usage, var status: Int = 1)
|
||||
|
||||
internal fun processMain(args: Array<String>): MainResult {
|
||||
val result = MainResult()
|
||||
if (args.isNotEmpty() && args[0].isNotBlank()) {
|
||||
val hasDecode = args[0] == "-d"
|
||||
val hasOption = hasDecode || args[0] == "-e"
|
||||
if (!hasOption || args.size >= 2) {
|
||||
val argsList = mutableListOf<String>()
|
||||
argsList.addAll(args)
|
||||
if (hasOption) argsList.removeAt(0)
|
||||
if (hasDecode) {
|
||||
result.output = decode(argsList.joinToString(" "))
|
||||
} else {
|
||||
result.output = encode(argsList.joinToString(" "))
|
||||
}
|
||||
result.status = 0
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,8 @@ package net.thauvin.erik.urlencoder
|
|||
|
||||
import net.thauvin.erik.urlencoder.UrlEncoder.decode
|
||||
import net.thauvin.erik.urlencoder.UrlEncoder.encode
|
||||
import net.thauvin.erik.urlencoder.UrlEncoder.processMain
|
||||
import net.thauvin.erik.urlencoder.UrlEncoder.usage
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
|
@ -44,9 +46,10 @@ class UrlEncoderTest {
|
|||
assertEquals(it.key, decode(it.value))
|
||||
}
|
||||
invalid.forEach {
|
||||
assertFailsWith(IllegalArgumentException::class) {
|
||||
decode(it)
|
||||
}
|
||||
assertFailsWith<IllegalArgumentException>(
|
||||
message = it,
|
||||
block = { decode(it) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,4 +66,45 @@ class UrlEncoderTest {
|
|||
assertEquals("?test=a%20test", encode("?test=a test", "=?"))
|
||||
assertEquals("aaa", encode("aaa", 'a'))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testMainDecode() {
|
||||
var result: UrlEncoder.MainResult
|
||||
validMap.forEach {
|
||||
result = processMain(arrayOf("-d", it.value))
|
||||
assertEquals(result.output, it.key, it.key)
|
||||
assertEquals(result.status, 0, it.key)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testMainEncode() {
|
||||
var result: UrlEncoder.MainResult
|
||||
validMap.forEach {
|
||||
result = processMain(arrayOf("-e", it.key))
|
||||
assertEquals(it.value, result.output, "-e ${it.key}")
|
||||
assertEquals(0, result.status, "-e ${it.key}")
|
||||
|
||||
result = processMain(arrayOf(it.key))
|
||||
assertEquals(it.value, result.output, it.value)
|
||||
assertEquals(0, result.status, it.value)
|
||||
}
|
||||
|
||||
invalid.forEach {
|
||||
assertFailsWith<IllegalArgumentException>(
|
||||
message = it,
|
||||
block = { processMain(arrayOf("-d", it)) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testMainUsage() {
|
||||
var result: UrlEncoder.MainResult
|
||||
for (arg in arrayOf("", " ", "-d", "-e")) {
|
||||
result = processMain(arrayOf(arg))
|
||||
assertEquals(usage, result.output, "processMain('$arg')")
|
||||
assertEquals(1, result.status, "processMain('$arg')")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue