1// run
2//go:build !nacl && !js && !wasip1 && !gccgo
3
4// Copyright 2017 The Go Authors. All rights reserved.
5// Use of this source code is governed by a BSD-style
6// license that can be found in the LICENSE file.
7
8// ensure that panic(x) where x is a numeric type displays a readable number
9package main
10
11import (
12	"bytes"
13	"fmt"
14	"io/ioutil"
15	"log"
16	"os"
17	"os/exec"
18	"path/filepath"
19)
20
21const fn = `
22package main
23
24import  "errors"
25type S struct {
26
27}
28func (s S) String() string {
29	return "s-stringer"
30}
31func main() {
32 	_ = errors.New
33  panic(%s(%s))
34}
35`
36
37func main() {
38	tempDir, err := ioutil.TempDir("", "")
39	if err != nil {
40		log.Fatal(err)
41	}
42	defer os.RemoveAll(tempDir)
43	tmpFile := filepath.Join(tempDir, "tmp.go")
44
45	for _, tc := range []struct {
46		Type   string
47		Input  string
48		Expect string
49	}{
50		{"", "nil", "panic: panic called with nil argument"},
51		{"errors.New", `"test"`, "panic: test"},
52		{"S", "S{}", "panic: s-stringer"},
53		{"byte", "8", "panic: 8"},
54		{"rune", "8", "panic: 8"},
55		{"int", "8", "panic: 8"},
56		{"int8", "8", "panic: 8"},
57		{"int16", "8", "panic: 8"},
58		{"int32", "8", "panic: 8"},
59		{"int64", "8", "panic: 8"},
60		{"uint", "8", "panic: 8"},
61		{"uint8", "8", "panic: 8"},
62		{"uint16", "8", "panic: 8"},
63		{"uint32", "8", "panic: 8"},
64		{"uint64", "8", "panic: 8"},
65		{"uintptr", "8", "panic: 8"},
66		{"bool", "true", "panic: true"},
67		{"complex64", "8 + 16i", "panic: (+8.000000e+000+1.600000e+001i)"},
68		{"complex128", "8+16i", "panic: (+8.000000e+000+1.600000e+001i)"},
69		{"string", `"test"`, "panic: test"}} {
70
71		b := bytes.Buffer{}
72		fmt.Fprintf(&b, fn, tc.Type, tc.Input)
73
74		err = ioutil.WriteFile(tmpFile, b.Bytes(), 0644)
75		if err != nil {
76			log.Fatal(err)
77		}
78
79		cmd := exec.Command("go", "run", tmpFile)
80		var buf bytes.Buffer
81		cmd.Stdout = &buf
82		cmd.Stderr = &buf
83		cmd.Env = os.Environ()
84		cmd.Run() // ignore err as we expect a panic
85
86		out := buf.Bytes()
87		panicIdx := bytes.Index(out, []byte("panic: "))
88		if panicIdx == -1 {
89			log.Fatalf("expected a panic in output for %s, got: %s", tc.Type, out)
90		}
91		eolIdx := bytes.IndexByte(out[panicIdx:], '\n') + panicIdx
92		if panicIdx == -1 {
93			log.Fatalf("expected a newline in output for %s after the panic, got: %s", tc.Type, out)
94		}
95		out = out[0:eolIdx]
96		if string(out) != tc.Expect {
97			log.Fatalf("expected '%s' for panic(%s(%s)), got %s", tc.Expect, tc.Type, tc.Input, out)
98		}
99	}
100}
101