SandpointsGitHook/vendor/github.com/evanw/esbuild/internal/fs/fs_mock.go

276 lines
5.5 KiB
Go

package fs
// This is a mock implementation of the "fs" module for use with tests. It does
// not actually read from the file system. Instead, it reads from a pre-specified
// map of file paths to files.
import (
"errors"
"path"
"strings"
"syscall"
)
type MockKind uint8
const (
MockUnix MockKind = iota
MockWindows
)
type mockFS struct {
dirs map[string]DirEntries
files map[string]string
Kind MockKind
}
func MockFS(input map[string]string, kind MockKind) FS {
dirs := make(map[string]DirEntries)
files := make(map[string]string)
for k, v := range input {
key := k
if kind == MockWindows {
key = "C:" + strings.ReplaceAll(key, "/", "\\")
}
files[key] = v
original := k
// Build the directory map
for {
kDir := path.Dir(k)
key := kDir
if kind == MockWindows {
key = "C:" + strings.ReplaceAll(key, "/", "\\")
}
dir, ok := dirs[key]
if !ok {
dir = DirEntries{dir: key, data: make(map[string]*Entry)}
dirs[key] = dir
}
if kDir == k {
break
}
base := path.Base(k)
if k == original {
dir.data[strings.ToLower(base)] = &Entry{kind: FileEntry, base: base}
} else {
dir.data[strings.ToLower(base)] = &Entry{kind: DirEntry, base: base}
}
k = kDir
}
}
return &mockFS{dirs, files, kind}
}
func (fs *mockFS) ReadDirectory(path string) (DirEntries, error, error) {
if fs.Kind == MockWindows {
path = strings.ReplaceAll(path, "/", "\\")
}
if dir, ok := fs.dirs[path]; ok {
return dir, nil, nil
}
return DirEntries{}, syscall.ENOENT, syscall.ENOENT
}
func (fs *mockFS) ReadFile(path string) (string, error, error) {
if fs.Kind == MockWindows {
path = strings.ReplaceAll(path, "/", "\\")
}
if contents, ok := fs.files[path]; ok {
return contents, nil, nil
}
return "", syscall.ENOENT, syscall.ENOENT
}
func (fs *mockFS) OpenFile(path string) (OpenedFile, error, error) {
if fs.Kind == MockWindows {
path = strings.ReplaceAll(path, "/", "\\")
}
if contents, ok := fs.files[path]; ok {
return &InMemoryOpenedFile{Contents: []byte(contents)}, nil, nil
}
return nil, syscall.ENOENT, syscall.ENOENT
}
func (fs *mockFS) ModKey(path string) (ModKey, error) {
return ModKey{}, errors.New("This is not available during tests")
}
func win2unix(p string) string {
if strings.HasPrefix(p, "C:\\") {
p = p[2:]
}
p = strings.ReplaceAll(p, "\\", "/")
return p
}
func unix2win(p string) string {
p = strings.ReplaceAll(p, "/", "\\")
if strings.HasPrefix(p, "\\") {
p = "C:" + p
}
return p
}
func (fs *mockFS) IsAbs(p string) bool {
if fs.Kind == MockWindows {
p = win2unix(p)
}
return path.IsAbs(p)
}
func (fs *mockFS) Abs(p string) (string, bool) {
if fs.Kind == MockWindows {
p = win2unix(p)
}
p = path.Clean(path.Join("/", p))
if fs.Kind == MockWindows {
p = unix2win(p)
}
return p, true
}
func (fs *mockFS) Dir(p string) string {
if fs.Kind == MockWindows {
p = win2unix(p)
}
p = path.Dir(p)
if fs.Kind == MockWindows {
p = unix2win(p)
}
return p
}
func (fs *mockFS) Base(p string) string {
if fs.Kind == MockWindows {
p = win2unix(p)
}
p = path.Base(p)
if fs.Kind == MockWindows && p == "/" {
p = "\\"
}
return p
}
func (fs *mockFS) Ext(p string) string {
if fs.Kind == MockWindows {
p = win2unix(p)
}
return path.Ext(p)
}
func (fs *mockFS) Join(parts ...string) string {
if fs.Kind == MockWindows {
converted := make([]string, len(parts))
for i, part := range parts {
converted[i] = win2unix(part)
}
parts = converted
}
p := path.Clean(path.Join(parts...))
if fs.Kind == MockWindows {
p = unix2win(p)
}
return p
}
func (fs *mockFS) Cwd() string {
if fs.Kind == MockWindows {
return "C:\\"
}
return "/"
}
func splitOnSlash(path string) (string, string) {
if slash := strings.IndexByte(path, '/'); slash != -1 {
return path[:slash], path[slash+1:]
}
return path, ""
}
func (fs *mockFS) Rel(base string, target string) (string, bool) {
if fs.Kind == MockWindows {
base = win2unix(base)
target = win2unix(target)
}
base = path.Clean(base)
target = path.Clean(target)
// Go's implementation does these checks
if base == target {
return ".", true
}
if base == "." {
base = ""
}
// Go's implementation fails when this condition is false. I believe this is
// because of this part of the contract, from Go's documentation: "An error
// is returned if targpath can't be made relative to basepath or if knowing
// the current working directory would be necessary to compute it."
if (len(base) > 0 && base[0] == '/') != (len(target) > 0 && target[0] == '/') {
return "", false
}
// Find the common parent directory
for {
bHead, bTail := splitOnSlash(base)
tHead, tTail := splitOnSlash(target)
if bHead != tHead {
break
}
base = bTail
target = tTail
}
// Stop now if base is a subpath of target
if base == "" {
if fs.Kind == MockWindows {
target = unix2win(target)
}
return target, true
}
// Traverse up to the common parent
commonParent := strings.Repeat("../", strings.Count(base, "/")+1)
// Stop now if target is a subpath of base
if target == "" {
target = commonParent[:len(commonParent)-1]
if fs.Kind == MockWindows {
target = unix2win(target)
}
return target, true
}
// Otherwise, down to the parent
target = commonParent + target
if fs.Kind == MockWindows {
target = unix2win(target)
}
return target, true
}
func (fs *mockFS) kind(dir string, base string) (symlink string, kind EntryKind) {
panic("This should never be called")
}
func (fs *mockFS) WatchData() WatchData {
panic("This should never be called")
}