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
4 changes: 2 additions & 2 deletions src/Processor/DefaultProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public function __construct(
) {
}

public static function fromFiltersAndValidators(Filter|Validator ...$chain): self
public static function fromFiltersAndValidators(Filter | Validator ...$chain): self
{
return new self(new Field('', ...$chain));
}
Expand All @@ -34,7 +34,7 @@ public function __toPHP(): string

public function processes(): string
{
return $this->processor->processes();
return '';
}

public function process(FieldName $parentFieldName, mixed $value): Result
Expand Down
9 changes: 4 additions & 5 deletions src/Processor/FieldSet.php
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ public function processes(): string

public function process(FieldName $parentFieldName, mixed $value): Result
{
$fieldName = $parentFieldName->push(new Fieldname($this->processes));
$fieldName = $parentFieldName->push(new FieldName($this->processes));
$fieldSetResult = Result::noResult($value);

if (isset($this->before)) {
Expand All @@ -132,7 +132,7 @@ public function process(FieldName $parentFieldName, mixed $value): Result
}
}

if (!empty($this->chain)) {
if (!empty($this->chain) || isset($this->default)) {
if (!is_array($value)) {
return Result::invalid(
$value,
Expand Down Expand Up @@ -161,10 +161,9 @@ public function process(FieldName $parentFieldName, mixed $value): Result
$this->handleProcessor($this->default, $fieldName, $value[$fieldKey], $fieldSetResult);
}
}
}

$fieldSetResult = $fieldSetResult->merge(Result::noResult($value));

$fieldSetResult = $fieldSetResult->merge(Result::noResult($value));
}
if (isset($this->after) && $fieldSetResult->isValid()) {
$this->handleProcessor($this->after, $fieldName, $value, $fieldSetResult);

Expand Down
31 changes: 31 additions & 0 deletions tests/OpenAPI/Builder/ObjectsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
use Membrane\OpenAPI\Builder\Numeric;
use Membrane\OpenAPI\Builder\Objects;
use Membrane\OpenAPI\Builder\Strings;
use Membrane\OpenAPI\Builder\TrueFalse;
use Membrane\OpenAPI\Processor\AnyOf;
use Membrane\OpenAPI\Processor\OneOf;
use Membrane\OpenAPI\Specification;
use Membrane\Processor;
use Membrane\Processor\BeforeSet;
Expand All @@ -20,6 +22,7 @@
use Membrane\Validator\FieldSet\FixedFields;
use Membrane\Validator\FieldSet\RequiredFields;
use Membrane\Validator\Type\IsArray;
use Membrane\Validator\Type\IsBool;
use Membrane\Validator\Type\IsInt;
use Membrane\Validator\Type\IsNull;
use Membrane\Validator\Type\IsString;
Expand All @@ -32,15 +35,18 @@
#[CoversClass(Objects::class)]
#[CoversClass(APIBuilder::class)]
#[UsesClass(Numeric::class)]
#[UsesClass(TrueFalse::class)]
#[UsesClass(Strings::class)]
#[UsesClass(AnyOf::class)]
#[UsesClass(Specification\APISchema::class)]
#[UsesClass(Specification\Numeric::class)]
#[UsesClass(Specification\Strings::class)]
#[UsesClass(Specification\TrueFalse::class)]
#[UsesClass(BeforeSet::class)]
#[UsesClass(DefaultProcessor::class)]
#[UsesClass(Field::class)]
#[UsesClass(FieldSet::class)]
#[UsesClass(OneOf::class)]
#[UsesClass(Contained::class)]
#[UsesClass(FixedFields::class)]
#[UsesClass(RequiredFields::class)]
Expand Down Expand Up @@ -83,6 +89,31 @@ public static function specificationsToBuild(): array
),
new FieldSet('', new BeforeSet(new IsArray(), new FixedFields('a')), new Field('a', new IsInt())),
],
'complex additional properties' => [
new Specification\Objects(
'',
new Schema([
'type' => 'object',
'additionalProperties' => [
'oneOf' => [
new Schema(['type' => 'boolean']),
new Schema(['type' => 'integer']),
],
],
])
),
new FieldSet(
'',
new BeforeSet(new IsArray()),
new DefaultProcessor(
new OneOf(
'',
new Field('', new IsBool()),
new Field('', new IsInt()),
)
)
),
],
'detailed input' => [
new Specification\Objects(
'',
Expand Down
180 changes: 75 additions & 105 deletions tests/Processor/DefaultProcessorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,20 @@

namespace Processor;

use Generator;
use Membrane\Filter;
use Membrane\Filter\Type\ToFloat;
use Membrane\OpenAPI\Processor\AllOf;
use Membrane\OpenAPI\Processor\AnyOf;
use Membrane\OpenAPI\Processor\OneOf;
use Membrane\Processor;
use Membrane\Processor\DefaultProcessor;
use Membrane\Processor\Field;
use Membrane\Result\FieldName;
use Membrane\Result\Message;
use Membrane\Result\MessageSet;
use Membrane\Result\Result;
use Membrane\Validator\Type\IsFloat;
use Membrane\Validator;
use Membrane\Validator\Utility\Fails;
use Membrane\Validator\Utility\Indifferent;
use Membrane\Validator\Utility\Passes;
Expand All @@ -28,139 +34,103 @@
#[UsesClass(MessageSet::class)]
#[UsesClass(Message::class)]
#[UsesClass(ToFloat::class)]
#[UsesClass(IsFloat::class)]
#[UsesClass(Validator\Type\IsFloat::class)]
#[UsesClass(Validator\Type\IsBool::class)]
#[UsesClass(Validator\Type\IsInt::class)]
#[UsesClass(Validator\Type\IsNumber::class)]
#[UsesClass(Fails::class)]
#[UsesClass(Indifferent::class)]
#[UsesClass(Passes::class)]
#[UsesClass(AllOf::class)]
#[UsesClass(AnyOf::class)]
#[UsesClass(OneOf::class)]
class DefaultProcessorTest extends TestCase
{
public static function dataSetsToConvertToString(): array
public static function provideFiltersAndValidators(): Generator
{
return [
'No chain returns empty string' => [
'',
DefaultProcessor::fromFiltersAndValidators(),
],
'Single item in chain returns one bullet point' => [
"\n\t- will return valid.",
DefaultProcessor::fromFiltersAndValidators(new Passes()),
],
'guaranteed noResult in chain is ignored' => [
'',
DefaultProcessor::fromFiltersAndValidators(new Indifferent()),
],
'Three items in chain returns three bullet points' => [
"\n\t- will return valid.\n\t- will return invalid.\n\t- will return valid.",
DefaultProcessor::fromFiltersAndValidators(new Passes(), new Fails(), new Passes()),
],
];
yield 'nothing' => [];
yield '1 fails' => [new Fails()];
yield '1 indifferent' => [new Indifferent()];
yield '1 passes' => [new Passes()];
yield '3 fails' => [new Fails(), new Fails(), new Fails()];
yield '3 indifferents' => [new Indifferent(), new Indifferent(), new Indifferent()];
yield '3 passes' => [new Passes(), new Passes(), new Passes()];
yield '1 fails, 1 indifferent, 1 passes' => [new Fails(), new Indifferent(), new Passes()];
yield '1 passes, 2 indifferent' => [new Passes(), new Indifferent(), new Indifferent()];
yield '1 toFloat' => [new ToFloat()];
yield '1 isFloat, 1 toFloat' => [new Validator\Type\IsFloat(), new ToFloat()];
yield '1 toFloat, 1 isFloat' => [new ToFloat(), new Validator\Type\IsFloat()];
}

#[DataProvider('dataSetsToConvertToString')]
#[Test]
public function toStringTest(string $expected, DefaultProcessor $sut): void
#[Test, DataProvider('provideFiltersAndValidators')]
public function itCanBeStaticallyConstructed(Filter | Validator ...$chain): void
{
$actual = (string)$sut;
$expected = new DefaultProcessor(new Field('', ...$chain));

$actual = DefaultProcessor::fromFiltersAndValidators(...$chain);

self::assertSame($expected, $actual);
self::assertEquals($expected, $actual);
}

public static function dataSetsToConvertToPHPString(): array
#[Test, DataProvider('provideFiltersAndValidators')]
public function toStringTest(Filter | Validator ...$chain): void
{
return [
'no chain' => [
DefaultProcessor::fromFiltersAndValidators(),
],
'1 validator' => [
DefaultProcessor::fromFiltersAndValidators(new Passes()),
],
'3 validators' => [
DefaultProcessor::fromFiltersAndValidators(new Passes(), new Fails(), new Passes()),
],
];
$expected = '';
foreach ($chain as $item) {
if ((string)$item !== '') {
$expected .= sprintf("\n\t- %s.", $item);
}
}

$sut = DefaultProcessor::fromFiltersAndValidators(...$chain);

self::assertSame($expected, (string)$sut);
}

#[DataProvider('dataSetsToConvertToPHPString')]
#[Test]
public function toPHPTest(DefaultProcessor $sut): void
#[Test, DataProvider('provideFiltersAndValidators')]
public function toPHPTest(Filter | Validator ...$chain): void
{
$actual = $sut->__toPHP();
$sut = DefaultProcessor::fromFiltersAndValidators(...$chain);

$actual = sprintf('return %s;', $sut->__toPHP());

self::assertEquals($sut, eval('return ' . $actual . ';'));
self::assertEquals($sut, eval($actual));
}

#[Test]
public function processesTest(): void
{
$expected = '';
$sut = DefaultProcessor::fromFiltersAndValidators();
$sut = new DefaultProcessor(new Field('This wont show up'));

$actual = $sut->processes();

self::assertSame($expected, $actual);
self::assertSame('', $sut->processes());
}

public static function dataSetsForFiltersOrValidators(): array
public static function provideProcessors(): Generator
{
return [
'no chain returns noResult' => [
Result::noResult(1),
DefaultProcessor::fromFiltersAndValidators(),
1,
],
'checks it can return valid' => [
Result::valid(1),
DefaultProcessor::fromFiltersAndValidators(new Passes()),
1,
],
'checks it can return invalid' => [
Result::invalid(
1,
new MessageSet(new FieldName('', 'parent field'), new Message('I always fail', []))
),
DefaultProcessor::fromFiltersAndValidators(new Fails()),
1,
],
'checks it can return noResult' => [
Result::noResult(1),
DefaultProcessor::fromFiltersAndValidators(new Indifferent()),
1,
],
'checks it keeps track of previous results' => [
Result::valid(1),
DefaultProcessor::fromFiltersAndValidators(new Passes(), new Indifferent(), new Indifferent()),
1,

],
'checks it can make changes to value' => [
Result::noResult(5.0),
DefaultProcessor::fromFiltersAndValidators(new ToFloat()),
'5',
],
'checks that changes made to value persist and chain runs in correct order' => [
Result::valid(5.0),
DefaultProcessor::fromFiltersAndValidators(new ToFloat(), new IsFloat()),
'5',
],
'checks that chain stops as soon as result is invalid' => [
Result::invalid(
'5',
new MessageSet(
new FieldName('', 'parent field'),
new Message('IsFloat expects float value, %s passed instead', ['string'])
)
),
DefaultProcessor::fromFiltersAndValidators(new IsFloat(), new ToFloat()),
'5',
],
];
foreach (self::provideFiltersAndValidators() as $case => $chain) {
yield sprintf('input of 5 and a field with %s', $case) => [5, new Field('', ...$chain)];
}

$isBool = new Field('', new Validator\Type\IsBool());
$isInt = new Field('', new Validator\Type\IsInt());
$isNumber = new Field('', new Validator\Type\IsNumber());

foreach ([true, 5, 5.5,] as $input) {
yield sprintf('input of %s and a oneOf: bool|int', $input) => [$input, new OneOf('', $isBool, $isInt)];
yield sprintf('input of %s and an anyOf: bool|int', $input) => [$input, new AnyOf('', $isBool, $isInt)];
yield sprintf('input of %s and an allOf: bool|int', $input) => [$input, new AllOf('', $isBool, $isInt)];
yield sprintf('input of %s and a oneOf: int|number', $input) => [$input, new OneOf('', $isInt, $isNumber)];
yield sprintf('input of %s and an anyOf: int|number', $input) => [$input, new AnyOf('', $isInt, $isNumber)];
yield sprintf('input of %s and an allOf: int|number', $input) => [$input, new AllOf('', $isInt, $isNumber)];
}
}

#[DataProvider('dataSetsForFiltersOrValidators')]
#[Test]
public function processesCallsFilterOrValidateMethods(Result $expected, DefaultProcessor $sut, mixed $input): void
#[Test, DataProvider('provideProcessors')]
public function itUsesTheWrappedProcessorToProcess(mixed $input, Processor $processor): void
{
$actual = $sut->process(new FieldName('parent field'), $input);
$expected = $processor->process(new FieldName(''), $input);

$actual = (new DefaultProcessor($processor))->process(new FieldName(''), $input);

self::assertEquals($expected, $actual);
self::assertSame($expected->value, $actual->value);
Expand Down
Loading