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
731 changes: 676 additions & 55 deletions Annotations/AnnotationGenerator.php

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions config/ParameterExamples.php
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,8 @@
'format:string' => 'html',
'visits:array<int,VisitDescriptor>' => [
[
'idVisit' => 12345,
'idSite' => 1,
'idvisit' => 12345,
'idsite' => 1,
],
],
'segment:string' => 'countryCode==NZ',
Expand Down
75 changes: 10 additions & 65 deletions tests/Resources/MockAnnotationGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,95 +19,40 @@ class MockAnnotationGenerator extends AnnotationGenerator
public function __construct(DocumentationGenerator $generator)
{
parent::__construct($generator);

// TODO - Extend the constructor behaviour
}

// TODO - Refactor the methods below to use dependency injection so that they can more easily be tested

/**
* @inheritDoc
*/
public function buildAnnotationForMethod(array $rules, string $pluginName, \ReflectionMethod $reflectionMethod): array
{
return parent::buildAnnotationForMethod($rules, $pluginName, $reflectionMethod);
}

/**
* @inheritDoc
*/
public function determineParameters(array $rules, string $plugin, string $method, \ReflectionMethod $reflectionMethod): array
public function shouldUseParameterLevelExample(array $typesMap, string $example): bool
{
return parent::determineParameters($rules, $plugin, $method, $reflectionMethod);
return parent::shouldUseParameterLevelExample($typesMap, $example);
}

/**
* @inheritDoc
*/
public function getApplicableDemoExampleUrls(string $pluginName, string $methodName, array $paramsData): array
{
return parent::getApplicableDemoExampleUrls($pluginName, $methodName, $paramsData);
}

/**
* @inheritDoc
*/
public function getDemoReportMetadata(): array
{
return parent::getDemoReportMetadata();
}

/**
* @inheritDoc
*/
public function getExampleIfAvailable(string $url, bool $useLocalToken = false, bool $ignoreCached = false): string
{
return parent::getExampleIfAvailable($url, $useLocalToken, $ignoreCached);
}

/**
* @inheritDoc
*/
public function getReportExampleUrlFromMetadata(string $pluginName, string $methodName): string
{
return parent::getReportExampleUrlFromMetadata($pluginName, $methodName);
}

public function getReportMetadataUrl(): string
{
return parent::getReportMetadataUrl();
}

public function prependInstanceUrl(string $path): string
{
return parent::prependInstanceUrl($path);
}

/**
* @inheritDoc
*/
public function determineResponses(array $rules, string $plugin, string $method, \ReflectionMethod $reflectionMethod, array $paramsData): array
{
return parent::determineResponses($rules, $plugin, $method, $reflectionMethod, $paramsData);
}

public function normaliseConfiguredParameterExample($example, array $typesMap = []): ?string
public function getReportExampleUrlFromMetadata(string $pluginName, string $methodName): string
{
return parent::normaliseConfiguredParameterExample($example, $typesMap);
return parent::getReportExampleUrlFromMetadata($pluginName, $methodName);
}

public function isBasicExampleArray(array $example): bool
public function expandTypeAliases(string $type): string
{
return parent::isBasicExampleArray($example);
return parent::expandTypeAliases($type);
}

public function supportsBasicArrayExample(array $typesMap): bool
public function parseArrayLikeTypeDefinition(string $type): ?array
{
return parent::supportsBasicArrayExample($typesMap);
return parent::parseArrayLikeTypeDefinition($type);
}

public function shouldUseParameterLevelExample(array $typesMap, string $example): bool
public function setCurrentTypeAliases(array $aliases): void
{
return parent::shouldUseParameterLevelExample($typesMap, $example);
$this->currentTypeAliases = $aliases;
}
}
148 changes: 137 additions & 11 deletions tests/Unit/AnnotationGeneratorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,20 @@ public function testGetParamInfoFromDocBlock(): void
$this->assertEquals($expected, $this->annotationGenerator->getParamInfoFromDocBlock(self::EXAMPLE_API_METHOD_DOC_BLOCK1));
}

public function testGetParamInfoFromDocBlockPreservesRawAliasTypes(): void
{
$docBlock = <<<'DOC'
/**
* @param array<int, VisitDescriptor> $visits Data subject visit descriptors to export.
*/
DOC;

$this->assertSame(
'array<int, VisitDescriptor>',
$this->annotationGenerator->getParamInfoFromDocBlock($docBlock)['visits']['type']
);
}

public function testGetResponseInfoFromDocBlock(): void
{
// TODO - Update to use resource file and/or dataprovider to test more than one comment block
Expand Down Expand Up @@ -1297,17 +1311,16 @@ public function testBuildSchemaObjectArrayIgnoresEnumForNonStringTypes(): void
$this->assertEquals($expectedWithoutEnum, $this->annotationGenerator->buildSchemaObjectArray('integer', '', NoDefaultValue::class, '1', ['1', '2']));
}

