浏览代码

Merge branch 'develop' prepare v1.5.0

Max Bruckner 8 年之前
父节点
当前提交
2d6a2e0133
共有 77 个文件被更改,包括 7215 次插入2019 次删除
  1. 5 13
      CMakeLists.txt
  2. 3 0
      CONTRIBUTORS.md
  3. 1 1
      LICENSE
  4. 0 5
      Makefile
  5. 14 4
      README.md
  6. 308 206
      cJSON.c
  7. 26 7
      cJSON.h
  8. 739 235
      cJSON_Utils.c
  9. 38 8
      cJSON_Utils.h
  10. 0 0
      library_config/cJSONConfig.cmake.in
  11. 0 0
      library_config/cJSONConfigVersion.cmake.in
  12. 0 0
      library_config/libcjson.pc.in
  13. 0 0
      library_config/libcjson_utils.pc.in
  14. 1 1
      test.c
  15. 0 206
      test_utils.c
  16. 27 0
      tests/CMakeLists.txt
  17. 192 0
      tests/compare_tests.c
  18. 10 0
      tests/json-patch-tests/.editorconfig
  19. 4 0
      tests/json-patch-tests/.gitignore
  20. 2 0
      tests/json-patch-tests/.npmignore
  21. 75 0
      tests/json-patch-tests/README.md
  22. 84 0
      tests/json-patch-tests/cjson-utils-tests.json
  23. 15 0
      tests/json-patch-tests/package.json
  24. 233 0
      tests/json-patch-tests/spec_tests.json
  25. 429 0
      tests/json-patch-tests/tests.json
  26. 243 0
      tests/json_patch_tests.c
  27. 125 0
      tests/misc_tests.c
  28. 205 0
      tests/old_utils_tests.c
  29. 12 4
      tests/parse_array.c
  30. 5 1
      tests/parse_number.c
  31. 12 4
      tests/parse_object.c
  32. 16 6
      tests/parse_string.c
  33. 6 2
      tests/parse_value.c
  34. 82 0
      tests/parse_with_opts.c
  35. 14 6
      tests/print_array.c
  36. 10 19
      tests/print_number.c
  37. 15 6
      tests/print_object.c
  38. 3 2
      tests/print_string.c
  39. 9 4
      tests/print_value.c
  40. 3 1
      tests/unity/.travis.yml
  41. 17 8
      tests/unity/README.md
  42. 67 64
      tests/unity/auto/colour_prompt.rb
  43. 20 20
      tests/unity/auto/colour_reporter.rb
  44. 141 144
      tests/unity/auto/generate_module.rb
  45. 234 232
      tests/unity/auto/generate_test_runner.rb
  46. 0 224
      tests/unity/auto/parseOutput.rb
  47. 220 0
      tests/unity/auto/parse_output.rb
  48. 108 120
      tests/unity/auto/stylize_as_junit.rb
  49. 11 9
      tests/unity/auto/test_file_filter.rb
  50. 1 3
      tests/unity/auto/type_sanitizer.rb
  51. 45 57
      tests/unity/auto/unity_test_summary.rb
  52. 207 0
      tests/unity/docs/ThrowTheSwitchCodingStandard.md
  53. 二进制
      tests/unity/docs/UnityAssertionsCheatSheetSuitableforPrintingandPossiblyFraming.pdf
  54. 716 0
      tests/unity/docs/UnityAssertionsReference.md
  55. 二进制
      tests/unity/docs/UnityAssertionsReference.pdf
  56. 398 0
      tests/unity/docs/UnityConfigurationGuide.md
  57. 二进制
      tests/unity/docs/UnityConfigurationGuide.pdf
  58. 191 0
      tests/unity/docs/UnityGettingStartedGuide.md
  59. 二进制
      tests/unity/docs/UnityGettingStartedGuide.pdf
  60. 242 0
      tests/unity/docs/UnityHelperScriptsGuide.md
  61. 二进制
      tests/unity/docs/UnityHelperScriptsGuide.pdf
  62. 15 15
      tests/unity/examples/example_3/rakefile.rb
  63. 93 102
      tests/unity/examples/example_3/rakefile_helper.rb
  64. 12 12
      tests/unity/extras/fixture/rakefile.rb
  65. 87 88
      tests/unity/extras/fixture/rakefile_helper.rb
  66. 1 0
      tests/unity/extras/fixture/src/unity_fixture_malloc_overrides.h
  67. 1 1
      tests/unity/release/version.info
  68. 125 29
      tests/unity/src/unity.c
  69. 48 0
      tests/unity/src/unity.h
  70. 81 31
      tests/unity/src/unity_internals.h
  71. 58 0
      tests/unity/test/.rubocop.yml
  72. 55 2
      tests/unity/test/rakefile
  73. 108 105
      tests/unity/test/rakefile_helper.rb
  74. 1 3
      tests/unity/test/targets/clang_strict.yml
  75. 2 0
      tests/unity/test/testdata/testRunnerGeneratorSmall.c
  76. 5 5
      tests/unity/test/tests/test_generate_test_runner.rb
  77. 939 4
      tests/unity/test/tests/testunity.c

+ 5 - 13
CMakeLists.txt

@@ -103,7 +103,7 @@ if (NOT WIN32)
     target_link_libraries("${CJSON_LIB}" m)
 endif()
 
-configure_file("${CMAKE_CURRENT_SOURCE_DIR}/libcjson.pc.in"
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/library_config/libcjson.pc.in"
     "${CMAKE_CURRENT_BINARY_DIR}/libcjson.pc" @ONLY)
 
 install(FILES cJSON.h DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/cjson")
@@ -130,7 +130,7 @@ if(ENABLE_CJSON_UTILS)
     add_library("${CJSON_UTILS_LIB}" "${HEADERS_UTILS}" "${SOURCES_UTILS}")
     target_link_libraries("${CJSON_UTILS_LIB}" "${CJSON_LIB}")
 
-    configure_file("${CMAKE_CURRENT_SOURCE_DIR}/libcjson_utils.pc.in"
+    configure_file("${CMAKE_CURRENT_SOURCE_DIR}/library_config/libcjson_utils.pc.in"
         "${CMAKE_CURRENT_BINARY_DIR}/libcjson_utils.pc" @ONLY)
 
     install(TARGETS "${CJSON_UTILS_LIB}" DESTINATION "${CMAKE_INSTALL_LIBDIR}" EXPORT "${CJSON_UTILS_LIB}")
@@ -149,10 +149,10 @@ endif()
 
 # create the other package config files
 configure_file(
-    cJSONConfig.cmake.in
+    "${CMAKE_CURRENT_SOURCE_DIR}/library_config/cJSONConfig.cmake.in"
     ${PROJECT_BINARY_DIR}/cJSONConfig.cmake @ONLY)
 configure_file(
-    cJSONConfigVersion.cmake.in
+    "${CMAKE_CURRENT_SOURCE_DIR}/library_config/cJSONConfigVersion.cmake.in"
     ${PROJECT_BINARY_DIR}/cJSONConfigVersion.cmake @ONLY)
 
 # Install package config files
@@ -179,18 +179,10 @@ if(ENABLE_CJSON_TEST)
         endif()
     endif()
 
-    if(ENABLE_CJSON_UTILS)
-        set(TEST_CJSON_UTILS cJSON_test_utils)
-        add_executable("${TEST_CJSON_UTILS}" test_utils.c)
-        target_link_libraries("${TEST_CJSON_UTILS}" "${CJSON_UTILS_LIB}")
-
-        add_test(NAME ${TEST_CJSON_UTILS} COMMAND "${CMAKE_CURRENT_BINARY_DIR}/${TEST_CJSON_UTILS}")
-    endif()
-
     #"check" target that automatically builds everything and runs the tests
     add_custom_target(check
         COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure
-        DEPENDS ${TEST_CJSON} ${TEST_CJSON_UTILS})
+        DEPENDS ${TEST_CJSON})
 endif()
 
 add_subdirectory(tests)

+ 3 - 0
CONTRIBUTORS.md

@@ -6,6 +6,7 @@ Contributors
 * [Anton Sergeev](https://github.com/anton-sergeev)
 * [Christian Schulze](https://github.com/ChristianSch)
 * [Dave Gamble](https://github.com/DaveGamble)
+* [Debora Grosse](https://github.com/DeboraG)
 * [dieyushi](https://github.com/dieyushi)
 * [Dongwen Huang (黄东文)](https://github.com/DongwenHuang)
 * Eswar Yaganti
@@ -22,7 +23,9 @@ Contributors
 * [Max Bruckner](https://github.com/FSMaxB)
 * Mike Pontillo
 * [Mike Jerris](https://github.com/mjerris)
+* [Mike Robinson](https://github.com/mhrobinson)
 * Paulo Antonio Alvarez
+* [Pawel Winogrodzki](https://github.com/PawelWMS)
 * [Rafael Leal Dias](https://github.com/rafaeldias)
 * [Rod Vagg](https://github.com/rvagg)
 * [Roland Meertens](https://github.com/rmeertens)

+ 1 - 1
LICENSE

@@ -1,4 +1,4 @@
-  Copyright (c) 2009 Dave Gamble
+  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

+ 0 - 5
Makefile

@@ -3,10 +3,8 @@ UTILS_OBJ = cJSON_Utils.o
 CJSON_LIBNAME = libcjson
 UTILS_LIBNAME = libcjson_utils
 CJSON_TEST = cJSON_test
-UTILS_TEST = cJSON_test_utils
 
 CJSON_TEST_SRC = cJSON.c test.c
-UTILS_TEST_SRC = cJSON.c cJSON_Utils.c test_utils.c
 
 LDLIBS = -lm
 
@@ -71,9 +69,6 @@ test: tests
 #cJSON
 $(CJSON_TEST): $(CJSON_TEST_SRC) cJSON.h
 	$(CC) $(R_CFLAGS) $(CJSON_TEST_SRC)  -o $@ $(LDLIBS) -I.
-#cJSON_Utils
-$(UTILS_TEST): $(UTILS_TEST_SRC) cJSON.h cJSON_Utils.h
-	$(CC) $(R_CFLAGS) $(UTILS_TEST_SRC) -o $@ $(LDLIBS) -I.
 
 #static libraries
 #cJSON

+ 14 - 4
README.md

@@ -14,7 +14,9 @@ Ultralightweight JSON parser in ANSI C.
 
 ## License
 
->  Copyright (c) 2009-2016 Dave Gamble
+MIT License
+
+>  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
@@ -136,8 +138,8 @@ 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_GetObjectItem(root, "format");
-cJSON *framerate_item = cJSON_GetObjectItem(format, "frame rate");
+cJSON *format = cJSON_GetObjectItemCaseSensitive(root, "format");
+cJSON *framerate_item = cJSON_GetObjectItemCaseSensitive(format, "frame rate");
 double framerate = 0;
 if (cJSON_IsNumber(framerate_item))
 {
@@ -148,7 +150,7 @@ if (cJSON_IsNumber(framerate_item))
 Want to change the framerate?
 
 ```c
-cJSON *framerate_item = cJSON_GetObjectItem(format, "frame rate");
+cJSON *framerate_item = cJSON_GetObjectItemCaseSensitive(format, "frame rate");
 cJSON_SetNumberValue(framerate_item, 25);
 ```
 
@@ -395,6 +397,10 @@ cJSON does not officially support any `double` implementations other than IEE754
 
 The maximum length of a floating point literal that cJSON supports is currently 63 characters.
 
+#### Deep Nesting Of Arrays And Objects
+
+cJSON doesn't support arrays and objects that are nested too deeply because this would result in a stack overflow. To prevent this cJSON limits the depth to `CJSON_NESTING_LIMIT` which is 1000 by default but can be changed at compile time.
+
 #### Thread Safety
 
 In general cJSON is **not thread safe**.
@@ -404,6 +410,10 @@ However it is thread safe under the following conditions:
 * `cJSON_InitHooks` is only ever called before using cJSON in any threads.
 * `setlocale` is never called before all calls to cJSON functions have returned.
 
+#### Case Sensitivity
+
+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.
+
 # Enjoy cJSON!
 
 - Dave Gamble, Aug 2009

文件差异内容过多而无法显示
+ 308 - 206
cJSON.c


+ 26 - 7
cJSON.h

@@ -1,5 +1,5 @@
 /*
-  Copyright (c) 2009 Dave Gamble
+  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
@@ -123,18 +123,24 @@ then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJ
 #endif
 #endif
 
+/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them.
+ * This is to prevent stack overflows. */
+#ifndef CJSON_NESTING_LIMIT
+#define CJSON_NESTING_LIMIT 1000
+#endif
+
 /* returns the version of cJSON as a string */
 CJSON_PUBLIC(const char*) cJSON_Version(void);
 
 /* Supply malloc, realloc and free functions to cJSON */
 CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks);
 
-
-/* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */
+/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */
+/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */
 CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
-/* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */
+/* Render a cJSON entity to text for transfer/storage. */
 CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
-/* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */
+/* Render a cJSON entity to text for transfer/storage without any formatting. */
 CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);
 /* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
 CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt);
@@ -147,10 +153,10 @@ CJSON_PUBLIC(void) cJSON_Delete(cJSON *c);
 /* Returns the number of items in an array (or object). */
 CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
 /* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */
-CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int item);
+CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
 /* Get item "string" from object. Case insensitive. */
 CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);
-CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON *object, const char *string);
+CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string);
 CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string);
 /* 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);
@@ -197,21 +203,30 @@ CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
 CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
 
 /* Remove/Detatch items from Arrays/Objects. */
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item);
 CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
 CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);
 CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string);
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string);
 CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string);
+CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);
 
 /* Update array items. */
 CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */
+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement);
 CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
 CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
+CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem);
 
 /* Duplicate a cJSON item */
 CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse);
 /* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
 need to be released. With recurse!=0, it will duplicate any children connected to the item.
 The item->next and ->prev pointers are always zero on return from Duplicate. */
+/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal.
+ * case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */
+CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive);
+
 
 /* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
 /* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error. If not, then cJSON_GetErrorPtr() does the job. */
@@ -237,6 +252,10 @@ CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
 /* Macro for iterating over an array */
 #define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next)
 
+/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */
+CJSON_PUBLIC(void *) cJSON_malloc(size_t size);
+CJSON_PUBLIC(void) cJSON_free(void *object);
+
 #ifdef __cplusplus
 }
 #endif

文件差异内容过多而无法显示
+ 739 - 235
cJSON_Utils.c


+ 38 - 8
cJSON_Utils.h

@@ -1,14 +1,40 @@
+/*
+  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 "cJSON.h"
 
 /* Implement RFC6901 (https://tools.ietf.org/html/rfc6901) JSON Pointer spec. */
-CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointer(cJSON *object, const char *pointer);
+CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointer(cJSON * const object, const char *pointer);
+CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointerCaseSensitive(cJSON * const object, const char *pointer);
 
 /* Implement RFC6902 (https://tools.ietf.org/html/rfc6902) JSON Patch spec. */
-CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatches(cJSON *from, cJSON *to);
+/* NOTE: This modifies objects in 'from' and 'to' by sorting the elements by their key */
+CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatches(cJSON * const from, cJSON * const to);
+CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatchesCaseSensitive(cJSON * const from, cJSON * const to);
 /* Utility for generating patch array entries. */
-CJSON_PUBLIC(void) cJSONUtils_AddPatchToArray(cJSON *array, const char *op, const char *path, cJSON *val);
+CJSON_PUBLIC(void) cJSONUtils_AddPatchToArray(cJSON * const array, const char * const operation, const char * const path, const cJSON * const value);
 /* Returns 0 for success. */
-CJSON_PUBLIC(int) cJSONUtils_ApplyPatches(cJSON *object, cJSON *patches);
+CJSON_PUBLIC(int) cJSONUtils_ApplyPatches(cJSON * const object, const cJSON * const patches);
+CJSON_PUBLIC(int) cJSONUtils_ApplyPatchesCaseSensitive(cJSON * const object, const cJSON * const patches);
 
 /*
 // Note that ApplyPatches is NOT atomic on failure. To implement an atomic ApplyPatches, use:
@@ -33,12 +59,16 @@ CJSON_PUBLIC(int) cJSONUtils_ApplyPatches(cJSON *object, cJSON *patches);
 
 /* Implement RFC7386 (https://tools.ietf.org/html/rfc7396) JSON Merge Patch spec. */
 /* target will be modified by patch. return value is new ptr for target. */
-CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatch(cJSON *target, cJSON *patch);
+CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatch(cJSON *target, const cJSON * const patch);
+CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatchCaseSensitive(cJSON *target, const cJSON * const patch);
 /* generates a patch to move from -> to */
-CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatch(cJSON *from, cJSON *to);
+/* NOTE: This modifies objects in 'from' and 'to' by sorting the elements by their key */
+CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatch(cJSON * const from, cJSON * const to);
+CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatchCaseSensitive(cJSON * const from, cJSON * const to);
 
 /* Given a root object and a target object, construct a pointer from one to the other. */
-CJSON_PUBLIC(char *) cJSONUtils_FindPointerFromObjectTo(cJSON *object, cJSON *target);
+CJSON_PUBLIC(char *) cJSONUtils_FindPointerFromObjectTo(const cJSON * const object, const cJSON * const target);
 
 /* Sorts the members of the object into alphabetical order. */
-CJSON_PUBLIC(void) cJSONUtils_SortObject(cJSON *object);
+CJSON_PUBLIC(void) cJSONUtils_SortObject(cJSON * const object);
+CJSON_PUBLIC(void) cJSONUtils_SortObjectCaseSensitive(cJSON * const object);

+ 0 - 0
cJSONConfig.cmake.in → library_config/cJSONConfig.cmake.in


+ 0 - 0
cJSONConfigVersion.cmake.in → library_config/cJSONConfigVersion.cmake.in


+ 0 - 0
libcjson.pc.in → library_config/libcjson.pc.in


+ 0 - 0
libcjson_utils.pc.in → library_config/libcjson_utils.pc.in


+ 1 - 1
test.c

@@ -1,5 +1,5 @@
 /*
-  Copyright (c) 2009 Dave Gamble
+  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

+ 0 - 206
test_utils.c

@@ -1,206 +0,0 @@
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include "cJSON_Utils.h"
-
-int main(void)
-{
-    /* Some variables */
-    char *temp = NULL;
-    char *patchtext = NULL;
-    char *patchedtext = NULL;
-
-    int i = 0;
-    /* JSON Pointer tests: */
-    cJSON *root = NULL;
-    const char *json=
-        "{"
-        "\"foo\": [\"bar\", \"baz\"],"
-        "\"\": 0,"
-        "\"a/b\": 1,"
-        "\"c%d\": 2,"
-        "\"e^f\": 3,"
-        "\"g|h\": 4,"
-        "\"i\\\\j\": 5,"
-        "\"k\\\"l\": 6,"
-        "\" \": 7,"
-        "\"m~n\": 8"
-        "}";
-
-    const char *tests[12] = {"","/foo","/foo/0","/","/a~1b","/c%d","/e^f","/g|h","/i\\j","/k\"l","/ ","/m~0n"};
-
-    /* JSON Apply Patch tests: */
-    const char *patches[15][3] =
-    {
-        {"{ \"foo\": \"bar\"}", "[{ \"op\": \"add\", \"path\": \"/baz\", \"value\": \"qux\" }]","{\"baz\": \"qux\",\"foo\": \"bar\"}"},
-        {"{ \"foo\": [ \"bar\", \"baz\" ] }", "[{ \"op\": \"add\", \"path\": \"/foo/1\", \"value\": \"qux\" }]","{\"foo\": [ \"bar\", \"qux\", \"baz\" ] }"},
-        {"{\"baz\": \"qux\",\"foo\": \"bar\"}"," [{ \"op\": \"remove\", \"path\": \"/baz\" }]","{\"foo\": \"bar\" }"},
-        {"{ \"foo\": [ \"bar\", \"qux\", \"baz\" ] }","[{ \"op\": \"remove\", \"path\": \"/foo/1\" }]","{\"foo\": [ \"bar\", \"baz\" ] }"},
-        {"{ \"baz\": \"qux\",\"foo\": \"bar\"}","[{ \"op\": \"replace\", \"path\": \"/baz\", \"value\": \"boo\" }]","{\"baz\": \"boo\",\"foo\": \"bar\"}"},
-        {"{\"foo\": {\"bar\": \"baz\",\"waldo\": \"fred\"},\"qux\": {\"corge\": \"grault\"}}","[{ \"op\": \"move\", \"from\": \"/foo/waldo\", \"path\": \"/qux/thud\" }]","{\"foo\": {\"bar\": \"baz\"},\"qux\": {\"corge\": \"grault\",\"thud\": \"fred\"}}"},
-        {"{ \"foo\": [ \"all\", \"grass\", \"cows\", \"eat\" ] }","[ { \"op\": \"move\", \"from\": \"/foo/1\", \"path\": \"/foo/3\" }]","{ \"foo\": [ \"all\", \"cows\", \"eat\", \"grass\" ] }"},
-        {"{\"baz\": \"qux\",\"foo\": [ \"a\", 2, \"c\" ]}","[{ \"op\": \"test\", \"path\": \"/baz\", \"value\": \"qux\" },{ \"op\": \"test\", \"path\": \"/foo/1\", \"value\": 2 }]",""},
-        {"{ \"baz\": \"qux\" }","[ { \"op\": \"test\", \"path\": \"/baz\", \"value\": \"bar\" }]",""},
-        {"{ \"foo\": \"bar\" }","[{ \"op\": \"add\", \"path\": \"/child\", \"value\": { \"grandchild\": { } } }]","{\"foo\": \"bar\",\"child\": {\"grandchild\": {}}}"},
-        {"{ \"foo\": \"bar\" }","[{ \"op\": \"add\", \"path\": \"/baz\", \"value\": \"qux\", \"xyz\": 123 }]","{\"foo\": \"bar\",\"baz\": \"qux\"}"},
-        {"{ \"foo\": \"bar\" }","[{ \"op\": \"add\", \"path\": \"/baz/bat\", \"value\": \"qux\" }]",""},
-        {"{\"/\": 9,\"~1\": 10}","[{\"op\": \"test\", \"path\": \"/~01\", \"value\": 10}]",""},
-        {"{\"/\": 9,\"~1\": 10}","[{\"op\": \"test\", \"path\": \"/~01\", \"value\": \"10\"}]",""},
-        {"{ \"foo\": [\"bar\"] }","[ { \"op\": \"add\", \"path\": \"/foo/-\", \"value\": [\"abc\", \"def\"] }]","{\"foo\": [\"bar\", [\"abc\", \"def\"]] }"}
-    };
-
-    /* JSON Apply Merge tests: */
-    const char *merges[15][3] =
-    {
-        {"{\"a\":\"b\"}", "{\"a\":\"c\"}", "{\"a\":\"c\"}"},
-        {"{\"a\":\"b\"}", "{\"b\":\"c\"}", "{\"a\":\"b\",\"b\":\"c\"}"},
-        {"{\"a\":\"b\"}", "{\"a\":null}", "{}"},
-        {"{\"a\":\"b\",\"b\":\"c\"}", "{\"a\":null}", "{\"b\":\"c\"}"},
-        {"{\"a\":[\"b\"]}", "{\"a\":\"c\"}", "{\"a\":\"c\"}"},
-        {"{\"a\":\"c\"}", "{\"a\":[\"b\"]}", "{\"a\":[\"b\"]}"},
-        {"{\"a\":{\"b\":\"c\"}}", "{\"a\":{\"b\":\"d\",\"c\":null}}", "{\"a\":{\"b\":\"d\"}}"},
-        {"{\"a\":[{\"b\":\"c\"}]}", "{\"a\":[1]}", "{\"a\":[1]}"},
-        {"[\"a\",\"b\"]", "[\"c\",\"d\"]", "[\"c\",\"d\"]"},
-        {"{\"a\":\"b\"}", "[\"c\"]", "[\"c\"]"},
-        {"{\"a\":\"foo\"}", "null", "null"},
-        {"{\"a\":\"foo\"}", "\"bar\"", "\"bar\""},
-        {"{\"e\":null}", "{\"a\":1}", "{\"e\":null,\"a\":1}"},
-        {"[1,2]", "{\"a\":\"b\",\"c\":null}", "{\"a\":\"b\"}"},
-        {"{}","{\"a\":{\"bb\":{\"ccc\":null}}}", "{\"a\":{\"bb\":{}}}"}
-    };
-
-
-    /* Misc tests */
-    int numbers[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
-    const char *random = "QWERTYUIOPASDFGHJKLZXCVBNM";
-    char buf[2] = {0,0};
-    char *before = NULL;
-    char *after = NULL;
-    cJSON *object = NULL;
-    cJSON *nums = NULL;
-    cJSON *num6 = NULL;
-    cJSON *sortme = NULL;
-
-
-    printf("JSON Pointer Tests\n");
-    root = cJSON_Parse(json);
-    for (i = 0; i < 12; i++)
-    {
-        char *output = cJSON_Print(cJSONUtils_GetPointer(root, tests[i]));
-        printf("Test %d:\n%s\n\n", i + 1, output);
-        free(output);
-    }
-    cJSON_Delete(root);
-
-
-    printf("JSON Apply Patch Tests\n");
-    for (i = 0; i < 15; i++)
-    {
-        cJSON *object_to_be_patched = cJSON_Parse(patches[i][0]);
-        cJSON *patch = cJSON_Parse(patches[i][1]);
-        int err = cJSONUtils_ApplyPatches(object_to_be_patched, patch);
-        char *output = cJSON_Print(object_to_be_patched);
-        printf("Test %d (err %d):\n%s\n\n", i + 1, err, output);
-
-        free(output);
-        cJSON_Delete(object_to_be_patched);
-        cJSON_Delete(patch);
-    }
-
-    /* JSON Generate Patch tests: */
-    printf("JSON Generate Patch Tests\n");
-    for (i = 0; i < 15; i++)
-    {
-        cJSON *from;
-        cJSON *to;
-        cJSON *patch;
-        char *out;
-        if (!strlen(patches[i][2]))
-        {
-            continue;
-        }
-        from = cJSON_Parse(patches[i][0]);
-        to = cJSON_Parse(patches[i][2]);
-        patch = cJSONUtils_GeneratePatches(from, to);
-        out = cJSON_Print(patch);
-        printf("Test %d: (patch: %s):\n%s\n\n", i + 1, patches[i][1], out);
-
-        free(out);
-        cJSON_Delete(from);
-        cJSON_Delete(to);
-        cJSON_Delete(patch);
-    }
-
-    /* Misc tests: */
-    printf("JSON Pointer construct\n");
-    object = cJSON_CreateObject();
-    nums = cJSON_CreateIntArray(numbers, 10);
-    num6 = cJSON_GetArrayItem(nums, 6);
-    cJSON_AddItemToObject(object, "numbers", nums);
-    temp = cJSONUtils_FindPointerFromObjectTo(object, num6);
-    printf("Pointer: [%s]\n", temp);
-    free(temp);
-    temp = cJSONUtils_FindPointerFromObjectTo(object, nums);
-    printf("Pointer: [%s]\n", temp);
-    free(temp);
-    temp = cJSONUtils_FindPointerFromObjectTo(object, object);
-    printf("Pointer: [%s]\n", temp);
-    free(temp);
-    cJSON_Delete(object);
-
-    /* JSON Sort test: */
-    sortme = cJSON_CreateObject();
-    for (i = 0; i < 26; i++)
-    {
-        buf[0] = random[i];
-        cJSON_AddItemToObject(sortme, buf, cJSON_CreateNumber(1));
-    }
-    before = cJSON_PrintUnformatted(sortme);
-    cJSONUtils_SortObject(sortme);
-    after = cJSON_PrintUnformatted(sortme);
-    printf("Before: [%s]\nAfter: [%s]\n\n", before, after);
-
-    free(before);
-    free(after);
-    cJSON_Delete(sortme);
-
-    /* Merge tests: */
-    printf("JSON Merge Patch tests\n");
-    for (i = 0; i < 15; i++)
-    {
-        cJSON *object_to_be_merged = cJSON_Parse(merges[i][0]);
-        cJSON *patch = cJSON_Parse(merges[i][1]);
-        char *before_merge = cJSON_PrintUnformatted(object_to_be_merged);
-        patchtext = cJSON_PrintUnformatted(patch);
-        printf("Before: [%s] -> [%s] = ", before_merge, patchtext);
-        object_to_be_merged = cJSONUtils_MergePatch(object_to_be_merged, patch);
-        after = cJSON_PrintUnformatted(object_to_be_merged);
-        printf("[%s] vs [%s] (%s)\n", after, merges[i][2], strcmp(after, merges[i][2]) ? "FAIL" : "OK");
-
-        free(before_merge);
-        free(patchtext);
-        free(after);
-        cJSON_Delete(object_to_be_merged);
-        cJSON_Delete(patch);
-    }
-
-    /* Generate Merge tests: */
-    for (i = 0; i < 15; i++)
-    {
-        cJSON *from = cJSON_Parse(merges[i][0]);
-        cJSON *to = cJSON_Parse(merges[i][2]);
-        cJSON *patch = cJSONUtils_GenerateMergePatch(from,to);
-        from = cJSONUtils_MergePatch(from,patch);
-        patchtext = cJSON_PrintUnformatted(patch);
-        patchedtext = cJSON_PrintUnformatted(from);
-        printf("Patch [%s] vs [%s] = [%s] vs [%s] (%s)\n", patchtext, merges[i][1], patchedtext, merges[i][2], strcmp(patchedtext, merges[i][2]) ? "FAIL" : "OK");
-
-        cJSON_Delete(from);
-        cJSON_Delete(to);
-        cJSON_Delete(patch);
-        free(patchtext);
-        free(patchedtext);
-    }
-
-    return 0;
-}

+ 27 - 0
tests/CMakeLists.txt

@@ -45,6 +45,8 @@ if(ENABLE_CJSON_TEST)
         print_object
         print_value
         misc_tests
+        parse_with_opts
+        compare_tests
     )
 
     add_library(test-common common.c)
@@ -73,4 +75,29 @@ if(ENABLE_CJSON_TEST)
     endforeach()
 
     add_dependencies(check ${unity_tests})
+
+    if (ENABLE_CJSON_UTILS)
+        #copy test files
+        file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/json-patch-tests")
+        file(GLOB test_files "json-patch-tests/*")
+        file(COPY ${test_files} DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/json-patch-tests/")
+
+        set (cjson_utils_tests
+            json_patch_tests
+            old_utils_tests)
+
+        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)
+            if(MEMORYCHECK_COMMAND)
+                add_test(NAME "${cjson_utils_test}"
+                    COMMAND "${MEMORYCHECK_COMMAND}" ${MEMORYCHECK_COMMAND_OPTIONS} "${CMAKE_CURRENT_BINARY_DIR}/${cjson_utils_test}")
+            else()
+                add_test(NAME "${cjson_utils_test}"
+                    COMMAND "./${cjson_utils_test}")
+            endif()
+        endforeach()
+
+        add_dependencies(check ${cjson_utils_tests})
+    endif()
 endif()

+ 192 - 0
tests/compare_tests.c

@@ -0,0 +1,192 @@
+/*
+  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 "unity/examples/unity_config.h"
+#include "unity/src/unity.h"
+#include "common.h"
+
+static cJSON_bool compare_from_string(const char * const a, const char * const b, const cJSON_bool case_sensitive)
+{
+    cJSON *a_json = NULL;
+    cJSON *b_json = NULL;
+    cJSON_bool result = false;
+
+    a_json = cJSON_Parse(a);
+    TEST_ASSERT_NOT_NULL_MESSAGE(a_json, "Failed to parse a.");
+    b_json = cJSON_Parse(b);
+    TEST_ASSERT_NOT_NULL_MESSAGE(b_json, "Failed to parse b.");
+
+    result = cJSON_Compare(a_json, b_json, case_sensitive);
+
+    cJSON_Delete(a_json);
+    cJSON_Delete(b_json);
+
+    return result;
+}
+
+static void cjson_compare_should_compare_null_pointer_as_not_equal(void)
+{
+    TEST_ASSERT_FALSE(cJSON_Compare(NULL, NULL, true));
+    TEST_ASSERT_FALSE(cJSON_Compare(NULL, NULL, false));
+}
+
+static void cjson_compare_should_compare_invalid_as_not_equal(void)
+{
+    cJSON invalid[1];
+    memset(invalid, '\0', sizeof(invalid));
+
+    TEST_ASSERT_FALSE(cJSON_Compare(invalid, invalid, false));
+    TEST_ASSERT_FALSE(cJSON_Compare(invalid, invalid, true));
+}
+
+static void cjson_compare_should_compare_numbers(void)
+{
+    TEST_ASSERT_TRUE(compare_from_string("1", "1", true));
+    TEST_ASSERT_TRUE(compare_from_string("1", "1", false));
+    TEST_ASSERT_TRUE(compare_from_string("0.0001", "0.0001", true));
+    TEST_ASSERT_TRUE(compare_from_string("0.0001", "0.0001", false));
+
+    TEST_ASSERT_FALSE(compare_from_string("1", "2", true));
+    TEST_ASSERT_FALSE(compare_from_string("1", "2", false));
+}
+
+static void cjson_compare_should_compare_booleans(void)
+{
+    /* true */
+    TEST_ASSERT_TRUE(compare_from_string("true", "true", true));
+    TEST_ASSERT_TRUE(compare_from_string("true", "true", false));
+
+    /* false */
+    TEST_ASSERT_TRUE(compare_from_string("false", "false", true));
+    TEST_ASSERT_TRUE(compare_from_string("false", "false", false));
+
+    /* mixed */
+    TEST_ASSERT_FALSE(compare_from_string("true", "false", true));
+    TEST_ASSERT_FALSE(compare_from_string("true", "false", false));
+    TEST_ASSERT_FALSE(compare_from_string("false", "true", true));
+    TEST_ASSERT_FALSE(compare_from_string("false", "true", false));
+}
+
+static void cjson_compare_should_compare_null(void)
+{
+    TEST_ASSERT_TRUE(compare_from_string("null", "null", true));
+    TEST_ASSERT_TRUE(compare_from_string("null", "null", false));
+
+    TEST_ASSERT_FALSE(compare_from_string("null", "true", true));
+    TEST_ASSERT_FALSE(compare_from_string("null", "true", false));
+}
+
+static void cjson_compare_should_not_accept_invalid_types(void)
+{
+    cJSON invalid[1];
+    memset(invalid, '\0', sizeof(invalid));
+
+    invalid->type = cJSON_Number | cJSON_String;
+
+    TEST_ASSERT_FALSE(cJSON_Compare(invalid, invalid, true));
+    TEST_ASSERT_FALSE(cJSON_Compare(invalid, invalid, false));
+}
+
+static void cjson_compare_should_compare_strings(void)
+{
+    TEST_ASSERT_TRUE(compare_from_string("\"abcdefg\"", "\"abcdefg\"", true));
+    TEST_ASSERT_TRUE(compare_from_string("\"abcdefg\"", "\"abcdefg\"", false));
+
+    TEST_ASSERT_FALSE(compare_from_string("\"ABCDEFG\"", "\"abcdefg\"", true));
+    TEST_ASSERT_FALSE(compare_from_string("\"ABCDEFG\"", "\"abcdefg\"", false));
+}
+
+static void cjson_compare_should_compare_raw(void)
+{
+    cJSON *raw1 = NULL;
+    cJSON *raw2 = NULL;
+
+    raw1 = cJSON_Parse("\"[true, false]\"");
+    TEST_ASSERT_NOT_NULL(raw1);
+    raw2 = cJSON_Parse("\"[true, false]\"");
+    TEST_ASSERT_NOT_NULL(raw2);
+
+    raw1->type = cJSON_Raw;
+    raw2->type = cJSON_Raw;
+
+    TEST_ASSERT_TRUE(cJSON_Compare(raw1, raw2, true));
+    TEST_ASSERT_TRUE(cJSON_Compare(raw1, raw2, false));
+
+    cJSON_Delete(raw1);
+    cJSON_Delete(raw2);
+}
+
+static void cjson_compare_should_compare_arrays(void)
+{
+    TEST_ASSERT_TRUE(compare_from_string("[]", "[]", true));
+    TEST_ASSERT_TRUE(compare_from_string("[]", "[]", false));
+
+    TEST_ASSERT_TRUE(compare_from_string("[false,true,null,42,\"string\",[],{}]", "[false, true, null, 42, \"string\", [], {}]", true));
+    TEST_ASSERT_TRUE(compare_from_string("[false,true,null,42,\"string\",[],{}]", "[false, true, null, 42, \"string\", [], {}]", false));
+
+    TEST_ASSERT_TRUE(compare_from_string("[[[1], 2]]", "[[[1], 2]]", true));
+    TEST_ASSERT_TRUE(compare_from_string("[[[1], 2]]", "[[[1], 2]]", false));
+
+    TEST_ASSERT_FALSE(compare_from_string("[true,null,42,\"string\",[],{}]", "[false, true, null, 42, \"string\", [], {}]", true));
+    TEST_ASSERT_FALSE(compare_from_string("[true,null,42,\"string\",[],{}]", "[false, true, null, 42, \"string\", [], {}]", false));
+}
+
+static void cjson_compare_should_compare_objects(void)
+{
+    TEST_ASSERT_TRUE(compare_from_string("{}", "{}", true));
+    TEST_ASSERT_TRUE(compare_from_string("{}", "{}", false));
+
+    TEST_ASSERT_TRUE(compare_from_string(
+                "{\"false\": false, \"true\": true, \"null\": null, \"number\": 42, \"string\": \"string\", \"array\": [], \"object\": {}}",
+                "{\"true\": true, \"false\": false, \"null\": null, \"number\": 42, \"string\": \"string\", \"array\": [], \"object\": {}}",
+                true));
+    TEST_ASSERT_FALSE(compare_from_string(
+                "{\"False\": false, \"true\": true, \"null\": null, \"number\": 42, \"string\": \"string\", \"array\": [], \"object\": {}}",
+                "{\"true\": true, \"false\": false, \"null\": null, \"number\": 42, \"string\": \"string\", \"array\": [], \"object\": {}}",
+                true));
+    TEST_ASSERT_TRUE(compare_from_string(
+                "{\"False\": false, \"true\": true, \"null\": null, \"number\": 42, \"string\": \"string\", \"array\": [], \"object\": {}}",
+                "{\"true\": true, \"false\": false, \"null\": null, \"number\": 42, \"string\": \"string\", \"array\": [], \"object\": {}}",
+                false));
+    TEST_ASSERT_FALSE(compare_from_string(
+                "{\"Flse\": false, \"true\": true, \"null\": null, \"number\": 42, \"string\": \"string\", \"array\": [], \"object\": {}}",
+                "{\"true\": true, \"false\": false, \"null\": null, \"number\": 42, \"string\": \"string\", \"array\": [], \"object\": {}}",
+                false));
+}
+
+int main(void)
+{
+    UNITY_BEGIN();
+
+    RUN_TEST(cjson_compare_should_compare_null_pointer_as_not_equal);
+    RUN_TEST(cjson_compare_should_compare_invalid_as_not_equal);
+    RUN_TEST(cjson_compare_should_compare_numbers);
+    RUN_TEST(cjson_compare_should_compare_booleans);
+    RUN_TEST(cjson_compare_should_compare_null);
+    RUN_TEST(cjson_compare_should_not_accept_invalid_types);
+    RUN_TEST(cjson_compare_should_compare_strings);
+    RUN_TEST(cjson_compare_should_compare_raw);
+    RUN_TEST(cjson_compare_should_compare_arrays);
+    RUN_TEST(cjson_compare_should_compare_objects);
+
+    return UNITY_END();
+}

+ 10 - 0
tests/json-patch-tests/.editorconfig

@@ -0,0 +1,10 @@
+# EditorConfig is awesome: http://EditorConfig.org
+
+root = true
+
+[*]
+end_of_line = lf
+insert_final_newline = true
+charset = utf-8
+trim_trailing_whitespace = true
+indent_style = space

+ 4 - 0
tests/json-patch-tests/.gitignore

@@ -0,0 +1,4 @@
+*~
+\#*
+!.editorconfig
+!.gitignore

+ 2 - 0
tests/json-patch-tests/.npmignore

@@ -0,0 +1,2 @@
+.editorconfig
+.gitignore

+ 75 - 0
tests/json-patch-tests/README.md

@@ -0,0 +1,75 @@
+JSON Patch Tests
+================
+
+These are test cases for implementations of [IETF JSON Patch (RFC6902)](http://tools.ietf.org/html/rfc6902).
+
+Some implementations can be found at [jsonpatch.com](http://jsonpatch.com).
+
+
+Test Format
+-----------
+
+Each test file is a JSON document that contains an array of test records. A
+test record is an object with the following members:
+
+- doc: The JSON document to test against
+- patch: The patch(es) to apply
+- expected: The expected resulting document, OR
+- error: A string describing an expected error
+- comment: A string describing the test
+- disabled: True if the test should be skipped
+
+All fields except 'doc' and 'patch' are optional. Test records consisting only
+of a comment are also OK.
+
+
+Files
+-----
+
+- tests.json: the main test file
+- spec_tests.json: tests from the RFC6902 spec
+
+
+Writing Tests
+-------------
+
+All tests should have a descriptive comment.  Tests should be as
+simple as possible - just what's required to test a specific piece of
+behavior.  If you want to test interacting behaviors, create tests for
+each behavior as well as the interaction.
+
+If an 'error' member is specified, the error text should describe the
+error the implementation should raise - *not* what's being tested.
+Implementation error strings will vary, but the suggested error should
+be easily matched to the implementation error string.  Try to avoid
+creating error tests that might pass because an incorrect error was
+reported.
+
+Please feel free to contribute!
+
+
+Credits
+-------
+
+The seed test set was adapted from Byron Ruth's
+[jsonpatch-js](https://github.com/bruth/jsonpatch-js/blob/master/test.js) and
+extended by [Mike McCabe](https://github.com/mikemccabe).
+
+
+License
+-------
+
+   Copyright 2014 The Authors
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+

+ 84 - 0
tests/json-patch-tests/cjson-utils-tests.json

@@ -0,0 +1,84 @@
+[
+    {
+	"comment": "1",
+	"doc": { "foo": "bar"},
+	"patch": [{ "op": "add", "path": "/baz", "value": "qux" }],
+	"expected": {"baz": "qux", "foo": "bar"}
+    },
+    {
+	"comment": "2",
+	"doc": { "foo": [ "bar", "baz" ] },
+	"patch": [{ "op": "add", "path": "/foo/1", "value": "qux" }],
+	"expected": {"foo": [ "bar", "qux", "baz" ] }
+    },
+    {
+	"comment": "3",
+	"doc": {"baz": "qux","foo": "bar"},
+	"patch": [{ "op": "remove", "path": "/baz" }],
+	"expected": {"foo": "bar" }
+    },
+    {
+	"comment": "4",
+	"doc": { "foo": [ "bar", "qux", "baz" ] },
+	"patch": [{ "op": "remove", "path": "/foo/1" }],
+	"expected": {"foo": [ "bar", "baz" ] }
+    },
+    {
+	"comment": "5",
+	"doc": { "baz": "qux","foo": "bar"},
+	"patch": [{ "op": "replace", "path": "/baz", "value": "boo" }],
+	"expected": {"baz": "boo","foo": "bar"}
+    },
+    {
+	"comment": "6",
+	"doc": {"foo": {"bar": "baz","waldo": "fred"},"qux": {"corge": "grault"}},
+	"patch": [{ "op": "move", "from": "/foo/waldo", "path": "/qux/thud" }],
+	"expected": {"foo": {"bar": "baz"},"qux": {"corge": "grault","thud": "fred"}}
+    },
+    {
+	"comment": "7",
+	"doc": { "foo": [ "all", "grass", "cows", "eat" ] },
+	"patch": [ { "op": "move", "from": "/foo/1", "path": "/foo/3" }],
+	"expected": { "foo": [ "all", "cows", "eat", "grass" ] }
+    },
+    {
+	"comment": "8",
+	"doc": {"baz": "qux","foo": [ "a", 2, "c" ]},
+	"patch": [{ "op": "test", "path": "/baz", "value": "qux" },{ "op": "test", "path": "/foo/1", "value": 2 }]
+    },
+    {
+	"comment": "9",
+	"doc": { "baz": "qux" },
+	"patch": [ { "op": "test", "path": "/baz", "value": "bar" }],
+	"error": "\"bar\" doesn't exist"
+    },
+    {
+	"comment": "10",
+	"doc": { "foo": "bar" },
+	"patch": [{ "op": "add", "path": "/child", "value": { "grandchild": { } } }],
+	"expected": {"foo": "bar","child": {"grandchild": {}}}
+    },
+    {
+	"comment": "11",
+	"doc": { "foo": "bar" },
+	"patch": [{ "op": "add", "path": "/baz", "value": "qux", "xyz": 123 }],
+	"expected": {"foo": "bar","baz": "qux"}
+    },
+    {
+	"comment": "12",
+	"doc": { "foo": "bar" },
+	"patch": [{ "op": "add", "path": "/baz/bat", "value": "qux" }],
+	"error": "Can't add to nonexistent object"
+    },
+    {
+	"comment": "13",
+	"doc": {"/": 9,"~1": 10},
+	"patch": [{"op": "test", "path": "/~01", "value": 10}]
+    },
+    {
+	"comment": "14",
+	"doc": { "foo": ["bar"] },
+	"patch": [ { "op": "add", "path": "/foo/-", "value": ["abc", "def"] }],
+	"expected": {"foo": ["bar", ["abc", "def"]] }
+    }
+]

+ 15 - 0
tests/json-patch-tests/package.json

@@ -0,0 +1,15 @@
+{
+  "name": "json-patch-test-suite",
+  "version": "1.1.0",
+  "description": "JSON Patch RFC 6902 test suite",
+  "repository": "github:json-patch/json-patch-tests",
+  "homepage": "https://github.com/json-patch/json-patch-tests",
+  "bugs": "https://github.com/json-patch/json-patch-tests/issues",
+  "keywords": [
+    "JSON",
+    "Patch",
+    "test",
+    "suite"
+  ],
+  "license": "Apache-2.0"
+}

+ 233 - 0
tests/json-patch-tests/spec_tests.json

@@ -0,0 +1,233 @@
+[
+  {
+    "comment": "4.1. add with missing object",
+    "doc": { "q": { "bar": 2 } },
+    "patch": [ {"op": "add", "path": "/a/b", "value": 1} ],
+    "error":
+       "path /a does not exist -- missing objects are not created recursively"
+  },
+
+  {
+    "comment": "A.1.  Adding an Object Member",
+    "doc": {
+  "foo": "bar"
+},
+    "patch": [
+  { "op": "add", "path": "/baz", "value": "qux" }
+],
+    "expected": {
+  "baz": "qux",
+  "foo": "bar"
+}
+  },
+
+  {
+    "comment": "A.2.  Adding an Array Element",
+    "doc": {
+  "foo": [ "bar", "baz" ]
+},
+    "patch": [
+  { "op": "add", "path": "/foo/1", "value": "qux" }
+],
+    "expected": {
+  "foo": [ "bar", "qux", "baz" ]
+}
+  },
+
+  {
+    "comment": "A.3.  Removing an Object Member",
+    "doc": {
+  "baz": "qux",
+  "foo": "bar"
+},
+    "patch": [
+  { "op": "remove", "path": "/baz" }
+],
+    "expected": {
+  "foo": "bar"
+}
+  },
+
+  {
+    "comment": "A.4.  Removing an Array Element",
+    "doc": {
+  "foo": [ "bar", "qux", "baz" ]
+},
+    "patch": [
+  { "op": "remove", "path": "/foo/1" }
+],
+    "expected": {
+  "foo": [ "bar", "baz" ]
+}
+  },
+
+  {
+    "comment": "A.5.  Replacing a Value",
+    "doc": {
+  "baz": "qux",
+  "foo": "bar"
+},
+    "patch": [
+  { "op": "replace", "path": "/baz", "value": "boo" }
+],
+    "expected": {
+  "baz": "boo",
+  "foo": "bar"
+}
+  },
+
+  {
+    "comment": "A.6.  Moving a Value",
+    "doc": {
+  "foo": {
+    "bar": "baz",
+    "waldo": "fred"
+  },
+  "qux": {
+    "corge": "grault"
+  }
+},
+    "patch": [
+  { "op": "move", "from": "/foo/waldo", "path": "/qux/thud" }
+],
+    "expected": {
+  "foo": {
+    "bar": "baz"
+  },
+  "qux": {
+    "corge": "grault",
+    "thud": "fred"
+  }
+}
+  },
+
+  {
+    "comment": "A.7.  Moving an Array Element",
+    "doc": {
+  "foo": [ "all", "grass", "cows", "eat" ]
+},
+    "patch": [
+  { "op": "move", "from": "/foo/1", "path": "/foo/3" }
+],
+    "expected": {
+  "foo": [ "all", "cows", "eat", "grass" ]
+}
+
+  },
+
+  {
+    "comment": "A.8.  Testing a Value: Success",
+    "doc": {
+  "baz": "qux",
+  "foo": [ "a", 2, "c" ]
+},
+    "patch": [
+  { "op": "test", "path": "/baz", "value": "qux" },
+  { "op": "test", "path": "/foo/1", "value": 2 }
+],
+    "expected": {
+     "baz": "qux",
+     "foo": [ "a", 2, "c" ]
+    }
+  },
+
+  {
+    "comment": "A.9.  Testing a Value: Error",
+    "doc": {
+  "baz": "qux"
+},
+    "patch": [
+  { "op": "test", "path": "/baz", "value": "bar" }
+],
+    "error": "string not equivalent"
+  },
+
+  {
+    "comment": "A.10.  Adding a nested Member Object",
+    "doc": {
+  "foo": "bar"
+},
+    "patch": [
+  { "op": "add", "path": "/child", "value": { "grandchild": { } } }
+],
+    "expected": {
+  "foo": "bar",
+  "child": {
+    "grandchild": {
+    }
+  }
+}
+  },
+
+  {
+    "comment": "A.11.  Ignoring Unrecognized Elements",
+    "doc": {
+  "foo":"bar"
+},
+    "patch": [
+  { "op": "add", "path": "/baz", "value": "qux", "xyz": 123 }
+],
+    "expected": {
+  "foo":"bar",
+  "baz":"qux"
+}
+  },
+
+ {
+    "comment": "A.12.  Adding to a Non-existent Target",
+    "doc": {
+  "foo": "bar"
+},
+    "patch": [
+  { "op": "add", "path": "/baz/bat", "value": "qux" }
+],
+    "error": "add to a non-existent target"
+  },
+
+ {
+    "comment": "A.13 Invalid JSON Patch Document",
+    "doc": {
+     "foo": "bar"
+    },
+    "patch": [
+  { "op": "add", "path": "/baz", "value": "qux", "op": "remove" }
+],
+    "error": "operation has two 'op' members",
+    "disabled": true
+  },
+
+  {
+    "comment": "A.14. ~ Escape Ordering",
+    "doc": {
+       "/": 9,
+       "~1": 10
+    },
+    "patch": [{"op": "test", "path": "/~01", "value": 10}],
+    "expected": {
+       "/": 9,
+       "~1": 10
+    }
+  },
+
+  {
+    "comment": "A.15. Comparing Strings and Numbers",
+    "doc": {
+       "/": 9,
+       "~1": 10
+    },
+    "patch": [{"op": "test", "path": "/~01", "value": "10"}],
+    "error": "number is not equal to string"
+  },
+
+  {
+    "comment": "A.16. Adding an Array Value",
+    "doc": {
+       "foo": ["bar"]
+    },
+    "patch": [{ "op": "add", "path": "/foo/-", "value": ["abc", "def"] }],
+    "expected": {
+      "foo": ["bar", ["abc", "def"]]
+    }
+  }
+
+]

+ 429 - 0
tests/json-patch-tests/tests.json

@@ -0,0 +1,429 @@
+[
+    { "comment": "empty list, empty docs",
+      "doc": {},
+      "patch": [],
+      "expected": {} },
+
+    { "comment": "empty patch list",
+      "doc": {"foo": 1},
+      "patch": [],
+      "expected": {"foo": 1} },
+
+    { "comment": "rearrangements OK?",
+      "doc": {"foo": 1, "bar": 2},
+      "patch": [],
+      "expected": {"bar":2, "foo": 1} },
+
+    { "comment": "rearrangements OK?  How about one level down ... array",
+      "doc": [{"foo": 1, "bar": 2}],
+      "patch": [],
+      "expected": [{"bar":2, "foo": 1}] },
+
+    { "comment": "rearrangements OK?  How about one level down...",
+      "doc": {"foo":{"foo": 1, "bar": 2}},
+      "patch": [],
+      "expected": {"foo":{"bar":2, "foo": 1}} },
+
+    { "comment": "add replaces any existing field",
+      "doc": {"foo": null},
+      "patch": [{"op": "add", "path": "/foo", "value":1}],
+      "expected": {"foo": 1} },
+
+    { "comment": "toplevel array",
+      "doc": [],
+      "patch": [{"op": "add", "path": "/0", "value": "foo"}],
+      "expected": ["foo"] },
+
+    { "comment": "toplevel array, no change",
+      "doc": ["foo"],
+      "patch": [],
+      "expected": ["foo"] },
+
+    { "comment": "toplevel object, numeric string",
+      "doc": {},
+      "patch": [{"op": "add", "path": "/foo", "value": "1"}],
+      "expected": {"foo":"1"} },
+
+    { "comment": "toplevel object, integer",
+      "doc": {},
+      "patch": [{"op": "add", "path": "/foo", "value": 1}],
+      "expected": {"foo":1} },
+
+    { "comment": "Toplevel scalar values OK?",
+      "doc": "foo",
+      "patch": [{"op": "replace", "path": "", "value": "bar"}],
+      "expected": "bar",
+      "disabled": true },
+
+    { "comment": "replace object document with array document?",
+      "doc": {},
+      "patch": [{"op": "add", "path": "", "value": []}],
+      "expected": [] },
+
+    { "comment": "replace array document with object document?",
+      "doc": [],
+      "patch": [{"op": "add", "path": "", "value": {}}],
+      "expected": {} },
+
+    { "comment": "append to root array document?",
+      "doc": [],
+      "patch": [{"op": "add", "path": "/-", "value": "hi"}],
+      "expected": ["hi"] },
+
+    { "comment": "Add, / target",
+      "doc": {},
+      "patch": [ {"op": "add", "path": "/", "value":1 } ],
+      "expected": {"":1} },
+
+    { "comment": "Add, /foo/ deep target (trailing slash)",
+      "doc": {"foo": {}},
+      "patch": [ {"op": "add", "path": "/foo/", "value":1 } ],
+      "expected": {"foo":{"": 1}} },
+
+    { "comment": "Add composite value at top level",
+      "doc": {"foo": 1},
+      "patch": [{"op": "add", "path": "/bar", "value": [1, 2]}],
+      "expected": {"foo": 1, "bar": [1, 2]} },
+
+    { "comment": "Add into composite value",
+      "doc": {"foo": 1, "baz": [{"qux": "hello"}]},
+      "patch": [{"op": "add", "path": "/baz/0/foo", "value": "world"}],
+      "expected": {"foo": 1, "baz": [{"qux": "hello", "foo": "world"}]} },
+
+    { "doc": {"bar": [1, 2]},
+      "patch": [{"op": "add", "path": "/bar/8", "value": "5"}],
+      "error": "Out of bounds (upper)" },
+
+    { "doc": {"bar": [1, 2]},
+      "patch": [{"op": "add", "path": "/bar/-1", "value": "5"}],
+      "error": "Out of bounds (lower)" },
+
+    { "doc": {"foo": 1},
+      "patch": [{"op": "add", "path": "/bar", "value": true}],
+      "expected": {"foo": 1, "bar": true} },
+
+    { "doc": {"foo": 1},
+      "patch": [{"op": "add", "path": "/bar", "value": false}],
+      "expected": {"foo": 1, "bar": false} },
+
+    { "doc": {"foo": 1},
+      "patch": [{"op": "add", "path": "/bar", "value": null}],
+      "expected": {"foo": 1, "bar": null} },
+
+    { "comment": "0 can be an array index or object element name",
+      "doc": {"foo": 1},
+      "patch": [{"op": "add", "path": "/0", "value": "bar"}],
+      "expected": {"foo": 1, "0": "bar" } },
+
+    { "doc": ["foo"],
+      "patch": [{"op": "add", "path": "/1", "value": "bar"}],
+      "expected": ["foo", "bar"] },
+
+    { "doc": ["foo", "sil"],
+      "patch": [{"op": "add", "path": "/1", "value": "bar"}],
+      "expected": ["foo", "bar", "sil"] },
+
+    { "doc": ["foo", "sil"],
+      "patch": [{"op": "add", "path": "/0", "value": "bar"}],
+      "expected": ["bar", "foo", "sil"] },
+
+    { "comment": "push item to array via last index + 1",
+      "doc": ["foo", "sil"],
+      "patch": [{"op":"add", "path": "/2", "value": "bar"}],
+      "expected": ["foo", "sil", "bar"] },
+
+    { "comment": "add item to array at index > length should fail",
+      "doc": ["foo", "sil"],
+      "patch": [{"op":"add", "path": "/3", "value": "bar"}],
+      "error": "index is greater than number of items in array" },
+      
+    { "comment": "test against implementation-specific numeric parsing",
+      "doc": {"1e0": "foo"},
+      "patch": [{"op": "test", "path": "/1e0", "value": "foo"}],
+      "expected": {"1e0": "foo"} },
+
+    { "comment": "test with bad number should fail",
+      "doc": ["foo", "bar"],
+      "patch": [{"op": "test", "path": "/1e0", "value": "bar"}],
+      "error": "test op shouldn't get array element 1" },
+
+    { "doc": ["foo", "sil"],
+      "patch": [{"op": "add", "path": "/bar", "value": 42}],
+      "error": "Object operation on array target" },
+
+    { "doc": ["foo", "sil"],
+      "patch": [{"op": "add", "path": "/1", "value": ["bar", "baz"]}],
+      "expected": ["foo", ["bar", "baz"], "sil"],
+      "comment": "value in array add not flattened" },
+
+    { "doc": {"foo": 1, "bar": [1, 2, 3, 4]},
+      "patch": [{"op": "remove", "path": "/bar"}],
+      "expected": {"foo": 1} },
+
+    { "doc": {"foo": 1, "baz": [{"qux": "hello"}]},
+      "patch": [{"op": "remove", "path": "/baz/0/qux"}],
+      "expected": {"foo": 1, "baz": [{}]} },
+
+    { "doc": {"foo": 1, "baz": [{"qux": "hello"}]},
+      "patch": [{"op": "replace", "path": "/foo", "value": [1, 2, 3, 4]}],
+      "expected": {"foo": [1, 2, 3, 4], "baz": [{"qux": "hello"}]} },
+
+    { "doc": {"foo": [1, 2, 3, 4], "baz": [{"qux": "hello"}]},
+      "patch": [{"op": "replace", "path": "/baz/0/qux", "value": "world"}],
+      "expected": {"foo": [1, 2, 3, 4], "baz": [{"qux": "world"}]} },
+
+    { "doc": ["foo"],
+      "patch": [{"op": "replace", "path": "/0", "value": "bar"}],
+      "expected": ["bar"] },
+
+    { "doc": [""],
+      "patch": [{"op": "replace", "path": "/0", "value": 0}],
+      "expected": [0] },
+
+    { "doc": [""],
+      "patch": [{"op": "replace", "path": "/0", "value": true}],
+      "expected": [true] },
+
+    { "doc": [""],
+      "patch": [{"op": "replace", "path": "/0", "value": false}],
+      "expected": [false] },
+
+    { "doc": [""],
+      "patch": [{"op": "replace", "path": "/0", "value": null}],
+      "expected": [null] },
+
+    { "doc": ["foo", "sil"],
+      "patch": [{"op": "replace", "path": "/1", "value": ["bar", "baz"]}],
+      "expected": ["foo", ["bar", "baz"]],
+      "comment": "value in array replace not flattened" },
+
+    { "comment": "replace whole document",
+      "doc": {"foo": "bar"},
+      "patch": [{"op": "replace", "path": "", "value": {"baz": "qux"}}],
+      "expected": {"baz": "qux"} },
+
+    { "comment": "spurious patch properties",
+      "doc": {"foo": 1},
+      "patch": [{"op": "test", "path": "/foo", "value": 1, "spurious": 1}],
+      "expected": {"foo": 1} },
+
+    { "doc": {"foo": null},
+      "patch": [{"op": "test", "path": "/foo", "value": null}],
+      "comment": "null value should be valid obj property" },
+
+    { "doc": {"foo": null},
+      "patch": [{"op": "replace", "path": "/foo", "value": "truthy"}],
+      "expected": {"foo": "truthy"},
+      "comment": "null value should be valid obj property to be replaced with something truthy" },
+
+    { "doc": {"foo": null},
+      "patch": [{"op": "move", "from": "/foo", "path": "/bar"}],
+      "expected": {"bar": null},
+      "comment": "null value should be valid obj property to be moved" },
+
+    { "doc": {"foo": null},
+      "patch": [{"op": "copy", "from": "/foo", "path": "/bar"}],
+      "expected": {"foo": null, "bar": null},
+      "comment": "null value should be valid obj property to be copied" },
+
+    { "doc": {"foo": null},
+      "patch": [{"op": "remove", "path": "/foo"}],
+      "expected": {},
+      "comment": "null value should be valid obj property to be removed" },
+
+    { "doc": {"foo": "bar"},
+      "patch": [{"op": "replace", "path": "/foo", "value": null}],
+      "expected": {"foo": null},
+      "comment": "null value should still be valid obj property replace other value" },
+
+    { "doc": {"foo": {"foo": 1, "bar": 2}},
+      "patch": [{"op": "test", "path": "/foo", "value": {"bar": 2, "foo": 1}}],
+      "comment": "test should pass despite rearrangement" },
+
+    { "doc": {"foo": [{"foo": 1, "bar": 2}]},
+      "patch": [{"op": "test", "path": "/foo", "value": [{"bar": 2, "foo": 1}]}],
+      "comment": "test should pass despite (nested) rearrangement" },
+
+    { "doc": {"foo": {"bar": [1, 2, 5, 4]}},
+      "patch": [{"op": "test", "path": "/foo", "value": {"bar": [1, 2, 5, 4]}}],
+      "comment": "test should pass - no error" },
+
+    { "doc": {"foo": {"bar": [1, 2, 5, 4]}},
+      "patch": [{"op": "test", "path": "/foo", "value": [1, 2]}],
+      "error": "test op should fail" },
+
+    { "comment": "Whole document",
+      "doc": { "foo": 1 },
+      "patch": [{"op": "test", "path": "", "value": {"foo": 1}}],
+      "disabled": true },
+
+    { "comment": "Empty-string element",
+      "doc": { "": 1 },
+      "patch": [{"op": "test", "path": "/", "value": 1}] },
+
+    { "doc": {
+            "foo": ["bar", "baz"],
+            "": 0,
+            "a/b": 1,
+            "c%d": 2,
+            "e^f": 3,
+            "g|h": 4,
+            "i\\j": 5,
+            "k\"l": 6,
+            " ": 7,
+            "m~n": 8
+            },
+      "patch": [{"op": "test", "path": "/foo", "value": ["bar", "baz"]},
+                {"op": "test", "path": "/foo/0", "value": "bar"},
+                {"op": "test", "path": "/", "value": 0},
+                {"op": "test", "path": "/a~1b", "value": 1},
+                {"op": "test", "path": "/c%d", "value": 2},
+                {"op": "test", "path": "/e^f", "value": 3},
+                {"op": "test", "path": "/g|h", "value": 4},
+                {"op": "test", "path":  "/i\\j", "value": 5},
+                {"op": "test", "path": "/k\"l", "value": 6},
+                {"op": "test", "path": "/ ", "value": 7},
+                {"op": "test", "path": "/m~0n", "value": 8}] },
+
+    { "comment": "Move to same location has no effect",
+      "doc": {"foo": 1},
+      "patch": [{"op": "move", "from": "/foo", "path": "/foo"}],
+      "expected": {"foo": 1} },
+
+    { "doc": {"foo": 1, "baz": [{"qux": "hello"}]},
+      "patch": [{"op": "move", "from": "/foo", "path": "/bar"}],
+      "expected": {"baz": [{"qux": "hello"}], "bar": 1} },
+
+    { "doc": {"baz": [{"qux": "hello"}], "bar": 1},
+      "patch": [{"op": "move", "from": "/baz/0/qux", "path": "/baz/1"}],
+      "expected": {"baz": [{}, "hello"], "bar": 1} },
+
+    { "doc": {"baz": [{"qux": "hello"}], "bar": 1},
+      "patch": [{"op": "copy", "from": "/baz/0", "path": "/boo"}],
+      "expected": {"baz":[{"qux":"hello"}],"bar":1,"boo":{"qux":"hello"}} },
+
+    { "comment": "replacing the root of the document is possible with add",
+      "doc": {"foo": "bar"},
+      "patch": [{"op": "add", "path": "", "value": {"baz": "qux"}}],
+      "expected": {"baz":"qux"}},
+
+    { "comment": "Adding to \"/-\" adds to the end of the array",
+      "doc": [ 1, 2 ],
+      "patch": [ { "op": "add", "path": "/-", "value": { "foo": [ "bar", "baz" ] } } ],
+      "expected": [ 1, 2, { "foo": [ "bar", "baz" ] } ]},
+
+    { "comment": "Adding to \"/-\" adds to the end of the array, even n levels down",
+      "doc": [ 1, 2, [ 3, [ 4, 5 ] ] ],
+      "patch": [ { "op": "add", "path": "/2/1/-", "value": { "foo": [ "bar", "baz" ] } } ],
+      "expected": [ 1, 2, [ 3, [ 4, 5, { "foo": [ "bar", "baz" ] } ] ] ]},
+
+    { "comment": "test remove with bad number should fail",
+      "doc": {"foo": 1, "baz": [{"qux": "hello"}]},
+      "patch": [{"op": "remove", "path": "/baz/1e0/qux"}],
+      "error": "remove op shouldn't remove from array with bad number" },
+
+    { "comment": "test remove on array",
+      "doc": [1, 2, 3, 4],
+      "patch": [{"op": "remove", "path": "/0"}],
+      "expected": [2, 3, 4] },
+
+    { "comment": "test repeated removes",
+      "doc": [1, 2, 3, 4],
+      "patch": [{ "op": "remove", "path": "/1" },
+                { "op": "remove", "path": "/2" }],
+      "expected": [1, 3] },
+
+    { "comment": "test remove with bad index should fail",
+      "doc": [1, 2, 3, 4],
+      "patch": [{"op": "remove", "path": "/1e0"}],
+      "error": "remove op shouldn't remove from array with bad number" },
+
+    { "comment": "test replace with bad number should fail",
+      "doc": [""],
+      "patch": [{"op": "replace", "path": "/1e0", "value": false}],
+      "error": "replace op shouldn't replace in array with bad number" },
+
+    { "comment": "test copy with bad number should fail",
+      "doc": {"baz": [1,2,3], "bar": 1},
+      "patch": [{"op": "copy", "from": "/baz/1e0", "path": "/boo"}],
+      "error": "copy op shouldn't work with bad number" },
+
+    { "comment": "test move with bad number should fail",
+      "doc": {"foo": 1, "baz": [1,2,3,4]},
+      "patch": [{"op": "move", "from": "/baz/1e0", "path": "/foo"}],
+      "error": "move op shouldn't work with bad number" },
+
+    { "comment": "test add with bad number should fail",
+      "doc": ["foo", "sil"],
+      "patch": [{"op": "add", "path": "/1e0", "value": "bar"}],
+      "error": "add op shouldn't add to array with bad number" },
+
+    { "comment": "missing 'value' parameter to add",
+      "doc": [ 1 ],
+      "patch": [ { "op": "add", "path": "/-" } ],
+      "error": "missing 'value' parameter" },
+
+    { "comment": "missing 'value' parameter to replace",
+      "doc": [ 1 ],
+      "patch": [ { "op": "replace", "path": "/0" } ],
+      "error": "missing 'value' parameter" },
+
+    { "comment": "missing 'value' parameter to test",
+      "doc": [ null ],
+      "patch": [ { "op": "test", "path": "/0" } ],
+      "error": "missing 'value' parameter" },
+
+    { "comment": "missing value parameter to test - where undef is falsy",
+      "doc": [ false ],
+      "patch": [ { "op": "test", "path": "/0" } ],
+      "error": "missing 'value' parameter" },
+
+    { "comment": "missing from parameter to copy",
+      "doc": [ 1 ],
+      "patch": [ { "op": "copy", "path": "/-" } ],
+      "error": "missing 'from' parameter" },
+
+    { "comment": "missing from parameter to move",
+      "doc": { "foo": 1 },
+      "patch": [ { "op": "move", "path": "" } ],
+      "error": "missing 'from' parameter" },
+
+    { "comment": "duplicate ops",
+      "doc": { "foo": "bar" },
+      "patch": [ { "op": "add", "path": "/baz", "value": "qux",
+                   "op": "move", "from":"/foo" } ],
+      "error": "patch has two 'op' members",
+      "disabled": true },
+
+    { "comment": "unrecognized op should fail",
+      "doc": {"foo": 1},
+      "patch": [{"op": "spam", "path": "/foo", "value": 1}],
+      "error": "Unrecognized op 'spam'" },
+
+    { "comment": "test with bad array number that has leading zeros",
+      "doc": ["foo", "bar"],
+      "patch": [{"op": "test", "path": "/00", "value": "foo"}],
+      "error": "test op should reject the array value, it has leading zeros" },
+
+    { "comment": "test with bad array number that has leading zeros",
+      "doc": ["foo", "bar"],
+      "patch": [{"op": "test", "path": "/01", "value": "bar"}],
+      "error": "test op should reject the array value, it has leading zeros" },
+
+    { "comment": "Removing nonexistent field",
+      "doc": {"foo" : "bar"},
+      "patch": [{"op": "remove", "path": "/baz"}],
+      "error": "removing a nonexistent field should fail" },
+
+    { "comment": "Removing nonexistent index",
+      "doc": ["foo", "bar"],
+      "patch": [{"op": "remove", "path": "/2"}],
+      "error": "removing a nonexistent index should fail" },
+
+    { "comment": "Patch with different capitalisation than doc",
+       "doc": {"foo":"bar"},
+       "patch": [{"op": "add", "path": "/FOO", "value": "BAR"}],
+       "expected": {"foo": "bar", "FOO": "BAR"}
+    }
+
+]

+ 243 - 0
tests/json_patch_tests.c

@@ -0,0 +1,243 @@
+/*
+  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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "unity/examples/unity_config.h"
+#include "unity/src/unity.h"
+#include "common.h"
+#include "../cJSON_Utils.h"
+
+static cJSON *parse_test_file(const char * const filename)
+{
+    char *file = NULL;
+    cJSON *json = NULL;
+
+    file = read_file(filename);
+    TEST_ASSERT_NOT_NULL_MESSAGE(file, "Failed to read file.");
+
+    json = cJSON_Parse(file);
+    TEST_ASSERT_NOT_NULL_MESSAGE(json, "Failed to parse test json.");
+    TEST_ASSERT_TRUE_MESSAGE(cJSON_IsArray(json), "Json is not an array.");
+
+    free(file);
+
+    return json;
+}
+
+static cJSON_bool test_apply_patch(const cJSON * const test)
+{
+    cJSON *doc = NULL;
+    cJSON *patch = NULL;
+    cJSON *expected = NULL;
+    cJSON *error_element = NULL;
+    cJSON *comment = NULL;
+    cJSON *disabled = NULL;
+
+    cJSON *object = NULL;
+    cJSON_bool successful = false;
+
+    /* extract all the data out of the test */
+    comment = cJSON_GetObjectItemCaseSensitive(test, "comment");
+    if (cJSON_IsString(comment))
+    {
+        printf("Testing \"%s\"\n", comment->valuestring);
+    }
+    else
+    {
+        printf("Testing unkown\n");
+    }
+
+    disabled = cJSON_GetObjectItemCaseSensitive(test, "disabled");
+    if (cJSON_IsTrue(disabled))
+    {
+        printf("SKIPPED\n");
+        return true;
+    }
+
+    doc = cJSON_GetObjectItemCaseSensitive(test, "doc");
+    TEST_ASSERT_NOT_NULL_MESSAGE(doc, "No \"doc\" in the test.");
+    patch = cJSON_GetObjectItemCaseSensitive(test, "patch");
+    TEST_ASSERT_NOT_NULL_MESSAGE(patch, "No \"patch\"in the test.");
+    /* Make a working copy of 'doc' */
+    object = cJSON_Duplicate(doc, true);
+    TEST_ASSERT_NOT_NULL(object);
+
+    expected = cJSON_GetObjectItemCaseSensitive(test, "expected");
+    error_element = cJSON_GetObjectItemCaseSensitive(test, "error");
+    if (error_element != NULL)
+    {
+        /* excepting an error */
+        TEST_ASSERT_TRUE_MESSAGE(0 != cJSONUtils_ApplyPatchesCaseSensitive(object, patch), "Test didn't fail as it's supposed to.");
+
+        successful = true;
+    }
+    else
+    {
+        /* apply the patch */
+        TEST_ASSERT_EQUAL_INT_MESSAGE(0, cJSONUtils_ApplyPatchesCaseSensitive(object, patch), "Failed to apply patches.");
+        successful = true;
+
+        if (expected != NULL)
+        {
+            successful = cJSON_Compare(object, expected, true);
+        }
+    }
+
+    cJSON_Delete(object);
+
+    if (successful)
+    {
+        printf("OK\n");
+    }
+    else
+    {
+        printf("FAILED\n");
+    }
+
+    return successful;
+}
+
+static cJSON_bool test_generate_test(cJSON *test __attribute__((unused)))
+{
+    cJSON *doc = NULL;
+    cJSON *patch = NULL;
+    cJSON *expected = NULL;
+    cJSON *disabled = NULL;
+
+    cJSON *object = NULL;
+    cJSON_bool successful = false;
+
+    char *printed_patch = NULL;
+
+    disabled = cJSON_GetObjectItemCaseSensitive(test, "disabled");
+    if (cJSON_IsTrue(disabled))
+    {
+        printf("SKIPPED\n");
+        return true;
+    }
+
+    doc = cJSON_GetObjectItemCaseSensitive(test, "doc");
+    TEST_ASSERT_NOT_NULL_MESSAGE(doc, "No \"doc\" in the test.");
+
+    /* Make a working copy of 'doc' */
+    object = cJSON_Duplicate(doc, true);
+    TEST_ASSERT_NOT_NULL(object);
+
+    expected = cJSON_GetObjectItemCaseSensitive(test, "expected");
+    if (expected == NULL)
+    {
+        cJSON_Delete(object);
+        /* if there is no expected output, this test doesn't make sense */
+        return true;
+    }
+
+    patch = cJSONUtils_GeneratePatchesCaseSensitive(doc, expected);
+    TEST_ASSERT_NOT_NULL_MESSAGE(patch, "Failed to generate patches.");
+
+    printed_patch = cJSON_Print(patch);
+    printf("%s\n", printed_patch);
+    free(printed_patch);
+
+    /* apply the generated patch */
+    TEST_ASSERT_EQUAL_INT_MESSAGE(0, cJSONUtils_ApplyPatchesCaseSensitive(object, patch), "Failed to apply generated patch.");
+
+    successful = cJSON_Compare(object, expected, true);
+
+    cJSON_Delete(patch);
+    cJSON_Delete(object);
+
+    if (successful)
+    {
+        printf("generated patch: OK\n");
+    }
+    else
+    {
+        printf("generated patch: FAILED\n");
+    }
+
+    return successful;
+}
+
+static void cjson_utils_should_pass_json_patch_test_tests(void)
+{
+    cJSON *tests = parse_test_file("json-patch-tests/tests.json");
+    cJSON *test = NULL;
+
+    cJSON_bool failed = false;
+    cJSON_ArrayForEach(test, tests)
+    {
+        failed |= !test_apply_patch(test);
+        failed |= !test_generate_test(test);
+    }
+
+    cJSON_Delete(tests);
+
+    TEST_ASSERT_FALSE_MESSAGE(failed, "Some tests failed.");
+}
+
+static void cjson_utils_should_pass_json_patch_test_spec_tests(void)
+{
+    cJSON *tests = parse_test_file("json-patch-tests/spec_tests.json");
+    cJSON *test = NULL;
+
+    cJSON_bool failed = false;
+    cJSON_ArrayForEach(test, tests)
+    {
+        failed |= !test_apply_patch(test);
+        failed |= !test_generate_test(test);
+    }
+
+    cJSON_Delete(tests);
+
+    TEST_ASSERT_FALSE_MESSAGE(failed, "Some tests failed.");
+}
+
+static void cjson_utils_should_pass_json_patch_test_cjson_utils_tests(void)
+{
+    cJSON *tests = parse_test_file("json-patch-tests/cjson-utils-tests.json");
+    cJSON *test = NULL;
+
+    cJSON_bool failed = false;
+    cJSON_ArrayForEach(test, tests)
+    {
+        failed |= !test_apply_patch(test);
+        failed |= !test_generate_test(test);
+    }
+
+    cJSON_Delete(tests);
+
+    TEST_ASSERT_FALSE_MESSAGE(failed, "Some tests failed.");
+}
+
+int main(void)
+{
+    UNITY_BEGIN();
+
+    RUN_TEST(cjson_utils_should_pass_json_patch_test_tests);
+    RUN_TEST(cjson_utils_should_pass_json_patch_test_spec_tests);
+    RUN_TEST(cjson_utils_should_pass_json_patch_test_cjson_utils_tests);
+
+    return UNITY_END();
+}

+ 125 - 0
tests/misc_tests.c

@@ -183,6 +183,127 @@ static void typecheck_functions_should_check_type(void)
     TEST_ASSERT_TRUE(cJSON_IsRaw(item));
 }
 
+static void cjson_should_not_parse_to_deeply_nested_jsons(void)
+{
+    char deep_json[CJSON_NESTING_LIMIT + 1];
+    size_t position = 0;
+
+    for (position = 0; position < sizeof(deep_json); position++)
+    {
+        deep_json[position] = '[';
+    }
+    deep_json[sizeof(deep_json) - 1] = '\0';
+
+    TEST_ASSERT_NULL_MESSAGE(cJSON_Parse(deep_json), "To deep JSONs should not be parsed.");
+}
+
+static void cjson_set_number_value_should_set_numbers(void)
+{
+    cJSON number[1] = {{NULL, NULL, NULL, cJSON_Number, NULL, 0, 0, NULL}};
+
+    cJSON_SetNumberValue(number, 1.5);
+    TEST_ASSERT_EQUAL(1, number->valueint);
+    TEST_ASSERT_EQUAL_DOUBLE(1.5, number->valuedouble);
+
+    cJSON_SetNumberValue(number, -1.5);
+    TEST_ASSERT_EQUAL(-1, number->valueint);
+    TEST_ASSERT_EQUAL_DOUBLE(-1.5, number->valuedouble);
+
+    cJSON_SetNumberValue(number, 1 + (double)INT_MAX);
+    TEST_ASSERT_EQUAL(INT_MAX, number->valueint);
+    TEST_ASSERT_EQUAL_DOUBLE(1 + (double)INT_MAX, number->valuedouble);
+
+    cJSON_SetNumberValue(number, -1 + (double)INT_MIN);
+    TEST_ASSERT_EQUAL(INT_MIN, number->valueint);
+    TEST_ASSERT_EQUAL_DOUBLE(-1 + (double)INT_MIN, number->valuedouble);
+}
+
+static void cjson_detach_item_via_pointer_should_detach_items(void)
+{
+    cJSON list[4];
+    cJSON parent[1];
+
+    memset(list, '\0', sizeof(list));
+
+    /* link the list */
+    list[0].next = &(list[1]);
+    list[1].next = &(list[2]);
+    list[2].next = &(list[3]);
+
+    list[3].prev = &(list[2]);
+    list[2].prev = &(list[1]);
+    list[1].prev = &(list[0]);
+
+    parent->child = &list[0];
+
+    /* detach in the middle (list[1]) */
+    TEST_ASSERT_TRUE_MESSAGE(cJSON_DetachItemViaPointer(parent, &(list[1])) == &(list[1]), "Failed to detach in the middle.");
+    TEST_ASSERT_TRUE_MESSAGE((list[1].prev == NULL) && (list[1].next == NULL), "Didn't set pointers of detached item to NULL.");
+    TEST_ASSERT_TRUE((list[0].next == &(list[2])) && (list[2].prev == &(list[0])));
+
+    /* detach beginning (list[0]) */
+    TEST_ASSERT_TRUE_MESSAGE(cJSON_DetachItemViaPointer(parent, &(list[0])) == &(list[0]), "Failed to detach beginning.");
+    TEST_ASSERT_TRUE_MESSAGE((list[0].prev == NULL) && (list[0].next == NULL), "Didn't set pointers of detached item to NULL.");
+    TEST_ASSERT_TRUE_MESSAGE((list[2].prev == NULL) && (parent->child == &(list[2])), "Didn't set the new beginning.");
+
+    /* detach end (list[3])*/
+    TEST_ASSERT_TRUE_MESSAGE(cJSON_DetachItemViaPointer(parent, &(list[3])) == &(list[3]), "Failed to detach end.");
+    TEST_ASSERT_TRUE_MESSAGE((list[3].prev == NULL) && (list[3].next == NULL), "Didn't set pointers of detached item to NULL.");
+    TEST_ASSERT_TRUE_MESSAGE((list[2].next == NULL) && (parent->child == &(list[2])), "Didn't set the new end");
+
+    /* detach single item (list[2]) */
+    TEST_ASSERT_TRUE_MESSAGE(cJSON_DetachItemViaPointer(parent, &list[2]) == &list[2], "Failed to detach single item.");
+    TEST_ASSERT_TRUE_MESSAGE((list[2].prev == NULL) && (list[2].next == NULL), "Didn't set pointers of detached item to NULL.");
+    TEST_ASSERT_NULL_MESSAGE(parent->child, "Child of the parent wasn't set to NULL.");
+}
+
+static void cjson_replace_item_via_pointer_should_replace_items(void)
+{
+    cJSON replacements[3];
+    cJSON *beginning = NULL;
+    cJSON *middle = NULL;
+    cJSON *end = NULL;
+    cJSON *array = NULL;
+
+    beginning = cJSON_CreateNull();
+    TEST_ASSERT_NOT_NULL(beginning);
+    middle = cJSON_CreateNull();
+    TEST_ASSERT_NOT_NULL(middle);
+    end = cJSON_CreateNull();
+    TEST_ASSERT_NOT_NULL(end);
+
+    array = cJSON_CreateArray();
+    TEST_ASSERT_NOT_NULL(array);
+
+    cJSON_AddItemToArray(array, beginning);
+    cJSON_AddItemToArray(array, middle);
+    cJSON_AddItemToArray(array, end);
+
+
+    memset(replacements, '\0', sizeof(replacements));
+
+    /* replace beginning */
+    TEST_ASSERT_TRUE(cJSON_ReplaceItemViaPointer(array, beginning, &(replacements[0])));
+    TEST_ASSERT_NULL(replacements[0].prev);
+    TEST_ASSERT_TRUE(replacements[0].next == middle);
+    TEST_ASSERT_TRUE(middle->prev == &(replacements[0]));
+    TEST_ASSERT_TRUE(array->child == &(replacements[0]));
+
+    /* replace middle */
+    TEST_ASSERT_TRUE(cJSON_ReplaceItemViaPointer(array, middle, &(replacements[1])));
+    TEST_ASSERT_TRUE(replacements[1].prev == &(replacements[0]));
+    TEST_ASSERT_TRUE(replacements[1].next == end);
+    TEST_ASSERT_TRUE(end->prev == &(replacements[1]));
+
+    /* replace end */
+    TEST_ASSERT_TRUE(cJSON_ReplaceItemViaPointer(array, end, &(replacements[2])));
+    TEST_ASSERT_TRUE(replacements[2].prev == &(replacements[1]));
+    TEST_ASSERT_NULL(replacements[2].next);
+    TEST_ASSERT_TRUE(replacements[1].next == &(replacements[2]));
+
+    cJSON_free(array);
+}
+
 int main(void)
 {
     UNITY_BEGIN();
@@ -192,6 +313,10 @@ int main(void)
     RUN_TEST(cjson_get_object_item_should_get_object_items);
     RUN_TEST(cjson_get_object_item_case_sensitive_should_get_object_items);
     RUN_TEST(typecheck_functions_should_check_type);
+    RUN_TEST(cjson_should_not_parse_to_deeply_nested_jsons);
+    RUN_TEST(cjson_set_number_value_should_set_numbers);
+    RUN_TEST(cjson_detach_item_via_pointer_should_detach_items);
+    RUN_TEST(cjson_replace_item_via_pointer_should_replace_items);
 
     return UNITY_END();
 }

+ 205 - 0
tests/old_utils_tests.c

@@ -0,0 +1,205 @@
+/*
+  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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "unity/examples/unity_config.h"
+#include "unity/src/unity.h"
+#include "common.h"
+#include "../cJSON_Utils.h"
+
+/* JSON Apply Merge tests: */
+const char *merges[15][3] =
+{
+    {"{\"a\":\"b\"}", "{\"a\":\"c\"}", "{\"a\":\"c\"}"},
+    {"{\"a\":\"b\"}", "{\"b\":\"c\"}", "{\"a\":\"b\",\"b\":\"c\"}"},
+    {"{\"a\":\"b\"}", "{\"a\":null}", "{}"},
+    {"{\"a\":\"b\",\"b\":\"c\"}", "{\"a\":null}", "{\"b\":\"c\"}"},
+    {"{\"a\":[\"b\"]}", "{\"a\":\"c\"}", "{\"a\":\"c\"}"},
+    {"{\"a\":\"c\"}", "{\"a\":[\"b\"]}", "{\"a\":[\"b\"]}"},
+    {"{\"a\":{\"b\":\"c\"}}", "{\"a\":{\"b\":\"d\",\"c\":null}}", "{\"a\":{\"b\":\"d\"}}"},
+    {"{\"a\":[{\"b\":\"c\"}]}", "{\"a\":[1]}", "{\"a\":[1]}"},
+    {"[\"a\",\"b\"]", "[\"c\",\"d\"]", "[\"c\",\"d\"]"},
+    {"{\"a\":\"b\"}", "[\"c\"]", "[\"c\"]"},
+    {"{\"a\":\"foo\"}", "null", "null"},
+    {"{\"a\":\"foo\"}", "\"bar\"", "\"bar\""},
+    {"{\"e\":null}", "{\"a\":1}", "{\"e\":null,\"a\":1}"},
+    {"[1,2]", "{\"a\":\"b\",\"c\":null}", "{\"a\":\"b\"}"},
+    {"{}","{\"a\":{\"bb\":{\"ccc\":null}}}", "{\"a\":{\"bb\":{}}}"}
+};
+
+static void json_pointer_tests(void)
+{
+    cJSON *root = NULL;
+    const char *json=
+        "{"
+        "\"foo\": [\"bar\", \"baz\"],"
+        "\"\": 0,"
+        "\"a/b\": 1,"
+        "\"c%d\": 2,"
+        "\"e^f\": 3,"
+        "\"g|h\": 4,"
+        "\"i\\\\j\": 5,"
+        "\"k\\\"l\": 6,"
+        "\" \": 7,"
+        "\"m~n\": 8"
+        "}";
+
+    root = cJSON_Parse(json);
+
+    TEST_ASSERT_EQUAL_PTR(cJSONUtils_GetPointer(root, ""), root);
+    TEST_ASSERT_EQUAL_PTR(cJSONUtils_GetPointer(root, "/foo"), cJSON_GetObjectItem(root, "foo"));
+    TEST_ASSERT_EQUAL_PTR(cJSONUtils_GetPointer(root, "/foo/0"), cJSON_GetObjectItem(root, "foo")->child);
+    TEST_ASSERT_EQUAL_PTR(cJSONUtils_GetPointer(root, "/foo/0"), cJSON_GetObjectItem(root, "foo")->child);
+    TEST_ASSERT_EQUAL_PTR(cJSONUtils_GetPointer(root, "/"), cJSON_GetObjectItem(root, ""));
+    TEST_ASSERT_EQUAL_PTR(cJSONUtils_GetPointer(root, "/a~1b"), cJSON_GetObjectItem(root, "a/b"));
+    TEST_ASSERT_EQUAL_PTR(cJSONUtils_GetPointer(root, "/c%d"), cJSON_GetObjectItem(root, "c%d"));
+    TEST_ASSERT_EQUAL_PTR(cJSONUtils_GetPointer(root, "/c^f"), cJSON_GetObjectItem(root, "c^f"));
+    TEST_ASSERT_EQUAL_PTR(cJSONUtils_GetPointer(root, "/c|f"), cJSON_GetObjectItem(root, "c|f"));
+    TEST_ASSERT_EQUAL_PTR(cJSONUtils_GetPointer(root, "/i\\j"), cJSON_GetObjectItem(root, "i\\j"));
+    TEST_ASSERT_EQUAL_PTR(cJSONUtils_GetPointer(root, "/k\"l"), cJSON_GetObjectItem(root, "k\"l"));
+    TEST_ASSERT_EQUAL_PTR(cJSONUtils_GetPointer(root, "/ "), cJSON_GetObjectItem(root, " "));
+    TEST_ASSERT_EQUAL_PTR(cJSONUtils_GetPointer(root, "/m~0n"), cJSON_GetObjectItem(root, "m~n"));
+
+    cJSON_Delete(root);
+}
+
+static void misc_tests(void)
+{
+    /* Misc tests */
+    int numbers[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+    cJSON *object = NULL;
+    cJSON *nums = NULL;
+    cJSON *num6 = NULL;
+    char *pointer = NULL;
+
+    printf("JSON Pointer construct\n");
+    object = cJSON_CreateObject();
+    nums = cJSON_CreateIntArray(numbers, 10);
+    num6 = cJSON_GetArrayItem(nums, 6);
+    cJSON_AddItemToObject(object, "numbers", nums);
+
+    pointer = cJSONUtils_FindPointerFromObjectTo(object, num6);
+    TEST_ASSERT_EQUAL_STRING("/numbers/6", pointer);
+    free(pointer);
+
+    pointer = cJSONUtils_FindPointerFromObjectTo(object, nums);
+    TEST_ASSERT_EQUAL_STRING("/numbers", pointer);
+    free(pointer);
+
+    pointer = cJSONUtils_FindPointerFromObjectTo(object, object);
+    TEST_ASSERT_EQUAL_STRING("", pointer);
+    free(pointer);
+
+    cJSON_Delete(object);
+}
+
+static void sort_tests(void)
+{
+    /* Misc tests */
+    const char *random = "QWERTYUIOPASDFGHJKLZXCVBNM";
+    char buf[2] = {'\0', '\0'};
+    cJSON *sortme = NULL;
+    size_t i = 0;
+    cJSON *current_element = NULL;
+
+    /* JSON Sort test: */
+    sortme = cJSON_CreateObject();
+    for (i = 0; i < 26; i++)
+    {
+        buf[0] = random[i];
+        cJSON_AddItemToObject(sortme, buf, cJSON_CreateNumber(1));
+    }
+
+    cJSONUtils_SortObject(sortme);
+
+    /* check sorting */
+    current_element = sortme->child->next;
+    for (i = 1; (i < 26) && (current_element != NULL) && (current_element->prev != NULL); i++)
+    {
+        TEST_ASSERT_TRUE(current_element->string[0] >= current_element->prev->string[0]);
+        current_element = current_element->next;
+    }
+
+    cJSON_Delete(sortme);
+}
+
+static void merge_tests(void)
+{
+    size_t i = 0;
+    char *patchtext = NULL;
+    char *after = NULL;
+
+    /* Merge tests: */
+    printf("JSON Merge Patch tests\n");
+    for (i = 0; i < 15; i++)
+    {
+        cJSON *object_to_be_merged = cJSON_Parse(merges[i][0]);
+        cJSON *patch = cJSON_Parse(merges[i][1]);
+        patchtext = cJSON_PrintUnformatted(patch);
+        object_to_be_merged = cJSONUtils_MergePatch(object_to_be_merged, patch);
+        after = cJSON_PrintUnformatted(object_to_be_merged);
+        TEST_ASSERT_EQUAL_STRING(merges[i][2], after);
+
+        free(patchtext);
+        free(after);
+        cJSON_Delete(object_to_be_merged);
+        cJSON_Delete(patch);
+    }
+}
+
+static void generate_merge_tests(void)
+{
+    size_t i = 0;
+    char *patchedtext = NULL;
+
+    /* Generate Merge tests: */
+    for (i = 0; i < 15; i++)
+    {
+        cJSON *from = cJSON_Parse(merges[i][0]);
+        cJSON *to = cJSON_Parse(merges[i][2]);
+        cJSON *patch = cJSONUtils_GenerateMergePatch(from,to);
+        from = cJSONUtils_MergePatch(from,patch);
+        patchedtext = cJSON_PrintUnformatted(from);
+        TEST_ASSERT_EQUAL_STRING(merges[i][2], patchedtext);
+
+        cJSON_Delete(from);
+        cJSON_Delete(to);
+        cJSON_Delete(patch);
+        free(patchedtext);
+    }
+}
+
+int main(void)
+{
+    UNITY_BEGIN();
+
+    RUN_TEST(json_pointer_tests);
+    RUN_TEST(misc_tests);
+    RUN_TEST(sort_tests);
+    RUN_TEST(merge_tests);
+    RUN_TEST(generate_merge_tests);
+
+    return UNITY_END();
+}

+ 12 - 4
tests/parse_array.c

@@ -30,8 +30,6 @@
 
 static cJSON item[1];
 
-static const unsigned char *error_pointer = NULL;
-
 static void assert_is_array(cJSON *array_item)
 {
     TEST_ASSERT_NOT_NULL_MESSAGE(array_item, "Item is NULL.");
@@ -46,13 +44,23 @@ static void assert_is_array(cJSON *array_item)
 
 static void assert_not_array(const char *json)
 {
-    TEST_ASSERT_NULL(parse_array(item, (const unsigned char*)json, &error_pointer, &global_hooks));
+    parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } };
+    buffer.content = (const unsigned char*)json;
+    buffer.length = strlen(json) + sizeof("");
+    buffer.hooks = global_hooks;
+
+    TEST_ASSERT_FALSE(parse_array(item, &buffer));
     assert_is_invalid(item);
 }
 
 static void assert_parse_array(const char *json)
 {
-    TEST_ASSERT_NOT_NULL(parse_array(item, (const unsigned char*)json, &error_pointer, &global_hooks));
+    parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } };
+    buffer.content = (const unsigned char*)json;
+    buffer.length = strlen(json) + sizeof("");
+    buffer.hooks = global_hooks;
+
+    TEST_ASSERT_TRUE(parse_array(item, &buffer));
     assert_is_array(item);
 }
 

+ 5 - 1
tests/parse_number.c

@@ -45,7 +45,11 @@ static void assert_is_number(cJSON *number_item)
 
 static void assert_parse_number(const char *string, int integer, double real)
 {
-    TEST_ASSERT_NOT_NULL(parse_number(item, (const unsigned char*)string));
+    parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } };
+    buffer.content = (const unsigned char*)string;
+    buffer.length = strlen(string) + sizeof("");
+
+    TEST_ASSERT_TRUE(parse_number(item, &buffer));
     assert_is_number(item);
     TEST_ASSERT_EQUAL_INT(integer, item->valueint);
     TEST_ASSERT_EQUAL_DOUBLE(real, item->valuedouble);

+ 12 - 4
tests/parse_object.c

@@ -30,8 +30,6 @@
 
 static cJSON item[1];
 
-static const unsigned char *error_pointer = NULL;
-
 static void assert_is_object(cJSON *object_item)
 {
     TEST_ASSERT_NOT_NULL_MESSAGE(object_item, "Item is NULL.");
@@ -54,14 +52,24 @@ static void assert_is_child(cJSON *child_item, const char *name, int type)
 
 static void assert_not_object(const char *json)
 {
-    TEST_ASSERT_NULL(parse_object(item, (const unsigned char*)json, &error_pointer, &global_hooks));
+    parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0 } };
+    parsebuffer.content = (const unsigned char*)json;
+    parsebuffer.length = strlen(json) + sizeof("");
+    parsebuffer.hooks = global_hooks;
+
+    TEST_ASSERT_FALSE(parse_object(item, &parsebuffer));
     assert_is_invalid(item);
     reset(item);
 }
 
 static void assert_parse_object(const char *json)
 {
-    TEST_ASSERT_NOT_NULL(parse_object(item, (const unsigned char*)json, &error_pointer, &global_hooks));
+    parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0 } };
+    parsebuffer.content = (const unsigned char*)json;
+    parsebuffer.length = strlen(json) + sizeof("");
+    parsebuffer.hooks = global_hooks;
+
+    TEST_ASSERT_TRUE(parse_object(item, &parsebuffer));
     assert_is_object(item);
 }
 

+ 16 - 6
tests/parse_string.c

@@ -30,8 +30,6 @@
 
 static cJSON item[1];
 
-static const unsigned char *error_pointer = NULL;
-
 static void assert_is_string(cJSON *string_item)
 {
     TEST_ASSERT_NOT_NULL_MESSAGE(string_item, "Item is NULL.");
@@ -47,16 +45,28 @@ static void assert_is_string(cJSON *string_item)
 
 static void assert_parse_string(const char *string, const char *expected)
 {
-    TEST_ASSERT_NOT_NULL_MESSAGE(parse_string(item, (const unsigned char*)string, &error_pointer, &global_hooks), "Couldn't parse string.");
+    parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } };
+    buffer.content = (const unsigned char*)string;
+    buffer.length = strlen(string) + sizeof("");
+    buffer.hooks = global_hooks;
+
+    TEST_ASSERT_TRUE_MESSAGE(parse_string(item, &buffer), "Couldn't parse string.");
     assert_is_string(item);
     TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, item->valuestring, "The parsed result isn't as expected.");
     global_hooks.deallocate(item->valuestring);
     item->valuestring = NULL;
 }
 
-#define assert_not_parse_string(string) \
-    TEST_ASSERT_NULL_MESSAGE(parse_string(item, (const unsigned char*)string, &error_pointer, &global_hooks), "Malformed string should not be accepted");\
-    assert_is_invalid(item)
+static void assert_not_parse_string(const char * const string)
+{
+    parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } };
+    buffer.content = (const unsigned char*)string;
+    buffer.length = strlen(string) + sizeof("");
+    buffer.hooks = global_hooks;
+
+    TEST_ASSERT_FALSE_MESSAGE(parse_string(item, &buffer), "Malformed string should not be accepted.");
+    assert_is_invalid(item);
+}
 
 
 

+ 6 - 2
tests/parse_value.c

@@ -29,7 +29,6 @@
 #include "common.h"
 
 static cJSON item[1];
-const unsigned char *error_pointer = NULL;
 
 static void assert_is_value(cJSON *value_item, int type)
 {
@@ -44,7 +43,12 @@ static void assert_is_value(cJSON *value_item, int type)
 
 static void assert_parse_value(const char *string, int type)
 {
-    TEST_ASSERT_NOT_NULL(parse_value(item, (const unsigned char*)string, &error_pointer, &global_hooks));
+    parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } };
+    buffer.content = (const unsigned char*) string;
+    buffer.length = strlen(string) + sizeof("");
+    buffer.hooks = global_hooks;
+
+    TEST_ASSERT_TRUE(parse_value(item, &buffer));
     assert_is_value(item, type);
 }
 

+ 82 - 0
tests/parse_with_opts.c

@@ -0,0 +1,82 @@
+/*
+  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 "unity/examples/unity_config.h"
+#include "unity/src/unity.h"
+#include "common.h"
+
+static void parse_with_opts_should_handle_null(void)
+{
+    const char *error_pointer = NULL;
+    cJSON *item = NULL;
+    TEST_ASSERT_NULL_MESSAGE(cJSON_ParseWithOpts(NULL, &error_pointer, false), "Failed to handle NULL input.");
+    item = cJSON_ParseWithOpts("{}", NULL, false);
+    TEST_ASSERT_NOT_NULL_MESSAGE(item, "Failed to handle NULL error pointer.");
+    cJSON_Delete(item);
+    TEST_ASSERT_NULL_MESSAGE(cJSON_ParseWithOpts(NULL, NULL, false), "Failed to handle both NULL.");
+    TEST_ASSERT_NULL_MESSAGE(cJSON_ParseWithOpts("{", NULL, false), "Failed to handle NULL error pointer with parse error.");
+}
+
+static void parse_with_opts_should_handle_empty_strings(void)
+{
+    const char empty_string[] = "";
+    const char *error_pointer = NULL;
+    TEST_ASSERT_NULL(cJSON_ParseWithOpts(empty_string, NULL, false));
+    error_pointer = cJSON_GetErrorPtr();
+    TEST_ASSERT_EQUAL_INT(0, error_pointer - empty_string);
+    TEST_ASSERT_NULL(cJSON_ParseWithOpts(empty_string, &error_pointer, false));
+    TEST_ASSERT_EQUAL_INT(0, error_pointer - empty_string);
+}
+
+static void parse_with_opts_should_require_null_if_requested(void)
+{
+    cJSON *item = cJSON_ParseWithOpts("{}", NULL, true);
+    TEST_ASSERT_NOT_NULL(item);
+    cJSON_Delete(item);
+    item = cJSON_ParseWithOpts("{} \n", NULL, true);
+    TEST_ASSERT_NOT_NULL(item);
+    cJSON_Delete(item);
+    TEST_ASSERT_NULL(cJSON_ParseWithOpts("{}x", NULL, true));
+}
+
+static void parse_with_opts_should_return_parse_end(void)
+{
+    const char json[] = "[] empty array XD";
+    const char *parse_end = NULL;
+
+    cJSON *item = cJSON_ParseWithOpts(json, &parse_end, false);
+    TEST_ASSERT_NOT_NULL(item);
+    TEST_ASSERT_EQUAL_INT(2, parse_end - json);
+    cJSON_Delete(item);
+}
+
+int main(void)
+{
+    UNITY_BEGIN();
+
+    RUN_TEST(parse_with_opts_should_handle_null);
+    RUN_TEST(parse_with_opts_should_handle_empty_strings);
+    RUN_TEST(parse_with_opts_should_require_null_if_requested);
+    RUN_TEST(parse_with_opts_should_return_parse_end);
+
+    return UNITY_END();
+}

+ 14 - 6
tests/print_array.c

@@ -29,31 +29,39 @@ static void assert_print_array(const char * const expected, const char * const i
     unsigned char printed_unformatted[1024];
     unsigned char printed_formatted[1024];
 
-    const unsigned char *error_pointer;
     cJSON item[1];
 
-    printbuffer formatted_buffer;
-    printbuffer unformatted_buffer;
+    printbuffer formatted_buffer = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
+    printbuffer unformatted_buffer = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
+
+    parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0 } };
+    parsebuffer.content = (const unsigned char*)input;
+    parsebuffer.length = strlen(input) + sizeof("");
+    parsebuffer.hooks = global_hooks;
 
     /* buffer for formatted printing */
     formatted_buffer.buffer = printed_formatted;
     formatted_buffer.length = sizeof(printed_formatted);
     formatted_buffer.offset = 0;
     formatted_buffer.noalloc = true;
+    formatted_buffer.hooks = global_hooks;
 
     /* buffer for unformatted printing */
     unformatted_buffer.buffer = printed_unformatted;
     unformatted_buffer.length = sizeof(printed_unformatted);
     unformatted_buffer.offset = 0;
     unformatted_buffer.noalloc = true;
+    unformatted_buffer.hooks = global_hooks;
 
     memset(item, 0, sizeof(item));
-    TEST_ASSERT_NOT_NULL_MESSAGE(parse_array(item, (const unsigned char*)input, &error_pointer, &global_hooks), "Failed to parse array.");
+    TEST_ASSERT_TRUE_MESSAGE(parse_array(item, &parsebuffer), "Failed to parse array.");
 
-    TEST_ASSERT_TRUE_MESSAGE(print_array(item, 0, false, &unformatted_buffer, &global_hooks), "Failed to print unformatted string.");
+    unformatted_buffer.format = false;
+    TEST_ASSERT_TRUE_MESSAGE(print_array(item, &unformatted_buffer), "Failed to print unformatted string.");
     TEST_ASSERT_EQUAL_STRING_MESSAGE(input, printed_unformatted, "Unformatted array is not correct.");
 
-    TEST_ASSERT_TRUE_MESSAGE(print_array(item, 0, true, &formatted_buffer, &global_hooks), "Failed to print formatted string.");
+    formatted_buffer.format = true;
+    TEST_ASSERT_TRUE_MESSAGE(print_array(item, &formatted_buffer), "Failed to print formatted string.");
     TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, printed_formatted, "Formatted array is not correct.");
 
     reset(item);

+ 10 - 19
tests/print_number.c

@@ -28,16 +28,17 @@ static void assert_print_number(const char *expected, double input)
 {
     unsigned char printed[1024];
     cJSON item[1];
-    printbuffer buffer;
+    printbuffer buffer = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
     buffer.buffer = printed;
     buffer.length = sizeof(printed);
     buffer.offset = 0;
     buffer.noalloc = true;
+    buffer.hooks = global_hooks;
 
     memset(item, 0, sizeof(item));
     cJSON_SetNumberValue(item, input);
 
-    TEST_ASSERT_TRUE_MESSAGE(print_number(item, &buffer, &global_hooks), "Failed to print number.");
+    TEST_ASSERT_TRUE_MESSAGE(print_number(item, &buffer), "Failed to print number.");
     TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, buffer.buffer, "Printed number is not as expected.");
 }
 
@@ -63,19 +64,19 @@ static void print_number_should_print_positive_integers(void)
 static void print_number_should_print_positive_reals(void)
 {
     assert_print_number("0.123", 0.123);
-    assert_print_number("1.000000e-09", 10e-10);
+    assert_print_number("1e-09", 10e-10);
     assert_print_number("1000000000000", 10e11);
-    assert_print_number("1.230000e+129", 123e+127);
-    assert_print_number("0", 123e-128); /* TODO: Maybe this shouldn't be 0 */
+    assert_print_number("1.23e+129", 123e+127);
+    assert_print_number("1.23e-126", 123e-128);
 }
 
 static void print_number_should_print_negative_reals(void)
 {
     assert_print_number("-0.0123", -0.0123);
-    assert_print_number("-1.000000e-09", -10e-10);
-    assert_print_number("-1000000000000000000000", -10e20);
-    assert_print_number("-1.230000e+129", -123e+127);
-    assert_print_number("-1.230000e-126", -123e-128);
+    assert_print_number("-1e-09", -10e-10);
+    assert_print_number("-1e+21", -10e20);
+    assert_print_number("-1.23e+129", -123e+127);
+    assert_print_number("-1.23e-126", -123e-128);
 }
 
 static void print_number_should_print_non_number(void)
@@ -87,15 +88,6 @@ static void print_number_should_print_non_number(void)
     /* assert_print_number("null", -INFTY); */
 }
 
-static void trim_trailing_zeroes_should_trim_trailing_zeroes(void)
-{
-    TEST_ASSERT_EQUAL_INT(2, trim_trailing_zeroes((const unsigned char*)"10.00", (int)(sizeof("10.00") - 1), '.'));
-    TEST_ASSERT_EQUAL_INT(0, trim_trailing_zeroes((const unsigned char*)".00", (int)(sizeof(".00") - 1), '.'));
-    TEST_ASSERT_EQUAL_INT(0, trim_trailing_zeroes((const unsigned char*)"00", (int)(sizeof("00") - 1), '.'));
-    TEST_ASSERT_EQUAL_INT(-1, trim_trailing_zeroes(NULL, 10, '.'));
-    TEST_ASSERT_EQUAL_INT(-1, trim_trailing_zeroes((const unsigned char*)"", 0, '.'));
-}
-
 int main(void)
 {
     /* initialize cJSON item */
@@ -107,7 +99,6 @@ int main(void)
     RUN_TEST(print_number_should_print_positive_reals);
     RUN_TEST(print_number_should_print_negative_reals);
     RUN_TEST(print_number_should_print_non_number);
-    RUN_TEST(trim_trailing_zeroes_should_trim_trailing_zeroes);
 
     return UNITY_END();
 }

+ 15 - 6
tests/print_object.c

@@ -29,31 +29,40 @@ static void assert_print_object(const char * const expected, const char * const
     unsigned char printed_unformatted[1024];
     unsigned char printed_formatted[1024];
 
-    const unsigned char *error_pointer;
     cJSON item[1];
 
-    printbuffer formatted_buffer;
-    printbuffer unformatted_buffer;
+    printbuffer formatted_buffer = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
+    printbuffer unformatted_buffer = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
+    parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0 } };
+
+    /* buffer for parsing */
+    parsebuffer.content = (const unsigned char*)input;
+    parsebuffer.length = strlen(input) + sizeof("");
+    parsebuffer.hooks = global_hooks;
 
     /* buffer for formatted printing */
     formatted_buffer.buffer = printed_formatted;
     formatted_buffer.length = sizeof(printed_formatted);
     formatted_buffer.offset = 0;
     formatted_buffer.noalloc = true;
+    formatted_buffer.hooks = global_hooks;
 
     /* buffer for unformatted printing */
     unformatted_buffer.buffer = printed_unformatted;
     unformatted_buffer.length = sizeof(printed_unformatted);
     unformatted_buffer.offset = 0;
     unformatted_buffer.noalloc = true;
+    unformatted_buffer.hooks = global_hooks;
 
     memset(item, 0, sizeof(item));
-    TEST_ASSERT_NOT_NULL_MESSAGE(parse_object(item, (const unsigned char*)input, &error_pointer, &global_hooks), "Failed to parse object.");
+    TEST_ASSERT_TRUE_MESSAGE(parse_object(item, &parsebuffer), "Failed to parse object.");
 
-    TEST_ASSERT_TRUE_MESSAGE(print_object(item, 0, false, &unformatted_buffer, &global_hooks), "Failed to print unformatted string.");
+    unformatted_buffer.format = false;
+    TEST_ASSERT_TRUE_MESSAGE(print_object(item, &unformatted_buffer), "Failed to print unformatted string.");
     TEST_ASSERT_EQUAL_STRING_MESSAGE(input, printed_unformatted, "Unformatted object is not correct.");
 
-    TEST_ASSERT_TRUE_MESSAGE(print_object(item, 0, true, &formatted_buffer, &global_hooks), "Failed to print formatted string.");
+    formatted_buffer.format = true;
+    TEST_ASSERT_TRUE_MESSAGE(print_object(item, &formatted_buffer), "Failed to print formatted string.");
     TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, printed_formatted, "Formatted ojbect is not correct.");
 
     reset(item);

+ 3 - 2
tests/print_string.c

@@ -27,13 +27,14 @@
 static void assert_print_string(const char *expected, const char *input)
 {
     unsigned char printed[1024];
-    printbuffer buffer;
+    printbuffer buffer = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
     buffer.buffer = printed;
     buffer.length = sizeof(printed);
     buffer.offset = 0;
     buffer.noalloc = true;
+    buffer.hooks = global_hooks;
 
-    TEST_ASSERT_TRUE_MESSAGE(print_string_ptr((const unsigned char*)input, &buffer, &global_hooks), "Failed to print string.");
+    TEST_ASSERT_TRUE_MESSAGE(print_string_ptr((const unsigned char*)input, &buffer), "Failed to print string.");
     TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, printed, "The printed string isn't as expected.");
 }
 

+ 9 - 4
tests/print_value.c

@@ -31,19 +31,24 @@
 static void assert_print_value(const char *input)
 {
     unsigned char printed[1024];
-    const unsigned char *error_pointer = NULL;
     cJSON item[1];
-    printbuffer buffer;
+    printbuffer buffer = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
+    parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0 } };
     buffer.buffer = printed;
     buffer.length = sizeof(printed);
     buffer.offset = 0;
     buffer.noalloc = true;
+    buffer.hooks = global_hooks;
+
+    parsebuffer.content = (const unsigned char*)input;
+    parsebuffer.length = strlen(input) + sizeof("");
+    parsebuffer.hooks = global_hooks;
 
     memset(item, 0, sizeof(item));
 
-    TEST_ASSERT_NOT_NULL_MESSAGE(parse_value(item, (const unsigned char*)input, &error_pointer, &global_hooks), "Failed to parse value.");
+    TEST_ASSERT_TRUE_MESSAGE(parse_value(item, &parsebuffer), "Failed to parse value.");
 
-    TEST_ASSERT_TRUE_MESSAGE(print_value(item, 0, false, &buffer, &global_hooks), "Failed to print value.");
+    TEST_ASSERT_TRUE_MESSAGE(print_value(item, &buffer), "Failed to print value.");
     TEST_ASSERT_EQUAL_STRING_MESSAGE(input, buffer.buffer, "Printed value is not as expected.");
 
     reset(item);

+ 3 - 1
tests/unity/.travis.yml

@@ -12,7 +12,9 @@ matrix:
 before_install:
   - if [ "$TRAVIS_OS_NAME" == "osx" ]; then rvm install 2.1 && rvm use 2.1 && ruby -v; fi
   - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get install --assume-yes --quiet gcc-multilib; fi
-install: gem install rspec
+install:
+  - gem install rspec
+  - gem install rubocop
 script:
   - cd test && rake ci
   - make -s

+ 17 - 8
tests/unity/README.md

@@ -2,7 +2,7 @@ Unity Test API
 ==============
 
 [![Unity Build Status](https://api.travis-ci.org/ThrowTheSwitch/Unity.png?branch=master)](https://travis-ci.org/ThrowTheSwitch/Unity)
-__Copyright (c) 2007 - 2014 Unity Project by Mike Karlesky, Mark VanderVoord, and Greg Williams__
+__Copyright (c) 2007 - 2017 Unity Project by Mike Karlesky, Mark VanderVoord, and Greg Williams__
 
 Running Tests
 -------------
@@ -109,6 +109,18 @@ Compares two integers for equality and display errors as hexadecimal.  Like the
 you can specify the size... here the size will also effect how many nibbles are shown (for example, `HEX16`
 will show 4 nibbles).
 
+    TEST_ASSERT_EQUAL(expected, actual)
+
+Another way of calling TEST_ASSERT_EQUAL_INT
+
+    TEST_ASSERT_INT_WITHIN(delta, expected, actual)
+
+Asserts that the actual value is within plus or minus delta of the expected value.  This also comes in
+size specific variants.
+
+Arrays
+------
+
     _ARRAY
 
 You can append `_ARRAY` to any of these macros to make an array comparison of that type.  Here you will
@@ -117,15 +129,12 @@ additional argument which is the number of elements to compare.  For example:
 
     TEST_ASSERT_EQUAL_HEX8_ARRAY(expected, actual, elements)
 
-    TEST_ASSERT_EQUAL(expected, actual)
-
-Another way of calling TEST_ASSERT_EQUAL_INT
-
-    TEST_ASSERT_INT_WITHIN(delta, expected, actual)
+    _EACH_EQUAL
 
-Asserts that the actual value is within plus or minus delta of the expected value.  This also comes in
-size specific variants.
+Another array comparison option is to check that EVERY element of an array is equal to a single expected
+value. You do this by specifying the EACH_EQUAL macro. For example:
 
+    TEST_ASSERT_EACH_EQUAL_INT32(expected, actual, elements)
 
 Numerical Assertions: Bitwise
 -----------------------------

+ 67 - 64
tests/unity/auto/colour_prompt.rb

@@ -4,63 +4,62 @@
 #   [Released under MIT License. Please refer to license.txt for details]
 # ==========================================
 
-if RUBY_PLATFORM =~/(win|w)32$/
-	begin
-		require 'Win32API'
-	rescue LoadError
-		puts "ERROR! \"Win32API\" library not found"
-		puts "\"Win32API\" is required for colour on a windows machine"
-		puts "  try => \"gem install Win32API\" on the command line"
-		puts
-	end
-	# puts
+if RUBY_PLATFORM =~ /(win|w)32$/
+  begin
+    require 'Win32API'
+  rescue LoadError
+    puts 'ERROR! "Win32API" library not found'
+    puts '"Win32API" is required for colour on a windows machine'
+    puts '  try => "gem install Win32API" on the command line'
+    puts
+  end
+  # puts
   # puts 'Windows Environment Detected...'
-	# puts 'Win32API Library Found.'
-	# puts
+  # puts 'Win32API Library Found.'
+  # puts
 end
 
 class ColourCommandLine
   def initialize
-    if RUBY_PLATFORM =~/(win|w)32$/
-      get_std_handle = Win32API.new("kernel32", "GetStdHandle", ['L'], 'L')
-      @set_console_txt_attrb =
-        Win32API.new("kernel32","SetConsoleTextAttribute",['L','N'], 'I')
-      @hout = get_std_handle.call(-11)
-    end
+    return unless RUBY_PLATFORM =~ /(win|w)32$/
+    get_std_handle = Win32API.new('kernel32', 'GetStdHandle', ['L'], 'L')
+    @set_console_txt_attrb =
+      Win32API.new('kernel32', 'SetConsoleTextAttribute', %w(L N), 'I')
+    @hout = get_std_handle.call(-11)
   end
 
   def change_to(new_colour)
-    if RUBY_PLATFORM =~/(win|w)32$/
-      @set_console_txt_attrb.call(@hout,self.win32_colour(new_colour))
+    if RUBY_PLATFORM =~ /(win|w)32$/
+      @set_console_txt_attrb.call(@hout, win32_colour(new_colour))
     else
-	  	"\033[30;#{posix_colour(new_colour)};22m"
-	 	end
+      "\033[30;#{posix_colour(new_colour)};22m"
+    end
   end
 
   def win32_colour(colour)
     case colour
-      when :black then 0
-      when :dark_blue then 1
-      when :dark_green then 2
-      when :dark_cyan then 3
-      when :dark_red then 4
-      when :dark_purple then 5
-      when :dark_yellow, :narrative then 6
-      when :default_white, :default, :dark_white then 7
-      when :silver then 8
-      when :blue then 9
-      when :green, :success then 10
-      when :cyan, :output then 11
-      when :red, :failure then 12
-      when :purple then 13
-      when :yellow then 14
-      when :white then 15
-      else
-        0
+    when :black then 0
+    when :dark_blue then 1
+    when :dark_green then 2
+    when :dark_cyan then 3
+    when :dark_red then 4
+    when :dark_purple then 5
+    when :dark_yellow, :narrative then 6
+    when :default_white, :default, :dark_white then 7
+    when :silver then 8
+    when :blue then 9
+    when :green, :success then 10
+    when :cyan, :output then 11
+    when :red, :failure then 12
+    when :purple then 13
+    when :yellow then 14
+    when :white then 15
+    else
+      0
     end
   end
 
-	def posix_colour(colour)
+  def posix_colour(colour)
     # ANSI Escape Codes - Foreground colors
     # | Code | Color                     |
     # | 39   | Default foreground color  |
@@ -81,35 +80,39 @@ class ColourCommandLine
     # | 96   | Light cyan                |
     # | 97   | White                     |
 
-	  case colour
-      when :black then 30
-      when :red, :failure then 31
-      when :green, :success then 32
-			when :yellow then 33
-      when :blue, :narrative then 34
-      when :purple, :magenta then 35
-      when :cyan, :output then 36
-      when :white, :default_white then 37
-      when :default then 39
-      else
-        39
+    case colour
+    when :black then 30
+    when :red, :failure then 31
+    when :green, :success then 32
+    when :yellow then 33
+    when :blue, :narrative then 34
+    when :purple, :magenta then 35
+    when :cyan, :output then 36
+    when :white, :default_white then 37
+    when :default then 39
+    else
+      39
     end
   end
 
   def out_c(mode, colour, str)
     case RUBY_PLATFORM
-			when /(win|w)32$/
-			  change_to(colour)
-				 $stdout.puts str if mode == :puts
-				 $stdout.print str if mode == :print
-			  change_to(:default_white)
-			else
-				$stdout.puts("#{change_to(colour)}#{str}\033[0m") if mode == :puts
-				$stdout.print("#{change_to(colour)}#{str}\033[0m") if mode == :print
-		end
+    when /(win|w)32$/
+      change_to(colour)
+      $stdout.puts str if mode == :puts
+      $stdout.print str if mode == :print
+      change_to(:default_white)
+    else
+      $stdout.puts("#{change_to(colour)}#{str}\033[0m") if mode == :puts
+      $stdout.print("#{change_to(colour)}#{str}\033[0m") if mode == :print
+    end
   end
 end # ColourCommandLine
 
-def colour_puts(role,str)  ColourCommandLine.new.out_c(:puts, role, str)  end
-def colour_print(role,str) ColourCommandLine.new.out_c(:print, role, str) end
+def colour_puts(role, str)
+  ColourCommandLine.new.out_c(:puts, role, str)
+end
 
+def colour_print(role, str)
+  ColourCommandLine.new.out_c(:print, role, str)
+end

+ 20 - 20
tests/unity/auto/colour_reporter.rb

@@ -2,38 +2,38 @@
 #   Unity Project - A Test Framework for C
 #   Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
 #   [Released under MIT License. Please refer to license.txt for details]
-# ========================================== 
+# ==========================================
 
 require "#{File.expand_path(File.dirname(__FILE__))}/colour_prompt"
 
 $colour_output = true
 
 def report(message)
-  if not $colour_output
+  if !$colour_output
     $stdout.puts(message)
   else
-    message = message.join('\n') if (message.class == Array)
+    message = message.join('\n') if message.class == Array
     message.each_line do |line|
       line.chomp!
-      colour = case(line)
-        when /(?:total\s+)?tests:?\s+(\d+)\s+(?:total\s+)?failures:?\s+\d+\s+Ignored:?/i
-          ($1.to_i == 0) ? :green : :red
-        when /PASS/
-          :green
-        when /^OK$/
-          :green
-        when /(?:FAIL|ERROR)/
-          :red
-        when /IGNORE/
-          :yellow
-        when /^(?:Creating|Compiling|Linking)/
-          :white
-        else
-          :silver
-      end
+      colour = case line
+               when /(?:total\s+)?tests:?\s+(\d+)\s+(?:total\s+)?failures:?\s+\d+\s+Ignored:?/i
+                 Regexp.last_match(1).to_i.zero? ? :green : :red
+               when /PASS/
+                 :green
+               when /^OK$/
+                 :green
+               when /(?:FAIL|ERROR)/
+                 :red
+               when /IGNORE/
+                 :yellow
+               when /^(?:Creating|Compiling|Linking)/
+                 :white
+               else
+                 :silver
+               end
       colour_puts(colour, line)
     end
   end
   $stdout.flush
   $stderr.flush
-end
+end

+ 141 - 144
tests/unity/auto/generate_module.rb

@@ -12,8 +12,8 @@ require 'rubygems'
 require 'fileutils'
 require 'pathname'
 
-#TEMPLATE_TST
-TEMPLATE_TST ||= %q[#include "unity.h"
+# TEMPLATE_TST
+TEMPLATE_TST ||= '#include "unity.h"
 %2$s#include "%1$s.h"
 
 void setUp(void)
@@ -28,115 +28,118 @@ void test_%1$s_NeedToImplement(void)
 {
     TEST_IGNORE_MESSAGE("Need to Implement %1$s");
 }
-]
+'.freeze
 
-#TEMPLATE_SRC
-TEMPLATE_SRC ||= %q[%2$s#include "%1$s.h"
-]
+# TEMPLATE_SRC
+TEMPLATE_SRC ||= '%2$s#include "%1$s.h"
+'.freeze
 
-#TEMPLATE_INC
-TEMPLATE_INC ||= %q[#ifndef _%3$s_H
+# TEMPLATE_INC
+TEMPLATE_INC ||= '#ifndef _%3$s_H
 #define _%3$s_H
 %2$s
 
 #endif // _%3$s_H
-]
+'.freeze
 
 class UnityModuleGenerator
-
   ############################
-  def initialize(options=nil)
-
+  def initialize(options = nil)
     here = File.expand_path(File.dirname(__FILE__)) + '/'
 
     @options = UnityModuleGenerator.default_options
-    case(options)
-      when NilClass then @options
-      when String   then @options.merge!(UnityModuleGenerator.grab_config(options))
-      when Hash     then @options.merge!(options)
-      else          raise "If you specify arguments, it should be a filename or a hash of options"
+    case options
+    when NilClass then @options
+    when String   then @options.merge!(UnityModuleGenerator.grab_config(options))
+    when Hash     then @options.merge!(options)
+    else raise 'If you specify arguments, it should be a filename or a hash of options'
     end
 
     # Create default file paths if none were provided
-    @options[:path_src] = here + "../src/"    if @options[:path_src].nil?
+    @options[:path_src] = here + '../src/'    if @options[:path_src].nil?
     @options[:path_inc] = @options[:path_src] if @options[:path_inc].nil?
-    @options[:path_tst] = here + "../test/"   if @options[:path_tst].nil?
-    @options[:path_src] += '/'                unless (@options[:path_src][-1] == 47)
-    @options[:path_inc] += '/'                unless (@options[:path_inc][-1] == 47)
-    @options[:path_tst] += '/'                unless (@options[:path_tst][-1] == 47)
-
-    #Built in patterns
-    @patterns = { 'src' => {''         => { :inc => [] } },
-                  'test'=> {''         => { :inc => [] } },
-                  'dh'  => {'Driver'   => { :inc => [create_filename('%1$s','Hardware.h')] },
-                            'Hardware' => { :inc => [] }
-                           },
-                  'dih' => {'Driver'   => { :inc => [create_filename('%1$s','Hardware.h'), create_filename('%1$s','Interrupt.h')] },
-                            'Interrupt'=> { :inc => [create_filename('%1$s','Hardware.h')] },
-                            'Hardware' => { :inc => [] }
-                           },
-                  'mch' => {'Model'    => { :inc => [] },
-                            'Conductor'=> { :inc => [create_filename('%1$s','Model.h'), create_filename('%1$s','Hardware.h')] },
-                            'Hardware' => { :inc => [] }
-                           },
-                  'mvp' => {'Model'    => { :inc => [] },
-                            'Presenter'=> { :inc => [create_filename('%1$s','Model.h'), create_filename('%1$s','View.h')] },
-                            'View'     => { :inc => [] }
-                           }
-                }
+    @options[:path_tst] = here + '../test/'   if @options[:path_tst].nil?
+    @options[:path_src] += '/'                unless @options[:path_src][-1] == 47
+    @options[:path_inc] += '/'                unless @options[:path_inc][-1] == 47
+    @options[:path_tst] += '/'                unless @options[:path_tst][-1] == 47
+
+    # Built in patterns
+    @patterns = {
+      'src'  =>  {
+        '' =>  { inc: [] }
+      },
+      'test' =>  {
+        '' =>  { inc: [] }
+      },
+      'dh'   =>  {
+        'Driver'    =>  { inc: [create_filename('%1$s', 'Hardware.h')] },
+        'Hardware'  =>  { inc: [] }
+      },
+      'dih'  =>  {
+        'Driver'    =>  { inc: [create_filename('%1$s', 'Hardware.h'), create_filename('%1$s', 'Interrupt.h')] },
+        'Interrupt' =>  { inc: [create_filename('%1$s', 'Hardware.h')] },
+        'Hardware'  =>  { inc: [] }
+      },
+      'mch'  =>  {
+        'Model'     =>  { inc: [] },
+        'Conductor' =>  { inc: [create_filename('%1$s', 'Model.h'), create_filename('%1$s', 'Hardware.h')] },
+        'Hardware'  =>  { inc: [] }
+      },
+      'mvp'  =>  {
+        'Model'     =>  { inc: [] },
+        'Presenter' =>  { inc: [create_filename('%1$s', 'Model.h'), create_filename('%1$s', 'View.h')] },
+        'View'      =>  { inc: [] }
+      }
+    }
   end
 
   ############################
   def self.default_options
     {
-      :pattern         => "src",
-      :includes        =>
-      {
-          :src         => [],
-          :inc         => [],
-          :tst         => [],
+      pattern: 'src',
+      includes: {
+        src: [],
+        inc: [],
+        tst: []
       },
-      :update_svn      => false,
-      :boilerplates    => {},
-      :test_prefix     => 'Test',
-      :mock_prefix     => 'Mock',
+      update_svn: false,
+      boilerplates: {},
+      test_prefix: 'Test',
+      mock_prefix: 'Mock'
     }
   end
 
   ############################
   def self.grab_config(config_file)
-    options = self.default_options
-    unless (config_file.nil? or config_file.empty?)
+    options = default_options
+    unless config_file.nil? || config_file.empty?
       require 'yaml'
       yaml_guts = YAML.load_file(config_file)
       options.merge!(yaml_guts[:unity] || yaml_guts[:cmock])
       raise "No :unity or :cmock section found in #{config_file}" unless options
     end
-    return(options)
+    options
   end
 
   ############################
-  def files_to_operate_on(module_name, pattern=nil)
-    #strip any leading path information from the module name and save for later
+  def files_to_operate_on(module_name, pattern = nil)
+    # strip any leading path information from the module name and save for later
     subfolder = File.dirname(module_name)
     module_name = File.basename(module_name)
 
-    #create triad definition
+    # create triad definition
     prefix = @options[:test_prefix] || 'Test'
-    triad = [ { :ext => '.c', :path => @options[:path_src], :prefix => "",     :template => TEMPLATE_SRC, :inc => :src, :boilerplate => @options[:boilerplates][:src] },
-              { :ext => '.h', :path => @options[:path_inc], :prefix => "",     :template => TEMPLATE_INC, :inc => :inc, :boilerplate => @options[:boilerplates][:inc] },
-              { :ext => '.c', :path => @options[:path_tst], :prefix => prefix, :template => TEMPLATE_TST, :inc => :tst, :boilerplate => @options[:boilerplates][:tst] },
-            ]
+    triad = [{ ext: '.c', path: @options[:path_src], prefix: '', template: TEMPLATE_SRC, inc: :src, boilerplate: @options[:boilerplates][:src] },
+             { ext: '.h', path: @options[:path_inc], prefix: '',     template: TEMPLATE_INC, inc: :inc, boilerplate: @options[:boilerplates][:inc] },
+             { ext: '.c', path: @options[:path_tst], prefix: prefix, template: TEMPLATE_TST, inc: :tst, boilerplate: @options[:boilerplates][:tst] }]
 
-    #prepare the pattern for use
+    # prepare the pattern for use
     pattern = (pattern || @options[:pattern] || 'src').downcase
     patterns = @patterns[pattern]
     raise "ERROR: The design pattern '#{pattern}' specified isn't one that I recognize!" if patterns.nil?
 
-    #single file patterns (currently just 'test') can reject the other parts of the triad
-    if (pattern == 'test')
-      triad.reject!{|v| v[:inc] != :tst }
-    end
+    # single file patterns (currently just 'test') can reject the other parts of the triad
+    triad.select! { |v| v[:inc] == :tst } if pattern == 'test'
 
     # Assemble the path/names of the files we need to work with.
     files = []
@@ -145,26 +148,26 @@ class UnityModuleGenerator
         submodule_name = create_filename(module_name, pattern_file)
         filename = cfg[:prefix] + submodule_name + cfg[:ext]
         files << {
-          :path => (Pathname.new("#{cfg[:path]}#{subfolder}") + filename).cleanpath,
-          :name => submodule_name,
-          :template => cfg[:template],
-          :boilerplate => cfg[:boilerplate],
-          :includes => case(cfg[:inc])
-                         when :src then (@options[:includes][:src] || []) | pattern_traits[:inc].map{|f| f % [module_name]}
-                         when :inc then (@options[:includes][:inc] || [])
-                         when :tst then (@options[:includes][:tst] || []) | pattern_traits[:inc].map{|f| "#{@options[:mock_prefix]}#{f}" % [module_name]}
-                       end
+          path: (Pathname.new("#{cfg[:path]}#{subfolder}") + filename).cleanpath,
+          name: submodule_name,
+          template: cfg[:template],
+          boilerplate: cfg[:boilerplate],
+          includes: case (cfg[:inc])
+                    when :src then (@options[:includes][:src] || []) | (pattern_traits[:inc].map { |f| format(f, module_name) })
+                    when :inc then (@options[:includes][:inc] || [])
+                    when :tst then (@options[:includes][:tst] || []) | (pattern_traits[:inc].map { |f| format("#{@options[:mock_prefix]}#{f}", module_name) })
+                    end
         }
       end
     end
 
-    return files
+    files
   end
 
   ############################
-  def create_filename(part1, part2="")
+  def create_filename(part1, part2 = '')
     if part2.empty?
-      case(@options[:naming])
+      case (@options[:naming])
       when 'bumpy' then part1
       when 'camel' then part1
       when 'snake' then part1.downcase
@@ -172,49 +175,45 @@ class UnityModuleGenerator
       else              part1.downcase
       end
     else
-      case(@options[:naming])
+      case (@options[:naming])
       when 'bumpy' then part1 + part2
       when 'camel' then part1 + part2
-      when 'snake' then part1.downcase + "_" + part2.downcase
-      when 'caps'  then part1.upcase + "_" + part2.upcase
-      else              part1.downcase + "_" + part2.downcase
+      when 'snake' then part1.downcase + '_' + part2.downcase
+      when 'caps'  then part1.upcase + '_' + part2.upcase
+      else              part1.downcase + '_' + part2.downcase
       end
     end
   end
 
   ############################
-  def generate(module_name, pattern=nil)
-
+  def generate(module_name, pattern = nil)
     files = files_to_operate_on(module_name, pattern)
 
-    #Abort if all of the module files already exist
+    # Abort if all of the module files already exist
     all_files_exist = true
     files.each do |file|
-      if not File.exist?(file[:path])
-        all_files_exist = false
-      end
+      all_files_exist = false unless File.exist?(file[:path])
     end
     raise "ERROR: File #{files[0][:name]} already exists. Exiting." if all_files_exist
 
     # Create Source Modules
-    files.each_with_index do |file, i|
+    files.each_with_index do |file, _i|
       # If this file already exists, don't overwrite it.
       if File.exist?(file[:path])
         puts "File #{file[:path]} already exists!"
         next
       end
       # Create the path first if necessary.
-      FileUtils.mkdir_p(File.dirname(file[:path]), :verbose => false)
+      FileUtils.mkdir_p(File.dirname(file[:path]), verbose: false)
       File.open(file[:path], 'w') do |f|
         f.write("#{file[:boilerplate]}\n" % [file[:name]]) unless file[:boilerplate].nil?
-        f.write(file[:template] % [ file[:name],
-                                    file[:includes].map{|f| "#include \"#{f}\"\n"}.join,
-                                    file[:name].upcase ]
-               )
+        f.write(file[:template] % [file[:name],
+                                   file[:includes].map { |ff| "#include \"#{ff}\"\n" }.join,
+                                   file[:name].upcase])
       end
-      if (@options[:update_svn])
+      if @options[:update_svn]
         `svn add \"#{file[:path]}\"`
-        if $?.exitstatus == 0
+        if $!.exitstatus.zero?
           puts "File #{file[:path]} created and added to source control"
         else
           puts "File #{file[:path]} created but FAILED adding to source control!"
@@ -227,8 +226,7 @@ class UnityModuleGenerator
   end
 
   ############################
-  def destroy(module_name, pattern=nil)
-
+  def destroy(module_name, pattern = nil)
     files_to_operate_on(module_name, pattern).each do |filespec|
       file = filespec[:path]
       if File.exist?(file)
@@ -243,66 +241,65 @@ class UnityModuleGenerator
         puts "File #{file} does not exist so cannot be removed."
       end
     end
-    puts "Destroy Complete"
+    puts 'Destroy Complete'
   end
-
 end
 
 ############################
-#Handle As Command Line If Called That Way
-if ($0 == __FILE__)
+# Handle As Command Line If Called That Way
+if $0 == __FILE__
   destroy = false
-  options = { }
+  options = {}
   module_name = nil
 
   # Parse the command line parameters.
   ARGV.each do |arg|
-    case(arg)
-      when /^-d/            then destroy = true
-      when /^-u/            then options[:update_svn] = true
-      when /^-p\"?(\w+)\"?/ then options[:pattern] = $1
-      when /^-s\"?(.+)\"?/  then options[:path_src] = $1
-      when /^-i\"?(.+)\"?/  then options[:path_inc] = $1
-      when /^-t\"?(.+)\"?/  then options[:path_tst] = $1
-      when /^-n\"?(.+)\"?/  then options[:naming] = $1
-      when /^-y\"?(.+)\"?/  then options = UnityModuleGenerator.grab_config($1)
-      when /^(\w+)/
-        raise "ERROR: You can't have more than one Module name specified!" unless module_name.nil?
-        module_name = arg
-      when /^-(h|-help)/
-        ARGV = []
-      else
-        raise "ERROR: Unknown option specified '#{arg}'"
+    case arg
+    when /^-d/            then destroy = true
+    when /^-u/            then options[:update_svn] = true
+    when /^-p\"?(\w+)\"?/ then options[:pattern] = Regexp.last_match(1)
+    when /^-s\"?(.+)\"?/  then options[:path_src] = Regexp.last_match(1)
+    when /^-i\"?(.+)\"?/  then options[:path_inc] = Regexp.last_match(1)
+    when /^-t\"?(.+)\"?/  then options[:path_tst] = Regexp.last_match(1)
+    when /^-n\"?(.+)\"?/  then options[:naming] = Regexp.last_match(1)
+    when /^-y\"?(.+)\"?/  then options = UnityModuleGenerator.grab_config(Regexp.last_match(1))
+    when /^(\w+)/
+      raise "ERROR: You can't have more than one Module name specified!" unless module_name.nil?
+      module_name = arg
+    when /^-(h|-help)/
+      ARGV = [].freeze
+    else
+      raise "ERROR: Unknown option specified '#{arg}'"
     end
   end
 
-  if (!ARGV[0])
-    puts [ "\nGENERATE MODULE\n-------- ------",
-           "\nUsage: ruby generate_module [options] module_name",
-           "  -i\"include\" sets the path to output headers to 'include' (DEFAULT ../src)",
-           "  -s\"../src\"  sets the path to output source to '../src'   (DEFAULT ../src)",
-           "  -t\"C:/test\" sets the path to output source to 'C:/test'  (DEFAULT ../test)",
-           "  -p\"MCH\"     sets the output pattern to MCH.",
-           "              dh   - driver hardware.",
-           "              dih  - driver interrupt hardware.",
-           "              mch  - model conductor hardware.",
-           "              mvp  - model view presenter.",
-           "              src  - just a source module, header and test. (DEFAULT)",
-           "              test - just a test file.",
-           "  -d          destroy module instead of creating it.",
-           "  -n\"camel\"   sets the file naming convention.",
-           "              bumpy - BumpyCaseFilenames.",
-           "              camel - camelCaseFilenames.",
-           "              snake - snake_case_filenames. (DEFAULT)",
-           "              caps  - CAPS_CASE_FILENAMES.",
-           "  -u          update subversion too (requires subversion command line)",
-           "  -y\"my.yml\"  selects a different yaml config file for module generation",
-           "" ].join("\n")
+  unless ARGV[0]
+    puts ["\nGENERATE MODULE\n-------- ------",
+          "\nUsage: ruby generate_module [options] module_name",
+          "  -i\"include\" sets the path to output headers to 'include' (DEFAULT ../src)",
+          "  -s\"../src\"  sets the path to output source to '../src'   (DEFAULT ../src)",
+          "  -t\"C:/test\" sets the path to output source to 'C:/test'  (DEFAULT ../test)",
+          '  -p"MCH"     sets the output pattern to MCH.',
+          '              dh   - driver hardware.',
+          '              dih  - driver interrupt hardware.',
+          '              mch  - model conductor hardware.',
+          '              mvp  - model view presenter.',
+          '              src  - just a source module, header and test. (DEFAULT)',
+          '              test - just a test file.',
+          '  -d          destroy module instead of creating it.',
+          '  -n"camel"   sets the file naming convention.',
+          '              bumpy - BumpyCaseFilenames.',
+          '              camel - camelCaseFilenames.',
+          '              snake - snake_case_filenames. (DEFAULT)',
+          '              caps  - CAPS_CASE_FILENAMES.',
+          '  -u          update subversion too (requires subversion command line)',
+          '  -y"my.yml"  selects a different yaml config file for module generation',
+          ''].join("\n")
     exit
   end
 
-  raise "ERROR: You must have a Module name specified! (use option -h for help)" if module_name.nil?
-  if (destroy)
+  raise 'ERROR: You must have a Module name specified! (use option -h for help)' if module_name.nil?
+  if destroy
     UnityModuleGenerator.new(options).destroy(module_name)
   else
     UnityModuleGenerator.new(options).generate(module_name)

+ 234 - 232
tests/unity/auto/generate_test_runner.rb

@@ -4,75 +4,70 @@
 #   [Released under MIT License. Please refer to license.txt for details]
 # ==========================================
 
-$QUICK_RUBY_VERSION = RUBY_VERSION.split('.').inject(0){|vv,v| vv * 100 + v.to_i }
-File.expand_path(File.join(File.dirname(__FILE__),'colour_prompt'))
+File.expand_path(File.join(File.dirname(__FILE__), 'colour_prompt'))
 
 class UnityTestRunnerGenerator
-
   def initialize(options = nil)
     @options = UnityTestRunnerGenerator.default_options
-    case(options)
-      when NilClass then @options
-      when String   then @options.merge!(UnityTestRunnerGenerator.grab_config(options))
-      when Hash     then @options.merge!(options)
-      else          raise "If you specify arguments, it should be a filename or a hash of options"
+    case options
+    when NilClass then @options
+    when String   then @options.merge!(UnityTestRunnerGenerator.grab_config(options))
+    when Hash     then @options.merge!(options)
+    else raise 'If you specify arguments, it should be a filename or a hash of options'
     end
     require "#{File.expand_path(File.dirname(__FILE__))}/type_sanitizer"
   end
 
   def self.default_options
     {
-      :includes         => [],
-      :defines          => [],
-      :plugins          => [],
-      :framework        => :unity,
-      :test_prefix      => "test|spec|should",
-      :setup_name       => "setUp",
-      :teardown_name    => "tearDown",
-      :main_name        => "main", #set to :auto to automatically generate each time
-      :main_export_decl => "",
-      :cmdline_args     => false,
-      :use_param_tests  => false,
+      includes: [],
+      defines: [],
+      plugins: [],
+      framework: :unity,
+      test_prefix: 'test|spec|should',
+      mock_prefix: 'Mock',
+      setup_name: 'setUp',
+      teardown_name: 'tearDown',
+      main_name: 'main', # set to :auto to automatically generate each time
+      main_export_decl: '',
+      cmdline_args: false,
+      use_param_tests: false
     }
   end
 
   def self.grab_config(config_file)
-    options = self.default_options
-    unless (config_file.nil? or config_file.empty?)
+    options = default_options
+    unless config_file.nil? || config_file.empty?
       require 'yaml'
       yaml_guts = YAML.load_file(config_file)
       options.merge!(yaml_guts[:unity] || yaml_guts[:cmock])
       raise "No :unity or :cmock section found in #{config_file}" unless options
     end
-    return(options)
+    options
   end
 
-  def run(input_file, output_file, options=nil)
-    tests = []
-    testfile_includes = []
-    used_mocks = []
-
+  def run(input_file, output_file, options = nil)
     @options.merge!(options) unless options.nil?
-    module_name = File.basename(input_file)
 
-    #pull required data from source file
+    # pull required data from source file
     source = File.read(input_file)
-    source = source.force_encoding("ISO-8859-1").encode("utf-8", :replace => nil) if ($QUICK_RUBY_VERSION > 10900)
+    source = source.force_encoding('ISO-8859-1').encode('utf-8', replace: nil)
     tests               = find_tests(source)
     headers             = find_includes(source)
     testfile_includes   = (headers[:local] + headers[:system])
     used_mocks          = find_mocks(testfile_includes)
     testfile_includes   = (testfile_includes - used_mocks)
-    testfile_includes.delete_if{|inc| inc =~ /(unity|cmock)/}
+    testfile_includes.delete_if { |inc| inc =~ /(unity|cmock)/ }
 
-    #build runner file
+    # build runner file
     generate(input_file, output_file, tests, used_mocks, testfile_includes)
 
-    #determine which files were used to return them
+    # determine which files were used to return them
     all_files_used = [input_file, output_file]
-    all_files_used += testfile_includes.map {|filename| filename + '.c'} unless testfile_includes.empty?
+    all_files_used += testfile_includes.map { |filename| filename + '.c' } unless testfile_includes.empty?
     all_files_used += @options[:includes] unless @options[:includes].empty?
-    return all_files_used.uniq
+    all_files_used += headers[:linkonly] unless headers[:linkonly].empty?
+    all_files_used.uniq
   end
 
   def generate(input_file, output_file, tests, used_mocks, testfile_includes)
@@ -80,15 +75,16 @@ class UnityTestRunnerGenerator
       create_header(output, used_mocks, testfile_includes)
       create_externs(output, tests, used_mocks)
       create_mock_management(output, used_mocks)
-      create_suite_setup_and_teardown(output)
+      create_suite_setup(output)
+      create_suite_teardown(output)
       create_reset(output, used_mocks)
       create_main(output, input_file, tests, used_mocks)
     end
 
-    if (@options[:header_file] && !@options[:header_file].empty?)
-      File.open(@options[:header_file], 'w') do |output|
-        create_h_file(output, @options[:header_file], tests, testfile_includes, used_mocks)
-      end
+    return unless @options[:header_file] && !@options[:header_file].empty?
+
+    File.open(@options[:header_file], 'w') do |output|
+      create_h_file(output, @options[:header_file], tests, testfile_includes, used_mocks)
     end
   end
 
@@ -96,103 +92,102 @@ class UnityTestRunnerGenerator
     tests_and_line_numbers = []
 
     source_scrubbed = source.clone
-    source_scrubbed = source_scrubbed.gsub(/"[^"\n]*"/, '')      # remove things in strings
+    source_scrubbed = source_scrubbed.gsub(/"[^"\n]*"/, '') # remove things in strings
     source_scrubbed = source_scrubbed.gsub(/\/\/.*$/, '')      # remove line comments
     source_scrubbed = source_scrubbed.gsub(/\/\*.*?\*\//m, '') # remove block comments
     lines = source_scrubbed.split(/(^\s*\#.*$)                 # Treat preprocessor directives as a logical line
                               | (;|\{|\}) /x)                  # Match ;, {, and } as end of lines
 
-    lines.each_with_index do |line, index|
-      #find tests
-      if line =~ /^((?:\s*TEST_CASE\s*\(.*?\)\s*)*)\s*void\s+((?:#{@options[:test_prefix]}).*)\s*\(\s*(.*)\s*\)/
-        arguments = $1
-        name = $2
-        call = $3
-        params = $4
-        args = nil
-        if (@options[:use_param_tests] and !arguments.empty?)
-          args = []
-          arguments.scan(/\s*TEST_CASE\s*\((.*)\)\s*$/) {|a| args << a[0]}
-        end
-        tests_and_line_numbers << { :test => name, :args => args, :call => call, :params => params, :line_number => 0 }
+    lines.each_with_index do |line, _index|
+      # find tests
+      next unless line =~ /^((?:\s*TEST_CASE\s*\(.*?\)\s*)*)\s*void\s+((?:#{@options[:test_prefix]}).*)\s*\(\s*(.*)\s*\)/
+      arguments = Regexp.last_match(1)
+      name = Regexp.last_match(2)
+      call = Regexp.last_match(3)
+      params = Regexp.last_match(4)
+      args = nil
+      if @options[:use_param_tests] && !arguments.empty?
+        args = []
+        arguments.scan(/\s*TEST_CASE\s*\((.*)\)\s*$/) { |a| args << a[0] }
       end
+      tests_and_line_numbers << { test: name, args: args, call: call, params: params, line_number: 0 }
     end
-    tests_and_line_numbers.uniq! {|v| v[:test] }
+    tests_and_line_numbers.uniq! { |v| v[:test] }
 
-    #determine line numbers and create tests to run
+    # determine line numbers and create tests to run
     source_lines = source.split("\n")
-    source_index = 0;
+    source_index = 0
     tests_and_line_numbers.size.times do |i|
       source_lines[source_index..-1].each_with_index do |line, index|
-        if (line =~ /#{tests_and_line_numbers[i][:test]}/)
-          source_index += index
-          tests_and_line_numbers[i][:line_number] = source_index + 1
-          break
-        end
+        next unless line =~ /#{tests_and_line_numbers[i][:test]}/
+        source_index += index
+        tests_and_line_numbers[i][:line_number] = source_index + 1
+        break
       end
     end
 
-    return tests_and_line_numbers
+    tests_and_line_numbers
   end
 
   def find_includes(source)
-
-    #remove comments (block and line, in three steps to ensure correct precedence)
+    # remove comments (block and line, in three steps to ensure correct precedence)
     source.gsub!(/\/\/(?:.+\/\*|\*(?:$|[^\/])).*$/, '')  # remove line comments that comment out the start of blocks
     source.gsub!(/\/\*.*?\*\//m, '')                     # remove block comments
     source.gsub!(/\/\/.*$/, '')                          # remove line comments (all that remain)
 
-    #parse out includes
+    # parse out includes
     includes = {
-      :local => source.scan(/^\s*#include\s+\"\s*(.+)\.[hH]\s*\"/).flatten,
-      :system => source.scan(/^\s*#include\s+<\s*(.+)\s*>/).flatten.map { |inc| "<#{inc}>" }
+      local: source.scan(/^\s*#include\s+\"\s*(.+)\.[hH]\s*\"/).flatten,
+      system: source.scan(/^\s*#include\s+<\s*(.+)\s*>/).flatten.map { |inc| "<#{inc}>" },
+      linkonly: source.scan(/^TEST_FILE\(\s*\"\s*(.+)\.[cC]\w*\s*\"/).flatten
     }
-    return includes
+    includes
   end
 
   def find_mocks(includes)
     mock_headers = []
     includes.each do |include_path|
       include_file = File.basename(include_path)
-      mock_headers << include_path if (include_file =~ /^mock/i)
+      mock_headers << include_path if include_file =~ /^#{@options[:mock_prefix]}/i
     end
-    return mock_headers
+    mock_headers
   end
 
-  def create_header(output, mocks, testfile_includes=[])
+  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("#include \"#{@options[:framework].to_s}.h\"")
-    output.puts('#include "cmock.h"') unless (mocks.empty?)
+    output.puts("#include \"#{@options[:framework]}.h\"")
+    output.puts('#include "cmock.h"') unless mocks.empty?
     output.puts('#include <setjmp.h>')
     output.puts('#include <stdio.h>')
-    output.puts('#include "CException.h"') if @options[:plugins].include?(:cexception)
-    if (@options[:defines] && !@options[:defines].empty?)
-      @options[:defines].each {|d| output.puts("#define #{d}")}
+    if @options[:defines] && !@options[:defines].empty?
+      @options[:defines].each { |d| output.puts("#define #{d}") }
     end
-    if (@options[:header_file] && !@options[:header_file].empty?)
+    if @options[:header_file] && !@options[:header_file].empty?
       output.puts("#include \"#{File.basename(@options[:header_file])}\"")
     else
       @options[:includes].flatten.uniq.compact.each do |inc|
-        output.puts("#include #{inc.include?('<') ? inc : "\"#{inc.gsub('.h','')}.h\""}")
+        output.puts("#include #{inc.include?('<') ? inc : "\"#{inc.gsub('.h', '')}.h\""}")
       end
       testfile_includes.each do |inc|
-        output.puts("#include #{inc.include?('<') ? inc : "\"#{inc.gsub('.h','')}.h\""}")
+        output.puts("#include #{inc.include?('<') ? inc : "\"#{inc.gsub('.h', '')}.h\""}")
       end
     end
     mocks.each do |mock|
-      output.puts("#include \"#{mock.gsub('.h','')}.h\"")
-    end
-    if @options[:enforce_strict_ordering]
-      output.puts('')
-      output.puts('int GlobalExpectCount;')
-      output.puts('int GlobalVerifyOrder;')
-      output.puts('char* GlobalOrderError;')
+      output.puts("#include \"#{mock.gsub('.h', '')}.h\"")
     end
+    output.puts('#include "CException.h"') if @options[:plugins].include?(:cexception)
+
+    return unless @options[:enforce_strict_ordering]
+
+    output.puts('')
+    output.puts('int GlobalExpectCount;')
+    output.puts('int GlobalVerifyOrder;')
+    output.puts('char* GlobalOrderError;')
   end
 
-  def create_externs(output, tests, mocks)
+  def create_externs(output, tests, _mocks)
     output.puts("\n/*=======External Functions This Runner Calls=====*/")
     output.puts("extern void #{@options[:setup_name]}(void);")
     output.puts("extern void #{@options[:teardown_name]}(void);")
@@ -203,55 +198,60 @@ class UnityTestRunnerGenerator
   end
 
   def create_mock_management(output, mock_headers)
-    unless (mock_headers.empty?)
-      output.puts("\n/*=======Mock Management=====*/")
-      output.puts("static void CMock_Init(void)")
-      output.puts("{")
-      if @options[:enforce_strict_ordering]
-        output.puts("  GlobalExpectCount = 0;")
-        output.puts("  GlobalVerifyOrder = 0;")
-        output.puts("  GlobalOrderError = NULL;")
-      end
-      mocks = mock_headers.map {|mock| File.basename(mock)}
-      mocks.each do |mock|
-        mock_clean = TypeSanitizer.sanitize_c_identifier(mock)
-        output.puts("  #{mock_clean}_Init();")
-      end
-      output.puts("}\n")
+    return if mock_headers.empty?
 
-      output.puts("static void CMock_Verify(void)")
-      output.puts("{")
-      mocks.each do |mock|
-        mock_clean = TypeSanitizer.sanitize_c_identifier(mock)
-        output.puts("  #{mock_clean}_Verify();")
-      end
-      output.puts("}\n")
+    output.puts("\n/*=======Mock Management=====*/")
+    output.puts('static void CMock_Init(void)')
+    output.puts('{')
 
-      output.puts("static void CMock_Destroy(void)")
-      output.puts("{")
-      mocks.each do |mock|
-        mock_clean = TypeSanitizer.sanitize_c_identifier(mock)
-        output.puts("  #{mock_clean}_Destroy();")
-      end
-      output.puts("}\n")
+    if @options[:enforce_strict_ordering]
+      output.puts('  GlobalExpectCount = 0;')
+      output.puts('  GlobalVerifyOrder = 0;')
+      output.puts('  GlobalOrderError = NULL;')
     end
-  end
 
-  def create_suite_setup_and_teardown(output)
-    unless (@options[:suite_setup].nil?)
-      output.puts("\n/*=======Suite Setup=====*/")
-      output.puts("static void suite_setup(void)")
-      output.puts("{")
-      output.puts(@options[:suite_setup])
-      output.puts("}")
+    mocks = mock_headers.map { |mock| File.basename(mock) }
+    mocks.each do |mock|
+      mock_clean = TypeSanitizer.sanitize_c_identifier(mock)
+      output.puts("  #{mock_clean}_Init();")
     end
-    unless (@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])
-      output.puts("}")
+    output.puts("}\n")
+
+    output.puts('static void CMock_Verify(void)')
+    output.puts('{')
+    mocks.each do |mock|
+      mock_clean = TypeSanitizer.sanitize_c_identifier(mock)
+      output.puts("  #{mock_clean}_Verify();")
+    end
+    output.puts("}\n")
+
+    output.puts('static void CMock_Destroy(void)')
+    output.puts('{')
+    mocks.each do |mock|
+      mock_clean = TypeSanitizer.sanitize_c_identifier(mock)
+      output.puts("  #{mock_clean}_Destroy();")
     end
+    output.puts("}\n")
+  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])
+    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])
+    output.puts('}')
   end
 
   def create_runtest(output, used_mocks)
@@ -259,124 +259,124 @@ class UnityTestRunnerGenerator
     va_args1   = @options[:use_param_tests] ? ', ...' : ''
     va_args2   = @options[:use_param_tests] ? '__VA_ARGS__' : ''
     output.puts("\n/*=======Test Runner Used To Run Each Test Below=====*/")
-    output.puts("#define RUN_TEST_NO_ARGS") if @options[:use_param_tests]
+    output.puts('#define RUN_TEST_NO_ARGS') if @options[:use_param_tests]
     output.puts("#define RUN_TEST(TestFunc, TestLineNum#{va_args1}) \\")
-    output.puts("{ \\")
+    output.puts('{ \\')
     output.puts("  Unity.CurrentTestName = #TestFunc#{va_args2.empty? ? '' : " \"(\" ##{va_args2} \")\""}; \\")
-    output.puts("  Unity.CurrentTestLineNumber = TestLineNum; \\")
-    output.puts("  if (UnityTestMatches()) { \\") if (@options[:cmdline_args])
-    output.puts("  Unity.NumberOfTests++; \\")
-    output.puts("  CMock_Init(); \\") unless (used_mocks.empty?)
-    output.puts("  UNITY_CLR_DETAILS(); \\") unless (used_mocks.empty?)
-    output.puts("  if (TEST_PROTECT()) \\")
-    output.puts("  { \\")
-    output.puts("    CEXCEPTION_T e; \\") if cexception
-    output.puts("    Try { \\") if cexception
+    output.puts('  Unity.CurrentTestLineNumber = TestLineNum; \\')
+    output.puts('  if (UnityTestMatches()) { \\') if @options[:cmdline_args]
+    output.puts('  Unity.NumberOfTests++; \\')
+    output.puts('  CMock_Init(); \\') unless used_mocks.empty?
+    output.puts('  UNITY_CLR_DETAILS(); \\') unless used_mocks.empty?
+    output.puts('  if (TEST_PROTECT()) \\')
+    output.puts('  { \\')
+    output.puts('    CEXCEPTION_T e; \\') if cexception
+    output.puts('    Try { \\') if cexception
     output.puts("      #{@options[:setup_name]}(); \\")
     output.puts("      TestFunc(#{va_args2}); \\")
-    output.puts("    } Catch(e) { TEST_ASSERT_EQUAL_HEX32_MESSAGE(CEXCEPTION_NONE, e, \"Unhandled Exception!\"); } \\") if cexception
-    output.puts("  } \\")
-    output.puts("  if (TEST_PROTECT()) \\")
-    output.puts("  { \\")
+    output.puts('    } Catch(e) { TEST_ASSERT_EQUAL_HEX32_MESSAGE(CEXCEPTION_NONE, e, "Unhandled Exception!"); } \\') if cexception
+    output.puts('  } \\')
+    output.puts('  if (TEST_PROTECT()) \\')
+    output.puts('  { \\')
     output.puts("    #{@options[:teardown_name]}(); \\")
-    output.puts("    CMock_Verify(); \\") unless (used_mocks.empty?)
-    output.puts("  } \\")
-    output.puts("  CMock_Destroy(); \\") unless (used_mocks.empty?)
-    output.puts("  UnityConcludeTest(); \\")
-    output.puts("  } \\")  if (@options[:cmdline_args])
+    output.puts('    CMock_Verify(); \\') unless used_mocks.empty?
+    output.puts('  } \\')
+    output.puts('  CMock_Destroy(); \\') unless used_mocks.empty?
+    output.puts('  UnityConcludeTest(); \\')
+    output.puts('  } \\') if @options[:cmdline_args]
     output.puts("}\n")
   end
 
   def create_reset(output, used_mocks)
     output.puts("\n/*=======Test Reset Option=====*/")
-    output.puts("void resetTest(void);")
-    output.puts("void resetTest(void)")
-    output.puts("{")
-    output.puts("  CMock_Verify();") unless (used_mocks.empty?)
-    output.puts("  CMock_Destroy();") unless (used_mocks.empty?)
+    output.puts('void resetTest(void);')
+    output.puts('void resetTest(void)')
+    output.puts('{')
+    output.puts('  CMock_Verify();') unless used_mocks.empty?
+    output.puts('  CMock_Destroy();') unless used_mocks.empty?
     output.puts("  #{@options[:teardown_name]}();")
-    output.puts("  CMock_Init();") unless (used_mocks.empty?)
+    output.puts('  CMock_Init();') unless used_mocks.empty?
     output.puts("  #{@options[:setup_name]}();")
-    output.puts("}")
+    output.puts('}')
   end
 
   def create_main(output, filename, tests, used_mocks)
     output.puts("\n\n/*=======MAIN=====*/")
-    main_name = (@options[:main_name].to_sym == :auto) ? "main_#{filename.gsub('.c','')}" : "#{@options[:main_name]}"
-    if (@options[:cmdline_args])
-      if (main_name != "main")
+    main_name = @options[:main_name].to_sym == :auto ? "main_#{filename.gsub('.c', '')}" : (@options[:main_name]).to_s
+    if @options[:cmdline_args]
+      if main_name != 'main'
         output.puts("#{@options[:main_export_decl]} int #{main_name}(int argc, char** argv);")
       end
       output.puts("#{@options[:main_export_decl]} int #{main_name}(int argc, char** argv)")
-      output.puts("{")
-      output.puts("  int parse_status = UnityParseOptions(argc, argv);")
-      output.puts("  if (parse_status != 0)")
-      output.puts("  {")
-      output.puts("    if (parse_status < 0)")
-      output.puts("    {")
-      output.puts("      UnityPrint(\"#{filename.gsub('.c','')}.\");")
-      output.puts("      UNITY_PRINT_EOL();")
-      if (@options[:use_param_tests])
+      output.puts('{')
+      output.puts('  int parse_status = UnityParseOptions(argc, argv);')
+      output.puts('  if (parse_status != 0)')
+      output.puts('  {')
+      output.puts('    if (parse_status < 0)')
+      output.puts('    {')
+      output.puts("      UnityPrint(\"#{filename.gsub('.c', '')}.\");")
+      output.puts('      UNITY_PRINT_EOL();')
+      if @options[:use_param_tests]
         tests.each do |test|
-          if ((test[:args].nil?) or (test[:args].empty?))
+          if test[:args].nil? || test[:args].empty?
             output.puts("      UnityPrint(\"  #{test[:test]}(RUN_TEST_NO_ARGS)\");")
-            output.puts("      UNITY_PRINT_EOL();")
+            output.puts('      UNITY_PRINT_EOL();')
           else
             test[:args].each do |args|
               output.puts("      UnityPrint(\"  #{test[:test]}(#{args})\");")
-              output.puts("      UNITY_PRINT_EOL();")
+              output.puts('      UNITY_PRINT_EOL();')
             end
           end
         end
       else
-        tests.each { |test| output.puts("      UnityPrint(\"  #{test[:test]}\");\n    UNITY_PRINT_EOL();")}
+        tests.each { |test| output.puts("      UnityPrint(\"  #{test[:test]}\");\n    UNITY_PRINT_EOL();") }
       end
-      output.puts("    return 0;")
-      output.puts("    }")
-      output.puts("  return parse_status;")
-      output.puts("  }")
+      output.puts('    return 0;')
+      output.puts('    }')
+      output.puts('  return parse_status;')
+      output.puts('  }')
     else
-      if (main_name != "main")
+      if main_name != 'main'
         output.puts("#{@options[:main_export_decl]} int #{main_name}(void);")
       end
       output.puts("int #{main_name}(void)")
-      output.puts("{")
+      output.puts('{')
     end
-    output.puts("  suite_setup();") unless @options[:suite_setup].nil?
-    output.puts("  UnityBegin(\"#{filename.gsub(/\\/,'\\\\\\')}\");")
-    if (@options[:use_param_tests])
+    output.puts('  suite_setup();') unless @options[:suite_setup].nil?
+    output.puts("  UnityBegin(\"#{filename.gsub(/\\/, '\\\\\\')}\");")
+    if @options[:use_param_tests]
       tests.each do |test|
-        if ((test[:args].nil?) or (test[:args].empty?))
+        if test[:args].nil? || test[:args].empty?
           output.puts("  RUN_TEST(#{test[:test]}, #{test[:line_number]}, RUN_TEST_NO_ARGS);")
         else
-          test[:args].each {|args| output.puts("  RUN_TEST(#{test[:test]}, #{test[:line_number]}, #{args});")}
+          test[:args].each { |args| output.puts("  RUN_TEST(#{test[:test]}, #{test[:line_number]}, #{args});") }
         end
       end
     else
-        tests.each { |test| output.puts("  RUN_TEST(#{test[:test]}, #{test[:line_number]});") }
+      tests.each { |test| output.puts("  RUN_TEST(#{test[:test]}, #{test[:line_number]});") }
     end
-    output.puts()
-    output.puts("  CMock_Guts_MemFreeFinal();") unless used_mocks.empty?
-    output.puts("  return #{@options[:suite_teardown].nil? ? "" : "suite_teardown"}(UnityEnd());")
-    output.puts("}")
+    output.puts
+    output.puts('  CMock_Guts_MemFreeFinal();') unless used_mocks.empty?
+    output.puts("  return #{@options[:suite_teardown].nil? ? '' : 'suite_teardown'}(UnityEnd());")
+    output.puts('}')
   end
 
   def create_h_file(output, filename, tests, testfile_includes, used_mocks)
-    filename = File.basename(filename).gsub(/[-\/\\\.\,\s]/, "_").upcase
-    output.puts("/* AUTOGENERATED FILE. DO NOT EDIT. */")
+    filename = File.basename(filename).gsub(/[-\/\\\.\,\s]/, '_').upcase
+    output.puts('/* AUTOGENERATED FILE. DO NOT EDIT. */')
     output.puts("#ifndef _#{filename}")
     output.puts("#define _#{filename}\n\n")
-    output.puts("#include \"#{@options[:framework].to_s}.h\"")
-    output.puts('#include "cmock.h"') unless (used_mocks.empty?)
+    output.puts("#include \"#{@options[:framework]}.h\"")
+    output.puts('#include "cmock.h"') unless used_mocks.empty?
     @options[:includes].flatten.uniq.compact.each do |inc|
-      output.puts("#include #{inc.include?('<') ? inc : "\"#{inc.gsub('.h','')}.h\""}")
+      output.puts("#include #{inc.include?('<') ? inc : "\"#{inc.gsub('.h', '')}.h\""}")
     end
     testfile_includes.each do |inc|
-      output.puts("#include #{inc.include?('<') ? inc : "\"#{inc.gsub('.h','')}.h\""}")
+      output.puts("#include #{inc.include?('<') ? inc : "\"#{inc.gsub('.h', '')}.h\""}")
     end
     output.puts "\n"
     tests.each do |test|
-      if ((test[:params].nil?) or (test[:params].empty?))
+      if test[:params].nil? || test[:params].empty?
         output.puts("void #{test[:test]}(void);")
       else
         output.puts("void #{test[:test]}(#{test[:params]});")
@@ -386,50 +386,52 @@ class UnityTestRunnerGenerator
   end
 end
 
-if ($0 == __FILE__)
-  options = { :includes => [] }
-  yaml_file = nil
+if $0 == __FILE__
+  options = { includes: [] }
 
-  #parse out all the options first (these will all be removed as we go)
+  # parse out all the options first (these will all be removed as we go)
   ARGV.reject! do |arg|
-    case(arg)
-      when '-cexception'
-        options[:plugins] = [:cexception]; true
-      when /\.*\.ya?ml/
-        options = UnityTestRunnerGenerator.grab_config(arg); true
-      when /--(\w+)=\"?(.*)\"?/
-        options[$1.to_sym] = $2; true
-      when /\.*\.h/
-        options[:includes] << arg; true
-      else false
+    case arg
+    when '-cexception'
+      options[:plugins] = [:cexception]
+      true
+    when /\.*\.ya?ml/
+      options = UnityTestRunnerGenerator.grab_config(arg)
+      true
+    when /--(\w+)=\"?(.*)\"?/
+      options[Regexp.last_match(1).to_sym] = Regexp.last_match(2)
+      true
+    when /\.*\.h/
+      options[:includes] << arg
+      true
+    else false
     end
   end
 
-  #make sure there is at least one parameter left (the input file)
-  if !ARGV[0]
+  # make sure there is at least one parameter left (the input file)
+  unless ARGV[0]
     puts ["\nusage: ruby #{__FILE__} (files) (options) input_test_file (output)",
-           "\n  input_test_file         - this is the C file you want to create a runner for",
-           "  output                  - this is the name of the runner file to generate",
-           "                            defaults to (input_test_file)_Runner",
-           "  files:",
-           "    *.yml / *.yaml        - loads configuration from here in :unity or :cmock",
-           "    *.h                   - header files are added as #includes in runner",
-           "  options:",
-           "    -cexception           - include cexception support",
-           "    --setup_name=\"\"       - redefine setUp func name to something else",
-           "    --teardown_name=\"\"    - redefine tearDown func name to something else",
-           "    --main_name=\"\"        - redefine main func name to something else",
-           "    --test_prefix=\"\"      - redefine test prefix from default test|spec|should",
-           "    --suite_setup=\"\"      - code to execute for setup of entire suite",
-           "    --suite_teardown=\"\"   - code to execute for teardown of entire suite",
-           "    --use_param_tests=1   - enable parameterized tests (disabled by default)",
-           "    --header_file=\"\"      - path/name of test header file to generate too"
-          ].join("\n")
+          "\n  input_test_file         - this is the C file you want to create a runner for",
+          '  output                  - this is the name of the runner file to generate',
+          '                            defaults to (input_test_file)_Runner',
+          '  files:',
+          '    *.yml / *.yaml        - loads configuration from here in :unity or :cmock',
+          '    *.h                   - header files are added as #includes in runner',
+          '  options:',
+          '    -cexception           - include cexception support',
+          '    --setup_name=""       - redefine setUp func name to something else',
+          '    --teardown_name=""    - redefine tearDown func name to something else',
+          '    --main_name=""        - redefine main func name to something else',
+          '    --test_prefix=""      - redefine test prefix from default test|spec|should',
+          '    --suite_setup=""      - code to execute for setup of entire suite',
+          '    --suite_teardown=""   - code to execute for teardown of entire suite',
+          '    --use_param_tests=1   - enable parameterized tests (disabled by default)',
+          '    --header_file=""      - path/name of test header file to generate too'].join("\n")
     exit 1
   end
 
-  #create the default test runner name if not specified
-  ARGV[1] = ARGV[0].gsub(".c","_Runner.c") if (!ARGV[1])
+  # create the default test runner name if not specified
+  ARGV[1] = ARGV[0].gsub('.c', '_Runner.c') unless ARGV[1]
 
   UnityTestRunnerGenerator.new(options).run(ARGV[0], ARGV[1])
 end

+ 0 - 224
tests/unity/auto/parseOutput.rb

@@ -1,224 +0,0 @@
-#============================================================
-#  Author:   John Theofanopoulos
-#  A simple parser.   Takes the output files generated during the build process and
-# extracts information relating to the tests.  
-#
-#  Notes:
-#    To capture an output file under VS builds use the following:
-#      devenv [build instructions]  > Output.txt & type Output.txt
-# 
-#    To capture an output file under GCC/Linux builds use the following:
-#      make | tee Output.txt
-#
-#    To use this parser use the following command
-#    ruby parseOutput.rb [options] [file]
-#        options:  -xml  : produce a JUnit compatible XML file
-#        file      :  file to scan for results
-#============================================================
-
-
-class ParseOutput
-# The following flag is set to true when a test is found or false otherwise.
-    @testFlag
-    @xmlOut
-    @arrayList
-    @totalTests
-    @classIndex
-
-#   Set the flag to indicate if there will be an XML output file or not  
-    def setXmlOutput()
-        @xmlOut = true
-    end
-    
-#  if write our output to XML
-    def writeXmlOuput()
-            output = File.open("report.xml", "w")
-            output << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
-            @arrayList.each do |item|
-                output << item << "\n"
-            end
-            output << "</testsuite>\n"
-    end
-    
-#  This function will try and determine when the suite is changed.   This is
-# is the name that gets added to the classname parameter.
-    def  testSuiteVerify(testSuiteName)
-        if @testFlag == false
-            @testFlag = true;
-            # Split the path name 
-            testName = testSuiteName.split("/")
-            # Remove the extension
-            baseName = testName[testName.size - 1].split(".")
-            @testSuite = "test." + baseName[0]
-            printf "New Test: %s\n", @testSuite
-        end
-    end
-    
-
-# Test was flagged as having passed so format the output
-    def testPassed(array)
-        lastItem = array.length - 1
-        testName = array[lastItem - 1]
-        testSuiteVerify(array[@className])
-        printf "%-40s PASS\n", testName
-        if @xmlOut == true
-            @arrayList.push "     <testcase classname=\"" + @testSuite + "\" name=\"" + testName + "\"/>"
-        end          
-    end
-    
-# Test was flagged as having passed so format the output.
-# This is using the Unity fixture output and not the original Unity output.
-    def testPassedUnityFixture(array)
-        testSuite = array[0].sub("TEST(", "")
-        testSuite = testSuite.sub(",", "")
-        testName = array[1].sub(")", "")
-        if @xmlOut == true
-            @arrayList.push "     <testcase classname=\"" + testSuite + "\" name=\"" + testName + "\"/>"
-        end          
-    end
-
-# Test was flagged as being ingored so format the output
-    def testIgnored(array)
-        lastItem = array.length - 1
-        testName = array[lastItem - 2]
-        reason = array[lastItem].chomp
-        testSuiteVerify(array[@className])
-        printf "%-40s IGNORED\n", testName
-
-        if testName.start_with? "TEST("
-          array2 = testName.split(" ")
-          @testSuite = array2[0].sub("TEST(", "")
-          @testSuite = @testSuite.sub(",", "")
-          testName = array2[1].sub(")", "")
-        end
-
-        if @xmlOut == true
-            @arrayList.push "     <testcase classname=\"" + @testSuite + "\" name=\"" + testName + "\">"
-            @arrayList.push "            <skipped type=\"TEST IGNORED\"> " + reason + " </skipped>"
-            @arrayList.push "     </testcase>"
-        end          
-    end
-
-# Test was flagged as having failed  so format the line
-    def testFailed(array)
-        lastItem = array.length - 1
-        testName = array[lastItem - 2]
-        reason = array[lastItem].chomp + " at line: " + array[lastItem - 3]
-        testSuiteVerify(array[@className])
-        printf "%-40s FAILED\n", testName
-        
-        if testName.start_with? "TEST("
-          array2 = testName.split(" ")
-          @testSuite = array2[0].sub("TEST(", "")
-          @testSuite = @testSuite.sub(",", "")
-          testName = array2[1].sub(")", "")
-        end
-        
-        if @xmlOut == true
-            @arrayList.push "     <testcase classname=\"" + @testSuite + "\" name=\"" + testName + "\">"
-            @arrayList.push "            <failure type=\"ASSERT FAILED\"> " + reason + " </failure>"
-            @arrayList.push "     </testcase>"
-        end          
-    end
-
-    
-# Figure out what OS we are running on.   For now we are assuming if it's not Windows it must
-# be Unix based.  
-    def detectOS()
-        myOS = RUBY_PLATFORM.split("-")
-        if myOS.size == 2
-            if myOS[1] == "mingw32"
-                @className = 1
-            else
-                @className = 0
-            end
-	else
-                @className = 0
-        end
-        
-    end
-
-# Main function used to parse the file that was captured.
-    def process(name)
-        @testFlag = false
-        @arrayList = Array.new
-
-        detectOS()
-
-        puts "Parsing file: " + name
-    
-      
-        testPass = 0
-        testFail = 0
-        testIgnore = 0
-        puts ""
-        puts "=================== RESULTS ====================="
-        puts ""
-        File.open(name).each do |line|
-        # Typical test lines look like this:
-        # <path>/<test_file>.c:36:test_tc1000_opsys:FAIL: Expected 1 Was 0
-        # <path>/<test_file>.c:112:test_tc5004_initCanChannel:IGNORE: Not Yet Implemented
-        # <path>/<test_file>.c:115:test_tc5100_initCanVoidPtrs:PASS
-        #
-        # where path is different on Unix vs Windows devices (Windows leads with a drive letter)
-            lineArray = line.split(":")
-            lineSize = lineArray.size
-            # If we were able to split the line then we can look to see if any of our target words
-            # were found.  Case is important.
-            if ((lineSize >= 4) || (line.start_with? "TEST("))
-                # Determine if this test passed
-                if  line.include? ":PASS"
-                    testPassed(lineArray)
-                    testPass += 1
-                elsif line.include? ":FAIL:"
-                    testFailed(lineArray)
-                    testFail += 1
-                elsif line.include? ":IGNORE:"
-                    testIgnored(lineArray)
-                    testIgnore += 1
-                elsif line.start_with? "TEST("
-                  if line.include? " PASS"
-                    lineArray = line.split(" ")
-                    testPassedUnityFixture(lineArray)
-                    testPass += 1
-                  end
-                # If none of the keywords are found there are no more tests for this suite so clear
-                # the test flag
-                else
-                    @testFlag = false
-                end
-            else
-                @testFlag = false
-                end
-            end
-        puts ""
-        puts "=================== SUMMARY ====================="
-        puts ""
-        puts "Tests Passed  : " + testPass.to_s
-        puts "Tests Failed  : " + testFail.to_s
-        puts "Tests Ignored : " + testIgnore.to_s
-        @totalTests = testPass + testFail + testIgnore
-        if @xmlOut == true
-            heading = "<testsuite tests=\"" +  @totalTests.to_s  + "\" failures=\"" + testFail.to_s + "\""  + " skips=\"" +  testIgnore.to_s + "\">" 
-            @arrayList.insert(0, heading) 
-            writeXmlOuput()
-        end
-
-    #  return result
-    end
-
- end
-
-# If the command line has no values in, used a default value of Output.txt
-parseMyFile = ParseOutput.new
-
-if ARGV.size >= 1 
-    ARGV.each do |a|
-        if a == "-xml"
-            parseMyFile.setXmlOutput();
-        else
-            parseMyFile.process(a)
-            break
-        end
-    end
-end

+ 220 - 0
tests/unity/auto/parse_output.rb

@@ -0,0 +1,220 @@
+#============================================================
+#  Author:   John Theofanopoulos
+#  A simple parser.   Takes the output files generated during the build process and
+# extracts information relating to the tests.
+#
+#  Notes:
+#    To capture an output file under VS builds use the following:
+#      devenv [build instructions]  > Output.txt & type Output.txt
+#
+#    To capture an output file under GCC/Linux builds use the following:
+#      make | tee Output.txt
+#
+#    To use this parser use the following command
+#    ruby parseOutput.rb [options] [file]
+#        options:  -xml  : produce a JUnit compatible XML file
+#        file      :  file to scan for results
+#============================================================
+
+class ParseOutput
+  def initialize
+    @test_flag = false
+    @xml_out = false
+    @array_list = false
+    @total_tests = false
+    @class_index = false
+  end
+
+  #   Set the flag to indicate if there will be an XML output file or not
+  def set_xml_output
+    @xml_out = true
+  end
+
+  #  if write our output to XML
+  def write_xml_output
+    output = File.open('report.xml', 'w')
+    output << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+    @array_list.each do |item|
+      output << item << "\n"
+    end
+    output << "</testsuite>\n"
+  end
+
+  #  This function will try and determine when the suite is changed.   This is
+  # is the name that gets added to the classname parameter.
+  def test_suite_verify(test_suite_name)
+    return if @test_flag
+
+    @test_flag = true
+    # Split the path name
+    test_name = test_suite_name.split('/')
+    # Remove the extension
+    base_name = test_name[test_name.size - 1].split('.')
+    @test_suite = 'test.' + base_name[0]
+    printf "New Test: %s\n", @test_suite
+  end
+
+  # Test was flagged as having passed so format the output
+  def test_passed(array)
+    last_item = array.length - 1
+    test_name = array[last_item - 1]
+    test_suite_verify(array[@class_name])
+    printf "%-40s PASS\n", test_name
+
+    return unless @xml_out
+
+    @array_list.push '     <testcase classname="' + @test_suite + '" name="' + test_name + '"/>'
+  end
+
+  # Test was flagged as having passed so format the output.
+  # This is using the Unity fixture output and not the original Unity output.
+  def test_passed_unity_fixture(array)
+    test_suite = array[0].sub('TEST(', '')
+    test_suite = test_suite.sub(',', '')
+    test_name = array[1].sub(')', '')
+
+    return unless @xml_out
+
+    @array_list.push '     <testcase classname="' + test_suite + '" name="' + test_name + '"/>'
+  end
+
+  # Test was flagged as being ingored so format the output
+  def test_ignored(array)
+    last_item = array.length - 1
+    test_name = array[last_item - 2]
+    reason = array[last_item].chomp
+    test_suite_verify(array[@class_name])
+    printf "%-40s IGNORED\n", test_name
+
+    if test_name.start_with? 'TEST('
+      array2 = test_name.split(' ')
+      @test_suite = array2[0].sub('TEST(', '')
+      @test_suite = @test_suite.sub(',', '')
+      test_name = array2[1].sub(')', '')
+    end
+
+    return unless @xml_out
+
+    @array_list.push '     <testcase classname="' + @test_suite + '" name="' + test_name + '">'
+    @array_list.push '            <skipped type="TEST IGNORED"> ' + reason + ' </skipped>'
+    @array_list.push '     </testcase>'
+  end
+
+  # Test was flagged as having failed  so format the line
+  def test_failed(array)
+    last_item = array.length - 1
+    test_name = array[last_item - 2]
+    reason = array[last_item].chomp + ' at line: ' + array[last_item - 3]
+    test_suite_verify(array[@class_name])
+    printf "%-40s FAILED\n", test_name
+
+    if test_name.start_with? 'TEST('
+      array2 = test_name.split(' ')
+      @test_suite = array2[0].sub('TEST(', '')
+      @test_suite = @test_suite.sub(',', '')
+      test_name = array2[1].sub(')', '')
+    end
+
+    return unless @xml_out
+
+    @array_list.push '     <testcase classname="' + @test_suite + '" name="' + test_name + '">'
+    @array_list.push '            <failure type="ASSERT FAILED"> ' + reason + ' </failure>'
+    @array_list.push '     </testcase>'
+  end
+
+  # Figure out what OS we are running on.   For now we are assuming if it's not Windows it must
+  # be Unix based.
+  def detect_os
+    os = RUBY_PLATFORM.split('-')
+    @class_name = if os.size == 2
+                    if os[1] == 'mingw32'
+                      1
+                    else
+                      0
+                    end
+                  else
+                    0
+                  end
+  end
+
+  # Main function used to parse the file that was captured.
+  def process(name)
+    @test_flag = false
+    @array_list = []
+
+    detect_os
+
+    puts 'Parsing file: ' + name
+
+    test_pass = 0
+    test_fail = 0
+    test_ignore = 0
+    puts ''
+    puts '=================== RESULTS ====================='
+    puts ''
+    File.open(name).each do |line|
+      # Typical test lines look like this:
+      # <path>/<test_file>.c:36:test_tc1000_opsys:FAIL: Expected 1 Was 0
+      # <path>/<test_file>.c:112:test_tc5004_initCanChannel:IGNORE: Not Yet Implemented
+      # <path>/<test_file>.c:115:test_tc5100_initCanVoidPtrs:PASS
+      #
+      # where path is different on Unix vs Windows devices (Windows leads with a drive letter)
+      line_array = line.split(':')
+
+      # If we were able to split the line then we can look to see if any of our target words
+      # were found.  Case is important.
+      if (line_array.size >= 4) || (line.start_with? 'TEST(')
+        # Determine if this test passed
+        if line.include? ':PASS'
+          test_passed(line_array)
+          test_pass += 1
+        elsif line.include? ':FAIL:'
+          test_failed(line_array)
+          test_fail += 1
+        elsif line.include? ':IGNORE:'
+          test_ignored(line_array)
+          test_ignore += 1
+        elsif line.start_with? 'TEST('
+          if line.include? ' PASS'
+            line_array = line.split(' ')
+            test_passed_unity_fixture(line_array)
+            test_pass += 1
+          end
+        # If none of the keywords are found there are no more tests for this suite so clear
+        # the test flag
+        else
+          @test_flag = false
+        end
+      else
+        @test_flag = false
+      end
+    end
+    puts ''
+    puts '=================== SUMMARY ====================='
+    puts ''
+    puts 'Tests Passed  : ' + test_pass.to_s
+    puts 'Tests Failed  : ' + test_fail.to_s
+    puts 'Tests Ignored : ' + test_ignore.to_s
+    @total_tests = test_pass + test_fail + test_ignore
+
+    return unless @xml_out
+
+    heading = '<testsuite tests="' + @total_tests.to_s + '" failures="' + test_fail.to_s + '"' + ' skips="' + test_ignore.to_s + '">'
+    @array_list.insert(0, heading)
+    write_xml_output
+  end
+end
+
+# If the command line has no values in, used a default value of Output.txt
+parse_my_file = ParseOutput.new
+
+if ARGV.size >= 1
+  ARGV.each do |a|
+    if a == '-xml'
+      parse_my_file.set_xml_output
+    else
+      parse_my_file.process(a)
+      break
+    end
+  end
+end

+ 108 - 120
tests/unity/auto/stylize_as_junit.rb

@@ -12,7 +12,6 @@ require 'pp'
 VERSION = 1.0
 
 class ArgvParser
-
   #
   # Return a structure describing the options.
   #
@@ -20,41 +19,41 @@ class ArgvParser
     # The options specified on the command line will be collected in *options*.
     # We set default values here.
     options = OpenStruct.new
-    options.results_dir = "."
-    options.root_path = "."
-    options.out_file = "results.xml"
+    options.results_dir = '.'
+    options.root_path = '.'
+    options.out_file = 'results.xml'
 
-    opts = OptionParser.new do |opts|
-      opts.banner = "Usage: unity_to_junit.rb [options]"
+    opts = OptionParser.new do |o|
+      o.banner = 'Usage: unity_to_junit.rb [options]'
 
-      opts.separator ""
-      opts.separator "Specific options:"
+      o.separator ''
+      o.separator 'Specific options:'
 
-      opts.on("-r", "--results <dir>", "Look for Unity Results files here.") do |results|
-        #puts "results #{results}"
+      o.on('-r', '--results <dir>', 'Look for Unity Results files here.') do |results|
+        # puts "results #{results}"
         options.results_dir = results
       end
 
-      opts.on("-p", "--root_path <path>", "Prepend this path to files in results.") do |root_path|
+      o.on('-p', '--root_path <path>', 'Prepend this path to files in results.') do |root_path|
         options.root_path = root_path
       end
 
-      opts.on("-o", "--output <filename>", "XML file to generate.") do |out_file|
-        #puts "out_file: #{out_file}"
+      o.on('-o', '--output <filename>', 'XML file to generate.') do |out_file|
+        # puts "out_file: #{out_file}"
         options.out_file = out_file
       end
 
-      opts.separator ""
-      opts.separator "Common options:"
+      o.separator ''
+      o.separator 'Common options:'
 
       # No argument, shows at tail.  This will print an options summary.
-      opts.on_tail("-h", "--help", "Show this message") do
-        puts opts
+      o.on_tail('-h', '--help', 'Show this message') do
+        puts o
         exit
       end
 
       # Another typical switch to print the version.
-      opts.on_tail("--version", "Show version") do
+      o.on_tail('--version', 'Show version') do
         puts "unity_to_junit.rb version #{VERSION}"
         exit
       end
@@ -62,13 +61,13 @@ class ArgvParser
 
     opts.parse!(args)
     options
-  end  # parse()
-
-end  # class OptparseExample
+  end # parse()
+end # class OptparseExample
 
 class UnityToJUnit
   include FileUtils::Verbose
   attr_reader :report, :total_tests, :failures, :ignored
+  attr_writer :targets, :root, :out_file
 
   def initialize
     @report = ''
@@ -77,125 +76,115 @@ class UnityToJUnit
 
   def run
     # Clean up result file names
-    results = @targets.map {|target| target.gsub(/\\/,"/")}
-    #puts "Output File: #{@out_file}"
-    f = File.new(@out_file, "w")
+    results = @targets.map { |target| target.tr('\\', '/') }
+    # puts "Output File: #{@out_file}"
+    f = File.new(@out_file, 'w')
     write_xml_header(f)
-    write_suites_header( f )
+    write_suites_header(f)
     results.each do |result_file|
-      lines = File.readlines(result_file).map { |line| line.chomp }
-      if lines.length == 0
-        raise "Empty test result file: #{result_file}"
-      else
-        result_output = get_details(result_file, lines)
-        tests,failures,ignored = parse_test_summary(lines)
-        result_output[:counts][:total] = tests
-        result_output[:counts][:failed] = failures
-        result_output[:counts][:ignored] = ignored
-        result_output[:counts][:passed] = (result_output[:counts][:total] - result_output[:counts][:failed] - result_output[:counts][:ignored])
-      end
-      #use line[0] from the test output to get the test_file path and name
-      test_file_str = lines[0].gsub("\\","/")
-      test_file_str = test_file_str.split(":")
-      test_file = if (test_file_str.length < 2)
-        result_file
-      else
-        test_file_str[0] + ':' + test_file_str[1]
-      end
+      lines = File.readlines(result_file).map(&:chomp)
+
+      raise "Empty test result file: #{result_file}" if lines.empty?
+
+      result_output = get_details(result_file, lines)
+      tests, failures, ignored = parse_test_summary(lines)
+      result_output[:counts][:total] = tests
+      result_output[:counts][:failed] = failures
+      result_output[:counts][:ignored] = ignored
+      result_output[:counts][:passed] = (result_output[:counts][:total] - result_output[:counts][:failed] - result_output[:counts][:ignored])
+
+      # use line[0] from the test output to get the test_file path and name
+      test_file_str = lines[0].tr('\\', '/')
+      test_file_str = test_file_str.split(':')
+      test_file = if test_file_str.length < 2
+                    result_file
+                  else
+                    test_file_str[0] + ':' + test_file_str[1]
+                  end
       result_output[:source][:path] = File.dirname(test_file)
       result_output[:source][:file] = File.basename(test_file)
 
       # save result_output
-      @unit_name = File.basename(test_file, ".*")
+      @unit_name = File.basename(test_file, '.*')
 
-      write_suite_header( result_output[:counts], f)
-      write_failures( result_output, f )
-      write_tests( result_output, f )
-      write_ignored( result_output, f )
-      write_suite_footer( f )
+      write_suite_header(result_output[:counts], f)
+      write_failures(result_output, f)
+      write_tests(result_output, f)
+      write_ignored(result_output, f)
+      write_suite_footer(f)
     end
-    write_suites_footer( f )
+    write_suites_footer(f)
     f.close
   end
 
-  def set_targets(target_array)
-    @targets = target_array
-  end
-
-  def set_root_path(path)
-    @root = path
-  end
-  def set_out_file(filename)
-    @out_file = filename
-  end
-  def usage(err_msg=nil)
+  def usage(err_msg = nil)
     puts "\nERROR: "
     puts err_msg if err_msg
-    puts "Usage: unity_to_junit.rb [options]"
-    puts ""
-    puts "Specific options:"
-    puts "    -r, --results <dir>              Look for Unity Results files here."
-    puts "    -p, --root_path <path>           Prepend this path to files in results."
-    puts "    -o, --output <filename>          XML file to generate."
-    puts ""
-    puts "Common options:"
-    puts "    -h, --help                       Show this message"
-    puts "        --version                    Show version"
+    puts 'Usage: unity_to_junit.rb [options]'
+    puts ''
+    puts 'Specific options:'
+    puts '    -r, --results <dir>              Look for Unity Results files here.'
+    puts '    -p, --root_path <path>           Prepend this path to files in results.'
+    puts '    -o, --output <filename>          XML file to generate.'
+    puts ''
+    puts 'Common options:'
+    puts '    -h, --help                       Show this message'
+    puts '        --version                    Show version'
 
     exit 1
   end
 
   protected
-  def get_details(result_file, lines)
-    results = get_results_structure
+
+  def get_details(_result_file, lines)
+    results = results_structure
     lines.each do |line|
-      line = line.gsub("\\","/")
-      src_file,src_line,test_name,status,msg = line.split(/:/)
-      line_out = ((@root and (@root != 0)) ? "#{@root}#{line}" : line ).gsub(/\//, "\\")
-      case(status)
-        when 'IGNORE' then results[:ignores] << {:test => test_name, :line => src_line, :message => msg}
-        when 'FAIL'   then results[:failures] << {:test => test_name, :line => src_line, :message => msg}
-        when 'PASS'   then results[:successes] << {:test => test_name, :line => src_line, :message => msg}
+      line = line.tr('\\', '/')
+      _src_file, src_line, test_name, status, msg = line.split(/:/)
+      case status
+      when 'IGNORE' then results[:ignores] << { test: test_name, line: src_line, message: msg }
+      when 'FAIL'   then results[:failures] << { test: test_name, line: src_line, message: msg }
+      when 'PASS'   then results[:successes] << { test: test_name, line: src_line, message: msg }
       end
     end
-    return results
+    results
   end
 
   def parse_test_summary(summary)
-    if summary.find { |v| v =~ /(\d+) Tests (\d+) Failures (\d+) Ignored/ }
-      [$1.to_i,$2.to_i,$3.to_i]
-    else
-      raise "Couldn't parse test results: #{summary}"
-    end
+    raise "Couldn't parse test results: #{summary}" unless summary.find { |v| v =~ /(\d+) Tests (\d+) Failures (\d+) Ignored/ }
+    [Regexp.last_match(1).to_i, Regexp.last_match(2).to_i, Regexp.last_match(3).to_i]
+  end
+
+  def here
+    File.expand_path(File.dirname(__FILE__))
   end
-  def here; File.expand_path(File.dirname(__FILE__)); end
 
   private
 
-  def get_results_structure
-    return {
-      :source    => {:path => '', :file => ''},
-      :successes => [],
-      :failures  => [],
-      :ignores   => [],
-      :counts    => {:total => 0, :passed => 0, :failed => 0, :ignored  => 0},
-      :stdout    => [],
+  def results_structure
+    {
+      source: { path: '', file: '' },
+      successes: [],
+      failures: [],
+      ignores: [],
+      counts: { total: 0, passed: 0, failed: 0, ignored: 0 },
+      stdout: []
     }
   end
 
-  def write_xml_header( stream )
+  def write_xml_header(stream)
     stream.puts "<?xml version='1.0' encoding='utf-8' ?>"
   end
 
-  def write_suites_header( stream )
-    stream.puts "<testsuites>"
+  def write_suites_header(stream)
+    stream.puts '<testsuites>'
   end
 
-  def write_suite_header( counts, stream )
+  def write_suite_header(counts, stream)
     stream.puts "\t<testsuite errors=\"0\" skipped=\"#{counts[:ignored]}\" failures=\"#{counts[:failed]}\" tests=\"#{counts[:total]}\" name=\"unity\">"
   end
 
-  def write_failures( results, stream )
+  def write_failures(results, stream)
     result = results[:failures]
     result.each do |item|
       filename = File.join(results[:source][:path], File.basename(results[:source][:file], '.*'))
@@ -206,15 +195,14 @@ class UnityToJUnit
     end
   end
 
-  def write_tests( results, stream )
+  def write_tests(results, stream)
     result = results[:successes]
     result.each do |item|
-      filename = File.join(results[:source][:path], File.basename(results[:source][:file], '.*'))
       stream.puts "\t\t<testcase classname=\"#{@unit_name}\" name=\"#{item[:test]}\" time=\"0\" />"
     end
   end
 
-  def write_ignored( results, stream )
+  def write_ignored(results, stream)
     result = results[:ignores]
     result.each do |item|
       filename = File.join(results[:source][:path], File.basename(results[:source][:file], '.*'))
@@ -226,39 +214,39 @@ class UnityToJUnit
     end
   end
 
-  def write_suite_footer( stream )
+  def write_suite_footer(stream)
     stream.puts "\t</testsuite>"
   end
 
-  def write_suites_footer( stream )
-    stream.puts "</testsuites>"
+  def write_suites_footer(stream)
+    stream.puts '</testsuites>'
   end
-end #UnityToJUnit
+end # UnityToJUnit
 
 if __FILE__ == $0
-  #parse out the command options
+  # parse out the command options
   options = ArgvParser.parse(ARGV)
 
-  #create an instance to work with
+  # create an instance to work with
   utj = UnityToJUnit.new
   begin
-    #look in the specified or current directory for result files
-    targets = "#{options.results_dir.gsub(/\\/, '/')}**/*.test*"
+    # look in the specified or current directory for result files
+    targets = "#{options.results_dir.tr('\\', '/')}**/*.test*"
 
     results = Dir[targets]
     raise "No *.testpass, *.testfail, or *.testresults files found in '#{targets}'" if results.empty?
-    utj.set_targets(results)
+    utj.targets = results
 
-    #set the root path
-    utj.set_root_path(options.root_path)
+    # set the root path
+    utj.root = options.root_path
 
-    #set the output XML file name
-    #puts "Output File from options: #{options.out_file}"
-    utj.set_out_file(options.out_file)
+    # set the output XML file name
+    # puts "Output File from options: #{options.out_file}"
+    utj.out_file = options.out_file
 
-    #run the summarizer
+    # run the summarizer
     puts utj.run
-  rescue Exception => e
+  rescue StandardError => e
     utj.usage e.message
   end
 end

+ 11 - 9
tests/unity/auto/test_file_filter.rb

@@ -2,7 +2,7 @@
 #   Unity Project - A Test Framework for C
 #   Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
 #   [Released under MIT License. Please refer to license.txt for details]
-# ========================================== 
+# ==========================================
 
 require'yaml'
 
@@ -10,14 +10,16 @@ module RakefileHelpers
   class TestFileFilter
     def initialize(all_files = false)
       @all_files = all_files
-      if not @all_files == true
-        if File.exist?('test_file_filter.yml')
-          filters = YAML.load_file( 'test_file_filter.yml' )
-          @all_files, @only_files, @exclude_files = 
-            filters[:all_files], filters[:only_files], filters[:exclude_files] 
-        end
-      end
-    end		
+
+      return false unless @all_files
+      return false unless File.exist?('test_file_filter.yml')
+
+      filters = YAML.load_file('test_file_filter.yml')
+      @all_files = filters[:all_files]
+      @only_files = filters[:only_files]
+      @exclude_files = filters[:exclude_files]
+    end
+
     attr_accessor :all_files, :only_files, :exclude_files
   end
 end

+ 1 - 3
tests/unity/auto/type_sanitizer.rb

@@ -1,8 +1,6 @@
 module TypeSanitizer
-  
   def self.sanitize_c_identifier(unsanitized)
     # convert filename to valid C identifier by replacing invalid chars with '_'
-    return unsanitized.gsub(/[-\/\\\.\,\s]/, "_")
+    unsanitized.gsub(/[-\/\\\.\,\s]/, '_')
   end
-
 end

+ 45 - 57
tests/unity/auto/unity_test_summary.rb

@@ -4,7 +4,7 @@
 #   [Released under MIT License. Please refer to license.txt for details]
 # ==========================================
 
-#!/usr/bin/ruby
+# !/usr/bin/ruby
 #
 # unity_test_summary.rb
 #
@@ -15,37 +15,35 @@ class UnityTestSummary
   include FileUtils::Verbose
 
   attr_reader :report, :total_tests, :failures, :ignored
+  attr_writer :targets, :root
 
-  def initialize(opts = {})
+  def initialize(_opts = {})
     @report = ''
     @total_tests = 0
     @failures = 0
     @ignored = 0
-
-
   end
 
   def run
     # Clean up result file names
-    results = @targets.map {|target| target.gsub(/\\/,'/')}
+    results = @targets.map { |target| target.tr('\\', '/') }
 
     # Dig through each result file, looking for details on pass/fail:
     failure_output = []
     ignore_output = []
 
     results.each do |result_file|
-      lines = File.readlines(result_file).map { |line| line.chomp }
-      if lines.length == 0
-        raise "Empty test result file: #{result_file}"
-      else
-        output = get_details(result_file, lines)
-        failure_output << output[:failures] unless output[:failures].empty?
-        ignore_output  << output[:ignores]  unless output[:ignores].empty?
-        tests,failures,ignored = parse_test_summary(lines)
-        @total_tests += tests
-        @failures += failures
-        @ignored += ignored
-      end
+      lines = File.readlines(result_file).map(&:chomp)
+
+      raise "Empty test result file: #{result_file}" if lines.empty?
+
+      output = get_details(result_file, lines)
+      failure_output << output[:failures] unless output[:failures].empty?
+      ignore_output  << output[:ignores]  unless output[:ignores].empty?
+      tests, failures, ignored = parse_test_summary(lines)
+      @total_tests += tests
+      @failures += failures
+      @ignored += ignored
     end
 
     if @ignored > 0
@@ -72,77 +70,67 @@ class UnityTestSummary
     @report += "\n"
   end
 
-  def set_targets(target_array)
-    @targets = target_array
-  end
-
-  def set_root_path(path)
-    @root = path
-  end
-
-  def usage(err_msg=nil)
+  def usage(err_msg = nil)
     puts "\nERROR: "
     puts err_msg if err_msg
     puts "\nUsage: unity_test_summary.rb result_file_directory/ root_path/"
-    puts "     result_file_directory - The location of your results files."
-    puts "                             Defaults to current directory if not specified."
-    puts "                             Should end in / if specified."
-    puts "     root_path - Helpful for producing more verbose output if using relative paths."
+    puts '     result_file_directory - The location of your results files.'
+    puts '                             Defaults to current directory if not specified.'
+    puts '                             Should end in / if specified.'
+    puts '     root_path - Helpful for producing more verbose output if using relative paths.'
     exit 1
   end
 
   protected
 
-  def get_details(result_file, lines)
-    results = { :failures => [], :ignores => [], :successes => [] }
+  def get_details(_result_file, lines)
+    results = { failures: [], ignores: [], successes: [] }
     lines.each do |line|
-      src_file,src_line,test_name,status,msg = line.split(/:/)
-      line_out = ((@root && (@root != 0)) ? "#{@root}#{line}" : line ).gsub(/\//, "\\")
-      case(status)
-        when 'IGNORE' then results[:ignores]   << line_out
-        when 'FAIL'   then results[:failures]  << line_out
-        when 'PASS'   then results[:successes] << line_out
+      _src_file, _src_line, _test_name, status, _msg = line.split(/:/)
+      line_out = (@root && (@root != 0) ? "#{@root}#{line}" : line).gsub(/\//, '\\')
+      case status
+      when 'IGNORE' then results[:ignores]   << line_out
+      when 'FAIL'   then results[:failures]  << line_out
+      when 'PASS'   then results[:successes] << line_out
       end
     end
-    return results
+    results
   end
 
   def parse_test_summary(summary)
-    if summary.find { |v| v =~ /(\d+) Tests (\d+) Failures (\d+) Ignored/ }
-      [$1.to_i,$2.to_i,$3.to_i]
-    else
-      raise "Couldn't parse test results: #{summary}"
-    end
+    raise "Couldn't parse test results: #{summary}" unless summary.find { |v| v =~ /(\d+) Tests (\d+) Failures (\d+) Ignored/ }
+    [Regexp.last_match(1).to_i, Regexp.last_match(2).to_i, Regexp.last_match(3).to_i]
   end
 
-  def here; File.expand_path(File.dirname(__FILE__)); end
-
+  def here
+    File.expand_path(File.dirname(__FILE__))
+  end
 end
 
 if $0 == __FILE__
 
-  #parse out the command options
-  opts, args = ARGV.partition {|v| v =~ /^--\w+/}
-  opts.map! {|v| v[2..-1].to_sym }
+  # parse out the command options
+  opts, args = ARGV.partition { |v| v =~ /^--\w+/ }
+  opts.map! { |v| v[2..-1].to_sym }
 
-  #create an instance to work with
+  # create an instance to work with
   uts = UnityTestSummary.new(opts)
 
   begin
-    #look in the specified or current directory for result files
+    # look in the specified or current directory for result files
     args[0] ||= './'
-    targets = "#{ARGV[0].gsub(/\\/, '/')}**/*.test*"
+    targets = "#{ARGV[0].tr('\\', '/')}**/*.test*"
     results = Dir[targets]
     raise "No *.testpass, *.testfail, or *.testresults files found in '#{targets}'" if results.empty?
-    uts.set_targets(results)
+    uts.targets = results
 
-    #set the root path
+    # set the root path
     args[1] ||= Dir.pwd + '/'
-    uts.set_root_path(ARGV[1])
+    uts.root = ARGV[1]
 
-    #run the summarizer
+    # run the summarizer
     puts uts.run
-  rescue Exception => e
+  rescue StandardError => e
     uts.usage e.message
   end
 end

+ 207 - 0
tests/unity/docs/ThrowTheSwitchCodingStandard.md

@@ -0,0 +1,207 @@
+# ThrowTheSwitch.org Coding Standard
+
+Hi. Welcome to the coding standard for ThrowTheSwitch.org. For the most part,
+we try to follow these standards to unify our contributors' code into a cohesive
+unit (puns intended). You might find places where these standards aren't
+followed. We're not perfect. Please be polite where you notice these discrepancies
+and we'll try to be polite when we notice yours.
+
+;)
+
+
+## Why Have A Coding Standard?
+
+Being consistent makes code easier to understand. We've made an attempt to keep
+our standard simple because we also believe that we can only expect someone to
+follow something that is understandable. Please do your best.
+
+
+## Our Philosophy
+
+Before we get into details on syntax, let's take a moment to talk about our
+vision for these tools. We're C developers and embedded software developers.
+These tools are great to test any C code, but catering to embedded software has
+made us more tolerant of compiler quirks. There are a LOT of quirky compilers
+out there. By quirky I mean "doesn't follow standards because they feel like
+they have a license to do as they wish."
+
+Our philosophy is "support every compiler we can". Most often, this means that
+we aim for writing C code that is standards compliant (often C89... that seems
+to be a sweet spot that is almost always compatible). But it also means these
+tools are tolerant of things that aren't common. Some that aren't even
+compliant. There are configuration options to override the size of standard
+types. There are configuration options to force Unity to not use certain
+standard library functions. A lot of Unity is configurable and we have worked
+hard to make it not TOO ugly in the process.
+
+Similarly, our tools that parse C do their best. They aren't full C parsers
+(yet) and, even if they were, they would still have to accept non-standard
+additions like gcc extensions or specifying `@0x1000` to force a variable to
+compile to a particular location. It's just what we do, because we like
+everything to Just Work™.
+
+Speaking of having things Just Work™, that's our second philosophy. By that, we
+mean that we do our best to have EVERY configuration option have a logical
+default. We believe that if you're working with a simple compiler and target,
+you shouldn't need to configure very much... we try to make the tools guess as
+much as they can, but give the user the power to override it when it's wrong.
+
+
+## Naming Things
+
+Let's talk about naming things. Programming is all about naming things. We name
+files, functions, variables, and so much more. While we're not always going to
+find the best name for something, we actually put quite a bit of effort into
+finding *What Something WANTS to be Called*™.
+
+When naming things, we more or less follow this hierarchy, the first being the
+most important to us (but we do all four whenever possible):
+1. Readable
+2. Descriptive
+3. Consistent
+4. Memorable
+
+
+#### Readable
+
+We want to read our code. This means we like names and flow that are more
+naturally read. We try to avoid double negatives. We try to avoid cryptic
+abbreviations (sticking to ones we feel are common).
+
+
+#### Descriptive
+
+We like descriptive names for things, especially functions and variables.
+Finding the right name for something is an important endeavor. You might notice
+from poking around our code that this often results in names that are a little
+longer than the average. Guilty. We're okay with a tiny bit more typing if it
+means our code is easier to understand.
+
+There are two exceptions to this rule that we also stick to as religiously as
+possible:
+
+First, while we realize hungarian notation (and similar systems for encoding
+type information into variable names) is providing a more descriptive name, we
+feel that (for the average developer) it takes away from readability and
+therefore is to be avoided.
+
+Second, loop counters and other local throw-away variables often have a purpose
+which is obvious. There's no need, therefore, to get carried away with complex
+naming. We find i, j, and k are better loop counters than loopCounterVar or
+whatnot. We only break this rule when we see that more description could improve
+understanding of an algorithm.
+
+
+#### Consistent
+
+We like consistency, but we're not really obsessed with it. We try to name our
+configuration macros in a consistent fashion... you'll notice a repeated use of
+UNITY_EXCLUDE_BLAH or UNITY_USES_BLAH macros. This helps users avoid having to
+remember each macro's details.
+
+
+#### Memorable
+
+Where ever it doesn't violate the above principles, we try to apply memorable
+names. Sometimes this means using something that is simply descriptive, but
+often we strive for descriptive AND unique... we like quirky names that stand
+out in our memory and are easier to search for. Take a look through the file
+names in Ceedling and you'll get a good idea of what we are talking about here.
+Why use preprocess when you can use preprocessinator? Or what better describes a
+module in charge of invoking tasks during releases than release_invoker? Don't
+get carried away. The names are still descriptive and fulfill the above
+requirements, but they don't feel stale.
+
+
+## C and C++ Details
+
+We don't really want to add to the style battles out there. Tabs or spaces?
+How many spaces? Where do the braces go? These are age-old questions that will
+never be answered... or at least not answered in a way that will make everyone
+happy.
+
+We've decided on our own style preferences. If you'd like to contribute to these
+projects (and we hope that you do), then we ask if you do your best to follow
+the same. It will only hurt a little. We promise.
+
+
+#### Whitespace
+
+Our C-style is to use spaces and to use 4 of them per indent level. It's a nice
+power-of-2 number that looks decent on a wide screen. We have no more reason
+than that. We break that rule when we have lines that wrap (macros or function
+arguments or whatnot). When that happens, we like to indent further to line
+things up in nice tidy columns.
+
+```C
+    if (stuff_happened)
+    {
+        do_something();
+    }
+```
+
+
+#### Case
+
+- Files - all lower case with underscores.
+- Variables - all lower case with underscores
+- Macros - all caps with underscores.
+- Typedefs - all caps with underscores. (also ends with _T).
+- Functions - camel cased. Usually named ModuleName_FuncName
+- Constants and Globals - camel cased.
+
+
+#### Braces
+
+The left brace is on the next line after the declaration. The right brace is
+directly below that. Everything in between in indented one level. If you're
+catching an error and you have a one-line, go ahead and to it on the same line.
+
+```C
+    while (blah)
+    {
+        //Like so. Even if only one line, we use braces.
+    }
+```
+
+
+#### Comments
+
+Do you know what we hate? Old-school C block comments. BUT, we're using them
+anyway. As we mentioned, our goal is to support every compiler we can,
+especially embedded compilers. There are STILL C compilers out there that only
+support old-school block comments. So that is what we're using. We apologize. We
+think they are ugly too.
+
+
+## Ruby Details
+
+Is there really such thing as a Ruby coding standard? Ruby is such a free form
+language, it seems almost sacrilegious to suggest that people should comply to
+one method! We'll keep it really brief!
+
+
+#### Whitespace
+
+Our Ruby style is to use spaces and to use 2 of them per indent level. It's a
+nice power-of-2 number that really grooves with Ruby's compact style. We have no
+more reason than that. We break that rule when we have lines that wrap. When
+that happens, we like to indent further to line things up in nice tidy columns.
+
+
+#### Case
+
+- Files - all lower case with underscores.
+- Variables - all lower case with underscores
+- Classes, Modules, etc - Camel cased.
+- Functions - all lower case with underscores
+- Constants - all upper case with underscores
+
+
+## Documentation
+
+Egad. Really? We use markdown and we like pdf files because they can be made to
+look nice while still being portable. Good enough?
+
+
+*Find The Latest of This And More at [ThrowTheSwitch.org](https://throwtheswitch.org)*

二进制
tests/unity/docs/UnityAssertionsCheatSheetSuitableforPrintingandPossiblyFraming.pdf


+ 716 - 0
tests/unity/docs/UnityAssertionsReference.md

@@ -0,0 +1,716 @@
+# Unity Assertions Reference
+
+## Background and Overview
+
+### Super Condensed Version
+
+- An assertion establishes truth (i.e. boolean True) for a single condition.
+Upon boolean False, an assertion stops execution and reports the failure.
+- Unity is mainly a rich collection of assertions and the support to gather up
+and easily execute those assertions.
+- The structure of Unity allows you to easily separate test assertions from
+source code in, well, test code.
+- Unity's assertions:
+- Come in many, many flavors to handle different C types and assertion cases.
+- Use context to provide detailed and helpful failure messages.
+- Document types, expected values, and basic behavior in your source code for
+free.
+
+
+### Unity Is Several Things But Mainly It's Assertions
+
+One way to think of Unity is simply as a rich collection of assertions you can
+use to establish whether your source code behaves the way you think it does.
+Unity provides a framework to easily organize and execute those assertions in
+test code separate from your source code.
+
+
+### What's an Assertion?
+
+At their core, assertions are an establishment of truth - boolean truth. Was this
+thing equal to that thing? Does that code doohickey have such-and-such property
+or not? You get the idea. Assertions are executable code (to appreciate the big
+picture on this read up on the difference between
+[link:Dynamic Verification and Static Analysis]). A failing assertion stops
+execution and reports an error through some appropriate I/O channel (e.g.
+stdout, GUI, file, blinky light).
+
+Fundamentally, for dynamic verification all you need is a single assertion
+mechanism. In fact, that's what the [assert() macro in C's standard library](http://en.wikipedia.org/en/wiki/Assert.h)
+is for. So why not just use it? Well, we can do far better in the reporting
+department. C's `assert()` is pretty dumb as-is and is particularly poor for
+handling common data types like arrays, structs, etc. And, without some other
+support, it's far too tempting to litter source code with C's `assert()`'s. It's
+generally much cleaner, manageable, and more useful to separate test and source
+code in the way Unity facilitates.
+
+
+### Unity's Assertions: Helpful Messages _and_ Free Source Code Documentation
+
+Asserting a simple truth condition is valuable, but using the context of the
+assertion is even more valuable. For instance, if you know you're comparing bit
+flags and not just integers, then why not use that context to give explicit,
+readable, bit-level feedback when an assertion fails?
+
+That's what Unity's collection of assertions do - capture context to give you
+helpful, meaningful assertion failure messages. In fact, the assertions
+themselves also serve as executable documentation about types and values in your
+source code. So long as your tests remain current with your source and all those
+tests pass, you have a detailed, up-to-date view of the intent and mechanisms in
+your source code. And due to a wondrous mystery, well-tested code usually tends
+to be well designed code.
+
+
+## Assertion Conventions and Configurations
+
+### Naming and Parameter Conventions
+
+The convention of assertion parameters generally follows this order:
+
+    TEST_ASSERT_X( {modifiers}, {expected}, actual, {size/count} )
+
+The very simplest assertion possible uses only a single "actual" parameter (e.g.
+a simple null check).
+
+"Actual" is the value being tested and unlike the other parameters in an
+assertion construction is the only parameter present in all assertion variants.
+"Modifiers" are masks, ranges, bit flag specifiers, floating point deltas.
+"Expected" is your expected value (duh) to compare to an "actual" value; it's
+marked as an optional parameter because some assertions only need a single
+"actual" parameter (e.g. null check).
+"Size/count" refers to string lengths, number of array elements, etc.
+
+Many of Unity's assertions are apparent duplications in that the same data type
+is handled by several assertions. The differences among these are in how failure
+messages are presented. For instance, a `_HEX` variant of an assertion prints
+the expected and actual values of that assertion formatted as hexadecimal.
+
+
+#### TEST_ASSERT_X_MESSAGE Variants
+
+_All_ assertions are complemented with a variant that includes a simple string
+message as a final parameter. The string you specify is appended to an assertion
+failure message in Unity output.
+
+For brevity, the assertion variants with a message parameter are not listed
+below. Just tack on `_MESSAGE` as the final component to any assertion name in
+the reference list below and add a string as the final parameter.
+
+_Example:_
+
+    TEST_ASSERT_X( {modifiers}, {expected}, actual, {size/count} )
+
+becomes messageified like thus...
+
+    TEST_ASSERT_X_MESSAGE( {modifiers}, {expected}, actual, {size/count}, message )
+
+
+#### TEST_ASSERT_X_ARRAY Variants
+
+Unity provides a collection of assertions for arrays containing a variety of
+types. These are documented in the Array section below. These are almost on par
+with the `_MESSAGE`variants of Unity's Asserts in that for pretty much any Unity
+type assertion you can tack on `_ARRAY` and run assertions on an entire block of
+memory.
+
+    TEST_ASSERT_EQUAL_TYPEX_ARRAY( expected, actual, {size/count} )
+
+"Expected" is an array itself.
+"Size/count" is one or two parameters necessary to establish the number of array
+elements and perhaps the length of elements within the array.
+
+Notes:
+- The `_MESSAGE` variant convention still applies here to array assertions. The
+`_MESSAGE` variants of the `_ARRAY` assertions have names ending with
+`_ARRAY_MESSAGE`.
+- Assertions for handling arrays of floating point values are grouped with float
+and double assertions (see immediately following section).
+
+
+### TEST_ASSERT_EACH_EQUAL_X Variants
+
+Unity provides a collection of assertions for arrays containing a variety of
+types which can be compared to a single value as well. These are documented in
+the Each Equal section below. these are almost on par with the `_MESSAGE`
+variants of Unity's Asserts in that for pretty much any Unity type assertion you
+can inject _EACH_EQUAL and run assertions on an entire block of memory.
+
+    TEST_ASSERT_EACH_EQUAL_TYPEX( expected, actual, {size/count} )
+
+"Expected" is a single value to compare to.
+"Actual" is an array where each element will be compared to the expected value.
+"Size/count" is one of two parameters necessary to establish the number of array
+elements and perhaps the length of elements within the array.
+
+Notes:
+- The `_MESSAGE` variant convention still applies here to Each Equal assertions.
+- Assertions for handling Each Equal of floating point values are grouped with
+float and double assertions (see immediately following section).
+
+
+### Configuration
+
+#### Floating Point Support Is Optional
+
+Support for floating point types is configurable. That is, by defining the
+appropriate preprocessor symbols, floats and doubles can be individually enabled
+or disabled in Unity code. This is useful for embedded targets with no floating
+point math support (i.e. Unity compiles free of errors for fixed point only
+platforms). See Unity documentation for specifics.
+
+
+#### Maximum Data Type Width Is Configurable
+
+Not all targets support 64 bit wide types or even 32 bit wide types. Define the
+appropriate preprocessor symbols and Unity will omit all operations from
+compilation that exceed the maximum width of your target. See Unity
+documentation for specifics.
+
+
+## The Assertions in All Their Blessed Glory
+
+### Basic Fail and Ignore
+
+##### `TEST_FAIL()`
+
+This fella is most often used in special conditions where your test code is
+performing logic beyond a simple assertion. That is, in practice, `TEST_FAIL()`
+will always be found inside a conditional code block.
+
+_Examples:_
+- Executing a state machine multiple times that increments a counter your test
+code then verifies as a final step.
+- Triggering an exception and verifying it (as in Try / Catch / Throw - see the
+[CException](https://github.com/ThrowTheSwitch/CException) project).
+
+##### `TEST_IGNORE()`
+
+Marks a test case (i.e. function meant to contain test assertions) as ignored.
+Usually this is employed as a breadcrumb to come back and implement a test case.
+An ignored test case has effects if other assertions are in the enclosing test
+case (see Unity documentation for more).
+
+### Boolean
+
+##### `TEST_ASSERT (condition)`
+
+##### `TEST_ASSERT_TRUE (condition)`
+
+##### `TEST_ASSERT_FALSE (condition)`
+
+##### `TEST_ASSERT_UNLESS (condition)`
+
+A simple wording variation on `TEST_ASSERT_FALSE`.The semantics of
+`TEST_ASSERT_UNLESS` aid readability in certain test constructions or
+conditional statements.
+
+##### `TEST_ASSERT_NULL (pointer)`
+
+##### `TEST_ASSERT_NOT_NULL (pointer)`
+
+
+### Signed and Unsigned Integers (of all sizes)
+
+Large integer sizes can be disabled for build targets that do not support them.
+For example, if your target only supports up to 16 bit types, by defining the
+appropriate symbols Unity can be configured to omit 32 and 64 bit operations
+that would break compilation (see Unity documentation for more). Refer to
+Advanced Asserting later in this document for advice on dealing with other word
+sizes.
+
+##### `TEST_ASSERT_EQUAL_INT (expected, actual)`
+
+##### `TEST_ASSERT_EQUAL_INT8 (expected, actual)`
+
+##### `TEST_ASSERT_EQUAL_INT16 (expected, actual)`
+
+##### `TEST_ASSERT_EQUAL_INT32 (expected, actual)`
+
+##### `TEST_ASSERT_EQUAL_INT64 (expected, actual)`
+
+##### `TEST_ASSERT_EQUAL (expected, actual)`
+
+##### `TEST_ASSERT_NOT_EQUAL (expected, actual)`
+
+##### `TEST_ASSERT_EQUAL_UINT (expected, actual)`
+
+##### `TEST_ASSERT_EQUAL_UINT8 (expected, actual)`
+
+##### `TEST_ASSERT_EQUAL_UINT16 (expected, actual)`
+
+##### `TEST_ASSERT_EQUAL_UINT32 (expected, actual)`
+
+##### `TEST_ASSERT_EQUAL_UINT64 (expected, actual)`
+
+
+### Unsigned Integers (of all sizes) in Hexadecimal
+
+All `_HEX` assertions are identical in function to unsigned integer assertions
+but produce failure messages with the `expected` and `actual` values formatted
+in hexadecimal. Unity output is big endian.
+
+##### `TEST_ASSERT_EQUAL_HEX (expected, actual)`
+
+##### `TEST_ASSERT_EQUAL_HEX8 (expected, actual)`
+
+##### `TEST_ASSERT_EQUAL_HEX16 (expected, actual)`
+
+##### `TEST_ASSERT_EQUAL_HEX32 (expected, actual)`
+
+##### `TEST_ASSERT_EQUAL_HEX64 (expected, actual)`
+
+
+### Masked and Bit-level Assertions
+
+Masked and bit-level assertions produce output formatted in hexadecimal. Unity
+output is big endian.
+
+
+##### `TEST_ASSERT_BITS (mask, expected, actual)`
+
+Only compares the masked (i.e. high) bits of `expected` and `actual` parameters.
+
+
+##### `TEST_ASSERT_BITS_HIGH (mask, actual)`
+
+Asserts the masked bits of the `actual` parameter are high.
+
+
+##### `TEST_ASSERT_BITS_LOW (mask, actual)`
+
+Asserts the masked bits of the `actual` parameter are low.
+
+
+##### `TEST_ASSERT_BIT_HIGH (bit, actual)`
+
+Asserts the specified bit of the `actual` parameter is high.
+
+
+##### `TEST_ASSERT_BIT_LOW (bit, actual)`
+
+Asserts the specified bit of the `actual` parameter is low.
+
+
+### Integer Ranges (of all sizes)
+
+These assertions verify that the `expected` parameter is within +/- `delta`
+(inclusive) of the `actual` parameter. For example, if the expected value is 10
+and the delta is 3 then the assertion will fail for any value outside the range
+of 7 - 13.
+
+##### `TEST_ASSERT_INT_WITHIN (delta, expected, actual)`
+
+##### `TEST_ASSERT_INT8_WITHIN (delta, expected, actual)`
+
+##### `TEST_ASSERT_INT16_WITHIN (delta, expected, actual)`
+
+##### `TEST_ASSERT_INT32_WITHIN (delta, expected, actual)`
+
+##### `TEST_ASSERT_INT64_WITHIN (delta, expected, actual)`
+
+##### `TEST_ASSERT_UINT_WITHIN (delta, expected, actual)`
+
+##### `TEST_ASSERT_UINT8_WITHIN (delta, expected, actual)`
+
+##### `TEST_ASSERT_UINT16_WITHIN (delta, expected, actual)`
+
+##### `TEST_ASSERT_UINT32_WITHIN (delta, expected, actual)`
+
+##### `TEST_ASSERT_UINT64_WITHIN (delta, expected, actual)`
+
+##### `TEST_ASSERT_HEX_WITHIN (delta, expected, actual)`
+
+##### `TEST_ASSERT_HEX8_WITHIN (delta, expected, actual)`
+
+##### `TEST_ASSERT_HEX16_WITHIN (delta, expected, actual)`
+
+##### `TEST_ASSERT_HEX32_WITHIN (delta, expected, actual)`
+
+##### `TEST_ASSERT_HEX64_WITHIN (delta, expected, actual)`
+
+
+### Structs and Strings
+
+##### `TEST_ASSERT_EQUAL_PTR (expected, actual)`
+
+Asserts that the pointers point to the same memory location.
+
+
+##### `TEST_ASSERT_EQUAL_STRING (expected, actual)`
+
+Asserts that the null terminated (`'\0'`)strings are identical. If strings are
+of different lengths or any portion of the strings before their terminators
+differ, the assertion fails. Two NULL strings (i.e. zero length) are considered
+equivalent.
+
+
+##### `TEST_ASSERT_EQUAL_MEMORY (expected, actual, len)`
+
+Asserts that the contents of the memory specified by the `expected` and `actual`
+pointers is identical. The size of the memory blocks in bytes is specified by
+the `len` parameter.
+
+
+### Arrays
+
+`expected` and `actual` parameters are both arrays. `num_elements` specifies the
+number of elements in the arrays to compare.
+
+`_HEX` assertions produce failure messages with expected and actual array
+contents formatted in hexadecimal.
+
+For array of strings comparison behavior, see comments for
+`TEST_ASSERT_EQUAL_STRING` in the preceding section.
+
+Assertions fail upon the first element in the compared arrays found not to
+match. Failure messages specify the array index of the failed comparison.
+
+##### `TEST_ASSERT_EQUAL_INT_ARRAY (expected, actual, num_elements)`
+
+##### `TEST_ASSERT_EQUAL_INT8_ARRAY (expected, actual, num_elements)`
+
+##### `TEST_ASSERT_EQUAL_INT16_ARRAY (expected, actual, num_elements)`
+
+##### `TEST_ASSERT_EQUAL_INT32_ARRAY (expected, actual, num_elements)`
+
+##### `TEST_ASSERT_EQUAL_INT64_ARRAY (expected, actual, num_elements)`
+
+##### `TEST_ASSERT_EQUAL_UINT_ARRAY (expected, actual, num_elements)`
+
+##### `TEST_ASSERT_EQUAL_UINT8_ARRAY (expected, actual, num_elements)`
+
+##### `TEST_ASSERT_EQUAL_UINT16_ARRAY (expected, actual, num_elements)`
+
+##### `TEST_ASSERT_EQUAL_UINT32_ARRAY (expected, actual, num_elements)`
+
+##### `TEST_ASSERT_EQUAL_UINT64_ARRAY (expected, actual, num_elements)`
+
+##### `TEST_ASSERT_EQUAL_HEX_ARRAY (expected, actual, num_elements)`
+
+##### `TEST_ASSERT_EQUAL_HEX8_ARRAY (expected, actual, num_elements)`
+
+##### `TEST_ASSERT_EQUAL_HEX16_ARRAY (expected, actual, num_elements)`
+
+##### `TEST_ASSERT_EQUAL_HEX32_ARRAY (expected, actual, num_elements)`
+
+##### `TEST_ASSERT_EQUAL_HEX64_ARRAY (expected, actual, num_elements)`
+
+##### `TEST_ASSERT_EQUAL_PTR_ARRAY (expected, actual, num_elements)`
+
+##### `TEST_ASSERT_EQUAL_STRING_ARRAY (expected, actual, num_elements)`
+
+##### `TEST_ASSERT_EQUAL_MEMORY_ARRAY (expected, actual, len, num_elements)`
+
+`len` is the memory in bytes to be compared at each array element.
+
+
+### Each Equal (Arrays to Single Value)
+
+`expected` are single values and `actual` are arrays. `num_elements` specifies
+the number of elements in the arrays to compare.
+
+`_HEX` assertions produce failure messages with expected and actual array
+contents formatted in hexadecimal.
+
+Assertions fail upon the first element in the compared arrays found not to
+match. Failure messages specify the array index of the failed comparison.
+
+#### `TEST_ASSERT_EACH_EQUAL_INT (expected, actual, num_elements)`
+
+#### `TEST_ASSERT_EACH_EQUAL_INT8 (expected, actual, num_elements)`
+
+#### `TEST_ASSERT_EACH_EQUAL_INT16 (expected, actual, num_elements)`
+
+#### `TEST_ASSERT_EACH_EQUAL_INT32 (expected, actual, num_elements)`
+
+#### `TEST_ASSERT_EACH_EQUAL_INT64 (expected, actual, num_elements)`
+
+#### `TEST_ASSERT_EACH_EQUAL_UINT (expected, actual, num_elements)`
+
+#### `TEST_ASSERT_EACH_EQUAL_UINT8 (expected, actual, num_elements)`
+
+#### `TEST_ASSERT_EACH_EQUAL_UINT16 (expected, actual, num_elements)`
+
+#### `TEST_ASSERT_EACH_EQUAL_UINT32 (expected, actual, num_elements)`
+
+#### `TEST_ASSERT_EACH_EQUAL_UINT64 (expected, actual, num_elements)`
+
+#### `TEST_ASSERT_EACH_EQUAL_HEX (expected, actual, num_elements)`
+
+#### `TEST_ASSERT_EACH_EQUAL_HEX8 (expected, actual, num_elements)`
+
+#### `TEST_ASSERT_EACH_EQUAL_HEX16 (expected, actual, num_elements)`
+
+#### `TEST_ASSERT_EACH_EQUAL_HEX32 (expected, actual, num_elements)`
+
+#### `TEST_ASSERT_EACH_EQUAL_HEX64 (expected, actual, num_elements)`
+
+#### `TEST_ASSERT_EACH_EQUAL_PTR (expected, actual, num_elements)`
+
+#### `TEST_ASSERT_EACH_EQUAL_STRING (expected, actual, num_elements)`
+
+#### `TEST_ASSERT_EACH_EQUAL_MEMORY (expected, actual, len, num_elements)`
+
+`len` is the memory in bytes to be compared at each array element.
+
+
+### Floating Point (If enabled)
+
+##### `TEST_ASSERT_FLOAT_WITHIN (delta, expected, actual)`
+
+Asserts that the `actual` value is within +/- `delta` of the `expected` value.
+The nature of floating point representation is such that exact evaluations of
+equality are not guaranteed.
+
+
+##### `TEST_ASSERT_EQUAL_FLOAT (expected, actual)`
+
+Asserts that the ?actual?value is "close enough to be considered equal" to the
+`expected` value. If you are curious about the details, refer to the Advanced
+Asserting section for more details on this. Omitting a user-specified delta in a
+floating point assertion is both a shorthand convenience and a requirement of
+code generation conventions for CMock.
+
+
+##### `TEST_ASSERT_EQUAL_FLOAT_ARRAY (expected, actual, num_elements)`
+
+See Array assertion section for details. Note that individual array element
+float comparisons are executed using T?EST_ASSERT_EQUAL_FLOAT?.That is, user
+specified delta comparison values requires a custom-implemented floating point
+array assertion.
+
+
+##### `TEST_ASSERT_FLOAT_IS_INF (actual)`
+
+Asserts that `actual` parameter is equivalent to positive infinity floating
+point representation.
+
+
+##### `TEST_ASSERT_FLOAT_IS_NEG_INF (actual)`
+
+Asserts that `actual` parameter is equivalent to negative infinity floating
+point representation.
+
+
+##### `TEST_ASSERT_FLOAT_IS_NAN (actual)`
+
+Asserts that `actual` parameter is a Not A Number floating point representation.
+
+
+##### `TEST_ASSERT_FLOAT_IS_DETERMINATE (actual)`
+
+Asserts that ?actual?parameter is a floating point representation usable for
+mathematical operations. That is, the `actual` parameter is neither positive
+infinity nor negative infinity nor Not A Number floating point representations.
+
+
+##### `TEST_ASSERT_FLOAT_IS_NOT_INF (actual)`
+
+Asserts that `actual` parameter is a value other than positive infinity floating
+point representation.
+
+
+##### `TEST_ASSERT_FLOAT_IS_NOT_NEG_INF (actual)`
+
+Asserts that `actual` parameter is a value other than negative infinity floating
+point representation.
+
+
+##### `TEST_ASSERT_FLOAT_IS_NOT_NAN (actual)`
+
+Asserts that `actual` parameter is a value other than Not A Number floating
+point representation.
+
+
+##### `TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE (actual)`
+
+Asserts that `actual` parameter is not usable for mathematical operations. That
+is, the `actual` parameter is either positive infinity or negative infinity or
+Not A Number floating point representations.
+
+
+### Double (If enabled)
+
+##### `TEST_ASSERT_DOUBLE_WITHIN (delta, expected, actual)`
+
+Asserts that the `actual` value is within +/- `delta` of the `expected` value.
+The nature of floating point representation is such that exact evaluations of
+equality are not guaranteed.
+
+
+##### `TEST_ASSERT_EQUAL_DOUBLE (expected, actual)`
+
+Asserts that the `actual` value is "close enough to be considered equal" to the
+`expected` value. If you are curious about the details, refer to the Advanced
+Asserting section for more details. Omitting a user-specified delta in a
+floating point assertion is both a shorthand convenience and a requirement of
+code generation conventions for CMock.
+
+
+##### `TEST_ASSERT_EQUAL_DOUBLE_ARRAY (expected, actual, num_elements)`
+
+See Array assertion section for details. Note that individual array element
+double comparisons are executed using `TEST_ASSERT_EQUAL_DOUBLE`.That is, user
+specified delta comparison values requires a custom implemented double array
+assertion.
+
+
+##### `TEST_ASSERT_DOUBLE_IS_INF (actual)`
+
+Asserts that `actual` parameter is equivalent to positive infinity floating
+point representation.
+
+
+##### `TEST_ASSERT_DOUBLE_IS_NEG_INF (actual)`
+
+Asserts that `actual` parameter is equivalent to negative infinity floating point
+representation.
+
+
+##### `TEST_ASSERT_DOUBLE_IS_NAN (actual)`
+
+Asserts that `actual` parameter is a Not A Number floating point representation.
+
+
+##### `TEST_ASSERT_DOUBLE_IS_DETERMINATE (actual)`
+
+Asserts that `actual` parameter is a floating point representation usable for
+mathematical operations. That is, the ?actual?parameter is neither positive
+infinity nor negative infinity nor Not A Number floating point representations.
+
+
+##### `TEST_ASSERT_DOUBLE_IS_NOT_INF (actual)`
+
+Asserts that `actual` parameter is a value other than positive infinity floating
+point representation.
+
+
+##### `TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF (actual)`
+
+Asserts that `actual` parameter is a value other than negative infinity floating
+point representation.
+
+
+##### `TEST_ASSERT_DOUBLE_IS_NOT_NAN (actual)`
+
+Asserts that `actual` parameter is a value other than Not A Number floating
+point representation.
+
+
+##### `TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE (actual)`
+
+Asserts that `actual` parameter is not usable for mathematical operations. That
+is, the `actual` parameter is either positive infinity or negative infinity or
+Not A Number floating point representations.
+
+
+## Advanced Asserting: Details On Tricky Assertions
+
+This section helps you understand how to deal with some of the trickier
+assertion situations you may run into. It will give you a glimpse into some of
+the under-the-hood details of Unity's assertion mechanisms. If you're one of
+those people who likes to know what is going on in the background, read on. If
+not, feel free to ignore the rest of this document until you need it.
+
+
+### How do the EQUAL assertions work for FLOAT and DOUBLE?
+
+As you may know, directly checking for equality between a pair of floats or a
+pair of doubles is sloppy at best and an outright no-no at worst. Floating point
+values can often be represented in multiple ways, particularly after a series of
+operations on a value. Initializing a variable to the value of 2.0 is likely to
+result in a floating point representation of 2 x 20,but a series of
+mathematical operations might result in a representation of 8 x 2-2
+that also evaluates to a value of 2. At some point repeated operations cause
+equality checks to fail.
+
+So Unity doesn't do direct floating point comparisons for equality. Instead, it
+checks if two floating point values are "really close." If you leave Unity
+running with defaults, "really close" means "within a significant bit or two."
+Under the hood, `TEST_ASSERT_EQUAL_FLOAT` is really `TEST_ASSERT_FLOAT_WITHIN`
+with the `delta` parameter calculated on the fly. For single precision, delta is
+the expected value multiplied by 0.00001, producing a very small proportional
+range around the expected value.
+
+If you are expecting a value of 20,000.0 the delta is calculated to be 0.2. So
+any value between 19,999.8 and 20,000.2 will satisfy the equality check. This
+works out to be roughly a single bit of range for a single-precision number, and
+that's just about as tight a tolerance as you can reasonably get from a floating
+point value.
+
+So what happens when it's zero? Zero - even more than other floating point
+values - can be represented many different ways. It doesn't matter if you have
+0 x 20or 0 x 263.It's still zero, right? Luckily, if you
+subtract these values from each other, they will always produce a difference of
+zero, which will still fall between 0 plus or minus a delta of 0. So it still
+works!
+
+Double precision floating point numbers use a much smaller multiplier, again
+approximating a single bit of error.
+
+If you don't like these ranges and you want to make your floating point equality
+assertions less strict, you can change these multipliers to whatever you like by
+defining UNITY_FLOAT_PRECISION and UNITY_DOUBLE_PRECISION. See Unity
+documentation for more.
+
+
+### How do we deal with targets with non-standard int sizes?
+
+It's "fun" that C is a standard where something as fundamental as an integer
+varies by target. According to the C standard, an `int` is to be the target's
+natural register size, and it should be at least 16-bits and a multiple of a
+byte. It also guarantees an order of sizes:
+
+```C
+char <= short <= int <= long <= long long
+```
+
+Most often, `int` is 32-bits. In many cases in the embedded world, `int` is
+16-bits. There are rare microcontrollers out there that have 24-bit integers,
+and this remains perfectly standard C.
+
+To make things even more interesting, there are compilers and targets out there
+that have a hard choice to make. What if their natural register size is 10-bits
+or 12-bits? Clearly they can't fulfill _both_ the requirement to be at least
+16-bits AND the requirement to match the natural register size. In these
+situations, they often choose the natural register size, leaving us with
+something like this:
+
+```C
+char (8 bit) <= short (12 bit) <= int (12 bit) <= long (16 bit)
+```
+
+Um... yikes. It's obviously breaking a rule or two... but they had to break SOME
+rules, so they made a choice.
+
+When the C99 standard rolled around, it introduced alternate standard-size types.
+It also introduced macros for pulling in MIN/MAX values for your integer types.
+It's glorious! Unfortunately, many embedded compilers can't be relied upon to
+use the C99 types (Sometimes because they have weird register sizes as described
+above. Sometimes because they don't feel like it?).
+
+A goal of Unity from the beginning was to support every combination of
+microcontroller or microprocessor and C compiler. Over time, we've gotten really
+close to this. There are a few tricks that you should be aware of, though, if
+you're going to do this effectively on some of these more idiosyncratic targets.
+
+First, when setting up Unity for a new target, you're going to want to pay
+special attention to the macros for automatically detecting types
+(where available) or manually configuring them yourself. You can get information
+on both of these in Unity's documentation.
+
+What about the times where you suddenly need to deal with something odd, like a
+24-bit `int`? The simplest solution is to use the next size up. If you have a
+24-bit `int`, configure Unity to use 32-bit integers. If you have a 12-bit
+`int`, configure Unity to use 16 bits. There are two ways this is going to
+affect you:
+
+1. When Unity displays errors for you, it's going to pad the upper unused bits
+with zeros.
+2. You're going to have to be careful of assertions that perform signed
+operations, particularly `TEST_ASSERT_INT_WITHIN`.Such assertions might wrap
+your `int` in the wrong place, and you could experience false failures. You can
+always back down to a simple `TEST_ASSERT` and do the operations yourself.
+
+
+*Find The Latest of This And More at [ThrowTheSwitch.org](https://throwtheswitch.org)*

二进制
tests/unity/docs/UnityAssertionsReference.pdf


+ 398 - 0
tests/unity/docs/UnityConfigurationGuide.md

@@ -0,0 +1,398 @@
+# Unity Configuration Guide
+
+## C Standards, Compilers and Microcontrollers
+
+The embedded software world contains its challenges. Compilers support different
+revisions of the C Standard. They ignore requirements in places, sometimes to
+make the language more usable in some special regard. Sometimes it's to simplify
+their support. Sometimes it's due to specific quirks of the microcontroller they
+are targeting. Simulators add another dimension to this menagerie.
+
+Unity is designed to run on almost anything that is targeted by a C compiler. It
+would be awesome if this could be done with zero configuration. While there are
+some targets that come close to this dream, it is sadly not universal. It is
+likely that you are going to need at least a couple of the configuration options
+described in this document.
+
+All of Unity's configuration options are `#defines`. Most of these are simple
+definitions. A couple are macros with arguments. They live inside the
+unity_internals.h header file. We don't necessarily recommend opening that file
+unless you really need to. That file is proof that a cross-platform library is
+challenging to build. From a more positive perspective, it is also proof that a
+great deal of complexity can be centralized primarily to one place in order to
+provide a more consistent and simple experience elsewhere.
+
+
+### Using These Options
+
+It doesn't matter if you're using a target-specific compiler and a simulator or
+a native compiler. In either case, you've got a couple choices for configuring
+these options:
+
+1. Because these options are specified via C defines, you can pass most of these
+options to your compiler through command line compiler flags. Even if you're
+using an embedded target that forces you to use their overbearing IDE for all
+configuration, there will be a place somewhere in your project to configure
+defines for your compiler.
+2. You can create a custom `unity_config.h` configuration file (present in your
+toolchain's search paths). In this file, you will list definitions and macros
+specific to your target. All you must do is define `UNITY_INCLUDE_CONFIG_H` and
+Unity will rely on `unity_config.h` for any further definitions it may need.
+
+
+## The Options
+
+### Integer Types
+
+If you've been a C developer for long, you probably already know that C's
+concept of an integer varies from target to target. The C Standard has rules
+about the `int` matching the register size of the target microprocessor. It has
+rules about the `int` and how its size relates to other integer types. An `int`
+on one target might be 16 bits while on another target it might be 64. There are
+more specific types in compilers compliant with C99 or later, but that's
+certainly not every compiler you are likely to encounter. Therefore, Unity has a
+number of features for helping to adjust itself to match your required integer
+sizes. It starts off by trying to do it automatically.
+
+
+##### `UNITY_EXCLUDE_STDINT_H`
+
+The first thing that Unity does to guess your types is check `stdint.h`.
+This file includes defines like `UINT_MAX` that Unity can make use of to
+learn a lot about your system. It's possible you don't want it to do this
+(um. why not?) or (more likely) it's possible that your system doesn't
+support `stdint.h`. If that's the case, you're going to want to define this.
+That way, Unity will know to skip the inclusion of this file and you won't
+be left with a compiler error.
+
+_Example:_
+        #define UNITY_EXCLUDE_STDINT_H
+
+
+##### `UNITY_EXCLUDE_LIMITS_H`
+
+The second attempt to guess your types is to check `limits.h`. Some compilers
+that don't support `stdint.h` could include `limits.h` instead. If you don't
+want Unity to check this file either, define this to make it skip the inclusion.
+
+_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
+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.
+
+
+##### `UNITY_INT_WIDTH`
+
+Define this to be the number of bits an `int` takes up on your system. The
+default, if not autodetected, is 32 bits.
+
+_Example:_
+        #define UNITY_INT_WIDTH 16
+
+
+##### `UNITY_LONG_WIDTH`
+
+Define this to be the number of bits a `long` takes up on your system. The
+default, if not autodetected, is 32 bits. This is used to figure out what kind
+of 64-bit support your system can handle. Does it need to specify a `long` or a
+`long long` to get a 64-bit value. On 16-bit systems, this option is going to be
+ignored.
+
+_Example:_
+        #define UNITY_LONG_WIDTH 16
+
+
+##### `UNITY_POINTER_WIDTH`
+
+Define this to be the number of bits a pointer takes up on your system. The
+default, if not autodetected, is 32-bits. If you're getting ugly compiler
+warnings about casting from pointers, this is the one to look at.
+
+_Example:_
+        #define UNITY_POINTER_WIDTH 64
+
+
+##### `UNITY_INCLUDE_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
+enable 64-bit support if none of the other options already did it for you. There
+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
+
+
+### Floating Point Types
+
+In the embedded world, it's not uncommon for targets to have no support for
+floating point operations at all or to have support that is limited to only
+single precision. We are able to guess integer sizes on the fly because integers
+are always available in at least one size. Floating point, on the other hand, is
+sometimes not available at all. Trying to include `float.h` on these platforms
+would result in an error. This leaves manual configuration as the only option.
+
+
+##### `UNITY_INCLUDE_FLOAT`
+
+##### `UNITY_EXCLUDE_FLOAT`
+
+##### `UNITY_INCLUDE_DOUBLE`
+
+##### `UNITY_EXCLUDE_DOUBLE`
+
+By default, Unity guesses that you will want single precision floating point
+support, but not double precision. It's easy to change either of these using the
+include and exclude options here. You may include neither, either, or both, as
+suits your needs. For features that are enabled, the following floating point
+options also become available.
+
+_Example:_
+
+        //what manner of strange processor is this?
+        #define UNITY_EXCLUDE_FLOAT
+        #define UNITY_INCLUDE_DOUBLE
+
+
+##### `UNITY_FLOAT_VERBOSE`
+
+##### `UNITY_DOUBLE_VERBOSE`
+
+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
+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.
+
+_Example:_
+        #define UNITY_DOUBLE_VERBOSE
+
+
+##### `UNITY_FLOAT_TYPE`
+
+If enabled, Unity assumes you want your `FLOAT` asserts to compare standard C
+floats. If your compiler supports a specialty floating point type, you can
+always override this behavior by using this definition.
+
+_Example:_
+        #define UNITY_FLOAT_TYPE float16_t
+
+
+##### `UNITY_DOUBLE_TYPE`
+
+If enabled, Unity assumes you want your `DOUBLE` asserts to compare standard C
+doubles. If you would like to change this, you can specify something else by
+using this option. For example, defining `UNITY_DOUBLE_TYPE` to `long double`
+could enable gargantuan floating point types on your 64-bit processor instead of
+the standard `double`.
+
+_Example:_
+        #define UNITY_DOUBLE_TYPE long double
+
+
+##### `UNITY_FLOAT_PRECISION`
+
+##### `UNITY_DOUBLE_PRECISION`
+
+If you look up `UNITY_ASSERT_EQUAL_FLOAT` and `UNITY_ASSERT_EQUAL_DOUBLE` as
+documented in the big daddy Unity Assertion Guide, you will learn that they are
+not really asserting that two values are equal but rather that two values are
+"close enough" to equal. "Close enough" is controlled by these precision
+configuration options. If you are working with 32-bit floats and/or 64-bit
+doubles (the normal on most processors), you should have no need to change these
+options. They are both set to give you approximately 1 significant bit in either
+direction. The float precision is 0.00001 while the double is 10-12.
+For further details on how this works, see the appendix of the Unity Assertion
+Guide.
+
+_Example:_
+        #define UNITY_FLOAT_PRECISION 0.001f
+
+
+### Toolset Customization
+
+In addition to the options listed above, there are a number of other options
+which will come in handy to customize Unity's behavior for your specific
+toolchain. It is possible that you may not need to touch any of these... but
+certain platforms, particularly those running in simulators, may need to jump
+through extra hoops to operate properly. These macros will help in those
+situations.
+
+
+##### `UNITY_OUTPUT_CHAR(a)`
+
+##### `UNITY_OUTPUT_FLUSH()`
+
+##### `UNITY_OUTPUT_START()`
+
+##### `UNITY_OUTPUT_COMPLETE()`
+
+By default, Unity prints its results to `stdout` as it runs. This works
+perfectly fine in most situations where you are using a native compiler for
+testing. It works on some simulators as well so long as they have `stdout`
+routed back to the command line. There are times, however, where the simulator
+will lack support for dumping results or you will want to route results
+elsewhere for other reasons. In these cases, you should define the
+`UNITY_OUTPUT_CHAR` macro. This macro accepts a single character at a time (as
+an `int`, since this is the parameter type of the standard C `putchar` function
+most commonly used). You may replace this with whatever function call you like.
+
+_Example:_
+Say you are forced to run your test suite on an embedded processor with no
+`stdout` option. You decide to route your test result output to a custom serial
+`RS232_putc()` function you wrote like thus:
+
+        #define UNITY_OUTPUT_CHAR(a) RS232_putc(a)
+        #define UNITY_OUTPUT_START() RS232_config(115200,1,8,0)
+        #define UNITY_OUTPUT_FLUSH() RS232_flush()
+        #define UNITY_OUTPUT_COMPLETE() RS232_close()
+
+_Note:_
+`UNITY_OUTPUT_FLUSH()` can be set to the standard out flush function simply by
+specifying `UNITY_USE_FLUSH_STDOUT`. No other defines are required. If you
+specify a custom flush function instead with `UNITY_OUTPUT_FLUSH` directly, it
+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`
+
+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:
+
+_Example:_
+        #define UNITY_SUPPORT_WEAK weak
+        #define UNITY_SUPPORT_WEAK __attribute__((weak))
+
+
+##### `UNITY_PTR_ATTRIBUTE`
+
+Some compilers require a custom attribute to be assigned to pointers, like
+`near` or `far`. In these cases, you can give Unity a safe default for these by
+defining this option with the attribute you would like.
+
+_Example:_
+        #define UNITY_PTR_ATTRIBUTE __attribute__((far))
+        #define UNITY_PTR_ATTRIBUTE near
+
+
+## Getting Into The Guts
+
+There will be cases where the options above aren't quite going to get everything
+perfect. They are likely sufficient for any situation where you are compiling
+and executing your tests with a native toolchain (e.g. clang on Mac). These
+options may even get you through the majority of cases encountered in working
+with a target simulator run from your local command line. But especially if you
+must run your test suite on your target hardware, your Unity configuration will
+require special help. This special help will usually reside in one of two
+places: the `main()` function or the `RUN_TEST` macro. Let's look at how these
+work.
+
+
+##### `main()`
+
+Each test module is compiled and run on its own, separate from the other test
+files in your project. Each test file, therefore, has a `main` function. This
+`main` function will need to contain whatever code is necessary to initialize
+your system to a workable state. This is particularly true for situations where
+you must set up a memory map or initialize a communication channel for the
+output of your test results.
+
+A simple main function looks something like this:
+
+        int main(void) {
+            UNITY_BEGIN();
+            RUN_TEST(test_TheFirst);
+            RUN_TEST(test_TheSecond);
+            RUN_TEST(test_TheThird);
+            return UNITY_END();
+        }
+
+You can see that our main function doesn't bother taking any arguments. For our
+most barebones case, we'll never have arguments because we just run all the
+tests each time. Instead, we start by calling `UNITY_BEGIN`. We run each test
+(in whatever order we wish). Finally, we call `UNITY_END`, returning its return
+value (which is the total number of failures).
+
+It should be easy to see that you can add code before any test cases are run or
+after all the test cases have completed. This allows you to do any needed
+system-wide setup or teardown that might be required for your special
+circumstances.
+
+
+##### `RUN_TEST`
+
+The `RUN_TEST` macro is called with each test case function. Its job is to
+perform whatever setup and teardown is necessary for executing a single test
+case function. This includes catching failures, calling the test module's
+`setUp()` and `tearDown()` functions, and calling `UnityConcludeTest()`. If
+using CMock or test coverage, there will be additional stubs in use here. A
+simple minimalist RUN_TEST macro looks something like this:
+
+        #define RUN_TEST(testfunc) \
+            UNITY_NEW_TEST(#testfunc) \
+            if (TEST_PROTECT()) { \
+                setUp(); \
+                testfunc(); \
+            } \
+            if (TEST_PROTECT() && (!TEST_IS_IGNORED)) \
+                tearDown(); \
+            UnityConcludeTest();
+
+So that's quite a macro, huh? It gives you a glimpse of what kind of stuff Unity
+has to deal with for every single test case. For each test case, we declare that
+it is a new test. Then we run `setUp` and our test function. These are run
+within a `TEST_PROTECT` block, the function of which is to handle failures that
+occur during the test. Then, assuming our test is still running and hasn't been
+ignored, we run `tearDown`. No matter what, our last step is to conclude this
+test before moving on to the next.
+
+Let's say you need to add a call to `fsync` to force all of your output data to
+flush to a file after each test. You could easily insert this after your
+`UnityConcludeTest` call. Maybe you want to write an xml tag before and after
+each result set. Again, you could do this by adding lines to this macro. Updates
+to this macro are for the occasions when you need an action before or after
+every single test case throughout your entire suite of tests.
+
+
+## Happy Porting
+
+The defines and macros in this guide should help you port Unity to just about
+any C target we can imagine. If you run into a snag or two, don't be afraid of
+asking for help on the forums. We love a good challenge!
+
+
+*Find The Latest of This And More at [ThrowTheSwitch.org](https://throwtheswitch.org)*

二进制
tests/unity/docs/UnityConfigurationGuide.pdf


+ 191 - 0
tests/unity/docs/UnityGettingStartedGuide.md

@@ -0,0 +1,191 @@
+# Unity - Getting Started
+
+## Welcome
+
+Congratulations. You're now the proud owner of your very own pile of bits! What
+are you going to do with all these ones and zeros? This document should be able
+to help you decide just that.
+
+Unity is a unit test framework. The goal has been to keep it small and
+functional. The core Unity test framework is three files: a single C file and a
+couple header files. These team up to provide functions and macros to make
+testing easier.
+
+Unity was designed to be cross platform. It works hard to stick with C standards
+while still providing support for the many embedded C compilers that bend the
+rules. Unity has been used with many compilers, including GCC, IAR, Clang,
+Green Hills, Microchip, and MS Visual Studio. It's not much work to get it to
+work with a new target.
+
+
+### Overview of the Documents
+
+#### Unity Assertions reference
+
+This document will guide you through all the assertion options provided by
+Unity. This is going to be your unit testing bread and butter. You'll spend more
+time with assertions than any other part of Unity.
+
+
+#### Unity Assertions Cheat Sheet
+
+This document contains an abridged summary of the assertions described in the
+previous document. It's perfect for printing and referencing while you
+familiarize yourself with Unity's options.
+
+
+#### Unity Configuration Guide
+
+This document is the one to reference when you are going to use Unity with a new
+target or compiler. It'll guide you through the configuration options and will
+help you customize your testing experience to meet your needs.
+
+
+#### Unity Helper Scripts
+
+This document describes the helper scripts that are available for simplifying
+your testing workflow. It describes the collection of optional Ruby scripts
+included in the auto directory of your Unity installation. Neither Ruby nor
+these scripts are necessary for using Unity. They are provided as a convenience
+for those who wish to use them.
+
+
+#### Unity License
+
+What's an open source project without a license file? This brief document
+describes the terms you're agreeing to when you use this software. Basically, we
+want it to be useful to you in whatever context you want to use it, but please
+don't blame us if you run into problems.
+
+
+### Overview of the Folders
+
+If you have obtained Unity through Github or something similar, you might be
+surprised by just how much stuff you suddenly have staring you in the face.
+Don't worry, Unity itself is very small. The rest of it is just there to make
+your life easier. You can ignore it or use it at your convenience. Here's an
+overview of everything in the project.
+
+- `src` - This is the code you care about! This folder contains a C file and two
+header files. These three files _are_ Unity.
+- `docs` - You're reading this document, so it's possible you have found your way
+into this folder already. This is where all the handy documentation can be
+found.
+- `examples` - This contains a few examples of using Unity.
+- `extras` - These are optional add ons to Unity that are not part of the core
+project. If you've reached us through James Grenning's book, you're going to
+want to look here.
+- `test` - This is how Unity and its scripts are all tested. If you're just using
+Unity, you'll likely never need to go in here. If you are the lucky team member
+who gets to port Unity to a new toolchain, this is a good place to verify
+everything is configured properly.
+- `auto` - Here you will find helpful Ruby scripts for simplifying your test
+workflow. They are purely optional and are not required to make use of Unity.
+
+
+## How to Create A Test File
+
+Test files are C files. Most often you will create a single test file for each C
+module that you want to test. The test file should include unity.h and the
+header for your C module to be tested.
+
+Next, a test file will include a `setUp()` and `tearDown()` function. The setUp
+function can contain anything you would like to run before each test. The
+tearDown function can contain anything you would like to run after each test.
+Both functions accept no arguments and return nothing. You may leave either or
+both of these blank if you have no need for them. If you're using a compiler
+that is configured to make these functions optional, you may leave them off
+completely. Not sure? Give it a try. If you compiler complains that it can't
+find setUp or tearDown when it links, you'll know you need to at least include
+an empty function for these.
+
+The majority of the file will be a series of test functions. Test functions
+follow the convention of starting with the word "test" or "spec". You don't HAVE
+to name them this way, but it makes it clear what functions are tests for other
+developers.  Test functions take no arguments and return nothing. All test
+accounting is handled internally in Unity.
+
+Finally, at the bottom of your test file, you will write a `main()` function.
+This function will call `UNITY_BEGIN()`, then `RUN_TEST` for each test, and
+finally `UNITY_END()`.This is what will actually trigger each of those test
+functions to run, so it is important that each function gets its own `RUN_TEST`
+call.
+
+Remembering to add each test to the main function can get to be tedious. If you
+enjoy using helper scripts in your build process, you might consider making use
+of our handy generate_test_runner.rb script. This will create the main function
+and all the calls for you, assuming that you have followed the suggested naming
+conventions. In this case, there is no need for you to include the main function
+in your test file at all.
+
+When you're done, your test file will look something like this:
+
+```C
+#include "unity.h"
+#include "file_to_test.h"
+
+void setUp(void) {
+    // set stuff up here
+}
+
+void tearDown(void) {
+    // clean stuff up here
+}
+
+void test_function_should_doBlahAndBlah(void) {
+    //test stuff
+}
+
+void test_function_should_doAlsoDoBlah(void) {
+    //more test stuff
+}
+
+int main(void) {
+    UNITY_BEGIN();
+    RUN_TEST(test_function_should_doBlahAndBlah);
+    RUN_TEST(test_function_should_doAlsoDoBlah);
+    return UNITY_END();
+}
+```
+
+It's possible that you will require more customization than this, eventually.
+For that sort of thing, you're going to want to look at the configuration guide.
+This should be enough to get you going, though.
+
+
+## How to Build and Run A Test File
+
+This is the single biggest challenge to picking up a new unit testing framework,
+at least in a language like C or C++. These languages are REALLY good at getting
+you "close to the metal" (why is the phrase metal? Wouldn't it be more accurate
+to say "close to the silicon"?). While this feature is usually a good thing, it
+can make testing more challenging.
+
+You have two really good options for toolchains. Depending on where you're
+coming from, it might surprise you that neither of these options is running the
+unit tests on your hardware.
+There are many reasons for this, but here's a short version:
+- On hardware, you have too many constraints (processing power, memory, etc),
+- On hardware, you don't have complete control over all registers,
+- On hardware, unit testing is more challenging,
+- Unit testing isn't System testing. Keep them separate.
+
+Instead of running your tests on your actual hardware, most developers choose to
+develop them as native applications (using gcc or MSVC for example) or as
+applications running on a simulator. Either is a good option. Native apps have
+the advantages of being faster and easier to set up. Simulator apps have the
+advantage of working with the same compiler as your target application. The
+options for configuring these are discussed in the configuration guide.
+
+To get either to work, you might need to make a few changes to the file
+containing your register set (discussed later).
+
+In either case, a test is built by linking unity, the test file, and the C
+file(s) being tested. These files create an executable which can be run as the
+test set for that module. Then, this process is repeated for the next test file.
+This flexibility of separating tests into individual executables allows us to
+much more thoroughly unit test our system and it keeps all the test code out of
+our final release!
+
+
+*Find The Latest of This And More at [ThrowTheSwitch.org](https://throwtheswitch.org)*

二进制
tests/unity/docs/UnityGettingStartedGuide.pdf


+ 242 - 0
tests/unity/docs/UnityHelperScriptsGuide.md

@@ -0,0 +1,242 @@
+# Unity Helper Scripts
+
+## With a Little Help From Our Friends
+
+Sometimes what it takes to be a really efficient C programmer is a little non-C.
+The Unity project includes a couple Ruby scripts for making your life just a tad
+easier. They are completely optional. If you choose to use them, you'll need a
+copy of Ruby, of course. Just install whatever the latest version is, and it is
+likely to work. You can find Ruby at [ruby-lang.org](https://ruby-labg.org/).
+
+
+### `generate_test_runner.rb`
+
+Are you tired of creating your own `main` function in your test file? Do you
+keep forgetting to add a `RUN_TEST` call when you add a new test case to your
+suite? Do you want to use CMock or other fancy add-ons but don't want to figure
+out how to create your own `RUN_TEST` macro?
+
+Well then we have the perfect script for you!
+
+The `generate_test_runner` script processes a given test file and automatically
+creates a separate test runner file that includes ?main?to execute the test
+cases within the scanned test file. All you do then is add the generated runner
+to your list of files to be compiled and linked, and presto you're done!
+
+This script searches your test file for void function signatures having a
+function name beginning with "test" or "spec". It treats each of these
+functions as a test case and builds up a test suite of them. For example, the
+following includes three test cases:
+
+```C
+void testVerifyThatUnityIsAwesomeAndWillMakeYourLifeEasier(void)
+{
+  ASSERT_TRUE(1);
+}
+void test_FunctionName_should_WorkProperlyAndReturn8(void) {
+  ASSERT_EQUAL_INT(8, FunctionName());
+}
+void spec_Function_should_DoWhatItIsSupposedToDo(void) {
+  ASSERT_NOT_NULL(Function(5));
+}
+```
+
+You can run this script a couple of ways. The first is from the command line:
+
+```Shell
+ruby generate_test_runner.rb TestFile.c NameOfRunner.c
+```
+
+Alternatively, if you include only the test file parameter, the script will copy
+the name of the test file and automatically append "_Runner" to the name of the
+generated file. The example immediately below will create TestFile_Runner.c.
+
+```Shell
+ruby generate_test_runner.rb TestFile.c
+```
+
+You can also add a [YAML](http://www.yaml.org/) file to configure extra options.
+Conveniently, this YAML file is of the same format as that used by Unity and
+CMock. So if you are using YAML files already, you can simply pass the very same
+file into the generator script.
+
+```Shell
+ruby generate_test_runner.rb TestFile.c my_config.yml
+```
+
+The contents of the YAML file `my_config.yml` could look something like the
+example below. If you're wondering what some of these options do, you're going
+to love the next section of this document.
+
+```YAML
+:unity:
+  :includes:
+    - stdio.h
+    - microdefs.h
+  :cexception: 1
+  :suit_setup: "blah = malloc(1024);"
+  :suite_teardown: "free(blah);"
+```
+
+If you would like to force your generated test runner to include one or more
+header files, you can just include those at the command line too. Just make sure
+these are _after_ the YAML file, if you are using one:
+
+```Shell
+ruby generate_test_runner.rb TestFile.c my_config.yml extras.h
+```
+
+Another option, particularly if you are already using Ruby to orchestrate your
+builds - or more likely the Ruby-based build tool Rake - is requiring this
+script directly. Anything that you would have specified in a YAML file can be
+passed to the script as part of a hash. Let's push the exact same requirement
+set as we did above but this time through Ruby code directly:
+
+```Ruby
+require "generate_test_runner.rb"
+options = {
+  :includes => ["stdio.h", "microdefs.h"],
+  :cexception => 1,
+  :suite_setup => "blah = malloc(1024);",
+  :suite_teardown => "free(blah);"
+}
+UnityTestRunnerGenerator.new.run(testfile, runner_name, options)
+```
+
+If you have multiple files to generate in a build script (such as a Rakefile),
+you might want to instantiate a generator object with your options and call it
+to generate each runner thereafter. Like thus:
+
+```Ruby
+gen = UnityTestRunnerGenerator.new(options)
+test_files.each do |f|
+  gen.run(f, File.basename(f,'.c')+"Runner.c"
+end
+```
+
+#### Options accepted by generate_test_runner.rb:
+
+The following options are available when executing `generate_test_runner`. You
+may pass these as a Ruby hash directly or specify them in a YAML file, both of
+which are described above. In the `examples` directory, Example 3's Rakefile
+demonstrates using a Ruby hash.
+
+
+##### `:includes`
+
+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.
+
+
+##### `:suite_setup`
+
+Define this option with C code to be executed _before any_ test cases are run.
+
+
+##### `:suite_teardown`
+
+Define this option with C code to be executed ?after all?test cases have
+finished.
+
+
+##### `:enforce_strict_ordering`
+
+This option should be defined if you have the strict order feature enabled in
+CMock (see CMock documentation). This generates extra variables required for
+everything to run smoothly. If you provide the same YAML to the generator as
+used in CMock's configuration, you've already configured the generator properly.
+
+
+##### `:plugins`
+
+This option specifies an array of plugins to be used (of course, the array can
+contain only a single plugin). This is your opportunity to enable support for
+CException support, which will add a check for unhandled exceptions in each
+test, reporting a failure if one is detected. To enable this feature using Ruby:
+
+```Ruby
+:plugins => [ :cexception ]
+```
+
+Or as a yaml file:
+
+```YAML
+:plugins:
+  -:cexception
+```
+
+If you are using CMock, it is very likely that you are already passing an array
+of plugins to CMock. You can just use the same array here. This script will just
+ignore the plugins that don't require additional support.
+
+
+### `unity_test_summary.rb`
+
+A Unity test file contains one or more test case functions. Each test case can
+pass, fail, or be ignored. Each test file is run individually producing results
+for its collection of test cases. A given project will almost certainly be
+composed of multiple test files. Therefore, the suite of tests is comprised of
+one or more test cases spread across one or more test files. This script
+aggregates individual test file results to generate a summary of all executed
+test cases. The output includes how many tests were run, how many were ignored,
+and how many failed. In addition, the output includes a listing of which
+specific tests were ignored and failed. A good example of the breadth and
+details of these results can be found in the `examples` directory. Intentionally
+ignored and failing tests in this project generate corresponding entries in the
+summary report.
+
+If you're interested in other (prettier?) output formats, check into the
+Ceedling build tool project (ceedling.sourceforge.net) that works with Unity and
+CMock and supports xunit-style xml as well as other goodies.
+
+This script assumes the existence of files ending with the extensions
+`.testpass` and `.testfail`.The contents of these files includes the test
+results summary corresponding to each test file executed with the extension set
+according to the presence or absence of failures for that test file. The script
+searches a specified path for these files, opens each one it finds, parses the
+results, and aggregates and prints a summary. Calling it from the command line
+looks like this:
+
+```Shell
+ruby unity_test_summary.rb build/test/
+```
+
+You can optionally specify a root path as well. This is really helpful when you
+are using relative paths in your tools' setup, but you want to pull the summary
+into an IDE like Eclipse for clickable shortcuts.
+
+```Shell
+ruby unity_test_summary.rb build/test/ ~/projects/myproject/
+```
+
+Or, if you're more of a Windows sort of person:
+
+```Shell
+ruby unity_test_summary.rb build\teat\ C:\projects\myproject\
+```
+
+When configured correctly, you'll see a final summary, like so:
+
+```Shell
+--------------------------
+UNITY IGNORED TEST SUMMARY
+--------------------------
+blah.c:22:test_sandwiches_should_HaveBreadOnTwoSides:IGNORE
+
+-------------------------
+UNITY FAILED TEST SUMMARY
+-------------------------
+blah.c:87:test_sandwiches_should_HaveCondiments:FAIL:Expected 1 was 0
+meh.c:38:test_soda_should_BeCalledPop:FAIL:Expected "pop" was "coke"
+
+--------------------------
+OVERALL UNITY TEST SUMMARY
+--------------------------
+45 TOTAL TESTS 2 TOTAL FAILURES 1 IGNORED
+```
+
+How convenient is that?
+
+
+*Find The Latest of This And More at [ThrowTheSwitch.org](https://throwtheswitch.org)*

二进制
tests/unity/docs/UnityHelperScriptsGuide.pdf


+ 15 - 15
tests/unity/examples/example_3/rakefile.rb

@@ -3,41 +3,41 @@ UNITY_ROOT = File.expand_path(File.dirname(__FILE__)) + '/../..'
 
 require 'rake'
 require 'rake/clean'
-require HERE+'rakefile_helper'
+require HERE + 'rakefile_helper'
 
 TEMP_DIRS = [
-	File.join(HERE, 'build')
-]
+  File.join(HERE, 'build')
+].freeze
 
 TEMP_DIRS.each do |dir|
   directory(dir)
   CLOBBER.include(dir)
 end
 
-task :prepare_for_tests => TEMP_DIRS
+task prepare_for_tests: TEMP_DIRS
 
 include RakefileHelpers
 
 # Load default configuration, for now
-DEFAULT_CONFIG_FILE = 'target_gcc_32.yml'
+DEFAULT_CONFIG_FILE = 'target_gcc_32.yml'.freeze
 configure_toolchain(DEFAULT_CONFIG_FILE)
 
-task :unit => [:prepare_for_tests] do
-  run_tests get_unit_test_files
+task unit: [:prepare_for_tests] do
+  run_tests unit_test_files
 end
 
-desc "Generate test summary"
+desc 'Generate test summary'
 task :summary do
   report_summary
 end
 
-desc "Build and test Unity"
-task :all => [:clean, :unit, :summary]
-task :default => [:clobber, :all]
-task :ci => [:default]
-task :cruise => [:default]
+desc 'Build and test Unity'
+task all: %i(clean unit summary)
+task default: %i(clobber all)
+task ci: [:default]
+task cruise: [:default]
 
-desc "Load configuration"
-task :config, :config_file do |t, args|
+desc 'Load configuration'
+task :config, :config_file do |_t, args|
   configure_toolchain(args[:config_file])
 end

+ 93 - 102
tests/unity/examples/example_3/rakefile_helper.rb

@@ -1,12 +1,11 @@
 require 'yaml'
 require 'fileutils'
-require UNITY_ROOT+'/auto/unity_test_summary'
-require UNITY_ROOT+'/auto/generate_test_runner'
-require UNITY_ROOT+'/auto/colour_reporter'
+require UNITY_ROOT + '/auto/unity_test_summary'
+require UNITY_ROOT + '/auto/generate_test_runner'
+require UNITY_ROOT + '/auto/colour_reporter'
 
 module RakefileHelpers
-
-  C_EXTENSION = '.c'
+  C_EXTENSION = '.c'.freeze
 
   def load_configuration(config_file)
     $cfg_file = config_file
@@ -17,22 +16,22 @@ module RakefileHelpers
     CLEAN.include($cfg['compiler']['build_path'] + '*.*') unless $cfg['compiler']['build_path'].nil?
   end
 
-  def configure_toolchain(config_file=DEFAULT_CONFIG_FILE)
+  def configure_toolchain(config_file = DEFAULT_CONFIG_FILE)
     config_file += '.yml' unless config_file =~ /\.yml$/
     load_configuration(config_file)
     configure_clean
   end
 
-  def get_unit_test_files
+  def unit_test_files
     path = $cfg['compiler']['unit_tests_path'] + 'Test*' + C_EXTENSION
-    path.gsub!(/\\/, '/')
+    path.tr!('\\', '/')
     FileList.new(path)
   end
 
-  def get_local_include_dirs
+  def local_include_dirs
     include_dirs = $cfg['compiler']['includes']['items'].dup
-    include_dirs.delete_if {|dir| dir.is_a?(Array)}
-    return include_dirs
+    include_dirs.delete_if { |dir| dir.is_a?(Array) }
+    include_dirs
   end
 
   def extract_headers(filename)
@@ -40,129 +39,126 @@ module RakefileHelpers
     lines = File.readlines(filename)
     lines.each do |line|
       m = line.match(/^\s*#include\s+\"\s*(.+\.[hH])\s*\"/)
-      if not m.nil?
-        includes << m[1]
-      end
+      includes << m[1] unless m.nil?
     end
-    return includes
+    includes
   end
 
   def find_source_file(header, paths)
     paths.each do |dir|
       src_file = dir + header.ext(C_EXTENSION)
-      if (File.exists?(src_file))
-        return src_file
-      end
+      return src_file if File.exist?(src_file)
     end
-    return nil
+    nil
   end
 
   def tackit(strings)
-    if strings.is_a?(Array)
-      result = "\"#{strings.join}\""
-    else
-      result = strings
-    end
-    return result
+    result = if strings.is_a?(Array)
+               "\"#{strings.join}\""
+             else
+               strings
+             end
+    result
   end
 
   def squash(prefix, items)
     result = ''
     items.each { |item| result += " #{prefix}#{tackit(item)}" }
-    return result
+    result
   end
 
   def build_compiler_fields
-    command  = tackit($cfg['compiler']['path'])
-    if $cfg['compiler']['defines']['items'].nil?
-      defines  = ''
-    else
-      defines  = squash($cfg['compiler']['defines']['prefix'], $cfg['compiler']['defines']['items'])
-    end
+    command = tackit($cfg['compiler']['path'])
+    defines = if $cfg['compiler']['defines']['items'].nil?
+                ''
+              else
+                squash($cfg['compiler']['defines']['prefix'], $cfg['compiler']['defines']['items'])
+              end
     options  = squash('', $cfg['compiler']['options'])
     includes = squash($cfg['compiler']['includes']['prefix'], $cfg['compiler']['includes']['items'])
     includes = includes.gsub(/\\ /, ' ').gsub(/\\\"/, '"').gsub(/\\$/, '') # Remove trailing slashes (for IAR)
-    return {:command => command, :defines => defines, :options => options, :includes => includes}
+
+    { command: command, defines: defines, options: options, includes: includes }
   end
 
-  def compile(file, defines=[])
+  def compile(file, _defines = [])
     compiler = build_compiler_fields
-    cmd_str  = "#{compiler[:command]}#{compiler[:defines]}#{compiler[:options]}#{compiler[:includes]} #{file} " +
+    cmd_str  = "#{compiler[:command]}#{compiler[:defines]}#{compiler[:options]}#{compiler[:includes]} #{file} " \
                "#{$cfg['compiler']['object_files']['prefix']}#{$cfg['compiler']['object_files']['destination']}"
     obj_file = "#{File.basename(file, C_EXTENSION)}#{$cfg['compiler']['object_files']['extension']}"
     execute(cmd_str + obj_file)
-    return obj_file
+    obj_file
   end
 
   def build_linker_fields
-    command  = tackit($cfg['linker']['path'])
-    if $cfg['linker']['options'].nil?
-      options  = ''
-    else
-      options  = squash('', $cfg['linker']['options'])
-    end
-    if ($cfg['linker']['includes'].nil? || $cfg['linker']['includes']['items'].nil?)
-      includes = ''
-    else
-      includes = squash($cfg['linker']['includes']['prefix'], $cfg['linker']['includes']['items'])
-    end
-    includes = includes.gsub(/\\ /, ' ').gsub(/\\\"/, '"').gsub(/\\$/, '') # Remove trailing slashes (for IAR)
-    return {:command => command, :options => options, :includes => includes}
+    command = tackit($cfg['linker']['path'])
+    options = if $cfg['linker']['options'].nil?
+                ''
+              else
+                squash('', $cfg['linker']['options'])
+              end
+    includes = if $cfg['linker']['includes'].nil? || $cfg['linker']['includes']['items'].nil?
+                 ''
+               else
+                 squash($cfg['linker']['includes']['prefix'], $cfg['linker']['includes']['items'])
+               end.gsub(/\\ /, ' ').gsub(/\\\"/, '"').gsub(/\\$/, '') # Remove trailing slashes (for IAR)
+
+    { command: command, options: options, includes: includes }
   end
 
   def link_it(exe_name, obj_list)
     linker = build_linker_fields
     cmd_str = "#{linker[:command]}#{linker[:options]}#{linker[:includes]} " +
-      (obj_list.map{|obj|"#{$cfg['linker']['object_files']['path']}#{obj} "}).join +
-      $cfg['linker']['bin_files']['prefix'] + ' ' +
-      $cfg['linker']['bin_files']['destination'] +
-      exe_name + $cfg['linker']['bin_files']['extension']
+              (obj_list.map { |obj| "#{$cfg['linker']['object_files']['path']}#{obj} " }).join +
+              $cfg['linker']['bin_files']['prefix'] + ' ' +
+              $cfg['linker']['bin_files']['destination'] +
+              exe_name + $cfg['linker']['bin_files']['extension']
     execute(cmd_str)
   end
 
   def build_simulator_fields
     return nil if $cfg['simulator'].nil?
-    if $cfg['simulator']['path'].nil?
-      command = ''
-    else
-      command = (tackit($cfg['simulator']['path']) + ' ')
-    end
-    if $cfg['simulator']['pre_support'].nil?
-      pre_support = ''
-    else
-      pre_support = squash('', $cfg['simulator']['pre_support'])
-    end
-    if $cfg['simulator']['post_support'].nil?
-      post_support = ''
-    else
-      post_support = squash('', $cfg['simulator']['post_support'])
-    end
-    return {:command => command, :pre_support => pre_support, :post_support => post_support}
-  end
-
-  def execute(command_string, verbose=true, raise_on_fail=true)
+    command = if $cfg['simulator']['path'].nil?
+                ''
+              else
+                (tackit($cfg['simulator']['path']) + ' ')
+              end
+    pre_support = if $cfg['simulator']['pre_support'].nil?
+                    ''
+                  else
+                    squash('', $cfg['simulator']['pre_support'])
+                  end
+    post_support = if $cfg['simulator']['post_support'].nil?
+                     ''
+                   else
+                     squash('', $cfg['simulator']['post_support'])
+                   end
+
+    { command: command, pre_support: pre_support, post_support: post_support }
+  end
+
+  def execute(command_string, verbose = true, raise_on_fail = true)
     report command_string
     output = `#{command_string}`.chomp
-    report(output) if (verbose && !output.nil? && (output.length > 0))
-    if (($?.exitstatus != 0) and (raise_on_fail))
+    report(output) if verbose && !output.nil? && !output.empty?
+    if !$?.exitstatus.zero? && raise_on_fail
       raise "Command failed. (Returned #{$?.exitstatus})"
     end
-    return output
+    output
   end
 
   def report_summary
     summary = UnityTestSummary.new
-    summary.set_root_path(HERE)
+    summary.root = HERE
     results_glob = "#{$cfg['compiler']['build_path']}*.test*"
-    results_glob.gsub!(/\\/, '/')
+    results_glob.tr!('\\', '/')
     results = Dir[results_glob]
-    summary.set_targets(results)
+    summary.targets = results
     summary.run
-    fail_out "FAIL: There were failures" if (summary.failures > 0)
+    fail_out 'FAIL: There were failures' if summary.failures > 0
   end
 
   def run_tests(test_files)
-
     report 'Running system tests...'
 
     # Tack on TEST define for compiling unit tests
@@ -171,7 +167,7 @@ module RakefileHelpers
     $cfg['compiler']['defines']['items'] = [] if $cfg['compiler']['defines']['items'].nil?
     $cfg['compiler']['defines']['items'] << 'TEST'
 
-    include_dirs = get_local_include_dirs
+    include_dirs = local_include_dirs
 
     # Build and execute each unit test
     test_files.each do |test|
@@ -181,9 +177,7 @@ module RakefileHelpers
       extract_headers(test).each do |header|
         # Compile corresponding source file if it exists
         src_file = find_source_file(header, include_dirs)
-        if !src_file.nil?
-          obj_list << compile(src_file, test_defines)
-        end
+        obj_list << compile(src_file, test_defines) unless src_file.nil?
       end
 
       # Build the test runner (generate if configured to do so)
@@ -208,25 +202,24 @@ module RakefileHelpers
       # Execute unit test and generate results file
       simulator = build_simulator_fields
       executable = $cfg['linker']['bin_files']['destination'] + test_base + $cfg['linker']['bin_files']['extension']
-      if simulator.nil?
-        cmd_str = executable
-      else
-        cmd_str = "#{simulator[:command]} #{simulator[:pre_support]} #{executable} #{simulator[:post_support]}"
-      end
+      cmd_str = if simulator.nil?
+                  executable
+                else
+                  "#{simulator[:command]} #{simulator[:pre_support]} #{executable} #{simulator[:post_support]}"
+                end
       output = execute(cmd_str, true, false)
       test_results = $cfg['compiler']['build_path'] + test_base
-      if output.match(/OK$/m).nil?
-        test_results += '.testfail'
-      else
-        test_results += '.testpass'
-      end
+      test_results += if output.match(/OK$/m).nil?
+                        '.testfail'
+                      else
+                        '.testpass'
+                      end
       File.open(test_results, 'w') { |f| f.print output }
     end
   end
 
   def build_application(main)
-
-    report "Building application..."
+    report 'Building application...'
 
     obj_list = []
     load_configuration($cfg_file)
@@ -236,9 +229,7 @@ module RakefileHelpers
     include_dirs = get_local_include_dirs
     extract_headers(main_path).each do |header|
       src_file = find_source_file(header, include_dirs)
-      if !src_file.nil?
-        obj_list << compile(src_file)
-      end
+      obj_list << compile(src_file) unless src_file.nil?
     end
 
     # Build the main source file
@@ -251,8 +242,8 @@ module RakefileHelpers
 
   def fail_out(msg)
     puts msg
-    puts "Not returning exit code so continuous integration can pass"
-#    exit(-1) # Only removed to pass example_3, which has failing tests on purpose.
-#               Still fail if the build fails for any other reason.
+    puts 'Not returning exit code so continuous integration can pass'
+    #    exit(-1) # Only removed to pass example_3, which has failing tests on purpose.
+    #               Still fail if the build fails for any other reason.
   end
 end

+ 12 - 12
tests/unity/extras/fixture/rakefile.rb

@@ -12,34 +12,34 @@ require 'rake/testtask'
 require HERE + 'rakefile_helper'
 
 TEMP_DIRS = [
-    File.join(HERE, 'build')
-]
+  File.join(HERE, 'build')
+].freeze
 
 TEMP_DIRS.each do |dir|
   directory(dir)
   CLOBBER.include(dir)
 end
 
-task :prepare_for_tests => TEMP_DIRS
+task prepare_for_tests: TEMP_DIRS
 
 include RakefileHelpers
 
 # Load default configuration, for now
-DEFAULT_CONFIG_FILE = 'gcc_auto_stdint.yml'
+DEFAULT_CONFIG_FILE = 'gcc_auto_stdint.yml'.freeze
 configure_toolchain(DEFAULT_CONFIG_FILE)
 
-task :unit => [:prepare_for_tests] do
+task unit: [:prepare_for_tests] do
   run_tests
 end
 
-desc "Build and test Unity Framework"
-task :all => [:clean, :unit]
-task :default => [:clobber, :all]
-task :ci => [:no_color, :default]
-task :cruise => [:no_color, :default]
+desc 'Build and test Unity Framework'
+task all: %i(clean unit)
+task default: %i(clobber all)
+task ci: %i(no_color default)
+task cruise: %i(no_color default)
 
-desc "Load configuration"
-task :config, :config_file do |t, args|
+desc 'Load configuration'
+task :config, :config_file do |_t, args|
   configure_toolchain(args[:config_file])
 end
 

+ 87 - 88
tests/unity/extras/fixture/rakefile_helper.rb

@@ -6,28 +6,27 @@
 
 require 'yaml'
 require 'fileutils'
-require HERE+'../../auto/unity_test_summary'
-require HERE+'../../auto/generate_test_runner'
-require HERE+'../../auto/colour_reporter'
+require HERE + '../../auto/unity_test_summary'
+require HERE + '../../auto/generate_test_runner'
+require HERE + '../../auto/colour_reporter'
 
 module RakefileHelpers
-
-  C_EXTENSION = '.c'
+  C_EXTENSION = '.c'.freeze
 
   def load_configuration(config_file)
-    unless ($configured)
-      $cfg_file = HERE+"../../test/targets/#{config_file}" unless (config_file =~ /[\\|\/]/)
-      $cfg = YAML.load(File.read($cfg_file))
-      $colour_output = false unless $cfg['colour']
-      $configured = true if (config_file != DEFAULT_CONFIG_FILE)
-    end
+    return if $configured
+
+    $cfg_file = HERE + "../../test/targets/#{config_file}" unless config_file =~ /[\\|\/]/
+    $cfg = YAML.load(File.read($cfg_file))
+    $colour_output = false unless $cfg['colour']
+    $configured = true if config_file != DEFAULT_CONFIG_FILE
   end
 
   def configure_clean
     CLEAN.include($cfg['compiler']['build_path'] + '*.*') unless $cfg['compiler']['build_path'].nil?
   end
 
-  def configure_toolchain(config_file=DEFAULT_CONFIG_FILE)
+  def configure_toolchain(config_file = DEFAULT_CONFIG_FILE)
     config_file += '.yml' unless config_file =~ /\.yml$/
     config_file = config_file unless config_file =~ /[\\|\/]/
     load_configuration(config_file)
@@ -35,105 +34,105 @@ module RakefileHelpers
   end
 
   def tackit(strings)
-    if strings.is_a?(Array)
-      result = "\"#{strings.join}\""
-    else
-      result = strings
-    end
-    return result
+    result = if strings.is_a?(Array)
+               "\"#{strings.join}\""
+             else
+               strings
+             end
+    result
   end
 
   def squash(prefix, items)
     result = ''
     items.each { |item| result += " #{prefix}#{tackit(item)}" }
-    return result
+    result
   end
 
   def build_compiler_fields
-    command  = tackit($cfg['compiler']['path'])
-    if $cfg['compiler']['defines']['items'].nil?
-      defines  = ''
-    else
-      defines  = squash($cfg['compiler']['defines']['prefix'], $cfg['compiler']['defines']['items'] + ['UNITY_OUTPUT_CHAR=UnityOutputCharSpy_OutputChar'])
-    end
+    command = tackit($cfg['compiler']['path'])
+    defines = if $cfg['compiler']['defines']['items'].nil?
+                ''
+              else
+                squash($cfg['compiler']['defines']['prefix'], $cfg['compiler']['defines']['items'] + ['UNITY_OUTPUT_CHAR=UnityOutputCharSpy_OutputChar'])
+              end
     options  = squash('', $cfg['compiler']['options'])
     includes = squash($cfg['compiler']['includes']['prefix'], $cfg['compiler']['includes']['items'])
     includes = includes.gsub(/\\ /, ' ').gsub(/\\\"/, '"').gsub(/\\$/, '') # Remove trailing slashes (for IAR)
-    return {:command => command, :defines => defines, :options => options, :includes => includes}
+
+    { command: command, defines: defines, options: options, includes: includes }
   end
 
-  def compile(file, defines=[])
+  def compile(file, _defines = [])
     compiler = build_compiler_fields
-    unity_include = $cfg['compiler']['includes']['prefix']+'../../src'
-    cmd_str = "#{compiler[:command]}#{compiler[:defines]}#{compiler[:options]}#{compiler[:includes]} #{unity_include} #{file} " +
-      "#{$cfg['compiler']['object_files']['prefix']}#{$cfg['compiler']['object_files']['destination']}" +
-      "#{File.basename(file, C_EXTENSION)}#{$cfg['compiler']['object_files']['extension']}"
+    unity_include = $cfg['compiler']['includes']['prefix'] + '../../src'
+    cmd_str = "#{compiler[:command]}#{compiler[:defines]}#{compiler[:options]}#{compiler[:includes]} #{unity_include} #{file} " \
+              "#{$cfg['compiler']['object_files']['prefix']}#{$cfg['compiler']['object_files']['destination']}" \
+              "#{File.basename(file, C_EXTENSION)}#{$cfg['compiler']['object_files']['extension']}"
+
     execute(cmd_str)
   end
 
   def build_linker_fields
-    command  = tackit($cfg['linker']['path'])
-    if $cfg['linker']['options'].nil?
-      options  = ''
-    else
-      options  = squash('', $cfg['linker']['options'])
-    end
-    if ($cfg['linker']['includes'].nil? || $cfg['linker']['includes']['items'].nil?)
-      includes = ''
-    else
-      includes = squash($cfg['linker']['includes']['prefix'], $cfg['linker']['includes']['items'])
-    end
-    includes = includes.gsub(/\\ /, ' ').gsub(/\\\"/, '"').gsub(/\\$/, '') # Remove trailing slashes (for IAR)
-    return {:command => command, :options => options, :includes => includes}
+    command = tackit($cfg['linker']['path'])
+    options = if $cfg['linker']['options'].nil?
+                ''
+              else
+                squash('', $cfg['linker']['options'])
+              end
+    includes = if $cfg['linker']['includes'].nil? || $cfg['linker']['includes']['items'].nil?
+                 ''
+               else
+                 squash($cfg['linker']['includes']['prefix'], $cfg['linker']['includes']['items'])
+               end.gsub(/\\ /, ' ').gsub(/\\\"/, '"').gsub(/\\$/, '') # Remove trailing slashes (for IAR)
+
+    { command: command, options: options, includes: includes }
   end
 
   def link_it(exe_name, obj_list)
     linker = build_linker_fields
     cmd_str = "#{linker[:command]}#{linker[:options]}#{linker[:includes]} " +
-      (obj_list.map{|obj|"#{$cfg['linker']['object_files']['path']}#{obj} "}).join +
-      $cfg['linker']['bin_files']['prefix'] + ' ' +
-      $cfg['linker']['bin_files']['destination'] +
-      exe_name + $cfg['linker']['bin_files']['extension']
+              (obj_list.map { |obj| "#{$cfg['linker']['object_files']['path']}#{obj} " }).join +
+              $cfg['linker']['bin_files']['prefix'] + ' ' +
+              $cfg['linker']['bin_files']['destination'] +
+              exe_name + $cfg['linker']['bin_files']['extension']
     execute(cmd_str)
   end
 
   def build_simulator_fields
     return nil if $cfg['simulator'].nil?
-    if $cfg['simulator']['path'].nil?
-      command = ''
-    else
-      command = (tackit($cfg['simulator']['path']) + ' ')
-    end
-    if $cfg['simulator']['pre_support'].nil?
-      pre_support = ''
-    else
-      pre_support = squash('', $cfg['simulator']['pre_support'])
-    end
-    if $cfg['simulator']['post_support'].nil?
-      post_support = ''
-    else
-      post_support = squash('', $cfg['simulator']['post_support'])
-    end
-    return {:command => command, :pre_support => pre_support, :post_support => post_support}
+    command = if $cfg['simulator']['path'].nil?
+                ''
+              else
+                (tackit($cfg['simulator']['path']) + ' ')
+              end
+    pre_support = if $cfg['simulator']['pre_support'].nil?
+                    ''
+                  else
+                    squash('', $cfg['simulator']['pre_support'])
+                  end
+    post_support = if $cfg['simulator']['post_support'].nil?
+                     ''
+                   else
+                     squash('', $cfg['simulator']['post_support'])
+                   end
+    { command: command, pre_support: pre_support, post_support: post_support }
   end
 
-  def execute(command_string, verbose=true)
+  def execute(command_string, verbose = true)
     report command_string
     output = `#{command_string}`.chomp
-    report(output) if (verbose && !output.nil? && (output.length > 0))
-    if ($?.exitstatus != 0)
-      raise "Command failed. (Returned #{$?.exitstatus})"
-    end
-    return output
+    report(output) if verbose && !output.nil? && !output.empty?
+    raise "Command failed. (Returned #{$?.exitstatus})" if $?.exitstatus != 0
+    output
   end
 
   def report_summary
     summary = UnityTestSummary.new
-    summary.set_root_path(HERE)
+    summary.root = HERE
     results_glob = "#{$cfg['compiler']['build_path']}*.test*"
-    results_glob.gsub!(/\\/, '/')
+    results_glob.tr!('\\', '/')
     results = Dir[results_glob]
-    summary.set_targets(results)
+    summary.targets = results
     summary.run
   end
 
@@ -146,34 +145,34 @@ module RakefileHelpers
     $cfg['compiler']['defines']['items'] = [] if $cfg['compiler']['defines']['items'].nil?
 
     # Get a list of all source files needed
-    src_files  = Dir[HERE+'src/*.c']
-    src_files += Dir[HERE+'test/*.c']
-    src_files += Dir[HERE+'test/main/*.c']
+    src_files  = Dir[HERE + 'src/*.c']
+    src_files += Dir[HERE + 'test/*.c']
+    src_files += Dir[HERE + 'test/main/*.c']
     src_files << '../../src/unity.c'
 
     # Build object files
     src_files.each { |f| compile(f, test_defines) }
-    obj_list = src_files.map {|f| File.basename(f.ext($cfg['compiler']['object_files']['extension'])) }
+    obj_list = src_files.map { |f| File.basename(f.ext($cfg['compiler']['object_files']['extension'])) }
 
     # Link the test executable
-    test_base = "framework_test"
+    test_base = 'framework_test'
     link_it(test_base, obj_list)
 
     # Execute unit test and generate results file
     simulator = build_simulator_fields
     executable = $cfg['linker']['bin_files']['destination'] + test_base + $cfg['linker']['bin_files']['extension']
-    if simulator.nil?
-      cmd_str = executable + " -v -r"
-    else
-      cmd_str = "#{simulator[:command]} #{simulator[:pre_support]} #{executable} #{simulator[:post_support]}"
-    end
+    cmd_str = if simulator.nil?
+                executable + ' -v -r'
+              else
+                "#{simulator[:command]} #{simulator[:pre_support]} #{executable} #{simulator[:post_support]}"
+              end
     output = execute(cmd_str)
     test_results = $cfg['compiler']['build_path'] + test_base
-    if output.match(/OK$/m).nil?
-      test_results += '.testfail'
-    else
-      test_results += '.testpass'
-    end
+    test_results += if output.match(/OK$/m).nil?
+                      '.testfail'
+                    else
+                      '.testpass'
+                    end
     File.open(test_results, 'w') { |f| f.print output }
   end
 end

+ 1 - 0
tests/unity/extras/fixture/src/unity_fixture_malloc_overrides.h

@@ -26,6 +26,7 @@
  * For example, when using FreeRTOS UNITY_FIXTURE_MALLOC becomes pvPortMalloc()
  * and UNITY_FIXTURE_FREE becomes vPortFree(). */
 #if !defined(UNITY_FIXTURE_MALLOC) || !defined(UNITY_FIXTURE_FREE)
+    #include <stdlib.h>
     #define UNITY_FIXTURE_MALLOC(size) malloc(size)
     #define UNITY_FIXTURE_FREE(ptr)    free(ptr)
 #else

+ 1 - 1
tests/unity/release/version.info

@@ -1,2 +1,2 @@
-2.4.0
+2.4.1
 

+ 125 - 29
tests/unity/src/unity.c

@@ -539,7 +539,8 @@ void UnityAssertEqualIntArray(UNITY_INTERNAL_PTR expected,
                               const UNITY_UINT32 num_elements,
                               const char* msg,
                               const UNITY_LINE_TYPE lineNumber,
-                              const UNITY_DISPLAY_STYLE_T style)
+                              const UNITY_DISPLAY_STYLE_T style,
+                              const UNITY_FLAGS_T flags)
 {
     UNITY_UINT32 elements = num_elements;
     unsigned int length   = style & 0xF;
@@ -569,17 +570,17 @@ void UnityAssertEqualIntArray(UNITY_INTERNAL_PTR expected,
                 expect_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT16*)expected;
                 actual_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT16*)actual;
                 break;
-            default: /* length 4 bytes */
-                expect_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT32*)expected;
-                actual_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT32*)actual;
-                length = 4;
-                break;
 #ifdef UNITY_SUPPORT_64
             case 8:
                 expect_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT64*)expected;
                 actual_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT64*)actual;
                 break;
 #endif
+            default: /* length 4 bytes */
+                expect_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT32*)expected;
+                actual_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT32*)actual;
+                length = 4;
+                break;
         }
 
         if (expect_val != actual_val)
@@ -601,7 +602,10 @@ void UnityAssertEqualIntArray(UNITY_INTERNAL_PTR expected,
             UnityAddMsgIfSpecified(msg);
             UNITY_FAIL_AND_BAIL;
         }
-        expected = (UNITY_INTERNAL_PTR)(length + (const char*)expected);
+        if (flags == UNITY_ARRAY_TO_ARRAY)
+        {
+            expected = (UNITY_INTERNAL_PTR)(length + (const char*)expected);
+        }
         actual   = (UNITY_INTERNAL_PTR)(length + (const char*)actual);
     }
 }
@@ -645,7 +649,8 @@ void UnityAssertEqualFloatArray(UNITY_PTR_ATTRIBUTE const UNITY_FLOAT* expected,
                                 UNITY_PTR_ATTRIBUTE const UNITY_FLOAT* actual,
                                 const UNITY_UINT32 num_elements,
                                 const char* msg,
-                                const UNITY_LINE_TYPE lineNumber)
+                                const UNITY_LINE_TYPE lineNumber,
+                                const UNITY_FLAGS_T flags)
 {
     UNITY_UINT32 elements = num_elements;
     UNITY_PTR_ATTRIBUTE const UNITY_FLOAT* ptr_expected = expected;
@@ -673,7 +678,10 @@ void UnityAssertEqualFloatArray(UNITY_PTR_ATTRIBUTE const UNITY_FLOAT* expected,
             UnityAddMsgIfSpecified(msg);
             UNITY_FAIL_AND_BAIL;
         }
-        ptr_expected++;
+        if (flags == UNITY_ARRAY_TO_ARRAY)
+        {
+            ptr_expected++;
+        }
         ptr_actual++;
     }
 }
@@ -771,7 +779,8 @@ void UnityAssertEqualDoubleArray(UNITY_PTR_ATTRIBUTE const UNITY_DOUBLE* expecte
                                  UNITY_PTR_ATTRIBUTE const UNITY_DOUBLE* actual,
                                  const UNITY_UINT32 num_elements,
                                  const char* msg,
-                                 const UNITY_LINE_TYPE lineNumber)
+                                 const UNITY_LINE_TYPE lineNumber,
+                                 const UNITY_FLAGS_T flags)
 {
     UNITY_UINT32 elements = num_elements;
     UNITY_PTR_ATTRIBUTE const UNITY_DOUBLE* ptr_expected = expected;
@@ -799,7 +808,10 @@ void UnityAssertEqualDoubleArray(UNITY_PTR_ATTRIBUTE const UNITY_DOUBLE* expecte
             UnityAddMsgIfSpecified(msg);
             UNITY_FAIL_AND_BAIL;
         }
-        ptr_expected++;
+        if (flags == UNITY_ARRAY_TO_ARRAY)
+        {
+            ptr_expected++;
+        }
         ptr_actual++;
     }
 }
@@ -898,16 +910,16 @@ void UnityAssertNumbersWithin(const UNITY_UINT delta,
     if ((style & UNITY_DISPLAY_RANGE_INT) == UNITY_DISPLAY_RANGE_INT)
     {
         if (actual > expected)
-            Unity.CurrentTestFailed = ((UNITY_UINT)(actual - expected) > delta);
+          Unity.CurrentTestFailed = (UNITY_UINT)((UNITY_UINT)(actual - expected) > delta);
         else
-            Unity.CurrentTestFailed = ((UNITY_UINT)(expected - actual) > delta);
+            Unity.CurrentTestFailed = (UNITY_UINT)((UNITY_UINT)(expected - actual) > delta);
     }
     else
     {
         if ((UNITY_UINT)actual > (UNITY_UINT)expected)
-            Unity.CurrentTestFailed = ((UNITY_UINT)(actual - expected) > delta);
+            Unity.CurrentTestFailed = (UNITY_UINT)((UNITY_UINT)(actual - expected) > delta);
         else
-            Unity.CurrentTestFailed = ((UNITY_UINT)(expected - actual) > delta);
+            Unity.CurrentTestFailed = (UNITY_UINT)((UNITY_UINT)(expected - actual) > delta);
     }
 
     if (Unity.CurrentTestFailed)
@@ -1004,13 +1016,17 @@ void UnityAssertEqualStringLen(const char* expected,
 }
 
 /*-----------------------------------------------*/
-void UnityAssertEqualStringArray(const char** expected,
+void UnityAssertEqualStringArray(UNITY_INTERNAL_PTR expected,
                                  const char** actual,
                                  const UNITY_UINT32 num_elements,
                                  const char* msg,
-                                 const UNITY_LINE_TYPE lineNumber)
+                                 const UNITY_LINE_TYPE lineNumber,
+                                 const UNITY_FLAGS_T flags)
 {
-    UNITY_UINT32 i, j = 0;
+    UNITY_UINT32 i = 0;
+    UNITY_UINT32 j = 0;
+    const char* exp = NULL;
+    const char* act = NULL;
 
     RETURN_IF_FAIL_OR_IGNORE;
 
@@ -1020,18 +1036,35 @@ void UnityAssertEqualStringArray(const char** expected,
         UnityPrintPointlessAndBail();
     }
 
-    if (expected == actual) return; /* Both are NULL or same pointer */
+    if ((const void*)expected == (const void*)actual)
+    {
+        return; /* Both are NULL or same pointer */
+    }
+
     if (UnityIsOneArrayNull((UNITY_INTERNAL_PTR)expected, (UNITY_INTERNAL_PTR)actual, lineNumber, msg))
+    {
         UNITY_FAIL_AND_BAIL;
+    }
+
+    if (flags != UNITY_ARRAY_TO_ARRAY)
+    {
+        exp = (const char*)expected;
+    }
 
     do
     {
+        act = actual[j];
+        if (flags == UNITY_ARRAY_TO_ARRAY)
+        {
+            exp = ((const char* const*)expected)[j];
+        }
+
         /* if both pointers not null compare the strings */
-        if (expected[j] && actual[j])
+        if (exp && act)
         {
-            for (i = 0; expected[j][i] || actual[j][i]; i++)
+            for (i = 0; exp[i] || act[i]; i++)
             {
-                if (expected[j][i] != actual[j][i])
+                if (exp[i] != act[i])
                 {
                     Unity.CurrentTestFailed = 1;
                     break;
@@ -1040,7 +1073,7 @@ void UnityAssertEqualStringArray(const char** expected,
         }
         else
         { /* handle case of one pointers being null (if both null, test should pass) */
-            if (expected[j] != actual[j])
+            if (exp != act)
             {
                 Unity.CurrentTestFailed = 1;
             }
@@ -1054,7 +1087,7 @@ void UnityAssertEqualStringArray(const char** expected,
                 UnityPrint(UnityStrElement);
                 UnityPrintNumberUnsigned(j);
             }
-            UnityPrintExpectedAndActualStrings((const char*)(expected[j]), (const char*)(actual[j]));
+            UnityPrintExpectedAndActualStrings(exp, act);
             UnityAddMsgIfSpecified(msg);
             UNITY_FAIL_AND_BAIL;
         }
@@ -1067,7 +1100,8 @@ void UnityAssertEqualMemory(UNITY_INTERNAL_PTR expected,
                             const UNITY_UINT32 length,
                             const UNITY_UINT32 num_elements,
                             const char* msg,
-                            const UNITY_LINE_TYPE lineNumber)
+                            const UNITY_LINE_TYPE lineNumber,
+                            const UNITY_FLAGS_T flags)
 {
     UNITY_PTR_ATTRIBUTE const unsigned char* ptr_exp = (UNITY_PTR_ATTRIBUTE const unsigned char*)expected;
     UNITY_PTR_ATTRIBUTE const unsigned char* ptr_act = (UNITY_PTR_ATTRIBUTE const unsigned char*)actual;
@@ -1111,9 +1145,70 @@ void UnityAssertEqualMemory(UNITY_INTERNAL_PTR expected,
             ptr_exp++;
             ptr_act++;
         }
+        if (flags == UNITY_ARRAY_TO_VAL)
+        {
+            ptr_exp = (UNITY_PTR_ATTRIBUTE const unsigned char*)expected;
+        }
     }
 }
 
+/*-----------------------------------------------*/
+
+static union
+{
+    UNITY_INT8 i8;
+    UNITY_INT16 i16;
+    UNITY_INT32 i32;
+#ifdef UNITY_SUPPORT_64
+    UNITY_INT64 i64;
+#endif
+#ifndef UNITY_EXCLUDE_FLOAT
+    float f;
+#endif
+#ifndef UNITY_EXCLUDE_DOUBLE
+    double d;
+#endif
+} UnityQuickCompare;
+
+UNITY_INTERNAL_PTR UnityNumToPtr(const UNITY_INT num, const UNITY_UINT8 size)
+{
+    switch(size)
+    {
+        case 1:
+          UnityQuickCompare.i8 = (UNITY_INT8)num;
+          return (UNITY_INTERNAL_PTR)(&UnityQuickCompare.i8);
+
+        case 2:
+          UnityQuickCompare.i16 = (UNITY_INT16)num;
+          return (UNITY_INTERNAL_PTR)(&UnityQuickCompare.i16);
+
+#ifdef UNITY_SUPPORT_64
+        case 8:
+          UnityQuickCompare.i64 = (UNITY_INT64)num;
+          return (UNITY_INTERNAL_PTR)(&UnityQuickCompare.i64);
+#endif
+        default: /* 4 bytes */
+          UnityQuickCompare.i32 = (UNITY_INT32)num;
+          return (UNITY_INTERNAL_PTR)(&UnityQuickCompare.i32);
+    }
+}
+
+#ifndef UNITY_EXCLUDE_FLOAT
+UNITY_INTERNAL_PTR UnityFloatToPtr(const float num)
+{
+    UnityQuickCompare.f = num;
+    return (UNITY_INTERNAL_PTR)(&UnityQuickCompare.f);
+}
+#endif
+
+#ifndef UNITY_EXCLUDE_DOUBLE
+UNITY_INTERNAL_PTR UnityDoubleToPtr(const double num)
+{
+    UnityQuickCompare.d = num;
+    return (UNITY_INTERNAL_PTR)(&UnityQuickCompare.d);
+}
+#endif
+
 /*-----------------------------------------------
  * Control Functions
  *-----------------------------------------------*/
@@ -1177,6 +1272,7 @@ void UnityIgnore(const char* msg, const UNITY_LINE_TYPE line)
   #pragma weak tearDown
   void tearDown(void) { }
 #endif
+
 /*-----------------------------------------------*/
 void UnityDefaultTestRun(UnityTestFunction Func, const char* FuncName, const int FuncLineNum)
 {
@@ -1309,9 +1405,9 @@ int UnityParseOptions(int argc, char** argv)
 
 int IsStringInBiggerString(const char* longstring, const char* shortstring)
 {
-    char* lptr = (char*)longstring;
-    char* sptr = (char*)shortstring;
-    char* lnext = lptr;
+    const char* lptr = longstring;
+    const char* sptr = shortstring;
+    const char* lnext = lptr;
 
     if (*sptr == '*')
         return 1;
@@ -1343,7 +1439,7 @@ int IsStringInBiggerString(const char* longstring, const char* shortstring)
 
         /* Otherwise we start in the long pointer 1 character further and try again */
         lptr = lnext;
-        sptr = (char*)shortstring;
+        sptr = shortstring;
     }
     return 0;
 }

+ 48 - 0
tests/unity/src/unity.h

@@ -74,6 +74,10 @@ void tearDown(void);
  * This method allows you to abort a test immediately with a PASS state, ignoring the remainder of the test. */
 #define TEST_PASS()                                                                                TEST_ABORT()
 
+/* This macro does nothing, but it is useful for build tools (like Ceedling) to make use of this to figure out
+ * which files should be linked to in order to perform a test. Use it like TEST_FILE("sandwiches.c") */
+#define TEST_FILE(a)
+
 /*-------------------------------------------------------
  * Test Asserts (simple)
  *-------------------------------------------------------*/
@@ -153,10 +157,31 @@ 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)
+#define TEST_ASSERT_EACH_EQUAL_INT16(expected, actual, num_elements)                               UNITY_TEST_ASSERT_EACH_EQUAL_INT16((expected), (actual), (num_elements), __LINE__, NULL)
+#define TEST_ASSERT_EACH_EQUAL_INT32(expected, actual, num_elements)                               UNITY_TEST_ASSERT_EACH_EQUAL_INT32((expected), (actual), (num_elements), __LINE__, NULL)
+#define TEST_ASSERT_EACH_EQUAL_INT64(expected, actual, num_elements)                               UNITY_TEST_ASSERT_EACH_EQUAL_INT64((expected), (actual), (num_elements), __LINE__, NULL)
+#define TEST_ASSERT_EACH_EQUAL_UINT(expected, actual, num_elements)                                UNITY_TEST_ASSERT_EACH_EQUAL_UINT((expected), (actual), (num_elements), __LINE__, NULL)
+#define TEST_ASSERT_EACH_EQUAL_UINT8(expected, actual, num_elements)                               UNITY_TEST_ASSERT_EACH_EQUAL_UINT8((expected), (actual), (num_elements), __LINE__, NULL)
+#define TEST_ASSERT_EACH_EQUAL_UINT16(expected, actual, num_elements)                              UNITY_TEST_ASSERT_EACH_EQUAL_UINT16((expected), (actual), (num_elements), __LINE__, NULL)
+#define TEST_ASSERT_EACH_EQUAL_UINT32(expected, actual, num_elements)                              UNITY_TEST_ASSERT_EACH_EQUAL_UINT32((expected), (actual), (num_elements), __LINE__, NULL)
+#define TEST_ASSERT_EACH_EQUAL_UINT64(expected, actual, num_elements)                              UNITY_TEST_ASSERT_EACH_EQUAL_UINT64((expected), (actual), (num_elements), __LINE__, NULL)
+#define TEST_ASSERT_EACH_EQUAL_HEX(expected, actual, num_elements)                                 UNITY_TEST_ASSERT_EACH_EQUAL_HEX32((expected), (actual), (num_elements), __LINE__, NULL)
+#define TEST_ASSERT_EACH_EQUAL_HEX8(expected, actual, num_elements)                                UNITY_TEST_ASSERT_EACH_EQUAL_HEX8((expected), (actual), (num_elements), __LINE__, NULL)
+#define TEST_ASSERT_EACH_EQUAL_HEX16(expected, actual, num_elements)                               UNITY_TEST_ASSERT_EACH_EQUAL_HEX16((expected), (actual), (num_elements), __LINE__, NULL)
+#define TEST_ASSERT_EACH_EQUAL_HEX32(expected, actual, num_elements)                               UNITY_TEST_ASSERT_EACH_EQUAL_HEX32((expected), (actual), (num_elements), __LINE__, NULL)
+#define TEST_ASSERT_EACH_EQUAL_HEX64(expected, actual, num_elements)                               UNITY_TEST_ASSERT_EACH_EQUAL_HEX64((expected), (actual), (num_elements), __LINE__, NULL)
+#define TEST_ASSERT_EACH_EQUAL_PTR(expected, actual, num_elements)                                 UNITY_TEST_ASSERT_EACH_EQUAL_PTR((expected), (actual), (num_elements), __LINE__, NULL)
+#define TEST_ASSERT_EACH_EQUAL_STRING(expected, actual, num_elements)                              UNITY_TEST_ASSERT_EACH_EQUAL_STRING((expected), (actual), (num_elements), __LINE__, NULL)
+#define TEST_ASSERT_EACH_EQUAL_MEMORY(expected, actual, len, num_elements)                         UNITY_TEST_ASSERT_EACH_EQUAL_MEMORY((expected), (actual), (len), (num_elements), __LINE__, NULL)
+
 /* Floating Point (If Enabled) */
 #define TEST_ASSERT_FLOAT_WITHIN(delta, expected, actual)                                          UNITY_TEST_ASSERT_FLOAT_WITHIN((delta), (expected), (actual), __LINE__, NULL)
 #define TEST_ASSERT_EQUAL_FLOAT(expected, actual)                                                  UNITY_TEST_ASSERT_EQUAL_FLOAT((expected), (actual), __LINE__, NULL)
 #define TEST_ASSERT_EQUAL_FLOAT_ARRAY(expected, actual, num_elements)                              UNITY_TEST_ASSERT_EQUAL_FLOAT_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)
+#define TEST_ASSERT_EACH_EQUAL_FLOAT(expected, actual, num_elements)                               UNITY_TEST_ASSERT_EACH_EQUAL_FLOAT((expected), (actual), (num_elements), __LINE__, NULL)
 #define TEST_ASSERT_FLOAT_IS_INF(actual)                                                           UNITY_TEST_ASSERT_FLOAT_IS_INF((actual), __LINE__, NULL)
 #define TEST_ASSERT_FLOAT_IS_NEG_INF(actual)                                                       UNITY_TEST_ASSERT_FLOAT_IS_NEG_INF((actual), __LINE__, NULL)
 #define TEST_ASSERT_FLOAT_IS_NAN(actual)                                                           UNITY_TEST_ASSERT_FLOAT_IS_NAN((actual), __LINE__, NULL)
@@ -170,6 +195,7 @@ void tearDown(void);
 #define TEST_ASSERT_DOUBLE_WITHIN(delta, expected, actual)                                         UNITY_TEST_ASSERT_DOUBLE_WITHIN((delta), (expected), (actual), __LINE__, NULL)
 #define TEST_ASSERT_EQUAL_DOUBLE(expected, actual)                                                 UNITY_TEST_ASSERT_EQUAL_DOUBLE((expected), (actual), __LINE__, NULL)
 #define TEST_ASSERT_EQUAL_DOUBLE_ARRAY(expected, actual, num_elements)                             UNITY_TEST_ASSERT_EQUAL_DOUBLE_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)
+#define TEST_ASSERT_EACH_EQUAL_DOUBLE(expected, actual, num_elements)                              UNITY_TEST_ASSERT_EACH_EQUAL_DOUBLE((expected), (actual), (num_elements), __LINE__, NULL)
 #define TEST_ASSERT_DOUBLE_IS_INF(actual)                                                          UNITY_TEST_ASSERT_DOUBLE_IS_INF((actual), __LINE__, NULL)
 #define TEST_ASSERT_DOUBLE_IS_NEG_INF(actual)                                                      UNITY_TEST_ASSERT_DOUBLE_IS_NEG_INF((actual), __LINE__, NULL)
 #define TEST_ASSERT_DOUBLE_IS_NAN(actual)                                                          UNITY_TEST_ASSERT_DOUBLE_IS_NAN((actual), __LINE__, NULL)
@@ -258,10 +284,31 @@ void tearDown(void);
 #define TEST_ASSERT_EQUAL_STRING_ARRAY_MESSAGE(expected, actual, num_elements, message)            UNITY_TEST_ASSERT_EQUAL_STRING_ARRAY((expected), (actual), (num_elements), __LINE__, (message))
 #define TEST_ASSERT_EQUAL_MEMORY_ARRAY_MESSAGE(expected, actual, len, num_elements, message)       UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY((expected), (actual), (len), (num_elements), __LINE__, (message))
 
+/* Arrays Compared To Single Value*/
+#define TEST_ASSERT_EACH_EQUAL_INT_MESSAGE(expected, actual, num_elements, message)                UNITY_TEST_ASSERT_EACH_EQUAL_INT((expected), (actual), (num_elements), __LINE__, (message))
+#define TEST_ASSERT_EACH_EQUAL_INT8_MESSAGE(expected, actual, num_elements, message)               UNITY_TEST_ASSERT_EACH_EQUAL_INT8((expected), (actual), (num_elements), __LINE__, (message))
+#define TEST_ASSERT_EACH_EQUAL_INT16_MESSAGE(expected, actual, num_elements, message)              UNITY_TEST_ASSERT_EACH_EQUAL_INT16((expected), (actual), (num_elements), __LINE__, (message))
+#define TEST_ASSERT_EACH_EQUAL_INT32_MESSAGE(expected, actual, num_elements, message)              UNITY_TEST_ASSERT_EACH_EQUAL_INT32((expected), (actual), (num_elements), __LINE__, (message))
+#define TEST_ASSERT_EACH_EQUAL_INT64_MESSAGE(expected, actual, num_elements, message)              UNITY_TEST_ASSERT_EACH_EQUAL_INT64((expected), (actual), (num_elements), __LINE__, (message))
+#define TEST_ASSERT_EACH_EQUAL_UINT_MESSAGE(expected, actual, num_elements, message)               UNITY_TEST_ASSERT_EACH_EQUAL_UINT((expected), (actual), (num_elements), __LINE__, (message))
+#define TEST_ASSERT_EACH_EQUAL_UINT8_MESSAGE(expected, actual, num_elements, message)              UNITY_TEST_ASSERT_EACH_EQUAL_UINT8((expected), (actual), (num_elements), __LINE__, (message))
+#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_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))
+#define TEST_ASSERT_EACH_EQUAL_HEX64_MESSAGE(expected, actual, num_elements, message)              UNITY_TEST_ASSERT_EACH_EQUAL_HEX64((expected), (actual), (num_elements), __LINE__, (message))
+#define TEST_ASSERT_EACH_EQUAL_PTR_MESSAGE(expected, actual, num_elements, message)                UNITY_TEST_ASSERT_EACH_EQUAL_PTR((expected), (actual), (num_elements), __LINE__, (message))
+#define TEST_ASSERT_EACH_EQUAL_STRING_MESSAGE(expected, actual, num_elements, message)             UNITY_TEST_ASSERT_EACH_EQUAL_STRING((expected), (actual), (num_elements), __LINE__, (message))
+#define TEST_ASSERT_EACH_EQUAL_MEMORY_MESSAGE(expected, actual, len, num_elements, message)        UNITY_TEST_ASSERT_EACH_EQUAL_MEMORY((expected), (actual), (len), (num_elements), __LINE__, (message))
+
 /* Floating Point (If Enabled) */
 #define TEST_ASSERT_FLOAT_WITHIN_MESSAGE(delta, expected, actual, message)                         UNITY_TEST_ASSERT_FLOAT_WITHIN((delta), (expected), (actual), __LINE__, (message))
 #define TEST_ASSERT_EQUAL_FLOAT_MESSAGE(expected, actual, message)                                 UNITY_TEST_ASSERT_EQUAL_FLOAT((expected), (actual), __LINE__, (message))
 #define TEST_ASSERT_EQUAL_FLOAT_ARRAY_MESSAGE(expected, actual, num_elements, message)             UNITY_TEST_ASSERT_EQUAL_FLOAT_ARRAY((expected), (actual), (num_elements), __LINE__, (message))
+#define TEST_ASSERT_EACH_EQUAL_FLOAT_MESSAGE(expected, actual, num_elements, message)              UNITY_TEST_ASSERT_EACH_EQUAL_FLOAT((expected), (actual), (num_elements), __LINE__, (message))
 #define TEST_ASSERT_FLOAT_IS_INF_MESSAGE(actual, message)                                          UNITY_TEST_ASSERT_FLOAT_IS_INF((actual), __LINE__, (message))
 #define TEST_ASSERT_FLOAT_IS_NEG_INF_MESSAGE(actual, message)                                      UNITY_TEST_ASSERT_FLOAT_IS_NEG_INF((actual), __LINE__, (message))
 #define TEST_ASSERT_FLOAT_IS_NAN_MESSAGE(actual, message)                                          UNITY_TEST_ASSERT_FLOAT_IS_NAN((actual), __LINE__, (message))
@@ -275,6 +322,7 @@ void tearDown(void);
 #define TEST_ASSERT_DOUBLE_WITHIN_MESSAGE(delta, expected, actual, message)                        UNITY_TEST_ASSERT_DOUBLE_WITHIN((delta), (expected), (actual), __LINE__, (message))
 #define TEST_ASSERT_EQUAL_DOUBLE_MESSAGE(expected, actual, message)                                UNITY_TEST_ASSERT_EQUAL_DOUBLE((expected), (actual), __LINE__, (message))
 #define TEST_ASSERT_EQUAL_DOUBLE_ARRAY_MESSAGE(expected, actual, num_elements, message)            UNITY_TEST_ASSERT_EQUAL_DOUBLE_ARRAY((expected), (actual), (num_elements), __LINE__, (message))
+#define TEST_ASSERT_EACH_EQUAL_DOUBLE_MESSAGE(expected, actual, num_elements, message)             UNITY_TEST_ASSERT_EACH_EQUAL_DOUBLE((expected), (actual), (num_elements), __LINE__, (message))
 #define TEST_ASSERT_DOUBLE_IS_INF_MESSAGE(actual, message)                                         UNITY_TEST_ASSERT_DOUBLE_IS_INF((actual), __LINE__, (message))
 #define TEST_ASSERT_DOUBLE_IS_NEG_INF_MESSAGE(actual, message)                                     UNITY_TEST_ASSERT_DOUBLE_IS_NEG_INF((actual), __LINE__, (message))
 #define TEST_ASSERT_DOUBLE_IS_NAN_MESSAGE(actual, message)                                         UNITY_TEST_ASSERT_DOUBLE_IS_NAN((actual), __LINE__, (message))

+ 81 - 31
tests/unity/src/unity_internals.h

@@ -250,14 +250,19 @@ extern void UNITY_OUTPUT_CHAR(int);
 #endif
 
 #ifndef UNITY_OUTPUT_FLUSH
-/* Default to using fflush, which is defined in stdio.h */
+#ifdef UNITY_USE_FLUSH_STDOUT
+/* We want to use the stdout flush utility */
 #include <stdio.h>
 #define UNITY_OUTPUT_FLUSH (void)fflush(stdout)
 #else
-  /* If defined as something else, make sure we declare it here so it's ready for use */
-  #ifndef UNITY_OMIT_OUTPUT_FLUSH_HEADER_DECLARATION
+/* We've specified nothing, therefore flush should just be ignored */
+#define UNITY_OUTPUT_FLUSH
+#endif
+#else
+/* We've defined flush as something else, so make sure we declare it here so it's ready for use */
+#ifndef UNITY_OMIT_OUTPUT_FLUSH_HEADER_DECLARATION
 extern void UNITY_OUTPUT_FLUSH(void);
-  #endif
+#endif
 #endif
 
 #ifndef UNITY_OUTPUT_FLUSH
@@ -360,6 +365,12 @@ typedef enum UNITY_FLOAT_TRAIT
 } UNITY_FLOAT_TRAIT_T;
 #endif
 
+typedef enum
+{
+    UNITY_ARRAY_TO_VAL = 0,
+    UNITY_ARRAY_TO_ARRAY
+} UNITY_FLAGS_T;
+
 struct UNITY_STORAGE_T
 {
     const char* TestFile;
@@ -447,7 +458,8 @@ void UnityAssertEqualIntArray(UNITY_INTERNAL_PTR expected,
                               const UNITY_UINT32 num_elements,
                               const char* msg,
                               const UNITY_LINE_TYPE lineNumber,
-                              const UNITY_DISPLAY_STYLE_T style);
+                              const UNITY_DISPLAY_STYLE_T style,
+                              const UNITY_FLAGS_T flags);
 
 void UnityAssertBits(const UNITY_INT mask,
                      const UNITY_INT expected,
@@ -466,18 +478,20 @@ void UnityAssertEqualStringLen(const char* expected,
                             const char* msg,
                             const UNITY_LINE_TYPE lineNumber);
 
-void UnityAssertEqualStringArray( const char** expected,
+void UnityAssertEqualStringArray( UNITY_INTERNAL_PTR expected,
                                   const char** actual,
                                   const UNITY_UINT32 num_elements,
                                   const char* msg,
-                                  const UNITY_LINE_TYPE lineNumber);
+                                  const UNITY_LINE_TYPE lineNumber,
+                                  const UNITY_FLAGS_T flags);
 
 void UnityAssertEqualMemory( UNITY_INTERNAL_PTR expected,
                              UNITY_INTERNAL_PTR actual,
                              const UNITY_UINT32 length,
                              const UNITY_UINT32 num_elements,
                              const char* msg,
-                             const UNITY_LINE_TYPE lineNumber);
+                             const UNITY_LINE_TYPE lineNumber,
+                             const UNITY_FLAGS_T flags);
 
 void UnityAssertNumbersWithin(const UNITY_UINT delta,
                               const UNITY_INT expected,
@@ -501,7 +515,8 @@ void UnityAssertEqualFloatArray(UNITY_PTR_ATTRIBUTE const UNITY_FLOAT* expected,
                                 UNITY_PTR_ATTRIBUTE const UNITY_FLOAT* actual,
                                 const UNITY_UINT32 num_elements,
                                 const char* msg,
-                                const UNITY_LINE_TYPE lineNumber);
+                                const UNITY_LINE_TYPE lineNumber,
+                                const UNITY_FLAGS_T flags);
 
 void UnityAssertFloatSpecial(const UNITY_FLOAT actual,
                              const char* msg,
@@ -520,7 +535,8 @@ void UnityAssertEqualDoubleArray(UNITY_PTR_ATTRIBUTE const UNITY_DOUBLE* expecte
                                  UNITY_PTR_ATTRIBUTE const UNITY_DOUBLE* actual,
                                  const UNITY_UINT32 num_elements,
                                  const char* msg,
-                                 const UNITY_LINE_TYPE lineNumber);
+                                 const UNITY_LINE_TYPE lineNumber,
+                                 const UNITY_FLAGS_T flags);
 
 void UnityAssertDoubleSpecial(const UNITY_DOUBLE actual,
                               const char* msg,
@@ -529,6 +545,18 @@ void UnityAssertDoubleSpecial(const UNITY_DOUBLE actual,
 #endif
 
 /*-------------------------------------------------------
+ * Helpers
+ *-------------------------------------------------------*/
+
+UNITY_INTERNAL_PTR UnityNumToPtr(const UNITY_INT num, const UNITY_UINT8 size);
+#ifndef UNITY_EXCLUDE_FLOAT
+UNITY_INTERNAL_PTR UnityFloatToPtr(const float num);
+#endif
+#ifndef UNITY_EXCLUDE_DOUBLE
+UNITY_INTERNAL_PTR UnityDoubleToPtr(const double num);
+#endif
+
+/*-------------------------------------------------------
  * Error Strings We Might Need
  *-------------------------------------------------------*/
 
@@ -637,30 +665,48 @@ int UnityTestMatches(void);
 #define UNITY_TEST_ASSERT_EQUAL_PTR(expected, actual, line, message)                             UnityAssertEqualNumber((UNITY_PTR_TO_INT)(expected), (UNITY_PTR_TO_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_POINTER)
 #define UNITY_TEST_ASSERT_EQUAL_STRING(expected, actual, line, message)                          UnityAssertEqualString((const char*)(expected), (const char*)(actual), (message), (UNITY_LINE_TYPE)(line))
 #define UNITY_TEST_ASSERT_EQUAL_STRING_LEN(expected, actual, len, line, message)                 UnityAssertEqualStringLen((const char*)(expected), (const char*)(actual), (UNITY_UINT32)(len), (message), (UNITY_LINE_TYPE)(line))
-#define UNITY_TEST_ASSERT_EQUAL_MEMORY(expected, actual, len, line, message)                     UnityAssertEqualMemory((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(len), 1, (message), (UNITY_LINE_TYPE)(line))
-
-#define UNITY_TEST_ASSERT_EQUAL_INT_ARRAY(expected, actual, num_elements, line, message)         UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT)
-#define UNITY_TEST_ASSERT_EQUAL_INT8_ARRAY(expected, actual, num_elements, line, message)        UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8)
-#define UNITY_TEST_ASSERT_EQUAL_INT16_ARRAY(expected, actual, num_elements, line, message)       UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16)
-#define UNITY_TEST_ASSERT_EQUAL_INT32_ARRAY(expected, actual, num_elements, line, message)       UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32)
-#define UNITY_TEST_ASSERT_EQUAL_UINT_ARRAY(expected, actual, num_elements, line, message)        UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT)
-#define UNITY_TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, actual, num_elements, line, message)       UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8)
-#define UNITY_TEST_ASSERT_EQUAL_UINT16_ARRAY(expected, actual, num_elements, line, message)      UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16)
-#define UNITY_TEST_ASSERT_EQUAL_UINT32_ARRAY(expected, actual, num_elements, line, message)      UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32)
-#define UNITY_TEST_ASSERT_EQUAL_HEX8_ARRAY(expected, actual, num_elements, line, message)        UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8)
-#define UNITY_TEST_ASSERT_EQUAL_HEX16_ARRAY(expected, actual, num_elements, line, message)       UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16)
-#define UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY(expected, actual, num_elements, line, message)       UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32)
-#define UNITY_TEST_ASSERT_EQUAL_PTR_ARRAY(expected, actual, num_elements, line, message)         UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_POINTER)
-#define UNITY_TEST_ASSERT_EQUAL_STRING_ARRAY(expected, actual, num_elements, line, message)      UnityAssertEqualStringArray((const char**)(expected), (const char**)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line))
-#define UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY(expected, actual, len, num_elements, line, message) UnityAssertEqualMemory((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(len), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line))
+#define UNITY_TEST_ASSERT_EQUAL_MEMORY(expected, actual, len, line, message)                     UnityAssertEqualMemory((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(len), 1, (message), (UNITY_LINE_TYPE)(line), UNITY_ARRAY_TO_ARRAY)
+
+#define UNITY_TEST_ASSERT_EQUAL_INT_ARRAY(expected, actual, num_elements, line, message)         UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT,     UNITY_ARRAY_TO_ARRAY)
+#define UNITY_TEST_ASSERT_EQUAL_INT8_ARRAY(expected, actual, num_elements, line, message)        UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8,    UNITY_ARRAY_TO_ARRAY)
+#define UNITY_TEST_ASSERT_EQUAL_INT16_ARRAY(expected, actual, num_elements, line, message)       UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16,   UNITY_ARRAY_TO_ARRAY)
+#define UNITY_TEST_ASSERT_EQUAL_INT32_ARRAY(expected, actual, num_elements, line, message)       UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32,   UNITY_ARRAY_TO_ARRAY)
+#define UNITY_TEST_ASSERT_EQUAL_UINT_ARRAY(expected, actual, num_elements, line, message)        UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT,    UNITY_ARRAY_TO_ARRAY)
+#define UNITY_TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, actual, num_elements, line, message)       UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8,   UNITY_ARRAY_TO_ARRAY)
+#define UNITY_TEST_ASSERT_EQUAL_UINT16_ARRAY(expected, actual, num_elements, line, message)      UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16,  UNITY_ARRAY_TO_ARRAY)
+#define UNITY_TEST_ASSERT_EQUAL_UINT32_ARRAY(expected, actual, num_elements, line, message)      UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32,  UNITY_ARRAY_TO_ARRAY)
+#define UNITY_TEST_ASSERT_EQUAL_HEX8_ARRAY(expected, actual, num_elements, line, message)        UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8,    UNITY_ARRAY_TO_ARRAY)
+#define UNITY_TEST_ASSERT_EQUAL_HEX16_ARRAY(expected, actual, num_elements, line, message)       UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16,   UNITY_ARRAY_TO_ARRAY)
+#define UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY(expected, actual, num_elements, line, message)       UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32,   UNITY_ARRAY_TO_ARRAY)
+#define UNITY_TEST_ASSERT_EQUAL_PTR_ARRAY(expected, actual, num_elements, line, message)         UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_POINTER, UNITY_ARRAY_TO_ARRAY)
+#define UNITY_TEST_ASSERT_EQUAL_STRING_ARRAY(expected, actual, num_elements, line, message)      UnityAssertEqualStringArray((UNITY_INTERNAL_PTR)(expected), (const char**)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_ARRAY_TO_ARRAY)
+#define UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY(expected, actual, len, num_elements, line, message) UnityAssertEqualMemory((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(len), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_ARRAY_TO_ARRAY)
+
+#define UNITY_TEST_ASSERT_EACH_EQUAL_INT(expected, actual, num_elements, line, message)          UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)              expected, sizeof(int)),  (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT,     UNITY_ARRAY_TO_VAL)
+#define UNITY_TEST_ASSERT_EACH_EQUAL_INT8(expected, actual, num_elements, line, message)         UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT8  )expected, 1),            (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8,    UNITY_ARRAY_TO_VAL)
+#define UNITY_TEST_ASSERT_EACH_EQUAL_INT16(expected, actual, num_elements, line, message)        UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT16 )expected, 2),            (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16,   UNITY_ARRAY_TO_VAL)
+#define UNITY_TEST_ASSERT_EACH_EQUAL_INT32(expected, actual, num_elements, line, message)        UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT32 )expected, 4),            (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32,   UNITY_ARRAY_TO_VAL)
+#define UNITY_TEST_ASSERT_EACH_EQUAL_UINT(expected, actual, num_elements, line, message)         UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)              expected, sizeof(unsigned int)), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT,    UNITY_ARRAY_TO_VAL)
+#define UNITY_TEST_ASSERT_EACH_EQUAL_UINT8(expected, actual, num_elements, line, message)        UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_UINT8 )expected, 1),            (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8,   UNITY_ARRAY_TO_VAL)
+#define UNITY_TEST_ASSERT_EACH_EQUAL_UINT16(expected, actual, num_elements, line, message)       UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_UINT16)expected, 2),            (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16,  UNITY_ARRAY_TO_VAL)
+#define UNITY_TEST_ASSERT_EACH_EQUAL_UINT32(expected, actual, num_elements, line, message)       UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_UINT32)expected, 4),            (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32,  UNITY_ARRAY_TO_VAL)
+#define UNITY_TEST_ASSERT_EACH_EQUAL_HEX8(expected, actual, num_elements, line, message)         UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT8  )expected, 1),            (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8,    UNITY_ARRAY_TO_VAL)
+#define UNITY_TEST_ASSERT_EACH_EQUAL_HEX16(expected, actual, num_elements, line, message)        UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT16 )expected, 2),            (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16,   UNITY_ARRAY_TO_VAL)
+#define UNITY_TEST_ASSERT_EACH_EQUAL_HEX32(expected, actual, num_elements, line, message)        UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT32 )expected, 4),            (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32,   UNITY_ARRAY_TO_VAL)
+#define UNITY_TEST_ASSERT_EACH_EQUAL_PTR(expected, actual, num_elements, line, message)          UnityAssertEqualIntArray(UnityNumToPtr((UNITY_PTR_TO_INT)       expected, sizeof(int*)), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_POINTER, UNITY_ARRAY_TO_VAL)
+#define UNITY_TEST_ASSERT_EACH_EQUAL_STRING(expected, actual, num_elements, line, message)       UnityAssertEqualStringArray((UNITY_INTERNAL_PTR)(expected), (const char**)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_ARRAY_TO_VAL)
+#define UNITY_TEST_ASSERT_EACH_EQUAL_MEMORY(expected, actual, len, num_elements, line, message)  UnityAssertEqualMemory((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(len), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_ARRAY_TO_VAL)
 
 #ifdef UNITY_SUPPORT_64
 #define UNITY_TEST_ASSERT_EQUAL_INT64(expected, actual, line, message)                           UnityAssertEqualNumber((UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64)
 #define UNITY_TEST_ASSERT_EQUAL_UINT64(expected, actual, line, message)                          UnityAssertEqualNumber((UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64)
 #define UNITY_TEST_ASSERT_EQUAL_HEX64(expected, actual, line, message)                           UnityAssertEqualNumber((UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64)
-#define UNITY_TEST_ASSERT_EQUAL_INT64_ARRAY(expected, actual, num_elements, line, message)       UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64)
-#define UNITY_TEST_ASSERT_EQUAL_UINT64_ARRAY(expected, actual, num_elements, line, message)      UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64)
-#define UNITY_TEST_ASSERT_EQUAL_HEX64_ARRAY(expected, actual, num_elements, line, message)       UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64)
+#define UNITY_TEST_ASSERT_EQUAL_INT64_ARRAY(expected, actual, num_elements, line, message)       UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64,  UNITY_ARRAY_TO_ARRAY)
+#define UNITY_TEST_ASSERT_EQUAL_UINT64_ARRAY(expected, actual, num_elements, line, message)      UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64, UNITY_ARRAY_TO_ARRAY)
+#define UNITY_TEST_ASSERT_EQUAL_HEX64_ARRAY(expected, actual, num_elements, line, message)       UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64,  UNITY_ARRAY_TO_ARRAY)
+#define UNITY_TEST_ASSERT_EACH_EQUAL_INT64(expected, actual, num_elements, line, message)        UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT64)expected, 8), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64,  UNITY_ARRAY_TO_ARRAY)
+#define UNITY_TEST_ASSERT_EACH_EQUAL_UINT64(expected, actual, num_elements, line, message)       UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT64)expected, 8), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64, UNITY_ARRAY_TO_ARRAY)
+#define UNITY_TEST_ASSERT_EACH_EQUAL_HEX64(expected, actual, num_elements, line, message)        UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT64)expected, 8), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64,  UNITY_ARRAY_TO_ARRAY)
 #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)
@@ -680,6 +726,7 @@ int UnityTestMatches(void);
 #define UNITY_TEST_ASSERT_FLOAT_WITHIN(delta, expected, actual, line, message)                   UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat)
 #define UNITY_TEST_ASSERT_EQUAL_FLOAT(expected, actual, line, message)                           UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat)
 #define UNITY_TEST_ASSERT_EQUAL_FLOAT_ARRAY(expected, actual, num_elements, line, message)       UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat)
+#define UNITY_TEST_ASSERT_EACH_EQUAL_FLOAT(expected, actual, num_elements, line, message)        UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat)
 #define UNITY_TEST_ASSERT_FLOAT_IS_INF(actual, line, message)                                    UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat)
 #define UNITY_TEST_ASSERT_FLOAT_IS_NEG_INF(actual, line, message)                                UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat)
 #define UNITY_TEST_ASSERT_FLOAT_IS_NAN(actual, line, message)                                    UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat)
@@ -691,7 +738,8 @@ int UnityTestMatches(void);
 #else
 #define UNITY_TEST_ASSERT_FLOAT_WITHIN(delta, expected, actual, line, message)                   UnityAssertFloatsWithin((UNITY_FLOAT)(delta), (UNITY_FLOAT)(expected), (UNITY_FLOAT)(actual), (message), (UNITY_LINE_TYPE)(line))
 #define UNITY_TEST_ASSERT_EQUAL_FLOAT(expected, actual, line, message)                           UNITY_TEST_ASSERT_FLOAT_WITHIN((UNITY_FLOAT)(expected) * (UNITY_FLOAT)UNITY_FLOAT_PRECISION, (UNITY_FLOAT)(expected), (UNITY_FLOAT)(actual), (UNITY_LINE_TYPE)(line), (message))
-#define UNITY_TEST_ASSERT_EQUAL_FLOAT_ARRAY(expected, actual, num_elements, line, message)       UnityAssertEqualFloatArray((UNITY_FLOAT*)(expected), (UNITY_FLOAT*)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line))
+#define UNITY_TEST_ASSERT_EQUAL_FLOAT_ARRAY(expected, actual, num_elements, line, message)       UnityAssertEqualFloatArray((UNITY_FLOAT*)(expected), (UNITY_FLOAT*)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_ARRAY_TO_ARRAY)
+#define UNITY_TEST_ASSERT_EACH_EQUAL_FLOAT(expected, actual, num_elements, line, message)        UnityAssertEqualFloatArray(UnityFloatToPtr(expected), (UNITY_FLOAT*)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_ARRAY_TO_VAL)
 #define UNITY_TEST_ASSERT_FLOAT_IS_INF(actual, line, message)                                    UnityAssertFloatSpecial((UNITY_FLOAT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_INF)
 #define UNITY_TEST_ASSERT_FLOAT_IS_NEG_INF(actual, line, message)                                UnityAssertFloatSpecial((UNITY_FLOAT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NEG_INF)
 #define UNITY_TEST_ASSERT_FLOAT_IS_NAN(actual, line, message)                                    UnityAssertFloatSpecial((UNITY_FLOAT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NAN)
@@ -706,6 +754,7 @@ int UnityTestMatches(void);
 #define UNITY_TEST_ASSERT_DOUBLE_WITHIN(delta, expected, actual, line, message)                  UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble)
 #define UNITY_TEST_ASSERT_EQUAL_DOUBLE(expected, actual, line, message)                          UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble)
 #define UNITY_TEST_ASSERT_EQUAL_DOUBLE_ARRAY(expected, actual, num_elements, line, message)      UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble)
+#define UNITY_TEST_ASSERT_EACH_EQUAL_DOUBLE(expected, actual, num_elements, line, message)       UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble)
 #define UNITY_TEST_ASSERT_DOUBLE_IS_INF(actual, line, message)                                   UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble)
 #define UNITY_TEST_ASSERT_DOUBLE_IS_NEG_INF(actual, line, message)                               UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble)
 #define UNITY_TEST_ASSERT_DOUBLE_IS_NAN(actual, line, message)                                   UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble)
@@ -717,7 +766,8 @@ int UnityTestMatches(void);
 #else
 #define UNITY_TEST_ASSERT_DOUBLE_WITHIN(delta, expected, actual, line, message)                  UnityAssertDoublesWithin((UNITY_DOUBLE)(delta), (UNITY_DOUBLE)(expected), (UNITY_DOUBLE)(actual), (message), (UNITY_LINE_TYPE)line)
 #define UNITY_TEST_ASSERT_EQUAL_DOUBLE(expected, actual, line, message)                          UNITY_TEST_ASSERT_DOUBLE_WITHIN((UNITY_DOUBLE)(expected) * (UNITY_DOUBLE)UNITY_DOUBLE_PRECISION, (UNITY_DOUBLE)expected, (UNITY_DOUBLE)actual, (UNITY_LINE_TYPE)(line), message)
-#define UNITY_TEST_ASSERT_EQUAL_DOUBLE_ARRAY(expected, actual, num_elements, line, message)      UnityAssertEqualDoubleArray((UNITY_DOUBLE*)(expected), (UNITY_DOUBLE*)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)line)
+#define UNITY_TEST_ASSERT_EQUAL_DOUBLE_ARRAY(expected, actual, num_elements, line, message)      UnityAssertEqualDoubleArray((UNITY_DOUBLE*)(expected), (UNITY_DOUBLE*)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)line, UNITY_ARRAY_TO_ARRAY)
+#define UNITY_TEST_ASSERT_EACH_EQUAL_DOUBLE(expected, actual, num_elements, line, message)       UnityAssertEqualDoubleArray(UnityDoubleToPtr(expected), (UNITY_DOUBLE*)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)line, UNITY_ARRAY_TO_VAL)
 #define UNITY_TEST_ASSERT_DOUBLE_IS_INF(actual, line, message)                                   UnityAssertDoubleSpecial((UNITY_DOUBLE)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_INF)
 #define UNITY_TEST_ASSERT_DOUBLE_IS_NEG_INF(actual, line, message)                               UnityAssertDoubleSpecial((UNITY_DOUBLE)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NEG_INF)
 #define UNITY_TEST_ASSERT_DOUBLE_IS_NAN(actual, line, message)                                   UnityAssertDoubleSpecial((UNITY_DOUBLE)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NAN)

+ 58 - 0
tests/unity/test/.rubocop.yml

@@ -0,0 +1,58 @@
+# This is the configuration used to check the rubocop source code.
+
+#inherit_from: .rubocop_todo.yml
+
+AllCops:
+  TargetRubyVersion: 2.1
+
+# These are areas where ThrowTheSwitch's coding style diverges from the Ruby standard
+Style/SpecialGlobalVars:
+  EnforcedStyle: use_perl_names
+Style/FormatString:
+  Enabled: false
+Style/GlobalVars:
+  Enabled: false
+Style/RegexpLiteral:
+  AllowInnerSlashes: true
+Style/HashSyntax:
+  EnforcedStyle: no_mixed_keys
+
+# This is disabled because it seems to get confused over nested hashes
+Style/AlignHash:
+  Enabled: false
+  EnforcedHashRocketStyle: table
+  EnforcedColonStyle: table
+
+# We purposefully use these insecure features because they're what makes Ruby awesome
+Security/Eval:
+  Enabled: false
+Security/YAMLLoad:
+  Enabled: false
+
+# At this point, we're not ready to enforce inline documentation requirements
+Style/Documentation:
+  Enabled: false
+Style/DocumentationMethod:
+  Enabled: false
+
+# At this point, we're not ready to enforce any metrics
+Metrics/AbcSize:
+  Enabled: false
+Metrics/BlockLength:
+  Enabled: false
+Metrics/BlockNesting:
+  Enabled: false
+Metrics/ClassLength:
+  Enabled: false
+Metrics/CyclomaticComplexity:
+  Enabled: false
+Metrics/LineLength:
+  Enabled: false
+Metrics/MethodLength:
+  Enabled: false
+Metrics/ModuleLength:
+  Enabled: false
+Metrics/ParameterLists:
+  Enabled: false
+Metrics/PerceivedComplexity:
+  Enabled: false

+ 55 - 2
tests/unity/test/rakefile

@@ -32,7 +32,7 @@ configure_toolchain(DEFAULT_CONFIG_FILE)
 
 desc "Test unity with its own unit tests"
 task :unit => [:prepare_for_tests] do
-  run_tests get_unit_test_files
+  run_tests unit_test_files
 end
 
 desc "Test unity's helper scripts"
@@ -53,7 +53,7 @@ task :summary do
 end
 
 desc "Build and test Unity"
-task :all => [:clean, :prepare_for_tests, :scripts, :unit, :summary]
+task :all => [:clean, :prepare_for_tests, :scripts, :unit, :style, :summary]
 task :default => [:clobber, :all]
 task :ci => [:no_color, :default]
 task :cruise => [:no_color, :default]
@@ -70,3 +70,56 @@ end
 task :verbose do
   $verbose = true
 end
+
+namespace :style do
+  desc "Check style"
+  task :check do
+    report "\nVERIFYING RUBY STYLE"
+    report execute("rubocop ../auto ../examples ../extras --config .rubocop.yml", true)
+    report "Styling Ruby:PASS"
+  end
+
+  namespace :check do
+    Dir['../**/*.rb'].each do |f|
+      filename = File.basename(f, '.rb')
+      desc "Check Style of #{filename}"
+      task filename.to_sym => ['style:clean'] do
+        report execute("rubocop #{f} --color --config .rubocop.yml", true)
+        report "Style Checked for #{f}"
+      end
+    end
+  end
+
+  desc "Fix Style of all C Code"
+  task :c do
+    run_astyle("../src/*.* ../extras/fixture/src/*.*")
+  end
+
+  namespace :c do
+    Dir['../{src,extras/**}/*.{c,h}'].each do |f|
+      filename = File.basename(f)[0..-3]
+      desc "Check Style of #{filename}"
+      task filename.to_sym do
+        run_astyle f
+      end
+    end
+  end
+
+  desc "Attempt to Autocorrect style"
+  task :auto  => ['style:clean'] do
+    execute("rubocop ../auto ../examples ../extras --auto-correct --config .rubocop.yml")
+    report "Autocorrected What We Could."
+  end
+
+  desc "Update style todo list"
+  task :todo  => ['style:clean'] do
+    execute("rubocop ../auto ../examples ../extras --auto-gen-config --config .rubocop.yml")
+    report "Updated Style TODO List."
+  end
+
+  task :clean do
+    File.delete(".rubocop_todo.yml") if File.exists?(".rubocop_todo.yml")
+  end
+end
+
+task :style => ['style:check']

+ 108 - 105
tests/unity/test/rakefile_helper.rb

@@ -11,39 +11,37 @@ require UNITY_ROOT + '../auto/generate_test_runner'
 require UNITY_ROOT + '../auto/colour_reporter'
 
 module RakefileHelpers
-
-  C_EXTENSION = '.c'
-
+  C_EXTENSION = '.c'.freeze
   def load_configuration(config_file)
-    unless ($configured)
-      $cfg_file = "targets/#{config_file}" unless (config_file =~ /[\\|\/]/)
-      $cfg = YAML.load(File.read($cfg_file))
-      $colour_output = false unless $cfg['colour']
-      $configured = true if (config_file != DEFAULT_CONFIG_FILE)
-    end
+    return if $configured
+
+    $cfg_file = "targets/#{config_file}" unless config_file =~ /[\\|\/]/
+    $cfg = YAML.load(File.read($cfg_file))
+    $colour_output = false unless $cfg['colour']
+    $configured = true if config_file != DEFAULT_CONFIG_FILE
   end
 
   def configure_clean
     CLEAN.include($cfg['compiler']['build_path'] + '*.*') unless $cfg['compiler']['build_path'].nil?
   end
 
-  def configure_toolchain(config_file=DEFAULT_CONFIG_FILE)
+  def configure_toolchain(config_file = DEFAULT_CONFIG_FILE)
     config_file += '.yml' unless config_file =~ /\.yml$/
     config_file = config_file unless config_file =~ /[\\|\/]/
     load_configuration(config_file)
     configure_clean
   end
 
-  def get_unit_test_files
+  def unit_test_files
     path = $cfg['compiler']['unit_tests_path'] + 'test*' + C_EXTENSION
-    path.gsub!(/\\/, '/')
+    path.tr!('\\', '/')
     FileList.new(path)
   end
 
-  def get_local_include_dirs
+  def local_include_dirs
     include_dirs = $cfg['compiler']['includes']['items'].dup
-    include_dirs.delete_if {|dir| dir.is_a?(Array)}
-    return include_dirs
+    include_dirs.delete_if { |dir| dir.is_a?(Array) }
+    include_dirs
   end
 
   def extract_headers(filename)
@@ -51,41 +49,37 @@ module RakefileHelpers
     lines = File.readlines(filename)
     lines.each do |line|
       m = line.match(/^\s*#include\s+\"\s*(.+\.[hH])\s*\"/)
-      if not m.nil?
-        includes << m[1]
-      end
+      includes << m[1] unless m.nil?
     end
-    return includes
+    includes
   end
 
   def find_source_file(header, paths)
     paths.each do |dir|
       src_file = dir + header.ext(C_EXTENSION)
-      if (File.exists?(src_file))
-        return src_file
-      end
+      return src_file if File.exist?(src_file)
     end
-    return nil
+    nil
   end
 
   def tackit(strings)
-    if strings.is_a?(Array)
-      result = "\"#{strings.join}\""
-    else
-      result = strings
-    end
-    return result
+    result = if strings.is_a?(Array)
+               "\"#{strings.join}\""
+             else
+               strings
+             end
+    result
   end
 
   def squash(prefix, items)
     result = ''
     items.each { |item| result += " #{prefix}#{tackit(item)}" }
-    return result
+    result
   end
 
   def should(behave, &block)
     if block
-      puts "Should " + behave
+      puts 'Should ' + behave
       yield block
     else
       puts "UNIMPLEMENTED CASE: Should #{behave}"
@@ -93,91 +87,103 @@ module RakefileHelpers
   end
 
   def build_compiler_fields(inject_defines)
-    command  = tackit($cfg['compiler']['path'])
-    if $cfg['compiler']['defines']['items'].nil?
-      defines  = ''
-    else
-      defines  = squash($cfg['compiler']['defines']['prefix'], $cfg['compiler']['defines']['items'] + ['UNITY_OUTPUT_CHAR=putcharSpy'] + inject_defines)
-    end
-    options  = squash('', $cfg['compiler']['options'])
+    command = tackit($cfg['compiler']['path'])
+    defines = if $cfg['compiler']['defines']['items'].nil?
+                ''
+              else
+                squash($cfg['compiler']['defines']['prefix'], $cfg['compiler']['defines']['items'] + ['UNITY_OUTPUT_CHAR=putcharSpy'] + inject_defines)
+              end
+    options = squash('', $cfg['compiler']['options'])
     includes = squash($cfg['compiler']['includes']['prefix'], $cfg['compiler']['includes']['items'])
     includes = includes.gsub(/\\ /, ' ').gsub(/\\\"/, '"').gsub(/\\$/, '') # Remove trailing slashes (for IAR)
-    return {:command => command, :defines => defines, :options => options, :includes => includes}
+
+    { :command => command, :defines => defines, :options => options, :includes => includes }
   end
 
-  def compile(file, defines=[])
+  def compile(file, defines = [])
     compiler = build_compiler_fields(defines)
-    defines  =
-    cmd_str  = "#{compiler[:command]}#{compiler[:defines]}#{compiler[:options]}#{compiler[:includes]} #{file} " +
+    cmd_str  = "#{compiler[:command]}#{compiler[:defines]}#{compiler[:options]}#{compiler[:includes]} #{file} " \
                "#{$cfg['compiler']['object_files']['prefix']}#{$cfg['compiler']['object_files']['destination']}"
     obj_file = "#{File.basename(file, C_EXTENSION)}#{$cfg['compiler']['object_files']['extension']}"
     execute(cmd_str + obj_file)
-    return obj_file
+
+    obj_file
   end
 
   def build_linker_fields
-    command  = tackit($cfg['linker']['path'])
-    if $cfg['linker']['options'].nil?
-      options  = ''
-    else
-      options  = squash('', $cfg['linker']['options'])
-    end
-    if ($cfg['linker']['includes'].nil? || $cfg['linker']['includes']['items'].nil?)
-      includes = ''
-    else
-      includes = squash($cfg['linker']['includes']['prefix'], $cfg['linker']['includes']['items'])
-    end
-    includes = includes.gsub(/\\ /, ' ').gsub(/\\\"/, '"').gsub(/\\$/, '') # Remove trailing slashes (for IAR)
-    return {:command => command, :options => options, :includes => includes}
+    command = tackit($cfg['linker']['path'])
+    options = if $cfg['linker']['options'].nil?
+                ''
+              else
+                squash('', $cfg['linker']['options'])
+              end
+    includes = if $cfg['linker']['includes'].nil? || $cfg['linker']['includes']['items'].nil?
+                 ''
+               else
+                 squash($cfg['linker']['includes']['prefix'], $cfg['linker']['includes']['items'])
+               end.gsub(/\\ /, ' ').gsub(/\\\"/, '"').gsub(/\\$/, '') # Remove trailing slashes (for IAR)
+
+    { :command => command, :options => options, :includes => includes }
   end
 
   def link_it(exe_name, obj_list)
     linker = build_linker_fields
     cmd_str = "#{linker[:command]}#{linker[:options]}#{linker[:includes]} " +
-      (obj_list.map{|obj|"#{$cfg['linker']['object_files']['path']}#{obj} "}).join +
-      $cfg['linker']['bin_files']['prefix'] + ' ' +
-      $cfg['linker']['bin_files']['destination'] +
-      exe_name + $cfg['linker']['bin_files']['extension']
+              (obj_list.map { |obj| "#{$cfg['linker']['object_files']['path']}#{obj} " }).join +
+              $cfg['linker']['bin_files']['prefix'] + ' ' +
+              $cfg['linker']['bin_files']['destination'] +
+              exe_name + $cfg['linker']['bin_files']['extension']
     execute(cmd_str)
   end
 
   def build_simulator_fields
     return nil if $cfg['simulator'].nil?
-    if $cfg['simulator']['path'].nil?
-      command = ''
-    else
-      command = (tackit($cfg['simulator']['path']) + ' ')
-    end
-    if $cfg['simulator']['pre_support'].nil?
-      pre_support = ''
-    else
-      pre_support = squash('', $cfg['simulator']['pre_support'])
-    end
-    if $cfg['simulator']['post_support'].nil?
-      post_support = ''
-    else
-      post_support = squash('', $cfg['simulator']['post_support'])
-    end
-    return {:command => command, :pre_support => pre_support, :post_support => post_support}
+    command = if $cfg['simulator']['path'].nil?
+                ''
+              else
+                (tackit($cfg['simulator']['path']) + ' ')
+              end
+    pre_support = if $cfg['simulator']['pre_support'].nil?
+                    ''
+                  else
+                    squash('', $cfg['simulator']['pre_support'])
+                  end
+    post_support = if $cfg['simulator']['post_support'].nil?
+                     ''
+                   else
+                     squash('', $cfg['simulator']['post_support'])
+                   end
+
+    { :command => command, :pre_support => pre_support, :post_support => post_support }
+  end
+
+  def run_astyle(style_what)
+    report "Styling C Code..."
+    command = "AStyle " \
+              "--style=allman --indent=spaces=4 --indent-switches --indent-preproc-define --indent-preproc-block " \
+              "--pad-oper --pad-comma --unpad-paren --pad-header " \
+              "--align-pointer=type --align-reference=name " \
+              "--add-brackets --mode=c --suffix=none " \
+              "#{style_what}"
+    execute(command, false)
+    report "Styling C:PASS"
   end
 
-  def execute(command_string, ok_to_fail=false)
+  def execute(command_string, ok_to_fail = false)
     report command_string if $verbose
     output = `#{command_string}`.chomp
-    report(output) if ($verbose && !output.nil? && (output.length > 0))
-    if (($?.exitstatus != 0) && !ok_to_fail)
-      raise "Command failed. (Returned #{$?.exitstatus})"
-    end
-    return output
+    report(output) if $verbose && !output.nil? && !output.empty?
+    raise "Command failed. (Returned #{$?.exitstatus})" if !$?.exitstatus.zero? && !ok_to_fail
+    output
   end
 
   def report_summary
     summary = UnityTestSummary.new
-    summary.set_root_path(UNITY_ROOT)
+    summary.root = UNITY_ROOT
     results_glob = "#{$cfg['compiler']['build_path']}*.test*"
-    results_glob.gsub!(/\\/, '/')
+    results_glob.tr!('\\', '/')
     results = Dir[results_glob]
-    summary.set_targets(results)
+    summary.targets = results
     report summary.run
   end
 
@@ -187,16 +193,16 @@ module RakefileHelpers
     # Tack on TEST define for compiling unit tests
     load_configuration($cfg_file)
     test_defines = ['TEST']
-    $cfg['compiler']['defines']['items'] = [] if $cfg['compiler']['defines']['items'].nil?
+    $cfg['compiler']['defines']['items'] ||= []
     $cfg['compiler']['defines']['items'] << 'TEST'
 
-    include_dirs = get_local_include_dirs
+    include_dirs = local_include_dirs
 
     # Build and execute each unit test
     test_files.each do |test|
       obj_list = []
 
-      if !$cfg['compiler']['aux_sources'].nil?
+      unless $cfg['compiler']['aux_sources'].nil?
         $cfg['compiler']['aux_sources'].each do |aux|
           obj_list << compile(aux, test_defines)
         end
@@ -206,25 +212,23 @@ module RakefileHelpers
       extract_headers(test).each do |header|
         # Compile corresponding source file if it exists
         src_file = find_source_file(header, include_dirs)
-        if !src_file.nil?
-          obj_list << compile(src_file, test_defines)
-        end
+
+        obj_list << compile(src_file, test_defines) unless src_file.nil?
       end
 
       # Build the test runner (generate if configured to do so)
       test_base = File.basename(test, C_EXTENSION)
 
       runner_name = test_base + '_Runner.c'
-      runner_path = ''
 
-      if $cfg['compiler']['runner_path'].nil?
-        runner_path = $cfg['compiler']['build_path'] + runner_name
-      else
-        runner_path = $cfg['compiler']['runner_path'] + runner_name
-      end
+      runner_path = if $cfg['compiler']['runner_path'].nil?
+                      $cfg['compiler']['build_path'] + runner_name
+                    else
+                      $cfg['compiler']['runner_path'] + runner_name
+                    end
 
       options = $cfg[:unity]
-      options[:use_param_tests] = (test =~ /parameterized/) ? true : false
+      options[:use_param_tests] = test =~ /parameterized/ ? true : false
       UnityTestRunnerGenerator.new(options).run(test, runner_path)
       obj_list << compile(runner_path, test_defines)
 
@@ -237,21 +241,20 @@ module RakefileHelpers
       # Execute unit test and generate results file
       simulator = build_simulator_fields
       executable = $cfg['linker']['bin_files']['destination'] + test_base + $cfg['linker']['bin_files']['extension']
-      if simulator.nil?
-        cmd_str = executable
-      else
-        cmd_str = "#{simulator[:command]} #{simulator[:pre_support]} #{executable} #{simulator[:post_support]}"
-      end
+      cmd_str = if simulator.nil?
+                  executable
+                else
+                  "#{simulator[:command]} #{simulator[:pre_support]} #{executable} #{simulator[:post_support]}"
+                end
       output = execute(cmd_str)
       test_results = $cfg['compiler']['build_path'] + test_base
       if output.match(/OK$/m).nil?
         test_results += '.testfail'
       else
-        report output if (!$verbose) #verbose already prints this line, as does a failure
+        report output unless $verbose # Verbose already prints this line, as does a failure
         test_results += '.testpass'
       end
       File.open(test_results, 'w') { |f| f.print output }
-
     end
   end
 end

+ 1 - 3
tests/unity/test/targets/clang_strict.yml

@@ -36,7 +36,7 @@ compiler:
     - '-Wbad-function-cast'
     - '-fms-extensions'
     - '-fno-omit-frame-pointer'
-    - '-ffloat-store'
+    #- '-ffloat-store'
     - '-fno-common'
     - '-fstrict-aliasing'
     - '-std=gnu99'
@@ -55,8 +55,6 @@ compiler:
       - UNITY_INCLUDE_DOUBLE
       - UNITY_SUPPORT_TEST_CASES
       - UNITY_SUPPORT_64
-      - UNITY_OUTPUT_FLUSH
-      - UNITY_OMIT_OUTPUT_FLUSH_HEADER_DECLARATION
   object_files:
     prefix: '-o'
     extension: '.o'

+ 2 - 0
tests/unity/test/testdata/testRunnerGeneratorSmall.c

@@ -4,6 +4,8 @@
 #include "unity.h"
 #include "Defs.h"
 
+TEST_FILE("some_file.c")
+
 /* Notes about prefixes:
    test     - normal default prefix. these are "always run" tests for this procedure
    spec     - normal default prefix. required to run default setup/teardown calls.

+ 5 - 5
tests/unity/test/tests/test_generate_test_runner.rb

@@ -1170,11 +1170,11 @@ def runner_test(test, runner, expected, test_defines, cmdline_args)
   simulator = build_simulator_fields
   cmdline_args ||= ""
   executable = $cfg['linker']['bin_files']['destination'] + test_base + $cfg['linker']['bin_files']['extension'] + " #{cmdline_args}"
-  if simulator.nil?
-    cmd_str = executable
-  else
-    cmd_str = "#{simulator[:command]} #{simulator[:pre_support]} #{executable} #{simulator[:post_support]}"
-  end
+  cmd_str = if simulator.nil?
+              executable
+            else
+              "#{simulator[:command]} #{simulator[:pre_support]} #{executable} #{simulator[:post_support]}"
+            end
   output = execute(cmd_str, true)
 
   #compare to the expected pass/fail

+ 939 - 4
tests/unity/test/tests/testunity.c

@@ -1519,6 +1519,61 @@ void testNotEqualStringArrayLengthZero(void)
     VERIFY_FAILS_END
 }
 
+void testEqualStringEachEqual(void)
+{
+    const char *testStrings1[] = { "foo", "foo", "foo", "foo" };
+    const char *testStrings2[] = { "boo", "boo", "boo", "zoo" };
+    const char *testStrings3[] = { "", "", "", "" };
+
+    TEST_ASSERT_EACH_EQUAL_STRING("foo", testStrings1, 4);
+    TEST_ASSERT_EACH_EQUAL_STRING("foo", testStrings1, 1);
+    TEST_ASSERT_EACH_EQUAL_STRING("boo", testStrings2, 3);
+    TEST_ASSERT_EACH_EQUAL_STRING("", testStrings3, 4);
+}
+
+void testNotEqualStringEachEqual1(void)
+{
+    const char *testStrings[] = { "foo", "foo", "foo", "moo" };
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_STRING("foo", testStrings, 4);
+    VERIFY_FAILS_END
+}
+
+void testNotEqualStringEachEqual2(void)
+{
+    const char *testStrings[] = { "boo", "foo", "foo", "foo" };
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_STRING("foo", testStrings, 4);
+    VERIFY_FAILS_END
+}
+
+void testNotEqualStringEachEqual3(void)
+{
+    const char *testStrings[] = { "foo", "foo", "foo", NULL };
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_STRING("foo", testStrings, 4);
+    VERIFY_FAILS_END
+}
+
+void testNotEqualStringEachEqual4(void)
+{
+    const char *testStrings[] = { "foo", "foo", "woo", "foo" };
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_STRING("foo", testStrings, 4);
+    VERIFY_FAILS_END
+}
+
+void testNotEqualStringEachEqual5(void)
+{
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_STRING("foo", NULL, 1);
+    VERIFY_FAILS_END
+}
+
 void testEqualMemory(void)
 {
     const char *testString = "whatever";
@@ -1641,6 +1696,65 @@ void testNotEqualIntArraysLengthZero(void)
     VERIFY_FAILS_END
 }
 
+void testEqualIntEachEqual(void)
+{
+    int p0[] = {1, 1, 1, 1};
+    int p1[] = {987, 987, 987, 987};
+    int p2[] = {-2, -2, -2, -3};
+    int p3[] = {1, 5, 600, 700};
+
+    TEST_ASSERT_EACH_EQUAL_INT(1, p0, 1);
+    TEST_ASSERT_EACH_EQUAL_INT(1, p0, 4);
+    TEST_ASSERT_EACH_EQUAL_INT(987, p1, 4);
+    TEST_ASSERT_EACH_EQUAL_INT(-2, p2, 3);
+    TEST_ASSERT_EACH_EQUAL_INT(1, p3, 1);
+}
+
+void testNotEqualIntEachEqualNullActual(void)
+{
+    int* p1 = NULL;
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_INT(1, p1, 4);
+    VERIFY_FAILS_END
+}
+
+void testNotEqualIntEachEqual1(void)
+{
+    int p0[] = {1, 1, 1, -2};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_INT(1, p0, 4);
+    VERIFY_FAILS_END
+}
+
+void testNotEqualIntEachEqual2(void)
+{
+    int p0[] = {-5, -5, -1, -5};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_INT(-5, p0, 4);
+    VERIFY_FAILS_END
+}
+
+void testNotEqualIntEachEqual3(void)
+{
+    int p0[] = {1, 88, 88, 88};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_INT(88, p0, 4);
+    VERIFY_FAILS_END
+}
+
+void testNotEqualEachEqualLengthZero(void)
+{
+    UNITY_UINT32 p0[1] = {1};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_INT(0, p0, 0);
+    VERIFY_FAILS_END
+}
+
 void testEqualPtrArrays(void)
 {
     char A = 1;
@@ -1721,6 +1835,77 @@ void testNotEqualPtrArrays3(void)
     VERIFY_FAILS_END
 }
 
+void testEqualPtrEachEqual(void)
+{
+    char A = 1;
+    char B = 2;
+    char C = 3;
+    char* p0[] = {&A, &A, &A};
+    char* p1[] = {&A, &B, &C, &A};
+    char* p2[] = {&B, &B};
+    char* p3[] = {&C};
+
+    TEST_ASSERT_EACH_EQUAL_PTR(&A, p0, 1);
+    TEST_ASSERT_EACH_EQUAL_PTR(&A, p0, 3);
+    TEST_ASSERT_EACH_EQUAL_PTR(&A, p1, 1);
+    TEST_ASSERT_EACH_EQUAL_PTR(&B, p2, 2);
+    TEST_ASSERT_EACH_EQUAL_PTR(&C, p3, 1);
+}
+
+void testNotEqualPtrEachEqualNullExpected(void)
+{
+    char A = 1;
+    char B = 1;
+    char* p0[] = {&A, &B};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_PTR(&A, p0, 2);
+    VERIFY_FAILS_END
+}
+
+void testNotEqualPtrEachEqualNullActual(void)
+{
+    char A = 1;
+    char** p0 = NULL;
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_PTR(&A, p0, 2);
+    VERIFY_FAILS_END
+}
+
+void testNotEqualPtrEachEqual1(void)
+{
+    char A = 1;
+    char B = 1;
+    char* p0[] = {&A, &A, &A, &B};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_PTR(&A, p0, 4);
+    VERIFY_FAILS_END
+}
+
+void testNotEqualPtrEachEqual2(void)
+{
+    char A = 1;
+    char B = 1;
+    char* p0[] = {&B, &B, &A, &B};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_PTR(&B, p0, 4);
+    VERIFY_FAILS_END
+}
+
+void testNotEqualPtrEachEqual3(void)
+{
+    char A = 1;
+    char B = 1;
+    char* p0[] = {&A, &B, &B, &B};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_PTR(&B, p0, 4);
+    VERIFY_FAILS_END
+}
+
 void testEqualInt8Arrays(void)
 {
     UNITY_INT8 p0[] = {1, 8, 117, -2};
@@ -1745,6 +1930,29 @@ void testNotEqualInt8Arrays(void)
     VERIFY_FAILS_END
 }
 
+void testEqualInt8EachEqual(void)
+{
+    UNITY_INT8 p0[] = {1, 1, 1, 1};
+    UNITY_INT8 p1[] = {117, 117, 117, -2};
+    UNITY_INT8 p2[] = {-1, -1, 117, 2};
+    UNITY_INT8 p3[] = {1, 50, 60, 70};
+
+    TEST_ASSERT_EACH_EQUAL_INT8(1, p0, 1);
+    TEST_ASSERT_EACH_EQUAL_INT8(1, p0, 4);
+    TEST_ASSERT_EACH_EQUAL_INT8(117, p1, 3);
+    TEST_ASSERT_EACH_EQUAL_INT8(-1, p2, 2);
+    TEST_ASSERT_EACH_EQUAL_INT8(1, p3, 1);
+}
+
+void testNotEqualInt8EachEqual(void)
+{
+    UNITY_INT8 p0[] = {1, 8, 36, -2};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_INT8(1, p0, 2);
+    VERIFY_FAILS_END
+}
+
 void testEqualUIntArrays(void)
 {
     unsigned int p0[] = {1, 8, 987, 65132u};
@@ -1789,6 +1997,47 @@ void testNotEqualUIntArrays3(void)
     VERIFY_FAILS_END
 }
 
+void testEqualUIntEachEqual(void)
+{
+    unsigned int p0[] = {1, 1, 1, 1};
+    unsigned int p1[] = {65132u, 65132u, 65132u, 65132u};
+    unsigned int p2[] = {8, 8, 987, 2};
+    unsigned int p3[] = {1, 500, 600, 700};
+
+    TEST_ASSERT_EACH_EQUAL_UINT(1, p0, 1);
+    TEST_ASSERT_EACH_EQUAL_UINT(1, p0, 4);
+    TEST_ASSERT_EACH_EQUAL_UINT(65132u, p1, 4);
+    TEST_ASSERT_EACH_EQUAL_UINT(8, p2, 2);
+    TEST_ASSERT_EACH_EQUAL_UINT(1, p3, 1);
+}
+
+void testNotEqualUIntEachEqual1(void)
+{
+    unsigned int p0[] = {1, 65132u, 65132u, 65132u};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_UINT(65132u, p0, 4);
+    VERIFY_FAILS_END
+}
+
+void testNotEqualUIntEachEqual2(void)
+{
+    unsigned int p0[] = {987, 8, 987, 987};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_UINT(987, p0, 4);
+    VERIFY_FAILS_END
+}
+
+void testNotEqualUIntEachEqual3(void)
+{
+    unsigned int p0[] = {1, 1, 1, 65132u};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_UINT(1, p0, 4);
+    VERIFY_FAILS_END
+}
+
 void testEqualInt16Arrays(void)
 {
     UNITY_INT16 p0[] = {1, 8, 117, 3};
@@ -1813,6 +2062,29 @@ void testNotEqualInt16Arrays(void)
     VERIFY_FAILS_END
 }
 
+void testEqualInt16EachEqual(void)
+{
+    UNITY_INT16 p0[] = {1, 1, 1, 1};
+    UNITY_INT16 p1[] = {32111, 32111, 32111, 3};
+    UNITY_INT16 p2[] = {-1, -1, -1, 2};
+    UNITY_INT16 p3[] = {1, 50, 60, 70};
+
+    TEST_ASSERT_EACH_EQUAL_INT16(1, p0, 1);
+    TEST_ASSERT_EACH_EQUAL_INT16(1, p0, 4);
+    TEST_ASSERT_EACH_EQUAL_INT16(32111, p1, 3);
+    TEST_ASSERT_EACH_EQUAL_INT16(-1, p2, 3);
+    TEST_ASSERT_EACH_EQUAL_INT16(1, p3, 1);
+}
+
+void testNotEqualInt16EachEqual(void)
+{
+    UNITY_INT16 p0[] = {127, 127, 127, 3};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_INT16(127, p0, 4);
+    VERIFY_FAILS_END
+}
+
 void testEqualInt32Arrays(void)
 {
     UNITY_INT32 p0[] = {1, 8, 117, 3};
@@ -1837,6 +2109,29 @@ void testNotEqualInt32Arrays(void)
     VERIFY_FAILS_END
 }
 
+void testEqualInt32EachEqual(void)
+{
+    UNITY_INT32 p0[] = {8, 8, 8, 8};
+    UNITY_INT32 p1[] = {65537, 65537, 65537, 65537};
+    UNITY_INT32 p2[] = {-3, -3, -3, 2};
+    UNITY_INT32 p3[] = {1, 50, 60, 70};
+
+    TEST_ASSERT_EACH_EQUAL_INT32(8, p0, 1);
+    TEST_ASSERT_EACH_EQUAL_INT32(8, p0, 4);
+    TEST_ASSERT_EACH_EQUAL_INT32(65537, p1, 4);
+    TEST_ASSERT_EACH_EQUAL_INT32(-3, p2, 3);
+    TEST_ASSERT_EACH_EQUAL_INT32(1, p3, 1);
+}
+
+void testNotEqualInt32EachEqual(void)
+{
+    UNITY_INT32 p0[] = {127, 8, 127, 127};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_INT32(127, p0, 4);
+    VERIFY_FAILS_END
+}
+
 void testEqualUINT8Arrays(void)
 {
     UNITY_UINT8 p0[] = {1, 8, 100, 127};
@@ -2104,10 +2399,10 @@ void testNotEqualHEX16Arrays3(void)
 
 void testEqualHEX8Arrays(void)
 {
-    unsigned short p0[] = {1, 8, 254u, 123};
-    unsigned short p1[] = {1, 8, 254u, 123};
-    unsigned short p2[] = {1, 8, 254u, 2};
-    unsigned short p3[] = {1, 23, 25, 26};
+    unsigned char p0[] = {1, 8, 254u, 123};
+    unsigned char p1[] = {1, 8, 254u, 123};
+    unsigned char p2[] = {1, 8, 254u, 2};
+    unsigned char p3[] = {1, 23, 25, 26};
 
     TEST_ASSERT_EQUAL_HEX8_ARRAY(p0, p0, 1);
     TEST_ASSERT_EQUAL_HEX8_ARRAY(p0, p0, 4);
@@ -2146,6 +2441,293 @@ void testNotEqualHEX8Arrays3(void)
     VERIFY_FAILS_END
 }
 
+void testEqualUINT8EachEqual(void)
+{
+    UNITY_UINT8 p0[] = {127u, 127u, 127u, 127u};
+    UNITY_UINT8 p1[] = {1u, 1u, 1u, 1u};
+    UNITY_UINT8 p2[] = {128u, 128u, 128u, 2u};
+    UNITY_UINT8 p3[] = {1u, 50u, 60u, 70u};
+
+    TEST_ASSERT_EACH_EQUAL_UINT8(127u, p0, 1);
+    TEST_ASSERT_EACH_EQUAL_UINT8(127u, p0, 4);
+    TEST_ASSERT_EACH_EQUAL_UINT8(1u, p1, 4);
+    TEST_ASSERT_EACH_EQUAL_UINT8(128u, p2, 3);
+    TEST_ASSERT_EACH_EQUAL_UINT8(1u, p3, 1);
+}
+
+void testNotEqualUINT8EachEqual1(void)
+{
+    unsigned char p0[] = {127u, 127u, 128u, 127u};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_UINT8(127u, p0, 4);
+    VERIFY_FAILS_END
+}
+
+void testNotEqualUINT8EachEqual2(void)
+{
+    unsigned char p0[] = {1, 1, 1, 127u};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_UINT8(1, p0, 4);
+    VERIFY_FAILS_END
+}
+
+void testNotEqualUINT8EachEqual3(void)
+{
+    unsigned char p0[] = {54u, 55u, 55u, 55u};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_UINT8(55u, p0, 4);
+    VERIFY_FAILS_END
+}
+
+void testEqualUINT16EachEqual(void)
+{
+    unsigned short p0[] = {65132u, 65132u, 65132u, 65132u};
+    unsigned short p1[] = {987, 987, 987, 987};
+    unsigned short p2[] = {1, 1, 1, 2};
+    unsigned short p3[] = {1, 500, 600, 700};
+
+    TEST_ASSERT_EACH_EQUAL_UINT16(65132u, p0, 1);
+    TEST_ASSERT_EACH_EQUAL_UINT16(65132u, p0, 4);
+    TEST_ASSERT_EACH_EQUAL_UINT16(987, p1, 4);
+    TEST_ASSERT_EACH_EQUAL_UINT16(1, p2, 3);
+    TEST_ASSERT_EACH_EQUAL_UINT16(1, p3, 1);
+}
+
+void testNotEqualUINT16EachEqual1(void)
+{
+    unsigned short p0[] = {1, 65132u, 65132u, 65132u};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_UINT16(65132u, p0, 4);
+    VERIFY_FAILS_END
+}
+
+void testNotEqualUINT16EachEqual2(void)
+{
+    unsigned short p0[] = {65132u, 65132u, 987, 65132u};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_UINT16(65132u, p0, 4);
+    VERIFY_FAILS_END
+}
+
+void testNotEqualUINT16EachEqual3(void)
+{
+    unsigned short p0[] = {65132u, 65132u, 65132u, 65133u};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_UINT16(65132u, p0, 4);
+    VERIFY_FAILS_END
+}
+
+void testEqualUINT32EachEqual(void)
+{
+    UNITY_UINT32 p0[] = {65132u, 65132u, 65132u, 65132u};
+    UNITY_UINT32 p1[] = {987, 987, 987, 987};
+    UNITY_UINT32 p2[] = {8, 8, 8, 2};
+    UNITY_UINT32 p3[] = {1, 500, 600, 700};
+
+    TEST_ASSERT_EACH_EQUAL_UINT32(65132u, p0, 1);
+    TEST_ASSERT_EACH_EQUAL_UINT32(65132u, p0, 4);
+    TEST_ASSERT_EACH_EQUAL_UINT32(987, p1, 4);
+    TEST_ASSERT_EACH_EQUAL_UINT32(8, p2, 3);
+    TEST_ASSERT_EACH_EQUAL_UINT32(1, p3, 1);
+}
+
+void testNotEqualUINT32EachEqual1(void)
+{
+    UNITY_UINT32 p0[] = {65132u, 65132u, 987, 65132u};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_UINT32(65132u, p0, 4);
+    VERIFY_FAILS_END
+}
+
+void testNotEqualUINT32EachEqual2(void)
+{
+    UNITY_UINT32 p0[] = {1, 987, 987, 987};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_UINT32(987, p0, 4);
+    VERIFY_FAILS_END
+}
+
+void testNotEqualUINT32EachEqual3(void)
+{
+    UNITY_UINT32 p0[] = {1, 1, 1, 65132u};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_UINT32(1, p0, 4);
+    VERIFY_FAILS_END
+}
+
+void testEqualHEXEachEqual(void)
+{
+    UNITY_UINT32 p0[] = {65132u, 65132u, 65132u, 65132u};
+    UNITY_UINT32 p1[] = {987, 987, 987, 987};
+    UNITY_UINT32 p2[] = {8, 8, 8, 2};
+    UNITY_UINT32 p3[] = {1, 500, 600, 700};
+
+    TEST_ASSERT_EACH_EQUAL_HEX(65132u, p0, 1);
+    TEST_ASSERT_EACH_EQUAL_HEX(65132u, p0, 4);
+    TEST_ASSERT_EACH_EQUAL_HEX(987, p1, 4);
+    TEST_ASSERT_EACH_EQUAL_HEX(8, p2, 3);
+    TEST_ASSERT_EACH_EQUAL_HEX(1, p3, 1);
+}
+
+void testNotEqualHEXEachEqual1(void)
+{
+    UNITY_UINT32 p0[] = {1, 65132u, 65132u, 65132u};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_HEX32(65132u, p0, 4);
+    VERIFY_FAILS_END
+}
+
+void testNotEqualHEXEachEqual2(void)
+{
+    UNITY_UINT32 p0[] = {987, 987, 987, 65132u};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_HEX32(987, p0, 4);
+    VERIFY_FAILS_END
+}
+
+void testNotEqualHEXEachEqual3(void)
+{
+    UNITY_UINT32 p0[] = {8, 8, 987, 8};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_HEX(8, p0, 4);
+    VERIFY_FAILS_END
+}
+
+void testEqualHEX32EachEqual(void)
+{
+    UNITY_UINT32 p0[] = {65132u, 65132u, 65132u, 65132u};
+    UNITY_UINT32 p1[] = {987, 987, 987, 987};
+    UNITY_UINT32 p2[] = {8, 8, 8, 2};
+    UNITY_UINT32 p3[] = {1, 500, 600, 700};
+
+    TEST_ASSERT_EACH_EQUAL_HEX32(65132u, p0, 1);
+    TEST_ASSERT_EACH_EQUAL_HEX32(65132u, p0, 4);
+    TEST_ASSERT_EACH_EQUAL_HEX32(987, p1, 4);
+    TEST_ASSERT_EACH_EQUAL_HEX32(8, p2, 3);
+    TEST_ASSERT_EACH_EQUAL_HEX32(1, p3, 1);
+}
+
+void testNotEqualHEX32EachEqual1(void)
+{
+    UNITY_UINT32 p0[] = {65132u, 8, 65132u, 65132u};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_HEX32(65132u, p0, 4);
+    VERIFY_FAILS_END
+}
+
+void testNotEqualHEX32EachEqual2(void)
+{
+    UNITY_UINT32 p0[] = {1, 987, 987, 987};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_HEX32(987, p0, 4);
+    VERIFY_FAILS_END
+}
+
+void testNotEqualHEX32EachEqual3(void)
+{
+    UNITY_UINT32 p0[] = {8, 8, 8, 65132u};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_HEX32(8, p0, 4);
+    VERIFY_FAILS_END
+}
+
+void testEqualHEX16EachEqual(void)
+{
+    UNITY_UINT16 p0[] = {65132u, 65132u, 65132u, 65132u};
+    UNITY_UINT16 p1[] = {987, 987, 987, 987};
+    UNITY_UINT16 p2[] = {8, 8, 8, 2};
+    UNITY_UINT16 p3[] = {1, 500, 600, 700};
+
+    TEST_ASSERT_EACH_EQUAL_HEX16(65132u, p0, 1);
+    TEST_ASSERT_EACH_EQUAL_HEX16(65132u, p0, 4);
+    TEST_ASSERT_EACH_EQUAL_HEX16(987, p1, 4);
+    TEST_ASSERT_EACH_EQUAL_HEX16(8, p2, 3);
+    TEST_ASSERT_EACH_EQUAL_HEX16(1, p3, 1);
+}
+
+void testNotEqualHEX16EachEqual1(void)
+{
+    unsigned short p0[] = {65132u, 65132u, 987, 65132u};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_HEX16(65132u, p0, 4);
+    VERIFY_FAILS_END
+}
+
+void testNotEqualHEX16EachEqual2(void)
+{
+    unsigned short p0[] = {1, 987, 987, 987};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_HEX16(987, p0, 4);
+    VERIFY_FAILS_END
+}
+
+void testNotEqualHEX16EachEqual3(void)
+{
+    unsigned short p0[] = {8, 8, 8, 65132u};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_HEX16(8, p0, 4);
+    VERIFY_FAILS_END
+}
+
+void testEqualHEX8EachEqual(void)
+{
+    unsigned char p0[] = {254u, 254u, 254u, 254u};
+    unsigned char p1[] = {123, 123, 123, 123};
+    unsigned char p2[] = {8, 8, 8, 2};
+    unsigned char p3[] = {1, 23, 25, 26};
+
+    TEST_ASSERT_EACH_EQUAL_HEX8(254u, p0, 1);
+    TEST_ASSERT_EACH_EQUAL_HEX8(254u, p0, 4);
+    TEST_ASSERT_EACH_EQUAL_HEX8(123, p1, 4);
+    TEST_ASSERT_EACH_EQUAL_HEX8(8, p2, 3);
+    TEST_ASSERT_EACH_EQUAL_HEX8(1, p3, 1);
+}
+
+void testNotEqualHEX8EachEqual1(void)
+{
+    unsigned char p0[] = {253u, 253u, 254u, 253u};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_HEX8(253u, p0, 4);
+    VERIFY_FAILS_END
+}
+
+void testNotEqualHEX8EachEqual2(void)
+{
+    unsigned char p0[] = {254u, 254u, 254u, 253u};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_HEX8(254u, p0, 4);
+    VERIFY_FAILS_END
+}
+
+void testNotEqualHEX8EachEqual3(void)
+{
+    unsigned char p0[] = {1, 8, 8, 8};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_HEX8(8, p0, 4);
+    VERIFY_FAILS_END
+}
+
 void testEqualMemoryArrays(void)
 {
     int p0[] = {1, 8, 987, -2};
@@ -2210,6 +2792,71 @@ void testNotEqualMemoryArrays3(void)
     VERIFY_FAILS_END
 }
 
+void testEqualMemoryEachEqual(void)
+{
+    int p0[] = {1, 8, 987, -2};
+    int p1[] = {1, 8, 987, -2, 1, 8, 987, -2};
+    int p2[] = {8, 8, 8, 2};
+    int p3[] = {8, 500, 600, 700};
+    int v = 8;
+
+    TEST_ASSERT_EACH_EQUAL_MEMORY(p0, p0, sizeof(int)*4, 1);
+    TEST_ASSERT_EACH_EQUAL_MEMORY(p0, p1, sizeof(int)*4, 2);
+    TEST_ASSERT_EACH_EQUAL_MEMORY(p0, p1, sizeof(int)*4, 1);
+    TEST_ASSERT_EACH_EQUAL_MEMORY(&v, p2, sizeof(int), 3);
+    TEST_ASSERT_EACH_EQUAL_MEMORY(&v, p3, sizeof(int), 1);
+}
+
+void testNotEqualMemoryEachEqualExpectedNull(void)
+{
+    int* p0 = NULL;
+    int p1[] = {1, 8, 987, 2};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_MEMORY(p0, p1, sizeof(int), 4);
+    VERIFY_FAILS_END
+}
+
+void testNotEqualMemoryEachEqualActualNull(void)
+{
+    int p0[] = {1, 8, 987, -2};
+    int* p1 = NULL;
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_MEMORY(p0, p1, sizeof(int), 4);
+    VERIFY_FAILS_END
+}
+
+void testNotEqualMemoryEachEqual1(void)
+{
+    int p0[] = {1, 8, 987, -2};
+    int p1[] = {9, 8, 987, -2, 1, 8, 987, -2, 1, 8, 987, -2};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_MEMORY(p0, p1, sizeof(int)*4, 3);
+    VERIFY_FAILS_END
+}
+
+void testNotEqualMemoryEachEqual2(void)
+{
+    int p0[] = {1, 8, 987, -2};
+    int p1[] = {1, 8, 987, -2, 1, 8, 987, -2, 1, 8, 987, 9};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_MEMORY(p0, p1, sizeof(int)*4, 3);
+    VERIFY_FAILS_END
+}
+
+void testNotEqualMemoryEachEqual3(void)
+{
+    int p0[] = {1, 8, 987, -2};
+    int p1[] = {1, 8, 987, -2, 1, 9, 987, -2, 1, 8, 987, -2};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_MEMORY(p0, p1, sizeof(int)*4, 3);
+    VERIFY_FAILS_END
+}
+
 void testProtection(void)
 {
     volatile int mask = 0;
@@ -3255,6 +3902,150 @@ void testNotEqualFloatArraysLengthZero(void)
 #endif
 }
 
+void testEqualFloatEachEqual(void)
+{
+#ifdef UNITY_EXCLUDE_FLOAT
+    TEST_IGNORE();
+#else
+    float p0[] = {1.0f, 1.0f, 1.0f, 1.0f};
+    float p1[] = {-0.123f, -0.123f, -0.123f, -0.123f};
+    float p2[] = {25.4f, 25.4f, 25.4f, -0.2f};
+    float p3[] = {1.0f, -23.0f, 25.0f, -0.26f};
+
+    TEST_ASSERT_EACH_EQUAL_FLOAT(1.0f, p0, 1);
+    TEST_ASSERT_EACH_EQUAL_FLOAT(1.0f, p0, 4);
+    TEST_ASSERT_EACH_EQUAL_FLOAT(-0.123f, p1, 4);
+    TEST_ASSERT_EACH_EQUAL_FLOAT(25.4f, p2, 3);
+    TEST_ASSERT_EACH_EQUAL_FLOAT(1.0f, p3, 1);
+#endif
+}
+
+void testNotEqualFloatEachEqualActualNull(void)
+{
+#ifdef UNITY_EXCLUDE_FLOAT
+    TEST_IGNORE();
+#else
+    float* p0 = NULL;
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_FLOAT(5, p0, 4);
+    VERIFY_FAILS_END
+#endif
+}
+
+void testNotEqualFloatEachEqual1(void)
+{
+#ifdef UNITY_EXCLUDE_FLOAT
+    TEST_IGNORE();
+#else
+    float p0[] = {0.253f, 8.0f, 0.253f, 0.253f};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_FLOAT(0.253f, p0, 4);
+    VERIFY_FAILS_END
+#endif
+}
+
+void testNotEqualFloatEachEqual2(void)
+{
+#ifdef UNITY_EXCLUDE_FLOAT
+    TEST_IGNORE();
+#else
+    float p0[] = {8.0f, 8.0f, 8.0f, 0.253f};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_FLOAT(8.0f, p0, 4);
+    VERIFY_FAILS_END
+#endif
+}
+
+void testNotEqualFloatEachEqual3(void)
+{
+#ifdef UNITY_EXCLUDE_FLOAT
+    TEST_IGNORE();
+#else
+    float p0[] = {1.0f, 1.0f, 1.0f, 0.253f};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_FLOAT(1.0f, p0, 4);
+    VERIFY_FAILS_END
+#endif
+}
+
+void testNotEqualFloatEachEqualNegative1(void)
+{
+#ifdef UNITY_EXCLUDE_FLOAT
+    TEST_IGNORE();
+#else
+    float p0[] = {-1.0f, -0.253f, -0.253f, -0.253f};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_FLOAT(-0.253f, p0, 4);
+    VERIFY_FAILS_END
+#endif
+}
+
+void testNotEqualFloatEachEqualNegative2(void)
+{
+#ifdef UNITY_EXCLUDE_FLOAT
+    TEST_IGNORE();
+#else
+    float p0[] = {-25.4f, -8.0f, -25.4f, -25.4f};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_FLOAT(-25.4f, p0, 4);
+    VERIFY_FAILS_END
+#endif
+}
+
+void testNotEqualFloatEachEqualNegative3(void)
+{
+#ifdef UNITY_EXCLUDE_FLOAT
+    TEST_IGNORE();
+#else
+    float p0[] = {-8.0f, -8.0f, -8.0f, -0.253f};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_FLOAT(-8.0f, p0, 4);
+    VERIFY_FAILS_END
+#endif
+}
+
+void testEqualFloatEachEqualNaN(void)
+{
+#ifdef UNITY_EXCLUDE_FLOAT
+    TEST_IGNORE();
+#else
+    float p0[] = {0.0f / f_zero, 0.0f / f_zero, 0.0f / f_zero, 0.0f / f_zero};
+
+    TEST_ASSERT_EACH_EQUAL_FLOAT(0.0f / f_zero, p0, 4);
+#endif
+}
+
+void testEqualFloatEachEqualInf(void)
+{
+#ifdef UNITY_EXCLUDE_FLOAT
+    TEST_IGNORE();
+#else
+    float p0[] = {1.0f / f_zero, 1.0f / f_zero, 25.4f, 0.253f};
+
+    TEST_ASSERT_EACH_EQUAL_FLOAT(1.0f / f_zero, p0, 2);
+#endif
+}
+
+void testNotEqualFloatEachEqualLengthZero(void)
+{
+#ifdef UNITY_EXCLUDE_FLOAT
+    TEST_IGNORE();
+#else
+    float p0[1] = {0.0f};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_FLOAT(0.0f, p0, 0);
+    VERIFY_FAILS_END
+#endif
+}
+
 #define TEST_ASSERT_EQUAL_PRINT_FLOATING(expected, actual) {            \
         startPutcharSpy(); UnityPrintFloat((actual)); endPutcharSpy();  \
         TEST_ASSERT_EQUAL_STRING((expected), getBufferPutcharSpy());    \
@@ -3953,6 +4744,150 @@ void testNotEqualDoubleArraysLengthZero(void)
 #endif
 }
 
+void testEqualDoubleEachEqual(void)
+{
+#ifdef UNITY_EXCLUDE_DOUBLE
+    TEST_IGNORE();
+#else
+    double p0[] = {1.0, 1.0, 1.0, 1.0};
+    double p1[] = {-0.123, -0.123, -0.123, -0.123};
+    double p2[] = {25.4, 25.4, 25.4, -0.2};
+    double p3[] = {1.0, -23.0, 25.0, -0.26};
+
+    TEST_ASSERT_EACH_EQUAL_DOUBLE(1.0, p0, 1);
+    TEST_ASSERT_EACH_EQUAL_DOUBLE(1.0, p0, 4);
+    TEST_ASSERT_EACH_EQUAL_DOUBLE(-0.123, p1, 4);
+    TEST_ASSERT_EACH_EQUAL_DOUBLE(25.4, p2, 3);
+    TEST_ASSERT_EACH_EQUAL_DOUBLE(1.0, p3, 1);
+#endif
+}
+
+void testNotEqualDoubleEachEqualActualNull(void)
+{
+#ifdef UNITY_EXCLUDE_DOUBLE
+    TEST_IGNORE();
+#else
+    double* p0 = NULL;
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_DOUBLE(5, p0, 4);
+    VERIFY_FAILS_END
+#endif
+}
+
+void testNotEqualDoubleEachEqual1(void)
+{
+#ifdef UNITY_EXCLUDE_DOUBLE
+    TEST_IGNORE();
+#else
+    double p0[] = {0.253, 8.0, 0.253, 0.253};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_DOUBLE(0.253, p0, 4);
+    VERIFY_FAILS_END
+#endif
+}
+
+void testNotEqualDoubleEachEqual2(void)
+{
+#ifdef UNITY_EXCLUDE_DOUBLE
+    TEST_IGNORE();
+#else
+    double p0[] = {8.0, 8.0, 8.0, 0.253};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_DOUBLE(8.0, p0, 4);
+    VERIFY_FAILS_END
+#endif
+}
+
+void testNotEqualDoubleEachEqual3(void)
+{
+#ifdef UNITY_EXCLUDE_DOUBLE
+    TEST_IGNORE();
+#else
+    double p0[] = {1.0, 1.0, 1.0, 0.253};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_DOUBLE(1.0, p0, 4);
+    VERIFY_FAILS_END
+#endif
+}
+
+void testNotEqualDoubleEachEqualNegative1(void)
+{
+#ifdef UNITY_EXCLUDE_DOUBLE
+    TEST_IGNORE();
+#else
+    double p0[] = {-1.0, -0.253, -0.253, -0.253};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_DOUBLE(-0.253, p0, 4);
+    VERIFY_FAILS_END
+#endif
+}
+
+void testNotEqualDoubleEachEqualNegative2(void)
+{
+#ifdef UNITY_EXCLUDE_DOUBLE
+    TEST_IGNORE();
+#else
+    double p0[] = {-25.4, -8.0, -25.4, -25.4};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_DOUBLE(-25.4, p0, 4);
+    VERIFY_FAILS_END
+#endif
+}
+
+void testNotEqualDoubleEachEqualNegative3(void)
+{
+#ifdef UNITY_EXCLUDE_DOUBLE
+    TEST_IGNORE();
+#else
+    double p0[] = {-8.0, -8.0, -8.0, -0.253};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_DOUBLE(-8.0, p0, 4);
+    VERIFY_FAILS_END
+#endif
+}
+
+void testEqualDoubleEachEqualNaN(void)
+{
+#ifdef UNITY_EXCLUDE_DOUBLE
+    TEST_IGNORE();
+#else
+    double p0[] = {0.0 / d_zero, 0.0 / d_zero, 0.0 / d_zero, 0.0 / d_zero};
+
+    TEST_ASSERT_EACH_EQUAL_DOUBLE(0.0 / d_zero, p0, 4);
+#endif
+}
+
+void testEqualDoubleEachEqualInf(void)
+{
+#ifdef UNITY_EXCLUDE_DOUBLE
+    TEST_IGNORE();
+#else
+    double p0[] = {1.0 / d_zero, 1.0 / d_zero, 25.4, 0.253};
+
+    TEST_ASSERT_EACH_EQUAL_DOUBLE(1.0 / d_zero, p0, 2);
+#endif
+}
+
+void testNotEqualDoubleEachEqualLengthZero(void)
+{
+#ifdef UNITY_EXCLUDE_DOUBLE
+    TEST_IGNORE();
+#else
+    double p0[1] = {0.0};
+
+    EXPECT_ABORT_BEGIN
+    TEST_ASSERT_EACH_EQUAL_DOUBLE(0.0, p0, 0);
+    VERIFY_FAILS_END
+#endif
+}
+
 void testDoublePrinting(void)
 {
 #if defined(UNITY_EXCLUDE_FLOAT_PRINT) || defined(UNITY_EXCLUDE_DOUBLE) || !defined(USING_OUTPUT_SPY)

部分文件因为文件数量过多而无法显示