github.com/cockroachdb/tools@v0.0.0-20230222021103-a6d27438930d/internal/typesinternal/errorcode_test.go (about) 1 // Copyright 2022 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package typesinternal_test 6 7 import ( 8 "fmt" 9 "go/ast" 10 "go/constant" 11 "go/parser" 12 "go/token" 13 "go/types" 14 "path/filepath" 15 "runtime" 16 "sort" 17 "strings" 18 "testing" 19 ) 20 21 func TestErrorCodes(t *testing.T) { 22 t.Skip("unskip this test to verify the correctness of errorcode.go for the current Go version") 23 24 // For older go versions, this file was src/go/types/errorcodes.go. 25 stdPath := filepath.Join(runtime.GOROOT(), "src", "internal", "types", "errors", "codes.go") 26 stdCodes, err := loadCodes(stdPath) 27 if err != nil { 28 t.Fatalf("loading std codes: %v", err) 29 } 30 31 localPath := "errorcode.go" 32 localCodes, err := loadCodes(localPath) 33 if err != nil { 34 t.Fatalf("loading local codes: %v", err) 35 } 36 37 // Verify that all std codes are present, with the correct value. 38 type codeVal struct { 39 Name string 40 Value int64 41 } 42 var byValue []codeVal 43 for k, v := range stdCodes { 44 byValue = append(byValue, codeVal{k, v}) 45 } 46 sort.Slice(byValue, func(i, j int) bool { 47 return byValue[i].Value < byValue[j].Value 48 }) 49 50 localLookup := make(map[int64]string) 51 for k, v := range localCodes { 52 if _, ok := localLookup[v]; ok { 53 t.Errorf("duplicate error code value %d", v) 54 } 55 localLookup[v] = k 56 } 57 58 for _, std := range byValue { 59 local, ok := localCodes[std.Name] 60 if !ok { 61 if v, ok := localLookup[std.Value]; ok { 62 t.Errorf("Missing code for %s (code %d is %s)", std.Name, std.Value, v) 63 } else { 64 t.Errorf("Missing code for %s", std.Name) 65 } 66 } 67 if local != std.Value { 68 t.Errorf("Mismatching value for %s: got %d, but stdlib has %d", std.Name, local, std.Value) 69 } 70 } 71 } 72 73 // loadCodes loads all constant values found in filepath. 74 // 75 // The given file must type-check cleanly as a standalone file. 76 func loadCodes(filepath string) (map[string]int64, error) { 77 fset := token.NewFileSet() 78 f, err := parser.ParseFile(fset, filepath, nil, 0) 79 if err != nil { 80 return nil, err 81 } 82 var config types.Config 83 pkg, err := config.Check("p", fset, []*ast.File{f}, nil) 84 if err != nil { 85 return nil, err 86 } 87 88 codes := make(map[string]int64) 89 for _, name := range pkg.Scope().Names() { 90 obj := pkg.Scope().Lookup(name) 91 c, ok := obj.(*types.Const) 92 if !ok { 93 continue 94 } 95 name := strings.TrimPrefix(name, "_") // compatibility with earlier go versions 96 codes[name], ok = constant.Int64Val(c.Val()) 97 if !ok { 98 return nil, fmt.Errorf("non integral value %v for %s", c.Val(), name) 99 } 100 } 101 if len(codes) < 100 { 102 return nil, fmt.Errorf("sanity check: got %d codes but expected at least 100", len(codes)) 103 } 104 return codes, nil 105 }