Blame tests/test_parse.c

Packit Service def718
#include <stdio.h>
Packit Service def718
#include <stdlib.h>
Packit Service def718
#include <stddef.h>
Packit Service def718
#include <string.h>
Packit Service def718
#include <assert.h>
Packit Service def718
Packit Service def718
#include "json.h"
Packit Service def718
#include "json_tokener.h"
Packit Service def718
#include "json_visit.h"
Packit Service def718
Packit Service def718
static void test_basic_parse(void);
Packit Service def718
static void test_verbose_parse(void);
Packit Service def718
static void test_incremental_parse(void);
Packit Service def718
Packit Service def718
int main(void)
Packit Service def718
{
Packit Service def718
	MC_SET_DEBUG(1);
Packit Service def718
Packit Service def718
	static const char separator[] = "==================================";
Packit Service def718
	test_basic_parse();
Packit Service def718
	puts(separator);
Packit Service def718
	test_verbose_parse();
Packit Service def718
	puts(separator);
Packit Service def718
	test_incremental_parse();
Packit Service def718
	puts(separator);
Packit Service def718
}
Packit Service def718
Packit Service def718
static json_c_visit_userfunc clear_serializer;
Packit Service def718
static void do_clear_serializer(json_object *jso);
Packit Service def718
Packit Service def718
static void single_basic_parse(const char *test_string, int clear_serializer)
Packit Service def718
{
Packit Service def718
	json_object *new_obj;
Packit Service def718
Packit Service def718
	new_obj = json_tokener_parse(test_string);
Packit Service def718
	if (clear_serializer)
Packit Service def718
		do_clear_serializer(new_obj);
Packit Service def718
	printf("new_obj.to_string(%s)=%s\n", test_string, json_object_to_json_string(new_obj));
Packit Service def718
	json_object_put(new_obj);
Packit Service def718
}
Packit Service def718
static void test_basic_parse()
Packit Service def718
{
Packit Service def718
	single_basic_parse("\"\003\"", 0);
Packit Service def718
	single_basic_parse("/* hello */\"foo\"", 0);
Packit Service def718
	single_basic_parse("// hello\n\"foo\"", 0);
Packit Service def718
	single_basic_parse("\"foo\"blue", 0);
Packit Service def718
	single_basic_parse("\"\\u0041\\u0042\\u0043\"", 0);
Packit Service def718
	// Test with a "short" high surrogate
Packit Service def718
	single_basic_parse("[9,'\\uDAD", 0);
Packit Service def718
	single_basic_parse("null", 0);
Packit Service def718
	single_basic_parse("NaN", 0);
Packit Service def718
	single_basic_parse("-NaN", 0); /* non-sensical, returns null */
Packit Service def718
Packit Service def718
	single_basic_parse("Inf", 0); /* must use full string, returns null */
Packit Service def718
	single_basic_parse("inf", 0); /* must use full string, returns null */
Packit Service def718
	single_basic_parse("Infinity", 0);
Packit Service def718
	single_basic_parse("infinity", 0);
Packit Service def718
	single_basic_parse("-Infinity", 0);
Packit Service def718
	single_basic_parse("-infinity", 0);
Packit Service def718
	single_basic_parse("{ \"min\": Infinity, \"max\": -Infinity}", 0);
Packit Service def718
Packit Service def718
	single_basic_parse("Infinity!", 0);
Packit Service def718
	single_basic_parse("Infinitynull", 0);
Packit Service def718
	single_basic_parse("InfinityXXXX", 0);
Packit Service def718
	single_basic_parse("-Infinitynull", 0);
Packit Service def718
	single_basic_parse("-InfinityXXXX", 0);
Packit Service def718
	single_basic_parse("Infinoodle", 0);
Packit Service def718
	single_basic_parse("InfinAAA", 0);
Packit Service def718
	single_basic_parse("-Infinoodle", 0);
Packit Service def718
	single_basic_parse("-InfinAAA", 0);
Packit Service def718
Packit Service def718
	single_basic_parse("True", 0);
Packit Service def718
	single_basic_parse("False", 0);
Packit Service def718
Packit Service def718
	single_basic_parse("12", 0);
Packit Service def718
	single_basic_parse("12.3", 0);
Packit Service def718
	single_basic_parse("12.3.4", 0); /* non-sensical, returns null */
Packit Service def718
	/* was returning (int)2015 before patch, should return null */
Packit Service def718
	single_basic_parse("2015-01-15", 0);
Packit Service def718
Packit Service def718
	/* ...but this works.  It's rather inconsistent, and a future major release
Packit Service def718
	 * should change the behavior so it either always returns null when extra
Packit Service def718
	 * bytes are present (preferred), or always return object created from as much
Packit Service def718
	 * as was able to be parsed.
Packit Service def718
	 */
Packit Service def718
	single_basic_parse("12.3xxx", 0);
Packit Service def718
Packit Service def718
	single_basic_parse("{\"FoO\"  :   -12.3E512}", 0);
Packit Service def718
	single_basic_parse("{\"FoO\"  :   -12.3E51.2}", 0); /* non-sensical, returns null */
Packit Service def718
	single_basic_parse("[\"\\n\"]", 0);
Packit Service def718
	single_basic_parse("[\"\\nabc\\n\"]", 0);
Packit Service def718
	single_basic_parse("[null]", 0);
Packit Service def718
	single_basic_parse("[]", 0);
Packit Service def718
	single_basic_parse("[false]", 0);
Packit Service def718
	single_basic_parse("[\"abc\",null,\"def\",12]", 0);
Packit Service def718
	single_basic_parse("{}", 0);
Packit Service def718
	single_basic_parse("{ \"foo\": \"bar\" }", 0);
Packit Service def718
	single_basic_parse("{ \"foo\": \"bar\", \"baz\": null, \"bool0\": true }", 0);
Packit Service def718
	single_basic_parse("{ \"foo\": [null, \"foo\"] }", 0);
Packit Service def718
	single_basic_parse("{ \"abc\": 12, \"foo\": \"bar\", \"bool0\": false, \"bool1\": true, \"arr\": [ 1, 2, 3, null, 5 ] }", 0);
Packit Service def718
	single_basic_parse("{ \"abc\": \"blue\nred\\ngreen\" }", 0);
Packit Service def718
Packit Service def718
	// Clear serializer for these tests so we see the actual parsed value.
Packit Service def718
	single_basic_parse("[0e]", 1);
Packit Service def718
	single_basic_parse("[0e+]", 1);
Packit Service def718
	single_basic_parse("[0e+-1]", 1);
Packit Service def718
	single_basic_parse("[18446744073709551616]", 1);
Packit Service def718
}
Packit Service def718
Packit Service def718
// Clear the re-serialization information that the tokener
Packit Service def718
// saves to ensure that the output reflects the actual
Packit Service def718
// values we parsed, rather than just the original input.
Packit Service def718
static void do_clear_serializer(json_object *jso)
Packit Service def718
{
Packit Service def718
	json_c_visit(jso, 0, clear_serializer, NULL);
Packit Service def718
}
Packit Service def718
Packit Service def718
static int clear_serializer(json_object *jso, int flags,
Packit Service def718
                     json_object *parent_jso,
Packit Service def718
                     const char *jso_key,
Packit Service def718
                     size_t *jso_index, void *userarg)
