2011-10-06 11:56:17 -07:00
|
|
|
// 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"
|
2024-11-10 16:57:06 +01:00
|
|
|
"runtime"
|
2024-05-22 13:38:40 -07:00
|
|
|
"slices"
|
2011-12-16 09:43:58 +11:00
|
|
|
"strings"
|
2011-10-06 11:56:17 -07:00
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
type InternalExample struct {
|
2016-02-05 14:16:31 -07:00
|
|
|
Name string
|
|
|
|
F func()
|
|
|
|
Output string
|
|
|
|
Unordered bool
|
2011-10-06 11:56:17 -07:00
|
|
|
}
|
|
|
|
|
2019-12-10 10:34:34 +00:00
|
|
|
// RunExamples is an internal function but exported because it is cross-package;
|
|
|
|
// it is part of the implementation of the "go test" command.
|
2012-02-27 12:49:10 +11:00
|
|
|
func RunExamples(matchString func(pat, str string) (bool, error), examples []InternalExample) (ok bool) {
|
2016-04-20 14:29:30 -03:00
|
|
|
_, ok = runExamples(matchString, examples)
|
|
|
|
return ok
|
|
|
|
}
|
|
|
|
|
|
|
|
func runExamples(matchString func(pat, str string) (bool, error), examples []InternalExample) (ran, ok bool) {
|
2011-10-06 11:56:17 -07:00
|
|
|
ok = true
|
|
|
|
|
2023-07-21 18:49:09 +00:00
|
|
|
m := newMatcher(matchString, *match, "-test.run", *skip)
|
2011-11-15 13:09:19 -05:00
|
|
|
|
2023-07-21 18:49:09 +00:00
|
|
|
var eg InternalExample
|
2011-11-15 13:09:19 -05:00
|
|
|
for _, eg = range examples {
|
2023-07-21 18:49:09 +00:00
|
|
|
_, matched, _ := m.fullName(nil, eg.Name)
|
2012-02-27 12:49:10 +11:00
|
|
|
if !matched {
|
|
|
|
continue
|
|
|
|
}
|
2016-04-20 14:29:30 -03:00
|
|
|
ran = true
|
2013-01-18 10:28:18 +11:00
|
|
|
if !runExample(eg) {
|
|
|
|
ok = false
|
2011-10-06 11:56:17 -07:00
|
|
|
}
|
2013-01-18 10:28:18 +11:00
|
|
|
}
|
|
|
|
|
2016-04-20 14:29:30 -03:00
|
|
|
return ran, ok
|
2013-01-18 10:28:18 +11:00
|
|
|
}
|
|
|
|
|
2019-03-05 03:58:37 -08:00
|
|
|
// 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.
|
2020-08-31 20:54:17 +02:00
|
|
|
// If the test panicked with nil, or invoked runtime.Goexit, it'll be
|
|
|
|
// made to fail and panic with errNilPanicOrGoexit
|
2021-12-01 12:15:45 -05:00
|
|
|
func (eg *InternalExample) processRunResult(stdout string, timeSpent time.Duration, finished bool, recovered any) (passed bool) {
|
2019-03-05 03:58:37 -08:00
|
|
|
passed = true
|
|
|
|
dstr := fmtDuration(timeSpent)
|
|
|
|
var fail string
|
|
|
|
got := strings.TrimSpace(stdout)
|
|
|
|
want := strings.TrimSpace(eg.Output)
|
2024-11-10 16:57:06 +01:00
|
|
|
if runtime.GOOS == "windows" {
|
|
|
|
got = strings.ReplaceAll(got, "\r\n", "\n")
|
|
|
|
want = strings.ReplaceAll(want, "\r\n", "\n")
|
|
|
|
}
|
2019-03-05 03:58:37 -08:00
|
|
|
if eg.Unordered {
|
2025-02-28 21:54:29 +08:00
|
|
|
gotLines := slices.Sorted(strings.SplitSeq(got, "\n"))
|
|
|
|
wantLines := slices.Sorted(strings.SplitSeq(want, "\n"))
|
|
|
|
if !slices.Equal(gotLines, wantLines) && recovered == nil {
|
2019-03-05 03:58:37 -08:00
|
|
|
fail = fmt.Sprintf("got:\n%s\nwant (unordered):\n%s\n", stdout, eg.Output)
|
2011-10-06 11:56:17 -07:00
|
|
|
}
|
2019-03-05 03:58:37 -08:00
|
|
|
} else {
|
|
|
|
if got != want && recovered == nil {
|
|
|
|
fail = fmt.Sprintf("got:\n%s\nwant:\n%s\n", got, want)
|
2013-01-18 10:28:18 +11:00
|
|
|
}
|
2019-03-05 03:58:37 -08:00
|
|
|
}
|
2020-08-31 20:54:17 +02:00
|
|
|
if fail != "" || !finished || recovered != nil {
|
testing: fix many test2json inaccuracies
Test2json is parsing the output stream from the test, which includes
package testing's own framing lines intermingled with other output,
in particular any output printed via fmt.Printf, println, and so on.
We have had recurring problems with unexpected partial output lines
causing a framing line to be missed.
A recent talk at GopherCon gave an example of an integration test
involving Docker that happened to print \r-terminated lines instead
of \n-terminated lines in some configurations, which in turn broke
test2json badly. (https://www.gophercon.com/agenda/session/944259)
There are also a variety of open reported issues with similar problems,
which this CL also addresses. The general approach is to add a new
testing flag -test.v=json that means to print additional output to help
test2json. And then test2json takes advantage of that output.
Among the fixes:
- Identify testing framing more reliably, using ^V
(#23036, #26325, #43683, GopherCon talk)
- Test that output with \r\n endings is handled correctly
(#43683, #34286)
- Use === RUN in fuzz tests (#52636, #48132)
- Add === RUN lines to note benchmark starts (#27764, #49505)
- Print subtest --- PASS/FAIL lines as they happen (#29811)
- Add === NAME lines to emit more test change events,
such as when a subtest stops and the parent continues running.
- Fix event shown in overall test failure (#27568)
- Avoid interleaving of writes to os.Stdout and os.Stderr (#33419)
Fixes #23036.
Fixes #26325.
Fixes #27568.
Fixes #27764.
Fixes #29811.
Fixes #33419.
Fixes #34286.
Fixes #43683.
Fixes #49505.
Fixes #52636.
Change-Id: Id4207b746a20693f92e52d68c6e4a7f8c41cc7c6
Reviewed-on: https://go-review.googlesource.com/c/go/+/443596
Auto-Submit: Russ Cox <rsc@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Bryan Mills <bcmills@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
2022-10-13 16:13:46 -04:00
|
|
|
fmt.Printf("%s--- FAIL: %s (%s)\n%s", chatty.prefix(), eg.Name, dstr, fail)
|
2019-03-05 03:58:37 -08:00
|
|
|
passed = false
|
testing: fix many test2json inaccuracies
Test2json is parsing the output stream from the test, which includes
package testing's own framing lines intermingled with other output,
in particular any output printed via fmt.Printf, println, and so on.
We have had recurring problems with unexpected partial output lines
causing a framing line to be missed.
A recent talk at GopherCon gave an example of an integration test
involving Docker that happened to print \r-terminated lines instead
of \n-terminated lines in some configurations, which in turn broke
test2json badly. (https://www.gophercon.com/agenda/session/944259)
There are also a variety of open reported issues with similar problems,
which this CL also addresses. The general approach is to add a new
testing flag -test.v=json that means to print additional output to help
test2json. And then test2json takes advantage of that output.
Among the fixes:
- Identify testing framing more reliably, using ^V
(#23036, #26325, #43683, GopherCon talk)
- Test that output with \r\n endings is handled correctly
(#43683, #34286)
- Use === RUN in fuzz tests (#52636, #48132)
- Add === RUN lines to note benchmark starts (#27764, #49505)
- Print subtest --- PASS/FAIL lines as they happen (#29811)
- Add === NAME lines to emit more test change events,
such as when a subtest stops and the parent continues running.
- Fix event shown in overall test failure (#27568)
- Avoid interleaving of writes to os.Stdout and os.Stderr (#33419)
Fixes #23036.
Fixes #26325.
Fixes #27568.
Fixes #27764.
Fixes #29811.
Fixes #33419.
Fixes #34286.
Fixes #43683.
Fixes #49505.
Fixes #52636.
Change-Id: Id4207b746a20693f92e52d68c6e4a7f8c41cc7c6
Reviewed-on: https://go-review.googlesource.com/c/go/+/443596
Auto-Submit: Russ Cox <rsc@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Bryan Mills <bcmills@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
2022-10-13 16:13:46 -04:00
|
|
|
} 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(), "")
|
2019-03-05 03:58:37 -08:00
|
|
|
}
|
2020-08-31 20:54:17 +02:00
|
|
|
|
2019-03-05 03:58:37 -08:00
|
|
|
if recovered != nil {
|
|
|
|
// Propagate the previously recovered result, by panicking.
|
|
|
|
panic(recovered)
|
2023-04-19 18:48:00 -04:00
|
|
|
} else if !finished {
|
2020-08-31 20:54:17 +02:00
|
|
|
panic(errNilPanicOrGoexit)
|
|
|
|
}
|
2011-10-06 11:56:17 -07:00
|
|
|
|
|
|
|
return
|
|
|
|
}
|