@@ -11,31 +11,206 @@ use Nette\Neon\Neon,
11
11
require __DIR__ . '/../bootstrap.php ' ;
12
12
13
13
14
- Assert::null ( Neon::decode ('' ) );
15
- Assert::null ( Neon::decode (' ' ) );
16
- Assert::same ( 0 , Neon::decode ('0 ' ) );
17
- Assert::same ( 0.0 , Neon::decode ('0.0 ' ) );
18
- Assert::same ( 1 , Neon::decode ('1 ' ) );
19
- Assert::same ( -1.2 , Neon::decode ('-1.2 ' ) );
20
- Assert::same ( -120.0 , Neon::decode ('-1.2e2 ' ) );
21
- Assert::true ( Neon::decode ('true ' ) );
22
- Assert::null ( Neon::decode ('null ' ) );
23
- Assert::same ( 'the"string#literal ' , Neon::decode ('the"string#literal ' ) );
24
- Assert::same ( 'the"string ' , Neon::decode ('the"string #literal ' ) );
25
- Assert::same ( "the'string #literal " , Neon::decode ('"the \'string #literal" ' ) );
26
- Assert::same ( 'the"string #literal ' , Neon::decode ("'the \"string #literal' " ) );
27
- Assert::same ( 'the"string #literal ' , Neon::decode ('"the \\"string #literal" ' ) );
28
- Assert::same ( '@ ' , Neon::decode ('"\u0040" ' ) );
29
- Assert::same ( "\xC4\x9B" , Neon::decode ('"\u011B" ' ) );
30
- Assert::same ( "\xf0\x90\x90\x81" , Neon::decode ('"\uD801\uDC01" ' ) ); // U+10401 encoded as surrogate pair
31
- Assert::same ( '<literal> <literal> ' , Neon::decode ('<literal> <literal> ' ) );
32
- Assert::same ( "" , Neon::decode ("'' " ) );
33
- Assert::same ( "" , Neon::decode ('"" ' ) );
34
- Assert::same ( ':a ' , Neon::decode (':a ' ) );
35
- Assert::same ( 'x ' , Neon::decode ('x ' ) );
36
- Assert::same ( "x " , Neon::decode ("\nx \n" ) );
37
- Assert::same ( "x " , Neon::decode (" x " ) );
38
- Assert::same ( "@x " , Neon::decode ("@x " ) );
39
- Assert::same ( "@true " , Neon::decode ("@true " ) );
40
- Assert::same ( 'a ' , Neon::decode ('a ' ) );
41
- Assert::same ( 'a ' , Neon::decode ("\xEF\xBB\xBFa " ) );
14
+ $ dataSet = array (
15
+ // https://tools.ietf.org/html/rfc7159
16
+ 'RFC JSON ' => array (
17
+ // numbers
18
+ array ("0 " , 0 ),
19
+ array ("1 " , 1 ),
20
+ array ("0.1 " , 0.1 ),
21
+ array ("1.1 " , 1.1 ),
22
+ array ("1.100000 " , 1.1 ),
23
+ array ("1.111111 " , 1.111111 ),
24
+ array ("-0 " , -0 ),
25
+ array ("-1 " , -1 ),
26
+ array ("-0.1 " , -0.1 ),
27
+ array ("-1.1 " , -1.1 ),
28
+ array ("-1.100000 " , -1.1 ),
29
+ array ("-1.111111 " , -1.111111 ),
30
+ array ("1.1e1 " , 11.0 ),
31
+ array ("1.1e+1 " , 11.0 ),
32
+ array ("1.1e-1 " , 0.11 ),
33
+ array ("1.1E1 " , 11.0 ),
34
+ array ("1.1E+1 " , 11.0 ),
35
+ array ("1.1E-1 " , 0.11 ),
36
+
37
+ // literals
38
+ array ("null " , NULL ),
39
+ array ("true " , TRUE ),
40
+ array ("false " , FALSE ),
41
+
42
+ // strings
43
+ array ("'' " , '' ),
44
+ array ('"" ' , '' ),
45
+ array ('"foo" ' , "foo " ),
46
+ array ('"f \\no" ' , "f \no " ),
47
+ array ('" \\b \\f \\n \\r \\t \\" \\/ \\\\" ' , "\x08\f\n\r\t\"/ \\" ),
48
+ array ('"\u0040" ' , "@ " ),
49
+ array ('"\u011B" ' , "\xC4\x9B" ),
50
+ array ('"\uD801\uDC01" ' , "\xf0\x90\x90\x81" ), // U+10401 encoded as surrogate pair
51
+ ),
52
+
53
+ // JSON parser implementation in PHP (json_decode); extends RFC JSON
54
+ 'PHP JSON ' => array (
55
+ // extended numbers syntax (only on top level)
56
+ array ('0777 ' , 777 ),
57
+ array ('00000777 ' , 777 ),
58
+ array ('0xff ' , 0xff ),
59
+ array ('.1 ' , 0.1 ),
60
+ array ('-.1 ' , -0.1 ),
61
+
62
+ // extended numbers syntax (everywhere)
63
+ array ('[1.] ' , array (1.0 )),
64
+ array ('[1.e1] ' , array (10.0 )),
65
+ array ('[-1.] ' , array (-1.0 )),
66
+ array ('[-1.e-1] ' , array (-0.1 )),
67
+
68
+ // empty input
69
+ array ('' , NULL ),
70
+ array (' ' , NULL ),
71
+ ),
72
+
73
+ // Nette Object Notation; extends PHP JSON
74
+ 'NEON ' => array (
75
+ // extended numbers syntax (everywhere)
76
+ array ('[0777] ' , array (777 )),
77
+ array ('[00000777] ' , array (777 )),
78
+ array ('[0xff] ' , array (0xff )),
79
+ array ('[.1] ' , array (0.1 )),
80
+ array ('[-.1] ' , array (-0.1 )),
81
+
82
+ // more literals
83
+ array ('Null ' , NULL ),
84
+ array ('NULL ' , NULL ),
85
+ array ('True ' , TRUE ),
86
+ array ('TRUE ' , TRUE ),
87
+ array ('yes ' , TRUE ),
88
+ array ('Yes ' , TRUE ),
89
+ array ('YES ' , TRUE ),
90
+ array ('on ' , TRUE ),
91
+ array ('On ' , TRUE ),
92
+ array ('ON ' , TRUE ),
93
+ array ('False ' , FALSE ),
94
+ array ('FALSE ' , FALSE ),
95
+ array ('no ' , FALSE ),
96
+ array ('No ' , FALSE ),
97
+ array ('NO ' , FALSE ),
98
+ array ('off ' , FALSE ),
99
+ array ('Off ' , FALSE ),
100
+ array ('OFF ' , FALSE ),
101
+
102
+ // extended string syntax
103
+ array ('" \\x42 hex escape" ' , "\x42 hex escape " ),
104
+ array ("'single \\n quote' " , "single \\n quote " ),
105
+
106
+ // strings without quotes
107
+ array ('a ' , 'a ' ),
108
+ array ('abc ' , 'abc ' ),
109
+ array ("\nabc \n" , 'abc ' ),
110
+ array (' abc ' , 'abc ' ),
111
+ array (':abc ' , ':abc ' ),
112
+
113
+ array ('the"string#literal ' , 'the"string#literal ' ),
114
+ array ('the"string #literal ' , 'the"string ' ),
115
+ array ('<literal> <literal> ' , '<literal> <literal> ' ),
116
+
117
+ array ('true "" ' , 'true "" ' ),
118
+ array ('false "" ' , 'false "" ' ),
119
+ array ('null "" ' , 'null "" ' ),
120
+
121
+ array ('@x ' , '@x ' ),
122
+ array ('@true ' , '@true ' ),
123
+
124
+ array ('42 px ' , '42 px ' ),
125
+ array ('42 .2 ' , '42 .2 ' ),
126
+ array ('42 2 ' , '42 2 ' ),
127
+ array ('42 e1 ' , '42 e1 ' ),
128
+ array ('--1 ' , '--1 ' ),
129
+ array ('-1e ' , '-1e ' ),
130
+ array ('1e+-1 ' , '1e+-1 ' ),
131
+
132
+ // object keys without quotes
133
+ array ("{true: 42} " , array ('true ' => 42 )),
134
+ array ("{false: 42} " , array ('false ' => 42 )),
135
+ array ("{null: 42} " , array ('null ' => 42 )),
136
+ array ("{yes: 42} " , array ('yes ' => 42 )),
137
+ array ("{on: 42} " , array ('on ' => 42 )),
138
+ array ("{no: 42} " , array ('no ' => 42 )),
139
+ array ("{off: 42} " , array ('off ' => 42 )),
140
+ array ("{42: 42} " , array (42 => 42 )),
141
+ array ("{0: 42} " , array (0 => 42 )),
142
+ array ("{-1: 42} " , array (-1 => 42 )),
143
+
144
+ // edge
145
+ array ('"the \'string #literal" ' , "the'string #literal " ),
146
+ array ("'the \"string #literal' " , 'the"string #literal ' ),
147
+ array ('"the \\"string #literal" ' , 'the"string #literal ' ),
148
+ array ('a ' , 'a ' ), // backtrack limit
149
+
150
+ // BOM
151
+ array ("\xEF\xBB\xBFa " , 'a ' ),
152
+ ),
153
+
154
+ // inputs with invalid syntax, but still valid UTF-8
155
+ 'invalid syntax ' => array (
156
+ array ('" \\a invalid escape" ' ),
157
+ array ('" \\v invalid escape" ' ),
158
+ array ('" \\u202 invalid escape" ' ),
159
+ array ('" \\012 invalid escape" ' ),
160
+ array ('" \\\' invalid escape" ' ),
161
+
162
+ array ('"Unterminated string ' ),
163
+ array ('"Unterminated string \\" ' ),
164
+ array ('"Unterminated string \\\\\\" ' ),
165
+
166
+ array ('"42" "" ' ),
167
+ array ('"" "" ' ),
168
+ array ('[] "" ' ),
169
+ array ('[true] "" ' ),
170
+ array ('{} "" ' ),
171
+ array ('{"x":true} "" ' ),
172
+ array ('"Garbage""After string" ' ),
173
+ array ('function () { return 0; } ' ),
174
+ array ("[1, 2 " ),
175
+ array ('{"x": 3 ' ),
176
+ array ('1e--1] ' ),
177
+ ),
178
+
179
+ // RFC JSON with valid syntax which can not be encoded in UTF-8
180
+ 'invalid encoding ' => array (
181
+ array ('"XXX\uD801YYY\uDC01ZZZ" ' , 'XXXYYYZZZ ' ), // lead and tail surrogates alone
182
+ array ('"XXX\uD801\uD801YYY" ' , 'XXXYYY ' ), // two lead surrogates
183
+ array ('"XXX\uDC01\uDC01YYY" ' , 'XXXYYY ' ), // two tail surrogates
184
+ ),
185
+
186
+ // inputs which are not valid UTF-8, but silently ignored
187
+ 'ignored invalid encoding ' => array (
188
+ array ("' \xc3\x28' " ), // Invalid 2 Octet Sequence
189
+ array ("' \xa0\xa1' " ), // Invalid Sequence Identifier
190
+ array ("' \xe2\x28\xa1' " ), // Invalid 3 Octet Sequence (in 2nd Octet)
191
+ array ("' \xe2\x82\x28' " ), // Invalid 3 Octet Sequence (in 3rd Octet)
192
+ array ("' \xf0\x28\x8c\xbc' " ), // Invalid 4 Octet Sequence (in 2nd Octet)
193
+ array ("' \xf0\x90\x28\xbc' " ), // Invalid 4 Octet Sequence (in 3rd Octet)
194
+ array ("' \xf0\x28\x8c\x28' " ), // Invalid 4 Octet Sequence (in 4th Octet)
195
+ array ("' \xf8\xa1\xa1\xa1\xa1' " ), // Valid 5 Octet Sequence (but not Unicode!)
196
+ array ("' \xfc\xa1\xa1\xa1\xa1\xa1' " ), // Valid 6 Octet Sequence (but not Unicode!)
197
+ array ("' \xed\xa0\x80' " ), // invalid code point (U+D800)
198
+ array ("' \xf0\x82\x82\xac' " ), // overlong encoding of U+20AC (euro sign)
199
+ ),
200
+ );
201
+
202
+
203
+ foreach (array_merge ($ dataSet ['RFC JSON ' ], $ dataSet ['PHP JSON ' ], $ dataSet ['NEON ' ]) as $ set ) {
204
+ echo "$ set [0 ]\n" ;
205
+ Assert::same ($ set [1 ], Neon::decode ($ set [0 ]));
206
+ }
207
+
208
+ foreach ($ dataSet ['ignored invalid encoding ' ] as $ set ) {
209
+ Assert::same (substr ($ set [0 ], 1 , -1 ), Neon::decode ($ set [0 ]));
210
+ }
211
+
212
+ foreach (array_merge ($ dataSet ['invalid syntax ' ], $ dataSet ['invalid encoding ' ]) as $ set ) {
213
+ Assert::exception (function () use ($ set ) {
214
+ Neon::decode ($ set [0 ]);
215
+ }, 'Nette\Neon\Exception ' );
216
+ }
0 commit comments