gitee.com/liu-zhao234568/cntest@v1.0.0/tests/init_test.go (about) 1 // Copyright 2017 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser 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 // The go-ethereum library 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 Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package tests 18 19 import ( 20 "encoding/json" 21 "fmt" 22 "io" 23 "io/ioutil" 24 "os" 25 "path/filepath" 26 "reflect" 27 "regexp" 28 "runtime" 29 "sort" 30 "strings" 31 "testing" 32 33 "gitee.com/liu-zhao234568/cntest/params" 34 ) 35 36 var ( 37 baseDir = filepath.Join(".", "testdata") 38 blockTestDir = filepath.Join(baseDir, "BlockchainTests") 39 stateTestDir = filepath.Join(baseDir, "GeneralStateTests") 40 legacyStateTestDir = filepath.Join(baseDir, "LegacyTests", "Constantinople", "GeneralStateTests") 41 transactionTestDir = filepath.Join(baseDir, "TransactionTests") 42 vmTestDir = filepath.Join(baseDir, "VMTests") 43 rlpTestDir = filepath.Join(baseDir, "RLPTests") 44 difficultyTestDir = filepath.Join(baseDir, "BasicTests") 45 ) 46 47 func readJSON(reader io.Reader, value interface{}) error { 48 data, err := ioutil.ReadAll(reader) 49 if err != nil { 50 return fmt.Errorf("error reading JSON file: %v", err) 51 } 52 if err = json.Unmarshal(data, &value); err != nil { 53 if syntaxerr, ok := err.(*json.SyntaxError); ok { 54 line := findLine(data, syntaxerr.Offset) 55 return fmt.Errorf("JSON syntax error at line %v: %v", line, err) 56 } 57 return err 58 } 59 return nil 60 } 61 62 func readJSONFile(fn string, value interface{}) error { 63 file, err := os.Open(fn) 64 if err != nil { 65 return err 66 } 67 defer file.Close() 68 69 err = readJSON(file, value) 70 if err != nil { 71 return fmt.Errorf("%s in file %s", err.Error(), fn) 72 } 73 return nil 74 } 75 76 // findLine returns the line number for the given offset into data. 77 func findLine(data []byte, offset int64) (line int) { 78 line = 1 79 for i, r := range string(data) { 80 if int64(i) >= offset { 81 return 82 } 83 if r == '\n' { 84 line++ 85 } 86 } 87 return 88 } 89 90 // testMatcher controls skipping and chain config assignment to tests. 91 type testMatcher struct { 92 configpat []testConfig 93 failpat []testFailure 94 skiploadpat []*regexp.Regexp 95 slowpat []*regexp.Regexp 96 whitelistpat *regexp.Regexp 97 } 98 99 type testConfig struct { 100 p *regexp.Regexp 101 config params.ChainConfig 102 } 103 104 type testFailure struct { 105 p *regexp.Regexp 106 reason string 107 } 108 109 // skipShortMode skips tests matching when the -short flag is used. 110 func (tm *testMatcher) slow(pattern string) { 111 tm.slowpat = append(tm.slowpat, regexp.MustCompile(pattern)) 112 } 113 114 // skipLoad skips JSON loading of tests matching the pattern. 115 func (tm *testMatcher) skipLoad(pattern string) { 116 tm.skiploadpat = append(tm.skiploadpat, regexp.MustCompile(pattern)) 117 } 118 119 // fails adds an expected failure for tests matching the pattern. 120 func (tm *testMatcher) fails(pattern string, reason string) { 121 if reason == "" { 122 panic("empty fail reason") 123 } 124 tm.failpat = append(tm.failpat, testFailure{regexp.MustCompile(pattern), reason}) 125 } 126 127 func (tm *testMatcher) whitelist(pattern string) { 128 tm.whitelistpat = regexp.MustCompile(pattern) 129 } 130 131 // config defines chain config for tests matching the pattern. 132 func (tm *testMatcher) config(pattern string, cfg params.ChainConfig) { 133 tm.configpat = append(tm.configpat, testConfig{regexp.MustCompile(pattern), cfg}) 134 } 135 136 // findSkip matches name against test skip patterns. 137 func (tm *testMatcher) findSkip(name string) (reason string, skipload bool) { 138 isWin32 := runtime.GOARCH == "386" && runtime.GOOS == "windows" 139 for _, re := range tm.slowpat { 140 if re.MatchString(name) { 141 if testing.Short() { 142 return "skipped in -short mode", false 143 } 144 if isWin32 { 145 return "skipped on 32bit windows", false 146 } 147 } 148 } 149 for _, re := range tm.skiploadpat { 150 if re.MatchString(name) { 151 return "skipped by skipLoad", true 152 } 153 } 154 return "", false 155 } 156 157 // findConfig returns the chain config matching defined patterns. 158 func (tm *testMatcher) findConfig(t *testing.T) *params.ChainConfig { 159 for _, m := range tm.configpat { 160 if m.p.MatchString(t.Name()) { 161 return &m.config 162 } 163 } 164 return new(params.ChainConfig) 165 } 166 167 // checkFailure checks whether a failure is expected. 168 func (tm *testMatcher) checkFailure(t *testing.T, err error) error { 169 failReason := "" 170 for _, m := range tm.failpat { 171 if m.p.MatchString(t.Name()) { 172 failReason = m.reason 173 break 174 } 175 } 176 if failReason != "" { 177 t.Logf("expected failure: %s", failReason) 178 if err != nil { 179 t.Logf("error: %v", err) 180 return nil 181 } 182 return fmt.Errorf("test succeeded unexpectedly") 183 } 184 return err 185 } 186 187 // walk invokes its runTest argument for all subtests in the given directory. 188 // 189 // runTest should be a function of type func(t *testing.T, name string, x <TestType>), 190 // where TestType is the type of the test contained in test files. 191 func (tm *testMatcher) walk(t *testing.T, dir string, runTest interface{}) { 192 // Walk the directory. 193 dirinfo, err := os.Stat(dir) 194 if os.IsNotExist(err) || !dirinfo.IsDir() { 195 fmt.Fprintf(os.Stderr, "can't find test files in %s, did you clone the tests submodule?\n", dir) 196 t.Skip("missing test files") 197 } 198 err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { 199 name := filepath.ToSlash(strings.TrimPrefix(path, dir+string(filepath.Separator))) 200 if info.IsDir() { 201 if _, skipload := tm.findSkip(name + "/"); skipload { 202 return filepath.SkipDir 203 } 204 return nil 205 } 206 if filepath.Ext(path) == ".json" { 207 t.Run(name, func(t *testing.T) { tm.runTestFile(t, path, name, runTest) }) 208 } 209 return nil 210 }) 211 if err != nil { 212 t.Fatal(err) 213 } 214 } 215 216 func (tm *testMatcher) runTestFile(t *testing.T, path, name string, runTest interface{}) { 217 if r, _ := tm.findSkip(name); r != "" { 218 t.Skip(r) 219 } 220 if tm.whitelistpat != nil { 221 if !tm.whitelistpat.MatchString(name) { 222 t.Skip("Skipped by whitelist") 223 } 224 } 225 t.Parallel() 226 227 // Load the file as map[string]<testType>. 228 m := makeMapFromTestFunc(runTest) 229 if err := readJSONFile(path, m.Addr().Interface()); err != nil { 230 t.Fatal(err) 231 } 232 233 // Run all tests from the map. Don't wrap in a subtest if there is only one test in the file. 234 keys := sortedMapKeys(m) 235 if len(keys) == 1 { 236 runTestFunc(runTest, t, name, m, keys[0]) 237 } else { 238 for _, key := range keys { 239 name := name + "/" + key 240 t.Run(key, func(t *testing.T) { 241 if r, _ := tm.findSkip(name); r != "" { 242 t.Skip(r) 243 } 244 runTestFunc(runTest, t, name, m, key) 245 }) 246 } 247 } 248 } 249 250 func makeMapFromTestFunc(f interface{}) reflect.Value { 251 stringT := reflect.TypeOf("") 252 testingT := reflect.TypeOf((*testing.T)(nil)) 253 ftyp := reflect.TypeOf(f) 254 if ftyp.Kind() != reflect.Func || ftyp.NumIn() != 3 || ftyp.NumOut() != 0 || ftyp.In(0) != testingT || ftyp.In(1) != stringT { 255 panic(fmt.Sprintf("bad test function type: want func(*testing.T, string, <TestType>), have %s", ftyp)) 256 } 257 testType := ftyp.In(2) 258 mp := reflect.New(reflect.MapOf(stringT, testType)) 259 return mp.Elem() 260 } 261 262 func sortedMapKeys(m reflect.Value) []string { 263 keys := make([]string, m.Len()) 264 for i, k := range m.MapKeys() { 265 keys[i] = k.String() 266 } 267 sort.Strings(keys) 268 return keys 269 } 270 271 func runTestFunc(runTest interface{}, t *testing.T, name string, m reflect.Value, key string) { 272 reflect.ValueOf(runTest).Call([]reflect.Value{ 273 reflect.ValueOf(t), 274 reflect.ValueOf(name), 275 m.MapIndex(reflect.ValueOf(key)), 276 }) 277 } 278 279 func TestMatcherWhitelist(t *testing.T) { 280 t.Parallel() 281 tm := new(testMatcher) 282 tm.whitelist("invalid*") 283 tm.walk(t, rlpTestDir, func(t *testing.T, name string, test *RLPTest) { 284 if name[:len("invalidRLPTest.json")] != "invalidRLPTest.json" { 285 t.Fatalf("invalid test found: %s != invalidRLPTest.json", name) 286 } 287 }) 288 }