@@ -46,24 +46,29 @@ function testLoopRunsCanBeConsecutiveAndNested()
4646 {
4747 $ this ->expectOutputString ("123456 " );
4848 $ this ->start (function (Driver $ loop ) {
49- $ loop ->defer (function () {
50- echo 1 ;
49+ $ loop ->stop ();
50+ $ loop ->defer (function () use (&$ run ) {
51+ echo $ run = 1 ;
5152 });
5253 $ loop ->run ();
54+ if (!$ run ) {
55+ $ this ->fail ("A loop stop before a run must not impact that run " );
56+ }
5357 $ loop ->defer (function () use ($ loop ) {
5458 $ loop ->run ();
5559 echo 4 ;
5660 $ loop ->defer (function () use ($ loop ) {
5761 echo 6 ;
5862 $ loop ->stop ();
5963 $ loop ->defer (function () {
60- $ this ->fail ("A loop stopped at all levels must not execute further deferreds " );
64+ $ this ->fail ("A loop stopped at all levels must not execute further defers " );
6165 });
6266 });
6367 });
6468 $ loop ->defer (function () use ($ loop ) {
6569 echo 2 ;
6670 $ loop ->stop ();
71+ $ loop ->stop ();
6772 $ loop ->defer (function () use ($ loop ) {
6873 echo 5 ;
6974 });
@@ -92,7 +97,7 @@ function testWatcherUnrefRerefRunResult()
9297 $ invoked = true ;
9398 });
9499 $ loop ->unreference ($ watcher );
95- $ loop ->reference ($ watcher );
100+ $ loop ->unreference ($ watcher );
96101 $ loop ->reference ($ watcher );
97102 });
98103 $ this ->assertTrue ($ invoked );
@@ -195,9 +200,7 @@ function provideRegistrationArgs()
195200 return $ args ;
196201 }
197202
198- /**
199- * @dataProvider provideRegistrationArgs
200- */
203+ /** @dataProvider provideRegistrationArgs */
201204 function testDisableWithConsecutiveCancel ($ type , $ args )
202205 {
203206 if ($ type === "onSignal " ) {
@@ -214,9 +217,7 @@ function testDisableWithConsecutiveCancel($type, $args)
214217 });
215218 }
216219
217- /**
218- * @dataProvider provideRegistrationArgs
219- */
220+ /** @dataProvider provideRegistrationArgs */
220221 function testWatcherReferenceInfo ($ type , $ args )
221222 {
222223 if ($ type === "onSignal " ) {
@@ -273,8 +274,6 @@ function testWatcherReferenceInfo($type, $args)
273274 // unreference() should just increment unreferenced count
274275 $ watcherId2 = \call_user_func_array ($ func , $ args );
275276 $ loop ->unreference ($ watcherId2 );
276- $ loop ->unreference ($ watcherId2 );
277- $ loop ->unreference ($ watcherId2 );
278277 $ info = $ loop ->info ();
279278 $ expected = ["enabled " => 2 , "disabled " => 0 ];
280279 $ this ->assertSame ($ expected , $ info [$ type ]);
@@ -285,9 +284,7 @@ function testWatcherReferenceInfo($type, $args)
285284 $ loop ->cancel ($ watcherId2 );
286285 }
287286
288- /**
289- * @dataProvider provideRegistrationArgs
290- */
287+ /** @dataProvider provideRegistrationArgs */
291288 function testWatcherRegistrationAndCancellationInfo ($ type , $ args )
292289 {
293290 if ($ type === "onSignal " ) {
@@ -347,9 +344,7 @@ function testWatcherRegistrationAndCancellationInfo($type, $args)
347344 $ this ->assertSame ($ expected , $ info [$ type ]);
348345 }
349346
350- /**
351- * @dataProvider provideRegistrationArgs
352- */
347+ /** @dataProvider provideRegistrationArgs */
353348 function testNoMemoryLeak ($ type , $ args )
354349 {
355350 if ($ type === "onSignal " ) {
@@ -463,15 +458,144 @@ function testNoMemoryLeak($type, $args)
463458 });
464459 }
465460
466- /**
467- * @expectedException \LogicException
468- */
469- function testSuccessOnEnableNonexistentWatcher ()
461+ function testExecutionOrderGuarantees ()
462+ {
463+ $ this ->expectOutputString ("01 02 03 04 05 05 10 11 12 13 13 20 21 22 23 " );
464+ $ this ->start (function (Driver $ loop ) use (&$ ticks ) {
465+ $ f = function () use ($ loop ) {
466+ $ args = func_get_args ();
467+ return function ($ watcherId ) use ($ loop , &$ args ) {
468+ if (!$ args ) {
469+ $ this ->fail ("Watcher callback called too often " );
470+ }
471+ $ loop ->cancel ($ watcherId );
472+ echo array_shift ($ args ) . array_shift ($ args ), " " ;
473+ };
474+ };
475+ $ dep = function ($ i , $ fn ) use ($ loop , &$ max , &$ cur ) {
476+ $ max || $ max = new \SplObjectStorage ;
477+ $ cur || $ cur = new \SplObjectStorage ;
478+ $ max [$ fn ] = max (isset ($ max [$ fn ]) ? $ max [$ fn ] : 0 , $ i );
479+ $ cur [$ fn ] = 0 ;
480+ return function ($ watcherId ) use ($ loop , $ i , $ fn , &$ max , &$ cur ) {
481+ $ this ->assertSame ($ i , $ cur [$ fn ]);
482+ if ($ cur [$ fn ] == $ max [$ fn ]) {
483+ $ fn ($ watcherId );
484+ } else {
485+ $ loop ->cancel ($ watcherId );
486+ }
487+ $ cur [$ fn ] = $ cur [$ fn ] + 1 ;
488+ };
489+ };
490+
491+ $ loop ->onWritable (STDIN , $ dep (0 , $ writ = $ f (0 , 5 )));
492+ $ writ1 = $ loop ->onWritable (STDIN , $ dep (1 , $ writ ));
493+ $ writ2 = $ loop ->onWritable (STDIN , $ dep (3 , $ writ ));
494+
495+ $ loop ->delay ($ msDelay = 0 , $ dep (0 , $ del = $ f (0 , 5 )));
496+ $ del1 = $ loop ->delay ($ msDelay = 0 , $ dep (1 , $ del ));
497+ $ del2 = $ loop ->delay ($ msDelay = 0 , $ dep (3 , $ del ));
498+ $ del3 = $ loop ->delay ($ msDelay = 0 , $ f ());
499+ $ del4 = $ loop ->delay ($ msDelay = 0 , $ f (1 , 3 ));
500+ $ loop ->cancel ($ del3 );
501+ $ loop ->disable ($ del1 );
502+ $ loop ->disable ($ del2 );
503+
504+ $ writ3 = $ loop ->onWritable (STDIN , $ f ());
505+ $ loop ->cancel ($ writ3 );
506+ $ loop ->disable ($ writ1 );
507+ $ loop ->disable ($ writ2 );
508+ $ loop ->enable ($ writ1 );
509+ $ writ4 = $ loop ->onWritable (STDIN , $ f (1 , 3 ));
510+ $ loop ->onWritable (STDIN , $ dep (2 , $ writ ));
511+ $ loop ->enable ($ writ2 );
512+ $ loop ->disable ($ writ4 );
513+ $ loop ->defer (function () use ($ loop , $ writ4 ) {
514+ $ loop ->enable ($ writ4 );
515+ });
516+
517+ $ loop ->enable ($ del1 );
518+ $ loop ->delay ($ msDelay = 0 , $ dep (2 , $ del ));
519+ $ loop ->enable ($ del2 );
520+ $ loop ->disable ($ del4 );
521+ $ loop ->defer (function () use ($ loop , $ del4 ) {
522+ $ loop ->enable ($ del4 );
523+ });
524+
525+ $ loop ->delay ($ msDelay = 5 , $ f (2 , 0 ));
526+ $ loop ->repeat ($ msDelay = 5 , $ f (2 , 1 ));
527+ $ rep1 = $ loop ->repeat ($ msDelay = 5 , $ f (2 , 3 ));
528+ $ loop ->disable ($ rep1 );
529+ $ loop ->delay ($ msDelay = 5 , $ f (2 , 2 ));
530+ $ loop ->enable ($ rep1 );
531+
532+ $ loop ->defer ($ f (0 , 1 ));
533+ $ def1 = $ loop ->defer ($ f (0 , 3 ));
534+ $ def2 = $ loop ->defer ($ f (1 , 1 ));
535+ $ def3 = $ loop ->defer ($ f ());
536+ $ loop ->defer ($ f (0 , 2 ));
537+ $ loop ->disable ($ def1 );
538+ $ loop ->cancel ($ def3 );
539+ $ loop ->enable ($ def1 );
540+ $ loop ->defer (function () use ($ loop , $ def2 , $ del4 , $ f ) {
541+ $ tick = $ f (0 , 4 );
542+ $ tick ("invalid " );
543+ $ loop ->defer ($ f (1 , 0 ));
544+ $ loop ->enable ($ def2 );
545+ $ loop ->defer ($ f (1 , 2 ));
546+ });
547+ $ loop ->disable ($ def2 );
548+ });
549+ }
550+
551+ /** @depends testSignalCapability */
552+ function testSignalExecutionOrder ()
553+ {
554+ if (!\extension_loaded ("posix " )) {
555+ $ this ->markTestSkipped ("ext/posix required to test signal handlers " );
556+ }
557+
558+ $ this ->expectOutputString ("123456 " );
559+ $ this ->start (function (Driver $ loop ) {
560+ $ f = function ($ i ) use ($ loop ) {
561+ return function ($ watcherId ) use ($ loop , $ i ) {
562+ $ loop ->cancel ($ watcherId );
563+ echo $ i ;
564+ };
565+ };
566+
567+ $ loop ->defer ($ f (1 ));
568+ $ loop ->onSignal (SIGUSR1 , $ f (2 ));
569+ $ sig1 = $ loop ->onSignal (SIGUSR1 , $ f (4 ));
570+ $ sig2 = $ loop ->onSignal (SIGUSR1 , $ f (6 ));
571+ $ sig3 = $ loop ->onSignal (SIGUSR1 , $ f (" FAIL - MUST NOT BE CALLED " ));
572+ $ loop ->disable ($ sig1 );
573+ $ loop ->onSignal (SIGUSR1 , $ f (3 ));
574+ $ loop ->disable ($ sig2 );
575+ $ loop ->enable ($ sig1 );
576+ $ loop ->cancel ($ sig3 );
577+ $ loop ->onSignal (SIGUSR1 , $ f (5 ));
578+ $ loop ->defer (function () use ($ loop , $ sig2 ) {
579+ $ loop ->enable ($ sig2 );
580+ });
581+
582+ $ loop ->delay ($ msDelay = 1 , function () use ($ loop ) {
583+ \posix_kill (\getmypid (), \SIGUSR1 );
584+ $ loop ->delay ($ msDelay = 10 , function () use ($ loop ) {
585+ $ loop ->stop ();
586+ });
587+ });
588+ });
589+ }
590+
591+ /** @expectedException InvalidWatcherException */
592+ function testExceptionOnEnableNonexistentWatcher ()
470593 {
471594 $ this ->loop ->enable ("nonexistentWatcher " );
472595 }
473596
474- function testSuccessOnDisableNonexistentWatcher ()
597+ /** @expectedException InvalidWatcherException */
598+ function testExceptionOnDisableNonexistentWatcher ()
475599 {
476600 $ this ->loop ->disable ("nonexistentWatcher " );
477601 }
@@ -481,6 +605,78 @@ function testSuccessOnCancelNonexistentWatcher()
481605 $ this ->loop ->cancel ("nonexistentWatcher " );
482606 }
483607
608+ /** @expectedException InvalidWatcherException */
609+ function testExceptionOnReferenceNonexistentWatcher ()
610+ {
611+ $ this ->loop ->reference ("nonexistentWatcher " );
612+ }
613+
614+ /** @expectedException InvalidWatcherException */
615+ function testExceptionOnUnreferenceNonexistentWatcher ()
616+ {
617+ $ this ->loop ->unreference ("nonexistentWatcher " );
618+ }
619+
620+ /** @expectedException InvalidWatcherException */
621+ function testWatcherInvalidityOnDefer () {
622+ $ this ->start (function (Driver $ loop ) {
623+ $ loop ->defer (function ($ watcher ) use ($ loop ) {
624+ $ loop ->disable ($ watcher );
625+ });
626+ });
627+ }
628+
629+ /** @expectedException InvalidWatcherException */
630+ function testWatcherInvalidityOnDelay () {
631+ $ this ->start (function (Driver $ loop ) {
632+ $ loop ->delay ($ msDelay = 0 , function ($ watcher ) use ($ loop ) {
633+ $ loop ->disable ($ watcher );
634+ });
635+ });
636+ }
637+
638+ function testEventsNotExecutedInSameTickAsEnabled ()
639+ {
640+ $ this ->start (function (Driver $ loop ) {
641+ $ loop ->defer (function () use ($ loop ) {
642+ $ loop ->defer (function () use ($ loop , &$ diswatchers , &$ watchers ) {
643+ foreach ($ watchers as $ watcher ) {
644+ $ loop ->cancel ($ watcher );
645+ }
646+ foreach ($ diswatchers as $ watcher ) {
647+ $ loop ->disable ($ watcher );
648+ $ loop ->enable ($ watcher );
649+ }
650+ $ loop ->defer (function () use ($ loop , $ diswatchers ) {
651+ foreach ($ diswatchers as $ watcher ) {
652+ $ loop ->disable ($ watcher );
653+ }
654+ $ loop ->defer (function () use ($ loop , $ diswatchers ) {
655+ foreach ($ diswatchers as $ watcher ) {
656+ $ loop ->enable ($ watcher );
657+ }
658+ $ loop ->defer (function () use ($ loop , $ diswatchers ) {
659+ foreach ($ diswatchers as $ watcher ) {
660+ $ loop ->cancel ($ watcher );
661+ }
662+ });
663+ });
664+ });
665+ });
666+
667+ $ f = function () use ($ loop ) {
668+ $ watchers [] = $ loop ->defer ([$ this , "fail " ]);
669+ $ watchers [] = $ loop ->delay ($ msDelay = 0 , [$ this , "fail " ]);
670+ $ watchers [] = $ loop ->repeat ($ msDelay = 0 , [$ this , "fail " ]);
671+ $ watchers [] = $ loop ->onWritable (STDIN , [$ this , "fail " ]);
672+ return $ watchers ;
673+ };
674+ $ watchers = $ f ();
675+ $ diswatchers = $ f ();
676+ });
677+ });
678+ }
679+
484680 function testEnablingWatcherAllowsSubsequentInvocation ()
485681 {
486682 $ loop = $ this ->loop ;
@@ -687,9 +883,7 @@ function testLoopException()
687883 });
688884 }
689885
690- /**
691- * @depends testSignalCapability
692- */
886+ /** @depends testSignalCapability */
693887 function testOnSignalWatcher ()
694888 {
695889 if (!\extension_loaded ("posix " )) {
@@ -712,9 +906,7 @@ function testOnSignalWatcher()
712906 });
713907 }
714908
715- /**
716- * @depends testSignalCapability
717- */
909+ /** @depends testSignalCapability */
718910 function testInitiallyDisabledOnSignalWatcher ()
719911 {
720912 if (!\extension_loaded ("posix " )) {
@@ -793,9 +985,7 @@ function testInitiallyDisabledWriteWatcherIsTriggeredOnceEnabled()
793985 });
794986 }
795987
796- /**
797- * @expectedException \RuntimeException
798- */
988+ /** @expectedException \RuntimeException */
799989 function testStreamWatcherDoesntSwallowExceptions ()
800990 {
801991 $ this ->start (function (Driver $ loop ) {
@@ -874,4 +1064,39 @@ function testOptionalCallbackDataPassedOnInvocation()
8741064 $ this ->assertTrue ($ callbackData ->repeat );
8751065 $ this ->assertTrue ($ callbackData ->onWritable );
8761066 }
1067+
1068+ // implementations SHOULD use Interop\Async\Loop\Registry trait, but are not forced to, hence test it here again
1069+ function testRegistry () {
1070+ $ this ->assertNull ($ this ->loop ->fetchState ("foo " ));
1071+ $ this ->loop ->storeState ("foo " , NAN );
1072+ $ this ->assertTrue (is_nan ($ this ->loop ->fetchState ("foo " )));
1073+ $ this ->loop ->storeState ("foo " , "1 " );
1074+ $ this ->assertNull ($ this ->loop ->fetchState ("bar " ));
1075+ $ this ->loop ->storeState ("baz " , -0.0 );
1076+ // running must not affect state
1077+ $ this ->loop ->defer ([$ this ->loop , "stop " ]);
1078+ $ this ->loop ->run ();
1079+ $ this ->assertSame (-INF , @1 /$ this ->loop ->fetchState ("baz " ));
1080+ $ this ->assertSame ("1 " , $ this ->loop ->fetchState ("foo " ));
1081+ }
1082+
1083+ /** @dataProvider provideRegistryValues */
1084+ function testRegistryValues ($ val ) {
1085+ $ this ->loop ->storeState ("foo " , $ val );
1086+ $ this ->assertSame ($ val , $ this ->loop ->fetchState ("foo " ));
1087+ }
1088+
1089+ function provideRegistryValues () {
1090+ return [
1091+ ["string " ],
1092+ [0 ],
1093+ [PHP_INT_MIN ],
1094+ [-1.0 ],
1095+ [true ],
1096+ [false ],
1097+ [[]],
1098+ [null ],
1099+ [new \StdClass ],
1100+ ];
1101+ }
8771102}
0 commit comments