public function testNormaliseConfiguredParameterExampleSupportsOnlySimpleValues(): void
public function testBuildParameterAnnotationDataUsesConfiguredArrayExample(): void
{
$annotationGenerator = new MockAnnotationGenerator(new DocumentationGenerator());
$result = $this->annotationGenerator->buildParameterAnnotationData(
'someMethodName',
'statuses',
[],
['type' => 'string|array<int, string>']
);

$this->assertSame('true', $annotationGenerator->normaliseConfiguredParameterExample(true));
$this->assertSame('1.5', $annotationGenerator->normaliseConfiguredParameterExample(1.5));
$this->assertSame('["one","two"]', $annotationGenerator->normaliseConfiguredParameterExample(['one', 'two'], ['array' => 'string']));
$this->assertNull($annotationGenerator->normaliseConfiguredParameterExample(['one', 'two'], ['string' => null]));
$this->assertSame('["one","two"]', $annotationGenerator->normaliseConfiguredParameterExample(['one', 'two'], ['array' => 'string', 'string' => null]));
$this->assertNull($annotationGenerator->normaliseConfiguredParameterExample(['key' => 'value'], ['array' => 'string']));
$this->assertNull($annotationGenerator->normaliseConfiguredParameterExample([['nested']], ['array' => 'string']));
$this->assertSame('["running","finished"]', $result['example']);
}

public function testShouldUseParameterLevelExampleForScalarArrayUnions(): void
Expand Down Expand Up @@ -1410,9 +1423,122 @@ public function testBuildSchemaObjectArrays(): void
$this->expectNotToPerformAssertions();
}

public function testExpandTypeAliasesExpandsNamedArrayShapeAliases(): void
{
$annotationGenerator = new MockAnnotationGenerator(new DocumentationGenerator());
$annotationGenerator->setCurrentTypeAliases([
'VisitDescriptor' => 'array{idsite: int, idvisit: int}',
]);

$this->assertSame(
'array<int,array{idsite: int, idvisit: int}>',
$annotationGenerator->expandTypeAliases('array<int,VisitDescriptor>')
);
}

public function testParseArrayLikeTypeDefinitionReturnsScalarArraySchema(): void
{
$annotationGenerator = new MockAnnotationGenerator(new DocumentationGenerator());

$this->assertSame([
'type' => 'array',
'items' => [
'type' => 'integer',
],
], $annotationGenerator->parseArrayLikeTypeDefinition('list<int>'));
}

public function testParseArrayLikeTypeDefinitionReturnsArrayShapeItemSchema(): void
{
$annotationGenerator = new MockAnnotationGenerator(new DocumentationGenerator());

$this->assertSame([
'type' => 'array',
'items' => [
'type' => 'object',
'properties' => [
[
'name' => 'idsite',
'schema' => [
'type' => 'integer',
],
],
],
'required' => ['idsite'],
],
], $annotationGenerator->parseArrayLikeTypeDefinition('array<int,array{idsite:int}>'));
}

public function testParseArrayLikeTypeDefinitionReturnsStringKeyedShapeSchema(): void
{
$annotationGenerator = new MockAnnotationGenerator(new DocumentationGenerator());

$this->assertSame([
'type' => 'object',
'properties' => [
[
'name' => 'idsite',
'schema' => [
'type' => 'integer',
],
],
],
'required' => ['idsite'],
], $annotationGenerator->parseArrayLikeTypeDefinition('array<string,array{idsite:int}>'));
}

public function testCompileOperationLines(): void
{
// TODO - compileOperationLines method
$this->expectNotToPerformAssertions();
$lines = $this->annotationGenerator->compileOperationLines(
'/index.php?module=API&method=PrivacyManager.exportDataSubjects',
'PrivacyManager.exportDataSubjects',
'PrivacyManager',
[
'refs' => [],
'custom' => [
[
'name' => 'idSite',
'types' => ['integer' => null],
'description' => 'Site ID',
'required' => 'true',
'default' => NoDefaultValue::class,
'example' => '1',
],
[
'name' => 'visits',
'types' => ['array' => 'string'],
'description' => 'Visit descriptors.',
'required' => 'true',
'default' => NoDefaultValue::class,
'example' => '',
'_docType' => 'array<int,array{idsite:int,idvisit:int}>',
'_configExample' => [
[
'idsite' => 1,
'idvisit' => 12345,
],
],
'_isComplex' => true,
],
],
],
[
[
'code' => 200,
'description' => 'OK',
'schema' => ['@OA\Schema' => ['type="array"']],
],
],
'',
true
);
$annotation = implode("\n", $lines);

$this->assertStringContainsString('@OA\Post(', $annotation);
$this->assertStringContainsString('name="idSite"', $annotation);
$this->assertStringContainsString('in="query"', $annotation);
$this->assertStringContainsString('@OA\RequestBody(', $annotation);
$this->assertStringNotContainsString('name="visits"', $annotation);
$this->assertStringContainsString('property="visits"', $annotation);
}
}
2 changes: 1 addition & 1 deletion vue/dist/OpenApiDocs.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading