| // Copyright 2023 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| package main | |
| import ( | |
| "bytes" | |
| "encoding/json" | |
| "flag" | |
| "fmt" | |
| "go/build/constraint" | |
| "math/rand" | |
| "os" | |
| "path/filepath" | |
| "strings" | |
| "testing" | |
| "golang.org/x/tools/internal/bisect" | |
| "golang.org/x/tools/internal/diffp" | |
| "golang.org/x/tools/txtar" | |
| ) | |
| var update = flag.Bool("update", false, "update testdata with new stdout/stderr") | |
| func Test(t *testing.T) { | |
| files, err := filepath.Glob("testdata/*.txt") | |
| if err != nil { | |
| t.Fatal(err) | |
| } | |
| for _, file := range files { | |
| t.Run(strings.TrimSuffix(filepath.Base(file), ".txt"), func(t *testing.T) { | |
| data, err := os.ReadFile(file) | |
| if err != nil { | |
| t.Fatal(err) | |
| } | |
| a := txtar.Parse(data) | |
| var wantStdout, wantStderr []byte | |
| files := a.Files | |
| if len(files) > 0 && files[0].Name == "stdout" { | |
| wantStdout = files[0].Data | |
| files = files[1:] | |
| } | |
| if len(files) > 0 && files[0].Name == "stderr" { | |
| wantStderr = files[0].Data | |
| files = files[1:] | |
| } | |
| if len(files) > 0 { | |
| t.Fatalf("unexpected txtar entry: %s", files[0].Name) | |
| } | |
| var tt struct { | |
| Fail string | |
| Bisect Bisect | |
| } | |
| if err := json.Unmarshal(a.Comment, &tt); err != nil { | |
| t.Fatal(err) | |
| } | |
| expr, err := constraint.Parse("//go:build " + tt.Fail) | |
| if err != nil { | |
| t.Fatalf("invalid Cmd: %v", err) | |
| } | |
| rnd := rand.New(rand.NewSource(1)) | |
| b := &tt.Bisect | |
| b.Cmd = "test" | |
| b.Args = []string{"PATTERN"} | |
| var stdout, stderr bytes.Buffer | |
| b.Stdout = &stdout | |
| b.Stderr = &stderr | |
| b.TestRun = func(env []string, cmd string, args []string) (out []byte, err error) { | |
| pattern := args[0] | |
| m, err := bisect.New(pattern) | |
| if err != nil { | |
| t.Fatal(err) | |
| } | |
| have := make(map[string]bool) | |
| for i, color := range colors { | |
| if m.ShouldEnable(uint64(i)) { | |
| have[color] = true | |
| } | |
| if m.ShouldReport(uint64(i)) { | |
| out = fmt.Appendf(out, "%s %s\n", color, bisect.Marker(uint64(i))) | |
| } | |
| } | |
| err = nil | |
| if eval(rnd, expr, have) { | |
| err = fmt.Errorf("failed") | |
| } | |
| return out, err | |
| } | |
| if !b.Search() { | |
| stderr.WriteString("<bisect failed>\n") | |
| } | |
| rewrite := false | |
| if !bytes.Equal(stdout.Bytes(), wantStdout) { | |
| if *update { | |
| rewrite = true | |
| } else { | |
| t.Errorf("incorrect stdout: %s", diffp.Diff("have", stdout.Bytes(), "want", wantStdout)) | |
| } | |
| } | |
| if !bytes.Equal(stderr.Bytes(), wantStderr) { | |
| if *update { | |
| rewrite = true | |
| } else { | |
| t.Errorf("incorrect stderr: %s", diffp.Diff("have", stderr.Bytes(), "want", wantStderr)) | |
| } | |
| } | |
| if rewrite { | |
| a.Files = []txtar.File{{Name: "stdout", Data: stdout.Bytes()}, {Name: "stderr", Data: stderr.Bytes()}} | |
| err := os.WriteFile(file, txtar.Format(a), 0666) | |
| if err != nil { | |
| t.Fatal(err) | |
| } | |
| t.Logf("updated %s", file) | |
| } | |
| }) | |
| } | |
| } | |
| func eval(rnd *rand.Rand, z constraint.Expr, have map[string]bool) bool { | |
| switch z := z.(type) { | |
| default: | |
| panic(fmt.Sprintf("unexpected type %T", z)) | |
| case *constraint.NotExpr: | |
| return !eval(rnd, z.X, have) | |
| case *constraint.AndExpr: | |
| return eval(rnd, z.X, have) && eval(rnd, z.Y, have) | |
| case *constraint.OrExpr: | |
| return eval(rnd, z.X, have) || eval(rnd, z.Y, have) | |
| case *constraint.TagExpr: | |
| if z.Tag == "random" { | |
| return rnd.Intn(2) == 1 | |
| } | |
| return have[z.Tag] | |
| } | |
| } | |
| var colors = strings.Fields(` | |
| aliceblue | |
| amaranth | |
| amber | |
| amethyst | |
| applegreen | |
| applered | |
| apricot | |
| aquamarine | |
| azure | |
| babyblue | |
| beige | |
| brickred | |
| black | |
| blue | |
| bluegreen | |
| blueviolet | |
| blush | |
| bronze | |
| brown | |
| burgundy | |
| byzantium | |
| carmine | |
| cerise | |
| cerulean | |
| champagne | |
| chartreusegreen | |
| chocolate | |
| cobaltblue | |
| coffee | |
| copper | |
| coral | |
| crimson | |
| cyan | |
| desertsand | |
| electricblue | |
| emerald | |
| erin | |
| gold | |
| gray | |
| green | |
| harlequin | |
| indigo | |
| ivory | |
| jade | |
| junglegreen | |
| lavender | |
| lemon | |
| lilac | |
| lime | |
| magenta | |
| magentarose | |
| maroon | |
| mauve | |
| navyblue | |
| ochre | |
| olive | |
| orange | |
| orangered | |
| orchid | |
| peach | |
| pear | |
| periwinkle | |
| persianblue | |
| pink | |
| plum | |
| prussianblue | |
| puce | |
| purple | |
| raspberry | |
| red | |
| redviolet | |
| rose | |
| ruby | |
| salmon | |
| sangria | |
| sapphire | |
| scarlet | |
| silver | |
| slategray | |
| springbud | |
| springgreen | |
| tan | |
| taupe | |
| teal | |
| turquoise | |
| ultramarine | |
| violet | |
| viridian | |
| white | |
| yellow | |
| `) |