elvish/pkg/eval/builtin_fn_flow_test.elvts
2024-01-30 20:21:39 +00:00

191 lines
4.9 KiB
Plaintext

////////////////
# run-parallel #
////////////////
~> run-parallel { put lorem } { put ipsum } | order
▶ ipsum
▶ lorem
~> run-parallel { } { fail foo }
Exception: foo
[tty]:1:20-28: run-parallel { } { fail foo }
[tty]:1:1-29: run-parallel { } { fail foo }
////////
# each #
////////
~> put 1 233 | each $put~
▶ 1
▶ 233
~> echo "1\n233" | each $put~
▶ 1
▶ 233
~> echo "1\r\n233" | each $put~
▶ 1
▶ 233
~> each $put~ [1 233]
▶ 1
▶ 233
~> range 10 | each {|x| if (== $x 4) { break }; put $x }
▶ (num 0)
▶ (num 1)
▶ (num 2)
▶ (num 3)
~> range 10 | each {|x| if (== $x 4) { continue }; put $x }
▶ (num 0)
▶ (num 1)
▶ (num 2)
▶ (num 3)
▶ (num 5)
▶ (num 6)
▶ (num 7)
▶ (num 8)
▶ (num 9)
~> range 10 | each {|x| if (== $x 4) { fail haha }; put $x }
▶ (num 0)
▶ (num 1)
▶ (num 2)
▶ (num 3)
Exception: haha
[tty]:1:37-46: range 10 | each {|x| if (== $x 4) { fail haha }; put $x }
[tty]:1:12-57: range 10 | each {|x| if (== $x 4) { fail haha }; put $x }
// TODO: Test that "each" does not close the stdin.
/////////
# peach #
/////////
~> range 5 | peach {|x| * 2 $x } | order
▶ (num 0)
▶ (num 2)
▶ (num 4)
▶ (num 6)
▶ (num 8)
// continue
~> range 5 | peach {|x| if (== $x 2) { continue }; * 2 $x } | order
▶ (num 0)
▶ (num 2)
▶ (num 6)
▶ (num 8)
## processing order is non-deterministic ##
// Test that inputs are not necessarily processed in order.
//
// Most of the time this effect can be observed without the need of any jitter,
// but if the system only has one CPU core to execute goroutines (which can
// happen even when GOMAXPROCS > 1), the scheduling of goroutines can become
// deterministic. The random jitter fixes that by forcing goroutines to yield
// the thread and allow other goroutines to execute.
~> var @in = (range 100)
while $true {
var @out = (all $in | peach {|x| sleep (* (rand) 0.01); put $x })
if (not-eq $in $out) {
put $true
break
}
}
▶ $true
## exception propagation ##
~> peach {|x| fail $x } [a]
Exception: a
[tty]:1:12-19: peach {|x| fail $x } [a]
[tty]:1:1-24: peach {|x| fail $x } [a]
## break ##
// It is technically possible for break to only take effect after the whole
// sequence has been consumed, but that doesn't seem to ever happen in practice.
~> range 1 101 |
peach {|x| if (== 50 $x) { break } else { put $x } } |
< (+ (all)) (+ (range 1 101))
▶ $true
## parallelism ##
//test-time-scale-in-global
// Test the parallelism of peach by observing its run time relative to the run
// time of the function. Since the exact run time is subject to scheduling
// differences, benchmark it multiple times and use the fastest run time.
// Unlimited workers: when scheduling allows, no two function runs are serial,
// so the best run time should be between t and 2t, regardless of input size.
~> var t = (* 0.005 $test-time-scale)
var best-run = (benchmark &min-runs=5 &min-time=0 {
range 6 | peach {|_| sleep $t }
} &on-end={|metrics| put $metrics[min] })
< $t $best-run (* 2 $t)
▶ $true
// 2 workers: when scheduling allows, at least two function runs are parallel.
// On the other hand, No more than two functions are parallel. Best run time
// should be between (ceil(n/2) * t) and n*t, where n is the input size.
~> var t = (* 0.005 $test-time-scale)
var best-run = (benchmark &min-runs=5 &min-time=0 {
range 6 | peach &num-workers=2 {|_| sleep $t }
} &on-end={|metrics| put $metrics[min] })
< (* 3 $t) $best-run (* 6 $t)
▶ $true
## invalid &num-workers ##
~> peach &num-workers=0 {|x| * 2 $x }
Exception: bad value: peach &num-workers must be exact positive integer or +inf, but is 0
[tty]:1:1-34: peach &num-workers=0 {|x| * 2 $x }
~> peach &num-workers=-2 {|x| * 2 $x }
Exception: bad value: peach &num-workers must be exact positive integer or +inf, but is -2
[tty]:1:1-35: peach &num-workers=-2 {|x| * 2 $x }
////////
# fail #
////////
~> fail haha
Exception: haha
[tty]:1:1-9: fail haha
~> fn f { fail haha }
fail ?(f)
Exception: haha
[tty]:1:8-17: fn f { fail haha }
[tty]:2:8-8: fail ?(f)
~> fail []
Exception: []
[tty]:1:1-7: fail []
~> put ?(fail 1)[reason][type]
▶ fail
~> put ?(fail 1)[reason][content]
▶ 1
//////////
# return #
//////////
~> return
Exception: return
[tty]:1:1-6: return
// Use of return inside fn is tested alongside fn in builtin_special_test.elvts.
/////////
# defer #
/////////
~> { defer { put a }; put b }
▶ b
▶ a
~> { defer { put a }; fail bad }
▶ a
Exception: bad
[tty]:1:20-28: { defer { put a }; fail bad }
[tty]:1:1-29: { defer { put a }; fail bad }
~> defer { }
Exception: defer must be called from within a closure
[tty]:1:1-9: defer { }
~> { defer { fail foo } }
Exception: foo
[tty]:1:11-19: { defer { fail foo } }
[tty]:1:1-22: { defer { fail foo } }
~> { defer {|x| } }
Exception: arity mismatch: arguments must be 1 value, but is 0 values
[tty]:1:3-15: { defer {|x| } }
[tty]:1:1-16: { defer {|x| } }