forked from mirror/glob
325 lines
6.6 KiB
Go
325 lines
6.6 KiB
Go
package glob
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"testing"
|
|
)
|
|
|
|
func TestParseString(t *testing.T) {
|
|
for id, test := range []struct {
|
|
items []item
|
|
tree node
|
|
}{
|
|
{
|
|
//pattern: "abc",
|
|
items: []item{
|
|
item{item_text, "abc"},
|
|
item{item_eof, ""},
|
|
},
|
|
tree: &nodePattern{
|
|
nodeImpl: nodeImpl{
|
|
desc: []node{
|
|
&nodeText{text: "abc"},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
//pattern: "a*c",
|
|
items: []item{
|
|
item{item_text, "a"},
|
|
item{item_any, "*"},
|
|
item{item_text, "c"},
|
|
item{item_eof, ""},
|
|
},
|
|
tree: &nodePattern{
|
|
nodeImpl: nodeImpl{
|
|
desc: []node{
|
|
&nodeText{text: "a"},
|
|
&nodeAny{},
|
|
&nodeText{text: "c"},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
//pattern: "a**c",
|
|
items: []item{
|
|
item{item_text, "a"},
|
|
item{item_super, "**"},
|
|
item{item_text, "c"},
|
|
item{item_eof, ""},
|
|
},
|
|
tree: &nodePattern{
|
|
nodeImpl: nodeImpl{
|
|
desc: []node{
|
|
&nodeText{text: "a"},
|
|
&nodeSuper{},
|
|
&nodeText{text: "c"},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
//pattern: "a?c",
|
|
items: []item{
|
|
item{item_text, "a"},
|
|
item{item_single, "?"},
|
|
item{item_text, "c"},
|
|
item{item_eof, ""},
|
|
},
|
|
tree: &nodePattern{
|
|
nodeImpl: nodeImpl{
|
|
desc: []node{
|
|
&nodeText{text: "a"},
|
|
&nodeSingle{},
|
|
&nodeText{text: "c"},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
//pattern: "[!a-z]",
|
|
items: []item{
|
|
item{item_range_open, "["},
|
|
item{item_not, "!"},
|
|
item{item_range_lo, "a"},
|
|
item{item_range_between, "-"},
|
|
item{item_range_hi, "z"},
|
|
item{item_range_close, "]"},
|
|
item{item_eof, ""},
|
|
},
|
|
tree: &nodePattern{
|
|
nodeImpl: nodeImpl{
|
|
desc: []node{
|
|
&nodeRange{lo: 'a', hi: 'z', not: true},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
//pattern: "[az]",
|
|
items: []item{
|
|
item{item_range_open, "["},
|
|
item{item_text, "az"},
|
|
item{item_range_close, "]"},
|
|
item{item_eof, ""},
|
|
},
|
|
tree: &nodePattern{
|
|
nodeImpl: nodeImpl{
|
|
desc: []node{
|
|
&nodeList{chars: "az"},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
//pattern: "{a,z}",
|
|
items: []item{
|
|
item{item_terms_open, "{"},
|
|
item{item_text, "a"},
|
|
item{item_separator, ","},
|
|
item{item_text, "z"},
|
|
item{item_terms_close, "}"},
|
|
item{item_eof, ""},
|
|
},
|
|
tree: &nodePattern{
|
|
nodeImpl: nodeImpl{
|
|
desc: []node{
|
|
&nodeAnyOf{nodeImpl: nodeImpl{desc: []node{
|
|
&nodePattern{
|
|
nodeImpl: nodeImpl{desc: []node{
|
|
&nodeText{text: "a"},
|
|
}},
|
|
},
|
|
&nodePattern{
|
|
nodeImpl: nodeImpl{desc: []node{
|
|
&nodeText{text: "z"},
|
|
}},
|
|
},
|
|
}}},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
//pattern: "/{z,ab}*",
|
|
items: []item{
|
|
item{item_text, "/"},
|
|
item{item_terms_open, "{"},
|
|
item{item_text, "z"},
|
|
item{item_separator, ","},
|
|
item{item_text, "ab"},
|
|
item{item_terms_close, "}"},
|
|
item{item_any, "*"},
|
|
item{item_eof, ""},
|
|
},
|
|
tree: &nodePattern{
|
|
nodeImpl: nodeImpl{
|
|
desc: []node{
|
|
&nodeText{text: "/"},
|
|
&nodeAnyOf{nodeImpl: nodeImpl{desc: []node{
|
|
&nodePattern{
|
|
nodeImpl: nodeImpl{desc: []node{
|
|
&nodeText{text: "z"},
|
|
}},
|
|
},
|
|
&nodePattern{
|
|
nodeImpl: nodeImpl{desc: []node{
|
|
&nodeText{text: "ab"},
|
|
}},
|
|
},
|
|
}}},
|
|
&nodeAny{},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
//pattern: "{a,{x,y},?,[a-z],[!qwe]}",
|
|
items: []item{
|
|
item{item_terms_open, "{"},
|
|
item{item_text, "a"},
|
|
item{item_separator, ","},
|
|
item{item_terms_open, "{"},
|
|
item{item_text, "x"},
|
|
item{item_separator, ","},
|
|
item{item_text, "y"},
|
|
item{item_terms_close, "}"},
|
|
item{item_separator, ","},
|
|
item{item_single, "?"},
|
|
item{item_separator, ","},
|
|
item{item_range_open, "["},
|
|
item{item_range_lo, "a"},
|
|
item{item_range_between, "-"},
|
|
item{item_range_hi, "z"},
|
|
item{item_range_close, "]"},
|
|
item{item_separator, ","},
|
|
item{item_range_open, "["},
|
|
item{item_not, "!"},
|
|
item{item_text, "qwe"},
|
|
item{item_range_close, "]"},
|
|
item{item_terms_close, "}"},
|
|
item{item_eof, ""},
|
|
},
|
|
tree: &nodePattern{
|
|
nodeImpl: nodeImpl{
|
|
desc: []node{
|
|
&nodeAnyOf{nodeImpl: nodeImpl{desc: []node{
|
|
&nodePattern{
|
|
nodeImpl: nodeImpl{desc: []node{
|
|
&nodeText{text: "a"},
|
|
}},
|
|
},
|
|
&nodePattern{
|
|
nodeImpl: nodeImpl{desc: []node{
|
|
&nodeAnyOf{nodeImpl: nodeImpl{desc: []node{
|
|
&nodePattern{
|
|
nodeImpl: nodeImpl{desc: []node{
|
|
&nodeText{text: "x"},
|
|
}},
|
|
},
|
|
&nodePattern{
|
|
nodeImpl: nodeImpl{desc: []node{
|
|
&nodeText{text: "y"},
|
|
}},
|
|
},
|
|
}}},
|
|
}},
|
|
},
|
|
&nodePattern{
|
|
nodeImpl: nodeImpl{desc: []node{
|
|
&nodeSingle{},
|
|
}},
|
|
},
|
|
&nodePattern{
|
|
nodeImpl: nodeImpl{
|
|
desc: []node{
|
|
&nodeRange{lo: 'a', hi: 'z', not: false},
|
|
},
|
|
},
|
|
},
|
|
&nodePattern{
|
|
nodeImpl: nodeImpl{
|
|
desc: []node{
|
|
&nodeList{chars: "qwe", not: true},
|
|
},
|
|
},
|
|
},
|
|
}}},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
} {
|
|
lexer := &stubLexer{Items: test.items}
|
|
pattern, err := parse(lexer)
|
|
|
|
if err != nil {
|
|
t.Errorf("#%d %s", id, err)
|
|
continue
|
|
}
|
|
|
|
if !reflect.DeepEqual(test.tree, pattern) {
|
|
t.Errorf("#%d tries are not equal", id)
|
|
if err = nodeEqual(test.tree, pattern); err != nil {
|
|
t.Errorf("#%d %s", id, err)
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const abstractNodeImpl = "nodeImpl"
|
|
|
|
func nodeEqual(a, b node) error {
|
|
if (a == nil || b == nil) && a != b {
|
|
return fmt.Errorf("nodes are not equal: exp %s, act %s", a, b)
|
|
}
|
|
|
|
aValue, bValue := reflect.Indirect(reflect.ValueOf(a)), reflect.Indirect(reflect.ValueOf(b))
|
|
aType, bType := aValue.Type(), bValue.Type()
|
|
if aType != bType {
|
|
return fmt.Errorf("nodes are not equal: exp %s, act %s", aValue.Type(), bValue.Type())
|
|
}
|
|
|
|
for i := 0; i < aType.NumField(); i++ {
|
|
var eq bool
|
|
|
|
f := aType.Field(i).Name
|
|
if f == abstractNodeImpl {
|
|
continue
|
|
}
|
|
|
|
af, bf := aValue.FieldByName(f), bValue.FieldByName(f)
|
|
|
|
switch af.Kind() {
|
|
case reflect.String:
|
|
eq = af.String() == bf.String()
|
|
case reflect.Bool:
|
|
eq = af.Bool() == bf.Bool()
|
|
default:
|
|
eq = fmt.Sprint(af) == fmt.Sprint(bf)
|
|
}
|
|
|
|
if !eq {
|
|
return fmt.Errorf("nodes<%s> %q fields are not equal: exp %q, act %q", aType, f, af, bf)
|
|
}
|
|
}
|
|
|
|
for i, aDesc := range a.children() {
|
|
if len(b.children())-1 < i {
|
|
return fmt.Errorf("node does not have enough children (got %d children, wanted %d-th token)", len(b.children()), i)
|
|
}
|
|
|
|
bDesc := b.children()[i]
|
|
|
|
if err := nodeEqual(aDesc, bDesc); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|