Eric Haszlakiewicz | c5c623a | 2012-03-31 22:51:39 -0500 | [diff] [blame] | 1 | #include <stdio.h> |
| 2 | #include <stdlib.h> |
| 3 | #include <stddef.h> |
| 4 | #include <string.h> |
| 5 | #include <assert.h> |
| 6 | |
| 7 | #include "json.h" |
| 8 | #include "json_tokener.h" |
| 9 | |
| 10 | static void test_basic_parse(void); |
| 11 | static void test_verbose_parse(void); |
| 12 | static void test_incremental_parse(void); |
| 13 | |
| 14 | int main(int argc, char **argv) |
| 15 | { |
| 16 | MC_SET_DEBUG(1); |
| 17 | |
| 18 | test_basic_parse(); |
| 19 | printf("==================================\n"); |
| 20 | test_verbose_parse(); |
| 21 | printf("==================================\n"); |
| 22 | test_incremental_parse(); |
| 23 | printf("==================================\n"); |
| 24 | } |
| 25 | |
| 26 | static void test_basic_parse() |
| 27 | { |
| 28 | json_object *new_obj; |
| 29 | |
| 30 | new_obj = json_tokener_parse("\"\003\""); |
| 31 | printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); |
| 32 | json_object_put(new_obj); |
| 33 | |
| 34 | new_obj = json_tokener_parse("/* hello */\"foo\""); |
| 35 | printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); |
| 36 | json_object_put(new_obj); |
| 37 | |
| 38 | new_obj = json_tokener_parse("// hello\n\"foo\""); |
| 39 | printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); |
| 40 | json_object_put(new_obj); |
| 41 | |
| 42 | new_obj = json_tokener_parse("\"\\u0041\\u0042\\u0043\""); |
| 43 | printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); |
| 44 | json_object_put(new_obj); |
| 45 | |
| 46 | new_obj = json_tokener_parse("null"); |
| 47 | printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); |
| 48 | json_object_put(new_obj); |
| 49 | |
| 50 | new_obj = json_tokener_parse("True"); |
| 51 | printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); |
| 52 | json_object_put(new_obj); |
| 53 | |
| 54 | new_obj = json_tokener_parse("12"); |
| 55 | printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); |
| 56 | json_object_put(new_obj); |
| 57 | |
| 58 | new_obj = json_tokener_parse("12.3"); |
| 59 | printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); |
| 60 | json_object_put(new_obj); |
| 61 | |
| 62 | new_obj = json_tokener_parse("[\"\\n\"]"); |
| 63 | printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); |
| 64 | json_object_put(new_obj); |
| 65 | |
| 66 | new_obj = json_tokener_parse("[\"\\nabc\\n\"]"); |
| 67 | printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); |
| 68 | json_object_put(new_obj); |
| 69 | |
| 70 | new_obj = json_tokener_parse("[null]"); |
| 71 | printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); |
| 72 | json_object_put(new_obj); |
| 73 | |
| 74 | new_obj = json_tokener_parse("[]"); |
| 75 | printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); |
| 76 | json_object_put(new_obj); |
| 77 | |
| 78 | new_obj = json_tokener_parse("[false]"); |
| 79 | printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); |
| 80 | json_object_put(new_obj); |
| 81 | |
| 82 | new_obj = json_tokener_parse("[\"abc\",null,\"def\",12]"); |
| 83 | printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); |
| 84 | json_object_put(new_obj); |
| 85 | |
| 86 | new_obj = json_tokener_parse("{}"); |
| 87 | printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); |
| 88 | json_object_put(new_obj); |
| 89 | |
| 90 | new_obj = json_tokener_parse("{ \"foo\": \"bar\" }"); |
| 91 | printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); |
| 92 | json_object_put(new_obj); |
| 93 | |
| 94 | new_obj = json_tokener_parse("{ \"foo\": \"bar\", \"baz\": null, \"bool0\": true }"); |
| 95 | printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); |
| 96 | json_object_put(new_obj); |
| 97 | |
| 98 | new_obj = json_tokener_parse("{ \"foo\": [null, \"foo\"] }"); |
| 99 | printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); |
| 100 | json_object_put(new_obj); |
| 101 | |
| 102 | new_obj = json_tokener_parse("{ \"abc\": 12, \"foo\": \"bar\", \"bool0\": false, \"bool1\": true, \"arr\": [ 1, 2, 3, null, 5 ] }"); |
| 103 | printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); |
| 104 | json_object_put(new_obj); |
| 105 | } |
| 106 | |
| 107 | static void test_verbose_parse() |
| 108 | { |
| 109 | json_object *new_obj; |
| 110 | enum json_tokener_error error = json_tokener_success; |
| 111 | |
| 112 | new_obj = json_tokener_parse_verbose("{ foo }", &error); |
| 113 | assert (error == json_tokener_error_parse_object_key_name); |
| 114 | assert (new_obj == NULL); |
| 115 | |
| 116 | new_obj = json_tokener_parse("{ foo }"); |
| 117 | assert (new_obj == NULL); |
| 118 | |
| 119 | new_obj = json_tokener_parse("foo"); |
| 120 | assert (new_obj == NULL); |
| 121 | new_obj = json_tokener_parse_verbose("foo", &error); |
| 122 | assert (new_obj == NULL); |
| 123 | |
| 124 | /* b/c the string starts with 'f' parsing return a boolean error */ |
| 125 | assert (error == json_tokener_error_parse_boolean); |
| 126 | |
| 127 | printf("json_tokener_parse_versbose() OK\n"); |
| 128 | } |
| 129 | |
| 130 | struct incremental_step { |
| 131 | const char *string_to_parse; |
| 132 | int length; |
| 133 | int char_offset; |
| 134 | enum json_tokener_error expected_error; |
| 135 | int reset_tokener; |
| 136 | } incremental_steps[] = { |
| 137 | |
| 138 | /* Check that full json messages can be parsed, both w/ and w/o a reset */ |
| 139 | { "{ \"foo\": 123 }", -1, -1, json_tokener_success, 0 }, |
| 140 | { "{ \"foo\": 456 }", -1, -1, json_tokener_success, 1 }, |
| 141 | { "{ \"foo\": 789 }", -1, -1, json_tokener_success, 1 }, |
| 142 | |
| 143 | /* Check a basic incremental parse */ |
| 144 | { "{ \"foo", -1, -1, json_tokener_continue, 0 }, |
| 145 | { "\": {\"bar", -1, -1, json_tokener_continue, 0 }, |
| 146 | { "\":13}}", -1, -1, json_tokener_success, 1 }, |
| 147 | |
| 148 | /* Check that json_tokener_reset actually resets */ |
| 149 | { "{ \"foo", -1, -1, json_tokener_continue, 1 }, |
| 150 | { ": \"bar\"}", -1, 0, json_tokener_error_parse_unexpected, 1 }, |
| 151 | |
| 152 | /* Check incremental parsing with trailing characters */ |
| 153 | { "{ \"foo", -1, -1, json_tokener_continue, 0 }, |
| 154 | { "\": {\"bar", -1, -1, json_tokener_continue, 0 }, |
| 155 | { "\":13}}XXXX", 10, 6, json_tokener_success, 0 }, |
| 156 | { "XXXX", 4, 0, json_tokener_error_parse_unexpected, 1 }, |
| 157 | |
| 158 | /* Check that trailing characters can change w/o a reset */ |
| 159 | { "{\"x\": 123 }\"X\"", -1, 11, json_tokener_success, 0 }, |
| 160 | { "\"Y\"", -1, -1, json_tokener_success, 1 }, |
| 161 | |
| 162 | /* To stop parsing a number we need to reach a non-digit, e.g. a \0 */ |
| 163 | { "1", 1, 1, json_tokener_continue, 0 }, |
| 164 | { "2", 2, 1, json_tokener_success, 0 }, |
| 165 | |
| 166 | /* Strings have a well defined end point, so we can stop at the quote */ |
| 167 | { "\"blue\"", -1, -1, json_tokener_success, 0 }, |
| 168 | |
| 169 | { "[1,2,3]", -1, -1, json_tokener_success, 0 }, |
| 170 | |
| 171 | /* This behaviour doesn't entirely follow the json spec, but until we have |
| 172 | a way to specify how strict to be we follow Postel's Law and be liberal |
| 173 | in what we accept (up to a point). */ |
| 174 | { "[1,2,3,]", -1, -1, json_tokener_success, 0 }, |
| 175 | { "[1,2,,3,]", -1, 5, json_tokener_error_parse_unexpected, 0 }, |
| 176 | |
| 177 | { NULL, json_tokener_success }, |
| 178 | }; |
| 179 | |
| 180 | static void test_incremental_parse() |
| 181 | { |
| 182 | json_object *new_obj; |
| 183 | enum json_tokener_error jerr; |
| 184 | json_tokener *tok; |
| 185 | const char *string_to_parse; |
| 186 | int ii; |
| 187 | int num_ok, num_error; |
| 188 | |
| 189 | num_ok = 0; |
| 190 | num_error = 0; |
| 191 | |
| 192 | printf("Starting incremental tests.\n"); |
| 193 | |
| 194 | string_to_parse = "{ \"foo"; /* } */ |
| 195 | printf("json_tokener_parse(%s) ... ", string_to_parse); |
| 196 | new_obj = json_tokener_parse(string_to_parse); |
| 197 | if (new_obj == NULL) printf("got error as expected\n"); |
| 198 | |
| 199 | /* test incremental parsing in various forms */ |
| 200 | tok = json_tokener_new(); |
| 201 | for (ii = 0; incremental_steps[ii].string_to_parse != NULL; ii++) |
| 202 | { |
| 203 | int this_step_ok = 0; |
| 204 | struct incremental_step *step = &incremental_steps[ii]; |
| 205 | int length = step->length; |
| 206 | int expected_char_offset = step->char_offset; |
| 207 | if (length == -1) |
| 208 | length = strlen(step->string_to_parse); |
| 209 | if (expected_char_offset == -1) |
| 210 | expected_char_offset = length; |
| 211 | |
| 212 | printf("json_tokener_parse_ex(tok, %-12s, %3d) ... ", |
| 213 | step->string_to_parse, length); |
| 214 | new_obj = json_tokener_parse_ex(tok, step->string_to_parse, length); |
| 215 | |
| 216 | jerr = json_tokener_get_error(tok); |
| 217 | if (step->expected_error != json_tokener_success) |
| 218 | { |
| 219 | if (new_obj != NULL) |
| 220 | printf("ERROR: invalid object returned: %s\n", |
| 221 | json_object_to_json_string(new_obj)); |
| 222 | else if (jerr != step->expected_error) |
| 223 | printf("ERROR: got wrong error: %s\n", |
| 224 | json_tokener_error_desc(jerr)); |
| 225 | else if (tok->char_offset != expected_char_offset) |
| 226 | printf("ERROR: wrong char_offset %d != expected %d\n", |
| 227 | tok->char_offset, |
| 228 | expected_char_offset); |
| 229 | else |
| 230 | { |
| 231 | printf("OK: got correct error: %s\n", json_tokener_error_desc(jerr)); |
| 232 | this_step_ok = 1; |
| 233 | } |
| 234 | } |
| 235 | else |
| 236 | { |
| 237 | if (new_obj == NULL) |
| 238 | printf("ERROR: expected valid object, instead: %s\n", |
| 239 | json_tokener_error_desc(jerr)); |
| 240 | else if (tok->char_offset != expected_char_offset) |
| 241 | printf("ERROR: wrong char_offset %d != expected %d\n", |
| 242 | tok->char_offset, |
| 243 | expected_char_offset); |
| 244 | else |
| 245 | { |
| 246 | printf("OK: got object of type [%s]: %s\n", |
| 247 | json_type_to_name(json_object_get_type(new_obj)), |
| 248 | json_object_to_json_string(new_obj)); |
| 249 | this_step_ok = 1; |
| 250 | } |
| 251 | } |
| 252 | |
| 253 | if (new_obj) |
| 254 | json_object_put(new_obj); |
| 255 | |
| 256 | if (step->reset_tokener) |
| 257 | json_tokener_reset(tok); |
| 258 | |
| 259 | if (this_step_ok) |
| 260 | num_ok++; |
| 261 | else |
| 262 | num_error++; |
| 263 | } |
| 264 | |
| 265 | json_tokener_free(tok); |
| 266 | |
| 267 | printf("End Incremental Tests OK=%d ERROR=%d\n", num_ok, num_error); |
| 268 | |
| 269 | return; |
| 270 | } |