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`