Skip to content

Commit

Permalink
Fixed #891
Browse files Browse the repository at this point in the history
Better messages when JSON-related assertions receive invalid JSON.
  • Loading branch information
whatthejeff committed May 4, 2013
1 parent d4dee43 commit aa917f1
Show file tree
Hide file tree
Showing 10 changed files with 215 additions and 73 deletions.
1 change: 1 addition & 0 deletions ChangeLog.md
Expand Up @@ -8,6 +8,7 @@ PHPUnit 3.7.20

* Fixed #883: Stand-alone functions `logicalAnd()`, `logicalOr()`, and `logicalXor()` did not work.
* Fixed #890: Correctly parse single-line @expectedException annotations.
* Fixed #891: Better messages when JSON-related assertions receive invalid JSON.
* Fixed #896: Use the proper `toString()` method inside `PHPUnit_Framework_TestFailure::toString()`.
* Fixed #902: Allow symfony/yaml >=2.0,<3.0

Expand Down
1 change: 1 addition & 0 deletions PHPUnit/Autoload.php
Expand Up @@ -118,6 +118,7 @@ function ($class)
'phpunit_framework_constraint_isfalse' => '/Framework/Constraint/IsFalse.php',
'phpunit_framework_constraint_isidentical' => '/Framework/Constraint/IsIdentical.php',
'phpunit_framework_constraint_isinstanceof' => '/Framework/Constraint/IsInstanceOf.php',
'phpunit_framework_constraint_isjson' => '/Framework/Constraint/IsJson.php',
'phpunit_framework_constraint_isnull' => '/Framework/Constraint/IsNull.php',
'phpunit_framework_constraint_istrue' => '/Framework/Constraint/IsTrue.php',
'phpunit_framework_constraint_istype' => '/Framework/Constraint/IsType.php',
Expand Down
90 changes: 50 additions & 40 deletions PHPUnit/Framework/Assert.php
Expand Up @@ -2134,6 +2134,22 @@ public static function assertThat($value, PHPUnit_Framework_Constraint $constrai
$constraint->evaluate($value, $message);
}

/**
* Asserts that a string is a valid JSON string.
*
* @param string $filename
* @param string $message
* @since Method available since Release 3.7.20
*/
public static function assertJson($expectedJson, $message = '')
{
if (!is_string($expectedJson)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string');
}

self::assertThat($expectedJson, self::isJson(), $message);
}

/**
* Asserts that two given JSON encoded objects or arrays are equal.
*
Expand All @@ -2143,23 +2159,12 @@ public static function assertThat($value, PHPUnit_Framework_Constraint $constrai
*/
public static function assertJsonStringEqualsJsonString($expectedJson, $actualJson, $message = '')
{
$expected = json_decode($expectedJson);
if ($jsonError = json_last_error()) {
$message .=
PHPUnit_Framework_Constraint_JsonMatches_ErrorMessageProvider::determineJsonError(
$jsonError,
PHPUnit_Framework_Constraint_JsonMatches_ErrorMessageProvider::translateTypeToPrefix('expected')
);
}
self::assertJson($expectedJson, $message);
self::assertJson($actualJson, $message);

$expected = json_decode($expectedJson);
$actual = json_decode($actualJson);
if ($jsonError = json_last_error()) {
$message .=
PHPUnit_Framework_Constraint_JsonMatches_ErrorMessageProvider::determineJsonError(
$jsonError,
PHPUnit_Framework_Constraint_JsonMatches_ErrorMessageProvider::translateTypeToPrefix('actual')
);
}

return self::assertEquals($expected, $actual, $message);
}

