From c14c3ae106fbf11bef6dfc3ec7668c59bdd7f58e Mon Sep 17 00:00:00 2001 From: Jan Tvrdik Date: Wed, 9 Apr 2014 15:24:21 +0200 Subject: [PATCH] improved tests --- tests/Neon/Decoder.array.phpt | 9 ++ tests/Neon/Decoder.scalar.phpt | 231 +++++++++++++++++++++++++++++---- 2 files changed, 212 insertions(+), 28 deletions(-) diff --git a/tests/Neon/Decoder.array.phpt b/tests/Neon/Decoder.array.phpt index f53dda42..75f3c2c4 100644 --- a/tests/Neon/Decoder.array.phpt +++ b/tests/Neon/Decoder.array.phpt @@ -202,3 +202,12 @@ Assert::same(array( - a ")); + + +Assert::same( array( + 'one' => NULL, + 'two' => NULL, +), Neon::decode(' +one: +two: +') ); diff --git a/tests/Neon/Decoder.scalar.phpt b/tests/Neon/Decoder.scalar.phpt index d3b5ceea..fae531ad 100644 --- a/tests/Neon/Decoder.scalar.phpt +++ b/tests/Neon/Decoder.scalar.phpt @@ -11,31 +11,206 @@ use Nette\Neon\Neon, require __DIR__ . '/../bootstrap.php'; -Assert::null( Neon::decode('') ); -Assert::null( Neon::decode(' ') ); -Assert::same( 0, Neon::decode('0') ); -Assert::same( 0.0, Neon::decode('0.0') ); -Assert::same( 1, Neon::decode('1') ); -Assert::same( -1.2, Neon::decode('-1.2') ); -Assert::same( -120.0, Neon::decode('-1.2e2') ); -Assert::true( Neon::decode('true') ); -Assert::null( Neon::decode('null') ); -Assert::same( 'the"string#literal', Neon::decode('the"string#literal') ); -Assert::same( 'the"string', Neon::decode('the"string #literal') ); -Assert::same( "the'string #literal", Neon::decode('"the\'string #literal"') ); -Assert::same( 'the"string #literal', Neon::decode("'the\"string #literal'") ); -Assert::same( 'the"string #literal', Neon::decode('"the\\"string #literal"') ); -Assert::same( '@', Neon::decode('"\u0040"') ); -Assert::same( "\xC4\x9B", Neon::decode('"\u011B"') ); -Assert::same( "\xf0\x90\x90\x81", Neon::decode('"\uD801\uDC01"') ); // U+10401 encoded as surrogate pair -Assert::same( ' ', Neon::decode(' ') ); -Assert::same( "", Neon::decode("''") ); -Assert::same( "", Neon::decode('""') ); -Assert::same( ':a', Neon::decode(':a') ); -Assert::same( 'x', Neon::decode('x') ); -Assert::same( "x", Neon::decode("\nx\n") ); -Assert::same( "x", Neon::decode(" x") ); -Assert::same( "@x", Neon::decode("@x") ); -Assert::same( "@true", Neon::decode("@true") ); -Assert::same( 'a', Neon::decode('a ') ); -Assert::same( 'a', Neon::decode("\xEF\xBB\xBFa") ); +$dataSet = array( + // https://tools.ietf.org/html/rfc7159 + 'RFC JSON' => array( + // numbers + array("0", 0), + array("1", 1), + array("0.1", 0.1), + array("1.1", 1.1), + array("1.100000", 1.1), + array("1.111111", 1.111111), + array("-0", -0), + array("-1", -1), + array("-0.1", -0.1), + array("-1.1", -1.1), + array("-1.100000", -1.1), + array("-1.111111", -1.111111), + array("1.1e1", 11.0), + array("1.1e+1", 11.0), + array("1.1e-1", 0.11), + array("1.1E1", 11.0), + array("1.1E+1", 11.0), + array("1.1E-1", 0.11), + + // literals + array("null", NULL), + array("true", TRUE), + array("false", FALSE), + + // strings + array("''", ''), + array('""', ''), + array('"foo"', "foo"), + array('"f\\no"', "f\no"), + array('"\\b\\f\\n\\r\\t\\"\\/\\\\"', "\x08\f\n\r\t\"/\\"), + array('"\u0040"', "@"), + array('"\u011B"', "\xC4\x9B"), + array('"\uD801\uDC01"', "\xf0\x90\x90\x81"), // U+10401 encoded as surrogate pair + ), + + // JSON parser implementation in PHP (json_decode); extends RFC JSON + 'PHP JSON' => array( + // extended numbers syntax (only on top level) + array('0777', 777), + array('00000777', 777), + array('0xff', 0xff), + array('.1', 0.1), + array('-.1', -0.1), + + // extended numbers syntax (everywhere) + array('[1.]', array(1.0)), + array('[1.e1]', array(10.0)), + array('[-1.]', array(-1.0)), + array('[-1.e-1]', array(-0.1)), + + // empty input + array('', NULL), + array(' ', NULL), + ), + + // Nette Object Notation; extends PHP JSON + 'NEON' => array( + // extended numbers syntax (everywhere) + array('[0777]', array(777)), + array('[00000777]', array(777)), + array('[0xff]', array(0xff)), + array('[.1]', array(0.1)), + array('[-.1]', array(-0.1)), + + // more literals + array('Null', NULL), + array('NULL', NULL), + array('True', TRUE), + array('TRUE', TRUE), + array('yes', TRUE), + array('Yes', TRUE), + array('YES', TRUE), + array('on', TRUE), + array('On', TRUE), + array('ON', TRUE), + array('False', FALSE), + array('FALSE', FALSE), + array('no', FALSE), + array('No', FALSE), + array('NO', FALSE), + array('off', FALSE), + array('Off', FALSE), + array('OFF', FALSE), + + // extended string syntax + array('"\\x42 hex escape"', "\x42 hex escape"), + array("'single \\n quote'", "single \\n quote"), + + // strings without quotes + array('a', 'a'), + array('abc', 'abc'), + array("\nabc\n", 'abc'), + array(' abc ', 'abc'), + array(':abc', ':abc'), + + array('the"string#literal', 'the"string#literal'), + array('the"string #literal', 'the"string'), + array(' ', ' '), + + array('true ""', 'true ""'), + array('false ""', 'false ""'), + array('null ""', 'null ""'), + + array('@x', '@x'), + array('@true', '@true'), + + array('42 px', '42 px'), + array('42 .2', '42 .2'), + array('42 2', '42 2'), + array('42 e1', '42 e1'), + array('--1', '--1'), + array('-1e', '-1e'), + array('1e+-1', '1e+-1'), + + // object keys without quotes + array("{true: 42}", array('true' => 42)), + array("{false: 42}", array('false' => 42)), + array("{null: 42}", array('null' => 42)), + array("{yes: 42}", array('yes' => 42)), + array("{on: 42}", array('on' => 42)), + array("{no: 42}", array('no' => 42)), + array("{off: 42}", array('off' => 42)), + array("{42: 42}", array(42 => 42)), + array("{0: 42}", array(0 => 42)), + array("{-1: 42}", array(-1 => 42)), + + // edge + array('"the\'string #literal"', "the'string #literal"), + array("'the\"string #literal'", 'the"string #literal'), + array('"the\\"string #literal"', 'the"string #literal'), + array('a ', 'a'), // backtrack limit + + // BOM + array("\xEF\xBB\xBFa", 'a'), + ), + + // inputs with invalid syntax, but still valid UTF-8 + 'invalid syntax' => array( + array('"\\a invalid escape"'), + array('"\\v invalid escape"'), + array('"\\u202 invalid escape"'), + array('"\\012 invalid escape"'), + array('"\\\' invalid escape"'), + + array('"Unterminated string'), + array('"Unterminated string\\"'), + array('"Unterminated string\\\\\\"'), + + array('"42" ""'), + array('"" ""'), + array('[] ""'), + array('[true] ""'), + array('{} ""'), + array('{"x":true} ""'), + array('"Garbage""After string"'), + array('function () { return 0; }'), + array("[1, 2"), + array('{"x": 3'), + array('1e--1]'), + ), + + // RFC JSON with valid syntax which can not be encoded in UTF-8 + 'invalid encoding' => array( + array('"XXX\uD801YYY\uDC01ZZZ"', 'XXXYYYZZZ'), // lead and tail surrogates alone + array('"XXX\uD801\uD801YYY"', 'XXXYYY'), // two lead surrogates + array('"XXX\uDC01\uDC01YYY"', 'XXXYYY'), // two tail surrogates + ), + + // inputs which are not valid UTF-8, but silently ignored + 'ignored invalid encoding' => array( + array("'\xc3\x28'"), // Invalid 2 Octet Sequence + array("'\xa0\xa1'"), // Invalid Sequence Identifier + array("'\xe2\x28\xa1'"), // Invalid 3 Octet Sequence (in 2nd Octet) + array("'\xe2\x82\x28'"), // Invalid 3 Octet Sequence (in 3rd Octet) + array("'\xf0\x28\x8c\xbc'"), // Invalid 4 Octet Sequence (in 2nd Octet) + array("'\xf0\x90\x28\xbc'"), // Invalid 4 Octet Sequence (in 3rd Octet) + array("'\xf0\x28\x8c\x28'"), // Invalid 4 Octet Sequence (in 4th Octet) + array("'\xf8\xa1\xa1\xa1\xa1'"), // Valid 5 Octet Sequence (but not Unicode!) + array("'\xfc\xa1\xa1\xa1\xa1\xa1'"), // Valid 6 Octet Sequence (but not Unicode!) + array("'\xed\xa0\x80'"), // invalid code point (U+D800) + array("'\xf0\x82\x82\xac'"), // overlong encoding of U+20AC (euro sign) + ), +); + + +foreach (array_merge($dataSet['RFC JSON'], $dataSet['PHP JSON'], $dataSet['NEON']) as $set) { + echo "$set[0]\n"; + Assert::same($set[1], Neon::decode($set[0])); +} + +foreach ($dataSet['ignored invalid encoding'] as $set) { + Assert::same(substr($set[0], 1, -1), Neon::decode($set[0])); +} + +foreach (array_merge($dataSet['invalid syntax'], $dataSet['invalid encoding']) as $set) { + Assert::exception(function () use ($set) { + Neon::decode($set[0]); + }, 'Nette\Neon\Exception'); +}