1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
|
<?php
declare(strict_types=1);
namespace malkusch\lock\Tests\util;
use malkusch\lock\exception\TimeoutException;
use malkusch\lock\util\Loop;
use phpmock\environment\SleepEnvironmentBuilder;
use phpmock\MockEnabledException;
use phpmock\phpunit\PHPMock;
use PHPUnit\Framework\Attributes\DoesNotPerformAssertions;
use PHPUnit\Framework\TestCase;
class LoopTest extends TestCase
{
use PHPMock;
#[\Override]
protected function setUp(): void
{
parent::setUp();
$sleepBuilder = new SleepEnvironmentBuilder();
$sleepBuilder->addNamespace(__NAMESPACE__);
$sleepBuilder->addNamespace('malkusch\lock\util');
$sleep = $sleepBuilder->build();
try {
$sleep->enable();
$this->registerForTearDown($sleep);
} catch (MockEnabledException $e) {
// workaround for burn testing
\assert($e->getMessage() === 'microtime is already enabled.Call disable() on the existing mock.');
}
}
/**
* Test an invalid timeout.
*/
public function testInvalidTimeout(): void
{
$this->expectException(\LengthException::class);
new Loop(0);
}
/**
* Tests execution within the timeout.
*
* @doesNotPerformAssertions
*/
#[DoesNotPerformAssertions]
public function testExecutionWithinTimeout(): void
{
$loop = new Loop(0.5);
$loop->execute(static function () use ($loop): void {
usleep(499 * 1000);
$loop->end();
});
}
/**
* Tests execution within the timeout without calling end().
*/
public function testExecutionWithinTimeoutWithoutExplicitEnd(): void
{
$this->expectException(TimeoutException::class);
$this->expectExceptionMessage('Timeout of 0.5 seconds exceeded');
$loop = new Loop(0.5);
$loop->execute(static function (): void {
usleep(10 * 1000);
});
}
/**
* Tests exceeding the execution timeout.
*
* @doesNotPerformAssertions
*/
#[DoesNotPerformAssertions]
public function testExceedTimeoutIsAcceptableIfEndWasCalled(): void
{
$loop = new Loop(0.5);
$loop->execute(static function () use ($loop): void {
usleep(501 * 1000);
$loop->end();
});
}
/**
* Tests exceeding the execution timeout without calling end().
*/
public function testExceedTimeoutWithoutExplicitEnd(): void
{
$this->expectException(TimeoutException::class);
$this->expectExceptionMessage('Timeout of 0.5 seconds exceeded');
$loop = new Loop(0.5);
$loop->execute(static function (): void {
usleep(501 * 1000);
});
}
/**
* Tests that an exception would stop any further iteration.
*/
public function testExceptionStopsIteration(): void
{
$this->expectException(\DomainException::class);
$loop = new Loop();
$loop->execute(static function () {
throw new \DomainException();
});
}
/**
* Tests end() will stop the iteration and return the result.
*/
public function testEnd(): void
{
$i = 0;
$loop = new Loop();
$loop->execute(static function () use ($loop, &$i) {
++$i;
$loop->end();
});
self::assertSame(1, $i);
}
/**
* Tests that the code is executed more times.
*/
public function testIteration(): void
{
$i = 0;
$loop = new Loop();
$loop->execute(static function () use ($loop, &$i): void {
++$i;
if ($i > 1) {
$loop->end();
}
});
self::assertSame(2, $i);
}
}
|