github.com/ipld/go-ipld-prime@v0.21.0/codec/dagcbor/roundtrip_test.go (about) 1 package dagcbor 2 3 import ( 4 "bytes" 5 "crypto/rand" 6 "encoding/hex" 7 "math" 8 "strings" 9 "testing" 10 11 qt "github.com/frankban/quicktest" 12 cid "github.com/ipfs/go-cid" 13 14 "github.com/ipld/go-ipld-prime/datamodel" 15 "github.com/ipld/go-ipld-prime/fluent" 16 cidlink "github.com/ipld/go-ipld-prime/linking/cid" 17 "github.com/ipld/go-ipld-prime/node/basicnode" 18 nodetests "github.com/ipld/go-ipld-prime/node/tests" 19 ) 20 21 var n = fluent.MustBuildMap(basicnode.Prototype.Map, 4, func(na fluent.MapAssembler) { 22 na.AssembleEntry("plain").AssignString("olde string") 23 na.AssembleEntry("map").CreateMap(2, func(na fluent.MapAssembler) { 24 na.AssembleEntry("one").AssignInt(1) 25 na.AssembleEntry("two").AssignInt(2) 26 }) 27 na.AssembleEntry("list").CreateList(2, func(na fluent.ListAssembler) { 28 na.AssembleValue().AssignString("three") 29 na.AssembleValue().AssignString("four") 30 }) 31 na.AssembleEntry("nested").CreateMap(1, func(na fluent.MapAssembler) { 32 na.AssembleEntry("deeper").CreateList(1, func(na fluent.ListAssembler) { 33 na.AssembleValue().AssignString("things") 34 }) 35 }) 36 }) 37 var nSorted = fluent.MustBuildMap(basicnode.Prototype.Map, 4, func(na fluent.MapAssembler) { 38 na.AssembleEntry("map").CreateMap(2, func(na fluent.MapAssembler) { 39 na.AssembleEntry("one").AssignInt(1) 40 na.AssembleEntry("two").AssignInt(2) 41 }) 42 na.AssembleEntry("list").CreateList(2, func(na fluent.ListAssembler) { 43 na.AssembleValue().AssignString("three") 44 na.AssembleValue().AssignString("four") 45 }) 46 na.AssembleEntry("plain").AssignString("olde string") 47 na.AssembleEntry("nested").CreateMap(1, func(na fluent.MapAssembler) { 48 na.AssembleEntry("deeper").CreateList(1, func(na fluent.ListAssembler) { 49 na.AssembleValue().AssignString("things") 50 }) 51 }) 52 }) 53 var serial = "\xa4cmap\xa2cone\x01ctwo\x02dlist\x82ethreedfoureplainkolde stringfnested\xa1fdeeper\x81fthings" 54 55 func TestRoundtrip(t *testing.T) { 56 t.Run("encoding", func(t *testing.T) { 57 var buf bytes.Buffer 58 err := Encode(n, &buf) 59 qt.Assert(t, err, qt.IsNil) 60 qt.Check(t, buf.String(), qt.Equals, serial) 61 }) 62 t.Run("length", func(t *testing.T) { 63 length, err := EncodedLength(n) 64 qt.Assert(t, err, qt.IsNil) 65 qt.Check(t, length, qt.Equals, int64(len(serial))) 66 }) 67 t.Run("decoding", func(t *testing.T) { 68 buf := strings.NewReader(serial) 69 nb := basicnode.Prototype.Map.NewBuilder() 70 err := Decode(nb, buf) 71 qt.Assert(t, err, qt.IsNil) 72 qt.Check(t, nb.Build(), nodetests.NodeContentEquals, nSorted) 73 }) 74 } 75 76 func TestRoundtripScalar(t *testing.T) { 77 nb := basicnode.Prototype__String{}.NewBuilder() 78 nb.AssignString("applesauce") 79 simple := nb.Build() 80 t.Run("encoding", func(t *testing.T) { 81 var buf bytes.Buffer 82 err := Encode(simple, &buf) 83 qt.Assert(t, err, qt.IsNil) 84 qt.Check(t, buf.String(), qt.Equals, `japplesauce`) 85 }) 86 t.Run("decoding", func(t *testing.T) { 87 buf := strings.NewReader(`japplesauce`) 88 nb := basicnode.Prototype__String{}.NewBuilder() 89 err := Decode(nb, buf) 90 qt.Assert(t, err, qt.IsNil) 91 qt.Check(t, nb.Build(), nodetests.NodeContentEquals, simple) 92 }) 93 } 94 95 func TestRoundtripLinksAndBytes(t *testing.T) { 96 lnk := cidlink.LinkPrototype{Prefix: cid.Prefix{ 97 Version: 1, 98 Codec: 0x71, 99 MhType: 0x13, 100 MhLength: 4, 101 }}.BuildLink([]byte{1, 2, 3, 4}) // dummy value, content does not matter to this test. 102 103 var linkByteNode = fluent.MustBuildMap(basicnode.Prototype.Map, 4, func(na fluent.MapAssembler) { 104 nva := na.AssembleEntry("Link") 105 nva.AssignLink(lnk) 106 nva = na.AssembleEntry("Bytes") 107 bytes := make([]byte, 100) 108 _, _ = rand.Read(bytes) 109 nva.AssignBytes(bytes) 110 }) 111 112 buf := bytes.Buffer{} 113 err := Encode(linkByteNode, &buf) 114 qt.Assert(t, err, qt.IsNil) 115 nb := basicnode.Prototype.Map.NewBuilder() 116 err = Decode(nb, &buf) 117 qt.Assert(t, err, qt.IsNil) 118 reconstructed := nb.Build() 119 qt.Check(t, reconstructed, nodetests.NodeContentEquals, linkByteNode) 120 } 121 122 func TestInts(t *testing.T) { 123 data := []struct { 124 name string 125 hex string 126 value uint64 127 intValue int64 128 intErr string 129 decodeErr string 130 }{ 131 {"max uint64", "1bffffffffffffffff", math.MaxUint64, 0, "unsigned integer out of range of int64 type", ""}, 132 {"max int64", "1b7fffffffffffffff", math.MaxInt64, math.MaxInt64, "", ""}, 133 {"1", "01", 1, 1, "", ""}, 134 {"0", "00", 0, 0, "", ""}, 135 {"-1", "20", 0, -1, "", ""}, 136 {"min int64", "3b7fffffffffffffff", 0, math.MinInt64, "", ""}, 137 {"~min uint64", "3bfffffffffffffffe", 0, 0, "", "cbor: negative integer out of rage of int64 type"}, 138 // TODO: 3bffffffffffffffff isn't properly handled by refmt, it's coerced to zero 139 // MaxUint64 gets overflowed here: https://github.com/polydawn/refmt/blob/30ac6d18308e584ca6a2e74ba81475559db94c5f/cbor/cborDecoderTerminals.go#L75 140 } 141 142 for _, td := range data { 143 t.Run(td.name, func(t *testing.T) { 144 buf, err := hex.DecodeString(td.hex) // max uint64 145 qt.Assert(t, err, qt.IsNil) 146 nb := basicnode.Prototype.Any.NewBuilder() 147 err = Decode(nb, bytes.NewReader(buf)) 148 if td.decodeErr != "" { 149 qt.Assert(t, err, qt.IsNotNil) 150 qt.Assert(t, err.Error(), qt.Equals, td.decodeErr) 151 return 152 } 153 qt.Assert(t, err, qt.IsNil) 154 n := nb.Build() 155 156 ii, err := n.AsInt() 157 if td.intErr != "" { 158 qt.Assert(t, err.Error(), qt.Equals, td.intErr) 159 } else { 160 qt.Assert(t, err, qt.IsNil) 161 qt.Assert(t, ii, qt.Equals, int64(td.intValue)) 162 } 163 164 // if the number is outside of the positive int64 range, we should be able 165 // to access it as a UintNode and be able to access the full int64 range 166 uin, ok := n.(datamodel.UintNode) 167 if td.value <= math.MaxInt64 { 168 qt.Assert(t, ok, qt.IsFalse) 169 } else { 170 qt.Assert(t, ok, qt.IsTrue) 171 val, err := uin.AsUint() 172 qt.Assert(t, err, qt.IsNil) 173 qt.Assert(t, val, qt.Equals, uint64(td.value)) 174 } 175 176 var byts bytes.Buffer 177 err = Encode(n, &byts) 178 qt.Assert(t, err, qt.IsNil) 179 qt.Assert(t, hex.EncodeToString(byts.Bytes()), qt.Equals, td.hex) 180 }) 181 } 182 }