@@ -275,6 +275,212 @@ func TestWithCustomType(t *testing.T) {
275275 }
276276}
277277
278+ func helpTB (tb testing.TB ) {
279+ tb .FailNow ()
280+ }
281+
282+ func TestTB (t * testing.T ) {
283+ go helpTB (t ) // want "call to .+TB.+FailNow from a non-test goroutine"
284+ }
285+
278286func TestIssue48124 (t * testing.T ) {
279- go h ()
287+ go helper (t ) // want "call to .+T.+Skip from a non-test goroutine"
288+ }
289+
290+ func TestEachCall (t * testing.T ) {
291+ go helper (t ) // want "call to .+T.+Skip from a non-test goroutine"
292+ go helper (t ) // want "call to .+T.+Skip from a non-test goroutine"
293+ }
294+
295+ func TestWithSubtest (t * testing.T ) {
296+ t .Run ("name" , func (t2 * testing.T ) {
297+ t .FailNow () // want "call to .+T.+FailNow on t defined outside of the subtest"
298+ t2 .Fatal ()
299+ })
300+
301+ f := func (t3 * testing.T ) {
302+ t .FailNow ()
303+ t3 .Fatal ()
304+ }
305+ t .Run ("name" , f ) // want "call to .+T.+FailNow on t defined outside of the subtest"
306+
307+ g := func (t4 * testing.T ) {
308+ t .FailNow ()
309+ t4 .Fatal ()
310+ }
311+ g (t )
312+
313+ t .Run ("name" , helper )
314+
315+ go t .Run ("name" , func (t2 * testing.T ) {
316+ t .FailNow () // want "call to .+T.+FailNow on t defined outside of the subtest"
317+ t2 .Fatal ()
318+ })
319+ }
320+
321+ func TestMultipleVariables (t * testing.T ) {
322+ { // short decl
323+ f , g := func (t1 * testing.T ) {
324+ t1 .Fatal ()
325+ }, func (t2 * testing.T ) {
326+ t2 .Error ()
327+ }
328+
329+ go f (t ) // want "call to .+T.+Fatal from a non-test goroutine"
330+ go g (t )
331+
332+ t .Run ("name" , f )
333+ t .Run ("name" , g )
334+ }
335+
336+ { // var decl
337+ var f , g = func (t1 * testing.T ) {
338+ t1 .Fatal ()
339+ }, func (t2 * testing.T ) {
340+ t2 .Error ()
341+ }
342+
343+ go f (t ) // want "call to .+T.+Fatal from a non-test goroutine"
344+ go g (t )
345+
346+ t .Run ("name" , f )
347+ t .Run ("name" , g )
348+ }
349+ }
350+
351+ func BadIgnoresMultipleAssignments (t * testing.T ) {
352+ {
353+ f := func (t1 * testing.T ) {
354+ t1 .Fatal ()
355+ }
356+ go f (t ) // want "call to .+T.+Fatal from a non-test goroutine"
357+
358+ f = func (t2 * testing.T ) {
359+ t2 .Error ()
360+ }
361+ go f (t ) // want "call to .+T.+Fatal from a non-test goroutine"
362+ }
363+ {
364+ f := func (t1 * testing.T ) {
365+ t1 .Error ()
366+ }
367+ go f (t )
368+
369+ f = func (t2 * testing.T ) {
370+ t2 .FailNow ()
371+ }
372+ go f (t ) // false negative
373+ }
374+ }
375+
376+ func TestGoDoesNotDescendIntoSubtest (t * testing.T ) {
377+ f := func (t2 * testing.T ) {
378+ g := func (t3 * testing.T ) {
379+ t3 .Fatal () // fine
380+ }
381+ t2 .Run ("name" , g )
382+ t2 .FailNow () // bad
383+ }
384+ go f (t ) // want "call to .+T.+FailNow from a non-test goroutine"
385+ }
386+
387+ func TestFreeVariableAssignedWithinEnclosing (t * testing.T ) {
388+ f := func (t2 * testing.T ) {
389+ inner := t
390+ inner .FailNow ()
391+ }
392+
393+ go f (nil ) // want "call to .+T.+FailNow from a non-test goroutine"
394+
395+ t .Run ("name" , func (t3 * testing.T ) {
396+ go f (nil ) // want "call to .+T.+FailNow from a non-test goroutine"
397+ })
398+
399+ // Without pointer analysis we cannot tell if inner is t or t2.
400+ // So we accept a false negatives on the following examples.
401+ t .Run ("name" , f )
402+
403+ go func (_ * testing.T ) {
404+ t .Run ("name" , f )
405+ }(nil )
406+
407+ go t .Run ("name" , f )
408+ }
409+
410+ func TestWithUnusedSelection (t * testing.T ) {
411+ go func () {
412+ _ = t .FailNow
413+ }()
414+ t .Run ("name" , func (t2 * testing.T ) {
415+ _ = t .FailNow
416+ })
417+ }
418+
419+ func TestMethodExprsAreIgnored (t * testing.T ) {
420+ go func () {
421+ (* testing .T ).FailNow (t )
422+ }()
423+ }
424+
425+ func TestRecursive (t * testing.T ) {
426+ t .SkipNow ()
427+
428+ go TestRecursive (t ) // want "call to .+T.+SkipNow from a non-test goroutine"
429+
430+ t .Run ("name" , TestRecursive )
431+ }
432+
433+ func TestMethodSelection (t * testing.T ) {
434+ var h helperType
435+
436+ go h .help (t ) // want "call to .+T.+SkipNow from a non-test goroutine"
437+ t .Run ("name" , h .help )
438+ }
439+
440+ type helperType struct {}
441+
442+ func (h * helperType ) help (t * testing.T ) { t .SkipNow () }
443+
444+ func TestIssue63799a (t * testing.T ) {
445+ done := make (chan struct {})
446+ go func () {
447+ defer close (done )
448+ t .Run ("" , func (t * testing.T ) {
449+ t .Fatal () // No warning. This is in a subtest.
450+ })
451+ }()
452+ <- done
453+ }
454+
455+ func TestIssue63799b (t * testing.T ) {
456+ // Simplified from go.dev/cl/538698
457+
458+ // nondet is some unspecified boolean placeholder.
459+ var nondet func () bool
460+
461+ t .Run ("nohup" , func (t * testing.T ) {
462+ if nondet () {
463+ t .Skip ("ignored" )
464+ }
465+
466+ go t .Run ("nohup-i" , func (t * testing.T ) {
467+ t .Parallel ()
468+ if nondet () {
469+ if nondet () {
470+ t .Skip ("go.dev/cl/538698 wanted to have skip here" )
471+ }
472+
473+ t .Error ("ignored" )
474+ } else {
475+ t .Log ("ignored" )
476+ }
477+ })
478+ })
479+ }
480+
481+ func TestIssue63849 (t * testing.T ) {
482+ go func () {
483+ helper (t ) // False negative. We do not do an actual interprodecural reachability analysis.
484+ }()
485+ go helper (t ) // want "call to .+T.+Skip from a non-test goroutine"
280486}
0 commit comments