json-test.c++ (41034B)
1 // Copyright (c) 2015 Sandstorm Development Group, Inc. and contributors 2 // Licensed under the MIT License: 3 // 4 // Permission is hereby granted, free of charge, to any person obtaining a copy 5 // of this software and associated documentation files (the "Software"), to deal 6 // in the Software without restriction, including without limitation the rights 7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 // copies of the Software, and to permit persons to whom the Software is 9 // furnished to do so, subject to the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included in 12 // all copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 // THE SOFTWARE. 21 22 #include "json.h" 23 #include <capnp/test-util.h> 24 #include <capnp/compat/json.capnp.h> 25 #include <capnp/compat/json-test.capnp.h> 26 #include <kj/debug.h> 27 #include <kj/string.h> 28 #include <kj/test.h> 29 30 namespace capnp { 31 namespace _ { // private 32 namespace { 33 34 KJ_TEST("basic json encoding") { 35 JsonCodec json; 36 37 KJ_EXPECT(json.encode(VOID) == "null"); 38 KJ_EXPECT(json.encode(true) == "true"); 39 KJ_EXPECT(json.encode(false) == "false"); 40 KJ_EXPECT(json.encode(123) == "123"); 41 KJ_EXPECT(json.encode(-5.5) == "-5.5"); 42 KJ_EXPECT(json.encode(Text::Reader("foo")) == "\"foo\""); 43 KJ_EXPECT(json.encode(Text::Reader("ab\"cd\\ef\x03")) == "\"ab\\\"cd\\\\ef\\u0003\""); 44 KJ_EXPECT(json.encode(test::TestEnum::CORGE) == "\"corge\""); 45 46 byte bytes[] = {12, 34, 56}; 47 KJ_EXPECT(json.encode(Data::Reader(bytes, 3)) == "[12,34,56]"); 48 49 json.setPrettyPrint(true); 50 KJ_EXPECT(json.encode(Data::Reader(bytes, 3)) == "[12, 34, 56]"); 51 } 52 53 const char ALL_TYPES_JSON[] = 54 "{ \"voidField\": null,\n" 55 " \"boolField\": true,\n" 56 " \"int8Field\": -123,\n" 57 " \"int16Field\": -12345,\n" 58 " \"int32Field\": -12345678,\n" 59 " \"int64Field\": \"-123456789012345\",\n" 60 " \"uInt8Field\": 234,\n" 61 " \"uInt16Field\": 45678,\n" 62 " \"uInt32Field\": 3456789012,\n" 63 " \"uInt64Field\": \"12345678901234567890\",\n" 64 " \"float32Field\": 1234.5,\n" 65 " \"float64Field\": -1.23e47,\n" 66 " \"textField\": \"foo\",\n" 67 " \"dataField\": [98, 97, 114],\n" 68 " \"structField\": {\n" 69 " \"voidField\": null,\n" 70 " \"boolField\": true,\n" 71 " \"int8Field\": -12,\n" 72 " \"int16Field\": 3456,\n" 73 " \"int32Field\": -78901234,\n" 74 " \"int64Field\": \"56789012345678\",\n" 75 " \"uInt8Field\": 90,\n" 76 " \"uInt16Field\": 1234,\n" 77 " \"uInt32Field\": 56789012,\n" 78 " \"uInt64Field\": \"345678901234567890\",\n" 79 " \"float32Field\": -1.2499999646475857e-10,\n" 80 " \"float64Field\": 345,\n" 81 " \"textField\": \"baz\",\n" 82 " \"dataField\": [113, 117, 120],\n" 83 " \"structField\": {\n" 84 " \"voidField\": null,\n" 85 " \"boolField\": false,\n" 86 " \"int8Field\": 0,\n" 87 " \"int16Field\": 0,\n" 88 " \"int32Field\": 0,\n" 89 " \"int64Field\": \"0\",\n" 90 " \"uInt8Field\": 0,\n" 91 " \"uInt16Field\": 0,\n" 92 " \"uInt32Field\": 0,\n" 93 " \"uInt64Field\": \"0\",\n" 94 " \"float32Field\": 0,\n" 95 " \"float64Field\": 0,\n" 96 " \"textField\": \"nested\",\n" 97 " \"structField\": {\"voidField\": null, \"boolField\": false, \"int8Field\": 0, \"int16Field\": 0, \"int32Field\": 0, \"int64Field\": \"0\", \"uInt8Field\": 0, \"uInt16Field\": 0, \"uInt32Field\": 0, \"uInt64Field\": \"0\", \"float32Field\": 0, \"float64Field\": 0, \"textField\": \"really nested\", \"enumField\": \"foo\", \"interfaceField\": null},\n" 98 " \"enumField\": \"foo\",\n" 99 " \"interfaceField\": null },\n" 100 " \"enumField\": \"baz\",\n" 101 " \"interfaceField\": null,\n" 102 " \"voidList\": [null, null, null],\n" 103 " \"boolList\": [false, true, false, true, true],\n" 104 " \"int8List\": [12, -34, -128, 127],\n" 105 " \"int16List\": [1234, -5678, -32768, 32767],\n" 106 " \"int32List\": [12345678, -90123456, -2147483648, 2147483647],\n" 107 " \"int64List\": [\"123456789012345\", \"-678901234567890\", \"-9223372036854775808\", \"9223372036854775807\"],\n" 108 " \"uInt8List\": [12, 34, 0, 255],\n" 109 " \"uInt16List\": [1234, 5678, 0, 65535],\n" 110 " \"uInt32List\": [12345678, 90123456, 0, 4294967295],\n" 111 " \"uInt64List\": [\"123456789012345\", \"678901234567890\", \"0\", \"18446744073709551615\"],\n" 112 " \"float32List\": [0, 1234567, 9.9999999338158125e36, -9.9999999338158125e36, 9.99999991097579e-38, -9.99999991097579e-38],\n" 113 " \"float64List\": [0, 123456789012345, 1e306, -1e306, 1e-306, -1e-306],\n" 114 " \"textList\": [\"quux\", \"corge\", \"grault\"],\n" 115 " \"dataList\": [[103, 97, 114, 112, 108, 121], [119, 97, 108, 100, 111], [102, 114, 101, 100]],\n" 116 " \"structList\": [\n" 117 " {\"voidField\": null, \"boolField\": false, \"int8Field\": 0, \"int16Field\": 0, \"int32Field\": 0, \"int64Field\": \"0\", \"uInt8Field\": 0, \"uInt16Field\": 0, \"uInt32Field\": 0, \"uInt64Field\": \"0\", \"float32Field\": 0, \"float64Field\": 0, \"textField\": \"x structlist 1\", \"enumField\": \"foo\", \"interfaceField\": null},\n" 118 " {\"voidField\": null, \"boolField\": false, \"int8Field\": 0, \"int16Field\": 0, \"int32Field\": 0, \"int64Field\": \"0\", \"uInt8Field\": 0, \"uInt16Field\": 0, \"uInt32Field\": 0, \"uInt64Field\": \"0\", \"float32Field\": 0, \"float64Field\": 0, \"textField\": \"x structlist 2\", \"enumField\": \"foo\", \"interfaceField\": null},\n" 119 " {\"voidField\": null, \"boolField\": false, \"int8Field\": 0, \"int16Field\": 0, \"int32Field\": 0, \"int64Field\": \"0\", \"uInt8Field\": 0, \"uInt16Field\": 0, \"uInt32Field\": 0, \"uInt64Field\": \"0\", \"float32Field\": 0, \"float64Field\": 0, \"textField\": \"x structlist 3\", \"enumField\": \"foo\", \"interfaceField\": null} ],\n" 120 " \"enumList\": [\"qux\", \"bar\", \"grault\"] },\n" 121 " \"enumField\": \"corge\",\n" 122 " \"interfaceField\": null,\n" 123 " \"voidList\": [null, null, null, null, null, null],\n" 124 " \"boolList\": [true, false, false, true],\n" 125 " \"int8List\": [111, -111],\n" 126 " \"int16List\": [11111, -11111],\n" 127 " \"int32List\": [111111111, -111111111],\n" 128 " \"int64List\": [\"1111111111111111111\", \"-1111111111111111111\"],\n" 129 " \"uInt8List\": [111, 222],\n" 130 " \"uInt16List\": [33333, 44444],\n" 131 " \"uInt32List\": [3333333333],\n" 132 " \"uInt64List\": [\"11111111111111111111\"],\n" 133 " \"float32List\": [5555.5, \"Infinity\", \"-Infinity\", \"NaN\"],\n" 134 " \"float64List\": [7777.75, \"Infinity\", \"-Infinity\", \"NaN\"],\n" 135 " \"textList\": [\"plugh\", \"xyzzy\", \"thud\"],\n" 136 " \"dataList\": [[111, 111, 112, 115], [101, 120, 104, 97, 117, 115, 116, 101, 100], [114, 102, 99, 51, 48, 57, 50]],\n" 137 " \"structList\": [\n" 138 " {\"voidField\": null, \"boolField\": false, \"int8Field\": 0, \"int16Field\": 0, \"int32Field\": 0, \"int64Field\": \"0\", \"uInt8Field\": 0, \"uInt16Field\": 0, \"uInt32Field\": 0, \"uInt64Field\": \"0\", \"float32Field\": 0, \"float64Field\": 0, \"textField\": \"structlist 1\", \"enumField\": \"foo\", \"interfaceField\": null},\n" 139 " {\"voidField\": null, \"boolField\": false, \"int8Field\": 0, \"int16Field\": 0, \"int32Field\": 0, \"int64Field\": \"0\", \"uInt8Field\": 0, \"uInt16Field\": 0, \"uInt32Field\": 0, \"uInt64Field\": \"0\", \"float32Field\": 0, \"float64Field\": 0, \"textField\": \"structlist 2\", \"enumField\": \"foo\", \"interfaceField\": null},\n" 140 " {\"voidField\": null, \"boolField\": false, \"int8Field\": 0, \"int16Field\": 0, \"int32Field\": 0, \"int64Field\": \"0\", \"uInt8Field\": 0, \"uInt16Field\": 0, \"uInt32Field\": 0, \"uInt64Field\": \"0\", \"float32Field\": 0, \"float64Field\": 0, \"textField\": \"structlist 3\", \"enumField\": \"foo\", \"interfaceField\": null} ],\n" 141 " \"enumList\": [\"foo\", \"garply\"] }"; 142 143 KJ_TEST("encode all types") { 144 MallocMessageBuilder message; 145 auto root = message.getRoot<TestAllTypes>(); 146 initTestMessage(root); 147 148 JsonCodec json; 149 json.setPrettyPrint(true); 150 KJ_EXPECT(json.encode(root) == ALL_TYPES_JSON); 151 152 // Verify that if we strip out the non-string spaces, we get the non-pretty-print version. 153 kj::Vector<char> chars; 154 bool inQuotes = false; 155 for (char c: ALL_TYPES_JSON) { 156 if (c == '\"') inQuotes = !inQuotes; 157 158 if ((c == '\n' || c == ' ') && !inQuotes) { 159 // skip space 160 } else { 161 chars.add(c); 162 } 163 } 164 kj::String nospaces(chars.releaseAsArray()); 165 166 json.setPrettyPrint(false); 167 KJ_EXPECT(json.encode(root) == nospaces); 168 } 169 170 KJ_TEST("encode union") { 171 MallocMessageBuilder message; 172 auto root = message.getRoot<test::TestUnnamedUnion>(); 173 174 root.setBefore("a"); 175 root.setMiddle(44); 176 root.setAfter("c"); 177 178 JsonCodec json; 179 180 root.setFoo(123); 181 KJ_EXPECT(json.encode(root) == "{\"before\":\"a\",\"foo\":123,\"middle\":44,\"after\":\"c\"}"); 182 183 root.setBar(321); 184 KJ_EXPECT(json.encode(root) == "{\"before\":\"a\",\"middle\":44,\"bar\":321,\"after\":\"c\"}"); 185 } 186 187 KJ_TEST("decode all types") { 188 JsonCodec json; 189 json.setHasMode(HasMode::NON_DEFAULT); 190 191 #define CASE_MAYBE_ROUNDTRIP(s, f, roundtrip) \ 192 { \ 193 MallocMessageBuilder message; \ 194 auto root = message.initRoot<TestAllTypes>(); \ 195 kj::StringPtr input = s; \ 196 json.decode(input, root); \ 197 KJ_EXPECT((f), input, root); \ 198 auto reencoded = json.encode(root); \ 199 KJ_EXPECT(roundtrip == (input == reencoded), roundtrip, input, reencoded); \ 200 } 201 #define CASE_NO_ROUNDTRIP(s, f) CASE_MAYBE_ROUNDTRIP(s, f, false) 202 #define CASE(s, f) CASE_MAYBE_ROUNDTRIP(s, f, true) 203 #define CASE_THROW(s, errorMessage) \ 204 { \ 205 MallocMessageBuilder message; \ 206 auto root = message.initRoot<TestAllTypes>(); \ 207 KJ_EXPECT_THROW_MESSAGE(errorMessage, json.decode(s, root)); \ 208 } 209 #define CASE_THROW_RECOVERABLE(s, errorMessage) \ 210 { \ 211 MallocMessageBuilder message; \ 212 auto root = message.initRoot<TestAllTypes>(); \ 213 KJ_EXPECT_THROW_RECOVERABLE_MESSAGE(errorMessage, json.decode(s, root)); \ 214 } 215 216 CASE(R"({})", root.getBoolField() == false); 217 CASE_NO_ROUNDTRIP(R"({"unknownField":7})", root.getBoolField() == false); 218 CASE(R"({"boolField":true})", root.getBoolField() == true); 219 CASE(R"({"int8Field":-128})", root.getInt8Field() == -128); 220 CASE_NO_ROUNDTRIP(R"({"int8Field":"127"})", root.getInt8Field() == 127); 221 CASE_THROW_RECOVERABLE(R"({"int8Field":"-129"})", "Value out-of-range"); 222 CASE_THROW_RECOVERABLE(R"({"int8Field":128})", "Value out-of-range"); 223 CASE(R"({"int16Field":-32768})", root.getInt16Field() == -32768); 224 CASE_NO_ROUNDTRIP(R"({"int16Field":"32767"})", root.getInt16Field() == 32767); 225 CASE_THROW_RECOVERABLE(R"({"int16Field":"-32769"})", "Value out-of-range"); 226 CASE_THROW_RECOVERABLE(R"({"int16Field":32768})", "Value out-of-range"); 227 CASE(R"({"int32Field":-2147483648})", root.getInt32Field() == -2147483648); 228 CASE_NO_ROUNDTRIP(R"({"int32Field":"2147483647"})", root.getInt32Field() == 2147483647); 229 CASE_NO_ROUNDTRIP(R"({"int64Field":-9007199254740992})", root.getInt64Field() == -9007199254740992LL); 230 CASE_NO_ROUNDTRIP(R"({"int64Field":9007199254740991})", root.getInt64Field() == 9007199254740991LL); 231 CASE(R"({"int64Field":"-9223372036854775808"})", root.getInt64Field() == -9223372036854775808ULL); 232 CASE(R"({"int64Field":"9223372036854775807"})", root.getInt64Field() == 9223372036854775807LL); 233 CASE_THROW_RECOVERABLE(R"({"int64Field":"-9223372036854775809"})", "Value out-of-range"); 234 CASE_THROW_RECOVERABLE(R"({"int64Field":"9223372036854775808"})", "Value out-of-range"); 235 CASE(R"({"uInt8Field":255})", root.getUInt8Field() == 255); 236 CASE_NO_ROUNDTRIP(R"({"uInt8Field":"0"})", root.getUInt8Field() == 0); 237 CASE_THROW_RECOVERABLE(R"({"uInt8Field":"256"})", "Value out-of-range"); 238 CASE_THROW_RECOVERABLE(R"({"uInt8Field":-1})", "Value out-of-range"); 239 CASE(R"({"uInt16Field":65535})", root.getUInt16Field() == 65535); 240 CASE_NO_ROUNDTRIP(R"({"uInt16Field":"0"})", root.getUInt16Field() == 0); 241 CASE_THROW_RECOVERABLE(R"({"uInt16Field":"655356"})", "Value out-of-range"); 242 CASE_THROW_RECOVERABLE(R"({"uInt16Field":-1})", "Value out-of-range"); 243 CASE(R"({"uInt32Field":4294967295})", root.getUInt32Field() == 4294967295); 244 CASE_NO_ROUNDTRIP(R"({"uInt32Field":"0"})", root.getUInt32Field() == 0); 245 CASE_THROW_RECOVERABLE(R"({"uInt32Field":"42949672956"})", "Value out-of-range"); 246 CASE_THROW_RECOVERABLE(R"({"uInt32Field":-1})", "Value out-of-range"); 247 CASE_NO_ROUNDTRIP(R"({"uInt64Field":9007199254740991})", root.getUInt64Field() == 9007199254740991ULL); 248 CASE(R"({"uInt64Field":"18446744073709551615"})", root.getUInt64Field() == 18446744073709551615ULL); 249 CASE_NO_ROUNDTRIP(R"({"uInt64Field":"0"})", root.getUInt64Field() == 0); 250 CASE_THROW_RECOVERABLE(R"({"uInt64Field":"18446744073709551616"})", "Value out-of-range"); 251 CASE_NO_ROUNDTRIP(R"({"float32Field":0})", root.getFloat32Field() == 0); 252 CASE(R"({"float32Field":4.5})", root.getFloat32Field() == 4.5); 253 CASE_NO_ROUNDTRIP(R"({"float32Field":null})", kj::isNaN(root.getFloat32Field())); 254 CASE(R"({"float32Field":"NaN"})", kj::isNaN(root.getFloat32Field())); 255 CASE_NO_ROUNDTRIP(R"({"float32Field":"nan"})", kj::isNaN(root.getFloat32Field())); 256 CASE(R"({"float32Field":"Infinity"})", root.getFloat32Field() == kj::inf()); 257 CASE(R"({"float32Field":"-Infinity"})", root.getFloat32Field() == -kj::inf()); 258 CASE_NO_ROUNDTRIP(R"({"float32Field":"infinity"})", root.getFloat32Field() == kj::inf()); 259 CASE_NO_ROUNDTRIP(R"({"float32Field":"-infinity"})", root.getFloat32Field() == -kj::inf()); 260 CASE_NO_ROUNDTRIP(R"({"float32Field":"INF"})", root.getFloat32Field() == kj::inf()); 261 CASE_NO_ROUNDTRIP(R"({"float32Field":"-INF"})", root.getFloat32Field() == -kj::inf()); 262 CASE_NO_ROUNDTRIP(R"({"float32Field":1e39})", root.getFloat32Field() == kj::inf()); 263 CASE_NO_ROUNDTRIP(R"({"float32Field":-1e39})", root.getFloat32Field() == -kj::inf()); 264 CASE_NO_ROUNDTRIP(R"({"float64Field":0})", root.getFloat64Field() == 0); 265 CASE(R"({"float64Field":4.5})", root.getFloat64Field() == 4.5); 266 CASE_NO_ROUNDTRIP(R"({"float64Field":null})", kj::isNaN(root.getFloat64Field())); 267 CASE(R"({"float64Field":"NaN"})", kj::isNaN(root.getFloat64Field())); 268 CASE_NO_ROUNDTRIP(R"({"float64Field":"nan"})", kj::isNaN(root.getFloat64Field())); 269 CASE(R"({"float64Field":"Infinity"})", root.getFloat64Field() == kj::inf()); 270 CASE_NO_ROUNDTRIP(R"({"float64Field":"infinity"})", root.getFloat64Field() == kj::inf()); 271 CASE_NO_ROUNDTRIP(R"({"float64Field":"-infinity"})", root.getFloat64Field() == -kj::inf()); 272 CASE_NO_ROUNDTRIP(R"({"float64Field":"INF"})", root.getFloat64Field() == kj::inf()); 273 CASE_NO_ROUNDTRIP(R"({"float64Field":"-INF"})", root.getFloat64Field() == -kj::inf()); 274 CASE_NO_ROUNDTRIP(R"({"float64Field":1e309})", root.getFloat64Field() == kj::inf()); 275 CASE_NO_ROUNDTRIP(R"({"float64Field":-1e309})", root.getFloat64Field() == -kj::inf()); 276 CASE(R"({"textField":"hello"})", kj::str("hello") == root.getTextField()); 277 CASE(R"({"dataField":[7,0,122]})", 278 kj::heapArray<byte>({7,0,122}).asPtr() == root.getDataField()); 279 CASE(R"({"structField":{}})", root.hasStructField() == true); 280 CASE(R"({"structField":{}})", root.getStructField().getBoolField() == false); 281 CASE_NO_ROUNDTRIP(R"({"structField":{"boolField":false}})", root.getStructField().getBoolField() == false); 282 CASE(R"({"structField":{"boolField":true}})", root.getStructField().getBoolField() == true); 283 CASE(R"({"enumField":"bar"})", root.getEnumField() == TestEnum::BAR); 284 285 CASE_NO_ROUNDTRIP(R"({"textField":"foo\u1234bar"})", 286 kj::str(u8"foo\u1234bar") == root.getTextField()); 287 288 CASE_THROW_RECOVERABLE(R"({"structField":null})", "Expected object value"); 289 CASE_THROW_RECOVERABLE(R"({"structList":null})", "Expected list value"); 290 CASE_THROW_RECOVERABLE(R"({"boolList":null})", "Expected list value"); 291 CASE_THROW_RECOVERABLE(R"({"structList":[null]})", "Expected object value"); 292 CASE_THROW_RECOVERABLE(R"({"int64Field":"177a"})", "String does not contain valid"); 293 CASE_THROW_RECOVERABLE(R"({"uInt64Field":"177a"})", "String does not contain valid"); 294 CASE_THROW_RECOVERABLE(R"({"float64Field":"177a"})", "String does not contain valid"); 295 296 CASE(R"({})", root.hasBoolList() == false); 297 CASE(R"({"boolList":[]})", root.hasBoolList() == true); 298 CASE(R"({"boolList":[]})", root.getBoolList().size() == 0); 299 CASE(R"({"boolList":[false]})", root.getBoolList().size() == 1); 300 CASE(R"({"boolList":[false]})", root.getBoolList()[0] == false); 301 CASE(R"({"boolList":[true]})", root.getBoolList()[0] == true); 302 CASE(R"({"int8List":[7]})", root.getInt8List()[0] == 7); 303 CASE_NO_ROUNDTRIP(R"({"int8List":["7"]})", root.getInt8List()[0] == 7); 304 CASE(R"({"int16List":[7]})", root.getInt16List()[0] == 7); 305 CASE_NO_ROUNDTRIP(R"({"int16List":["7"]})", root.getInt16List()[0] == 7); 306 CASE(R"({"int32List":[7]})", root.getInt32List()[0] == 7); 307 CASE_NO_ROUNDTRIP(R"({"int32List":["7"]})", root.getInt32List()[0] == 7); 308 CASE_NO_ROUNDTRIP(R"({"int64List":[7]})", root.getInt64List()[0] == 7); 309 CASE(R"({"int64List":["7"]})", root.getInt64List()[0] == 7); 310 CASE(R"({"uInt8List":[7]})", root.getUInt8List()[0] == 7); 311 CASE_NO_ROUNDTRIP(R"({"uInt8List":["7"]})", root.getUInt8List()[0] == 7); 312 CASE(R"({"uInt16List":[7]})", root.getUInt16List()[0] == 7); 313 CASE_NO_ROUNDTRIP(R"({"uInt16List":["7"]})", root.getUInt16List()[0] == 7); 314 CASE(R"({"uInt32List":[7]})", root.getUInt32List()[0] == 7); 315 CASE_NO_ROUNDTRIP(R"({"uInt32List":["7"]})", root.getUInt32List()[0] == 7); 316 CASE_NO_ROUNDTRIP(R"({"uInt64List":[7]})", root.getUInt64List()[0] == 7); 317 CASE(R"({"uInt64List":["7"]})", root.getUInt64List()[0] == 7); 318 CASE(R"({"float32List":[4.5]})", root.getFloat32List()[0] == 4.5); 319 CASE_NO_ROUNDTRIP(R"({"float32List":["4.5"]})", root.getFloat32List()[0] == 4.5); 320 CASE_NO_ROUNDTRIP(R"({"float32List":[null]})", kj::isNaN(root.getFloat32List()[0])); 321 CASE(R"({"float32List":["NaN"]})", kj::isNaN(root.getFloat32List()[0])); 322 CASE(R"({"float32List":["Infinity"]})", root.getFloat32List()[0] == kj::inf()); 323 CASE(R"({"float32List":["-Infinity"]})", root.getFloat32List()[0] == -kj::inf()); 324 CASE(R"({"float64List":[4.5]})", root.getFloat64List()[0] == 4.5); 325 CASE_NO_ROUNDTRIP(R"({"float64List":["4.5"]})", root.getFloat64List()[0] == 4.5); 326 CASE_NO_ROUNDTRIP(R"({"float64List":[null]})", kj::isNaN(root.getFloat64List()[0])); 327 CASE(R"({"float64List":["NaN"]})", kj::isNaN(root.getFloat64List()[0])); 328 CASE(R"({"float64List":["Infinity"]})", root.getFloat64List()[0] == kj::inf()); 329 CASE(R"({"float64List":["-Infinity"]})", root.getFloat64List()[0] == -kj::inf()); 330 CASE(R"({"textList":["hello"]})", kj::str("hello") == root.getTextList()[0]); 331 CASE(R"({"dataList":[[7,0,122]]})", 332 kj::heapArray<byte>({7,0,122}).asPtr() == root.getDataList()[0]); 333 CASE(R"({"structList":[{}]})", root.hasStructList() == true); 334 CASE(R"({"structList":[{}]})", root.getStructList()[0].getBoolField() == false); 335 CASE_NO_ROUNDTRIP(R"({"structList":[{"boolField":false}]})", root.getStructList()[0].getBoolField() == false); 336 CASE(R"({"structList":[{"boolField":true}]})", root.getStructList()[0].getBoolField() == true); 337 CASE(R"({"enumList":["bar"]})", root.getEnumList()[0] == TestEnum::BAR); 338 #undef CASE_MAYBE_ROUNDTRIP 339 #undef CASE_NO_ROUNDTRIP 340 #undef CASE 341 #undef CASE_THROW 342 #undef CASE_THROW_RECOVERABLE 343 } 344 345 KJ_TEST("decode test message") { 346 MallocMessageBuilder message; 347 auto root = message.getRoot<TestAllTypes>(); 348 initTestMessage(root); 349 350 JsonCodec json; 351 auto encoded = json.encode(root); 352 353 MallocMessageBuilder decodedMessage; 354 auto decodedRoot = decodedMessage.initRoot<TestAllTypes>(); 355 json.decode(encoded, decodedRoot); 356 357 KJ_EXPECT(root.toString().flatten() == decodedRoot.toString().flatten()); 358 } 359 360 KJ_TEST("basic json decoding") { 361 // TODO(cleanup): this test is a mess! 362 JsonCodec json; 363 { 364 MallocMessageBuilder message; 365 auto root = message.initRoot<JsonValue>(); 366 json.decodeRaw("null", root); 367 368 KJ_EXPECT(root.which() == JsonValue::NULL_); 369 KJ_EXPECT(root.getNull() == VOID); 370 } 371 372 { 373 MallocMessageBuilder message; 374 auto root = message.initRoot<JsonValue>(); 375 376 json.decodeRaw("false", root); 377 KJ_EXPECT(root.which() == JsonValue::BOOLEAN); 378 KJ_EXPECT(root.getBoolean() == false); 379 } 380 381 { 382 MallocMessageBuilder message; 383 auto root = message.initRoot<JsonValue>(); 384 385 json.decodeRaw("true", root); 386 KJ_EXPECT(root.which() == JsonValue::BOOLEAN); 387 KJ_EXPECT(root.getBoolean() == true); 388 } 389 390 { 391 MallocMessageBuilder message; 392 auto root = message.initRoot<JsonValue>(); 393 394 json.decodeRaw("\"foo\"", root); 395 KJ_EXPECT(root.which() == JsonValue::STRING); 396 KJ_EXPECT(kj::str("foo") == root.getString()); 397 } 398 399 { 400 MallocMessageBuilder message; 401 auto root = message.initRoot<JsonValue>(); 402 403 json.decodeRaw(R"("\"")", root); 404 KJ_EXPECT(root.which() == JsonValue::STRING); 405 KJ_EXPECT(kj::str("\"") == root.getString()); 406 } 407 408 { 409 MallocMessageBuilder message; 410 auto root = message.initRoot<JsonValue>(); 411 412 json.decodeRaw(R"("\\abc\"d\\e")", root); 413 KJ_EXPECT(root.which() == JsonValue::STRING); 414 KJ_EXPECT(kj::str("\\abc\"d\\e") == root.getString()); 415 } 416 417 { 418 MallocMessageBuilder message; 419 auto root = message.initRoot<JsonValue>(); 420 421 json.decodeRaw(R"("\"\\\/\b\f\n\r\t\u0003abc\u0064\u0065f")", root); 422 KJ_EXPECT(root.which() == JsonValue::STRING); 423 KJ_EXPECT(kj::str("\"\\/\b\f\n\r\t\x03""abcdef") == root.getString(), root.getString()); 424 } 425 { 426 MallocMessageBuilder message; 427 auto root = message.initRoot<JsonValue>(); 428 429 json.decodeRaw("[]", root); 430 KJ_EXPECT(root.which() == JsonValue::ARRAY, (uint)root.which()); 431 KJ_EXPECT(root.getArray().size() == 0); 432 } 433 434 { 435 MallocMessageBuilder message; 436 auto root = message.initRoot<JsonValue>(); 437 438 json.decodeRaw("[true]", root); 439 KJ_EXPECT(root.which() == JsonValue::ARRAY); 440 auto array = root.getArray(); 441 KJ_EXPECT(array.size() == 1, array.size()); 442 KJ_EXPECT(root.getArray()[0].which() == JsonValue::BOOLEAN); 443 KJ_EXPECT(root.getArray()[0].getBoolean() == true); 444 } 445 446 { 447 MallocMessageBuilder message; 448 auto root = message.initRoot<JsonValue>(); 449 450 json.decodeRaw(" [ true , false\t\n , null]", root); 451 KJ_EXPECT(root.which() == JsonValue::ARRAY); 452 auto array = root.getArray(); 453 KJ_EXPECT(array.size() == 3); 454 KJ_EXPECT(array[0].which() == JsonValue::BOOLEAN); 455 KJ_EXPECT(array[0].getBoolean() == true); 456 KJ_EXPECT(array[1].which() == JsonValue::BOOLEAN); 457 KJ_EXPECT(array[1].getBoolean() == false); 458 KJ_EXPECT(array[2].which() == JsonValue::NULL_); 459 KJ_EXPECT(array[2].getNull() == VOID); 460 } 461 462 { 463 MallocMessageBuilder message; 464 auto root = message.initRoot<JsonValue>(); 465 466 json.decodeRaw("{}", root); 467 KJ_EXPECT(root.which() == JsonValue::OBJECT, (uint)root.which()); 468 KJ_EXPECT(root.getObject().size() == 0); 469 } 470 471 { 472 MallocMessageBuilder message; 473 auto root = message.initRoot<JsonValue>(); 474 475 json.decodeRaw("\r\n\t {\r\n\t }\r\n\t ", root); 476 KJ_EXPECT(root.which() == JsonValue::OBJECT, (uint)root.which()); 477 KJ_EXPECT(root.getObject().size() == 0); 478 } 479 480 { 481 MallocMessageBuilder message; 482 auto root = message.initRoot<JsonValue>(); 483 484 json.decodeRaw(R"({"some": null})", root); 485 KJ_EXPECT(root.which() == JsonValue::OBJECT, (uint)root.which()); 486 auto object = root.getObject(); 487 KJ_EXPECT(object.size() == 1); 488 KJ_EXPECT(kj::str("some") == object[0].getName()); 489 KJ_EXPECT(object[0].getValue().which() == JsonValue::NULL_); 490 } 491 492 { 493 MallocMessageBuilder message; 494 auto root = message.initRoot<JsonValue>(); 495 496 json.decodeRaw(R"({"foo\n\tbaz": "a val", "bar": ["a", -5.5e11, { "z": {}}]})", root); 497 KJ_EXPECT(root.which() == JsonValue::OBJECT, (uint)root.which()); 498 auto object = root.getObject(); 499 KJ_EXPECT(object.size() == 2); 500 KJ_EXPECT(kj::str("foo\n\tbaz") == object[0].getName()); 501 KJ_EXPECT(object[0].getValue().which() == JsonValue::STRING); 502 KJ_EXPECT(kj::str("a val") == object[0].getValue().getString()); 503 504 KJ_EXPECT(kj::str("bar") == object[1].getName()); 505 KJ_EXPECT(object[1].getValue().which() == JsonValue::ARRAY); 506 auto array = object[1].getValue().getArray(); 507 KJ_EXPECT(array.size() == 3, array.size()); 508 KJ_EXPECT(array[0].which() == JsonValue::STRING); 509 KJ_EXPECT(kj::str("a") == array[0].getString()); 510 KJ_EXPECT(array[1].which() == JsonValue::NUMBER); 511 KJ_EXPECT(array[1].getNumber() == -5.5e11); 512 KJ_EXPECT(array[2].which() == JsonValue::OBJECT); 513 KJ_EXPECT(array[2].getObject().size() == 1); 514 KJ_EXPECT(array[2].getObject()[0].getValue().which() == JsonValue::OBJECT); 515 KJ_EXPECT(array[2].getObject()[0].getValue().getObject().size() == 0); 516 } 517 518 { 519 MallocMessageBuilder message; 520 auto root = message.initRoot<JsonValue>(); 521 522 json.decodeRaw("123", root); 523 KJ_EXPECT(root.which() == JsonValue::NUMBER); 524 KJ_EXPECT(root.getNumber() == 123); 525 } 526 527 { 528 MallocMessageBuilder message; 529 auto root = message.initRoot<JsonValue>(); 530 531 KJ_EXPECT_THROW_MESSAGE("input", json.decodeRaw("z", root)); 532 } 533 534 { 535 MallocMessageBuilder message; 536 auto root = message.initRoot<JsonValue>(); 537 538 // Leading + not allowed in numbers. 539 KJ_EXPECT_THROW_MESSAGE("Unexpected", json.decodeRaw("+123", root)); 540 } 541 542 { 543 MallocMessageBuilder message; 544 auto root = message.initRoot<JsonValue>(); 545 546 KJ_EXPECT_THROW_MESSAGE("Unexpected", json.decodeRaw("[00]", root)); 547 KJ_EXPECT_THROW_MESSAGE("Unexpected", json.decodeRaw("[01]", root)); 548 } 549 550 { 551 MallocMessageBuilder message; 552 auto root = message.initRoot<JsonValue>(); 553 554 KJ_EXPECT_THROW_MESSAGE("ends prematurely", json.decodeRaw("-", root)); 555 } 556 557 { 558 MallocMessageBuilder message; 559 auto root = message.initRoot<JsonValue>(); 560 561 json.decodeRaw("-5", root); 562 KJ_EXPECT(root.which() == JsonValue::NUMBER); 563 KJ_EXPECT(root.getNumber() == -5); 564 } 565 566 { 567 MallocMessageBuilder message; 568 auto root = message.initRoot<JsonValue>(); 569 570 json.decodeRaw("-5.5", root); 571 KJ_EXPECT(root.which() == JsonValue::NUMBER); 572 KJ_EXPECT(root.getNumber() == -5.5); 573 } 574 575 { 576 MallocMessageBuilder message; 577 auto root = message.initRoot<JsonValue>(); 578 579 KJ_EXPECT_THROW_MESSAGE("Unexpected input", json.decodeRaw("a", root)); 580 KJ_EXPECT_THROW_MESSAGE("ends prematurely", json.decodeRaw("[", root)); 581 KJ_EXPECT_THROW_MESSAGE("ends prematurely", json.decodeRaw("{", root)); 582 KJ_EXPECT_THROW_MESSAGE("ends prematurely", json.decodeRaw("\"\\u\"", root)); 583 KJ_EXPECT_THROW_MESSAGE("Unexpected input", json.decodeRaw("[}", root)); 584 KJ_EXPECT_THROW_MESSAGE("Unexpected input", json.decodeRaw("{]", root)); 585 KJ_EXPECT_THROW_MESSAGE("Unexpected input", json.decodeRaw("[}]", root)); 586 KJ_EXPECT_THROW_MESSAGE("Unexpected input", json.decodeRaw("[1, , ]", root)); 587 KJ_EXPECT_THROW_MESSAGE("Unexpected input", json.decodeRaw("[,]", root)); 588 KJ_EXPECT_THROW_MESSAGE("Unexpected input", json.decodeRaw("[true,]", root)); 589 KJ_EXPECT_THROW_MESSAGE("Unexpected input", json.decodeRaw("[, 1]", root)); 590 KJ_EXPECT_THROW_MESSAGE("Unexpected input", json.decodeRaw("[1\"\"]", root)); 591 KJ_EXPECT_THROW_MESSAGE("Unexpected input", json.decodeRaw("[1,, \"\"]", root)); 592 KJ_EXPECT_THROW_MESSAGE("Unexpected input", json.decodeRaw("{\"a\"1: 0}", root)); 593 KJ_EXPECT_THROW_MESSAGE("Unexpected input", json.decodeRaw(R"({"some": null,})", root)); 594 KJ_EXPECT_THROW_MESSAGE("Input remains", json.decodeRaw("11a", root)); 595 KJ_EXPECT_THROW_MESSAGE("Invalid escape", json.decodeRaw(R"("\z")", root)); 596 KJ_EXPECT_THROW_MESSAGE("Invalid escape", json.decodeRaw(R"("\z")", root)); 597 { 598 // TODO(msvc): This raw string literal currently confuses MSVC's preprocessor, so I hoisted 599 // it outside the macro. 600 auto f = [&] { json.decodeRaw(R"(["\n\", 3])", root); }; 601 KJ_EXPECT_THROW_MESSAGE("ends prematurely", f()); 602 } 603 KJ_EXPECT_THROW_MESSAGE("Invalid hex", json.decodeRaw(R"("\u12zz")", root)); 604 KJ_EXPECT_THROW_MESSAGE("ends prematurely", json.decodeRaw("-", root)); 605 KJ_EXPECT_THROW_MESSAGE("Unexpected input", json.decodeRaw("--", root)); 606 KJ_EXPECT_THROW_MESSAGE("Unexpected input", json.decodeRaw("\f{}", root)); 607 KJ_EXPECT_THROW_MESSAGE("Unexpected input", json.decodeRaw("{\v}", root)); 608 } 609 } 610 611 KJ_TEST("maximum nesting depth") { 612 JsonCodec json; 613 auto input = kj::str(R"({"foo": "a", "bar": ["b", { "baz": [-5.5e11] }, [ [ 1 ], { "z": 2 }]]})"); 614 // `input` has a maximum nesting depth of 4, reached 3 times. 615 616 { 617 MallocMessageBuilder message; 618 auto root = message.initRoot<JsonValue>(); 619 620 json.decodeRaw(input, root); 621 } 622 623 { 624 json.setMaxNestingDepth(0); 625 MallocMessageBuilder message; 626 auto root = message.initRoot<JsonValue>(); 627 628 KJ_EXPECT_THROW_MESSAGE("nest", 629 json.decodeRaw(input, root)); 630 } 631 632 { 633 json.setMaxNestingDepth(3); 634 MallocMessageBuilder message; 635 auto root = message.initRoot<JsonValue>(); 636 637 KJ_EXPECT_THROW_MESSAGE("nest", 638 json.decodeRaw(input, root)); 639 } 640 641 { 642 json.setMaxNestingDepth(4); 643 MallocMessageBuilder message; 644 auto root = message.initRoot<JsonValue>(); 645 646 json.decodeRaw(input, root); 647 } 648 } 649 650 KJ_TEST("unknown fields") { 651 JsonCodec json; 652 MallocMessageBuilder message; 653 auto root = message.initRoot<TestJsonAnnotations2>(); 654 auto valid = R"({"foo": "a"})"_kj; 655 auto unknown = R"({"foo": "a", "unknown-field": "b"})"_kj; 656 json.decode(valid, root); 657 json.decode(unknown, root); 658 json.setRejectUnknownFields(true); 659 json.decode(valid, root); 660 KJ_EXPECT_THROW_MESSAGE("Unknown field", json.decode(unknown, root)); 661 662 // Verify unknown field rejection still works when handling by annotation. 663 json.handleByAnnotation<TestJsonAnnotations2>(); 664 KJ_EXPECT_THROW_MESSAGE("Unknown field", json.decode(unknown, root)); 665 } 666 667 class TestCallHandler: public JsonCodec::Handler<Text> { 668 public: 669 void encode(const JsonCodec& codec, Text::Reader input, 670 JsonValue::Builder output) const override { 671 auto call = output.initCall(); 672 call.setFunction("Frob"); 673 auto params = call.initParams(2); 674 params[0].setNumber(123); 675 params[1].setString(input); 676 } 677 678 Orphan<Text> decode(const JsonCodec& codec, JsonValue::Reader input, 679 Orphanage orphanage) const override { 680 KJ_UNIMPLEMENTED("TestHandler::decode"); 681 } 682 }; 683 684 class TestDynamicStructHandler: public JsonCodec::Handler<DynamicStruct> { 685 public: 686 void encode(const JsonCodec& codec, DynamicStruct::Reader input, 687 JsonValue::Builder output) const override { 688 auto fields = input.getSchema().getFields(); 689 auto items = output.initArray(fields.size()); 690 for (auto field: fields) { 691 KJ_REQUIRE(field.getIndex() < items.size()); 692 auto item = items[field.getIndex()]; 693 if (input.has(field)) { 694 codec.encode(input.get(field), field.getType(), item); 695 } else { 696 item.setNull(); 697 } 698 } 699 } 700 701 void decode(const JsonCodec& codec, JsonValue::Reader input, 702 DynamicStruct::Builder output) const override { 703 auto orphanage = Orphanage::getForMessageContaining(output); 704 auto fields = output.getSchema().getFields(); 705 auto items = input.getArray(); 706 for (auto field: fields) { 707 KJ_REQUIRE(field.getIndex() < items.size()); 708 auto item = items[field.getIndex()]; 709 if (!item.isNull()) { 710 output.adopt(field, codec.decode(item, field.getType(), orphanage)); 711 } 712 } 713 } 714 }; 715 716 class TestStructHandler: public JsonCodec::Handler<test::TestOldVersion> { 717 public: 718 void encode(const JsonCodec& codec, test::TestOldVersion::Reader input, JsonValue::Builder output) const override { 719 dynamicHandler.encode(codec, input, output); 720 } 721 722 void decode(const JsonCodec& codec, JsonValue::Reader input, test::TestOldVersion::Builder output) const override { 723 dynamicHandler.decode(codec, input, output); 724 } 725 726 private: 727 TestDynamicStructHandler dynamicHandler; 728 }; 729 730 KJ_TEST("register custom encoding handlers") { 731 JsonCodec json; 732 733 TestStructHandler structHandler; 734 json.addTypeHandler(structHandler); 735 736 // JSON decoder can't parse calls back, so test only encoder here 737 TestCallHandler callHandler; 738 json.addTypeHandler(callHandler); 739 740 MallocMessageBuilder message; 741 auto root = message.getRoot<test::TestOldVersion>(); 742 root.setOld1(123); 743 root.setOld2("foo"); 744 745 KJ_EXPECT(json.encode(root) == "[\"123\",Frob(123,\"foo\"),null]"); 746 } 747 748 KJ_TEST("register custom roundtrip handler") { 749 for (auto i = 1; i <= 2; i++) { 750 JsonCodec json; 751 TestStructHandler staticHandler; 752 TestDynamicStructHandler dynamicHandler; 753 kj::String encoded; 754 755 if (i == 1) { 756 // first iteration: test with explicit struct handler 757 json.addTypeHandler(staticHandler); 758 } else { 759 // second iteration: same checks, but with DynamicStruct handler 760 json.addTypeHandler(StructSchema::from<test::TestOldVersion>(), dynamicHandler); 761 } 762 763 { 764 MallocMessageBuilder message; 765 auto root = message.getRoot<test::TestOldVersion>(); 766 root.setOld1(123); 767 root.initOld3().setOld2("foo"); 768 769 encoded = json.encode(root); 770 771 KJ_EXPECT(encoded == "[\"123\",null,[\"0\",\"foo\",null]]"); 772 } 773 774 { 775 MallocMessageBuilder message; 776 auto root = message.getRoot<test::TestOldVersion>(); 777 json.decode(encoded, root); 778 779 KJ_EXPECT(root.getOld1() == 123); 780 KJ_EXPECT(!root.hasOld2()); 781 auto nested = root.getOld3(); 782 KJ_EXPECT(nested.getOld1() == 0); 783 KJ_EXPECT("foo" == nested.getOld2()); 784 KJ_EXPECT(!nested.hasOld3()); 785 } 786 } 787 } 788 789 KJ_TEST("register field handler") { 790 TestStructHandler handler; 791 JsonCodec json; 792 json.addFieldHandler(StructSchema::from<test::TestOldVersion>().getFieldByName("old3"), 793 handler); 794 795 kj::String encoded; 796 797 { 798 MallocMessageBuilder message; 799 auto root = message.getRoot<test::TestOldVersion>(); 800 root.setOld1(123); 801 root.setOld2("foo"); 802 auto nested = root.initOld3(); 803 nested.setOld2("bar"); 804 805 encoded = json.encode(root); 806 807 KJ_EXPECT(encoded == "{\"old1\":\"123\",\"old2\":\"foo\",\"old3\":[\"0\",\"bar\",null]}") 808 } 809 810 { 811 MallocMessageBuilder message; 812 auto root = message.getRoot<test::TestOldVersion>(); 813 json.decode(encoded, root); 814 815 KJ_EXPECT(root.getOld1() == 123); 816 KJ_EXPECT("foo" == root.getOld2()); 817 auto nested = root.getOld3(); 818 KJ_EXPECT(nested.getOld1() == 0); 819 KJ_EXPECT("bar" == nested.getOld2()); 820 KJ_EXPECT(!nested.hasOld3()); 821 } 822 } 823 824 class TestCapabilityHandler: public JsonCodec::Handler<test::TestInterface> { 825 public: 826 void encode(const JsonCodec& codec, test::TestInterface::Client input, 827 JsonValue::Builder output) const override { 828 KJ_UNIMPLEMENTED("TestCapabilityHandler::encode"); 829 } 830 831 test::TestInterface::Client decode( 832 const JsonCodec& codec, JsonValue::Reader input) const override { 833 return nullptr; 834 } 835 }; 836 837 KJ_TEST("register capability handler") { 838 // This test currently only checks that this compiles, which at one point wasn't the caes. 839 // TODO(test): Actually run some code here. 840 841 TestCapabilityHandler handler; 842 JsonCodec json; 843 json.addTypeHandler(handler); 844 } 845 846 static constexpr kj::StringPtr GOLDEN_ANNOTATED = 847 R"({ "names-can_contain!anything Really": "foo", 848 "flatFoo": 123, 849 "flatBar": "abc", 850 "renamed-flatBaz": {"hello": true}, 851 "flatQux": "cba", 852 "pfx.foo": "this is a long string in order to force multi-line pretty printing", 853 "pfx.renamed-bar": 321, 854 "pfx.baz": {"hello": true}, 855 "pfx.xfp.qux": "fed", 856 "union-type": "renamed-bar", 857 "barMember": 789, 858 "multiMember": "ghi", 859 "dependency": {"renamed-foo": "corge"}, 860 "simpleGroup": {"renamed-grault": "garply"}, 861 "enums": ["qux", "renamed-bar", "foo", "renamed-baz"], 862 "innerJson": [123, "hello", {"object": true}], 863 "customFieldHandler": "add-prefix-waldo", 864 "testBase64": "ZnJlZA==", 865 "testHex": "706c756768", 866 "bUnion": "renamed-bar", 867 "bValue": 678, 868 "externalUnion": {"type": "bar", "value": "cba"}, 869 "unionWithVoid": {"type": "voidValue"} })"_kj; 870 871 static constexpr kj::StringPtr GOLDEN_ANNOTATED_REVERSE = 872 R"({ 873 "unionWithVoid": {"type": "voidValue"}, 874 "externalUnion": {"type": "bar", "value": "cba"}, 875 "bValue": 678, 876 "bUnion": "renamed-bar", 877 "testHex": "706c756768", 878 "testBase64": "ZnJlZA==", 879 "customFieldHandler": "add-prefix-waldo", 880 "innerJson": [123, "hello", {"object": true}], 881 "enums": ["qux", "renamed-bar", "foo", "renamed-baz"], 882 "simpleGroup": { "renamed-grault": "garply" }, 883 "dependency": { "renamed-foo": "corge" }, 884 "multiMember": "ghi", 885 "barMember": 789, 886 "union-type": "renamed-bar", 887 "pfx.xfp.qux": "fed", 888 "pfx.baz": {"hello": true}, 889 "pfx.renamed-bar": 321, 890 "pfx.foo": "this is a long string in order to force multi-line pretty printing", 891 "flatQux": "cba", 892 "renamed-flatBaz": {"hello": true}, 893 "flatBar": "abc", 894 "flatFoo": 123, 895 "names-can_contain!anything Really": "foo" 896 })"_kj; 897 898 class PrefixAdder: public JsonCodec::Handler<capnp::Text> { 899 public: 900 void encode(const JsonCodec& codec, capnp::Text::Reader input, JsonValue::Builder output) const { 901 output.setString(kj::str("add-prefix-", input)); 902 } 903 904 Orphan<capnp::Text> decode(const JsonCodec& codec, JsonValue::Reader input, 905 Orphanage orphanage) const { 906 return orphanage.newOrphanCopy(capnp::Text::Reader(input.getString().slice(11))); 907 } 908 }; 909 910 KJ_TEST("rename fields") { 911 JsonCodec json; 912 json.handleByAnnotation<TestJsonAnnotations>(); 913 json.setPrettyPrint(true); 914 915 PrefixAdder customHandler; 916 json.addFieldHandler(Schema::from<TestJsonAnnotations>().getFieldByName("customFieldHandler"), 917 customHandler); 918 919 kj::String goldenText; 920 921 { 922 MallocMessageBuilder message; 923 auto root = message.getRoot<TestJsonAnnotations>(); 924 root.setSomeField("foo"); 925 926 auto aGroup = root.getAGroup(); 927 aGroup.setFlatFoo(123); 928 aGroup.setFlatBar("abc"); 929 aGroup.getFlatBaz().setHello(true); 930 aGroup.getDoubleFlat().setFlatQux("cba"); 931 932 auto prefixedGroup = root.getPrefixedGroup(); 933 prefixedGroup.setFoo("this is a long string in order to force multi-line pretty printing"); 934 prefixedGroup.setBar(321); 935 prefixedGroup.getBaz().setHello(true); 936 prefixedGroup.getMorePrefix().setQux("fed"); 937 938 auto unionBar = root.getAUnion().initBar(); 939 unionBar.setBarMember(789); 940 unionBar.setMultiMember("ghi"); 941 942 root.initDependency().setFoo("corge"); 943 root.initSimpleGroup().setGrault("garply"); 944 945 root.setEnums({ 946 TestJsonAnnotatedEnum::QUX, 947 TestJsonAnnotatedEnum::BAR, 948 TestJsonAnnotatedEnum::FOO, 949 TestJsonAnnotatedEnum::BAZ 950 }); 951 952 auto val = root.initInnerJson(); 953 auto arr = val.initArray(3); 954 arr[0].setNumber(123); 955 arr[1].setString("hello"); 956 auto field = arr[2].initObject(1)[0]; 957 field.setName("object"); 958 field.initValue().setBoolean(true); 959 960 root.setCustomFieldHandler("waldo"); 961 962 root.setTestBase64("fred"_kj.asBytes()); 963 root.setTestHex("plugh"_kj.asBytes()); 964 965 root.getBUnion().setBar(678); 966 967 root.initExternalUnion().initBar().setValue("cba"); 968 969 root.initUnionWithVoid().setVoidValue(); 970 971 auto encoded = json.encode(root.asReader()); 972 KJ_EXPECT(encoded == GOLDEN_ANNOTATED, encoded); 973 974 goldenText = kj::str(root); 975 } 976 977 { 978 MallocMessageBuilder message; 979 auto root = message.getRoot<TestJsonAnnotations>(); 980 json.decode(GOLDEN_ANNOTATED, root); 981 982 KJ_EXPECT(kj::str(root) == goldenText, root, goldenText); 983 } 984 985 { 986 // Try parsing in reverse, mostly to test that union tags can come after content. 987 MallocMessageBuilder message; 988 auto root = message.getRoot<TestJsonAnnotations>(); 989 json.decode(GOLDEN_ANNOTATED_REVERSE, root); 990 991 KJ_EXPECT(kj::str(root) == goldenText, root, goldenText); 992 } 993 } 994 995 KJ_TEST("base64 union encoded correctly") { 996 // At one point field handlers were not correctly applied when the field was a member of a union 997 // in a type that was handled by annotation. 998 999 JsonCodec json; 1000 json.handleByAnnotation<TestBase64Union>(); 1001 json.setPrettyPrint(true); 1002 1003 MallocMessageBuilder message; 1004 auto root = message.getRoot<TestBase64Union>(); 1005 root.initFoo(5); 1006 1007 KJ_EXPECT(json.encode(root) == "{\"foo\": \"AAAAAAA=\"}", json.encode(root)); 1008 } 1009 1010 } // namespace 1011 } // namespace _ (private) 1012 } // namespace capnp