Skip to content

Commit

Permalink
Merge pull request #11 from sburba/feature/fix-escaping-mutants
Browse files Browse the repository at this point in the history
Feature/fix escaping mutants
  • Loading branch information
sburba committed Apr 12, 2019
2 parents 59d42ff + 5a821c0 commit 4063948
Show file tree
Hide file tree
Showing 10 changed files with 92 additions and 41 deletions.
4 changes: 2 additions & 2 deletions scripts/run_mutation_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ set -euo pipefail
vendor/bin/infection \
--threads=$(nproc) \
--coverage=test-results/phpunit/ \
--min-msi=89 \
--min-covered-msi=92
--min-msi=93 \
--min-covered-msi=96
4 changes: 2 additions & 2 deletions src/StrictJson.php
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ private function requireCompatibleTypes(ReflectionParameter $parameter, $value):
if (!$this->typesAreCompatible($parameter, $value)) {
$json_type = gettype($value);
throw new JsonFormatException(
"{$parameter->getName()} has type {$parameter->getType()} in class but has type $json_type in json"
"Parameter \"{$parameter->getName()}\" has type \"{$parameter->getType()}\" in class but has type \"$json_type\" in JSON"
);
}
}
Expand Down Expand Up @@ -295,7 +295,7 @@ private function mapClass($parsed_json, string $classname): object
throw new InvalidConfigurationException("$classname::__construct has parameter named $parameter_name with no specified type");
}

