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 { { // Keep only 5 subex: `(5|(.>_))*`, input: []walk.Value { walk.NumberValue(0), walk.NumberValue(1), walk.NumberValue(2), walk.NumberValue(3), walk.NumberValue(4), walk.NumberValue(5), walk.NumberValue(9), walk.NumberValue(10), walk.NumberValue(11), walk.NumberValue(2.5), walk.NumberValue(7.0), walk.NumberValue(-3), }, expected: []walk.Value { walk.NumberValue(5), }, }, { // Keep only odd numbers between 0 and 10 subex: `([c5*2+1]|(.>_))*`, input: []walk.Value { walk.NumberValue(0), walk.NumberValue(1), walk.NumberValue(2), walk.NumberValue(3), walk.NumberValue(4), walk.NumberValue(5), walk.NumberValue(9), walk.NumberValue(10), walk.NumberValue(11), walk.NumberValue(2.5), walk.NumberValue(7.0), walk.NumberValue(-3), }, expected: []walk.Value { walk.NumberValue(1), walk.NumberValue(3), walk.NumberValue(5), walk.NumberValue(9), walk.NumberValue(7), }, }, { subex: "r*([pi*2]%a`_(.*))~`, input: []walk.Value { walk.StringValue("hello"), }, expected: []walk.Value { walk.StringValue("ello"), }, }, { subex: `#(".".*)-`, input: []walk.Value { walk.MapValue { { Key: "a", Value: walk.NullValue{}, }, }, }, expected: []walk.Value { walk.StringValue("a"), walk.NullValue{}, }, }, { subex: "@(((..)%a_~(.{-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: "~(-(.)~*):", 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: "#((..>_)*):", 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`)*)#", 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: `#((".>_.*".)*)#`, 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: ".*`\"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)) } } } func doCollatzTest(t *testing.T, init int) { input := []walk.Value { walk.NumberValue(init), } last := init lexer := NewStringRuneReader("r*([pi*2]%a`