mirror of
https://github.com/go-sylixos/elvish.git
synced 2024-12-04 02:37:50 +08:00
d7fe04414b
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.
186 lines
5.6 KiB
Go
186 lines
5.6 KiB
Go
package eval_test
|
|
|
|
import (
|
|
"embed"
|
|
"errors"
|
|
"fmt"
|
|
"math/rand"
|
|
"strconv"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"src.elv.sh/pkg/eval"
|
|
"src.elv.sh/pkg/eval/evaltest"
|
|
"src.elv.sh/pkg/eval/vals"
|
|
"src.elv.sh/pkg/eval/vars"
|
|
"src.elv.sh/pkg/fsutil"
|
|
"src.elv.sh/pkg/must"
|
|
"src.elv.sh/pkg/prog"
|
|
"src.elv.sh/pkg/testutil"
|
|
)
|
|
|
|
//go:embed *.elvts
|
|
var transcripts embed.FS
|
|
|
|
func TestTranscripts(t *testing.T) {
|
|
evaltest.TestTranscriptsInFS(t, transcripts,
|
|
"args", func(ev *eval.Evaler, arg string) {
|
|
ev.Args = vals.MakeListSlice(strings.Fields(arg))
|
|
},
|
|
"recv-bg-job-notification-in-global", func(ev *eval.Evaler) {
|
|
noteCh := make(chan string, 10)
|
|
ev.BgJobNotify = func(s string) { noteCh <- s }
|
|
ev.ExtendGlobal(eval.BuildNs().
|
|
AddGoFn("recv-bg-job-notification", func() any { return <-noteCh }))
|
|
},
|
|
"with-temp-home", func(t *testing.T) { testutil.TempHome(t) },
|
|
"reseed-afterwards", func(t *testing.T) {
|
|
t.Cleanup(func() {
|
|
//lint:ignore SA1019 Reseed to make other RNG-dependent tests non-deterministic
|
|
rand.Seed(time.Now().UTC().UnixNano())
|
|
})
|
|
},
|
|
"check-exit-code-afterwards", func(t *testing.T, arg string) {
|
|
var exitCodes []int
|
|
testutil.Set(t, eval.OSExit, func(i int) {
|
|
exitCodes = append(exitCodes, i)
|
|
})
|
|
wantExitCode := must.OK1(strconv.Atoi(arg))
|
|
t.Cleanup(func() {
|
|
if len(exitCodes) != 1 {
|
|
t.Errorf("os.Exit called %d times, want once", len(exitCodes))
|
|
} else if exitCodes[0] != wantExitCode {
|
|
t.Errorf("os.Exit called with %d, want %d", exitCodes[0], wantExitCode)
|
|
}
|
|
})
|
|
},
|
|
"check-pre-exit-hook-afterwards", func(t *testing.T, ev *eval.Evaler) {
|
|
testutil.Set(t, eval.OSExit, func(int) {})
|
|
calls := 0
|
|
ev.PreExitHooks = append(ev.PreExitHooks, func() { calls++ })
|
|
t.Cleanup(func() {
|
|
if calls != 1 {
|
|
t.Errorf("pre-exit hook called %v times, want 1", calls)
|
|
}
|
|
})
|
|
},
|
|
"add-bad-var", func(ev *eval.Evaler, arg string) {
|
|
name, allowedSetsString, _ := strings.Cut(arg, " ")
|
|
allowedSets := must.OK1(strconv.Atoi(allowedSetsString))
|
|
ev.ExtendGlobal(eval.BuildNs().AddVar(name, &badVar{allowedSets}))
|
|
},
|
|
"tmp-lib-dir", func(t *testing.T, ev *eval.Evaler) {
|
|
libdir := testutil.TempDir(t)
|
|
ev.LibDirs = []string{libdir}
|
|
ev.ExtendGlobal(eval.BuildNs().
|
|
AddVar("lib", vars.NewReadOnly(libdir)))
|
|
},
|
|
"two-tmp-lib-dirs", func(t *testing.T, ev *eval.Evaler) {
|
|
libdir1 := testutil.TempDir(t)
|
|
libdir2 := testutil.TempDir(t)
|
|
ev.LibDirs = []string{libdir1, libdir2}
|
|
ev.ExtendGlobal(eval.BuildNs().
|
|
AddVar("lib1", vars.NewReadOnly(libdir1)).
|
|
AddVar("lib2", vars.NewReadOnly(libdir2)))
|
|
},
|
|
"add-var-in-builtin", func(ev *eval.Evaler) {
|
|
addVar := func(name string, val any) {
|
|
ev.ExtendGlobal(eval.BuildNs().AddVar(name, vars.FromInit(val)))
|
|
}
|
|
ev.ExtendBuiltin(eval.BuildNs().AddGoFn("add-var", addVar))
|
|
},
|
|
"test-time-scale-in-global", func(ev *eval.Evaler) {
|
|
ev.ExtendGlobal(eval.BuildNs().
|
|
AddVar("test-time-scale", vars.NewReadOnly(testutil.TestTimeScale())))
|
|
},
|
|
"mock-get-home-error", func(t *testing.T, msg string) {
|
|
err := errors.New(msg)
|
|
testutil.Set(t, eval.GetHome,
|
|
func(name string) (string, error) { return "", err })
|
|
},
|
|
"force-eval-source-count", func(t *testing.T, arg string) {
|
|
c := must.OK1(strconv.Atoi(arg))
|
|
testutil.Set(t, eval.NextEvalCount, func() int { return c })
|
|
},
|
|
"with-deprecation-level", func(t *testing.T, arg string) {
|
|
testutil.Set(t, &prog.DeprecationLevel, must.OK1(strconv.Atoi(arg)))
|
|
},
|
|
"mock-time-after", func(t *testing.T) {
|
|
testutil.Set(t, eval.TimeAfter,
|
|
func(fm *eval.Frame, d time.Duration) <-chan time.Time {
|
|
fmt.Fprintf(fm.ByteOutput(), "slept for %s\n", d)
|
|
return time.After(0)
|
|
})
|
|
},
|
|
"mock-benchmark-run-durations", func(t *testing.T, arg string) {
|
|
// The benchmark command calls time.Now once before a run and once
|
|
// after a run.
|
|
var ticks []int64
|
|
for i, field := range strings.Fields(arg) {
|
|
d := must.OK1(strconv.ParseInt(field, 0, 64))
|
|
if i == 0 {
|
|
ticks = append(ticks, 0, d)
|
|
} else {
|
|
last := ticks[len(ticks)-1]
|
|
ticks = append(ticks, last, last+d)
|
|
}
|
|
}
|
|
testutil.Set(t, eval.TimeNow, func() time.Time {
|
|
if len(ticks) == 0 {
|
|
panic("mock TimeNow called more than len(ticks)")
|
|
}
|
|
v := ticks[0]
|
|
ticks = ticks[1:]
|
|
return time.Unix(v, 0)
|
|
})
|
|
},
|
|
"inject-time-after-with-sigint-or-skip", injectTimeAfterWithSIGINTOrSkip,
|
|
"mock-getwd-error", func(t *testing.T, msg string) {
|
|
err := errors.New(msg)
|
|
testutil.Set(t, eval.Getwd, func() (string, error) { return "", err })
|
|
},
|
|
"mock-no-other-home", func(t *testing.T) {
|
|
testutil.Set(t, eval.GetHome, func(name string) (string, error) {
|
|
switch name {
|
|
case "":
|
|
return fsutil.GetHome("")
|
|
default:
|
|
return "", fmt.Errorf("don't know home of %v", name)
|
|
}
|
|
})
|
|
},
|
|
"mock-one-other-home", func(t *testing.T, ev *eval.Evaler) {
|
|
otherHome := testutil.TempDir(t)
|
|
ev.ExtendGlobal(eval.BuildNs().AddVar("other-home", vars.NewReadOnly(otherHome)))
|
|
testutil.Set(t, eval.GetHome, func(name string) (string, error) {
|
|
switch name {
|
|
case "":
|
|
return fsutil.GetHome("")
|
|
case "other":
|
|
return otherHome, nil
|
|
default:
|
|
return "", fmt.Errorf("don't know home of %v", name)
|
|
}
|
|
})
|
|
},
|
|
"go-fns-mod-in-global", func(ev *eval.Evaler) {
|
|
ev.ExtendGlobal(eval.BuildNs().AddNs("go-fns", goFnsMod))
|
|
},
|
|
)
|
|
}
|
|
|
|
var errBadVar = errors.New("bad var")
|
|
|
|
type badVar struct{ allowedSets int }
|
|
|
|
func (v *badVar) Get() any { return nil }
|
|
|
|
func (v *badVar) Set(any) error {
|
|
if v.allowedSets == 0 {
|
|
return errBadVar
|
|
}
|
|
v.allowedSets--
|
|
return nil
|
|
}
|