pkg/eval/evaltest: Import all builtin modules.

This removes the need for various "use-foo" setups for the standard library
modules - test code can just call "use foo" like normal Elvish code.
This commit is contained in:
Qi Xiao 2024-02-01 14:17:53 +00:00
parent 0afb509d29
commit d7fe04414b
31 changed files with 75 additions and 114 deletions

View File

@ -14,9 +14,9 @@
//in-temp-dir
## explicit argument ##
//use-os
//use-path
~> os:mkdir ~/d1
~> use os
use path
os:mkdir ~/d1
~> cd ~/d1
eq $pwd (path:join ~ d1)
▶ $true

View File

@ -24,13 +24,13 @@ Compilation error: variable $return~ is read-only
//unset-env PATH
## $E:PATH to $paths ##
//use-path
~> use path
~> set E:PATH = /bin1$path:list-separator/bin2
~> put $paths
▶ [/bin1 /bin2]
## $paths to $E:PATH ##
//use-path
~> use path
~> set paths = [/bin1 /bin2]
~> eq $E:PATH /bin1$path:list-separator/bin2
▶ $true
@ -51,8 +51,8 @@ Exception: path cannot contain NUL byte, colon on Unix or semicolon on Windows
////////
//in-temp-dir
//use-os
//use-path
~> use os
use path
// Test both reading and writing $pwd.
~> var start = $pwd
os:mkdir d

View File

@ -744,9 +744,9 @@ lib1/shadow
## use of module in subdirectory ##
//tmp-lib-dir
//use-os
// TODO: Use os:mkdir-all when it's available.
~> os:mkdir $lib/a
~> use os
os:mkdir $lib/a
os:mkdir $lib/a/b
echo 'var name = a/b/c' > $lib/a/b/c.elv
~> use a/b/c
@ -763,9 +763,9 @@ lib1/shadow
## renaming module ##
//tmp-lib-dir
//use-os
// TODO: Use os:mkdir-all when it's available.
~> os:mkdir $lib/a
~> use os
os:mkdir $lib/a
os:mkdir $lib/a/b
echo 'var name = a/b/c' > $lib/a/b/c.elv
~> use a/b/c mod
@ -783,9 +783,9 @@ lib1/shadow
## variable referencing a module can be shadowed ##
//tmp-lib-dir
//use-os
// TODO: Use os:mkdir-all when it's available.
~> os:mkdir $lib/a
~> use os
os:mkdir $lib/a
os:mkdir $lib/a/b
echo 'var name = c' > $lib/c.elv
echo 'var name = a/b/c' > $lib/a/b/c.elv
@ -798,8 +798,8 @@ lib1/shadow
## relative uses ##
//tmp-lib-dir
//use-os
~> os:mkdir $lib/a
~> use os
os:mkdir $lib/a
os:mkdir $lib/a/b
echo 'var name = ipsum' > $lib/lorem.elv
echo 'var name = a/b/c' > $lib/a/b/c.elv

View File

