master

laravel/framework

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

Factory.php

TLDR

This file contains the implementation of the Factory class in the Illuminate\Process namespace. The class provides methods for creating, recording, and faking process instances for testing purposes.

Methods

result

Create a new fake process response for testing purposes.

describe

Begin describing a fake process lifecycle.

sequence

Begin describing a fake process sequence.

fake

Indicate that the process factory should fake processes.

isRecording

Determine if the process factory has fake process handlers and is recording processes.

recordIfRecording

Record the given process if processes should be recorded.

record

Record the given process.

preventStrayProcesses

Indicate that an exception should be thrown if any process is not faked.

preventingStrayProcesses

Determine if stray processes are being prevented.

assertRan

Assert that a process was recorded matching a given truth test.

assertRanTimes

Assert that a process was recorded a given number of times matching a given truth test.

assertNotRan

Assert that a process was not recorded matching a given truth test.

assertDidntRun

Assert that a process was not recorded matching a given truth test.

assertNothingRan

Assert that no processes were recorded.

pool

Start defining a pool of processes.

pipe

Start defining a series of piped processes.

concurrently

Run a pool of processes and wait for them to finish executing.

newPendingProcess

Create a new pending process associated with this factory.

__call

Dynamically proxy methods to a new pending process instance.

Classes

<?php

namespace Illuminate\Process;

use Closure;
use Illuminate\Contracts\Process\ProcessResult as ProcessResultContract;
use Illuminate\Support\Traits\Macroable;
use PHPUnit\Framework\Assert as PHPUnit;

class Factory
{
    use Macroable {
        __call as macroCall;
    }

    /**
     * Indicates if the process factory has faked process handlers.
     *
     * @var bool
     */
    protected $recording = false;

    /**
     * All of the recorded processes.
     *
     * @var array
     */
    protected $recorded = [];

    /**
     * The registered fake handler callbacks.
     *
     * @var array
     */
    protected $fakeHandlers = [];

    /**
     * Indicates that an exception should be thrown if any process is not faked.
     *
     * @var bool
     */
    protected $preventStrayProcesses = false;

    /**
     * Create a new fake process response for testing purposes.
     *
     * @param  array|string  $output
     * @param  array|string  $errorOutput
     * @param  int  $exitCode
     * @return \Illuminate\Process\FakeProcessResult
     */
    public function result(array|string $output = '', array|string $errorOutput = '', int $exitCode = 0)
    {
        return new FakeProcessResult(
            output: $output,
            errorOutput: $errorOutput,
            exitCode: $exitCode,
        );
    }

    /**
     * Begin describing a fake process lifecycle.
     *
     * @return \Illuminate\Process\FakeProcessDescription
     */
    public function describe()
    {
        return new FakeProcessDescription;
    }

    /**
     * Begin describing a fake process sequence.
     *
     * @param  array  $processes
     * @return \Illuminate\Process\FakeProcessSequence
     */
    public function sequence(array $processes = [])
    {
        return new FakeProcessSequence($processes);
    }

    /**
     * Indicate that the process factory should fake processes.
     *
     * @param  \Closure|array|null  $callback
     * @return $this
     */
    public function fake(Closure|array $callback = null)
    {
        $this->recording = true;

        if (is_null($callback)) {
            $this->fakeHandlers = ['*' => fn () => new FakeProcessResult];

            return $this;
        }

        if ($callback instanceof Closure) {
            $this->fakeHandlers = ['*' => $callback];

            return $this;
        }

        foreach ($callback as $command => $handler) {
            $this->fakeHandlers[is_numeric($command) ? '*' : $command] = $handler instanceof Closure
                    ? $handler
                    : fn () => $handler;
        }

        return $this;
    }

    /**
     * Determine if the process factory has fake process handlers and is recording processes.
     *
     * @return bool
     */
    public function isRecording()
    {
        return $this->recording;
    }

    /**
     * Record the given process if processes should be recorded.
     *
     * @param  \Illuminate\Process\PendingProcess  $process
     * @param  \Illuminate\Contracts\Process\ProcessResult  $result
     * @return $this
     */
    public function recordIfRecording(PendingProcess $process, ProcessResultContract $result)
    {
        if ($this->isRecording()) {
            $this->record($process, $result);
        }

        return $this;
    }

    /**
     * Record the given process.
     *
     * @param  \Illuminate\Process\PendingProcess  $process
     * @param  \Illuminate\Contracts\Process\ProcessResult  $result
     * @return $this
     */
    public function record(PendingProcess $process, ProcessResultContract $result)
    {
        $this->recorded[] = [$process, $result];

        return $this;
    }

