Skip to content

Commit

Permalink
Merge 5ff7dd6 into 6607eac
Browse files Browse the repository at this point in the history
  • Loading branch information
Firehed committed Mar 18, 2018
2 parents 6607eac + 5ff7dd6 commit 2b9ae54
Show file tree
Hide file tree
Showing 2 changed files with 164 additions and 11 deletions.
53 changes: 42 additions & 11 deletions src/Containers/ParsedInput.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public function validate(ValidationInterface $validator): SafeInput {
$clean_out = [];
$missing = [];
$invalid = [];

$unexpected = [];

foreach ($validator->getRequiredInputs() as $key => $input) {
if (!isset($data[$key]) && !array_key_exists($key, $data)) {
Expand All @@ -58,10 +58,20 @@ public function validate(ValidationInterface $validator): SafeInput {
try {
$clean_out[$key] = $input->setValue($data[$key])
->evaluate();
unset($data[$key]);
}
catch (UnexpectedValueException $e) {
} catch (InputException $e) {
$invalid = array_merge($invalid, array_map(function ($k) use ($key) {
return $key . '.' . $k;
}, $e->getInvalid()));
$missing = array_merge($missing, array_map(function ($k) use ($key) {
return $key . '.' . $k;
}, $e->getMissing()));
$unexpected = array_merge($unexpected, array_map(function ($k) use ($key) {
return $key . '.' . $k;
}, $e->getUnexpected()));
} catch (UnexpectedValueException $e) {
$invalid[] = $key;
} finally {
unset($data[$key]);
}
} unset($key, $input);

Expand All @@ -70,13 +80,22 @@ public function validate(ValidationInterface $validator): SafeInput {
try {
$clean_out[$key] = $input->setValue($data[$key])
->evaluate();
unset($data[$key]);
}
catch (UnexpectedValueException $e) {
} catch (InputException $e) {
$invalid = array_merge($invalid, array_map(function ($k) use ($key) {
return $key . '.' . $k;
}, $e->getInvalid()));
$missing = array_merge($missing, array_map(function ($k) use ($key) {
return $key . '.' . $k;
}, $e->getMissing()));
$unexpected = array_merge($unexpected, array_map(function ($k) use ($key) {
return $key . '.' . $k;
}, $e->getUnexpected()));
} catch (UnexpectedValueException $e) {
$invalid[] = $key;
} finally {
unset($data[$key]);
}
}
else {
} else {
// Somehow, there should be a concept of "use default
// value" (null unless overridden) so that optional inputs
// can correctly be resolved as dependencies
Expand All @@ -85,14 +104,26 @@ public function validate(ValidationInterface $validator): SafeInput {
}
} unset($key, $input);

$unexpected = array_merge($unexpected, array_keys($data));

// This is a not-beautiful way of expressing "if at least two error
// arrays are nonempty", since this should retain the more specific
// exception code when only one type of error is present.
if (($missing && ($invalid || $unexpected)) || ($invalid && $unexpected)) {
throw new InputException(
InputException::MULTIPLE_VALUE_ERRORS,
compact('invalid', 'missing', 'unexpected')
);
}

if ($missing) {
throw new InputException(InputException::MISSING_VALUES, $missing);
}
if ($invalid) {
throw new InputException(InputException::INVALID_VALUES, $invalid);
}
if ($data) {
throw new InputException(InputException::UNEXPECTED_VALUES, $data);
if ($unexpected) {
throw new InputException(InputException::UNEXPECTED_VALUES, $unexpected);
}

$this->setData($clean_out);
Expand Down
122 changes: 122 additions & 0 deletions tests/Containers/ParsedInputTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Firehed\Input\Containers;

use Firehed\Input\Exceptions\InputException;
use Firehed\Input\Objects\InputObject;

/**
Expand Down Expand Up @@ -186,7 +187,128 @@ public function testMissingOptionalParametersAreSetToNull() {
} // testMissingOptionalParametersAreSetToNull


// ----(Validation:Nesting)-------------------------------------------------

/**
* @covers ::validate
* @dataProvider nestedValidationExceptions
*/
public function testValidateHandlesInputExceptions(
InputException $ex,
array $invalid,
array $missing,
array $unexpected,
bool $required
) {
$io = $this->createMock(InputObject::class);
$io->expects($this->atLeastOnce())
->method('evaluate')
->will($this->throwException($ex));
if ($required) {
$this->addRequired('struct', $io);
$msg = 'Required:';
} else {
$this->addOptional('struct', $io);
$msg = 'Optional:';
}
$parsed = new ParsedInput(['struct' => ['a' => 1, 'b' => 2]]);
try {
$ret = $parsed->validate($this->getValidation());
$this->fail('An inputException should have been thrown');
} catch (InputException $e) {
$this->assertSame($invalid, $e->getInvalid(), "$msg Invalid was wrong");
$this->assertSame($missing, $e->getMissing(), "$msg Missing was wrong");
$this->assertSame($unexpected, $e->getUnexpected(), "$msg Unexpected was wrong");
}
}


public function nestedValidationExceptions()
{

return [
// Required inputs
[
new InputException(InputException::INVALID_VALUES, ['a']),
['struct.a'],
[],
[],
true,
],
[
new InputException(InputException::MISSING_VALUES, ['c']),
[],
['struct.c'],
[],
true,
],
[
new InputException(InputException::MISSING_VALUES, ['c', 'd']),
[],
['struct.c', 'struct.d'],
[],
true,
],
[
new InputException(InputException::UNEXPECTED_VALUES, ['b']),
[],
[],
['struct.b'],
true,
],
[
new InputException(InputException::MULTIPLE_VALUE_ERRORS, [
'invalid' => ['a'],
'missing' => ['c'],
'unexpected' => ['b'],
]),
['struct.a'],
['struct.c'],
['struct.b'],
true,
],
// Optional inputs
[
new InputException(InputException::INVALID_VALUES, ['a']),
['struct.a'],
[],
[],
false,
],
[
new InputException(InputException::MISSING_VALUES, ['c']),
[],
['struct.c'],
[],
false,
],
[
new InputException(InputException::MISSING_VALUES, ['c', 'd']),
[],
['struct.c', 'struct.d'],
[],
false,
],
[
new InputException(InputException::UNEXPECTED_VALUES, ['b']),
[],
[],
['struct.b'],
false,
],
[
new InputException(InputException::MULTIPLE_VALUE_ERRORS, [
'invalid' => ['a'],
'missing' => ['c'],
'unexpected' => ['b'],
]),
['struct.a'],
['struct.c'],
['struct.b'],
false,
],
];
}

// ----(Helpers)-----------------------------------------------------------

Expand Down

0 comments on commit 2b9ae54

Please sign in to comment.