github.com/nitinawathare/ethereumassignment3@v0.0.0-20211021213010-f07344c2b868/go-ethereum/signer/core/signed_data_test.go (about) 1 // Copyright 2018 The go-ethereum Authors 2 // This file is part of go-ethereum. 3 // 4 // go-ethereum is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // go-ethereum is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. 16 // 17 package core_test 18 19 import ( 20 "context" 21 "encoding/json" 22 "fmt" 23 "math/big" 24 "testing" 25 26 "github.com/ethereum/go-ethereum/accounts/keystore" 27 "github.com/ethereum/go-ethereum/common" 28 "github.com/ethereum/go-ethereum/common/hexutil" 29 "github.com/ethereum/go-ethereum/signer/core" 30 ) 31 32 var typesStandard = core.Types{ 33 "EIP712Domain": { 34 { 35 Name: "name", 36 Type: "string", 37 }, 38 { 39 Name: "version", 40 Type: "string", 41 }, 42 { 43 Name: "chainId", 44 Type: "uint256", 45 }, 46 { 47 Name: "verifyingContract", 48 Type: "address", 49 }, 50 }, 51 "Person": { 52 { 53 Name: "name", 54 Type: "string", 55 }, 56 { 57 Name: "wallet", 58 Type: "address", 59 }, 60 }, 61 "Mail": { 62 { 63 Name: "from", 64 Type: "Person", 65 }, 66 { 67 Name: "to", 68 Type: "Person", 69 }, 70 { 71 Name: "contents", 72 Type: "string", 73 }, 74 }, 75 } 76 77 var jsonTypedData = ` 78 { 79 "types": { 80 "EIP712Domain": [ 81 { 82 "name": "name", 83 "type": "string" 84 }, 85 { 86 "name": "version", 87 "type": "string" 88 }, 89 { 90 "name": "chainId", 91 "type": "uint256" 92 }, 93 { 94 "name": "verifyingContract", 95 "type": "address" 96 } 97 ], 98 "Person": [ 99 { 100 "name": "name", 101 "type": "string" 102 }, 103 { 104 "name": "test", 105 "type": "uint8" 106 }, 107 { 108 "name": "wallet", 109 "type": "address" 110 } 111 ], 112 "Mail": [ 113 { 114 "name": "from", 115 "type": "Person" 116 }, 117 { 118 "name": "to", 119 "type": "Person" 120 }, 121 { 122 "name": "contents", 123 "type": "string" 124 } 125 ] 126 }, 127 "primaryType": "Mail", 128 "domain": { 129 "name": "Ether Mail", 130 "version": "1", 131 "chainId": 1, 132 "verifyingContract": "0xCCCcccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" 133 }, 134 "message": { 135 "from": { 136 "name": "Cow", 137 "test": 3, 138 "wallet": "0xcD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" 139 }, 140 "to": { 141 "name": "Bob", 142 "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" 143 }, 144 "contents": "Hello, Bob!" 145 } 146 } 147 ` 148 149 const primaryType = "Mail" 150 151 var domainStandard = core.TypedDataDomain{ 152 "Ether Mail", 153 "1", 154 big.NewInt(1), 155 "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC", 156 "", 157 } 158 159 var messageStandard = map[string]interface{}{ 160 "from": map[string]interface{}{ 161 "name": "Cow", 162 "wallet": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826", 163 }, 164 "to": map[string]interface{}{ 165 "name": "Bob", 166 "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB", 167 }, 168 "contents": "Hello, Bob!", 169 } 170 171 var typedData = core.TypedData{ 172 Types: typesStandard, 173 PrimaryType: primaryType, 174 Domain: domainStandard, 175 Message: messageStandard, 176 } 177 178 func TestSignData(t *testing.T) { 179 api, control := setup(t) 180 //Create two accounts 181 createAccount(control, api, t) 182 createAccount(control, api, t) 183 control.approveCh <- "1" 184 list, err := api.List(context.Background()) 185 if err != nil { 186 t.Fatal(err) 187 } 188 a := common.NewMixedcaseAddress(list[0]) 189 190 control.approveCh <- "Y" 191 control.inputCh <- "wrongpassword" 192 signature, err := api.SignData(context.Background(), core.TextPlain.Mime, a, hexutil.Encode([]byte("EHLO world"))) 193 if signature != nil { 194 t.Errorf("Expected nil-data, got %x", signature) 195 } 196 if err != keystore.ErrDecrypt { 197 t.Errorf("Expected ErrLocked! '%v'", err) 198 } 199 control.approveCh <- "No way" 200 signature, err = api.SignData(context.Background(), core.TextPlain.Mime, a, hexutil.Encode([]byte("EHLO world"))) 201 if signature != nil { 202 t.Errorf("Expected nil-data, got %x", signature) 203 } 204 if err != core.ErrRequestDenied { 205 t.Errorf("Expected ErrRequestDenied! '%v'", err) 206 } 207 // text/plain 208 control.approveCh <- "Y" 209 control.inputCh <- "a_long_password" 210 signature, err = api.SignData(context.Background(), core.TextPlain.Mime, a, hexutil.Encode([]byte("EHLO world"))) 211 if err != nil { 212 t.Fatal(err) 213 } 214 if signature == nil || len(signature) != 65 { 215 t.Errorf("Expected 65 byte signature (got %d bytes)", len(signature)) 216 } 217 // data/typed 218 control.approveCh <- "Y" 219 control.inputCh <- "a_long_password" 220 signature, err = api.SignTypedData(context.Background(), a, typedData) 221 if err != nil { 222 t.Fatal(err) 223 } 224 if signature == nil || len(signature) != 65 { 225 t.Errorf("Expected 65 byte signature (got %d bytes)", len(signature)) 226 } 227 } 228 229 func TestDomainChainId(t *testing.T) { 230 withoutChainID := core.TypedData{ 231 Types: core.Types{ 232 "EIP712Domain": []core.Type{ 233 {Name: "name", Type: "string"}, 234 }, 235 }, 236 Domain: core.TypedDataDomain{ 237 Name: "test", 238 }, 239 } 240 241 if _, ok := withoutChainID.Domain.Map()["chainId"]; ok { 242 t.Errorf("Expected the chainId key to not be present in the domain map") 243 } 244 245 withChainID := core.TypedData{ 246 Types: core.Types{ 247 "EIP712Domain": []core.Type{ 248 {Name: "name", Type: "string"}, 249 {Name: "chainId", Type: "uint256"}, 250 }, 251 }, 252 Domain: core.TypedDataDomain{ 253 Name: "test", 254 ChainId: big.NewInt(1), 255 }, 256 } 257 258 if _, ok := withChainID.Domain.Map()["chainId"]; !ok { 259 t.Errorf("Expected the chainId key be present in the domain map") 260 } 261 } 262 263 func TestHashStruct(t *testing.T) { 264 hash, err := typedData.HashStruct(typedData.PrimaryType, typedData.Message) 265 if err != nil { 266 t.Fatal(err) 267 } 268 mainHash := fmt.Sprintf("0x%s", common.Bytes2Hex(hash)) 269 if mainHash != "0xc52c0ee5d84264471806290a3f2c4cecfc5490626bf912d01f240d7a274b371e" { 270 t.Errorf("Expected different hashStruct result (got %s)", mainHash) 271 } 272 273 hash, err = typedData.HashStruct("EIP712Domain", typedData.Domain.Map()) 274 if err != nil { 275 t.Error(err) 276 } 277 domainHash := fmt.Sprintf("0x%s", common.Bytes2Hex(hash)) 278 if domainHash != "0xf2cee375fa42b42143804025fc449deafd50cc031ca257e0b194a650a912090f" { 279 t.Errorf("Expected different domain hashStruct result (got %s)", domainHash) 280 } 281 } 282 283 func TestEncodeType(t *testing.T) { 284 domainTypeEncoding := string(typedData.EncodeType("EIP712Domain")) 285 if domainTypeEncoding != "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" { 286 t.Errorf("Expected different encodeType result (got %s)", domainTypeEncoding) 287 } 288 289 mailTypeEncoding := string(typedData.EncodeType(typedData.PrimaryType)) 290 if mailTypeEncoding != "Mail(Person from,Person to,string contents)Person(string name,address wallet)" { 291 t.Errorf("Expected different encodeType result (got %s)", mailTypeEncoding) 292 } 293 } 294 295 func TestTypeHash(t *testing.T) { 296 mailTypeHash := fmt.Sprintf("0x%s", common.Bytes2Hex(typedData.TypeHash(typedData.PrimaryType))) 297 if mailTypeHash != "0xa0cedeb2dc280ba39b857546d74f5549c3a1d7bdc2dd96bf881f76108e23dac2" { 298 t.Errorf("Expected different typeHash result (got %s)", mailTypeHash) 299 } 300 } 301 302 func TestEncodeData(t *testing.T) { 303 hash, err := typedData.EncodeData(typedData.PrimaryType, typedData.Message, 0) 304 if err != nil { 305 t.Fatal(err) 306 } 307 dataEncoding := fmt.Sprintf("0x%s", common.Bytes2Hex(hash)) 308 if dataEncoding != "0xa0cedeb2dc280ba39b857546d74f5549c3a1d7bdc2dd96bf881f76108e23dac2fc71e5fa27ff56c350aa531bc129ebdf613b772b6604664f5d8dbe21b85eb0c8cd54f074a4af31b4411ff6a60c9719dbd559c221c8ac3492d9d872b041d703d1b5aadf3154a261abdd9086fc627b61efca26ae5702701d05cd2305f7c52a2fc8" { 309 t.Errorf("Expected different encodeData result (got %s)", dataEncoding) 310 } 311 } 312 313 func TestMalformedDomainkeys(t *testing.T) { 314 // Verifies that malformed domain keys are properly caught: 315 //{ 316 // "name": "Ether Mail", 317 // "version": "1", 318 // "chainId": 1, 319 // "vxerifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" 320 //} 321 jsonTypedData := ` 322 { 323 "types": { 324 "EIP712Domain": [ 325 { 326 "name": "name", 327 "type": "string" 328 }, 329 { 330 "name": "version", 331 "type": "string" 332 }, 333 { 334 "name": "chainId", 335 "type": "uint256" 336 }, 337 { 338 "name": "verifyingContract", 339 "type": "address" 340 } 341 ], 342 "Person": [ 343 { 344 "name": "name", 345 "type": "string" 346 }, 347 { 348 "name": "wallet", 349 "type": "address" 350 } 351 ], 352 "Mail": [ 353 { 354 "name": "from", 355 "type": "Person" 356 }, 357 { 358 "name": "to", 359 "type": "Person" 360 }, 361 { 362 "name": "contents", 363 "type": "string" 364 } 365 ] 366 }, 367 "primaryType": "Mail", 368 "domain": { 369 "name": "Ether Mail", 370 "version": "1", 371 "chainId": 1, 372 "vxerifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" 373 }, 374 "message": { 375 "from": { 376 "name": "Cow", 377 "wallet": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" 378 }, 379 "to": { 380 "name": "Bob", 381 "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" 382 }, 383 "contents": "Hello, Bob!" 384 } 385 } 386 ` 387 var malformedDomainTypedData core.TypedData 388 err := json.Unmarshal([]byte(jsonTypedData), &malformedDomainTypedData) 389 if err != nil { 390 t.Fatalf("unmarshalling failed '%v'", err) 391 } 392 _, err = malformedDomainTypedData.HashStruct("EIP712Domain", malformedDomainTypedData.Domain.Map()) 393 if err == nil || err.Error() != "provided data '<nil>' doesn't match type 'address'" { 394 t.Errorf("Expected `provided data '<nil>' doesn't match type 'address'`, got '%v'", err) 395 } 396 } 397 398 func TestMalformedTypesAndExtradata(t *testing.T) { 399 // Verifies several quirks 400 // 1. Using dynamic types and only validating the prefix: 401 //{ 402 // "name": "chainId", 403 // "type": "uint256 ... and now for something completely different" 404 //} 405 // 2. Extra data in message: 406 //{ 407 // "blahonga": "zonk bonk" 408 //} 409 jsonTypedData := ` 410 { 411 "types": { 412 "EIP712Domain": [ 413 { 414 "name": "name", 415 "type": "string" 416 }, 417 { 418 "name": "version", 419 "type": "string" 420 }, 421 { 422 "name": "chainId", 423 "type": "uint256 ... and now for something completely different" 424 }, 425 { 426 "name": "verifyingContract", 427 "type": "address" 428 } 429 ], 430 "Person": [ 431 { 432 "name": "name", 433 "type": "string" 434 }, 435 { 436 "name": "wallet", 437 "type": "address" 438 } 439 ], 440 "Mail": [ 441 { 442 "name": "from", 443 "type": "Person" 444 }, 445 { 446 "name": "to", 447 "type": "Person" 448 }, 449 { 450 "name": "contents", 451 "type": "string" 452 } 453 ] 454 }, 455 "primaryType": "Mail", 456 "domain": { 457 "name": "Ether Mail", 458 "version": "1", 459 "chainId": 1, 460 "verifyingContract": "0xCCCcccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" 461 }, 462 "message": { 463 "from": { 464 "name": "Cow", 465 "wallet": "0xcD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" 466 }, 467 "to": { 468 "name": "Bob", 469 "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" 470 }, 471 "contents": "Hello, Bob!" 472 } 473 } 474 ` 475 var malformedTypedData core.TypedData 476 err := json.Unmarshal([]byte(jsonTypedData), &malformedTypedData) 477 if err != nil { 478 t.Fatalf("unmarshalling failed '%v'", err) 479 } 480 481 malformedTypedData.Types["EIP712Domain"][2].Type = "uint256" 482 malformedTypedData.Message["blahonga"] = "zonk bonk" 483 _, err = malformedTypedData.HashStruct(malformedTypedData.PrimaryType, malformedTypedData.Message) 484 if err == nil || err.Error() != "there is extra data provided in the message" { 485 t.Errorf("Expected `there is extra data provided in the message`, got '%v'", err) 486 } 487 } 488 489 func TestTypeMismatch(t *testing.T) { 490 // Verifies that: 491 // 1. Mismatches between the given type and data, i.e. `Person` and 492 // the data item is a string, are properly caught: 493 //{ 494 // "name": "contents", 495 // "type": "Person" 496 //}, 497 //{ 498 // "contents": "Hello, Bob!" <-- string not "Person" 499 //} 500 // 2. Nonexistent types are properly caught: 501 //{ 502 // "name": "contents", 503 // "type": "Blahonga" 504 //} 505 jsonTypedData := ` 506 { 507 "types": { 508 "EIP712Domain": [ 509 { 510 "name": "name", 511 "type": "string" 512 }, 513 { 514 "name": "version", 515 "type": "string" 516 }, 517 { 518 "name": "chainId", 519 "type": "uint256" 520 }, 521 { 522 "name": "verifyingContract", 523 "type": "address" 524 } 525 ], 526 "Person": [ 527 { 528 "name": "name", 529 "type": "string" 530 }, 531 { 532 "name": "wallet", 533 "type": "address" 534 } 535 ], 536 "Mail": [ 537 { 538 "name": "from", 539 "type": "Person" 540 }, 541 { 542 "name": "to", 543 "type": "Person" 544 }, 545 { 546 "name": "contents", 547 "type": "Person" 548 } 549 ] 550 }, 551 "primaryType": "Mail", 552 "domain": { 553 "name": "Ether Mail", 554 "version": "1", 555 "chainId": 1, 556 "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" 557 }, 558 "message": { 559 "from": { 560 "name": "Cow", 561 "wallet": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" 562 }, 563 "to": { 564 "name": "Bob", 565 "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" 566 }, 567 "contents": "Hello, Bob!" 568 } 569 } 570 ` 571 var mismatchTypedData core.TypedData 572 err := json.Unmarshal([]byte(jsonTypedData), &mismatchTypedData) 573 if err != nil { 574 t.Fatalf("unmarshalling failed '%v'", err) 575 } 576 _, err = mismatchTypedData.HashStruct(mismatchTypedData.PrimaryType, mismatchTypedData.Message) 577 if err.Error() != "provided data 'Hello, Bob!' doesn't match type 'Person'" { 578 t.Errorf("Expected `provided data 'Hello, Bob!' doesn't match type 'Person'`, got '%v'", err) 579 } 580 581 mismatchTypedData.Types["Mail"][2].Type = "Blahonga" 582 _, err = mismatchTypedData.HashStruct(mismatchTypedData.PrimaryType, mismatchTypedData.Message) 583 if err == nil || err.Error() != "reference type 'Blahonga' is undefined" { 584 t.Fatalf("Expected `reference type 'Blahonga' is undefined`, got '%v'", err) 585 } 586 } 587 588 func TestTypeOverflow(t *testing.T) { 589 // Verifies data that doesn't fit into it: 590 //{ 591 // "test": 65536 <-- test defined as uint8 592 //} 593 var overflowTypedData core.TypedData 594 err := json.Unmarshal([]byte(jsonTypedData), &overflowTypedData) 595 if err != nil { 596 t.Fatalf("unmarshalling failed '%v'", err) 597 } 598 // Set test to something outside uint8 599 (overflowTypedData.Message["from"]).(map[string]interface{})["test"] = big.NewInt(65536) 600 601 _, err = overflowTypedData.HashStruct(overflowTypedData.PrimaryType, overflowTypedData.Message) 602 if err == nil || err.Error() != "integer larger than 'uint8'" { 603 t.Fatalf("Expected `integer larger than 'uint8'`, got '%v'", err) 604 } 605 606 (overflowTypedData.Message["from"]).(map[string]interface{})["test"] = big.NewInt(3) 607 (overflowTypedData.Message["to"]).(map[string]interface{})["test"] = big.NewInt(4) 608 609 _, err = overflowTypedData.HashStruct(overflowTypedData.PrimaryType, overflowTypedData.Message) 610 if err != nil { 611 t.Fatalf("Expected no err, got '%v'", err) 612 } 613 } 614 615 func TestArray(t *testing.T) { 616 // Makes sure that arrays work fine 617 //{ 618 // "type": "address[]" 619 //}, 620 //{ 621 // "type": "string[]" 622 //}, 623 //{ 624 // "type": "uint16[]", 625 //} 626 627 jsonTypedData := ` 628 { 629 "types": { 630 "EIP712Domain": [ 631 { 632 "name": "name", 633 "type": "string" 634 }, 635 { 636 "name": "version", 637 "type": "string" 638 }, 639 { 640 "name": "chainId", 641 "type": "uint256" 642 }, 643 { 644 "name": "verifyingContract", 645 "type": "address" 646 } 647 ], 648 "Foo": [ 649 { 650 "name": "bar", 651 "type": "address[]" 652 } 653 ] 654 }, 655 "primaryType": "Foo", 656 "domain": { 657 "name": "Lorem", 658 "version": "1", 659 "chainId": 1, 660 "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" 661 }, 662 "message": { 663 "bar": [ 664 "0x0000000000000000000000000000000000000001", 665 "0x0000000000000000000000000000000000000002", 666 "0x0000000000000000000000000000000000000003" 667 ] 668 } 669 } 670 ` 671 var arrayTypedData core.TypedData 672 err := json.Unmarshal([]byte(jsonTypedData), &arrayTypedData) 673 if err != nil { 674 t.Fatalf("unmarshalling failed '%v'", err) 675 } 676 _, err = arrayTypedData.HashStruct(arrayTypedData.PrimaryType, arrayTypedData.Message) 677 if err != nil { 678 t.Fatalf("Expected no err, got '%v'", err) 679 } 680 681 // Change array to string 682 arrayTypedData.Types["Foo"][0].Type = "string[]" 683 arrayTypedData.Message["bar"] = []interface{}{ 684 "lorem", 685 "ipsum", 686 "dolores", 687 } 688 _, err = arrayTypedData.HashStruct(arrayTypedData.PrimaryType, arrayTypedData.Message) 689 if err != nil { 690 t.Fatalf("Expected no err, got '%v'", err) 691 } 692 693 // Change array to uint 694 arrayTypedData.Types["Foo"][0].Type = "uint[]" 695 arrayTypedData.Message["bar"] = []interface{}{ 696 big.NewInt(1955), 697 big.NewInt(108), 698 big.NewInt(44010), 699 } 700 _, err = arrayTypedData.HashStruct(arrayTypedData.PrimaryType, arrayTypedData.Message) 701 if err != nil { 702 t.Fatalf("Expected no err, got '%v'", err) 703 } 704 705 // Should not work with fixed-size arrays 706 arrayTypedData.Types["Foo"][0].Type = "uint[3]" 707 _, err = arrayTypedData.HashStruct(arrayTypedData.PrimaryType, arrayTypedData.Message) 708 if err == nil || err.Error() != "unknown type 'uint[3]'" { 709 t.Fatalf("Expected `unknown type 'uint[3]'`, got '%v'", err) 710 } 711 } 712 713 func TestCustomTypeAsArray(t *testing.T) { 714 var jsonTypedData = ` 715 { 716 "types": { 717 "EIP712Domain": [ 718 { 719 "name": "name", 720 "type": "string" 721 }, 722 { 723 "name": "version", 724 "type": "string" 725 }, 726 { 727 "name": "chainId", 728 "type": "uint256" 729 }, 730 { 731 "name": "verifyingContract", 732 "type": "address" 733 } 734 ], 735 "Person": [ 736 { 737 "name": "name", 738 "type": "string" 739 }, 740 { 741 "name": "wallet", 742 "type": "address" 743 } 744 ], 745 "Person[]": [ 746 { 747 "name": "baz", 748 "type": "string" 749 } 750 ], 751 "Mail": [ 752 { 753 "name": "from", 754 "type": "Person" 755 }, 756 { 757 "name": "to", 758 "type": "Person[]" 759 }, 760 { 761 "name": "contents", 762 "type": "string" 763 } 764 ] 765 }, 766 "primaryType": "Mail", 767 "domain": { 768 "name": "Ether Mail", 769 "version": "1", 770 "chainId": 1, 771 "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" 772 }, 773 "message": { 774 "from": { 775 "name": "Cow", 776 "wallet": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" 777 }, 778 "to": {"baz": "foo"}, 779 "contents": "Hello, Bob!" 780 } 781 } 782 783 ` 784 var malformedTypedData core.TypedData 785 err := json.Unmarshal([]byte(jsonTypedData), &malformedTypedData) 786 if err != nil { 787 t.Fatalf("unmarshalling failed '%v'", err) 788 } 789 _, err = malformedTypedData.HashStruct("EIP712Domain", malformedTypedData.Domain.Map()) 790 if err != nil { 791 t.Errorf("Expected no error, got '%v'", err) 792 } 793 } 794 795 func TestFormatter(t *testing.T) { 796 var d core.TypedData 797 err := json.Unmarshal([]byte(jsonTypedData), &d) 798 if err != nil { 799 t.Fatalf("unmarshalling failed '%v'", err) 800 } 801 formatted := d.Format() 802 for _, item := range formatted { 803 fmt.Printf("'%v'\n", item.Pprint(0)) 804 } 805 806 j, _ := json.Marshal(formatted) 807 fmt.Printf("'%v'\n", string(j)) 808 }