Files
cid/cid_test.go

451 lines
9.1 KiB
Go
Raw Normal View History

2016-08-26 17:56:12 -07:00
package cid
import (
"bytes"
2017-02-05 23:52:06 -08:00
"encoding/json"
2016-11-17 14:40:43 +01:00
"fmt"
"math/rand"
2016-11-17 14:40:43 +01:00
"strings"
2016-08-26 17:56:12 -07:00
"testing"
2017-06-19 16:37:07 +02:00
mbase "github.com/multiformats/go-multibase"
2016-10-05 12:08:42 -07:00
mh "github.com/multiformats/go-multihash"
2016-08-26 17:56:12 -07:00
)
2017-06-29 21:00:23 -04:00
// Copying the "silly test" idea from
// https://github.com/multiformats/go-multihash/blob/7aa9f26a231c6f34f4e9fad52bf580fd36627285/multihash_test.go#L13
2017-06-30 03:01:26 -04:00
// Makes it so changing the table accidentally has to happen twice.
2017-06-30 10:00:21 -04:00
var tCodecs = map[uint64]string{
2017-06-29 21:00:23 -04:00
Raw: "raw",
DagProtobuf: "protobuf",
DagCBOR: "cbor",
GitRaw: "git-raw",
EthBlock: "eth-block",
EthBlockList: "eth-block-list",
EthTxTrie: "eth-tx-trie",
EthTx: "eth-tx",
EthTxReceiptTrie: "eth-tx-receipt-trie",
EthTxReceipt: "eth-tx-receipt",
EthStateTrie: "eth-state-trie",
EthAccountSnapshot: "eth-account-snapshot",
EthStorageTrie: "eth-storage-trie",
BitcoinBlock: "bitcoin-block",
BitcoinTx: "bitcoin-tx",
ZcashBlock: "zcash-block",
ZcashTx: "zcash-tx",
DecredBlock: "decred-block",
DecredTx: "decred-tx",
2018-10-07 11:44:18 -07:00
DashBlock: "dash-block",
DashTx: "dash-tx",
2017-06-29 21:00:23 -04:00
}
func assertEqual(t *testing.T, a, b Cid) {
if a.Type() != b.Type() {
2016-08-30 10:04:50 -07:00
t.Fatal("mismatch on type")
}
if a.Version() != b.Version() {
2016-08-30 10:04:50 -07:00
t.Fatal("mismatch on version")
}
if !bytes.Equal(a.Hash(), b.Hash()) {
2016-08-30 10:04:50 -07:00
t.Fatal("multihash mismatch")
}
}
2017-06-29 21:00:23 -04:00
func TestTable(t *testing.T) {
2017-06-30 03:01:26 -04:00
if len(tCodecs) != len(Codecs)-1 {
t.Errorf("Item count mismatch in the Table of Codec. Should be %d, got %d", len(tCodecs)+1, len(Codecs))
}
for k, v := range tCodecs {
2017-06-29 21:00:23 -04:00
if Codecs[v] != k {
t.Errorf("Table mismatch: 0x%x %s", k, v)
}
}
}
// The table returns cid.DagProtobuf for "v0"
// so we test it apart
func TestTableForV0(t *testing.T) {
if Codecs["v0"] != DagProtobuf {
t.Error("Table mismatch: Codecs[\"v0\"] should resolve to DagProtobuf (0x70)")
}
}
2016-08-26 17:56:12 -07:00
func TestBasicMarshaling(t *testing.T) {
h, err := mh.Sum([]byte("TEST"), mh.SHA3, 4)
if err != nil {
t.Fatal(err)
}
cid := NewCidV1(7, h)
2016-08-26 17:56:12 -07:00
data := cid.Bytes()
2016-08-26 17:56:12 -07:00
out, err := Cast(data)
if err != nil {
t.Fatal(err)
}
2016-08-30 10:04:50 -07:00
assertEqual(t, cid, out)
s := cid.String()
out2, err := Decode(s)
if err != nil {
t.Fatal(err)
2016-08-26 17:56:12 -07:00
}
2016-08-30 10:04:50 -07:00
assertEqual(t, cid, out2)
}
2017-06-19 16:37:07 +02:00
func TestBasesMarshaling(t *testing.T) {
h, err := mh.Sum([]byte("TEST"), mh.SHA3, 4)
if err != nil {
t.Fatal(err)
}
cid := NewCidV1(7, h)
2017-06-19 16:37:07 +02:00
data := cid.Bytes()
out, err := Cast(data)
if err != nil {
t.Fatal(err)
}
assertEqual(t, cid, out)
2017-06-29 21:00:23 -04:00
testBases := []mbase.Encoding{
2017-06-19 16:37:07 +02:00
mbase.Base16,
mbase.Base32,
mbase.Base32hex,
mbase.Base32pad,
mbase.Base32hexPad,
mbase.Base58BTC,
mbase.Base58Flickr,
mbase.Base64pad,
mbase.Base64urlPad,
mbase.Base64url,
mbase.Base64,
}
for _, b := range testBases {
s, err := cid.StringOfBase(b)
if err != nil {
t.Fatal(err)
}
if s[0] != byte(b) {
t.Fatal("Invalid multibase header")
}
out2, err := Decode(s)
if err != nil {
t.Fatal(err)
}
assertEqual(t, cid, out2)
2018-08-01 15:34:58 -04:00
encoder, err := mbase.NewEncoder(b)
if err != nil {
t.Fatal(err)
}
2018-08-01 15:34:58 -04:00
s2 := cid.Encode(encoder)
if s != s2 {
t.Fatalf("'%s' != '%s'", s, s2)
}
2017-06-19 16:37:07 +02:00
}
}
2016-10-24 17:30:53 -07:00
func TestEmptyString(t *testing.T) {
_, err := Decode("")
if err == nil {
t.Fatal("shouldnt be able to parse an empty cid")
}
}
2016-08-30 10:04:50 -07:00
func TestV0Handling(t *testing.T) {
old := "QmdfTbBqBPQ7VNxZEYEj14VmRuZBkqFbiwReogJgS1zR1n"
cid, err := Decode(old)
if err != nil {
t.Fatal(err)
2016-08-26 17:56:12 -07:00
}
if cid.Version() != 0 {
2016-08-30 10:04:50 -07:00
t.Fatal("should have gotten version 0 cid")
}
if cid.Hash().B58String() != old {
t.Fatalf("marshaling roundtrip failed: %s != %s", cid.Hash().B58String(), old)
2016-08-30 10:04:50 -07:00
}
if cid.String() != old {
t.Fatal("marshaling roundtrip failed")
}
2018-08-01 16:51:58 -04:00
new, err := cid.StringOfBase(mbase.Base58BTC)
if err != nil {
t.Fatal(err)
}
if new != old {
t.Fatal("StringOfBase roundtrip failed")
}
encoder, err := mbase.NewEncoder(mbase.Base58BTC)
if err != nil {
t.Fatal(err)
}
if cid.Encode(encoder) != old {
t.Fatal("Encode roundtrip failed")
}
2016-08-30 10:04:50 -07:00
}
func TestV0ErrorCases(t *testing.T) {
badb58 := "QmdfTbBqBPQ7VNxZEYEj14VmRuZBkqFbiwReogJgS1zIII"
_, err := Decode(badb58)
if err == nil {
t.Fatal("should have failed to decode that ref")
}
}
func TestNewPrefixV1(t *testing.T) {
data := []byte("this is some test content")
// Construct c1
prefix := NewPrefixV1(DagCBOR, mh.SHA2_256)
c1, err := prefix.Sum(data)
if err != nil {
t.Fatal(err)
}
if c1.Prefix() != prefix {
t.Fatal("prefix not preserved")
}
// Construct c2
hash, err := mh.Sum(data, mh.SHA2_256, -1)
if err != nil {
t.Fatal(err)
}
c2 := NewCidV1(DagCBOR, hash)
if !c1.Equals(c2) {
t.Fatal("cids mismatch")
}
if c1.Prefix() != c2.Prefix() {
t.Fatal("prefixes mismatch")
}
}
func TestNewPrefixV0(t *testing.T) {
data := []byte("this is some test content")
// Construct c1
prefix := NewPrefixV0(mh.SHA2_256)
c1, err := prefix.Sum(data)
if err != nil {
t.Fatal(err)
}
if c1.Prefix() != prefix {
t.Fatal("prefix not preserved")
}
// Construct c2
hash, err := mh.Sum(data, mh.SHA2_256, -1)
if err != nil {
t.Fatal(err)
}
c2 := NewCidV0(hash)
if !c1.Equals(c2) {
t.Fatal("cids mismatch")
}
if c1.Prefix() != c2.Prefix() {
t.Fatal("prefixes mismatch")
}
}
func TestPrefixRoundtrip(t *testing.T) {
data := []byte("this is some test content")
hash, _ := mh.Sum(data, mh.SHA2_256, -1)
2016-11-23 10:01:51 -08:00
c := NewCidV1(DagCBOR, hash)
pref := c.Prefix()
c2, err := pref.Sum(data)
if err != nil {
t.Fatal(err)
}
if !c.Equals(c2) {
t.Fatal("output didnt match original")
}
pb := pref.Bytes()
pref2, err := PrefixFromBytes(pb)
if err != nil {
t.Fatal(err)
}
if pref.Version != pref2.Version || pref.Codec != pref2.Codec ||
pref.MhType != pref2.MhType || pref.MhLength != pref2.MhLength {
t.Fatal("input prefix didnt match output")
}
}
2016-11-17 18:50:50 +01:00
func Test16BytesVarint(t *testing.T) {
data := []byte("this is some test content")
hash, _ := mh.Sum(data, mh.SHA2_256, -1)
c := NewCidV1(1<<63, hash)
2016-11-17 18:50:50 +01:00
_ = c.Bytes()
}
func TestFuzzCid(t *testing.T) {
buf := make([]byte, 128)
for i := 0; i < 200; i++ {
s := rand.Intn(128)
rand.Read(buf[:s])
_, _ = Cast(buf[:s])
}
}
2016-11-17 14:40:43 +01:00
func TestParse(t *testing.T) {
cid, err := Parse(123)
if err == nil {
t.Fatalf("expected error from Parse()")
}
if !strings.Contains(err.Error(), "can't parse 123 as Cid") {
t.Fatalf("expected int error, got %s", err.Error())
}
theHash := "QmdfTbBqBPQ7VNxZEYEj14VmRuZBkqFbiwReogJgS1zR1n"
h, err := mh.FromB58String(theHash)
if err != nil {
t.Fatal(err)
}
assertions := [][]interface{}{
[]interface{}{NewCidV0(h), theHash},
[]interface{}{NewCidV0(h).Bytes(), theHash},
[]interface{}{h, theHash},
[]interface{}{theHash, theHash},
[]interface{}{"/ipfs/" + theHash, theHash},
[]interface{}{"https://ipfs.io/ipfs/" + theHash, theHash},
[]interface{}{"http://localhost:8080/ipfs/" + theHash, theHash},
}
assert := func(arg interface{}, expected string) error {
cid, err = Parse(arg)
if err != nil {
return err
}
if cid.Version() != 0 {
return fmt.Errorf("expected version 0, got %s", string(cid.Version()))
2016-11-17 14:40:43 +01:00
}
actual := cid.Hash().B58String()
if actual != expected {
return fmt.Errorf("expected hash %s, got %s", expected, actual)
}
actual = cid.String()
if actual != expected {
return fmt.Errorf("expected string %s, got %s", expected, actual)
}
return nil
}
for _, args := range assertions {
err := assert(args[0], args[1].(string))
if err != nil {
t.Fatal(err)
}
}
}
func TestHexDecode(t *testing.T) {
hexcid := "f015512209d8453505bdc6f269678e16b3e56c2a2948a41f2c792617cc9611ed363c95b63"
c, err := Decode(hexcid)
if err != nil {
t.Fatal(err)
}
if c.String() != "zb2rhhFAEMepUBbGyP1k8tGfz7BSciKXP6GHuUeUsJBaK6cqG" {
t.Fatal("hash value failed to round trip decoding from hex")
}
}
2017-02-05 23:52:06 -08:00
func ExampleDecode() {
encoded := "zb2rhhFAEMepUBbGyP1k8tGfz7BSciKXP6GHuUeUsJBaK6cqG"
c, err := Decode(encoded)
if err != nil {
fmt.Printf("Error: %s", err)
return
}
fmt.Println(c)
// Output: zb2rhhFAEMepUBbGyP1k8tGfz7BSciKXP6GHuUeUsJBaK6cqG
}
2017-02-05 23:52:06 -08:00
func TestFromJson(t *testing.T) {
cval := "zb2rhhFAEMepUBbGyP1k8tGfz7BSciKXP6GHuUeUsJBaK6cqG"
jsoncid := []byte(`{"/":"` + cval + `"}`)
var c Cid
err := json.Unmarshal(jsoncid, &c)
if err != nil {
t.Fatal(err)
}
if c.String() != cval {
t.Fatal("json parsing failed")
}
}
2018-07-11 11:20:53 -10:00
func TestJsonRoundTrip(t *testing.T) {
exp, err := Decode("zb2rhhFAEMepUBbGyP1k8tGfz7BSciKXP6GHuUeUsJBaK6cqG")
if err != nil {
t.Fatal(err)
}
// Verify it works for a *Cid.
enc, err := json.Marshal(exp)
if err != nil {
t.Fatal(err)
}
var actual Cid
err = json.Unmarshal(enc, &actual)
if !exp.Equals(actual) {
2018-07-11 11:20:53 -10:00
t.Fatal("cids not equal for *Cid")
}
// Verify it works for a Cid.
enc, err = json.Marshal(exp)
2018-07-11 11:20:53 -10:00
if err != nil {
t.Fatal(err)
}
var actual2 Cid
err = json.Unmarshal(enc, &actual2)
if !exp.Equals(actual2) {
2018-07-11 11:21:16 -10:00
t.Fatal("cids not equal for Cid")
2018-07-11 11:20:53 -10:00
}
}
func BenchmarkStringV1(b *testing.B) {
data := []byte("this is some test content")
hash, _ := mh.Sum(data, mh.SHA2_256, -1)
cid := NewCidV1(Raw, hash)
b.ReportAllocs()
b.ResetTimer()
count := 0
for i := 0; i < b.N; i++ {
count += len(cid.String())
}
if count != 49*b.N {
b.FailNow()
}
}