github.com/moby/docker@v26.1.3+incompatible/internal/test/suite/suite.go (about)

     1  // Package suite is a simplified version of testify's suite package which has unnecessary dependencies.
     2  // Please remove this package whenever possible.
     3  package suite
     4  
     5  import (
     6  	"context"
     7  	"flag"
     8  	"reflect"
     9  	"runtime/debug"
    10  	"strings"
    11  	"testing"
    12  
    13  	"github.com/docker/docker/testutil"
    14  )
    15  
    16  // TimeoutFlag is the flag to set a per-test timeout when running tests. Defaults to `-timeout`.
    17  var TimeoutFlag = flag.Duration("timeout", 0, "DO NOT USE")
    18  
    19  var typTestingT = reflect.TypeOf(new(testing.T))
    20  
    21  // Run takes a testing suite and runs all of the tests attached to it.
    22  func Run(ctx context.Context, t *testing.T, suite interface{}) {
    23  	defer failOnPanic(t)
    24  
    25  	ctx = testutil.StartSpan(ctx, t)
    26  	suiteCtx := ctx
    27  
    28  	suiteSetupDone := false
    29  
    30  	defer func() {
    31  		if suiteSetupDone {
    32  			if tearDownAllSuite, ok := getTeardownAllSuite(suite); ok {
    33  				tearDownAllSuite.TearDownSuite(suiteCtx, t)
    34  			}
    35  		}
    36  	}()
    37  
    38  	methodFinder := reflect.TypeOf(suite)
    39  	for index := 0; index < methodFinder.NumMethod(); index++ {
    40  		method := methodFinder.Method(index)
    41  		if !methodFilter(method.Name, method.Type) {
    42  			continue
    43  		}
    44  		t.Run(method.Name, func(t *testing.T) {
    45  			ctx := testutil.StartSpan(ctx, t)
    46  			testutil.SetContext(t, ctx)
    47  			t.Cleanup(func() {
    48  				testutil.CleanupContext(t)
    49  			})
    50  
    51  			defer failOnPanic(t)
    52  
    53  			if !suiteSetupDone {
    54  				if setupAllSuite, ok := getSetupAllSuite(suite); ok {
    55  					setupAllSuite.SetUpSuite(suiteCtx, t)
    56  				}
    57  				suiteSetupDone = true
    58  			}
    59  
    60  			if setupTestSuite, ok := getSetupTestSuite(suite); ok {
    61  				setupTestSuite.SetUpTest(ctx, t)
    62  			}
    63  			defer func() {
    64  				if tearDownTestSuite, ok := getTearDownTestSuite(suite); ok {
    65  					tearDownTestSuite.TearDownTest(ctx, t)
    66  				}
    67  			}()
    68  
    69  			method.Func.Call([]reflect.Value{reflect.ValueOf(suite), reflect.ValueOf(t)})
    70  		})
    71  	}
    72  }
    73  
    74  func getSetupAllSuite(suite interface{}) (SetupAllSuite, bool) {
    75  	setupAllSuite, ok := suite.(SetupAllSuite)
    76  	if ok {
    77  		return setupAllSuite, ok
    78  	}
    79  
    80  	t := reflect.TypeOf(suite)
    81  	for i := 0; i < t.NumMethod(); i++ {
    82  		if t.Method(i).Name == "SetUpSuite" {
    83  			panic("Wrong SetUpSuite signature")
    84  		}
    85  	}
    86  	return nil, false
    87  }
    88  
    89  func getSetupTestSuite(suite interface{}) (SetupTestSuite, bool) {
    90  	setupAllTest, ok := suite.(SetupTestSuite)
    91  	if ok {
    92  		return setupAllTest, ok
    93  	}
    94  
    95  	t := reflect.TypeOf(suite)
    96  	for i := 0; i < t.NumMethod(); i++ {
    97  		if t.Method(i).Name == "SetUpTest" {
    98  			panic("Wrong SetUpTest signature")
    99  		}
   100  	}
   101  	return nil, false
   102  }
   103  
   104  func getTearDownTestSuite(suite interface{}) (TearDownTestSuite, bool) {
   105  	tearDownTest, ok := suite.(TearDownTestSuite)
   106  	if ok {
   107  		return tearDownTest, ok
   108  	}
   109  
   110  	t := reflect.TypeOf(suite)
   111  	for i := 0; i < t.NumMethod(); i++ {
   112  		if t.Method(i).Name == "TearDownTest" {
   113  			panic("Wrong TearDownTest signature")
   114  		}
   115  	}
   116  	return nil, false
   117  }
   118  
   119  func getTeardownAllSuite(suite interface{}) (TearDownAllSuite, bool) {
   120  	tearDownAll, ok := suite.(TearDownAllSuite)
   121  	if ok {
   122  		return tearDownAll, ok
   123  	}
   124  
   125  	t := reflect.TypeOf(suite)
   126  	for i := 0; i < t.NumMethod(); i++ {
   127  		if t.Method(i).Name == "TearDownSuite" {
   128  			panic("Wrong TearDownSuite signature")
   129  		}
   130  	}
   131  	return nil, false
   132  }
   133  
   134  func failOnPanic(t *testing.T) {
   135  	r := recover()
   136  	if r != nil {
   137  		t.Errorf("test suite panicked: %v\n%s", r, debug.Stack())
   138  		t.FailNow()
   139  	}
   140  }
   141  
   142  func methodFilter(name string, typ reflect.Type) bool {
   143  	return strings.HasPrefix(name, "Test") && typ.NumIn() == 2 && typ.In(1) == typTestingT // 2 params: method receiver and *testing.T
   144  }