github.com/mavryk-network/mvgo@v1.19.9/micheline/marshal_test.go (about) 1 // Copyright (c) 2023 Blockwatch Data Inc. 2 // Author: alex@blockwatch.cc 3 // 4 5 package micheline 6 7 import ( 8 "testing" 9 "time" 10 11 "github.com/mavryk-network/mvgo/mavryk" 12 ) 13 14 type marshalTest struct { 15 Name string 16 Spec string 17 Value any 18 Optimized bool 19 Want string 20 } 21 22 var marshalTests = []marshalTest{ 23 // scalars 24 // int 25 { 26 Name: "int", 27 Spec: `{"annots": ["%payoutDelay"],"prim": "int"}`, 28 Value: map[string]any{"payoutDelay": 1}, 29 Optimized: false, 30 Want: `{"int":"1"}`, 31 }, 32 // nat 33 { 34 Name: "nat", 35 Spec: `{"annots": ["%payoutFrequency"],"prim": "nat"}`, 36 Value: map[string]any{"payoutFrequency": 1}, 37 Optimized: false, 38 Want: `{"int":"1"}`, 39 }, 40 // mumav 41 { 42 Name: "mumav", 43 Spec: `{"annots": ["%money"],"prim": "mumav"}`, 44 Value: map[string]any{"money": 1}, 45 Optimized: false, 46 Want: `{"int":"1"}`, 47 }, 48 // string 49 { 50 Name: "string", 51 Spec: `{"annots": ["%name"],"prim": "string"}`, 52 Value: map[string]any{"name": "hello"}, 53 Optimized: false, 54 Want: `{"string":"hello"}`, 55 }, 56 // bytes 57 { 58 Name: "bytes", 59 Spec: `{"annots": ["%bakerName"],"prim": "bytes"}`, 60 Value: map[string]any{"bakerName": []byte{0xfa, 0xfe}}, 61 Optimized: false, 62 Want: `{"bytes":"fafe"}`, 63 }, 64 // bool 65 { 66 Name: "bool", 67 Spec: `{"annots": ["%bakerChargesTransactionFee"],"prim": "bool"}`, 68 Value: map[string]any{"bakerChargesTransactionFee": true}, 69 Optimized: false, 70 Want: `{"prim":"True"}`, 71 }, 72 // timestamp 73 { 74 Name: "timestamp_unix_noopt", 75 Spec: `{"annots": ["%last_update"],"prim": "timestamp"}`, 76 Value: map[string]any{"last_update": time.Unix(1696945397, 0)}, 77 Optimized: false, 78 Want: `{"string":"2023-10-10T13:43:17Z"}`, 79 }, 80 { 81 Name: "timestamp_unix_opt", 82 Spec: `{"annots": ["%last_update"],"prim": "timestamp"}`, 83 Value: map[string]any{"last_update": time.Unix(1696945397, 0)}, 84 Optimized: true, 85 Want: `{"int":"1696945397"}`, 86 }, 87 { 88 Name: "timestamp_rfc_noopt", 89 Spec: `{"annots": ["%last_update"],"prim": "timestamp"}`, 90 Value: map[string]any{"last_update": "2023-10-10T13:43:17Z"}, 91 Optimized: false, 92 Want: `{"string":"2023-10-10T13:43:17Z"}`, 93 }, 94 { 95 Name: "timestamp_rfc_opt", 96 Spec: `{"annots": ["%last_update"],"prim": "timestamp"}`, 97 Value: map[string]any{"last_update": "2023-10-10T13:43:17Z"}, 98 Optimized: true, 99 Want: `{"int":"1696945397"}`, 100 }, 101 // key_hash 102 { 103 Name: "key_hash_string_opt", 104 Spec: `{"annots": ["%baker"],"prim": "key_hash"}`, 105 Value: map[string]any{"baker": "mv1NUuSgQ3rvNBZE9FWTdgQ2oEomsRvP1Le4"}, 106 Optimized: false, 107 Want: `{"string":"mv1NUuSgQ3rvNBZE9FWTdgQ2oEomsRvP1Le4"}`, 108 }, 109 { 110 Name: "key_hash_string_noopt", 111 Spec: `{"annots": ["%baker"],"prim": "key_hash"}`, 112 Value: map[string]any{"baker": "mv1NUuSgQ3rvNBZE9FWTdgQ2oEomsRvP1Le4"}, 113 Optimized: true, 114 Want: `{"bytes":"009ec090ac91d1351dc4791bdb48a98f64421caa1c"}`, 115 }, 116 { 117 Name: "key_hash_addr_opt", 118 Spec: `{"annots": ["%baker"],"prim": "key_hash"}`, 119 Value: map[string]any{"baker": mavryk.MustParseAddress("mv1NUuSgQ3rvNBZE9FWTdgQ2oEomsRvP1Le4")}, 120 Optimized: false, 121 Want: `{"string":"mv1NUuSgQ3rvNBZE9FWTdgQ2oEomsRvP1Le4"}`, 122 }, 123 { 124 Name: "key_hash_addr_noopt", 125 Spec: `{"annots": ["%baker"],"prim": "key_hash"}`, 126 Value: map[string]any{"baker": mavryk.MustParseAddress("mv1NUuSgQ3rvNBZE9FWTdgQ2oEomsRvP1Le4")}, 127 Optimized: true, 128 Want: `{"bytes":"009ec090ac91d1351dc4791bdb48a98f64421caa1c"}`, 129 }, 130 // address 131 { 132 Name: "address_string_opt", 133 Spec: `{"annots": ["%reporterAccount"],"prim": "address"}`, 134 Value: map[string]any{"reporterAccount": "mv1NUuSgQ3rvNBZE9FWTdgQ2oEomsRvP1Le4"}, 135 Optimized: false, 136 Want: `{"string":"mv1NUuSgQ3rvNBZE9FWTdgQ2oEomsRvP1Le4"}`, 137 }, 138 { 139 Name: "address_string_noopt", 140 Spec: `{"annots": ["%reporterAccount"],"prim": "address"}`, 141 Value: map[string]any{"reporterAccount": "mv1NUuSgQ3rvNBZE9FWTdgQ2oEomsRvP1Le4"}, 142 Optimized: true, 143 Want: `{"bytes":"00009ec090ac91d1351dc4791bdb48a98f64421caa1c"}`, 144 }, 145 { 146 Name: "address_addr_opt", 147 Spec: `{"annots": ["%reporterAccount"],"prim": "address"}`, 148 Value: map[string]any{"reporterAccount": mavryk.MustParseAddress("mv1NUuSgQ3rvNBZE9FWTdgQ2oEomsRvP1Le4")}, 149 Optimized: false, 150 Want: `{"string":"mv1NUuSgQ3rvNBZE9FWTdgQ2oEomsRvP1Le4"}`, 151 }, 152 { 153 Name: "address_addr_noopt", 154 Spec: `{"annots": ["%reporterAccount"],"prim": "address"}`, 155 Value: map[string]any{"reporterAccount": mavryk.MustParseAddress("mv1NUuSgQ3rvNBZE9FWTdgQ2oEomsRvP1Le4")}, 156 Optimized: true, 157 Want: `{"bytes":"00009ec090ac91d1351dc4791bdb48a98f64421caa1c"}`, 158 }, 159 // key 160 { 161 Name: "key_string_noopt", 162 Spec: `{"annots": ["%pour_authorizer"],"prim": "key"}`, 163 Value: map[string]any{"pour_authorizer": "edpkvEfPbB2Q8dpo8D7DcLXC7ft4ogfeayPzxnvTiuz3iKM9TonxHh"}, 164 Optimized: false, 165 Want: `{"string":"edpkvEfPbB2Q8dpo8D7DcLXC7ft4ogfeayPzxnvTiuz3iKM9TonxHh"}`, 166 }, 167 { 168 Name: "key_string_opt", 169 Spec: `{"annots": ["%pour_authorizer"],"prim": "key"}`, 170 Value: map[string]any{"pour_authorizer": "edpkvEfPbB2Q8dpo8D7DcLXC7ft4ogfeayPzxnvTiuz3iKM9TonxHh"}, 171 Optimized: true, 172 Want: `{"bytes":"00d1e4cae729906793005dbdfddef090c4153042bf922e4db3a99a0467c45b9898"}`, 173 }, 174 { 175 Name: "key_key_noopt", 176 Spec: `{"annots": ["%pour_authorizer"],"prim": "key"}`, 177 Value: map[string]any{"pour_authorizer": mavryk.MustParseKey("edpkvEfPbB2Q8dpo8D7DcLXC7ft4ogfeayPzxnvTiuz3iKM9TonxHh")}, 178 Optimized: false, 179 Want: `{"string":"edpkvEfPbB2Q8dpo8D7DcLXC7ft4ogfeayPzxnvTiuz3iKM9TonxHh"}`, 180 }, 181 { 182 Name: "key_key_opt", 183 Spec: `{"annots": ["%pour_authorizer"],"prim": "key"}`, 184 Value: map[string]any{"pour_authorizer": mavryk.MustParseKey("edpkvEfPbB2Q8dpo8D7DcLXC7ft4ogfeayPzxnvTiuz3iKM9TonxHh")}, 185 Optimized: true, 186 Want: `{"bytes":"00d1e4cae729906793005dbdfddef090c4153042bf922e4db3a99a0467c45b9898"}`, 187 }, 188 // unit 189 { 190 Name: "unit_string", 191 Spec: `{"annots": ["%arg"],"prim": "unit"}`, 192 Value: map[string]any{"arg": ""}, 193 Optimized: false, 194 Want: `{"prim":"Unit"}`, 195 }, 196 { 197 Name: "unit_nil", 198 Spec: `{"annots": ["%arg"],"prim": "unit"}`, 199 Value: map[string]any{"arg": nil}, 200 Optimized: false, 201 Want: `{"prim":"Unit"}`, 202 }, 203 // signature 204 { 205 Name: "signature_string_noopt", 206 Spec: `{"annots": ["%sig"],"prim": "signature"}`, 207 Value: map[string]any{"sig": "sigqgQgW5qQCsuHP5HhMhAYR2HjcChUE7zAczsyCdF681rfZXpxnXFHu3E6ycmz4pQahjvu3VLfa7FMCxZXmiMiuZFQS4MHy"}, 208 Optimized: false, 209 Want: `{"string":"sigqgQgW5qQCsuHP5HhMhAYR2HjcChUE7zAczsyCdF681rfZXpxnXFHu3E6ycmz4pQahjvu3VLfa7FMCxZXmiMiuZFQS4MHy"}`, 210 }, 211 { 212 Name: "signature_string_opt", 213 Spec: `{"annots": ["%sig"],"prim": "signature"}`, 214 Value: map[string]any{"sig": "sigqgQgW5qQCsuHP5HhMhAYR2HjcChUE7zAczsyCdF681rfZXpxnXFHu3E6ycmz4pQahjvu3VLfa7FMCxZXmiMiuZFQS4MHy"}, 215 Optimized: true, 216 Want: `{"bytes":"d3a9e1467b32104921d4e2dd93265739c1a5faee7a7f8880842b096c0b6714200c43fd5872f82581dfe1cb3a76ccdadaa4d6361d72b4abee6884cb7ed87f0b04"}`, 217 }, 218 { 219 Name: "signature_sig_noopt", 220 Spec: `{"annots": ["%sig"],"prim": "signature"}`, 221 Value: map[string]any{"sig": mavryk.MustParseSignature("sigqgQgW5qQCsuHP5HhMhAYR2HjcChUE7zAczsyCdF681rfZXpxnXFHu3E6ycmz4pQahjvu3VLfa7FMCxZXmiMiuZFQS4MHy")}, 222 Optimized: false, 223 Want: `{"string":"sigqgQgW5qQCsuHP5HhMhAYR2HjcChUE7zAczsyCdF681rfZXpxnXFHu3E6ycmz4pQahjvu3VLfa7FMCxZXmiMiuZFQS4MHy"}`, 224 }, 225 { 226 Name: "signature_sig_opt", 227 Spec: `{"annots": ["%sig"],"prim": "signature"}`, 228 Value: map[string]any{"sig": mavryk.MustParseSignature("sigqgQgW5qQCsuHP5HhMhAYR2HjcChUE7zAczsyCdF681rfZXpxnXFHu3E6ycmz4pQahjvu3VLfa7FMCxZXmiMiuZFQS4MHy")}, 229 Optimized: true, 230 Want: `{"bytes":"d3a9e1467b32104921d4e2dd93265739c1a5faee7a7f8880842b096c0b6714200c43fd5872f82581dfe1cb3a76ccdadaa4d6361d72b4abee6884cb7ed87f0b04"}`, 231 }, 232 // arg list 233 { 234 Name: "args_named", 235 Spec: `{"args":[{"prim":"nat","annots":["%num1"]},{"args":[{"prim":"string","annots":["%name"]},{"prim":"int","annots":["%num2"]}],"prim": "pair"}],"prim": "pair"}`, 236 Value: map[string]any{"num1": 1, "name": "hello", "num2": 42}, 237 Optimized: false, 238 Want: `{"prim":"Pair","args":[{"int":"1"},{"prim":"Pair","args":[{"string":"hello"},{"int":"42"}]}]}`, 239 }, 240 // anon arg list 241 { 242 Name: "args_anon", 243 Spec: `{"args":[{"prim":"nat"},{"args":[{"prim":"string"},{"prim":"int"}],"prim": "pair"}],"prim": "pair"}`, 244 Value: map[string]any{"0": 1, "1": "hello", "2": 42}, 245 Optimized: false, 246 Want: `{"prim":"Pair","args":[{"int":"1"},{"prim":"Pair","args":[{"string":"hello"},{"int":"42"}]}]}`, 247 }, 248 // set 249 { 250 Name: "set", 251 Spec: `{"annots": ["%admins"],"prim": "set", "args": [{"prim": "key_hash"}]}`, 252 Value: map[string]any{"admins": []any{"mv1NUuSgQ3rvNBZE9FWTdgQ2oEomsRvP1Le4"}}, 253 Optimized: false, 254 Want: `[{"string":"mv1NUuSgQ3rvNBZE9FWTdgQ2oEomsRvP1Le4"}]`, 255 }, 256 { 257 Name: "set", 258 Spec: `{"annots": ["%admins"],"prim": "set", "args": [{"prim": "key_hash"}]}`, 259 Value: map[string]any{"admins": []any{mavryk.MustParseAddress("mv1NUuSgQ3rvNBZE9FWTdgQ2oEomsRvP1Le4")}}, 260 Optimized: false, 261 Want: `[{"string":"mv1NUuSgQ3rvNBZE9FWTdgQ2oEomsRvP1Le4"}]`, 262 }, 263 // map 264 { 265 Name: "map", 266 Spec: `{"annots":["%approvals"],"prim":"map","args":[{"prim":"address"},{"prim":"nat"}]}`, 267 Value: map[string]any{"approvals": map[string]any{"mv1NUuSgQ3rvNBZE9FWTdgQ2oEomsRvP1Le4": "1"}}, 268 Optimized: false, 269 Want: `[{"prim":"Elt","args":[{"string":"mv1NUuSgQ3rvNBZE9FWTdgQ2oEomsRvP1Le4"},{"int":"1"}]}]`, 270 }, 271 { 272 Name: "map", 273 Spec: `{"prim":"pair","annots":["%add_token"],"args":[{"prim":"nat","annots":["%token_id"]},{"prim":"map","annots":["%token_info"],"args":[{"prim":"string"},{"prim":"bytes"}]}]}`, 274 Value: map[string]any{"token_id": "1", "token_info": map[string]any{"": "ipfs://Qmb94zFKazBKxuYk4QyTWmgiVP3zXLkGjNDDTq3DShEs8E"}}, 275 Optimized: false, 276 Want: `{"prim":"Pair","args":[{"int":"1"},[{"prim":"Elt","args":[{"string":""},{"bytes":"697066733a2f2f516d6239347a464b617a424b7875596b34517954576d67695650337a584c6b476a4e444454713344536845733845"}]}]]}`, 277 }, 278 279 // option 280 { 281 Name: "option_no_value", 282 Spec: `{"annots":["%reporterAccount"],"prim":"option","args":[{"prim":"address"}]}`, 283 Value: map[string]any{"reporterAccount": nil}, 284 Optimized: false, 285 Want: `{"prim":"None"}`, 286 }, 287 { 288 Name: "option_with_value", 289 Spec: `{"annots":["%reporterAccount"],"prim":"option","args":[{"prim":"address"}]}`, 290 Value: map[string]any{"reporterAccount": "mv1NUuSgQ3rvNBZE9FWTdgQ2oEomsRvP1Le4"}, 291 Optimized: false, 292 Want: `{"prim":"Some","args":[{"string":"mv1NUuSgQ3rvNBZE9FWTdgQ2oEomsRvP1Le4"}]}`, 293 }, 294 295 // named union type 296 { 297 Name: "named-union", 298 Spec: `{"annots":["%update_operators"],"args":[{"args":[{"annots":["%add_operator"],"args":[{"annots":["%owner"],"prim":"address"},{"args":[{"annots":["%operator"],"prim":"address"},{"annots":["%token_id"],"prim":"nat"}],"prim":"pair"}],"prim":"pair"},{"annots":["%remove_operator"],"args":[{"annots":["%owner"],"prim":"address"},{"args":[{"annots":["%operator"],"prim":"address"},{"annots":["%token_id"],"prim":"nat"}],"prim":"pair"}],"prim":"pair"}],"prim":"or"}],"prim":"list"}`, 299 Value: map[string]any{"update_operators": []any{map[string]any{"add_operator": map[string]any{"owner": "mv1NUuSgQ3rvNBZE9FWTdgQ2oEomsRvP1Le4", "operator": "mv1NUuSgQ3rvNBZE9FWTdgQ2oEomsRvP1Le4", "token_id": "0"}}}}, 300 Optimized: false, 301 Want: `[{"prim":"Left","args":[{"prim":"Pair","args":[{"string":"mv1NUuSgQ3rvNBZE9FWTdgQ2oEomsRvP1Le4"},{"prim":"Pair","args":[{"string":"mv1NUuSgQ3rvNBZE9FWTdgQ2oEomsRvP1Le4"},{"int":"0"}]}]}]}]`, 302 }, 303 304 // TODO 305 306 // // anonymous union type 307 // { 308 // Name: "anon-union", 309 // Spec: `{"args":[{"args":[{"prim":"unit"},{"prim":"operation"}],"prim":"lambda"},{"args":[{"prim":"key_hash"}],"prim":"set"}],"prim":"or"}`, 310 // }, 311 // // nested map 312 // { 313 // Name: "nested_map", 314 // Spec: `{"annots": ["%deck"],"args": [{"prim": "int"},{"args": [{"prim": "int"},{"prim": "int"}],"prim": "map"}],"prim": "map"}`, 315 // }, 316 // // nested list (FA2) 317 // { 318 // Name: "nested_list", 319 // Spec: `{"annots": ["%transfer"],"args": [{"args": [{"annots": ["%from_"],"prim": "address"},{"annots": ["%txs"],"args": [{"args": [{"annots": ["%to_"],"prim": "address"},{"args": [{"annots": ["%token_id"],"prim": "nat"},{"annots": ["%amount"],"prim": "nat"}],"prim": "pair"}],"prim": "pair"}],"prim": "list"}],"prim": "pair"}],"prim": "list"}`, 320 // }, 321 // // right-hand pair tree 322 // { 323 // Name: "right_hand_pair_tree", 324 // Spec: `{"args":[{"annots":["%tokenPool"],"prim":"nat"},{"args":[{"annots":["%xtzPool"],"prim":"mumav"},{"args":[{"annots":["%lqtTotal"],"prim":"nat"},{"args":[{"annots":["%tokenAddress"],"prim":"address"},{"annots":["%lqtAddress"],"prim":"address"}],"prim":"pair"}],"prim":"pair"}],"prim":"pair"}],"prim":"pair"}`, 325 // }, 326 327 // unsupported 328 // // chain_id 329 // // bls12_381_g1 330 // // bls12_381_g2 331 // // bls12_381_fr 332 // { 333 // Name: "bls", 334 // Spec: `{"annots":["%g2"],"prim":"bls12_381_g2"}`, 335 // }, 336 // // sapling_state 337 // { 338 // Name: "sapling_state", 339 // Spec: `{"prim":"sapling_state","args":[{"int":"8"}]}`, 340 // }, 341 // // sapling_transaction 342 // { 343 // Name: "sapling_transaction", 344 // Spec: `{"prim":"sapling_transaction","args":[{"int":"8"}]}`, 345 // }, 346 // // never 347 // { 348 // Name: "never", 349 // Spec: `{"prim":"never"}`, 350 // }, 351 // // lambda, ticket, callbacks 352 // { 353 // Name: "lambda", 354 // Spec: `{"args": [{"args": [{"args": [{"prim": "string"},{"prim": "bytes"}],"prim": "pair"},{"args": [{"prim": "bytes"},{"prim": "bytes"}],"prim": "big_map"}],"prim": "pair"},{"args": [{"args": [{"prim": "operation"}],"prim": "list"},{"args": [{"prim": "bytes"},{"prim": "bytes"}],"prim": "big_map"}],"prim": "pair"}],"prim": "lambda"}`, 355 // }, 356 // // ticket 357 // { 358 // Name: "ticket", 359 // Spec: `{"prim": "ticket", "args":[{"prim":"timestamp"}]}`, 360 // }, 361 // // ticket 2 362 // { 363 // Name: "ticket2", 364 // Spec: `{"prim": "ticket", "annots":["%save"], "args":[{"prim":"string"}]}`, 365 // }, 366 // // contract 367 // { 368 // Name: "contract", 369 // Spec: `{"annots": ["%pour_dest"],"args": [{"prim": "unit"}],"prim": "contract"}`, 370 // }, 371 } 372 373 func TestTypeMarshaling(t *testing.T) { 374 for _, test := range marshalTests { 375 t.Run(test.Name, func(T *testing.T) { 376 typ := Type{} 377 err := typ.UnmarshalJSON([]byte(test.Spec)) 378 if err != nil { 379 T.Fatalf("unmarshal error: %v", err) 380 } 381 prim, err := typ.Typedef("").Marshal(test.Value, test.Optimized) 382 if err != nil { 383 T.Fatalf("marshal error: %v", err) 384 } 385 have, err := prim.MarshalJSON() 386 if err != nil { 387 T.Fatalf("render error: %v", err) 388 } 389 // fmt.Printf("HAVE: %s\n", string(have)) 390 if !jsonDiff(T, have, []byte(test.Want)) { 391 T.Error("render mismatch, see log for details") 392 t.FailNow() 393 } 394 }) 395 } 396 }