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 }