Skip to content

Commit

Permalink
Fixed FQCN bug and multiple custom datetime class bug. Added tests
Browse files Browse the repository at this point in the history
  • Loading branch information
msalakhov committed Dec 18, 2023
1 parent 681eda6 commit f0affbc
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 25 deletions.
5 changes: 5 additions & 0 deletions src/Exception/CannotParseOpenApi.php
Original file line number Diff line number Diff line change
Expand Up @@ -117,4 +117,9 @@ public static function becauseUnknownType(string $name): self
{
return new self(sprintf('Class "%s" does not exist', $name));
}

public static function becauseNotFQCN(string $name): self
{
return new self(sprintf('Class "%s" should have fully qualified name', $name));
}
}
8 changes: 5 additions & 3 deletions src/Specification/SpecificationParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,7 @@ public function parseOpenApi(string $specificationName, SpecificationConfig $spe

$operationDefinitions = [];

if ($specificationConfig->getDateTimeClass() !== null) {
$this->dateTimeClass = $specificationConfig->getDateTimeClass();
}
$this->dateTimeClass = $specificationConfig->getDateTimeClass();

/**
* @var string $url
Expand Down Expand Up @@ -395,6 +393,10 @@ private function getProperty(
$propertyDefinition->setScalarTypeId($scalarTypeId);

if ($this->typeResolver->isDateTime($scalarTypeId) && $this->dateTimeClass !== null) {
if (preg_match('/^\\\\/', $this->dateTimeClass) !== 1) {
throw CannotParseOpenApi::becauseNotFQCN($this->dateTimeClass);
}

if (! class_exists($this->dateTimeClass)) {
throw CannotParseOpenApi::becauseUnknownType($this->dateTimeClass);
}
Expand Down
140 changes: 118 additions & 22 deletions test/unit/Specification/SpecificationParserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,13 @@
use cebe\openapi\spec\Responses;
use cebe\openapi\spec\Schema;
use cebe\openapi\spec\Type;
use DateTimeImmutable;
use OnMoon\OpenApiServerBundle\Exception\CannotParseOpenApi;
use OnMoon\OpenApiServerBundle\Specification\Definitions\ObjectSchema;
use OnMoon\OpenApiServerBundle\Specification\Definitions\SpecificationConfig;
use OnMoon\OpenApiServerBundle\Specification\SpecificationParser;
use OnMoon\OpenApiServerBundle\Types\ScalarTypesResolver;
use PHPUnit\Framework\Assert;
use PHPUnit\Framework\TestCase;
use stdClass;

use function array_map;
use function sprintf;
Expand Down Expand Up @@ -293,15 +291,24 @@ public function testParseOpenApiSuccess(): void

public function testParseOpenApiWithCustomDateTimeClassSuccess(): void
{
$specificationName = 'SomeCustomSpecification';
$specificationConfig = new SpecificationConfig(
'/some/custom/specification/path',
$customDateTimeClass = '\DateTimeImmutable';
$specificationNameOne = 'SomeCustomSpecificationOne';
$specificationConfigOne = new SpecificationConfig(
'/some/custom/specification/one/path',
null,
'\\Some\\Custom\\Namespace',
'application/json',
DateTimeImmutable::class
$customDateTimeClass
);
$parsedSpecification = new OpenApi([
$specificationNameTwo = 'SomeCustomSpecificationTwo';
$specificationConfigTwo = new SpecificationConfig(
'/some/custom/specification/two/path',
null,
'\\Some\\Custom\\Namespace',
'application/json',
null
);
$parsedSpecification = new OpenApi([
'paths' => new Paths([
'/some/custom/url' => [
'post' => new Operation([
Expand Down Expand Up @@ -349,19 +356,32 @@ public function testParseOpenApiWithCustomDateTimeClassSuccess(): void

$specificationParser = new SpecificationParser(new ScalarTypesResolver(), []);

$specification = $specificationParser->parseOpenApi(
$specificationName,
$specificationConfig,
$specificationOne = $specificationParser->parseOpenApi(
$specificationNameOne,
$specificationConfigOne,
$parsedSpecification
);

$requestBody = $specification
$specificationOneRequestBody = $specificationOne
->getOperation('SomeCustomOperationWithRequestAndResponses')
->getRequestBody();
Assert::assertNotNull($requestBody);
Assert::assertNotNull($specificationOneRequestBody);

$requestBodyProperties = $requestBody->getProperties();
Assert::assertSame(DateTimeImmutable::class, $requestBodyProperties[0]->getOutputType());
$specificationOneRequestBodyProperties = $specificationOneRequestBody->getProperties();
Assert::assertSame($customDateTimeClass, $specificationOneRequestBodyProperties[0]->getOutputType());

$specificationTwo = $specificationParser->parseOpenApi(
$specificationNameTwo,
$specificationConfigTwo,
$parsedSpecification
);
$specificationTwoRequestBody = $specificationTwo
->getOperation('SomeCustomOperationWithRequestAndResponses')
->getRequestBody();
Assert::assertNotNull($specificationTwoRequestBody);

$specificationTwoRequestBodyProperties = $specificationTwoRequestBody->getProperties();
Assert::assertNull($specificationTwoRequestBodyProperties[0]->getOutputType());
}

public function testParseOpenApiSuccessRequestBadMediaType(): void
Expand Down Expand Up @@ -1006,15 +1026,16 @@ public function testParseOpenApiThrowExceptionDuplicateOperationId(): void

public function testParseOpenApiWithCustomDateTimeClassThrowExceptionUnknownType(): void
{
$specificationName = 'SomeCustomSpecification';
$specificationConfig = new SpecificationConfig(
$someNotExistedDateTimeClass = '\SomeNotExistedDateTimeClass';
$specificationName = 'SomeCustomSpecification';
$specificationConfig = new SpecificationConfig(
'/some/custom/specification/path',
null,
'\\Some\\Custom\\Namespace',
'application/json',
'SomeNotExistedDateTimeClass'
$someNotExistedDateTimeClass
);
$parsedSpecification = new OpenApi([
$parsedSpecification = new OpenApi([
'paths' => new Paths([
'/some/custom/url' => [
'post' => new Operation([
Expand Down Expand Up @@ -1063,7 +1084,10 @@ public function testParseOpenApiWithCustomDateTimeClassThrowExceptionUnknownType
$specificationParser = new SpecificationParser(new ScalarTypesResolver(), []);

$this->expectException(CannotParseOpenApi::class);
$this->expectExceptionMessage('Class "SomeNotExistedDateTimeClass" does not exist');
$this->expectExceptionMessage(sprintf(
'Class "%s" does not exist',
$someNotExistedDateTimeClass
));

$specificationParser->parseOpenApi(
$specificationName,
Expand All @@ -1075,13 +1099,13 @@ public function testParseOpenApiWithCustomDateTimeClassThrowExceptionUnknownType
public function testParseOpenApiWithCustomDateTimeClassThrowExceptionTypeNotSupported(): void
{
$specificationName = 'SomeCustomSpecification';
$someNotDateTimeClass = $this->getMockBuilder(stdClass::class)->getMock();
$someNotDateTimeClass = '\stdClass';
$specificationConfig = new SpecificationConfig(
'/some/custom/specification/path',
null,
'\\Some\\Custom\\Namespace',
'application/json',
$someNotDateTimeClass::class
$someNotDateTimeClass
);
$parsedSpecification = new OpenApi([
'paths' => new Paths([
Expand Down Expand Up @@ -1136,7 +1160,79 @@ public function testParseOpenApiWithCustomDateTimeClassThrowExceptionTypeNotSupp
'Cannot generate property for DTO class, property "someDateTimeProperty" type "%s" is not supported ' .
'in response (code "200") for operation: "post" of path: "/some/custom/url" in specification file: ' .
'"/some/custom/specification/path".',
$someNotDateTimeClass::class
$someNotDateTimeClass
));

$specificationParser->parseOpenApi(
$specificationName,
$specificationConfig,
$parsedSpecification
);
}

public function testParseOpenApiWithCustomDateTimeClassThrowExceptionNotFQCN(): void
{
$someNotFqcnClassName = 'SomeNotFqcnClassName';
$specificationName = 'SomeCustomSpecification';
$specificationConfig = new SpecificationConfig(
'/some/custom/specification/path',
null,
'\\Some\\Custom\\Namespace',
'application/json',
$someNotFqcnClassName
);
$parsedSpecification = new OpenApi([
'paths' => new Paths([
'/some/custom/url' => [
'post' => new Operation([
'operationId' => 'SomeCustomOperationWithRequestAndResponses',
'requestBody' => new RequestBody([
'description' => 'SomeCustomRequestParam',
'content' => [
'application/json' => new MediaType([
'schema' => new Schema([
'type' => Type::OBJECT,
'properties' => [
'someDateTimeProperty' => new Schema([
'type' => Type::STRING,
'format' => 'date-time',
'default' => 1605101247,
]),
],
]),
]),
],
]),
'responses' => new Responses([
'200' => new Response([
'description' => 'SomeCustomResponseParam200',
'content' => [
'application/json' => new MediaType([
'schema' => new Schema([
'type' => Type::OBJECT,
'properties' => [
'someDateTimeProperty' => new Schema([
'type' => Type::STRING,
'format' => 'date-time',
'default' => 1605101247,
]),
],
]),
]),
],
]),
]),
]),
],
]),
]);

$specificationParser = new SpecificationParser(new ScalarTypesResolver(), []);

$this->expectException(CannotParseOpenApi::class);
$this->expectExceptionMessage(sprintf(
'Class "%s" should have fully qualified name',
$someNotFqcnClassName
));

$specificationParser->parseOpenApi(
Expand Down

0 comments on commit f0affbc

Please sign in to comment.