github.com/storacha/go-ucanto@v0.7.2/core/car/car_test.go (about)

     1  package car
     2  
     3  import (
     4  	"bytes"
     5  	"io"
     6  	"os"
     7  	"testing"
     8  
     9  	"github.com/ipfs/go-cid"
    10  	cidlink "github.com/ipld/go-ipld-prime/linking/cid"
    11  	"github.com/storacha/go-ucanto/core/ipld"
    12  )
    13  
    14  type fixture struct {
    15  	path   string
    16  	root   ipld.Link
    17  	blocks []ipld.Link
    18  }
    19  
    20  var fixtures = []fixture{
    21  	{
    22  		path: "testdata/lost-dog.jpg.car",
    23  		root: cidlink.Link{Cid: cid.MustParse("bafybeif4owy5gno5lwnixqm52rwqfodklf76hsetxdhffuxnplvijskzqq")},
    24  		blocks: []ipld.Link{
    25  			cidlink.Link{Cid: cid.MustParse("bafkreifau35r7vi37tvbvfy3hdwvgb4tlflqf7zcdzeujqcjk3rsphiwte")},
    26  			cidlink.Link{Cid: cid.MustParse("bafkreicj3ozpzd46nx26hflpoi6hgm5linwo65cvphd5ol3ke3vk5nb7aa")},
    27  			cidlink.Link{Cid: cid.MustParse("bafybeihkqv2ukwgpgzkwsuz7whmvneztvxglkljbs3zosewgku2cfluvba")},
    28  			cidlink.Link{Cid: cid.MustParse("bafybeif4owy5gno5lwnixqm52rwqfodklf76hsetxdhffuxnplvijskzqq")},
    29  		},
    30  	},
    31  }
    32  
    33  func TestDecodeCAR(t *testing.T) {
    34  	file, err := os.Open(fixtures[0].path)
    35  	if err != nil {
    36  		t.Fatal(err)
    37  	}
    38  
    39  	roots, blocks, err := Decode(file)
    40  	if err != nil {
    41  		t.Fatal(err)
    42  	}
    43  	if len(roots) != 1 {
    44  		t.Fatalf("unexpected number of roots: %d, expected: 1", len(roots))
    45  	}
    46  	if roots[0].String() != fixtures[0].root.String() {
    47  		t.Fatalf("unexpected root: %s, expected: %s", roots[0], fixtures[0].root)
    48  	}
    49  
    50  	var blks []CarBlock
    51  	for b, err := range blocks {
    52  		if err != nil {
    53  			t.Fatalf("reading blocks: %s", err)
    54  		}
    55  		cb, ok := b.(CarBlock)
    56  		if !ok {
    57  			t.Fatalf("should have returned a car block")
    58  		}
    59  		blks = append(blks, cb)
    60  	}
    61  
    62  	if len(blks) != len(fixtures[0].blocks) {
    63  		t.Fatalf("incorrect number of blocks: %d, expected: %d", len(blks), len(fixtures[0].blocks))
    64  	}
    65  	for i, b := range fixtures[0].blocks {
    66  		if b.String() != blks[i].Link().String() {
    67  			t.Fatalf("unexpected block: %s, expected: %s", b, blks[i].Link())
    68  		}
    69  		// verify offset and length can be used to directly read the block in the CAR file
    70  		file.Seek(int64(blks[i].Offset()), io.SeekStart)
    71  		data := make([]byte, blks[i].Length())
    72  		_, err := file.Read(data)
    73  		if err != nil {
    74  			t.Fatalf("error reading block from raw file")
    75  		}
    76  		hashed, err := blks[i].Link().(cidlink.Link).Cid.Prefix().Sum(data)
    77  		if err != nil {
    78  			t.Fatalf("error hashing block from raw file")
    79  		}
    80  
    81  		if hashed.String() != blks[i].Link().String() {
    82  			t.Fatalf("raw read from offset block: %s, expected: %s", hashed, blks[i].Link())
    83  		}
    84  
    85  	}
    86  }
    87  
    88  func TestEncodeCAR(t *testing.T) {
    89  	file, err := os.Open(fixtures[0].path)
    90  	if err != nil {
    91  		t.Fatal(err)
    92  	}
    93  
    94  	fbytes, err := io.ReadAll(file)
    95  	if err != nil {
    96  		t.Fatal(err)
    97  	}
    98  
    99  	roots, blocks, err := Decode(bytes.NewReader(fbytes))
   100  	if err != nil {
   101  		t.Fatal(err)
   102  	}
   103  
   104  	rd := Encode(roots, blocks)
   105  
   106  	dbytes, err := io.ReadAll(rd)
   107  	if err != nil {
   108  		t.Fatal(err)
   109  	}
   110  
   111  	if !bytes.Equal(fbytes, dbytes) {
   112  		t.Fatal("failed to round trip")
   113  	}
   114  }