GoPLS Viewer

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