github.com/aswedchain/aswed@v1.0.1/internal/utesting/utesting.go (about)

     1  // Copyright 2020 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  // Package utesting provides a standalone replacement for package testing.
    18  //
    19  // This package exists because package testing cannot easily be embedded into a
    20  // standalone go program. It provides an API that mirrors the standard library
    21  // testing API.
    22  package utesting
    23  
    24  import (
    25  	"bytes"
    26  	"fmt"
    27  	"io"
    28  	"regexp"
    29  	"runtime"
    30  	"sync"
    31  	"time"
    32  )
    33  
    34  // Test represents a single test.
    35  type Test struct {
    36  	Name string
    37  	Fn   func(*T)
    38  }
    39  
    40  // Result is the result of a test execution.
    41  type Result struct {
    42  	Name     string
    43  	Failed   bool
    44  	Output   string
    45  	Duration time.Duration
    46  }
    47  
    48  // MatchTests returns the tests whose name matches a regular expression.
    49  func MatchTests(tests []Test, expr string) []Test {
    50  	var results []Test
    51  	re, err := regexp.Compile(expr)
    52  	if err != nil {
    53  		return nil
    54  	}
    55  	for _, test := range tests {
    56  		if re.MatchString(test.Name) {
    57  			results = append(results, test)
    58  		}
    59  	}
    60  	return results
    61  }
    62  
    63  // RunTests executes all given tests in order and returns their results.
    64  // If the report writer is non-nil, a test report is written to it in real time.
    65  func RunTests(tests []Test, report io.Writer) []Result {
    66  	results := make([]Result, len(tests))
    67  	for i, test := range tests {
    68  		var output io.Writer
    69  		buffer := new(bytes.Buffer)
    70  		output = buffer
    71  		if report != nil {
    72  			output = io.MultiWriter(buffer, report)
    73  		}
    74  		start := time.Now()
    75  		results[i].Name = test.Name
    76  		results[i].Failed = run(test, output)
    77  		results[i].Duration = time.Since(start)
    78  		results[i].Output = buffer.String()
    79  		if report != nil {
    80  			printResult(results[i], report)
    81  		}
    82  	}
    83  	return results
    84  }
    85  
    86  func printResult(r Result, w io.Writer) {
    87  	pd := r.Duration.Truncate(100 * time.Microsecond)
    88  	if r.Failed {
    89  		fmt.Fprintf(w, "-- FAIL %s (%v)\n", r.Name, pd)
    90  	} else {
    91  		fmt.Fprintf(w, "-- OK %s (%v)\n", r.Name, pd)
    92  	}
    93  }
    94  
    95  // CountFailures returns the number of failed tests in the result slice.
    96  func CountFailures(rr []Result) int {
    97  	count := 0
    98  	for _, r := range rr {
    99  		if r.Failed {
   100  			count++
   101  		}
   102  	}
   103  	return count
   104  }
   105  
   106  // Run executes a single test.
   107  func Run(test Test) (bool, string) {
   108  	output := new(bytes.Buffer)
   109  	failed := run(test, output)
   110  	return failed, output.String()
   111  }
   112  
   113  func run(test Test, output io.Writer) bool {
   114  	t := &T{output: output}
   115  	done := make(chan struct{})
   116  	go func() {
   117  		defer close(done)
   118  		defer func() {
   119  			if err := recover(); err != nil {
   120  				buf := make([]byte, 4096)
   121  				i := runtime.Stack(buf, false)
   122  				t.Logf("panic: %v\n\n%s", err, buf[:i])
   123  				t.Fail()
   124  			}
   125  		}()
   126  		test.Fn(t)
   127  	}()
   128  	<-done
   129  	return t.failed
   130  }
   131  
   132  // T is the value given to the test function. The test can signal failures
   133  // and log output by calling methods on this object.
   134  type T struct {
   135  	mu     sync.Mutex
   136  	failed bool
   137  	output io.Writer
   138  }
   139  
   140  // FailNow marks the test as having failed and stops its execution by calling
   141  // runtime.Goexit (which then runs all deferred calls in the current goroutine).
   142  func (t *T) FailNow() {
   143  	t.Fail()
   144  	runtime.Goexit()
   145  }
   146  
   147  // Fail marks the test as having failed but continues execution.
   148  func (t *T) Fail() {
   149  	t.mu.Lock()
   150  	defer t.mu.Unlock()
   151  	t.failed = true
   152  }
   153  
   154  // Failed reports whether the test has failed.
   155  func (t *T) Failed() bool {
   156  	t.mu.Lock()
   157  	defer t.mu.Unlock()
   158  	return t.failed
   159  }
   160  
   161  // Log formats its arguments using default formatting, analogous to Println, and records
   162  // the text in the error log.
   163  func (t *T) Log(vs ...interface{}) {
   164  	t.mu.Lock()
   165  	defer t.mu.Unlock()
   166  	fmt.Fprintln(t.output, vs...)
   167  }
   168  
   169  // Logf formats its arguments according to the format, analogous to Printf, and records
   170  // the text in the error log. A final newline is added if not provided.
   171  func (t *T) Logf(format string, vs ...interface{}) {
   172  	t.mu.Lock()
   173  	defer t.mu.Unlock()
   174  	if len(format) == 0 || format[len(format)-1] != '\n' {
   175  		format += "\n"
   176  	}
   177  	fmt.Fprintf(t.output, format, vs...)
   178  }
   179  
   180  // Error is equivalent to Log followed by Fail.
   181  func (t *T) Error(vs ...interface{}) {
   182  	t.Log(vs...)
   183  	t.Fail()
   184  }
   185  
   186  // Errorf is equivalent to Logf followed by Fail.
   187  func (t *T) Errorf(format string, vs ...interface{}) {
   188  	t.Logf(format, vs...)
   189  	t.Fail()
   190  }
   191  
   192  // Fatal is equivalent to Log followed by FailNow.
   193  func (t *T) Fatal(vs ...interface{}) {
   194  	t.Log(vs...)
   195  	t.FailNow()
   196  }
   197  
   198  // Fatalf is equivalent to Logf followed by FailNow.
   199  func (t *T) Fatalf(format string, vs ...interface{}) {
   200  	t.Logf(format, vs...)
   201  	t.FailNow()
   202  }