forked from
tangled.org/core
Mirror of @tangled.org/core. Running on a Raspberry Pi Zero 2
1package git
2
3import (
4 "path/filepath"
5 "testing"
6 "time"
7
8 gogit "github.com/go-git/go-git/v5"
9 "github.com/go-git/go-git/v5/plumbing"
10 "github.com/go-git/go-git/v5/plumbing/object"
11 "github.com/stretchr/testify/assert"
12 "github.com/stretchr/testify/require"
13 "github.com/stretchr/testify/suite"
14)
15
16type TagSuite struct {
17 suite.Suite
18 *RepoSuite
19}
20
21func TestTagSuite(t *testing.T) {
22 t.Parallel()
23 suite.Run(t, new(TagSuite))
24}
25
26func (s *TagSuite) SetupTest() {
27 s.RepoSuite = NewRepoSuite(s.T())
28}
29
30func (s *TagSuite) TearDownTest() {
31 s.RepoSuite.cleanup()
32}
33
34func (s *TagSuite) setupRepoWithTags() {
35 s.init()
36
37 // create commits for tagging
38 commit1 := s.commitFile("file1.txt", "content 1", "Add file1")
39 commit2 := s.commitFile("file2.txt", "content 2", "Add file2")
40 commit3 := s.commitFile("file3.txt", "content 3", "Add file3")
41 commit4 := s.commitFile("file4.txt", "content 4", "Add file4")
42 commit5 := s.commitFile("file5.txt", "content 5", "Add file5")
43
44 // create annotated tags
45 s.createAnnotatedTag(
46 "v1.0.0",
47 commit1,
48 "Tagger One",
49 "tagger1@example.com",
50 "Release version 1.0.0\n\nThis is the first stable release.",
51 s.baseTime.Add(1*time.Hour),
52 )
53
54 s.createAnnotatedTag(
55 "v1.1.0",
56 commit2,
57 "Tagger Two",
58 "tagger2@example.com",
59 "Release version 1.1.0",
60 s.baseTime.Add(2*time.Hour),
61 )
62
63 // create lightweight tags
64 s.createLightweightTag("v2.0.0", commit3)
65 s.createLightweightTag("v2.1.0", commit4)
66
67 // create another annotated tag
68 s.createAnnotatedTag(
69 "v3.0.0",
70 commit5,
71 "Tagger Three",
72 "tagger3@example.com",
73 "Major version 3.0.0\n\nBreaking changes included.",
74 s.baseTime.Add(3*time.Hour),
75 )
76}
77
78func (s *TagSuite) TestTags_All() {
79 s.setupRepoWithTags()
80
81 tags, err := s.repo.Tags(nil)
82 require.NoError(s.T(), err)
83
84 // we created 5 tags total (3 annotated, 2 lightweight)
85 assert.Len(s.T(), tags, 5, "expected 5 tags")
86
87 // verify tags are sorted by creation date (newest first)
88 expectedAnnotated := map[string]bool{
89 "v1.0.0": true,
90 "v1.1.0": true,
91 "v3.0.0": true,
92 }
93
94 expectedLightweight := map[string]bool{
95 "v2.0.0": true,
96 "v2.1.0": true,
97 }
98
99 for _, tag := range tags {
100 if expectedAnnotated[tag.Name] {
101 // annotated tags should have tagger info
102 assert.NotEmpty(s.T(), tag.Tagger.Name, "annotated tag %s should have tagger name", tag.Name)
103 assert.NotEmpty(s.T(), tag.Message, "annotated tag %s should have message", tag.Name)
104 } else if expectedLightweight[tag.Name] {
105 // lightweight tags won't have tagger info or message (they'll have empty values)
106 } else {
107 s.T().Errorf("unexpected tag name: %s", tag.Name)
108 }
109 }
110}
111
112func (s *TagSuite) TestTags_WithLimit() {
113 s.setupRepoWithTags()
114
115 tests := []struct {
116 name string
117 limit int
118 expectedCount int
119 }{
120 {
121 name: "limit 1",
122 limit: 1,
123 expectedCount: 1,
124 },
125 {
126 name: "limit 2",
127 limit: 2,
128 expectedCount: 2,
129 },
130 {
131 name: "limit 3",
132 limit: 3,
133 expectedCount: 3,
134 },
135 {
136 name: "limit 10 (more than available)",
137 limit: 10,
138 expectedCount: 5,
139 },
140 }
141
142 for _, tt := range tests {
143 s.Run(tt.name, func() {
144 tags, err := s.repo.Tags(&TagsOptions{
145 Limit: tt.limit,
146 })
147 require.NoError(s.T(), err)
148 assert.Len(s.T(), tags, tt.expectedCount, "expected %d tags", tt.expectedCount)
149 })
150 }
151}
152
153func (s *TagSuite) TestTags_WithOffset() {
154 s.setupRepoWithTags()
155
156 tests := []struct {
157 name string
158 offset int
159 expectedCount int
160 }{
161 {
162 name: "offset 0",
163 offset: 0,
164 expectedCount: 5,
165 },
166 {
167 name: "offset 1",
168 offset: 1,
169 expectedCount: 4,
170 },
171 {
172 name: "offset 2",
173 offset: 2,
174 expectedCount: 3,
175 },
176 {
177 name: "offset 4",
178 offset: 4,
179 expectedCount: 1,
180 },
181 {
182 name: "offset 5 (all skipped)",
183 offset: 5,
184 expectedCount: 0,
185 },
186 {
187 name: "offset 10 (more than available)",
188 offset: 10,
189 expectedCount: 0,
190 },
191 }
192
193 for _, tt := range tests {
194 s.Run(tt.name, func() {
195 tags, err := s.repo.Tags(&TagsOptions{
196 Offset: tt.offset,
197 })
198 require.NoError(s.T(), err)
199 assert.Len(s.T(), tags, tt.expectedCount, "expected %d tags", tt.expectedCount)
200 })
201 }
202}
203
204func (s *TagSuite) TestTags_WithLimitAndOffset() {
205 s.setupRepoWithTags()
206
207 tests := []struct {
208 name string
209 limit int
210 offset int
211 expectedCount int
212 }{
213 {
214 name: "limit 2, offset 0",
215 limit: 2,
216 offset: 0,
217 expectedCount: 2,
218 },
219 {
220 name: "limit 2, offset 1",
221 limit: 2,
222 offset: 1,
223 expectedCount: 2,
224 },
225 {
226 name: "limit 2, offset 3",
227 limit: 2,
228 offset: 3,
229 expectedCount: 2,
230 },
231 {
232 name: "limit 2, offset 4",
233 limit: 2,
234 offset: 4,
235 expectedCount: 1,
236 },
237 {
238 name: "limit 3, offset 2",
239 limit: 3,
240 offset: 2,
241 expectedCount: 3,
242 },
243 {
244 name: "limit 10, offset 3",
245 limit: 10,
246 offset: 3,
247 expectedCount: 2,
248 },
249 }
250
251 for _, tt := range tests {
252 s.Run(tt.name, func() {
253 tags, err := s.repo.Tags(&TagsOptions{
254 Limit: tt.limit,
255 Offset: tt.offset,
256 })
257 require.NoError(s.T(), err)
258 assert.Len(s.T(), tags, tt.expectedCount, "expected %d tags", tt.expectedCount)
259 })
260 }
261}
262
263func (s *TagSuite) TestTags_EmptyRepo() {
264 repoPath := filepath.Join(s.tempDir, "empty-repo")
265
266 _, err := gogit.PlainInit(repoPath, false)
267 require.NoError(s.T(), err)
268
269 gitRepo, err := PlainOpen(repoPath)
270 require.NoError(s.T(), err)
271
272 tags, err := gitRepo.Tags(nil)
273 require.NoError(s.T(), err)
274
275 if tags != nil {
276 assert.Empty(s.T(), tags, "expected no tags in empty repo")
277 }
278}
279
280func (s *TagSuite) TestTags_Pagination() {
281 s.setupRepoWithTags()
282
283 allTags, err := s.repo.Tags(nil)
284 require.NoError(s.T(), err)
285 assert.Len(s.T(), allTags, 5, "expected 5 tags")
286
287 pageSize := 2
288 var paginatedTags []object.Tag
289
290 for offset := 0; offset < len(allTags); offset += pageSize {
291 tags, err := s.repo.Tags(&TagsOptions{
292 Limit: pageSize,
293 Offset: offset,
294 })
295 require.NoError(s.T(), err)
296 paginatedTags = append(paginatedTags, tags...)
297 }
298
299 assert.Len(s.T(), paginatedTags, len(allTags), "pagination should return all tags")
300
301 for i := range allTags {
302 assert.Equal(s.T(), allTags[i].Name, paginatedTags[i].Name,
303 "tag at index %d differs", i)
304 }
305}
306
307func (s *TagSuite) TestTags_VerifyAnnotatedTagFields() {
308 s.setupRepoWithTags()
309
310 tags, err := s.repo.Tags(nil)
311 require.NoError(s.T(), err)
312
313 var v1Tag *object.Tag
314 for i := range tags {
315 if tags[i].Name == "v1.0.0" {
316 v1Tag = &tags[i]
317 break
318 }
319 }
320
321 require.NotNil(s.T(), v1Tag, "v1.0.0 tag not found")
322
323 assert.Equal(s.T(), "Tagger One", v1Tag.Tagger.Name, "tagger name should match")
324 assert.Equal(s.T(), "tagger1@example.com", v1Tag.Tagger.Email, "tagger email should match")
325
326 assert.Equal(s.T(), "Release version 1.0.0\n\nThis is the first stable release.\n",
327 v1Tag.Message, "tag message should match")
328
329 assert.Equal(s.T(), plumbing.TagObject, v1Tag.TargetType,
330 "target type should be CommitObject")
331
332 assert.False(s.T(), v1Tag.Hash.IsZero(), "tag hash should be set")
333
334 assert.False(s.T(), v1Tag.Target.IsZero(), "target hash should be set")
335}
336
337func (s *TagSuite) TestTags_NilOptions() {
338 s.setupRepoWithTags()
339
340 tags, err := s.repo.Tags(nil)
341 require.NoError(s.T(), err)
342 assert.Len(s.T(), tags, 5, "nil options should return all tags")
343}
344
345func (s *TagSuite) TestTags_ZeroLimitAndOffset() {
346 s.setupRepoWithTags()
347
348 tags, err := s.repo.Tags(&TagsOptions{
349 Limit: 0,
350 Offset: 0,
351 })
352 require.NoError(s.T(), err)
353 assert.Len(s.T(), tags, 5, "zero limit should return all tags")
354}
355
356func (s *TagSuite) TestTags_OrderedNewestFirst() {
357 s.setupRepoWithTags()
358
359 tags, err := s.repo.Tags(nil)
360 require.NoError(s.T(), err)
361 require.Len(s.T(), tags, 5)
362
363 // v3.0.0 has the latest tagger date (baseTime+3h), should be first
364 assert.Equal(s.T(), "v3.0.0", tags[0].Name, "newest tag should be first")
365}
366
367func (s *TagSuite) TestTags_LatestWithLimit1() {
368 s.setupRepoWithTags()
369
370 tags, err := s.repo.Tags(&TagsOptions{Limit: 1})
371 require.NoError(s.T(), err)
372 require.Len(s.T(), tags, 1)
373
374 assert.Equal(s.T(), "v3.0.0", tags[0].Name, "limit=1 should return the newest tag")
375}
376
377func (s *TagSuite) TestTags_Pattern() {
378 s.setupRepoWithTags()
379
380 v1tag, err := s.repo.Tags(&TagsOptions{
381 Pattern: "refs/tags/v1.0.0",
382 })
383
384 require.NoError(s.T(), err)
385 assert.Len(s.T(), v1tag, 1, "expected 1 tag")
386}