github.com/storacha/go-ucanto@v0.7.2/core/ipld/rebind_test.go (about) 1 package ipld 2 3 import ( 4 "fmt" 5 "testing" 6 7 "github.com/ipfs/go-cid" 8 "github.com/ipld/go-ipld-prime" 9 "github.com/ipld/go-ipld-prime/datamodel" 10 cidlink "github.com/ipld/go-ipld-prime/linking/cid" 11 "github.com/ipld/go-ipld-prime/node/bindnode" 12 "github.com/storacha/go-ucanto/core/ipld/codec/cbor" 13 "github.com/stretchr/testify/require" 14 ) 15 16 func TestRebind(t *testing.T) { 17 type Target struct { 18 Abool bool 19 Aint int 20 Afloat float64 21 Astring string 22 Abytes []byte 23 Aenumstr string 24 Aenumint int 25 Alist []string 26 Amap struct { 27 Keys []string 28 Values map[string]int 29 } 30 Alink ipld.Link 31 Aoptionalstr *string 32 Anullablestr *string 33 } 34 type Origin struct { 35 Value Target 36 } 37 type Base struct { 38 Value datamodel.Node 39 } 40 41 ts, err := ipld.LoadSchemaBytes([]byte(` 42 type Origin struct { 43 value Target 44 } 45 type Base struct { 46 value Any 47 } 48 type Target struct { 49 abool Bool 50 aint Int 51 afloat Float 52 astring String 53 abytes Bytes 54 aenumstr EnumString 55 aenumint EnumInt 56 alist [String] 57 amap { String: Int } 58 alink Link 59 aoptionalstr optional String 60 anullablestr nullable String 61 } 62 type EnumString enum { 63 | Nope 64 | Yep 65 | Maybe 66 } 67 type EnumInt enum { 68 | Nope ("0") 69 | Yep ("1") 70 | Maybe ("100") 71 } representation int 72 `)) 73 if err != nil { 74 t.Fatalf("failed to load schema: %s", err) 75 } 76 otyp := ts.TypeByName("Origin") 77 btyp := ts.TypeByName("Base") 78 ttyp := ts.TypeByName("Target") 79 80 str := "foo" 81 origin := Origin{ 82 Value: Target{ 83 Abool: true, 84 Aint: 138, 85 Afloat: 1.138, 86 Astring: "foo", 87 Abytes: []byte{1, 2, 3}, 88 Aenumstr: "Yep", 89 Aenumint: 100, 90 Alist: []string{"bar"}, 91 Amap: struct { 92 Keys []string 93 Values map[string]int 94 }{ 95 Keys: []string{"foo"}, 96 Values: map[string]int{"foo": 1138}, 97 }, 98 Alink: cidlink.Link{Cid: cid.MustParse("bafkreiem4twkqzsq2aj4shbycd4yvoj2cx72vezicletlhi7dijjciqpui")}, 99 Aoptionalstr: &str, 100 Anullablestr: &str, 101 }, 102 } 103 b, err := cbor.Encode(&origin, otyp) 104 if err != nil { 105 t.Fatalf("encoding origin: %s", err) 106 } 107 108 var bind Base 109 err = cbor.Decode(b, &bind, btyp) 110 if err != nil { 111 t.Fatalf("decoding base: %s", err) 112 } 113 114 sub, err := Rebind[Target](bind.Value, ttyp) 115 if err != nil { 116 t.Fatalf("binding subtype: %s", err) 117 } 118 119 fmt.Printf("%+v\n", sub) 120 121 if sub.Astring != "foo" { 122 t.Fatalf("failed round trip") 123 } 124 if sub.Aint != 138 { 125 t.Fatalf("failed round trip") 126 } 127 } 128 129 func TestRebindNonCompatibleStruct(t *testing.T) { 130 type Target struct { 131 Astring string 132 Aint int 133 } 134 type TargetIncompatible struct { 135 Abool bool 136 } 137 type Origin struct { 138 Value Target 139 } 140 type Base struct { 141 Value datamodel.Node 142 } 143 144 ts, err := ipld.LoadSchemaBytes([]byte(` 145 type Origin struct { 146 value Target 147 } 148 type Base struct { 149 value Any 150 } 151 type Target struct { 152 astring String 153 aint Int 154 } 155 `)) 156 if err != nil { 157 t.Fatalf("failed to load schema: %s", err) 158 } 159 otyp := ts.TypeByName("Origin") 160 btyp := ts.TypeByName("Base") 161 ttyp := ts.TypeByName("Target") 162 163 origin := Origin{Value: Target{Astring: "foo", Aint: 138}} 164 b, err := cbor.Encode(&origin, otyp) 165 if err != nil { 166 t.Fatalf("encoding origin: %s", err) 167 } 168 169 var bind Base 170 err = cbor.Decode(b, &bind, btyp) 171 if err != nil { 172 t.Fatalf("decoding base: %s", err) 173 } 174 175 _, err = Rebind[TargetIncompatible](bind.Value, ttyp) 176 if err == nil { 177 t.Fatalf("expected error rebinding") 178 } 179 fmt.Println(err) 180 } 181 182 func TestRebindNonCompatibleSchema(t *testing.T) { 183 type Target struct { 184 Astring string 185 Aint int 186 } 187 type Origin struct { 188 Value Target 189 } 190 type Base struct { 191 Value datamodel.Node 192 } 193 194 ts, err := ipld.LoadSchemaBytes([]byte(` 195 type Origin struct { 196 value Target 197 } 198 type Base struct { 199 value Any 200 } 201 type Target struct { 202 astring String 203 aint Int 204 } 205 type TargetIncompatible struct { 206 abool Bool 207 } 208 `)) 209 if err != nil { 210 t.Fatalf("failed to load schema: %s", err) 211 } 212 otyp := ts.TypeByName("Origin") 213 btyp := ts.TypeByName("Base") 214 ttyp := ts.TypeByName("TargetIncompatible") 215 216 origin := Origin{Value: Target{Astring: "foo", Aint: 138}} 217 b, err := cbor.Encode(&origin, otyp) 218 if err != nil { 219 t.Fatalf("encoding origin: %s", err) 220 } 221 222 var bind Base 223 err = cbor.Decode(b, &bind, btyp) 224 if err != nil { 225 t.Fatalf("decoding base: %s", err) 226 } 227 228 _, err = Rebind[Target](bind.Value, ttyp) 229 if err == nil { 230 t.Fatalf("expected error rebinding") 231 } 232 fmt.Println(err) 233 } 234 235 func TestRebindTypedNode(t *testing.T) { 236 type Target struct { 237 Astring string 238 Aint int 239 } 240 241 ts, err := ipld.LoadSchemaBytes([]byte(` 242 type Target struct { 243 astring String 244 aint Int 245 } representation tuple 246 `)) 247 require.NoError(t, err) 248 249 typ := ts.TypeByName("Target") 250 251 target := Target{Astring: "hello", Aint: 1} 252 nd := bindnode.Wrap(&target, typ) 253 254 rebindTarget, err := Rebind[Target](nd, typ) 255 require.NoError(t, err) 256 fmt.Printf("%+v\n", rebindTarget) 257 }