| // 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" | |
| "os" | |
| "sort" | |
| "strings" | |
| "time" | |
| ) | |
| type InternalExample struct { | |
| Name string | |
| F func() | |
| Output string | |
| Unordered bool | |
| } | |
| // RunExamples is an internal function but exported because it is cross-package; | |
| // it is 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") | |
| } | |
| // processRunResult computes a summary and status of the result of running an example test. | |
| // stdout is the captured output from stdout of the test. | |
| // recovered is the result of invoking recover after running the test, in case it panicked. | |
| // | |
| // If stdout doesn't match the expected output or if recovered is non-nil, it'll print the cause of failure to stdout. | |
| // If the test is chatty/verbose, it'll print a success message to stdout. | |
| // If recovered is non-nil, it'll panic with that value. | |
| // If the test panicked with nil, or invoked runtime.Goexit, it'll be | |
| // made to fail and panic with errNilPanicOrGoexit | |
| func (eg *InternalExample) processRunResult(stdout string, timeSpent time.Duration, finished bool, recovered any) (passed bool) { | |
| passed = true | |
| dstr := fmtDuration(timeSpent) | |
| var fail string | |
| got := strings.TrimSpace(stdout) | |
| want := strings.TrimSpace(eg.Output) | |
| if eg.Unordered { | |
| if sortLines(got) != sortLines(want) && recovered == nil { | |
| fail = fmt.Sprintf("got:\n%s\nwant (unordered):\n%s\n", stdout, eg.Output) | |
| } | |
| } else { | |
| if got != want && recovered == nil { | |
| fail = fmt.Sprintf("got:\n%s\nwant:\n%s\n", got, want) | |
| } | |
| } | |
| if fail != "" || !finished || recovered != nil { | |
| fmt.Printf("%s--- FAIL: %s (%s)\n%s", chatty.prefix(), eg.Name, dstr, fail) | |
| passed = false | |
| } else if chatty.on { | |
| fmt.Printf("%s--- PASS: %s (%s)\n", chatty.prefix(), eg.Name, dstr) | |
| } | |
| if chatty.on && chatty.json { | |
| fmt.Printf("%s=== NAME %s\n", chatty.prefix(), "") | |
| } | |
| if recovered != nil { | |
| // Propagate the previously recovered result, by panicking. | |
| panic(recovered) | |
| } | |
| if !finished && recovered == nil { | |
| panic(errNilPanicOrGoexit) | |
| } | |
| return | |
| } |