From cf48ea81759083021500e847d6e9285d5e34a37d Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 15 Feb 2017 16:03:35 +0100 Subject: [PATCH 1/5] New Type: cJSON_Invalid This assigns the macro cJSON_Invalid to 0. --- cJSON.h | 1 + 1 file changed, 1 insertion(+) diff --git a/cJSON.h b/cJSON.h index 8502048..6f371f9 100644 --- a/cJSON.h +++ b/cJSON.h @@ -39,6 +39,7 @@ extern const char* cJSON_Version(void); #include /* cJSON Types: */ +#define cJSON_Invalid (0) #define cJSON_False (1 << 0) #define cJSON_True (1 << 1) #define cJSON_NULL (1 << 2) From 3facca479249986256804a29c64d15dd19c38cee Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 15 Feb 2017 16:15:15 +0100 Subject: [PATCH 2/5] parse functions: Only set type after successful This sets the type of an item only if parsing was successful. This means that in case of failure, the item's type will remain to be cJSON_Invalid. --- cJSON.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/cJSON.c b/cJSON.c index 7d2c690..0f861c5 100644 --- a/cJSON.c +++ b/cJSON.c @@ -468,7 +468,6 @@ static const unsigned char *parse_string(cJSON *item, const unsigned char *str, { goto fail; } - item->type = cJSON_String; ptr = str + 1; ptr2 = out; @@ -607,6 +606,7 @@ static const unsigned char *parse_string(cJSON *item, const unsigned char *str, ptr++; } + item->type = cJSON_String; item->valuestring = (char*)out; return ptr; @@ -1054,12 +1054,11 @@ static const unsigned char *parse_array(cJSON *item, const unsigned char *value, goto fail; } - item->type = cJSON_Array; value = skip(value + 1); if (*value == ']') { /* empty array. */ - return value + 1; + goto success; } item->child = child = cJSON_New_Item(); @@ -1101,11 +1100,17 @@ static const unsigned char *parse_array(cJSON *item, const unsigned char *value, if (*value == ']') { /* end of array */ - return value + 1; + goto success; } /* malformed. */ *ep = value; + goto fail; + +success: + item->type = cJSON_Array; + + return value + 1; fail: if (item->child != NULL) @@ -1297,12 +1302,11 @@ static const unsigned char *parse_object(cJSON *item, const unsigned char *value goto fail; } - item->type = cJSON_Object; value = skip(value + 1); if (*value == '}') { /* empty object. */ - return value + 1; + goto success; } child = cJSON_New_Item(); @@ -1373,11 +1377,17 @@ static const unsigned char *parse_object(cJSON *item, const unsigned char *value /* end of object */ if (*value == '}') { - return value + 1; + goto success; } /* malformed */ *ep = value; + goto fail; + +success: + item->type = cJSON_Object; + + return value + 1; fail: if (item->child != NULL) From 4f58695ed32065f34a509fcda6c7b481059b754a Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 15 Feb 2017 18:41:55 +0100 Subject: [PATCH 3/5] tests: extract common functionality to common.c --- tests/CMakeLists.txt | 4 +- tests/common.c | 97 ++++++++++++++++++++++++++++++++++++++++++ tests/common.h | 31 ++++++++++++++ tests/parse_array.c | 23 +++------- tests/parse_examples.c | 58 +------------------------ tests/parse_hex4.c | 2 +- tests/parse_number.c | 2 +- tests/parse_object.c | 23 +++------- tests/parse_string.c | 2 +- tests/parse_value.c | 31 ++++---------- 10 files changed, 158 insertions(+), 115 deletions(-) create mode 100644 tests/common.c create mode 100644 tests/common.h diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index b7107c5..c372127 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -16,6 +16,8 @@ if(ENABLE_CJSON_TEST) parse_value ) + add_library(test-common common.c) + option(ENABLE_VALGRIND OFF "Enable the valgrind memory checker for the tests.") if (ENABLE_VALGRIND) find_program(MEMORYCHECK_COMMAND valgrind) @@ -29,7 +31,7 @@ if(ENABLE_CJSON_TEST) foreach(unity_test ${unity_tests}) add_executable("${unity_test}" "${unity_test}.c") - target_link_libraries("${unity_test}" "${CJSON_LIB}" unity) + target_link_libraries("${unity_test}" "${CJSON_LIB}" unity test-common) if(MEMORYCHECK_COMMAND) add_test(NAME "${unity_test}" COMMAND "${MEMORYCHECK_COMMAND}" ${MEMORYCHECK_COMMAND_OPTIONS} "./${unity_test}") diff --git a/tests/common.c b/tests/common.c new file mode 100644 index 0000000..65ef97c --- /dev/null +++ b/tests/common.c @@ -0,0 +1,97 @@ +/* + Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include "common.h" + +extern void reset(cJSON *item) +{ + if ((item != NULL) && (item->child != NULL)) + { + cJSON_Delete(item->child); + } + if ((item->valuestring != NULL) && !(item->type & cJSON_IsReference)) + { + cJSON_free(item->valuestring); + } + if ((item->string != NULL) && !(item->type & cJSON_StringIsConst)) + { + cJSON_free(item->string); + } + + memset(item, 0, sizeof(cJSON)); +} + +extern char *read_file(const char *filename) +{ + FILE *file = NULL; + long length = 0; + char *content = NULL; + size_t read_chars = 0; + + /* open in read binary mode */ + file = fopen(filename, "rb"); + if (file == NULL) + { + goto cleanup; + } + + /* get the length */ + if (fseek(file, 0, SEEK_END) != 0) + { + goto cleanup; + } + length = ftell(file); + if (length < 0) + { + goto cleanup; + } + if (fseek(file, 0, SEEK_SET) != 0) + { + goto cleanup; + } + + /* allocate content buffer */ + content = (char*)malloc((size_t)length + sizeof('\0')); + if (content == NULL) + { + goto cleanup; + } + + /* read the file into memory */ + read_chars = fread(content, sizeof(char), (size_t)length, file); + if ((long)read_chars != length) + { + free(content); + content = NULL; + goto cleanup; + } + content[read_chars] = '\0'; + + +cleanup: + if (file != NULL) + { + fclose(file); + } + + return content; +} diff --git a/tests/common.h b/tests/common.h new file mode 100644 index 0000000..ea87a57 --- /dev/null +++ b/tests/common.h @@ -0,0 +1,31 @@ +/* + Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#ifndef CJSON_TESTS_COMMON_H +#define CJSON_TESTS_COMMON_H + +#include "../cJSON.c" + +extern void reset(cJSON *item); +extern char *read_file(const char *filename); + +#endif diff --git a/tests/parse_array.c b/tests/parse_array.c index 306964c..e8638f5 100644 --- a/tests/parse_array.c +++ b/tests/parse_array.c @@ -26,7 +26,7 @@ #include "unity/examples/unity_config.h" #include "unity/src/unity.h" -#include "../cJSON.c" +#include "common.h" static cJSON item[1]; @@ -56,15 +56,6 @@ static void assert_parse_array(const char *json) assert_is_array(item); } -static void reset(void) -{ - if (item->child != NULL) - { - cJSON_Delete(item->child); - } - memset(item, 0, sizeof(cJSON)); -} - static void parse_array_should_parse_empty_arrays(void) { assert_parse_array("[]"); @@ -80,24 +71,24 @@ static void parse_array_should_parse_arrays_with_one_element(void) assert_parse_array("[1]"); TEST_ASSERT_NOT_NULL(item->child); TEST_ASSERT_BITS(0xFF, cJSON_Number, item->child->type); - reset(); + reset(item); assert_parse_array("[\"hello!\"]"); TEST_ASSERT_NOT_NULL(item->child); TEST_ASSERT_BITS(0xFF, cJSON_String, item->child->type); TEST_ASSERT_EQUAL_STRING("hello!", item->child->valuestring); - reset(); + reset(item); assert_parse_array("[[]]"); TEST_ASSERT_NOT_NULL(item->child); assert_is_array(item->child); TEST_ASSERT_NULL(item->child->child); - reset(); + reset(item); assert_parse_array("[null]"); TEST_ASSERT_NOT_NULL(item->child); TEST_ASSERT_BITS(0xFF, cJSON_NULL, item->child->type); - reset(); + reset(item); } static void parse_array_should_parse_arrays_with_multiple_elements(void) @@ -110,7 +101,7 @@ static void parse_array_should_parse_arrays_with_multiple_elements(void) TEST_ASSERT_BITS(0xFF, cJSON_Number, item->child->type); TEST_ASSERT_BITS(0xFF, cJSON_Number, item->child->next->type); TEST_ASSERT_BITS(0xFF, cJSON_Number, item->child->next->next->type); - reset(); + reset(item); { size_t i = 0; @@ -137,7 +128,7 @@ static void parse_array_should_parse_arrays_with_multiple_elements(void) TEST_ASSERT_BITS(0xFF, expected_types[i], node->type); } TEST_ASSERT_EQUAL_INT(i, 7); - reset(); + reset(item); } } diff --git a/tests/parse_examples.c b/tests/parse_examples.c index 8232e8a..7562c45 100644 --- a/tests/parse_examples.c +++ b/tests/parse_examples.c @@ -26,63 +26,7 @@ #include "unity/examples/unity_config.h" #include "unity/src/unity.h" -#include "../cJSON.h" - -static char *read_file(const char *filename) -{ - FILE *file = NULL; - long length = 0; - char *content = NULL; - size_t read_chars = 0; - - /* open in read binary mode */ - file = fopen(filename, "rb"); - if (file == NULL) - { - goto cleanup; - } - - /* get the length */ - if (fseek(file, 0, SEEK_END) != 0) - { - goto cleanup; - } - length = ftell(file); - if (length < 0) - { - goto cleanup; - } - if (fseek(file, 0, SEEK_SET) != 0) - { - goto cleanup; - } - - /* allocate content buffer */ - content = (char*)malloc((size_t)length + sizeof('\0')); - if (content == NULL) - { - goto cleanup; - } - - /* read the file into memory */ - read_chars = fread(content, sizeof(char), (size_t)length, file); - if ((long)read_chars != length) - { - free(content); - content = NULL; - goto cleanup; - } - content[read_chars] = '\0'; - - -cleanup: - if (file != NULL) - { - fclose(file); - } - - return content; -} +#include "common.h" static cJSON *parse_file(const char *filename) { diff --git a/tests/parse_hex4.c b/tests/parse_hex4.c index 286157f..59b07ee 100644 --- a/tests/parse_hex4.c +++ b/tests/parse_hex4.c @@ -26,7 +26,7 @@ #include "unity/examples/unity_config.h" #include "unity/src/unity.h" -#include "../cJSON.c" +#include "common.h" static void parse_hex4_should_parse_all_combinations(void) { diff --git a/tests/parse_number.c b/tests/parse_number.c index bfd0914..4419d40 100644 --- a/tests/parse_number.c +++ b/tests/parse_number.c @@ -26,7 +26,7 @@ #include "unity/examples/unity_config.h" #include "unity/src/unity.h" -#include "../cJSON.c" +#include "common.h" static cJSON item[1]; diff --git a/tests/parse_object.c b/tests/parse_object.c index 3031851..93b543c 100644 --- a/tests/parse_object.c +++ b/tests/parse_object.c @@ -26,7 +26,7 @@ #include "unity/examples/unity_config.h" #include "unity/src/unity.h" -#include "../cJSON.c" +#include "common.h" static cJSON item[1]; @@ -64,15 +64,6 @@ static void assert_parse_object(const char *json) assert_is_object(item); } -static void reset(void) -{ - if (item->child != NULL) - { - cJSON_Delete(item->child); - } - memset(item, 0, sizeof(cJSON)); -} - static void parse_object_should_parse_empty_objects(void) { assert_parse_object("{}"); @@ -86,19 +77,19 @@ static void parse_array_should_parse_arrays_with_one_element(void) assert_parse_object("{\"one\":1}"); assert_is_child(item->child, "one", cJSON_Number); - reset(); + reset(item); assert_parse_object("{\"hello\":\"world!\"}"); assert_is_child(item->child, "hello", cJSON_String); - reset(); + reset(item); assert_parse_object("{\"array\":[]}"); assert_is_child(item->child, "array", cJSON_Array); - reset(); + reset(item); assert_parse_object("{\"null\":null}"); assert_is_child(item->child, "null", cJSON_NULL); - reset(); + reset(item); } static void parse_object_should_parse_objects_with_multiple_elements(void) @@ -107,7 +98,7 @@ static void parse_object_should_parse_objects_with_multiple_elements(void) assert_is_child(item->child, "one", cJSON_Number); assert_is_child(item->child->next, "two", cJSON_Number); assert_is_child(item->child->next->next, "three", cJSON_Number); - reset(); + reset(item); { size_t i = 0; @@ -144,7 +135,7 @@ static void parse_object_should_parse_objects_with_multiple_elements(void) assert_is_child(node, expected_names[i], expected_types[i]); } TEST_ASSERT_EQUAL_INT(i, 7); - reset(); + reset(item); } } diff --git a/tests/parse_string.c b/tests/parse_string.c index b121eff..8fd6920 100644 --- a/tests/parse_string.c +++ b/tests/parse_string.c @@ -26,7 +26,7 @@ #include "unity/examples/unity_config.h" #include "unity/src/unity.h" -#include "../cJSON.c" +#include "common.h" static cJSON item[1]; diff --git a/tests/parse_value.c b/tests/parse_value.c index f0c8b66..7528df7 100644 --- a/tests/parse_value.c +++ b/tests/parse_value.c @@ -26,7 +26,7 @@ #include "unity/examples/unity_config.h" #include "unity/src/unity.h" -#include "../cJSON.c" +#include "common.h" static cJSON item[1]; const unsigned char *error_pointer = NULL; @@ -49,61 +49,48 @@ static void assert_parse_value(const char *string, int type) assert_is_value(item, type); } -static void reset(void) -{ - if (item->child != NULL) - { - cJSON_Delete(item->child); - } - if (item->valuestring != NULL) - { - cJSON_free(item->valuestring); - } - memset(item, 0, sizeof(cJSON)); -} - static void parse_value_should_parse_null(void) { assert_parse_value("null", cJSON_NULL); - reset(); + reset(item); } static void parse_value_should_parse_true(void) { assert_parse_value("true", cJSON_True); - reset(); + reset(item); } static void parse_value_should_parse_false(void) { assert_parse_value("false", cJSON_False); - reset(); + reset(item); } static void parse_value_should_parse_number(void) { assert_parse_value("1.5", cJSON_Number); - reset(); + reset(item); } static void parse_value_should_parse_string(void) { assert_parse_value("\"\"", cJSON_String); - reset(); + reset(item); assert_parse_value("\"hello\"", cJSON_String); - reset(); + reset(item); } static void parse_value_should_parse_array(void) { assert_parse_value("[]", cJSON_Array); - reset(); + reset(item); } static void parse_value_should_parse_object(void) { assert_parse_value("{}", cJSON_Object); - reset(); + reset(item); } int main(void) From c6e1a281f9047cc0dfe88abf582a6f12c42c4b2c Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 15 Feb 2017 19:57:54 +0100 Subject: [PATCH 4/5] tests: assertion macros --- tests/common.h | 14 ++++++++++++++ tests/parse_array.c | 46 ++++++++++++++++++++++---------------------- tests/parse_number.c | 15 +++++++-------- tests/parse_object.c | 13 ++++++------- tests/parse_string.c | 27 +++++++++++++------------- tests/parse_value.c | 11 +++++------ 6 files changed, 69 insertions(+), 57 deletions(-) diff --git a/tests/common.h b/tests/common.h index ea87a57..bbe2db9 100644 --- a/tests/common.h +++ b/tests/common.h @@ -28,4 +28,18 @@ extern void reset(cJSON *item); extern char *read_file(const char *filename); +/* assertion helper macros */ +#define assert_has_type(item, item_type) TEST_ASSERT_BITS_MESSAGE(0xFF, item_type, item->type, "Item doesn't have expected type.") +#define assert_has_no_reference(item) TEST_ASSERT_BITS_MESSAGE(cJSON_IsReference, 0, item->type, "Item should not have a string as reference.") +#define assert_has_no_const_string(item) TEST_ASSERT_BITS_MESSAGE(cJSON_StringIsConst, 0, item->type, "Item should not have a const string.") +#define assert_has_valuestring(item) TEST_ASSERT_NOT_NULL_MESSAGE(item->valuestring, "Valuestring is NULL.") +#define assert_has_no_valuestring(item) TEST_ASSERT_NULL_MESSAGE(item->valuestring, "Valuestring is not NULL.") +#define assert_has_string(item) TEST_ASSERT_NOT_NULL_MESSAGE(item->string, "String is NULL") +#define assert_has_no_string(item) TEST_ASSERT_NULL_MESSAGE(item->string, "String is not NULL.") +#define assert_not_in_list(item) \ + TEST_ASSERT_NULL_MESSAGE(item->next, "Linked list next pointer is not NULL.");\ + TEST_ASSERT_NULL_MESSAGE(item->prev, "Linked list previous pointer is not NULL.") +#define assert_has_child(item) TEST_ASSERT_NOT_NULL_MESSAGE(item->child, "Item doesn't have a child.") +#define assert_has_no_child(item) TEST_ASSERT_NULL_MESSAGE(item->child, "Item has a child.") + #endif diff --git a/tests/parse_array.c b/tests/parse_array.c index e8638f5..405f530 100644 --- a/tests/parse_array.c +++ b/tests/parse_array.c @@ -32,17 +32,16 @@ static cJSON item[1]; static const unsigned char *error_pointer = NULL; -static void assert_is_array(cJSON *string_item) +static void assert_is_array(cJSON *array_item) { - TEST_ASSERT_NOT_NULL_MESSAGE(string_item, "Item is NULL."); + TEST_ASSERT_NOT_NULL_MESSAGE(array_item, "Item is NULL."); - TEST_ASSERT_NULL_MESSAGE(string_item->next, "Linked list next pointer is not NULL."); - TEST_ASSERT_NULL_MESSAGE(string_item->prev, "Linked list previous pointer is not NULL"); - TEST_ASSERT_BITS_MESSAGE(0xFF, cJSON_Array, string_item->type, "Item type is not array."); - TEST_ASSERT_BITS_MESSAGE(cJSON_IsReference, 0, string_item->type, "Item should not have a string as reference."); - TEST_ASSERT_BITS_MESSAGE(cJSON_StringIsConst, 0, string_item->type, "Item should not have a const string."); - TEST_ASSERT_NULL_MESSAGE(string_item->valuestring, "Valuestring is not NULL."); - TEST_ASSERT_NULL_MESSAGE(string_item->string, "String is not NULL."); + assert_not_in_list(array_item); + assert_has_type(array_item, cJSON_Array); + assert_has_no_reference(array_item); + assert_has_no_const_string(array_item); + assert_has_no_valuestring(array_item); + assert_has_no_string(array_item); } static void assert_not_array(const char *json) @@ -59,9 +58,10 @@ static void assert_parse_array(const char *json) static void parse_array_should_parse_empty_arrays(void) { assert_parse_array("[]"); - TEST_ASSERT_NULL(item->child); + assert_has_no_child(item); + assert_parse_array("[\n\t]"); - TEST_ASSERT_NULL(item->child); + assert_has_no_child(item); } @@ -69,38 +69,38 @@ static void parse_array_should_parse_arrays_with_one_element(void) { assert_parse_array("[1]"); - TEST_ASSERT_NOT_NULL(item->child); - TEST_ASSERT_BITS(0xFF, cJSON_Number, item->child->type); + assert_has_child(item); + assert_has_type(item->child, cJSON_Number); reset(item); assert_parse_array("[\"hello!\"]"); - TEST_ASSERT_NOT_NULL(item->child); - TEST_ASSERT_BITS(0xFF, cJSON_String, item->child->type); + assert_has_child(item); + assert_has_type(item->child, cJSON_String); TEST_ASSERT_EQUAL_STRING("hello!", item->child->valuestring); reset(item); assert_parse_array("[[]]"); - TEST_ASSERT_NOT_NULL(item->child); + assert_has_child(item); assert_is_array(item->child); - TEST_ASSERT_NULL(item->child->child); + assert_has_no_child(item->child); reset(item); assert_parse_array("[null]"); - TEST_ASSERT_NOT_NULL(item->child); - TEST_ASSERT_BITS(0xFF, cJSON_NULL, item->child->type); + assert_has_child(item); + assert_has_type(item->child, cJSON_NULL); reset(item); } static void parse_array_should_parse_arrays_with_multiple_elements(void) { assert_parse_array("[1\t,\n2, 3]"); - TEST_ASSERT_NOT_NULL(item->child); + assert_has_child(item); TEST_ASSERT_NOT_NULL(item->child->next); TEST_ASSERT_NOT_NULL(item->child->next->next); TEST_ASSERT_NULL(item->child->next->next->next); - TEST_ASSERT_BITS(0xFF, cJSON_Number, item->child->type); - TEST_ASSERT_BITS(0xFF, cJSON_Number, item->child->next->type); - TEST_ASSERT_BITS(0xFF, cJSON_Number, item->child->next->next->type); + assert_has_type(item->child, cJSON_Number); + assert_has_type(item->child->next, cJSON_Number); + assert_has_type(item->child->next->next, cJSON_Number); reset(item); { diff --git a/tests/parse_number.c b/tests/parse_number.c index 4419d40..73f5538 100644 --- a/tests/parse_number.c +++ b/tests/parse_number.c @@ -34,14 +34,13 @@ static void assert_is_number(cJSON *number_item) { TEST_ASSERT_NOT_NULL_MESSAGE(number_item, "Item is NULL."); - TEST_ASSERT_NULL_MESSAGE(number_item->next, "Linked list next pointer is not NULL."); - TEST_ASSERT_NULL_MESSAGE(number_item->prev, "Linked list previous pointer is not NULL"); - TEST_ASSERT_NULL_MESSAGE(number_item->child, "Child pointer is not NULL."); - TEST_ASSERT_BITS_MESSAGE(0xFF, cJSON_Number, number_item->type, "Message type is not number."); - TEST_ASSERT_BITS_MESSAGE(cJSON_IsReference, 0, number_item->type, "Item should not have a string as reference."); - TEST_ASSERT_BITS_MESSAGE(cJSON_StringIsConst, 0, number_item->type, "Item should not have a const string."); - TEST_ASSERT_NULL_MESSAGE(number_item->valuestring, "Valuestring is not NULL."); - TEST_ASSERT_NULL_MESSAGE(number_item->string, "String is not NULL."); + assert_not_in_list(number_item); + assert_has_no_child(number_item); + assert_has_type(number_item, cJSON_Number); + assert_has_no_reference(number_item); + assert_has_no_const_string(number_item); + assert_has_no_valuestring(number_item); + assert_has_no_string(number_item); } static void assert_parse_number(const char *string, int integer, double real) diff --git a/tests/parse_object.c b/tests/parse_object.c index 93b543c..e79cd65 100644 --- a/tests/parse_object.c +++ b/tests/parse_object.c @@ -36,13 +36,12 @@ static void assert_is_object(cJSON *object_item) { TEST_ASSERT_NOT_NULL_MESSAGE(object_item, "Item is NULL."); - TEST_ASSERT_NULL_MESSAGE(object_item->next, "Linked list next pointer is not NULL."); - TEST_ASSERT_NULL_MESSAGE(object_item->prev, "Linked list previous pointer is not NULL"); - TEST_ASSERT_BITS_MESSAGE(0xFF, cJSON_Object, object_item->type, "Item type is not object."); - TEST_ASSERT_BITS_MESSAGE(cJSON_IsReference, 0, object_item->type, "Item should not have a string as reference."); - TEST_ASSERT_BITS_MESSAGE(cJSON_StringIsConst, 0, object_item->type, "Item should not have a const string."); - TEST_ASSERT_NULL_MESSAGE(object_item->valuestring, "Valuestring is not NULL."); - TEST_ASSERT_NULL_MESSAGE(object_item->string, "String is not NULL."); + assert_not_in_list(object_item); + assert_has_type(object_item, cJSON_Object); + assert_has_no_reference(object_item); + assert_has_no_const_string(object_item); + assert_has_no_valuestring(object_item); + assert_has_no_string(object_item); } static void assert_is_child(cJSON *child_item, const char *name, int type) diff --git a/tests/parse_string.c b/tests/parse_string.c index 8fd6920..db1fbb9 100644 --- a/tests/parse_string.c +++ b/tests/parse_string.c @@ -36,14 +36,13 @@ static void assert_is_string(cJSON *string_item) { TEST_ASSERT_NOT_NULL_MESSAGE(string_item, "Item is NULL."); - TEST_ASSERT_NULL_MESSAGE(string_item->next, "Linked list next pointer is not NULL."); - TEST_ASSERT_NULL_MESSAGE(string_item->prev, "Linked list previous pointer is not NULL"); - TEST_ASSERT_NULL_MESSAGE(string_item->child, "Child pointer is not NULL."); - TEST_ASSERT_BITS_MESSAGE(0xFF, cJSON_String, string_item->type, "Item type is not string."); - TEST_ASSERT_BITS_MESSAGE(cJSON_IsReference, 1, string_item->type, "Item should have a string as reference."); - TEST_ASSERT_BITS_MESSAGE(cJSON_StringIsConst, 0, string_item->type, "Item should not have a const string."); - TEST_ASSERT_NOT_NULL_MESSAGE(string_item->valuestring, "Valuestring is NULL."); - TEST_ASSERT_NULL_MESSAGE(string_item->string, "String is not NULL."); + assert_not_in_list(string_item); + assert_has_no_child(string_item); + assert_has_type(string_item, cJSON_String); + assert_has_no_reference(string_item); + assert_has_no_const_string(string_item); + assert_has_valuestring(string_item); + assert_has_no_string(string_item); } static void assert_parse_string(const char *string, const char *expected) @@ -55,6 +54,8 @@ static void assert_parse_string(const char *string, const char *expected) item->valuestring = NULL; } +#define assert_not_parse_string(string) TEST_ASSERT_NULL_MESSAGE(parse_string(item, (const unsigned char*)string, &error_pointer), "Malformed string should not be accepted") + static void parse_string_should_parse_strings(void) { assert_parse_string("\"\"", ""); @@ -74,19 +75,19 @@ static void parse_string_should_parse_utf16_surrogate_pairs(void) static void parse_string_should_not_parse_non_strings(void) { - TEST_ASSERT_NULL(parse_string(item, (const unsigned char*)"this\" is not a string\"", &error_pointer)); - TEST_ASSERT_NULL(parse_string(item, (const unsigned char*) "", &error_pointer)); + assert_not_parse_string("this\" is not a string\""); + assert_not_parse_string(""); } static void parse_string_should_not_parse_invalid_backslash(void) { - TEST_ASSERT_NULL_MESSAGE(parse_string(item, (const unsigned char*)"Abcdef\\123", &error_pointer), "Invalid backshlash should not be accepted."); - TEST_ASSERT_NULL_MESSAGE(parse_string(item, (const unsigned char*)"Abcdef\\e23", &error_pointer), "Invalid backshlash should not be accepted."); + assert_not_parse_string("Abcdef\\123"); + assert_not_parse_string("Abcdef\\e23"); } static void parse_string_should_not_overflow_with_closing_backslash(void) { - TEST_ASSERT_NULL_MESSAGE(parse_string(item, (const unsigned char*)"\"000000000000000000\\", &error_pointer), "Malformed string should not be accepted."); + assert_not_parse_string("\"000000000000000000\\"); } static void parse_string_should_parse_bug_94(void) diff --git a/tests/parse_value.c b/tests/parse_value.c index 7528df7..bbd52c5 100644 --- a/tests/parse_value.c +++ b/tests/parse_value.c @@ -35,12 +35,11 @@ static void assert_is_value(cJSON *value_item, int type) { TEST_ASSERT_NOT_NULL_MESSAGE(value_item, "Item is NULL."); - TEST_ASSERT_NULL_MESSAGE(value_item->next, "Linked list next pointer is not NULL."); - TEST_ASSERT_NULL_MESSAGE(value_item->prev, "Linked list previous pointer is not NULL"); - TEST_ASSERT_BITS_MESSAGE(0xFF, type, value_item->type, "Message type is not number."); - TEST_ASSERT_BITS_MESSAGE(cJSON_IsReference, 0, value_item->type, "Item should not have a string as reference."); - TEST_ASSERT_BITS_MESSAGE(cJSON_StringIsConst, 0, value_item->type, "Item should not have a const string."); - TEST_ASSERT_NULL_MESSAGE(value_item->string, "String is not NULL."); + assert_not_in_list(value_item); + assert_has_type(value_item, type); + assert_has_no_reference(value_item); + assert_has_no_const_string(value_item); + assert_has_no_string(value_item); } static void assert_parse_value(const char *string, int type) From 5986edba1de5b59d03d0a6d45bce5cb8182a0014 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 15 Feb 2017 21:12:10 +0100 Subject: [PATCH 5/5] tests: Ensure that failed parsing returns invalid items --- tests/common.h | 7 +++++++ tests/parse_array.c | 1 + tests/parse_object.c | 9 +++++++-- tests/parse_string.c | 15 ++++++++++++++- 4 files changed, 29 insertions(+), 3 deletions(-) diff --git a/tests/common.h b/tests/common.h index bbe2db9..d5c8def 100644 --- a/tests/common.h +++ b/tests/common.h @@ -27,6 +27,7 @@ extern void reset(cJSON *item); extern char *read_file(const char *filename); +extern cjbool assert_is_invalid(cJSON *item); /* assertion helper macros */ #define assert_has_type(item, item_type) TEST_ASSERT_BITS_MESSAGE(0xFF, item_type, item->type, "Item doesn't have expected type.") @@ -41,5 +42,11 @@ extern char *read_file(const char *filename); TEST_ASSERT_NULL_MESSAGE(item->prev, "Linked list previous pointer is not NULL.") #define assert_has_child(item) TEST_ASSERT_NOT_NULL_MESSAGE(item->child, "Item doesn't have a child.") #define assert_has_no_child(item) TEST_ASSERT_NULL_MESSAGE(item->child, "Item has a child.") +#define assert_is_invalid(item) \ + assert_has_type(item, cJSON_Invalid);\ + assert_not_in_list(item);\ + assert_has_no_child(item);\ + assert_has_no_string(item);\ + assert_has_no_valuestring(item) #endif diff --git a/tests/parse_array.c b/tests/parse_array.c index 405f530..5364739 100644 --- a/tests/parse_array.c +++ b/tests/parse_array.c @@ -47,6 +47,7 @@ static void assert_is_array(cJSON *array_item) static void assert_not_array(const char *json) { TEST_ASSERT_NULL(parse_array(item, (const unsigned char*)json, &error_pointer)); + assert_is_invalid(item); } static void assert_parse_array(const char *json) diff --git a/tests/parse_object.c b/tests/parse_object.c index e79cd65..e8ede1d 100644 --- a/tests/parse_object.c +++ b/tests/parse_object.c @@ -55,6 +55,8 @@ static void assert_is_child(cJSON *child_item, const char *name, int type) static void assert_not_object(const char *json) { TEST_ASSERT_NULL(parse_object(item, (const unsigned char*)json, &error_pointer)); + assert_is_invalid(item); + reset(item); } static void assert_parse_object(const char *json) @@ -66,9 +68,12 @@ static void assert_parse_object(const char *json) static void parse_object_should_parse_empty_objects(void) { assert_parse_object("{}"); - TEST_ASSERT_NULL(item->child); + assert_has_no_child(item); + reset(item); + assert_parse_object("{\n\t}"); - TEST_ASSERT_NULL(item->child); + assert_has_no_child(item); + reset(item); } static void parse_array_should_parse_arrays_with_one_element(void) diff --git a/tests/parse_string.c b/tests/parse_string.c index db1fbb9..67d78c4 100644 --- a/tests/parse_string.c +++ b/tests/parse_string.c @@ -54,7 +54,11 @@ static void assert_parse_string(const char *string, const char *expected) item->valuestring = NULL; } -#define assert_not_parse_string(string) TEST_ASSERT_NULL_MESSAGE(parse_string(item, (const unsigned char*)string, &error_pointer), "Malformed string should not be accepted") +#define assert_not_parse_string(string) \ + TEST_ASSERT_NULL_MESSAGE(parse_string(item, (const unsigned char*)string, &error_pointer), "Malformed string should not be accepted");\ + assert_is_invalid(item) + + static void parse_string_should_parse_strings(void) { @@ -65,35 +69,44 @@ static void parse_string_should_parse_strings(void) assert_parse_string( "\"\\\"\\\\\\/\\b\\f\\n\\r\\t\\u20AC\\u732b\"", "\"\\/\b\f\n\r\t€猫"); + reset(item); assert_parse_string("\"\b\f\n\r\t\"", "\b\f\n\r\t"); + reset(item); } static void parse_string_should_parse_utf16_surrogate_pairs(void) { assert_parse_string("\"\\uD83D\\udc31\"", "🐱"); + reset(item); } static void parse_string_should_not_parse_non_strings(void) { assert_not_parse_string("this\" is not a string\""); + reset(item); assert_not_parse_string(""); + reset(item); } static void parse_string_should_not_parse_invalid_backslash(void) { assert_not_parse_string("Abcdef\\123"); + reset(item); assert_not_parse_string("Abcdef\\e23"); + reset(item); } static void parse_string_should_not_overflow_with_closing_backslash(void) { assert_not_parse_string("\"000000000000000000\\"); + reset(item); } static void parse_string_should_parse_bug_94(void) { const char string[] = "\"~!@\\\\#$%^&*()\\\\\\\\-\\\\+{}[]:\\\\;\\\\\\\"\\\\<\\\\>?/.,DC=ad,DC=com\""; assert_parse_string(string, "~!@\\#$%^&*()\\\\-\\+{}[]:\\;\\\"\\<\\>?/.,DC=ad,DC=com"); + reset(item); } int main(void)