104 lines
2.7 KiB
Go
104 lines
2.7 KiB
Go
package baseline
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"hash/fnv"
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
"testing"
|
|
|
|
"github.com/microsoft/typescript-go/internal/collections"
|
|
)
|
|
|
|
var (
|
|
// recordedBaselines tracks all baseline file paths that were written during the test run.
|
|
recordedBaselines collections.SyncSet[string]
|
|
|
|
// trackingInitialized is set to true when Track() is called.
|
|
trackingInitialized bool
|
|
|
|
// trackingDir is the directory where tracking files should be written.
|
|
// If non-empty, baseline tracking is enabled.
|
|
// Set by Herebyfile.mjs when running full test suites with tracking enabled.
|
|
trackingDir = os.Getenv("TSGO_BASELINE_TRACKING_DIR")
|
|
)
|
|
|
|
// Track sets up baseline tracking and returns a cleanup function that writes the tracking file.
|
|
// It should be called from TestMain using defer:
|
|
//
|
|
// func TestMain(m *testing.M) {
|
|
// defer baseline.Track()()
|
|
// m.Run()
|
|
// }
|
|
func Track() func() {
|
|
trackingInitialized = true
|
|
|
|
if trackingDir == "" {
|
|
return func() {}
|
|
}
|
|
|
|
// Hash the entire call stack to create a unique filename per calling package.
|
|
// This must be done in Track(), not in the deferred cleanup, because
|
|
// the deferred function's call stack won't include the caller's info.
|
|
var pcs [32]uintptr
|
|
n := runtime.Callers(2, pcs[:]) // Skip Track and runtime.Callers
|
|
h := fnv.New64a()
|
|
frames := runtime.CallersFrames(pcs[:n])
|
|
for {
|
|
frame, more := frames.Next()
|
|
h.Write([]byte(frame.File))
|
|
if !more {
|
|
break
|
|
}
|
|
}
|
|
trackingPath := filepath.Join(trackingDir, fmt.Sprintf("%016x.txt", h.Sum64()))
|
|
|
|
return func() {
|
|
// After tests complete, write the recorded baselines
|
|
writeRecordedBaselines(trackingPath)
|
|
}
|
|
}
|
|
|
|
// recordBaseline adds a baseline file path to the recorded set.
|
|
// The path should be relative to the baselines/reference directory.
|
|
func recordBaseline(t testing.TB, relativePath string) {
|
|
if trackingDir != "" {
|
|
if !trackingInitialized {
|
|
t.Error("baseline: package uses baselines but TestMain did not call baseline.Track(). " +
|
|
"Please add a TestMain function with: defer baseline.Track()()")
|
|
return
|
|
}
|
|
recordedBaselines.Add(relativePath)
|
|
}
|
|
}
|
|
|
|
// writeRecordedBaselines writes the list of recorded baseline files to a tracking file.
|
|
func writeRecordedBaselines(trackingPath string) {
|
|
if recordedBaselines.Size() == 0 {
|
|
return
|
|
}
|
|
|
|
if err := doWriteRecordedBaselines(trackingPath); err != nil {
|
|
fmt.Fprintf(os.Stderr, "baseline: failed to write tracking file %s: %v\n", trackingPath, err)
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
func doWriteRecordedBaselines(trackingPath string) error {
|
|
f, err := os.Create(trackingPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
|
|
w := bufio.NewWriter(f)
|
|
for baseline := range recordedBaselines.Keys() {
|
|
if _, err := fmt.Fprintln(w, baseline); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return w.Flush()
|
|
}
|