package packrev_test import ( "bytes" "errors" "os" "testing" "lindenii.org/go/furgit/internal/format/packidx" "lindenii.org/go/furgit/internal/format/packrev" "lindenii.org/go/furgit/object/id" ) // writeSyntheticRev writes one reverse index over positions // with a fixed fake pack hash. func writeSyntheticRev(t *testing.T, objectFormat id.ObjectFormat, positions []uint32) []byte { t.Helper() packHash := bytes.Repeat([]byte{0x5a}, objectFormat.Size()) var buf bytes.Buffer err := packrev.Write(&buf, objectFormat, positions, packHash) if err != nil { t.Fatalf("Write: %v", err) } return buf.Bytes() } func TestWriteRoundTrip(t *testing.T) { t.Parallel() for _, objectFormat := range id.SupportedObjectFormats() { t.Run(objectFormat.String(), func(t *testing.T) { t.Parallel() positions := []uint32{8, 6, 7, 5, 3, 0, 4, 1, 2} data := writeSyntheticRev(t, objectFormat, positions) rev, err := packrev.Parse(data, objectFormat) if err != nil { t.Fatalf("Parse: %v", err) } if rev.NumObjects() != len(positions) { t.Fatalf("NumObjects = %d, want %d", rev.NumObjects(), len(positions)) } if !bytes.Equal(rev.PackHash(), bytes.Repeat([]byte{0x5a}, objectFormat.Size())) { t.Fatalf("PackHash mismatch") } for packOrder, want := range positions { position, err := rev.PositionAt(packOrder) if err != nil { t.Fatalf("PositionAt(%d): %v", packOrder, err) } if position != int(want) { t.Fatalf("PositionAt(%d) = %d, want %d", packOrder, position, want) } } }) } } func TestWriteMatchesGit(t *testing.T) { t.Parallel() for _, objectFormat := range id.SupportedObjectFormats() { t.Run(objectFormat.String(), func(t *testing.T) { t.Parallel() prefix := makeGitPack(t, objectFormat) gitData, err := os.ReadFile(prefix + ".rev") //nolint:gosec if err != nil { t.Fatalf("ReadFile: %v", err) } idxData, err := os.ReadFile(prefix + ".idx") //nolint:gosec if err != nil { t.Fatalf("ReadFile: %v", err) } idx, err := packidx.Parse(idxData, objectFormat.Size()) if err != nil { t.Fatalf("packidx.Parse: %v", err) } positions := packOrderPositions(t, &idx) var buf bytes.Buffer err = packrev.Write(&buf, objectFormat, positions, idx.PackHash()) if err != nil { t.Fatalf("Write: %v", err) } if !bytes.Equal(buf.Bytes(), gitData) { t.Fatalf("Write output differs from git's reverse index (%d vs %d bytes)", buf.Len(), len(gitData)) } }) } } func TestWriteInvalidPositions(t *testing.T) { t.Parallel() for _, objectFormat := range id.SupportedObjectFormats() { t.Run(objectFormat.String(), func(t *testing.T) { t.Parallel() packHash := bytes.Repeat([]byte{0x5a}, objectFormat.Size()) err := packrev.Write(&bytes.Buffer{}, objectFormat, []uint32{0, 5}, packHash) if !errors.Is(err, packrev.ErrInvalidPositions) { t.Fatalf("Write error = %v, want ErrInvalidPositions", err) } }) } } func TestWriteBadPackHashPanics(t *testing.T) { t.Parallel() defer func() { if recover() == nil { t.Fatalf("Write with short pack hash: expected panic") } }() _ = packrev.Write(&bytes.Buffer{}, id.ObjectFormatSHA256, nil, []byte{0x01}) }