github.com/aigarnetwork/aigar@v0.0.0-20191115204914-d59a6eb70f8e/tests/rlp_test_util.go (about) 1 // Copyright 2018 The go-ethereum Authors 2 // Copyright 2019 The go-aigar Authors 3 // This file is part of the go-aigar library. 4 // 5 // The go-aigar library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-aigar library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-aigar library. If not, see <http://www.gnu.org/licenses/>. 17 18 package tests 19 20 import ( 21 "bytes" 22 "encoding/hex" 23 "errors" 24 "fmt" 25 "math/big" 26 "strings" 27 28 "github.com/AigarNetwork/aigar/rlp" 29 ) 30 31 // RLPTest is the JSON structure of a single RLP test. 32 type RLPTest struct { 33 // If the value of In is "INVALID" or "VALID", the test 34 // checks whether Out can be decoded into a value of 35 // type interface{}. 36 // 37 // For other JSON values, In is treated as a driver for 38 // calls to rlp.Stream. The test also verifies that encoding 39 // In produces the bytes in Out. 40 In interface{} 41 42 // Out is a hex-encoded RLP value. 43 Out string 44 } 45 46 // FromHex returns the bytes represented by the hexadecimal string s. 47 // s may be prefixed with "0x". 48 // This is copy-pasted from bytes.go, which does not return the error 49 func FromHex(s string) ([]byte, error) { 50 if len(s) > 1 && (s[0:2] == "0x" || s[0:2] == "0X") { 51 s = s[2:] 52 } 53 if len(s)%2 == 1 { 54 s = "0" + s 55 } 56 return hex.DecodeString(s) 57 } 58 59 // Run executes the test. 60 func (t *RLPTest) Run() error { 61 outb, err := FromHex(t.Out) 62 if err != nil { 63 return fmt.Errorf("invalid hex in Out") 64 } 65 66 // Handle simple decoding tests with no actual In value. 67 if t.In == "VALID" || t.In == "INVALID" { 68 return checkDecodeInterface(outb, t.In == "VALID") 69 } 70 71 // Check whether encoding the value produces the same bytes. 72 in := translateJSON(t.In) 73 b, err := rlp.EncodeToBytes(in) 74 if err != nil { 75 return fmt.Errorf("encode failed: %v", err) 76 } 77 if !bytes.Equal(b, outb) { 78 return fmt.Errorf("encode produced %x, want %x", b, outb) 79 } 80 // Test stream decoding. 81 s := rlp.NewStream(bytes.NewReader(outb), 0) 82 return checkDecodeFromJSON(s, in) 83 } 84 85 func checkDecodeInterface(b []byte, isValid bool) error { 86 err := rlp.DecodeBytes(b, new(interface{})) 87 switch { 88 case isValid && err != nil: 89 return fmt.Errorf("decoding failed: %v", err) 90 case !isValid && err == nil: 91 return fmt.Errorf("decoding of invalid value succeeded") 92 } 93 return nil 94 } 95 96 // translateJSON makes test json values encodable with RLP. 97 func translateJSON(v interface{}) interface{} { 98 switch v := v.(type) { 99 case float64: 100 return uint64(v) 101 case string: 102 if len(v) > 0 && v[0] == '#' { // # starts a faux big int. 103 big, ok := new(big.Int).SetString(v[1:], 10) 104 if !ok { 105 panic(fmt.Errorf("bad test: bad big int: %q", v)) 106 } 107 return big 108 } 109 return []byte(v) 110 case []interface{}: 111 new := make([]interface{}, len(v)) 112 for i := range v { 113 new[i] = translateJSON(v[i]) 114 } 115 return new 116 default: 117 panic(fmt.Errorf("can't handle %T", v)) 118 } 119 } 120 121 // checkDecodeFromJSON decodes from s guided by exp. exp drives the 122 // Stream by invoking decoding operations (Uint, Big, List, ...) based 123 // on the type of each value. The value decoded from the RLP stream 124 // must match the JSON value. 125 func checkDecodeFromJSON(s *rlp.Stream, exp interface{}) error { 126 switch exp := exp.(type) { 127 case uint64: 128 i, err := s.Uint() 129 if err != nil { 130 return addStack("Uint", exp, err) 131 } 132 if i != exp { 133 return addStack("Uint", exp, fmt.Errorf("result mismatch: got %d", i)) 134 } 135 case *big.Int: 136 big := new(big.Int) 137 if err := s.Decode(&big); err != nil { 138 return addStack("Big", exp, err) 139 } 140 if big.Cmp(exp) != 0 { 141 return addStack("Big", exp, fmt.Errorf("result mismatch: got %d", big)) 142 } 143 case []byte: 144 b, err := s.Bytes() 145 if err != nil { 146 return addStack("Bytes", exp, err) 147 } 148 if !bytes.Equal(b, exp) { 149 return addStack("Bytes", exp, fmt.Errorf("result mismatch: got %x", b)) 150 } 151 case []interface{}: 152 if _, err := s.List(); err != nil { 153 return addStack("List", exp, err) 154 } 155 for i, v := range exp { 156 if err := checkDecodeFromJSON(s, v); err != nil { 157 return addStack(fmt.Sprintf("[%d]", i), exp, err) 158 } 159 } 160 if err := s.ListEnd(); err != nil { 161 return addStack("ListEnd", exp, err) 162 } 163 default: 164 panic(fmt.Errorf("unhandled type: %T", exp)) 165 } 166 return nil 167 } 168 169 func addStack(op string, val interface{}, err error) error { 170 lines := strings.Split(err.Error(), "\n") 171 lines = append(lines, fmt.Sprintf("\t%s: %v", op, val)) 172 return errors.New(strings.Join(lines, "\n")) 173 }