Skip to content
Merged
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
14 changes: 7 additions & 7 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,25 @@
}
],
"require": {
"php": "^8.0",
"php": "^8.4.2",
"ext-json": "*",
"cebe/php-openapi": "^1.7",
"fakerphp/faker": "^1.20",
"league/openapi-psr7-validator": "^0.18",
"thecodingmachine/safe": "^2.4"
"thecodingmachine/safe": "^3.0"
},
"require-dev": {
"doctrine/coding-standard": "^11",
"ergebnis/composer-normalize": "^2.29",
"infection/infection": "^0.26",
"infection/infection": "^0.32",
"phpstan/extension-installer": "^1.1",
"phpstan/phpstan": "^1.9",
"phpstan/phpstan-phpunit": "^1",
"phpstan/phpstan": "^2.1",
"phpstan/phpstan-phpunit": "^2.0",
"phpunit/phpunit": "^9.5",
"rector/rector": "^0.15.2",
"rector/rector": "^2.4",
"spatie/phpunit-snapshot-assertions": "^4.2",
"symfony/var-dumper": "^6",
"thecodingmachine/phpstan-safe-rule": "^1.2"
"thecodingmachine/phpstan-safe-rule": "^1.4"
},
"prefer-stable": true,
"autoload": {
Expand Down
21 changes: 1 addition & 20 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
@@ -1,21 +1,2 @@
parameters:
ignoreErrors:
-
message: "#^Method Vural\\\\OpenAPIFaker\\\\OpenAPIFaker\\:\\:findComponentSchema\\(\\) should return cebe\\\\openapi\\\\spec\\\\Schema but returns cebe\\\\openapi\\\\spec\\\\Reference\\|cebe\\\\openapi\\\\spec\\\\Schema\\.$#"
count: 1
path: src/OpenAPIFaker.php

-
message: "#^Parameter \\#1 \\$schema of class Vural\\\\OpenAPIFaker\\\\SchemaFaker\\\\SchemaFaker constructor expects cebe\\\\openapi\\\\spec\\\\Schema, cebe\\\\openapi\\\\spec\\\\Reference\\|cebe\\\\openapi\\\\spec\\\\Schema\\|null given\\.$#"
count: 1
path: src/SchemaFaker/ArrayFaker.php

-
message: "#^Parameter \\#1 \\$schema of class Vural\\\\OpenAPIFaker\\\\SchemaFaker\\\\SchemaFaker constructor expects cebe\\\\openapi\\\\spec\\\\Schema, cebe\\\\openapi\\\\spec\\\\Reference\\|cebe\\\\openapi\\\\spec\\\\Schema\\|null given\\.$#"
count: 1
path: src/SchemaFaker/RequestFaker.php

-
message: "#^Parameter \\#1 \\$schema of class Vural\\\\OpenAPIFaker\\\\SchemaFaker\\\\SchemaFaker constructor expects cebe\\\\openapi\\\\spec\\\\Schema, cebe\\\\openapi\\\\spec\\\\Reference\\|cebe\\\\openapi\\\\spec\\\\Schema\\|null given\\.$#"
count: 1
path: src/SchemaFaker/ResponseFaker.php
ignoreErrors:
45 changes: 28 additions & 17 deletions src/OpenAPIFaker.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
use Vural\OpenAPIFaker\SchemaFaker\ResponseFaker;
use Vural\OpenAPIFaker\SchemaFaker\SchemaFaker;

use function array_intersect_key;
use function array_key_exists;
use function method_exists;
use function strtolower;

final class OpenAPIFaker
Expand All @@ -46,7 +46,7 @@ private function __construct()
public static function createFromJson(string $json): self
{
$instance = new self();
$instance->openAPISchema = (new LeagueOpenAPI\SchemaFactory\JsonFactory($json))->createSchema();
$instance->openAPISchema = new LeagueOpenAPI\SchemaFactory\JsonFactory($json)->createSchema();

return $instance;
}
Expand All @@ -58,7 +58,7 @@ public static function createFromJson(string $json): self
public static function createFromYaml(string $yaml): self
{
$instance = new self();
$instance->openAPISchema = (new LeagueOpenAPI\SchemaFactory\YamlFactory($yaml))->createSchema();
$instance->openAPISchema = new LeagueOpenAPI\SchemaFactory\YamlFactory($yaml)->createSchema();

return $instance;
}
Expand All @@ -74,6 +74,7 @@ public static function createFromSchema(OpenApi $schema): self
/**
* @throws NoPath
* @throws NoRequest
* @throws NoExample
*/
public function mockRequest(
string $path,
Expand All @@ -82,7 +83,7 @@ public function mockRequest(
): mixed {
$content = $this->findContentForRequest($path, $method, $contentType);

return (new RequestFaker($content, $this->options))->generate();
return new RequestFaker($content, $this->options)->generate();
}

/**
Expand All @@ -98,12 +99,13 @@ public function mockRequestForExample(
): mixed {
$content = $this->findContentForRequest($path, $method, $contentType);

return (new RequestFaker($content, $this->options))->generate($exampleName);
return new RequestFaker($content, $this->options)->generate($exampleName);
}

/**
* @throws NoPath
* @throws NoResponse
* @throws NoExample
*/
public function mockResponse(
string $path,
Expand All @@ -113,7 +115,7 @@ public function mockResponse(
): mixed {
$content = $this->findContentForResponse($path, $method, $statusCode, $contentType);

return (new ResponseFaker($content, $this->options))->generate();
return new ResponseFaker($content, $this->options)->generate();
}

/**
Expand All @@ -130,15 +132,15 @@ public function mockResponseForExample(
): mixed {
$content = $this->findContentForResponse($path, $method, $statusCode, $contentType);

return (new ResponseFaker($content, $this->options))->generate($exampleName);
return new ResponseFaker($content, $this->options)->generate($exampleName);
}

/** @throws Exception */
public function mockComponentSchema(string $schemaName): mixed
{
$schema = $this->findComponentSchema($schemaName);

return (new SchemaFaker($schema, $this->options))->generate();
return new SchemaFaker($schema, $this->options)->generate();
}

/** @throws Exception */
Expand All @@ -153,15 +155,18 @@ public function mockComponentSchemaForExample(string $schemaName): mixed
return $schema->example;
}

/** @param array{minItems?:?int, maxItems?:?int, alwaysFakeOptionals?:bool, strategy?:string} $options */
/** @param array{minItems?:int|null, maxItems?:int|null, alwaysFakeOptionals?:bool, strategy?:string} $options */
public function setOptions(array $options): self
{
foreach ($options as $key => $value) {
if (! method_exists($this->options, 'set' . $key)) {
continue;
}

$this->options->{'set' . $key}($value);
$knownKeys = ['minItems' => 1, 'maxItems' => 1, 'alwaysFakeOptionals' => 1, 'strategy' => 1];

foreach (array_intersect_key($options, $knownKeys) as $key => $value) {
match ($key) {
'minItems' => $value !== null ? $this->options->setMinItems($value) : null,
'maxItems' => $value !== null ? $this->options->setMaxItems($value) : null,
'alwaysFakeOptionals' => $this->options->setAlwaysFakeOptionals($value),
default => $this->options->setStrategy($value),
};
}

return $this;
Expand All @@ -171,7 +176,7 @@ public function setOptions(array $options): self
private function findOperation(string $path, string $method): Operation
{
try {
$operation = (new LeagueOpenAPI\SpecFinder($this->openAPISchema))
$operation = new LeagueOpenAPI\SpecFinder($this->openAPISchema)
->findOperationSpec(new LeagueOpenAPI\OperationAddress($path, strtolower($method)));
} catch (LeagueOpenAPI\Exception\NoPath) {
throw NoPath::forPathAndMethod($path, $method);
Expand Down Expand Up @@ -254,6 +259,12 @@ private function findComponentSchema(string $schemaName): Schema
throw NoSchema::forComponentName($schemaName);
}

return $this->openAPISchema->components->schemas[$schemaName];
$schema = $this->openAPISchema->components->schemas[$schemaName];

if (! $schema instanceof Schema) {
throw NoSchema::forComponentName($schemaName);
}

return $schema;
}
}
14 changes: 7 additions & 7 deletions src/Options.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@

final class Options
{
public const STRATEGY_STATIC = 'static';
public const string STRATEGY_STATIC = 'static';

public const STRATEGY_DYNAMIC = 'dynamic';
public const string STRATEGY_DYNAMIC = 'dynamic';

private int|null $minItems = null;

Expand All @@ -23,31 +23,31 @@ final class Options

private string $strategy = self::STRATEGY_DYNAMIC;

private const ALLOWED = [self::STRATEGY_STATIC, self::STRATEGY_DYNAMIC];
private const array ALLOWED = [self::STRATEGY_STATIC, self::STRATEGY_DYNAMIC];

public function setMinItems(int $minItems): Options
public function setMinItems(int $minItems): self
{
$this->minItems = $minItems;

return $this;
}

public function setMaxItems(int $maxItems): Options
public function setMaxItems(int $maxItems): self
{
$this->maxItems = $maxItems;

return $this;
}

public function setAlwaysFakeOptionals(bool $alwaysFakeOptionals): Options
public function setAlwaysFakeOptionals(bool $alwaysFakeOptionals): self
{
$this->alwaysFakeOptionals = $alwaysFakeOptionals;

return $this;
}

/** @throws InvalidArgumentException */
public function setStrategy(string $strategy): Options
public function setStrategy(string $strategy): self
{
if (! in_array($strategy, self::ALLOWED, true)) {
throw new InvalidArgumentException(sprintf('Unknown generation strategy: %s', $strategy));
Expand Down
13 changes: 7 additions & 6 deletions src/SchemaFaker/ArrayFaker.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@
use Vural\OpenAPIFaker\Options;

use function array_unique;
use function array_values;
use function count;
use function is_array;

use const SORT_REGULAR;
use const SORT_STRING;

/** @internal */
final class ArrayFaker
Expand All @@ -30,12 +29,10 @@ public static function generate(Schema $schema, Options $options): array
}

if ($options->getMinItems() && $minimum < $options->getMinItems()) {
/** @var int $minimum */
$minimum = $options->getMinItems();
}

if ($options->getMaxItems() && $maximum > $options->getMaxItems()) {
/** @var int $maximum */
$maximum = $options->getMaxItems();

// Don't allow user to set min items above our maximum
Expand All @@ -48,6 +45,10 @@ public static function generate(Schema $schema, Options $options): array

$fakeData = [];

if (! $schema->items instanceof Schema) {
return $fakeData;
}

$itemSchema = new SchemaFaker($schema->items, $options);

for ($i = 0; $i < $itemSize; ++$i) {
Expand All @@ -57,15 +58,15 @@ public static function generate(Schema $schema, Options $options): array
continue;
}

$uniqueData = array_unique($fakeData, is_array($fakeData[0]) ? SORT_REGULAR : SORT_STRING);
$uniqueData = array_unique($fakeData, SORT_REGULAR);

if (count($uniqueData) > count($fakeData)) {
continue;
}

$i -= count($fakeData) - count($uniqueData);

$fakeData = $uniqueData;
$fakeData = array_values($uniqueData);
}

return $fakeData;
Expand Down
4 changes: 2 additions & 2 deletions src/SchemaFaker/BooleanFaker.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public static function generate(Schema $schema, Options $options): bool|null

private static function generateDynamic(Schema $schema): bool
{
if ($schema->enum !== null) {
if (! empty($schema->enum)) {
return Base::randomElement($schema->enum);
}

Expand All @@ -46,7 +46,7 @@ private static function generateStatic(Schema $schema): bool|null
return null;
}

if ($schema->enum !== null) {
if (! empty($schema->enum)) {
$enums = $schema->enum;

return reset($enums);
Expand Down
4 changes: 2 additions & 2 deletions src/SchemaFaker/NumberFaker.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public static function generate(Schema $schema, Options $options): int|float|nul

private static function generateDynamic(Schema $schema): int|float|null
{
if ($schema->enum !== null) {
if (! empty($schema->enum)) {
return Base::randomElement($schema->enum);
}

Expand Down Expand Up @@ -65,7 +65,7 @@ private static function generateStatic(Schema $schema): int|float|null
return null;
}

if ($schema->enum !== null) {
if (! empty($schema->enum)) {
$enums = $schema->enum;

return reset($enums);
Expand Down
17 changes: 10 additions & 7 deletions src/SchemaFaker/ObjectFaker.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,26 +34,29 @@ public static function generate(Schema $schema, Options $options, bool $request

$allPropertyKeys = array_merge($requiredKeys, $selectedOptionalKeys);

/** @var Schema $property */
foreach ($schema->properties as $key => $property) {
if ($property instanceof Schema && (($request && $property->readOnly) || (! $request && $property->writeOnly))) {
if (! $property instanceof Schema) {
continue;
}

if (($request && $property->readOnly) || (! $request && $property->writeOnly)) {
continue;
}

if (
! $options->getAlwaysFakeOptionals()
&& ! $useStaticStrategy
! $useStaticStrategy
&& ! $options->getAlwaysFakeOptionals()
&& ! in_array($key, $allPropertyKeys, true)
) {
continue;
}

$value = (new SchemaFaker($property, $options))->generate();
$value = new SchemaFaker($property, $options)->generate();

if (
! $options->getAlwaysFakeOptionals()
&& $useStaticStrategy
$useStaticStrategy
&& $property->nullable
&& ! $options->getAlwaysFakeOptionals()
) {
continue;
}
Expand Down
Loading
Loading