Files
moxa/interp/src_test.go
Johnny b5bf4ef31a interp: allow for reading source files from diverse filesystems
Make use of fs.FS (new to go 1.16) to allow for reading source files from diverse filesystems (local, embed, custom).

* `Options` has a new field `SourcecodeFilesystem fs.FS` so users can supply their own read-only filesystem containing source code.
* Defaults to the local filesystems (via `RealFS` - a thin `os.Open` wrapper complying with `fs.FS`) so regular users should see no change in behaviour.
* When no filesystem is available (e.g. WASM, or if you want to embed files to retain single binary distribution) an alternative filesystem is preferable to using `Eval(string)` as that requires the stringy code to be a single file monolith instead of multiple files. By using an `fs.FS` we can use `EvalPath()` and gain the ability to handle multiple files and packages.
* You can make use of embed filesystems (https://pkg.go.dev/embed) and custom filesystems obeying the `fs.FS` interface (I use one for http served zip files when targeting wasm as there is no local filesystem on wasm). Tests can make use of `fstest.Map`.
* NOTE: This does NOT affect what the running yaegi code considers its local filesystem, this is only for the interpreter finding the source code.

See `example/fs/fs_test.go` for an example.

Fixes #1200.
2021-08-19 11:28:13 +02:00

265 lines
6.7 KiB
Go

package interp
import (
"io/ioutil"
"os"
"path/filepath"
"testing"
)
func Test_effectivePkg(t *testing.T) {
testCases := []struct {
desc string
root string
path string
expected string
}{
{
desc: "path is a subpackage",
root: "github.com/foo/plugin/vendor/guthib.com/traefik/fromage",
path: "guthib.com/traefik/fromage/couteau/lol",
expected: "github.com/foo/plugin/vendor/guthib.com/traefik/fromage/couteau/lol",
},
{
desc: "path is a vendored package",
root: "github.com/foo/plugin/vendor/guthib.com/traefik/fromage",
path: "vendor/guthib.com/traefik/vin",
expected: "github.com/foo/plugin/vendor/guthib.com/traefik/fromage/vendor/guthib.com/traefik/vin",
},
{
desc: "path is non-existent",
root: "foo",
path: "githib.com/foo/app",
expected: "foo/githib.com/foo/app",
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
pkg := effectivePkg(test.root, test.path)
if pkg != test.expected {
t.Errorf("Got %s, want %s", pkg, test.expected)
}
})
}
}
func Test_pkgDir(t *testing.T) {
// create GOPATH
goPath, err := ioutil.TempDir("", "pkdir")
if err != nil {
t.Fatal(err)
}
defer func() {
_ = os.RemoveAll(goPath)
}()
// Create project
project := filepath.Join(goPath, "src", "guthib.com", "foo", "root")
if err := os.MkdirAll(project, 0700); err != nil {
t.Fatal(err)
}
type expected struct {
dir string
rpath string
}
testCases := []struct {
desc string
path string
root string
setup func() error
expected expected
}{
{
desc: "GOPATH only",
path: "guthib.com/foo/bar",
root: "",
setup: func() error {
return os.MkdirAll(filepath.Join(goPath, "src", "guthib.com", "foo", "bar"), 0700)
},
expected: expected{
dir: filepath.Join(goPath, "src", "guthib.com", "foo", "bar"),
rpath: "",
},
},
{
desc: "vendor",
path: "guthib.com/foo/bar",
root: filepath.Join("guthib.com", "foo", "root"),
setup: func() error {
return os.MkdirAll(filepath.Join(project, "vendor", "guthib.com", "foo", "bar"), 0700)
},
expected: expected{
dir: filepath.Join(goPath, "src", "guthib.com", "foo", "root", "vendor", "guthib.com", "foo", "bar"),
rpath: filepath.Join("guthib.com", "foo", "root", "vendor"),
},
},
{
desc: "GOPATH flat",
path: "guthib.com/foo/bar",
root: filepath.Join("guthib.com", "foo", "root"),
setup: func() error {
return os.MkdirAll(filepath.Join(goPath, "src", "guthib.com", "foo", "bar"), 0700)
},
expected: expected{
dir: filepath.Join(goPath, "src", "guthib.com", "foo", "bar"),
rpath: "",
},
},
{
desc: "vendor flat",
path: "guthib.com/foo/bar",
root: filepath.Join("guthib.com", "foo", "root", "vendor", "guthib.com", "foo", "bir"),
setup: func() error {
if err := os.MkdirAll(filepath.Join(project, "vendor", "guthib.com", "foo", "bar"), 0700); err != nil {
return err
}
return os.MkdirAll(filepath.Join(project, "vendor", "guthib.com", "foo", "bir"), 0700)
},
expected: expected{
dir: filepath.Join(goPath, "src", "guthib.com", "foo", "root", "vendor", "guthib.com", "foo", "bar"),
rpath: filepath.Join("guthib.com", "foo", "root", "vendor"),
},
},
{
desc: "fallback to GOPATH",
path: "guthib.com/foo/bar",
root: filepath.Join("guthib.com", "foo", "root", "vendor", "guthib.com", "foo", "bir"),
setup: func() error {
if err := os.MkdirAll(filepath.Join(goPath, "src", "guthib.com", "foo", "bar"), 0700); err != nil {
return err
}
return os.MkdirAll(filepath.Join(project, "vendor", "guthib.com", "foo", "bir"), 0700)
},
expected: expected{
dir: filepath.Join(goPath, "src", "guthib.com", "foo", "bar"),
rpath: "",
},
},
{
desc: "vendor recursive",
path: "guthib.com/foo/bar",
root: filepath.Join("guthib.com", "foo", "root", "vendor", "guthib.com", "foo", "bir", "vendor", "guthib.com", "foo", "bur"),
setup: func() error {
if err := os.MkdirAll(
filepath.Join(goPath, "src", "guthib.com", "foo", "root", "vendor", "guthib.com", "foo", "bir", "vendor", "guthib.com", "foo", "bur"),
0700); err != nil {
return err
}
return os.MkdirAll(filepath.Join(project, "vendor", "guthib.com", "foo", "bar"), 0700)
},
expected: expected{
dir: filepath.Join(project, "vendor", "guthib.com", "foo", "bar"),
rpath: filepath.Join("guthib.com", "foo", "root", "vendor"),
},
},
}
interp := &Interpreter{
opt: opt{
filesystem: &RealFS{},
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
if err := os.RemoveAll(goPath); err != nil {
t.Fatal(err)
}
if err := os.MkdirAll(goPath, 0700); err != nil {
t.Fatal(err)
}
if test.setup != nil {
err := test.setup()
if err != nil {
t.Fatal(err)
}
}
dir, rPath, err := interp.pkgDir(goPath, test.root, test.path)
if err != nil {
t.Fatal(err)
}
if dir != test.expected.dir {
t.Errorf("[dir] got: %s, want: %s", dir, test.expected.dir)
}
if rPath != test.expected.rpath {
t.Errorf(" [rpath] got: %s, want: %s", rPath, test.expected.rpath)
}
})
}
}
func Test_previousRoot(t *testing.T) {
testCases := []struct {
desc string
root string
rootPathSuffix string
expected string
}{
{
desc: "GOPATH",
root: "github.com/foo/pkg/",
expected: "",
},
{
desc: "vendor level 1",
root: "github.com/foo/pkg/vendor/guthib.com/traefik/fromage",
expected: "github.com/foo/pkg",
},
{
desc: "vendor level 2",
root: "github.com/foo/pkg/vendor/guthib.com/traefik/fromage/vendor/guthib.com/traefik/fuu",
expected: "github.com/foo/pkg/vendor/guthib.com/traefik/fromage",
},
{
desc: "vendor is sibling",
root: "github.com/foo/bar",
rootPathSuffix: "testdata/src/github.com/foo/bar",
expected: "github.com/foo",
},
{
desc: "vendor is uncle",
root: "github.com/foo/bar/baz",
rootPathSuffix: "testdata/src/github.com/foo/bar/baz",
expected: "github.com/foo",
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
var rootPath string
if test.rootPathSuffix != "" {
wd, err := os.Getwd()
if err != nil {
t.Fatal(err)
}
rootPath = filepath.Join(wd, test.rootPathSuffix)
} else {
rootPath = vendor
}
p, err := previousRoot(&RealFS{}, rootPath, test.root)
if err != nil {
t.Error(err)
}
if p != test.expected {
t.Errorf("got: %s, want: %s", p, test.expected)
}
})
}
}