From df09dbdf0f814aa87e53673258bb46f2f72e81ee Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Wed, 24 Jun 2026 18:54:44 +0200 Subject: [PATCH] transform: restore previous test behavior I think it's much nicer to have the test output inline in the source file, that way it's much easier to review any changes. For example, when escape analysis is improved this is visible with removed `// OUT` lines. This is similar to how LLVM writes its tests, and I like that style. --- transform/allocs_test.go | 52 +++++++++++++++++---------- transform/testdata/allocs2.go | 22 ++++++------ transform/testdata/allocs2.out.cover | 22 ++++++------ transform/testdata/allocs2.out.reason | 11 ------ 4 files changed, 56 insertions(+), 51 deletions(-) delete mode 100644 transform/testdata/allocs2.out.reason diff --git a/transform/allocs_test.go b/transform/allocs_test.go index 2b524392f..83ba90ffe 100644 --- a/transform/allocs_test.go +++ b/transform/allocs_test.go @@ -1,7 +1,9 @@ package transform_test import ( + "fmt" "go/token" + "os" "regexp" "sort" "strings" @@ -49,23 +51,37 @@ func TestAllocs2(t *testing.T) { }) sort.Slice(reports, func(i, j int) bool { return reports[i].pos.Line < reports[j].pos.Line }) - // Render every report in each format and diff against its golden file. - for _, format := range []struct { - name string - render func(report) string - }{ - {"reason", func(r report) string { return transform.FormatAllocReason(r.pos, r.reason) }}, - {"cover", func(r report) string { return transform.FormatAllocCover(r.pos) }}, - } { - t.Run(format.name, func(t *testing.T) { - var got strings.Builder - for _, r := range reports { - if line := format.render(r); line != "" { - got.WriteString(line) - got.WriteByte('\n') - } - } - checkGolden(t, goldenFile+"."+format.name, got.String()) - }) + // Load expected test output (the OUT: lines). + testInput, err := os.ReadFile("./testdata/allocs2.go") + if err != nil { + t.Fatal("could not read test input:", err) } + var expectedTestOutput strings.Builder + for i, line := range strings.Split(strings.ReplaceAll(string(testInput), "\r\n", "\n"), "\n") { + const prefix = " // OUT: " + if idx := strings.Index(line, prefix); idx > 0 { + msg := line[idx+len(prefix):] + fmt.Fprintf(&expectedTestOutput, "allocs2.go:%d: %s\n", i+1, msg) + } + } + + // Check whether the '// OUT' lines in allocs2.go match with the output we + // got from the test. + var actualTestOutput strings.Builder + for _, r := range reports { + fmt.Fprintf(&actualTestOutput, "allocs2.go:%d: %s\n", r.pos.Line, r.reason) + } + if actualTestOutput.String() != expectedTestOutput.String() { + t.Errorf("expected:\n%s\nactual:\n%s", expectedTestOutput.String(), actualTestOutput.String()) + } + + // Render the cover report and diff it against its golden file. + var got strings.Builder + for _, r := range reports { + if line := transform.FormatAllocCover(r.pos); line != "" { + got.WriteString(line) + got.WriteByte('\n') + } + } + checkGolden(t, goldenFile+".cover", got.String()) } diff --git a/transform/testdata/allocs2.go b/transform/testdata/allocs2.go index 88c411493..b8131d821 100644 --- a/transform/testdata/allocs2.go +++ b/transform/testdata/allocs2.go @@ -21,19 +21,19 @@ func main() { s3 := make([]int, 3) returnIntSlice(s3) - useSlice(make([]int, getUnknownNumber())) + useSlice(make([]int, getUnknownNumber())) // OUT: size is not constant - s4 := make([]byte, 300) + s4 := make([]byte, 300) // OUT: object size 300 exceeds maximum stack allocation size 256 readByteSlice(s4) - s5 := make([]int, 4) + s5 := make([]int, 4) // OUT: escapes at line 30 _ = append(s5, 5) s6 := make([]int, 3) s7 := []int{1, 2, 3} copySlice(s6, s7) - c1 := getComplex128() + c1 := getComplex128() // OUT: escapes at line 37 useInterface(c1) n3 := 5 @@ -41,13 +41,13 @@ func main() { return n3 }() - callVariadic(3, 5, 8) + callVariadic(3, 5, 8) // OUT: escapes at line 44 - s8 := []int{3, 5, 8} + s8 := []int{3, 5, 8} // OUT: escapes at line 47 callVariadic(s8...) - n4 := 3 - n5 := 7 + n4 := 3 // OUT: escapes at line 51 + n5 := 7 // OUT: escapes at line 51 func() { n4 = n5 }() @@ -104,14 +104,14 @@ func nonEscapingReturnedPointer() vector3 { var escapedSlice []int func escapingReturnedSlice() { - s := make([]int, 3) + s := make([]int, 3) // OUT: escapes at line 108 escapedSlice = returnIntSlice(s) } var escapedVector3 *vector3 func escapingReturnedPointer() { - b := vector3{4, 5, 6} + b := vector3{4, 5, 6} // OUT: escapes at line 117 c := scaleVector3(&b, 0.5) escapedVector3 = c @@ -125,7 +125,7 @@ func recursiveScaleVector3(vec *vector3, n int) *vector3 { } func recursiveReturnedPointer() vector3 { - b := vector3{4, 5, 6} + b := vector3{4, 5, 6} // OUT: escapes at unknown line c := recursiveScaleVector3(&b, 1) return *c diff --git a/transform/testdata/allocs2.out.cover b/transform/testdata/allocs2.out.cover index afd5ed7bb..e17f3d421 100644 --- a/transform/testdata/allocs2.out.cover +++ b/transform/testdata/allocs2.out.cover @@ -1,11 +1,11 @@ -testdata/allocs2.go:24.1,24.43 1 0 -testdata/allocs2.go:26.1,26.25 1 0 -testdata/allocs2.go:29.1,29.22 1 0 -testdata/allocs2.go:36.1,36.23 1 0 -testdata/allocs2.go:44.1,44.23 1 0 -testdata/allocs2.go:46.1,46.22 1 0 -testdata/allocs2.go:49.1,49.9 1 0 -testdata/allocs2.go:50.1,50.9 1 0 -testdata/allocs2.go:107.1,107.21 1 0 -testdata/allocs2.go:114.1,114.23 1 0 -testdata/allocs2.go:128.1,128.23 1 0 +testdata/allocs2.go:24.1,24.72 1 0 +testdata/allocs2.go:26.1,26.91 1 0 +testdata/allocs2.go:29.1,29.49 1 0 +testdata/allocs2.go:36.1,36.50 1 0 +testdata/allocs2.go:44.1,44.50 1 0 +testdata/allocs2.go:46.1,46.49 1 0 +testdata/allocs2.go:49.1,49.36 1 0 +testdata/allocs2.go:50.1,50.36 1 0 +testdata/allocs2.go:107.1,107.49 1 0 +testdata/allocs2.go:114.1,114.51 1 0 +testdata/allocs2.go:128.1,128.55 1 0 diff --git a/transform/testdata/allocs2.out.reason b/transform/testdata/allocs2.out.reason deleted file mode 100644 index adc83392d..000000000 --- a/transform/testdata/allocs2.out.reason +++ /dev/null @@ -1,11 +0,0 @@ -testdata/allocs2.go:24:15: object allocated on the heap: size is not constant -testdata/allocs2.go:26:12: object allocated on the heap: object size 300 exceeds maximum stack allocation size 256 -testdata/allocs2.go:29:12: object allocated on the heap: escapes at line 30 -testdata/allocs2.go:36:21: object allocated on the heap: escapes at line 37 -testdata/allocs2.go:44:22: object allocated on the heap: escapes at line 44 -testdata/allocs2.go:46:13: object allocated on the heap: escapes at line 47 -testdata/allocs2.go:49:2: object allocated on the heap: escapes at line 51 -testdata/allocs2.go:50:2: object allocated on the heap: escapes at line 51 -testdata/allocs2.go:107:11: object allocated on the heap: escapes at line 108 -testdata/allocs2.go:114:2: object allocated on the heap: escapes at line 117 -testdata/allocs2.go:128:2: object allocated on the heap: escapes at unknown line