github.com/jxskiss/gopkg/v2@v2.14.9-0.20240514120614-899f3e7952b4/internal/linkname/source_test.go (about) 1 package linkname 2 3 import ( 4 "context" 5 "fmt" 6 "io" 7 "net/http" 8 "regexp" 9 "strconv" 10 "strings" 11 "testing" 12 "time" 13 "unicode" 14 15 "github.com/stretchr/testify/assert" 16 "github.com/stretchr/testify/require" 17 ) 18 19 type SourceCodeTestCase struct { 20 MinVer, MaxVer int 21 FileName string 22 Lines []string 23 } 24 25 func newVer(major, minor, patch int) int { 26 return major*1_000_000 + minor*1_000 + patch 27 } 28 29 func parseGoVer(ver string) int { 30 ver = strings.TrimPrefix(ver, "go") 31 if x := strings.IndexFunc(ver, func(r rune) bool { 32 return r != '.' && !unicode.IsDigit(r) 33 }); x > 0 { 34 ver = ver[:x] 35 } 36 parts := strings.Split(ver, ".") 37 intVer := 0 38 multiplier := [3]int{1_000_000, 1_000, 1} 39 for i := 0; i < 3 && i < len(parts); i++ { 40 x := parts[i] 41 a, err := strconv.Atoi(x) 42 if err != nil { 43 panic(err) 44 } 45 intVer += a * multiplier[i] 46 } 47 return intVer 48 } 49 50 func TestParseGoVer(t *testing.T) { 51 testCases := []struct { 52 str string 53 want int 54 }{ 55 {"go1.19", 1_019_000}, 56 {"go1.19.13", 1_019_013}, 57 {"go1.20", 1_020_000}, 58 {"go1.21.0", 1_021_000}, 59 {"go1.22rc2", 1_022_000}, 60 } 61 for _, tc := range testCases { 62 t.Run(tc.str, func(t *testing.T) { 63 assert.Equal(t, tc.want, parseGoVer(tc.str)) 64 }) 65 } 66 } 67 68 func TestSourceCode(t *testing.T) { 69 versions := []string{ 70 "go1.19", 71 "go1.20", 72 "go1.20.13", 73 "go1.21.0", 74 "go1.21.6", 75 "go1.22.0", 76 "master", 77 } 78 79 fileURLTmpl := "https://raw.githubusercontent.com/golang/go/%s/src/%s" 80 81 for _, goVersion := range versions { 82 var intVer int 83 if goVersion == "master" { 84 intVer = newVer(1, 999, 999) 85 } else { 86 intVer = parseGoVer(goVersion) 87 } 88 89 // reflect source code 90 for _, code := range reflectSourceCode { 91 if (code.MinVer > 0 && intVer < code.MinVer) || 92 (code.MaxVer > 0 && intVer > code.MaxVer) { 93 continue 94 } 95 96 testName := fmt.Sprintf("%s / %s", goVersion, code.FileName) 97 t.Run(testName, func(t *testing.T) { 98 fileURL := fmt.Sprintf(fileURLTmpl, goVersion, code.FileName) 99 content, err := getFileContent(fileURL) 100 require.Nil(t, err) 101 102 for _, line := range code.Lines { 103 rePattern := `(?m)^` + regexp.QuoteMeta(line) + `($|\s*\{.*)` 104 re := regexp.MustCompile(rePattern) 105 match := re.MatchString(content) 106 assert.Truef(t, match, "line= %q", line) 107 } 108 }) 109 } 110 111 // runtime source code 112 for _, code := range runtimeSourceCode { 113 if (code.MinVer > 0 && intVer < code.MinVer) || 114 (code.MaxVer > 0 && intVer > code.MaxVer) { 115 continue 116 } 117 118 testName := fmt.Sprintf("%s / %s", goVersion, code.FileName) 119 t.Run(testName, func(t *testing.T) { 120 fileURL := fmt.Sprintf(fileURLTmpl, goVersion, code.FileName) 121 content, err := getFileContent(fileURL) 122 require.Nil(t, err) 123 124 for _, line := range code.Lines { 125 rePattern := `(?m)^` + regexp.QuoteMeta(line) + `($|\s*\{.*)` 126 re := regexp.MustCompile(rePattern) 127 match := re.MatchString(content) 128 assert.Truef(t, match, "line= %q", line) 129 } 130 }) 131 } 132 } 133 } 134 135 func getFileContent(url string) (string, error) { 136 ctx, cancel := context.WithTimeout(context.Background(), time.Second) 137 defer cancel() 138 req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) 139 if err != nil { 140 return "", fmt.Errorf("failed new HTTP request: %w", err) 141 } 142 resp, err := http.DefaultClient.Do(req) 143 if err != nil { 144 return "", fmt.Errorf("failed get url %v: %w", url, err) 145 } 146 defer resp.Body.Close() 147 body, err := io.ReadAll(resp.Body) 148 if err != nil { 149 return "", fmt.Errorf("failed read HTTP response body: %v: %w", url, err) 150 } 151 return string(body), nil 152 }