1 /* 2 * Copyright 2021 Google Inc. All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.google.flatbuffers.kotlin 17 18 import kotlin.test.Test 19 import kotlin.test.assertEquals 20 import kotlin.test.assertTrue 21 22 class JSONTest { 23 24 @Test parse2Testnull25 fun parse2Test() { 26 val dataStr = """ 27 { "myKey" : [1, "yay"] } 28 """.trimIndent() 29 val data = dataStr.encodeToByteArray() 30 val buffer = ArrayReadWriteBuffer(data, writePosition = data.size) 31 val parser = JSONParser() 32 val root = parser.parse(buffer) 33 println(root.toJson()) 34 } 35 36 @Test parseSamplenull37 fun parseSample() { 38 val dataStr = """ 39 { 40 "ary" : [1, 2, 3], 41 "boolean_false": false, 42 "boolean_true": true, "double": 1.2E33, 43 "hello":"world" 44 ,"interesting": "value", 45 46 "null_value": null, 47 48 49 "object" : { 50 "field1": "hello" 51 } 52 } 53 """ 54 val data = dataStr.encodeToByteArray() 55 val root = JSONParser().parse(ArrayReadWriteBuffer(data, writePosition = data.size)) 56 println(root.toJson()) 57 val map = root.toMap() 58 59 assertEquals(8, map.size) 60 assertEquals("world", map["hello"].toString()) 61 assertEquals("value", map["interesting"].toString()) 62 assertEquals(12e32, map["double"].toDouble()) 63 assertArrayEquals(intArrayOf(1, 2, 3), map["ary"].toIntArray()) 64 assertEquals(true, map["boolean_true"].toBoolean()) 65 assertEquals(false, map["boolean_false"].toBoolean()) 66 assertEquals(true, map["null_value"].isNull) 67 assertEquals("hello", map["object"]["field1"].toString()) 68 69 val obj = map["object"] 70 assertEquals(true, obj.isMap) 71 assertEquals("{\"field1\":\"hello\"}", obj.toJson()) 72 // TODO: Kotlin Double.toString() produce different strings dependending on the platform, so on JVM 73 // is 1.2E33, while on js is 1.2e+33. For now we are disabling this test. 74 // 75 // val minified = data.filterNot { it == ' '.toByte() || it == '\n'.toByte() }.toByteArray().decodeToString() 76 // assertEquals(minified, root.toJson()) 77 } 78 79 @Test testDoublesnull80 fun testDoubles() { 81 val values = arrayOf( 82 "-0.0", 83 "1.0", 84 "1.7976931348613157", 85 "0.0", 86 "-0.5", 87 "3.141592653589793", 88 "2.718281828459045E-3", 89 "2.2250738585072014E-308", 90 "4.9E-15", 91 ) 92 val parser = JSONParser() 93 assertEquals(-0.0, parser.parse(values[0]).toDouble()) 94 assertEquals(1.0, parser.parse(values[1]).toDouble()) 95 assertEquals(1.7976931348613157, parser.parse(values[2]).toDouble()) 96 assertEquals(0.0, parser.parse(values[3]).toDouble()) 97 assertEquals(-0.5, parser.parse(values[4]).toDouble()) 98 assertEquals(3.141592653589793, parser.parse(values[5]).toDouble()) 99 assertEquals(2.718281828459045e-3, parser.parse(values[6]).toDouble()) 100 assertEquals(2.2250738585072014E-308, parser.parse(values[7]).toDouble()) 101 assertEquals(4.9E-15, parser.parse(values[8]).toDouble()) 102 } 103 104 @Test testIntsnull105 fun testInts() { 106 val values = arrayOf( 107 "-0", 108 "0", 109 "-1", 110 "${Int.MAX_VALUE}", 111 "${Int.MIN_VALUE}", 112 "${Long.MAX_VALUE}", 113 "${Long.MIN_VALUE}", 114 ) 115 val parser = JSONParser() 116 117 assertEquals(parser.parse(values[0]).toInt(), 0) 118 assertEquals(parser.parse(values[1]).toInt(), 0) 119 assertEquals(parser.parse(values[2]).toInt(), -1) 120 assertEquals(parser.parse(values[3]).toInt(), Int.MAX_VALUE) 121 assertEquals(parser.parse(values[4]).toInt(), Int.MIN_VALUE) 122 assertEquals(parser.parse(values[5]).toLong(), Long.MAX_VALUE) 123 assertEquals(parser.parse(values[6]).toLong(), Long.MIN_VALUE) 124 } 125 126 @Test testBooleansAndNullnull127 fun testBooleansAndNull() { 128 val values = arrayOf( 129 "true", 130 "false", 131 "null" 132 ) 133 val parser = JSONParser() 134 135 assertEquals(true, parser.parse(values[0]).toBoolean()) 136 assertEquals(false, parser.parse(values[1]).toBoolean()) 137 assertEquals(true, parser.parse(values[2]).isNull) 138 } 139 140 @Test testStringsnull141 fun testStrings() { 142 val values = arrayOf( 143 "\"\"", 144 "\"a\"", 145 "\"hello world\"", 146 "\"\\\"\\\\\\/\\b\\f\\n\\r\\t cool\"", 147 "\"\\u0000\"", 148 "\"\\u0021\"", 149 "\"hell\\u24AC\\n\\ro wor \\u0021 ld\"", 150 "\"\\/_\\\\_\\\"_\\uCAFE\\uBABE\\uAB98\\uFCDE\\ubcda\\uef4A\\b\\n\\r\\t`1~!@#\$%^&*()_+-=[]{}|;:',./<>?\"", 151 ) 152 val parser = JSONParser() 153 154 // empty 155 var ref = parser.parse(values[0]) 156 assertEquals(true, ref.isString) 157 assertEquals("", ref.toString()) 158 // a 159 ref = parser.parse(values[1]) 160 assertEquals(true, ref.isString) 161 assertEquals("a", ref.toString()) 162 // hello world 163 ref = parser.parse(values[2]) 164 assertEquals(true, ref.isString) 165 assertEquals("hello world", ref.toString()) 166 // "\\\"\\\\\\/\\b\\f\\n\\r\\t\"" 167 ref = parser.parse(values[3]) 168 assertEquals(true, ref.isString) 169 assertEquals("\"\\/\b${12.toChar()}\n\r\t cool", ref.toString()) 170 // 0 171 ref = parser.parse(values[4]) 172 assertEquals(true, ref.isString) 173 assertEquals(0.toChar().toString(), ref.toString()) 174 // u0021 175 ref = parser.parse(values[5]) 176 assertEquals(true, ref.isString) 177 assertEquals(0x21.toChar().toString(), ref.toString()) 178 // "\"hell\\u24AC\\n\\ro wor \\u0021 ld\"", 179 ref = parser.parse(values[6]) 180 assertEquals(true, ref.isString) 181 assertEquals("hell${0x24AC.toChar()}\n\ro wor ${0x21.toChar()} ld", ref.toString()) 182 183 ref = parser.parse(values[7]) 184 println(ref.toJson()) 185 assertEquals(true, ref.isString) 186 assertEquals("/_\\_\"_쫾몾ꮘﳞ볚\b\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?", ref.toString()) 187 } 188 189 @Test testUnicodenull190 fun testUnicode() { 191 // took from test/unicode_test.json 192 val data = """ 193 { 194 "name": "unicode_test", 195 "testarrayofstring": [ 196 "Цлїςσδε", 197 "フムアムカモケモ", 198 "フムヤムカモケモ", 199 "㊀㊁㊂㊃㊄", 200 "☳☶☲", 201 "" 202 ], 203 "testarrayoftables": [ 204 { 205 "name": "Цлїςσδε" 206 }, 207 { 208 "name": "☳☶☲" 209 }, 210 { 211 "name": "フムヤムカモケモ" 212 }, 213 { 214 "name": "㊀㊁㊂㊃㊄" 215 }, 216 { 217 "name": "フムアムカモケモ" 218 }, 219 { 220 "name": "" 221 } 222 ] 223 } 224 """.trimIndent() 225 val parser = JSONParser() 226 val ref = parser.parse(data) 227 228 // name 229 assertEquals(3, ref.toMap().size) 230 assertEquals("unicode_test", ref["name"].toString()) 231 // testarrayofstring 232 assertEquals(6, ref["testarrayofstring"].toVector().size) 233 assertEquals("Цлїςσδε", ref["testarrayofstring"][0].toString()) 234 assertEquals("フムアムカモケモ", ref["testarrayofstring"][1].toString()) 235 assertEquals("フムヤムカモケモ", ref["testarrayofstring"][2].toString()) 236 assertEquals("㊀㊁㊂㊃㊄", ref["testarrayofstring"][3].toString()) 237 assertEquals("☳☶☲", ref["testarrayofstring"][4].toString()) 238 assertEquals("", ref["testarrayofstring"][5].toString()) 239 // testarrayoftables 240 assertEquals(6, ref["testarrayoftables"].toVector().size) 241 assertEquals("Цлїςσδε", ref["testarrayoftables"][0]["name"].toString()) 242 assertEquals("☳☶☲", ref["testarrayoftables"][1]["name"].toString()) 243 assertEquals("フムヤムカモケモ", ref["testarrayoftables"][2]["name"].toString()) 244 assertEquals("㊀㊁㊂㊃㊄", ref["testarrayoftables"][3]["name"].toString()) 245 assertEquals("フムアムカモケモ", ref["testarrayoftables"][4]["name"].toString()) 246 assertEquals("", ref["testarrayoftables"][5]["name"].toString()) 247 } 248 249 @Test testArraysnull250 fun testArrays() { 251 val values = arrayOf( 252 "[]", 253 "[1]", 254 "[0,1, 2,3 , 4 ]", 255 "[1.0, 2.2250738585072014E-308, 4.9E-320]", 256 "[1.0, 2, \"hello world\"] ", 257 "[ 1.1, 2, [ \"hello\" ] ]", 258 "[[[1]]]" 259 ) 260 val parser = JSONParser() 261 262 // empty 263 var ref = parser.parse(values[0]) 264 assertEquals(true, ref.isVector) 265 assertEquals(0, parser.parse(values[0]).toVector().size) 266 // single 267 ref = parser.parse(values[1]) 268 assertEquals(true, ref.isTypedVector) 269 assertEquals(1, ref[0].toInt()) 270 // ints 271 ref = parser.parse(values[2]) 272 assertEquals(true, ref.isTypedVector) 273 assertEquals(T_VECTOR_INT, ref.type) 274 assertEquals(5, ref.toVector().size) 275 for (i in 0..4) { 276 assertEquals(i, ref[i].toInt()) 277 } 278 // floats 279 ref = parser.parse(values[3]) 280 assertEquals(true, ref.isTypedVector) 281 assertEquals(T_VECTOR_FLOAT, ref.type) 282 assertEquals(3, ref.toVector().size) 283 assertEquals(1.0, ref[0].toDouble()) 284 assertEquals(2.2250738585072014E-308, ref[1].toDouble()) 285 assertEquals(4.9E-320, ref[2].toDouble()) 286 // mixed 287 ref = parser.parse(values[4]) 288 assertEquals(false, ref.isTypedVector) 289 assertEquals(T_VECTOR, ref.type) 290 assertEquals(1.0, ref[0].toDouble()) 291 assertEquals(2, ref[1].toInt()) 292 assertEquals("hello world", ref[2].toString()) 293 // nester array 294 ref = parser.parse(values[5]) 295 assertEquals(false, ref.isTypedVector) 296 assertEquals(T_VECTOR, ref.type) 297 assertEquals(1.1, ref[0].toDouble()) 298 assertEquals(2, ref[1].toInt()) 299 assertEquals("hello", ref[2][0].toString()) 300 } 301 302 /** 303 * Several test cases provided by json.org 304 * For more details, see: http://json.org/JSON_checker/, with only 305 * one exception. Single strings are considered accepted, whereas on 306 * the test suit is should fail. 307 */ 308 @Test testParseMustFailnull309 fun testParseMustFail() { 310 val failList = listOf( 311 "[\"Unclosed array\"", 312 "{unquoted_key: \"keys must be quoted\"}", 313 "[\"extra comma\",]", 314 "[\"double extra comma\",,]", 315 "[ , \"<-- missing value\"]", 316 "[\"Comma after the close\"],", 317 "[\"Extra close\"]]", 318 "{\"Extra comma\": true,}", 319 "{\"Extra value after close\": true} \"misplaced quoted value\"", 320 "{\"Illegal expression\": 1 + 2}", 321 "{\"Illegal invocation\": alert()}", 322 "{\"Numbers cannot have leading zeroes\": 013}", 323 "{\"Numbers cannot be hex\": 0x14}", 324 "[\"Illegal backslash escape: \\x15\"]", 325 "[\\naked]", 326 "[\"Illegal backslash escape: \\017\"]", 327 "[[[[[[[[[[[[[[[[[[[[[[[\"Too deep\"]]]]]]]]]]]]]]]]]]]]]]]", 328 "{\"Missing colon\" null}", 329 "{\"Double colon\":: null}", 330 "{\"Comma instead of colon\", null}", 331 "[\"Colon instead of comma\": false]", 332 "[\"Bad value\", truth]", 333 "['single quote']", 334 "[\"\ttab\tcharacter\tin\tstring\t\"]", 335 "[\"tab\\ character\\ in\\ string\\ \"]", 336 "[\"line\nbreak\"]", 337 "[\"line\\\nbreak\"]", 338 "[0e]", 339 "[0e+]", 340 "[0e+-1]", 341 "{\"Comma instead if closing brace\": true,", 342 "[\"mismatch\"}" 343 ) 344 for (data in failList) { 345 try { 346 JSONParser().parse(ArrayReadBuffer(data.encodeToByteArray())) 347 assertTrue(false, "SHOULD NOT PASS: $data") 348 } catch (e: IllegalStateException) { 349 println("FAIL $e") 350 } 351 } 352 } 353 354 @Test testParseMustPassnull355 fun testParseMustPass() { 356 val passList = listOf( 357 "[\n" + 358 " \"JSON Test Pattern pass1\",\n" + 359 " {\"object with 1 member\":[\"array with 1 element\"]},\n" + 360 " {},\n" + 361 " [],\n" + 362 " -42,\n" + 363 " true,\n" + 364 " false,\n" + 365 " null,\n" + 366 " {\n" + 367 " \"integer\": 1234567890,\n" + 368 " \"real\": -9876.543210,\n" + 369 " \"e\": 0.123456789e-12,\n" + 370 " \"E\": 1.234567890E+34,\n" + 371 " \"\": 23456789012E66,\n" + 372 " \"zero\": 0,\n" + 373 " \"one\": 1,\n" + 374 " \"space\": \" \",\n" + 375 " \"quote\": \"\\\"\",\n" + 376 " \"backslash\": \"\\\\\",\n" + 377 " \"controls\": \"\\b\\f\\n\\r\\t\",\n" + 378 " \"slash\": \"/ & \\/\",\n" + 379 " \"alpha\": \"abcdefghijklmnopqrstuvwyz\",\n" + 380 " \"ALPHA\": \"ABCDEFGHIJKLMNOPQRSTUVWYZ\",\n" + 381 " \"digit\": \"0123456789\",\n" + 382 " \"0123456789\": \"digit\",\n" + 383 " \"special\": \"`1~!@#\$%^&*()_+-={':[,]}|;.</>?\",\n" + 384 " \"hex\": \"\\u0123\\u4567\\u89AB\\uCDEF\\uabcd\\uef4A\",\n" + 385 " \"true\": true,\n" + 386 " \"false\": false,\n" + 387 " \"null\": null,\n" + 388 " \"array\":[ ],\n" + 389 " \"object\":{ },\n" + 390 " \"address\": \"50 St. James Street\",\n" + 391 " \"url\": \"http://www.JSON.org/\",\n" + 392 " \"comment\": \"// /* <!-- --\",\n" + 393 " \"# -- --> */\": \" \",\n" + 394 " \" s p a c e d \" :[1,2 , 3\n" + 395 "\n" + 396 ",\n" + 397 "\n" + 398 "4 , 5 , 6 ,7 ],\"compact\":[1,2,3,4,5,6,7],\n" + 399 " \"jsontext\": \"{\\\"object with 1 member\\\":[\\\"array with 1 element\\\"]}\",\n" + 400 " \"quotes\": \"" \\u0022 %22 0x22 034 "\",\n" + 401 " \"\\/\\\\\\\"\\uCAFE\\uBABE\\uAB98\\uFCDE\\ubcda\\uef4A\\b\\f\\n\\r\\t`1~!@#\$%^&*()_+-=[]{}|;:',./<>?\"\n" + 402 ": \"A key can be any string\"\n" + 403 " },\n" + 404 " 0.5 ,98.6\n" + 405 ",\n" + 406 "99.44\n" + 407 ",\n" + 408 "\n" + 409 "1066,\n" + 410 "1e1,\n" + 411 "0.1e1,\n" + 412 "1e-1,\n" + 413 "1e00,2e+00,2e-00\n" + 414 ",\"rosebud\"]", 415 "{\n" + 416 " \"JSON Test Pattern pass3\": {\n" + 417 " \"The outermost value\": \"must be an object or array.\",\n" + 418 " \"In this test\": \"It is an object.\"\n" + 419 " }\n" + 420 "}", 421 "[[[[[[[[[[[[[[[[[[[\"Not too deep\"]]]]]]]]]]]]]]]]]]]", 422 ) 423 for (data in passList) { 424 JSONParser().parse(ArrayReadBuffer(data.encodeToByteArray())) 425 } 426 } 427 } 428