github.com/markusbkk/elvish@v0.0.0-20231204143114-91dc52438621/pkg/eval/builtin_fn_misc_test.go (about) 1 package eval_test 2 3 import ( 4 "os" 5 "testing" 6 "time" 7 8 "github.com/markusbkk/elvish/pkg/diag" 9 . "github.com/markusbkk/elvish/pkg/eval" 10 "github.com/markusbkk/elvish/pkg/parse" 11 12 "github.com/markusbkk/elvish/pkg/eval/errs" 13 . "github.com/markusbkk/elvish/pkg/eval/evaltest" 14 "github.com/markusbkk/elvish/pkg/eval/vals" 15 "github.com/markusbkk/elvish/pkg/testutil" 16 ) 17 18 func TestKindOf(t *testing.T) { 19 Test(t, 20 That("kind-of a []").Puts("string", "list"), 21 thatOutputErrorIsBubbled("kind-of a"), 22 ) 23 } 24 25 func TestConstantly(t *testing.T) { 26 Test(t, 27 That(`var f = (constantly foo); $f; $f`).Puts("foo", "foo"), 28 thatOutputErrorIsBubbled("(constantly foo)"), 29 ) 30 } 31 32 func TestCallCommand(t *testing.T) { 33 Test(t, 34 That(`call {|arg &opt=v| put $arg $opt } [foo] [&opt=bar]`). 35 Puts("foo", "bar"), 36 That(`call { } [foo] [&[]=bar]`). 37 Throws(errs.BadValue{What: "option key", Valid: "string", Actual: "list"}), 38 ) 39 } 40 41 func TestEval(t *testing.T) { 42 Test(t, 43 That("eval 'put x'").Puts("x"), 44 // Using variable from the local scope. 45 That("var x = foo; eval 'put $x'").Puts("foo"), 46 // Setting a variable in the local scope. 47 That("var x = foo; eval 'set x = bar'; put $x").Puts("bar"), 48 // Using variable from the upvalue scope. 49 That("var x = foo; { nop $x; eval 'put $x' }").Puts("foo"), 50 // Specifying a namespace. 51 That("var n = (ns [&x=foo]); eval 'put $x' &ns=$n").Puts("foo"), 52 // Altering variables in the specified namespace. 53 That("var n = (ns [&x=foo]); eval 'set x = bar' &ns=$n; put $n[x]").Puts("bar"), 54 // Newly created variables do not appear in the local namespace. 55 That("eval 'x = foo'; put $x").DoesNotCompile(), 56 // Newly created variables do not alter the specified namespace, either. 57 That("var n = (ns [&]); eval &ns=$n 'var x = foo'; put $n[x]"). 58 Throws(vals.NoSuchKey("x"), "$n[x]"), 59 // However, newly created variable can be accessed in the final 60 // namespace using &on-end. 61 That("eval &on-end={|n| put $n[x] } 'var x = foo'").Puts("foo"), 62 // Parse error. 63 That("eval '['").Throws(ErrorWithType(&parse.Error{})), 64 // Compilation error. 65 That("eval 'put $x'").Throws(ErrorWithType(&diag.Error{})), 66 // Exception. 67 That("eval 'fail x'").Throws(FailError{"x"}), 68 ) 69 } 70 71 func TestDeprecate(t *testing.T) { 72 Test(t, 73 That("deprecate msg").PrintsStderrWith("msg"), 74 // Different call sites trigger multiple deprecation messages 75 That("fn f { deprecate msg }", "f 2>"+os.DevNull, "f"). 76 PrintsStderrWith("msg"), 77 // The same call site only triggers the message once 78 That("fn f { deprecate msg}", "fn g { f }", "g 2>"+os.DevNull, "g 2>&1"). 79 DoesNothing(), 80 ) 81 } 82 83 func TestTime(t *testing.T) { 84 Test(t, 85 // Since runtime duration is non-deterministic, we only have some sanity 86 // checks here. 87 That("time { echo foo } | var a _ = (all)", "put $a").Puts("foo"), 88 That("var duration = ''", 89 "time &on-end={|x| set duration = $x } { echo foo } | var out = (all)", 90 "put $out", "kind-of $duration").Puts("foo", "number"), 91 That("time { fail body } | nop (all)").Throws(FailError{"body"}), 92 That("time &on-end={|_| fail on-end } { }").Throws( 93 FailError{"on-end"}), 94 95 That("time &on-end={|_| fail on-end } { fail body }").Throws( 96 FailError{"body"}), 97 98 thatOutputErrorIsBubbled("time { }"), 99 ) 100 } 101 102 func TestUseMod(t *testing.T) { 103 testutil.InTempDir(t) 104 testutil.MustWriteFile("mod.elv", "var x = value") 105 106 Test(t, 107 That("put (use-mod ./mod)[x]").Puts("value"), 108 ) 109 } 110 111 func timeAfterMock(fm *Frame, d time.Duration) <-chan time.Time { 112 fm.ValueOutput().Put(d) // report to the test framework the duration we received 113 return time.After(0) 114 } 115 116 func TestSleep(t *testing.T) { 117 TimeAfter = timeAfterMock 118 Test(t, 119 That(`sleep 0`).Puts(0*time.Second), 120 That(`sleep 1`).Puts(1*time.Second), 121 That(`sleep 1.3s`).Puts(1300*time.Millisecond), 122 That(`sleep 0.1`).Puts(100*time.Millisecond), 123 That(`sleep 0.1ms`).Puts(100*time.Microsecond), 124 That(`sleep 3h5m7s`).Puts((3*3600+5*60+7)*time.Second), 125 126 That(`sleep 1x`).Throws(ErrInvalidSleepDuration, "sleep 1x"), 127 That(`sleep -7`).Throws(ErrNegativeSleepDuration, "sleep -7"), 128 That(`sleep -3h`).Throws(ErrNegativeSleepDuration, "sleep -3h"), 129 130 That(`sleep 1/2`).Puts(time.Second/2), // rational number string 131 132 // Verify the correct behavior if a numeric type, rather than a string, is passed to the 133 // command. 134 That(`sleep (num 42)`).Puts(42*time.Second), 135 That(`sleep (float64 0)`).Puts(0*time.Second), 136 That(`sleep (float64 1.7)`).Puts(1700*time.Millisecond), 137 That(`sleep (float64 -7)`).Throws(ErrNegativeSleepDuration, "sleep (float64 -7)"), 138 139 // An invalid argument type should raise an exception. 140 That(`sleep [1]`).Throws(ErrInvalidSleepDuration, "sleep [1]"), 141 ) 142 } 143 144 func TestResolve(t *testing.T) { 145 libdir := testutil.InTempDir(t) 146 testutil.MustWriteFile("mod.elv", "fn func { }") 147 148 TestWithSetup(t, func(ev *Evaler) { ev.LibDirs = []string{libdir} }, 149 That("resolve for").Puts("special"), 150 That("resolve put").Puts("$put~"), 151 That("fn f { }; resolve f").Puts("$f~"), 152 That("use mod; resolve mod:func").Puts("$mod:func~"), 153 That("resolve cat").Puts("(external cat)"), 154 That(`resolve external`).Puts("$external~"), 155 ) 156 }