mirror of
https://github.com/Luzifer/ansible-role-version.git
synced 2024-12-23 19:11:20 +00:00
396 lines
11 KiB
Go
396 lines
11 KiB
Go
|
package revision
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"regexp"
|
||
|
"time"
|
||
|
|
||
|
. "gopkg.in/check.v1"
|
||
|
)
|
||
|
|
||
|
type ParserSuite struct{}
|
||
|
|
||
|
var _ = Suite(&ParserSuite{})
|
||
|
|
||
|
func (s *ParserSuite) TestErrInvalidRevision(c *C) {
|
||
|
e := ErrInvalidRevision{"test"}
|
||
|
|
||
|
c.Assert(e.Error(), Equals, "Revision invalid : test")
|
||
|
}
|
||
|
|
||
|
func (s *ParserSuite) TestNewParserFromString(c *C) {
|
||
|
p := NewParserFromString("test")
|
||
|
|
||
|
c.Assert(p, FitsTypeOf, &Parser{})
|
||
|
}
|
||
|
|
||
|
func (s *ParserSuite) TestScan(c *C) {
|
||
|
parser := NewParser(bytes.NewBufferString("Hello world !"))
|
||
|
|
||
|
expected := []struct {
|
||
|
t token
|
||
|
s string
|
||
|
}{
|
||
|
{
|
||
|
word,
|
||
|
"Hello",
|
||
|
},
|
||
|
{
|
||
|
space,
|
||
|
" ",
|
||
|
},
|
||
|
{
|
||
|
word,
|
||
|
"world",
|
||
|
},
|
||
|
{
|
||
|
space,
|
||
|
" ",
|
||
|
},
|
||
|
{
|
||
|
emark,
|
||
|
"!",
|
||
|
},
|
||
|
}
|
||
|
|
||
|
for i := 0; ; {
|
||
|
tok, str, err := parser.scan()
|
||
|
|
||
|
if tok == eof {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
c.Assert(err, Equals, nil)
|
||
|
c.Assert(str, Equals, expected[i].s)
|
||
|
c.Assert(tok, Equals, expected[i].t)
|
||
|
|
||
|
i++
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (s *ParserSuite) TestUnscan(c *C) {
|
||
|
parser := NewParser(bytes.NewBufferString("Hello world !"))
|
||
|
|
||
|
tok, str, err := parser.scan()
|
||
|
|
||
|
c.Assert(err, Equals, nil)
|
||
|
c.Assert(str, Equals, "Hello")
|
||
|
c.Assert(tok, Equals, word)
|
||
|
|
||
|
parser.unscan()
|
||
|
|
||
|
tok, str, err = parser.scan()
|
||
|
|
||
|
c.Assert(err, Equals, nil)
|
||
|
c.Assert(str, Equals, "Hello")
|
||
|
c.Assert(tok, Equals, word)
|
||
|
}
|
||
|
|
||
|
func (s *ParserSuite) TestParseWithValidExpression(c *C) {
|
||
|
tim, _ := time.Parse("2006-01-02T15:04:05Z", "2016-12-16T21:42:47Z")
|
||
|
|
||
|
datas := map[string]Revisioner{
|
||
|
"@": []Revisioner{Ref("HEAD")},
|
||
|
"@~3": []Revisioner{
|
||
|
Ref("HEAD"),
|
||
|
TildePath{3},
|
||
|
},
|
||
|
"@{2016-12-16T21:42:47Z}": []Revisioner{AtDate{tim}},
|
||
|
"@{1}": []Revisioner{AtReflog{1}},
|
||
|
"@{-1}": []Revisioner{AtCheckout{1}},
|
||
|
"master@{upstream}": []Revisioner{
|
||
|
Ref("master"),
|
||
|
AtUpstream{},
|
||
|
},
|
||
|
"@{upstream}": []Revisioner{
|
||
|
AtUpstream{},
|
||
|
},
|
||
|
"@{u}": []Revisioner{
|
||
|
AtUpstream{},
|
||
|
},
|
||
|
"master@{push}": []Revisioner{
|
||
|
Ref("master"),
|
||
|
AtPush{},
|
||
|
},
|
||
|
"master@{2016-12-16T21:42:47Z}": []Revisioner{
|
||
|
Ref("master"),
|
||
|
AtDate{tim},
|
||
|
},
|
||
|
"HEAD^": []Revisioner{
|
||
|
Ref("HEAD"),
|
||
|
CaretPath{1},
|
||
|
},
|
||
|
"master~3": []Revisioner{
|
||
|
Ref("master"),
|
||
|
TildePath{3},
|
||
|
},
|
||
|
"v0.99.8^{commit}": []Revisioner{
|
||
|
Ref("v0.99.8"),
|
||
|
CaretType{"commit"},
|
||
|
},
|
||
|
"v0.99.8^{}": []Revisioner{
|
||
|
Ref("v0.99.8"),
|
||
|
CaretType{"tag"},
|
||
|
},
|
||
|
"HEAD^{/fix nasty bug}": []Revisioner{
|
||
|
Ref("HEAD"),
|
||
|
CaretReg{regexp.MustCompile("fix nasty bug"), false},
|
||
|
},
|
||
|
":/fix nasty bug": []Revisioner{
|
||
|
ColonReg{regexp.MustCompile("fix nasty bug"), false},
|
||
|
},
|
||
|
"HEAD:README": []Revisioner{
|
||
|
Ref("HEAD"),
|
||
|
ColonPath{"README"},
|
||
|
},
|
||
|
":README": []Revisioner{
|
||
|
ColonPath{"README"},
|
||
|
},
|
||
|
"master:./README": []Revisioner{
|
||
|
Ref("master"),
|
||
|
ColonPath{"./README"},
|
||
|
},
|
||
|
"master^1~:./README": []Revisioner{
|
||
|
Ref("master"),
|
||
|
CaretPath{1},
|
||
|
TildePath{1},
|
||
|
ColonPath{"./README"},
|
||
|
},
|
||
|
":0:README": []Revisioner{
|
||
|
ColonStagePath{"README", 0},
|
||
|
},
|
||
|
":3:README": []Revisioner{
|
||
|
ColonStagePath{"README", 3},
|
||
|
},
|
||
|
"master~1^{/update}~5~^^1": []Revisioner{
|
||
|
Ref("master"),
|
||
|
TildePath{1},
|
||
|
CaretReg{regexp.MustCompile("update"), false},
|
||
|
TildePath{5},
|
||
|
TildePath{1},
|
||
|
CaretPath{1},
|
||
|
CaretPath{1},
|
||
|
},
|
||
|
}
|
||
|
|
||
|
for d, expected := range datas {
|
||
|
parser := NewParser(bytes.NewBufferString(d))
|
||
|
|
||
|
result, err := parser.Parse()
|
||
|
|
||
|
c.Assert(err, Equals, nil)
|
||
|
c.Assert(result, DeepEquals, expected)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (s *ParserSuite) TestParseWithUnValidExpression(c *C) {
|
||
|
datas := map[string]error{
|
||
|
"..": &ErrInvalidRevision{`must not start with "."`},
|
||
|
"master^1master": &ErrInvalidRevision{`reference must be defined once at the beginning`},
|
||
|
"master^1@{2016-12-16T21:42:47Z}": &ErrInvalidRevision{`"@" statement is not valid, could be : <refname>@{<ISO-8601 date>}, @{<ISO-8601 date>}`},
|
||
|
"master^1@{1}": &ErrInvalidRevision{`"@" statement is not valid, could be : <refname>@{<n>}, @{<n>}`},
|
||
|
"master@{-1}": &ErrInvalidRevision{`"@" statement is not valid, could be : @{-<n>}`},
|
||
|
"master^1@{upstream}": &ErrInvalidRevision{`"@" statement is not valid, could be : <refname>@{upstream}, @{upstream}, <refname>@{u}, @{u}`},
|
||
|
"master^1@{u}": &ErrInvalidRevision{`"@" statement is not valid, could be : <refname>@{upstream}, @{upstream}, <refname>@{u}, @{u}`},
|
||
|
"master^1@{push}": &ErrInvalidRevision{`"@" statement is not valid, could be : <refname>@{push}, @{push}`},
|
||
|
"^1": &ErrInvalidRevision{`"~" or "^" statement must have a reference defined at the beginning`},
|
||
|
"^{/test}": &ErrInvalidRevision{`"~" or "^" statement must have a reference defined at the beginning`},
|
||
|
"~1": &ErrInvalidRevision{`"~" or "^" statement must have a reference defined at the beginning`},
|
||
|
"master:/test": &ErrInvalidRevision{`":" statement is not valid, could be : :/<regexp>`},
|
||
|
"master:0:README": &ErrInvalidRevision{`":" statement is not valid, could be : :<n>:<path>`},
|
||
|
}
|
||
|
|
||
|
for s, e := range datas {
|
||
|
parser := NewParser(bytes.NewBufferString(s))
|
||
|
_, err := parser.Parse()
|
||
|
c.Assert(err, DeepEquals, e)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (s *ParserSuite) TestParseAtWithValidExpression(c *C) {
|
||
|
tim, _ := time.Parse("2006-01-02T15:04:05Z", "2016-12-16T21:42:47Z")
|
||
|
|
||
|
datas := map[string]Revisioner{
|
||
|
"": Ref("HEAD"),
|
||
|
"{1}": AtReflog{1},
|
||
|
"{-1}": AtCheckout{1},
|
||
|
"{push}": AtPush{},
|
||
|
"{upstream}": AtUpstream{},
|
||
|
"{u}": AtUpstream{},
|
||
|
"{2016-12-16T21:42:47Z}": AtDate{tim},
|
||
|
}
|
||
|
|
||
|
for d, expected := range datas {
|
||
|
parser := NewParser(bytes.NewBufferString(d))
|
||
|
|
||
|
result, err := parser.parseAt()
|
||
|
|
||
|
c.Assert(err, Equals, nil)
|
||
|
c.Assert(result, DeepEquals, expected)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (s *ParserSuite) TestParseAtWithUnValidExpression(c *C) {
|
||
|
datas := map[string]error{
|
||
|
"{test}": &ErrInvalidRevision{`wrong date "test" must fit ISO-8601 format : 2006-01-02T15:04:05Z`},
|
||
|
"{-1": &ErrInvalidRevision{`missing "}" in @{-n} structure`},
|
||
|
}
|
||
|
|
||
|
for s, e := range datas {
|
||
|
parser := NewParser(bytes.NewBufferString(s))
|
||
|
|
||
|
_, err := parser.parseAt()
|
||
|
|
||
|
c.Assert(err, DeepEquals, e)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (s *ParserSuite) TestParseCaretWithValidExpression(c *C) {
|
||
|
datas := map[string]Revisioner{
|
||
|
"": CaretPath{1},
|
||
|
"2": CaretPath{2},
|
||
|
"{}": CaretType{"tag"},
|
||
|
"{commit}": CaretType{"commit"},
|
||
|
"{tree}": CaretType{"tree"},
|
||
|
"{blob}": CaretType{"blob"},
|
||
|
"{tag}": CaretType{"tag"},
|
||
|
"{object}": CaretType{"object"},
|
||
|
"{/hello world !}": CaretReg{regexp.MustCompile("hello world !"), false},
|
||
|
"{/!-hello world !}": CaretReg{regexp.MustCompile("hello world !"), true},
|
||
|
"{/!! hello world !}": CaretReg{regexp.MustCompile("! hello world !"), false},
|
||
|
}
|
||
|
|
||
|
for d, expected := range datas {
|
||
|
parser := NewParser(bytes.NewBufferString(d))
|
||
|
|
||
|
result, err := parser.parseCaret()
|
||
|
|
||
|
c.Assert(err, Equals, nil)
|
||
|
c.Assert(result, DeepEquals, expected)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (s *ParserSuite) TestParseCaretWithUnValidExpression(c *C) {
|
||
|
datas := map[string]error{
|
||
|
"3": &ErrInvalidRevision{`"3" found must be 0, 1 or 2 after "^"`},
|
||
|
"{test}": &ErrInvalidRevision{`"test" is not a valid revision suffix brace component`},
|
||
|
"{/!test}": &ErrInvalidRevision{`revision suffix brace component sequences starting with "/!" others than those defined are reserved`},
|
||
|
"{/test**}": &ErrInvalidRevision{"revision suffix brace component, error parsing regexp: invalid nested repetition operator: `**`"},
|
||
|
}
|
||
|
|
||
|
for s, e := range datas {
|
||
|
parser := NewParser(bytes.NewBufferString(s))
|
||
|
|
||
|
_, err := parser.parseCaret()
|
||
|
|
||
|
c.Assert(err, DeepEquals, e)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (s *ParserSuite) TestParseTildeWithValidExpression(c *C) {
|
||
|
datas := map[string]Revisioner{
|
||
|
"3": TildePath{3},
|
||
|
"1": TildePath{1},
|
||
|
"": TildePath{1},
|
||
|
}
|
||
|
|
||
|
for d, expected := range datas {
|
||
|
parser := NewParser(bytes.NewBufferString(d))
|
||
|
|
||
|
result, err := parser.parseTilde()
|
||
|
|
||
|
c.Assert(err, Equals, nil)
|
||
|
c.Assert(result, DeepEquals, expected)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (s *ParserSuite) TestParseColonWithValidExpression(c *C) {
|
||
|
datas := map[string]Revisioner{
|
||
|
"/hello world !": ColonReg{regexp.MustCompile("hello world !"), false},
|
||
|
"/!-hello world !": ColonReg{regexp.MustCompile("hello world !"), true},
|
||
|
"/!! hello world !": ColonReg{regexp.MustCompile("! hello world !"), false},
|
||
|
"../parser.go": ColonPath{"../parser.go"},
|
||
|
"./parser.go": ColonPath{"./parser.go"},
|
||
|
"parser.go": ColonPath{"parser.go"},
|
||
|
"0:parser.go": ColonStagePath{"parser.go", 0},
|
||
|
"1:parser.go": ColonStagePath{"parser.go", 1},
|
||
|
"2:parser.go": ColonStagePath{"parser.go", 2},
|
||
|
"3:parser.go": ColonStagePath{"parser.go", 3},
|
||
|
}
|
||
|
|
||
|
for d, expected := range datas {
|
||
|
parser := NewParser(bytes.NewBufferString(d))
|
||
|
|
||
|
result, err := parser.parseColon()
|
||
|
|
||
|
c.Assert(err, Equals, nil)
|
||
|
c.Assert(result, DeepEquals, expected)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (s *ParserSuite) TestParseColonWithUnValidExpression(c *C) {
|
||
|
datas := map[string]error{
|
||
|
"/!test": &ErrInvalidRevision{`revision suffix brace component sequences starting with "/!" others than those defined are reserved`},
|
||
|
"/*": &ErrInvalidRevision{"revision suffix brace component, error parsing regexp: missing argument to repetition operator: `*`"},
|
||
|
}
|
||
|
|
||
|
for s, e := range datas {
|
||
|
parser := NewParser(bytes.NewBufferString(s))
|
||
|
|
||
|
_, err := parser.parseColon()
|
||
|
|
||
|
c.Assert(err, DeepEquals, e)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (s *ParserSuite) TestParseRefWithValidName(c *C) {
|
||
|
datas := []string{
|
||
|
"lock",
|
||
|
"master",
|
||
|
"v1.0.0",
|
||
|
"refs/stash",
|
||
|
"refs/tags/v1.0.0",
|
||
|
"refs/heads/master",
|
||
|
"refs/remotes/test",
|
||
|
"refs/remotes/origin/HEAD",
|
||
|
"refs/remotes/origin/master",
|
||
|
}
|
||
|
|
||
|
for _, d := range datas {
|
||
|
parser := NewParser(bytes.NewBufferString(d))
|
||
|
|
||
|
result, err := parser.parseRef()
|
||
|
|
||
|
c.Assert(err, Equals, nil)
|
||
|
c.Assert(result, Equals, Ref(d))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (s *ParserSuite) TestParseRefWithUnvalidName(c *C) {
|
||
|
datas := map[string]error{
|
||
|
".master": &ErrInvalidRevision{`must not start with "."`},
|
||
|
"/master": &ErrInvalidRevision{`must not start with "/"`},
|
||
|
"master/": &ErrInvalidRevision{`must not end with "/"`},
|
||
|
"master.": &ErrInvalidRevision{`must not end with "."`},
|
||
|
"refs/remotes/.origin/HEAD": &ErrInvalidRevision{`must not contains "/."`},
|
||
|
"test..test": &ErrInvalidRevision{`must not contains ".."`},
|
||
|
"test..": &ErrInvalidRevision{`must not contains ".."`},
|
||
|
"test test": &ErrInvalidRevision{`must not contains " "`},
|
||
|
"test*test": &ErrInvalidRevision{`must not contains "*"`},
|
||
|
"test?test": &ErrInvalidRevision{`must not contains "?"`},
|
||
|
"test\\test": &ErrInvalidRevision{`must not contains "\"`},
|
||
|
"test[test": &ErrInvalidRevision{`must not contains "["`},
|
||
|
"te//st": &ErrInvalidRevision{`must not contains consecutively "/"`},
|
||
|
"refs/remotes/test.lock/HEAD": &ErrInvalidRevision{`cannot end with .lock`},
|
||
|
"test.lock": &ErrInvalidRevision{`cannot end with .lock`},
|
||
|
}
|
||
|
|
||
|
for s, e := range datas {
|
||
|
parser := NewParser(bytes.NewBufferString(s))
|
||
|
|
||
|
_, err := parser.parseRef()
|
||
|
|
||
|
c.Assert(err, DeepEquals, e)
|
||
|
}
|
||
|
}
|