github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/grpc/internal/grpctest/grpctest.go (about)

     1  /*
     2   *
     3   * Copyright 2018 gRPC authors.
     4   *
     5   * Licensed under the Apache License, Version 2.0 (the "License");
     6   * you may not use this file except in compliance with the License.
     7   * You may obtain a copy of the License at
     8   *
     9   *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   *
    17   */
    18  
    19  // package grpctest implements testing helpers.
    20  package grpctest
    21  
    22  import (
    23  	"reflect"
    24  	"strings"
    25  	"sync/atomic"
    26  	"testing"
    27  
    28  	"github.com/hxx258456/ccgo/grpc/internal/leakcheck"
    29  )
    30  
    31  var lcFailed uint32
    32  
    33  type errorer struct {
    34  	t *testing.T
    35  }
    36  
    37  func (e errorer) Errorf(format string, args ...interface{}) {
    38  	atomic.StoreUint32(&lcFailed, 1)
    39  	e.t.Errorf(format, args...)
    40  }
    41  
    42  // Tester is an implementation of the x interface parameter to
    43  // grpctest.RunSubTests with default Setup and Teardown behavior. Setup updates
    44  // the tlogger and Teardown performs a leak check. Embed in a struct with tests
    45  // defined to use.
    46  type Tester struct{}
    47  
    48  // Setup updates the tlogger.
    49  func (Tester) Setup(t *testing.T) {
    50  	TLogger.Update(t)
    51  }
    52  
    53  // Teardown performs a leak check.
    54  func (Tester) Teardown(t *testing.T) {
    55  	if atomic.LoadUint32(&lcFailed) == 1 {
    56  		return
    57  	}
    58  	leakcheck.Check(errorer{t: t})
    59  	if atomic.LoadUint32(&lcFailed) == 1 {
    60  		t.Log("Leak check disabled for future tests")
    61  	}
    62  	TLogger.EndTest(t)
    63  }
    64  
    65  func getTestFunc(t *testing.T, xv reflect.Value, name string) func(*testing.T) {
    66  	if m := xv.MethodByName(name); m.IsValid() {
    67  		if f, ok := m.Interface().(func(*testing.T)); ok {
    68  			return f
    69  		}
    70  		// Method exists but has the wrong type signature.
    71  		t.Fatalf("grpctest: function %v has unexpected signature (%T)", name, m.Interface())
    72  	}
    73  	return func(*testing.T) {}
    74  }
    75  
    76  // RunSubTests runs all "Test___" functions that are methods of x as subtests
    77  // of the current test.  If x contains methods "Setup(*testing.T)" or
    78  // "Teardown(*testing.T)", those are run before or after each of the test
    79  // functions, respectively.
    80  //
    81  // For example usage, see example_test.go.  Run it using:
    82  //     $ go test -v -run TestExample .
    83  //
    84  // To run a specific test/subtest:
    85  //     $ go test -v -run 'TestExample/^Something$' .
    86  func RunSubTests(t *testing.T, x interface{}) {
    87  	xt := reflect.TypeOf(x)
    88  	xv := reflect.ValueOf(x)
    89  
    90  	setup := getTestFunc(t, xv, "Setup")
    91  	teardown := getTestFunc(t, xv, "Teardown")
    92  
    93  	for i := 0; i < xt.NumMethod(); i++ {
    94  		methodName := xt.Method(i).Name
    95  		if !strings.HasPrefix(methodName, "Test") {
    96  			continue
    97  		}
    98  		tfunc := getTestFunc(t, xv, methodName)
    99  		t.Run(strings.TrimPrefix(methodName, "Test"), func(t *testing.T) {
   100  			// Run leakcheck in t.Cleanup() to guarantee it is run even if tfunc
   101  			// or setup uses t.Fatal().
   102  			//
   103  			// Note that a defer would run before t.Cleanup, so if a goroutine
   104  			// is closed by a test's t.Cleanup, a deferred leakcheck would fail.
   105  			t.Cleanup(func() { teardown(t) })
   106  			setup(t)
   107  			tfunc(t)
   108  		})
   109  	}
   110  }