Monorepo for Tangled

knotserver/git: add comprehensive tag tests, improve parseTagRecord coverage

Signed-off-by: Matías Insaurralde <matias@insaurral.de>

authored by matias.tngl.sh and committed by tangled.org 56f8d335 fce83643

+156
+156
knotserver/git/tag_test.go
··· 1 1 package git 2 2 3 3 import ( 4 + "os" 4 5 "path/filepath" 6 + "strings" 5 7 "testing" 6 8 "time" 7 9 ··· 384 386 require.NoError(s.T(), err) 385 387 assert.Len(s.T(), v1tag, 1, "expected 1 tag") 386 388 } 389 + 390 + func (s *TagSuite) TestTags_PatternGlob() { 391 + s.setupRepoWithTags() 392 + 393 + tags, err := s.repo.Tags(&TagsOptions{ 394 + Pattern: "refs/tags/v1.*", 395 + }) 396 + require.NoError(s.T(), err) 397 + require.Len(s.T(), tags, 2, "glob pattern refs/tags/v1.* should match 2 tags") 398 + 399 + names := map[string]bool{} 400 + for _, t := range tags { 401 + names[t.Name] = true 402 + } 403 + assert.True(s.T(), names["v1.0.0"], "v1.0.0 should match pattern") 404 + assert.True(s.T(), names["v1.1.0"], "v1.1.0 should match pattern") 405 + } 406 + 407 + func (s *TagSuite) TestTags_PatternNoMatch() { 408 + s.setupRepoWithTags() 409 + 410 + tags, err := s.repo.Tags(&TagsOptions{ 411 + Pattern: "refs/tags/v9.*", 412 + }) 413 + require.NoError(s.T(), err) 414 + assert.Empty(s.T(), tags, "non-matching pattern should return no tags") 415 + } 416 + 417 + func (s *TagSuite) TestTags_VerifyLightweightTagFields() { 418 + s.setupRepoWithTags() 419 + 420 + tags, err := s.repo.Tags(nil) 421 + require.NoError(s.T(), err) 422 + 423 + var v2Tag *object.Tag 424 + for i := range tags { 425 + if tags[i].Name == "v2.0.0" { 426 + v2Tag = &tags[i] 427 + break 428 + } 429 + } 430 + require.NotNil(s.T(), v2Tag, "v2.0.0 tag not found") 431 + 432 + assert.Empty(s.T(), v2Tag.Tagger.Name, "lightweight tag should have no tagger name") 433 + assert.Empty(s.T(), v2Tag.Tagger.Email, "lightweight tag should have no tagger email") 434 + assert.True(s.T(), v2Tag.Tagger.When.IsZero(), "lightweight tag should have zero tagger date") 435 + // For a lightweight tag %(contents:subject) returns the commit subject, not a tag annotation 436 + assert.Equal(s.T(), "Add file3", v2Tag.Message, "lightweight tag message should be the commit subject") 437 + assert.False(s.T(), v2Tag.Hash.IsZero(), "lightweight tag hash should be the commit hash") 438 + assert.Equal(s.T(), plumbing.CommitObject, v2Tag.TargetType, "lightweight tag should resolve to a commit") 439 + } 440 + 441 + func (s *TagSuite) TestTags_SubjectOnlyMessage() { 442 + s.setupRepoWithTags() 443 + 444 + tags, err := s.repo.Tags(nil) 445 + require.NoError(s.T(), err) 446 + 447 + var v11Tag *object.Tag 448 + for i := range tags { 449 + if tags[i].Name == "v1.1.0" { 450 + v11Tag = &tags[i] 451 + break 452 + } 453 + } 454 + require.NotNil(s.T(), v11Tag, "v1.1.0 tag not found") 455 + 456 + // v1.1.0 was created with a subject-only message (no body paragraph) 457 + assert.Equal(s.T(), "Release version 1.1.0", v11Tag.Message, 458 + "subject-only tag message should equal the subject line") 459 + } 460 + 461 + func (s *TagSuite) TestTags_FullOrdering() { 462 + s.setupRepoWithTags() 463 + 464 + tags, err := s.repo.Tags(nil) 465 + require.NoError(s.T(), err) 466 + require.Len(s.T(), tags, 5) 467 + 468 + // Annotated tags carry explicit tagger dates (baseTime+3h, +2h, +1h) so they 469 + // sort ahead of lightweight tags whose commits have no explicit author date. 470 + assert.Equal(s.T(), "v3.0.0", tags[0].Name, "v3.0.0 should be newest (baseTime+3h)") 471 + assert.Equal(s.T(), "v1.1.0", tags[1].Name, "v1.1.0 should be second (baseTime+2h)") 472 + assert.Equal(s.T(), "v1.0.0", tags[2].Name, "v1.0.0 should be third (baseTime+1h)") 473 + 474 + // Lightweight tags v2.0.0 and v2.1.0 have zero-time commits and sort to the 475 + // end; their relative order is not guaranteed. 476 + lastName := map[string]bool{tags[3].Name: true, tags[4].Name: true} 477 + assert.True(s.T(), lastName["v2.0.0"], "v2.0.0 should be in the last two positions") 478 + assert.True(s.T(), lastName["v2.1.0"], "v2.1.0 should be in the last two positions") 479 + } 480 + 481 + func (s *TagSuite) TestTags_ForEachRefError() { 482 + s.setupRepoWithTags() 483 + 484 + // Remove .git so the underlying git command fails. 485 + err := os.RemoveAll(filepath.Join(s.repo.path, ".git")) 486 + require.NoError(s.T(), err) 487 + 488 + _, err = s.repo.Tags(nil) 489 + assert.Error(s.T(), err, "Tags should return an error when the git command fails") 490 + } 491 + 492 + func (s *TagSuite) TestParseTagRecord_BodyOnly() { 493 + // When subject is empty and body is non-empty the else branch sets message = body. 494 + fields := []string{ 495 + "v1.0.0", // tagName 496 + "abc123", // objectHash 497 + "tag", // objectType 498 + "def456", // targetHash 499 + "commit", // targetType 500 + "Tagger", // taggerName 501 + "<t@t.com>", // taggerEmail 502 + "0", // taggerDate 503 + "", // subject — empty 504 + "body text", // body — non-empty 505 + "", // signature 506 + } 507 + line := strings.Join(fields, fieldSeparator) 508 + tag, ok, err := parseTagRecord(line) 509 + require.NoError(s.T(), err) 510 + require.True(s.T(), ok) 511 + assert.Equal(s.T(), "body text", tag.Message, "body-only message should equal the body field") 512 + } 513 + 514 + func (s *TagSuite) TestParseTagRecord_ShortRecord() { 515 + // A record with fewer than 6 fields must be skipped without error. 516 + short := strings.Join([]string{"v1.0.0", "abc123", "tag", "def456"}, fieldSeparator) 517 + tag, ok, err := parseTagRecord(short) 518 + require.NoError(s.T(), err) 519 + assert.False(s.T(), ok, "short record should be skipped") 520 + assert.Equal(s.T(), object.Tag{}, tag) 521 + } 522 + 523 + func (s *TagSuite) TestParseTagRecord_InvalidObjectType() { 524 + // A record whose objecttype field is unrecognised must surface an error. 525 + fields := []string{ 526 + "v1.0.0", // tagName 527 + "abc123", // objectHash 528 + "invalid_type", // objectType — not a valid git object type 529 + "def456", // targetHash 530 + "commit", // targetType 531 + "Tagger", // taggerName 532 + "<t@t.com>", // taggerEmail 533 + "0", // taggerDate 534 + "subject", // subject 535 + "body", // body 536 + "", // signature 537 + } 538 + line := strings.Join(fields, fieldSeparator) 539 + _, ok, err := parseTagRecord(line) 540 + assert.Error(s.T(), err, "invalid object type should return an error") 541 + assert.False(s.T(), ok) 542 + }