Home | History | Annotate | Download | only in testing
      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 	"strings"
     13 	"time"
     14 )
     15 
     16 type InternalExample struct {
     17 	Name   string
     18 	F      func()
     19 	Output string
     20 }
     21 
     22 func RunExamples(matchString func(pat, str string) (bool, error), examples []InternalExample) (ok bool) {
     23 	ok = true
     24 
     25 	var eg InternalExample
     26 
     27 	for _, eg = range examples {
     28 		matched, err := matchString(*match, eg.Name)
     29 		if err != nil {
     30 			fmt.Fprintf(os.Stderr, "testing: invalid regexp for -test.run: %s\n", err)
     31 			os.Exit(1)
     32 		}
     33 		if !matched {
     34 			continue
     35 		}
     36 		if !runExample(eg) {
     37 			ok = false
     38 		}
     39 	}
     40 
     41 	return
     42 }
     43 
     44 func runExample(eg InternalExample) (ok bool) {
     45 	if *chatty {
     46 		fmt.Printf("=== RUN   %s\n", eg.Name)
     47 	}
     48 
     49 	// Capture stdout.
     50 	stdout := os.Stdout
     51 	r, w, err := os.Pipe()
     52 	if err != nil {
     53 		fmt.Fprintln(os.Stderr, err)
     54 		os.Exit(1)
     55 	}
     56 	os.Stdout = w
     57 	outC := make(chan string)
     58 	go func() {
     59 		var buf bytes.Buffer
     60 		_, err := io.Copy(&buf, r)
     61 		r.Close()
     62 		if err != nil {
     63 			fmt.Fprintf(os.Stderr, "testing: copying pipe: %v\n", err)
     64 			os.Exit(1)
     65 		}
     66 		outC <- buf.String()
     67 	}()
     68 
     69 	start := time.Now()
     70 	ok = true
     71 
     72 	// Clean up in a deferred call so we can recover if the example panics.
     73 	defer func() {
     74 		dstr := fmtDuration(time.Now().Sub(start))
     75 
     76 		// Close pipe, restore stdout, get output.
     77 		w.Close()
     78 		os.Stdout = stdout
     79 		out := <-outC
     80 
     81 		var fail string
     82 		err := recover()
     83 		if g, e := strings.TrimSpace(out), strings.TrimSpace(eg.Output); g != e && err == nil {
     84 			fail = fmt.Sprintf("got:\n%s\nwant:\n%s\n", g, e)
     85 		}
     86 		if fail != "" || err != nil {
     87 			fmt.Printf("--- FAIL: %s (%s)\n%s", eg.Name, dstr, fail)
     88 			ok = false
     89 		} else if *chatty {
     90 			fmt.Printf("--- PASS: %s (%s)\n", eg.Name, dstr)
     91 		}
     92 		if err != nil {
     93 			panic(err)
     94 		}
     95 	}()
     96 
     97 	// Run example.
     98 	eg.F()
     99 	return
    100 }
    101