diff --git a/CHANGELOG.md b/CHANGELOG.md index a7308ec..66315e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [Unreleased] + +### Added + +- `Innmind\Server\Control\Server\Process\Builder`, internal tool to mock processes + ## 7.0.0 - 2026-01-31 ### Changed diff --git a/src/Server/Process/Builder.php b/src/Server/Process/Builder.php new file mode 100644 index 0000000..9f398b5 --- /dev/null +++ b/src/Server/Process/Builder.php @@ -0,0 +1,162 @@ + $pid + */ + private function __construct( + private ?int $pid, + private Success|Signaled|TimedOut|Failed $result, + ) { + } + + /** + * @internal + * @psalm-pure + * + * @param int<2, max> $pid + */ + #[\NoDiscard] + public static function foreground(int $pid): self + { + return new self($pid, new Success(Sequence::of())); + } + + /** + * @internal + * @psalm-pure + */ + #[\NoDiscard] + public static function background(): self + { + return new self(null, new Success(Sequence::of())); + } + + /** + * @psalm-mutation-free + * + * @param Sequence|list $output + */ + #[\NoDiscard] + public function success(Sequence|array|null $output = null): self + { + return new self( + $this->pid, + new Success(self::output($output)), + ); + } + + /** + * @psalm-mutation-free + * + * @param Sequence|list $output + */ + #[\NoDiscard] + public function signaled(Sequence|array|null $output = null): self + { + return new self( + $this->pid, + new Signaled(self::output($output)), + ); + } + + /** + * @psalm-mutation-free + * + * @param Sequence|list $output + */ + #[\NoDiscard] + public function timedOut(Sequence|array|null $output = null): self + { + return new self( + $this->pid, + new TimedOut(self::output($output)), + ); + } + + /** + * @psalm-mutation-free + * + * @param int<1, 255> $exitCode + * @param Sequence|list $output + */ + #[\NoDiscard] + public function failed(int $exitCode = 1, Sequence|array|null $output = null): self + { + return new self( + $this->pid, + new Failed( + new ExitCode($exitCode), + self::output($output), + ), + ); + } + + /** + * @internal + */ + #[\NoDiscard] + public function build(): Process + { + $pid = $this->pid; + $result = $this->result; + + /** + * This a trick to not expose any mock contructor on the Process class. + * + * @psalm-suppress PossiblyNullFunctionCall + * @psalm-suppress MixedReturnStatement + * @psalm-suppress InaccessibleMethod + */ + return (\Closure::bind( + static fn() => new Process(new Mock($pid, $result)), + null, + Process::class, + ))(); + } + + /** + * @psalm-pure + * + * @param Sequence|list $output + * + * @return Sequence + */ + private static function output(Sequence|array|null $output = null): Sequence + { + if (\is_null($output)) { + return Sequence::of(); + } + + if (\is_array($output)) { + return Sequence::of(...$output)->map(static fn($pair) => Chunk::of( + Str::of($pair[0]), + match ($pair[1]) { + 'output' => Type::output, + 'error' => Type::error, + }, + )); + } + + return $output; + } +} diff --git a/src/Server/Process/Failed.php b/src/Server/Process/Failed.php index cc36c09..82e47e6 100644 --- a/src/Server/Process/Failed.php +++ b/src/Server/Process/Failed.php @@ -5,6 +5,9 @@ use Innmind\Immutable\Sequence; +/** + * @psalm-immutable + */ final class Failed { /** diff --git a/src/Server/Process/Signaled.php b/src/Server/Process/Signaled.php index 65f6d9d..953e02f 100644 --- a/src/Server/Process/Signaled.php +++ b/src/Server/Process/Signaled.php @@ -5,6 +5,9 @@ use Innmind\Immutable\Sequence; +/** + * @psalm-immutable + */ final class Signaled { /** diff --git a/src/Server/Process/Success.php b/src/Server/Process/Success.php index 5644343..c89cbc3 100644 --- a/src/Server/Process/Success.php +++ b/src/Server/Process/Success.php @@ -5,6 +5,9 @@ use Innmind\Immutable\Sequence; +/** + * @psalm-immutable + */ final class Success { /** diff --git a/src/Server/Process/TimedOut.php b/src/Server/Process/TimedOut.php index 042eb35..c49a6d2 100644 --- a/src/Server/Process/TimedOut.php +++ b/src/Server/Process/TimedOut.php @@ -5,6 +5,9 @@ use Innmind\Immutable\Sequence; +/** + * @psalm-immutable + */ final class TimedOut { /**