src/Testing/InteractsWithServiceProvider.php
<?php
namespace Laragear\Meta\Testing;
use DateTimeInterface;
use Illuminate\Auth\AuthManager;
use Illuminate\Console\Scheduling\Event;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Contracts\Auth\Access\Gate;
use Illuminate\Contracts\Http\Kernel;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Str;
use InvalidArgumentException;
use function now;
use function preg_replace;
use ReflectionException;
use ReflectionMethod;
/**
* @internal
*/
trait InteractsWithServiceProvider
{
/**
* Assert that a service manager contains a given driver.
*
* @param string $service
* @param string $driver
* @param class-string|string|null $class
* @return void
*/
protected function assertHasDriver(string $service, string $driver, string $class = null): void
{
$manager = $this->app->make($service);
try {
$instance = $manager instanceof AuthManager ? $manager->guard($driver) : $manager->driver($driver);
} catch (InvalidArgumentException) {
static::fail("The '$service' service doesn't have the driver '$driver'.");
}
static::assertNotNull($instance, "The '$driver' for '$service' returns null.");
if ($class) {
static::assertInstanceOf($class, $instance, "The the driver '$driver' is not an instance of '$class'.");
}
}
/**
* Assert the services are registered in the Service Container.
*
* @param string ...$services
* @return void
*/
protected function assertHasServices(string ...$services): void
{
foreach ($services as $service) {
static::assertThat(
$this->app->bound($service),
static::isTrue(),
"The '$service' was not registered in the Service Container."
);
}
}
/**
* Assert a service is registered as a shared instance.
*
* @param string ...$services
* @return void
*/
protected function assertHasSingletons(string ...$services): void
{
$this->assertHasServices(...$services);
foreach ($services as $service) {
static::assertThat(
$this->app->isShared($service),
static::isTrue(),
"The '$service' is registered as a shared instance in the Service Container."
);
}
}
/**
* Assert a service is registered as a shared instance.
*
* @param string ...$services
* @return void
*/
protected function assertHasShared(string ...$services): void
{
$this->assertHasSingletons(...$services);
}
/**
* Assert that the config file is merged into the application using the given key.
*
* @param string $file
* @param string|null $configKey
* @return void
*/
protected function assertConfigMerged(string $file, string $configKey = null): void
{
$configKey ??= Str::of($file)->beforeLast('.php')->afterLast('/')->afterLast('\\')->toString();
static::assertThat(
$this->app->make('config')->has($configKey),
static::isTrue(),
"The configuration file was not merged as '$configKey'."
);
static::assertSame(
$this->app->make('files')->getRequire($file),
$this->app->make('config')->get($configKey),
"The configuration file in '$file' is not the same for '$configKey'."
);
}
/**
* Asserts that the given files are set to be published.
*
* @param string $file
* @param string $tag
* @return void
*/
protected function assertPublishes(string $file, string $tag): void
{
static::assertArrayHasKey($tag, ServiceProvider::$publishGroups, "The '$tag' is not a publishable tag.");
static::assertContains(
$file, ServiceProvider::$publishGroups[$tag], "The '$file' is not publishable in the '$tag' tag."
);
}
/**
* Assert that the migration files in the given path are published.
*
* @param string $dir
* @param string $tag
* @return void
*/
protected function assertPublishesMigrations(string $dir, string $tag = 'migrations'): void
{
static::assertArrayHasKey($tag, ServiceProvider::$publishGroups, "The '$tag' is not a publishable tag.");
$files = $this->app->make('files')->files($dir);
static::assertNotEmpty($files, "The '$dir' has no migration files.");
$this->travelTo(now()->startOfSecond(), function () use ($tag, $files): void {
$prefix = now()->format('Y_m_d_His');
foreach ($files as $file) {
$filename = $prefix.'_'.preg_replace('/^[\d|_]+/', '', $file->getFilename());
static::assertContains(
$this->app->databasePath("migrations/$filename"),
ServiceProvider::$publishGroups[$tag],
"The '$filename' is not publishable in the '$tag' tag."
);
}
});
}
/**
* Assert the translation namespace is registered.
*
* @param string $path
* @param string $namespace
* @return void
*/
protected function assertHasTranslations(string $path, string $namespace): void
{
$namespaces = $this->app->make('translator')->getLoader()->namespaces();
static::assertArrayHasKey($namespace, $namespaces, "The '$namespace' translations were not registered.");
static::assertSame($path, $namespaces[$namespace], "The '$namespace' does not correspond to the path '$path'.");
}
/**
* Assert the view namespace is registered.
*
* @param string $path
* @param string $namespace
* @return void
*/
protected function assertHasViews(string $path, string $namespace): void
{
$namespaces = $this->app->make('view')->getFinder()->getHints();
static::assertArrayHasKey($namespace, $namespaces, "The '$namespace' views were not registered.");
static::assertContains($path, $namespaces[$namespace], "The '$namespace' does not correspond to the path '$path'.");
}
/**
* Assert the blade components are registered.
*
* @param string $alias
* @param string $component
* @return void
*/
protected function assertHasBladeComponent(string $alias, string $component): void
{
$aliases = $this->app->make('blade.compiler')->getClassComponentAliases();
static::assertArrayHasKey($alias, $aliases, "The '$alias' is not registered as component.");
static::assertSame($component, $aliases[$alias], "The '$component' component is not registered as '$alias'.");
}
/**
* Assert the blade directives are registered.
*
* @param string ...$directives
* @return void
*/
protected function assertHasBladeDirectives(string ...$directives): void
{
$list = $this->app->make('blade.compiler')->getCustomDirectives();
foreach ($directives as $directive) {
static::assertArrayHasKey($directive, $list, "The '$directive' was not registered as a blade directive.");
}
}
/**
* Assert the validation rules are registered.
*
* @param string ...$rules
* @return void
*/
protected function assertHasValidationRules(string ...$rules): void
{
$extensions = $this->app->make('validator')->make([], [])->extensions;
foreach ($rules as $rule) {
static::assertArrayHasKey($rule, $extensions, "The '$rule' rule was not registered in the validator.");
}
}
/**
* Assert the middleware are aliased.
*
* @param string $alias
* @param string $middleware
* @return void
*/
protected function assertHasMiddlewareAlias(string $alias, string $middleware): void
{
$registered = $this->app->make('router')->getMiddleware();
static::assertArrayHasKey($alias, $registered, "The '$alias' alias was not registered as middleware.");
static::assertSame($middleware, $registered[$alias], "The '$middleware' was not aliased as '$alias' middleware.");
}
/**
* Assert the middleware is registered globally.
*
* @param string ...$middleware
* @return void
*/
protected function assertHasGlobalMiddleware(string ...$middleware): void
{
$kernel = $this->app->make(Kernel::class);
foreach ($middleware as $class) {
static::assertThat(
$kernel->hasMiddleware($class),
static::isTrue(),
"The '$class' middleware was not registered as global."
);
}
}
/**
* Assert the middleware is registered in a middleware group.
*
* @param string $group
* @param string $middleware
* @return void
*/
protected function assertHasMiddlewareInGroup(string $group, string $middleware): void
{
$list = $this->app->make(Kernel::class)->getMiddlewareGroups();
static::assertThat(
$list, static::arrayHasKey($group), "The middleware group '$group' is not defined by default."
);
static::assertThat(
$list[$group],
static::containsEqual($middleware),
"The middleware '$middleware' is not part of the '$group' group."
);
}
/**
* Assert the gate has a given ability.
*
* @param string ...$abilities
* @return void
*/
protected function assertGateHasAbility(string ...$abilities): void
{
$gates = $this->app->make(Gate::class)->abilities();
foreach ($abilities as $ability) {
static::assertThat($gates, static::arrayHasKey($ability), "The '$ability' is not registered as a gate.");
}
}
/**
* Assert that a model has registered a Policy.
*
* @param string $model
* @param string ...$abilities
* @return void
*/
protected function assertGateHasPolicy(string $model, string ...$abilities): void
{
$policy = $this->app->make(Gate::class)->getPolicyFor($model);
static::assertNotNull($policy, "The policy for '$model' does not exist.");
$target = get_class($policy);
foreach ($abilities as $ability) {
try {
$method = new ReflectionMethod($policy, $ability);
} catch (ReflectionException) {
static::fail("The '$ability' ability is not declared in the '$target' policy for '$model'.");
}
static::assertThat(
$method->isPublic() && ! $method->isStatic(),
static::isTrue(),
"The '$ability' ability declared in '$target' is private/protected or static."
);
}
}
/**
* Asserts a task is scheduled.
*
* @param string $task
* @return void
*/
protected function assertHasScheduledTask(string $task): void
{
$contains = Collection::make($this->app->make(Schedule::class)->events())
->contains(static function (Event $event) use ($task): bool {
return Str::of($event->command)->after('artisan')->contains($task)
|| $event->description === $task;
});
static::assertThat($contains, static::isTrue(), "The '$task' is has not been scheduled.");
}
/**
* Assert that a scheduled task will run at the given date.
*
* @param string $task
* @param \DateTimeInterface $date
* @return void
*/
protected function assertScheduledTaskRunsAt(string $task, DateTimeInterface $date): void
{
$this->assertHasScheduledTask($task);
$contains = $this->travelTo($date, function () use ($task): bool {
return $this->app->make(Schedule::class)->dueEvents($this->app)
->contains(static function (Event $event) use ($task): bool {
return Str::of($event->command)->after('artisan')->contains($task)
|| $event->description === $task;
});
});
static::assertThat($contains, static::isTrue(), "The '$task' is not scheduled to run at '$date'.");
}
/**
* Assert the given class has registered the given macros.
*
* @param string|class-string $macroable
* @param string ...$macros
* @return void
*/
protected function assertHasMacro(string $macroable, string ...$macros): void
{
$call = $macroable === Builder::class ? 'hasGlobalMacro' : 'hasMacro';
foreach ($macros as $macro) {
static::assertThat(
$macroable::{$call}($macro), static::isTrue(), "The macro '$macro' for '$macroable' is missing."
);
}
}
}