xref: /aosp_15_r20/build/blueprint/gotestmain/gotestmain.go (revision 1fa6dee971e1612fa5cc0aa5ca2d35a22e2c34a3)
1*1fa6dee9SAndroid Build Coastguard Worker// Copyright 2015 Google Inc. All rights reserved.
2*1fa6dee9SAndroid Build Coastguard Worker//
3*1fa6dee9SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*1fa6dee9SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*1fa6dee9SAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*1fa6dee9SAndroid Build Coastguard Worker//
7*1fa6dee9SAndroid Build Coastguard Worker//     http://www.apache.org/licenses/LICENSE-2.0
8*1fa6dee9SAndroid Build Coastguard Worker//
9*1fa6dee9SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*1fa6dee9SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*1fa6dee9SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*1fa6dee9SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*1fa6dee9SAndroid Build Coastguard Worker// limitations under the License.
14*1fa6dee9SAndroid Build Coastguard Worker
15*1fa6dee9SAndroid Build Coastguard Workerpackage main
16*1fa6dee9SAndroid Build Coastguard Worker
17*1fa6dee9SAndroid Build Coastguard Workerimport (
18*1fa6dee9SAndroid Build Coastguard Worker	"bytes"
19*1fa6dee9SAndroid Build Coastguard Worker	"flag"
20*1fa6dee9SAndroid Build Coastguard Worker	"fmt"
21*1fa6dee9SAndroid Build Coastguard Worker	"go/ast"
22*1fa6dee9SAndroid Build Coastguard Worker	"go/doc"
23*1fa6dee9SAndroid Build Coastguard Worker	"go/parser"
24*1fa6dee9SAndroid Build Coastguard Worker	"go/token"
25*1fa6dee9SAndroid Build Coastguard Worker	"io/ioutil"
26*1fa6dee9SAndroid Build Coastguard Worker	"os"
27*1fa6dee9SAndroid Build Coastguard Worker	"reflect"
28*1fa6dee9SAndroid Build Coastguard Worker	"sort"
29*1fa6dee9SAndroid Build Coastguard Worker	"strings"
30*1fa6dee9SAndroid Build Coastguard Worker	"testing"
31*1fa6dee9SAndroid Build Coastguard Worker	"text/template"
32*1fa6dee9SAndroid Build Coastguard Worker)
33*1fa6dee9SAndroid Build Coastguard Worker
34*1fa6dee9SAndroid Build Coastguard Workervar (
35*1fa6dee9SAndroid Build Coastguard Worker	output   = flag.String("o", "", "output filename")
36*1fa6dee9SAndroid Build Coastguard Worker	pkg      = flag.String("pkg", "", "test package")
37*1fa6dee9SAndroid Build Coastguard Worker	exitCode = 0
38*1fa6dee9SAndroid Build Coastguard Worker)
39*1fa6dee9SAndroid Build Coastguard Worker
40*1fa6dee9SAndroid Build Coastguard Workertype data struct {
41*1fa6dee9SAndroid Build Coastguard Worker	Package               string
42*1fa6dee9SAndroid Build Coastguard Worker	Tests                 []string
43*1fa6dee9SAndroid Build Coastguard Worker	Examples              []*doc.Example
44*1fa6dee9SAndroid Build Coastguard Worker	HasMain               bool
45*1fa6dee9SAndroid Build Coastguard Worker	MainStartTakesFuzzers bool
46*1fa6dee9SAndroid Build Coastguard Worker}
47*1fa6dee9SAndroid Build Coastguard Worker
48*1fa6dee9SAndroid Build Coastguard Workerfunc findTests(srcs []string) (tests []string, examples []*doc.Example, hasMain bool) {
49*1fa6dee9SAndroid Build Coastguard Worker	for _, src := range srcs {
50*1fa6dee9SAndroid Build Coastguard Worker		f, err := parser.ParseFile(token.NewFileSet(), src, nil, parser.ParseComments)
51*1fa6dee9SAndroid Build Coastguard Worker		if err != nil {
52*1fa6dee9SAndroid Build Coastguard Worker			panic(err)
53*1fa6dee9SAndroid Build Coastguard Worker		}
54*1fa6dee9SAndroid Build Coastguard Worker		for _, obj := range f.Scope.Objects {
55*1fa6dee9SAndroid Build Coastguard Worker			if obj.Kind != ast.Fun || !strings.HasPrefix(obj.Name, "Test") {
56*1fa6dee9SAndroid Build Coastguard Worker				continue
57*1fa6dee9SAndroid Build Coastguard Worker			}
58*1fa6dee9SAndroid Build Coastguard Worker			if obj.Name == "TestMain" {
59*1fa6dee9SAndroid Build Coastguard Worker				hasMain = true
60*1fa6dee9SAndroid Build Coastguard Worker			} else {
61*1fa6dee9SAndroid Build Coastguard Worker				tests = append(tests, obj.Name)
62*1fa6dee9SAndroid Build Coastguard Worker			}
63*1fa6dee9SAndroid Build Coastguard Worker		}
64*1fa6dee9SAndroid Build Coastguard Worker
65*1fa6dee9SAndroid Build Coastguard Worker		examples = append(examples, doc.Examples(f)...)
66*1fa6dee9SAndroid Build Coastguard Worker	}
67*1fa6dee9SAndroid Build Coastguard Worker	sort.Strings(tests)
68*1fa6dee9SAndroid Build Coastguard Worker	return
69*1fa6dee9SAndroid Build Coastguard Worker}
70*1fa6dee9SAndroid Build Coastguard Worker
71*1fa6dee9SAndroid Build Coastguard Worker// Returns true for go1.18+, where testing.MainStart takes an extra slice of fuzzers.
72*1fa6dee9SAndroid Build Coastguard Workerfunc mainStartTakesFuzzers() bool {
73*1fa6dee9SAndroid Build Coastguard Worker	return reflect.TypeOf(testing.MainStart).NumIn() > 4
74*1fa6dee9SAndroid Build Coastguard Worker}
75*1fa6dee9SAndroid Build Coastguard Worker
76*1fa6dee9SAndroid Build Coastguard Workerfunc main() {
77*1fa6dee9SAndroid Build Coastguard Worker	flag.Parse()
78*1fa6dee9SAndroid Build Coastguard Worker
79*1fa6dee9SAndroid Build Coastguard Worker	if flag.NArg() == 0 {
80*1fa6dee9SAndroid Build Coastguard Worker		fmt.Fprintln(os.Stderr, "error: must pass at least one input")
81*1fa6dee9SAndroid Build Coastguard Worker		exitCode = 1
82*1fa6dee9SAndroid Build Coastguard Worker		return
83*1fa6dee9SAndroid Build Coastguard Worker	}
84*1fa6dee9SAndroid Build Coastguard Worker
85*1fa6dee9SAndroid Build Coastguard Worker	buf := &bytes.Buffer{}
86*1fa6dee9SAndroid Build Coastguard Worker
87*1fa6dee9SAndroid Build Coastguard Worker	tests, examples, hasMain := findTests(flag.Args())
88*1fa6dee9SAndroid Build Coastguard Worker
89*1fa6dee9SAndroid Build Coastguard Worker	d := data{
90*1fa6dee9SAndroid Build Coastguard Worker		Package:               *pkg,
91*1fa6dee9SAndroid Build Coastguard Worker		Tests:                 tests,
92*1fa6dee9SAndroid Build Coastguard Worker		Examples:              examples,
93*1fa6dee9SAndroid Build Coastguard Worker		HasMain:               hasMain,
94*1fa6dee9SAndroid Build Coastguard Worker		MainStartTakesFuzzers: mainStartTakesFuzzers(),
95*1fa6dee9SAndroid Build Coastguard Worker	}
96*1fa6dee9SAndroid Build Coastguard Worker
97*1fa6dee9SAndroid Build Coastguard Worker	err := testMainTmpl.Execute(buf, d)
98*1fa6dee9SAndroid Build Coastguard Worker	if err != nil {
99*1fa6dee9SAndroid Build Coastguard Worker		panic(err)
100*1fa6dee9SAndroid Build Coastguard Worker	}
101*1fa6dee9SAndroid Build Coastguard Worker
102*1fa6dee9SAndroid Build Coastguard Worker	err = ioutil.WriteFile(*output, buf.Bytes(), 0666)
103*1fa6dee9SAndroid Build Coastguard Worker	if err != nil {
104*1fa6dee9SAndroid Build Coastguard Worker		panic(err)
105*1fa6dee9SAndroid Build Coastguard Worker	}
106*1fa6dee9SAndroid Build Coastguard Worker}
107*1fa6dee9SAndroid Build Coastguard Worker
108*1fa6dee9SAndroid Build Coastguard Workervar testMainTmpl = template.Must(template.New("testMain").Parse(`
109*1fa6dee9SAndroid Build Coastguard Workerpackage main
110*1fa6dee9SAndroid Build Coastguard Worker
111*1fa6dee9SAndroid Build Coastguard Workerimport (
112*1fa6dee9SAndroid Build Coastguard Worker	"io"
113*1fa6dee9SAndroid Build Coastguard Worker{{if not .HasMain}}
114*1fa6dee9SAndroid Build Coastguard Worker	"os"
115*1fa6dee9SAndroid Build Coastguard Worker{{end}}
116*1fa6dee9SAndroid Build Coastguard Worker	"reflect"
117*1fa6dee9SAndroid Build Coastguard Worker	"regexp"
118*1fa6dee9SAndroid Build Coastguard Worker	"testing"
119*1fa6dee9SAndroid Build Coastguard Worker	"time"
120*1fa6dee9SAndroid Build Coastguard Worker
121*1fa6dee9SAndroid Build Coastguard Worker	pkg "{{.Package}}"
122*1fa6dee9SAndroid Build Coastguard Worker)
123*1fa6dee9SAndroid Build Coastguard Worker
124*1fa6dee9SAndroid Build Coastguard Workervar t = []testing.InternalTest{
125*1fa6dee9SAndroid Build Coastguard Worker{{range .Tests}}
126*1fa6dee9SAndroid Build Coastguard Worker	{"{{.}}", pkg.{{.}}},
127*1fa6dee9SAndroid Build Coastguard Worker{{end}}
128*1fa6dee9SAndroid Build Coastguard Worker}
129*1fa6dee9SAndroid Build Coastguard Worker
130*1fa6dee9SAndroid Build Coastguard Workervar e = []testing.InternalExample{
131*1fa6dee9SAndroid Build Coastguard Worker{{range .Examples}}
132*1fa6dee9SAndroid Build Coastguard Worker	{{if or .Output .EmptyOutput}}
133*1fa6dee9SAndroid Build Coastguard Worker		{"{{.Name}}", pkg.Example{{.Name}}, {{.Output | printf "%q" }}, {{.Unordered}}},
134*1fa6dee9SAndroid Build Coastguard Worker	{{end}}
135*1fa6dee9SAndroid Build Coastguard Worker{{end}}
136*1fa6dee9SAndroid Build Coastguard Worker}
137*1fa6dee9SAndroid Build Coastguard Worker
138*1fa6dee9SAndroid Build Coastguard Workervar matchPat string
139*1fa6dee9SAndroid Build Coastguard Workervar matchRe *regexp.Regexp
140*1fa6dee9SAndroid Build Coastguard Worker
141*1fa6dee9SAndroid Build Coastguard Workertype matchString struct{}
142*1fa6dee9SAndroid Build Coastguard Worker
143*1fa6dee9SAndroid Build Coastguard Workerfunc MatchString(pat, str string) (result bool, err error) {
144*1fa6dee9SAndroid Build Coastguard Worker	if matchRe == nil || matchPat != pat {
145*1fa6dee9SAndroid Build Coastguard Worker		matchPat = pat
146*1fa6dee9SAndroid Build Coastguard Worker		matchRe, err = regexp.Compile(matchPat)
147*1fa6dee9SAndroid Build Coastguard Worker		if err != nil {
148*1fa6dee9SAndroid Build Coastguard Worker			return
149*1fa6dee9SAndroid Build Coastguard Worker		}
150*1fa6dee9SAndroid Build Coastguard Worker	}
151*1fa6dee9SAndroid Build Coastguard Worker	return matchRe.MatchString(str), nil
152*1fa6dee9SAndroid Build Coastguard Worker}
153*1fa6dee9SAndroid Build Coastguard Worker
154*1fa6dee9SAndroid Build Coastguard Workerfunc (matchString) MatchString(pat, str string) (bool, error) {
155*1fa6dee9SAndroid Build Coastguard Worker	return MatchString(pat, str)
156*1fa6dee9SAndroid Build Coastguard Worker}
157*1fa6dee9SAndroid Build Coastguard Worker
158*1fa6dee9SAndroid Build Coastguard Workerfunc (matchString) StartCPUProfile(w io.Writer) error {
159*1fa6dee9SAndroid Build Coastguard Worker	panic("shouldn't get here")
160*1fa6dee9SAndroid Build Coastguard Worker}
161*1fa6dee9SAndroid Build Coastguard Worker
162*1fa6dee9SAndroid Build Coastguard Workerfunc (matchString) StopCPUProfile() {
163*1fa6dee9SAndroid Build Coastguard Worker}
164*1fa6dee9SAndroid Build Coastguard Worker
165*1fa6dee9SAndroid Build Coastguard Workerfunc (matchString) WriteHeapProfile(w io.Writer) error {
166*1fa6dee9SAndroid Build Coastguard Worker    panic("shouldn't get here")
167*1fa6dee9SAndroid Build Coastguard Worker}
168*1fa6dee9SAndroid Build Coastguard Worker
169*1fa6dee9SAndroid Build Coastguard Workerfunc (matchString) WriteProfileTo(string, io.Writer, int) error {
170*1fa6dee9SAndroid Build Coastguard Worker    panic("shouldn't get here")
171*1fa6dee9SAndroid Build Coastguard Worker}
172*1fa6dee9SAndroid Build Coastguard Worker
173*1fa6dee9SAndroid Build Coastguard Workerfunc (matchString) ImportPath() string {
174*1fa6dee9SAndroid Build Coastguard Worker	return "{{.Package}}"
175*1fa6dee9SAndroid Build Coastguard Worker}
176*1fa6dee9SAndroid Build Coastguard Worker
177*1fa6dee9SAndroid Build Coastguard Workerfunc (matchString) StartTestLog(io.Writer) {
178*1fa6dee9SAndroid Build Coastguard Worker	panic("shouldn't get here")
179*1fa6dee9SAndroid Build Coastguard Worker}
180*1fa6dee9SAndroid Build Coastguard Worker
181*1fa6dee9SAndroid Build Coastguard Workerfunc (matchString) StopTestLog() error {
182*1fa6dee9SAndroid Build Coastguard Worker	panic("shouldn't get here")
183*1fa6dee9SAndroid Build Coastguard Worker}
184*1fa6dee9SAndroid Build Coastguard Worker
185*1fa6dee9SAndroid Build Coastguard Workerfunc (matchString) SetPanicOnExit0(bool) {
186*1fa6dee9SAndroid Build Coastguard Worker	panic("shouldn't get here")
187*1fa6dee9SAndroid Build Coastguard Worker}
188*1fa6dee9SAndroid Build Coastguard Worker
189*1fa6dee9SAndroid Build Coastguard Workerfunc (matchString) CoordinateFuzzing(time.Duration, int64, time.Duration, int64, int, []corpusEntry, []reflect.Type, string, string) error {
190*1fa6dee9SAndroid Build Coastguard Worker	panic("shouldn't get here")
191*1fa6dee9SAndroid Build Coastguard Worker}
192*1fa6dee9SAndroid Build Coastguard Worker
193*1fa6dee9SAndroid Build Coastguard Workerfunc (matchString) RunFuzzWorker(func(corpusEntry) error) error {
194*1fa6dee9SAndroid Build Coastguard Worker	panic("shouldn't get here")
195*1fa6dee9SAndroid Build Coastguard Worker}
196*1fa6dee9SAndroid Build Coastguard Worker
197*1fa6dee9SAndroid Build Coastguard Workerfunc (matchString) ReadCorpus(string, []reflect.Type) ([]corpusEntry, error) {
198*1fa6dee9SAndroid Build Coastguard Worker	panic("shouldn't get here")
199*1fa6dee9SAndroid Build Coastguard Worker}
200*1fa6dee9SAndroid Build Coastguard Worker
201*1fa6dee9SAndroid Build Coastguard Workerfunc (matchString) CheckCorpus([]interface{}, []reflect.Type) error {
202*1fa6dee9SAndroid Build Coastguard Worker	panic("shouldn't get here")
203*1fa6dee9SAndroid Build Coastguard Worker}
204*1fa6dee9SAndroid Build Coastguard Worker
205*1fa6dee9SAndroid Build Coastguard Workerfunc (matchString) ResetCoverage() {
206*1fa6dee9SAndroid Build Coastguard Worker	panic("shouldn't get here")
207*1fa6dee9SAndroid Build Coastguard Worker}
208*1fa6dee9SAndroid Build Coastguard Worker
209*1fa6dee9SAndroid Build Coastguard Workerfunc (matchString) SnapshotCoverage() {
210*1fa6dee9SAndroid Build Coastguard Worker	panic("shouldn't get here")
211*1fa6dee9SAndroid Build Coastguard Worker}
212*1fa6dee9SAndroid Build Coastguard Worker
213*1fa6dee9SAndroid Build Coastguard Workerfunc (f matchString) InitRuntimeCoverage() (mode string, tearDown func(string, string) (string, error), snapcov func() float64) {
214*1fa6dee9SAndroid Build Coastguard Worker	return
215*1fa6dee9SAndroid Build Coastguard Worker}
216*1fa6dee9SAndroid Build Coastguard Worker
217*1fa6dee9SAndroid Build Coastguard Workertype corpusEntry = struct {
218*1fa6dee9SAndroid Build Coastguard Worker	Parent     string
219*1fa6dee9SAndroid Build Coastguard Worker	Path       string
220*1fa6dee9SAndroid Build Coastguard Worker	Data       []byte
221*1fa6dee9SAndroid Build Coastguard Worker	Values     []interface{}
222*1fa6dee9SAndroid Build Coastguard Worker	Generation int
223*1fa6dee9SAndroid Build Coastguard Worker	IsSeed     bool
224*1fa6dee9SAndroid Build Coastguard Worker}
225*1fa6dee9SAndroid Build Coastguard Worker
226*1fa6dee9SAndroid Build Coastguard Workerfunc main() {
227*1fa6dee9SAndroid Build Coastguard Worker{{if .MainStartTakesFuzzers }}
228*1fa6dee9SAndroid Build Coastguard Worker	m := testing.MainStart(matchString{}, t, nil, nil, e)
229*1fa6dee9SAndroid Build Coastguard Worker{{else}}
230*1fa6dee9SAndroid Build Coastguard Worker	m := testing.MainStart(matchString{}, t, nil, e)
231*1fa6dee9SAndroid Build Coastguard Worker{{end}}
232*1fa6dee9SAndroid Build Coastguard Worker{{if .HasMain}}
233*1fa6dee9SAndroid Build Coastguard Worker	pkg.TestMain(m)
234*1fa6dee9SAndroid Build Coastguard Worker{{else}}
235*1fa6dee9SAndroid Build Coastguard Worker	os.Exit(m.Run())
236*1fa6dee9SAndroid Build Coastguard Worker{{end}}
237*1fa6dee9SAndroid Build Coastguard Worker}
238*1fa6dee9SAndroid Build Coastguard Worker`))
239