view 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 source

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)
    }
}