golang.org/x/tools@v0.21.0/go/analysis/passes/loopclosure/testdata/src/subtests/subtest.go (about)

     1  // Copyright 2022 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  // This file contains legacy tests that the loopclosure analyzer detects leaked
     6  // references via parallel subtests.
     7  // Legacy expectations are incorrect after go1.22.
     8  
     9  package subtests
    10  
    11  import (
    12  	"testing"
    13  )
    14  
    15  // T is used to test that loopclosure only matches T.Run when T is from the
    16  // testing package.
    17  type T struct{}
    18  
    19  // Run should not match testing.T.Run. Note that the second argument is
    20  // intentionally a *testing.T, not a *T, so that we can check both
    21  // testing.T.Parallel inside a T.Run, and a T.Parallel inside a testing.T.Run.
    22  func (t *T) Run(string, func(*testing.T)) {
    23  }
    24  
    25  func (t *T) Parallel() {}
    26  
    27  func _(t *testing.T) {
    28  	for i, test := range []int{1, 2, 3} {
    29  		// Check that parallel subtests are identified.
    30  		t.Run("", func(t *testing.T) {
    31  			t.Parallel()
    32  			println(i)    // want "loop variable i captured by func literal"
    33  			println(test) // want "loop variable test captured by func literal"
    34  		})
    35  
    36  		// Check that serial tests are OK.
    37  		t.Run("", func(t *testing.T) {
    38  			println(i)
    39  			println(test)
    40  		})
    41  
    42  		// Check that the location of t.Parallel matters.
    43  		t.Run("", func(t *testing.T) {
    44  			println(i)
    45  			println(test)
    46  			t.Parallel()
    47  			println(i)    // want "loop variable i captured by func literal"
    48  			println(test) // want "loop variable test captured by func literal"
    49  		})
    50  
    51  		// Check that *testing.T value matters.
    52  		t.Run("", func(t *testing.T) {
    53  			var x testing.T
    54  			x.Parallel()
    55  			println(i)
    56  			println(test)
    57  		})
    58  
    59  		// Check that shadowing the loop variables within the test literal is OK if
    60  		// it occurs before t.Parallel().
    61  		t.Run("", func(t *testing.T) {
    62  			i := i
    63  			test := test
    64  			t.Parallel()
    65  			println(i)
    66  			println(test)
    67  		})
    68  
    69  		// Check that shadowing the loop variables within the test literal is Not
    70  		// OK if it occurs after t.Parallel().
    71  		t.Run("", func(t *testing.T) {
    72  			t.Parallel()
    73  			i := i        // want "loop variable i captured by func literal"
    74  			test := test  // want "loop variable test captured by func literal"
    75  			println(i)    // OK
    76  			println(test) // OK
    77  		})
    78  
    79  		// Check uses in nested blocks.
    80  		t.Run("", func(t *testing.T) {
    81  			t.Parallel()
    82  			{
    83  				println(i)    // want "loop variable i captured by func literal"
    84  				println(test) // want "loop variable test captured by func literal"
    85  			}
    86  		})
    87  
    88  		// Check that we catch uses in nested subtests.
    89  		t.Run("", func(t *testing.T) {
    90  			t.Parallel()
    91  			t.Run("", func(t *testing.T) {
    92  				println(i)    // want "loop variable i captured by func literal"
    93  				println(test) // want "loop variable test captured by func literal"
    94  			})
    95  		})
    96  
    97  		// Check that there is no diagnostic if t is not a *testing.T.
    98  		t.Run("", func(_ *testing.T) {
    99  			t := &T{}
   100  			t.Parallel()
   101  			println(i)
   102  			println(test)
   103  		})
   104  
   105  		// Check that there is no diagnostic when a jump to a label may have caused
   106  		// the call to t.Parallel to have been skipped.
   107  		t.Run("", func(t *testing.T) {
   108  			if true {
   109  				goto Test
   110  			}
   111  			t.Parallel()
   112  		Test:
   113  			println(i)
   114  			println(test)
   115  		})
   116  
   117  		// Check that there is no diagnostic when a jump to a label may have caused
   118  		// the loop variable reference to be skipped, but there is a diagnostic
   119  		// when both the call to t.Parallel and the loop variable reference occur
   120  		// after the final label in the block.
   121  		t.Run("", func(t *testing.T) {
   122  			if true {
   123  				goto Test
   124  			}
   125  			t.Parallel()
   126  			println(i) // maybe OK
   127  		Test:
   128  			t.Parallel()
   129  			println(test) // want "loop variable test captured by func literal"
   130  		})
   131  
   132  		// Check that multiple labels are handled.
   133  		t.Run("", func(t *testing.T) {
   134  			if true {
   135  				goto Test1
   136  			} else {
   137  				goto Test2
   138  			}
   139  		Test1:
   140  		Test2:
   141  			t.Parallel()
   142  			println(test) // want "loop variable test captured by func literal"
   143  		})
   144  
   145  		// Check that we do not have problems when t.Run has a single argument.
   146  		fn := func() (string, func(t *testing.T)) { return "", nil }
   147  		t.Run(fn())
   148  	}
   149  }
   150  
   151  // Check that there is no diagnostic when loop variables are shadowed within
   152  // the loop body.
   153  func _(t *testing.T) {
   154  	for i, test := range []int{1, 2, 3} {
   155  		i := i
   156  		test := test
   157  		t.Run("", func(t *testing.T) {
   158  			t.Parallel()
   159  			println(i)
   160  			println(test)
   161  		})
   162  	}
   163  }
   164  
   165  // Check that t.Run must be *testing.T.Run.
   166  func _(t *T) {
   167  	for i, test := range []int{1, 2, 3} {
   168  		t.Run("", func(t *testing.T) {
   169  			t.Parallel()
   170  			println(i)
   171  			println(test)
   172  		})
   173  	}
   174  }
   175  
   176  // Check that the top-level must be parallel in order to cause a diagnostic.
   177  //
   178  // From https://pkg.go.dev/testing:
   179  //
   180  //	"Run does not return until parallel subtests have completed, providing a
   181  //	way to clean up after a group of parallel tests"
   182  func _(t *testing.T) {
   183  	for _, test := range []int{1, 2, 3} {
   184  		// In this subtest, a/b must complete before the synchronous subtest "a"
   185  		// completes, so the reference to test does not escape the current loop
   186  		// iteration.
   187  		t.Run("a", func(s *testing.T) {
   188  			s.Run("b", func(u *testing.T) {
   189  				u.Parallel()
   190  				println(test)
   191  			})
   192  		})
   193  
   194  		// In this subtest, c executes concurrently, so the reference to test may
   195  		// escape the current loop iteration.
   196  		t.Run("c", func(s *testing.T) {
   197  			s.Parallel()
   198  			s.Run("d", func(u *testing.T) {
   199  				println(test) // want "loop variable test captured by func literal"
   200  			})
   201  		})
   202  	}
   203  }