package osvfs import ( "os" "os/exec" "path/filepath" "testing" "github.com/microsoft/typescript-go/internal/tspath" "gotest.tools/v3/assert" ) func TestSymlinkRealpath(t *testing.T) { t.Parallel() targetFile, linkFile := setupSymlinks(t) gotContents, err := os.ReadFile(linkFile) assert.NilError(t, err) assert.Equal(t, string(gotContents), "hello") fs := FS() targetRealpath := fs.Realpath(tspath.NormalizePath(targetFile)) linkRealpath := fs.Realpath(tspath.NormalizePath(linkFile)) if targetRealpath != linkRealpath { t.Errorf("expected realpath of target and link to be equal, got %q and %q", targetRealpath, linkRealpath) cmd := exec.Command("node", "-e", `console.log({ native: fs.realpathSync.native(process.argv[1]), node: fs.realpathSync(process.argv[1]) })`, linkFile) out, err := cmd.CombinedOutput() assert.NilError(t, err) t.Logf("node: %s", out) } } func setupSymlinks(tb testing.TB) (targetFile, linkFile string) { tb.Helper() tmp := tb.TempDir() target := filepath.Join(tmp, "target") targetFile = filepath.Join(target, "file") link := filepath.Join(tmp, "link") linkFile = filepath.Join(link, "file") assert.NilError(tb, os.MkdirAll(target, 0o777)) assert.NilError(tb, os.WriteFile(targetFile, []byte("hello"), 0o666)) mklink(tb, target, link, true) return targetFile, linkFile } func BenchmarkRealpath(b *testing.B) { targetFile, linkFile := setupSymlinks(b) fs := FS() normalizedTargetFile := tspath.NormalizePath(targetFile) normalizedLinkFile := tspath.NormalizePath(linkFile) b.Run("target", func(b *testing.B) { b.ReportAllocs() for b.Loop() { fs.Realpath(normalizedTargetFile) } }) b.Run("link", func(b *testing.B) { b.ReportAllocs() for b.Loop() { fs.Realpath(normalizedLinkFile) } }) // Simulate a deep node_modules path to show scaling with depth. deepDir := b.TempDir() for _, seg := range []string{"project", "node_modules", "@scope", "package", "node_modules", "dep", "lib", "dist", "esm", "internal", "utils"} { deepDir = filepath.Join(deepDir, seg) } assert.NilError(b, os.MkdirAll(deepDir, 0o777)) deepFile := filepath.Join(deepDir, "index.js") assert.NilError(b, os.WriteFile(deepFile, []byte("module.exports = {}"), 0o666)) normalizedDeepFile := tspath.NormalizePath(deepFile) b.Run("deep", func(b *testing.B) { b.ReportAllocs() for b.Loop() { fs.Realpath(normalizedDeepFile) } }) b.Run("deep_evalSymlinks", func(b *testing.B) { b.ReportAllocs() deepNative := filepath.FromSlash(normalizedDeepFile) for b.Loop() { filepath.EvalSymlinks(deepNative) //nolint:errcheck } }) } func TestGetAccessibleEntries(t *testing.T) { t.Parallel() tmp := t.TempDir() target := filepath.Join(tmp, "target") link := filepath.Join(tmp, "link") assert.NilError(t, os.MkdirAll(target, 0o777)) assert.NilError(t, os.MkdirAll(link, 0o777)) targetFile1 := filepath.Join(target, "file1") targetFile2 := filepath.Join(target, "file2") assert.NilError(t, os.WriteFile(targetFile1, []byte("hello"), 0o666)) assert.NilError(t, os.WriteFile(targetFile2, []byte("world"), 0o666)) targetDir1 := filepath.Join(target, "dir1") targetDir2 := filepath.Join(target, "dir2") assert.NilError(t, os.MkdirAll(targetDir1, 0o777)) assert.NilError(t, os.MkdirAll(targetDir2, 0o777)) mklink(t, targetFile1, filepath.Join(link, "file1"), false) mklink(t, targetFile2, filepath.Join(link, "file2"), false) mklink(t, targetDir1, filepath.Join(link, "dir1"), true) mklink(t, targetDir2, filepath.Join(link, "dir2"), true) fs := FS() entries := fs.GetAccessibleEntries(tspath.NormalizePath(link)) assert.DeepEqual(t, entries.Directories, []string{"dir1", "dir2"}) assert.DeepEqual(t, entries.Files, []string{"file1", "file2"}) assert.Check(t, entries.Symlinks != nil, "expected Symlinks to be set for directory with symlinks") assert.Equal(t, len(entries.Symlinks), 4) for _, name := range []string{"file1", "file2", "dir1", "dir2"} { _, ok := entries.Symlinks[name] assert.Check(t, ok, "expected %q to be in Symlinks", name) } // Non-symlink directory should have empty Symlinks. entries = fs.GetAccessibleEntries(tspath.NormalizePath(target)) assert.DeepEqual(t, entries.Directories, []string{"dir1", "dir2"}) assert.DeepEqual(t, entries.Files, []string{"file1", "file2"}) assert.Check(t, entries.Symlinks != nil, "expected Symlinks to be non-nil for directory without symlinks") assert.Equal(t, len(entries.Symlinks), 0) }