refactor test harness
This commit is contained in:
parent
0e236fb688
commit
a09675fc27
10
boot.go
10
boot.go
@ -187,21 +187,17 @@ func defineAllBoot(s *Syntax, defs [][]string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func initBoot(definitions [][]string) (*Syntax, error) {
|
func createBoot() (*Syntax, error) {
|
||||||
s := NewSyntax()
|
s := NewSyntax()
|
||||||
if err := defineAllBoot(s, definitions); err != nil {
|
if err := defineAllBoot(s, bootSyntaxDefs); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return s, s.Init()
|
return s, s.Init()
|
||||||
}
|
}
|
||||||
|
|
||||||
func createBoot() (*Syntax, error) {
|
|
||||||
return initBoot(bootSyntaxDefs)
|
|
||||||
}
|
|
||||||
|
|
||||||
func bootSyntax() (*Syntax, error) {
|
func bootSyntax() (*Syntax, error) {
|
||||||
b, err := initBoot(bootSyntaxDefs)
|
b, err := createBoot()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ func testParseFromTree(t *testing.T, n *Node, f io.ReadSeeker) *Node {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
checkNode(t, nn, n)
|
checkNode(t, false, nn, n)
|
||||||
return nn
|
return nn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
69
check_test.go
Normal file
69
check_test.go
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
package treerack
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func checkNodes(t *testing.T, ignorePosition bool, left, right []*Node) {
|
||||||
|
if len(left) != len(right) {
|
||||||
|
t.Error("length doesn't match", len(left), len(right))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for len(left) > 0 {
|
||||||
|
checkNode(t, ignorePosition, left[0], right[0])
|
||||||
|
if t.Failed() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
left, right = left[1:], right[1:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkNode(t *testing.T, ignorePosition bool, left, right *Node) {
|
||||||
|
if (left == nil) != (right == nil) {
|
||||||
|
t.Error("nil reference doesn't match", left == nil, right == nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if left == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if left.Name != right.Name {
|
||||||
|
t.Error("name doesn't match", left.Name, right.Name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ignorePosition && left.From != right.From {
|
||||||
|
t.Error("from doesn't match", left.Name, left.From, right.From)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ignorePosition && left.To != right.To {
|
||||||
|
t.Error("to doesn't match", left.Name, left.To, right.To)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(left.Nodes) != len(right.Nodes) {
|
||||||
|
t.Error("length doesn't match", left.Name, len(left.Nodes), len(right.Nodes))
|
||||||
|
t.Log(left)
|
||||||
|
t.Log(right)
|
||||||
|
for {
|
||||||
|
if len(left.Nodes) > 0 {
|
||||||
|
t.Log("<", left.Nodes[0])
|
||||||
|
left.Nodes = left.Nodes[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(right.Nodes) > 0 {
|
||||||
|
t.Log(">", right.Nodes[0])
|
||||||
|
right.Nodes = right.Nodes[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(left.Nodes) == 0 && len(right.Nodes) == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
checkNodes(t, ignorePosition, left.Nodes, right.Nodes)
|
||||||
|
}
|
@ -724,10 +724,12 @@ func eskipTreeToEskip(n *Node) ([]*eskip.Route, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestEskip(t *testing.T) {
|
func TestEskip(t *testing.T) {
|
||||||
r := generateEskip(1 << 9)
|
const count = 1 << 9
|
||||||
|
|
||||||
|
r := generateEskip(count)
|
||||||
e := eskip.Print(true, r...)
|
e := eskip.Print(true, r...)
|
||||||
b := bytes.NewBufferString(e)
|
b := bytes.NewBufferString(e)
|
||||||
s, err := testSyntax("eskip.parser", -1)
|
s, err := openSyntaxFile("eskip.parser")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
|
32
json_test.go
32
json_test.go
@ -285,9 +285,9 @@ func jsonTreeToJSON(n *Node) (interface{}, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestJSON(t *testing.T) {
|
func TestJSON(t *testing.T) {
|
||||||
test(t, "json.parser", "value", []testItem{{
|
runTestsFile(t, "json.parser", []testItem{{
|
||||||
msg: "true",
|
title: "true",
|
||||||
text: "true",
|
text: "true",
|
||||||
node: &Node{
|
node: &Node{
|
||||||
Name: "json",
|
Name: "json",
|
||||||
Nodes: []*Node{{
|
Nodes: []*Node{{
|
||||||
@ -296,8 +296,8 @@ func TestJSON(t *testing.T) {
|
|||||||
},
|
},
|
||||||
ignorePosition: true,
|
ignorePosition: true,
|
||||||
}, {
|
}, {
|
||||||
msg: "false",
|
title: "false",
|
||||||
text: "false",
|
text: "false",
|
||||||
node: &Node{
|
node: &Node{
|
||||||
Name: "json",
|
Name: "json",
|
||||||
Nodes: []*Node{{
|
Nodes: []*Node{{
|
||||||
@ -306,8 +306,8 @@ func TestJSON(t *testing.T) {
|
|||||||
},
|
},
|
||||||
ignorePosition: true,
|
ignorePosition: true,
|
||||||
}, {
|
}, {
|
||||||
msg: "null",
|
title: "null",
|
||||||
text: "null",
|
text: "null",
|
||||||
node: &Node{
|
node: &Node{
|
||||||
Name: "json",
|
Name: "json",
|
||||||
Nodes: []*Node{{
|
Nodes: []*Node{{
|
||||||
@ -316,8 +316,8 @@ func TestJSON(t *testing.T) {
|
|||||||
},
|
},
|
||||||
ignorePosition: true,
|
ignorePosition: true,
|
||||||
}, {
|
}, {
|
||||||
msg: "string",
|
title: "string",
|
||||||
text: `"\"\\n\b\t\uabcd"`,
|
text: `"\"\\n\b\t\uabcd"`,
|
||||||
node: &Node{
|
node: &Node{
|
||||||
Name: "json",
|
Name: "json",
|
||||||
Nodes: []*Node{{
|
Nodes: []*Node{{
|
||||||
@ -326,8 +326,8 @@ func TestJSON(t *testing.T) {
|
|||||||
},
|
},
|
||||||
ignorePosition: true,
|
ignorePosition: true,
|
||||||
}, {
|
}, {
|
||||||
msg: "number",
|
title: "number",
|
||||||
text: "6.62e-34",
|
text: "6.62e-34",
|
||||||
node: &Node{
|
node: &Node{
|
||||||
Name: "json",
|
Name: "json",
|
||||||
Nodes: []*Node{{
|
Nodes: []*Node{{
|
||||||
@ -336,7 +336,7 @@ func TestJSON(t *testing.T) {
|
|||||||
},
|
},
|
||||||
ignorePosition: true,
|
ignorePosition: true,
|
||||||
}, {
|
}, {
|
||||||
msg: "object",
|
title: "object",
|
||||||
text: `{
|
text: `{
|
||||||
"true": true,
|
"true": true,
|
||||||
"false": false,
|
"false": false,
|
||||||
@ -404,7 +404,7 @@ func TestJSON(t *testing.T) {
|
|||||||
},
|
},
|
||||||
ignorePosition: true,
|
ignorePosition: true,
|
||||||
}, {
|
}, {
|
||||||
msg: "array",
|
title: "array",
|
||||||
text: `[true, false, null, "string", 42, {
|
text: `[true, false, null, "string", 42, {
|
||||||
"true": true,
|
"true": true,
|
||||||
"false": false,
|
"false": false,
|
||||||
@ -487,8 +487,8 @@ func TestJSON(t *testing.T) {
|
|||||||
},
|
},
|
||||||
ignorePosition: true,
|
ignorePosition: true,
|
||||||
}, {
|
}, {
|
||||||
msg: "bugfix, 100",
|
title: "bugfix, 100",
|
||||||
text: "100",
|
text: "100",
|
||||||
node: &Node{
|
node: &Node{
|
||||||
Name: "json",
|
Name: "json",
|
||||||
Nodes: []*Node{{
|
Nodes: []*Node{{
|
||||||
@ -509,7 +509,7 @@ func TestRandomJSON(t *testing.T) {
|
|||||||
|
|
||||||
buf := bytes.NewBuffer(b)
|
buf := bytes.NewBuffer(b)
|
||||||
|
|
||||||
s, err := testSyntax("json.parser", -1)
|
s, err := openSyntaxFile("json.parser")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
|
@ -3,14 +3,14 @@ package treerack
|
|||||||
import "testing"
|
import "testing"
|
||||||
|
|
||||||
func TestKeyVal(t *testing.T) {
|
func TestKeyVal(t *testing.T) {
|
||||||
test(t, "keyval.parser", "doc", []testItem{{
|
runTestsFile(t, "keyval.parser", []testItem{{
|
||||||
msg: "empty",
|
title: "empty",
|
||||||
}, {
|
}, {
|
||||||
msg: "a comment",
|
title: "a comment",
|
||||||
text: "# a comment",
|
text: "# a comment",
|
||||||
}, {
|
}, {
|
||||||
msg: "a key",
|
title: "a key",
|
||||||
text: "a key",
|
text: "a key",
|
||||||
nodes: []*Node{{
|
nodes: []*Node{{
|
||||||
Name: "key-val",
|
Name: "key-val",
|
||||||
To: 5,
|
To: 5,
|
||||||
@ -24,8 +24,8 @@ func TestKeyVal(t *testing.T) {
|
|||||||
}},
|
}},
|
||||||
}},
|
}},
|
||||||
}, {
|
}, {
|
||||||
msg: "a key with a preceeding whitespace",
|
title: "a key with a preceeding whitespace",
|
||||||
text: " a key",
|
text: " a key",
|
||||||
nodes: []*Node{{
|
nodes: []*Node{{
|
||||||
Name: "key-val",
|
Name: "key-val",
|
||||||
From: 1,
|
From: 1,
|
||||||
@ -42,7 +42,7 @@ func TestKeyVal(t *testing.T) {
|
|||||||
}},
|
}},
|
||||||
}},
|
}},
|
||||||
}, {
|
}, {
|
||||||
msg: "a key and a comment",
|
title: "a key and a comment",
|
||||||
text: `
|
text: `
|
||||||
# a comment
|
# a comment
|
||||||
|
|
||||||
@ -64,8 +64,8 @@ func TestKeyVal(t *testing.T) {
|
|||||||
}},
|
}},
|
||||||
}},
|
}},
|
||||||
}, {
|
}, {
|
||||||
msg: "a key value pair",
|
title: "a key value pair",
|
||||||
text: "a key = a value",
|
text: "a key = a value",
|
||||||
nodes: []*Node{{
|
nodes: []*Node{{
|
||||||
Name: "key-val",
|
Name: "key-val",
|
||||||
To: 15,
|
To: 15,
|
||||||
@ -83,7 +83,7 @@ func TestKeyVal(t *testing.T) {
|
|||||||
}},
|
}},
|
||||||
}},
|
}},
|
||||||
}, {
|
}, {
|
||||||
msg: "key value pairs with a comment at the end of line",
|
title: "key value pairs with a comment at the end of line",
|
||||||
text: `
|
text: `
|
||||||
a key = a value # a comment
|
a key = a value # a comment
|
||||||
another key = another value # another comment
|
another key = another value # another comment
|
||||||
@ -126,8 +126,8 @@ func TestKeyVal(t *testing.T) {
|
|||||||
}},
|
}},
|
||||||
}},
|
}},
|
||||||
}, {
|
}, {
|
||||||
msg: "value without a key",
|
title: "value without a key",
|
||||||
text: "= a value",
|
text: "= a value",
|
||||||
nodes: []*Node{{
|
nodes: []*Node{{
|
||||||
Name: "key-val",
|
Name: "key-val",
|
||||||
To: 9,
|
To: 9,
|
||||||
@ -138,7 +138,7 @@ func TestKeyVal(t *testing.T) {
|
|||||||
}},
|
}},
|
||||||
}},
|
}},
|
||||||
}, {
|
}, {
|
||||||
msg: "a key value pair with comment",
|
title: "a key value pair with comment",
|
||||||
text: `
|
text: `
|
||||||
# a comment
|
# a comment
|
||||||
a key = a value
|
a key = a value
|
||||||
@ -167,8 +167,8 @@ func TestKeyVal(t *testing.T) {
|
|||||||
}},
|
}},
|
||||||
}},
|
}},
|
||||||
}, {
|
}, {
|
||||||
msg: "a key with multiple symbols",
|
title: "a key with multiple symbols",
|
||||||
text: "a key . with.multiple.symbols=a value",
|
text: "a key . with.multiple.symbols=a value",
|
||||||
nodes: []*Node{{
|
nodes: []*Node{{
|
||||||
Name: "key-val",
|
Name: "key-val",
|
||||||
To: 37,
|
To: 37,
|
||||||
@ -200,7 +200,7 @@ func TestKeyVal(t *testing.T) {
|
|||||||
}},
|
}},
|
||||||
}},
|
}},
|
||||||
}, {
|
}, {
|
||||||
msg: "a group key",
|
title: "a group key",
|
||||||
text: `
|
text: `
|
||||||
# a comment
|
# a comment
|
||||||
[a group key.empty]
|
[a group key.empty]
|
||||||
@ -224,7 +224,7 @@ func TestKeyVal(t *testing.T) {
|
|||||||
}},
|
}},
|
||||||
}},
|
}},
|
||||||
}, {
|
}, {
|
||||||
msg: "a group key with multiple values",
|
title: "a group key with multiple values",
|
||||||
text: `
|
text: `
|
||||||
[foo.bar.baz]
|
[foo.bar.baz]
|
||||||
= one
|
= one
|
||||||
@ -258,8 +258,8 @@ func TestKeyVal(t *testing.T) {
|
|||||||
}},
|
}},
|
||||||
ignorePosition: true,
|
ignorePosition: true,
|
||||||
}, {
|
}, {
|
||||||
msg: "a group key with multiple values, in a single line",
|
title: "a group key with multiple values, in a single line",
|
||||||
text: "[foo.bar.baz] = one = two = three",
|
text: "[foo.bar.baz] = one = two = three",
|
||||||
nodes: []*Node{{
|
nodes: []*Node{{
|
||||||
Name: "group-key",
|
Name: "group-key",
|
||||||
Nodes: []*Node{{
|
Nodes: []*Node{{
|
||||||
@ -287,7 +287,7 @@ func TestKeyVal(t *testing.T) {
|
|||||||
}},
|
}},
|
||||||
ignorePosition: true,
|
ignorePosition: true,
|
||||||
}, {
|
}, {
|
||||||
msg: "full example",
|
title: "full example",
|
||||||
text: `
|
text: `
|
||||||
# a keyval document
|
# a keyval document
|
||||||
|
|
||||||
|
456
mml_test.go
456
mml_test.go
File diff suppressed because it is too large
Load Diff
45
open_test.go
Normal file
45
open_test.go
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
package treerack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func openSyntaxReader(r io.Reader) (*Syntax, error) {
|
||||||
|
b, err := bootSyntax()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
doc, err := b.Parse(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
s := NewSyntax()
|
||||||
|
if err := define(s, doc); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.Init(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func openSyntaxFile(file string) (*Syntax, error) {
|
||||||
|
f, err := os.Open(file)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer f.Close()
|
||||||
|
return openSyntaxReader(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func openSyntaxString(syntax string) (*Syntax, error) {
|
||||||
|
b := bytes.NewBufferString(syntax)
|
||||||
|
return openSyntaxReader(b)
|
||||||
|
}
|
507
parse_test.go
507
parse_test.go
@ -1,217 +1,16 @@
|
|||||||
package treerack
|
package treerack
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type testItem struct {
|
|
||||||
msg string
|
|
||||||
text string
|
|
||||||
fail bool
|
|
||||||
node *Node
|
|
||||||
nodes []*Node
|
|
||||||
ignorePosition bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func testSyntaxReader(r io.Reader, traceLevel int) (*Syntax, error) {
|
|
||||||
b, err := bootSyntax()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
doc, err := b.Parse(r)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var trace Trace
|
|
||||||
if traceLevel >= 0 {
|
|
||||||
trace = NewTrace(traceLevel)
|
|
||||||
}
|
|
||||||
|
|
||||||
s := NewSyntaxTrace(trace)
|
|
||||||
if err := define(s, doc); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := s.Init(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return s, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func testSyntax(file string, traceLevel int) (*Syntax, error) {
|
|
||||||
f, err := os.Open(file)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
defer f.Close()
|
|
||||||
return testSyntaxReader(f, traceLevel)
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkNodesPosition(t *testing.T, left, right []*Node, position bool) {
|
|
||||||
if len(left) != len(right) {
|
|
||||||
t.Error("length doesn't match", len(left), len(right))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for len(left) > 0 {
|
|
||||||
checkNodePosition(t, left[0], right[0], position)
|
|
||||||
if t.Failed() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
left, right = left[1:], right[1:]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkNodePosition(t *testing.T, left, right *Node, position bool) {
|
|
||||||
if (left == nil) != (right == nil) {
|
|
||||||
t.Error("nil reference doesn't match", left == nil, right == nil)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if left == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if left.Name != right.Name {
|
|
||||||
t.Error("name doesn't match", left.Name, right.Name)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if position && left.From != right.From {
|
|
||||||
t.Error("from doesn't match", left.Name, left.From, right.From)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if position && left.To != right.To {
|
|
||||||
t.Error("to doesn't match", left.Name, left.To, right.To)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(left.Nodes) != len(right.Nodes) {
|
|
||||||
t.Error("length doesn't match", left.Name, len(left.Nodes), len(right.Nodes))
|
|
||||||
t.Log(left)
|
|
||||||
t.Log(right)
|
|
||||||
for {
|
|
||||||
if len(left.Nodes) > 0 {
|
|
||||||
t.Log("<", left.Nodes[0])
|
|
||||||
left.Nodes = left.Nodes[1:]
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(right.Nodes) > 0 {
|
|
||||||
t.Log(">", right.Nodes[0])
|
|
||||||
right.Nodes = right.Nodes[1:]
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(left.Nodes) == 0 && len(right.Nodes) == 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
checkNodesPosition(t, left.Nodes, right.Nodes, position)
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkNodes(t *testing.T, left, right []*Node) {
|
|
||||||
checkNodesPosition(t, left, right, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkNode(t *testing.T, left, right *Node) {
|
|
||||||
checkNodePosition(t, left, right, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkNodesIgnorePosition(t *testing.T, left, right []*Node) {
|
|
||||||
checkNodesPosition(t, left, right, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkNodeIgnorePosition(t *testing.T, left, right *Node) {
|
|
||||||
checkNodePosition(t, left, right, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func testReaderTrace(t *testing.T, r io.Reader, rootName string, traceLevel int, tests []testItem) {
|
|
||||||
s, err := testSyntaxReader(r, traceLevel)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, ti := range tests {
|
|
||||||
t.Run(ti.msg, func(t *testing.T) {
|
|
||||||
b := bytes.NewBufferString(ti.text)
|
|
||||||
|
|
||||||
start := time.Now()
|
|
||||||
n, err := s.Parse(b)
|
|
||||||
t.Log("parse duration:", time.Now().Sub(start))
|
|
||||||
|
|
||||||
if ti.fail && err == nil {
|
|
||||||
t.Error("failed to fail")
|
|
||||||
return
|
|
||||||
} else if !ti.fail && err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
} else if ti.fail {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Log(n)
|
|
||||||
|
|
||||||
cn := checkNode
|
|
||||||
if ti.ignorePosition {
|
|
||||||
cn = checkNodeIgnorePosition
|
|
||||||
}
|
|
||||||
|
|
||||||
if ti.node != nil {
|
|
||||||
cn(t, n, ti.node)
|
|
||||||
} else {
|
|
||||||
cn(t, n, &Node{
|
|
||||||
Name: rootName,
|
|
||||||
To: len(ti.text),
|
|
||||||
Nodes: ti.nodes,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func testStringTrace(t *testing.T, s string, traceLevel int, tests []testItem) {
|
|
||||||
testReaderTrace(t, bytes.NewBufferString(s), "", traceLevel, tests)
|
|
||||||
}
|
|
||||||
|
|
||||||
func testString(t *testing.T, s string, tests []testItem) {
|
|
||||||
testStringTrace(t, s, -1, tests)
|
|
||||||
}
|
|
||||||
|
|
||||||
func testTrace(t *testing.T, file, rootName string, traceLevel int, tests []testItem) {
|
|
||||||
f, err := os.Open(file)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
defer f.Close()
|
|
||||||
testReaderTrace(t, f, rootName, traceLevel, tests)
|
|
||||||
}
|
|
||||||
|
|
||||||
func test(t *testing.T, file, rootName string, tests []testItem) {
|
|
||||||
testTrace(t, file, rootName, -1, tests)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRecursion(t *testing.T) {
|
func TestRecursion(t *testing.T) {
|
||||||
testString(
|
runTests(
|
||||||
t,
|
t,
|
||||||
`A = "a" | A "a"`,
|
`A = "a" | A "a"`,
|
||||||
[]testItem{{
|
[]testItem{{
|
||||||
msg: "recursion in choice, right, left, commit",
|
title: "recursion in choice, right, left, commit",
|
||||||
text: "aaa",
|
text: "aaa",
|
||||||
node: &Node{
|
node: &Node{
|
||||||
Name: "A",
|
Name: "A",
|
||||||
Nodes: []*Node{{
|
Nodes: []*Node{{
|
||||||
@ -225,12 +24,12 @@ func TestRecursion(t *testing.T) {
|
|||||||
}},
|
}},
|
||||||
)
|
)
|
||||||
|
|
||||||
testString(
|
runTests(
|
||||||
t,
|
t,
|
||||||
`A = "a" | "a" A`,
|
`A = "a" | "a" A`,
|
||||||
[]testItem{{
|
[]testItem{{
|
||||||
msg: "recursion in choice, right, right, commit",
|
title: "recursion in choice, right, right, commit",
|
||||||
text: "aaa",
|
text: "aaa",
|
||||||
node: &Node{
|
node: &Node{
|
||||||
Name: "A",
|
Name: "A",
|
||||||
Nodes: []*Node{{
|
Nodes: []*Node{{
|
||||||
@ -244,12 +43,12 @@ func TestRecursion(t *testing.T) {
|
|||||||
}},
|
}},
|
||||||
)
|
)
|
||||||
|
|
||||||
testString(
|
runTests(
|
||||||
t,
|
t,
|
||||||
`A = "a" A | "a"`,
|
`A = "a" A | "a"`,
|
||||||
[]testItem{{
|
[]testItem{{
|
||||||
msg: "recursion in choice, left, right, commit",
|
title: "recursion in choice, left, right, commit",
|
||||||
text: "aaa",
|
text: "aaa",
|
||||||
node: &Node{
|
node: &Node{
|
||||||
Name: "A",
|
Name: "A",
|
||||||
Nodes: []*Node{{
|
Nodes: []*Node{{
|
||||||
@ -263,12 +62,12 @@ func TestRecursion(t *testing.T) {
|
|||||||
}},
|
}},
|
||||||
)
|
)
|
||||||
|
|
||||||
testString(
|
runTests(
|
||||||
t,
|
t,
|
||||||
`A = A "a" | "a"`,
|
`A = A "a" | "a"`,
|
||||||
[]testItem{{
|
[]testItem{{
|
||||||
msg: "recursion in choice, left, left, commit",
|
title: "recursion in choice, left, left, commit",
|
||||||
text: "aaa",
|
text: "aaa",
|
||||||
node: &Node{
|
node: &Node{
|
||||||
Name: "A",
|
Name: "A",
|
||||||
Nodes: []*Node{{
|
Nodes: []*Node{{
|
||||||
@ -282,12 +81,12 @@ func TestRecursion(t *testing.T) {
|
|||||||
}},
|
}},
|
||||||
)
|
)
|
||||||
|
|
||||||
testString(
|
runTests(
|
||||||
t,
|
t,
|
||||||
`A':alias = "a" | A' "a"; A = A'`,
|
`A':alias = "a" | A' "a"; A = A'`,
|
||||||
[]testItem{{
|
[]testItem{{
|
||||||
msg: "recursion in choice, right, left, alias",
|
title: "recursion in choice, right, left, alias",
|
||||||
text: "aaa",
|
text: "aaa",
|
||||||
node: &Node{
|
node: &Node{
|
||||||
Name: "A",
|
Name: "A",
|
||||||
To: 3,
|
To: 3,
|
||||||
@ -295,12 +94,12 @@ func TestRecursion(t *testing.T) {
|
|||||||
}},
|
}},
|
||||||
)
|
)
|
||||||
|
|
||||||
testString(
|
runTests(
|
||||||
t,
|
t,
|
||||||
`A':alias = "a" | "a" A'; A = A'`,
|
`A':alias = "a" | "a" A'; A = A'`,
|
||||||
[]testItem{{
|
[]testItem{{
|
||||||
msg: "recursion in choice, right, right, alias",
|
title: "recursion in choice, right, right, alias",
|
||||||
text: "aaa",
|
text: "aaa",
|
||||||
node: &Node{
|
node: &Node{
|
||||||
Name: "A",
|
Name: "A",
|
||||||
To: 3,
|
To: 3,
|
||||||
@ -308,12 +107,12 @@ func TestRecursion(t *testing.T) {
|
|||||||
}},
|
}},
|
||||||
)
|
)
|
||||||
|
|
||||||
testString(
|
runTests(
|
||||||
t,
|
t,
|
||||||
`A':alias = "a" A' | "a"; A = A'`,
|
`A':alias = "a" A' | "a"; A = A'`,
|
||||||
[]testItem{{
|
[]testItem{{
|
||||||
msg: "recursion in choice, left, right, alias",
|
title: "recursion in choice, left, right, alias",
|
||||||
text: "aaa",
|
text: "aaa",
|
||||||
node: &Node{
|
node: &Node{
|
||||||
Name: "A",
|
Name: "A",
|
||||||
To: 3,
|
To: 3,
|
||||||
@ -321,12 +120,12 @@ func TestRecursion(t *testing.T) {
|
|||||||
}},
|
}},
|
||||||
)
|
)
|
||||||
|
|
||||||
testString(
|
runTests(
|
||||||
t,
|
t,
|
||||||
`A':alias = A' "a" | "a"; A = A'`,
|
`A':alias = A' "a" | "a"; A = A'`,
|
||||||
[]testItem{{
|
[]testItem{{
|
||||||
msg: "recursion in choice, left, left, alias",
|
title: "recursion in choice, left, left, alias",
|
||||||
text: "aaa",
|
text: "aaa",
|
||||||
node: &Node{
|
node: &Node{
|
||||||
Name: "A",
|
Name: "A",
|
||||||
To: 3,
|
To: 3,
|
||||||
@ -336,19 +135,19 @@ func TestRecursion(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestSequence(t *testing.T) {
|
func TestSequence(t *testing.T) {
|
||||||
testString(
|
runTests(
|
||||||
t,
|
t,
|
||||||
`AB = "a" | "a"? "a"? "b" "b"`,
|
`AB = "a" | "a"? "a"? "b" "b"`,
|
||||||
[]testItem{{
|
[]testItem{{
|
||||||
msg: "sequence with optional items",
|
title: "sequence with optional items",
|
||||||
text: "abb",
|
text: "abb",
|
||||||
node: &Node{
|
node: &Node{
|
||||||
Name: "AB",
|
Name: "AB",
|
||||||
To: 3,
|
To: 3,
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
msg: "sequence with optional items, none",
|
title: "sequence with optional items, none",
|
||||||
text: "bb",
|
text: "bb",
|
||||||
node: &Node{
|
node: &Node{
|
||||||
Name: "AB",
|
Name: "AB",
|
||||||
To: 2,
|
To: 2,
|
||||||
@ -356,12 +155,12 @@ func TestSequence(t *testing.T) {
|
|||||||
}},
|
}},
|
||||||
)
|
)
|
||||||
|
|
||||||
testString(
|
runTests(
|
||||||
t,
|
t,
|
||||||
`A = "a" | (A?)*`,
|
`A = "a" | (A?)*`,
|
||||||
[]testItem{{
|
[]testItem{{
|
||||||
msg: "sequence in choice with redundant quantifier",
|
title: "sequence in choice with redundant quantifier",
|
||||||
text: "aaa",
|
text: "aaa",
|
||||||
node: &Node{
|
node: &Node{
|
||||||
Name: "A",
|
Name: "A",
|
||||||
Nodes: []*Node{{
|
Nodes: []*Node{{
|
||||||
@ -376,12 +175,12 @@ func TestSequence(t *testing.T) {
|
|||||||
}},
|
}},
|
||||||
)
|
)
|
||||||
|
|
||||||
testString(
|
runTests(
|
||||||
t,
|
t,
|
||||||
`A = ("a"*)*`,
|
`A = ("a"*)*`,
|
||||||
[]testItem{{
|
[]testItem{{
|
||||||
msg: "sequence with redundant quantifier",
|
title: "sequence with redundant quantifier",
|
||||||
text: "aaa",
|
text: "aaa",
|
||||||
node: &Node{
|
node: &Node{
|
||||||
Name: "A",
|
Name: "A",
|
||||||
To: 3,
|
To: 3,
|
||||||
@ -391,268 +190,268 @@ func TestSequence(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestQuantifiers(t *testing.T) {
|
func TestQuantifiers(t *testing.T) {
|
||||||
testString(
|
runTests(
|
||||||
t,
|
t,
|
||||||
`A = "a" "b"{0} "a"`,
|
`A = "a" "b"{0} "a"`,
|
||||||
[]testItem{{
|
[]testItem{{
|
||||||
msg: "zero, considered as one",
|
title: "zero, considered as one",
|
||||||
text: "aba",
|
text: "aba",
|
||||||
node: &Node{
|
node: &Node{
|
||||||
Name: "A",
|
Name: "A",
|
||||||
To: 3,
|
To: 3,
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
msg: "zero, fail",
|
title: "zero, fail",
|
||||||
text: "aa",
|
text: "aa",
|
||||||
fail: true,
|
fail: true,
|
||||||
}},
|
}},
|
||||||
)
|
)
|
||||||
|
|
||||||
testString(
|
runTests(
|
||||||
t,
|
t,
|
||||||
`A = "a" "b"{1} "a"`,
|
`A = "a" "b"{1} "a"`,
|
||||||
[]testItem{{
|
[]testItem{{
|
||||||
msg: "one, missing",
|
title: "one, missing",
|
||||||
text: "aa",
|
text: "aa",
|
||||||
fail: true,
|
fail: true,
|
||||||
}, {
|
}, {
|
||||||
msg: "one",
|
title: "one",
|
||||||
text: "aba",
|
text: "aba",
|
||||||
node: &Node{
|
node: &Node{
|
||||||
Name: "A",
|
Name: "A",
|
||||||
To: 3,
|
To: 3,
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
msg: "one, too much",
|
title: "one, too much",
|
||||||
text: "abba",
|
text: "abba",
|
||||||
fail: true,
|
fail: true,
|
||||||
}},
|
}},
|
||||||
)
|
)
|
||||||
|
|
||||||
testString(
|
runTests(
|
||||||
t,
|
t,
|
||||||
`A = "a" "b"{3} "a"`,
|
`A = "a" "b"{3} "a"`,
|
||||||
[]testItem{{
|
[]testItem{{
|
||||||
msg: "three, missing",
|
title: "three, missing",
|
||||||
text: "abba",
|
text: "abba",
|
||||||
fail: true,
|
fail: true,
|
||||||
}, {
|
}, {
|
||||||
msg: "three",
|
title: "three",
|
||||||
text: "abbba",
|
text: "abbba",
|
||||||
node: &Node{
|
node: &Node{
|
||||||
Name: "A",
|
Name: "A",
|
||||||
To: 5,
|
To: 5,
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
msg: "three, too much",
|
title: "three, too much",
|
||||||
text: "abbbba",
|
text: "abbbba",
|
||||||
fail: true,
|
fail: true,
|
||||||
}},
|
}},
|
||||||
)
|
)
|
||||||
|
|
||||||
testString(
|
runTests(
|
||||||
t,
|
t,
|
||||||
`A = "a" "b"{0,1} "a"`,
|
`A = "a" "b"{0,1} "a"`,
|
||||||
[]testItem{{
|
[]testItem{{
|
||||||
msg: "zero or one explicit, missing",
|
title: "zero or one explicit, missing",
|
||||||
text: "aa",
|
text: "aa",
|
||||||
node: &Node{
|
node: &Node{
|
||||||
Name: "A",
|
Name: "A",
|
||||||
To: 2,
|
To: 2,
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
msg: "zero or one explicit",
|
title: "zero or one explicit",
|
||||||
text: "aba",
|
text: "aba",
|
||||||
node: &Node{
|
node: &Node{
|
||||||
Name: "A",
|
Name: "A",
|
||||||
To: 3,
|
To: 3,
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
msg: "zero or one explicit, too much",
|
title: "zero or one explicit, too much",
|
||||||
text: "abba",
|
text: "abba",
|
||||||
fail: true,
|
fail: true,
|
||||||
}},
|
}},
|
||||||
)
|
)
|
||||||
|
|
||||||
testString(
|
runTests(
|
||||||
t,
|
t,
|
||||||
`A = "a" "b"{,1} "a"`,
|
`A = "a" "b"{,1} "a"`,
|
||||||
[]testItem{{
|
[]testItem{{
|
||||||
msg: "zero or one explicit, omit zero, missing",
|
title: "zero or one explicit, omit zero, missing",
|
||||||
text: "aa",
|
text: "aa",
|
||||||
node: &Node{
|
node: &Node{
|
||||||
Name: "A",
|
Name: "A",
|
||||||
To: 2,
|
To: 2,
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
msg: "zero or one explicit, omit zero",
|
title: "zero or one explicit, omit zero",
|
||||||
text: "aba",
|
text: "aba",
|
||||||
node: &Node{
|
node: &Node{
|
||||||
Name: "A",
|
Name: "A",
|
||||||
To: 3,
|
To: 3,
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
msg: "zero or one explicit, omit zero, too much",
|
title: "zero or one explicit, omit zero, too much",
|
||||||
text: "abba",
|
text: "abba",
|
||||||
fail: true,
|
fail: true,
|
||||||
}},
|
}},
|
||||||
)
|
)
|
||||||
|
|
||||||
testString(
|
runTests(
|
||||||
t,
|
t,
|
||||||
`A = "a" "b"? "a"`,
|
`A = "a" "b"? "a"`,
|
||||||
[]testItem{{
|
[]testItem{{
|
||||||
msg: "zero or one explicit, shortcut, missing",
|
title: "zero or one explicit, shortcut, missing",
|
||||||
text: "aa",
|
text: "aa",
|
||||||
node: &Node{
|
node: &Node{
|
||||||
Name: "A",
|
Name: "A",
|
||||||
To: 2,
|
To: 2,
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
msg: "zero or one explicit, shortcut",
|
title: "zero or one explicit, shortcut",
|
||||||
text: "aba",
|
text: "aba",
|
||||||
node: &Node{
|
node: &Node{
|
||||||
Name: "A",
|
Name: "A",
|
||||||
To: 3,
|
To: 3,
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
msg: "zero or one explicit, shortcut, too much",
|
title: "zero or one explicit, shortcut, too much",
|
||||||
text: "abba",
|
text: "abba",
|
||||||
fail: true,
|
fail: true,
|
||||||
}},
|
}},
|
||||||
)
|
)
|
||||||
|
|
||||||
testString(
|
runTests(
|
||||||
t,
|
t,
|
||||||
`A = "a" "b"{0,3} "a"`,
|
`A = "a" "b"{0,3} "a"`,
|
||||||
[]testItem{{
|
[]testItem{{
|
||||||
msg: "zero or three, missing",
|
title: "zero or three, missing",
|
||||||
text: "aa",
|
text: "aa",
|
||||||
node: &Node{
|
node: &Node{
|
||||||
Name: "A",
|
Name: "A",
|
||||||
To: 2,
|
To: 2,
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
msg: "zero or three",
|
title: "zero or three",
|
||||||
text: "abba",
|
text: "abba",
|
||||||
node: &Node{
|
node: &Node{
|
||||||
Name: "A",
|
Name: "A",
|
||||||
To: 4,
|
To: 4,
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
msg: "zero or three",
|
title: "zero or three",
|
||||||
text: "abbba",
|
text: "abbba",
|
||||||
node: &Node{
|
node: &Node{
|
||||||
Name: "A",
|
Name: "A",
|
||||||
To: 5,
|
To: 5,
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
msg: "zero or three, too much",
|
title: "zero or three, too much",
|
||||||
text: "abbbba",
|
text: "abbbba",
|
||||||
fail: true,
|
fail: true,
|
||||||
}},
|
}},
|
||||||
)
|
)
|
||||||
|
|
||||||
testString(
|
runTests(
|
||||||
t,
|
t,
|
||||||
`A = "a" "b"{,3} "a"`,
|
`A = "a" "b"{,3} "a"`,
|
||||||
[]testItem{{
|
[]testItem{{
|
||||||
msg: "zero or three, omit zero, missing",
|
title: "zero or three, omit zero, missing",
|
||||||
text: "aa",
|
text: "aa",
|
||||||
node: &Node{
|
node: &Node{
|
||||||
Name: "A",
|
Name: "A",
|
||||||
To: 2,
|
To: 2,
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
msg: "zero or three, omit zero",
|
title: "zero or three, omit zero",
|
||||||
text: "abba",
|
text: "abba",
|
||||||
node: &Node{
|
node: &Node{
|
||||||
Name: "A",
|
Name: "A",
|
||||||
To: 4,
|
To: 4,
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
msg: "zero or three, omit zero",
|
title: "zero or three, omit zero",
|
||||||
text: "abbba",
|
text: "abbba",
|
||||||
node: &Node{
|
node: &Node{
|
||||||
Name: "A",
|
Name: "A",
|
||||||
To: 5,
|
To: 5,
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
msg: "zero or three, omit zero, too much",
|
title: "zero or three, omit zero, too much",
|
||||||
text: "abbbba",
|
text: "abbbba",
|
||||||
fail: true,
|
fail: true,
|
||||||
}},
|
}},
|
||||||
)
|
)
|
||||||
|
|
||||||
testString(
|
runTests(
|
||||||
t,
|
t,
|
||||||
`A = "a" "b"{1,3} "a"`,
|
`A = "a" "b"{1,3} "a"`,
|
||||||
[]testItem{{
|
[]testItem{{
|
||||||
msg: "one or three, missing",
|
title: "one or three, missing",
|
||||||
text: "aa",
|
text: "aa",
|
||||||
fail: true,
|
fail: true,
|
||||||
}, {
|
}, {
|
||||||
msg: "one or three",
|
title: "one or three",
|
||||||
text: "abba",
|
text: "abba",
|
||||||
node: &Node{
|
node: &Node{
|
||||||
Name: "A",
|
Name: "A",
|
||||||
To: 4,
|
To: 4,
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
msg: "one or three",
|
title: "one or three",
|
||||||
text: "abbba",
|
text: "abbba",
|
||||||
node: &Node{
|
node: &Node{
|
||||||
Name: "A",
|
Name: "A",
|
||||||
To: 5,
|
To: 5,
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
msg: "one or three, too much",
|
title: "one or three, too much",
|
||||||
text: "abbbba",
|
text: "abbbba",
|
||||||
fail: true,
|
fail: true,
|
||||||
}},
|
}},
|
||||||
)
|
)
|
||||||
|
|
||||||
testString(
|
runTests(
|
||||||
t,
|
t,
|
||||||
`A = "a" "b"{3,5} "a"`,
|
`A = "a" "b"{3,5} "a"`,
|
||||||
[]testItem{{
|
[]testItem{{
|
||||||
msg: "three or five, missing",
|
title: "three or five, missing",
|
||||||
text: "abba",
|
text: "abba",
|
||||||
fail: true,
|
fail: true,
|
||||||
}, {
|
}, {
|
||||||
msg: "three or five",
|
title: "three or five",
|
||||||
text: "abbbba",
|
text: "abbbba",
|
||||||
node: &Node{
|
node: &Node{
|
||||||
Name: "A",
|
Name: "A",
|
||||||
To: 6,
|
To: 6,
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
msg: "three or five",
|
title: "three or five",
|
||||||
text: "abbbbba",
|
text: "abbbbba",
|
||||||
node: &Node{
|
node: &Node{
|
||||||
Name: "A",
|
Name: "A",
|
||||||
To: 7,
|
To: 7,
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
msg: "three or five, too much",
|
title: "three or five, too much",
|
||||||
text: "abbbbbba",
|
text: "abbbbbba",
|
||||||
fail: true,
|
fail: true,
|
||||||
}},
|
}},
|
||||||
)
|
)
|
||||||
|
|
||||||
testString(
|
runTests(
|
||||||
t,
|
t,
|
||||||
`A = "a" "b"{0,} "a"`,
|
`A = "a" "b"{0,} "a"`,
|
||||||
[]testItem{{
|
[]testItem{{
|
||||||
msg: "zero or more, explicit, missing",
|
title: "zero or more, explicit, missing",
|
||||||
text: "aa",
|
text: "aa",
|
||||||
node: &Node{
|
node: &Node{
|
||||||
Name: "A",
|
Name: "A",
|
||||||
To: 2,
|
To: 2,
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
msg: "zero or more, explicit",
|
title: "zero or more, explicit",
|
||||||
text: "abba",
|
text: "abba",
|
||||||
node: &Node{
|
node: &Node{
|
||||||
Name: "A",
|
Name: "A",
|
||||||
To: 4,
|
To: 4,
|
||||||
@ -660,19 +459,19 @@ func TestQuantifiers(t *testing.T) {
|
|||||||
}},
|
}},
|
||||||
)
|
)
|
||||||
|
|
||||||
testString(
|
runTests(
|
||||||
t,
|
t,
|
||||||
`A = "a" "b"* "a"`,
|
`A = "a" "b"* "a"`,
|
||||||
[]testItem{{
|
[]testItem{{
|
||||||
msg: "zero or more, shortcut, missing",
|
title: "zero or more, shortcut, missing",
|
||||||
text: "aa",
|
text: "aa",
|
||||||
node: &Node{
|
node: &Node{
|
||||||
Name: "A",
|
Name: "A",
|
||||||
To: 2,
|
To: 2,
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
msg: "zero or more, shortcut",
|
title: "zero or more, shortcut",
|
||||||
text: "abba",
|
text: "abba",
|
||||||
node: &Node{
|
node: &Node{
|
||||||
Name: "A",
|
Name: "A",
|
||||||
To: 4,
|
To: 4,
|
||||||
@ -680,16 +479,16 @@ func TestQuantifiers(t *testing.T) {
|
|||||||
}},
|
}},
|
||||||
)
|
)
|
||||||
|
|
||||||
testString(
|
runTests(
|
||||||
t,
|
t,
|
||||||
`A = "a" "b"{1,} "a"`,
|
`A = "a" "b"{1,} "a"`,
|
||||||
[]testItem{{
|
[]testItem{{
|
||||||
msg: "one or more, explicit, missing",
|
title: "one or more, explicit, missing",
|
||||||
text: "aa",
|
text: "aa",
|
||||||
fail: true,
|
fail: true,
|
||||||
}, {
|
}, {
|
||||||
msg: "one or more, explicit",
|
title: "one or more, explicit",
|
||||||
text: "abba",
|
text: "abba",
|
||||||
node: &Node{
|
node: &Node{
|
||||||
Name: "A",
|
Name: "A",
|
||||||
To: 4,
|
To: 4,
|
||||||
@ -697,16 +496,16 @@ func TestQuantifiers(t *testing.T) {
|
|||||||
}},
|
}},
|
||||||
)
|
)
|
||||||
|
|
||||||
testString(
|
runTests(
|
||||||
t,
|
t,
|
||||||
`A = "a" "b"+ "a"`,
|
`A = "a" "b"+ "a"`,
|
||||||
[]testItem{{
|
[]testItem{{
|
||||||
msg: "one or more, shortcut, missing",
|
title: "one or more, shortcut, missing",
|
||||||
text: "aa",
|
text: "aa",
|
||||||
fail: true,
|
fail: true,
|
||||||
}, {
|
}, {
|
||||||
msg: "one or more, shortcut",
|
title: "one or more, shortcut",
|
||||||
text: "abba",
|
text: "abba",
|
||||||
node: &Node{
|
node: &Node{
|
||||||
Name: "A",
|
Name: "A",
|
||||||
To: 4,
|
To: 4,
|
||||||
@ -714,16 +513,16 @@ func TestQuantifiers(t *testing.T) {
|
|||||||
}},
|
}},
|
||||||
)
|
)
|
||||||
|
|
||||||
testString(
|
runTests(
|
||||||
t,
|
t,
|
||||||
`A = "a" "b"{3,} "a"`,
|
`A = "a" "b"{3,} "a"`,
|
||||||
[]testItem{{
|
[]testItem{{
|
||||||
msg: "three or more, explicit, missing",
|
title: "three or more, explicit, missing",
|
||||||
text: "abba",
|
text: "abba",
|
||||||
fail: true,
|
fail: true,
|
||||||
}, {
|
}, {
|
||||||
msg: "three or more, explicit",
|
title: "three or more, explicit",
|
||||||
text: "abbbba",
|
text: "abbbba",
|
||||||
node: &Node{
|
node: &Node{
|
||||||
Name: "A",
|
Name: "A",
|
||||||
To: 6,
|
To: 6,
|
||||||
|
64
run_test.go
Normal file
64
run_test.go
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
package treerack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type testItem struct {
|
||||||
|
title string
|
||||||
|
text string
|
||||||
|
fail bool
|
||||||
|
node *Node
|
||||||
|
nodes []*Node
|
||||||
|
ignorePosition bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func runTestsSyntax(t *testing.T, s *Syntax, tests []testItem) {
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.title, func(t *testing.T) {
|
||||||
|
b := bytes.NewBufferString(test.text)
|
||||||
|
|
||||||
|
start := time.Now()
|
||||||
|
n, err := s.Parse(b)
|
||||||
|
t.Log("parse duration:", time.Now().Sub(start))
|
||||||
|
|
||||||
|
if test.fail && err == nil {
|
||||||
|
t.Error("failed to fail")
|
||||||
|
return
|
||||||
|
} else if !test.fail && err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
} else if test.fail {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if test.node != nil {
|
||||||
|
checkNode(t, test.ignorePosition, n, test.node)
|
||||||
|
} else {
|
||||||
|
checkNodes(t, test.ignorePosition, n.Nodes, test.nodes)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func runTests(t *testing.T, syntax string, tests []testItem) {
|
||||||
|
s, err := openSyntaxString(syntax)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
runTestsSyntax(t, s, tests)
|
||||||
|
}
|
||||||
|
|
||||||
|
func runTestsFile(t *testing.T, file string, tests []testItem) {
|
||||||
|
s, err := openSyntaxFile(file)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
runTestsSyntax(t, s, tests)
|
||||||
|
}
|
@ -3,10 +3,10 @@ package treerack
|
|||||||
import "testing"
|
import "testing"
|
||||||
|
|
||||||
func TestScheme(t *testing.T) {
|
func TestScheme(t *testing.T) {
|
||||||
test(t, "scheme.parser", "scheme", []testItem{{
|
runTestsFile(t, "scheme.parser", []testItem{{
|
||||||
msg: "empty",
|
title: "empty",
|
||||||
}, {
|
}, {
|
||||||
msg: "a function",
|
title: "a function",
|
||||||
text: `
|
text: `
|
||||||
(define (foo a b c)
|
(define (foo a b c)
|
||||||
(let ([bar (+ a b c)]
|
(let ([bar (+ a b c)]
|
||||||
|
@ -3,37 +3,37 @@ package treerack
|
|||||||
import "testing"
|
import "testing"
|
||||||
|
|
||||||
func TestSExpr(t *testing.T) {
|
func TestSExpr(t *testing.T) {
|
||||||
test(t, "sexpr.parser", "s-expression", []testItem{{
|
runTestsFile(t, "sexpr.parser", []testItem{{
|
||||||
msg: "number",
|
title: "number",
|
||||||
text: "42",
|
text: "42",
|
||||||
nodes: []*Node{{
|
nodes: []*Node{{
|
||||||
Name: "number",
|
Name: "number",
|
||||||
}},
|
}},
|
||||||
ignorePosition: true,
|
ignorePosition: true,
|
||||||
}, {
|
}, {
|
||||||
msg: "string",
|
title: "string",
|
||||||
text: "\"foo\"",
|
text: "\"foo\"",
|
||||||
nodes: []*Node{{
|
nodes: []*Node{{
|
||||||
Name: "string",
|
Name: "string",
|
||||||
}},
|
}},
|
||||||
ignorePosition: true,
|
ignorePosition: true,
|
||||||
}, {
|
}, {
|
||||||
msg: "symbol",
|
title: "symbol",
|
||||||
text: "foo",
|
text: "foo",
|
||||||
nodes: []*Node{{
|
nodes: []*Node{{
|
||||||
Name: "symbol",
|
Name: "symbol",
|
||||||
}},
|
}},
|
||||||
ignorePosition: true,
|
ignorePosition: true,
|
||||||
}, {
|
}, {
|
||||||
msg: "nil",
|
title: "nil",
|
||||||
text: "()",
|
text: "()",
|
||||||
nodes: []*Node{{
|
nodes: []*Node{{
|
||||||
Name: "list",
|
Name: "list",
|
||||||
}},
|
}},
|
||||||
ignorePosition: true,
|
ignorePosition: true,
|
||||||
}, {
|
}, {
|
||||||
msg: "list",
|
title: "list",
|
||||||
text: "(foo bar baz)",
|
text: "(foo bar baz)",
|
||||||
nodes: []*Node{{
|
nodes: []*Node{{
|
||||||
Name: "list",
|
Name: "list",
|
||||||
Nodes: []*Node{{
|
Nodes: []*Node{{
|
||||||
@ -46,8 +46,8 @@ func TestSExpr(t *testing.T) {
|
|||||||
}},
|
}},
|
||||||
ignorePosition: true,
|
ignorePosition: true,
|
||||||
}, {
|
}, {
|
||||||
msg: "embedded list",
|
title: "embedded list",
|
||||||
text: "(foo (bar (baz)) qux)",
|
text: "(foo (bar (baz)) qux)",
|
||||||
nodes: []*Node{{
|
nodes: []*Node{{
|
||||||
Name: "list",
|
Name: "list",
|
||||||
Nodes: []*Node{{
|
Nodes: []*Node{{
|
||||||
|
Loading…
Reference in New Issue
Block a user