if (isset($parsed_json[$parameter_name])) {
if (array_key_exists($parameter_name, $parsed_json)) {
$value = $parsed_json[$parameter_name];
} elseif ($parameter->isDefaultValueAvailable()) {
// Guaranteed not to throw because we checked in the if condition
Expand Down
4 changes: 2 additions & 2 deletions test/Fixtures/BasicClass.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class BasicClass
private $array_prop;
/** @var int|null */
private $nullable_int_prop;
/** @var IntPropClass */
/** @var HasIntProp */
private $class_prop;

public function __construct(
Expand All @@ -25,7 +25,7 @@ public function __construct(
float $float_prop,
bool $bool_prop,
array $array_prop,
IntPropClass $class_prop,
HasIntProp $class_prop,
?int $nullable_int_prop = null
) {
$this->string_prop = $string_prop;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<?php namespace Burba\StrictJson\Fixtures;

class ClassPropClass
class HasClassProp
{
/** @var IntPropClass */
/** @var HasIntProp */
private $int_prop_class;

public function __construct(IntPropClass $int_prop_class)
public function __construct(HasIntProp $int_prop_class)
{
$this->int_prop_class = $int_prop_class;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace Burba\StrictJson\Fixtures;

class IntArrayPropClass
class HasIntArrayProp
{
/** @var int[] */
private $int_array_prop;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace Burba\StrictJson\Fixtures;

class IntPropClass
class HasIntProp
{
/** @var int */
private $int_prop;
Expand Down
12 changes: 12 additions & 0 deletions test/Fixtures/HasNullableProp.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php namespace Burba\StrictJson\Fixtures;

class HasNullableProp
{
/** @var string|null */
private $nullable_prop;

public function __construct(?string $nullable_prop)
{
$this->nullable_prop = $nullable_prop;
}
}
6 changes: 3 additions & 3 deletions test/Fixtures/IntPropClassAdapterThatAddsFour.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ class IntPropClassAdapterThatAddsFour
/**
* @param StrictJson $delegate
* @param array $parsed_json
* @return IntPropClass
* @return HasIntProp
*
* @throws JsonFormatException
*/
public function fromJson(StrictJson $delegate, array $parsed_json): IntPropClass
public function fromJson(StrictJson $delegate, array $parsed_json): HasIntProp
{
$original_number = $delegate->mapParsed($parsed_json['int_prop'], 'int');
return new IntPropClass($original_number + 4);
return new HasIntProp($original_number + 4);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?php namespace Burba\StrictJson\Fixtures;

class MissingConstructorClass
class MissingConstructor
{
}
91 changes: 65 additions & 26 deletions test/StrictJsonTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@
use Burba\StrictJson\Fixtures\AdapterWithoutFromJson;
use Burba\StrictJson\Fixtures\AdapterWithWrongNumberOfArguments;
use Burba\StrictJson\Fixtures\BasicClass;
use Burba\StrictJson\Fixtures\ClassPropClass;
use Burba\StrictJson\Fixtures\HasClassProp;
use Burba\StrictJson\Fixtures\Example\User;
use Burba\StrictJson\Fixtures\IntArrayPropClass;
use Burba\StrictJson\Fixtures\IntPropClass;
use Burba\StrictJson\Fixtures\HasIntArrayProp;
use Burba\StrictJson\Fixtures\HasIntProp;
use Burba\StrictJson\Fixtures\HasNullableProp;
use Burba\StrictJson\Fixtures\IntPropClassAdapterThatAddsFour;
use Burba\StrictJson\Fixtures\MissingConstructorClass;
use Burba\StrictJson\Fixtures\MissingConstructor;
use Burba\StrictJson\Fixtures\NoTypesInConstructor;
use PHPUnit\Framework\TestCase;

Expand Down Expand Up @@ -42,7 +43,7 @@ public function testBasicCase()
1.2,
true,
[1, 2, 3],
new IntPropClass(5)
new HasIntProp(5)
),
$mapper->map($json, BasicClass::class)
);
Expand All @@ -56,15 +57,15 @@ public function testIntArrayProperty()
$json = '{ "int_array_prop": [1, 2, 3] }';
$mapper = StrictJson::builder()
->addParameterAdapter(
IntArrayPropClass::class,
HasIntArrayProp::class,
'int_array_prop',
new ArrayAdapter('int')
)
->build();

$this->assertEquals(
new IntArrayPropClass([1, 2, 3]),
$mapper->map($json, IntArrayPropClass::class)
new HasIntArrayProp([1, 2, 3]),
$mapper->map($json, HasIntArrayProp::class)
);
}

Expand All @@ -74,13 +75,13 @@ public function testIntArrayProperty()
public function testClassAdapterForRootObject()
{
$mapper = StrictJson::builder()
->addClassAdapter(IntPropClass::class, new IntPropClassAdapterThatAddsFour())
->addClassAdapter(HasIntProp::class, new IntPropClassAdapterThatAddsFour())
->build();

$json = '{ "int_prop": 1 }';
$this->assertEquals(
new IntPropClass(5),
$mapper->map($json, IntPropClass::class)
new HasIntProp(5),
$mapper->map($json, HasIntProp::class)
);
}

Expand All @@ -90,13 +91,13 @@ public function testClassAdapterForRootObject()
public function testClassAdapterForProperty()
{
$mapper = StrictJson::builder()
->addClassAdapter(IntPropClass::class, new IntPropClassAdapterThatAddsFour())
->addClassAdapter(HasIntProp::class, new IntPropClassAdapterThatAddsFour())
->build();

$json = '{ "int_prop_class": { "int_prop": 1 } }';
$this->assertEquals(
new ClassPropClass(new IntPropClass(5)),
$mapper->map($json, ClassPropClass::class)
new HasClassProp(new HasIntProp(5)),
$mapper->map($json, HasClassProp::class)
);
}

Expand Down Expand Up @@ -134,11 +135,11 @@ public function testInvalidTargetType()
*/
public function testInvalidClassAdapter($adapter, $expected_exception_message)
{
$mapper = new StrictJson([IntPropClass::class => $adapter]);
$mapper = new StrictJson([HasIntProp::class => $adapter]);
$json = '{"does_not": "matter"}';
$this->expectException(InvalidConfigurationException::class);
$this->expectExceptionMessage($expected_exception_message);
$mapper->map($json, IntPropClass::class);
$mapper->map($json, HasIntProp::class);
}

/**
Expand All @@ -149,21 +150,21 @@ public function testInvalidClassAdapter($adapter, $expected_exception_message)
*/
public function testInvalidParameterAdapter($adapter)
{
$mapper = new StrictJson([], [IntPropClass::class => ['int_prop' => $adapter]]);
$mapper = new StrictJson([], [HasIntProp::class => ['int_prop' => $adapter]]);
$json = '{ "int_prop": 1 }';
$this->expectException(InvalidConfigurationException::class);
$mapper->map($json, IntPropClass::class);
$mapper->map($json, HasIntProp::class);
}

/**
* @throws JsonFormatException
*/
public function testClassAdapterThatThrowsJsonFormatException()
{
$mapper = new StrictJson([IntPropClass::class => new AdapterThatThrowsJsonFormatException()]);
$mapper = new StrictJson([HasIntProp::class => new AdapterThatThrowsJsonFormatException()]);
$json = '{"does_not": "matter"}';
$this->expectException(JsonFormatException::class);
$mapper->map($json, IntPropClass::class);
$mapper->map($json, HasIntProp::class);
}

/**
Expand All @@ -176,7 +177,7 @@ public function testMismatchedTypes()
$mapper = new StrictJson();
$json = '{"int_prop": "1"}';
$this->expectException(JsonFormatException::class);
$mapper->map($json, IntPropClass::class);
$mapper->map($json, HasIntProp::class);
}

/**
Expand All @@ -200,7 +201,7 @@ public function testMissingProperty()
$mapper = new StrictJson();
$json = '{"unknown_property": "value"}';
$this->expectException(JsonFormatException::class);
$mapper->map($json, IntPropClass::class);
$mapper->map($json, HasIntProp::class);
}

/**
Expand All @@ -209,11 +210,11 @@ public function testMissingProperty()
public function testJsonHasWrongItemType()
{
$mapper = StrictJson::builder()
->addParameterArrayAdapter(IntArrayPropClass::class, 'int_array_prop', 'int')
->addParameterArrayAdapter(HasIntArrayProp::class, 'int_array_prop', 'int')
->build();
$json = '{"int_array_prop": [1, "2", 3]}';
$this->expectException(JsonFormatException::class);
$mapper->map($json, IntArrayPropClass::class);
$mapper->map($json, HasIntArrayProp::class);
}

/**
Expand All @@ -224,9 +225,47 @@ public function testMissingConstructor()
$mapper = new StrictJson();
$json = '{"does not": "mattter"}';
$this->expectException(InvalidConfigurationException::class);
$classname = MissingConstructorClass::class;
$classname = MissingConstructor::class;
$this->expectExceptionMessage("Type $classname does not have a valid constructor");
$mapper->map($json, MissingConstructorClass::class);
$mapper->map($json, MissingConstructor::class);
}

/**
* Verify that StrictJson throws an exception when an Adapter specifies a type but the JSON type doesn't match
*
* @throws JsonFormatException
*/
public function testMismatchedAdapterParameterJsonField()
{
$mapper = new StrictJson([HasIntProp::class => new IntPropClassAdapterThatAddsFour()]);
$json = '{"int_prop_class": 4}';
$this->expectException(JsonFormatException::class);
$this->expectExceptionMessage('Parameter "parsed_json" has type "array" in class but has type "integer" in JSON');
$mapper->map($json, HasClassProp::class);
}

/**
* @throws JsonFormatException
*/
public function testNullableParameterWithNullValue()
{
$mapper = new StrictJson();
$json = '{"nullable_prop": null}';
$this->assertEquals(
new HasNullableProp(null),
$mapper->map($json, HasNullableProp::class)
);
}

/**
* @throws JsonFormatException
*/
public function testNullValueForNonNullableParameter()
{
$mapper = new StrictJson();
$json = '{"int_prop": null}';
$this->expectException(JsonFormatException::class);
$mapper->map($json, HasIntProp::class);
}

public function invalidAdapterProvider()
Expand Down

0 comments on commit 4063948

Please sign in to comment.