go.uber.org/yarpc@v1.72.1/internal/yarpctest/testing.go (about)

     1  // Copyright (c) 2022 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package yarpctest
    22  
    23  import (
    24  	"fmt"
    25  	"runtime"
    26  
    27  	"github.com/stretchr/testify/require"
    28  )
    29  
    30  // FakeTestStatus states how a fake TestingT finished.
    31  type FakeTestStatus int
    32  
    33  const (
    34  	// Finished is the default. This indicates that it was run to completion
    35  	// but may have recorded errors using Errorf.
    36  	Finished FakeTestStatus = iota
    37  
    38  	// Fatal indicates that the TestingT aborted early with a FailNow.
    39  	Fatal
    40  
    41  	// Panicked indicates that the TestingT aborted with a panic.
    42  	Panicked
    43  )
    44  
    45  func (f FakeTestStatus) String() string {
    46  	switch f {
    47  	case Finished:
    48  		return "Finished"
    49  	case Fatal:
    50  		return "Fatal"
    51  	case Panicked:
    52  		return "Panicked"
    53  	default:
    54  		return fmt.Sprintf("FakeTestStatus(%v)", int(f))
    55  	}
    56  }
    57  
    58  // FakeTestResult contains the result of using a fake TestingT.
    59  type FakeTestResult struct {
    60  	Errors []string
    61  	Status FakeTestStatus
    62  	Panic  interface{} // non-nil if we panicked
    63  }
    64  
    65  // WithFakeTestingT yields a TestingT that records its results and exposes
    66  // them in FakeTestResult.
    67  func WithFakeTestingT(f func(require.TestingT)) *FakeTestResult {
    68  	var (
    69  		r FakeTestResult
    70  		t = fakeTestingT{&r}
    71  	)
    72  
    73  	done := make(chan struct{})
    74  	go func() {
    75  		defer func() {
    76  			if v := recover(); v != nil {
    77  				t.result.Status = Panicked
    78  			}
    79  			close(done)
    80  		}()
    81  
    82  		f(&t)
    83  	}()
    84  	<-done
    85  
    86  	return &r
    87  }
    88  
    89  type fakeTestingT struct{ result *FakeTestResult }
    90  
    91  func (t *fakeTestingT) Errorf(msg string, args ...interface{}) {
    92  	if len(args) > 0 {
    93  		msg = fmt.Sprintf(msg, args)
    94  	}
    95  	t.result.Errors = append(t.result.Errors, msg)
    96  }
    97  
    98  func (t *fakeTestingT) FailNow() {
    99  	t.result.Status = Fatal
   100  
   101  	// this kills the current goroutine, unwinding deferred functions.
   102  	runtime.Goexit()
   103  }