Expand All @@ -2172,23 +2177,11 @@ public static function assertJsonStringEqualsJsonString($expectedJson, $actualJs
*/
public static function assertJsonStringNotEqualsJsonString($expectedJson, $actualJson, $message = '')
{
$expected = json_decode($expectedJson);
if ($jsonError = json_last_error()) {
$message .=
PHPUnit_Framework_Constraint_JsonMatches_ErrorMessageProvider::determineJsonError(
$jsonError,
PHPUnit_Framework_Constraint_JsonMatches_ErrorMessageProvider::translateTypeToPrefix('expected')
);
}
self::assertJson($expectedJson, $message);
self::assertJson($actualJson, $message);

$expected = json_decode($expectedJson);
$actual = json_decode($actualJson);
if ($jsonError = json_last_error()) {
$message .=
PHPUnit_Framework_Constraint_JsonMatches_ErrorMessageProvider::determineJsonError(
$jsonError,
PHPUnit_Framework_Constraint_JsonMatches_ErrorMessageProvider::translateTypeToPrefix('actual')
);
}

self::assertNotEquals($expected, $actual, $message);
}
Expand All @@ -2203,14 +2196,14 @@ public static function assertJsonStringNotEqualsJsonString($expectedJson, $actua
public static function assertJsonStringEqualsJsonFile($expectedFile, $actualJson, $message = '')
{
self::assertFileExists($expectedFile, $message);
$expectedJson = file_get_contents($expectedFile);

if (!is_string($actualJson)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string');
}
self::assertJson($expectedJson, $message);
self::assertJson($actualJson, $message);

// call constraint
$constraint = new PHPUnit_Framework_Constraint_JsonMatches(
file_get_contents($expectedFile)
$expectedJson
);

self::assertThat($actualJson, $constraint, $message);
Expand All @@ -2226,14 +2219,14 @@ public static function assertJsonStringEqualsJsonFile($expectedFile, $actualJson
public static function assertJsonStringNotEqualsJsonFile($expectedFile, $actualJson, $message = '')
{
self::assertFileExists($expectedFile, $message);
$expectedJson = file_get_contents($expectedFile);

if (!is_string($actualJson)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string');
}
self::assertJson($expectedJson, $message);
self::assertJson($actualJson, $message);

// call constraint
$constraint = new PHPUnit_Framework_Constraint_JsonMatches(
file_get_contents($expectedFile)
$expectedJson
);

self::assertThat($actualJson, new PHPUnit_Framework_Constraint_Not($constraint), $message);
Expand All @@ -2254,9 +2247,12 @@ public static function assertJsonFileNotEqualsJsonFile($expectedFile, $actualFil
$actualJson = file_get_contents($actualFile);
$expectedJson = file_get_contents($expectedFile);

self::assertJson($expectedJson, $message);
self::assertJson($actualJson, $message);

// call constraint
$constraintExpected = new PHPUnit_Framework_Constraint_JsonMatches(
file_get_contents($expectedFile)
$expectedJson
);

$constraintActual = new PHPUnit_Framework_Constraint_JsonMatches($actualJson);
Expand All @@ -2280,9 +2276,12 @@ public static function assertJsonFileEqualsJsonFile($expectedFile, $actualFile,
$actualJson = file_get_contents($actualFile);
$expectedJson = file_get_contents($expectedFile);

self::assertJson($expectedJson, $message);
self::assertJson($actualJson, $message);

// call constraint
$constraintExpected = new PHPUnit_Framework_Constraint_JsonMatches(
file_get_contents($expectedFile)
$expectedJson
);

$constraintActual = new PHPUnit_Framework_Constraint_JsonMatches($actualJson);
Expand Down Expand Up @@ -2395,6 +2394,17 @@ public static function isFalse()
return new PHPUnit_Framework_Constraint_IsFalse;
}

/**
* Returns a PHPUnit_Framework_Constraint_IsJson matcher object.
*
* @return PHPUnit_Framework_Constraint_IsJson
* @since Method available since Release 3.7.20
*/
public static function isJson()
{
return new PHPUnit_Framework_Constraint_IsJson;
}

/**
* Returns a PHPUnit_Framework_Constraint_IsNull matcher object.
*
Expand Down
29 changes: 29 additions & 0 deletions PHPUnit/Framework/Assert/Functions.php
Expand Up @@ -806,6 +806,21 @@ function assertInternalType($expected, $actual, $message = '')
);
}

/**
* Asserts that a string is a valid JSON string.
*
* @param string $filename
* @param string $message
* @since Method available since Release 3.7.20
*/
function assertJson($expectedJson, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertJson',
func_get_args()
);
}

/**
* Asserts that two JSON files are equal.
*
Expand Down Expand Up @@ -2039,6 +2054,20 @@ function isInstanceOf($className)
);
}

/**
* Returns a PHPUnit_Framework_Constraint_IsJson matcher object.
*
* @return PHPUnit_Framework_Constraint_IsJson
* @since Method available since Release 3.7.20
*/
function isJson()
{
return call_user_func_array(
'PHPUnit_Framework_Assert::isJson',
func_get_args()
);
}

/**
* Returns a PHPUnit_Framework_Constraint_IsNull matcher object.
*
Expand Down
111 changes: 111 additions & 0 deletions PHPUnit/Framework/Constraint/IsJson.php
@@ -0,0 +1,111 @@
<?php
/**
* PHPUnit
*
* Copyright (c) 2001-2013, Sebastian Bergmann <sebastian@phpunit.de>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Sebastian Bergmann nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package PHPUnit
* @subpackage Framework_Constraint
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @author Bernhard Schussek <bschussek@2bepublished.at>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since File available since Release 3.0.0
*/

/**
* Constraint that asserts that a string is valid JSON.
*
* @package PHPUnit
* @subpackage Framework_Constraint
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @author Bernhard Schussek <bschussek@2bepublished.at>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since Class available since Release 3.0.0
*/
class PHPUnit_Framework_Constraint_IsJson extends PHPUnit_Framework_Constraint
{
/**
* Evaluates the constraint for parameter $other. Returns TRUE if the
* constraint is met, FALSE otherwise.
*
* @param mixed $other Value or object to evaluate.
* @return bool
*/
protected function matches($other)
{
json_decode($other);
if (json_last_error()) {
return FALSE;
}

return TRUE;
}

/**
* Returns the description of the failure
*
* The beginning of failure messages is "Failed asserting that" in most
* cases. This method should return the second part of that sentence.
*
* @param mixed $other Evaluated value or object.
* @return string
*/
protected function failureDescription($other)
{
json_decode($other);
$error = PHPUnit_Framework_Constraint_JsonMatches_ErrorMessageProvider::determineJsonError(
json_last_error()
);

return sprintf(
'%s is valid JSON (%s)',

PHPUnit_Util_Type::shortenedExport($other),
$error
);
}

/**
* Returns a string representation of the constraint.
*
* @return string
*/
public function toString()
{
return 'is valid JSON';
}
}
16 changes: 0 additions & 16 deletions PHPUnit/Framework/Constraint/JsonMatches.php
Expand Up @@ -84,33 +84,17 @@ protected function matches($other)
{
$decodedOther = json_decode($other);
if (json_last_error()) {
$this->failure_reason = $this->getJsonError();
return FALSE;
}

$decodedValue = json_decode($this->value);
if (json_last_error()) {
$this->failure_reason = $this->getJsonError();
return FALSE;
}

return $decodedOther == $decodedValue;
}

/**
* Finds the last occurd JSON error.
*
* @param string $messagePrefix
* @return string The last JSON error prefixed with $messagePrefix.
*/
protected function getJsonError($messagePrefix = 'Json error!')
{
return PHPUnit_Framework_Constraint_JsonMatches_ErrorMessageProvider::determineJsonError(
json_last_error(),
$messagePrefix
);
}

/**
* Returns a string representation of the object.
*
Expand Down

0 comments on commit aa917f1

Please sign in to comment.