src.elv.sh@v0.21.0-dev.0.20240515223629-06979efb9a2a/pkg/eval/builtin_fn_flow_test.elvts (about) 1 //////////////// 2 # run-parallel # 3 //////////////// 4 5 ~> run-parallel { put lorem } { put ipsum } | order 6 ▶ ipsum 7 ▶ lorem 8 ~> run-parallel { } { fail foo } 9 Exception: foo 10 [tty]:1:20-28: run-parallel { } { fail foo } 11 [tty]:1:1-29: run-parallel { } { fail foo } 12 13 //////// 14 # each # 15 //////// 16 17 ~> put 1 233 | each $put~ 18 ▶ 1 19 ▶ 233 20 ~> echo "1\n233" | each $put~ 21 ▶ 1 22 ▶ 233 23 ~> echo "1\r\n233" | each $put~ 24 ▶ 1 25 ▶ 233 26 ~> each $put~ [1 233] 27 ▶ 1 28 ▶ 233 29 ~> range 10 | each {|x| if (== $x 4) { break }; put $x } 30 ▶ (num 0) 31 ▶ (num 1) 32 ▶ (num 2) 33 ▶ (num 3) 34 ~> range 10 | each {|x| if (== $x 4) { continue }; put $x } 35 ▶ (num 0) 36 ▶ (num 1) 37 ▶ (num 2) 38 ▶ (num 3) 39 ▶ (num 5) 40 ▶ (num 6) 41 ▶ (num 7) 42 ▶ (num 8) 43 ▶ (num 9) 44 ~> range 10 | each {|x| if (== $x 4) { fail haha }; put $x } 45 ▶ (num 0) 46 ▶ (num 1) 47 ▶ (num 2) 48 ▶ (num 3) 49 Exception: haha 50 [tty]:1:37-46: range 10 | each {|x| if (== $x 4) { fail haha }; put $x } 51 [tty]:1:12-57: range 10 | each {|x| if (== $x 4) { fail haha }; put $x } 52 53 // TODO: Test that "each" does not close the stdin. 54 55 ///////// 56 # peach # 57 ///////// 58 59 ~> range 5 | peach {|x| * 2 $x } | order 60 ▶ (num 0) 61 ▶ (num 2) 62 ▶ (num 4) 63 ▶ (num 6) 64 ▶ (num 8) 65 // continue 66 ~> range 5 | peach {|x| if (== $x 2) { continue }; * 2 $x } | order 67 ▶ (num 0) 68 ▶ (num 2) 69 ▶ (num 6) 70 ▶ (num 8) 71 72 ## processing order is non-deterministic ## 73 // Test that inputs are not necessarily processed in order. 74 // 75 // Most of the time this effect can be observed without the need of any jitter, 76 // but if the system only has one CPU core to execute goroutines (which can 77 // happen even when GOMAXPROCS > 1), the scheduling of goroutines can become 78 // deterministic. The random jitter fixes that by forcing goroutines to yield 79 // the thread and allow other goroutines to execute. 80 ~> var @in = (range 100) 81 while $true { 82 var @out = (all $in | peach {|x| sleep (* (rand) 0.01); put $x }) 83 if (not-eq $in $out) { 84 put $true 85 break 86 } 87 } 88 ▶ $true 89 90 ## exception propagation ## 91 ~> peach {|x| fail $x } [a] 92 Exception: a 93 [tty]:1:12-19: peach {|x| fail $x } [a] 94 [tty]:1:1-24: peach {|x| fail $x } [a] 95 96 ## break ## 97 // It is technically possible for break to only take effect after the whole 98 // sequence has been consumed, but that doesn't seem to ever happen in practice. 99 ~> range 1 101 | 100 peach {|x| if (== 50 $x) { break } else { put $x } } | 101 < (+ (all)) (+ (range 1 101)) 102 ▶ $true 103 104 ## parallelism ## 105 106 //test-time-scale-in-global 107 108 // Test the parallelism of peach by observing its run time relative to the run 109 // time of the function. Since the exact run time is subject to scheduling 110 // differences, benchmark it multiple times and use the fastest run time. 111 112 // Unlimited workers: when scheduling allows, no two function runs are serial, 113 // so the best run time should be between t and 2t, regardless of input size. 114 ~> var t = (* 0.005 $test-time-scale) 115 var best-run = (benchmark &min-runs=5 &min-time=0 { 116 range 6 | peach {|_| sleep $t } 117 } &on-end={|metrics| put $metrics[min] }) 118 < $t $best-run (* 2 $t) 119 ▶ $true 120 // 2 workers: when scheduling allows, at least two function runs are parallel. 121 // On the other hand, No more than two functions are parallel. Best run time 122 // should be between (ceil(n/2) * t) and n*t, where n is the input size. 123 ~> var t = (* 0.005 $test-time-scale) 124 var best-run = (benchmark &min-runs=5 &min-time=0 { 125 range 6 | peach &num-workers=2 {|_| sleep $t } 126 } &on-end={|metrics| put $metrics[min] }) 127 < (* 3 $t) $best-run (* 6 $t) 128 ▶ $true 129 130 ## invalid &num-workers ## 131 ~> peach &num-workers=0 {|x| * 2 $x } 132 Exception: bad value: peach &num-workers must be exact positive integer or +inf, but is 0 133 [tty]:1:1-34: peach &num-workers=0 {|x| * 2 $x } 134 ~> peach &num-workers=-2 {|x| * 2 $x } 135 Exception: bad value: peach &num-workers must be exact positive integer or +inf, but is -2 136 [tty]:1:1-35: peach &num-workers=-2 {|x| * 2 $x } 137 138 //////// 139 # fail # 140 //////// 141 142 ~> fail haha 143 Exception: haha 144 [tty]:1:1-9: fail haha 145 ~> fn f { fail haha } 146 fail ?(f) 147 Exception: haha 148 [tty]:1:8-17: fn f { fail haha } 149 [tty]:2:8-8: fail ?(f) 150 ~> fail [] 151 Exception: [] 152 [tty]:1:1-7: fail [] 153 ~> put ?(fail 1)[reason][type] 154 ▶ fail 155 ~> put ?(fail 1)[reason][content] 156 ▶ 1 157 158 ////////// 159 # return # 160 ////////// 161 162 ~> return 163 Exception: return 164 [tty]:1:1-6: return 165 166 // Use of return inside fn is tested alongside fn in builtin_special_test.elvts. 167 168 ///////// 169 # defer # 170 ///////// 171 172 ~> { defer { put a }; put b } 173 ▶ b 174 ▶ a 175 ~> { defer { put a }; fail bad } 176 ▶ a 177 Exception: bad 178 [tty]:1:20-28: { defer { put a }; fail bad } 179 [tty]:1:1-29: { defer { put a }; fail bad } 180 ~> defer { } 181 Exception: defer must be called from within a closure 182 [tty]:1:1-9: defer { } 183 ~> { defer { fail foo } } 184 Exception: foo 185 [tty]:1:11-19: { defer { fail foo } } 186 [tty]:1:1-22: { defer { fail foo } } 187 ~> { defer {|x| } } 188 Exception: arity mismatch: arguments must be 1 value, but is 0 values 189 [tty]:1:3-15: { defer {|x| } } 190 [tty]:1:1-16: { defer {|x| } }