master

laravel/framework

Last updated at: 29/12/2023 09:25

Sleep.php

TLDR

The Sleep class in the provided file is responsible for simulating sleep operations in PHP. It allows you to delay the execution of code by a specified duration of time. The class provides methods for sleeping for a given duration in different units (e.g., seconds, minutes, milliseconds) and also allows for faking the sleep operation for testing purposes.

Methods

__construct($duration)

Constructor method. Initializes a new instance of the Sleep class with the specified duration.

for($duration)

Static method. Creates a new instance of the Sleep class with the specified duration.

until($timestamp)

Static method. Creates a new instance of the Sleep class that sleeps until the specified timestamp.

usleep($duration)

Static method. Creates a new instance of the Sleep class that sleeps for the specified number of microseconds.

sleep($duration)

Static method. Creates a new instance of the Sleep class that sleeps for the specified number of seconds.

minutes()

Sets the duration to sleep in minutes.

minute()

Alias for the minutes() method.

seconds()

Sets the duration to sleep in seconds.

second()

Alias for the seconds() method.

milliseconds()

Sets the duration to sleep in milliseconds.

millisecond()

Alias for the milliseconds() method.

microseconds()

Sets the duration to sleep in microseconds.

microsecond()

Alias for the microseconds() method.

and($duration)

Adds additional time to sleep for.

__destruct()

Destructor method. Executes the sleep operation and fakes it if the static fake() method has been called.

pullPending()

Internal method. Resolves the pending duration.

fake($value = true)

Static method. Configures all sleep operations to be faked or not.

assertSlept($expected, $times = 1)

Static method. Asserts that a given amount of sleeping occurred a specific number of times.

assertSleptTimes($expected)

Static method. Asserts that sleeping occurred a given number of times.

assertSequence($sequence)

Static method. Asserts that the given sleep sequence was encountered.

assertNeverSlept()

Static method. Asserts that no sleeping occurred.

assertInsomniac()

Static method. Asserts that no sleeping occurred.

shouldNotSleep()

Internal method. Indicates that the instance should not sleep.

when($condition)

Specifies that sleep should only occur when the given condition is true.

unless($condition)

Specifies that sleep should not occur when the given condition is true.

whenFakingSleep($callback)

Static method. Specifies a callback that should be invoked when faking sleep within a test.

Classes

The provided file does not define any additional classes.

<?php

namespace Illuminate\Support;

use Carbon\Carbon;
use Carbon\CarbonInterval;
use DateInterval;
use Illuminate\Support\Traits\Macroable;
use PHPUnit\Framework\Assert as PHPUnit;
use RuntimeException;

class Sleep
{
    use Macroable;

    /**
     * The fake sleep callbacks.
     *
     * @var array
     */
    public static $fakeSleepCallbacks = [];

    /**
     * The total duration to sleep.
     *
     * @var \Carbon\CarbonInterval
     */
    public $duration;

    /**
     * The pending duration to sleep.
     *
     * @var int|float|null
     */
    protected $pending = null;

    /**
     * Indicates that all sleeping should be faked.
     *
     * @var bool
     */
    protected static $fake = false;

    /**
     * The sequence of sleep durations encountered while faking.
     *
     * @var array<int, \Carbon\CarbonInterval>
     */
    protected static $sequence = [];

    /**
     * Indicates if the instance should sleep.
     *
     * @var bool
     */
    protected $shouldSleep = true;

    /**
     * Create a new class instance.
     *
     * @param  int|float|\DateInterval  $duration
     * @return void
     */
    public function __construct($duration)
    {
        $this->duration($duration);
    }

    /**
     * Sleep for the given duration.
     *
     * @param  \DateInterval|int|float  $duration
     * @return static
     */
    public static function for($duration)
    {
        return new static($duration);
    }

    /**
     * Sleep until the given timestamp.
     *
     * @param  \DateTimeInterface|int|float|numeric-string  $timestamp
     * @return static
     */
    public static function until($timestamp)
    {
        if (is_numeric($timestamp)) {
            $timestamp = Carbon::createFromTimestamp($timestamp);
        }

        return new static(Carbon::now()->diff($timestamp));
    }

    /**
     * Sleep for the given number of microseconds.
     *
     * @param  int  $duration
     * @return static
     */
    public static function usleep($duration)
    {
        return (new static($duration))->microseconds();
    }

    /**
     * Sleep for the given number of seconds.
     *
     * @param  int|float  $duration
     * @return static
     */
    public static function sleep($duration)
    {
        return (new static($duration))->seconds();
    }

    /**
     * Sleep for the given duration. Replaces any previously defined duration.
     *
     * @param  \DateInterval|int|float  $duration
     * @return $this
     */
    protected function duration($duration)
    {
        if (! $duration instanceof DateInterval) {
            $this->duration = CarbonInterval::microsecond(0);

            $this->pending = $duration;
        } else {
            $duration = CarbonInterval::instance($duration);

            if ($duration->totalMicroseconds < 0) {
                $duration = CarbonInterval::seconds(0);
            }

            $this->duration = $duration;
            $this->pending = null;
        }

        return $this;
    }

    /**
     * Sleep for the given number of minutes.
     *
     * @return $this
     */
    public function minutes()
    {
        $this->duration->add('minutes', $this->pullPending());

        return $this;
    }

    /**
     * Sleep for one minute.
     *
     * @return $this
     */
    public function minute()
    {
        return $this->minutes();
    }

    /**
     * Sleep for the given number of seconds.
     *
     * @return $this
     */
    public function seconds()
    {
        $this->duration->add('seconds', $this->pullPending());

        return $this;
    }

