package semantic_test
import (
"bytes"
"flag"
"path/filepath"
"testing"
"git.sr.ht/~mna/snow/pkg/internal/filetest"
"git.sr.ht/~mna/snow/pkg/scanner"
"git.sr.ht/~mna/snow/pkg/semantic"
)
var testUpdateScopesTests = flag.Bool("test.update-scopes-tests", false, "If set, replace expected semantic scopes test results with actual results.")
func TestScopes(t *testing.T) {
baseDir := "testdata"
expectDir := filepath.Join(baseDir, "scopes")
for _, fi := range filetest.SourceFiles(t, baseDir) {
t.Run(fi.Name(), func(t *testing.T) {
unit, err := semantic.Run(semantic.TranslatePass, filepath.Join(baseDir, fi.Name()))
var ebuf bytes.Buffer
scanner.PrintError(&ebuf, err)
if unit == nil && err != nil {
t.Fatal(ebuf.String())
}
var buf bytes.Buffer
unit.Scope().WriteTo(&buf, 0, true)
filetest.DiffOutput(t, fi, buf.String(), expectDir, testUpdateScopesTests)
filetest.DiffErrors(t, fi, ebuf.String(), expectDir, testUpdateScopesTests)
// sanity check: input files are all present in the unit, in the same order
// (well, currently all tests are only single files, but...)
if len(unit.Files) != 1 {
t.Fatalf("want unit to have 1 file, got %d", len(unit.Files))
}
file := unit.FileSet.File(unit.Files[0].Pos())
if file == nil {
t.Fatalf("unit.FileSet.File returned nil")
}
wantNm := filepath.Join(baseDir, fi.Name())
if got := file.Name(); got != wantNm {
t.Fatalf("want unit.FileSet.File to have return filename %s, got %s", wantNm, got)
}
// sanity check: all nodes have a scope
var hasScope visitorFunc
hasScope = func(n semantic.Node) semantic.Visitor {
if n == nil {
return nil
}
if n.Scope() == nil {
lpos := unit.FileSet.Position(n.Pos())
t.Fatalf("%s: no scope for %s", lpos, semantic.TypeIdentString(n))
}
return hasScope
}
semantic.Walk(hasScope, unit)
})
}
}
type visitorFunc func(semantic.Node) semantic.Visitor
func (v visitorFunc) Visit(n semantic.Node) semantic.Visitor {
return v(n)
}