| 1 | #include <cassert> |
| 2 | #include <iostream> |
| 3 | #include <suwa/json.hh> |
| 4 | #include "file.hh" |
| 5 | |
| 6 | json::ParseResult parse_from_file(const string &path) { |
| 7 | vector<u8> data = read_file(path, false); |
| 8 | string content(data.begin(), data.end()); |
| 9 | return json::Parser(content).parse(); |
| 10 | } |
| 11 | |
| 12 | bool serialize_to_file(const string &path, const json::Value &value, const json::SerializeOptions &opts) { |
| 13 | return write_file(path, { value.serialize(opts) }, false); |
| 14 | } |
| 15 | |
| 16 | int main(void) { |
| 17 | { |
| 18 | const string src = R"({ |
| 19 | "name": "諏訪子", |
| 20 | "kero": "🐸", |
| 21 | "age": 2300, |
| 22 | "alive": true, |
| 23 | "power": 99.5, |
| 24 | "items": ["hat", "frog", 42], |
| 25 | "nested": { |
| 26 | "faith": null |
| 27 | } |
| 28 | })"; |
| 29 | |
| 30 | auto res = json::Parser(src).parse(); |
| 31 | assert(res.error == json::Error::None); |
| 32 | assert(res.value); |
| 33 | assert(res.value->is_object()); |
| 34 | |
| 35 | auto &root = res.value->as_object(); |
| 36 | std::cout << root["name"] << std::endl; |
| 37 | assert(root.contains("kero")); |
| 38 | assert(root.get("name")->as_string() == "諏訪子"); |
| 39 | assert(root.get("kero")->as_string() == "🐸"); |
| 40 | assert(root.get("age")->as_number() == 2300); |
| 41 | assert(root.get("alive")->as_bool() == true); |
| 42 | assert(root.get("power")->as_number() == 99.5); |
| 43 | |
| 44 | auto &items = root.get("items")->as_array(); |
| 45 | assert(items.size() == 3); |
| 46 | assert(items[0].as_string() == "hat"); |
| 47 | assert(items[1].as_string() == "frog"); |
| 48 | assert(items[2].as_number() == 42); |
| 49 | |
| 50 | auto &nested = root.get("nested")->as_object(); |
| 51 | assert(nested.get("faith")->is_null()); |
| 52 | |
| 53 | auto out = res.value->serialize(); |
| 54 | std::cout << out << std::endl; |
| 55 | auto out2 = res.value->serialize({ .pretty = true, .indent = 2 }); |
| 56 | std::cout << out2 << std::endl; |
| 57 | auto out3 = res.value->serialize({ .pretty = true, .indent = 8 }); |
| 58 | std::cout << out3 << std::endl; |
| 59 | |
| 60 | auto res2 = json::Parser(out).parse(); |
| 61 | assert(res2.error == json::Error::None); |
| 62 | |
| 63 | auto res3 = json::Parser(out2).parse(); |
| 64 | assert(res3.error == json::Error::None); |
| 65 | |
| 66 | auto res4 = json::Parser(out3).parse(); |
| 67 | assert(res4.error == json::Error::None); |
| 68 | |
| 69 | std::cout << "Memory OK" << std::endl; |
| 70 | } |
| 71 | |
| 72 | { |
| 73 | auto res = parse_from_file("webfinger.json"); |
| 74 | assert(res.error == json::Error::None); |
| 75 | assert(res.value); |
| 76 | assert(res.value->is_object()); |
| 77 | |
| 78 | auto &root = res.value->as_object(); |
| 79 | auto *links = root.get("links"); |
| 80 | assert(links); |
| 81 | assert(links->is_array()); |
| 82 | |
| 83 | auto &arr = links->as_array(); |
| 84 | assert(arr.size() == 1); |
| 85 | assert(arr[0].is_object()); |
| 86 | auto &link = arr[0].as_object(); |
| 87 | |
| 88 | assert(link.get("href")); |
| 89 | assert(link.get("rel")); |
| 90 | assert(link.get("type")); |
| 91 | |
| 92 | assert(link.get("href")->as_string() == "https://sns.076.moe/users/suwako"); |
| 93 | assert(link.get("rel")->as_string() == "self"); |
| 94 | assert(link.get("type")->as_string() == "application/activity+json"); |
| 95 | |
| 96 | auto *subject = root.get("subject"); |
| 97 | assert(subject); |
| 98 | assert(subject->as_string() == "acct:suwako@sns.076.moe"); |
| 99 | |
| 100 | auto out = serialize_to_file("webfinger2.json", *res.value, {}); |
| 101 | auto out2 = serialize_to_file("webfinger3.json", *res.value, { .pretty = true, .indent = 2 }); |
| 102 | |
| 103 | auto res2 = parse_from_file("webfinger2.json"); |
| 104 | assert(res2.error == json::Error::None); |
| 105 | |
| 106 | auto res3 = parse_from_file("webfinger3.json"); |
| 107 | assert(res3.error == json::Error::None); |
| 108 | |
| 109 | std::cout << "WebFinger OK" << std::endl; |
| 110 | } |
| 111 | |
| 112 | { |
| 113 | auto res = parse_from_file("gltf.json"); |
| 114 | assert(res.error == json::Error::None); |
| 115 | assert(res.value); |
| 116 | assert(res.value->is_object()); |
| 117 | |
| 118 | auto &root = res.value->as_object(); |
| 119 | assert(root.get("scene")->as_number() == 0); |
| 120 | |
| 121 | { |
| 122 | auto *scenes = root.get("scenes"); |
| 123 | assert(scenes); |
| 124 | assert(scenes->is_array()); |
| 125 | |
| 126 | auto &arr = scenes->as_array(); |
| 127 | assert(arr.size() == 1); |
| 128 | assert(arr[0].is_object()); |
| 129 | auto &scene = arr[0].as_object(); |
| 130 | |
| 131 | assert(scene.get("nodes")->is_array()); |
| 132 | auto &sceneNodes = scene.get("nodes")->as_array(); |
| 133 | assert(sceneNodes.size() == 1); |
| 134 | assert(sceneNodes[0].as_number() == 0); |
| 135 | } |
| 136 | |
| 137 | { |
| 138 | auto *nodes = root.get("nodes"); |
| 139 | auto &arr = nodes->as_array(); |
| 140 | assert(arr.size() == 1); |
| 141 | assert(arr[0].is_object()); |
| 142 | auto &node = arr[0].as_object(); |
| 143 | |
| 144 | assert(node.get("mesh")->as_number() == 0); |
| 145 | } |
| 146 | |
| 147 | { |
| 148 | auto *buffers = root.get("buffers"); |
| 149 | auto &arr = buffers->as_array(); |
| 150 | assert(arr.size() == 1); |
| 151 | assert(arr[0].is_object()); |
| 152 | assert(arr[0].as_object().get("uri")->as_string() == "data:application/octet-stream;base64,AAABAAIAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAACAPwAAAAA="); |
| 153 | assert(arr[0].as_object().get("byteLength")->as_number() == 44); |
| 154 | } |
| 155 | |
| 156 | { |
| 157 | auto *bufferViews = root.get("bufferViews"); |
| 158 | auto &arr = bufferViews->as_array(); |
| 159 | assert(arr.size() == 2); |
| 160 | assert(arr[0].is_object()); |
| 161 | assert(arr[0].as_object().get("buffer")->as_number() == 0); |
| 162 | assert(arr[0].as_object().get("byteOffset")->as_number() == 0); |
| 163 | assert(arr[0].as_object().get("byteLength")->as_number() == 6); |
| 164 | assert(arr[0].as_object().get("target")->as_number() == 34963); |
| 165 | |
| 166 | assert(arr[1].as_object().get("buffer")->as_number() == 0); |
| 167 | assert(arr[1].as_object().get("byteOffset")->as_number() == 8); |
| 168 | assert(arr[1].as_object().get("byteLength")->as_number() == 36); |
| 169 | assert(arr[1].as_object().get("target")->as_number() == 34962); |
| 170 | } |
| 171 | |
| 172 | { |
| 173 | auto *accessors = root.get("accessors"); |
| 174 | auto &arr = accessors->as_array(); |
| 175 | assert(arr.size() == 2); |
| 176 | assert(arr[0].is_object()); |
| 177 | assert(arr[0].as_object().get("bufferView")->as_number() == 0); |
| 178 | assert(arr[0].as_object().get("byteOffset")->as_number() == 0); |
| 179 | assert(arr[0].as_object().get("componentType")->as_number() == 5123); |
| 180 | assert(arr[0].as_object().get("count")->as_number() == 3); |
| 181 | assert(arr[0].as_object().get("type")->as_string() == "SCALAR"); |
| 182 | const auto &max0 = arr[0].as_object().get("max")->as_array(); |
| 183 | assert(max0.size() == 1); |
| 184 | assert(max0[0].get_number() == 2); |
| 185 | const auto &min0 = arr[0].as_object().get("min")->as_array(); |
| 186 | assert(min0.size() == 1); |
| 187 | assert(min0[0].get_number() == 0); |
| 188 | |
| 189 | assert(arr[1].is_object()); |
| 190 | assert(arr[1].as_object().get("bufferView")->as_number() == 1); |
| 191 | assert(arr[1].as_object().get("byteOffset")->as_number() == 0); |
| 192 | assert(arr[1].as_object().get("componentType")->as_number() == 5126); |
| 193 | assert(arr[1].as_object().get("count")->as_number() == 3); |
| 194 | assert(arr[1].as_object().get("type")->as_string() == "VEC3"); |
| 195 | const auto &max1 = arr[1].as_object().get("max")->as_array(); |
| 196 | assert(max1.size() == 3); |
| 197 | assert(max1[0].get_number() == 1.0); |
| 198 | assert(max1[1].get_number() == 1.0); |
| 199 | assert(max1[2].get_number() == 0.0); |
| 200 | const auto &min1 = arr[1].as_object().get("min")->as_array(); |
| 201 | assert(min1.size() == 3); |
| 202 | assert(min1[0].get_number() == 0.0); |
| 203 | assert(min1[1].get_number() == 0.0); |
| 204 | assert(min1[2].get_number() == 0.0); |
| 205 | } |
| 206 | |
| 207 | { |
| 208 | auto *asset = root.get("asset"); |
| 209 | auto &obj = asset->as_object(); |
| 210 | assert(obj.get("version")->as_string() == "2.0"); |
| 211 | } |
| 212 | |
| 213 | auto out = serialize_to_file("gltf2.json", *res.value, {}); |
| 214 | auto out2 = serialize_to_file("gltf3.json", *res.value, {.pretty = true, .indent = 2}); |
| 215 | |
| 216 | auto res2 = parse_from_file("gltf2.json"); |
| 217 | assert(res2.error == json::Error::None); |
| 218 | |
| 219 | auto res3 = parse_from_file("gltf3.json"); |
| 220 | assert(res3.error == json::Error::None); |
| 221 | |
| 222 | std::cout << "glTF OK" << std::endl; |
| 223 | } |
| 224 | |
| 225 | { |
| 226 | auto res = parse_from_file("activitypub.json"); |
| 227 | assert(res.error == json::Error::None); |
| 228 | assert(res.value); |
| 229 | assert(res.value->is_object()); |
| 230 | |
| 231 | auto &root = res.value->as_object(); |
| 232 | auto *context = root.get("@context"); |
| 233 | assert(context); |
| 234 | assert(context->is_array()); |
| 235 | |
| 236 | auto &arr = context->as_array(); |
| 237 | assert(arr.size() == 2); |
| 238 | assert(arr[0].is_string()); |
| 239 | assert(arr[1].is_string()); |
| 240 | assert(arr[0].get_string() == "https://www.w3.org/ns/activitystreams"); |
| 241 | assert(arr[1].get_string() == "https://w3id.org/security/v1"); |
| 242 | |
| 243 | auto *type = root.get("type"); |
| 244 | assert(type); |
| 245 | assert(type->as_string() == "Person"); |
| 246 | |
| 247 | auto *id = root.get("id"); |
| 248 | assert(id); |
| 249 | assert(id->as_string() == "https://example.social/users/sam"); |
| 250 | |
| 251 | auto *preferredUsername = root.get("preferredUsername"); |
| 252 | assert(preferredUsername); |
| 253 | assert(preferredUsername->as_string() == "sam"); |
| 254 | |
| 255 | auto *inbox = root.get("inbox"); |
| 256 | assert(inbox); |
| 257 | assert(inbox->as_string() == "https://example.social/inbox"); |
| 258 | |
| 259 | auto *publicKey = root.get("publicKey"); |
| 260 | assert(publicKey); |
| 261 | assert(publicKey->is_object()); |
| 262 | |
| 263 | auto &pubkey = publicKey->as_object(); |
| 264 | assert(pubkey.get("id")->as_string() == "https://example.social/users/sam#main-key"); |
| 265 | assert(pubkey.get("owner")->as_string() == "https://example.social/users/sam"); |
| 266 | assert(pubkey.get("publicKeyPem")->as_string() == "-----BEGIN PUBLIC KEY-----\n...\n----END PUBLIC KEY----"); |
| 267 | |
| 268 | auto out = serialize_to_file("activitypub2.json", *res.value, {}); |
| 269 | auto out2 = serialize_to_file("activitypub3.json", *res.value, { .pretty = true, .indent = 2 }); |
| 270 | |
| 271 | auto res2 = parse_from_file("activitypub2.json"); |
| 272 | assert(res2.error == json::Error::None); |
| 273 | |
| 274 | auto res3 = parse_from_file("activitypub3.json"); |
| 275 | assert(res3.error == json::Error::None); |
| 276 | |
| 277 | std::cout << "ActivityPub OK" << std::endl; |
| 278 | } |
| 279 | |
| 280 | { |
| 281 | { |
| 282 | const string src = R"({ |
| 283 | "a": [,,,])"; |
| 284 | auto res = json::Parser(src).parse(); |
| 285 | assert(res.error == json::Error::InvalidValue); |
| 286 | } |
| 287 | { |
| 288 | const string src = R"({"x":"\q"})"; |
| 289 | auto res = json::Parser(src).parse(); |
| 290 | assert(res.error == json::Error::SyntaxError); |
| 291 | } |
| 292 | { |
| 293 | const string src = R"({"x":1.2345g})"; |
| 294 | auto res = json::Parser(src).parse(); |
| 295 | assert(res.error == json::Error::SyntaxError); |
| 296 | } |
| 297 | { |
| 298 | const string src = R"({"x":"suwa})"; |
| 299 | auto res = json::Parser(src).parse(); |
| 300 | assert(res.error == json::Error::UnterminatedString); |
| 301 | } |
| 302 | { |
| 303 | const string src = R"({"x":tru})"; |
| 304 | auto res = json::Parser(src).parse(); |
| 305 | assert(res.error == json::Error::InvalidValue); |
| 306 | } |
| 307 | { |
| 308 | const string src = R"([[[[[[[[[[[]]]]]]]]]]])"; |
| 309 | auto res = json::Parser(src).parse(); |
| 310 | assert(res.error == json::Error::None); |
| 311 | } |
| 312 | { |
| 313 | const string src = R"([[[[[[[[[[[[]]]]]]]]]]])"; |
| 314 | auto res = json::Parser(src).parse(); |
| 315 | assert(res.error == json::Error::SyntaxError); |
| 316 | } |
| 317 | { |
| 318 | const string src = R"({"x":"\uXXXX"})"; |
| 319 | auto res = json::Parser(src).parse(); |
| 320 | assert(res.error == json::Error::SyntaxError); |
| 321 | } |
| 322 | |
| 323 | std::cout << "Bad OK" << std::endl; |
| 324 | } |
| 325 | |
| 326 | return 0; |
| 327 | } |