aboutsummaryrefslogtreecommitdiffstats
path: root/internal/revision/parser_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/revision/parser_test.go')
-rw-r--r--internal/revision/parser_test.go395
1 files changed, 395 insertions, 0 deletions
diff --git a/internal/revision/parser_test.go b/internal/revision/parser_test.go
new file mode 100644
index 0000000..a58f0ad
--- /dev/null
+++ b/internal/revision/parser_test.go
@@ -0,0 +1,395 @@
+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)
+ }
+}