vendor tsgo
This commit is contained in:
233
tools/tsgo/internal/parser/parser_test.go
Normal file
233
tools/tsgo/internal/parser/parser_test.go
Normal file
@@ -0,0 +1,233 @@
|
||||
package parser_test
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"iter"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/microsoft/typescript-go/internal/ast"
|
||||
"github.com/microsoft/typescript-go/internal/collections"
|
||||
"github.com/microsoft/typescript-go/internal/core"
|
||||
"github.com/microsoft/typescript-go/internal/parser"
|
||||
"github.com/microsoft/typescript-go/internal/repo"
|
||||
"github.com/microsoft/typescript-go/internal/testrunner"
|
||||
"github.com/microsoft/typescript-go/internal/testutil/fixtures"
|
||||
"github.com/microsoft/typescript-go/internal/tspath"
|
||||
"github.com/microsoft/typescript-go/internal/vfs/osvfs"
|
||||
"gotest.tools/v3/assert"
|
||||
)
|
||||
|
||||
func BenchmarkParse(b *testing.B) {
|
||||
for _, f := range fixtures.BenchFixtures {
|
||||
b.Run(f.Name(), func(b *testing.B) {
|
||||
f.SkipIfNotExist(b)
|
||||
|
||||
fileName := tspath.GetNormalizedAbsolutePath(f.Path(), "/")
|
||||
path := tspath.ToPath(fileName, "/", osvfs.FS().UseCaseSensitiveFileNames())
|
||||
sourceText := f.ReadFile(b)
|
||||
scriptKind := core.GetScriptKindFromFileName(fileName)
|
||||
|
||||
opts := ast.SourceFileParseOptions{
|
||||
FileName: fileName,
|
||||
Path: path,
|
||||
}
|
||||
|
||||
for b.Loop() {
|
||||
parser.ParseSourceFile(opts, sourceText, scriptKind)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type parsableFile struct {
|
||||
path string
|
||||
name string
|
||||
}
|
||||
|
||||
func allParsableFiles(tb testing.TB, root string) iter.Seq[parsableFile] {
|
||||
tb.Helper()
|
||||
return func(yield func(parsableFile) bool) {
|
||||
tb.Helper()
|
||||
err := filepath.WalkDir(root, func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if d.IsDir() || tspath.TryGetExtensionFromPath(path) == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
testName, err := filepath.Rel(root, path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
testName = filepath.ToSlash(testName)
|
||||
|
||||
if !yield(parsableFile{path, testName}) {
|
||||
return filepath.SkipAll
|
||||
}
|
||||
return nil
|
||||
})
|
||||
assert.NilError(tb, err)
|
||||
}
|
||||
}
|
||||
|
||||
func FuzzParser(f *testing.F) {
|
||||
repo.SkipIfNoTypeScriptSubmodule(f)
|
||||
|
||||
tests := []string{
|
||||
"src",
|
||||
"scripts",
|
||||
"Herebyfile.mjs",
|
||||
}
|
||||
|
||||
var extensions collections.Set[string]
|
||||
for _, es := range tspath.AllSupportedExtensionsWithJson {
|
||||
for _, e := range es {
|
||||
extensions.Add(e)
|
||||
}
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
root := filepath.Join(repo.TypeScriptSubmodulePath(), test)
|
||||
|
||||
for file := range allParsableFiles(f, root) {
|
||||
sourceText, err := os.ReadFile(file.path)
|
||||
assert.NilError(f, err)
|
||||
extension := tspath.TryGetExtensionFromPath(file.path)
|
||||
f.Add(extension, string(sourceText), false, false)
|
||||
}
|
||||
}
|
||||
|
||||
testDirs := []string{
|
||||
filepath.Join(repo.TypeScriptSubmodulePath(), "tests/cases/compiler"),
|
||||
filepath.Join(repo.TypeScriptSubmodulePath(), "tests/cases/conformance"),
|
||||
filepath.Join(repo.TestDataPath(), "tests/cases/compiler"),
|
||||
}
|
||||
|
||||
for _, testDir := range testDirs {
|
||||
if _, err := os.Stat(testDir); os.IsNotExist(err) {
|
||||
continue
|
||||
}
|
||||
|
||||
for file := range allParsableFiles(f, testDir) {
|
||||
sourceText, err := os.ReadFile(file.path)
|
||||
assert.NilError(f, err)
|
||||
|
||||
type testFile struct {
|
||||
content string
|
||||
name string
|
||||
}
|
||||
|
||||
testUnits, _, _, _, err := testrunner.ParseTestFilesAndSymlinks(
|
||||
string(sourceText),
|
||||
file.path,
|
||||
func(filename string, content string, fileOptions map[string]string) (testFile, error) {
|
||||
return testFile{content: content, name: filename}, nil
|
||||
},
|
||||
)
|
||||
assert.NilError(f, err)
|
||||
|
||||
for _, unit := range testUnits {
|
||||
extension := tspath.TryGetExtensionFromPath(unit.name)
|
||||
if extension == "" {
|
||||
continue
|
||||
}
|
||||
f.Add(extension, unit.content, false, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
f.Fuzz(func(t *testing.T, extension string, sourceText string, externalModuleIndicatorOptionsJSX bool, externalModuleIndicatorOptionsForce bool) {
|
||||
if !extensions.Has(extension) {
|
||||
t.Skip()
|
||||
}
|
||||
|
||||
fileName := "/index" + extension
|
||||
path := tspath.Path(fileName)
|
||||
|
||||
opts := ast.SourceFileParseOptions{
|
||||
FileName: fileName,
|
||||
Path: path,
|
||||
ExternalModuleIndicatorOptions: ast.ExternalModuleIndicatorOptions{
|
||||
JSX: externalModuleIndicatorOptionsJSX,
|
||||
Force: externalModuleIndicatorOptionsForce,
|
||||
},
|
||||
}
|
||||
|
||||
parser.ParseSourceFile(opts, sourceText, core.GetScriptKindFromFileName(fileName))
|
||||
})
|
||||
}
|
||||
|
||||
func TestJSDocImportTypeParentChain(t *testing.T) {
|
||||
t.Parallel()
|
||||
sourceText := `test("", async function () {
|
||||
;(/** @type {typeof import("a")} */ ({}))
|
||||
})
|
||||
|
||||
test("", async function () {
|
||||
;(/** @type {typeof import("a")} */ a)
|
||||
})
|
||||
|
||||
test("", async function () {
|
||||
(/** @type {typeof import("a")} */ ({}))
|
||||
;(/** @type {typeof import("a")} */ ({}))
|
||||
})
|
||||
|
||||
test("", async function () {
|
||||
(/** @type {typeof import("a")} */ a)
|
||||
;(/** @type {typeof import("a")} */ a)
|
||||
})
|
||||
|
||||
test("", async function () {
|
||||
(/** @type {typeof import("a")} */ ({}))
|
||||
;(/** @type {typeof import("a")} */ ({}))
|
||||
})
|
||||
`
|
||||
opts := ast.SourceFileParseOptions{
|
||||
FileName: "/index.js",
|
||||
Path: "/index.js",
|
||||
}
|
||||
|
||||
file := parser.ParseSourceFile(opts, sourceText, core.ScriptKindJS)
|
||||
|
||||
for i := 1; i < len(file.ReparsedClones); i++ {
|
||||
a, b := file.ReparsedClones[i-1], file.ReparsedClones[i]
|
||||
if a.Pos() == b.Pos() && a.End() == b.End() && a.Kind == b.Kind {
|
||||
t.Errorf("duplicate ReparsedClones at [%d] and [%d]: %s pos=%d end=%d", i-1, i, a.Kind.String(), a.Pos(), a.End())
|
||||
}
|
||||
}
|
||||
|
||||
for _, imp := range file.Imports() {
|
||||
reparsed := ast.GetReparsedNodeForNode(imp)
|
||||
if ast.GetSourceFileOfNode(reparsed) == nil {
|
||||
t.Errorf("reparsed import at pos=%d has broken parent chain", imp.Pos())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSourceFileContainsNonASCIIInStringLiteralFastPath(t *testing.T) {
|
||||
t.Parallel()
|
||||
sourceText := `const x = "─";
|
||||
|
||||
namespace N {
|
||||
export const y = x;
|
||||
}
|
||||
`
|
||||
opts := ast.SourceFileParseOptions{
|
||||
FileName: "/index.ts",
|
||||
Path: "/index.ts",
|
||||
}
|
||||
|
||||
file := parser.ParseSourceFile(opts, sourceText, core.ScriptKindTS)
|
||||
|
||||
assert.Assert(t, file.ContainsNonASCII)
|
||||
positionMap := file.GetPositionMap()
|
||||
assert.Assert(t, !positionMap.IsAsciiOnly())
|
||||
afterBoxDrawingCharacter := strings.Index(sourceText, "─") + len("─")
|
||||
assert.Equal(t, positionMap.UTF8ToUTF16(afterBoxDrawingCharacter), afterBoxDrawingCharacter-2)
|
||||
assert.Equal(t, positionMap.UTF8ToUTF16(len(sourceText)), len(sourceText)-2)
|
||||
}
|
||||
Reference in New Issue
Block a user