github.com/kolbycrouch/elvish@v0.14.1-0.20210614162631-215b9ac1c423/pkg/eval/builtin_fn_misc_test.go (about)

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