diff src/test/kotlin/name/blackcap/passman/ShplitterTest.kt @ 19:7d80cbcb67bb

add shlex-style splitter and tests
author David Barts <n5jrn@me.com>
date Sun, 30 Jun 2024 20:37:36 -0700
parents
children 4391afcf6bd0
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/test/kotlin/name/blackcap/passman/ShplitterTest.kt	Sun Jun 30 20:37:36 2024 -0700
@@ -0,0 +1,119 @@
+package name.blackcap.passman
+
+import org.junit.jupiter.api.Assertions.assertFalse
+import org.junit.jupiter.api.Assertions.assertTrue
+import org.junit.jupiter.api.Test
+
+class ShplitterTest {
+    private lateinit var fixture: Shplitter
+
+    @Test
+    fun complete() {
+        val CASES = arrayOf<String>(
+            "unquoted",
+            "\"double quoted\"",
+            "'single quoted'",
+            "back\\ slash",
+            "in\\terior back slash",
+            "\"first\" word double quoted",
+            "last word double \"quoted\"",
+            "'first' word single quoted",
+            "last word single 'quoted'")
+
+        for (case in CASES) {
+            val fixture = Shplitter()
+            fixture.feed(case)
+            assertTrue(fixture.complete, "should be complete but is not: ${case}")
+        }
+    }
+
+    @Test
+    fun incomplete() {
+        val CASES = arrayOf<String>(
+            "ends with backslash\\",
+            "unclosed double \"quote",
+            "ends with double quote\"",
+            "unclosed single 'quote",
+            "ends with single quote'"
+        )
+        for (case in CASES) {
+            val fixture = Shplitter()
+            fixture.feed(case)
+            assertFalse(fixture.complete, "should not be complete but is: ${case}")
+        }
+    }
+
+    // Test cases cribbed from Python shlex source.
+    data class TestDatum(val from: String, val to: Array<String>)
+    val TEST_DATA_1 = arrayOf<TestDatum>(
+        TestDatum("foo bar", arrayOf<String>("foo", "bar")),
+        TestDatum(" foo bar", arrayOf<String>("foo", "bar")),
+        TestDatum(" foo bar ", arrayOf<String>("foo", "bar")),
+        TestDatum("foo\tbar\tbla\tfasel", arrayOf<String>("foo", "bar", "bla", "fasel")),
+        TestDatum("x y  z\t\txxxx", arrayOf<String>("x", "y", "z", "xxxx")),
+        TestDatum("\\x bar", arrayOf<String>("x", "bar")),
+        TestDatum("\\ x bar", arrayOf<String>(" x", "bar")),
+        TestDatum("\\ bar", arrayOf<String>(" bar")),
+        TestDatum("foo \\x bar", arrayOf<String>("foo", "x", "bar")),
+        TestDatum("foo \\ x bar", arrayOf<String>("foo", " x", "bar")),
+        TestDatum("foo \\ bar", arrayOf<String>("foo", " bar")),
+        TestDatum("foo \"bar\" bla", arrayOf<String>("foo", "bar", "bla")),
+        TestDatum("\"foo\" \"bar\" \"bla\"", arrayOf<String>("foo", "bar", "bla")),
+        TestDatum("\"foo\" bar \"bla\"", arrayOf<String>("foo", "bar", "bla")),
+        TestDatum("\"foo\" bar bla", arrayOf<String>("foo", "bar", "bla")),
+        TestDatum("foo 'bar' bla", arrayOf<String>("foo", "bar", "bla")),
+        TestDatum("'foo' 'bar' 'bla'", arrayOf<String>("foo", "bar", "bla")),
+        TestDatum("'foo' bar 'bla'", arrayOf<String>("foo", "bar", "bla")),
+        TestDatum("'foo' bar bla", arrayOf<String>("foo", "bar", "bla")),
+        TestDatum("blurb foo\"bar\"bar\"fasel\" baz", arrayOf<String>("blurb", "foobarbarfasel", "baz")),
+        TestDatum("blurb foo'bar'bar'fasel' baz", arrayOf<String>("blurb", "foobarbarfasel", "baz")),
+        TestDatum("\"\"", arrayOf<String>("")),
+        TestDatum("''", arrayOf<String>("")),
+        TestDatum("foo \"\" bar", arrayOf<String>("foo", "", "bar")),
+        TestDatum("foo '' bar", arrayOf<String>("foo", "", "bar")),
+        TestDatum("foo \"\" \"\" \"\" bar", arrayOf<String>("foo", "", "", "", "bar")),
+        TestDatum("foo '' '' '' bar", arrayOf<String>("foo", "", "", "", "bar")),
+        TestDatum("\"foo\\ bar\"", arrayOf<String>("foo bar")));
+    val TEST_DATA_2 = arrayOf<TestDatum>(
+        TestDatum("\"foo\\\\ bar\"", arrayOf<String>("foo\\ bar")),
+        TestDatum("\"foo\\\\ bar\\\\\"", arrayOf<String>("foo\\ bar\\")),
+        TestDatum("\"foo\\\\\" bar\\\"", arrayOf<String>("foo\\", "bar\"")),
+        TestDatum("\"foo\\\\ bar\" dfadf", arrayOf<String>("foo\\ bar", "dfadf")),
+        TestDatum("\"foo\\\\\\ bar\\\" dfadf\"", arrayOf<String>("foo\\ bar\" dfadf")),
+        TestDatum("\"foo\\\\\\x bar\" dfadf", arrayOf<String>("foo\\x bar", "dfadf")),
+        TestDatum("\"foo\\x bar\\\" dfadf\"", arrayOf<String>("foox bar\" dfadf")),
+        TestDatum("\"foo\\x\"", arrayOf<String>("foox")),
+        TestDatum("\"foo\\ \"", arrayOf<String>("foo ")),
+        TestDatum("foo\\ xx", arrayOf<String>("foo xx")),
+        TestDatum("foo\\ x\\x", arrayOf<String>("foo xx")),
+        TestDatum("foo\\ x\\x\\\"\"\"", arrayOf<String>("foo xx\"")),
+        TestDatum("\"foo\\ x\\x\"", arrayOf<String>("foo xx")),
+        TestDatum("\"foo\\ x\\x\\\\\"", arrayOf<String>("foo xx\\")),
+        TestDatum("\"foo\\ x\\x\\\\\"\"foobar\"", arrayOf<String>("foo xx\\foobar")),
+        TestDatum("\"foo\\ x\\x\\\\\"\\'\"foobar\"", arrayOf<String>("foo xx\\'foobar")),
+        TestDatum("\"foo\\ x\\x\\\\\"\\'\"fo'obar\" 'don'\\''t'", arrayOf<String>("foo xx\\'foobar\" don\\t")),
+        TestDatum("'foo\\ bar'", arrayOf<String>("foo\\ bar")),
+        TestDatum("'foo\\\\ bar'", arrayOf<String>("foo\\\\ bar")),
+        TestDatum("foo\\ bar", arrayOf<String>("foo bar")),
+        TestDatum("foo#bar\\nbaz", arrayOf<String>("foo#barnbaz")),
+        TestDatum(":-) ;-)", arrayOf<String>(":-)", ":-)")),
+        TestDatum("áéíóú", arrayOf<String>("áéíóú"))
+    )
+
+    fun runArray(testData: Array<TestDatum>) {
+        for (testDatum in testData) {
+            val s = Shplitter()
+            s.feed(testDatum.from)
+            assertTrue(s.complete, "${testDatum.from}: should be complete, is not")
+            val split = s.split().toList()
+            val expecting = testDatum.to.asList()
+            assertTrue(split == expecting, "${testDatum.from}: expected ${expecting}, got $split")
+        }
+    }
+
+    @Test
+    fun split() {
+        runArray(TEST_DATA_1)
+        runArray(TEST_DATA_2)
+    }
+}