Skip to content

Commit 102c398

Browse files
committed
#9: + fix coroutine tests
1 parent d50b73e commit 102c398

9 files changed

+70
-72
lines changed

coroutine.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,8 @@ METHOD(getException)
9696

9797
async_coroutine_t *coroutine = THIS_COROUTINE;
9898

99-
if (!ZEND_COROUTINE_IS_FINISHED(&coroutine->coroutine)) {
100-
async_throw_error("Cannot get exception of a running coroutine");
101-
RETURN_THROWS();
99+
if (false == ZEND_COROUTINE_IS_FINISHED(&coroutine->coroutine)) {
100+
RETURN_NULL();
102101
}
103102

104103
if (coroutine->coroutine.exception == NULL) {
@@ -220,7 +219,8 @@ METHOD(isCancelled)
220219
{
221220
ZEND_PARSE_PARAMETERS_NONE();
222221

223-
RETURN_BOOL(ZEND_COROUTINE_IS_CANCELLED(&THIS_COROUTINE->coroutine));
222+
RETURN_BOOL(ZEND_COROUTINE_IS_CANCELLED(&THIS_COROUTINE->coroutine)
223+
&& ZEND_COROUTINE_IS_FINISHED(&THIS_COROUTINE->coroutine));
224224
}
225225

226226
METHOD(isCancellationRequested)
@@ -229,9 +229,9 @@ METHOD(isCancellationRequested)
229229

230230
async_coroutine_t *coroutine = THIS_COROUTINE;
231231

232-
// TODO: Implement cancellation request tracking in waker
233-
// For now, return same as isCancelled
234-
RETURN_BOOL(ZEND_COROUTINE_IS_CANCELLED(&coroutine->coroutine));
232+
RETURN_BOOL((ZEND_COROUTINE_IS_CANCELLED(&coroutine->coroutine)
233+
&& !ZEND_COROUTINE_IS_FINISHED(&coroutine->coroutine))
234+
|| coroutine->deferred_cancellation != NULL);
235235
}
236236

237237
METHOD(isFinished)

tests/coroutine/004-coroutine_getException_running.phpt

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,12 @@ $coroutine = spawn(function() {
99
return "test";
1010
});
1111

12-
try {
13-
$coroutine->getException();
14-
echo "Should not reach here\n";
15-
} catch (Async\AsyncException $e) {
16-
echo "Caught: " . $e->getMessage() . "\n";
12+
if($coroutine->getException() === null) {
13+
echo "No exception\n";
14+
} else {
15+
echo "Exception: " . get_class($coroutine->getException()) . "\n";
1716
}
1817

1918
?>
2019
--EXPECT--
21-
Caught: Cannot get exception of a running coroutine
20+
No exception

tests/coroutine/028-coroutine_state_transitions.phpt

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Coroutine state transitions and edge cases
55

66
use function Async\spawn;
77
use function Async\suspend;
8+
use function Async\await;
89

910
echo "start\n";
1011

@@ -38,7 +39,8 @@ echo "suspended state - isFinished: " . ($running_coroutine->isFinished() ? "tru
3839

3940
try {
4041
$result = $running_coroutine->getResult();
41-
echo "getResult on suspended should fail\n";
42+
echo "getResult: ";
43+
var_dump($result);
4244
} catch (\Error $e) {
4345
echo "getResult on suspended failed: " . get_class($e) . "\n";
4446
} catch (Throwable $e) {
@@ -52,7 +54,12 @@ $exception_coroutine = spawn(function() {
5254
throw new \RuntimeException("Test exception");
5355
});
5456

55-
suspend(); // Let it start and suspend
57+
try {
58+
await($exception_coroutine);
59+
} catch (\RuntimeException $e) {
60+
} catch (Throwable $e) {
61+
echo "Unexpected exception: " . get_class($e) . ": " . $e->getMessage() . "\n";
62+
}
5663

5764
echo "before exception - getException: ";
5865
try {
@@ -98,14 +105,15 @@ start
98105
before suspend - isQueued: true
99106
before suspend - isStarted: false
100107
queued coroutine executing
101-
after start - isQueued: false
108+
after start - isQueued: true
102109
after start - isStarted: true
103110
after start - isSuspended: true
104111
running coroutine started
105112
suspended state - isFinished: false
106-
getResult on suspended failed: Error
113+
getResult: NULL
114+
running coroutine continuing
107115
exception coroutine started
108-
before exception - getException: Error
116+
before exception - getException: RuntimeException
109117
after exception - getException: RuntimeException: Test exception
110118
cancel request coroutine started
111119
before cancel request - isCancellationRequested: false

tests/coroutine/029-coroutine_deferred_cancellation_basic.phpt

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ Basic coroutine deferred cancellation with protected operation
66
use function Async\spawn;
77
use function Async\suspend;
88
use function Async\protect;
9+
use function Async\await;
910

1011
echo "start\n";
1112

@@ -38,12 +39,15 @@ suspend();
3839
echo "after protected completion - cancelled: " . ($protected_coroutine->isCancelled() ? "true" : "false") . "\n";
3940

4041
try {
41-
$result = $protected_coroutine->getResult();
42-
echo "protected result should not be available\n";
42+
await($protected_coroutine);
4343
} catch (\Async\CancellationException $e) {
44-
echo "deferred cancellation executed: " . $e->getMessage() . "\n";
4544
}
4645

46+
$result = $protected_coroutine->getResult();
47+
48+
echo "protected result: ";
49+
var_dump($result);
50+
4751
echo "end\n";
4852

4953
?>
@@ -52,9 +56,9 @@ start
5256
protected coroutine started
5357
inside protected operation
5458
cancelling protected coroutine
55-
protected coroutine cancelled: true
59+
protected coroutine cancelled: false
5660
cancellation requested: true
5761
protected operation completed
5862
after protected completion - cancelled: true
59-
deferred cancellation executed: Deferred cancellation
63+
protected result: NULL
6064
end

tests/coroutine/030-coroutine_deferred_cancellation_multiple.phpt

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ Multiple deferred cancellations with sequential protect blocks
66
use function Async\spawn;
77
use function Async\suspend;
88
use function Async\protect;
9+
use function Async\await;
910

1011
echo "start\n";
1112

@@ -35,13 +36,8 @@ suspend(); // Enter first protection
3536
$multi_protected->cancel(new \Async\CancellationException("Multi deferred"));
3637
echo "multi cancelled during first protection\n";
3738

38-
suspend(); // Complete first protection
39-
suspend(); // Enter second protection
40-
suspend(); // Complete second protection
41-
4239
try {
43-
$result = $multi_protected->getResult();
44-
echo "multi result should not be available\n";
40+
await($multi_protected);
4541
} catch (\Async\CancellationException $e) {
4642
echo "multi deferred cancellation: " . $e->getMessage() . "\n";
4743
}
@@ -55,9 +51,5 @@ multi protected started
5551
first protected operation
5652
multi cancelled during first protection
5753
first protected completed
58-
between protections
59-
second protected operation
60-
second protected completed
61-
all protections completed
6254
multi deferred cancellation: Multi deferred
6355
end

tests/coroutine/031-coroutine_deferred_cancellation_during_protection.phpt

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ Cancellation of coroutine during protected operation with exception handling
66
use function Async\spawn;
77
use function Async\suspend;
88
use function Async\protect;
9+
use function Async\await;
910

1011
echo "start\n";
1112

@@ -33,12 +34,8 @@ suspend(); // Enter protection
3334
// Cancel while protected
3435
$already_protected->cancel(new \Async\CancellationException("Cancel during protection"));
3536

36-
suspend(); // Still in protection
37-
suspend(); // Protection completes, cancellation should execute
38-
3937
try {
40-
$result = $already_protected->getResult();
41-
echo "should not get result\n";
38+
await($already_protected);
4239
} catch (\Async\CancellationException $e) {
4340
echo "protection cancellation: " . $e->getMessage() . "\n";
4441
}

tests/coroutine/032-coroutine_composite_exception.phpt

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,25 @@ CompositeException with multiple finally handlers
66
use function Async\spawn;
77
use function Async\suspend;
88
use function Async\currentCoroutine;
9+
use function Async\await;
910

1011
echo "start\n";
1112

12-
$composite_coroutine = spawn(function() {
13+
$scope = new \Async\Scope();
14+
$scope->setExceptionHandler(function($scope, $coroutine, $exception) {
15+
16+
if(!$exception instanceof \Async\CompositeException) {
17+
echo "caught exception: {$exception->getMessage()}\n";
18+
return;
19+
}
20+
21+
foreach ($exception->getExceptions() as $i => $error) {
22+
$type = get_class($error);
23+
echo "error {$i}: {$type}: {$error->getMessage()}\n";
24+
}
25+
});
26+
27+
$composite_coroutine = $scope->spawn(function() {
1328
echo "composite coroutine started\n";
1429

1530
$coroutine = \Async\currentCoroutine();
@@ -31,22 +46,13 @@ $composite_coroutine = spawn(function() {
3146
});
3247

3348
suspend();
34-
throw new \RuntimeException("Main coroutine error");
49+
throw new \RuntimeException("coroutine error");
3550
});
3651

37-
suspend(); // Let it start and suspend
38-
suspend(); // Let it throw
39-
4052
try {
41-
$result = $composite_coroutine->getResult();
42-
echo "should not get result\n";
43-
} catch (\Async\CompositeException $e) {
44-
echo "caught CompositeException with " . count($e->getErrors()) . " errors\n";
45-
foreach ($e->getErrors() as $index => $error) {
46-
echo "error $index: " . get_class($error) . ": " . $error->getMessage() . "\n";
47-
}
53+
await($composite_coroutine);
4854
} catch (Throwable $e) {
49-
echo "unexpected exception: " . get_class($e) . ": " . $e->getMessage() . "\n";
55+
echo "caught: {$e->getMessage()}\n";
5056
}
5157

5258
echo "end\n";
@@ -55,12 +61,11 @@ echo "end\n";
5561
--EXPECTF--
5662
start
5763
composite coroutine started
58-
finally 3 executing
59-
finally 2 executing
6064
finally 1 executing
61-
caught CompositeException with %d errors
62-
error %d: %s: %s
63-
error %d: %s: %s
64-
error %d: %s: %s
65-
error %d: %s: %s
65+
finally 2 executing
66+
finally 3 executing
67+
error 0: RuntimeException: Finally 1 error
68+
error 1: InvalidArgumentException: Finally 2 error
69+
error 2: LogicException: Finally 3 error
70+
caught: coroutine error
6671
end

tests/coroutine/034-coroutine_cancel_invalid_exception.phpt

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,20 +37,12 @@ try {
3737
// Valid cancellation
3838
$invalid_cancel_coroutine->cancel(new \Async\CancellationException("Valid cancellation"));
3939

40-
try {
41-
$result = $invalid_cancel_coroutine->getResult();
42-
echo "should not get cancelled result\n";
43-
} catch (\Async\CancellationException $e) {
44-
echo "valid cancellation: " . $e->getMessage() . "\n";
45-
}
46-
4740
echo "end\n";
4841

4942
?>
5043
--EXPECTF--
5144
start
5245
invalid cancel coroutine started
53-
cancel string TypeError: %s
54-
%sRuntimeException%s
55-
valid cancellation: Valid cancellation
46+
cancel string TypeError: %a
47+
cancel RuntimeException TypeError:%a
5648
end

tests/coroutine/035-coroutine_deep_recursion.phpt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@ Coroutine with deep recursion and stack limits
55

66
use function Async\spawn;
77
use function Async\suspend;
8+
use function Async\await;
89

910
echo "start\n";
1011

1112
$deep_recursion_coroutine = spawn(function() {
1213
echo "deep recursion coroutine started\n";
1314

14-
function deepRecursionTest($depth, $maxDepth = 100) {
15+
function deepRecursionTest($depth, $maxDepth = 1000) {
1516
if ($depth >= $maxDepth) {
1617
echo "reached max depth: $depth\n";
1718
return $depth;
@@ -28,7 +29,7 @@ $deep_recursion_coroutine = spawn(function() {
2829
return "recursion_result_$result";
2930
});
3031

31-
$result = $deep_recursion_coroutine->getResult();
32+
$result = await($deep_recursion_coroutine);
3233
echo "deep recursion result: $result\n";
3334

3435
echo "end\n";
@@ -37,6 +38,6 @@ echo "end\n";
3738
--EXPECTF--
3839
start
3940
deep recursion coroutine started
40-
reached max depth: 100
41-
deep recursion result: recursion_result_100
41+
reached max depth: 1000
42+
deep recursion result: recursion_result_1000
4243
end

0 commit comments

Comments
 (0)