Packit Service def718
{
Packit Service def718
	if (jso)
Packit Service def718
		json_object_set_serializer(jso, NULL, NULL, NULL);
Packit Service def718
	return JSON_C_VISIT_RETURN_CONTINUE;
Packit Service def718
}
Packit Service def718
Packit Service def718
static void test_verbose_parse()
Packit Service def718
{
Packit Service def718
	json_object *new_obj;
Packit Service def718
	enum json_tokener_error error = json_tokener_success;
Packit Service def718
Packit Service def718
	new_obj = json_tokener_parse_verbose("{ foo }", &error);
Packit Service def718
	assert (error == json_tokener_error_parse_object_key_name);
Packit Service def718
	assert (new_obj == NULL);
Packit Service def718
Packit Service def718
	new_obj = json_tokener_parse("{ foo }");
Packit Service def718
	assert (new_obj == NULL);
Packit Service def718
Packit Service def718
	new_obj = json_tokener_parse("foo");
Packit Service def718
	assert (new_obj == NULL);
Packit Service def718
	new_obj = json_tokener_parse_verbose("foo", &error);
Packit Service def718
	assert (new_obj == NULL);
Packit Service def718
Packit Service def718
	/* b/c the string starts with 'f' parsing return a boolean error */
Packit Service def718
	assert (error == json_tokener_error_parse_boolean);
Packit Service def718
Packit Service def718
	puts("json_tokener_parse_versbose() OK");
Packit Service def718
}
Packit Service def718
Packit Service def718
struct incremental_step {
Packit Service def718
	const char *string_to_parse;
Packit Service def718
	int length;
Packit Service def718
	int char_offset;
Packit Service def718
	enum json_tokener_error expected_error;
Packit Service def718
	int reset_tokener;
Packit Service def718
} incremental_steps[] = {
Packit Service def718
Packit Service def718
	/* Check that full json messages can be parsed, both w/ and w/o a reset */
Packit Service def718
	{ "{ \"foo\": 123 }", -1, -1, json_tokener_success,  0 },
Packit Service def718
	{ "{ \"foo\": 456 }", -1, -1, json_tokener_success,  1 },
Packit Service def718
	{ "{ \"foo\": 789 }", -1, -1, json_tokener_success,  1 },
Packit Service def718
Packit Service def718
	/*  Check a basic incremental parse */
Packit Service def718
	{ "{ \"foo",          -1, -1, json_tokener_continue, 0 },
Packit Service def718
	{ "\": {\"bar",       -1, -1, json_tokener_continue, 0 },
Packit Service def718
	{ "\":13}}",          -1, -1, json_tokener_success,  1 },
Packit Service def718
Packit Service def718
	/* Check that json_tokener_reset actually resets */
Packit Service def718
	{ "{ \"foo",          -1, -1, json_tokener_continue, 1 },
Packit Service def718
	{ ": \"bar\"}",       -1, 0, json_tokener_error_parse_unexpected, 1 },
Packit Service def718
Packit Service def718
	/* Check incremental parsing with trailing characters */
Packit Service def718
	{ "{ \"foo",          -1, -1, json_tokener_continue, 0 },
Packit Service def718
	{ "\": {\"bar",       -1, -1, json_tokener_continue, 0 },
Packit Service def718
	{ "\":13}}XXXX",      10, 6, json_tokener_success,  0 },
Packit Service def718
	{ "XXXX",              4, 0, json_tokener_error_parse_unexpected, 1 },
Packit Service def718
Packit Service def718
	/* Check that trailing characters can change w/o a reset */
Packit Service def718
	{ "{\"x\": 123 }\"X\"", -1, 11, json_tokener_success, 0 },
Packit Service def718
	{ "\"Y\"",            -1, -1, json_tokener_success, 1 },
Packit Service def718
Packit Service def718
	/* To stop parsing a number we need to reach a non-digit, e.g. a \0 */
Packit Service def718
	{ "1",                 1, 1, json_tokener_continue, 0 },
Packit Service def718
	/* This should parse as the number 12, since it continues the "1" */
Packit Service def718
	{ "2",                 2, 1, json_tokener_success, 0 },
Packit Service def718
	{ "12{",               3, 2, json_tokener_success, 1 },
Packit Service def718
Packit Service def718
	/* Similar tests for other kinds of objects: */
Packit Service def718
	/* These could all return success immediately, since regardless of
Packit Service def718
	   what follows the false/true/null token we *will* return a json object,
Packit Service def718
       but it currently doesn't work that way.  hmm... */
Packit Service def718
	{ "false",             5, 5, json_tokener_continue, 1 },
Packit Service def718
	{ "false",             6, 5, json_tokener_success, 1 },
Packit Service def718
	{ "true",              4, 4, json_tokener_continue, 1 },
Packit Service def718
	{ "true",              5, 4, json_tokener_success, 1 },
Packit Service def718
	{ "null",              4, 4, json_tokener_continue, 1 },
Packit Service def718
	{ "null",              5, 4, json_tokener_success, 1 },
Packit Service def718
Packit Service def718
	{ "Infinity",          9, 8, json_tokener_success, 1 },
Packit Service def718
	{ "infinity",          9, 8, json_tokener_success, 1 },
Packit Service def718
	{ "-infinity",        10, 9, json_tokener_success, 1 },
Packit Service def718
	{ "infinity",          9, 0, json_tokener_error_parse_unexpected, 3 },
Packit Service def718
	{ "-infinity",        10, 1, json_tokener_error_parse_unexpected, 3 },
Packit Service def718
Packit Service def718
	{ "inf",               3, 3, json_tokener_continue, 0 },
Packit Service def718
	{ "inity",             6, 5, json_tokener_success, 1 },
Packit Service def718
	{ "-inf",              4, 4, json_tokener_continue, 0 },
Packit Service def718
	{ "inity",             6, 5, json_tokener_success, 1 },
Packit Service def718
Packit Service def718
	{ "i",                 1, 1, json_tokener_continue, 0 },
Packit Service def718
	{ "n",                 1, 1, json_tokener_continue, 0 },
Packit Service def718
	{ "f",                 1, 1, json_tokener_continue, 0 },
Packit Service def718
	{ "i",                 1, 1, json_tokener_continue, 0 },
Packit Service def718
	{ "n",                 1, 1, json_tokener_continue, 0 },
Packit Service def718
	{ "i",                 1, 1, json_tokener_continue, 0 },
Packit Service def718
	{ "t",                 1, 1, json_tokener_continue, 0 },
Packit Service def718
	{ "y",                 1, 1, json_tokener_continue, 0 },
Packit Service def718
	{ "",                  1, 0, json_tokener_success, 1 },
Packit Service def718
Packit Service def718
	{ "-",                 1, 1, json_tokener_continue, 0 },
Packit Service def718
	{ "inf",               3, 3, json_tokener_continue, 0 },
Packit Service def718
	{ "ini",               3, 3, json_tokener_continue, 0 },
Packit Service def718
	{ "ty",                3, 2, json_tokener_success, 1 },
Packit Service def718
Packit Service def718
	{ "-",                 1, 1, json_tokener_continue, 0 },
Packit Service def718
	{ "i",                 1, 1, json_tokener_continue, 0 },
Packit Service def718
	{ "nfini",             5, 5, json_tokener_continue, 0 },
Packit Service def718
	{ "ty",                3, 2, json_tokener_success, 1 },
Packit Service def718
Packit Service def718
	{ "-i",                2, 2, json_tokener_continue, 0 },
Packit Service def718
	{ "nfinity",           8, 7, json_tokener_success, 1 },
Packit Service def718
Packit Service def718
	{ "InfinityX",        10, 8, json_tokener_success, 0 },
Packit Service def718
	{ "X",                 1, 0, json_tokener_error_parse_unexpected, 1 },
Packit Service def718
Packit Service def718
	{ "Infinity1234",     13, 8, json_tokener_success, 0 },
Packit Service def718
	{ "1234",              5, 4, json_tokener_success, 1 },
Packit Service def718
Packit Service def718
	{ "Infinity9999",      8, 8, json_tokener_continue, 0 },
Packit Service def718
	/* returns the Infinity loaded up by the previous call: */
Packit Service def718
	{ "1234",              5, 0, json_tokener_success, 0 },
Packit Service def718
	{ "1234",              5, 4, json_tokener_success, 1 },
Packit Service def718
Packit Service def718
	/* offset=1 because "n" is the start of "null".  hmm... */
Packit Service def718
	{ "noodle",            7, 1, json_tokener_error_parse_null, 1 },
Packit Service def718
	/* offset=2 because "na" is the start of "nan".  hmm... */
Packit Service def718
	{ "naodle",            7, 2, json_tokener_error_parse_null, 1 },
Packit Service def718
	/* offset=2 because "tr" is the start of "true".  hmm... */
Packit Service def718
	{ "track",             6, 2, json_tokener_error_parse_boolean, 1 },
Packit Service def718
Packit Service def718
	/* Although they may initially look like they should fail,
Packit Service def718
	   the next few tests check that parsing multiple sequential
Packit Service def718
       json objects in the input works as expected */
Packit Service def718
	{ "null123",           9, 4, json_tokener_success, 0 },
Packit Service def718
	{ "null123" + 4,       4, 3, json_tokener_success, 1 },
Packit Service def718
	{ "nullx",             5, 4, json_tokener_success, 0 },
Packit Service def718
	{ "nullx" + 4,         2, 0, json_tokener_error_parse_unexpected, 1 },
Packit Service def718
	{ "{\"a\":1}{\"b\":2}",15, 7, json_tokener_success, 0 },
Packit Service def718
	{ "{\"a\":1}{\"b\":2}" + 7,
Packit Service def718
	                       8, 7, json_tokener_success, 1 },
Packit Service def718
Packit Service def718
	/* Some bad formatting. Check we get the correct error status */
Packit Service def718
	{ "2015-01-15",       10, 4, json_tokener_error_parse_number, 1 },
Packit Service def718
Packit Service def718
	/* Strings have a well defined end point, so we can stop at the quote */
Packit Service def718
	{ "\"blue\"",         -1, -1, json_tokener_success, 0 },
Packit Service def718
Packit Service def718
	/* Check each of the escape sequences defined by the spec */
Packit Service def718
	{ "\"\\\"\"",         -1, -1, json_tokener_success, 0 },
Packit Service def718
	{ "\"\\\\\"",         -1, -1, json_tokener_success, 0 },
Packit Service def718
	{ "\"\\b\"",         -1, -1, json_tokener_success, 0 },
Packit Service def718
	{ "\"\\f\"",         -1, -1, json_tokener_success, 0 },
Packit Service def718
	{ "\"\\n\"",         -1, -1, json_tokener_success, 0 },
Packit Service def718
	{ "\"\\r\"",         -1, -1, json_tokener_success, 0 },
Packit Service def718
	{ "\"\\t\"",         -1, -1, json_tokener_success, 0 },
Packit Service def718
	{ "\"\\/\"",         -1, -1, json_tokener_success, 0 },
Packit Service def718
	// Escaping a forward slash is optional
Packit Service def718
	{ "\"/\"",           -1, -1, json_tokener_success, 0 },
Packit Service def718
Packit Service def718
	{ "[1,2,3]",          -1, -1, json_tokener_success, 0 },
Packit Service def718
Packit Service def718
	/* This behaviour doesn't entirely follow the json spec, but until we have
Packit Service def718
	   a way to specify how strict to be we follow Postel's Law and be liberal
Packit Service def718
	   in what we accept (up to a point). */
Packit Service def718
	{ "[1,2,3,]",         -1, -1, json_tokener_success, 0 },
Packit Service def718
	{ "[1,2,,3,]",        -1, 5, json_tokener_error_parse_unexpected, 0 },
Packit Service def718
Packit Service def718
	{ "[1,2,3,]",         -1, 7, json_tokener_error_parse_unexpected, 3 },
Packit Service def718
	{ "{\"a\":1,}",         -1, 7, json_tokener_error_parse_unexpected, 3 },
Packit Service def718
Packit Service def718
	{ NULL, -1, -1, json_tokener_success, 0 },
Packit Service def718
};
Packit Service def718
Packit Service def718
static void test_incremental_parse()
Packit Service def718
{
Packit Service def718
	json_object *new_obj;
Packit Service def718
	enum json_tokener_error jerr;
Packit Service def718
	struct json_tokener *tok;
Packit Service def718
	const char *string_to_parse;
Packit Service def718
	int ii;
Packit Service def718
	int num_ok, num_error;
Packit Service def718
Packit Service def718
	num_ok = 0;
Packit Service def718
	num_error = 0;
Packit Service def718
Packit Service def718
	printf("Starting incremental tests.\n");
Packit Service def718
	printf("Note: quotes and backslashes seen in the output here are literal values passed\n");
Packit Service def718
	printf("     to the parse functions.  e.g. this is 4 characters: \"\\f\"\n");
Packit Service def718
Packit Service def718
	string_to_parse = "{ \"foo"; /* } */
Packit Service def718
	printf("json_tokener_parse(%s) ... ", string_to_parse);
Packit Service def718
	new_obj = json_tokener_parse(string_to_parse);
Packit Service def718
	if (new_obj == NULL) puts("got error as expected");
Packit Service def718
Packit Service def718
	/* test incremental parsing in various forms */
Packit Service def718
	tok = json_tokener_new();
Packit Service def718
	for (ii = 0; incremental_steps[ii].string_to_parse != NULL; ii++)
Packit Service def718
	{
Packit Service def718
		int this_step_ok = 0;
Packit Service def718
		struct incremental_step *step = &incremental_steps[ii];
Packit Service def718
		int length = step->length;
Packit Service def718
		int expected_char_offset = step->char_offset;
Packit Service def718
Packit Service def718
		if (step->reset_tokener & 2)
Packit Service def718
			json_tokener_set_flags(tok, JSON_TOKENER_STRICT);
Packit Service def718
		else
Packit Service def718
			json_tokener_set_flags(tok, 0);
Packit Service def718
Packit Service def718
		if (length == -1)
Packit Service def718
			length = strlen(step->string_to_parse);
Packit Service def718
		if (expected_char_offset == -1)
Packit Service def718
			expected_char_offset = length;
Packit Service def718
Packit Service def718
		printf("json_tokener_parse_ex(tok, %-12s, %3d) ... ",
Packit Service def718
			step->string_to_parse, length);
Packit Service def718
		new_obj = json_tokener_parse_ex(tok, step->string_to_parse, length);
Packit Service def718
Packit Service def718
		jerr = json_tokener_get_error(tok);
Packit Service def718
		if (step->expected_error != json_tokener_success)
Packit Service def718
		{
Packit Service def718
			if (new_obj != NULL)
Packit Service def718
				printf("ERROR: invalid object returned: %s\n",
Packit Service def718
				       json_object_to_json_string(new_obj));
Packit Service def718
			else if (jerr != step->expected_error)
Packit Service def718
				printf("ERROR: got wrong error: %s\n",
Packit Service def718
				       json_tokener_error_desc(jerr));
Packit Service def718
			else if (tok->char_offset != expected_char_offset)
Packit Service def718
				printf("ERROR: wrong char_offset %d != expected %d\n",
Packit Service def718
				       tok->char_offset,
Packit Service def718
				       expected_char_offset);
Packit Service def718
			else
Packit Service def718
			{
Packit Service def718
				printf("OK: got correct error: %s\n",
Packit Service def718
				       json_tokener_error_desc(jerr));
Packit Service def718
				this_step_ok = 1;
Packit Service def718
			}
Packit Service def718
		}
Packit Service def718
		else
Packit Service def718
		{
Packit Service def718
			if (new_obj == NULL &&
Packit Service def718
			    !(step->length >= 4 &&
Packit Service def718
			      strncmp(step->string_to_parse, "null", 4) == 0))
Packit Service def718
				printf("ERROR: expected valid object, instead: %s\n",
Packit Service def718
				       json_tokener_error_desc(jerr));
Packit Service def718
			else if (tok->char_offset != expected_char_offset)
Packit Service def718
				printf("ERROR: wrong char_offset %d != expected %d\n",
Packit Service def718
				       tok->char_offset,
Packit Service def718
				       expected_char_offset);
Packit Service def718
			else
Packit Service def718
			{
Packit Service def718
				printf("OK: got object of type [%s]: %s\n",
Packit Service def718
					json_type_to_name(json_object_get_type(new_obj)),
Packit Service def718
					json_object_to_json_string(new_obj));
Packit Service def718
				this_step_ok = 1;
Packit Service def718
			}
Packit Service def718
		}
Packit Service def718
Packit Service def718
		if (new_obj)
Packit Service def718
			json_object_put(new_obj);
Packit Service def718
Packit Service def718
		if (step->reset_tokener & 1)
Packit Service def718
			json_tokener_reset(tok);
Packit Service def718
Packit Service def718
		if (this_step_ok)
Packit Service def718
			num_ok++;
Packit Service def718
		else
Packit Service def718
			num_error++;
Packit Service def718
	}
Packit Service def718
Packit Service def718
	json_tokener_free(tok);
Packit Service def718
Packit Service def718
	printf("End Incremental Tests OK=%d ERROR=%d\n", num_ok, num_error);
Packit Service def718
}