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 5package testing 6 7import ( 8 "fmt" 9 "slices" 10 "strings" 11 "time" 12) 13 14type InternalExample struct { 15 Name string 16 F func() 17 Output string 18 Unordered bool 19} 20 21// RunExamples is an internal function but exported because it is cross-package; 22// it is part of the implementation of the "go test" command. 23func RunExamples(matchString func(pat, str string) (bool, error), examples []InternalExample) (ok bool) { 24 _, ok = runExamples(matchString, examples) 25 return ok 26} 27 28func runExamples(matchString func(pat, str string) (bool, error), examples []InternalExample) (ran, ok bool) { 29 ok = true 30 31 m := newMatcher(matchString, *match, "-test.run", *skip) 32 33 var eg InternalExample 34 for _, eg = range examples { 35 _, matched, _ := m.fullName(nil, eg.Name) 36 if !matched { 37 continue 38 } 39 ran = true 40 if !runExample(eg) { 41 ok = false 42 } 43 } 44 45 return ran, ok 46} 47 48func sortLines(output string) string { 49 lines := strings.Split(output, "\n") 50 slices.Sort(lines) 51 return strings.Join(lines, "\n") 52} 53 54// processRunResult computes a summary and status of the result of running an example test. 55// stdout is the captured output from stdout of the test. 56// recovered is the result of invoking recover after running the test, in case it panicked. 57// 58// If stdout doesn't match the expected output or if recovered is non-nil, it'll print the cause of failure to stdout. 59// If the test is chatty/verbose, it'll print a success message to stdout. 60// If recovered is non-nil, it'll panic with that value. 61// If the test panicked with nil, or invoked runtime.Goexit, it'll be 62// made to fail and panic with errNilPanicOrGoexit 63func (eg *InternalExample) processRunResult(stdout string, timeSpent time.Duration, finished bool, recovered any) (passed bool) { 64 passed = true 65 dstr := fmtDuration(timeSpent) 66 var fail string 67 got := strings.TrimSpace(stdout) 68 want := strings.TrimSpace(eg.Output) 69 if eg.Unordered { 70 if sortLines(got) != sortLines(want) && recovered == nil { 71 fail = fmt.Sprintf("got:\n%s\nwant (unordered):\n%s\n", stdout, eg.Output) 72 } 73 } else { 74 if got != want && recovered == nil { 75 fail = fmt.Sprintf("got:\n%s\nwant:\n%s\n", got, want) 76 } 77 } 78 if fail != "" || !finished || recovered != nil { 79 fmt.Printf("%s--- FAIL: %s (%s)\n%s", chatty.prefix(), eg.Name, dstr, fail) 80 passed = false 81 } else if chatty.on { 82 fmt.Printf("%s--- PASS: %s (%s)\n", chatty.prefix(), eg.Name, dstr) 83 } 84 85 if chatty.on && chatty.json { 86 fmt.Printf("%s=== NAME %s\n", chatty.prefix(), "") 87 } 88 89 if recovered != nil { 90 // Propagate the previously recovered result, by panicking. 91 panic(recovered) 92 } else if !finished { 93 panic(errNilPanicOrGoexit) 94 } 95 96 return 97} 98