github.com/corona10/go@v0.0.0-20180224231303-7a218942be57/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  }