2017-08-07 12:07:29 +02:00
|
|
|
package goparsify
|
2017-08-06 06:31:35 +02:00
|
|
|
|
|
|
|
import (
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestParsify(t *testing.T) {
|
2017-08-13 09:30:10 +02:00
|
|
|
result := Result{}
|
2017-08-06 06:31:35 +02:00
|
|
|
t.Run("strings", func(t *testing.T) {
|
2017-08-13 09:30:10 +02:00
|
|
|
Parsify("ff")(NewState("ffooo"), &result)
|
|
|
|
require.Equal(t, "ff", result.Token)
|
2017-08-06 06:31:35 +02:00
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("parsers", func(t *testing.T) {
|
2017-08-13 09:30:10 +02:00
|
|
|
Parsify(Chars("f"))(NewState("ffooo"), &result)
|
|
|
|
require.Equal(t, "ff", result.Token)
|
2017-08-06 06:31:35 +02:00
|
|
|
})
|
|
|
|
|
2017-08-06 07:43:23 +02:00
|
|
|
t.Run("parser funcs", func(t *testing.T) {
|
2017-08-13 09:30:10 +02:00
|
|
|
Parsify(func(p *State, node *Result) { node.Token = "hello" })(NewState("ffooo"), &result)
|
2017-08-06 15:32:10 +02:00
|
|
|
|
2017-08-13 09:30:10 +02:00
|
|
|
require.Equal(t, "hello", result.Token)
|
2017-08-06 07:43:23 +02:00
|
|
|
})
|
|
|
|
|
2017-08-06 06:31:35 +02:00
|
|
|
t.Run("*parsers", func(t *testing.T) {
|
|
|
|
var parser Parser
|
|
|
|
parserfied := Parsify(&parser)
|
2017-08-06 15:32:10 +02:00
|
|
|
parser = Chars("f")
|
2017-08-06 06:31:35 +02:00
|
|
|
|
2017-08-13 09:30:10 +02:00
|
|
|
parserfied(NewState("ffooo"), &result)
|
|
|
|
require.Equal(t, "ff", result.Token)
|
2017-08-06 06:31:35 +02:00
|
|
|
})
|
2017-08-06 07:43:23 +02:00
|
|
|
|
|
|
|
require.Panics(t, func() {
|
|
|
|
Parsify(1)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestParsifyAll(t *testing.T) {
|
|
|
|
parsers := ParsifyAll("ff", "gg")
|
|
|
|
|
2017-08-13 09:30:10 +02:00
|
|
|
result := Result{}
|
|
|
|
parsers[0](NewState("ffooo"), &result)
|
2017-08-07 10:25:23 +02:00
|
|
|
require.Equal(t, "ff", result.Token)
|
2017-08-06 07:43:23 +02:00
|
|
|
|
2017-08-13 09:30:10 +02:00
|
|
|
result = Result{}
|
|
|
|
parsers[1](NewState("ffooo"), &result)
|
2017-08-07 13:45:12 +02:00
|
|
|
require.Equal(t, "", result.Token)
|
2017-08-06 06:31:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestExact(t *testing.T) {
|
2017-08-07 13:57:12 +02:00
|
|
|
t.Run("success string", func(t *testing.T) {
|
2017-08-06 15:32:10 +02:00
|
|
|
node, ps := runParser("foobar", Exact("fo"))
|
2017-08-07 10:25:23 +02:00
|
|
|
require.Equal(t, "fo", node.Token)
|
2017-08-06 15:32:10 +02:00
|
|
|
require.Equal(t, "obar", ps.Get())
|
2017-08-06 06:31:35 +02:00
|
|
|
})
|
|
|
|
|
2017-08-07 13:57:12 +02:00
|
|
|
t.Run("success char", func(t *testing.T) {
|
|
|
|
node, ps := runParser("foobar", Exact("f"))
|
|
|
|
require.Equal(t, "f", node.Token)
|
|
|
|
require.Equal(t, "oobar", ps.Get())
|
|
|
|
})
|
|
|
|
|
2017-08-06 06:31:35 +02:00
|
|
|
t.Run("error", func(t *testing.T) {
|
2017-08-06 15:32:10 +02:00
|
|
|
_, ps := runParser("foobar", Exact("bar"))
|
2017-08-09 13:18:14 +02:00
|
|
|
require.Equal(t, "bar", ps.Error.expected)
|
2017-08-06 15:32:10 +02:00
|
|
|
require.Equal(t, 0, ps.Pos)
|
2017-08-06 06:31:35 +02:00
|
|
|
})
|
2017-08-07 13:57:12 +02:00
|
|
|
|
|
|
|
t.Run("error char", func(t *testing.T) {
|
|
|
|
_, ps := runParser("foobar", Exact("o"))
|
2017-08-09 13:18:14 +02:00
|
|
|
require.Equal(t, "o", ps.Error.expected)
|
2017-08-07 13:57:12 +02:00
|
|
|
require.Equal(t, 0, ps.Pos)
|
|
|
|
})
|
2017-08-07 14:38:34 +02:00
|
|
|
|
|
|
|
t.Run("eof char", func(t *testing.T) {
|
|
|
|
_, ps := runParser("", Exact("o"))
|
2017-08-09 13:18:14 +02:00
|
|
|
require.Equal(t, "o", ps.Error.expected)
|
2017-08-07 14:38:34 +02:00
|
|
|
require.Equal(t, 0, ps.Pos)
|
|
|
|
})
|
2017-08-06 06:31:35 +02:00
|
|
|
}
|
|
|
|
|
2017-08-06 15:32:10 +02:00
|
|
|
func TestChars(t *testing.T) {
|
2017-08-06 07:43:23 +02:00
|
|
|
t.Run("full match", func(t *testing.T) {
|
2017-08-06 15:32:10 +02:00
|
|
|
node, ps := runParser("foobar", Chars("a-z"))
|
2017-08-07 10:25:23 +02:00
|
|
|
require.Equal(t, "foobar", node.Token)
|
2017-08-06 15:32:10 +02:00
|
|
|
require.Equal(t, "", ps.Get())
|
|
|
|
require.False(t, ps.Errored())
|
2017-08-06 07:43:23 +02:00
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("partial match", func(t *testing.T) {
|
2017-08-06 15:32:10 +02:00
|
|
|
node, ps := runParser("a1b2c3d4efg", Chars("1-4d-a"))
|
2017-08-07 10:25:23 +02:00
|
|
|
require.Equal(t, "a1b2c3d4", node.Token)
|
2017-08-06 15:32:10 +02:00
|
|
|
require.Equal(t, "efg", ps.Get())
|
|
|
|
require.False(t, ps.Errored())
|
2017-08-06 07:43:23 +02:00
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("limited match", func(t *testing.T) {
|
2017-08-06 15:32:10 +02:00
|
|
|
node, ps := runParser("a1b2c3d4efg", Chars("1-4d-a", 1, 2))
|
2017-08-07 10:25:23 +02:00
|
|
|
require.Equal(t, "a1", node.Token)
|
2017-08-06 15:32:10 +02:00
|
|
|
require.Equal(t, "b2c3d4efg", ps.Get())
|
|
|
|
require.False(t, ps.Errored())
|
2017-08-06 07:43:23 +02:00
|
|
|
})
|
|
|
|
|
2017-08-09 13:58:36 +02:00
|
|
|
t.Run("escaped hyphen", func(t *testing.T) {
|
|
|
|
node, ps := runParser(`ab-ab\cde`, Chars(`a\-b`))
|
|
|
|
require.Equal(t, "ab-ab", node.Token)
|
|
|
|
require.Equal(t, `\cde`, ps.Get())
|
|
|
|
require.False(t, ps.Errored())
|
|
|
|
})
|
|
|
|
|
2018-03-01 20:11:40 +01:00
|
|
|
t.Run("unescaped hyphen", func(t *testing.T) {
|
|
|
|
node, ps := runParser("19-", Chars("0-9"))
|
|
|
|
require.Equal(t, "19", node.Token)
|
|
|
|
require.Equal(t, 2, ps.Pos)
|
|
|
|
require.False(t, ps.Errored())
|
|
|
|
})
|
|
|
|
|
2017-08-06 07:43:23 +02:00
|
|
|
t.Run("no match", func(t *testing.T) {
|
2017-08-06 15:32:10 +02:00
|
|
|
_, ps := runParser("ffffff", Chars("0-9"))
|
2017-08-09 13:18:14 +02:00
|
|
|
require.Equal(t, "offset 0: expected 0-9", ps.Error.Error())
|
2017-08-06 15:32:10 +02:00
|
|
|
require.Equal(t, 0, ps.Pos)
|
2017-08-06 07:43:23 +02:00
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("no match with min", func(t *testing.T) {
|
2017-08-06 15:32:10 +02:00
|
|
|
_, ps := runParser("ffffff", Chars("0-9", 4))
|
2017-08-09 13:18:14 +02:00
|
|
|
require.Equal(t, "0-9", ps.Error.expected)
|
2017-08-06 15:32:10 +02:00
|
|
|
require.Equal(t, 0, ps.Pos)
|
2017-08-06 07:43:23 +02:00
|
|
|
})
|
|
|
|
|
2017-08-06 15:32:10 +02:00
|
|
|
t.Run("test exact matches", func(t *testing.T) {
|
|
|
|
node, ps := runParser("aaff", Chars("abcd"))
|
2017-08-07 10:25:23 +02:00
|
|
|
require.Equal(t, "aa", node.Token)
|
2017-08-06 15:32:10 +02:00
|
|
|
require.Equal(t, 2, ps.Pos)
|
|
|
|
require.False(t, ps.Errored())
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("test not matches", func(t *testing.T) {
|
|
|
|
node, ps := runParser("aaff", NotChars("ff"))
|
2017-08-07 10:25:23 +02:00
|
|
|
require.Equal(t, "aa", node.Token)
|
2017-08-06 15:32:10 +02:00
|
|
|
require.Equal(t, 2, ps.Pos)
|
|
|
|
require.False(t, ps.Errored())
|
2017-08-06 07:43:23 +02:00
|
|
|
})
|
|
|
|
|
|
|
|
require.Panics(t, func() {
|
2017-08-06 15:32:10 +02:00
|
|
|
Chars("a-b", 1, 2, 3)
|
2017-08-06 07:43:23 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2017-08-09 13:41:57 +02:00
|
|
|
func TestRegex(t *testing.T) {
|
|
|
|
t.Run("full match", func(t *testing.T) {
|
|
|
|
node, ps := runParser("hello", Regex("[a-z]*"))
|
|
|
|
require.Equal(t, "hello", node.Token)
|
|
|
|
require.Equal(t, "", ps.Get())
|
|
|
|
require.False(t, ps.Errored())
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("limited match", func(t *testing.T) {
|
|
|
|
node, ps := runParser("hello world", Regex("[a-z]*"))
|
|
|
|
require.Equal(t, "hello", node.Token)
|
|
|
|
require.Equal(t, " world", ps.Get())
|
|
|
|
require.False(t, ps.Errored())
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("no match", func(t *testing.T) {
|
|
|
|
_, ps := runParser("1234", Regex("[a-z]*"))
|
|
|
|
require.Equal(t, "offset 0: expected [a-z]*", ps.Error.Error())
|
|
|
|
require.Equal(t, 0, ps.Pos)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("eof", func(t *testing.T) {
|
|
|
|
_, ps := runParser("", Regex("[a-z]*"))
|
|
|
|
require.Equal(t, "offset 0: expected [a-z]*", ps.Error.Error())
|
|
|
|
require.Equal(t, 0, ps.Pos)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2017-08-06 07:43:23 +02:00
|
|
|
func TestParseString(t *testing.T) {
|
2017-08-13 09:30:10 +02:00
|
|
|
Y := Map("hello", func(n *Result) { n.Result = n.Token })
|
2017-08-09 13:18:14 +02:00
|
|
|
|
|
|
|
t.Run("full match", func(t *testing.T) {
|
|
|
|
result, err := Run(Y, "hello")
|
2017-08-06 09:02:39 +02:00
|
|
|
require.Equal(t, "hello", result)
|
2017-08-06 07:43:23 +02:00
|
|
|
require.NoError(t, err)
|
|
|
|
})
|
|
|
|
|
2017-08-09 13:18:14 +02:00
|
|
|
t.Run("partial match", func(t *testing.T) {
|
|
|
|
result, err := Run(Y, "hello world")
|
|
|
|
require.Equal(t, "hello", result)
|
|
|
|
require.Error(t, err)
|
|
|
|
require.Equal(t, "left unparsed: world", err.Error())
|
|
|
|
})
|
|
|
|
|
2017-08-06 07:43:23 +02:00
|
|
|
t.Run("error", func(t *testing.T) {
|
2017-08-09 13:18:14 +02:00
|
|
|
result, err := Run(Y, "world")
|
2017-08-07 10:25:23 +02:00
|
|
|
require.Nil(t, result)
|
2017-08-06 07:43:23 +02:00
|
|
|
require.Error(t, err)
|
2017-08-09 13:18:14 +02:00
|
|
|
require.Equal(t, "offset 0: expected hello", err.Error())
|
2017-08-06 07:43:23 +02:00
|
|
|
})
|
2017-08-06 06:31:35 +02:00
|
|
|
}
|
2017-08-06 09:28:34 +02:00
|
|
|
|
2017-08-09 13:58:36 +02:00
|
|
|
func TestAutoWS(t *testing.T) {
|
|
|
|
t.Run("ws is not automatically consumed", func(t *testing.T) {
|
|
|
|
_, ps := runParser(" hello", NoAutoWS("hello"))
|
|
|
|
require.Equal(t, "offset 0: expected hello", ps.Error.Error())
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("ws is can be explicitly consumed ", func(t *testing.T) {
|
2017-08-13 11:27:41 +02:00
|
|
|
result, ps := runParser(" hello", NoAutoWS(Seq(ASCIIWhitespace, "hello")))
|
2017-08-09 13:58:36 +02:00
|
|
|
require.Equal(t, "hello", result.Child[1].Token)
|
|
|
|
require.Equal(t, "", ps.Get())
|
|
|
|
})
|
2017-08-09 14:14:27 +02:00
|
|
|
|
|
|
|
t.Run("unicode whitespace", func(t *testing.T) {
|
2017-08-13 11:27:41 +02:00
|
|
|
result, ps := runParser(" \u202f hello", NoAutoWS(Seq(UnicodeWhitespace, "hello")))
|
2017-08-13 09:30:10 +02:00
|
|
|
require.Equal(t, "hello", result.Child[1].Token)
|
|
|
|
require.Equal(t, "", ps.Get())
|
2017-08-09 14:14:27 +02:00
|
|
|
require.False(t, ps.Errored())
|
|
|
|
})
|
2017-08-09 13:58:36 +02:00
|
|
|
}
|
|
|
|
|
2017-08-15 10:57:00 +02:00
|
|
|
func TestUntil(t *testing.T) {
|
|
|
|
parser := Until("world", ".")
|
|
|
|
|
|
|
|
t.Run("success", func(t *testing.T) {
|
|
|
|
result, ps := runParser("this is the end of the world", parser)
|
|
|
|
require.Equal(t, "this is the end of the ", result.Token)
|
|
|
|
require.Equal(t, "world", ps.Get())
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("eof", func(t *testing.T) {
|
|
|
|
result, ps := runParser("this is the end of it all", parser)
|
|
|
|
require.Equal(t, "this is the end of it all", result.Token)
|
|
|
|
require.Equal(t, "", ps.Get())
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2017-08-09 13:18:14 +02:00
|
|
|
func runParser(input string, parser Parser) (Result, *State) {
|
|
|
|
ps := NewState(input)
|
2017-08-13 09:30:10 +02:00
|
|
|
result := Result{}
|
|
|
|
parser(ps, &result)
|
2017-08-06 15:32:10 +02:00
|
|
|
return result, ps
|
|
|
|
}
|