github.com/markusbkk/elvish@v0.0.0-20231204143114-91dc52438621/pkg/eval/builtin_fn_flow_test.go (about)

     1  package eval_test
     2  
     3  import (
     4  	"testing"
     5  
     6  	. "github.com/markusbkk/elvish/pkg/eval"
     7  
     8  	"github.com/markusbkk/elvish/pkg/eval/errs"
     9  	. "github.com/markusbkk/elvish/pkg/eval/evaltest"
    10  	"github.com/markusbkk/elvish/pkg/eval/vals"
    11  )
    12  
    13  func TestRunParallel(t *testing.T) {
    14  	Test(t,
    15  		That(`run-parallel { put lorem } { echo ipsum }`).
    16  			Puts("lorem").Prints("ipsum\n"),
    17  		That(`run-parallel { } { fail foo }`).Throws(FailError{"foo"}),
    18  	)
    19  }
    20  
    21  func TestEach(t *testing.T) {
    22  	Test(t,
    23  		That(`put 1 233 | each $put~`).Puts("1", "233"),
    24  		That(`echo "1\n233" | each $put~`).Puts("1", "233"),
    25  		That(`echo "1\r\n233" | each $put~`).Puts("1", "233"),
    26  		That(`each $put~ [1 233]`).Puts("1", "233"),
    27  		That(`range 10 | each {|x| if (== $x 4) { break }; put $x }`).
    28  			Puts(0, 1, 2, 3),
    29  		That(`range 10 | each {|x| if (== $x 4) { continue }; put $x }`).
    30  			Puts(0, 1, 2, 3, 5, 6, 7, 8, 9),
    31  		That(`range 10 | each {|x| if (== $x 4) { fail haha }; put $x }`).
    32  			Puts(0, 1, 2, 3).Throws(FailError{"haha"}),
    33  		// TODO(xiaq): Test that "each" does not close the stdin.
    34  	)
    35  }
    36  
    37  func TestPeach(t *testing.T) {
    38  	// Testing the `peach` builtin is a challenge since, by definition, the order of execution is
    39  	// undefined.
    40  	Test(t,
    41  		// Verify the output has the expected values when sorted.
    42  		That(`range 5 | peach {|x| * 2 $x } | order`).Puts(0, 2, 4, 6, 8),
    43  
    44  		// Handling of "continue".
    45  		That(`range 5 | peach {|x| if (== $x 2) { continue }; * 2 $x } | order`).
    46  			Puts(0, 2, 6, 8),
    47  
    48  		// Test that the order of output does not necessarily match the order of
    49  		// input.
    50  		//
    51  		// Most of the time this effect can be observed without the need of any
    52  		// jitter, but if the system only has one CPU core to execute goroutines
    53  		// (which can happen even when GOMAXPROCS > 1), the scheduling of
    54  		// goroutines can become deterministic. The random jitter fixes that by
    55  		// forcing goroutines to yield the thread and allow other goroutines to
    56  		// execute.
    57  		That(`
    58  			var @in = (range 100)
    59  			while $true {
    60  				var @out = (all $in | peach {|x| sleep (* (rand) 0.01); put $x })
    61  				if (not-eq $in $out) {
    62  					put $true
    63  					break
    64  				}
    65  			}
    66  		`).Puts(true),
    67  		// Verify that exceptions are propagated.
    68  		That(`peach {|x| fail $x } [a]`).
    69  			Throws(FailError{"a"}, "fail $x ", "peach {|x| fail $x } [a]"),
    70  		// Verify that `break` works by terminating the `peach` before the entire sequence is
    71  		// consumed.
    72  		That(`
    73  			var tot = 0
    74  			range 1 101 |
    75  				peach {|x| if (== 50 $x) { break } else { put $x } } |
    76  				< (+ (all)) (+ (range 1 101))
    77  		`).Puts(true),
    78  	)
    79  }
    80  
    81  func TestFail(t *testing.T) {
    82  	Test(t,
    83  		That("fail haha").Throws(FailError{"haha"}, "fail haha"),
    84  		That("fn f { fail haha }", "fail ?(f)").Throws(
    85  			FailError{"haha"}, "fail haha ", "f"),
    86  		That("fail []").Throws(
    87  			FailError{vals.EmptyList}, "fail []"),
    88  		That("put ?(fail 1)[reason][type]").Puts("fail"),
    89  		That("put ?(fail 1)[reason][content]").Puts("1"),
    90  	)
    91  }
    92  
    93  func TestReturn(t *testing.T) {
    94  	Test(t,
    95  		That("return").Throws(Return),
    96  		// Use of return inside fn is tested in TestFn
    97  	)
    98  }
    99  
   100  func TestDefer(t *testing.T) {
   101  	Test(t,
   102  		That("{ defer { put a }; put b }").Puts("b", "a"),
   103  		That("defer { }").
   104  			Throws(ErrorWithMessage("defer must be called from within a closure")),
   105  		That("{ defer { fail foo } }").
   106  			Throws(FailError{"foo"}, "fail foo ", "{ defer { fail foo } }"),
   107  		That("{ defer {|x| } }").Throws(
   108  			errs.ArityMismatch{What: "arguments",
   109  				ValidLow: 1, ValidHigh: 1, Actual: 0},
   110  			"defer {|x| } ", "{ defer {|x| } }"),
   111  	)
   112  }