From c129d570e8dbde06040a8b6d12d87443e5215941 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 31 Oct 2011 14:43:41 +0100 Subject: [PATCH] Add more json validation rules --- src/Composer/Json/JsonFile.php | 19 ++++++- tests/Composer/Test/Json/JsonFileTest.php | 69 +++++++++++++++++++++++ 2 files changed, 85 insertions(+), 3 deletions(-) create mode 100644 tests/Composer/Test/Json/JsonFileTest.php diff --git a/src/Composer/Json/JsonFile.php b/src/Composer/Json/JsonFile.php index 2b13d18d3..cba1e28de 100644 --- a/src/Composer/Json/JsonFile.php +++ b/src/Composer/Json/JsonFile.php @@ -19,6 +19,7 @@ use Composer\Composer; * Reads/writes json files. * * @author Konstantin Kudryashiv + * @author Jordi Boggiano */ class JsonFile { @@ -120,17 +121,29 @@ class JsonFile break; case JSON_ERROR_SYNTAX: $msg = 'Syntax error'; + $charOffset = 0; if (preg_match('#["}\]]\s*(,)\s*\}#', $json, $match, PREG_OFFSET_CAPTURE)) { - $msg .= ', extra comma on line '.(substr_count(substr($json, 0, $match[1][1]), "\n")+1); + $msg .= ', extra comma'; + } elseif (preg_match('#(["}\]]) *\r?\n *"#', $json, $match, PREG_OFFSET_CAPTURE)) { + $msg .= ', missing comma'; + $charOffset = 1; + } elseif (preg_match('#^ *([a-z0-9_-]+) *:#mi', $json, $match, PREG_OFFSET_CAPTURE)) { + $msg .= ', you must use double quotes (") around keys'; } elseif (preg_match('#(\'.+?\' *:|: *\'.+?\')#', $json, $match, PREG_OFFSET_CAPTURE)) { - $msg .= ', use double quotes (") instead of single quotes (\') on line '.(substr_count(substr($json, 0, $match[1][1]), "\n")+1); + $msg .= ', use double quotes (") instead of single quotes (\')'; + } elseif (preg_match('#(\[".*?":.*?\])#', $json, $match, PREG_OFFSET_CAPTURE)) { + $msg .= ', you must use the hash syntax (e.g. {"foo": "bar"}) instead of array syntax (e.g. ["foo", "bar"])'; + } + if (isset($match[1][1])) { + $preError = substr($json, 0, $match[1][1]); + $msg .= ' on line '.(substr_count($preError, "\n")+1).', char '.abs(strrpos($preError, "\n") - strlen($preError) - $charOffset); } break; case JSON_ERROR_UTF8: $msg = 'Malformed UTF-8 characters, possibly incorrectly encoded'; break; } - throw new \UnexpectedValueException('Incorrect composer.json file: '.$msg); + throw new \UnexpectedValueException('JSON Parse Error: '.$msg); } return $data; diff --git a/tests/Composer/Test/Json/JsonFileTest.php b/tests/Composer/Test/Json/JsonFileTest.php new file mode 100644 index 000000000..e25f86fdf --- /dev/null +++ b/tests/Composer/Test/Json/JsonFileTest.php @@ -0,0 +1,69 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Test\Json; + +use Composer\Json\JsonFile; + +class JsonFileTest extends \PHPUnit_Framework_TestCase +{ + public function testParseErrorDetectExtraComma() + { + $json = '{ + "foo": "bar", +}'; + $this->expectParseException('extra comma on line 2, char 21', $json); + } + + public function testParseErrorDetectSingleQuotes() + { + $json = '{ + \'foo\': "bar" +}'; + $this->expectParseException('use double quotes (") instead of single quotes (\') on line 2, char 9', $json); + } + + public function testParseErrorDetectMissingQuotes() + { + $json = '{ + foo: "bar" +}'; + $this->expectParseException('must use double quotes (") around keys on line 2, char 9', $json); + } + + public function testParseErrorDetectArrayAsHash() + { + $json = '{ + "foo": ["bar": "baz"] +}'; + $this->expectParseException('you must use the hash syntax (e.g. {"foo": "bar"}) instead of array syntax (e.g. ["foo", "bar"]) on line 2, char 16', $json); + } + + public function testParseErrorDetectMissingComma() + { + $json = '{ + "foo": "bar" + "bar": "foo" +}'; + $this->expectParseException('missing comma on line 2, char 21', $json); + } + + private function expectParseException($text, $json) + { + try { + JsonFile::parseJson($json); + $this->fail(); + } catch (\UnexpectedValueException $e) { + $this->assertContains($text, $e->getMessage()); + } + } +}