6 class FormatJsonTest
extends MediaWikiTestCase
{
8 public static function provideEncoderPrettyPrinting() {
21 * @dataProvider provideEncoderPrettyPrinting
23 public function testEncoderPrettyPrinting( $pretty, $expectedIndent ) {
25 'emptyObject' => new stdClass
,
26 'emptyArray' => array(),
27 'string' => 'foobar\\',
28 'filledArray' => array(
33 // Nested json works without problems
34 '"7":["8",{"9":"10"}]',
35 // Whitespace clean up doesn't touch strings that look alike
36 "{\n\t\"emptyObject\": {\n\t},\n\t\"emptyArray\": [ ]\n}",
40 // No trailing whitespace, no trailing linefeed
44 "string": "foobar\\\\",
50 "\"7\":[\"8\",{\"9\":\"10\"}]",
51 "{\n\t\"emptyObject\": {\n\t},\n\t\"emptyArray\": [ ]\n}"
55 $json = str_replace( "\r", '', $json ); // Windows compat
56 $json = str_replace( "\t", $expectedIndent, $json );
57 $this->assertSame( $json, FormatJson
::encode( $obj, $pretty ) );
60 public static function provideEncodeDefault() {
61 return self
::getEncodeTestCases( array() );
65 * @dataProvider provideEncodeDefault
67 public function testEncodeDefault( $from, $to ) {
68 $this->assertSame( $to, FormatJson
::encode( $from ) );
71 public static function provideEncodeUtf8() {
72 return self
::getEncodeTestCases( array( 'unicode' ) );
76 * @dataProvider provideEncodeUtf8
78 public function testEncodeUtf8( $from, $to ) {
79 $this->assertSame( $to, FormatJson
::encode( $from, false, FormatJson
::UTF8_OK
) );
82 public static function provideEncodeXmlMeta() {
83 return self
::getEncodeTestCases( array( 'xmlmeta' ) );
87 * @dataProvider provideEncodeXmlMeta
89 public function testEncodeXmlMeta( $from, $to ) {
90 $this->assertSame( $to, FormatJson
::encode( $from, false, FormatJson
::XMLMETA_OK
) );
93 public static function provideEncodeAllOk() {
94 return self
::getEncodeTestCases( array( 'unicode', 'xmlmeta' ) );
98 * @dataProvider provideEncodeAllOk
100 public function testEncodeAllOk( $from, $to ) {
101 $this->assertSame( $to, FormatJson
::encode( $from, false, FormatJson
::ALL_OK
) );
104 public function testEncodePhpBug46944() {
105 $this->assertNotEquals(
107 strtolower( FormatJson
::encode( "\xf0\xa0\x80\x80" ) ),
108 'Test encoding an broken json_encode character (U+20000)'
112 public function testDecodeReturnType() {
113 $this->assertInternalType(
115 FormatJson
::decode( '{"Name": "Cheeso", "Rank": 7}' ),
119 $this->assertInternalType(
121 FormatJson
::decode( '{"Name": "Cheeso", "Rank": 7}', true ),
126 public static function provideParse() {
136 array( array( 0, 1, 2 ) ),
137 array( array( 'a' => 'b' ) ),
138 array( array( 'a' => 'b' ) ),
139 array( array( 'a' => 'b', 'x' => array( 'c' => 'd' ) ) ),
144 * Recursively convert arrays into stdClass
145 * @param array|string|bool|int|float|null $value
146 * @return stdClass|string|bool|int|float|null
148 public static function toObject( $value ) {
149 return !is_array( $value ) ?
$value : (object) array_map( __METHOD__
, $value );
153 * @dataProvider provideParse
154 * @param mixed $value
156 public function testParse( $value ) {
157 $expected = self
::toObject( $value );
158 $json = FormatJson
::encode( $expected, false, FormatJson
::ALL_OK
);
159 $this->assertJson( $json );
161 $st = FormatJson
::parse( $json );
162 $this->assertType( 'Status', $st );
163 $this->assertTrue( $st->isGood() );
164 $this->assertEquals( $expected, $st->getValue() );
166 $st = FormatJson
::parse( $json, FormatJson
::FORCE_ASSOC
);
167 $this->assertType( 'Status', $st );
168 $this->assertTrue( $st->isGood() );
169 $this->assertEquals( $value, $st->getValue() );
172 public static function provideParseTryFixing() {
174 array( "[,]", '[]' ),
175 array( "[ , ]", '[]' ),
176 array( "[ , }", false ),
177 array( '[1],', false ),
178 array( "[1,]", '[1]' ),
179 array( "[1\n,]", '[1]' ),
180 array( "[1,\n]", '[1]' ),
181 array( "[1,]\n", '[1]' ),
182 array( "[1\n,\n]\n", '[1]' ),
183 array( '["a,",]', '["a,"]' ),
184 array( "[[1,]\n,[2,\n],[3\n,]]", '[[1],[2],[3]]' ),
185 array( '[[1,],[2,],[3,]]', false ), // I wish we could parse this, but would need quote parsing
186 array( '[1,,]', false ),
191 * @dataProvider provideParseTryFixing
192 * @param string $value
193 * @param string|bool $expected
195 public function testParseTryFixing( $value, $expected ) {
196 $st = FormatJson
::parse( $value, FormatJson
::TRY_FIXING
);
197 $this->assertType( 'Status', $st );
198 if ( $expected === false ) {
199 $this->assertFalse( $st->isOK() );
201 $this->assertFalse( $st->isGood() );
202 $this->assertTrue( $st->isOK() );
203 $val = FormatJson
::encode( $st->getValue(), false, FormatJson
::ALL_OK
);
204 $this->assertEquals( $expected, $val );
208 public static function provideParseErrors() {
211 array( '{"j": 1 ] }' ),
216 * @dataProvider provideParseErrors
217 * @param mixed $value
219 public function testParseErrors( $value ) {
220 $st = FormatJson
::parse( $value );
221 $this->assertType( 'Status', $st );
222 $this->assertFalse( $st->isOK() );
226 * Generate a set of test cases for a particular combination of encoder options.
228 * @param array $unescapedGroups List of character groups to leave unescaped
229 * @return array Arrays of unencoded strings and corresponding encoded strings
231 private static function getEncodeTestCases( array $unescapedGroups ) {
234 // Forward slash (always unescaped)
237 // Control characters
244 "\x1f" => '\u001f', // representative example
251 '\\\\' => '\\\\\\\\',
252 '\\u00e9' => '\\\u00e9', // security check for Unicode unescaping
255 "\xe2\x80\xa8" => '\u2028',
256 "\xe2\x80\xa9" => '\u2029',
259 "\xc3\xa9" => '\u00e9',
260 "\xf0\x9d\x92\x9e" => '\ud835\udc9e', // U+1D49E, outside the BMP
263 '<' => '\u003C', // JSON_HEX_TAG uses uppercase hex digits
270 foreach ( $groups as $name => $rules ) {
271 $leaveUnescaped = in_array( $name, $unescapedGroups );
272 foreach ( $rules as $from => $to ) {
273 $cases[] = array( $from, '"' . ( $leaveUnescaped ?
$from : $to ) . '"' );