liyujie
2025-08-28 d9927380ed7c8366f762049be9f3fee225860833
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
// Copyright 2009 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 testing
 
import (
   "fmt"
   "io"
   "os"
   "sort"
   "strings"
   "time"
)
 
type InternalExample struct {
   Name      string
   F         func()
   Output    string
   Unordered bool
}
 
// An internal function but exported because it is cross-package; part of the implementation
// of the "go test" command.
func RunExamples(matchString func(pat, str string) (bool, error), examples []InternalExample) (ok bool) {
   _, ok = runExamples(matchString, examples)
   return ok
}
 
func runExamples(matchString func(pat, str string) (bool, error), examples []InternalExample) (ran, ok bool) {
   ok = true
 
   var eg InternalExample
 
   for _, eg = range examples {
       matched, err := matchString(*match, eg.Name)
       if err != nil {
           fmt.Fprintf(os.Stderr, "testing: invalid regexp for -test.run: %s\n", err)
           os.Exit(1)
       }
       if !matched {
           continue
       }
       ran = true
       if !runExample(eg) {
           ok = false
       }
   }
 
   return ran, ok
}
 
func sortLines(output string) string {
   lines := strings.Split(output, "\n")
   sort.Strings(lines)
   return strings.Join(lines, "\n")
}
 
func runExample(eg InternalExample) (ok bool) {
   if *chatty {
       fmt.Printf("=== RUN   %s\n", eg.Name)
   }
 
   // Capture stdout.
   stdout := os.Stdout
   r, w, err := os.Pipe()
   if err != nil {
       fmt.Fprintln(os.Stderr, err)
       os.Exit(1)
   }
   os.Stdout = w
   outC := make(chan string)
   go func() {
       var buf strings.Builder
       _, err := io.Copy(&buf, r)
       r.Close()
       if err != nil {
           fmt.Fprintf(os.Stderr, "testing: copying pipe: %v\n", err)
           os.Exit(1)
       }
       outC <- buf.String()
   }()
 
   start := time.Now()
   ok = true
 
   // Clean up in a deferred call so we can recover if the example panics.
   defer func() {
       dstr := fmtDuration(time.Since(start))
 
       // Close pipe, restore stdout, get output.
       w.Close()
       os.Stdout = stdout
       out := <-outC
 
       var fail string
       err := recover()
       got := strings.TrimSpace(out)
       want := strings.TrimSpace(eg.Output)
       if eg.Unordered {
           if sortLines(got) != sortLines(want) && err == nil {
               fail = fmt.Sprintf("got:\n%s\nwant (unordered):\n%s\n", out, eg.Output)
           }
       } else {
           if got != want && err == nil {
               fail = fmt.Sprintf("got:\n%s\nwant:\n%s\n", got, want)
           }
       }
       if fail != "" || err != nil {
           fmt.Printf("--- FAIL: %s (%s)\n%s", eg.Name, dstr, fail)
           ok = false
       } else if *chatty {
           fmt.Printf("--- PASS: %s (%s)\n", eg.Name, dstr)
       }
       if err != nil {
           panic(err)
       }
   }()
 
   // Run example.
   eg.F()
   return
}