changelog generator & diff tool
stormlightlabs.github.io/git-storm/
changelog
changeset
markdown
golang
git
1package changeset
2
3import (
4 "encoding/json"
5 "os"
6 "path/filepath"
7 "strings"
8 "testing"
9 "time"
10
11 "github.com/goccy/go-yaml"
12 "github.com/stormlightlabs/git-storm/internal/testutils"
13)
14
15func TestWrite(t *testing.T) {
16 tmpDir := t.TempDir()
17 tests := []struct {
18 name string
19 entry Entry
20 wantType string
21 wantScope string
22 wantSummary string
23 }{
24 {
25 name: "basic entry",
26 entry: Entry{
27 Type: "added",
28 Scope: "cli",
29 Summary: "Add changelog command",
30 Breaking: false,
31 },
32 wantType: "added",
33 wantScope: "cli",
34 wantSummary: "Add changelog command",
35 },
36 {
37 name: "entry without scope",
38 entry: Entry{
39 Type: "fixed",
40 Scope: "",
41 Summary: "Fix bug in parser",
42 Breaking: false,
43 },
44 wantType: "fixed",
45 wantScope: "",
46 wantSummary: "Fix bug in parser",
47 },
48 {
49 name: "breaking change",
50 entry: Entry{
51 Type: "changed",
52 Scope: "api",
53 Summary: "Remove legacy endpoints",
54 Breaking: true,
55 },
56 wantType: "changed",
57 wantScope: "api",
58 wantSummary: "Remove legacy endpoints",
59 },
60 }
61
62 for _, tt := range tests {
63 t.Run(tt.name, func(t *testing.T) {
64 filePath, err := Write(tmpDir, tt.entry)
65 if err != nil {
66 t.Fatalf("Write() error = %v", err)
67 }
68
69 if _, err := os.Stat(filePath); os.IsNotExist(err) {
70 t.Errorf("File was not created: %s", filePath)
71 }
72
73 content, err := os.ReadFile(filePath)
74 if err != nil {
75 t.Fatalf("Failed to read file: %v", err)
76 }
77
78 contentStr := string(content)
79 if !strings.HasPrefix(contentStr, "---\n") {
80 t.Errorf("File should start with YAML frontmatter delimiter")
81 }
82
83 parts := strings.SplitN(contentStr, "---\n", 3)
84 if len(parts) < 3 {
85 t.Fatalf("Invalid YAML frontmatter format")
86 }
87
88 var parsed Entry
89 if err := yaml.Unmarshal([]byte(parts[1]), &parsed); err != nil {
90 t.Fatalf("Failed to parse YAML: %v", err)
91 }
92
93 if parsed.Type != tt.wantType {
94 t.Errorf("Type = %v, want %v", parsed.Type, tt.wantType)
95 }
96 if parsed.Scope != tt.wantScope {
97 t.Errorf("Scope = %v, want %v", parsed.Scope, tt.wantScope)
98 }
99 if parsed.Summary != tt.wantSummary {
100 t.Errorf("Summary = %v, want %v", parsed.Summary, tt.wantSummary)
101 }
102 if parsed.Breaking != tt.entry.Breaking {
103 t.Errorf("Breaking = %v, want %v", parsed.Breaking, tt.entry.Breaking)
104 }
105 })
106 }
107}
108
109func TestWrite_CollisionHandling(t *testing.T) {
110 tmpDir := t.TempDir()
111
112 entry := Entry{
113 Type: "added",
114 Scope: "test",
115 Summary: "Test collision handling",
116 }
117
118 path1, err := Write(tmpDir, entry)
119 if err != nil {
120 t.Fatalf("First Write() error = %v", err)
121 }
122
123 path2, err := Write(tmpDir, entry)
124 if err != nil {
125 t.Fatalf("Second Write() error = %v", err)
126 }
127
128 if path1 == path2 {
129 t.Errorf("Expected different file paths for collision, got same path: %s", path1)
130 }
131
132 if _, err := os.Stat(path1); os.IsNotExist(err) {
133 t.Errorf("First file was not created: %s", path1)
134 }
135 if _, err := os.Stat(path2); os.IsNotExist(err) {
136 t.Errorf("Second file was not created: %s", path2)
137 }
138}
139
140func TestSlugify(t *testing.T) {
141 tests := []struct {
142 name string
143 input string
144 want string
145 }{
146 {
147 name: "simple text",
148 input: "Add new feature",
149 want: "add-new-feature",
150 },
151 {
152 name: "text with special chars",
153 input: "Fix: bug in parser!",
154 want: "fix-bug-in-parser",
155 },
156 {
157 name: "text with numbers",
158 input: "Update version 1.2.3",
159 want: "update-version-1-2-3",
160 },
161 {
162 name: "text with underscores",
163 input: "Add user_profile field",
164 want: "add-user-profile-field",
165 },
166 {
167 name: "long text gets truncated",
168 input: "This is a very long summary that should be truncated to fifty characters maximum",
169 want: "this-is-a-very-long-summary-that-should-be-truncat",
170 },
171 }
172
173 for _, tt := range tests {
174 t.Run(tt.name, func(t *testing.T) {
175 got := slugify(tt.input)
176 if got != tt.want {
177 t.Errorf("slugify() = %v, want %v", got, tt.want)
178 }
179 })
180 }
181}
182
183func TestWrite_DirectoryCreation(t *testing.T) {
184 tmpDir := t.TempDir()
185 changesDir := filepath.Join(tmpDir, "nested", "changes")
186
187 entry := Entry{
188 Type: "added",
189 Summary: "Test directory creation",
190 }
191
192 filePath, err := Write(changesDir, entry)
193 if err != nil {
194 t.Fatalf("Write() error = %v", err)
195 }
196
197 if _, err := os.Stat(changesDir); os.IsNotExist(err) {
198 t.Errorf("Directory was not created: %s", changesDir)
199 }
200
201 if _, err := os.Stat(filePath); os.IsNotExist(err) {
202 t.Errorf("File was not created: %s", filePath)
203 }
204}
205
206func TestComputeDiffHash_Stability(t *testing.T) {
207 repo := testutils.SetupTestRepo(t)
208 commits := testutils.GetCommitHistory(t, repo)
209
210 if len(commits) == 0 {
211 t.Fatal("Expected at least one commit in test repo")
212 }
213
214 commit := commits[0]
215 hash1, err := ComputeDiffHash(commit)
216 if err != nil {
217 t.Fatalf("ComputeDiffHash() error = %v", err)
218 }
219
220 hash2, err := ComputeDiffHash(commit)
221 if err != nil {
222 t.Fatalf("ComputeDiffHash() second call error = %v", err)
223 }
224
225 testutils.Expect.Equal(t, hash1, hash2, "Diff hash should be stable across multiple calls")
226 testutils.Expect.Equal(t, len(hash1), 64, "Diff hash should be 64 characters (SHA256 hex)")
227}
228
229func TestComputeDiffHash_DifferentCommits(t *testing.T) {
230 repo := testutils.SetupTestRepo(t)
231
232 testutils.AddCommit(t, repo, "file1.txt", "content1", "Add file1")
233 testutils.AddCommit(t, repo, "file2.txt", "content2", "Add file2")
234
235 commits := testutils.GetCommitHistory(t, repo)
236 if len(commits) < 2 {
237 t.Fatal("Expected at least 2 commits")
238 }
239
240 hash1, err := ComputeDiffHash(commits[0])
241 if err != nil {
242 t.Fatalf("ComputeDiffHash() for commit 1 error = %v", err)
243 }
244
245 hash2, err := ComputeDiffHash(commits[1])
246 if err != nil {
247 t.Fatalf("ComputeDiffHash() for commit 2 error = %v", err)
248 }
249
250 testutils.Expect.NotEqual(t, hash1, hash2, "Different commits should have different diff hashes")
251}
252
253func TestWriteWithMetadata(t *testing.T) {
254 tmpDir := t.TempDir()
255
256 meta := Metadata{
257 CommitHash: "abc123def456",
258 DiffHash: "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
259 Type: "added",
260 Scope: "cli",
261 Summary: "Add new feature",
262 Breaking: false,
263 Author: "Test User",
264 Date: time.Now(),
265 Filename: "",
266 }
267
268 filePath, err := WriteWithMetadata(tmpDir, meta)
269 if err != nil {
270 t.Fatalf("WriteWithMetadata() error = %v", err)
271 }
272
273 testutils.Expect.True(t, strings.HasSuffix(filePath, ".md"), "File path should have .md extension")
274 if _, err := os.Stat(filePath); os.IsNotExist(err) {
275 t.Errorf("Markdown file was not created: %s", filePath)
276 }
277
278 filename := filepath.Base(filePath)
279 testutils.Expect.True(t, strings.HasPrefix(filename, meta.DiffHash[:7]), "Filename should start with first 7 chars of diff hash")
280
281 content, err := os.ReadFile(filePath)
282 if err != nil {
283 t.Fatalf("Failed to read markdown file: %v", err)
284 }
285
286 var parsedEntry Entry
287 parts := strings.SplitN(string(content), "---\n", 3)
288 if len(parts) < 3 {
289 t.Fatal("Invalid YAML frontmatter format")
290 }
291
292 if err := yaml.Unmarshal([]byte(parts[1]), &parsedEntry); err != nil {
293 t.Fatalf("Failed to parse YAML: %v", err)
294 }
295
296 testutils.Expect.Equal(t, parsedEntry.Type, meta.Type)
297 testutils.Expect.Equal(t, parsedEntry.Summary, meta.Summary)
298 testutils.Expect.Equal(t, parsedEntry.CommitHash, meta.CommitHash)
299 testutils.Expect.Equal(t, parsedEntry.DiffHash, meta.DiffHash)
300
301 jsonPath := filepath.Join(tmpDir, "data", meta.DiffHash+".json")
302 if _, err := os.Stat(jsonPath); os.IsNotExist(err) {
303 t.Errorf("JSON metadata file was not created: %s", jsonPath)
304 }
305
306 jsonContent, err := os.ReadFile(jsonPath)
307 if err != nil {
308 t.Fatalf("Failed to read JSON metadata: %v", err)
309 }
310
311 var parsedMeta Metadata
312 if err := json.Unmarshal(jsonContent, &parsedMeta); err != nil {
313 t.Fatalf("Failed to parse JSON metadata: %v", err)
314 }
315
316 testutils.Expect.Equal(t, parsedMeta.CommitHash, meta.CommitHash)
317 testutils.Expect.Equal(t, parsedMeta.DiffHash, meta.DiffHash)
318 testutils.Expect.Equal(t, parsedMeta.Type, meta.Type)
319 testutils.Expect.Equal(t, parsedMeta.Summary, meta.Summary)
320}
321
322func TestLoadExistingMetadata(t *testing.T) {
323 tmpDir := t.TempDir()
324
325 meta1 := Metadata{
326 CommitHash: "abc123",
327 DiffHash: "hash1111111111111111111111111111111111111111111111111111111111111",
328 Type: "added",
329 Summary: "Feature 1",
330 Author: "User1",
331 Date: time.Now(),
332 }
333
334 meta2 := Metadata{
335 CommitHash: "def456",
336 DiffHash: "hash2222222222222222222222222222222222222222222222222222222222222",
337 Type: "fixed",
338 Summary: "Fix 1",
339 Author: "User2",
340 Date: time.Now(),
341 }
342
343 _, err := WriteWithMetadata(tmpDir, meta1)
344 if err != nil {
345 t.Fatalf("Failed to write meta1: %v", err)
346 }
347
348 _, err = WriteWithMetadata(tmpDir, meta2)
349 if err != nil {
350 t.Fatalf("Failed to write meta2: %v", err)
351 }
352
353 loaded, err := LoadExistingMetadata(tmpDir)
354 if err != nil {
355 t.Fatalf("LoadExistingMetadata() error = %v", err)
356 }
357
358 testutils.Expect.Equal(t, len(loaded), 2, "Should load 2 metadata entries")
359
360 if m, exists := loaded[meta1.DiffHash]; exists {
361 testutils.Expect.Equal(t, m.CommitHash, meta1.CommitHash)
362 testutils.Expect.Equal(t, m.Type, meta1.Type)
363 } else {
364 t.Errorf("meta1 not found in loaded metadata")
365 }
366
367 if m, exists := loaded[meta2.DiffHash]; exists {
368 testutils.Expect.Equal(t, m.CommitHash, meta2.CommitHash)
369 testutils.Expect.Equal(t, m.Type, meta2.Type)
370 } else {
371 t.Errorf("meta2 not found in loaded metadata")
372 }
373}
374
375func TestLoadExistingMetadata_EmptyDirectory(t *testing.T) {
376 tmpDir := t.TempDir()
377
378 loaded, err := LoadExistingMetadata(tmpDir)
379 if err != nil {
380 t.Fatalf("LoadExistingMetadata() error = %v", err)
381 }
382
383 testutils.Expect.Equal(t, len(loaded), 0, "Should return empty map for non-existent data directory")
384}
385
386func TestUpdateMetadata(t *testing.T) {
387 tmpDir := t.TempDir()
388
389 meta := Metadata{
390 CommitHash: "original123",
391 DiffHash: "diffhash111111111111111111111111111111111111111111111111111111111",
392 Type: "added",
393 Summary: "Feature",
394 Author: "User",
395 Date: time.Now(),
396 }
397
398 _, err := WriteWithMetadata(tmpDir, meta)
399 if err != nil {
400 t.Fatalf("Failed to write metadata: %v", err)
401 }
402
403 newCommitHash := "rebased456"
404 err = UpdateMetadata(tmpDir, meta.DiffHash, newCommitHash)
405 if err != nil {
406 t.Fatalf("UpdateMetadata() error = %v", err)
407 }
408
409 loaded, err := LoadExistingMetadata(tmpDir)
410 if err != nil {
411 t.Fatalf("LoadExistingMetadata() error = %v", err)
412 }
413
414 updated, exists := loaded[meta.DiffHash]
415 if !exists {
416 t.Fatal("Updated metadata not found")
417 }
418
419 testutils.Expect.Equal(t, updated.CommitHash, newCommitHash, "CommitHash should be updated")
420 testutils.Expect.Equal(t, updated.Type, meta.Type, "Other fields should remain unchanged")
421 testutils.Expect.Equal(t, updated.Summary, meta.Summary, "Other fields should remain unchanged")
422}
423
424func TestDeduplication_SameCommit(t *testing.T) {
425 tmpDir := t.TempDir()
426 repo := testutils.SetupTestRepo(t)
427 commits := testutils.GetCommitHistory(t, repo)
428 if len(commits) == 0 {
429 t.Fatal("Expected at least one commit")
430 }
431
432 commit := commits[0]
433 diffHash, err := ComputeDiffHash(commit)
434 if err != nil {
435 t.Fatalf("ComputeDiffHash() error = %v", err)
436 }
437
438 meta := Metadata{
439 CommitHash: commit.Hash.String(),
440 DiffHash: diffHash,
441 Type: "added",
442 Summary: "Test feature",
443 Author: commit.Author.Name,
444 Date: commit.Author.When,
445 }
446
447 _, err = WriteWithMetadata(tmpDir, meta)
448 if err != nil {
449 t.Fatalf("First WriteWithMetadata() error = %v", err)
450 }
451
452 existing, err := LoadExistingMetadata(tmpDir)
453 if err != nil {
454 t.Fatalf("LoadExistingMetadata() error = %v", err)
455 }
456
457 if existingMeta, exists := existing[diffHash]; exists {
458 testutils.Expect.Equal(t, existingMeta.CommitHash, commit.Hash.String(), "Should detect exact duplicate")
459 } else {
460 t.Error("Metadata should exist in loaded entries")
461 }
462}
463
464func TestDeduplication_RebasedCommit(t *testing.T) {
465 tmpDir := t.TempDir()
466 repo := testutils.SetupTestRepo(t)
467
468 commits := testutils.GetCommitHistory(t, repo)
469 if len(commits) == 0 {
470 t.Fatal("Expected at least one commit")
471 }
472
473 commit := commits[0]
474 diffHash, err := ComputeDiffHash(commit)
475 if err != nil {
476 t.Fatalf("ComputeDiffHash() error = %v", err)
477 }
478
479 originalMeta := Metadata{
480 CommitHash: "original_commit_hash_123",
481 DiffHash: diffHash,
482 Type: "added",
483 Summary: "Test feature",
484 Author: commit.Author.Name,
485 Date: commit.Author.When,
486 }
487
488 _, err = WriteWithMetadata(tmpDir, originalMeta)
489 if err != nil {
490 t.Fatalf("WriteWithMetadata() error = %v", err)
491 }
492
493 existing, err := LoadExistingMetadata(tmpDir)
494 if err != nil {
495 t.Fatalf("LoadExistingMetadata() error = %v", err)
496 }
497
498 if existingMeta, exists := existing[diffHash]; exists {
499 if existingMeta.CommitHash != commit.Hash.String() {
500 err = UpdateMetadata(tmpDir, diffHash, commit.Hash.String())
501 if err != nil {
502 t.Fatalf("UpdateMetadata() error = %v", err)
503 }
504
505 updated, err := LoadExistingMetadata(tmpDir)
506 if err != nil {
507 t.Fatalf("LoadExistingMetadata() after update error = %v", err)
508 }
509
510 updatedMeta := updated[diffHash]
511 testutils.Expect.Equal(t, updatedMeta.CommitHash, commit.Hash.String(), "CommitHash should be updated for rebased commit")
512 }
513 }
514}
515
516func TestWritePartial(t *testing.T) {
517 tmpDir := t.TempDir()
518
519 tests := []struct {
520 name string
521 filename string
522 entry Entry
523 wantErr bool
524 wantType string
525 wantSummary string
526 }{
527 {
528 name: "basic partial entry",
529 filename: "abc1234.added.md",
530 entry: Entry{
531 Type: "added",
532 Scope: "cli",
533 Summary: "Add feature",
534 CommitHash: "abc123def456",
535 },
536 wantErr: false,
537 wantType: "added",
538 wantSummary: "Add feature",
539 },
540 {
541 name: "partial with different type",
542 filename: "def5678.fixed.md",
543 entry: Entry{
544 Type: "fixed",
545 Summary: "Fix bug",
546 CommitHash: "def5678abc",
547 },
548 wantErr: false,
549 wantType: "fixed",
550 wantSummary: "Fix bug",
551 },
552 }
553
554 for _, tt := range tests {
555 t.Run(tt.name, func(t *testing.T) {
556 filePath, err := WritePartial(tmpDir, tt.filename, tt.entry)
557 if (err != nil) != tt.wantErr {
558 t.Fatalf("WritePartial() error = %v, wantErr %v", err, tt.wantErr)
559 }
560
561 if tt.wantErr {
562 return
563 }
564
565 expectedPath := filepath.Join(tmpDir, tt.filename)
566 testutils.Expect.Equal(t, filePath, expectedPath, "File path should match expected")
567
568 if _, err := os.Stat(filePath); os.IsNotExist(err) {
569 t.Errorf("File was not created: %s", filePath)
570 }
571
572 content, err := os.ReadFile(filePath)
573 if err != nil {
574 t.Fatalf("Failed to read file: %v", err)
575 }
576
577 parts := strings.SplitN(string(content), "---\n", 3)
578 if len(parts) < 3 {
579 t.Fatal("Invalid YAML frontmatter format")
580 }
581
582 var parsed Entry
583 if err := yaml.Unmarshal([]byte(parts[1]), &parsed); err != nil {
584 t.Fatalf("Failed to parse YAML: %v", err)
585 }
586
587 testutils.Expect.Equal(t, parsed.Type, tt.wantType)
588 testutils.Expect.Equal(t, parsed.Summary, tt.wantSummary)
589 testutils.Expect.Equal(t, parsed.CommitHash, tt.entry.CommitHash)
590 })
591 }
592}
593
594func TestWritePartial_DuplicateFilename(t *testing.T) {
595 tmpDir := t.TempDir()
596
597 filename := "abc1234.added.md"
598 entry := Entry{
599 Type: "added",
600 Summary: "Test feature",
601 CommitHash: "abc1234",
602 }
603
604 _, err := WritePartial(tmpDir, filename, entry)
605 if err != nil {
606 t.Fatalf("First WritePartial() error = %v", err)
607 }
608
609 _, err = WritePartial(tmpDir, filename, entry)
610 if err == nil {
611 t.Error("Expected error when writing duplicate filename, got nil")
612 }
613
614 if !strings.Contains(err.Error(), "already exists") {
615 t.Errorf("Expected 'already exists' error, got: %v", err)
616 }
617}
618
619func TestDelete(t *testing.T) {
620 tmpDir := t.TempDir()
621
622 entry := Entry{
623 Type: "added",
624 Scope: "test",
625 Summary: "Test deletion",
626 }
627
628 filePath, err := Write(tmpDir, entry)
629 if err != nil {
630 t.Fatalf("Write() error = %v", err)
631 }
632
633 filename := filepath.Base(filePath)
634
635 if _, err := os.Stat(filePath); os.IsNotExist(err) {
636 t.Fatalf("File should exist before deletion: %s", filePath)
637 }
638
639 err = Delete(tmpDir, filename)
640 if err != nil {
641 t.Fatalf("Delete() error = %v", err)
642 }
643
644 if _, err := os.Stat(filePath); !os.IsNotExist(err) {
645 t.Errorf("File should not exist after deletion: %s", filePath)
646 }
647}
648
649func TestDelete_NonExistentFile(t *testing.T) {
650 tmpDir := t.TempDir()
651
652 err := Delete(tmpDir, "nonexistent.md")
653 if err == nil {
654 t.Error("Expected error when deleting non-existent file, got nil")
655 }
656
657 if !strings.Contains(err.Error(), "does not exist") {
658 t.Errorf("Expected 'does not exist' error, got: %v", err)
659 }
660}
661
662func TestUpdate(t *testing.T) {
663 tmpDir := t.TempDir()
664
665 originalEntry := Entry{
666 Type: "added",
667 Scope: "cli",
668 Summary: "Original summary",
669 }
670
671 filePath, err := Write(tmpDir, originalEntry)
672 if err != nil {
673 t.Fatalf("Write() error = %v", err)
674 }
675
676 filename := filepath.Base(filePath)
677
678 updatedEntry := Entry{
679 Type: "changed",
680 Scope: "api",
681 Summary: "Updated summary",
682 }
683
684 err = Update(tmpDir, filename, updatedEntry)
685 if err != nil {
686 t.Fatalf("Update() error = %v", err)
687 }
688
689 content, err := os.ReadFile(filePath)
690 if err != nil {
691 t.Fatalf("Failed to read updated file: %v", err)
692 }
693
694 parts := strings.SplitN(string(content), "---\n", 3)
695 if len(parts) < 3 {
696 t.Fatal("Invalid YAML frontmatter format")
697 }
698
699 var parsed Entry
700 if err := yaml.Unmarshal([]byte(parts[1]), &parsed); err != nil {
701 t.Fatalf("Failed to parse YAML: %v", err)
702 }
703
704 testutils.Expect.Equal(t, parsed.Type, updatedEntry.Type, "Type should be updated")
705 testutils.Expect.Equal(t, parsed.Scope, updatedEntry.Scope, "Scope should be updated")
706 testutils.Expect.Equal(t, parsed.Summary, updatedEntry.Summary, "Summary should be updated")
707}
708
709func TestUpdate_NonExistentFile(t *testing.T) {
710 tmpDir := t.TempDir()
711
712 entry := Entry{
713 Type: "added",
714 Summary: "Test",
715 }
716
717 err := Update(tmpDir, "nonexistent.md", entry)
718 if err == nil {
719 t.Error("Expected error when updating non-existent file, got nil")
720 }
721
722 if !strings.Contains(err.Error(), "does not exist") {
723 t.Errorf("Expected 'does not exist' error, got: %v", err)
724 }
725}
726
727func TestUpdate_PreserveMetadata(t *testing.T) {
728 tmpDir := t.TempDir()
729
730 originalEntry := Entry{
731 Type: "added",
732 Scope: "cli",
733 Summary: "Original",
734 Breaking: false,
735 CommitHash: "abc123",
736 DiffHash: "def456",
737 }
738
739 filePath, err := Write(tmpDir, originalEntry)
740 if err != nil {
741 t.Fatalf("Write() error = %v", err)
742 }
743
744 filename := filepath.Base(filePath)
745
746 updatedEntry := Entry{
747 Type: "changed",
748 Scope: "api",
749 Summary: "Updated",
750 Breaking: true,
751 CommitHash: "abc123",
752 DiffHash: "def456",
753 }
754
755 err = Update(tmpDir, filename, updatedEntry)
756 if err != nil {
757 t.Fatalf("Update() error = %v", err)
758 }
759
760 content, err := os.ReadFile(filePath)
761 if err != nil {
762 t.Fatalf("Failed to read updated file: %v", err)
763 }
764
765 parts := strings.SplitN(string(content), "---\n", 3)
766 var parsed Entry
767 if err := yaml.Unmarshal([]byte(parts[1]), &parsed); err != nil {
768 t.Fatalf("Failed to parse YAML: %v", err)
769 }
770
771 testutils.Expect.Equal(t, parsed.CommitHash, updatedEntry.CommitHash, "CommitHash should be preserved")
772 testutils.Expect.Equal(t, parsed.DiffHash, updatedEntry.DiffHash, "DiffHash should be preserved")
773 testutils.Expect.Equal(t, parsed.Breaking, updatedEntry.Breaking, "Breaking should be updated")
774}