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
5package runtime_test
6
7import (
8	"internal/platform"
9	"internal/testenv"
10	"os/exec"
11	"runtime"
12	"strings"
13	"testing"
14)
15
16func TestExitHooks(t *testing.T) {
17	bmodes := []string{""}
18	if testing.Short() {
19		t.Skip("skipping due to -short")
20	}
21	// Note the HasCGO() test below; this is to prevent the test
22	// running if CGO_ENABLED=0 is in effect.
23	haverace := platform.RaceDetectorSupported(runtime.GOOS, runtime.GOARCH)
24	if haverace && testenv.HasCGO() {
25		bmodes = append(bmodes, "-race")
26	}
27	for _, bmode := range bmodes {
28		scenarios := []struct {
29			mode     string
30			expected string
31			musthave []string
32		}{
33			{
34				mode:     "simple",
35				expected: "bar foo",
36			},
37			{
38				mode:     "goodexit",
39				expected: "orange apple",
40			},
41			{
42				mode:     "badexit",
43				expected: "blub blix",
44			},
45			{
46				mode: "panics",
47				musthave: []string{
48					"fatal error: exit hook invoked panic",
49					"main.testPanics",
50				},
51			},
52			{
53				mode: "callsexit",
54				musthave: []string{
55					"fatal error: exit hook invoked exit",
56				},
57			},
58			{
59				mode:     "exit2",
60				expected: "",
61			},
62		}
63
64		exe, err := buildTestProg(t, "testexithooks", bmode)
65		if err != nil {
66			t.Fatal(err)
67		}
68
69		bt := ""
70		if bmode != "" {
71			bt = " bmode: " + bmode
72		}
73		for _, s := range scenarios {
74			cmd := exec.Command(exe, []string{"-mode", s.mode}...)
75			out, _ := cmd.CombinedOutput()
76			outs := strings.ReplaceAll(string(out), "\n", " ")
77			outs = strings.TrimSpace(outs)
78			if s.expected != "" && s.expected != outs {
79				t.Fatalf("failed%s mode %s: wanted %q\noutput:\n%s", bt,
80					s.mode, s.expected, outs)
81			}
82			for _, need := range s.musthave {
83				if !strings.Contains(outs, need) {
84					t.Fatalf("failed mode %s: output does not contain %q\noutput:\n%s",
85						s.mode, need, outs)
86				}
87			}
88			if s.expected == "" && s.musthave == nil && outs != "" {
89				t.Errorf("failed mode %s: wanted no output\noutput:\n%s", s.mode, outs)
90			}
91		}
92	}
93}
94