Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions src/OpenApiSpecFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace Osteel\OpenApi\Testing;

use cebe\openapi\Reader;
use cebe\openapi\SpecObjectInterface;

final class OpenApiSpecFactory implements OpenApiSpecFactoryInterface
{
/** @inheritDoc */
public function readFromJsonFile(string $fileName): SpecObjectInterface
{
return Reader::readFromJsonFile($fileName);
}

/** @inheritDoc */
public function readFromYamlFile(string $fileName): SpecObjectInterface
{
return Reader::readFromYamlFile($fileName);
}
}
17 changes: 17 additions & 0 deletions src/OpenApiSpecFactoryInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

declare(strict_types=1);

namespace Osteel\OpenApi\Testing;

use cebe\openapi\spec\OpenApi;
use cebe\openapi\SpecObjectInterface;

interface OpenApiSpecFactoryInterface
{
/** @return SpecObjectInterface|OpenApi */
public function readFromJsonFile(string $fileName): SpecObjectInterface;

/** @return SpecObjectInterface|OpenApi */
public function readFromYamlFile(string $fileName): SpecObjectInterface;
}
56 changes: 48 additions & 8 deletions src/ValidatorBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Osteel\OpenApi\Testing;

use Closure;
use InvalidArgumentException;
use League\OpenAPIValidation\PSR7\ValidatorBuilder as BaseValidatorBuilder;
use Osteel\OpenApi\Testing\Adapters\MessageAdapterInterface;
Expand All @@ -16,6 +17,9 @@
*/
final class ValidatorBuilder implements ValidatorBuilderInterface
{
/** @var ?Closure():OpenApiSpecFactoryInterface */
private static ?Closure $openApiSpecFactoryResolver = null;

/** @var class-string<MessageAdapterInterface> */
private string $adapter = HttpFoundationAdapter::class;

Expand All @@ -33,9 +37,7 @@ public function __construct(private BaseValidatorBuilder $validatorBuilder)
*/
public static function fromYaml(string $definition): ValidatorBuilderInterface
{
$method = is_file($definition) ? 'fromYamlFile' : 'fromYaml';

return self::fromMethod($method, $definition);
return self::fromYamlFile($definition);
}

/**
Expand All @@ -45,9 +47,7 @@ public static function fromYaml(string $definition): ValidatorBuilderInterface
*/
public static function fromJson(string $definition): ValidatorBuilderInterface
{
$method = is_file($definition) ? 'fromJsonFile' : 'fromJson';

return self::fromMethod($method, $definition);
return self::fromJsonFile($definition);
}

/**
Expand All @@ -57,7 +57,7 @@ public static function fromJson(string $definition): ValidatorBuilderInterface
*/
public static function fromYamlFile(string $definition): ValidatorBuilderInterface
{
return self::fromMethod('fromYamlFile', $definition);
return self::fromMethod(self::determineMethod($definition, 'yaml'), $definition);
}

/**
Expand All @@ -67,7 +67,7 @@ public static function fromYamlFile(string $definition): ValidatorBuilderInterfa
*/
public static function fromJsonFile(string $definition): ValidatorBuilderInterface
{
return self::fromMethod('fromJsonFile', $definition);
return self::fromMethod(self::determineMethod($definition, 'json'), $definition);
}

/**
Expand Down Expand Up @@ -98,11 +98,51 @@ public static function fromJsonString(string $definition): ValidatorBuilderInter
*/
private static function fromMethod(string $method, string $definition): ValidatorBuilderInterface
{
$openApiFactory = self::getOpenApiSpecFactory();

$definition = match ($method) {
'fromJsonSchema' => $openApiFactory->readFromJsonFile($definition),
'fromYamlSchema' => $openApiFactory->readFromYamlFile($definition),
default => $definition,
};

if (in_array($method, ['fromJsonSchema', 'fromYamlSchema'], true)) {
$method = 'fromSchema';
}

$builder = (new BaseValidatorBuilder())->{$method}($definition);

return new ValidatorBuilder($builder);
}

private static function determineMethod(string $definition, string $format): string
{
if (filter_var($definition, FILTER_VALIDATE_URL) && in_array(parse_url($definition, PHP_URL_SCHEME), ['http', 'https'], true)) {
return sprintf('from%sSchema', ucfirst($format));
}

if (is_file($definition)) {
return sprintf('from%sFile', ucfirst($format));
}

return sprintf('from%s', ucfirst($format));
}

/** @param ?Closure():OpenApiSpecFactoryInterface $resolver */
public static function setOpenApiSpecFactoryResolver(?Closure $resolver = null): void
{
self::$openApiSpecFactoryResolver = $resolver;
}

public static function getOpenApiSpecFactory(): OpenApiSpecFactoryInterface
{
if (self::$openApiSpecFactoryResolver === null) {
return new OpenApiSpecFactory();
}

return (self::$openApiSpecFactoryResolver)();
}

/** @inheritDoc */
public function setCache(object $cache): ValidatorBuilderInterface
{
Expand Down
28 changes: 28 additions & 0 deletions tests/OpenApiSpecFactoryTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

declare(strict_types=1);

namespace Osteel\OpenApi\Testing\Tests;

use cebe\openapi\spec\OpenApi;
use cebe\openapi\SpecObjectInterface;
use Osteel\OpenApi\Testing\OpenApiSpecFactory;

class OpenApiSpecFactoryTest extends TestCase
{
public function test_it_creates_an_open_api_spec_from_yaml_file(): void
{
$result = (new OpenApiSpecFactory())->readFromYamlFile(self::$yamlDefinition);

$this->assertInstanceOf(SpecObjectInterface::class, $result);
$this->assertInstanceOf(OpenApi::class, $result);
}

public function test_it_creates_an_open_api_spec_from_json_file(): void
{
$result = (new OpenApiSpecFactory())->readFromJsonFile(self::$jsonDefinition);

$this->assertInstanceOf(SpecObjectInterface::class, $result);
$this->assertInstanceOf(OpenApi::class, $result);
}
}
26 changes: 26 additions & 0 deletions tests/ValidatorBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@

namespace Osteel\OpenApi\Testing\Tests;

use cebe\openapi\Reader;
use InvalidArgumentException;
use Osteel\OpenApi\Testing\Adapters\MessageAdapterInterface;
use Osteel\OpenApi\Testing\Cache\CacheAdapterInterface;
use Osteel\OpenApi\Testing\OpenApiSpecFactoryInterface;
use Osteel\OpenApi\Testing\Validator;
use Osteel\OpenApi\Testing\ValidatorBuilder;
use stdClass;
Expand Down Expand Up @@ -42,6 +44,30 @@ public function test_it_builds_a_validator(string $method, string $definition)
$this->assertTrue($result->get($response, static::PATH));
}

public function test_it_builds_a_validator_given_a_absolute_url(): void
{
$url = 'https://foobar.localhost/openapi.yaml';

$openApiFactory = $this->createMock(OpenApiSpecFactoryInterface::class);
$openApiFactory->expects($this->once())
->method('readFromYamlFile')
->with($url)
->willReturn(Reader::readFromYamlFile(self::$yamlDefinition));

ValidatorBuilder::setOpenApiSpecFactoryResolver(fn () => $openApiFactory);

$result = ValidatorBuilder::fromYaml($url)->getValidator();

$this->assertInstanceOf(Validator::class, $result);

$request = $this->httpFoundationRequest(static::PATH, 'get', ['foo' => 'bar']);
$response = $this->httpFoundationResponse(['foo' => 'bar']);

// Validate a request and a response to make sure the definition was correctly parsed.
$this->assertTrue($result->get($request, static::PATH));
$this->assertTrue($result->get($response, static::PATH));
}

public function test_it_does_not_set_the_adapter_because_its_type_is_invalid()
{
$this->expectException(InvalidArgumentException::class);
Expand Down