From b2afbd3c9f38dafc0b2b8c761aa9be2b3b5f4f37 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 12 Nov 2017 14:30:26 +0100 Subject: [PATCH 01/27] cJSON_GetStringValue --- cJSON.c | 8 ++++++++ cJSON.h | 3 +++ tests/misc_tests.c | 14 ++++++++++++++ 3 files changed, 25 insertions(+) diff --git a/cJSON.c b/cJSON.c index cef719f5..d4d2bed2 100644 --- a/cJSON.c +++ b/cJSON.c @@ -73,6 +73,14 @@ CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) return (const char*) (global_error.json + global_error.position); } +CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item) { + if (!cJSON_IsString(item)) { + return NULL; + } + + return item->valuestring; +} + /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ #if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 6) || (CJSON_VERSION_PATCH != 0) #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. diff --git a/cJSON.h b/cJSON.h index 7c4f8e7c..c8650000 100644 --- a/cJSON.h +++ b/cJSON.h @@ -165,6 +165,9 @@ CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *st /* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void); +/* Check if the item is a string and return its valuestring */ +CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item); + /* These functions check the type of an item */ CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item); CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item); diff --git a/tests/misc_tests.c b/tests/misc_tests.c index 1643007e..af0cc7f9 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -450,6 +450,19 @@ static void skip_utf8_bom_should_not_skip_bom_if_not_at_beginning(void) TEST_ASSERT_NULL(skip_utf8_bom(&buffer)); } +static void cjson_get_string_value_should_get_a_string(void) +{ + cJSON *string = cJSON_CreateString("test"); + cJSON *number = cJSON_CreateNumber(1); + + TEST_ASSERT_TRUE(cJSON_GetStringValue(string) == string->valuestring); + TEST_ASSERT_NULL(cJSON_GetStringValue(number)); + TEST_ASSERT_NULL(cJSON_GetStringValue(NULL)); + + cJSON_Delete(number); + cJSON_Delete(string); +} + int main(void) { UNITY_BEGIN(); @@ -468,6 +481,7 @@ int main(void) RUN_TEST(ensure_should_fail_on_failed_realloc); RUN_TEST(skip_utf8_bom_should_skip_bom); RUN_TEST(skip_utf8_bom_should_not_skip_bom_if_not_at_beginning); + RUN_TEST(cjson_get_string_value_should_get_a_string); return UNITY_END(); } From 2718d30a3df525c31454dd4dc24dd0d786a401da Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Mon, 20 Nov 2017 22:04:57 +0100 Subject: [PATCH 02/27] Squashed 'tests/json-patch-tests/' changes from 0dd0fbc..99264bb 99264bb Merge pull request #37 from FormAPI/missing_parent_key c2fae3a Added a test case to check replace op with a missing parent key git-subtree-dir: tests/json-patch-tests git-subtree-split: 99264bb634d32c03df7472f21afb7d3681d8619e --- tests.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests.json b/tests.json index 28fe4bc2..86305c16 100644 --- a/tests.json +++ b/tests.json @@ -202,6 +202,11 @@ "patch": [{"op": "replace", "path": "", "value": {"baz": "qux"}}], "expected": {"baz": "qux"} }, + { "comment": "test replace with missing parent key should fail", + "doc": {"bar": "baz"}, + "patch": [{"op": "replace", "path": "/foo/bar", "value": false}], + "error": "replace op should fail with missing parent key" }, + { "comment": "spurious patch properties", "doc": {"foo": 1}, "patch": [{"op": "test", "path": "/foo", "value": 1, "spurious": 1}], From 440390a9a59b86e066b654f95482161fbc402606 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Tue, 28 Nov 2017 01:54:21 +0100 Subject: [PATCH 03/27] extract function cast_away_const_from_string --- cJSON.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/cJSON.c b/cJSON.c index d4d2bed2..8ad32e2f 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1891,6 +1891,14 @@ CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSO #ifdef __GNUC__ #pragma GCC diagnostic ignored "-Wcast-qual" #endif +/* helper function to cast away const */ +static char* cast_away_const_from_string(const char* string) +{ + return (char*)string; +} +#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) + #pragma GCC diagnostic pop +#endif /* Add an item to an object with constant string as key */ CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) @@ -1903,13 +1911,10 @@ CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJ { global_hooks.deallocate(item->string); } - item->string = (char*)string; + item->string = cast_away_const_from_string(string); item->type |= cJSON_StringIsConst; cJSON_AddItemToArray(object, item); } -#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) - #pragma GCC diagnostic pop -#endif CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) { From eaa90a6b74494c64526cb29f54429672241b7707 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Tue, 28 Nov 2017 02:02:55 +0100 Subject: [PATCH 04/27] Add cJSON_CreateStringReference --- cJSON.c | 12 ++++++++++++ cJSON.h | 4 ++++ tests/misc_tests.c | 11 +++++++++++ 3 files changed, 27 insertions(+) diff --git a/cJSON.c b/cJSON.c index 8ad32e2f..befa6a77 100644 --- a/cJSON.c +++ b/cJSON.c @@ -2198,6 +2198,18 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string) return item; } +CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item != NULL) + { + item->type = cJSON_String | cJSON_IsReference; + item->valuestring = cast_away_const_from_string(string); + } + + return item; +} + CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw) { cJSON *item = cJSON_New_Item(&global_hooks); diff --git a/cJSON.h b/cJSON.h index c8650000..c1ba0326 100644 --- a/cJSON.h +++ b/cJSON.h @@ -192,6 +192,10 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw); CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void); CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void); +/* Create a string where valuestring references a string so + * it will not be freed by cJSON_Delete */ +CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string); + /* These utilities create an Array of count items. */ CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count); CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count); diff --git a/tests/misc_tests.c b/tests/misc_tests.c index af0cc7f9..1b09a870 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -463,6 +463,16 @@ static void cjson_get_string_value_should_get_a_string(void) cJSON_Delete(string); } +static void cjson_create_string_reference_should_create_a_string_reference(void) { + const char *string = "I am a string!"; + + cJSON *string_reference = cJSON_CreateStringReference(string); + TEST_ASSERT_TRUE(string_reference->valuestring == string); + TEST_ASSERT_EQUAL_INT(cJSON_IsReference | cJSON_String, string_reference->type); + + cJSON_Delete(string_reference); +} + int main(void) { UNITY_BEGIN(); @@ -482,6 +492,7 @@ int main(void) RUN_TEST(skip_utf8_bom_should_skip_bom); RUN_TEST(skip_utf8_bom_should_not_skip_bom_if_not_at_beginning); RUN_TEST(cjson_get_string_value_should_get_a_string); + RUN_TEST(cjson_create_string_reference_should_create_a_string_reference); return UNITY_END(); } From 1f543f0e2842f5f5af2631756d20d0cb9a410b5a Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Tue, 28 Nov 2017 02:05:02 +0100 Subject: [PATCH 05/27] cast_away_const: Generalize for void* --- cJSON.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cJSON.c b/cJSON.c index befa6a77..3d3d5d28 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1892,9 +1892,9 @@ CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSO #pragma GCC diagnostic ignored "-Wcast-qual" #endif /* helper function to cast away const */ -static char* cast_away_const_from_string(const char* string) +static void* cast_away_const(const void* string) { - return (char*)string; + return (void*)string; } #if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) #pragma GCC diagnostic pop @@ -1911,7 +1911,7 @@ CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJ { global_hooks.deallocate(item->string); } - item->string = cast_away_const_from_string(string); + item->string = (char*)cast_away_const(string); item->type |= cJSON_StringIsConst; cJSON_AddItemToArray(object, item); } @@ -2204,7 +2204,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string) if (item != NULL) { item->type = cJSON_String | cJSON_IsReference; - item->valuestring = cast_away_const_from_string(string); + item->valuestring = (char*)cast_away_const(string); } return item; From 11844dd5a6be2e16e6107c1ab9c51b81a4910306 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Tue, 28 Nov 2017 03:06:02 +0100 Subject: [PATCH 06/27] Add cJSON_Create{Array,Object}Reference --- cJSON.c | 21 +++++++++++++++++++++ cJSON.h | 4 ++++ tests/misc_tests.c | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+) diff --git a/cJSON.c b/cJSON.c index 3d3d5d28..d08cb5b2 100644 --- a/cJSON.c +++ b/cJSON.c @@ -2210,6 +2210,27 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string) return item; } +CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item != NULL) { + item->type = cJSON_Object | cJSON_IsReference; + item->child = (cJSON*)cast_away_const(child); + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child) { + cJSON *item = cJSON_New_Item(&global_hooks); + if (item != NULL) { + item->type = cJSON_Array | cJSON_IsReference; + item->child = (cJSON*)cast_away_const(child); + } + + return item; +} + CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw) { cJSON *item = cJSON_New_Item(&global_hooks); diff --git a/cJSON.h b/cJSON.h index c1ba0326..ba0b2587 100644 --- a/cJSON.h +++ b/cJSON.h @@ -195,6 +195,10 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void); /* Create a string where valuestring references a string so * it will not be freed by cJSON_Delete */ CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string); +/* Create an object/arrray that only references it's elements so + * they will not be freed by cJSON_Delete */ +CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child); +CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child); /* These utilities create an Array of count items. */ CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count); diff --git a/tests/misc_tests.c b/tests/misc_tests.c index 1b09a870..a900e8fc 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -473,6 +473,41 @@ static void cjson_create_string_reference_should_create_a_string_reference(void) cJSON_Delete(string_reference); } +static void cjson_create_object_reference_should_create_an_object_reference(void) { + cJSON *number_reference = NULL; + cJSON *number_object = cJSON_CreateObject(); + cJSON *number = cJSON_CreateNumber(42); + const char key[] = "number"; + + TEST_ASSERT_TRUE(cJSON_IsNumber(number)); + TEST_ASSERT_TRUE(cJSON_IsObject(number_object)); + cJSON_AddItemToObjectCS(number_object, key, number); + + number_reference = cJSON_CreateObjectReference(number); + TEST_ASSERT_TRUE(number_reference->child == number); + TEST_ASSERT_EQUAL_INT(cJSON_Object | cJSON_IsReference, number_reference->type); + + cJSON_Delete(number_object); + cJSON_Delete(number_reference); +} + +static void cjson_create_array_reference_should_create_an_array_reference(void) { + cJSON *number_reference = NULL; + cJSON *number_array = cJSON_CreateArray(); + cJSON *number = cJSON_CreateNumber(42); + + TEST_ASSERT_TRUE(cJSON_IsNumber(number)); + TEST_ASSERT_TRUE(cJSON_IsArray(number_array)); + cJSON_AddItemToArray(number_array, number); + + number_reference = cJSON_CreateArrayReference(number); + TEST_ASSERT_TRUE(number_reference->child == number); + TEST_ASSERT_EQUAL_INT(cJSON_Array | cJSON_IsReference, number_reference->type); + + cJSON_Delete(number_array); + cJSON_Delete(number_reference); +} + int main(void) { UNITY_BEGIN(); @@ -493,6 +528,8 @@ int main(void) RUN_TEST(skip_utf8_bom_should_not_skip_bom_if_not_at_beginning); RUN_TEST(cjson_get_string_value_should_get_a_string); RUN_TEST(cjson_create_string_reference_should_create_a_string_reference); + RUN_TEST(cjson_create_object_reference_should_create_an_object_reference); + RUN_TEST(cjson_create_array_reference_should_create_an_array_reference); return UNITY_END(); } From da8c48668da6e82f9cbea94e4be04d74162e71fa Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Tue, 28 Nov 2017 03:15:50 +0100 Subject: [PATCH 07/27] Squashed 'tests/unity/' changes from 60b13f0..287e076 287e076 Post release 774da10 Merge pull request #296 from jlindgren90/master 629b86d Merge unity_setup.h into unity.h. 0914d80 Merge pull request #308 from codehearts/patch-1 5ee55fe Fix missing TEST_ASSERT_EACH_EQUAL_HEX_MESSAGE 38c387b Merge pull request #304 from VLambret/master 17d4ea9 Color test results using ANSI escape codes 031b1ba Merge pull request #300 from jsalling/bugfix/greater-than df78aad Make weak symbol usage more portable: a7e8797 Fix link errors with MinGW. 94a3008 Update continuous integration to build 32-bit Unity b119919 Add 64-bit comparison asserts 91bcbe1 Add 'greater/less or equal to' asserts on integers 8caade7 Fix bug in greater/less than asserts on unsigned int 1381a1a Update documentation. 2593c31 Allow suiteSetUp() and suiteTearDown() to be provided as normal C functions. 60def10 Update configuration docs git-subtree-dir: tests/unity git-subtree-split: 287e076962ec711cd2bdf08364a8df9ce51e106b --- .travis.yml | 4 +- auto/generate_test_runner.rb | 33 +++++++-- docs/UnityConfigurationGuide.md | 123 ++++++++++++++++++++----------- docs/UnityHelperScriptsGuide.md | 18 ++++- release/build.info | 2 +- release/version.info | 2 +- src/unity.c | 81 ++++++++++---------- src/unity.h | 118 ++++++++++++++++++++++++++++-- src/unity_internals.h | 126 ++++++++++++++++++++++---------- test/Makefile | 4 +- 10 files changed, 369 insertions(+), 142 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8ae9fa0c..bd165b1e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,7 +18,9 @@ install: script: - cd test && rake ci - make -s - - make -s DEBUG=-m32 + - make -s DEBUG=-m32 #32-bit architecture with 64-bit support + - make -s DEBUG=-m32 UNITY_SUPPORT_64= #32-bit build without 64-bit types + - make -s UNITY_INCLUDE_DOUBLE= # without double - cd ../extras/fixture/test && rake ci - make -s default noStdlibMalloc - make -s C89 diff --git a/auto/generate_test_runner.rb b/auto/generate_test_runner.rb index 07bde814..344a2d0f 100644 --- a/auto/generate_test_runner.rb +++ b/auto/generate_test_runner.rb @@ -157,6 +157,9 @@ def create_header(output, mocks, testfile_includes = []) output.puts('/* AUTOGENERATED FILE. DO NOT EDIT. */') create_runtest(output, mocks) output.puts("\n/*=======Automagically Detected Files To Include=====*/") + output.puts('#ifdef __WIN32__') + output.puts('#define UNITY_INCLUDE_SETUP_STUBS') + output.puts('#endif') output.puts("#include \"#{@options[:framework]}.h\"") output.puts('#include "cmock.h"') unless mocks.empty? output.puts('#include ') @@ -235,22 +238,36 @@ def create_mock_management(output, mock_headers) end def create_suite_setup(output) - return if @options[:suite_setup].nil? - output.puts("\n/*=======Suite Setup=====*/") output.puts('static void suite_setup(void)') output.puts('{') - output.puts(@options[:suite_setup]) + if @options[:suite_setup].nil? + # New style, call suiteSetUp() if we can use weak symbols + output.puts('#if defined(UNITY_WEAK_ATTRIBUTE) || defined(UNITY_WEAK_PRAGMA)') + output.puts(' suiteSetUp();') + output.puts('#endif') + else + # Old style, C code embedded in the :suite_setup option + output.puts(@options[:suite_setup]) + end output.puts('}') end def create_suite_teardown(output) - return if @options[:suite_teardown].nil? - output.puts("\n/*=======Suite Teardown=====*/") output.puts('static int suite_teardown(int num_failures)') output.puts('{') - output.puts(@options[:suite_teardown]) + if @options[:suite_teardown].nil? + # New style, call suiteTearDown() if we can use weak symbols + output.puts('#if defined(UNITY_WEAK_ATTRIBUTE) || defined(UNITY_WEAK_PRAGMA)') + output.puts(' return suiteTearDown(num_failures);') + output.puts('#else') + output.puts(' return num_failures;') + output.puts('#endif') + else + # Old style, C code embedded in the :suite_teardown option + output.puts(@options[:suite_teardown]) + end output.puts('}') end @@ -342,7 +359,7 @@ def create_main(output, filename, tests, used_mocks) output.puts("int #{main_name}(void)") output.puts('{') end - output.puts(' suite_setup();') unless @options[:suite_setup].nil? + output.puts(' suite_setup();') output.puts(" UnityBegin(\"#{filename.gsub(/\\/, '\\\\\\')}\");") if @options[:use_param_tests] tests.each do |test| @@ -357,7 +374,7 @@ def create_main(output, filename, tests, used_mocks) end output.puts output.puts(' CMock_Guts_MemFreeFinal();') unless used_mocks.empty? - output.puts(" return #{@options[:suite_teardown].nil? ? '' : 'suite_teardown'}(UnityEnd());") + output.puts(" return suite_teardown(UnityEnd());") output.puts('}') end diff --git a/docs/UnityConfigurationGuide.md b/docs/UnityConfigurationGuide.md index 283d7799..96e5358d 100644 --- a/docs/UnityConfigurationGuide.md +++ b/docs/UnityConfigurationGuide.md @@ -79,18 +79,7 @@ _Example:_ #define UNITY_EXCLUDE_LIMITS_H -##### `UNITY_EXCLUDE_SIZEOF` - -The third and final attempt to guess your types is to use the `sizeof()` -operator. Even if the first two options don't work, this one covers most cases. -There _is_ a rare compiler or two out there that doesn't support sizeof() in the -preprocessing stage, though. For these, you have the ability to disable this -feature as well. - -_Example:_ - #define UNITY_EXCLUDE_SIZEOF - -If you've disabled all of the automatic options above, you're going to have to +If you've disabled both of the automatic options above, you're going to have to do the configuration yourself. Don't worry. Even this isn't too bad... there are just a handful of defines that you are going to specify if you don't like the defaults. @@ -127,7 +116,7 @@ _Example:_ #define UNITY_POINTER_WIDTH 64 -##### `UNITY_INCLUDE_64` +##### `UNITY_SUPPORT_64` Unity will automatically include 64-bit support if it auto-detects it, or if your `int`, `long`, or pointer widths are greater than 32-bits. Define this to @@ -136,7 +125,7 @@ can be a significant size and speed impact to enabling 64-bit support on small targets, so don't define it if you don't need it. _Example:_ - #define UNITY_INCLUDE_64 + #define UNITY_SUPPORT_64 ### Floating Point Types @@ -170,24 +159,20 @@ _Example:_ #define UNITY_INCLUDE_DOUBLE -##### `UNITY_FLOAT_VERBOSE` - -##### `UNITY_DOUBLE_VERBOSE` +##### `UNITY_EXCLUDE_FLOAT_PRINT` Unity aims for as small of a footprint as possible and avoids most standard -library calls (some embedded platforms don't have a standard library!). Because +library calls (some embedded platforms don’t have a standard library!). Because of this, its routines for printing integer values are minimalist and hand-coded. -To keep Unity universal, though, we chose to _not_ develop our own floating -point print routines. Instead, the display of floating point values during a -failure are optional. By default, Unity will not print the actual results of -floating point assertion failure. So a failed assertion will produce a message -like `"Values Not Within Delta"`. If you would like verbose failure messages for -floating point assertions, use these options to give more explicit failure -messages (e.g. `"Expected 4.56 Was 4.68"`). Note that this feature requires the -use of `sprintf` so might not be desirable in all cases. +Therefore, the display of floating point values during a failure are optional. +By default, Unity will print the actual results of floating point assertion +failure (e.g. ”Expected 4.56 Was 4.68”). To not include this extra support, you +can use this define to instead respond to a failed assertion with a message like +”Values Not Within Delta”. If you would like verbose failure messages for floating +point assertions, use these options to give more explicit failure messages. _Example:_ - #define UNITY_DOUBLE_VERBOSE + #define UNITY_EXCLUDE_FLOAT_PRINT ##### `UNITY_FLOAT_TYPE` @@ -277,25 +262,32 @@ will declare an instance of your function by default. If you want to disable this behavior, add `UNITY_OMIT_OUTPUT_FLUSH_HEADER_DECLARATION`. -##### `UNITY_SUPPORT_WEAK` +##### `UNITY_WEAK_ATTRIBUTE` + +##### `UNITY_WEAK_PRAGMA` + +##### `UNITY_NO_WEAK` -For some targets, Unity can make the otherwise required `setUp()` and -`tearDown()` functions optional. This is a nice convenience for test writers -since `setUp` and `tearDown` don't often actually _do_ anything. If you're using -gcc or clang, this option is automatically defined for you. Other compilers can -also support this behavior, if they support a C feature called weak functions. A -weak function is a function that is compiled into your executable _unless_ a -non-weak version of the same function is defined elsewhere. If a non-weak -version is found, the weak version is ignored as if it never existed. If your -compiler supports this feature, you can let Unity know by defining -`UNITY_SUPPORT_WEAK` as the function attributes that would need to be applied to -identify a function as weak. If your compiler lacks support for weak functions, -you will always need to define `setUp` and `tearDown` functions (though they can -be and often will be just empty). The most common options for this feature are: +For some targets, Unity can make the otherwise required setUp() and tearDown() +functions optional. This is a nice convenience for test writers since setUp and +tearDown don’t often actually do anything. If you’re using gcc or clang, this +option is automatically defined for you. Other compilers can also support this +behavior, if they support a C feature called weak functions. A weak function is +a function that is compiled into your executable unless a non-weak version of +the same function is defined elsewhere. If a non-weak version is found, the weak +version is ignored as if it never existed. If your compiler supports this feature, +you can let Unity know by defining UNITY_WEAK_ATTRIBUTE or UNITY_WEAK_PRAGMA as +the function attributes that would need to be applied to identify a function as +weak. If your compiler lacks support for weak functions, you will always need to +define setUp and tearDown functions (though they can be and often will be just +empty). You can also force Unity to NOT use weak functions by defining +UNITY_NO_WEAK. The most common options for this feature are: _Example:_ - #define UNITY_SUPPORT_WEAK weak - #define UNITY_SUPPORT_WEAK __attribute__((weak)) + #define UNITY_WEAK_ATTRIBUTE weak + #define UNITY_WEAK_ATTRIBUTE __attribute__((weak)) + #define UNITY_WEAK_PRAGMA + #define UNITY_NO_WEAK ##### `UNITY_PTR_ATTRIBUTE` @@ -309,6 +301,51 @@ _Example:_ #define UNITY_PTR_ATTRIBUTE near +##### `UNITY_PRINT_EOL` + +By default, Unity outputs \n at the end of each line of output. This is easy +to parse by the scripts, by Ceedling, etc, but it might not be ideal for YOUR +system. Feel free to override this and to make it whatever you wish. + +_Example:_ + #define UNITY_PRINT_EOL { UNITY_OUTPUT_CHAR('\r'); UNITY_OUTPUT_CHAR('\n') } + + + +##### `UNITY_EXCLUDE_DETAILS` + +This is an option for if you absolutely must squeeze every byte of memory out of +your system. Unity stores a set of internal scratchpads which are used to pass +extra detail information around. It's used by systems like CMock in order to +report which function or argument flagged an error. If you're not using CMock and +you're not using these details for other things, then you can exclude them. + +_Example:_ + #define UNITY_EXCLUDE_DETAILS + + + +##### `UNITY_EXCLUDE_SETJMP` + +If your embedded system doesn't support the standard library setjmp, you can +exclude Unity's reliance on this by using this define. This dropped dependence +comes at a price, though. You will be unable to use custom helper functions for +your tests, and you will be unable to use tools like CMock. Very likely, if your +compiler doesn't support setjmp, you wouldn't have had the memory space for those +things anyway, though... so this option exists for those situations. + +_Example:_ + #define UNITY_EXCLUDE_SETJMP + +##### `UNITY_OUTPUT_COLOR` + +If you want to add color using ANSI escape codes you can use this define. +t +_Example:_ + #define UNITY_OUTPUT_COLOR + + + ## Getting Into The Guts There will be cases where the options above aren't quite going to get everything diff --git a/docs/UnityHelperScriptsGuide.md b/docs/UnityHelperScriptsGuide.md index 3a930096..42429900 100644 --- a/docs/UnityHelperScriptsGuide.md +++ b/docs/UnityHelperScriptsGuide.md @@ -124,7 +124,7 @@ demonstrates using a Ruby hash. ##### `:includes` -This option specifies an array of file names to be ?#include?'d at the top of +This option specifies an array of file names to be `#include`'d at the top of your runner C file. You might use it to reference custom types or anything else universally needed in your generated runners. @@ -133,11 +133,23 @@ universally needed in your generated runners. Define this option with C code to be executed _before any_ test cases are run. +Alternatively, if your C compiler supports weak symbols, you can leave this +option unset and instead provide a `void suiteSetUp(void)` function in your test +suite. The linker will look for this symbol and fall back to a Unity-provided +stub if it is not found. + ##### `:suite_teardown` -Define this option with C code to be executed ?after all?test cases have -finished. +Define this option with C code to be executed _after all_ test cases have +finished. An integer variable `num_failures` is available for diagnostics. +The code should end with a `return` statement; the value returned will become +the exit code of `main`. You can normally just return `num_failures`. + +Alternatively, if your C compiler supports weak symbols, you can leave this +option unset and instead provide a `int suiteTearDown(int num_failures)` +function in your test suite. The linker will look for this symbol and fall +back to a Unity-provided stub if it is not found. ##### `:enforce_strict_ordering` diff --git a/release/build.info b/release/build.info index 50fb6eaf..56d59128 100644 --- a/release/build.info +++ b/release/build.info @@ -1,2 +1,2 @@ -121 +122 diff --git a/release/version.info b/release/version.info index b674b923..cf12b30d 100644 --- a/release/version.info +++ b/release/version.info @@ -1,2 +1,2 @@ -2.4.2 +2.4.3 diff --git a/src/unity.c b/src/unity.c index 9783efac..0f2d2dea 100644 --- a/src/unity.c +++ b/src/unity.c @@ -4,6 +4,7 @@ [Released under MIT License. Please refer to license.txt for details] ============================================================================ */ +#define UNITY_INCLUDE_SETUP_STUBS #include "unity.h" #include @@ -19,16 +20,24 @@ void UNITY_OUTPUT_CHAR(int); struct UNITY_STORAGE_T Unity; +#ifdef UNITY_OUTPUT_COLOR +static const char UnityStrOk[] = "\033[42mOK\033[00m"; +static const char UnityStrPass[] = "\033[42mPASS\033[00m"; +static const char UnityStrFail[] = "\033[41mFAIL\033[00m"; +static const char UnityStrIgnore[] = "\033[43mIGNORE\033[00m"; +#else static const char UnityStrOk[] = "OK"; static const char UnityStrPass[] = "PASS"; static const char UnityStrFail[] = "FAIL"; static const char UnityStrIgnore[] = "IGNORE"; +#endif static const char UnityStrNull[] = "NULL"; static const char UnityStrSpacer[] = ". "; static const char UnityStrExpected[] = " Expected "; static const char UnityStrWas[] = " Was "; static const char UnityStrGt[] = " to be greater than "; static const char UnityStrLt[] = " to be less than "; +static const char UnityStrOrEqual[] = "or equal to "; static const char UnityStrElement[] = " Element "; static const char UnityStrByte[] = " Byte "; static const char UnityStrMemory[] = " Memory Mismatch."; @@ -83,6 +92,18 @@ void UnityPrint(const char* string) UNITY_OUTPUT_CHAR('\\'); UNITY_OUTPUT_CHAR('n'); } +#ifdef UNITY_OUTPUT_COLOR + /* print ANSI escape code */ + else if (*pch == 27 && *(pch + 1) == '[') + { + while (*pch && *pch != 'm') + { + UNITY_OUTPUT_CHAR(*pch); + pch++; + } + UNITY_OUTPUT_CHAR('m'); + } +#endif /* unprintable characters are shown as codes */ else { @@ -531,49 +552,44 @@ void UnityAssertEqualNumber(const UNITY_INT expected, } /*-----------------------------------------------*/ -void UnityAssertGreaterNumber(const UNITY_INT threshold, - const UNITY_INT actual, - const char *msg, - const UNITY_LINE_TYPE lineNumber, - const UNITY_DISPLAY_STYLE_T style) +void UnityAssertGreaterOrLessOrEqualNumber(const UNITY_INT threshold, + const UNITY_INT actual, + const UNITY_COMPARISON_T compare, + const char *msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style) { + int failed = 0; RETURN_IF_FAIL_OR_IGNORE; - if (!(actual > threshold)) + if (threshold == actual && compare & UNITY_EQUAL_TO) return; + if (threshold == actual) failed = 1; + + if ((style & UNITY_DISPLAY_RANGE_INT) == UNITY_DISPLAY_RANGE_INT) { - UnityTestResultsFailBegin(lineNumber); - UnityPrint(UnityStrExpected); - UnityPrintNumberByStyle(actual, style); - UnityPrint(UnityStrGt); - UnityPrintNumberByStyle(threshold, style); - UnityAddMsgIfSpecified(msg); - UNITY_FAIL_AND_BAIL; + if (actual > threshold && compare & UNITY_SMALLER_THAN) failed = 1; + if (actual < threshold && compare & UNITY_GREATER_THAN) failed = 1; + } + else /* UINT or HEX */ + { + if ((UNITY_UINT)actual > (UNITY_UINT)threshold && compare & UNITY_SMALLER_THAN) failed = 1; + if ((UNITY_UINT)actual < (UNITY_UINT)threshold && compare & UNITY_GREATER_THAN) failed = 1; } -} - -/*-----------------------------------------------*/ -void UnityAssertSmallerNumber(const UNITY_INT threshold, - const UNITY_INT actual, - const char *msg, - const UNITY_LINE_TYPE lineNumber, - const UNITY_DISPLAY_STYLE_T style) -{ - RETURN_IF_FAIL_OR_IGNORE; - if (!(actual < threshold)) + if (failed) { UnityTestResultsFailBegin(lineNumber); UnityPrint(UnityStrExpected); UnityPrintNumberByStyle(actual, style); - UnityPrint(UnityStrLt); + if (compare & UNITY_GREATER_THAN) UnityPrint(UnityStrGt); + if (compare & UNITY_SMALLER_THAN) UnityPrint(UnityStrLt); + if (compare & UNITY_EQUAL_TO) UnityPrint(UnityStrOrEqual); UnityPrintNumberByStyle(threshold, style); UnityAddMsgIfSpecified(msg); UNITY_FAIL_AND_BAIL; } } - - #define UnityPrintPointlessAndBail() \ { \ UnityTestResultsFailBegin(lineNumber); \ @@ -1310,17 +1326,6 @@ void UnityIgnore(const char* msg, const UNITY_LINE_TYPE line) UNITY_IGNORE_AND_BAIL; } -/*-----------------------------------------------*/ -#if defined(UNITY_WEAK_ATTRIBUTE) - UNITY_WEAK_ATTRIBUTE void setUp(void) { } - UNITY_WEAK_ATTRIBUTE void tearDown(void) { } -#elif defined(UNITY_WEAK_PRAGMA) - #pragma weak setUp - void setUp(void) { } - #pragma weak tearDown - void tearDown(void) { } -#endif - /*-----------------------------------------------*/ void UnityDefaultTestRun(UnityTestFunction Func, const char* FuncName, const int FuncLineNum) { diff --git a/src/unity.h b/src/unity.h index 258e21c9..32ff0e6d 100644 --- a/src/unity.h +++ b/src/unity.h @@ -15,9 +15,43 @@ extern "C" #include "unity_internals.h" +/*------------------------------------------------------- + * Test Setup / Teardown + *-------------------------------------------------------*/ + +/* These functions are intended to be called before and after each test. */ void setUp(void); void tearDown(void); +/* These functions are intended to be called at the beginning and end of an + * entire test suite. suiteTearDown() is passed the number of tests that + * failed, and its return value becomes the exit code of main(). */ +void suiteSetUp(void); +int suiteTearDown(int num_failures); + +/* If the compiler supports it, the following block provides stub + * implementations of the above functions as weak symbols. Note that on + * some platforms (MinGW for example), weak function implementations need + * to be in the same translation unit they are called from. This can be + * achieved by defining UNITY_INCLUDE_SETUP_STUBS before including unity.h. */ +#ifdef UNITY_INCLUDE_SETUP_STUBS + #ifdef UNITY_WEAK_ATTRIBUTE + UNITY_WEAK_ATTRIBUTE void setUp(void) { } + UNITY_WEAK_ATTRIBUTE void tearDown(void) { } + UNITY_WEAK_ATTRIBUTE void suiteSetUp(void) { } + UNITY_WEAK_ATTRIBUTE int suiteTearDown(int num_failures) { return num_failures; } + #elif defined(UNITY_WEAK_PRAGMA) + #pragma weak setUp + void setUp(void) { } + #pragma weak tearDown + void tearDown(void) { } + #pragma weak suiteSetUp + void suiteSetUp(void) { } + #pragma weak suiteTearDown + int suiteTearDown(int num_failures) { return num_failures; } + #endif +#endif + /*------------------------------------------------------- * Configuration Options *------------------------------------------------------- @@ -120,28 +154,64 @@ void tearDown(void); #define TEST_ASSERT_GREATER_THAN_INT8(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT8((threshold), (actual), __LINE__, NULL) #define TEST_ASSERT_GREATER_THAN_INT16(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT16((threshold), (actual), __LINE__, NULL) #define TEST_ASSERT_GREATER_THAN_INT32(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_INT64(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT64((threshold), (actual), __LINE__, NULL) #define TEST_ASSERT_GREATER_THAN_UINT(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT((threshold), (actual), __LINE__, NULL) #define TEST_ASSERT_GREATER_THAN_UINT8(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT8((threshold), (actual), __LINE__, NULL) #define TEST_ASSERT_GREATER_THAN_UINT16(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT16((threshold), (actual), __LINE__, NULL) #define TEST_ASSERT_GREATER_THAN_UINT32(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_UINT64(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT64((threshold), (actual), __LINE__, NULL) #define TEST_ASSERT_GREATER_THAN_HEX8(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_HEX8((threshold), (actual), __LINE__, NULL) #define TEST_ASSERT_GREATER_THAN_HEX16(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_HEX16((threshold), (actual), __LINE__, NULL) #define TEST_ASSERT_GREATER_THAN_HEX32(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_HEX32((threshold), (actual), __LINE__, NULL) - +#define TEST_ASSERT_GREATER_THAN_HEX64(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_HEX64((threshold), (actual), __LINE__, NULL) #define TEST_ASSERT_LESS_THAN(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT((threshold), (actual), __LINE__, NULL) #define TEST_ASSERT_LESS_THAN_INT(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT((threshold), (actual), __LINE__, NULL) #define TEST_ASSERT_LESS_THAN_INT8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT8((threshold), (actual), __LINE__, NULL) #define TEST_ASSERT_LESS_THAN_INT16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT16((threshold), (actual), __LINE__, NULL) #define TEST_ASSERT_LESS_THAN_INT32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_INT64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT64((threshold), (actual), __LINE__, NULL) #define TEST_ASSERT_LESS_THAN_UINT(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT((threshold), (actual), __LINE__, NULL) #define TEST_ASSERT_LESS_THAN_UINT8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT8((threshold), (actual), __LINE__, NULL) #define TEST_ASSERT_LESS_THAN_UINT16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT16((threshold), (actual), __LINE__, NULL) #define TEST_ASSERT_LESS_THAN_UINT32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_UINT64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT64((threshold), (actual), __LINE__, NULL) #define TEST_ASSERT_LESS_THAN_HEX8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_HEX8((threshold), (actual), __LINE__, NULL) #define TEST_ASSERT_LESS_THAN_HEX16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_HEX16((threshold), (actual), __LINE__, NULL) #define TEST_ASSERT_LESS_THAN_HEX32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_HEX32((threshold), (actual), __LINE__, NULL) - +#define TEST_ASSERT_LESS_THAN_HEX64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_HEX64((threshold), (actual), __LINE__, NULL) + +#define TEST_ASSERT_GREATER_OR_EQUAL(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT8(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT16(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT32(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT64(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT8(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT16(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT32(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT64(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX8(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX16(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX32(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX64(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX64((threshold), (actual), __LINE__, NULL) + +#define TEST_ASSERT_LESS_OR_EQUAL(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_INT(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_INT8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_INT16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_INT32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_INT64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX64((threshold), (actual), __LINE__, NULL) /* Integer Ranges (of all sizes) */ #define TEST_ASSERT_INT_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_INT_WITHIN((delta), (expected), (actual), __LINE__, NULL) @@ -186,8 +256,6 @@ void tearDown(void); #define TEST_ASSERT_EQUAL_STRING_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_STRING_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) #define TEST_ASSERT_EQUAL_MEMORY_ARRAY(expected, actual, len, num_elements) UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY((expected), (actual), (len), (num_elements), __LINE__, NULL) - - /* Arrays Compared To Single Value */ #define TEST_ASSERT_EACH_EQUAL_INT(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_INT((expected), (actual), (num_elements), __LINE__, NULL) #define TEST_ASSERT_EACH_EQUAL_INT8(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_INT8((expected), (actual), (num_elements), __LINE__, NULL) @@ -278,28 +346,64 @@ void tearDown(void); #define TEST_ASSERT_GREATER_THAN_INT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT8((threshold), (actual), __LINE__, (message)) #define TEST_ASSERT_GREATER_THAN_INT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT16((threshold), (actual), __LINE__, (message)) #define TEST_ASSERT_GREATER_THAN_INT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_INT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT64((threshold), (actual), __LINE__, (message)) #define TEST_ASSERT_GREATER_THAN_UINT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT((threshold), (actual), __LINE__, (message)) #define TEST_ASSERT_GREATER_THAN_UINT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT8((threshold), (actual), __LINE__, (message)) #define TEST_ASSERT_GREATER_THAN_UINT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT16((threshold), (actual), __LINE__, (message)) #define TEST_ASSERT_GREATER_THAN_UINT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_UINT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT64((threshold), (actual), __LINE__, (message)) #define TEST_ASSERT_GREATER_THAN_HEX8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_HEX8((threshold), (actual), __LINE__, (message)) #define TEST_ASSERT_GREATER_THAN_HEX16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_HEX16((threshold), (actual), __LINE__, (message)) #define TEST_ASSERT_GREATER_THAN_HEX32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_HEX32((threshold), (actual), __LINE__, (message)) - +#define TEST_ASSERT_GREATER_THAN_HEX64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_HEX64((threshold), (actual), __LINE__, (message)) #define TEST_ASSERT_LESS_THAN_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT((threshold), (actual), __LINE__, (message)) #define TEST_ASSERT_LESS_THAN_INT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT((threshold), (actual), __LINE__, (message)) #define TEST_ASSERT_LESS_THAN_INT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT8((threshold), (actual), __LINE__, (message)) #define TEST_ASSERT_LESS_THAN_INT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT16((threshold), (actual), __LINE__, (message)) #define TEST_ASSERT_LESS_THAN_INT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_INT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT64((threshold), (actual), __LINE__, (message)) #define TEST_ASSERT_LESS_THAN_UINT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT((threshold), (actual), __LINE__, (message)) #define TEST_ASSERT_LESS_THAN_UINT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT8((threshold), (actual), __LINE__, (message)) #define TEST_ASSERT_LESS_THAN_UINT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT16((threshold), (actual), __LINE__, (message)) #define TEST_ASSERT_LESS_THAN_UINT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_UINT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT64((threshold), (actual), __LINE__, (message)) #define TEST_ASSERT_LESS_THAN_HEX8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_HEX8((threshold), (actual), __LINE__, (message)) #define TEST_ASSERT_LESS_THAN_HEX16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_HEX16((threshold), (actual), __LINE__, (message)) #define TEST_ASSERT_LESS_THAN_HEX32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_HEX32((threshold), (actual), __LINE__, (message)) - +#define TEST_ASSERT_LESS_THAN_HEX64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_HEX64((threshold), (actual), __LINE__, (message)) + +#define TEST_ASSERT_GREATER_OR_EQUAL_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX64((threshold), (actual), __LINE__, (message)) + +#define TEST_ASSERT_LESS_OR_EQUAL_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_INT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_INT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_INT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_INT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_INT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_HEX32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_HEX64((threshold), (actual), __LINE__, (message)) /* Integer Ranges (of all sizes) */ #define TEST_ASSERT_INT_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_INT_WITHIN((delta), (expected), (actual), __LINE__, (message)) @@ -355,7 +459,7 @@ void tearDown(void); #define TEST_ASSERT_EACH_EQUAL_UINT16_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_UINT16((expected), (actual), (num_elements), __LINE__, (message)) #define TEST_ASSERT_EACH_EQUAL_UINT32_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_UINT32((expected), (actual), (num_elements), __LINE__, (message)) #define TEST_ASSERT_EACH_EQUAL_UINT64_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_UINT64((expected), (actual), (num_elements), __LINE__, (message)) -#define TEST_ASSERT_EACH_EQUAL_HEX32_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_HEX32((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_HEX_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_HEX32((expected), (actual), (num_elements), __LINE__, (message)) #define TEST_ASSERT_EACH_EQUAL_HEX8_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_HEX8((expected), (actual), (num_elements), __LINE__, (message)) #define TEST_ASSERT_EACH_EQUAL_HEX16_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_HEX16((expected), (actual), (num_elements), __LINE__, (message)) #define TEST_ASSERT_EACH_EQUAL_HEX32_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_HEX32((expected), (actual), (num_elements), __LINE__, (message)) diff --git a/src/unity_internals.h b/src/unity_internals.h index 1b57cd02..67e219b8 100644 --- a/src/unity_internals.h +++ b/src/unity_internals.h @@ -301,7 +301,7 @@ extern void UNITY_OMIT_OUTPUT_FLUSH_HEADER_DECLARATION; * Language Features Available *-------------------------------------------------------*/ #if !defined(UNITY_WEAK_ATTRIBUTE) && !defined(UNITY_WEAK_PRAGMA) -# ifdef __GNUC__ /* includes clang */ +# if defined(__GNUC__) || defined(__ghs__) /* __GNUC__ includes clang */ # if !(defined(__WIN32__) && defined(__clang__)) && !defined(__TMS470__) # define UNITY_WEAK_ATTRIBUTE __attribute__((weak)) # endif @@ -352,6 +352,15 @@ UNITY_DISPLAY_STYLE_UINT = sizeof(unsigned) + UNITY_DISPLAY_RANGE_UINT, UNITY_DISPLAY_STYLE_UNKNOWN } UNITY_DISPLAY_STYLE_T; +typedef enum +{ + UNITY_EQUAL_TO = 1, + UNITY_GREATER_THAN = 2, + UNITY_GREATER_OR_EQUAL = 2 + UNITY_EQUAL_TO, + UNITY_SMALLER_THAN = 4, + UNITY_SMALLER_OR_EQUAL = 4 + UNITY_EQUAL_TO +} UNITY_COMPARISON_T; + #ifndef UNITY_EXCLUDE_FLOAT typedef enum UNITY_FLOAT_TRAIT { @@ -455,17 +464,12 @@ void UnityAssertEqualNumber(const UNITY_INT expected, const UNITY_LINE_TYPE lineNumber, const UNITY_DISPLAY_STYLE_T style); -void UnityAssertGreaterNumber(const UNITY_INT threshold, - const UNITY_INT actual, - const char* msg, - const UNITY_LINE_TYPE lineNumber, - const UNITY_DISPLAY_STYLE_T style); - -void UnityAssertSmallerNumber(const UNITY_INT threshold, - const UNITY_INT actual, - const char* msg, - const UNITY_LINE_TYPE lineNumber, - const UNITY_DISPLAY_STYLE_T style); +void UnityAssertGreaterOrLessOrEqualNumber(const UNITY_INT threshold, + const UNITY_INT actual, + const UNITY_COMPARISON_T compare, + const char *msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style); void UnityAssertEqualIntArray(UNITY_INTERNAL_PTR expected, UNITY_INTERNAL_PTR actual, @@ -664,33 +668,53 @@ int UnityTestMatches(void); #define UNITY_TEST_ASSERT_EQUAL_HEX32(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_INT32)(expected), (UNITY_INT)(UNITY_INT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) #define UNITY_TEST_ASSERT_BITS(mask, expected, actual, line, message) UnityAssertBits((UNITY_INT)(mask), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line)) - -#define UNITY_TEST_ASSERT_GREATER_THAN_INT(threshold, actual, line, message) UnityAssertGreaterNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) -#define UNITY_TEST_ASSERT_GREATER_THAN_INT8(threshold, actual, line, message) UnityAssertGreaterNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) -#define UNITY_TEST_ASSERT_GREATER_THAN_INT16(threshold, actual, line, message) UnityAssertGreaterNumber((UNITY_INT)(UNITY_INT16)(threshold), (UNITY_INT)(UNITY_INT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) -#define UNITY_TEST_ASSERT_GREATER_THAN_INT32(threshold, actual, line, message) UnityAssertGreaterNumber((UNITY_INT)(UNITY_INT32)(threshold), (UNITY_INT)(UNITY_INT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) -#define UNITY_TEST_ASSERT_GREATER_THAN_UINT(threshold, actual, line, message) UnityAssertGreaterNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) -#define UNITY_TEST_ASSERT_GREATER_THAN_UINT8(threshold, actual, line, message) UnityAssertGreaterNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) -#define UNITY_TEST_ASSERT_GREATER_THAN_UINT16(threshold, actual, line, message) UnityAssertGreaterNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) -#define UNITY_TEST_ASSERT_GREATER_THAN_UINT32(threshold, actual, line, message) UnityAssertGreaterNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) -#define UNITY_TEST_ASSERT_GREATER_THAN_HEX8(threshold, actual, line, message) UnityAssertGreaterNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) -#define UNITY_TEST_ASSERT_GREATER_THAN_HEX16(threshold, actual, line, message) UnityAssertGreaterNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) -#define UNITY_TEST_ASSERT_GREATER_THAN_HEX32(threshold, actual, line, message) UnityAssertGreaterNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) - - -#define UNITY_TEST_ASSERT_SMALLER_THAN_INT(threshold, actual, line, message) UnityAssertSmallerNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) -#define UNITY_TEST_ASSERT_SMALLER_THAN_INT8(threshold, actual, line, message) UnityAssertSmallerNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) -#define UNITY_TEST_ASSERT_SMALLER_THAN_INT16(threshold, actual, line, message) UnityAssertSmallerNumber((UNITY_INT)(UNITY_INT16)(threshold), (UNITY_INT)(UNITY_INT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) -#define UNITY_TEST_ASSERT_SMALLER_THAN_INT32(threshold, actual, line, message) UnityAssertSmallerNumber((UNITY_INT)(UNITY_INT32)(threshold), (UNITY_INT)(UNITY_INT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) -#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT(threshold, actual, line, message) UnityAssertSmallerNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) -#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT8(threshold, actual, line, message) UnityAssertSmallerNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) -#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT16(threshold, actual, line, message) UnityAssertSmallerNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) -#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT32(threshold, actual, line, message) UnityAssertSmallerNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) -#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX8(threshold, actual, line, message) UnityAssertSmallerNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) -#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX16(threshold, actual, line, message) UnityAssertSmallerNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) -#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX32(threshold, actual, line, message) UnityAssertSmallerNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) - - +#define UNITY_TEST_ASSERT_GREATER_THAN_INT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) +#define UNITY_TEST_ASSERT_GREATER_THAN_INT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) +#define UNITY_TEST_ASSERT_GREATER_THAN_INT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT16)(threshold), (UNITY_INT)(UNITY_INT16)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) +#define UNITY_TEST_ASSERT_GREATER_THAN_INT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT32)(threshold), (UNITY_INT)(UNITY_INT32)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) +#define UNITY_TEST_ASSERT_GREATER_THAN_UINT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) +#define UNITY_TEST_ASSERT_GREATER_THAN_UINT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) +#define UNITY_TEST_ASSERT_GREATER_THAN_UINT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) +#define UNITY_TEST_ASSERT_GREATER_THAN_UINT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) +#define UNITY_TEST_ASSERT_GREATER_THAN_HEX8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) +#define UNITY_TEST_ASSERT_GREATER_THAN_HEX16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) +#define UNITY_TEST_ASSERT_GREATER_THAN_HEX32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) + +#define UNITY_TEST_ASSERT_SMALLER_THAN_INT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) +#define UNITY_TEST_ASSERT_SMALLER_THAN_INT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) +#define UNITY_TEST_ASSERT_SMALLER_THAN_INT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT16)(threshold), (UNITY_INT)(UNITY_INT16)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) +#define UNITY_TEST_ASSERT_SMALLER_THAN_INT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT32)(threshold), (UNITY_INT)(UNITY_INT32)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) +#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) +#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) +#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) +#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) +#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) +#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) +#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) + +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT16)(threshold), (UNITY_INT)(UNITY_INT16)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT32)(threshold), (UNITY_INT)(UNITY_INT32)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) + +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT16)(threshold), (UNITY_INT)(UNITY_INT16)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT32)(threshold), (UNITY_INT)(UNITY_INT32)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) #define UNITY_TEST_ASSERT_INT_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((delta), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) #define UNITY_TEST_ASSERT_INT8_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT8 )(delta), (UNITY_INT)(UNITY_INT8 )(expected), (UNITY_INT)(UNITY_INT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) @@ -752,6 +776,18 @@ int UnityTestMatches(void); #define UNITY_TEST_ASSERT_INT64_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((delta), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) #define UNITY_TEST_ASSERT_UINT64_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((delta), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) #define UNITY_TEST_ASSERT_HEX64_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((delta), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) +#define UNITY_TEST_ASSERT_GREATER_THAN_INT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) +#define UNITY_TEST_ASSERT_GREATER_THAN_UINT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) +#define UNITY_TEST_ASSERT_GREATER_THAN_HEX64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) +#define UNITY_TEST_ASSERT_SMALLER_THAN_INT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) +#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) +#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) #else #define UNITY_TEST_ASSERT_EQUAL_INT64(expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) #define UNITY_TEST_ASSERT_EQUAL_UINT64(expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) @@ -762,6 +798,18 @@ int UnityTestMatches(void); #define UNITY_TEST_ASSERT_INT64_WITHIN(delta, expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) #define UNITY_TEST_ASSERT_UINT64_WITHIN(delta, expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) #define UNITY_TEST_ASSERT_HEX64_WITHIN(delta, expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_GREATER_THAN_INT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_GREATER_THAN_UINT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_GREATER_THAN_HEX64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_SMALLER_THAN_INT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) #endif #ifdef UNITY_EXCLUDE_FLOAT diff --git a/test/Makefile b/test/Makefile index 9de7a49a..c2710f1f 100644 --- a/test/Makefile +++ b/test/Makefile @@ -15,7 +15,9 @@ CFLAGS += -Wbad-function-cast -Wcast-qual -Wold-style-definition -Wshadow -Wstri CFLAGS += $(DEBUG) DEFINES = -D UNITY_OUTPUT_CHAR=putcharSpy DEFINES += -D UNITY_OUTPUT_CHAR_HEADER_DECLARATION=putcharSpy\(int\) -DEFINES += -D UNITY_SUPPORT_64 -D UNITY_INCLUDE_DOUBLE +DEFINES += $(UNITY_SUPPORT_64) $(UNITY_INCLUDE_DOUBLE) +UNITY_SUPPORT_64 = -D UNITY_SUPPORT_64 +UNITY_INCLUDE_DOUBLE = -D UNITY_INCLUDE_DOUBLE SRC = ../src/unity.c tests/testunity.c build/testunityRunner.c INC_DIR = -I ../src COV_FLAGS = -fprofile-arcs -ftest-coverage -I ../../src From eb7c681a4b363c1ca7eebc5d1259e89283866ffb Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Tue, 28 Nov 2017 16:44:24 +0100 Subject: [PATCH 08/27] Fix tests when building as static library --- tests/CMakeLists.txt | 6 +-- tests/common.c | 97 -------------------------------------------- tests/common.h | 75 +++++++++++++++++++++++++++++++++- 3 files changed, 75 insertions(+), 103 deletions(-) delete mode 100644 tests/common.c diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f7c1779c..e63c500d 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -57,8 +57,6 @@ if(ENABLE_CJSON_TEST) compare_tests ) - 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) @@ -72,7 +70,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 test-common) + target_link_libraries("${unity_test}" "${CJSON_LIB}" unity) if(MEMORYCHECK_COMMAND) add_test(NAME "${unity_test}" COMMAND "${MEMORYCHECK_COMMAND}" ${MEMORYCHECK_COMMAND_OPTIONS} "${CMAKE_CURRENT_BINARY_DIR}/${unity_test}") @@ -97,7 +95,7 @@ if(ENABLE_CJSON_TEST) foreach (cjson_utils_test ${cjson_utils_tests}) add_executable("${cjson_utils_test}" "${cjson_utils_test}.c") - target_link_libraries("${cjson_utils_test}" "${CJSON_LIB}" "${CJSON_UTILS_LIB}" unity test-common) + target_link_libraries("${cjson_utils_test}" "${CJSON_LIB}" "${CJSON_UTILS_LIB}" unity) if(MEMORYCHECK_COMMAND) add_test(NAME "${cjson_utils_test}" COMMAND "${MEMORYCHECK_COMMAND}" ${MEMORYCHECK_COMMAND_OPTIONS} "${CMAKE_CURRENT_BINARY_DIR}/${cjson_utils_test}") diff --git a/tests/common.c b/tests/common.c deleted file mode 100644 index 12022e11..00000000 --- a/tests/common.c +++ /dev/null @@ -1,97 +0,0 @@ -/* - 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" - -CJSON_PUBLIC(void) reset(cJSON *item) -{ - if ((item != NULL) && (item->child != NULL)) - { - cJSON_Delete(item->child); - } - if ((item->valuestring != NULL) && !(item->type & cJSON_IsReference)) - { - global_hooks.deallocate(item->valuestring); - } - if ((item->string != NULL) && !(item->type & cJSON_StringIsConst)) - { - global_hooks.deallocate(item->string); - } - - memset(item, 0, sizeof(cJSON)); -} - -CJSON_PUBLIC(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("")); - 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 index 97c09bf2..4db6bf8c 100644 --- a/tests/common.h +++ b/tests/common.h @@ -25,8 +25,79 @@ #include "../cJSON.c" -CJSON_PUBLIC(void) reset(cJSON *item); -CJSON_PUBLIC(char*) read_file(const char *filename); +void reset(cJSON *item); +void reset(cJSON *item) { + if ((item != NULL) && (item->child != NULL)) + { + cJSON_Delete(item->child); + } + if ((item->valuestring != NULL) && !(item->type & cJSON_IsReference)) + { + global_hooks.deallocate(item->valuestring); + } + if ((item->string != NULL) && !(item->type & cJSON_StringIsConst)) + { + global_hooks.deallocate(item->string); + } + + memset(item, 0, sizeof(cJSON)); +} + +char* read_file(const char *filename); +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("")); + 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; +} /* 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.") From 2a087843e4f8b6bfae57d35621e3787e0b999a21 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Tue, 28 Nov 2017 17:16:11 +0100 Subject: [PATCH 09/27] Add overrides for BUILD_SHARED_LIBS --- CMakeLists.txt | 13 +++++++++++-- README.md | 1 + tests/CMakeLists.txt | 2 +- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 24132562..97f9cfe6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -123,9 +123,18 @@ file(GLOB HEADERS cJSON.h) set(SOURCES cJSON.c) option(BUILD_SHARED_AND_STATIC_LIBS "Build both shared and static libraries" Off) +option(CJSON_OVERRIDE_BUILD_SHARED_LIBS "Override BUILD_SHARED_LIBS with CJSON_BUILD_SHARED_LIBS" OFF) +option(CJSON_BUILD_SHARED_LIBS "Overrides BUILD_SHARED_LIBS if CJSON_OVERRIDE_BUILD_SHARED_LIBS is enabled" ON) + +if ((CJSON_OVERRIDE_BUILD_SHARED_LIBS AND CJSON_BUILD_SHARED_LIBS) OR ((NOT CJSON_OVERRIDE_BUILD_SHARED_LIBS) AND BUILD_SHARED_LIBS)) + set(CJSON_LIBRARY_TYPE SHARED) +else() + set(CJSON_LIBRARY_TYPE STATIC) +endif() + if (NOT BUILD_SHARED_AND_STATIC_LIBS) - add_library("${CJSON_LIB}" "${HEADERS}" "${SOURCES}") + add_library("${CJSON_LIB}" "${CJSON_LIBRARY_TYPE}" "${HEADERS}" "${SOURCES}") else() # See https://cmake.org/Wiki/CMake_FAQ#How_do_I_make_my_shared_and_static_libraries_have_the_same_root_name.2C_but_different_suffixes.3F add_library("${CJSON_LIB}" SHARED "${HEADERS}" "${SOURCES}") @@ -165,7 +174,7 @@ if(ENABLE_CJSON_UTILS) set(SOURCES_UTILS cJSON_Utils.c) if (NOT BUILD_SHARED_AND_STATIC_LIBS) - add_library("${CJSON_UTILS_LIB}" "${HEADERS_UTILS}" "${SOURCES_UTILS}") + add_library("${CJSON_UTILS_LIB}" "${CJSON_LIBRARY_TYPE}" "${HEADERS_UTILS}" "${SOURCES_UTILS}") target_link_libraries("${CJSON_UTILS_LIB}" "${CJSON_LIB}") else() add_library("${CJSON_UTILS_LIB}" SHARED "${HEADERS_UTILS}" "${SOURCES_UTILS}") diff --git a/README.md b/README.md index ddfea3f4..82245cba 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,7 @@ You can change the build process with a list of different options that you can p * `-DBUILD_SHARED_AND_STATIC_LIBS=On`: Build both shared and static libraries. (off by default) * `-DCMAKE_INSTALL_PREFIX=/usr`: Set a prefix for the installation. * `-DENABLE_LOCALES=On`: Enable the usage of localeconv method. ( on by default ) +* `-DCJSON_OVERRIDE_BUILD_SHARED_LIBS=On`: Enable overriding the value of `BUILD_SHARED_LIBS` with `-DCJSON_BUILD_SHARED_LIBS`. If you are packaging cJSON for a distribution of Linux, you would probably take these steps for example: ``` diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index e63c500d..f8b121c7 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,5 +1,5 @@ if(ENABLE_CJSON_TEST) - add_library(unity unity/src/unity.c) + add_library(unity "${CJSON_LIBRARY_TYPE}" unity/src/unity.c) # Disable -Werror for Unity if (FLAG_SUPPORTED_Werror) From 55c597c719fcadb7e4963c2b9f819e0e0e00a699 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Thu, 28 Dec 2017 12:45:28 +0100 Subject: [PATCH 10/27] add_item_to_array with boolean return value --- cJSON.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/cJSON.c b/cJSON.c index d08cb5b2..98f70814 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1844,14 +1844,13 @@ static cJSON *create_reference(const cJSON *item, const internal_hooks * const h return reference; } -/* Add item to array/object. */ -CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item) +static cJSON_bool add_item_to_array(cJSON *array, cJSON *item) { cJSON *child = NULL; if ((item == NULL) || (array == NULL)) { - return; + return false; } child = array->child; @@ -1870,6 +1869,14 @@ CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item) } suffix_object(child, item); } + + return true; +} + +/* Add item to array/object. */ +CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item) +{ + add_item_to_array(array, item); } CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) @@ -1913,7 +1920,7 @@ CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJ } item->string = (char*)cast_away_const(string); item->type |= cJSON_StringIsConst; - cJSON_AddItemToArray(object, item); + add_item_to_array(object, item); } CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) @@ -1923,7 +1930,7 @@ CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) return; } - cJSON_AddItemToArray(array, create_reference(item, &global_hooks)); + add_item_to_array(array, create_reference(item, &global_hooks)); } CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item) @@ -2018,7 +2025,7 @@ CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newit after_inserted = get_array_item(array, (size_t)which); if (after_inserted == NULL) { - cJSON_AddItemToArray(array, newitem); + add_item_to_array(array, newitem); return; } From de729a1635503af70b7b285dc167503c34b5be06 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Thu, 28 Dec 2017 17:19:03 +0100 Subject: [PATCH 11/27] Extract add_item_to_object function that returns a boolean --- cJSON.c | 61 +++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/cJSON.c b/cJSON.c index 98f70814..79ce826d 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1879,19 +1879,6 @@ CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item) add_item_to_array(array, item); } -CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) -{ - if (item == NULL) - { - return; - } - - /* call cJSON_AddItemToObjectCS for code reuse */ - cJSON_AddItemToObjectCS(object, (char*)cJSON_strdup((const unsigned char*)string, &global_hooks), item); - /* remove cJSON_StringIsConst flag */ - item->type &= ~cJSON_StringIsConst; -} - #if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) #pragma GCC diagnostic push #endif @@ -1907,20 +1894,48 @@ static void* cast_away_const(const void* string) #pragma GCC diagnostic pop #endif -/* Add an item to an object with constant string as key */ -CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) + +static cJSON_bool add_item_to_object(cJSON * const object, const char * const string, cJSON * const item, const internal_hooks * const hooks, const cJSON_bool constant_key) { - if ((item == NULL) || (string == NULL)) + if ((object == NULL) || (string == NULL) || (item == NULL)) { - return; + return false; } - if (!(item->type & cJSON_StringIsConst) && item->string) + + if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) + { + hooks->deallocate(item->string); + } + + if (constant_key) { - global_hooks.deallocate(item->string); + item->string = (char*)cast_away_const(string); + item->type |= cJSON_StringIsConst; } - item->string = (char*)cast_away_const(string); - item->type |= cJSON_StringIsConst; - add_item_to_array(object, item); + else + { + char *key = (char*)cJSON_strdup((const unsigned char*)string, hooks); + if (key == NULL) + { + return false; + } + + item->string = key; + item->type &= ~cJSON_StringIsConst; + } + + return add_item_to_array(object, item); +} + +CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) +{ + add_item_to_object(object, string, item, &global_hooks, false); +} + +/* Add an item to an object with constant string as key */ +CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) +{ + add_item_to_object(object, string, item, &global_hooks, true); } CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) @@ -1940,7 +1955,7 @@ CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *str return; } - cJSON_AddItemToObject(object, string, create_reference(item, &global_hooks)); + add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false); } CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item) From f966409b33ef07bcc6beb2416eeaee4181b622e1 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Thu, 28 Dec 2017 22:56:57 +0100 Subject: [PATCH 12/27] Add tests for cJSON_Add...ToObject macros --- tests/CMakeLists.txt | 1 + tests/cjson_add.c | 145 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 146 insertions(+) create mode 100644 tests/cjson_add.c diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f8b121c7..01496f87 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -55,6 +55,7 @@ if(ENABLE_CJSON_TEST) misc_tests parse_with_opts compare_tests + cjson_add ) option(ENABLE_VALGRIND OFF "Enable the valgrind memory checker for the tests.") diff --git a/tests/cjson_add.c b/tests/cjson_add.c new file mode 100644 index 00000000..601d6664 --- /dev/null +++ b/tests/cjson_add.c @@ -0,0 +1,145 @@ +/* + 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 +#include +#include + +#include "unity/examples/unity_config.h" +#include "unity/src/unity.h" +#include "common.h" + +static void cjson_add_null_should_add_null(void) +{ + cJSON *root = cJSON_CreateObject(); + cJSON *null = NULL; + + cJSON_AddNullToObject(root, "null"); + + TEST_ASSERT_NOT_NULL(null = cJSON_GetObjectItemCaseSensitive(root, "null")); + TEST_ASSERT_EQUAL_INT(null->type, cJSON_NULL); + + cJSON_Delete(root); +} + +static void cjson_add_true_should_add_true(void) +{ + cJSON *root = cJSON_CreateObject(); + cJSON *true_item = NULL; + + cJSON_AddTrueToObject(root, "true"); + + TEST_ASSERT_NOT_NULL(true_item = cJSON_GetObjectItemCaseSensitive(root, "true")); + TEST_ASSERT_EQUAL_INT(true_item->type, cJSON_True); + + cJSON_Delete(root); +} + +static void cjson_add_false_should_add_false(void) +{ + cJSON *root = cJSON_CreateObject(); + cJSON *false_item = NULL; + + cJSON_AddFalseToObject(root, "false"); + + TEST_ASSERT_NOT_NULL(false_item = cJSON_GetObjectItemCaseSensitive(root, "false")); + TEST_ASSERT_EQUAL_INT(false_item->type, cJSON_False); + + cJSON_Delete(root); +} + +static void cjson_add_bool_should_add_bool(void) +{ + cJSON *root = cJSON_CreateObject(); + cJSON *true_item = NULL; + cJSON *false_item = NULL; + + /* true */ + cJSON_AddBoolToObject(root, "true", true); + TEST_ASSERT_NOT_NULL(true_item = cJSON_GetObjectItemCaseSensitive(root, "true")); + TEST_ASSERT_EQUAL_INT(true_item->type, cJSON_True); + + /* false */ + cJSON_AddBoolToObject(root, "false", false); + TEST_ASSERT_NOT_NULL(false_item = cJSON_GetObjectItemCaseSensitive(root, "false")); + TEST_ASSERT_EQUAL_INT(false_item->type, cJSON_False); + + cJSON_Delete(root); +} + +static void cjson_add_number_should_add_number(void) +{ + cJSON *root = cJSON_CreateObject(); + cJSON *number = NULL; + + cJSON_AddNumberToObject(root, "number", 42); + + TEST_ASSERT_NOT_NULL(number = cJSON_GetObjectItemCaseSensitive(root, "number")); + + TEST_ASSERT_EQUAL_INT(number->type, cJSON_Number); + TEST_ASSERT_EQUAL_DOUBLE(number->valuedouble, 42); + TEST_ASSERT_EQUAL_INT(number->valueint, 42); + + cJSON_Delete(root); +} + +static void cjson_add_string_should_add_string(void) +{ + cJSON *root = cJSON_CreateObject(); + cJSON *string = NULL; + + cJSON_AddStringToObject(root, "string", "Hello World!"); + + TEST_ASSERT_NOT_NULL(string = cJSON_GetObjectItemCaseSensitive(root, "string")); + TEST_ASSERT_EQUAL_INT(string->type, cJSON_String); + TEST_ASSERT_EQUAL_STRING(string->valuestring, "Hello World!"); + + cJSON_Delete(root); +} + +static void cjson_add_raw_should_add_raw(void) +{ + cJSON *root = cJSON_CreateObject(); + cJSON *raw = NULL; + + cJSON_AddRawToObject(root, "raw", "{}"); + + TEST_ASSERT_NOT_NULL(raw = cJSON_GetObjectItemCaseSensitive(root, "raw")); + TEST_ASSERT_EQUAL_INT(raw->type, cJSON_Raw); + TEST_ASSERT_EQUAL_STRING(raw->valuestring, "{}"); + + cJSON_Delete(root); +} + +int main(void) +{ + UNITY_BEGIN(); + + RUN_TEST(cjson_add_null_should_add_null); + RUN_TEST(cjson_add_true_should_add_true); + RUN_TEST(cjson_add_false_should_add_false); + RUN_TEST(cjson_add_bool_should_add_bool); + RUN_TEST(cjson_add_number_should_add_number); + RUN_TEST(cjson_add_string_should_add_string); + + return UNITY_END(); +} From 5865faffa371b8334a28fb0d49c9d3ba8f43ced0 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Thu, 28 Dec 2017 23:56:39 +0100 Subject: [PATCH 13/27] Convert cJSON_Add...ToObject macros into functions These functions return the added object. Functions to add objects and arrays have also been added. --- cJSON.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++ cJSON.h | 16 ++++--- tests/cjson_add.c | 27 ++++++++++++ 3 files changed, 144 insertions(+), 7 deletions(-) diff --git a/cJSON.c b/cJSON.c index 79ce826d..e2272e66 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1958,6 +1958,114 @@ CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *str add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false); } +CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name) +{ + cJSON *null = cJSON_CreateNull(); + if (add_item_to_object(object, name, null, &global_hooks, false)) + { + return null; + } + + cJSON_Delete(null); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name) +{ + cJSON *true_item = cJSON_CreateTrue(); + if (add_item_to_object(object, name, true_item, &global_hooks, false)) + { + return true_item; + } + + cJSON_Delete(true_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name) +{ + cJSON *false_item = cJSON_CreateFalse(); + if (add_item_to_object(object, name, false_item, &global_hooks, false)) + { + return false_item; + } + + cJSON_Delete(false_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean) +{ + cJSON *bool_item = cJSON_CreateBool(boolean); + if (add_item_to_object(object, name, bool_item, &global_hooks, false)) + { + return bool_item; + } + + cJSON_Delete(bool_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number) +{ + cJSON *number_item = cJSON_CreateNumber(number); + if (add_item_to_object(object, name, number_item, &global_hooks, false)) + { + return number_item; + } + + cJSON_Delete(number_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string) +{ + cJSON *string_item = cJSON_CreateString(string); + if (add_item_to_object(object, name, string_item, &global_hooks, false)) + { + return string_item; + } + + cJSON_Delete(string_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw) +{ + cJSON *raw_item = cJSON_CreateRaw(raw); + if (add_item_to_object(object, name, raw_item, &global_hooks, false)) + { + return raw_item; + } + + cJSON_Delete(raw_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name) +{ + cJSON *object_item = cJSON_CreateObject(); + if (add_item_to_object(object, name, object_item, &global_hooks, false)) + { + return object_item; + } + + cJSON_Delete(object_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name) +{ + cJSON *array = cJSON_CreateArray(); + if (add_item_to_object(object, name, array, &global_hooks, false)) + { + return array; + } + + cJSON_Delete(array); + return NULL; +} + CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item) { if ((parent == NULL) || (item == NULL)) diff --git a/cJSON.h b/cJSON.h index ba0b2587..17345131 100644 --- a/cJSON.h +++ b/cJSON.h @@ -246,13 +246,15 @@ CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * cons CJSON_PUBLIC(void) cJSON_Minify(char *json); /* Macros for creating things quickly. */ -#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull()) -#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue()) -#define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse()) -#define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b)) -#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n)) -#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s)) -#define cJSON_AddRawToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateRaw(s)) +CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean); +CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number); +CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string); +CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw); +CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name); /* When assigning an integer value, it needs to be propagated to valuedouble too. */ #define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number)) diff --git a/tests/cjson_add.c b/tests/cjson_add.c index 601d6664..03d39ef4 100644 --- a/tests/cjson_add.c +++ b/tests/cjson_add.c @@ -130,6 +130,30 @@ static void cjson_add_raw_should_add_raw(void) cJSON_Delete(root); } +static void cJSON_add_object_should_add_object(void) +{ + cJSON *root = cJSON_CreateObject(); + cJSON *object = NULL; + + cJSON_AddObjectToObject(root, "object"); + TEST_ASSERT_NOT_NULL(object = cJSON_GetObjectItemCaseSensitive(root, "object")); + TEST_ASSERT_EQUAL_INT(object->type, cJSON_Object); + + cJSON_Delete(root); +} + +static void cJSON_add_array_should_add_array(void) +{ + cJSON *root = cJSON_CreateObject(); + cJSON *array = NULL; + + cJSON_AddArrayToObject(root, "array"); + TEST_ASSERT_NOT_NULL(array = cJSON_GetObjectItemCaseSensitive(root, "array")); + TEST_ASSERT_EQUAL_INT(array->type, cJSON_Array); + + cJSON_Delete(root); +} + int main(void) { UNITY_BEGIN(); @@ -140,6 +164,9 @@ int main(void) RUN_TEST(cjson_add_bool_should_add_bool); RUN_TEST(cjson_add_number_should_add_number); RUN_TEST(cjson_add_string_should_add_string); + RUN_TEST(cjson_add_raw_should_add_raw); + RUN_TEST(cJSON_add_object_should_add_object); + RUN_TEST(cJSON_add_array_should_add_array); return UNITY_END(); } From 77931e7fc0993c07cb2f4c1ade1aa23b9d01bb51 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Fri, 29 Dec 2017 23:26:53 +0100 Subject: [PATCH 14/27] cJSON_Add...ToObject: Add tests for failure conditions --- tests/cjson_add.c | 244 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 244 insertions(+) diff --git a/tests/cjson_add.c b/tests/cjson_add.c index 03d39ef4..01668a94 100644 --- a/tests/cjson_add.c +++ b/tests/cjson_add.c @@ -28,6 +28,17 @@ #include "unity/src/unity.h" #include "common.h" +static void *failing_malloc(size_t size) +{ + (void)size; + return NULL; +} + +static cJSON_Hooks failing_hooks = { + failing_malloc, + free +}; + static void cjson_add_null_should_add_null(void) { cJSON *root = cJSON_CreateObject(); @@ -41,6 +52,29 @@ static void cjson_add_null_should_add_null(void) cJSON_Delete(root); } +static void cjson_add_null_should_fail_with_null_pointers(void) +{ + cJSON *root = cJSON_CreateObject(); + + TEST_ASSERT_NULL(cJSON_AddNullToObject(NULL, "null")); + TEST_ASSERT_NULL(cJSON_AddNullToObject(root, NULL)); + + cJSON_Delete(root); +} + +static void cjson_add_null_should_fail_on_allocation_failure(void) +{ + cJSON *root = cJSON_CreateObject(); + + cJSON_InitHooks(&failing_hooks); + + TEST_ASSERT_NULL(cJSON_AddNullToObject(root, "null")); + + cJSON_InitHooks(NULL); + + cJSON_Delete(root); +} + static void cjson_add_true_should_add_true(void) { cJSON *root = cJSON_CreateObject(); @@ -54,6 +88,29 @@ static void cjson_add_true_should_add_true(void) cJSON_Delete(root); } +static void cjson_add_true_should_fail_with_null_pointers(void) +{ + cJSON *root = cJSON_CreateObject(); + + TEST_ASSERT_NULL(cJSON_AddTrueToObject(NULL, "true")); + TEST_ASSERT_NULL(cJSON_AddTrueToObject(root, NULL)); + + cJSON_Delete(root); +} + +static void cjson_add_true_should_fail_on_allocation_failure(void) +{ + cJSON *root = cJSON_CreateObject(); + + cJSON_InitHooks(&failing_hooks); + + TEST_ASSERT_NULL(cJSON_AddTrueToObject(root, "true")); + + cJSON_InitHooks(NULL); + + cJSON_Delete(root); +} + static void cjson_add_false_should_add_false(void) { cJSON *root = cJSON_CreateObject(); @@ -67,6 +124,29 @@ static void cjson_add_false_should_add_false(void) cJSON_Delete(root); } +static void cjson_add_false_should_fail_with_null_pointers(void) +{ + cJSON *root = cJSON_CreateObject(); + + TEST_ASSERT_NULL(cJSON_AddFalseToObject(NULL, "false")); + TEST_ASSERT_NULL(cJSON_AddFalseToObject(root, NULL)); + + cJSON_Delete(root); +} + +static void cjson_add_false_should_fail_on_allocation_failure(void) +{ + cJSON *root = cJSON_CreateObject(); + + cJSON_InitHooks(&failing_hooks); + + TEST_ASSERT_NULL(cJSON_AddFalseToObject(root, "false")); + + cJSON_InitHooks(NULL); + + cJSON_Delete(root); +} + static void cjson_add_bool_should_add_bool(void) { cJSON *root = cJSON_CreateObject(); @@ -86,6 +166,29 @@ static void cjson_add_bool_should_add_bool(void) cJSON_Delete(root); } +static void cjson_add_bool_should_fail_with_null_pointers(void) +{ + cJSON *root = cJSON_CreateObject(); + + TEST_ASSERT_NULL(cJSON_AddBoolToObject(NULL, "false", false)); + TEST_ASSERT_NULL(cJSON_AddBoolToObject(root, NULL, false)); + + cJSON_Delete(root); +} + +static void cjson_add_bool_should_fail_on_allocation_failure(void) +{ + cJSON *root = cJSON_CreateObject(); + + cJSON_InitHooks(&failing_hooks); + + TEST_ASSERT_NULL(cJSON_AddBoolToObject(root, "false", false)); + + cJSON_InitHooks(NULL); + + cJSON_Delete(root); +} + static void cjson_add_number_should_add_number(void) { cJSON *root = cJSON_CreateObject(); @@ -102,6 +205,29 @@ static void cjson_add_number_should_add_number(void) cJSON_Delete(root); } +static void cjson_add_number_should_fail_with_null_pointers(void) +{ + cJSON *root = cJSON_CreateObject(); + + TEST_ASSERT_NULL(cJSON_AddNumberToObject(NULL, "number", 42)); + TEST_ASSERT_NULL(cJSON_AddNumberToObject(root, NULL, 42)); + + cJSON_Delete(root); +} + +static void cjson_add_number_should_fail_on_allocation_failure(void) +{ + cJSON *root = cJSON_CreateObject(); + + cJSON_InitHooks(&failing_hooks); + + TEST_ASSERT_NULL(cJSON_AddNumberToObject(root, "number", 42)); + + cJSON_InitHooks(NULL); + + cJSON_Delete(root); +} + static void cjson_add_string_should_add_string(void) { cJSON *root = cJSON_CreateObject(); @@ -116,6 +242,29 @@ static void cjson_add_string_should_add_string(void) cJSON_Delete(root); } +static void cjson_add_string_should_fail_with_null_pointers(void) +{ + cJSON *root = cJSON_CreateObject(); + + TEST_ASSERT_NULL(cJSON_AddStringToObject(NULL, "string", "string")); + TEST_ASSERT_NULL(cJSON_AddStringToObject(root, NULL, "string")); + + cJSON_Delete(root); +} + +static void cjson_add_string_should_fail_on_allocation_failure(void) +{ + cJSON *root = cJSON_CreateObject(); + + cJSON_InitHooks(&failing_hooks); + + TEST_ASSERT_NULL(cJSON_AddStringToObject(root, "string", "string")); + + cJSON_InitHooks(NULL); + + cJSON_Delete(root); +} + static void cjson_add_raw_should_add_raw(void) { cJSON *root = cJSON_CreateObject(); @@ -130,6 +279,29 @@ static void cjson_add_raw_should_add_raw(void) cJSON_Delete(root); } +static void cjson_add_raw_should_fail_with_null_pointers(void) +{ + cJSON *root = cJSON_CreateObject(); + + TEST_ASSERT_NULL(cJSON_AddRawToObject(NULL, "raw", "{}")); + TEST_ASSERT_NULL(cJSON_AddRawToObject(root, NULL, "{}")); + + cJSON_Delete(root); +} + +static void cjson_add_raw_should_fail_on_allocation_failure(void) +{ + cJSON *root = cJSON_CreateObject(); + + cJSON_InitHooks(&failing_hooks); + + TEST_ASSERT_NULL(cJSON_AddRawToObject(root, "raw", "{}")); + + cJSON_InitHooks(NULL); + + cJSON_Delete(root); +} + static void cJSON_add_object_should_add_object(void) { cJSON *root = cJSON_CreateObject(); @@ -142,6 +314,29 @@ static void cJSON_add_object_should_add_object(void) cJSON_Delete(root); } +static void cjson_add_object_should_fail_with_null_pointers(void) +{ + cJSON *root = cJSON_CreateObject(); + + TEST_ASSERT_NULL(cJSON_AddObjectToObject(NULL, "object")); + TEST_ASSERT_NULL(cJSON_AddObjectToObject(root, NULL)); + + cJSON_Delete(root); +} + +static void cjson_add_object_should_fail_on_allocation_failure(void) +{ + cJSON *root = cJSON_CreateObject(); + + cJSON_InitHooks(&failing_hooks); + + TEST_ASSERT_NULL(cJSON_AddObjectToObject(root, "object")); + + cJSON_InitHooks(NULL); + + cJSON_Delete(root); +} + static void cJSON_add_array_should_add_array(void) { cJSON *root = cJSON_CreateObject(); @@ -154,19 +349,68 @@ static void cJSON_add_array_should_add_array(void) cJSON_Delete(root); } +static void cjson_add_array_should_fail_with_null_pointers(void) +{ + cJSON *root = cJSON_CreateObject(); + + TEST_ASSERT_NULL(cJSON_AddArrayToObject(NULL, "array")); + TEST_ASSERT_NULL(cJSON_AddArrayToObject(root, NULL)); + + cJSON_Delete(root); +} + +static void cjson_add_array_should_fail_on_allocation_failure(void) +{ + cJSON *root = cJSON_CreateObject(); + + cJSON_InitHooks(&failing_hooks); + + TEST_ASSERT_NULL(cJSON_AddArrayToObject(root, "array")); + + cJSON_InitHooks(NULL); + + cJSON_Delete(root); +} + int main(void) { UNITY_BEGIN(); RUN_TEST(cjson_add_null_should_add_null); + RUN_TEST(cjson_add_null_should_fail_with_null_pointers); + RUN_TEST(cjson_add_null_should_fail_on_allocation_failure); + RUN_TEST(cjson_add_true_should_add_true); + RUN_TEST(cjson_add_true_should_fail_with_null_pointers); + RUN_TEST(cjson_add_true_should_fail_on_allocation_failure); + RUN_TEST(cjson_add_false_should_add_false); + RUN_TEST(cjson_add_false_should_fail_with_null_pointers); + RUN_TEST(cjson_add_false_should_fail_on_allocation_failure); + RUN_TEST(cjson_add_bool_should_add_bool); + RUN_TEST(cjson_add_bool_should_fail_with_null_pointers); + RUN_TEST(cjson_add_bool_should_fail_on_allocation_failure); + RUN_TEST(cjson_add_number_should_add_number); + RUN_TEST(cjson_add_number_should_fail_with_null_pointers); + RUN_TEST(cjson_add_number_should_fail_on_allocation_failure); + RUN_TEST(cjson_add_string_should_add_string); + RUN_TEST(cjson_add_string_should_fail_with_null_pointers); + RUN_TEST(cjson_add_string_should_fail_on_allocation_failure); + RUN_TEST(cjson_add_raw_should_add_raw); + RUN_TEST(cjson_add_raw_should_fail_with_null_pointers); + RUN_TEST(cjson_add_raw_should_fail_on_allocation_failure); + RUN_TEST(cJSON_add_object_should_add_object); + RUN_TEST(cjson_add_object_should_fail_with_null_pointers); + RUN_TEST(cjson_add_object_should_fail_on_allocation_failure); + RUN_TEST(cJSON_add_array_should_add_array); + RUN_TEST(cjson_add_array_should_fail_with_null_pointers); + RUN_TEST(cjson_add_array_should_fail_on_allocation_failure); return UNITY_END(); } From 1b21bcd150145ac83351a159d82e4f712ac544b7 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Fri, 29 Dec 2017 23:29:09 +0100 Subject: [PATCH 15/27] cJSON_Add..ToObject: Add comment to header file --- cJSON.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cJSON.h b/cJSON.h index 17345131..c3d8c76b 100644 --- a/cJSON.h +++ b/cJSON.h @@ -245,7 +245,8 @@ CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * cons CJSON_PUBLIC(void) cJSON_Minify(char *json); -/* Macros for creating things quickly. */ +/* Helper functions for creating and adding items to an object at the same time. + * They return the added item or NULL on failure. */ CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name); CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name); CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name); From c31ee79ad1de522a8766bf02f9f10e568d7523e9 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Fri, 10 Nov 2017 21:36:05 +0100 Subject: [PATCH 16/27] README: new doc: Data Structure section --- README.md | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/README.md b/README.md index 82245cba..5a793922 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ Ultralightweight JSON parser in ANSI C. * [Welcome to cJSON](#welcome-to-cjson) * [Building](#building) * [Including cJSON](#including-cjson) + * [Data Structure](#data-structure) * [Some JSON](#some-json) * [Here's the structure](#heres-the-structure) * [Caveats](#caveats) @@ -123,6 +124,45 @@ If you installed it via CMake or the Makefile, you can include cJSON like this: #include ``` +### Data Structure + +cJSON represents JSON data using the `cJSON` struct data type: + +```c +/* The cJSON structure: */ +typedef struct cJSON +{ + struct cJSON *next; + struct cJSON *prev; + struct cJSON *child; + int type; + char *valuestring; + /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */ + int valueint; + double valuedouble; + char *string; +} cJSON; +``` + +An item of this type represents a JSON value. The type is stored in `type` as a bit-flag (**this means that you cannot find out the type by just comparing the value of `type`**). + +To check the type of an item, use the corresponding `cJSON_Is...` function. It does a `NULL` check followed by a type check and returns a boolean value if the item is of this type. + +The type can be one of the following: +* `cJSON_Invalid` (check with `cJSON_IsInvalid`): Represents an invalid item that doesn't contain any value. You automatically have this type if you set the item to all zero bytes. +* `cJSON_False` (check with `cJSON_IsFalse`): Represents a `false` boolean value. You can also check for boolean values in general with `cJSON_IsBool`. +* `cJSON_True` (check with `cJSON_IsTrue`): Represents a `true` boolean value. You can also check for boolean values in general with `cJSON_IsBool`. +* `cJSON_NULL` (check with `cJSON_IsNull`): Represents a `null` value. +* `cJSON_Number` (check with `cJSON_IsNumber`): Represents a number value. The value is stored as a double in `valuedouble` and also in `valueint`. If the number is outside of the range of an integer, `INT_MAX` or `INT_MIN` are used for `valueint`. +* `cJSON_String` (check with `cJSON_IsString`): Represents a string value. It is stored in the form of a zero terminated string in `valuestring`. +* `cJSON_Array` (check with `cJSON_IsArray`): Represent an array value. This is implemented by pointing `child` to a linked list of `cJSON` items that represent the values in the array. The elements are linked together using `next` and `prev`, where the first element has `prev == NULL` and the last element `next == NULL`. +* `cJSON_Object` (check with `cJSON_IsObject`): Represents an object value. Objects are stored same way as an array, the only difference is that the items in the object store their keys in `string`. +* `cJSON_Raw` (check with `cJSON_IsRaw`): Represents any kind of JSON that is stored as a zero terminated array of characters in `valuestring`. This can be used, for example, to avoid printing the same static JSON over and over again to save performance. cJSON will never create this type when parsing. Also note that cJSON doesn't check if it is valid JSON. + +Additionally there are the following two flags: +* `cJSON_IsReference`: Specifies that the item that `child` points to and/or `valuestring` is not owned by this item, it is only a reference. So `cJSON_Delete` and other functions will only deallocate this item, not it's children/valuestring. +* `cJSON_StringIsConst`: This means that `string` points to a constant string. This means that `cJSON_Delete` and other functions will not try to deallocate `string`. + ### Some JSON: ```json From b54b81251e62f9bebe4d981afcee22335ba44ddf Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Fri, 10 Nov 2017 22:08:57 +0100 Subject: [PATCH 17/27] README: new doc: Parsing --- README.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/README.md b/README.md index 5a793922..93af9dd1 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ Ultralightweight JSON parser in ANSI C. * [Building](#building) * [Including cJSON](#including-cjson) * [Data Structure](#data-structure) + * [Parsing JSON](#parsing-json) * [Some JSON](#some-json) * [Here's the structure](#heres-the-structure) * [Caveats](#caveats) @@ -163,6 +164,24 @@ Additionally there are the following two flags: * `cJSON_IsReference`: Specifies that the item that `child` points to and/or `valuestring` is not owned by this item, it is only a reference. So `cJSON_Delete` and other functions will only deallocate this item, not it's children/valuestring. * `cJSON_StringIsConst`: This means that `string` points to a constant string. This means that `cJSON_Delete` and other functions will not try to deallocate `string`. +### Parsing JSON + +Given some JSON in a zero terminated string, you can parse it with `cJSON_Parse`. + +```c +cJSON *json = cJSON_Parse(string); +``` + +It will parse the JSON and allocate a tree of `cJSON` items that represents it. Once it returns, you are fully responsible for deallocating it after use with `cJSON_Delete`. + +The allocator used by `cJSON_Parse` is `malloc` and `free` by default but can be changed (globally) with `cJSON_InitHooks`. + +If an error occurs a pointer to the position of the error in the input string can be accessed using `cJSON_GetErrorPtr`. Note though that this can produce race conditions in multithreading scenarios, in that case it is better to use `cJSON_ParseWithOpts` with `return_parse_end`. +By default, characters in the input string that follow the parsed JSON will not be considered as an error. + +If you want more options, use `cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated)`. +`return_parse_end` returns a pointer to the end of the JSON in the input string or the position that an error occurs at (thereby replacing `cJSON_GetErrorPtr` in a thread safe way). `require_null_terminated`, if set to `1` will make it an error if the input string contains data after the JSON. + ### Some JSON: ```json From 1285e6ac6889a62c06ffb8da74d8e9a5fc265b74 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 11 Nov 2017 13:07:05 +0100 Subject: [PATCH 18/27] README: new doc: Printing --- README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/README.md b/README.md index 93af9dd1..2994af47 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ Ultralightweight JSON parser in ANSI C. * [Including cJSON](#including-cjson) * [Data Structure](#data-structure) * [Parsing JSON](#parsing-json) + * [Printing JSON](#printing-json) * [Some JSON](#some-json) * [Here's the structure](#heres-the-structure) * [Caveats](#caveats) @@ -182,6 +183,22 @@ By default, characters in the input string that follow the parsed JSON will not If you want more options, use `cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated)`. `return_parse_end` returns a pointer to the end of the JSON in the input string or the position that an error occurs at (thereby replacing `cJSON_GetErrorPtr` in a thread safe way). `require_null_terminated`, if set to `1` will make it an error if the input string contains data after the JSON. +### Printing JSON + +Given a tree of `cJSON` items, you can print them as a string using `cJSON_Print`. + +```c +char *string = cJSON_Print(json); +``` + +It will allocate a string and print a JSON representation of the tree into it. Once it returns, you are fully responsible for deallocating it after use with your allocator. (usually `free`, depends on what has been set with `cJSON_InitHooks`). + +`cJSON_Print` will print with whitespace for formatting. If you want to print without formatting, use `cJSON_PrintUnformatted`. + +If you have a rough idea of how big your resulting string will be, you can use `cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt)`. `fmt` is a boolean to turn formatting with whitespace on and off. `prebuffer` specifies the first buffer size to use for printing. `cJSON_Print` currently uses 256 bytes for it's first buffer size. Once printing runs out of space, a new buffer is allocated and the old gets copied over before printing is continued. + +These dynamic buffer allocations can be completely avoided by using `cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format)`. It takes a buffer to a pointer to print to and it's length. If the length is reached, printing will fail and it returns `0`. In case of success, `1` is returned. Note that you should provide 5 bytes more than is actually needed, because cJSON is not 100% accurate in estimating if the provided memory is enough. + ### Some JSON: ```json From 61dd7f1e413a10f8a67b96da5c15f447aba5b763 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 15 Nov 2017 18:07:54 +0100 Subject: [PATCH 19/27] README: new doc: Working with the data structure --- README.md | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/README.md b/README.md index 2994af47..e904de16 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ Ultralightweight JSON parser in ANSI C. * [Building](#building) * [Including cJSON](#including-cjson) * [Data Structure](#data-structure) + * [Working with the data structure](#working-with-the-data-structure) * [Parsing JSON](#parsing-json) * [Printing JSON](#printing-json) * [Some JSON](#some-json) @@ -165,6 +166,58 @@ Additionally there are the following two flags: * `cJSON_IsReference`: Specifies that the item that `child` points to and/or `valuestring` is not owned by this item, it is only a reference. So `cJSON_Delete` and other functions will only deallocate this item, not it's children/valuestring. * `cJSON_StringIsConst`: This means that `string` points to a constant string. This means that `cJSON_Delete` and other functions will not try to deallocate `string`. +### Working with the data structure + +For every value type there is a `cJSON_Create...` function that can be used to create an item of that type. +All of these will allocate a `cJSON` struct that can later be deleted with `cJSON_Delete`. +Note that you have to delete them at some point, otherwise you will get a memory leak. +**Important**: If you have added an item to an array or an object already, you **mustn't** delete it with `cJSON_Delete`. Adding it to an array or object transfers its ownership so that when that array or object is deleted, it gets deleted as well. + +#### Basic types +* **null** is created with `cJSON_CreateNull` +* **booleans** are created with `cJSON_CreateTrue`, `cJSON_CreateFalse` or `cJSON_CreateBool` +* **numbers** are created with `cJSON_CreateNumber`. This will set both `valuedouble` and `valueint`. If the number is outside of the range of an integer, `INT_MAX` or `INT_MIN` are used for `valueint` +* **strings** are created with `cJSON_CreateString` (copies the string) or with `cJSON_CreateStringReference` (directly points to the string. This means that `valuestring` won't be deleted by `cJSON_Delete` and you are responsible for it's lifetime, useful for constants) + +#### Arrays + +You can create an empty array with `cJSON_CreateArray`. `cJSON_CreateArrayReference` can be used to create an array that doesn't "own" its content, so its content doesn't get deleted by `cJSON_Delete`. + +To add items to an array, use `cJSON_AddItemToArray` to append items to the end. +Using `cJSON_AddItemReferenceToArray` an element can be added as a reference to another item, array or string. This means that `cJSON_Delete` will not delete that items `child` or `valuestring` properties, so no double frees are occuring if they are already used elsewhere. +To insert items in the middle, use `cJSON_InsertItemInArray`. It will insert an item at the given 0 based index and shift all the existing items to the right. + +If you want to take an item out of an array at a given index and continue using it, use `cJSON_DetachItemFromArray`, it will return the detached item, so be sure to assign it to a pointer, otherwise you will have a memory leak. + +Deleting items is done with `cJSON_DeleteItemFromArray`. It works like `cJSON_DetachItemFromArray`, but deletes the detached item via `cJSON_Delete`. + +You can also replace an item in an array in place. Either with `cJSON_ReplaceItemInArray` using an index or with `cJSON_ReplaceItemViaPointer` given a pointer to an element. `cJSON_ReplaceItemViaPointer` will return `0` if it fails. What this does internally is to detach the old item, delete it and insert the new item in its place. + +To get the size of an array, use `cJSON_GetArraySize`. Use `cJSON_GetArrayItem` to get an element at a given index. + +Because an array is stored as a linked list, iterating it via index is inefficient (`O(n²)`), so you can iterate over an array using the `cJSON_ArrayForEach` macro in `O(n)` time complexity. + +#### Objects + +You can create an empty object with `cJSON_CreateObject`. `cJSON_CreateObjectReference` can be used to create an object that doesn't "own" its content, so its content doesn't get deleted by `cJSON_Delete`. + +To add items to an object, use `cJSON_AddItemToObject`. Use `cJSON_AddItemToObjectCS` to add an item to an object with a name that is a constant or reference (key of the item, `string` in the `cJSON` struct), so that it doesn't get freed by `cJSON_Delete`. +Using `cJSON_AddItemReferenceToArray` an element can be added as a reference to another object, array or string. This means that `cJSON_Delete` will not delete that items `child` or `valuestring` properties, so no double frees are occuring if they are already used elsewhere. + +If you want to take an item out of an object, use `cJSON_DetachItemFromObjectCaseSensitive`, it will return the detached item, so be sure to assign it to a pointer, otherwise you will have a memory leak. + +Deleting items is done with `cJSON_DeleteItemFromObjectCaseSensitive`. It works like `cJSON_DetachItemFromObjectCaseSensitive` followed by `cJSON_Delete`. + +You can also replace an item in an object in place. Either with `cJSON_ReplaceItemInObjectCaseSensitive` using a key or with `cJSON_ReplaceItemViaPointer` given a pointer to an element. `cJSON_ReplaceItemViaPointer` will return `0` if it fails. What this does internally is to detach the old item, delete it and insert the new item in its place. + +To get the size of an object, you can use `cJSON_GetArraySize`, this works because internally objects are stored as arrays. + +If you want to access an item in an object, use `cJSON_GetObjectItemCaseSensitive`. + +To iterate over an object, you can use the `cJSON_ArrayForEach` macro the same way as for arrays. + +cJSON also provides convenient helper functions for quickly creating a new item and adding it to an object, like `cJSON_AddNullToObject`. They return a pointer to the new item or `NULL` if they failed. + ### Parsing JSON Given some JSON in a zero terminated string, you can parse it with `cJSON_Parse`. From cdcd5537697467ff533e8b8b9248a019195af930 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 20 Dec 2017 02:42:30 +0100 Subject: [PATCH 20/27] README: new doc: Example --- README.md | 211 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 211 insertions(+) diff --git a/README.md b/README.md index e904de16..8435e1e1 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ Ultralightweight JSON parser in ANSI C. * [Working with the data structure](#working-with-the-data-structure) * [Parsing JSON](#parsing-json) * [Printing JSON](#printing-json) + * [Example](#example) * [Some JSON](#some-json) * [Here's the structure](#heres-the-structure) * [Caveats](#caveats) @@ -252,6 +253,216 @@ If you have a rough idea of how big your resulting string will be, you can use ` These dynamic buffer allocations can be completely avoided by using `cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format)`. It takes a buffer to a pointer to print to and it's length. If the length is reached, printing will fail and it returns `0`. In case of success, `1` is returned. Note that you should provide 5 bytes more than is actually needed, because cJSON is not 100% accurate in estimating if the provided memory is enough. +### Example +In this example we want to build and parse the following JSON: + +```json +{ + "name": "Awesome 4K", + "resolutions": [ + { + "width": 1280, + "height": 720 + }, + { + "width": 1920, + "height": 1080 + }, + { + "width": 3840, + "height": 2160 + } + ] +} +``` + +#### Printing +Let's build the above JSON and print it to a string: +```c +//create a monitor with a list of supported resolutions +char* create_monitor(void) +{ + const unsigned int resolution_numbers[3][2] = { + {1280, 720}, + {1920, 1080}, + {3840, 2160} + }; + char *string = NULL; + cJSON *name = NULL; + cJSON *resolutions = NULL; + cJSON *resolution = NULL; + cJSON *width = NULL; + cJSON *height = NULL; + size_t index = 0; + + cJSON *monitor = cJSON_CreateObject(); + if (monitor == NULL) + { + goto end; + } + + name = cJSON_CreateString("Awesome 4K"); + if (name == NULL) + { + goto end; + } + /* after creation was successful, immediately add it to the monitor, + * thereby transfering ownership of the pointer to it */ + cJSON_AddItemToObject(monitor, "name", name); + + resolutions = cJSON_CreateArray(); + if (resolutions == NULL) + { + goto end; + } + cJSON_AddItemToObject(monitor, "resolutions", resolutions); + + for (index = 0; index < (sizeof(resolution_numbers) / (2 * sizeof(int))); ++index) + { + resolution = cJSON_CreateObject(); + if (resolution == NULL) + { + goto end; + } + cJSON_AddItemToArray(resolutions, resolution); + + width = cJSON_CreateNumber(resolution_numbers[index][0]); + if (width == NULL) + { + goto end; + } + cJSON_AddItemToObject(resolution, "width", width); + + height = cJSON_CreateNumber(resolution_numbers[index][1]); + if (height == NULL) + { + goto end; + } + cJSON_AddItemToObject(resolution, "height", height); + } + + string = cJSON_Print(monitor); + if (string == NULL) + { + fprintf(stderr, "Failed to print monitor.\n"); + } + +end: + cJSON_Delete(monitor); + return string; +} +``` + +Alternatively we can use the `cJSON_Add...ToObject` helper functions to make our lifes a little easier: +```c +char *create_monitor_with_helpers(void) +{ + const unsigned int resolution_numbers[3][2] = { + {1280, 720}, + {1920, 1080}, + {3840, 2160} + }; + char *string = NULL; + cJSON *resolutions = NULL; + size_t index = 0; + + cJSON *monitor = cJSON_CreateObject(); + + if (cJSON_AddStringToObject(monitor, "name", "Awesome 4K") == NULL) + { + goto end; + } + + resolutions = cJSON_AddArrayToObject(monitor, "resolutions"); + if (resolutions == NULL) + { + goto end; + } + + for (index = 0; index < (sizeof(resolution_numbers) / (2 * sizeof(int))); ++index) + { + cJSON *resolution = cJSON_CreateObject(); + + if (cJSON_AddNumberToObject(resolution, "width", resolution_numbers[index][0]) == NULL) + { + goto end; + } + + if(cJSON_AddNumberToObject(resolution, "height", resolution_numbers[index][1]) == NULL) + { + goto end; + } + + cJSON_AddItemToArray(resolutions, resolution); + } + + string = cJSON_Print(monitor); + if (string == NULL) { + fprintf(stderr, "Failed to print monitor.\n"); + } + +end: + cJSON_Delete(monitor); + return string; +} +``` + +#### Parsing +In this example we will parse a JSON in the above format and check if the monitor supports a Full HD resolution while printing some diagnostic output: + +```c +/* return 1 if the monitor supports full hd, 0 otherwise */ +int supports_full_hd(const char * const monitor) +{ + const cJSON *resolution = NULL; + const cJSON *resolutions = NULL; + const cJSON *name = NULL; + int status = 0; + cJSON *monitor_json = cJSON_Parse(monitor); + if (monitor_json == NULL) + { + const char *error_ptr = cJSON_GetErrorPtr(); + if (error_ptr != NULL) + { + fprintf(stderr, "Error before: %s\n", error_ptr); + } + status = 0; + goto end; + } + + name = cJSON_GetObjectItemCaseSensitive(monitor_json, "name"); + if (cJSON_IsString(name) && (name->valuestring != NULL)) + { + printf("Checking monitor \"%s\"\n", name->valuestring); + } + + resolutions = cJSON_GetObjectItemCaseSensitive(monitor_json, "resolutions"); + cJSON_ArrayForEach(resolution, resolutions) + { + cJSON *width = cJSON_GetObjectItemCaseSensitive(resolution, "width"); + cJSON *height = cJSON_GetObjectItemCaseSensitive(resolution, "height"); + + if (!cJSON_IsNumber(width) || !cJSON_IsNumber(height)) + { + status = 0; + goto end; + } + + if ((width->valuedouble == 1920) && (height->valuedouble == 1080)) + { + status = 1; + goto end; + } + } + +end: + cJSON_Delete(monitor_json); + return status; +} +``` + +Note that there are no NULL checks except for the result of `cJSON_Parse` because `cJSON_GetObjectItemCaseSensitive` checks for `NULL` inputs already, so a `NULL` value is just propagated and `cJSON_IsNumber` and `cJSON_IsString` return `0` if the input is `NULL`. + ### Some JSON: ```json From 5605fa4ad5d1a162e14fcb5bbab8a90b1b4803ce Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 30 Dec 2017 01:54:27 +0100 Subject: [PATCH 21/27] README: new doc: Remove old explanation. --- README.md | 271 +----------------------------------------------------- 1 file changed, 3 insertions(+), 268 deletions(-) diff --git a/README.md b/README.md index 8435e1e1..aa345e7e 100644 --- a/README.md +++ b/README.md @@ -13,8 +13,6 @@ Ultralightweight JSON parser in ANSI C. * [Parsing JSON](#parsing-json) * [Printing JSON](#printing-json) * [Example](#example) - * [Some JSON](#some-json) - * [Here's the structure](#heres-the-structure) * [Caveats](#caveats) * [Enjoy cJSON!](#enjoy-cjson) @@ -463,270 +461,6 @@ end: Note that there are no NULL checks except for the result of `cJSON_Parse` because `cJSON_GetObjectItemCaseSensitive` checks for `NULL` inputs already, so a `NULL` value is just propagated and `cJSON_IsNumber` and `cJSON_IsString` return `0` if the input is `NULL`. -### Some JSON: - -```json -{ - "name": "Jack (\"Bee\") Nimble", - "format": { - "type": "rect", - "width": 1920, - "height": 1080, - "interlace": false, - "frame rate": 24 - } -} -``` - -Assume that you got this from a file, a webserver, or magic JSON elves, whatever, -you have a `char *` to it. Everything is a `cJSON` struct. -Get it parsed: - -```c -cJSON * root = cJSON_Parse(my_json_string); -``` - -This is an object. We're in C. We don't have objects. But we do have structs. -What's the framerate? - -```c -cJSON *format = cJSON_GetObjectItemCaseSensitive(root, "format"); -cJSON *framerate_item = cJSON_GetObjectItemCaseSensitive(format, "frame rate"); -double framerate = 0; -if (cJSON_IsNumber(framerate_item)) -{ - framerate = framerate_item->valuedouble; -} -``` - -Want to change the framerate? - -```c -cJSON *framerate_item = cJSON_GetObjectItemCaseSensitive(format, "frame rate"); -cJSON_SetNumberValue(framerate_item, 25); -``` - -Back to disk? - -```c -char *rendered = cJSON_Print(root); -``` - -Finished? Delete the root (this takes care of everything else). - -```c -cJSON_Delete(root); -``` - -That's AUTO mode. If you're going to use Auto mode, you really ought to check pointers -before you dereference them. If you want to see how you'd build this struct in code? - -```c -cJSON *root; -cJSON *fmt; -root = cJSON_CreateObject(); -cJSON_AddItemToObject(root, "name", cJSON_CreateString("Jack (\"Bee\") Nimble")); -cJSON_AddItemToObject(root, "format", fmt = cJSON_CreateObject()); -cJSON_AddStringToObject(fmt, "type", "rect"); -cJSON_AddNumberToObject(fmt, "width", 1920); -cJSON_AddNumberToObject(fmt, "height", 1080); -cJSON_AddFalseToObject (fmt, "interlace"); -cJSON_AddNumberToObject(fmt, "frame rate", 24); -``` - -Hopefully we can agree that's not a lot of code? There's no overhead, no unnecessary setup. -Look at `test.c` for a bunch of nice examples, mostly all ripped off the [json.org](http://json.org) site, and -a few from elsewhere. - -What about manual mode? First up you need some detail. -Let's cover how the `cJSON` objects represent the JSON data. -cJSON doesn't distinguish arrays from objects in handling; just type. -Each `cJSON` has, potentially, a child, siblings, value, a name. - -* The `root` object has: *Object* Type and a Child -* The Child has name "name", with value "Jack ("Bee") Nimble", and a sibling: -* Sibling has type *Object*, name "format", and a child. -* That child has type *String*, name "type", value "rect", and a sibling: -* Sibling has type *Number*, name "width", value 1920, and a sibling: -* Sibling has type *Number*, name "height", value 1080, and a sibling: -* Sibling has type *False*, name "interlace", and a sibling: -* Sibling has type *Number*, name "frame rate", value 24 - -### Here's the structure: - -```c -typedef struct cJSON { - struct cJSON *next,*prev; - struct cJSON *child; - - int type; - - char *valuestring; - int valueint; /* writing to valueint is DEPRECATED, please use cJSON_SetNumberValue instead */ - double valuedouble; - - char *string; -} cJSON; -``` - -By default all values are 0 unless set by virtue of being meaningful. - -`next`/`prev` is a doubly linked list of siblings. `next` takes you to your sibling, -`prev` takes you back from your sibling to you. -Only objects and arrays have a `child`, and it's the head of the doubly linked list. -A `child` entry will have `prev == 0`, but next potentially points on. The last sibling has `next == 0`. -The type expresses *Null*/*True*/*False*/*Number*/*String*/*Array*/*Object*, all of which are `#defined` in -`cJSON.h`. - -A *Number* has `valueint` and `valuedouble`. `valueint` is a relict of the past, so always use `valuedouble`. - -Any entry which is in the linked list which is the child of an object will have a `string` -which is the "name" of the entry. When I said "name" in the above example, that's `string`. -`string` is the JSON name for the 'variable name' if you will. - -Now you can trivially walk the lists, recursively, and parse as you please. -You can invoke `cJSON_Parse` to get cJSON to parse for you, and then you can take -the root object, and traverse the structure (which is, formally, an N-tree), -and tokenise as you please. If you wanted to build a callback style parser, this is how -you'd do it (just an example, since these things are very specific): - -```c -void parse_and_callback(cJSON *item, const char *prefix) -{ - while (item) - { - char *newprefix = malloc(strlen(prefix) + strlen(item->string) + 2); - sprintf(newprefix, "%s/%s", prefix, item->string); - int dorecurse = callback(newprefix, item->type, item); - if (item->child && dorecurse) - { - parse_and_callback(item->child, newprefix); - } - item = item->next; - free(newprefix); - } -} -``` - -The `prefix` process will build you a separated list, to simplify your callback handling. -The `dorecurse` flag would let the callback decide to handle sub-arrays on it's own, or -let you invoke it per-item. For the item above, your callback might look like this: - -```c -int callback(const char *name, int type, cJSON *item) -{ - if (!strcmp(name, "name")) - { - /* populate name */ - } - else if (!strcmp(name, "format/type")) - { - /* handle "rect" */ } - else if (!strcmp(name, "format/width")) - { - /* 800 */ - } - else if (!strcmp(name, "format/height")) - { - /* 600 */ - } - else if (!strcmp(name, "format/interlace")) - { - /* false */ - } - else if (!strcmp(name, "format/frame rate")) - { - /* 24 */ - } - - return 1; -} -``` - -Alternatively, you might like to parse iteratively. -You'd use: - -```c -void parse_object(cJSON *item) -{ - int i; - for (i = 0; i < cJSON_GetArraySize(item); i++) - { - cJSON *subitem = cJSON_GetArrayItem(item, i); - // handle subitem - } -} -``` - -Or, for PROPER manual mode: - -```c -void parse_object(cJSON *item) -{ - cJSON *subitem = item->child; - while (subitem) - { - // handle subitem - if (subitem->child) - { - parse_object(subitem->child); - } - - subitem = subitem->next; - } -} -``` - -Of course, this should look familiar, since this is just a stripped-down version -of the callback-parser. - -This should cover most uses you'll find for parsing. The rest should be possible -to infer.. and if in doubt, read the source! There's not a lot of it! ;) - -In terms of constructing JSON data, the example code above is the right way to do it. -You can, of course, hand your sub-objects to other functions to populate. -Also, if you find a use for it, you can manually build the objects. -For instance, suppose you wanted to build an array of objects? - -```c -cJSON *objects[24]; - -cJSON *Create_array_of_anything(cJSON **items, int num) -{ - int i; - cJSON *prev; - cJSON *root = cJSON_CreateArray(); - for (i = 0; i < 24; i++) - { - if (!i) - { - root->child = objects[i]; - } - else - { - prev->next = objects[i]; - objects[i]->prev = prev; - } - - prev = objects[i]; - } - - return root; -} -``` - -and simply: `Create_array_of_anything(objects, 24);` - -cJSON doesn't make any assumptions about what order you create things in. -You can attach the objects, as above, and later add children to each -of those objects. - -As soon as you call `cJSON_Print`, it renders the structure to text. - -The `test.c` code shows how to handle a bunch of typical cases. If you uncomment -the code, it'll load, parse and print a bunch of test files, also from [json.org](http://json.org), -which are more complex than I'd care to try and stash into a `const char array[]`. - ### Caveats #### Zero Character @@ -768,5 +502,6 @@ When cJSON was originally created, it didn't follow the JSON standard and didn't # Enjoy cJSON! -- Dave Gamble, Aug 2009 -- [cJSON contributors](CONTRIBUTORS.md) +- Dave Gamble (original author) +- Max Bruckner (current maintainer) +- and the other [cJSON contributors](CONTRIBUTORS.md) From e7d0c1dc375f74937844f01b0352a236856ccf69 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 30 Dec 2017 02:24:06 +0100 Subject: [PATCH 22/27] Tests: Test if the readme examples are working --- tests/CMakeLists.txt | 1 + tests/readme_examples.c | 258 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 259 insertions(+) create mode 100644 tests/readme_examples.c diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 01496f87..79672927 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -56,6 +56,7 @@ if(ENABLE_CJSON_TEST) parse_with_opts compare_tests cjson_add + readme_examples ) option(ENABLE_VALGRIND OFF "Enable the valgrind memory checker for the tests.") diff --git a/tests/readme_examples.c b/tests/readme_examples.c new file mode 100644 index 00000000..f3fa4438 --- /dev/null +++ b/tests/readme_examples.c @@ -0,0 +1,258 @@ +/* + 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 +#include +#include + +#include "unity/examples/unity_config.h" +#include "unity/src/unity.h" +#include "common.h" + +static const char *json = "{\n\ +\t\"name\":\t\"Awesome 4K\",\n\ +\t\"resolutions\":\t[{\n\ +\t\t\t\"width\":\t1280,\n\ +\t\t\t\"height\":\t720\n\ +\t\t}, {\n\ +\t\t\t\"width\":\t1920,\n\ +\t\t\t\"height\":\t1080\n\ +\t\t}, {\n\ +\t\t\t\"width\":\t3840,\n\ +\t\t\t\"height\":\t2160\n\ +\t\t}]\n\ +}"; + +static char* create_monitor(void) +{ + const unsigned int resolution_numbers[3][2] = { + {1280, 720}, + {1920, 1080}, + {3840, 2160} + }; + char *string = NULL; + cJSON *name = NULL; + cJSON *resolutions = NULL; + cJSON *resolution = NULL; + cJSON *width = NULL; + cJSON *height = NULL; + size_t index = 0; + + cJSON *monitor = cJSON_CreateObject(); + if (monitor == NULL) + { + goto end; + } + + name = cJSON_CreateString("Awesome 4K"); + if (name == NULL) + { + goto end; + } + /* after creation was successful, immediately add it to the monitor, + * thereby transfering ownership of the pointer to it */ + cJSON_AddItemToObject(monitor, "name", name); + + resolutions = cJSON_CreateArray(); + if (resolutions == NULL) + { + goto end; + } + cJSON_AddItemToObject(monitor, "resolutions", resolutions); + + for (index = 0; index < (sizeof(resolution_numbers) / (2 * sizeof(int))); ++index) + { + resolution = cJSON_CreateObject(); + if (resolution == NULL) + { + goto end; + } + cJSON_AddItemToArray(resolutions, resolution); + + width = cJSON_CreateNumber(resolution_numbers[index][0]); + if (width == NULL) + { + goto end; + } + cJSON_AddItemToObject(resolution, "width", width); + + height = cJSON_CreateNumber(resolution_numbers[index][1]); + if (height == NULL) + { + goto end; + } + cJSON_AddItemToObject(resolution, "height", height); + } + + string = cJSON_Print(monitor); + if (string == NULL) + { + fprintf(stderr, "Failed to print monitor.\n"); + } + +end: + cJSON_Delete(monitor); + return string; +} + +static char *create_monitor_with_helpers(void) +{ + const unsigned int resolution_numbers[3][2] = { + {1280, 720}, + {1920, 1080}, + {3840, 2160} + }; + char *string = NULL; + cJSON *resolutions = NULL; + size_t index = 0; + + cJSON *monitor = cJSON_CreateObject(); + + if (cJSON_AddStringToObject(monitor, "name", "Awesome 4K") == NULL) + { + goto end; + } + + resolutions = cJSON_AddArrayToObject(monitor, "resolutions"); + if (resolutions == NULL) + { + goto end; + } + + for (index = 0; index < (sizeof(resolution_numbers) / (2 * sizeof(int))); ++index) + { + cJSON *resolution = cJSON_CreateObject(); + + if (cJSON_AddNumberToObject(resolution, "width", resolution_numbers[index][0]) == NULL) + { + goto end; + } + + if(cJSON_AddNumberToObject(resolution, "height", resolution_numbers[index][1]) == NULL) + { + goto end; + } + + cJSON_AddItemToArray(resolutions, resolution); + } + + string = cJSON_Print(monitor); + if (string == NULL) { + fprintf(stderr, "Failed to print monitor.\n"); + } + +end: + cJSON_Delete(monitor); + return string; +} + +/* return 1 if the monitor supports full hd, 0 otherwise */ +static int supports_full_hd(const char * const monitor) +{ + const cJSON *resolution = NULL; + const cJSON *resolutions = NULL; + const cJSON *name = NULL; + int status = 0; + cJSON *monitor_json = cJSON_Parse(monitor); + if (monitor_json == NULL) + { + const char *error_ptr = cJSON_GetErrorPtr(); + if (error_ptr != NULL) + { + fprintf(stderr, "Error before: %s\n", error_ptr); + } + status = 0; + goto end; + } + + name = cJSON_GetObjectItemCaseSensitive(monitor_json, "name"); + if (cJSON_IsString(name) && (name->valuestring != NULL)) + { + printf("Checking monitor \"%s\"\n", name->valuestring); + } + + resolutions = cJSON_GetObjectItemCaseSensitive(monitor_json, "resolutions"); + cJSON_ArrayForEach(resolution, resolutions) + { + cJSON *width = cJSON_GetObjectItemCaseSensitive(resolution, "width"); + cJSON *height = cJSON_GetObjectItemCaseSensitive(resolution, "height"); + + if (!cJSON_IsNumber(width) || !cJSON_IsNumber(height)) + { + status = 0; + goto end; + } + + if ((width->valuedouble == 1920) && (height->valuedouble == 1080)) + { + status = 1; + goto end; + } + } + +end: + cJSON_Delete(monitor_json); + return status; +} + +static void create_monitor_should_create_a_monitor(void) +{ + char *monitor = create_monitor(); + + TEST_ASSERT_EQUAL_STRING(monitor, json); + + free(monitor); +} + +static void create_monitor_with_helpers_should_create_a_monitor(void) +{ + char *monitor = create_monitor_with_helpers(); + + TEST_ASSERT_EQUAL_STRING(json, monitor); + + free(monitor); +} + +static void supports_full_hd_should_check_for_full_hd_support(void) +{ + static const char *monitor_without_hd = "{\n\ +\t\t\"name\": \"lame monitor\",\n\ +\t\t\"resolutions\":\t[{\n\ +\t\t\t\"width\":\t640,\n\ +\t\t\t\"height\":\t480\n\ +\t\t}]\n\ +}"; + + TEST_ASSERT(supports_full_hd(json)); + TEST_ASSERT_FALSE(supports_full_hd(monitor_without_hd)); +} + +int main(void) +{ + UNITY_BEGIN(); + + RUN_TEST(create_monitor_should_create_a_monitor); + RUN_TEST(create_monitor_with_helpers_should_create_a_monitor); + RUN_TEST(supports_full_hd_should_check_for_full_hd_support); + + return UNITY_END(); +} From f26d8f3175c2b41ba9568e9ec1c2425b401e8d0f Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 30 Dec 2017 02:32:43 +0100 Subject: [PATCH 23/27] README: Add small note about CMake on Windows. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index aa345e7e..2969ba3d 100644 --- a/README.md +++ b/README.md @@ -108,6 +108,8 @@ make make DESTDIR=$pkgdir install ``` +On Windows CMake is usually used to create a Visual Studio solution file by running it inside the Developer Command Prompt for Visual Studio, for exact steps follow the official documentation from CMake and Microsoft and use the online search engine of your choice. The descriptions of the the options above still generally apply, although not all of them work on Windows. + #### Makefile If you don't have CMake available, but still have GNU make. You can use the makefile to build cJSON: From d7e711c0de28e6ea316531a355ae2150e9a00c65 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 30 Dec 2017 21:47:28 +0100 Subject: [PATCH 24/27] README: new doc: Add links for 4th level sections --- README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/README.md b/README.md index 2969ba3d..e8903332 100644 --- a/README.md +++ b/README.md @@ -7,13 +7,28 @@ Ultralightweight JSON parser in ANSI C. * [Usage](#usage) * [Welcome to cJSON](#welcome-to-cjson) * [Building](#building) + * [Copying the source](#copying-the-source) + * [CMake](#cmake) + * [Makefile](#makefile) * [Including cJSON](#including-cjson) * [Data Structure](#data-structure) * [Working with the data structure](#working-with-the-data-structure) + * [Basic types](#basic-types) + * [Arrays](#arrays) + * [Objects](#objects) * [Parsing JSON](#parsing-json) * [Printing JSON](#printing-json) * [Example](#example) + * [Printing](#printing) + * [Parsing](#parsing) * [Caveats](#caveats) + * [Zero Character](#zero-character) + * [Character Encoding](#character-encoding) + * [C Standard](#c-standard) + * [Floating Point Numbers](#floating-point-numbers) + * [Deep Nesting Of Arrays And Objects](#deep-nesting-of-arrays-and-objects) + * [Thread Safety](#thread-safety) + * [Case Sensitivity](#case-sensitivity) * [Enjoy cJSON!](#enjoy-cjson) ## License From 1e953636389224bf3be77f7dd1671a751c76cb4d Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 31 Dec 2017 01:24:35 +0100 Subject: [PATCH 25/27] README: Caveats: Duplicate object members --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index e8903332..01971360 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ Ultralightweight JSON parser in ANSI C. * [Deep Nesting Of Arrays And Objects](#deep-nesting-of-arrays-and-objects) * [Thread Safety](#thread-safety) * [Case Sensitivity](#case-sensitivity) + * [Duplicate Object Members](#duplicate-object-members) * [Enjoy cJSON!](#enjoy-cjson) ## License @@ -517,6 +518,10 @@ However it is thread safe under the following conditions: When cJSON was originally created, it didn't follow the JSON standard and didn't make a distinction between uppercase and lowercase letters. If you want the correct, standard compliant, behavior, you need to use the `CaseSensitive` functions where available. +#### Duplicate Object Members + +cJSON supports parsing and printing JSON that contains objects that have multiple members with the same name. `cJSON_GetObjectItemCaseSensitive` however will always only return the first one. + # Enjoy cJSON! - Dave Gamble (original author) From 17b83e76e9c6f446bf15a6c1187bd1ab9157916c Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 31 Dec 2017 02:01:53 +0100 Subject: [PATCH 26/27] Update Changelog for version 1.7 --- CHANGELOG.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a7856838..3d1a2dbf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,26 @@ +1.7.0 +===== +Features: +--------- +* Large rewrite of the documentation, see #215 +* Added the `cJSON_GetStringValue` function +* Added the `cJSON_CreateStringReference` function +* Added the `cJSON_CreateArrayReference` function +* Added the `cJSON_CreateObjectReference` function +* The `cJSON_Add...ToObject` macros are now functions that return a pointer to the added item, see #226 + +Fixes: +------ +* Fix a problem with `GNUInstallDirs` in the CMakeLists.txt, thanks @yangfl, see #210 +* Fix linking the tests when building as static library, see #213 +* New overrides for the CMake option `BUILD_SHARED_LIBS`, see #207 + +Other Changes: +-------------- +* Readme: Explain how to include cJSON, see #211 +* Removed some trailing spaces in the code, thanks @yangfl, see#212 +* Updated [Unity](https://github.com/ThrowTheSwitch/Unity) and [json-patch-tests](https://github.com/json-patch/json-patch-tests) + 1.6.0 ===== Features: From 13a2d337a8a308b738728008ec12cda876bd1c2b Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 31 Dec 2017 02:03:40 +0100 Subject: [PATCH 27/27] Update version number to 1.7 --- CMakeLists.txt | 2 +- Makefile | 2 +- cJSON.c | 2 +- cJSON.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 97f9cfe6..8b3c33cb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ project(cJSON C) include(GNUInstallDirs) set(PROJECT_VERSION_MAJOR 1) -set(PROJECT_VERSION_MINOR 6) +set(PROJECT_VERSION_MINOR 7) set(PROJECT_VERSION_PATCH 0) set(CJSON_VERSION_SO 1) set(CJSON_UTILS_VERSION_SO 1) diff --git a/Makefile b/Makefile index 2d472078..75c12c9d 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ CJSON_TEST_SRC = cJSON.c test.c LDLIBS = -lm -LIBVERSION = 1.6.0 +LIBVERSION = 1.7.0 CJSON_SOVERSION = 1 UTILS_SOVERSION = 1 diff --git a/cJSON.c b/cJSON.c index e2272e66..2f747ea9 100644 --- a/cJSON.c +++ b/cJSON.c @@ -82,7 +82,7 @@ CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item) { } /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ -#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 6) || (CJSON_VERSION_PATCH != 0) +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 0) #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. #endif diff --git a/cJSON.h b/cJSON.h index c3d8c76b..770e1ef6 100644 --- a/cJSON.h +++ b/cJSON.h @@ -30,7 +30,7 @@ extern "C" /* project version */ #define CJSON_VERSION_MAJOR 1 -#define CJSON_VERSION_MINOR 6 +#define CJSON_VERSION_MINOR 7 #define CJSON_VERSION_PATCH 0 #include