github.com/mh-cbon/go@v0.0.0-20160603070303-9e112a3fe4c0/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  func RunExamples(matchString func(pat, str string) (bool, error), examples []InternalExample) (ok bool) {
    25  	ok = true
    26  
    27  	var eg InternalExample
    28  
    29  	for _, eg = range examples {
    30  		matched, err := matchString(*match, eg.Name)
    31  		if err != nil {
    32  			fmt.Fprintf(os.Stderr, "testing: invalid regexp for -test.run: %s\n", err)
    33  			os.Exit(1)
    34  		}
    35  		if !matched {
    36  			continue
    37  		}
    38  		if !runExample(eg) {
    39  			ok = false
    40  		}
    41  	}
    42  
    43  	return
    44  }
    45  
    46  func sortLines(output string) string {
    47  	lines := strings.Split(output, "\n")
    48  	sort.Strings(lines)
    49  	return strings.Join(lines, "\n")
    50  }
    51  
    52  func runExample(eg InternalExample) (ok bool) {
    53  	if *chatty {
    54  		fmt.Printf("=== RUN   %s\n", eg.Name)
    55  	}
    56  
    57  	// Capture stdout.
    58  	stdout := os.Stdout
    59  	r, w, err := os.Pipe()
    60  	if err != nil {
    61  		fmt.Fprintln(os.Stderr, err)
    62  		os.Exit(1)
    63  	}
    64  	os.Stdout = w
    65  	outC := make(chan string)
    66  	go func() {
    67  		var buf bytes.Buffer
    68  		_, err := io.Copy(&buf, r)
    69  		r.Close()
    70  		if err != nil {
    71  			fmt.Fprintf(os.Stderr, "testing: copying pipe: %v\n", err)
    72  			os.Exit(1)
    73  		}
    74  		outC <- buf.String()
    75  	}()
    76  
    77  	start := time.Now()
    78  	ok = true
    79  
    80  	// Clean up in a deferred call so we can recover if the example panics.
    81  	defer func() {
    82  		dstr := fmtDuration(time.Now().Sub(start))
    83  
    84  		// Close pipe, restore stdout, get output.
    85  		w.Close()
    86  		os.Stdout = stdout
    87  		out := <-outC
    88  
    89  		var fail string
    90  		err := recover()
    91  		got := strings.TrimSpace(out)
    92  		want := strings.TrimSpace(eg.Output)
    93  		if eg.Unordered {
    94  			if sortLines(got) != sortLines(want) && err == nil {
    95  				fail = fmt.Sprintf("got:\n%s\nwant (unordered):\n%s\n", out, eg.Output)
    96  			}
    97  		} else {
    98  			if got != want && err == nil {
    99  				fail = fmt.Sprintf("got:\n%s\nwant:\n%s\n", got, want)
   100  			}
   101  		}
   102  		if fail != "" || err != nil {
   103  			fmt.Printf("--- FAIL: %s (%s)\n%s", eg.Name, dstr, fail)
   104  			ok = false
   105  		} else if *chatty {
   106  			fmt.Printf("--- PASS: %s (%s)\n", eg.Name, dstr)
   107  		}
   108  		if err != nil {
   109  			panic(err)
   110  		}
   111  	}()
   112  
   113  	// Run example.
   114  	eg.F()
   115  	return
   116  }