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