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 }