shithub: furgit

ref: 0587025b7d48bae29b0843c2c4ab691b99f82752
dir: /pack_test.go/

View raw version
package furgit

import (
	"bytes"
	"compress/zlib"
	"encoding/binary"
	"testing"
)

func compressBytes(t *testing.T, payload []byte) []byte {
	var buf bytes.Buffer
	zw := zlib.NewWriter(&buf)
	if _, err := zw.Write(payload); err != nil {
		t.Fatalf("compress write: %v", err)
	}
	if err := zw.Close(); err != nil {
		t.Fatalf("compress close: %v", err)
	}
	return buf.Bytes()
}

func TestPackSectionInflate(t *testing.T) {
	payload := []byte("pack payload")
	compressed := compressBytes(t, payload)
	body, err := packSectionInflate(bytes.NewReader(compressed), len(payload))
	if err != nil {
		t.Fatalf("packSectionInflate error: %v", err)
	}
	if got := string(body.Bytes()); got != string(payload) {
		t.Fatalf("unexpected inflated data: %q", got)
	}
	body.Release()

	body, err = packSectionInflate(bytes.NewReader(compressed), 0)
	if err != nil {
		t.Fatalf("packSectionInflate streaming error: %v", err)
	}
	if got := string(body.Bytes()); got != string(payload) {
		t.Fatalf("unexpected streaming data: %q", got)
	}
	body.Release()
}

func encodePackHeader(ty ObjType, size int) []byte {
	first := byte((ty & 0x7) << 4)
	first |= byte(size & 0x0f)
	size >>= 4
	if size == 0 {
		return []byte{first}
	}
	first |= 0x80
	out := []byte{first}
	for size > 0 {
		b := byte(size & 0x7f)
		size >>= 7
		if size != 0 {
			b |= 0x80
		}
		out = append(out, b)
	}
	return out
}

func TestPackHeaderRead(t *testing.T) {
	buf := encodePackHeader(ObjTree, 0x1fff)
	ty, size, err := packHeaderRead(bytes.NewReader(buf))
	if err != nil {
		t.Fatalf("packHeaderRead error: %v", err)
	}
	if ty != ObjTree || size != 0x1fff {
		t.Fatalf("unexpected header decode ty=%d size=%d", ty, size)
	}
	if _, _, err := packHeaderRead(bytes.NewReader([]byte{0x80})); err == nil {
		t.Fatal("expected error for truncated header")
	}
}

func encodeVarint(value int) []byte {
	var out []byte
	for {
		b := byte(value & 0x7f)
		value >>= 7
		if value != 0 {
			b |= 0x80
		}
		out = append(out, b)
		if value == 0 {
			break
		}
	}
	return out
}

func TestPackVarintRead(t *testing.T) {
	buf := encodeVarint(0x3456)
	pos := 0
	val, err := packVarintRead(buf, &pos)
	if err != nil {
		t.Fatalf("packVarintRead error: %v", err)
	}
	if val != 0x3456 {
		t.Fatalf("unexpected varint value: %d", val)
	}
	if pos != len(buf) {
		t.Fatalf("expected pos %d, got %d", len(buf), pos)
	}
	bad := []byte{0x80}
	pos = 0
	if _, err := packVarintRead(bad, &pos); err == nil {
		t.Fatal("expected error for unterminated varint")
	}
}

func TestPackDeltaApply(t *testing.T) {
	base := borrowedFromOwned([]byte("abcdefghij"))
	defer base.Release()
	deltaBytes := []byte{0x0a, 0x0a, 0x91, 0x00, 0x03, 0x03, 'X', 'Y', 'Z', 0x91, 0x06, 0x04}
	delta := borrowedFromOwned(deltaBytes)
	defer delta.Release()
	out, err := packDeltaApply(base, delta)
	if err != nil {
		t.Fatalf("packDeltaApply error: %v", err)
	}
	if got := string(out.Bytes()); got != "abcXYZghij" {
		t.Fatalf("unexpected delta output: %q", got)
	}
	out.Release()
}

func TestPackDeltaApplyMismatchedBaseSize(t *testing.T) {
	base := borrowedFromOwned([]byte("abc"))
	defer base.Release()
	delta := borrowedFromOwned([]byte{0x04, 0x04})
	defer delta.Release()
	if _, err := packDeltaApply(base, delta); err == nil {
		t.Fatal("expected error for mismatched base size")
	}
}

func TestPackDeltaReadOfsDistance(t *testing.T) {
	dist, err := packDeltaReadOfsDistance(bytes.NewReader([]byte{0x81, 0x01}))
	if err != nil {
		t.Fatalf("packDeltaReadOfsDistance error: %v", err)
	}
	if dist != 257 {
		t.Fatalf("unexpected distance: %d", dist)
	}
	if _, err := packDeltaReadOfsDistance(bytes.NewReader([]byte{})); err == nil {
		t.Fatal("expected error for empty reader")
	}
}

func TestBsearchHash(t *testing.T) {
	h1 := hashWithByte(0x01)
	h2 := hashWithByte(0x03)
	names := append(append([]byte(nil), h1[:]...), h2[:]...)
	idx, found := bsearchHash(names, HashSize, 0, 2, h2)
	if !found || idx != 1 {
		t.Fatalf("expected to find second hash, idx=%d found=%v", idx, found)
	}
	_, found = bsearchHash(names, HashSize, 0, 2, hashWithByte(0x05))
	if found {
		t.Fatalf("did not expect to find unknown hash")
	}
}

func buildTestPackIndexBuffer(hash Hash, offset uint32) []byte {
	fanout := make([]byte, 256*4)
	first := int(hash[0])
	for i := 0; i < 256; i++ {
		var val uint32
		if i >= first {
			val = 1
		}
		binary.BigEndian.PutUint32(fanout[i*4:], val)
	}
	var buf bytes.Buffer
	_ = binary.Write(&buf, binary.BigEndian, uint32(idxMagic))
	_ = binary.Write(&buf, binary.BigEndian, uint32(idxVersion2))
	buf.Write(fanout)
	buf.Write(hash[:])
	buf.Write(make([]byte, 4))
	off32 := make([]byte, 4)
	binary.BigEndian.PutUint32(off32, offset)
	buf.Write(off32)
	buf.Write(make([]byte, 40))
	return buf.Bytes()
}

func TestPackIndexParse(t *testing.T) {
	h := hashWithByte(0x11)
	data := buildTestPackIndexBuffer(h, 0x12345678)
	pi := &packIndex{}
	if err := pi.parse(data); err != nil {
		t.Fatalf("parse error: %v", err)
	}
	if pi.numObjects != 1 {
		t.Fatalf("expected 1 object, got %d", pi.numObjects)
	}
	if got, err := pi.offset(0); err != nil || got != 0x12345678 {
		t.Fatalf("unexpected 32-bit offset or error: %d, %v", got, err)
	}
}

func TestPackIndexOffset64(t *testing.T) {
	pi := &packIndex{}
	pi.offset32 = make([]byte, 4)
	binary.BigEndian.PutUint32(pi.offset32, 0x80000000)
	pi.offset64 = make([]byte, 8)
	binary.BigEndian.PutUint64(pi.offset64, 0x1_0000_0000)
	if got, err := pi.offset(0); err != nil || got != 0x1_0000_0000 {
		t.Fatalf("unexpected 64-bit offset or error: %d, %v", got, err)
	}
}