...

Source file src/testing/sub_test.go

Documentation: testing

		 1  // Copyright 2016 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  package testing
		 6  
		 7  import (
		 8  	"bytes"
		 9  	"fmt"
		10  	"reflect"
		11  	"regexp"
		12  	"runtime"
		13  	"strings"
		14  	"sync"
		15  	"sync/atomic"
		16  	"time"
		17  )
		18  
		19  func init() {
		20  	// Make benchmark tests run 10x faster.
		21  	benchTime.d = 100 * time.Millisecond
		22  }
		23  
		24  func TestTestContext(t *T) {
		25  	const (
		26  		add1 = 0
		27  		done = 1
		28  	)
		29  	// After each of the calls are applied to the context, the
		30  	type call struct {
		31  		typ int // run or done
		32  		// result from applying the call
		33  		running int
		34  		waiting int
		35  		started bool
		36  	}
		37  	testCases := []struct {
		38  		max int
		39  		run []call
		40  	}{{
		41  		max: 1,
		42  		run: []call{
		43  			{typ: add1, running: 1, waiting: 0, started: true},
		44  			{typ: done, running: 0, waiting: 0, started: false},
		45  		},
		46  	}, {
		47  		max: 1,
		48  		run: []call{
		49  			{typ: add1, running: 1, waiting: 0, started: true},
		50  			{typ: add1, running: 1, waiting: 1, started: false},
		51  			{typ: done, running: 1, waiting: 0, started: true},
		52  			{typ: done, running: 0, waiting: 0, started: false},
		53  			{typ: add1, running: 1, waiting: 0, started: true},
		54  		},
		55  	}, {
		56  		max: 3,
		57  		run: []call{
		58  			{typ: add1, running: 1, waiting: 0, started: true},
		59  			{typ: add1, running: 2, waiting: 0, started: true},
		60  			{typ: add1, running: 3, waiting: 0, started: true},
		61  			{typ: add1, running: 3, waiting: 1, started: false},
		62  			{typ: add1, running: 3, waiting: 2, started: false},
		63  			{typ: add1, running: 3, waiting: 3, started: false},
		64  			{typ: done, running: 3, waiting: 2, started: true},
		65  			{typ: add1, running: 3, waiting: 3, started: false},
		66  			{typ: done, running: 3, waiting: 2, started: true},
		67  			{typ: done, running: 3, waiting: 1, started: true},
		68  			{typ: done, running: 3, waiting: 0, started: true},
		69  			{typ: done, running: 2, waiting: 0, started: false},
		70  			{typ: done, running: 1, waiting: 0, started: false},
		71  			{typ: done, running: 0, waiting: 0, started: false},
		72  		},
		73  	}}
		74  	for i, tc := range testCases {
		75  		ctx := &testContext{
		76  			startParallel: make(chan bool),
		77  			maxParallel:	 tc.max,
		78  		}
		79  		for j, call := range tc.run {
		80  			doCall := func(f func()) chan bool {
		81  				done := make(chan bool)
		82  				go func() {
		83  					f()
		84  					done <- true
		85  				}()
		86  				return done
		87  			}
		88  			started := false
		89  			switch call.typ {
		90  			case add1:
		91  				signal := doCall(ctx.waitParallel)
		92  				select {
		93  				case <-signal:
		94  					started = true
		95  				case ctx.startParallel <- true:
		96  					<-signal
		97  				}
		98  			case done:
		99  				signal := doCall(ctx.release)
	 100  				select {
	 101  				case <-signal:
	 102  				case <-ctx.startParallel:
	 103  					started = true
	 104  					<-signal
	 105  				}
	 106  			}
	 107  			if started != call.started {
	 108  				t.Errorf("%d:%d:started: got %v; want %v", i, j, started, call.started)
	 109  			}
	 110  			if ctx.running != call.running {
	 111  				t.Errorf("%d:%d:running: got %v; want %v", i, j, ctx.running, call.running)
	 112  			}
	 113  			if ctx.numWaiting != call.waiting {
	 114  				t.Errorf("%d:%d:waiting: got %v; want %v", i, j, ctx.numWaiting, call.waiting)
	 115  			}
	 116  		}
	 117  	}
	 118  }
	 119  
	 120  func TestTRun(t *T) {
	 121  	realTest := t
	 122  	testCases := []struct {
	 123  		desc	 string
	 124  		ok		 bool
	 125  		maxPar int
	 126  		chatty bool
	 127  		output string
	 128  		f			func(*T)
	 129  	}{{
	 130  		desc:	 "failnow skips future sequential and parallel tests at same level",
	 131  		ok:		 false,
	 132  		maxPar: 1,
	 133  		output: `
	 134  --- FAIL: failnow skips future sequential and parallel tests at same level (N.NNs)
	 135  		--- FAIL: failnow skips future sequential and parallel tests at same level/#00 (N.NNs)
	 136  		`,
	 137  		f: func(t *T) {
	 138  			ranSeq := false
	 139  			ranPar := false
	 140  			t.Run("", func(t *T) {
	 141  				t.Run("par", func(t *T) {
	 142  					t.Parallel()
	 143  					ranPar = true
	 144  				})
	 145  				t.Run("seq", func(t *T) {
	 146  					ranSeq = true
	 147  				})
	 148  				t.FailNow()
	 149  				t.Run("seq", func(t *T) {
	 150  					realTest.Error("test must be skipped")
	 151  				})
	 152  				t.Run("par", func(t *T) {
	 153  					t.Parallel()
	 154  					realTest.Error("test must be skipped.")
	 155  				})
	 156  			})
	 157  			if !ranPar {
	 158  				realTest.Error("parallel test was not run")
	 159  			}
	 160  			if !ranSeq {
	 161  				realTest.Error("sequential test was not run")
	 162  			}
	 163  		},
	 164  	}, {
	 165  		desc:	 "failure in parallel test propagates upwards",
	 166  		ok:		 false,
	 167  		maxPar: 1,
	 168  		output: `
	 169  --- FAIL: failure in parallel test propagates upwards (N.NNs)
	 170  		--- FAIL: failure in parallel test propagates upwards/#00 (N.NNs)
	 171  				--- FAIL: failure in parallel test propagates upwards/#00/par (N.NNs)
	 172  				`,
	 173  		f: func(t *T) {
	 174  			t.Run("", func(t *T) {
	 175  				t.Parallel()
	 176  				t.Run("par", func(t *T) {
	 177  					t.Parallel()
	 178  					t.Fail()
	 179  				})
	 180  			})
	 181  		},
	 182  	}, {
	 183  		desc:	 "skipping without message, chatty",
	 184  		ok:		 true,
	 185  		chatty: true,
	 186  		output: `
	 187  === RUN	 skipping without message, chatty
	 188  --- SKIP: skipping without message, chatty (N.NNs)`,
	 189  		f: func(t *T) { t.SkipNow() },
	 190  	}, {
	 191  		desc:	 "chatty with recursion",
	 192  		ok:		 true,
	 193  		chatty: true,
	 194  		output: `
	 195  === RUN	 chatty with recursion
	 196  === RUN	 chatty with recursion/#00
	 197  === RUN	 chatty with recursion/#00/#00
	 198  --- PASS: chatty with recursion (N.NNs)
	 199  		--- PASS: chatty with recursion/#00 (N.NNs)
	 200  				--- PASS: chatty with recursion/#00/#00 (N.NNs)`,
	 201  		f: func(t *T) {
	 202  			t.Run("", func(t *T) {
	 203  				t.Run("", func(t *T) {})
	 204  			})
	 205  		},
	 206  	}, {
	 207  		desc: "skipping without message, not chatty",
	 208  		ok:	 true,
	 209  		f:		func(t *T) { t.SkipNow() },
	 210  	}, {
	 211  		desc: "skipping after error",
	 212  		output: `
	 213  --- FAIL: skipping after error (N.NNs)
	 214  		sub_test.go:NNN: an error
	 215  		sub_test.go:NNN: skipped`,
	 216  		f: func(t *T) {
	 217  			t.Error("an error")
	 218  			t.Skip("skipped")
	 219  		},
	 220  	}, {
	 221  		desc:	 "use Run to locally synchronize parallelism",
	 222  		ok:		 true,
	 223  		maxPar: 1,
	 224  		f: func(t *T) {
	 225  			var count uint32
	 226  			t.Run("waitGroup", func(t *T) {
	 227  				for i := 0; i < 4; i++ {
	 228  					t.Run("par", func(t *T) {
	 229  						t.Parallel()
	 230  						atomic.AddUint32(&count, 1)
	 231  					})
	 232  				}
	 233  			})
	 234  			if count != 4 {
	 235  				t.Errorf("count was %d; want 4", count)
	 236  			}
	 237  		},
	 238  	}, {
	 239  		desc: "alternate sequential and parallel",
	 240  		// Sequential tests should partake in the counting of running threads.
	 241  		// Otherwise, if one runs parallel subtests in sequential tests that are
	 242  		// itself subtests of parallel tests, the counts can get askew.
	 243  		ok:		 true,
	 244  		maxPar: 1,
	 245  		f: func(t *T) {
	 246  			t.Run("a", func(t *T) {
	 247  				t.Parallel()
	 248  				t.Run("b", func(t *T) {
	 249  					// Sequential: ensure running count is decremented.
	 250  					t.Run("c", func(t *T) {
	 251  						t.Parallel()
	 252  					})
	 253  
	 254  				})
	 255  			})
	 256  		},
	 257  	}, {
	 258  		desc: "alternate sequential and parallel 2",
	 259  		// Sequential tests should partake in the counting of running threads.
	 260  		// Otherwise, if one runs parallel subtests in sequential tests that are
	 261  		// itself subtests of parallel tests, the counts can get askew.
	 262  		ok:		 true,
	 263  		maxPar: 2,
	 264  		f: func(t *T) {
	 265  			for i := 0; i < 2; i++ {
	 266  				t.Run("a", func(t *T) {
	 267  					t.Parallel()
	 268  					time.Sleep(time.Nanosecond)
	 269  					for i := 0; i < 2; i++ {
	 270  						t.Run("b", func(t *T) {
	 271  							time.Sleep(time.Nanosecond)
	 272  							for i := 0; i < 2; i++ {
	 273  								t.Run("c", func(t *T) {
	 274  									t.Parallel()
	 275  									time.Sleep(time.Nanosecond)
	 276  								})
	 277  							}
	 278  
	 279  						})
	 280  					}
	 281  				})
	 282  			}
	 283  		},
	 284  	}, {
	 285  		desc:	 "stress test",
	 286  		ok:		 true,
	 287  		maxPar: 4,
	 288  		f: func(t *T) {
	 289  			t.Parallel()
	 290  			for i := 0; i < 12; i++ {
	 291  				t.Run("a", func(t *T) {
	 292  					t.Parallel()
	 293  					time.Sleep(time.Nanosecond)
	 294  					for i := 0; i < 12; i++ {
	 295  						t.Run("b", func(t *T) {
	 296  							time.Sleep(time.Nanosecond)
	 297  							for i := 0; i < 12; i++ {
	 298  								t.Run("c", func(t *T) {
	 299  									t.Parallel()
	 300  									time.Sleep(time.Nanosecond)
	 301  									t.Run("d1", func(t *T) {})
	 302  									t.Run("d2", func(t *T) {})
	 303  									t.Run("d3", func(t *T) {})
	 304  									t.Run("d4", func(t *T) {})
	 305  								})
	 306  							}
	 307  						})
	 308  					}
	 309  				})
	 310  			}
	 311  		},
	 312  	}, {
	 313  		desc:	 "skip output",
	 314  		ok:		 true,
	 315  		maxPar: 4,
	 316  		f: func(t *T) {
	 317  			t.Skip()
	 318  		},
	 319  	}, {
	 320  		desc: "subtest calls error on parent",
	 321  		ok:	 false,
	 322  		output: `
	 323  --- FAIL: subtest calls error on parent (N.NNs)
	 324  		sub_test.go:NNN: first this
	 325  		sub_test.go:NNN: and now this!
	 326  		sub_test.go:NNN: oh, and this too`,
	 327  		maxPar: 1,
	 328  		f: func(t *T) {
	 329  			t.Errorf("first this")
	 330  			outer := t
	 331  			t.Run("", func(t *T) {
	 332  				outer.Errorf("and now this!")
	 333  			})
	 334  			t.Errorf("oh, and this too")
	 335  		},
	 336  	}, {
	 337  		desc: "subtest calls fatal on parent",
	 338  		ok:	 false,
	 339  		output: `
	 340  --- FAIL: subtest calls fatal on parent (N.NNs)
	 341  		sub_test.go:NNN: first this
	 342  		sub_test.go:NNN: and now this!
	 343  		--- FAIL: subtest calls fatal on parent/#00 (N.NNs)
	 344  				testing.go:NNN: test executed panic(nil) or runtime.Goexit: subtest may have called FailNow on a parent test`,
	 345  		maxPar: 1,
	 346  		f: func(t *T) {
	 347  			outer := t
	 348  			t.Errorf("first this")
	 349  			t.Run("", func(t *T) {
	 350  				outer.Fatalf("and now this!")
	 351  			})
	 352  			t.Errorf("Should not reach here.")
	 353  		},
	 354  	}, {
	 355  		desc: "subtest calls error on ancestor",
	 356  		ok:	 false,
	 357  		output: `
	 358  --- FAIL: subtest calls error on ancestor (N.NNs)
	 359  		sub_test.go:NNN: Report to ancestor
	 360  		--- FAIL: subtest calls error on ancestor/#00 (N.NNs)
	 361  				sub_test.go:NNN: Still do this
	 362  		sub_test.go:NNN: Also do this`,
	 363  		maxPar: 1,
	 364  		f: func(t *T) {
	 365  			outer := t
	 366  			t.Run("", func(t *T) {
	 367  				t.Run("", func(t *T) {
	 368  					outer.Errorf("Report to ancestor")
	 369  				})
	 370  				t.Errorf("Still do this")
	 371  			})
	 372  			t.Errorf("Also do this")
	 373  		},
	 374  	}, {
	 375  		desc: "subtest calls fatal on ancestor",
	 376  		ok:	 false,
	 377  		output: `
	 378  --- FAIL: subtest calls fatal on ancestor (N.NNs)
	 379  		sub_test.go:NNN: Nope`,
	 380  		maxPar: 1,
	 381  		f: func(t *T) {
	 382  			outer := t
	 383  			t.Run("", func(t *T) {
	 384  				for i := 0; i < 4; i++ {
	 385  					t.Run("", func(t *T) {
	 386  						outer.Fatalf("Nope")
	 387  					})
	 388  					t.Errorf("Don't do this")
	 389  				}
	 390  				t.Errorf("And neither do this")
	 391  			})
	 392  			t.Errorf("Nor this")
	 393  		},
	 394  	}, {
	 395  		desc:	 "panic on goroutine fail after test exit",
	 396  		ok:		 false,
	 397  		maxPar: 4,
	 398  		f: func(t *T) {
	 399  			ch := make(chan bool)
	 400  			t.Run("", func(t *T) {
	 401  				go func() {
	 402  					<-ch
	 403  					defer func() {
	 404  						if r := recover(); r == nil {
	 405  							realTest.Errorf("expected panic")
	 406  						}
	 407  						ch <- true
	 408  					}()
	 409  					t.Errorf("failed after success")
	 410  				}()
	 411  			})
	 412  			ch <- true
	 413  			<-ch
	 414  		},
	 415  	}, {
	 416  		desc: "log in finished sub test logs to parent",
	 417  		ok:	 false,
	 418  		output: `
	 419  		--- FAIL: log in finished sub test logs to parent (N.NNs)
	 420  		sub_test.go:NNN: message2
	 421  		sub_test.go:NNN: message1
	 422  		sub_test.go:NNN: error`,
	 423  		maxPar: 1,
	 424  		f: func(t *T) {
	 425  			ch := make(chan bool)
	 426  			t.Run("sub", func(t2 *T) {
	 427  				go func() {
	 428  					<-ch
	 429  					t2.Log("message1")
	 430  					ch <- true
	 431  				}()
	 432  			})
	 433  			t.Log("message2")
	 434  			ch <- true
	 435  			<-ch
	 436  			t.Errorf("error")
	 437  		},
	 438  	}, {
	 439  		// A chatty test should always log with fmt.Print, even if the
	 440  		// parent test has completed.
	 441  		desc:	 "log in finished sub test with chatty",
	 442  		ok:		 false,
	 443  		chatty: true,
	 444  		output: `
	 445  		--- FAIL: log in finished sub test with chatty (N.NNs)`,
	 446  		maxPar: 1,
	 447  		f: func(t *T) {
	 448  			ch := make(chan bool)
	 449  			t.Run("sub", func(t2 *T) {
	 450  				go func() {
	 451  					<-ch
	 452  					t2.Log("message1")
	 453  					ch <- true
	 454  				}()
	 455  			})
	 456  			t.Log("message2")
	 457  			ch <- true
	 458  			<-ch
	 459  			t.Errorf("error")
	 460  		},
	 461  	}, {
	 462  		// If a subtest panics we should run cleanups.
	 463  		desc:	 "cleanup when subtest panics",
	 464  		ok:		 false,
	 465  		chatty: false,
	 466  		output: `
	 467  --- FAIL: cleanup when subtest panics (N.NNs)
	 468  		--- FAIL: cleanup when subtest panics/sub (N.NNs)
	 469  		sub_test.go:NNN: running cleanup`,
	 470  		f: func(t *T) {
	 471  			t.Cleanup(func() { t.Log("running cleanup") })
	 472  			t.Run("sub", func(t2 *T) {
	 473  				t2.FailNow()
	 474  			})
	 475  		},
	 476  	}}
	 477  	for _, tc := range testCases {
	 478  		t.Run(tc.desc, func(t *T) {
	 479  			ctx := newTestContext(tc.maxPar, newMatcher(regexp.MatchString, "", ""))
	 480  			buf := &bytes.Buffer{}
	 481  			root := &T{
	 482  				common: common{
	 483  					signal: make(chan bool),
	 484  					name:	 "Test",
	 485  					w:			buf,
	 486  				},
	 487  				context: ctx,
	 488  			}
	 489  			if tc.chatty {
	 490  				root.chatty = newChattyPrinter(root.w)
	 491  			}
	 492  			ok := root.Run(tc.desc, tc.f)
	 493  			ctx.release()
	 494  
	 495  			if ok != tc.ok {
	 496  				t.Errorf("%s:ok: got %v; want %v", tc.desc, ok, tc.ok)
	 497  			}
	 498  			if ok != !root.Failed() {
	 499  				t.Errorf("%s:root failed: got %v; want %v", tc.desc, !ok, root.Failed())
	 500  			}
	 501  			if ctx.running != 0 || ctx.numWaiting != 0 {
	 502  				t.Errorf("%s:running and waiting non-zero: got %d and %d", tc.desc, ctx.running, ctx.numWaiting)
	 503  			}
	 504  			got := strings.TrimSpace(buf.String())
	 505  			want := strings.TrimSpace(tc.output)
	 506  			re := makeRegexp(want)
	 507  			if ok, err := regexp.MatchString(re, got); !ok || err != nil {
	 508  				t.Errorf("%s:output:\ngot:\n%s\nwant:\n%s", tc.desc, got, want)
	 509  			}
	 510  		})
	 511  	}
	 512  }
	 513  
	 514  func TestBRun(t *T) {
	 515  	work := func(b *B) {
	 516  		for i := 0; i < b.N; i++ {
	 517  			time.Sleep(time.Nanosecond)
	 518  		}
	 519  	}
	 520  	testCases := []struct {
	 521  		desc	 string
	 522  		failed bool
	 523  		chatty bool
	 524  		output string
	 525  		f			func(*B)
	 526  	}{{
	 527  		desc: "simulate sequential run of subbenchmarks.",
	 528  		f: func(b *B) {
	 529  			b.Run("", func(b *B) { work(b) })
	 530  			time1 := b.result.NsPerOp()
	 531  			b.Run("", func(b *B) { work(b) })
	 532  			time2 := b.result.NsPerOp()
	 533  			if time1 >= time2 {
	 534  				t.Errorf("no time spent in benchmark t1 >= t2 (%d >= %d)", time1, time2)
	 535  			}
	 536  		},
	 537  	}, {
	 538  		desc: "bytes set by all benchmarks",
	 539  		f: func(b *B) {
	 540  			b.Run("", func(b *B) { b.SetBytes(10); work(b) })
	 541  			b.Run("", func(b *B) { b.SetBytes(10); work(b) })
	 542  			if b.result.Bytes != 20 {
	 543  				t.Errorf("bytes: got: %d; want 20", b.result.Bytes)
	 544  			}
	 545  		},
	 546  	}, {
	 547  		desc: "bytes set by some benchmarks",
	 548  		// In this case the bytes result is meaningless, so it must be 0.
	 549  		f: func(b *B) {
	 550  			b.Run("", func(b *B) { b.SetBytes(10); work(b) })
	 551  			b.Run("", func(b *B) { work(b) })
	 552  			b.Run("", func(b *B) { b.SetBytes(10); work(b) })
	 553  			if b.result.Bytes != 0 {
	 554  				t.Errorf("bytes: got: %d; want 0", b.result.Bytes)
	 555  			}
	 556  		},
	 557  	}, {
	 558  		desc:	 "failure carried over to root",
	 559  		failed: true,
	 560  		output: "--- FAIL: root",
	 561  		f:			func(b *B) { b.Fail() },
	 562  	}, {
	 563  		desc:	 "skipping without message, chatty",
	 564  		chatty: true,
	 565  		output: "--- SKIP: root",
	 566  		f:			func(b *B) { b.SkipNow() },
	 567  	}, {
	 568  		desc:	 "chatty with recursion",
	 569  		chatty: true,
	 570  		f: func(b *B) {
	 571  			b.Run("", func(b *B) {
	 572  				b.Run("", func(b *B) {})
	 573  			})
	 574  		},
	 575  	}, {
	 576  		desc: "skipping without message, not chatty",
	 577  		f:		func(b *B) { b.SkipNow() },
	 578  	}, {
	 579  		desc:	 "skipping after error",
	 580  		failed: true,
	 581  		output: `
	 582  --- FAIL: root
	 583  		sub_test.go:NNN: an error
	 584  		sub_test.go:NNN: skipped`,
	 585  		f: func(b *B) {
	 586  			b.Error("an error")
	 587  			b.Skip("skipped")
	 588  		},
	 589  	}, {
	 590  		desc: "memory allocation",
	 591  		f: func(b *B) {
	 592  			const bufSize = 256
	 593  			alloc := func(b *B) {
	 594  				var buf [bufSize]byte
	 595  				for i := 0; i < b.N; i++ {
	 596  					_ = append([]byte(nil), buf[:]...)
	 597  				}
	 598  			}
	 599  			b.Run("", func(b *B) {
	 600  				alloc(b)
	 601  				b.ReportAllocs()
	 602  			})
	 603  			b.Run("", func(b *B) {
	 604  				alloc(b)
	 605  				b.ReportAllocs()
	 606  			})
	 607  			// runtime.MemStats sometimes reports more allocations than the
	 608  			// benchmark is responsible for. Luckily the point of this test is
	 609  			// to ensure that the results are not underreported, so we can
	 610  			// simply verify the lower bound.
	 611  			if got := b.result.MemAllocs; got < 2 {
	 612  				t.Errorf("MemAllocs was %v; want 2", got)
	 613  			}
	 614  			if got := b.result.MemBytes; got < 2*bufSize {
	 615  				t.Errorf("MemBytes was %v; want %v", got, 2*bufSize)
	 616  			}
	 617  		},
	 618  	}, {
	 619  		desc: "cleanup is called",
	 620  		f: func(b *B) {
	 621  			var calls, cleanups, innerCalls, innerCleanups int
	 622  			b.Run("", func(b *B) {
	 623  				calls++
	 624  				b.Cleanup(func() {
	 625  					cleanups++
	 626  				})
	 627  				b.Run("", func(b *B) {
	 628  					b.Cleanup(func() {
	 629  						innerCleanups++
	 630  					})
	 631  					innerCalls++
	 632  				})
	 633  				work(b)
	 634  			})
	 635  			if calls == 0 || calls != cleanups {
	 636  				t.Errorf("mismatched cleanups; got %d want %d", cleanups, calls)
	 637  			}
	 638  			if innerCalls == 0 || innerCalls != innerCleanups {
	 639  				t.Errorf("mismatched cleanups; got %d want %d", cleanups, calls)
	 640  			}
	 641  		},
	 642  	}, {
	 643  		desc:	 "cleanup is called on failure",
	 644  		failed: true,
	 645  		f: func(b *B) {
	 646  			var calls, cleanups int
	 647  			b.Run("", func(b *B) {
	 648  				calls++
	 649  				b.Cleanup(func() {
	 650  					cleanups++
	 651  				})
	 652  				b.Fatalf("failure")
	 653  			})
	 654  			if calls == 0 || calls != cleanups {
	 655  				t.Errorf("mismatched cleanups; got %d want %d", cleanups, calls)
	 656  			}
	 657  		},
	 658  	}}
	 659  	for _, tc := range testCases {
	 660  		t.Run(tc.desc, func(t *T) {
	 661  			var ok bool
	 662  			buf := &bytes.Buffer{}
	 663  			// This is almost like the Benchmark function, except that we override
	 664  			// the benchtime and catch the failure result of the subbenchmark.
	 665  			root := &B{
	 666  				common: common{
	 667  					signal: make(chan bool),
	 668  					name:	 "root",
	 669  					w:			buf,
	 670  				},
	 671  				benchFunc: func(b *B) { ok = b.Run("test", tc.f) }, // Use Run to catch failure.
	 672  				benchTime: benchTimeFlag{d: 1 * time.Microsecond},
	 673  			}
	 674  			if tc.chatty {
	 675  				root.chatty = newChattyPrinter(root.w)
	 676  			}
	 677  			root.runN(1)
	 678  			if ok != !tc.failed {
	 679  				t.Errorf("%s:ok: got %v; want %v", tc.desc, ok, !tc.failed)
	 680  			}
	 681  			if !ok != root.Failed() {
	 682  				t.Errorf("%s:root failed: got %v; want %v", tc.desc, !ok, root.Failed())
	 683  			}
	 684  			// All tests are run as subtests
	 685  			if root.result.N != 1 {
	 686  				t.Errorf("%s: N for parent benchmark was %d; want 1", tc.desc, root.result.N)
	 687  			}
	 688  			got := strings.TrimSpace(buf.String())
	 689  			want := strings.TrimSpace(tc.output)
	 690  			re := makeRegexp(want)
	 691  			if ok, err := regexp.MatchString(re, got); !ok || err != nil {
	 692  				t.Errorf("%s:output:\ngot:\n%s\nwant:\n%s", tc.desc, got, want)
	 693  			}
	 694  		})
	 695  	}
	 696  }
	 697  
	 698  func makeRegexp(s string) string {
	 699  	s = regexp.QuoteMeta(s)
	 700  	s = strings.ReplaceAll(s, ":NNN:", `:\d\d\d\d?:`)
	 701  	s = strings.ReplaceAll(s, "N\\.NNs", `\d*\.\d*s`)
	 702  	return s
	 703  }
	 704  
	 705  func TestBenchmarkOutput(t *T) {
	 706  	// Ensure Benchmark initialized common.w by invoking it with an error and
	 707  	// normal case.
	 708  	Benchmark(func(b *B) { b.Error("do not print this output") })
	 709  	Benchmark(func(b *B) {})
	 710  }
	 711  
	 712  func TestBenchmarkStartsFrom1(t *T) {
	 713  	var first = true
	 714  	Benchmark(func(b *B) {
	 715  		if first && b.N != 1 {
	 716  			panic(fmt.Sprintf("Benchmark() first N=%v; want 1", b.N))
	 717  		}
	 718  		first = false
	 719  	})
	 720  }
	 721  
	 722  func TestBenchmarkReadMemStatsBeforeFirstRun(t *T) {
	 723  	var first = true
	 724  	Benchmark(func(b *B) {
	 725  		if first && (b.startAllocs == 0 || b.startBytes == 0) {
	 726  			panic(fmt.Sprintf("ReadMemStats not called before first run"))
	 727  		}
	 728  		first = false
	 729  	})
	 730  }
	 731  
	 732  func TestParallelSub(t *T) {
	 733  	c := make(chan int)
	 734  	block := make(chan int)
	 735  	for i := 0; i < 10; i++ {
	 736  		go func(i int) {
	 737  			<-block
	 738  			t.Run(fmt.Sprint(i), func(t *T) {})
	 739  			c <- 1
	 740  		}(i)
	 741  	}
	 742  	close(block)
	 743  	for i := 0; i < 10; i++ {
	 744  		<-c
	 745  	}
	 746  }
	 747  
	 748  type funcWriter struct {
	 749  	write func([]byte) (int, error)
	 750  }
	 751  
	 752  func (fw *funcWriter) Write(b []byte) (int, error) {
	 753  	return fw.write(b)
	 754  }
	 755  
	 756  func TestRacyOutput(t *T) {
	 757  	var runs int32	// The number of running Writes
	 758  	var races int32 // Incremented for each race detected
	 759  	raceDetector := func(b []byte) (int, error) {
	 760  		// Check if some other goroutine is concurrently calling Write.
	 761  		if atomic.LoadInt32(&runs) > 0 {
	 762  			atomic.AddInt32(&races, 1) // Race detected!
	 763  		}
	 764  		atomic.AddInt32(&runs, 1)
	 765  		defer atomic.AddInt32(&runs, -1)
	 766  		runtime.Gosched() // Increase probability of a race
	 767  		return len(b), nil
	 768  	}
	 769  
	 770  	var wg sync.WaitGroup
	 771  	root := &T{
	 772  		common:	common{w: &funcWriter{raceDetector}},
	 773  		context: newTestContext(1, newMatcher(regexp.MatchString, "", "")),
	 774  	}
	 775  	root.chatty = newChattyPrinter(root.w)
	 776  	root.Run("", func(t *T) {
	 777  		for i := 0; i < 100; i++ {
	 778  			wg.Add(1)
	 779  			go func(i int) {
	 780  				defer wg.Done()
	 781  				t.Run(fmt.Sprint(i), func(t *T) {
	 782  					t.Logf("testing run %d", i)
	 783  				})
	 784  			}(i)
	 785  		}
	 786  	})
	 787  	wg.Wait()
	 788  
	 789  	if races > 0 {
	 790  		t.Errorf("detected %d racy Writes", races)
	 791  	}
	 792  }
	 793  
	 794  // The late log message did not include the test name.	Issue 29388.
	 795  func TestLogAfterComplete(t *T) {
	 796  	ctx := newTestContext(1, newMatcher(regexp.MatchString, "", ""))
	 797  	var buf bytes.Buffer
	 798  	t1 := &T{
	 799  		common: common{
	 800  			// Use a buffered channel so that tRunner can write
	 801  			// to it although nothing is reading from it.
	 802  			signal: make(chan bool, 1),
	 803  			w:			&buf,
	 804  		},
	 805  		context: ctx,
	 806  	}
	 807  
	 808  	c1 := make(chan bool)
	 809  	c2 := make(chan string)
	 810  	tRunner(t1, func(t *T) {
	 811  		t.Run("TestLateLog", func(t *T) {
	 812  			go func() {
	 813  				defer close(c2)
	 814  				defer func() {
	 815  					p := recover()
	 816  					if p == nil {
	 817  						c2 <- "subtest did not panic"
	 818  						return
	 819  					}
	 820  					s, ok := p.(string)
	 821  					if !ok {
	 822  						c2 <- fmt.Sprintf("subtest panic with unexpected value %v", p)
	 823  						return
	 824  					}
	 825  					const want = "Log in goroutine after TestLateLog has completed: log after test"
	 826  					if !strings.Contains(s, want) {
	 827  						c2 <- fmt.Sprintf("subtest panic %q does not contain %q", s, want)
	 828  					}
	 829  				}()
	 830  
	 831  				<-c1
	 832  				t.Log("log after test")
	 833  			}()
	 834  		})
	 835  	})
	 836  	close(c1)
	 837  
	 838  	if s := <-c2; s != "" {
	 839  		t.Error(s)
	 840  	}
	 841  }
	 842  
	 843  func TestBenchmark(t *T) {
	 844  	if Short() {
	 845  		t.Skip("skipping in short mode")
	 846  	}
	 847  	res := Benchmark(func(b *B) {
	 848  		for i := 0; i < 5; i++ {
	 849  			b.Run("", func(b *B) {
	 850  				for i := 0; i < b.N; i++ {
	 851  					time.Sleep(time.Millisecond)
	 852  				}
	 853  			})
	 854  		}
	 855  	})
	 856  	if res.NsPerOp() < 4000000 {
	 857  		t.Errorf("want >5ms; got %v", time.Duration(res.NsPerOp()))
	 858  	}
	 859  }
	 860  
	 861  func TestCleanup(t *T) {
	 862  	var cleanups []int
	 863  	t.Run("test", func(t *T) {
	 864  		t.Cleanup(func() { cleanups = append(cleanups, 1) })
	 865  		t.Cleanup(func() { cleanups = append(cleanups, 2) })
	 866  	})
	 867  	if got, want := cleanups, []int{2, 1}; !reflect.DeepEqual(got, want) {
	 868  		t.Errorf("unexpected cleanup record; got %v want %v", got, want)
	 869  	}
	 870  }
	 871  
	 872  func TestConcurrentCleanup(t *T) {
	 873  	cleanups := 0
	 874  	t.Run("test", func(t *T) {
	 875  		done := make(chan struct{})
	 876  		for i := 0; i < 2; i++ {
	 877  			i := i
	 878  			go func() {
	 879  				t.Cleanup(func() {
	 880  					cleanups |= 1 << i
	 881  				})
	 882  				done <- struct{}{}
	 883  			}()
	 884  		}
	 885  		<-done
	 886  		<-done
	 887  	})
	 888  	if cleanups != 1|2 {
	 889  		t.Errorf("unexpected cleanup; got %d want 3", cleanups)
	 890  	}
	 891  }
	 892  
	 893  func TestCleanupCalledEvenAfterGoexit(t *T) {
	 894  	cleanups := 0
	 895  	t.Run("test", func(t *T) {
	 896  		t.Cleanup(func() {
	 897  			cleanups++
	 898  		})
	 899  		t.Cleanup(func() {
	 900  			runtime.Goexit()
	 901  		})
	 902  	})
	 903  	if cleanups != 1 {
	 904  		t.Errorf("unexpected cleanup count; got %d want 1", cleanups)
	 905  	}
	 906  }
	 907  
	 908  func TestRunCleanup(t *T) {
	 909  	outerCleanup := 0
	 910  	innerCleanup := 0
	 911  	t.Run("test", func(t *T) {
	 912  		t.Cleanup(func() { outerCleanup++ })
	 913  		t.Run("x", func(t *T) {
	 914  			t.Cleanup(func() { innerCleanup++ })
	 915  		})
	 916  	})
	 917  	if innerCleanup != 1 {
	 918  		t.Errorf("unexpected inner cleanup count; got %d want 1", innerCleanup)
	 919  	}
	 920  	if outerCleanup != 1 {
	 921  		t.Errorf("unexpected outer cleanup count; got %d want 0", outerCleanup)
	 922  	}
	 923  }
	 924  
	 925  func TestCleanupParallelSubtests(t *T) {
	 926  	ranCleanup := 0
	 927  	t.Run("test", func(t *T) {
	 928  		t.Cleanup(func() { ranCleanup++ })
	 929  		t.Run("x", func(t *T) {
	 930  			t.Parallel()
	 931  			if ranCleanup > 0 {
	 932  				t.Error("outer cleanup ran before parallel subtest")
	 933  			}
	 934  		})
	 935  	})
	 936  	if ranCleanup != 1 {
	 937  		t.Errorf("unexpected cleanup count; got %d want 1", ranCleanup)
	 938  	}
	 939  }
	 940  
	 941  func TestNestedCleanup(t *T) {
	 942  	ranCleanup := 0
	 943  	t.Run("test", func(t *T) {
	 944  		t.Cleanup(func() {
	 945  			if ranCleanup != 2 {
	 946  				t.Errorf("unexpected cleanup count in first cleanup: got %d want 2", ranCleanup)
	 947  			}
	 948  			ranCleanup++
	 949  		})
	 950  		t.Cleanup(func() {
	 951  			if ranCleanup != 0 {
	 952  				t.Errorf("unexpected cleanup count in second cleanup: got %d want 0", ranCleanup)
	 953  			}
	 954  			ranCleanup++
	 955  			t.Cleanup(func() {
	 956  				if ranCleanup != 1 {
	 957  					t.Errorf("unexpected cleanup count in nested cleanup: got %d want 1", ranCleanup)
	 958  				}
	 959  				ranCleanup++
	 960  			})
	 961  		})
	 962  	})
	 963  	if ranCleanup != 3 {
	 964  		t.Errorf("unexpected cleanup count: got %d want 3", ranCleanup)
	 965  	}
	 966  }
	 967  

View as plain text