github.com/klaytn/klaytn@v1.12.1/tests/rlp_test_util.go (about) 1 // Modifications Copyright 2018 The klaytn Authors 2 // Copyright 2015 The go-ethereum Authors 3 // This file is part of the go-ethereum library. 4 // 5 // The go-ethereum 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-ethereum 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-ethereum library. If not, see <http://www.gnu.org/licenses/>. 17 // 18 // This file is derived from tests/rlp_test_util.go (2018/06/04). 19 // Modified and improved for the klaytn development. 20 21 package tests 22 23 import ( 24 "bytes" 25 "encoding/hex" 26 "errors" 27 "fmt" 28 "math/big" 29 "strings" 30 31 "github.com/klaytn/klaytn/rlp" 32 ) 33 34 // RLPTest is the JSON structure of a single RLP test. 35 type RLPTest struct { 36 // If the value of In is "INVALID" or "VALID", the test 37 // checks whether Out can be decoded into a value of 38 // type interface{}. 39 // 40 // For other JSON values, In is treated as a driver for 41 // calls to rlp.Stream. The test also verifies that encoding 42 // In produces the bytes in Out. 43 In interface{} 44 45 // Out is a hex-encoded RLP value. 46 Out string 47 } 48 49 // Run executes the test. 50 func (t *RLPTest) Run() error { 51 outb, err := hex.DecodeString(t.Out) 52 if err != nil { 53 return fmt.Errorf("invalid hex in Out") 54 } 55 56 // Handle simple decoding tests with no actual In value. 57 if t.In == "VALID" || t.In == "INVALID" { 58 return checkDecodeInterface(outb, t.In == "VALID") 59 } 60 61 // Check whether encoding the value produces the same bytes. 62 in := translateJSON(t.In) 63 b, err := rlp.EncodeToBytes(in) 64 if err != nil { 65 return fmt.Errorf("encode failed: %v", err) 66 } 67 if !bytes.Equal(b, outb) { 68 return fmt.Errorf("encode produced %x, want %x", b, outb) 69 } 70 // Test stream decoding. 71 s := rlp.NewStream(bytes.NewReader(outb), 0) 72 return checkDecodeFromJSON(s, in) 73 } 74 75 func checkDecodeInterface(b []byte, isValid bool) error { 76 err := rlp.DecodeBytes(b, new(interface{})) 77 switch { 78 case isValid && err != nil: 79 return fmt.Errorf("decoding failed: %v", err) 80 case !isValid && err == nil: 81 return fmt.Errorf("decoding of invalid value succeeded") 82 } 83 return nil 84 } 85 86 // translateJSON makes test json values encodable with RLP. 87 func translateJSON(v interface{}) interface{} { 88 switch v := v.(type) { 89 case float64: 90 return uint64(v) 91 case string: 92 if len(v) > 0 && v[0] == '#' { // # starts a faux big int. 93 big, ok := new(big.Int).SetString(v[1:], 10) 94 if !ok { 95 panic(fmt.Errorf("bad test: bad big int: %q", v)) 96 } 97 return big 98 } 99 return []byte(v) 100 case []interface{}: 101 new := make([]interface{}, len(v)) 102 for i := range v { 103 new[i] = translateJSON(v[i]) 104 } 105 return new 106 default: 107 panic(fmt.Errorf("can't handle %T", v)) 108 } 109 } 110 111 // checkDecodeFromJSON decodes from s guided by exp. exp drives the 112 // Stream by invoking decoding operations (Uint, Big, List, ...) based 113 // on the type of each value. The value decoded from the RLP stream 114 // must match the JSON value. 115 func checkDecodeFromJSON(s *rlp.Stream, exp interface{}) error { 116 switch exp := exp.(type) { 117 case uint64: 118 i, err := s.Uint() 119 if err != nil { 120 return addStack("Uint", exp, err) 121 } 122 if i != exp { 123 return addStack("Uint", exp, fmt.Errorf("result mismatch: got %d", i)) 124 } 125 case *big.Int: 126 big := new(big.Int) 127 if err := s.Decode(&big); err != nil { 128 return addStack("Big", exp, err) 129 } 130 if big.Cmp(exp) != 0 { 131 return addStack("Big", exp, fmt.Errorf("result mismatch: got %d", big)) 132 } 133 case []byte: 134 b, err := s.Bytes() 135 if err != nil { 136 return addStack("Bytes", exp, err) 137 } 138 if !bytes.Equal(b, exp) { 139 return addStack("Bytes", exp, fmt.Errorf("result mismatch: got %x", b)) 140 } 141 case []interface{}: 142 if _, err := s.List(); err != nil { 143 return addStack("List", exp, err) 144 } 145 for i, v := range exp { 146 if err := checkDecodeFromJSON(s, v); err != nil { 147 return addStack(fmt.Sprintf("[%d]", i), exp, err) 148 } 149 } 150 if err := s.ListEnd(); err != nil { 151 return addStack("ListEnd", exp, err) 152 } 153 default: 154 panic(fmt.Errorf("unhandled type: %T", exp)) 155 } 156 return nil 157 } 158 159 func addStack(op string, val interface{}, err error) error { 160 lines := strings.Split(err.Error(), "\n") 161 lines = append(lines, fmt.Sprintf("\t%s: %v", op, val)) 162 return errors.New(strings.Join(lines, "\n")) 163 }