Skip to content

Commit

Permalink
Child process test double: (#430)
Browse files Browse the repository at this point in the history
- ChildProcess::class now implements Contracts\ChildProcess::class interface
- Facades\ChildProcess::fake() swaps implementations with a test double concrete
- Implement new binding in NativeServiceProvider::class
- Implement Contracts/ChildProcess::class methods, mimicing that of the implementation
- Implement ChildProcessFake::class with assertion helpers
- Test that ChildProcessFake::class assertions work
  • Loading branch information
XbNz authored Nov 22, 2024
1 parent 3b3d8dc commit ff9283e
Show file tree
Hide file tree
Showing 6 changed files with 518 additions and 4 deletions.
3 changes: 2 additions & 1 deletion src/ChildProcess.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
namespace Native\Laravel;

use Native\Laravel\Client\Client;
use Native\Laravel\Contracts\ChildProcess as ChildProcessContract;

class ChildProcess
class ChildProcess implements ChildProcessContract
{
public readonly int $pid;

Expand Down
28 changes: 28 additions & 0 deletions src/Contracts/ChildProcess.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

namespace Native\Laravel\Contracts;

interface ChildProcess
{
public function get(?string $alias = null): ?self;

public function all(): array;

public function start(
string|array $cmd,
string $alias,
?string $cwd = null,
?array $env = null,
bool $persistent = false
): self;

public function php(string|array $cmd, string $alias, ?array $env = null, ?bool $persistent = false): self;

public function artisan(string|array $cmd, string $alias, ?array $env = null, ?bool $persistent = false): self;

public function stop(?string $alias = null): void;

public function restart(?string $alias = null): ?self;

public function message(string $message, ?string $alias = null): self;
}
14 changes: 11 additions & 3 deletions src/Facades/ChildProcess.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
namespace Native\Laravel\Facades;

use Illuminate\Support\Facades\Facade;
use Native\Laravel\ChildProcess as Implement;
use Native\Laravel\Contracts\ChildProcess as ChildProcessContract;
use Native\Laravel\Fakes\ChildProcessFake;

/**
* @method static \Native\Laravel\ChildProcess[] all()
Expand All @@ -17,10 +18,17 @@
*/
class ChildProcess extends Facade
{
public static function fake()
{
return tap(static::getFacadeApplication()->make(ChildProcessFake::class), function ($fake) {
static::swap($fake);
});
}

protected static function getFacadeAccessor()
{
self::clearResolvedInstance(Implement::class);
self::clearResolvedInstance(ChildProcessContract::class);

return Implement::class;
return ChildProcessContract::class;
}
}
252 changes: 252 additions & 0 deletions src/Fakes/ChildProcessFake.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
<?php

namespace Native\Laravel\Fakes;

use Closure;
use Native\Laravel\Contracts\ChildProcess as ChildProcessContract;
use PHPUnit\Framework\Assert as PHPUnit;

class ChildProcessFake implements ChildProcessContract
{
/**
* @var array<int, string|null>
*/
public array $gets = [];

/**
* @var array<int, array{cmd: array|string, alias: string, cwd: string|null, env: array|null, persistent: bool}>
*/
public array $starts = [];

/**
* @var array<int, array{cmd: array|string, alias: string, env: array|null, persistent: bool}>
*/
public array $phps = [];

/**
* @var array<int, array{cmd: array|string, alias: string, env: array|null, persistent: bool}>
*/
public array $artisans = [];

/**
* @var array<int, string|null>
*/
public array $stops = [];

/**
* @var array<int, string|null>
*/
public array $restarts = [];

/**
* @var array<int, array{message: string, alias: string|null}>
*/
public array $messages = [];

public function get(?string $alias = null): self
{
$this->gets[] = $alias;

return $this;
}

public function all(): array
{
return [$this];
}

public function start(
array|string $cmd,
string $alias,
?string $cwd = null,
?array $env = null,
bool $persistent = false
): self {
$this->starts[] = [
'cmd' => $cmd,
'alias' => $alias,
'cwd' => $cwd,
'env' => $env,
'persistent' => $persistent,
];

return $this;
}

public function php(
array|string $cmd,
string $alias,
?array $env = null,
?bool $persistent = false
): self {
$this->phps[] = [
'cmd' => $cmd,
'alias' => $alias,
'env' => $env,
'persistent' => $persistent,
];

return $this;
}

public function artisan(
array|string $cmd,
string $alias,
?array $env = null,
?bool $persistent = false
): self {
$this->artisans[] = [
'cmd' => $cmd,
'alias' => $alias,
'env' => $env,
'persistent' => $persistent,
];

return $this;
}

public function stop(?string $alias = null): void
{
$this->stops[] = $alias;
}

public function restart(?string $alias = null): self
{
$this->restarts[] = $alias;

return $this;
}

public function message(string $message, ?string $alias = null): self
{
$this->messages[] = [
'message' => $message,
'alias' => $alias,
];

return $this;
}

/**
* @param string|Closure(string): bool $alias
*/
public function assertGet(string|Closure $alias): void
{
if (is_callable($alias) === false) {
PHPUnit::assertContains($alias, $this->gets);

return;
}

$hit = empty(
array_filter(
$this->gets,
fn (mixed $get) => $alias($get) === true
)
) === false;

PHPUnit::assertTrue($hit);
}

/**
* @param Closure(array|string $cmd, string $alias, ?string $cwd, ?array $env, bool $persistent): bool $callback
*/
public function assertStarted(Closure $callback): void
{
$hit = empty(
array_filter(
$this->starts,
fn (array $started) => $callback(...$started) === true
)
) === false;

PHPUnit::assertTrue($hit);
}

/**
* @param Closure(array|string $cmd, string $alias, ?array $env, ?bool $persistent): bool $callback
*/
public function assertPhp(Closure $callback): void
{
$hit = empty(
array_filter(
$this->phps,
fn (array $php) => $callback(...$php) === true
)
) === false;

PHPUnit::assertTrue($hit);
}

/**
* @param Closure(array|string $cmd, string $alias, ?array $env, ?bool $persistent): bool $callback
*/
public function assertArtisan(Closure $callback): void
{
$hit = empty(
array_filter(
$this->artisans,
fn (array $artisan) => $callback(...$artisan) === true
)
) === false;

PHPUnit::assertTrue($hit);
}

/**
* @param string|Closure(string): bool $alias
*/
public function assertStop(string|Closure $alias): void
{
if (is_callable($alias) === false) {
PHPUnit::assertContains($alias, $this->stops);

return;
}

$hit = empty(
array_filter(
$this->stops,
fn (mixed $stop) => $alias($stop) === true
)
) === false;

PHPUnit::assertTrue($hit);
}

/**
* @param string|Closure(string): bool $alias
*/
public function assertRestart(string|Closure $alias): void
{
if (is_callable($alias) === false) {
PHPUnit::assertContains($alias, $this->restarts);

return;
}

$hit = empty(
array_filter(
$this->restarts,
fn (mixed $restart) => $alias($restart) === true
)
) === false;

PHPUnit::assertTrue($hit);
}

/**
* @param Closure(string $message, string|null $alias): bool $callback
*/
public function assertMessage(Closure $callback): void
{
$hit = empty(
array_filter(
$this->messages,
fn (array $message) => $callback(...$message) === true
)
) === false;

PHPUnit::assertTrue($hit);
}
}
6 changes: 6 additions & 0 deletions src/NativeServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\DB;
use Native\Laravel\ChildProcess as ChildProcessImplementation;
use Native\Laravel\Commands\FreshCommand;
use Native\Laravel\Commands\LoadPHPConfigurationCommand;
use Native\Laravel\Commands\LoadStartupConfigurationCommand;
use Native\Laravel\Commands\MigrateCommand;
use Native\Laravel\Commands\MinifyApplicationCommand;
use Native\Laravel\Commands\SeedDatabaseCommand;
use Native\Laravel\Contracts\ChildProcess as ChildProcessContract;
use Native\Laravel\Contracts\WindowManager as WindowManagerContract;
use Native\Laravel\Events\EventWatcher;
use Native\Laravel\Exceptions\Handler;
Expand Down Expand Up @@ -54,6 +56,10 @@ public function packageRegistered()
return $app->make(WindowManagerImplementation::class);
});

$this->app->bind(ChildProcessContract::class, function (Foundation $app) {
return $app->make(ChildProcessImplementation::class);
});

if (config('nativephp-internal.running')) {
$this->app->singleton(
\Illuminate\Contracts\Debug\ExceptionHandler::class,
Expand Down
Loading

0 comments on commit ff9283e

Please sign in to comment.