mirror of https://github.com/gobwas/glob.git
257 lines
6.1 KiB
Go
257 lines
6.1 KiB
Go
|
package ast
|
||
|
|
||
|
import (
|
||
|
"github.com/gobwas/glob/syntax"
|
||
|
"reflect"
|
||
|
"testing"
|
||
|
)
|
||
|
|
||
|
type stubLexer struct {
|
||
|
tokens []syntax.Token
|
||
|
pos int
|
||
|
}
|
||
|
|
||
|
func (s *stubLexer) Next() (ret syntax.Token) {
|
||
|
if s.pos == len(s.tokens) {
|
||
|
return syntax.Token{syntax.EOF, ""}
|
||
|
}
|
||
|
ret = s.tokens[s.pos]
|
||
|
s.pos++
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func TestParseString(t *testing.T) {
|
||
|
for id, test := range []struct {
|
||
|
tokens []syntax.Token
|
||
|
tree Node
|
||
|
}{
|
||
|
{
|
||
|
//pattern: "abc",
|
||
|
tokens: []syntax.Token{
|
||
|
syntax.Token{syntax.Text, "abc"},
|
||
|
syntax.Token{syntax.EOF, ""},
|
||
|
},
|
||
|
tree: NewNode(KindPattern, nil,
|
||
|
NewNode(KindText, &Text{Text: "abc"}),
|
||
|
),
|
||
|
},
|
||
|
{
|
||
|
//pattern: "a*c",
|
||
|
tokens: []syntax.Token{
|
||
|
syntax.Token{syntax.Text, "a"},
|
||
|
syntax.Token{syntax.Any, "*"},
|
||
|
syntax.Token{syntax.Text, "c"},
|
||
|
syntax.Token{syntax.EOF, ""},
|
||
|
},
|
||
|
tree: NewNode(KindPattern, nil,
|
||
|
NewNode(KindText, &Text{Text: "a"}),
|
||
|
NewNode(KindAny, nil),
|
||
|
NewNode(KindText, &Text{Text: "c"}),
|
||
|
),
|
||
|
},
|
||
|
{
|
||
|
//pattern: "a**c",
|
||
|
tokens: []syntax.Token{
|
||
|
syntax.Token{syntax.Text, "a"},
|
||
|
syntax.Token{syntax.Super, "**"},
|
||
|
syntax.Token{syntax.Text, "c"},
|
||
|
syntax.Token{syntax.EOF, ""},
|
||
|
},
|
||
|
tree: NewNode(KindPattern, nil,
|
||
|
NewNode(KindText, &Text{Text: "a"}),
|
||
|
NewNode(KindSuper, nil),
|
||
|
NewNode(KindText, &Text{Text: "c"}),
|
||
|
),
|
||
|
},
|
||
|
{
|
||
|
//pattern: "a?c",
|
||
|
tokens: []syntax.Token{
|
||
|
syntax.Token{syntax.Text, "a"},
|
||
|
syntax.Token{syntax.Single, "?"},
|
||
|
syntax.Token{syntax.Text, "c"},
|
||
|
syntax.Token{syntax.EOF, ""},
|
||
|
},
|
||
|
tree: NewNode(KindPattern, nil,
|
||
|
NewNode(KindText, &Text{Text: "a"}),
|
||
|
NewNode(KindSingle, nil),
|
||
|
NewNode(KindText, &Text{Text: "c"}),
|
||
|
),
|
||
|
},
|
||
|
{
|
||
|
//pattern: "[!a-z]",
|
||
|
tokens: []syntax.Token{
|
||
|
syntax.Token{syntax.RangeOpen, "["},
|
||
|
syntax.Token{syntax.Not, "!"},
|
||
|
syntax.Token{syntax.RangeLo, "a"},
|
||
|
syntax.Token{syntax.RangeBetween, "-"},
|
||
|
syntax.Token{syntax.RangeHi, "z"},
|
||
|
syntax.Token{syntax.RangeClose, "]"},
|
||
|
syntax.Token{syntax.EOF, ""},
|
||
|
},
|
||
|
tree: NewNode(KindPattern, nil,
|
||
|
NewNode(KindRange, &Range{Lo: 'a', Hi: 'z', Not: true}),
|
||
|
),
|
||
|
},
|
||
|
{
|
||
|
//pattern: "[az]",
|
||
|
tokens: []syntax.Token{
|
||
|
syntax.Token{syntax.RangeOpen, "["},
|
||
|
syntax.Token{syntax.Text, "az"},
|
||
|
syntax.Token{syntax.RangeClose, "]"},
|
||
|
syntax.Token{syntax.EOF, ""},
|
||
|
},
|
||
|
tree: NewNode(KindPattern, nil,
|
||
|
NewNode(KindList, &List{Chars: "az"}),
|
||
|
),
|
||
|
},
|
||
|
{
|
||
|
//pattern: "{a,z}",
|
||
|
tokens: []syntax.Token{
|
||
|
syntax.Token{syntax.TermsOpen, "{"},
|
||
|
syntax.Token{syntax.Text, "a"},
|
||
|
syntax.Token{syntax.Separator, ","},
|
||
|
syntax.Token{syntax.Text, "z"},
|
||
|
syntax.Token{syntax.TermsClose, "}"},
|
||
|
syntax.Token{syntax.EOF, ""},
|
||
|
},
|
||
|
tree: NewNode(KindPattern, nil,
|
||
|
NewNode(KindAnyOf, nil,
|
||
|
NewNode(KindPattern, nil,
|
||
|
NewNode(KindText, &Text{Text: "a"}),
|
||
|
),
|
||
|
NewNode(KindPattern, nil,
|
||
|
NewNode(KindText, &Text{Text: "z"}),
|
||
|
),
|
||
|
),
|
||
|
),
|
||
|
},
|
||
|
{
|
||
|
//pattern: "/{z,ab}*",
|
||
|
tokens: []syntax.Token{
|
||
|
syntax.Token{syntax.Text, "/"},
|
||
|
syntax.Token{syntax.TermsOpen, "{"},
|
||
|
syntax.Token{syntax.Text, "z"},
|
||
|
syntax.Token{syntax.Separator, ","},
|
||
|
syntax.Token{syntax.Text, "ab"},
|
||
|
syntax.Token{syntax.TermsClose, "}"},
|
||
|
syntax.Token{syntax.Any, "*"},
|
||
|
syntax.Token{syntax.EOF, ""},
|
||
|
},
|
||
|
tree: NewNode(KindPattern, nil,
|
||
|
NewNode(KindText, &Text{Text: "/"}),
|
||
|
NewNode(KindAnyOf, nil,
|
||
|
NewNode(KindPattern, nil,
|
||
|
NewNode(KindText, &Text{Text: "z"}),
|
||
|
),
|
||
|
NewNode(KindPattern, nil,
|
||
|
NewNode(KindText, &Text{Text: "ab"}),
|
||
|
),
|
||
|
),
|
||
|
NewNode(KindAny, nil),
|
||
|
),
|
||
|
},
|
||
|
{
|
||
|
//pattern: "{a,{x,y},?,[a-z],[!qwe]}",
|
||
|
tokens: []syntax.Token{
|
||
|
syntax.Token{syntax.TermsOpen, "{"},
|
||
|
syntax.Token{syntax.Text, "a"},
|
||
|
syntax.Token{syntax.Separator, ","},
|
||
|
syntax.Token{syntax.TermsOpen, "{"},
|
||
|
syntax.Token{syntax.Text, "x"},
|
||
|
syntax.Token{syntax.Separator, ","},
|
||
|
syntax.Token{syntax.Text, "y"},
|
||
|
syntax.Token{syntax.TermsClose, "}"},
|
||
|
syntax.Token{syntax.Separator, ","},
|
||
|
syntax.Token{syntax.Single, "?"},
|
||
|
syntax.Token{syntax.Separator, ","},
|
||
|
syntax.Token{syntax.RangeOpen, "["},
|
||
|
syntax.Token{syntax.RangeLo, "a"},
|
||
|
syntax.Token{syntax.RangeBetween, "-"},
|
||
|
syntax.Token{syntax.RangeHi, "z"},
|
||
|
syntax.Token{syntax.RangeClose, "]"},
|
||
|
syntax.Token{syntax.Separator, ","},
|
||
|
syntax.Token{syntax.RangeOpen, "["},
|
||
|
syntax.Token{syntax.Not, "!"},
|
||
|
syntax.Token{syntax.Text, "qwe"},
|
||
|
syntax.Token{syntax.RangeClose, "]"},
|
||
|
syntax.Token{syntax.TermsClose, "}"},
|
||
|
syntax.Token{syntax.EOF, ""},
|
||
|
},
|
||
|
tree: NewNode(KindPattern, nil,
|
||
|
NewNode(KindAnyOf, nil,
|
||
|
NewNode(KindPattern, nil,
|
||
|
NewNode(KindText, &Text{Text: "a"}),
|
||
|
),
|
||
|
NewNode(KindPattern, nil,
|
||
|
NewNode(KindAnyOf, nil,
|
||
|
NewNode(KindPattern, nil,
|
||
|
NewNode(KindText, &Text{Text: "x"}),
|
||
|
),
|
||
|
NewNode(KindPattern, nil,
|
||
|
NewNode(KindText, &Text{Text: "y"}),
|
||
|
),
|
||
|
),
|
||
|
),
|
||
|
NewNode(KindPattern, nil,
|
||
|
NewNode(KindSingle, nil),
|
||
|
),
|
||
|
NewNode(KindPattern, nil,
|
||
|
NewNode(KindRange, &Range{Lo: 'a', Hi: 'z', Not: false}),
|
||
|
),
|
||
|
NewNode(KindPattern, nil,
|
||
|
NewNode(KindList, &List{Chars: "qwe", Not: true}),
|
||
|
),
|
||
|
),
|
||
|
),
|
||
|
},
|
||
|
} {
|
||
|
lexer := &stubLexer{tokens: test.tokens}
|
||
|
result, err := Parse(lexer)
|
||
|
if err != nil {
|
||
|
t.Errorf("[%d] unexpected error: %s", id, err)
|
||
|
}
|
||
|
if !reflect.DeepEqual(test.tree, result) {
|
||
|
t.Errorf("[%d] Parse():\nact:\t%s\nexp:\t%s\n", id, result, test.tree)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type kv struct {
|
||
|
kind Kind
|
||
|
value interface{}
|
||
|
}
|
||
|
|
||
|
type visitor struct {
|
||
|
visited []kv
|
||
|
}
|
||
|
|
||
|
func (v *visitor) Visit(n Node) Visitor {
|
||
|
v.visited = append(v.visited, kv{n.Kind(), n.Value()})
|
||
|
return v
|
||
|
}
|
||
|
|
||
|
func TestWalkTree(t *testing.T) {
|
||
|
|
||
|
for i, test := range []struct {
|
||
|
tree *Node
|
||
|
visited []kv
|
||
|
}{
|
||
|
{
|
||
|
tree: NewNode(KindPattern, nil,
|
||
|
NewNode(KindSingle, nil),
|
||
|
),
|
||
|
visited: []kv{
|
||
|
kv{KindPattern, nil},
|
||
|
kv{KindSingle, nil},
|
||
|
},
|
||
|
},
|
||
|
} {
|
||
|
v := &visitor{}
|
||
|
Walk(v, test.tree)
|
||
|
|
||
|
if !reflect.DeepEqual(test.visited, v.visited) {
|
||
|
t.Errorf("[%d] unexpected result of Walk():\nvisited:\t%v\nwant:\t\t%v", i, v.visited, test.visited)
|
||
|
}
|
||
|
}
|
||
|
}
|