Source file
src/cmd/covdata/tool_test.go
1
2
3
4
5 package main_test
6
7 import (
8 cmdcovdata "cmd/covdata"
9 "flag"
10 "fmt"
11 "internal/coverage/pods"
12 "internal/goexperiment"
13 "internal/testenv"
14 "log"
15 "os"
16 "path/filepath"
17 "regexp"
18 "strconv"
19 "strings"
20 "sync"
21 "testing"
22 )
23
24
25
26 func testcovdata(t testing.TB) string {
27 exe, err := os.Executable()
28 if err != nil {
29 t.Helper()
30 t.Fatal(err)
31 }
32 return exe
33 }
34
35
36 var testTempDir string
37
38
39 var preserveTmp = flag.Bool("preservetmp", false, "keep tmpdir files for debugging")
40
41
42
43
44 func TestMain(m *testing.M) {
45
46
47
48
49 if os.Getenv("CMDCOVDATA_TEST_RUN_MAIN") != "" {
50 cmdcovdata.Main()
51 os.Exit(0)
52 }
53 flag.Parse()
54 topTmpdir, err := os.MkdirTemp("", "cmd-covdata-test-")
55 if err != nil {
56 log.Fatal(err)
57 }
58 testTempDir = topTmpdir
59 if !*preserveTmp {
60 defer os.RemoveAll(topTmpdir)
61 } else {
62 fmt.Fprintf(os.Stderr, "debug: preserving tmpdir %s\n", topTmpdir)
63 }
64 os.Setenv("CMDCOVDATA_TEST_RUN_MAIN", "true")
65 os.Exit(m.Run())
66 }
67
68 var tdmu sync.Mutex
69 var tdcount int
70
71 func tempDir(t *testing.T) string {
72 tdmu.Lock()
73 dir := filepath.Join(testTempDir, fmt.Sprintf("%03d", tdcount))
74 tdcount++
75 if err := os.Mkdir(dir, 0777); err != nil {
76 t.Fatal(err)
77 }
78 defer tdmu.Unlock()
79 return dir
80 }
81
82 const debugtrace = false
83
84 func gobuild(t *testing.T, indir string, bargs []string) {
85 t.Helper()
86
87 if debugtrace {
88 if indir != "" {
89 t.Logf("in dir %s: ", indir)
90 }
91 t.Logf("cmd: %s %+v\n", testenv.GoToolPath(t), bargs)
92 }
93 cmd := testenv.Command(t, testenv.GoToolPath(t), bargs...)
94 cmd.Dir = indir
95 b, err := cmd.CombinedOutput()
96 if len(b) != 0 {
97 t.Logf("## build output:\n%s", b)
98 }
99 if err != nil {
100 t.Fatalf("build error: %v", err)
101 }
102 }
103
104 func emitFile(t *testing.T, dst, src string) {
105 payload, err := os.ReadFile(src)
106 if err != nil {
107 t.Fatalf("error reading %q: %v", src, err)
108 }
109 if err := os.WriteFile(dst, payload, 0666); err != nil {
110 t.Fatalf("writing %q: %v", dst, err)
111 }
112 }
113
114 const mainPkgPath = "prog"
115
116 func buildProg(t *testing.T, prog string, dir string, tag string, flags []string) (string, string) {
117
118 subdir := filepath.Join(dir, prog+"dir"+tag)
119 if err := os.Mkdir(subdir, 0777); err != nil {
120 t.Fatalf("can't create outdir %s: %v", subdir, err)
121 }
122 depdir := filepath.Join(subdir, "dep")
123 if err := os.Mkdir(depdir, 0777); err != nil {
124 t.Fatalf("can't create outdir %s: %v", depdir, err)
125 }
126
127
128 insrc := filepath.Join("testdata", prog+".go")
129 src := filepath.Join(subdir, prog+".go")
130 emitFile(t, src, insrc)
131 indep := filepath.Join("testdata", "dep.go")
132 dep := filepath.Join(depdir, "dep.go")
133 emitFile(t, dep, indep)
134
135
136 mod := filepath.Join(subdir, "go.mod")
137 modsrc := "\nmodule " + mainPkgPath + "\n\ngo 1.19\n"
138 if err := os.WriteFile(mod, []byte(modsrc), 0666); err != nil {
139 t.Fatal(err)
140 }
141 exepath := filepath.Join(subdir, prog+".exe")
142 bargs := []string{"build", "-cover", "-o", exepath}
143 bargs = append(bargs, flags...)
144 gobuild(t, subdir, bargs)
145 return exepath, subdir
146 }
147
148 type state struct {
149 dir string
150 exedir1 string
151 exedir2 string
152 exedir3 string
153 exepath1 string
154 exepath2 string
155 exepath3 string
156 tool string
157 outdirs [4]string
158 }
159
160 const debugWorkDir = false
161
162 func TestCovTool(t *testing.T) {
163 testenv.MustHaveGoBuild(t)
164 if !goexperiment.CoverageRedesign {
165 t.Skipf("stubbed out due to goexperiment.CoverageRedesign=false")
166 }
167 dir := tempDir(t)
168 if testing.Short() {
169 t.Skip()
170 }
171 if debugWorkDir {
172
173 dir = "/tmp/qqq"
174 os.RemoveAll(dir)
175 os.Mkdir(dir, 0777)
176 }
177
178 s := state{
179 dir: dir,
180 }
181 s.exepath1, s.exedir1 = buildProg(t, "prog1", dir, "", nil)
182 s.exepath2, s.exedir2 = buildProg(t, "prog2", dir, "", nil)
183 flags := []string{"-covermode=atomic"}
184 s.exepath3, s.exedir3 = buildProg(t, "prog1", dir, "atomic", flags)
185
186
187 s.tool = testcovdata(t)
188
189
190 for i := 0; i < 4; i++ {
191 d := filepath.Join(dir, fmt.Sprintf("covdata%d", i))
192 s.outdirs[i] = d
193 if err := os.Mkdir(d, 0777); err != nil {
194 t.Fatalf("can't create outdir %s: %v", d, err)
195 }
196 }
197
198
199
200
201
202
203
204
205
206 for m := 0; m < 2; m++ {
207 for k := 0; k < 2; k++ {
208 args := []string{}
209 if k != 0 {
210 args = append(args, "foo", "bar")
211 }
212 for i := 0; i <= k; i++ {
213 exepath := s.exepath1
214 if m != 0 {
215 exepath = s.exepath3
216 }
217 cmd := testenv.Command(t, exepath, args...)
218 cmd.Env = append(cmd.Env, "GOCOVERDIR="+s.outdirs[m*2+k])
219 b, err := cmd.CombinedOutput()
220 if len(b) != 0 {
221 t.Logf("## instrumented run output:\n%s", b)
222 }
223 if err != nil {
224 t.Fatalf("instrumented run error: %v", err)
225 }
226 }
227 }
228 }
229
230
231
232 t.Run("MergeSimple", func(t *testing.T) {
233 t.Parallel()
234 testMergeSimple(t, s, s.outdirs[0], s.outdirs[1], "set")
235 testMergeSimple(t, s, s.outdirs[2], s.outdirs[3], "atomic")
236 })
237 t.Run("MergeSelect", func(t *testing.T) {
238 t.Parallel()
239 testMergeSelect(t, s, s.outdirs[0], s.outdirs[1], "set")
240 testMergeSelect(t, s, s.outdirs[2], s.outdirs[3], "atomic")
241 })
242 t.Run("MergePcombine", func(t *testing.T) {
243 t.Parallel()
244 testMergeCombinePrograms(t, s)
245 })
246 t.Run("Dump", func(t *testing.T) {
247 t.Parallel()
248 testDump(t, s)
249 })
250 t.Run("Percent", func(t *testing.T) {
251 t.Parallel()
252 testPercent(t, s)
253 })
254 t.Run("PkgList", func(t *testing.T) {
255 t.Parallel()
256 testPkgList(t, s)
257 })
258 t.Run("Textfmt", func(t *testing.T) {
259 t.Parallel()
260 testTextfmt(t, s)
261 })
262 t.Run("Subtract", func(t *testing.T) {
263 t.Parallel()
264 testSubtract(t, s)
265 })
266 t.Run("Intersect", func(t *testing.T) {
267 t.Parallel()
268 testIntersect(t, s, s.outdirs[0], s.outdirs[1], "set")
269 testIntersect(t, s, s.outdirs[2], s.outdirs[3], "atomic")
270 })
271 t.Run("CounterClash", func(t *testing.T) {
272 t.Parallel()
273 testCounterClash(t, s)
274 })
275 t.Run("TestEmpty", func(t *testing.T) {
276 t.Parallel()
277 testEmpty(t, s)
278 })
279 t.Run("TestCommandLineErrors", func(t *testing.T) {
280 t.Parallel()
281 testCommandLineErrors(t, s, s.outdirs[0])
282 })
283 }
284
285 const showToolInvocations = true
286
287 func runToolOp(t *testing.T, s state, op string, args []string) []string {
288
289 t.Helper()
290 args = append([]string{op}, args...)
291 if showToolInvocations {
292 t.Logf("%s cmd is: %s %+v", op, s.tool, args)
293 }
294 cmd := testenv.Command(t, s.tool, args...)
295 b, err := cmd.CombinedOutput()
296 if err != nil {
297 fmt.Fprintf(os.Stderr, "## %s output: %s\n", op, b)
298 t.Fatalf("%q run error: %v", op, err)
299 }
300 output := strings.TrimSpace(string(b))
301 lines := strings.Split(output, "\n")
302 if len(lines) == 1 && lines[0] == "" {
303 lines = nil
304 }
305 return lines
306 }
307
308 func testDump(t *testing.T, s state) {
309
310 dargs := []string{"-pkg=" + mainPkgPath, "-live", "-i=" + s.outdirs[0] + "," + s.outdirs[1]}
311 lines := runToolOp(t, s, "debugdump", dargs)
312
313
314 testpoints := []struct {
315 tag string
316 re *regexp.Regexp
317 }{
318 {
319 "args",
320 regexp.MustCompile(`^data file .+ GOOS=.+ GOARCH=.+ program args: .+$`),
321 },
322 {
323 "main package",
324 regexp.MustCompile(`^Package path: ` + mainPkgPath + `\s*$`),
325 },
326 {
327 "main function",
328 regexp.MustCompile(`^Func: main\s*$`),
329 },
330 }
331
332 bad := false
333 for _, testpoint := range testpoints {
334 found := false
335 for _, line := range lines {
336 if m := testpoint.re.FindStringSubmatch(line); m != nil {
337 found = true
338 break
339 }
340 }
341 if !found {
342 t.Errorf("dump output regexp match failed for %q", testpoint.tag)
343 bad = true
344 }
345 }
346 if bad {
347 dumplines(lines)
348 }
349 }
350
351 func testPercent(t *testing.T, s state) {
352
353 dargs := []string{"-pkg=" + mainPkgPath, "-i=" + s.outdirs[0] + "," + s.outdirs[1]}
354 lines := runToolOp(t, s, "percent", dargs)
355
356
357 testpoints := []struct {
358 tag string
359 re *regexp.Regexp
360 }{
361 {
362 "statement coverage percent",
363 regexp.MustCompile(`coverage: \d+\.\d% of statements\s*$`),
364 },
365 }
366
367 bad := false
368 for _, testpoint := range testpoints {
369 found := false
370 for _, line := range lines {
371 if m := testpoint.re.FindStringSubmatch(line); m != nil {
372 found = true
373 break
374 }
375 }
376 if !found {
377 t.Errorf("percent output regexp match failed for %s", testpoint.tag)
378 bad = true
379 }
380 }
381 if bad {
382 dumplines(lines)
383 }
384 }
385
386 func testPkgList(t *testing.T, s state) {
387 dargs := []string{"-i=" + s.outdirs[0] + "," + s.outdirs[1]}
388 lines := runToolOp(t, s, "pkglist", dargs)
389
390 want := []string{mainPkgPath, mainPkgPath + "/dep"}
391 bad := false
392 if len(lines) != 2 {
393 t.Errorf("expect pkglist to return two lines")
394 bad = true
395 } else {
396 for i := 0; i < 2; i++ {
397 lines[i] = strings.TrimSpace(lines[i])
398 if want[i] != lines[i] {
399 t.Errorf("line %d want %s got %s", i, want[i], lines[i])
400 bad = true
401 }
402 }
403 }
404 if bad {
405 dumplines(lines)
406 }
407 }
408
409 func testTextfmt(t *testing.T, s state) {
410 outf := s.dir + "/" + "t.txt"
411 dargs := []string{"-pkg=" + mainPkgPath, "-i=" + s.outdirs[0] + "," + s.outdirs[1],
412 "-o", outf}
413 lines := runToolOp(t, s, "textfmt", dargs)
414
415
416 if len(lines) != 0 {
417 dumplines(lines)
418 t.Errorf("unexpected output from go tool covdata textfmt")
419 }
420
421
422 payload, err := os.ReadFile(outf)
423 if err != nil {
424 t.Errorf("opening %s: %v\n", outf, err)
425 }
426 lines = strings.Split(string(payload), "\n")
427 want0 := "mode: set"
428 if lines[0] != want0 {
429 dumplines(lines[0:10])
430 t.Errorf("textfmt: want %s got %s", want0, lines[0])
431 }
432 want1 := mainPkgPath + "/prog1.go:13.14,15.2 1 1"
433 if lines[1] != want1 {
434 dumplines(lines[0:10])
435 t.Errorf("textfmt: want %s got %s", want1, lines[1])
436 }
437 }
438
439 func dumplines(lines []string) {
440 for i := range lines {
441 fmt.Fprintf(os.Stderr, "%s\n", lines[i])
442 }
443 }
444
445 type dumpCheck struct {
446 tag string
447 re *regexp.Regexp
448 negate bool
449 nonzero bool
450 zero bool
451 }
452
453
454
455
456 func runDumpChecks(t *testing.T, s state, dir string, flags []string, checks []dumpCheck) {
457 dargs := []string{"-i", dir}
458 dargs = append(dargs, flags...)
459 lines := runToolOp(t, s, "debugdump", dargs)
460 if len(lines) == 0 {
461 t.Fatalf("dump run produced no output")
462 }
463
464 bad := false
465 for _, check := range checks {
466 found := false
467 for _, line := range lines {
468 if m := check.re.FindStringSubmatch(line); m != nil {
469 found = true
470 if check.negate {
471 t.Errorf("tag %q: unexpected match", check.tag)
472 bad = true
473
474 }
475 if check.nonzero || check.zero {
476 if len(m) < 2 {
477 t.Errorf("tag %s: submatch failed (short m)", check.tag)
478 bad = true
479 continue
480 }
481 if m[1] == "" {
482 t.Errorf("tag %s: submatch failed", check.tag)
483 bad = true
484 continue
485 }
486 i, err := strconv.Atoi(m[1])
487 if err != nil {
488 t.Errorf("tag %s: match Atoi failed on %s",
489 check.tag, m[1])
490 continue
491 }
492 if check.zero && i != 0 {
493 t.Errorf("tag %s: match zero failed on %s",
494 check.tag, m[1])
495 } else if check.nonzero && i == 0 {
496 t.Errorf("tag %s: match nonzero failed on %s",
497 check.tag, m[1])
498 }
499 }
500 break
501 }
502 }
503 if !found && !check.negate {
504 t.Errorf("dump output regexp match failed for %s", check.tag)
505 bad = true
506 }
507 }
508 if bad {
509 fmt.Printf("output from 'dump' run:\n")
510 dumplines(lines)
511 }
512 }
513
514 func testMergeSimple(t *testing.T, s state, indir1, indir2, tag string) {
515 outdir := filepath.Join(s.dir, "simpleMergeOut"+tag)
516 if err := os.Mkdir(outdir, 0777); err != nil {
517 t.Fatalf("can't create outdir %s: %v", outdir, err)
518 }
519
520
521 ins := fmt.Sprintf("-i=%s,%s", indir1, indir2)
522 out := fmt.Sprintf("-o=%s", outdir)
523 margs := []string{ins, out}
524 lines := runToolOp(t, s, "merge", margs)
525 if len(lines) != 0 {
526 t.Errorf("merge run produced %d lines of unexpected output", len(lines))
527 dumplines(lines)
528 }
529
530
531
532
533 podlist, err := pods.CollectPods([]string{outdir}, true)
534 if err != nil {
535 t.Fatal(err)
536 }
537 if len(podlist) != 1 {
538 t.Fatalf("expected 1 pod, got %d pods", len(podlist))
539 }
540 ncdfs := len(podlist[0].CounterDataFiles)
541 if ncdfs != 1 {
542 t.Fatalf("expected 1 counter data file, got %d", ncdfs)
543 }
544
545
546
547
548 testpoints := []dumpCheck{
549 {
550 tag: "first function",
551 re: regexp.MustCompile(`^Func: first\s*$`),
552 },
553 {
554 tag: "second function",
555 re: regexp.MustCompile(`^Func: second\s*$`),
556 },
557 {
558 tag: "third function",
559 re: regexp.MustCompile(`^Func: third\s*$`),
560 },
561 {
562 tag: "third function unit 0",
563 re: regexp.MustCompile(`^0: L23:C23 -- L24:C12 NS=1 = (\d+)$`),
564 nonzero: true,
565 },
566 {
567 tag: "third function unit 1",
568 re: regexp.MustCompile(`^1: L27:C2 -- L28:C10 NS=2 = (\d+)$`),
569 nonzero: true,
570 },
571 {
572 tag: "third function unit 2",
573 re: regexp.MustCompile(`^2: L24:C12 -- L26:C3 NS=1 = (\d+)$`),
574 nonzero: true,
575 },
576 }
577 flags := []string{"-live", "-pkg=" + mainPkgPath}
578 runDumpChecks(t, s, outdir, flags, testpoints)
579 }
580
581 func testMergeSelect(t *testing.T, s state, indir1, indir2 string, tag string) {
582 outdir := filepath.Join(s.dir, "selectMergeOut"+tag)
583 if err := os.Mkdir(outdir, 0777); err != nil {
584 t.Fatalf("can't create outdir %s: %v", outdir, err)
585 }
586
587
588
589 ins := fmt.Sprintf("-i=%s,%s", indir1, indir2)
590 out := fmt.Sprintf("-o=%s", outdir)
591 margs := []string{"-pkg=" + mainPkgPath + "/dep", ins, out}
592 lines := runToolOp(t, s, "merge", margs)
593 if len(lines) != 0 {
594 t.Errorf("merge run produced %d lines of unexpected output", len(lines))
595 dumplines(lines)
596 }
597
598
599
600 dargs := []string{"-i=" + outdir}
601 lines = runToolOp(t, s, "debugdump", dargs)
602 if len(lines) == 0 {
603 t.Fatalf("dump run produced no output")
604 }
605 want := map[string]int{
606 "Package path: " + mainPkgPath + "/dep": 0,
607 "Func: Dep1": 0,
608 "Func: PDep": 0,
609 }
610 bad := false
611 for _, line := range lines {
612 if v, ok := want[line]; ok {
613 if v != 0 {
614 t.Errorf("duplicate line %s", line)
615 bad = true
616 break
617 }
618 want[line] = 1
619 continue
620 }
621
622 if strings.HasPrefix(line, "Func:") || strings.HasPrefix(line, "Package path:") {
623 t.Errorf("unexpected line: %s", line)
624 bad = true
625 break
626 }
627 }
628 if bad {
629 dumplines(lines)
630 }
631 }
632
633 func testMergeCombinePrograms(t *testing.T, s state) {
634
635
636
637 runout := [2]string{}
638 for k := 0; k < 2; k++ {
639 runout[k] = filepath.Join(s.dir, fmt.Sprintf("newcovdata%d", k))
640 if err := os.Mkdir(runout[k], 0777); err != nil {
641 t.Fatalf("can't create outdir %s: %v", runout[k], err)
642 }
643 args := []string{}
644 if k != 0 {
645 args = append(args, "foo", "bar")
646 }
647 cmd := testenv.Command(t, s.exepath2, args...)
648 cmd.Env = append(cmd.Env, "GOCOVERDIR="+runout[k])
649 b, err := cmd.CombinedOutput()
650 if len(b) != 0 {
651 t.Logf("## instrumented run output:\n%s", b)
652 }
653 if err != nil {
654 t.Fatalf("instrumented run error: %v", err)
655 }
656 }
657
658
659 moutdir := filepath.Join(s.dir, "mergeCombineOut")
660 if err := os.Mkdir(moutdir, 0777); err != nil {
661 t.Fatalf("can't create outdir %s: %v", moutdir, err)
662 }
663
664
665
666 ins := fmt.Sprintf("-i=%s,%s,%s,%s", s.outdirs[0], s.outdirs[1],
667 runout[0], runout[1])
668 out := fmt.Sprintf("-o=%s", moutdir)
669 margs := []string{"-pcombine", ins, out}
670 lines := runToolOp(t, s, "merge", margs)
671 if len(lines) != 0 {
672 t.Errorf("merge run produced unexpected output: %v", lines)
673 }
674
675
676
677
678 podlist, err := pods.CollectPods([]string{moutdir}, true)
679 if err != nil {
680 t.Fatal(err)
681 }
682 if len(podlist) != 1 {
683 t.Fatalf("expected 1 pod, got %d pods", len(podlist))
684 }
685 ncdfs := len(podlist[0].CounterDataFiles)
686 if ncdfs != 1 {
687 t.Fatalf("expected 1 counter data file, got %d", ncdfs)
688 }
689
690
691 testpoints := []dumpCheck{
692 {
693 tag: "first function",
694 re: regexp.MustCompile(`^Func: first\s*$`),
695 },
696 {
697 tag: "sixth function",
698 re: regexp.MustCompile(`^Func: sixth\s*$`),
699 },
700 }
701
702 flags := []string{"-live", "-pkg=" + mainPkgPath}
703 runDumpChecks(t, s, moutdir, flags, testpoints)
704 }
705
706 func testSubtract(t *testing.T, s state) {
707
708 soutdir := filepath.Join(s.dir, "subtractOut")
709 if err := os.Mkdir(soutdir, 0777); err != nil {
710 t.Fatalf("can't create outdir %s: %v", soutdir, err)
711 }
712
713
714 ins := fmt.Sprintf("-i=%s,%s", s.outdirs[0], s.outdirs[1])
715 out := fmt.Sprintf("-o=%s", soutdir)
716 sargs := []string{ins, out}
717 lines := runToolOp(t, s, "subtract", sargs)
718 if len(lines) != 0 {
719 t.Errorf("subtract run produced unexpected output: %+v", lines)
720 }
721
722
723 dargs := []string{"-pkg=" + mainPkgPath, "-live", "-i=" + soutdir}
724 lines = runToolOp(t, s, "debugdump", dargs)
725 if len(lines) == 0 {
726 t.Errorf("dump run produced no output")
727 }
728
729
730 testpoints := []dumpCheck{
731 {
732 tag: "first function",
733 re: regexp.MustCompile(`^Func: first\s*$`),
734 },
735 {
736 tag: "dep function",
737 re: regexp.MustCompile(`^Func: Dep1\s*$`),
738 },
739 {
740 tag: "third function",
741 re: regexp.MustCompile(`^Func: third\s*$`),
742 },
743 {
744 tag: "third function unit 0",
745 re: regexp.MustCompile(`^0: L23:C23 -- L24:C12 NS=1 = (\d+)$`),
746 zero: true,
747 },
748 {
749 tag: "third function unit 1",
750 re: regexp.MustCompile(`^1: L27:C2 -- L28:C10 NS=2 = (\d+)$`),
751 nonzero: true,
752 },
753 {
754 tag: "third function unit 2",
755 re: regexp.MustCompile(`^2: L24:C12 -- L26:C3 NS=1 = (\d+)$`),
756 zero: true,
757 },
758 }
759 flags := []string{}
760 runDumpChecks(t, s, soutdir, flags, testpoints)
761 }
762
763 func testIntersect(t *testing.T, s state, indir1, indir2, tag string) {
764
765 ioutdir := filepath.Join(s.dir, "intersectOut"+tag)
766 if err := os.Mkdir(ioutdir, 0777); err != nil {
767 t.Fatalf("can't create outdir %s: %v", ioutdir, err)
768 }
769
770
771 ins := fmt.Sprintf("-i=%s,%s", indir1, indir2)
772 out := fmt.Sprintf("-o=%s", ioutdir)
773 sargs := []string{ins, out}
774 lines := runToolOp(t, s, "intersect", sargs)
775 if len(lines) != 0 {
776 t.Errorf("intersect run produced unexpected output: %+v", lines)
777 }
778
779
780 dargs := []string{"-pkg=" + mainPkgPath, "-live", "-i=" + ioutdir}
781 lines = runToolOp(t, s, "debugdump", dargs)
782 if len(lines) == 0 {
783 t.Errorf("dump run produced no output")
784 }
785
786
787 testpoints := []dumpCheck{
788 {
789 tag: "first function",
790 re: regexp.MustCompile(`^Func: first\s*$`),
791 negate: true,
792 },
793 {
794 tag: "third function",
795 re: regexp.MustCompile(`^Func: third\s*$`),
796 },
797 }
798 flags := []string{"-live"}
799 runDumpChecks(t, s, ioutdir, flags, testpoints)
800 }
801
802 func testCounterClash(t *testing.T, s state) {
803
804 ccoutdir := filepath.Join(s.dir, "ccOut")
805 if err := os.Mkdir(ccoutdir, 0777); err != nil {
806 t.Fatalf("can't create outdir %s: %v", ccoutdir, err)
807 }
808
809
810
811
812 ins := fmt.Sprintf("-i=%s,%s", s.outdirs[0], s.outdirs[3])
813 out := fmt.Sprintf("-o=%s", ccoutdir)
814 args := append([]string{}, "merge", ins, out, "-pcombine")
815 if debugtrace {
816 t.Logf("cc merge command is %s %v\n", s.tool, args)
817 }
818 cmd := testenv.Command(t, s.tool, args...)
819 b, err := cmd.CombinedOutput()
820 t.Logf("%% output: %s\n", string(b))
821 if err != nil {
822 t.Fatalf("clash merge failed: %v", err)
823 }
824
825
826
827 out = "-o=" + filepath.Join(ccoutdir, "file.txt")
828 args = append([]string{}, "textfmt", ins, out)
829 if debugtrace {
830 t.Logf("clash textfmt command is %s %v\n", s.tool, args)
831 }
832 cmd = testenv.Command(t, s.tool, args...)
833 b, err = cmd.CombinedOutput()
834 t.Logf("%% output: %s\n", string(b))
835 if err == nil {
836 t.Fatalf("expected mode clash")
837 }
838 got := string(b)
839 want := "counter mode clash while reading meta-data"
840 if !strings.Contains(got, want) {
841 t.Errorf("counter clash textfmt: wanted %s got %s", want, got)
842 }
843 }
844
845 func testEmpty(t *testing.T, s state) {
846
847
848 empty := filepath.Join(s.dir, "empty")
849 if err := os.Mkdir(empty, 0777); err != nil {
850 t.Fatalf("can't create dir %s: %v", empty, err)
851 }
852
853
854 eoutdir := filepath.Join(s.dir, "emptyOut")
855 if err := os.Mkdir(eoutdir, 0777); err != nil {
856 t.Fatalf("can't create outdir %s: %v", eoutdir, err)
857 }
858
859
860
861
862
863
864 scenarios := []struct {
865 tag string
866 args []string
867 }{
868 {
869 tag: "merge",
870 args: []string{"merge", "-o", eoutdir},
871 },
872 {
873 tag: "textfmt",
874 args: []string{"textfmt", "-o", filepath.Join(eoutdir, "foo.txt")},
875 },
876 {
877 tag: "func",
878 args: []string{"func"},
879 },
880 {
881 tag: "pkglist",
882 args: []string{"pkglist"},
883 },
884 {
885 tag: "debugdump",
886 args: []string{"debugdump"},
887 },
888 {
889 tag: "percent",
890 args: []string{"percent"},
891 },
892 }
893
894 for _, x := range scenarios {
895 ins := fmt.Sprintf("-i=%s", empty)
896 args := append([]string{}, x.args...)
897 args = append(args, ins)
898 if false {
899 t.Logf("cmd is %s %v\n", s.tool, args)
900 }
901 cmd := testenv.Command(t, s.tool, args...)
902 b, err := cmd.CombinedOutput()
903 t.Logf("%% output: %s\n", string(b))
904 if err != nil {
905 t.Fatalf("command %s %+v failed with %v",
906 s.tool, x.args, err)
907 }
908 }
909 }
910
911 func testCommandLineErrors(t *testing.T, s state, outdir string) {
912
913
914 eoutdir := filepath.Join(s.dir, "errorsOut")
915 if err := os.Mkdir(eoutdir, 0777); err != nil {
916 t.Fatalf("can't create outdir %s: %v", eoutdir, err)
917 }
918
919
920
921
922
923
924 scenarios := []struct {
925 tag string
926 args []string
927 exp string
928 }{
929 {
930 tag: "input missing",
931 args: []string{"merge", "-o", eoutdir, "-i", "not there"},
932 exp: "error: reading inputs: ",
933 },
934 {
935 tag: "badv",
936 args: []string{"textfmt", "-i", outdir, "-v=abc"},
937 },
938 }
939
940 for _, x := range scenarios {
941 args := append([]string{}, x.args...)
942 if false {
943 t.Logf("cmd is %s %v\n", s.tool, args)
944 }
945 cmd := testenv.Command(t, s.tool, args...)
946 b, err := cmd.CombinedOutput()
947 if err == nil {
948 t.Logf("%% output: %s\n", string(b))
949 t.Fatalf("command %s %+v unexpectedly succeeded",
950 s.tool, x.args)
951 } else {
952 if !strings.Contains(string(b), x.exp) {
953 t.Fatalf("command %s %+v:\ngot:\n%s\nwanted to see: %v\n",
954 s.tool, x.args, string(b), x.exp)
955 }
956 }
957 }
958 }
959
View as plain text