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  }