@ -74,7 +74,7 @@ Berlin
# background pipeline #
///////////////////////
//use-file
//eval use file
## basic behavior ##
~> set notify-bg-job-success = $false
@ -162,9 +162,9 @@ Exception: external commands don't accept elvish options
## external command from PATH ##
//in-temp-dir
//use-os
//unset-env PATH
~> os:mkdir bin
~> use os
os:mkdir bin
to-lines ['#!/bin/sh' 'echo hello'] > bin/say-hello
os:chmod 0o700 bin/say-hello
to-lines ['@echo hello'] > bin/say-hello.bat
@ -194,8 +194,8 @@ hello
## external command relative to working directory ##
//in-temp-dir
//use-os
~> fn make-echo-script {|name msg|
~> use os
fn make-echo-script {|name msg|
to-lines ['#!/bin/sh' 'echo '$msg] > $name
os:chmod 0o700 $name
to-lines ['@echo '$msg] > $name.bat
@ -368,16 +368,16 @@ Exception: invalid fd: 4
ok
## redirections from file objects ##
//use-file
~> echo haha > out3
~> use file
echo haha > out3
var f = (file:open out3)
slurp <$f
file:close $f
▶ "haha\n"
## redirections from pipe objects ##
//use-file
~> var p = (file:pipe)
~> use file
var p = (file:pipe)
echo haha > $p
file:close $p[w]
slurp < $p

View File

@ -274,7 +274,7 @@ Compilation error: variable $:x not found
▶ val
## module name access is checked at runtime ##
//use-os
~> use os
~> put $os:non-existent-variable
Exception: variable $os:non-existent-variable not found
[tty]:1:5-29: put $os:non-existent-variable

View File

@ -3,9 +3,9 @@
//////////////////////////////////
//in-temp-dir
//use-os
~> os:mkdir d
~> use os
os:mkdir d
var before-dst after-dst
set @before-chdir = {|dst| set before-dst = $dst }
set @after-chdir = {|dst| set after-dst = $dst }

View File

@ -15,6 +15,7 @@ import (
"src.elv.sh/pkg/diff"
"src.elv.sh/pkg/eval"
"src.elv.sh/pkg/eval/vals"
"src.elv.sh/pkg/mods"
"src.elv.sh/pkg/must"
"src.elv.sh/pkg/parse"
"src.elv.sh/pkg/testutil"
@ -98,6 +99,7 @@ func testTranscripts(t *testing.T, sessions []transcript.Session, setupPairs []a
for _, session := range sessions {
t.Run(session.Name, func(t *testing.T) {
ev := eval.NewEvaler()
mods.AddTo(ev)
for _, directive := range session.Directives {
name, arg, _ := strings.Cut(directive, " ")
if f, ok := setupMap[name]; ok {
@ -231,11 +233,3 @@ func stripSGR(bs []byte) []byte { return sgrPattern.ReplaceAllLiteral(bs, n
func stripSGRString(s string) string { return sgrPattern.ReplaceAllLiteralString(s, "") }
func normalizeLineEnding(bs []byte) []byte { return bytes.ReplaceAll(bs, []byte("\r\n"), []byte("\n")) }
// Use returns a function that simulates "use" on an Evaler and can be used as a
// setup function for [TestTranscriptsInFS].
func Use(name string, ns eval.Nser) func(*eval.Evaler) {
return func(ev *eval.Evaler) {
ev.ExtendGlobal(eval.BuildNs().AddNs(name, ns))
}
}

View File

@ -5,8 +5,8 @@
//in-temp-dir
## simple patterns ##
//use-os
~> put z z2 | each $os:mkdir~
~> use os
put z z2 | each $os:mkdir~
put bar foo ipsum lorem | each {|x| echo > $x}
~> put *
▶ bar
@ -33,9 +33,9 @@
▶ xz.w
## recursive patterns ##
//use-os
~> put 1 1/2 1/2/3 | each $os:mkdir~
~> put a.go 1/a.go 1/2/3/a.go | each {|x| echo > $x}
~> use os
put 1 1/2 1/2/3 | each $os:mkdir~
put a.go 1/a.go 1/2/3/a.go | each {|x| echo > $x}
~> put **
▶ 1/2/3/a.go
▶ 1/2/3
@ -58,9 +58,9 @@ Exception: wildcard has no match
~> put a/b/nonexistent*[nomatch-ok]
## hidden files ##
//use-os
~> put d .d | each $os:mkdir~
~> put a .a d/a d/.a .d/a .d/.a | each {|x| echo > $x}
~> use os
put d .d | each $os:mkdir~
put a .a d/a d/.a .d/a .d/.a | each {|x| echo > $x}
~> put *
▶ a
▶ d
@ -122,8 +122,8 @@ Exception: bad range modifier: foo
▶ lorem
## type ##
//use-os
~> put d1 d2 .d b b/c | each $os:mkdir~
~> use os
put d1 d2 .d b b/c | each $os:mkdir~
put bar foo ipsum lorem d1/f1 d2/fm | each {|x| echo > $x}
~> put **[type:dir]
▶ b/c

View File

@ -15,9 +15,6 @@ import (
"src.elv.sh/pkg/eval/vals"
"src.elv.sh/pkg/eval/vars"
"src.elv.sh/pkg/fsutil"
"src.elv.sh/pkg/mods/file"
osmod "src.elv.sh/pkg/mods/os"
pathmod "src.elv.sh/pkg/mods/path"
"src.elv.sh/pkg/must"
"src.elv.sh/pkg/prog"
"src.elv.sh/pkg/testutil"
@ -37,9 +34,6 @@ func TestTranscripts(t *testing.T) {
ev.ExtendGlobal(eval.BuildNs().
AddGoFn("recv-bg-job-notification", func() any { return <-noteCh }))
},
"use-file", evaltest.Use("file", file.Ns),
"use-os", evaltest.Use("os", osmod.Ns),
"use-path", evaltest.Use("path", pathmod.Ns),
"with-temp-home", func(t *testing.T) { testutil.TempHome(t) },
"reseed-afterwards", func(t *testing.T) {
t.Cleanup(func() {
@ -170,7 +164,9 @@ func TestTranscripts(t *testing.T) {
}
})
},
"go-fns-mod-in-global", evaltest.Use("go-fns", goFnsMod),
"go-fns-mod-in-global", func(ev *eval.Evaler) {
ev.ExtendGlobal(eval.BuildNs().AddNs("go-fns", goFnsMod))
},
)
}

View File

@ -1,4 +1,4 @@
//use-doc-with-fakepkg
//eval use doc
////////////
# doc:show #

View File

@ -20,6 +20,5 @@ func TestTranscripts(t *testing.T) {
// be reverted, so we just do it here instead of properly inside a setup
// function.
*doc.ElvFiles, _ = fs.Sub(fakepkg, "fakepkg")
evaltest.TestTranscriptsInFS(t, transcripts,
"use-doc-with-fakepkg", evaltest.Use("doc", doc.Ns))
evaltest.TestTranscriptsInFS(t, transcripts)
}

View File

@ -1,4 +1,4 @@
//use-file
//eval use file
//in-temp-dir
/////////////
@ -198,8 +198,8 @@ Exception: bad value: offset must be exact integer, but is 1.5
## good case ##
//use-os
~> echo > file100
~> use os
echo > file100
file:truncate file100 100
put (os:stat file100)[size]
▶ (num 100)

View File

@ -6,8 +6,6 @@ import (
"testing"
"src.elv.sh/pkg/eval/evaltest"
"src.elv.sh/pkg/mods/file"
osmod "src.elv.sh/pkg/mods/os"
)
//go:embed *.elvts
@ -15,8 +13,6 @@ var transcripts embed.FS
func TestTranscripts(t *testing.T) {
evaltest.TestTranscriptsInFS(t, transcripts,
"use-file", evaltest.Use("file", file.Ns),
"use-os", evaltest.Use("os", osmod.Ns),
"skip-unless-can-open", func(t *testing.T, name string) {
if !canOpen(name) {
t.SkipNow()

View File

@ -1,4 +1,4 @@
//use-flag
//eval use flag
/////////////
# flag:call #

View File

@ -1,4 +1,4 @@
//use-math
//eval use math
////////////
# math:abs #

View File

@ -5,14 +5,11 @@ import (
"testing"
"src.elv.sh/pkg/eval/evaltest"
"src.elv.sh/pkg/mods/math"
)
//go:embed *.elvts
var transcripts embed.FS
func TestTranscripts(t *testing.T) {
evaltest.TestTranscriptsInFS(t, transcripts,
"use-math", evaltest.Use("math", math.Ns),
)
evaltest.TestTranscriptsInFS(t, transcripts)
}

View File

@ -20,8 +20,8 @@ import (
// AddTo adds all standard library modules to the Evaler.
//
// All the public properties of the Evaler should be set before this function is
// called.
// Some modules (the runtime module for now) may rely on properties set on the
// Evaler, so any mutations afterwards may not be properly reflected.
func AddTo(ev *eval.Evaler) {
ev.AddModule("runtime", runtime.Ns(ev))
ev.AddModule("math", math.Ns)

View File

@ -1,4 +1,4 @@
//use-os
//eval use os
//in-temp-dir
////////////
@ -243,9 +243,9 @@ Exception: CreateFile non-existent: The system cannot find the file specified.
/////////////////////////
//apply-test-dir-with-symlinks-or-skip
//use-path
// These tests can run on Windows, where the output of os:eval-symlinks will use
// \ as the path separator, so we can't rely on the exact output.
~> use path
// Not symlink
~> eq (os:eval-symlinks d/f) (path:join d f)
▶ $true
@ -321,7 +321,8 @@ Exception: CreateFile bad: The system cannot find the file specified.
# os:temp-dir #
///////////////
//use-re
//eval use re
// default name template is elvish-*
~> var x = (os:temp-dir)
os:remove $x
@ -353,8 +354,9 @@ Exception: arity mismatch: arguments must be 0 to 1 values, but is 2 values
# os:temp-file #
////////////////
//use-re
//use-file
//eval use re
//eval use file
~> var f = (os:temp-file)
re:match '[/\\]elvish-.*$' $f[name]
file:close $f

View File

@ -8,10 +8,6 @@ import (
"testing"
"src.elv.sh/pkg/eval/evaltest"
"src.elv.sh/pkg/mods/file"
osmod "src.elv.sh/pkg/mods/os"
"src.elv.sh/pkg/mods/path"
"src.elv.sh/pkg/mods/re"
"src.elv.sh/pkg/must"
"src.elv.sh/pkg/testutil"
)
@ -21,10 +17,6 @@ var transcripts embed.FS
func TestTranscripts(t *testing.T) {
evaltest.TestTranscriptsInFS(t, transcripts,
"use-os", evaltest.Use("os", osmod.Ns),
"use-file", evaltest.Use("file", file.Ns),
"use-re", evaltest.Use("re", re.Ns),
"use-path", evaltest.Use("path", path.Ns),
"umask", func(t *testing.T, arg string) {
testutil.Umask(t, must.OK1(strconv.Atoi(arg)))
},

View File

@ -1,4 +1,4 @@
//use-path
//eval use path
// All the functions in path: are either simple wrappers of Go functions or
// compatibility aliases of their os: counterparts.
@ -10,8 +10,8 @@
# functions #
/////////////
//use-str
~> var abs = (path:abs a/b/c.png)
~> use str
var abs = (path:abs a/b/c.png)
path:is-abs $abs
str:has-suffix $abs (path:join a b c.png)
▶ $true
@ -71,10 +71,10 @@
# compatibility aliases #
/////////////////////////
//use-file
//use-re
//use-os
//in-temp-dir-with-d-f
~> use file
use re
use os
~> path:eval-symlinks d
▶ d
~> path:is-dir d

View File

@ -5,11 +5,6 @@ import (
"testing"
"src.elv.sh/pkg/eval/evaltest"
"src.elv.sh/pkg/mods/file"
osmod "src.elv.sh/pkg/mods/os"
"src.elv.sh/pkg/mods/path"
"src.elv.sh/pkg/mods/re"
"src.elv.sh/pkg/mods/str"
"src.elv.sh/pkg/testutil"
)
@ -18,11 +13,6 @@ var transcripts embed.FS
func TestTranscripts(t *testing.T) {
evaltest.TestTranscriptsInFS(t, transcripts,
"use-path", evaltest.Use("path", path.Ns),
"use-file", evaltest.Use("file", file.Ns),
"use-os", evaltest.Use("os", osmod.Ns),
"use-re", evaltest.Use("re", re.Ns),
"use-str", evaltest.Use("str", str.Ns),
"in-temp-dir-with-d-f", func(t *testing.T) {
testutil.InTempDir(t)
testutil.ApplyDir(testutil.Dir{

View File

@ -1,4 +1,4 @@
//use-platform
//eval use platform
//////////////////
# $platform:arch #

View File

@ -15,7 +15,6 @@ var transcripts embed.FS
func TestTranscripts(t *testing.T) {
evaltest.TestTranscriptsInFS(t, transcripts,
"use-platform", evaltest.Use("platform", platform.Ns),
"mock-hostname", func(t *testing.T, hostname string) {
testutil.Set(t, platform.OSHostname, func() (string, error) { return hostname, nil })
},

View File

@ -1,4 +1,4 @@
//use-re
//eval use re
////////////
# re:match #

View File

@ -5,14 +5,11 @@ import (
"testing"
"src.elv.sh/pkg/eval/evaltest"
"src.elv.sh/pkg/mods/re"
)
//go:embed *.elvts
var transcripts embed.FS
func TestTranscripts(t *testing.T) {
evaltest.TestTranscriptsInFS(t, transcripts,
"use-re", evaltest.Use("re", re.Ns),
)
evaltest.TestTranscriptsInFS(t, transcripts)
}

View File

@ -16,6 +16,9 @@ var transcripts embed.FS
func TestTranscripts(t *testing.T) {
evaltest.TestTranscriptsInFS(t, transcripts,
// We can't rely on the default runtime module installed by evaltest
// because the runtime modules reads Evaler fields during
// initialization.
"use-runtime-good-paths", func(t *testing.T, ev *eval.Evaler) {
testutil.Set(t, runtime.OSExecutable,
func() (string, error) { return "/path/to/elvish", nil })

View File

@ -1,4 +1,4 @@
//use-str
//eval use str
///////////////
# str:compare #

View File

@ -5,14 +5,11 @@ import (
"testing"
"src.elv.sh/pkg/eval/evaltest"
"src.elv.sh/pkg/mods/str"
)
//go:embed *.elvts
var transcripts embed.FS
func TestTranscripts(t *testing.T) {
evaltest.TestTranscriptsInFS(t, transcripts,
"use-str", evaltest.Use("str", str.Ns),
)
evaltest.TestTranscriptsInFS(t, transcripts)
}

View File

@ -1,4 +1,4 @@
//use-unix
//eval use unix
//mock-rlimit
///////////

View File

@ -1,4 +1,4 @@
//use-unix
//eval use unix
///////////
# parsing #

View File

@ -22,7 +22,6 @@ func TestTranscripts(t *testing.T) {
// Intention is to restore umask after test finishes
testutil.Umask(t, 0)
evaltest.TestTranscriptsInFS(t, transcripts,
"use-unix", evaltest.Use("unix", unixmod.Ns),
"mock-rlimit", mockRlimit,
)
}