package subex import ( "main/walk" "reflect" "strings" "testing" ) func buildTransducer(subex string) Transducer { lexer := NewStringRuneReader(subex) ast := Parse(lexer) transducer := CompileTransducer(ast) return transducer } func fmtValueList(values []walk.Value) string { var builder strings.Builder builder.WriteRune('[') for i, value := range values { if i != 0 { builder.WriteString(", ") } builder.WriteString(value.Debug()) } builder.WriteRune(']') return builder.String() } func TestSubexMain(t *testing.T) { type test struct { subex string input []walk.Value expected []walk.Value } tests := []test { { subex: `..+`, input: []walk.Value { walk.NumberValue(12), walk.NumberValue(34), }, expected: []walk.Value { walk.NumberValue(46), }, }, { subex: `.`, input: []walk.Value { walk.MapValue {{ Key: "a", Value: walk.StringValue("b"), }}, }, expected: []walk.Value { walk.MapValue {{ Key: "a", Value: walk.StringValue("b"), }}, }, }, { subex: `~(.)~`, input: []walk.Value { walk.StringValue("a"), }, expected: []walk.Value { walk.StringValue("a"), }, }, { subex: `~(.$_(.{-0}))~`, input: []walk.Value { walk.StringValue("hello"), }, expected: []walk.Value { walk.StringValue("ello"), }, }, { subex: `#(".".{-0})-`, input: []walk.Value { walk.MapValue { { Key: "a", Value: walk.NullValue{}, }, }, }, expected: []walk.Value { walk.StringValue("a"), walk.NullValue{}, }, }, { subex: "@(..$a`$a$a`{-0})@", input: []walk.Value { walk.ArrayValue { walk.ArrayElement { Index: 0, Value: walk.NullValue{}, }, walk.ArrayElement { Index: 0, Value: walk.BoolValue(true), }, walk.ArrayElement { Index: 0, Value: walk.NumberValue(5.4), }, walk.ArrayElement { Index: 5, Value: walk.StringValue("hello"), }, walk.ArrayElement { Index: 3, Value: walk.ArrayValue { walk.ArrayElement { Index: 0, Value: walk.NullValue{}, }, }, }, walk.ArrayElement { Index: 1, Value: walk.MapValue { walk.MapElement { Key: "key", Value: walk.StringValue("value"), }, }, }, }, }, expected: []walk.Value { walk.ArrayValue { walk.ArrayElement { Index: 0, Value: walk.NullValue{}, }, walk.ArrayElement { Index: 0, Value: walk.NullValue{}, }, walk.ArrayElement { Index: 0, Value: walk.BoolValue(true), }, walk.ArrayElement { Index: 0, Value: walk.BoolValue(true), }, walk.ArrayElement { Index: 0, Value: walk.NumberValue(5.4), }, walk.ArrayElement { Index: 0, Value: walk.NumberValue(5.4), }, walk.ArrayElement { Index: 5, Value: walk.StringValue("hello"), }, walk.ArrayElement { Index: 5, Value: walk.StringValue("hello"), }, walk.ArrayElement { Index: 3, Value: walk.ArrayValue { walk.ArrayElement { Index: 0, Value: walk.NullValue{}, }, }, }, walk.ArrayElement { Index: 3, Value: walk.ArrayValue { walk.ArrayElement { Index: 0, Value: walk.NullValue{}, }, }, }, walk.ArrayElement { Index: 1, Value: walk.MapValue { walk.MapElement { Key: "key", Value: walk.StringValue("value"), }, }, }, walk.ArrayElement { Index: 1, Value: walk.MapValue { walk.MapElement { Key: "key", Value: walk.StringValue("value"), }, }, }, }, }, }, { subex: "-(`0`.)@", input: []walk.Value { walk.NumberValue(4), }, expected: []walk.Value { walk.ArrayValue { { Index: 0, Value: walk.NumberValue(4), }, }, }, }, { subex: `@(.$_~(.{-0})-{-0})~`, input: []walk.Value { walk.ArrayValue { { Index: 0, Value: walk.StringValue("ab"), }, { Index: 1, Value: walk.StringValue("cd"), }, { Index: 2, Value: walk.StringValue("efg"), }, { Index: 3, Value: walk.StringValue(""), }, { Index: 4, Value: walk.StringValue("hijklm"), }, }, }, expected: []walk.Value { walk.StringValue("abcdefghijklm"), }, }, { subex: ":(.)-", input: []walk.Value { walk.ArrayValue { { Index: 0, Value: walk.NullValue{}, }, }, }, expected: []walk.Value { walk.NullValue{}, }, }, { subex: ":(.{-0}+)-", input: []walk.Value { walk.ArrayValue { { Index: 0, Value: walk.NumberValue(4), }, { Index: 1, Value: walk.NumberValue(-123), }, { Index: 2, Value: walk.NumberValue(124), }, }, }, expected: []walk.Value { walk.NumberValue(5), }, }, { subex: "~(-(.)~{-0}):", input: []walk.Value { walk.StringValue("abc"), }, expected: []walk.Value { walk.ArrayValue { { Index: 0, Value: walk.StringValue("a"), }, { Index: 0, Value: walk.StringValue("b"), }, { Index: 0, Value: walk.StringValue("c"), }, }, }, }, { subex: "#(.(.$_){-0}):", input: []walk.Value { walk.MapValue { { Key: "a", Value: walk.NullValue{}, }, { Key: "b", Value: walk.NumberValue(4), }, { Key: "c", Value: walk.StringValue("hello"), }, }, }, expected: []walk.Value { walk.ArrayValue { { Index: 0, Value: walk.StringValue("a"), }, { Index: 0, Value: walk.StringValue("b"), }, { Index: 0, Value: walk.StringValue("c"), }, }, }, }, { subex: ":(.`null`{-0})#", input: []walk.Value { walk.ArrayValue { { Index: 0, Value: walk.StringValue("a"), }, { Index: 1, Value: walk.StringValue("b"), }, { Index: 2, Value: walk.StringValue("c"), }, }, }, expected: []walk.Value { walk.MapValue { { Key: "a", Value: walk.NullValue{}, }, { Key: "b", Value: walk.NullValue{}, }, { Key: "c", Value: walk.NullValue{}, }, }, }, }, { subex: `#(".$_(.{-0})".{-0})#`, input: []walk.Value { walk.MapValue { { Key: "hello", Value: walk.NullValue{}, }, { Key: "world", Value: walk.NullValue{}, }, }, }, expected: []walk.Value { walk.MapValue { { Key: "ello", Value: walk.NullValue{}, }, { Key: "orld", Value: walk.NullValue{}, }, }, }, }, { subex: ".{-0}`\"hello\"`", input: []walk.Value { walk.NumberValue(1), walk.NumberValue(2), }, expected: []walk.Value { walk.NumberValue(1), walk.NumberValue(2), walk.StringValue("hello"), }, }, } for i, test := range tests { t.Logf("Running test: %d", i) lexer := NewStringRuneReader(test.subex) ast := Parse(lexer) transducer := CompileTransducer(ast) output, err := RunTransducer(transducer, test.input) if err { t.Errorf("Subex %q rejected input %v", test.subex, fmtValueList(test.input)) t.Logf("AST: %v", ast) continue } if !reflect.DeepEqual(output, test.expected) { t.Errorf("Subex %q transformed input %s to output %s", test.subex, fmtValueList(test.input), fmtValueList(output)) } } }