<- Back to shtanton's homepage
aboutsummaryrefslogtreecommitdiff
path: root/subex/main_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'subex/main_test.go')
-rw-r--r--subex/main_test.go442
1 files changed, 442 insertions, 0 deletions
diff --git a/subex/main_test.go b/subex/main_test.go
new file mode 100644
index 0000000..f0350d2
--- /dev/null
+++ b/subex/main_test.go
@@ -0,0 +1,442 @@
+package subex
+
+import (
+ "testing"
+ "main/walk"
+ "fmt"
+ "strings"
+)
+
+func buildTransducer(subex string) Transducer {
+ lexer := NewStringRuneReader(subex)
+ ast := Parse(lexer)
+ transducer := CompileTransducer(ast)
+ return transducer
+}
+
+func fatalMismatch(t *testing.T, path walk.ValueList, message string) {
+ var sep string
+ var builder strings.Builder
+ for _, segment := range path {
+ builder.WriteString(sep)
+ builder.WriteString(segment.Debug())
+ sep = "."
+ }
+ builder.WriteString(": ")
+ builder.WriteString(message)
+ t.Fatal(builder.String())
+}
+
+func expectEqual(t *testing.T, path walk.ValueList, output walk.Value, expected walk.Value) {
+ switch expected := expected.(type) {
+ case walk.NullScalar:
+ _, isNull := output.(walk.NullScalar)
+ if !isNull {
+ fatalMismatch(t, path, fmt.Sprintf("expected null, found %s", output.Debug()))
+ }
+ case walk.BoolScalar:
+ b, isBool := output.(walk.BoolScalar)
+ if !isBool {
+ fatalMismatch(t, path, fmt.Sprintf("expected boolean, found %s", output.Debug()))
+ }
+ if expected != b {
+ fatalMismatch(t, path, fmt.Sprintf("expected %s, found %s", expected.Debug(), b.Debug()))
+ }
+ case walk.NumberScalar:
+ n, isNumber := output.(walk.NumberScalar)
+ if !isNumber {
+ fatalMismatch(t, path, fmt.Sprintf("expected number, found %s", output.Debug()))
+ }
+ if expected != n {
+ fatalMismatch(t, path, fmt.Sprintf("expected %s, found %s", expected.Debug(), n.Debug()))
+ }
+ case walk.StringStructure:
+ s, isString := output.(walk.StringStructure)
+ if !isString {
+ fatalMismatch(t, path, fmt.Sprintf("expected string, found %s", output.Debug()))
+ }
+ if s != expected {
+ fatalMismatch(t, path, fmt.Sprintf("expected %s, found %s", expected.Debug(), s.Debug()))
+ }
+ case walk.ArrayStructure:
+ array, isArray := output.(walk.ArrayStructure)
+ if !isArray {
+ fatalMismatch(t, path, fmt.Sprintf("expected array, found %s", output.Debug()))
+ }
+ if len(array) != len(expected) {
+ fatalMismatch(t, path, fmt.Sprintf("Expected array length %d, found %d", len(expected), len(array)))
+ }
+ for i, value := range expected {
+ expectEqual(t, append(path, walk.NumberScalar(i)), array[i], value)
+ }
+ case walk.MapStructure:
+ m, isMap := output.(walk.MapStructure)
+ if !isMap {
+ fatalMismatch(t, path, fmt.Sprintf("expected map, found %s", output.Debug()))
+ }
+ for key, expected := range expected {
+ value, hasValue := m[key]
+ if !hasValue {
+ fatalMismatch(t, path, fmt.Sprintf("expected map to have key %s, but it doesn't", key))
+ }
+ expectEqual(t, append(path, walk.StringStructure(key)), value, expected)
+ }
+ for key := range m {
+ _, hasValue := expected[key]
+ if !hasValue {
+ fatalMismatch(t, path, fmt.Sprintf("Didn't expect map to have key %s, but it does", key))
+ }
+ }
+ default:
+ panic("Expected contains an invalid value")
+ }
+}
+
+func expectOutput(t *testing.T, transducer Transducer, input walk.ValueList, expected walk.ValueList) {
+ output, err := RunTransducer(transducer, input)
+
+ if err {
+ t.Fatalf("Error")
+ }
+
+ if len(output) != len(expected) {
+ t.Fatalf("Output has incorrect length. Expected %d, got %d", len(expected), len(output))
+ }
+
+ for i, value := range output {
+ expectEqual(t, walk.ValueList{walk.NumberScalar(i)}, value, expected[i])
+ }
+}
+
+func expectReject(t *testing.T, transducer Transducer, input walk.ValueList) {
+ _, err := RunTransducer(transducer, input)
+
+ if !err {
+ t.Fatalf("Expected transducer to error, but it accepted input: %v", input)
+ }
+}
+
+func TestSimpleProcessInput(t *testing.T) {
+ states := []SubexBranch{{
+ state: SubexCopyState {
+ next: SubexNoneState{},
+ filter: anyValueFilter{},
+ },
+ aux: auxiliaryState {
+ outputStack: OutputStack {
+ head: walk.ValueList{},
+ tail: nil,
+ },
+ store: nil,
+ nesting: 0,
+ },
+ }}
+
+ input := walk.ValueList{
+ walk.NumberScalar(2),
+ }
+
+ states = processInput(states, walk.NewValueIter(input), 0)
+
+ if len(states) != 1 {
+ t.Fatalf("States has wrong length")
+ }
+
+ accepting := states[0].accepting()
+
+ if len(accepting) != 1 {
+ t.Fatalf("Wrong number of accepting branches")
+ }
+
+ values, isValues := accepting[0].head.(walk.ValueList)
+
+ if !isValues {
+ t.Fatalf("Output is not a value list")
+ }
+
+ if len(values) != 1 {
+ t.Fatalf("Output has wrong length")
+ }
+
+ if values[0] != walk.NumberScalar(2) {
+ t.Fatalf("Outputted the wrong value")
+ }
+}
+
+func TestTopAppendFromEmpty(t *testing.T) {
+ output := OutputStack {
+ head: walk.ValueList{},
+ tail: nil,
+ }
+
+ output = topAppend(output, []walk.Value{walk.NumberScalar(1), walk.NumberScalar(2)})
+
+ values, isValues := output.head.(walk.ValueList)
+
+ if !isValues {
+ t.Fatalf("head is not values")
+ }
+
+ if len(values) != 2 {
+ t.Fatalf("values has the wrong length")
+ }
+
+ if values[0] != walk.NumberScalar(1) || values[1] != walk.NumberScalar(2) {
+ t.Fatalf("output has the wrong values")
+ }
+}
+
+func TestArrayPriority1(t *testing.T) {
+ expectOutput(
+ t,
+ buildTransducer(":[.$_]|."),
+ walk.ValueList{
+ walk.ArrayStructure{
+ walk.NumberScalar(5),
+ },
+ },
+ walk.ValueList{
+ walk.ArrayStructure{},
+ },
+ )
+}
+
+func TestArrayPriority2(t *testing.T) {
+ expectOutput(
+ t,
+ buildTransducer(".|:[.$_]"),
+ walk.ValueList{
+ walk.ArrayStructure{
+ walk.NumberScalar(5),
+ },
+ },
+ walk.ValueList{
+ walk.ArrayStructure{
+ walk.NumberScalar(5),
+ },
+ },
+ )
+}
+
+func TestDropSecondArrayElement(t *testing.T) {
+ expectOutput(
+ t,
+ buildTransducer(":[.(.$_)(.{-0})]"),
+ walk.ValueList{
+ walk.ArrayStructure{
+ walk.NumberScalar(1),
+ walk.NumberScalar(2),
+ walk.NumberScalar(3),
+ walk.NumberScalar(4),
+ },
+ },
+ walk.ValueList{
+ walk.ArrayStructure{
+ walk.NumberScalar(1),
+ walk.NumberScalar(3),
+ walk.NumberScalar(4),
+ },
+ },
+ )
+}
+
+func TestDropSecondElement(t *testing.T) {
+ expectOutput(
+ t,
+ buildTransducer(".(.$_)(.{-0})"),
+ walk.ValueList{
+ walk.NumberScalar(1),
+ walk.NumberScalar(2),
+ walk.NumberScalar(3),
+ walk.NumberScalar(4),
+ },
+ walk.ValueList{
+ walk.NumberScalar(1),
+ walk.NumberScalar(3),
+ walk.NumberScalar(4),
+ },
+ )
+}
+
+func TestCopyManyValues(t *testing.T) {
+ expectOutput(
+ t,
+ buildTransducer(".{-0}"),
+ walk.ValueList{
+ walk.NumberScalar(1),
+ walk.NumberScalar(2),
+ walk.NumberScalar(3),
+ walk.NumberScalar(4),
+ },
+ walk.ValueList{
+ walk.NumberScalar(1),
+ walk.NumberScalar(2),
+ walk.NumberScalar(3),
+ walk.NumberScalar(4),
+ },
+ )
+}
+
+func TestCopyTwoValues(t *testing.T) {
+ expectOutput(
+ t,
+ buildTransducer(".."),
+ walk.ValueList{
+ walk.NumberScalar(1),
+ walk.NumberScalar(2),
+ },
+ walk.ValueList{
+ walk.NumberScalar(1),
+ walk.NumberScalar(2),
+ },
+ )
+}
+
+func TestCopyValue(t *testing.T) {
+ expectOutput(
+ t,
+ buildTransducer("."),
+ walk.ValueList{
+ walk.NumberScalar(1),
+ },
+ walk.ValueList{
+ walk.NumberScalar(1),
+ },
+ )
+}
+
+func TestSimpleArrayEntry(t *testing.T) {
+ expectOutput(
+ t,
+ buildTransducer(":[..]"),
+ walk.ValueList{
+ walk.ArrayStructure{
+ walk.NumberScalar(1),
+ walk.NumberScalar(2),
+ },
+ },
+ walk.ValueList{
+ walk.ArrayStructure{
+ walk.NumberScalar(1),
+ walk.NumberScalar(2),
+ },
+ },
+ )
+}
+
+func TestArrayEntrySum(t *testing.T) {
+ expectOutput(
+ t,
+ buildTransducer(":[%{-0}+]"),
+ walk.ValueList{
+ walk.ArrayStructure{
+ walk.NumberScalar(1),
+ walk.NumberScalar(7),
+ walk.NumberScalar(8),
+ walk.NumberScalar(3),
+ },
+ },
+ walk.ValueList{
+ walk.ArrayStructure{
+ walk.NumberScalar(19),
+ },
+ },
+ )
+}
+
+func TestStringEmptyMatch(t *testing.T) {
+ expectOutput(
+ t,
+ buildTransducer("~\"\""),
+ walk.ValueList{
+ walk.StringStructure(""),
+ },
+ walk.ValueList{
+ walk.StringStructure(""),
+ },
+ )
+}
+
+func TestStringSimpleMatch(t *testing.T) {
+ expectOutput(
+ t,
+ buildTransducer("~\"hello\""),
+ walk.ValueList{
+ walk.StringStructure("hello"),
+ },
+ walk.ValueList{
+ walk.StringStructure("hello"),
+ },
+ )
+}
+
+func TestDiscardString(t *testing.T) {
+ expectOutput(
+ t,
+ buildTransducer("~\"test\"$_."),
+ walk.ValueList{
+ walk.StringStructure("test"),
+ walk.NumberScalar(2),
+ },
+ walk.ValueList{
+ walk.NumberScalar(2),
+ },
+ )
+}
+
+func TestStringThenValue(t *testing.T) {
+ expectOutput(
+ t,
+ buildTransducer("~\"test\"."),
+ walk.ValueList{
+ walk.StringStructure("test"),
+ walk.NumberScalar(2),
+ },
+ walk.ValueList{
+ walk.StringStructure("test"),
+ walk.NumberScalar(2),
+ },
+ )
+}
+
+func TestCutStringFromStart(t *testing.T) {
+ //transducer := buildTransducer("~\"test\"$_(.{-0})")
+ lexer := NewStringRuneReader("~\"test\"$_(.{-0})")
+ ast := Parse(lexer)
+ t.Log(ast)
+ transducer := CompileTransducer(ast)
+
+ expectOutput(
+ t,
+ transducer,
+ walk.ValueList{
+ walk.StringStructure("test"),
+ walk.NumberScalar(2),
+ walk.StringStructure("test"),
+ },
+ walk.ValueList{
+ walk.NumberScalar(2),
+ walk.StringStructure("test"),
+ },
+ )
+ expectOutput(
+ t,
+ transducer,
+ walk.ValueList{
+ walk.StringStructure("test"),
+ },
+ walk.ValueList{},
+ )
+ expectReject(
+ t,
+ transducer,
+ walk.ValueList{
+ walk.StringStructure("yeet"),
+ },
+ )
+ expectReject(
+ t,
+ transducer,
+ walk.ValueList{},
+ )
+}