File: rnr_test.go

package info (click to toggle)
golang-golang-x-tools 1%3A0.25.0%2Bds-1
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 22,724 kB
  • sloc: javascript: 2,027; asm: 1,645; sh: 166; yacc: 155; makefile: 49; ansic: 8
file content (145 lines) | stat: -rw-r--r-- 5,060 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"testing"

	"golang.org/x/tools/internal/testenv"
)

func canRace(t *testing.T) bool {
	_, err := exec.Command("go", "run", "-race", "./testdata/himom.go").CombinedOutput()
	return err == nil
}

// buildRunner builds the fuzz-runner executable, returning its path.
func buildRunner(t *testing.T) string {
	bindir := filepath.Join(t.TempDir(), "bin")
	err := os.Mkdir(bindir, os.ModePerm)
	if err != nil {
		t.Fatal(err)
	}
	binary := filepath.Join(bindir, "runner")
	if runtime.GOOS == "windows" {
		binary += ".exe"
	}
	cmd := exec.Command("go", "build", "-o", binary)
	if err := cmd.Run(); err != nil {
		t.Fatalf("Building fuzz-runner: %v", err)
	}
	return binary
}

// TestRunner builds the binary, then kicks off a collection of sub-tests that invoke it.
func TestRunner(t *testing.T) {
	testenv.NeedsTool(t, "go")
	if runtime.GOOS == "android" {
		t.Skipf("the dependencies are not available on android")
	}
	binaryPath := buildRunner(t)

	// Sub-tests using the binary built above.
	t.Run("Basic", func(t *testing.T) { testBasic(t, binaryPath) })
	t.Run("Race", func(t *testing.T) { testRace(t, binaryPath) })
	t.Run("Minimization1", func(t *testing.T) { testMinimization1(t, binaryPath) })
	t.Run("Minimization2", func(t *testing.T) { testMinimization2(t, binaryPath) })
}

func testBasic(t *testing.T, binaryPath string) {
	t.Parallel()
	args := []string{"-numit=1", "-numfcns=1", "-numpkgs=1", "-seed=103", "-cleancache=0"}
	c := exec.Command(binaryPath, args...)
	b, err := c.CombinedOutput()
	t.Logf("%s\n", b)
	if err != nil {
		t.Fatalf("error invoking fuzz-runner: %v", err)
	}
}

func testRace(t *testing.T, binaryPath string) {
	t.Parallel()
	// For this test to work, the current test platform has to support the
	// race detector. Check to see if that is the case by running a very
	// simple Go program through it.
	if !canRace(t) {
		t.Skip("current platform does not appear to support the race detector")
	}

	args := []string{"-v=1", "-numit=1", "-race", "-numfcns=3", "-numpkgs=3", "-seed=987", "-cleancache=0"}
	c := exec.Command(binaryPath, args...)
	b, err := c.CombinedOutput()
	t.Logf("%s\n", b)
	if err != nil {
		t.Fatalf("error invoking fuzz-runner: %v", err)
	}
}

func testMinimization1(t *testing.T, binaryPath string) {
	if binaryPath == "" {
		t.Skipf("No runner binary")
	}
	t.Parallel()
	// Fire off the runner passing it -emitbad=1, so that the generated code
	// contains illegal Go code (which will force the build to fail). Verify that
	// it does fail, that the error reflects the nature of the failure, and that
	// we can minimize the error down to a single package.
	args := []string{"-emitbad=1", "-badfcnidx=2", "-badpkgidx=2",
		"-forcetmpclean", "-cleancache=0",
		"-numit=1", "-numfcns=3", "-numpkgs=3", "-seed=909"}
	invocation := fmt.Sprintf("%s %v", binaryPath, args)
	c := exec.Command(binaryPath, args...)
	b, err := c.CombinedOutput()
	t.Logf("%s\n", b)
	if err == nil {
		t.Fatalf("unexpected pass of fuzz-runner (invocation %q): %v", invocation, err)
	}
	result := string(b)
	if !strings.Contains(result, "syntax error") {
		t.Fatalf("-emitbad=1 did not trigger syntax error (invocation %q): output: %s", invocation, result)
	}
	if !strings.Contains(result, "package minimization succeeded: found bad pkg 2") {
		t.Fatalf("failed to minimize package (invocation %q): output: %s", invocation, result)
	}
	if !strings.Contains(result, "function minimization succeeded: found bad fcn 2") {
		t.Fatalf("failed to minimize package (invocation %q): output: %s", invocation, result)
	}
}

func testMinimization2(t *testing.T, binaryPath string) {
	if binaryPath == "" {
		t.Skipf("No runner binary")
	}
	t.Parallel()
	// Fire off the runner passing it -emitbad=2, so that the
	// generated code forces a runtime error. Verify that it does
	// fail, and that the error is reflective.
	args := []string{"-emitbad=2", "-badfcnidx=1", "-badpkgidx=1",
		"-forcetmpclean", "-cleancache=0",
		"-numit=1", "-numfcns=3", "-numpkgs=3", "-seed=55909"}
	invocation := fmt.Sprintf("%s %v", binaryPath, args)
	c := exec.Command(binaryPath, args...)
	b, err := c.CombinedOutput()
	t.Logf("%s\n", b)
	if err == nil {
		t.Fatalf("unexpected pass of fuzz-runner (invocation %q): %v", invocation, err)
	}
	result := string(b)
	if !strings.Contains(result, "Error: fail") || !strings.Contains(result, "Checker1.Test1") {
		t.Fatalf("-emitbad=2 did not trigger runtime error (invocation %q): output: %s", invocation, result)
	}
	if !strings.Contains(result, "package minimization succeeded: found bad pkg 1") {
		t.Fatalf("failed to minimize package (invocation %q): output: %s", invocation, result)
	}
	if !strings.Contains(result, "function minimization succeeded: found bad fcn 1") {
		t.Fatalf("failed to minimize package (invocation %q): output: %s", invocation, result)
	}
}