1
1
<?php namespace lang \ast \unittest \emit ;
2
2
3
- use test \{Assert , Test , Values };
3
+ use lang \Error ;
4
+ use test \verify \Runtime ;
5
+ use test \{Assert , Expect , Test , Values };
4
6
5
7
/** @see https://wiki.php.net/rfc/pipe-operator-v3 */
6
8
class PipelinesTest extends EmittingTest {
@@ -98,6 +100,24 @@ public function run() {
98
100
Assert::equals ('test: OK ' , $ r );
99
101
}
100
102
103
+ #[Test, Expect(Error::class)]
104
+ public function pipe_to_throw () {
105
+ $ this ->run ('use lang\Error; class %T {
106
+ public function run() {
107
+ return "test" |> throw new Error("Test");
108
+ }
109
+ } ' );
110
+ }
111
+
112
+ #[Test, Expect(Error::class)]
113
+ public function pipe_to_missing () {
114
+ $ this ->run ('class %T {
115
+ public function run() {
116
+ return "test" |> "__missing";
117
+ }
118
+ } ' );
119
+ }
120
+
101
121
#[Test]
102
122
public function pipe_chain () {
103
123
$ r = $ this ->run ('class %T {
@@ -109,7 +129,7 @@ public function run() {
109
129
Assert::equals ('TEST ' , $ r );
110
130
}
111
131
112
- #[Test, Values([[['test ' ], 'TEST ' ], [[], null ]])]
132
+ #[Test, Values([[['test ' ], 'TEST ' ], [['' ], '' ], [[ ], null ]])]
113
133
public function nullsafe_pipe ($ input , $ expected ) {
114
134
$ r = $ this ->run ('class %T {
115
135
public function run($arg) {
@@ -120,7 +140,7 @@ public function run($arg) {
120
140
Assert::equals ($ expected , $ r );
121
141
}
122
142
123
- #[Test, Values([[null , null ], ['test ' , 'TEST ' ], [' test ' , 'TEST ' ]])]
143
+ #[Test, Values([[null , null ], ['' , '' ], [ ' test ' , 'TEST ' ], [' test ' , 'TEST ' ]])]
124
144
public function nullsafe_chain ($ input , $ expected ) {
125
145
$ r = $ this ->run ('class %T {
126
146
public function run($arg) {
@@ -132,7 +152,7 @@ public function run($arg) {
132
152
}
133
153
134
154
#[Test]
135
- public function precedence () {
155
+ public function concat_precedence () {
136
156
$ r = $ this ->run ('class %T {
137
157
public function run() {
138
158
return "te"."st" |> strtoupper(...);
@@ -142,6 +162,54 @@ public function run() {
142
162
Assert::equals ('TEST ' , $ r );
143
163
}
144
164
165
+ #[Test]
166
+ public function addition_precedence () {
167
+ $ r = $ this ->run ('class %T {
168
+ public function run() {
169
+ return 5 + 2 |> fn($i) => $i * 2;
170
+ }
171
+ } ' );
172
+
173
+ Assert::equals (14 , $ r );
174
+ }
175
+
176
+ #[Test]
177
+ public function comparison_precedence () {
178
+ $ r = $ this ->run ('class %T {
179
+ public function run() {
180
+ return 5 |> fn($i) => $i * 2 === 10;
181
+ }
182
+ } ' );
183
+
184
+ Assert::true ($ r );
185
+ }
186
+
187
+ #[Test, Values([[0 , 'even ' ], [1 , 'odd ' ], [2 , 'even ' ]])]
188
+ public function ternary_precedence ($ arg , $ expected ) {
189
+ $ r = $ this ->run ('class %T {
190
+ public function run($arg) {
191
+ return $arg |> fn($i) => $i % 2 ? "odd" : "even";
192
+ }
193
+ } ' , $ arg );
194
+
195
+ Assert::equals ($ expected , $ r );
196
+ }
197
+
198
+ #[Test, Values([[0 , 'root ' ], [1001 , 'test ' ], [1002 , '#unknown ' ]])]
199
+ public function coalesce_precedence ($ arg , $ expected ) {
200
+ $ r = $ this ->run ('class %T {
201
+ private $users= [0 => "root", 1001 => "test"];
202
+
203
+ private function user($id) { return $this->users[$id] ?? null; }
204
+
205
+ public function run($arg) {
206
+ return $arg |> $this->user(...) ?? "#unknown";
207
+ }
208
+ } ' , $ arg );
209
+
210
+ Assert::equals ($ expected , $ r );
211
+ }
212
+
145
213
#[Test]
146
214
public function rfc_example () {
147
215
$ r = $ this ->run ('class %T {
@@ -156,4 +224,94 @@ public function run() {
156
224
} ' );
157
225
Assert::equals (['H ' , 'E ' , 'L ' , 'L ' , ' ' , 'W ' , 'R ' , 'L ' , 'D ' ], array_values ($ r ));
158
226
}
227
+
228
+ #[Test, Expect(Error::class), Runtime(php: '>=8.5.0 ' )]
229
+ public function rejects_by_reference_functions () {
230
+ $ this ->run ('class %T {
231
+ private function modify(&$arg) { $arg++; }
232
+
233
+ public function run() {
234
+ $val= 1;
235
+ return $val |> $this->modify(...);
236
+ }
237
+ } ' );
238
+ }
239
+
240
+ #[Test]
241
+ public function accepts_prefer_by_reference_functions () {
242
+ $ r = $ this ->run ('class %T {
243
+ public function run() {
244
+ return ["hello", "world"] |> array_multisort(...);
245
+ }
246
+ } ' );
247
+
248
+ Assert::true ($ r );
249
+ }
250
+
251
+ #[Test]
252
+ public function execution_order () {
253
+ $ r = $ this ->run ('class %T {
254
+ public function run() {
255
+ $invoked= [];
256
+
257
+ $first= function() use(&$invoked) { $invoked[]= "first"; return 1; };
258
+ $second= function() use(&$invoked) { $invoked[]= "second"; return false; };
259
+ $skipped= function() use(&$invoked) { $invoked[]= "skipped"; return $in; };
260
+ $third= function($in) use(&$invoked) { $invoked[]= "third"; return $in; };
261
+ $capture= function($result) use(&$invoked) { $invoked[]= $result; };
262
+
263
+ $first() |> ($second() ? $skipped : $third) |> $capture;
264
+ return $invoked;
265
+ }
266
+ } ' );
267
+
268
+ Assert::equals (['first ' , 'second ' , 'third ' , 1 ], $ r );
269
+ }
270
+
271
+ #[Test]
272
+ public function interrupted_by_exception () {
273
+ $ r = $ this ->run ('use lang\Error; class %T {
274
+ public function run() {
275
+ $invoked= [];
276
+
277
+ $provide= function() use(&$invoked) { $invoked[]= "provide"; return 1; };
278
+ $transform= function($in) use(&$invoked) { $invoked[]= "transform"; return $in * 2; };
279
+ $throw= function() use(&$invoked) { $invoked[]= "throw"; throw new Error("Break"); };
280
+
281
+ try {
282
+ $provide() |> $transform |> $throw |> throw new Error("Unreachable");
283
+ } catch (Error $e) {
284
+ $invoked[]= $e->compoundMessage();
285
+ }
286
+ return $invoked;
287
+ }
288
+ } ' );
289
+
290
+ Assert::equals (['provide ' , 'transform ' , 'throw ' , 'Exception lang.Error (Break) ' ], $ r );
291
+ }
292
+
293
+ #[Test]
294
+ public function generators () {
295
+ $ r = $ this ->run ('class %T {
296
+ private function range($lo, $hi) {
297
+ for ($i= $lo; $i <= $hi; $i++) {
298
+ yield $i;
299
+ }
300
+ }
301
+
302
+ private function map($fn) {
303
+ return function($it) use($fn) {
304
+ foreach ($it as $element) {
305
+ yield $fn($element);
306
+ }
307
+ };
308
+ }
309
+
310
+ public function run() {
311
+ return $this->range(1, 3) |> $this->map(fn($e) => $e + 1) |> iterator_to_array(...);
312
+ }
313
+ } ' );
314
+
315
+ Assert::equals ([2 , 3 , 4 ], $ r );
316
+ }
159
317
}
0 commit comments