mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-07-26 06:38:42 +00:00
df09dbdf0f
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.
88 lines
2.4 KiB
Go
88 lines
2.4 KiB
Go
package transform_test
|
|
|
|
import (
|
|
"fmt"
|
|
"go/token"
|
|
"os"
|
|
"regexp"
|
|
"sort"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/tinygo-org/tinygo/transform"
|
|
"tinygo.org/x/go-llvm"
|
|
)
|
|
|
|
func TestAllocs(t *testing.T) {
|
|
t.Parallel()
|
|
testTransform(t, "testdata/allocs", func(mod llvm.Module) {
|
|
transform.OptimizeAllocs(mod, nil, 256, nil)
|
|
})
|
|
}
|
|
|
|
// Test with a Go file as input (for more accurate tests).
|
|
func TestAllocs2(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
const (
|
|
basePath = "testdata/allocs2"
|
|
goFile = basePath + ".go"
|
|
goldenFile = basePath + ".out"
|
|
)
|
|
mod := compileGoFileForTesting(t, goFile)
|
|
|
|
// Run functionattrs pass, which is necessary for escape analysis.
|
|
po := llvm.NewPassBuilderOptions()
|
|
defer po.Dispose()
|
|
err := mod.RunPasses("function(instcombine),function-attrs", llvm.TargetMachine{}, po)
|
|
if err != nil {
|
|
t.Error("failed to run passes:", err)
|
|
}
|
|
|
|
// Run heap to stack transform.
|
|
type report struct {
|
|
pos token.Position
|
|
reason string
|
|
}
|
|
var reports []report
|
|
transform.OptimizeAllocs(mod, regexp.MustCompile("."), 256, func(pos token.Position, reason string) {
|
|
pos.Filename = goFile
|
|
reports = append(reports, report{pos, reason})
|
|
})
|
|
sort.Slice(reports, func(i, j int) bool { return reports[i].pos.Line < reports[j].pos.Line })
|
|
|
|
// 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())
|
|
}
|