261 lines
6.9 KiB
Go
261 lines
6.9 KiB
Go
package parsekit_test
|
|
|
|
import (
|
|
"testing"
|
|
|
|
p "github.com/mmakaay/toml/parsekit"
|
|
)
|
|
|
|
var c = p.C
|
|
|
|
const TestItem p.ItemType = 1
|
|
|
|
func newParser(input string, matcher p.Matcher) *p.P {
|
|
stateFn := func(p *p.P) {
|
|
if p.On(matcher).Accept() {
|
|
p.EmitLiteral(TestItem)
|
|
p.Repeat()
|
|
} else {
|
|
p.UnexpectedInput("MATCH")
|
|
}
|
|
}
|
|
return p.New(input, stateFn)
|
|
}
|
|
|
|
func TestMatchAny(t *testing.T) {
|
|
p := newParser("o", c.Any())
|
|
r, err, ok := p.Next()
|
|
if !ok {
|
|
t.Fatalf("Parsing failed: %s", err)
|
|
}
|
|
if r.Type != TestItem {
|
|
t.Error("Parser item type not expected TestTitem")
|
|
}
|
|
if r.Value != "o" {
|
|
t.Errorf("Parser item value is %q instead of expected \"o\"", r.Value)
|
|
}
|
|
}
|
|
|
|
func TestMatchAny_AtEndOfFile(t *testing.T) {
|
|
p := newParser("", c.Any())
|
|
_, err, ok := p.Next()
|
|
if ok {
|
|
t.Fatalf("Parsing unexpectedly succeeded")
|
|
}
|
|
expected := "unexpected end of file (expected MATCH)"
|
|
if err.Error() != expected {
|
|
t.Fatalf("Unexpected error from parser:\nexpectd: %s\nactual: %s\n", expected, err.Error())
|
|
}
|
|
}
|
|
|
|
func TestMatchAny_AtInvalidUtf8Rune(t *testing.T) {
|
|
p := newParser("\xcd", c.Any())
|
|
_, err, ok := p.Next()
|
|
if ok {
|
|
t.Fatalf("Parsing unexpectedly succeeded")
|
|
}
|
|
expected := "invalid UTF8 character in input (expected MATCH)"
|
|
if err.Error() != expected {
|
|
t.Fatalf("Unexpected error from parser:\nexpectd: %s\nactual: %s\n", expected, err.Error())
|
|
}
|
|
}
|
|
|
|
func TestMatchRune(t *testing.T) {
|
|
p := newParser("xxx", c.Rune('x'))
|
|
r, err, ok := p.Next()
|
|
if !ok {
|
|
t.Fatalf("Parsing failed: %s", err)
|
|
}
|
|
if r.Type != TestItem {
|
|
t.Error("Parser item type not expected TestTitem")
|
|
}
|
|
if r.Value != "x" {
|
|
t.Errorf("Parser item value is %q instead of expected \"x\"", r.Value)
|
|
}
|
|
}
|
|
|
|
func TestMatchRune_OnMismatch(t *testing.T) {
|
|
p := newParser("x ", c.Rune(' '))
|
|
_, err, ok := p.Next()
|
|
if ok {
|
|
t.Fatalf("Parsing did not fail unexpectedly")
|
|
}
|
|
expected := "unexpected character 'x' (expected MATCH)"
|
|
if err.Error() != expected {
|
|
t.Fatalf("Unexpected error from parser:\nexpectd: %s\nactual: %s\n", expected, err.Error())
|
|
}
|
|
}
|
|
|
|
func TestMatchRuneRange(t *testing.T) {
|
|
m := c.RuneRange('b', 'y')
|
|
s := "mnopqrstuvwxybcdefghijkl"
|
|
p := newParser(s, m)
|
|
for i := 0; i < len(s); i++ {
|
|
r, err, ok := p.Next()
|
|
if !ok {
|
|
t.Fatalf("Parsing failed: %s", err)
|
|
}
|
|
if s[i] != r.Value[0] {
|
|
t.Fatalf("Unexpected parse output on cycle %d:\nexpected: %q\nactual: %q\n", i+1, s[i], r.Value[0])
|
|
}
|
|
}
|
|
if _, _, ok := newParser("a", m).Next(); ok {
|
|
t.Fatalf("Unexpected parse success for input 'a'")
|
|
}
|
|
if _, _, ok := newParser("z", m).Next(); ok {
|
|
t.Fatalf("Unexpected parse success for input 'z'")
|
|
}
|
|
}
|
|
|
|
func TestMatchRunes(t *testing.T) {
|
|
m := c.Runes('+', '-', '*', '/')
|
|
s := "-+/*+++"
|
|
p := newParser(s, m)
|
|
for i := 0; i < len(s); i++ {
|
|
r, err, ok := p.Next()
|
|
if !ok {
|
|
t.Fatalf("Parsing failed: %s", err)
|
|
}
|
|
if s[i] != r.Value[0] {
|
|
t.Fatalf("Unexpected parse output on cycle %d:\nexpected: %q\nactual: %q\n", i+1, s[i], r.Value[0])
|
|
}
|
|
}
|
|
if _, _, ok := newParser("^", m).Next(); ok {
|
|
t.Fatalf("Unexpected parse success for input '^'")
|
|
}
|
|
if _, _, ok := newParser("x", m).Next(); ok {
|
|
t.Fatalf("Unexpected parse success for input 'x'")
|
|
}
|
|
}
|
|
|
|
func TestMatchAnyOf(t *testing.T) {
|
|
p := newParser("abc", c.AnyOf(c.Rune('a'), c.Rune('b')))
|
|
r, err, ok := p.Next()
|
|
if !ok {
|
|
t.Fatalf("Parsing failed: %s", err)
|
|
}
|
|
if r.Type != TestItem {
|
|
t.Error("Parser item type not expected TestTitem")
|
|
}
|
|
if r.Value != "a" {
|
|
t.Errorf("Parser item value is %q instead of expected \"a\"", r.Value)
|
|
}
|
|
|
|
r, err, ok = p.Next()
|
|
if !ok {
|
|
t.Fatalf("Parsing failed: %s", err)
|
|
}
|
|
if r.Type != TestItem {
|
|
t.Error("Parser item type not expected TestTitem")
|
|
}
|
|
if r.Value != "b" {
|
|
t.Errorf("Parser item value is %q instead of expected \"a\"", r.Value)
|
|
}
|
|
}
|
|
|
|
func TestMatchRepeat(t *testing.T) {
|
|
p := newParser("xxxxyyyy", c.Repeat(4, c.Rune('x')))
|
|
r, err, ok := p.Next()
|
|
if !ok {
|
|
t.Fatalf("Parsing failed: %s at row: %d, column %d\n", err, err.Row, err.Column)
|
|
}
|
|
if r.Value != "xxxx" {
|
|
t.Errorf("Parser item value is %q instead of expected \"xxxx\"", r.Value)
|
|
}
|
|
}
|
|
|
|
func TestMatchRepeat_Mismatch(t *testing.T) {
|
|
p := newParser("xxxyyyy", c.Repeat(4, c.Rune('x')))
|
|
_, err, ok := p.Next()
|
|
if ok {
|
|
t.Fatalf("Parsing did not fail unexpectedly")
|
|
}
|
|
expected := "unexpected character 'x' (expected MATCH)"
|
|
if err.Error() != expected {
|
|
t.Fatalf("Unexpected error from parser:\nexpectd: %s\nactual: %s\n", expected, err.Error())
|
|
}
|
|
}
|
|
|
|
func TestMatchOneOrMore(t *testing.T) {
|
|
p := newParser("xxxxxxxxyyyy", c.OneOrMore(c.Rune('x')))
|
|
r, err, ok := p.Next()
|
|
if !ok {
|
|
t.Fatalf("Parsing failed: %s at row: %d, column %d\n", err, err.Row, err.Column)
|
|
}
|
|
if r.Value != "xxxxxxxx" {
|
|
t.Errorf("Parser item value is %q instead of expected \"xxxxxxxx\"", r.Value)
|
|
}
|
|
}
|
|
|
|
func TestMatchSequence(t *testing.T) {
|
|
p := newParser("10101", c.Sequence(c.Rune('1'), c.Rune('0')))
|
|
r, err, ok := p.Next()
|
|
if !ok {
|
|
t.Fatalf("Parsing failed: %s at row: %d, column %d\n", err, err.Row, err.Column)
|
|
}
|
|
if r.Value != "10" {
|
|
t.Errorf("Parser item value is %q instead of expected \"10\"", r.Value)
|
|
}
|
|
}
|
|
|
|
func TestMatchSequence_CombinedWithOneOrMore(t *testing.T) {
|
|
p := newParser("101010987", c.OneOrMore(c.Sequence(c.Rune('1'), c.Rune('0'))))
|
|
r, err, ok := p.Next()
|
|
if !ok {
|
|
t.Fatalf("Parsing failed: %s at row: %d, column %d\n", err, err.Row, err.Column)
|
|
}
|
|
if r.Value != "101010" {
|
|
t.Errorf("Parser item value is %q instead of expected \"101010\"", r.Value)
|
|
}
|
|
}
|
|
|
|
func TestSequence_WithRepeatedRunes(t *testing.T) {
|
|
whitespace := c.Optional(c.OneOrMore(c.Rune(' ')))
|
|
equal := c.Rune('=')
|
|
assignment := c.Sequence(whitespace, equal, whitespace)
|
|
p := newParser(" == 10", assignment)
|
|
r, err, ok := p.Next()
|
|
if !ok {
|
|
t.Fatalf("Parsing failed: %s at row: %d, column %d\n", err, err.Row, err.Column)
|
|
}
|
|
if r.Value != " =" {
|
|
t.Errorf("Parser item value is %q instead of expected \" =\"", r.Value)
|
|
}
|
|
}
|
|
|
|
func TestMatchOptional(t *testing.T) {
|
|
p := newParser("xyz", c.Optional(c.Rune('x')))
|
|
r, err, ok := p.Next()
|
|
if !ok {
|
|
t.Fatalf("Parsing failed: %s at row: %d, column %d\n", err, err.Row, err.Column)
|
|
}
|
|
if r.Value != "x" {
|
|
t.Errorf("Parser item value is %q instead of expected \"x\"", r.Value)
|
|
}
|
|
|
|
p = newParser("xyz", c.Optional(c.Rune('y')))
|
|
r, err, ok = p.Next()
|
|
if !ok {
|
|
t.Fatalf("Parsing failed: %s at row: %d, column %d\n", err, err.Row, err.Column)
|
|
}
|
|
if r.Value != "" {
|
|
t.Errorf("Parser item value is %q instead of expected \"\"", r.Value)
|
|
}
|
|
}
|
|
|
|
func TestMixAndMatch(t *testing.T) {
|
|
hex := c.AnyOf(c.RuneRange('0', '9'), c.RuneRange('a', 'f'), c.RuneRange('A', 'F'))
|
|
backslash := c.Rune('\\')
|
|
x := c.Rune('x')
|
|
hexbyte := c.Sequence(backslash, x, c.Repeat(2, hex))
|
|
|
|
p := newParser(`\x9a\x01\xF0\xfCAndSomeMoreStuff`, c.Repeat(4, hexbyte))
|
|
r, err, ok := p.Next()
|
|
if !ok {
|
|
t.Fatalf("Parsing failed: %s at row: %d, column %d\n", err, err.Row, err.Column)
|
|
}
|
|
if r.Value != `\x9a\x01\xF0\xfC` {
|
|
t.Errorf("Parser item value is %q instead of expected \"%q\"", r.Value, `\x9a\x01\xF0\xfC`)
|
|
}
|
|
}
|