    /**
     * Sleep for one second.
     *
     * @return $this
     */
    public function second()
    {
        return $this->seconds();
    }

    /**
     * Sleep for the given number of milliseconds.
     *
     * @return $this
     */
    public function milliseconds()
    {
        $this->duration->add('milliseconds', $this->pullPending());

        return $this;
    }

    /**
     * Sleep for one millisecond.
     *
     * @return $this
     */
    public function millisecond()
    {
        return $this->milliseconds();
    }

    /**
     * Sleep for the given number of microseconds.
     *
     * @return $this
     */
    public function microseconds()
    {
        $this->duration->add('microseconds', $this->pullPending());

        return $this;
    }

    /**
     * Sleep for on microsecond.
     *
     * @return $this
     */
    public function microsecond()
    {
        return $this->microseconds();
    }

    /**
     * Add additional time to sleep for.
     *
     * @param  int|float  $duration
     * @return $this
     */
    public function and($duration)
    {
        $this->pending = $duration;

        return $this;
    }

    /**
     * Handle the object's destruction.
     *
     * @return void
     */
    public function __destruct()
    {
        if (! $this->shouldSleep) {
            return;
        }

        if ($this->pending !== null) {
            throw new RuntimeException('Unknown duration unit.');
        }

        if (static::$fake) {
            static::$sequence[] = $this->duration;

            foreach (static::$fakeSleepCallbacks as $callback) {
                $callback($this->duration);
            }

            return;
        }

        $remaining = $this->duration->copy();

        $seconds = (int) $remaining->totalSeconds;

        if ($seconds > 0) {
            sleep($seconds);

            $remaining = $remaining->subSeconds($seconds);
        }

        $microseconds = (int) $remaining->totalMicroseconds;

        if ($microseconds > 0) {
            usleep($microseconds);
        }
    }

    /**
     * Resolve the pending duration.
     *
     * @return int|float
     */
    protected function pullPending()
    {
        if ($this->pending === null) {
            $this->shouldNotSleep();

            throw new RuntimeException('No duration specified.');
        }

        if ($this->pending < 0) {
            $this->pending = 0;
        }

        return tap($this->pending, function () {
            $this->pending = null;
        });
    }

    /**
     * Stay awake and capture any attempts to sleep.
     *
     * @param  bool  $value
     * @return void
     */
    public static function fake($value = true)
    {
        static::$fake = $value;

        static::$sequence = [];
        static::$fakeSleepCallbacks = [];
    }

    /**
     * Assert a given amount of sleeping occurred a specific number of times.
     *
     * @param  \Closure  $expected
     * @param  int  $times
     * @return void
     */
    public static function assertSlept($expected, $times = 1)
    {
        $count = collect(static::$sequence)->filter($expected)->count();

        PHPUnit::assertSame(
            $times,
            $count,
            "The expected sleep was found [{$count}] times instead of [{$times}]."
        );
    }

    /**
     * Assert sleeping occurred a given number of times.
     *
     * @param  int  $expected
     * @return void
     */
    public static function assertSleptTimes($expected)
    {
        PHPUnit::assertSame($expected, $count = count(static::$sequence), "Expected [{$expected}] sleeps but found [{$count}].");
    }

    /**
     * Assert the given sleep sequence was encountered.
     *
     * @param  array  $sequence
     * @return void
     */
    public static function assertSequence($sequence)
    {
        static::assertSleptTimes(count($sequence));

        collect($sequence)
            ->zip(static::$sequence)
            ->eachSpread(function (?Sleep $expected, CarbonInterval $actual) {
                if ($expected === null) {
                    return;
                }

                PHPUnit::assertTrue(
                    $expected->shouldNotSleep()->duration->equalTo($actual),
                    vsprintf('Expected sleep duration of [%s] but actually slept for [%s].', [
                        $expected->duration->cascade()->forHumans([
                            'options' => 0,
                            'minimumUnit' => 'microsecond',
                        ]),
                        $actual->cascade()->forHumans([
                            'options' => 0,
                            'minimumUnit' => 'microsecond',
                        ]),
                    ])
                );
            });
    }

    /**
     * Assert that no sleeping occurred.
     *
     * @return void
     */
    public static function assertNeverSlept()
    {
        return static::assertSleptTimes(0);
    }

    /**
     * Assert that no sleeping occurred.
     *
     * @return void
     */
    public static function assertInsomniac()
    {
        if (static::$sequence === []) {
            PHPUnit::assertTrue(true);
        }

        foreach (static::$sequence as $duration) {
            PHPUnit::assertSame(0, $duration->totalMicroseconds, vsprintf('Unexpected sleep duration of [%s] found.', [
                $duration->cascade()->forHumans([
                    'options' => 0,
                    'minimumUnit' => 'microsecond',
                ]),
            ]));
        }
    }

    /**
     * Indicate that the instance should not sleep.
     *
     * @return $this
     */
    protected function shouldNotSleep()
    {
        $this->shouldSleep = false;

        return $this;
    }

    /**
     * Only sleep when the given condition is true.
     *
     * @param  (\Closure($this): bool)|bool  $condition
     * @return $this
     */
    public function when($condition)
    {
        $this->shouldSleep = (bool) value($condition, $this);

        return $this;
    }

    /**
     * Don't sleep when the given condition is true.
     *
     * @param  (\Closure($this): bool)|bool  $condition
     * @return $this
     */
    public function unless($condition)
    {
        return $this->when(! value($condition, $this));
    }

    /**
     * Specify a callback that should be invoked when faking sleep within a test.
     *
     * @param  callable  $callback
     * @return void
     */
    public static function whenFakingSleep($callback)
    {
        static::$fakeSleepCallbacks[] = $callback;
    }
}