mirror of
https://github.com/golang/go
synced 2024-10-05 09:11:21 -06:00
9323de3da7
Adds a type of output to Examples that allows tests to have unordered output. This is intended to help clarify when the output of a command will produce a fixed return, but that return might not be in an constant order. Examples where this is useful would be documenting the rand.Perm() call, or perhaps the (os.File).Readdir(), both of which can not guarantee order, but can guarantee the elements of the output. Fixes #10149 Change-Id: Iaf0cf1580b686afebd79718ed67ea744f5ed9fc5 Reviewed-on: https://go-review.googlesource.com/19280 Reviewed-by: Andrew Gerrand <adg@golang.org>
117 lines
2.2 KiB
Go
117 lines
2.2 KiB
Go
// 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 (
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"sort"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
type InternalExample struct {
|
|
Name string
|
|
F func()
|
|
Output string
|
|
Unordered bool
|
|
}
|
|
|
|
func RunExamples(matchString func(pat, str string) (bool, error), examples []InternalExample) (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
|
|
}
|
|
if !runExample(eg) {
|
|
ok = false
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
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 bytes.Buffer
|
|
_, 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.Now().Sub(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
|
|
}
|