Skip to content
This repository was archived by the owner on Sep 11, 2020. It is now read-only.

Commit d0cf207

Browse files
anthammcuadros
authored andcommitted
Add revision implementation (#139)
1 parent 41e5a1f commit d0cf207

File tree

8 files changed

+1546
-0
lines changed

8 files changed

+1546
-0
lines changed

internal/revision/parser.go

+622
Large diffs are not rendered by default.

internal/revision/parser_test.go

+395
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,395 @@
1+
package revision
2+
3+
import (
4+
"bytes"
5+
"regexp"
6+
"time"
7+
8+
. "gopkg.in/check.v1"
9+
)
10+
11+
type ParserSuite struct{}
12+
13+
var _ = Suite(&ParserSuite{})
14+
15+
func (s *ParserSuite) TestErrInvalidRevision(c *C) {
16+
e := ErrInvalidRevision{"test"}
17+
18+
c.Assert(e.Error(), Equals, "Revision invalid : test")
19+
}
20+
21+
func (s *ParserSuite) TestNewParserFromString(c *C) {
22+
p := NewParserFromString("test")
23+
24+
c.Assert(p, FitsTypeOf, &Parser{})
25+
}
26+
27+
func (s *ParserSuite) TestScan(c *C) {
28+
parser := NewParser(bytes.NewBufferString("Hello world !"))
29+
30+
expected := []struct {
31+
t token
32+
s string
33+
}{
34+
{
35+
word,
36+
"Hello",
37+
},
38+
{
39+
space,
40+
" ",
41+
},
42+
{
43+
word,
44+
"world",
45+
},
46+
{
47+
space,
48+
" ",
49+
},
50+
{
51+
emark,
52+
"!",
53+
},
54+
}
55+
56+
for i := 0; ; {
57+
tok, str, err := parser.scan()
58+
59+
if tok == eof {
60+
return
61+
}
62+
63+
c.Assert(err, Equals, nil)
64+
c.Assert(str, Equals, expected[i].s)
65+
c.Assert(tok, Equals, expected[i].t)
66+
67+
i++
68+
}
69+
}
70+
71+
func (s *ParserSuite) TestUnscan(c *C) {
72+
parser := NewParser(bytes.NewBufferString("Hello world !"))
73+
74+
tok, str, err := parser.scan()
75+
76+
c.Assert(err, Equals, nil)
77+
c.Assert(str, Equals, "Hello")
78+
c.Assert(tok, Equals, word)
79+
80+
parser.unscan()
81+
82+
tok, str, err = parser.scan()
83+
84+
c.Assert(err, Equals, nil)
85+
c.Assert(str, Equals, "Hello")
86+
c.Assert(tok, Equals, word)
87+
}
88+
89+
func (s *ParserSuite) TestParseWithValidExpression(c *C) {
90+
tim, _ := time.Parse("2006-01-02T15:04:05Z", "2016-12-16T21:42:47Z")
91+
92+
datas := map[string]Revisioner{
93+
"@": []Revisioner{Ref("HEAD")},
94+
"@~3": []Revisioner{
95+
Ref("HEAD"),
96+
TildePath{3},
97+
},
98+
"@{2016-12-16T21:42:47Z}": []Revisioner{AtDate{tim}},
99+
"@{1}": []Revisioner{AtReflog{1}},
100+
"@{-1}": []Revisioner{AtCheckout{1}},
101+
"master@{upstream}": []Revisioner{
102+
Ref("master"),
103+
AtUpstream{},
104+
},
105+
"@{upstream}": []Revisioner{
106+
AtUpstream{},
107+
},
108+
"@{u}": []Revisioner{
109+
AtUpstream{},
110+
},
111+
"master@{push}": []Revisioner{
112+
Ref("master"),
113+
AtPush{},
114+
},
115+
"master@{2016-12-16T21:42:47Z}": []Revisioner{
116+
Ref("master"),
117+
AtDate{tim},
118+
},
119+
"HEAD^": []Revisioner{
120+
Ref("HEAD"),
121+
CaretPath{1},
122+
},
123+
"master~3": []Revisioner{
124+
Ref("master"),
125+
TildePath{3},
126+
},
127+
"v0.99.8^{commit}": []Revisioner{
128+
Ref("v0.99.8"),
129+
CaretType{"commit"},
130+
},
131+
"v0.99.8^{}": []Revisioner{
132+
Ref("v0.99.8"),
133+
CaretType{"tag"},
134+
},
135+
"HEAD^{/fix nasty bug}": []Revisioner{
136+
Ref("HEAD"),
137+
CaretReg{regexp.MustCompile("fix nasty bug"), false},
138+
},
139+
":/fix nasty bug": []Revisioner{
140+
ColonReg{regexp.MustCompile("fix nasty bug"), false},
141+
},
142+
"HEAD:README": []Revisioner{
143+
Ref("HEAD"),
144+
ColonPath{"README"},
145+
},
146+
":README": []Revisioner{
147+
ColonPath{"README"},
148+
},
149+
"master:./README": []Revisioner{
150+
Ref("master"),
151+
ColonPath{"./README"},
152+
},
153+
"master^1~:./README": []Revisioner{
154+
Ref("master"),
155+
CaretPath{1},
156+
TildePath{1},
157+
ColonPath{"./README"},
158+
},
159+
":0:README": []Revisioner{
160+
ColonStagePath{"README", 0},
161+
},
162+
":3:README": []Revisioner{
163+
ColonStagePath{"README", 3},
164+
},
165+
"master~1^{/update}~5~^^1": []Revisioner{
166+
Ref("master"),
167+
TildePath{1},
168+
CaretReg{regexp.MustCompile("update"), false},
169+
TildePath{5},
170+
TildePath{1},
171+
CaretPath{1},
172+
CaretPath{1},
173+
},
174+
}
175+
176+
for d, expected := range datas {
177+
parser := NewParser(bytes.NewBufferString(d))
178+
179+
result, err := parser.Parse()
180+
181+
c.Assert(err, Equals, nil)
182+
c.Assert(result, DeepEquals, expected)
183+
}
184+
}
185+
186+
func (s *ParserSuite) TestParseWithUnValidExpression(c *C) {
187+
datas := map[string]error{
188+
"..": &ErrInvalidRevision{`must not start with "."`},
189+
"master^1master": &ErrInvalidRevision{`reference must be defined once at the beginning`},
190+
"master^1@{2016-12-16T21:42:47Z}": &ErrInvalidRevision{`"@" statement is not valid, could be : <refname>@{<ISO-8601 date>}, @{<ISO-8601 date>}`},
191+
"master^1@{1}": &ErrInvalidRevision{`"@" statement is not valid, could be : <refname>@{<n>}, @{<n>}`},
192+
"master@{-1}": &ErrInvalidRevision{`"@" statement is not valid, could be : @{-<n>}`},
193+
"master^1@{upstream}": &ErrInvalidRevision{`"@" statement is not valid, could be : <refname>@{upstream}, @{upstream}, <refname>@{u}, @{u}`},
194+
"master^1@{u}": &ErrInvalidRevision{`"@" statement is not valid, could be : <refname>@{upstream}, @{upstream}, <refname>@{u}, @{u}`},
195+
"master^1@{push}": &ErrInvalidRevision{`"@" statement is not valid, could be : <refname>@{push}, @{push}`},
196+
"^1": &ErrInvalidRevision{`"~" or "^" statement must have a reference defined at the beginning`},
197+
"^{/test}": &ErrInvalidRevision{`"~" or "^" statement must have a reference defined at the beginning`},
198+
"~1": &ErrInvalidRevision{`"~" or "^" statement must have a reference defined at the beginning`},
199+
"master:/test": &ErrInvalidRevision{`":" statement is not valid, could be : :/<regexp>`},
200+
"master:0:README": &ErrInvalidRevision{`":" statement is not valid, could be : :<n>:<path>`},
201+
}
202+
203+
for s, e := range datas {
204+
parser := NewParser(bytes.NewBufferString(s))
205+
_, err := parser.Parse()
206+
c.Assert(err, DeepEquals, e)
207+
}
208+
}
209+
210+
func (s *ParserSuite) TestParseAtWithValidExpression(c *C) {
211+
tim, _ := time.Parse("2006-01-02T15:04:05Z", "2016-12-16T21:42:47Z")
212+
213+
datas := map[string]Revisioner{
214+
"": Ref("HEAD"),
215+
"{1}": AtReflog{1},
216+
"{-1}": AtCheckout{1},
217+
"{push}": AtPush{},
218+
"{upstream}": AtUpstream{},
219+
"{u}": AtUpstream{},
220+
"{2016-12-16T21:42:47Z}": AtDate{tim},
221+
}
222+
223+
for d, expected := range datas {
224+
parser := NewParser(bytes.NewBufferString(d))
225+
226+
result, err := parser.parseAt()
227+
228+
c.Assert(err, Equals, nil)
229+
c.Assert(result, DeepEquals, expected)
230+
}
231+
}
232+
233+
func (s *ParserSuite) TestParseAtWithUnValidExpression(c *C) {
234+
datas := map[string]error{
235+
"{test}": &ErrInvalidRevision{`wrong date "test" must fit ISO-8601 format : 2006-01-02T15:04:05Z`},
236+
"{-1": &ErrInvalidRevision{`missing "}" in @{-n} structure`},
237+
}
238+
239+
for s, e := range datas {
240+
parser := NewParser(bytes.NewBufferString(s))
241+
242+
_, err := parser.parseAt()
243+
244+
c.Assert(err, DeepEquals, e)
245+
}
246+
}
247+
248+
func (s *ParserSuite) TestParseCaretWithValidExpression(c *C) {
249+
datas := map[string]Revisioner{
250+
"": CaretPath{1},
251+
"2": CaretPath{2},
252+
"{}": CaretType{"tag"},
253+
"{commit}": CaretType{"commit"},
254+
"{tree}": CaretType{"tree"},
255+
"{blob}": CaretType{"blob"},
256+
"{tag}": CaretType{"tag"},
257+
"{object}": CaretType{"object"},
258+
"{/hello world !}": CaretReg{regexp.MustCompile("hello world !"), false},
259+
"{/!-hello world !}": CaretReg{regexp.MustCompile("hello world !"), true},
260+
"{/!! hello world !}": CaretReg{regexp.MustCompile("! hello world !"), false},
261+
}
262+
263+
for d, expected := range datas {
264+
parser := NewParser(bytes.NewBufferString(d))
265+
266+
result, err := parser.parseCaret()
267+
268+
c.Assert(err, Equals, nil)
269+
c.Assert(result, DeepEquals, expected)
270+
}
271+
}
272+
273+
func (s *ParserSuite) TestParseCaretWithUnValidExpression(c *C) {
274+
datas := map[string]error{
275+
"3": &ErrInvalidRevision{`"3" found must be 0, 1 or 2 after "^"`},
276+
"{test}": &ErrInvalidRevision{`"test" is not a valid revision suffix brace component`},
277+
"{/!test}": &ErrInvalidRevision{`revision suffix brace component sequences starting with "/!" others than those defined are reserved`},
278+
"{/test**}": &ErrInvalidRevision{"revision suffix brace component, error parsing regexp: invalid nested repetition operator: `**`"},
279+
}
280+
281+
for s, e := range datas {
282+
parser := NewParser(bytes.NewBufferString(s))
283+
284+
_, err := parser.parseCaret()
285+
286+
c.Assert(err, DeepEquals, e)
287+
}
288+
}
289+
290+
func (s *ParserSuite) TestParseTildeWithValidExpression(c *C) {
291+
datas := map[string]Revisioner{
292+
"3": TildePath{3},
293+
"1": TildePath{1},
294+
"": TildePath{1},
295+
}
296+
297+
for d, expected := range datas {
298+
parser := NewParser(bytes.NewBufferString(d))
299+
300+
result, err := parser.parseTilde()
301+
302+
c.Assert(err, Equals, nil)
303+
c.Assert(result, DeepEquals, expected)
304+
}
305+
}
306+
307+
func (s *ParserSuite) TestParseColonWithValidExpression(c *C) {
308+
datas := map[string]Revisioner{
309+
"/hello world !": ColonReg{regexp.MustCompile("hello world !"), false},
310+
"/!-hello world !": ColonReg{regexp.MustCompile("hello world !"), true},
311+
"/!! hello world !": ColonReg{regexp.MustCompile("! hello world !"), false},
312+
"../parser.go": ColonPath{"../parser.go"},
313+
"./parser.go": ColonPath{"./parser.go"},
314+
"parser.go": ColonPath{"parser.go"},
315+
"0:parser.go": ColonStagePath{"parser.go", 0},
316+
"1:parser.go": ColonStagePath{"parser.go", 1},
317+
"2:parser.go": ColonStagePath{"parser.go", 2},
318+
"3:parser.go": ColonStagePath{"parser.go", 3},
319+
}
320+
321+
for d, expected := range datas {
322+
parser := NewParser(bytes.NewBufferString(d))
323+
324+
result, err := parser.parseColon()
325+
326+
c.Assert(err, Equals, nil)
327+
c.Assert(result, DeepEquals, expected)
328+
}
329+
}
330+
331+
func (s *ParserSuite) TestParseColonWithUnValidExpression(c *C) {
332+
datas := map[string]error{
333+
"/!test": &ErrInvalidRevision{`revision suffix brace component sequences starting with "/!" others than those defined are reserved`},
334+
"/*": &ErrInvalidRevision{"revision suffix brace component, error parsing regexp: missing argument to repetition operator: `*`"},
335+
}
336+
337+
for s, e := range datas {
338+
parser := NewParser(bytes.NewBufferString(s))
339+
340+
_, err := parser.parseColon()
341+
342+
c.Assert(err, DeepEquals, e)
343+
}
344+
}
345+
346+
func (s *ParserSuite) TestParseRefWithValidName(c *C) {
347+
datas := []string{
348+
"lock",
349+
"master",
350+
"v1.0.0",
351+
"refs/stash",
352+
"refs/tags/v1.0.0",
353+
"refs/heads/master",
354+
"refs/remotes/test",
355+
"refs/remotes/origin/HEAD",
356+
"refs/remotes/origin/master",
357+
}
358+
359+
for _, d := range datas {
360+
parser := NewParser(bytes.NewBufferString(d))
361+
362+
result, err := parser.parseRef()
363+
364+
c.Assert(err, Equals, nil)
365+
c.Assert(result, Equals, Ref(d))
366+
}
367+
}
368+
369+
func (s *ParserSuite) TestParseRefWithUnvalidName(c *C) {
370+
datas := map[string]error{
371+
".master": &ErrInvalidRevision{`must not start with "."`},
372+
"/master": &ErrInvalidRevision{`must not start with "/"`},
373+
"master/": &ErrInvalidRevision{`must not end with "/"`},
374+
"master.": &ErrInvalidRevision{`must not end with "."`},
375+
"refs/remotes/.origin/HEAD": &ErrInvalidRevision{`must not contains "/."`},
376+
"test..test": &ErrInvalidRevision{`must not contains ".."`},
377+
"test..": &ErrInvalidRevision{`must not contains ".."`},
378+
"test test": &ErrInvalidRevision{`must not contains " "`},
379+
"test*test": &ErrInvalidRevision{`must not contains "*"`},
380+
"test?test": &ErrInvalidRevision{`must not contains "?"`},
381+
"test\\test": &ErrInvalidRevision{`must not contains "\"`},
382+
"test[test": &ErrInvalidRevision{`must not contains "["`},
383+
"te//st": &ErrInvalidRevision{`must not contains consecutively "/"`},
384+
"refs/remotes/test.lock/HEAD": &ErrInvalidRevision{`cannot end with .lock`},
385+
"test.lock": &ErrInvalidRevision{`cannot end with .lock`},
386+
}
387+
388+
for s, e := range datas {
389+
parser := NewParser(bytes.NewBufferString(s))
390+
391+
_, err := parser.parseRef()
392+
393+
c.Assert(err, DeepEquals, e)
394+
}
395+
}

0 commit comments

Comments
 (0)