    /**
     * Indicate that an exception should be thrown if any process is not faked.
     *
     * @param  bool  $prevent
     * @return $this
     */
    public function preventStrayProcesses(bool $prevent = true)
    {
        $this->preventStrayProcesses = $prevent;

        return $this;
    }

    /**
     * Determine if stray processes are being prevented.
     *
     * @return bool
     */
    public function preventingStrayProcesses()
    {
        return $this->preventStrayProcesses;
    }

    /**
     * Assert that a process was recorded matching a given truth test.
     *
     * @param  \Closure|string  $callback
     * @return $this
     */
    public function assertRan(Closure|string $callback)
    {
        $callback = is_string($callback) ? fn ($process) => $process->command === $callback : $callback;

        PHPUnit::assertTrue(
            collect($this->recorded)->filter(function ($pair) use ($callback) {
                return $callback($pair[0], $pair[1]);
            })->count() > 0,
            'An expected process was not invoked.'
        );

        return $this;
    }

    /**
     * Assert that a process was recorded a given number of times matching a given truth test.
     *
     * @param  \Closure|string  $callback
     * @param  int  $times
     * @return $this
     */
    public function assertRanTimes(Closure|string $callback, int $times = 1)
    {
        $callback = is_string($callback) ? fn ($process) => $process->command === $callback : $callback;

        $count = collect($this->recorded)->filter(function ($pair) use ($callback) {
            return $callback($pair[0], $pair[1]);
        })->count();

        PHPUnit::assertSame(
            $times, $count,
            "An expected process ran {$count} times instead of {$times} times."
        );

        return $this;
    }

    /**
     * Assert that a process was not recorded matching a given truth test.
     *
     * @param  \Closure|string  $callback
     * @return $this
     */
    public function assertNotRan(Closure|string $callback)
    {
        $callback = is_string($callback) ? fn ($process) => $process->command === $callback : $callback;

        PHPUnit::assertTrue(
            collect($this->recorded)->filter(function ($pair) use ($callback) {
                return $callback($pair[0], $pair[1]);
            })->count() === 0,
            'An unexpected process was invoked.'
        );

        return $this;
    }

    /**
     * Assert that a process was not recorded matching a given truth test.
     *
     * @param  \Closure|string  $callback
     * @return $this
     */
    public function assertDidntRun(Closure|string $callback)
    {
        return $this->assertNotRan($callback);
    }

    /**
     * Assert that no processes were recorded.
     *
     * @return $this
     */
    public function assertNothingRan()
    {
        PHPUnit::assertEmpty(
            $this->recorded,
            'An unexpected process was invoked.'
        );

        return $this;
    }

    /**
     * Start defining a pool of processes.
     *
     * @param  callable  $callback
     * @return \Illuminate\Process\Pool
     */
    public function pool(callable $callback)
    {
        return new Pool($this, $callback);
    }

    /**
     * Start defining a series of piped processes.
     *
     * @param  callable|array  $callback
     * @return \Illuminate\Contracts\Process\ProcessResult
     */
    public function pipe(callable|array $callback, ?callable $output = null)
    {
        return is_array($callback)
            ? (new Pipe($this, fn ($pipe) => collect($callback)->each(
                fn ($command) => $pipe->command($command)
            )))->run(output: $output)
            : (new Pipe($this, $callback))->run(output: $output);
    }

    /**
     * Run a pool of processes and wait for them to finish executing.
     *
     * @param  callable  $callback
     * @param  callable|null  $output
     * @return \Illuminate\Process\ProcessPoolResults
     */
    public function concurrently(callable $callback, ?callable $output = null)
    {
        return (new Pool($this, $callback))->start($output)->wait();
    }

    /**
     * Create a new pending process associated with this factory.
     *
     * @return \Illuminate\Process\PendingProcess
     */
    public function newPendingProcess()
    {
        return (new PendingProcess($this))->withFakeHandlers($this->fakeHandlers);
    }

    /**
     * Dynamically proxy methods to a new pending process instance.
     *
     * @param  string  $method
     * @param  array  $parameters
     * @return mixed
     */
    public function __call($method, $parameters)
    {
        if (static::hasMacro($method)) {
            return $this->macroCall($method, $parameters);
        }

        return $this->newPendingProcess()->{$method}(...$parameters);
    }
}