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  }