From a86f2316046351fbcc4c7c36d3155230b3b5fe7a Mon Sep 17 00:00:00 2001 From: Paul Jacobson <20469645+pajacobson@users.noreply.github.com> Date: Sun, 4 Dec 2022 17:57:32 +1100 Subject: [PATCH 01/22] Update project.yml --- project.yml | 74 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 56 insertions(+), 18 deletions(-) diff --git a/project.yml b/project.yml index 10782c8..418ff15 100644 --- a/project.yml +++ b/project.yml @@ -10,14 +10,23 @@ :use_test_preprocessor: TRUE :use_auxiliary_dependencies: TRUE :build_root: build - :release_build: TRUE + :release_build: FALSE :test_file_prefix: test_ + :which_ceedling: vendor/ceedling + :ceedling_version: 0.31.1 + :default_tasks: + - test:all -:release_build: - :output: MyPicApp.out - :use_assembly: FALSE +#:test_build: +# :use_assembly: TRUE + +# :release_build: +# :output: MyApp.out +# :use_assembly: FALSE :environment: + - :mcu: 24HJ128GP202 + - :homedir: /User/directory :extension: :executable: .out @@ -31,13 +40,13 @@ :support: - test/support :include: - - "C:/ProgramFiles/Microchip/xc16/v1.61/support/PIC24H/h/" + - /Applications/microchip/xc16/v2.00/support/PIC24H/h/ :defines: # in order to add common defines: # 1) remove the trailing [] from the :common: section # 2) add entries to the :common: section (e.g. :test: has TEST defined) - :commmon: &common_defines + :common: &common_defines - __PIC24HJ128GP202__ - UNITY_INT_WIDTH=16 - CMOCK_MEM_INDEX_TYPE=uint16_t @@ -65,11 +74,22 @@ int8: INT8 bool: UINT8 +# Add -gcov to the plugins list to make sure of the gcov plugin +# You will need to have gcov and gcovr both installed to make it work. +# For more information on these options, see docs in plugins/gcov +:gcov: + :reports: + - HtmlDetailed + :gcovr: + :html_medium_threshold: 75 + :html_high_threshold: 90 + + :tools: :test_compiler: :executable: xc16-gcc :arguments: - - -mcpu=24HJ128GP202 + - -mcpu=#{ENV['MCU']} - -x c - -c - "${1}" @@ -79,26 +99,27 @@ - -Wall #- -Werror # We can't keep this on during test becuase of a CMock pointer issue # - -Os # This works only with paid XC16 compiler versions - - -mlarge-code - - -mlarge-arrays + # - -mlarge-code + # - -mlarge-arrays + - -mdfp=#{ENV['HOMEDIR']}/.mchp_packs/Microchip/dsPIC33F-GP-MC_DFP/1.3.64/xc16 :test_linker: :executable: xc16-gcc :arguments: - - -mcpu=24HJ128GP202 + - -mcpu=#{ENV['MCU']} - ${1} - - -o "./build/release/TestBuild.out" - - -Wl,-Tp24HJ128GP202.gld,-Map=./build/release/TestOutput.map,--report-mem + - -o "./build/test/TestBuild.out" + - -Wl,-Tp24HJ128GP202.gld :test_fixture: :executable: ruby :name: "Microchip simulator test fixture" - :stderr_redirect: :win #inform Ceedling what model of $stderr capture to use + :stderr_redirect: :auto #inform Ceedling what model of $stderr capture to use :arguments: - test/simulation/sim_test_fixture.rb :release_compiler: :executable: xc16-gcc :arguments: - - -mcpu=24HJ128GP202 + - -mcpu=#{ENV['MCU']} - -x c - -c - "${1}" @@ -109,15 +130,31 @@ - -Wall - -Werror # - -Os # This works only with paid XC16 compiler versions - - -mlarge-code - - -mlarge-arrays + # - -mlarge-code + # - -mlarge-arrays :release_linker: :executable: xc16-gcc :arguments: - - -mcpu=24HJ128GP202 + - -mcpu=#{ENV['MCU']} - ${1} - -o "${2}" - - -Wl,-Tp24HJ128GP202.gld,-Map=./build/release/MyPicApp.map,--report-mem + - -Wl,-Tp#{ENV['MCU']}.gld,-Map=./build/release/MyApp.map,--report-mem +#:tools: +# Ceedling defaults to using gcc for compiling, linking, etc. +# As [:tools] is blank, gcc will be used (so long as it's in your system path) +# See documentation to configure a given toolchain for use + +# LIBRARIES +# These libraries are automatically injected into the build process. Those specified as +# common will be used in all types of builds. Otherwise, libraries can be injected in just +# tests or releases. These options are MERGED with the options in supplemental yaml files. +:libraries: + :placement: :end + :flag: "-l${1}" + :path_flag: "-L ${1}" + :system: [] # for example, you might list 'm' to grab the math library + :test: [] + :release: [] :plugins: :load_paths: @@ -125,4 +162,5 @@ :enabled: - stdout_pretty_tests_report - module_generator + - raw_output_report ... From 7e6e0ee37d72fdc2bf997f843f5244c70fb7dcb2 Mon Sep 17 00:00:00 2001 From: Paul Jacobson <20469645+pajacobson@users.noreply.github.com> Date: Sun, 4 Dec 2022 17:58:43 +1100 Subject: [PATCH 02/22] Update to use mdb --- test/simulation/sim_instructions.txt | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/test/simulation/sim_instructions.txt b/test/simulation/sim_instructions.txt index 9da0d5e..0659778 100644 --- a/test/simulation/sim_instructions.txt +++ b/test/simulation/sim_instructions.txt @@ -1,6 +1,17 @@ -LD pic24super -LC build/release/TestBuild.out -IO NULL test/simulation/out.txt -RP -E -quit \ No newline at end of file +Device PIC24HJ128GP202 +Hwtool SIM + +set uart1io.output file +set uart1io.outputfile ./test/simulation/out.txt +set uart1io.uartioenabled true + + + +program ./build/test/TestBuild.out +Reset +Sleep 100 +Run + +# Wait for mdb to write results to outputfile. +Wait 500 +Quit From 3fc52755e7cdedf1a7ddd1fc3b667997324a1772 Mon Sep 17 00:00:00 2001 From: Paul Jacobson <20469645+pajacobson@users.noreply.github.com> Date: Sun, 4 Dec 2022 17:59:20 +1100 Subject: [PATCH 03/22] Remove archaic files --- rakefile.rb | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 rakefile.rb diff --git a/rakefile.rb b/rakefile.rb deleted file mode 100644 index 563d2e0..0000000 --- a/rakefile.rb +++ /dev/null @@ -1,4 +0,0 @@ -PROJECT_CEEDLING_ROOT = "vendor/ceedling" -load "#{PROJECT_CEEDLING_ROOT}/lib/rakefile.rb" - -task :default => %w[ test:all release ] From e8731013857b60207d6363402db771f576dc8371 Mon Sep 17 00:00:00 2001 From: Paul Jacobson <20469645+pajacobson@users.noreply.github.com> Date: Sun, 4 Dec 2022 18:03:38 +1100 Subject: [PATCH 04/22] Update vendor folder to Ceedling 0.31.1 2012 is soooo last decade. --- ceedling | 3 + vendor/ceedling/bin/ceedling | 350 +++ vendor/ceedling/docs/CExceptionSummary.pdf | Bin 136237 -> 0 bytes vendor/ceedling/docs/CMock Summary.pdf | Bin 148108 -> 0 bytes vendor/ceedling/docs/CeedlingPacket.pdf | Bin 207590 -> 0 bytes vendor/ceedling/docs/Unity Summary.pdf | Bin 218553 -> 0 bytes vendor/ceedling/lib/cacheinator_helper.rb | 12 - vendor/ceedling/lib/ceedling.rb | 116 +- .../lib/{ => ceedling}/build_invoker_utils.rb | 18 +- .../lib/{ => ceedling}/cacheinator.rb | 11 +- .../lib/ceedling/cacheinator_helper.rb | 35 + .../lib/{ => ceedling}/cmock_builder.rb | 0 .../lib/{ => ceedling}/configurator.rb | 201 +- .../{ => ceedling}/configurator_builder.rb | 292 ++- .../lib/ceedling/configurator_plugins.rb | 131 + .../lib/{ => ceedling}/configurator_setup.rb | 42 +- .../{ => ceedling}/configurator_validator.rb | 21 +- vendor/ceedling/lib/ceedling/constants.rb | 99 + .../ceedling/lib/{ => ceedling}/defaults.rb | 195 +- .../lib/{ => ceedling}/dependinator.rb | 55 +- .../lib/{ => ceedling}/erb_wrapper.rb | 0 .../lib/{ => ceedling}/file_finder.rb | 105 +- .../lib/{ => ceedling}/file_finder_helper.rb | 12 +- .../lib/{ => ceedling}/file_path_utils.rb | 91 +- .../lib/{ => ceedling}/file_system_utils.rb | 2 +- .../lib/{ => ceedling}/file_system_wrapper.rb | 0 .../lib/{ => ceedling}/file_wrapper.rb | 22 +- .../ceedling/lib/{ => ceedling}/flaginator.rb | 46 +- .../ceedling/lib/{ => ceedling}/generator.rb | 80 +- .../lib/{ => ceedling}/generator_helper.rb | 2 +- .../{ => ceedling}/generator_test_results.rb | 67 +- .../generator_test_results_sanity_checker.rb | 31 +- .../lib/ceedling/generator_test_runner.rb | 58 + .../ceedling/lib/{ => ceedling}/loginator.rb | 0 .../ceedling/lib/{ => ceedling}/makefile.rb | 0 .../ceedling/lib/{ => ceedling}/objects.yml | 52 +- vendor/ceedling/lib/{ => ceedling}/par_map.rb | 0 vendor/ceedling/lib/{ => ceedling}/plugin.rb | 4 +- .../lib/{ => ceedling}/plugin_builder.rb | 2 +- .../lib/{ => ceedling}/plugin_manager.rb | 42 +- .../{ => ceedling}/plugin_manager_helper.rb | 0 .../lib/{ => ceedling}/plugin_reportinator.rb | 9 +- .../plugin_reportinator_helper.rb | 7 +- .../ceedling/lib/ceedling/preprocessinator.rb | 56 + .../preprocessinator_extractor.rb | 29 +- .../ceedling/preprocessinator_file_handler.rb | 34 + .../{ => ceedling}/preprocessinator_helper.rb | 14 +- .../preprocessinator_includes_handler.rb | 189 ++ .../lib/ceedling/project_config_manager.rb | 52 + .../lib/{ => ceedling}/project_file_loader.rb | 69 +- .../ceedling/lib/{ => ceedling}/rake_utils.rb | 0 .../lib/{ => ceedling}/rake_wrapper.rb | 2 +- .../ceedling/lib/{ => ceedling}/rakefile.rb | 37 +- .../ceedling/lib/ceedling/release_invoker.rb | 98 + .../{ => ceedling}/release_invoker_helper.rb | 7 +- vendor/ceedling/lib/ceedling/reportinator.rb | 26 + .../lib/{ => ceedling}/rules_cmock.rake | 2 +- .../lib/{ => ceedling}/rules_preprocess.rake | 0 .../lib/{ => ceedling}/rules_release.rake | 42 +- .../rules_release_deep_dependencies.rake | 2 +- .../lib/{ => ceedling}/rules_tests.rake | 36 +- .../rules_tests_deep_dependencies.rake | 4 +- .../lib/{ => ceedling}/setupinator.rb | 4 +- .../lib/{ => ceedling}/stream_wrapper.rb | 10 +- .../lib/{ => ceedling}/streaminator.rb | 3 +- .../lib/{ => ceedling}/streaminator_helper.rb | 0 .../lib/{ => ceedling}/system_utils.rb | 7 +- .../lib/{ => ceedling}/system_wrapper.rb | 24 +- .../lib/{ => ceedling}/target_loader.rb | 4 +- .../lib/{ => ceedling}/task_invoker.rb | 51 +- .../lib/{ => ceedling}/tasks_base.rake | 70 +- .../lib/{ => ceedling}/tasks_filesystem.rake | 64 +- .../lib/{ => ceedling}/tasks_release.rake | 8 +- .../tasks_release_deep_dependencies.rake | 2 +- .../lib/{ => ceedling}/tasks_tests.rake | 38 +- .../tasks_tests_deep_dependencies.rake | 2 +- .../ceedling/lib/ceedling/tasks_vendor.rake | 35 + .../{ => ceedling}/test_includes_extractor.rb | 54 +- vendor/ceedling/lib/ceedling/test_invoker.rb | 165 ++ .../lib/{ => ceedling}/test_invoker_helper.rb | 8 +- .../lib/{ => ceedling}/tool_executor.rb | 75 +- .../{ => ceedling}/tool_executor_helper.rb | 95 +- .../lib/{ => ceedling}/verbosinator.rb | 0 vendor/ceedling/lib/ceedling/version.rb | 56 +- vendor/ceedling/lib/ceedling/version.rb.erb | 16 - .../lib/{ => ceedling}/yaml_wrapper.rb | 3 +- vendor/ceedling/lib/configurator_plugins.rb | 124 - vendor/ceedling/lib/constants.rb | 91 - vendor/ceedling/lib/generator_test_runner.rb | 63 - vendor/ceedling/lib/preprocessinator.rb | 43 - .../lib/preprocessinator_file_handler.rb | 21 - .../lib/preprocessinator_includes_handler.rb | 55 - vendor/ceedling/lib/project_config_manager.rb | 38 - vendor/ceedling/lib/release_invoker.rb | 58 - vendor/ceedling/lib/reportinator.rb | 9 - vendor/ceedling/lib/tasks_vendor.rake | 36 - vendor/ceedling/lib/test_invoker.rb | 97 - vendor/ceedling/plugins/beep/README.md | 22 + vendor/ceedling/plugins/beep/lib/beep.rb | 40 + vendor/ceedling/plugins/bullseye/README.md | 76 + .../ceedling/plugins/bullseye/bullseye.rake | 103 +- .../plugins/bullseye/config/defaults.yml | 4 + .../ceedling/plugins/bullseye/lib/bullseye.rb | 36 +- vendor/ceedling/plugins/bullseye/readme.txt | 0 .../ceedling/plugins/colour_report/README.md | 20 + .../colour_report/lib/colour_report.rb | 16 + .../ceedling/plugins/command_hooks/README.md | 53 + .../command_hooks/lib/command_hooks.rb | 92 + .../plugins/compile_commands_json/README.md | 29 + .../lib/compile_commands_json.rb | 35 + .../ceedling/plugins/dependencies/README.md | 254 ++ .../plugins/dependencies/config/defaults.yml | 5 + .../plugins/dependencies/dependencies.rake | 147 ++ .../plugins/dependencies/lib/dependencies.rb | 237 ++ .../plugins/fake_function_framework/README.md | 250 ++ .../plugins/fake_function_framework/Rakefile | 19 + .../examples/fff_example/project.yml | 71 + .../examples/fff_example/rakefile.rb | 7 + .../examples/fff_example/src/bar.c | 1 + .../examples/fff_example/src/bar.h | 14 + .../examples/fff_example/src/custom_types.h | 6 + .../examples/fff_example/src/display.c | 7 + .../examples/fff_example/src/display.h | 16 + .../fff_example/src/event_processor.c | 93 + .../fff_example/src/event_processor.h | 11 + .../examples/fff_example/src/foo.c | 16 + .../examples/fff_example/src/foo.h | 8 + .../examples/fff_example/src/subfolder/zzz.c | 1 + .../examples/fff_example/src/subfolder/zzz.h | 6 + .../fff_example/test/test_event_processor.c | 155 ++ .../examples/fff_example/test/test_foo.c | 47 + .../lib/fake_function_framework.rb | 87 + .../lib/fff_mock_generator.rb | 163 ++ .../spec/fff_mock_header_generator_spec.rb | 304 +++ .../spec/fff_mock_source_generator_spec.rb | 149 ++ .../spec/header_generator.rb | 51 + .../spec/spec_helper.rb | 96 + .../src/fff_unity_helper.h | 33 + vendor/ceedling/plugins/gcov/README.md | 433 ++++ .../plugins/gcov/{ => assets}/template.erb | 2 +- .../plugins/gcov/config/defaults_gcov.rb | 118 + vendor/ceedling/plugins/gcov/defaults.yml | 34 - vendor/ceedling/plugins/gcov/gcov.rake | 187 +- vendor/ceedling/plugins/gcov/gcov.rb | 128 - vendor/ceedling/plugins/gcov/lib/gcov.rb | 136 ++ .../plugins/gcov/lib/gcov_constants.rb | 48 + .../plugins/gcov/lib/gcovr_reportinator.rb | 331 +++ .../gcov/lib/reportgenerator_reportinator.rb | 195 ++ .../plugins/gcov/lib/reportinator_helper.rb | 15 + vendor/ceedling/plugins/gcov/readme.txt | 0 .../plugins/json_tests_report/README.md | 36 + .../lib/json_tests_report.rb | 83 + .../plugins/junit_tests_report/README.md | 36 + .../lib/junit_tests_report.rb | 134 ++ .../plugins/module_generator/README.md | 119 + .../module_generator/lib/module_generator.rb | 184 +- .../module_generator/module_generator.rake | 56 +- .../plugins/raw_output_report/README.md | 19 + .../lib/raw_output_report.rb | 41 + .../stdout_gtestlike_tests_report/README.md | 19 + .../assets/template.erb | 84 + .../assets/template.erb copy | 59 + .../config/stdout_gtestlike_tests_report.yml | 4 + .../lib/stdout_gtestlike_tests_report.rb | 43 + .../plugins/stdout_ide_tests_report/README.md | 18 + .../lib/stdout_ide_tests_report.rb | 16 +- .../stdout_pretty_tests_report/README.md | 20 + .../assets/template.erb | 26 +- .../lib/stdout_pretty_tests_report.rb | 6 +- vendor/ceedling/plugins/subprojects/README.md | 63 + .../plugins/subprojects/config/defaults.yml | 33 + .../plugins/subprojects/lib/subprojects.rb | 92 + .../plugins/subprojects/subprojects.rake | 78 + .../plugins/teamcity_tests_report/README.md | 18 + .../config/teamcity_tests_report.yml | 4 + .../lib/teamcity_tests_report.rb | 57 + .../plugins/warnings_report/README.md | 19 + .../warnings_report/lib/warnings_report.rb | 69 + .../warnings_report/warnings_report.rb | 71 - .../plugins/xml_tests_report/README.md | 36 + .../xml_tests_report/lib/xml_tests_report.rb | 110 + .../xml_tests_report/xml_tests_report.rb | 110 - vendor/ceedling/release/build.info | 2 - vendor/ceedling/release/version.info | 1 - .../vendor/c_exception/lib/CException.c | 15 +- .../vendor/c_exception/lib/CException.h | 35 +- .../vendor/c_exception/lib/meson.build | 11 + .../vendor/c_exception/release/build.info | 2 - .../vendor/c_exception/release/version.info | 2 - .../cmock/config/production_environment.rb | 12 +- .../vendor/cmock/config/test_environment.rb | 16 +- vendor/ceedling/vendor/cmock/lib/cmock.rb | 110 +- .../ceedling/vendor/cmock/lib/cmock_config.rb | 163 +- .../vendor/cmock/lib/cmock_file_writer.rb | 34 +- .../vendor/cmock/lib/cmock_generator.rb | 374 ++- .../cmock/lib/cmock_generator_plugin_array.rb | 42 +- .../lib/cmock_generator_plugin_callback.rb | 92 +- .../lib/cmock_generator_plugin_cexception.rb | 39 +- .../lib/cmock_generator_plugin_expect.rb | 98 +- .../cmock_generator_plugin_expect_any_args.rb | 50 + .../lib/cmock_generator_plugin_ignore.rb | 109 +- .../lib/cmock_generator_plugin_ignore_arg.rb | 42 + ...cmock_generator_plugin_ignore_stateless.rb | 85 + .../cmock_generator_plugin_return_thru_ptr.rb | 79 + .../vendor/cmock/lib/cmock_generator_utils.rb | 309 ++- .../vendor/cmock/lib/cmock_header_parser.rb | 682 ++++-- .../vendor/cmock/lib/cmock_plugin_manager.rb | 48 +- .../cmock/lib/cmock_unityhelper_parser.rb | 78 +- .../ceedling/vendor/cmock/release/build.info | 2 - .../vendor/cmock/release/version.info | 2 - vendor/ceedling/vendor/cmock/src/cmock.c | 176 +- vendor/ceedling/vendor/cmock/src/cmock.h | 39 +- .../vendor/cmock/src/cmock_internals.h | 91 + vendor/ceedling/vendor/cmock/src/meson.build | 12 + .../vendor/constructor/lib/constructor.rb | 127 - .../constructor/lib/constructor_struct.rb | 33 - .../vendor/deep_merge/lib/deep_merge.rb | 211 -- .../vendor/unity/auto/colour_prompt.rb | 163 +- .../vendor/unity/auto/colour_reporter.rb | 42 +- .../vendor/unity/auto/generate_config.yml | 36 + .../vendor/unity/auto/generate_module.rb | 433 ++-- .../vendor/unity/auto/generate_test_runner.rb | 670 ++++-- .../vendor/unity/auto/parse_output.rb | 322 +++ .../ceedling/vendor/unity/auto/run_test.erb | 37 + .../vendor/unity/auto/stylize_as_junit.rb | 251 ++ .../vendor/unity/auto/test_file_filter.rb | 20 +- .../vendor/unity/auto/type_sanitizer.rb | 6 + .../vendor/unity/auto/unity_test_summary.py | 139 ++ .../vendor/unity/auto/unity_test_summary.rb | 134 +- .../vendor/unity/auto/unity_to_junit.py | 146 ++ .../ceedling/vendor/unity/release/build.info | 2 - .../vendor/unity/release/version.info | 2 - vendor/ceedling/vendor/unity/src/meson.build | 11 + vendor/ceedling/vendor/unity/src/unity.c | 2105 +++++++++++++---- vendor/ceedling/vendor/unity/src/unity.h | 803 +++++-- .../vendor/unity/src/unity_internals.h | 1145 ++++++--- 236 files changed, 15360 insertions(+), 4841 deletions(-) create mode 100755 ceedling create mode 100755 vendor/ceedling/bin/ceedling delete mode 100644 vendor/ceedling/docs/CExceptionSummary.pdf delete mode 100644 vendor/ceedling/docs/CMock Summary.pdf delete mode 100644 vendor/ceedling/docs/CeedlingPacket.pdf delete mode 100644 vendor/ceedling/docs/Unity Summary.pdf delete mode 100644 vendor/ceedling/lib/cacheinator_helper.rb rename vendor/ceedling/lib/{ => ceedling}/build_invoker_utils.rb (62%) rename vendor/ceedling/lib/{ => ceedling}/cacheinator.rb (85%) create mode 100644 vendor/ceedling/lib/ceedling/cacheinator_helper.rb rename vendor/ceedling/lib/{ => ceedling}/cmock_builder.rb (100%) rename vendor/ceedling/lib/{ => ceedling}/configurator.rb (79%) rename vendor/ceedling/lib/{ => ceedling}/configurator_builder.rb (63%) create mode 100644 vendor/ceedling/lib/ceedling/configurator_plugins.rb rename vendor/ceedling/lib/{ => ceedling}/configurator_setup.rb (89%) rename vendor/ceedling/lib/{ => ceedling}/configurator_validator.rb (86%) create mode 100644 vendor/ceedling/lib/ceedling/constants.rb rename vendor/ceedling/lib/{ => ceedling}/defaults.rb (65%) rename vendor/ceedling/lib/{ => ceedling}/dependinator.rb (60%) rename vendor/ceedling/lib/{ => ceedling}/erb_wrapper.rb (100%) rename vendor/ceedling/lib/{ => ceedling}/file_finder.rb (64%) rename vendor/ceedling/lib/{ => ceedling}/file_finder_helper.rb (81%) rename vendor/ceedling/lib/{ => ceedling}/file_path_utils.rb (74%) rename vendor/ceedling/lib/{ => ceedling}/file_system_utils.rb (98%) rename vendor/ceedling/lib/{ => ceedling}/file_system_wrapper.rb (100%) rename vendor/ceedling/lib/{ => ceedling}/file_wrapper.rb (79%) rename vendor/ceedling/lib/{ => ceedling}/flaginator.rb (57%) rename vendor/ceedling/lib/{ => ceedling}/generator.rb (77%) rename vendor/ceedling/lib/{ => ceedling}/generator_helper.rb (98%) rename vendor/ceedling/lib/{ => ceedling}/generator_test_results.rb (61%) rename vendor/ceedling/lib/{ => ceedling}/generator_test_results_sanity_checker.rb (70%) create mode 100644 vendor/ceedling/lib/ceedling/generator_test_runner.rb rename vendor/ceedling/lib/{ => ceedling}/loginator.rb (100%) rename vendor/ceedling/lib/{ => ceedling}/makefile.rb (100%) rename vendor/ceedling/lib/{ => ceedling}/objects.yml (88%) rename vendor/ceedling/lib/{ => ceedling}/par_map.rb (100%) rename vendor/ceedling/lib/{ => ceedling}/plugin.rb (97%) rename vendor/ceedling/lib/{ => ceedling}/plugin_builder.rb (98%) rename vendor/ceedling/lib/{ => ceedling}/plugin_manager.rb (90%) rename vendor/ceedling/lib/{ => ceedling}/plugin_manager_helper.rb (100%) rename vendor/ceedling/lib/{ => ceedling}/plugin_reportinator.rb (94%) rename vendor/ceedling/lib/{ => ceedling}/plugin_reportinator_helper.rb (96%) create mode 100644 vendor/ceedling/lib/ceedling/preprocessinator.rb rename vendor/ceedling/lib/{ => ceedling}/preprocessinator_extractor.rb (52%) create mode 100644 vendor/ceedling/lib/ceedling/preprocessinator_file_handler.rb rename vendor/ceedling/lib/{ => ceedling}/preprocessinator_helper.rb (89%) create mode 100644 vendor/ceedling/lib/ceedling/preprocessinator_includes_handler.rb create mode 100644 vendor/ceedling/lib/ceedling/project_config_manager.rb rename vendor/ceedling/lib/{ => ceedling}/project_file_loader.rb (55%) rename vendor/ceedling/lib/{ => ceedling}/rake_utils.rb (100%) rename vendor/ceedling/lib/{ => ceedling}/rake_wrapper.rb (86%) rename vendor/ceedling/lib/{ => ceedling}/rakefile.rb (65%) create mode 100644 vendor/ceedling/lib/ceedling/release_invoker.rb rename vendor/ceedling/lib/{ => ceedling}/release_invoker_helper.rb (57%) create mode 100644 vendor/ceedling/lib/ceedling/reportinator.rb rename vendor/ceedling/lib/{ => ceedling}/rules_cmock.rake (74%) rename vendor/ceedling/lib/{ => ceedling}/rules_preprocess.rake (100%) rename vendor/ceedling/lib/{ => ceedling}/rules_release.rake (59%) rename vendor/ceedling/lib/{ => ceedling}/rules_release_deep_dependencies.rake (95%) rename vendor/ceedling/lib/{ => ceedling}/rules_tests.rake (63%) rename vendor/ceedling/lib/{ => ceedling}/rules_tests_deep_dependencies.rake (79%) rename vendor/ceedling/lib/{ => ceedling}/setupinator.rb (94%) rename vendor/ceedling/lib/{ => ceedling}/stream_wrapper.rb (54%) rename vendor/ceedling/lib/{ => ceedling}/streaminator.rb (97%) rename vendor/ceedling/lib/{ => ceedling}/streaminator_helper.rb (100%) rename vendor/ceedling/lib/{ => ceedling}/system_utils.rb (80%) rename vendor/ceedling/lib/{ => ceedling}/system_wrapper.rb (71%) rename vendor/ceedling/lib/{ => ceedling}/target_loader.rb (87%) rename vendor/ceedling/lib/{ => ceedling}/task_invoker.rb (53%) rename vendor/ceedling/lib/{ => ceedling}/tasks_base.rake (56%) rename vendor/ceedling/lib/{ => ceedling}/tasks_filesystem.rake (61%) rename vendor/ceedling/lib/{ => ceedling}/tasks_release.rake (77%) rename vendor/ceedling/lib/{ => ceedling}/tasks_release_deep_dependencies.rake (80%) rename vendor/ceedling/lib/{ => ceedling}/tasks_tests.rake (72%) rename vendor/ceedling/lib/{ => ceedling}/tasks_tests_deep_dependencies.rake (79%) create mode 100644 vendor/ceedling/lib/ceedling/tasks_vendor.rake rename vendor/ceedling/lib/{ => ceedling}/test_includes_extractor.rb (68%) create mode 100644 vendor/ceedling/lib/ceedling/test_invoker.rb rename vendor/ceedling/lib/{ => ceedling}/test_invoker_helper.rb (82%) rename vendor/ceedling/lib/{ => ceedling}/tool_executor.rb (84%) rename vendor/ceedling/lib/{ => ceedling}/tool_executor_helper.rb (63%) rename vendor/ceedling/lib/{ => ceedling}/verbosinator.rb (100%) delete mode 100644 vendor/ceedling/lib/ceedling/version.rb.erb rename vendor/ceedling/lib/{ => ceedling}/yaml_wrapper.rb (72%) delete mode 100644 vendor/ceedling/lib/configurator_plugins.rb delete mode 100644 vendor/ceedling/lib/constants.rb delete mode 100644 vendor/ceedling/lib/generator_test_runner.rb delete mode 100644 vendor/ceedling/lib/preprocessinator.rb delete mode 100644 vendor/ceedling/lib/preprocessinator_file_handler.rb delete mode 100644 vendor/ceedling/lib/preprocessinator_includes_handler.rb delete mode 100644 vendor/ceedling/lib/project_config_manager.rb delete mode 100644 vendor/ceedling/lib/release_invoker.rb delete mode 100644 vendor/ceedling/lib/reportinator.rb delete mode 100644 vendor/ceedling/lib/tasks_vendor.rake delete mode 100644 vendor/ceedling/lib/test_invoker.rb create mode 100644 vendor/ceedling/plugins/beep/README.md create mode 100644 vendor/ceedling/plugins/beep/lib/beep.rb create mode 100644 vendor/ceedling/plugins/bullseye/README.md delete mode 100644 vendor/ceedling/plugins/bullseye/readme.txt create mode 100644 vendor/ceedling/plugins/colour_report/README.md create mode 100644 vendor/ceedling/plugins/colour_report/lib/colour_report.rb create mode 100644 vendor/ceedling/plugins/command_hooks/README.md create mode 100644 vendor/ceedling/plugins/command_hooks/lib/command_hooks.rb create mode 100644 vendor/ceedling/plugins/compile_commands_json/README.md create mode 100644 vendor/ceedling/plugins/compile_commands_json/lib/compile_commands_json.rb create mode 100644 vendor/ceedling/plugins/dependencies/README.md create mode 100644 vendor/ceedling/plugins/dependencies/config/defaults.yml create mode 100644 vendor/ceedling/plugins/dependencies/dependencies.rake create mode 100644 vendor/ceedling/plugins/dependencies/lib/dependencies.rb create mode 100644 vendor/ceedling/plugins/fake_function_framework/README.md create mode 100644 vendor/ceedling/plugins/fake_function_framework/Rakefile create mode 100644 vendor/ceedling/plugins/fake_function_framework/examples/fff_example/project.yml create mode 100644 vendor/ceedling/plugins/fake_function_framework/examples/fff_example/rakefile.rb create mode 100644 vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/bar.c create mode 100644 vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/bar.h create mode 100644 vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/custom_types.h create mode 100644 vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/display.c create mode 100644 vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/display.h create mode 100644 vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/event_processor.c create mode 100644 vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/event_processor.h create mode 100644 vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/foo.c create mode 100644 vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/foo.h create mode 100644 vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/subfolder/zzz.c create mode 100644 vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/subfolder/zzz.h create mode 100644 vendor/ceedling/plugins/fake_function_framework/examples/fff_example/test/test_event_processor.c create mode 100644 vendor/ceedling/plugins/fake_function_framework/examples/fff_example/test/test_foo.c create mode 100644 vendor/ceedling/plugins/fake_function_framework/lib/fake_function_framework.rb create mode 100644 vendor/ceedling/plugins/fake_function_framework/lib/fff_mock_generator.rb create mode 100644 vendor/ceedling/plugins/fake_function_framework/spec/fff_mock_header_generator_spec.rb create mode 100644 vendor/ceedling/plugins/fake_function_framework/spec/fff_mock_source_generator_spec.rb create mode 100644 vendor/ceedling/plugins/fake_function_framework/spec/header_generator.rb create mode 100644 vendor/ceedling/plugins/fake_function_framework/spec/spec_helper.rb create mode 100644 vendor/ceedling/plugins/fake_function_framework/src/fff_unity_helper.h create mode 100644 vendor/ceedling/plugins/gcov/README.md rename vendor/ceedling/plugins/gcov/{ => assets}/template.erb (80%) create mode 100644 vendor/ceedling/plugins/gcov/config/defaults_gcov.rb delete mode 100644 vendor/ceedling/plugins/gcov/defaults.yml delete mode 100644 vendor/ceedling/plugins/gcov/gcov.rb create mode 100644 vendor/ceedling/plugins/gcov/lib/gcov.rb create mode 100644 vendor/ceedling/plugins/gcov/lib/gcov_constants.rb create mode 100644 vendor/ceedling/plugins/gcov/lib/gcovr_reportinator.rb create mode 100644 vendor/ceedling/plugins/gcov/lib/reportgenerator_reportinator.rb create mode 100644 vendor/ceedling/plugins/gcov/lib/reportinator_helper.rb delete mode 100644 vendor/ceedling/plugins/gcov/readme.txt create mode 100644 vendor/ceedling/plugins/json_tests_report/README.md create mode 100644 vendor/ceedling/plugins/json_tests_report/lib/json_tests_report.rb create mode 100644 vendor/ceedling/plugins/junit_tests_report/README.md create mode 100644 vendor/ceedling/plugins/junit_tests_report/lib/junit_tests_report.rb create mode 100644 vendor/ceedling/plugins/module_generator/README.md create mode 100644 vendor/ceedling/plugins/raw_output_report/README.md create mode 100644 vendor/ceedling/plugins/raw_output_report/lib/raw_output_report.rb create mode 100644 vendor/ceedling/plugins/stdout_gtestlike_tests_report/README.md create mode 100644 vendor/ceedling/plugins/stdout_gtestlike_tests_report/assets/template.erb create mode 100644 vendor/ceedling/plugins/stdout_gtestlike_tests_report/assets/template.erb copy create mode 100644 vendor/ceedling/plugins/stdout_gtestlike_tests_report/config/stdout_gtestlike_tests_report.yml create mode 100644 vendor/ceedling/plugins/stdout_gtestlike_tests_report/lib/stdout_gtestlike_tests_report.rb create mode 100644 vendor/ceedling/plugins/stdout_ide_tests_report/README.md create mode 100644 vendor/ceedling/plugins/stdout_pretty_tests_report/README.md create mode 100644 vendor/ceedling/plugins/subprojects/README.md create mode 100644 vendor/ceedling/plugins/subprojects/config/defaults.yml create mode 100644 vendor/ceedling/plugins/subprojects/lib/subprojects.rb create mode 100644 vendor/ceedling/plugins/subprojects/subprojects.rake create mode 100644 vendor/ceedling/plugins/teamcity_tests_report/README.md create mode 100644 vendor/ceedling/plugins/teamcity_tests_report/config/teamcity_tests_report.yml create mode 100644 vendor/ceedling/plugins/teamcity_tests_report/lib/teamcity_tests_report.rb create mode 100644 vendor/ceedling/plugins/warnings_report/README.md create mode 100644 vendor/ceedling/plugins/warnings_report/lib/warnings_report.rb delete mode 100644 vendor/ceedling/plugins/warnings_report/warnings_report.rb create mode 100644 vendor/ceedling/plugins/xml_tests_report/README.md create mode 100644 vendor/ceedling/plugins/xml_tests_report/lib/xml_tests_report.rb delete mode 100644 vendor/ceedling/plugins/xml_tests_report/xml_tests_report.rb delete mode 100644 vendor/ceedling/release/build.info delete mode 100644 vendor/ceedling/release/version.info create mode 100644 vendor/ceedling/vendor/c_exception/lib/meson.build delete mode 100644 vendor/ceedling/vendor/c_exception/release/build.info delete mode 100644 vendor/ceedling/vendor/c_exception/release/version.info create mode 100644 vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_expect_any_args.rb create mode 100644 vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_ignore_arg.rb create mode 100644 vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_ignore_stateless.rb create mode 100644 vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_return_thru_ptr.rb delete mode 100644 vendor/ceedling/vendor/cmock/release/build.info delete mode 100644 vendor/ceedling/vendor/cmock/release/version.info create mode 100644 vendor/ceedling/vendor/cmock/src/cmock_internals.h create mode 100644 vendor/ceedling/vendor/cmock/src/meson.build delete mode 100644 vendor/ceedling/vendor/constructor/lib/constructor.rb delete mode 100644 vendor/ceedling/vendor/constructor/lib/constructor_struct.rb delete mode 100644 vendor/ceedling/vendor/deep_merge/lib/deep_merge.rb create mode 100644 vendor/ceedling/vendor/unity/auto/generate_config.yml create mode 100644 vendor/ceedling/vendor/unity/auto/parse_output.rb create mode 100644 vendor/ceedling/vendor/unity/auto/run_test.erb create mode 100644 vendor/ceedling/vendor/unity/auto/stylize_as_junit.rb create mode 100644 vendor/ceedling/vendor/unity/auto/type_sanitizer.rb create mode 100644 vendor/ceedling/vendor/unity/auto/unity_test_summary.py create mode 100644 vendor/ceedling/vendor/unity/auto/unity_to_junit.py delete mode 100644 vendor/ceedling/vendor/unity/release/build.info delete mode 100644 vendor/ceedling/vendor/unity/release/version.info create mode 100644 vendor/ceedling/vendor/unity/src/meson.build diff --git a/ceedling b/ceedling new file mode 100755 index 0000000..5393085 --- /dev/null +++ b/ceedling @@ -0,0 +1,3 @@ +#!/bin/bash + +ruby vendor/ceedling/bin/ceedling $* diff --git a/vendor/ceedling/bin/ceedling b/vendor/ceedling/bin/ceedling new file mode 100755 index 0000000..d110f3d --- /dev/null +++ b/vendor/ceedling/bin/ceedling @@ -0,0 +1,350 @@ +#!/usr/bin/env ruby + +#these are always used +require 'rubygems' +require 'fileutils' + +# Check for the main project file (either the one defined in the ENV or the default) +main_filepath = ENV['CEEDLING_MAIN_PROJECT_FILE'] +project_found = (!main_filepath.nil? && File.exists?(main_filepath)) +if (!project_found) + main_filepath = "project.yml" + project_found = File.exists?(main_filepath) +end + +def is_windows? + return ((RbConfig::CONFIG['host_os'] =~ /mswin|mingw/) ? true : false) if defined?(RbConfig) + return ((Config::CONFIG['host_os'] =~ /mswin|mingw/) ? true : false) +end + +unless (project_found) +#===================================== We Do Not Have A Project ================================================ + + puts "Welcome to Ceedling!" + require 'thor' + + def here + File.dirname(__FILE__) + "/.." + end + + class CeedlingTasks < Thor + include Thor::Actions + + desc "new PROJECT_NAME", "create a new ceedling project" + method_option :docs, :type => :boolean, :default => false, :desc => "Add docs in project vendor directory" + method_option :local, :type => :boolean, :default => false, :desc => "Create a copy of Ceedling in the project vendor directory" + method_option :gitignore, :type => :boolean, :default => false, :desc => "Create a gitignore file for ignoring ceedling generated files" + method_option :no_configs, :type => :boolean, :default => false, :desc => "Don't install starter configuration files" + method_option :noconfigs, :type => :boolean, :default => false + + #deprecated: + method_option :no_docs, :type => :boolean, :default => false + method_option :nodocs, :type => :boolean, :default => false + method_option :as_gem, :type => :boolean, :default => false + method_option :asgem, :type => :boolean, :default => false + method_option :with_ignore, :type => :boolean, :default => false + method_option :withignore, :type => :boolean, :default => false + def new(name, silent = false) + copy_assets_and_create_structure(name, silent, false, options) + end + + desc "upgrade PROJECT_NAME", "upgrade ceedling for a project (not req'd if gem used)" + def upgrade(name, silent = false) + as_local = true + begin + require "yaml" + as_local = (YAML.load_file(File.join(name, "project.yml"))[:project][:which_ceedling] != 'gem') + rescue + raise "ERROR: Could not find valid project file '#{yaml_path}'" + end + found_docs = File.exists?( File.join(name, "docs", "CeedlingPacket.md") ) + copy_assets_and_create_structure(name, silent, true, {:upgrade => true, :no_configs => true, :local => as_local, :docs => found_docs}) + end + + no_commands do + def copy_assets_and_create_structure(name, silent=false, force=false, options = {}) + + puts "WARNING: --no_docs deprecated. It is now the default. Specify -docs if you want docs installed." if (options[:no_docs] || options[:nodocs]) + puts "WARNING: --as_gem deprecated. It is now the default. Specify -local if you want ceedling installed to this project." if (options[:as_gem] || options[:asgem]) + puts "WARNING: --with_ignore deprecated. It is now called -gitignore" if (options[:with_ignore] || options[:with_ignore]) + + use_docs = options[:docs] || false + use_configs = !(options[:no_configs] || options[:noconfigs] || false) + use_gem = !(options[:local]) + use_ignore = options[:gitignore] || false + is_upgrade = options[:upgrade] || false + + ceedling_path = File.join(name, 'vendor', 'ceedling') + source_path = File.join(name, 'src') + test_path = File.join(name, 'test') + test_support_path = File.join(name, 'test/support') + + # If it's not an upgrade, make sure we have the paths we expect + if (!is_upgrade) + [source_path, test_path, test_support_path].each do |d| + FileUtils.mkdir_p d + end + end + + # Genarate gitkeep in test support path + FileUtils.touch(File.join(test_support_path, '.gitkeep')) + + # If documentation requested, create a place to dump them and do so + doc_path = "" + if use_docs + doc_path = use_gem ? File.join(name, 'docs') : File.join(ceedling_path, 'docs') + FileUtils.mkdir_p doc_path + + in_doc_path = lambda {|f| File.join(doc_path, f)} + + # Add documentation from main projects to list + doc_files = {} + ['docs','vendor/unity/docs','vendor/cmock/docs','vendor/cexception/docs'].each do |p| + Dir[ File.expand_path(File.join(here, p, '*.md')) ].each do |f| + doc_files[ File.basename(f) ] = f unless(doc_files.include? f) + end + end + + # Add documentation from plugins to list + Dir[ File.join(here, 'plugins/**/README.md') ].each do |plugin_path| + k = "plugin_" + plugin_path.split(/\\|\//)[-2] + ".md" + doc_files[ k ] = File.expand_path(plugin_path) + end + + # Copy all documentation + doc_files.each_pair do |k, v| + copy_file(v, in_doc_path.call(k), :force => force) + end + end + + # If installed locally to project, copy ceedling, unity, cmock, & supports to vendor + unless use_gem + FileUtils.mkdir_p ceedling_path + + #copy full folders from ceedling gem into project + %w{plugins lib bin}.map do |f| + {:src => f, :dst => File.join(ceedling_path, f)} + end.each do |f| + directory(f[:src], f[:dst], :force => force) + end + + # mark ceedling as an executable + File.chmod(0755, File.join(ceedling_path, 'bin', 'ceedling')) unless is_windows? + + #copy necessary subcomponents from ceedling gem into project + sub_components = [ + {:src => 'vendor/c_exception/lib/', :dst => 'vendor/c_exception/lib'}, + {:src => 'vendor/cmock/config/', :dst => 'vendor/cmock/config'}, + {:src => 'vendor/cmock/lib/', :dst => 'vendor/cmock/lib'}, + {:src => 'vendor/cmock/src/', :dst => 'vendor/cmock/src'}, + {:src => 'vendor/diy/lib', :dst => 'vendor/diy/lib'}, + {:src => 'vendor/unity/auto/', :dst => 'vendor/unity/auto'}, + {:src => 'vendor/unity/src/', :dst => 'vendor/unity/src'}, + ] + + sub_components.each do |c| + directory(c[:src], File.join(ceedling_path, c[:dst]), :force => force) + end + end + + # We're copying in a configuration file if we haven't said not to + if (use_configs) + dst_yaml = File.join(name, 'project.yml') + src_yaml = if use_gem + File.join(here, 'assets', 'project_as_gem.yml') + else + if is_windows? + copy_file(File.join('assets', 'ceedling.cmd'), File.join(name, 'ceedling.cmd'), :force => force) + else + copy_file(File.join('assets', 'ceedling'), File.join(name, 'ceedling'), :force => force) + File.chmod(0755, File.join(name, 'ceedling')) + end + File.join(here, 'assets', 'project_with_guts.yml') + end + + # Perform the actual clone of the config file, while updating the version + File.open(dst_yaml,'w') do |dst| + require File.expand_path(File.join(File.dirname(__FILE__),"..","lib","ceedling","version.rb")) + dst << File.read(src_yaml).gsub(":ceedling_version: '?'",":ceedling_version: #{Ceedling::Version::CEEDLING}") + puts " create #{dst_yaml}" + end + end + + # Copy the gitignore file if requested + if (use_ignore) + copy_file(File.join('assets', 'default_gitignore'), File.join(name, '.gitignore'), :force => force) + end + + unless silent + puts "\n" + puts "Project '#{name}' #{force ? "upgraded" : "created"}!" + puts " - Tool documentation is located in #{doc_path}" if use_docs + puts " - Execute 'ceedling help' from #{name} to view available test & build tasks" + puts '' + end + end + end + + desc "examples", "list available example projects" + def examples() + puts "Available sample projects:" + FileUtils.cd(File.join(here, "examples")) do + Dir["*"].each {|proj| puts " #{proj}"} + end + end + + desc "example PROJ_NAME [DEST]", "new specified example project (in DEST, if specified)" + def example(proj_name, dest=nil) + if dest.nil? then dest = proj_name end + + copy_assets_and_create_structure(dest, true, false, {:local=>true, :docs=>true}) + + dest_src = File.join(dest,'src') + dest_test = File.join(dest,'test') + dest_project = File.join(dest,'project.yml') + + directory "examples/#{proj_name}/src", dest_src + directory "examples/#{proj_name}/test", dest_test + remove_file dest_project + copy_file "examples/#{proj_name}/project.yml", dest_project + + puts "\n" + puts "Example project '#{proj_name}' created!" + puts " - Tool documentation is located in vendor/ceedling/docs" + puts " - Execute 'ceedling help' to view available test & build tasks" + puts '' + end + + desc "version", "return the version of the tools installed" + def version() + require File.expand_path(File.join(File.dirname(__FILE__),"..","lib","ceedling","version.rb")) + puts " Ceedling:: #{Ceedling::Version::CEEDLING}" + puts " CMock:: #{Ceedling::Version::CMOCK}" + puts " Unity:: #{Ceedling::Version::UNITY}" + puts " CException:: #{Ceedling::Version::CEXCEPTION}" + end + end + + if (ARGV[0] =~ /^\-T$/) + puts "\n(No Project Detected, Therefore Showing Options to Create Projects)" + CeedlingTasks.tasks.each_pair do |k,v| + puts v.usage.ljust(25,' ') + v.description + end + puts "\n" + else + CeedlingTasks.source_root here + CeedlingTasks.start + end + +#===================================== We Have A Project Already ================================================ +else + require 'yaml' + require 'rbconfig' + + #determine platform + platform = begin + case(RbConfig::CONFIG['host_os']) + when /mswin|mingw|cygwin/i + :mswin + when /darwin/ + :osx + else + :linux + end + rescue + :linux + end + + #create our default meta-runner option set + options = { + :pretest => nil, + :args => [], + :add_path => [], + :path_connector => (platform == :mswin) ? ";" : ":", + :graceful_fail => false, + :which_ceedling => (Dir.exists?("vendor/ceedling") ? "vendor/ceedling" : 'gem'), + :default_tasks => [ 'test:all' ], + :list_tasks => false + } + + #guess that we need a special script file first if it exists + if (platform == :mswin) + options[:pretest] = File.exists?("#{ platform.to_s }_setup.bat") ? "#{ platform.to_s }_setup.bat" : nil + else + options[:pretest] = File.exists?("#{ platform.to_s }_setup.sh") ? "source #{ platform.to_s }_setup.sh" : nil + end + + #merge in project settings if they can be found here + yaml_options = YAML.load_file(main_filepath) + if (yaml_options[:paths]) + options[:add_path] = yaml_options[:paths][:tools] || [] + else + options[:add_path] = [] + end + options[:graceful_fail] = yaml_options[:graceful_fail] if yaml_options[:graceful_fail] + options[:which_ceedling] = yaml_options[:project][:which_ceedling] if (yaml_options[:project] && yaml_options[:project][:which_ceedling]) + options[:default_tasks] = yaml_options[:default_tasks] if yaml_options[:default_tasks] + + #sort through command line options + ARGV.each do |v| + case(v) + when /^(?:new|examples?|templates?)$/ + puts "\nOops. You called ceedling with argument '#{v}'.\n" + + " This is an operation that will create a new project... \n" + + " but it looks like you're already in a project. If you really \n" + + " want to do this, try moving to an empty folder.\n\n" + abort + when /^help$/ + options[:list_tasks] = true + when /^-T$/ + options[:list_tasks] = true + when /^--tasks$/ + options[:list_tasks] = true + when /^project:(\w+)/ + ENV['CEEDLING_USER_PROJECT_FILE'] = "#{$1}.yml" + else + options[:args].push(v) + end + end + + #add to the path + if (options[:add_path] && !options[:add_path].empty?) + path = ENV["PATH"] + options[:add_path].each do |p| + f = File.expand_path(File.dirname(__FILE__),p) + path = (f + options[:path_connector] + path) unless path.include? f + end + ENV["PATH"] = path + end + + # Load Ceedling (either through the rakefile OR directly) + if (File.exists?("rakefile.rb")) + load 'rakefile.rb' + else + if (options[:which_ceedling] == 'gem') + require 'ceedling' + else + load "#{options[:which_ceedling]}/lib/ceedling.rb" + end + Ceedling.load_project + end + + Rake.application.standard_exception_handling do + if options[:list_tasks] + # Display helpful task list when requested. This required us to dig into Rake internals a bit + Rake.application.define_singleton_method(:name=) {|n| @name = n} + Rake.application.name = 'ceedling' + Rake.application.options.show_tasks = :tasks + Rake.application.options.show_task_pattern = /^(?!.*build).*$/ + Rake.application.display_tasks_and_comments() + else + task :default => options[:default_tasks] + + # Run our Tasks! + Rake.application.collect_command_line_tasks(options[:args]) + Rake.application.top_level + end + end + true +#=================================================================================================================== +end diff --git a/vendor/ceedling/docs/CExceptionSummary.pdf b/vendor/ceedling/docs/CExceptionSummary.pdf deleted file mode 100644 index 70c28a64cfe5fe1893fd944ac56a67633c9ad415..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 136237 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 SzBX2$0OhYo2^VT)2A_#s}O z|4gYWV>3q=f;guo;G`2(A`Uy-+i?;_|EphtPcG0l$hku+9>LycVCZS3EQ6N_g_lp@ zToX6%Oq){yf$hfkZAbKH-FPy;at|6{h#WBEeTaX4rKkAHh69r$SL=_pCz8IQcRk?? z3{uA>Sn}A0^kewNC%u<_<*`CQ`wIRQRM~SXtsqXJhbkk)A1}e-F~QVQWzWD`=^Mbu zpEmzO|L=N%_nm34$*wmk7*}bML%Kg=`i_TRJIjwv)z9Q#(GY|EHIB@GiDusj;W$e< z!01U(a6pC1#`KLO8Y7Peo zA@j+HN5$Iu{KhRKDm3-2Q}ld{ZIJC5j6mZ2tzp0n94X4rF~NTF!Y<;G@zXy7&grd& z-jmDGMy71fS#x(|U*QR*XI;bC(FqZiu&sGf?Q@WVJhyj)3l+0+?PhSj#==|J7Duii zO_So`W~4hc<&$aJsymsV@zfS?G{mRaTmRnRjI1D%BO4O^bam&eYQvFo~tr$*+&`rJ?h&%mD8+`y2EaiemDKfXI(5bM_D8-JyKX~d;bGBPBmVH|DoqXp+-(gpf&^_arhexMvnXe)ESW( z7iK*!9fwRe`q!k_z)UScte$`r2Bb1YB(@66FsU)xHyQGDaUsrLIJ|n55ys0L&6ie1 z#d(3br0Z4!?DXL8kJ?OqQfkzgG;~=!+x|nRFsvS6B!uS)0exL^E9*L_TEhgXj3Z2` zf2%~59wsBv5?X>6i&Wm&U%qfT{pxs#gv!?ShwL~)*;WpQj)2LWGmDzK$@|)=JJM8rzK{2>(1k7 z!Y2pnNgYGw<@m-)+I-xgpSyFbh_jhn9{q;fB9R9YpHE)WpGCRoJe3l*$5fETYAY>U#bl*?a;f+jFi#^g|Aj%~dw-X!oTMD(`q_JBxFW}$Pnwf; zgi-FF95{rlZIdjyi%R(68E3WcBho1RTznp=7Mcl4+oAT7!Lh?=z!3Q~Ctsa6)I?C{5 z)%TZklD}R2$gIM+Y@X7@K&a)ctH6-`FzqB$u|w1*1;y>=bc$?X4+BbmKyvUvV`IFF zJq5eR;UQo1HreJD>hm3-b2!|Y#e~!wr*js;1qGoapM$)VC zwf;)=1ri@&eFd1b@kFN_7A_<35j%E}|CQQnO25Zljxp88dr~1Mk605!If<6ecWD$#OrD z8ymoFQ}T>4=*4s@QCA+c1(u{_u^%KKm2GM#a#$0wNirP5>bO7}Qaw;uOpRf>&V z?nP~@N=4y9+^JJJldpYn$RH#F(h@(a~$}4_O&+Mw2?z* zr~CZ!J4VjXgs`4sIVv>WZN^S**ol4Mk4N{tBM55L!lzk5+{fy;3DAFh0(SQkvnilz zLa{mO+Q0vZZ~7Z>e>G9~crJ802AY&96MuNmZ$+~$!bIiHB+sF%`NeY)$P98iU7z-< zB_^e#5~DMPFs;tLH{n_x_0;Qim1c1*FTu)QJXZlyy|j@?>PJ$&nvkA-H6?_(@iwt9p{K_fid&&emnJ%KLJcl{jfHsWf*`D4DakN;WFKcuR!Yg19U!0m(`#v;COM`tMKd!F-h7URBatHyWL zkTNycSLpz$^!bKr7>K>C1goUcr}=QpF4WZhKX+9TkTfkWg1YC-i4fYxa0u1?$p=#} zJ(4y}XlO}JZrc0HVx%28qsqC-&p1>^I5{oRa(CM0@lm2up#u8HTGi5kKR>T2E@}`5!9dDG<9j;!LS=Gaa^Bk0-AqU3(WTRRKfqduR?EjtUrM<>aK$K zxvGk*H)>?~@H2BC4*Ai)Fdz_IbvLwR1rG3(Ze4VF_`QXsao~3ENE&b7BX<65-qG9b zI*F{j|1;ng?3O)z!pg3911q84$rj}Q-K1@qtX^=yefZQDchk{G-;ZJm9aAqYU>bAj zvdaFEJai?o+~ptnFd&OMtvfDo3;4sPhB+CIN;U6-n&Nu}k&iG#{O|{2O#@*@L4aaV)6XEcyPmsmU zc?E#yYKwp>8snM=Swruaw@IU1Nq|GADc@@*1xMhXK9gWUbWo) zY#~P4qG_|2bI)6DiVvYbsQER`{nHLtIiNraB=YZmADktz)zQH z@*#NH(v8(zceUu0q6hGKU)DqpZbG0E2kvk#vhiVOXSG6`VDwkVHl|@wk)}l@t#rEBqNgVIX@nYW@kjvEj9tI*2`HGk0k7 z#c66*_po+fE;X1s+)T<+P`;k!*#KB%vgB*=&V4(1LysuNRL#iB7nI43$1XJOvg1L5`vbTPD7leh{}}xk3{^6EkWv zhYHYy)3?~8>m^TT?;4I78qKh6uJq_9GUx0;JZvW|!Juo8vw*l~oPjK%O30mJmCpBl z*Y(p(zS3b%9c{LfxI>}JPtUiqN4`YXG7k&ig^XuLoI#S4;X5f@GiA=<_+EHMznxp; zSTFBZlB*w`eU8`nm$Y>K9Jw{|x!|8CW`?AXX&`kqE*CC=PYHTHX_gdQ1Nc70@~m1C zDKEVgmG5D5A6bkFoiC(ei>=S&ya<9Sq7}6V$qt~=DShZDAIqS!=2O6Mf3dNUzrV+u zKFeFb(vA0NknAk8J2Q-C0R0vK+!$w!f%(IhTTv)T>=hpq*}k_kid3w-)F{upFQR+G zgPhW$ZZHz}lZ$YTbIhQ@BiLz14p}z_h6Yg6I1n2m@_p8H(ey4{{dY`tab(df!vM9& zb7X^%U8%<#(J1&!*}$~wCmIh39x8zThf$OeI^zh(q?6V<33{dY6;=r?K?gmAurtEQ zL<<)>hE`Y)r)$;2e9UU2i3uE4bVA}^4v~;&){FQ1C_si)jmwoHjVAqTF!{}E7LQ(} zK!g5ox2`+Ejo9Q%$$I15j84pBOt31*mqt`Q%auEcufUBcmvOvjXS<6uv9iLs!sJfF z1?7r zez6Ay%~4`7d-jr^%K<0JAbqpGd2>GO_|R9nt$By{GL6Si#%Mka?p&Ef#G2h^5Xnpa z|1=axL}vBZE+0=y3Dx5ahciZXCVZt{*z|U}NZiJtdIJshyIdKm$|QALUN(cr>c5+J z>dd(4_wGk6E>*vy@0EbX`wNiNHH{j9EcgNdRTfd(N@$I-3sOB|%^HD`v-QV4cdtc}2g0-pgD|EeVpgYf9Q&2QoCfNvT zJ5S%&#kRmau5hZWJQUlW&cM-n@rW`&k2OTS8>^?rQT>d&M&cp4uqzSjVKS78d20*NIkbSDRC^OKQmpa zJ9SppiqPr`kofy2P87vfN1|>(u7OTcPwjKn!O>>ssar*Zk686WWTt0E7LiJ=uhle; zr8Lpp$z@n=bOETGP=URrpa@S5*4C4DmMORL=$IM0Zj)*q>OV5x3U+Y6dq{OPvWQ4x zSfO+1pk8SumS@B>#kjGS#s>LH$?iT3euPD5lffaRuQ(EO+}nO-c~>i2rR#_8hLYzm z41X&x9r86)O)VvxAj>&fO*g9{#lS|ocx*(l%4^Ga^7N_Ij|ze`;8x69vWqpszmzo< z?u0cdqS;{82@4s5C?f>DHiPiCys&cmi$8{>4<7etVH<_(bQfe6;4TLJ4&K9@yzs-s znee8@5g|EG@b}7#S#QytJ2ABUP}EhjXr9cQ5=Q?NfMKAvYu=+O5-92SBX|)dhl6f1 z1t>ie-&E!?ceK)d?DYo{KNJNwn&#lW;B*?;yC)?oo}P28GD~OngyS}z{`SeRv26tgRlB;hf47yAs>tQ=hCg}n1;XpeAE^y8t zJ6iR%ZaYI%N)8X(^<{294kEWA>A7gHC|&y!&{JT+Dl3N122=(AwzEE;^eA^(5Z=ew zI1(v_LTCm__A+&o$(zN2`3^@0YQBn6Tw^8t=ZtKIC@N2|+h;3$`R>6-sCV=cBzPF& zw=w!CJR!4&QcS3{)Vw)2ciR3~x8$GJG&S?T82hH^OoBGd*qqqO#I|i)6WbGgv29~w z+qP}nm{?yjv9tMi&%b-Id$AXN`mO3dr%zX3bk$Q2vS+Bv2y*SUed6-J!Cr|-(Yc?+ z-W5<2rh(pu?Dw(7TSl13xIK8crp+uirJ==KV+{^Z*GFiS^UR$5souAsk{XvwoJ(Du zGKA8G30w?d4X@VyXpo8}8_P)5$GpZV)Atik5!aLok$ukn2dq6R%R3LMt4jFRrF_?{ zIHd}Ql>Ha5g&9CJ%GQN(!Q`RovWN)&y5%vTT_QaV&t|NPzWi;M%3I%$WtX5wKqZ9h z)j!6&=G@$mkBnL$|5WcQ=G*LAbxX~jN1?ZwRl+{E{}!@6kN*0%&7+!(FWTI$M>a=p ztFSu8`i>UjLv4f^{CR2Ije%)rQz&dZM}ve)o<*eRFDcP@{-icSDSa<1kp|*49BTxg zJ%ylydr`j}9|o1XFjH&Yt4{9Odb$H7HL|K)bqNTawY^?qIU{79RV?f5-`z+3UjQQ` zhLd_-BY91{Q!`8S#6zL#G+Qe!Mlf6lO&LEn%)?+;2HUWvv@Bj z1*j^;>oy6)(+9q~jI$l3f5XeB`qM4~00>co4GBN?&`^_c3zDg&d&@J35RYLnbn224 z9!;@omPKiAou_XwLl#|>qrAGRdeB2#x~{E!n`r8YOk%7H*KPWWmheIW`>1}AItGKA+qPU{<2hvBmUe_Q#!(L} z>roFu4UV=K?j*(0)P7XjI3mUascZ1ineRnIhR&Z`Se2a+R-U%I`a2^5KK^G3$NAwPk?rdYn(3W_IJT{7ykWcOC-;6_BsH zAv@DaW5WAKiDc4Ly>&ZEtFfNYgZG%OG7_#ZEl;V`$$56@F@e7Ao$H7WU~9sC@}cGg zhWt2(pWAS}q>JrExUKhaWC0j=etMbxPh;-;$WnEclb>p@TCuX8VJ-C$q4vPbEK-Yb zH{XwL;m(=qI;ngqnbS(OG@73eFyl`taqs?a<*MPPDoxTKCw*^vL9-mC?AqVX9gfZt zb(`y_MrB`TpRKB{BHy^+RE;IDVm|vb2{mn5Fxz=$?g~YMo8iMs27E^yen(p!CSLp8 zteWIOqXdajx;#JNB@IP@Dix6S4vHe9XRl&AlHA8WsEqxPkQc|Y9>pKu?`v^M1<#-cLnvx zU*+^zi4=0+y@RLf$=-k1Q6sL)VVZm0*Gl55xG&vaQ< zyV~@|+Z^OG+@+fSCS0+x9n`2;mj0~muHgegWIk<0E)i?gN2G?2fue|{c$4qL>bgt@Q~b=Z|M0+py^j6fewI#X)7 zO*#vi>7ejs-H1_Hw=bd?j)T))%A4ta1PI%KC0;dce?8Vy<|vNsl_Tx#*J*3#`u^w79)R&yCg_nr-G)wd=UvY#x zgVcnTmaT~H5S@TpTZ@FdfxCs3lFvlta<|}n@?%w=%SntuX)%b#x*H%zNWfz4O~~8T zjCq}v3ZH%F;5Ol)z{pB@Xjn5AlgzBW+DaCa=_WBX%`1Hr;1?&V46HXxU61j}lE z97-xEnmY*Zo>e9dCrf@zE#f)@NL_EAV;2G-bmoDjCP3ms! zdVyCr!)Iml5P=6~ayAy35nYIFLm0Pf-;{l^M0?hsCy%-Un`{lMQSjn;#Cot0y}+Dm zk_YO8I(YIWZ_UX&@ViQRjb-PxRSNXut@vx|H8jKKm>ONvB1jB$H{?4{3bAqdEpa*I zWJb;N4=XawB_c!MTi-9vuL)}OMox)0nP+>KKj;L z2$Jy#b>7h3vTUNe^Rr3FwThJm+)kG2K>g_r<$#=c?_ffH(~e#;ElaW|oYz%W)hm$0 zRwQ>SUVe2~ubPvL9A0T++Oo*y!FRpaL)lihW_oJv^2FlX?E=afIo@t$%IN`gXmrRT zVLJeG7oO-@9;HoRLCHz8b;seu3~TzE7L!>AgcslCocys@8k(mUquQQ&!at4)|)X$1yYo7wI0|CfJe>Cx@Puo(bSSkmEFe4 z1%IW14z9D<_iOtuU+J-kqNp zll|V=WRo9{O{4DR4*Wb9%0Kai$M7JCOeo2RuJ=3o9hvnHNL_25^$W~^|0rrJXy}I& z4pFj@0F;=&$_z2;vF5HUwruDQicIaRx`kU3iG>5IR3CrAmYi$;H)R9?hRdSk!zA|i zEaztvP@!_Mx@aVlMs|wbtFxD-0q}%34;K}h!D0NZe7etCLDj#tLEed8h4hQ?7%nW% zLP!<@UJ7Xk01?%f64q3WTzr+h?ECR;Oaj=bc1RRcmT3X>H~#;k z2mBOw$OLL-)-^pumyOgQc4F+_NyV2>g4O~*Pv>^%Nq!RUMK9;NezE+jgBXZ5A$_sp z;@}8de3B<>1}7IECC%_4svCFjrE-Z`4dkShjs2j}PzrQV;K)ML9M=~rFug0wn%`aC zuLYDf3C1&LK%d-RNU(m-eGiS;Gr0Y)C0LPf7A%iJ^>L@EnyM{}WP9O?XkC4xheonw zbHmji%?OEzkIO?F<55ASP>bmjVjo3o0i0)QzbrBp`17$@X2O|fA=W^PbyXp#pfguc zMW<;z*|PG>@=vmEI+v2IGB2Q6L+bq#xKttW`>$*r_;u3|+?j_G*wIG3?RY{YR?r?3 zdmzh&?&;Y!HDPGZxvN+HL7O9V(q;d2tI;STVMi*&Aom5yl!-T+9Kvl#(@kYtBdH%zdK|~~S|GE+a}PtyEOJ=W~PGOe`D+1#> z(@=#Xm<6pq|K+b1pW4<;g`(<0d5QXmv-|_xsnujUOeijQGrOz15w< z(%deA<#*VGyu^!;HNqAo98vtA<2tp0dh8{b?R8Qe^3;A53POP1B2X@(6CP4O@YO0^52Fr{DD$wg=U7o~Ni- z-)jrUCYO3l{5N}E<)YIiH~@_i;Y_)`z?X4`iKnnaaVR$#_%B@k0`Nhf(!F!*ztmRD z4$xFEXi8vQ=*QAR6gsksgYnfqtzGk;mID6@^qR76)NUEUrVNPGAjQxP(C65Rfx=CB7d=#@mtM$Q z`Le4h>?ewjW2_d|7yS6t>(vGr7E`#&)i#ewvG>F62XEmi>7be z_LYpnQ;UDlH|Vc^>4zDSOiG_^;4m_q(Hr0C3)d-BI?3ZAI%dh%j;l44cAbpJ8NCu1kO&(=^;N;K4v|iT(LbbwwNS9&Z?{|B|`PG zj+3_}(V8DqP$oS3abTg5UF%BU$Z@J0w2QwZO&3P&W@m7x&dUkUo4A$P#eiOcqbR6# z_qPXv&f-r4>7VqgpRXspz$$YykinG36?}p0R1fytJp{Sl9cUVw|0=(Mx^#p7QoTTr*S{ARe>NpIe#YHwcYd`ew| zNiRjR@M~77Awk!iB#bVB4U#+Wwe6sv{Km#QcC4VwEzJHWjRM|B3O< zhUJko?@Ie!WQ*Dng_DbehTg8uX-6Ms^-gMrRoRfta6W*3-oW~1!C0xS`6nHW13LoK zn$nbLuahwo0vE&)O%pA{M5J$)pA^M}k01a$I)V}g!pq?B1*$-j6Boqb$z73ncS(=Z zmpQjBgO|Xdcp~bLf%izkZr4HYdFMsSbwD~#ne&-!y0?tQF+q^#W28uB@Fg5F zj+z6fbbFxr1}}cnq*w`eXYEJAJQ|r1UULJ1m4Paw*sQT7Tv3ZHbRuTE{!^qpbRdgA zLo+Oke*!cgonItoCa&KTm&t6wADv&Ot@n9b#Hpmkj>{tUFIliLdMU096?>*A|LCe8 zf;^u@*JHVca>K!TfcbLLH-k|_`R$upBb~E_N*v;mSEQuctL$HkeJ8{#w)~^+3H?A= z{{&t@3O@43(50nx)O3AT<4nQib~ZC%5}(DzK7-l86d$d*ghuq{aQ?kYbhu?m;{?^q zb&7*F%Y|S9{j8z|v47R%5B@fj%4?TRT%9S8_^3eA(cFigUe`eP}n8-E0{Lbtx{r%kW7 z<;z`T?_Fm{Ga<33vmnR@g%cf_6;Ig?36mJ`N-d0p#TRZ~{dYlIBW#uEs@oC+S@4g0b9sr1| zucefen{7AszeS^1Hd@iEAYRq6npvu;*sm%pBK|4Z>zTxxwHWU79HSHC=Hig7yBsxo z(Y>!(o+b!F@R3+EPK^)Wg_HNuSPA+Hl|N$OR)s{YUzid40Rl$ZK^XuG1y{#9_F(I=G@&Pm6k}> zf(r{)IVYiVRAVrzR%tpwsRgypJSn19IC#+_P7)j2hHa4wQico;Rrp&9Yb1DgZ0v4P z-qm?MK!~xnaB`a(gIbPc&Oe#>BECDjIy@Z@^M`qtN^1wcG*1mJH2_)zpaj&p$TN?~E${^iFg4Nd zFNGk;__ zWtU|EmVS49q?}}yMZ&WzPcohXS}x3nEyyr^R^7qYshL3*8Y9(x>s>AWTy!k4Cg#X| z6Xx1L#YSU*;mIm?eUQJyc^r7jrx#$!&ZE7-xVJSFbB<=(_8|Z~^q{RK3>3ssbDgrH z8w(nVBew8JIr!aw^9@zbr;IdaXC50umw7o(7q$qICp{ zgBbZ%RUx=`LvMvOQ-ef1)W@smFh}*Lb*2{#uTnE%t~@SZln1aR{h}Xy$IpzbUrL&u zhL5WovMW*8VP!maZ|8U31upBw7 z$$qORM#{ISa}>@UKem87iwTH9&5jZE^C(WxZj&iaXykxj6dMD*RLZEHbDTkQim^%# zUzV(u-mTduyQ?xTGMZ{wXP=0NoVU++%X?aY_Ecx5CGsr~1#u!0JpL@fqBcA_^3jA% z2buhzM^9hSd1`gX|1VYaf3(j3OBKz|_J4wqnc4quRW!%{k1ASky~2ze;4@o0W)W0N zE^Zk(GAFw1B^uz@2hP^i|M7SCDZ!cLN#7#9oak=;F@p|{`X!Z6r?&YKP z>pke}#lY`vv$gB%KBVmZx$rwPSu_*mw$=k07v$u^Z`c0;=`yy@0N9t%bB?$MdR1m1 zUXTsz|9AoRdAr%#>-)2N`qeDV*~^Cs^K3aF_FhfvcA1wof-s%@x5Xx_d-s(O(-Z^f3x6O!BU&%~R%Q|yLkl$k@DC!D2vXEE+ z8W3^d@nP*(ZCbKw7y;{X#JzvRiQLaom&O1GrF|!09c@8t-jec>(?202z}YjsaZB_C zj|i<$1YW2YFnk@B6}WEGR5Kfn_h+e#xJlwi6_vr#k*2zB7^?3HjdQ;c8(`iUd1rxKy0(G16i{pXHVF?Cec@XDF*lo9_R;gxm%9h}EkG_A zMKlmnnhCHRmn79zOGrfmL7D6EZrWajIG%=b#w0dVSVQ4mKu{7zQ^3g2&8iFR*`gET z72yTKP1liim;R{I0{&)#0jx)kSZUL&1G&cay0R!O>1$4@Y+d7CE_w9?^lf+g?s7sOwMjo7)>)I5o>S}YWPW$~sonOK|MSu$S6zmOYPvv&kA zx<2*z{&{4b*zNv@gD~`-1yFK*+k~9tb3NNjAy{_-2PMI}0Ng%kl?2V2Uk|M~hWF%# z!{K^ziz*%a*l=dlkv+lMy8P6SpifF}IQiBVNL1o1k7aX{$@YN&pkcGvQVx z+RMmo3+T>0e5Qt_cb4URw`E+R@%^k0#jAFmqT%d&^t-lLmY)QEm`hvTS;cIuo_o4wYX&h)D_m9?VTwc25~@ongE*@m>imh7RE@pJ{TJ zW6A72#kQ4{?G~;$NmD3NBJy(2taAf6S=MHe+@FU17xj*93Mn2B&4=vDTH%na$_AFX zFt>3D%#%K*@7vlW`BSJ2dOZFJ(^NEt(jn1Ror$Qxo|%S}abhW}4q*wU+MKF8R_PwL zO!YXP4kLJ(@yce(!thSR$uLucdgEIbjCu&RBD2?6?eTrY^nq)Sy3Z($Ug8!%MOKPy z=XN)kUMc?mh2mm+FEu+FZOS&!h(>7$h-UW>3@{B>2L~S1vwq zfgqgGnSZktniTp4&zHqXCp@3|#tozVc142Bdz7*V>XWxyEp;)MUOZbw&MGT*ao?A@ zif&~k&m&lyeDO2Yx+EICcN!`ssJl0VxwY@I`U|~D(KD?t_e^&rzy5noOV!L zO1Xw9?ok#w+pkf8(0CmRm7~lkvu!#-b+Gn7QtG9)VUS;ZZX>8pOB?C0xz%HF_u09y*>n^K(}*&1Mc$#~ECDlGGXb+I zvZLu7E>KAerBO4i!s-Qai3`Z0+$SlZI3(v~9yJQbLsC13r!&wtL{Nb#h9z4xy{0%8 z>LoFiehKjgOAd)TBm?_1978e&vXe7%p~<2WrkG(Ffo)~xJznZ@3h{%~CklsP-m4@E zz5CCKxF_vxx^tnKRj$NJ6s9Hp&}L&v33Sta1$#*x@xWT&bBvxl9wIx28=FMD(^~W` zPbQ)J&&&f^r-50uyuFaza-saF9OwI6Hm2309gK7MWgz$MdJbvsRk}Baug)B@@@$ou zz}xoIkBwvW>WInG)~dGO*y<6Qm}gt(-tzK{7OQQvGd1O%;v6xZ6>0MPojN=R_Zoqx zC)H37`{zbhwU_*m`s?iqBRi&}uVIgTKU9J{n5hDduxwDwfsQ1cN`b0gG`Z?d2~|0s ztklphQu1Zh2+KHP@}kyq(`lv3STu!8Z-u>PDylZ)!uVz4PG{TODoelM{yMWuT8di2 z)Aek?0QS#2KFfhbfc?0S>fFnB{_W~3U8@?nFhRF&r_am&Bn?y;I;#)uJz*zBH?lqw6oTZNcQ5FeydxAC5= z3UnC-Rg>wL*d#-pWr#Px4!vLhi!RU|Pd?gp=?Cs;MtEw5+NLA5^%RKA{V!;$IE5>8 z+4+Oetx`-)(R|fR8c3Q1MPl_d#k0!OYP7teO4ib9R~H$BkQe-aa8XkhzupF-=@)lM z?dp^Z?4t9Z*pf}YYu{G00C{8`NJJDVy|jR{GPnMtS9$RLNj zC2+-)8Jr+4HgK%aFE-khNSh{poYVffrTo*K=O zlq|cTONV0lt!A$*#11IgdJr@vKOA*7CLE&Yfaf-3WktD}H@QR#Gj82%@O)d=oWoL2? zT8L>4RhpuZ1*0OmB#nBp%oUSNO(b16Bi&avJ522nIBRA&O7byFk^!#ksUFCmpYn9n zW-MI!*(-IZY=OR3c~%?`&U6=DuKhf->;*?I$Gq48(Z@(w`P-9Gm)INB6j2kj^$$?Z zMv9n=^KU`iRFd#Vlca728hZ>w5cX|u4fD5mWHo!CJ*!cPHaxQvKf5xNvmDV&t;$cv z9;AQG`skv9GwKP25cQFD0ZLW3S@-y?2R=)s`Scr&$cG~bEYd4mYw1Zty2=u|jtSAH zED`xDB$Q9Z^3wLCaRFXC>PffamDVis*Myx3yGZxrx>(J9CcPCD(@|Eq7ggF8$3nHT zqc_xZWiG*jM->+^elllSvJ?}57-MFl1y#BdSqjoRdD2c_T~g4uzt$Cn5B%rFyvecE z(_rnJ0>GrsjZq&N&1q#gwNxGn+yULB`#25RJ)7vN491MSRf;Kk=o~jaws{X=MM}oX z7zb(0Wg7$0;VN;c7G>lqaj(DRUL_f})=Q!cym8u<1vy#nV45v@WA3Vwv-w%F#bVwE zVV`o^tZ?t&k%|^)if)GTwkG{u(rbWTU8ni#~Wp4QeaBjy9h+cZWPFfx~T4rRZNLCT>*x zicN3ck%}*36d^BSB^Nq8M-yX+zWk7<;;5#K&-D6fPoNFtk=7zpYV+)Ua#_D|%oH*7 z;-0-XsIZdtS%uBW&)kwxrHy(C$X5A%^&L&_VeY2FU;h1=(Bpi@^%JGaPRNhQr%yf@ zAI@17_pvo4FZ`1~NaZCYdbV5{*m2;K#qH94-Xm62#$PIvsO{DyRFO-eBCD<-{xZMj zAmStb{bvbW9Dc-iY%k1KtALd;gf&Cyj+-~AQ{*$rJZ)_+u?)b_q5r&F-fC>6 zSfU1h>%L+d+}`xfEzEx-?_@~sNPdB#F!>009#xDm*(o39x)WNF7|aytg)nNBQ+&^ zHPrP98v$}EO{bO6vVil}K267Msw})9pdJ3zbeFqT*X_P<_F3#J^l=}}2ePJfgo(ZT z4~u5$#ek&;RfrR+mX;Dd`nKiT!hP&hWBG(gg^_E7XQRYV7l?|So=49>8w ztbn072G2+Q?HOf#y0o-XWwmXeMYXAI;-F>iVP#3;ZSR!#VHnX2t#s5{+U`~ThV2Z` zgnUolbduh5`B)Z}{8of51Wg9n92hze2e^(zFndrFKfTM77n} z+&5V56)A7>Na11~1Dd|NARLLnTu6=B?4G>0cikw@bi;n-~eCf z@ojn1{T&%S38r@1mR zCsZZ~PCq;{oy@Ff$1Rc1no!DR+hLJ=ykq~kzm;?>*c-wJWIRlYNdxC#R)GRD05%BE-KP}b~!*Caeb(N`OC=M+pB6Y6Ga&i#1 z=SE{%?Fi>CytmS{*ikbQxGM?7E6(FkoruJJaW^ixAm~gHBJm-!wuYrU-5PKAksTfr zTUTNJ8!-B777?o(=zA`HTi~{&LAL?*iY74M&o4-13L1HOEGK$4-=%@{_`7tGp3J^< z(MPy`FbB^X{|_nY+^9=$vGkh`WLPXq=&O`sMf~NNhrVR?pclrU0TfI`j1O2Wd^9E} z=>$hTx!or{l;VVMHGN2XA&20sp3q4detEzy#|pP6Txu6S#aEFNAGK*&g7YIwkw8wV z-5=-GAmTjs`$On&6HY0<4b^#$zbW8^o%yx}%blcgXMAJyH?Y2*+gRpwNi-7R$yXjJ zqT?%>kf?7yuLVqQ6B(!f)=*951?cMXU0#1!jtEV8zy3`S0E9}%^*qWum4f$umG4Y$a(i&k^(*0bU2q-JR)1dK-72A#-@>vPC|&uc7IoLqM;;sP(}H3rUa|MT4ZqAGC96+zHxp=1Cf# z>O*No<`~SX3#tI*-s~It;H^FO4O5 z9)pcp&oO?@zfc$~V~Dt=7dX%F_>7B~8n5A}{6^Z2fUo<^AwJc;^2y%;AzG1#oi+b# z;2VR}%0+!W!{MALJc)V@3Ot%;)I;@GnTD8}0&MRgNQ^F6`nu#^4SVkXW zbr72-6iB7qrFh-amuozc3*r&?&{CKSB^$PTmq`ERfa(UUs~)EFFZUs>jKfKt{-Y^K z>3=g7U)!Z|ViUhsW+n-8DF)?|?p=_QW`{sW(Wy z;gg3>G>VsZ8cnih8?{TER6$Hy!QpqW$Ul69y|4b+Wi66lv$_1PZomwEA@593A(V%w z&R?9wpJOMFG*~F`DFh=7#Gm@!P)%j(7JxU(_#9hoDH#6R_#-TyDR^*noE$MRnfN^Uj|j{o+uF#m4| zmY7k_%+A8ulK6k#sPf+?GchwO3lkGDqlDFOXEVU}`L~g?nV6Z0y{Q?ofB>A6Gr-Kq z7S0{?%G1M8ZTaD={pqUFK0UqajzaVYG2Rc?Adh%R5d>J2GzeHZ7?L~^JYEK}A1Gil zzc9pwD`B)ve?SD~LBO>zpl@`jU^Ok-tCzK4Tq%xCJ#}#!)$cyOU0>&3%O3B%0lTjm zPIB(JC%vLFuvYy+wf#Yhzdf)?Ej5>T)4G+rO%w3jvE0DJ-DYg7^ibMcb-@h3IXIIi z62NRC@FDV<%JK}f_Ar|?MS@^5_;CwT)u6(nMGH8EWK5{Re>CUEyLXiTbKeV`^F zr^5Ll*D#-;pK0Ah^M4wr)-{PWmU4V*W_b1K@!#)zF++SYa7(;oe}%Ost{B+%odhe2 zw1S?h)_*hstMTZqD?Q0wReLTD4HY?$I$Fwb7BR5*xJSAm{v3MUC@rY7jxNd%M6L=B znxx2@TBq;>O0q~f$7qiZ0KYJ&8@T6_#;8o34<*;cefuynnWvRy553G>i&xPm-T9f9 zF4pNGLI?x6i3w6?WOAiJqbxZp`ygRn!W&A{YHNe{_pWQw>rW;&Dw zXv5GvkY{v$&JJwq-C8s-nMxTK&~aW~B54v$IaqsWhBg*vwsmsFWe{Xda$f@}CWOW3 zZW*RV*T$qQ$(@YYxW1gu<}6F6X=o&+k$*`4yy(zgNIulF#@Z-Ouc18NHa z4l#DcgyePJuP8~db^hK^oT)eWP=2Ra`y=TBhVu~PBt)pL_wK00&Q2=z#4s<@+pDgB zJ*55Y#`5Hj9-QAR76r{mm)X4q8grBfs|n#o4La80I>~r=uj<~9Wx@k%hMWJU;|7yq z1{Nd1u`_G&eOvCOUol(tqm9^QowmRB=*g&u(ArUXu;ZN4U7s{4U!ScKIcX{A6Km0t zXr<;=Ij3+4;Q@-%r)%;>;R97)GO{zve$}lJAL+HM7w>|fmUObG^%Ld|be`7tftXf{+8F?>aP}gm5XJ`U*lUE+C*g* z5*Z(dRbQ-Mt)F$dh;QS>xra$Sv571wc|oSs?INSf`6gj=^>U|{m^>N5vF##~f99A~ zPpPn8BO(guD8e0$qfarj3q+eDFz3l|#j>d)yT&5bAm--@dh+saP#n0Hm&SFLqAiw_ zmnSeQQkeVE+x3c=K&6!HN^v92C;N#?o;xD!7Ve2p@MHs9ep1okT~G+~s)|LGL?gyZ z(Vt@)0UX?|m6d3^E4z~7C28t7q*h(gsA#V#=B<~{*YfCF-(gT#+#d$(tqJu%9K<2H zQV-jle!KmW#60}SBy(tFiBEkMWPGAmFDi3>!R9CQhW{}u8rkF=ox+0zms1?L(rOvG zQ7(G1l<#s*Y+Z^Jn9cLb(|!=N8C8-DJ^7b5FlbqXtEYg9%P5i$+-*+8^Y$(_o{+tg zN-*%}Qlg+%CF4wG8Pz$(u(lw8W#L-PKoE!r_%{Dh0PJpUAX|^Y;v=6gA&ednC>6$N z4)Qkn-v1lxYJTQ>gfGK+T+9vAt~RLte6RiphrPJtv0l4D_``JAfR%8H+RZh@ebApX&yvHKZkFf!oU$BfVNoBs(qT*sz;vE z<#L)I7>=^%&Qk+iO!rc+M)Px(T1=z8u=l+CGxkFH1?;_&-);4$tT$}6mq^;i2gv~p zT_5<^Yb#(MpRI2LZM;1IC-_(GepbFBwmAor7r~UblM}qTO4hd>$5c+YKI$GAk|=`t zPM{9hCUcVmTg zLEZW#wvI^L!QCDN>XQ&yq7@23U-397ym@2k3Q^8I(k#!;P!lXW8k=rE@?QA z6y0AsI;fTg+vu?Clu&@zoW%__(Oz@C45VwB%TF;Y&G(SfzsBLz~fJs z!c4r=;nN}ME$mCM=PAT187Z@9I_#9pF~%{QQ^HH+ODN>ZWUOIkn;JvZ8|#zB&J5!r z(UIG&-heK%G$$=YK9<@h^S$}$q7oG!KOgHm32;8tA|>=h9~QA~R9vc)Lw6VR-3vD- zfWHnawolqUHBW&I%J^qJ8EUy;Ry4(;6l8iBtzLki&A3KGCO$D^65653Ek=7J#2jge zz=lNY0)ZS)QiNYpdUM;c)0AY@P^|bw_Y5f3UPk+B+mk!xS3w=FRTqJuVDDq1 z@xb84Du)PvBNFuswYOqUNj=v!#>fc1IW|T5qXX@k3@$QqStq4eKD5Rh&uK`ZE+GMU zqZLwCklQ@rXjC?Mry;}aLjFCnQHtXnc{EPRAQs91Yev8ilo;nUQ1N}zx=X?En=kb* zBFN8PWe}t}$N_hUfGFPaY_-XIHd`TB*;25q{-yx9dmmT2-{yfLY0<|kXz6~LewkZ{ zPF!H)N&_=wo8!CVwR^<8_-1F&q%ryE|)Z}7#>7$XQr0`DI1~MFa-zF` z0IpezbeQ~Z;||>8%&JJWcJkq9<#b^&PqlQkfKav{%)o?_x-G~OQafI-A}P>vC>xsc z`Svy_M8F#z+9L6`@)$yv^3Tc1uxB^MnU!#&&Q&G>#4?=Ra)(e2hkX1jBHRYs?K`pE zkCn-6EB-6I4tgfuc=$7hYlkdGMlQQyaW_wG&UIA{!ejvZ>J^L} zOsg|y%V9o$Tw^}y>s{rPV%*Hx==qu68u+!jtFopI403eZEV%Z&HY27dcZ%YOgh9+R-lSR}F8nBCqb$ z9#A)+WLI82rA43_^H^r7DcZs+k|td$GKXl=jO#<|uM8v>KOy}9yGl`R>m*J!{WpH4 z39>%u_OdW*Q}Js3Og4$3gr`o?(H}0X;?j*TCy$7PUj~SbkCKd{?G)`K%E)OU`*mp3 zG}iyqIXbTipQr-+PXyVM=d!B)Zgt=9F4z`1nz*e=Cf*kKWVw4>bBom zL4bpQ{>bU?X6!5=%EHVqBfaZ?n@(o&Fvw=UirXm`^!_G?N%Q2MkpD?b%wy?&}i1biji)X5O^ z*yWO~%tEoxu_;NQ@7Bhep{d}*7fgTD5jP#5YnmtTM=pI|htHIkC1=I{k3V$&sCtCm zutKt1yPAdSU$O<-!O5`BEul=B~5Rv-9X&-3_yHxXb+vVMZdi~aAT6&B3ST`#6zkv>vG-D1*5^eAX!i=g5iyxQ2IRt-v| z@VyA#_xZ@Ti*%S-5l)L74=9v!cxRcKGN+WtP}c4s;D#yV@{XNL6`H(r^}NY97cy3cK{k1nwz$phf>e2n?8F=?*coU{D4? zCeK?1p>%*~8jS5U_Sna?6=Y7TO5)~V9KD^!a5CtN(Wr&=8u|t7)MJ!)$vJLQcU)s| zZ+06-TQkeWo9L{G%%&tI9O>p*zT`i%9O}-rdvE4#9ZgUr8nR@>V3H1wQZAC|{mA{@ zDse>&OXdpQMn)$N{|kU^%S#;FKUD5^P0Wl>Va<0G+9+7}M^;X{MLQIE5_f8&0DnnL z6{@hIxJS&|Wi8A3D3@^EFYjZ(7wk!1d*O4fPE#S9$NODuJ0UpLSCNonQ_%BY_S~al zr-+}smBs`IOKzJqemdR;ZihRAvulVqx&z1>KdKF&)B?AuB`65QSvS;wOlV{=5 zPi2FRJvQ>{DSql|W?QcfCt&Gfpj8JSwPI@NtW&EO7qa_8(zfXK3$WcZ!mGKH-!{`L z%p&ec>nUdq3k}IVM_xeAzzA8V<0@=B%)}sqH^pJgiR#5cMz@~oAvLi}0jmgFZ|KOF zcso&Haj{x%p9yaKs<8}))I#hEZV!}{+fb1lD0>jxdq!R`Xu`I zoK!R#OLhoO0$Tg`5I2;!J-tn?R838$OloY7$z3@xt=iF4ld{rQYdu@wNmp5J@1-Lu z5@ORfVmdVlj3?pSMA%b+uYXR9tqgOrjvIfOQ_P?*B7nConI{_FaG>c$#xEfhK%`tQ zUFslJH#cL@WJ;N-CVe0Uj$$6|L6%yRr-w5#bCYwMxr1pSFU*{b`wM)cB0WV(W|uvR9J|d|lWK{P=Sm?)Le2r}iQ|Do+@?TB zOUnw6dw~Z)*5=ee|6E!iYVWGhVtXj6D{(IRlCIKp**_~*L zN_1f6{R8(9D0?_r&Fh)FRUb2hq*sjZc18*9A;=c5<8|e9czv|b$b}4Cgcc@;o!|DS z!re6>96?~6y#qcF0*E3P@wQP~qxFn8PX4lpami3WwkTH=ZTJWjZqIOUM$3udQLbP7 z<}k>PoMk}(g9HVLsK{ljt=UhPXHqF?dE;mSc^XMFwHUM+tl!By|9Xh(HpCw)EKrW# zF+25}^^yG#!rlQ&vgX+rou1Zo_q1)>?w+=7+o-l}+vc=w+qP}n*6r{6pL6e7@7=dv z)n0pNX2i;f%#2mFD(V*z%91HiGk=aWkzTo5RM3Apk3dlj-RB7eFTWZ=3!~UUV2oWW zhmVC?FnTQ8OvaZdeAMgd9G7uLBRqW$bzW0;7J+4&^R!ybB_Ri6!fa+?$#^Z$djg<# zZ+W;0D5Iz~wQFcv?+T>A`G*98VJy>G%^eu+#&GG?*|1v%0#=Oz5ts!dSgQKto79yt zr1TZFsBkF4Z@dS77)wNsfCSRpXElfZP5Oma_FR`lB|UV)p4CL! z5@#7y+|n;aZ)>yIvTc}aeeSMXwn6E?;M<1c;``)!p?tNy(^sC9V7P@l!Y41N&ge-U zZ!$!7$B$&dxx5ph;{0CMI<3S+_nRz~N;{Kgkb5iE55r1NeaH7JK$y-`% z1kTaz!$Hn2B$wzEnz8~V9Elw?52k}c&U&8x45>2xSC|$T?1^K{#9(LN^TI@5NNA@Q z*49w7J2Q~Nfdm&i2#+N5P3xB3X(OK%CsArEw%jAxD5Drl&q{!ZzZjCWwo1bzs5ziq@r*lz9Fboc&wO5?%PiI|K-d3~#4~lz1)5RoeBIl9Z+O|J! z%@T~>9Tp2~Y90Q7>ZXMBtv6%w_0wBq83HNPyu+2~xKuF|%BQt<=vE)+yvl($vV%MP zY?PZlP@%N#R>s2N^mL|9?@yoh`SyCh-wJlOWPo~C!PV#bk`dbe_FmjX?VHn>7Le&> zNrqFzXRiVI&PuwI$^8Y7^lIU*!No=Ii60v1f7i1k++5ShD~LVmvWJffoCtpzX5j9XrGt^dH+!pdK^c0lXlJ0gRvwS z@TrL?I`T>qH!o8(l)NpqEyaYcWH^A>pAV}Ar;(OU0rAP9<>~fINxmy#KS#g{6rFq2 z*QKx242nQKd^wLxKwGu*DuCzdVp<24mSnxH0yR9?%_$#C=i{0d>b48Nvh66iv$_2t zcsED8*80^lzVwl{qRoE4IL@^pn(M2nyS&EPgnRzx`5gcX>RNDj<@IVq*6yO+1Gyg{ zMyBO1hX6vRR9h_TKin4zRL`fL4+CiG_ce?)1jHy(*p_aHefCr{b3Va>;!-2=gokJu z-8>DiZ9SEs49^hJ>Z7T9Dqj&T;>I-v>^4iJd$~omNi=v&{xufuR=bcbIBsHC14$z~ z{Uro}S-w0jpFm;Y7}QZesePO>HwS**kxb}hB7Jj^@oRK|js<@ttv@}Vq*vV(@z1*p zTm*Fd8B(x#f;Tt;3nY{}76l*t{FH^)RbrIDTvHJD^N}^bN?D7<(taMUGOo2gjb^++ zj`I_Od~lfum7+xUylH$DkzKnWnSxk%Z%tym?p$#V3R>e&N5`D!>B4lnYkLs>SyPJz z5xD-`Au`leUX%yz0~)C}Z-3*GA|J*?0OJ9LcF=)Kjy1ukAjxhEWIfE{u3#M|!9MTZ z=h0(b7z2o!O6Jfhc378K!pQ~kM2<+a#8B`ma|tCGGQx$wo~@BdQ`+^@itlGIvj9+)BB?u1{e7Jqsu0 z?KrSy`BJ>7$P)gJwJq*yNd1>*3MEqWT7Tip!UX1c>4w8{m}FXZA;yy+7(S(p{9RoF z{X8Y5HMvt;SPhl8jot;3w*j}tfmwEwv&9Qfn++`ahWpBqObOE&p0Fz|Rjz`4w7U1K zG~&kE-^<(bASN5LL@LSCLOP`1cs>)gfsLso}xU2Gh^<%(B z$xLyr*n-T`Lm-&2C}pGquMl3OApInoc9n!MxDiR{4n5zK5y{^-hPo+TzFwpxY84CH zo8OpI{WJ%=%K-&&**<){&@OllRlx(t)#Yhb(3CQ}E%l`*Y@GL0ydq)rXC zfZi7k1F>)Q-L2=sI?l5pdrh|HgV)UHO!T;_<9q){)dHf`0@{~4f3`>;X-5ZF zSIJIqQ4x(-l!rpFheDXgUbkou`as=M^$r(2|;>D3EfR$Oir|8%ha>N&eK#{vDPGCnf6)*$Dd8zP}Y8e zHdVS%Mw0OWG{)MPpopcG-b1_94GH#SYBO?M;T3Gw7JdWDXsQ!Kay|018P{Zl70OW7 zKg9?o1ZR$7Am#z;a;2$QIg8ah;|A&LhZk1z533PE8IvgtPNz(9{A{_T9}37K`!k})nzo5fhk^JT?w^+cxsMFOH6w;GIT4ArNOHYYzhuAb~S;6`cn zcUMslXlKzRa=UE7+2byj6bjeF%3kTEe+h#%?>)N=>)uXcP4wv zvvi=U6ovvp?|O~Sh)#W-iuP|@(L0_P-`#G81K+Fkt`gU%tw+U=--N%6J>>cj8f85W zpC7oio@5AXa>XB%ndxn;k13c|=#7yAVfw(+Z+5x4Y%WgG^AF8MC(!Z>ad4DICxrcs zJMe0-hQj=0C+uOej>!5H>*D;4h{g8F!sUdLb{vn5%Btk%o5=ho`_niPXywc3 zO|*+$#!~7c!k5H%&(uE+BPc|R6SMbL+%=sh^|D#j+mLet>4l&9fmiwDyUE7L@h|<*{wVO)Bx&El2Fb z^YP#c-t+BeKfB-me-Ir6$E(gVcEcwwb?u{TR(ez-46wZkxpri;g4w&=M2<%?XTh zWAY9g^y8iagyxF8&Xa*tg-hg7vboUD) ztLR;hk*XEL^-TCYP+BstKr)X|RedV@_TA zcr)?{$rdc?CUK^_X%J5E5^|hLRA7RVtONap_Txm-D2VqiRv?P=E|AH;(8SP#O#OTn zMdb)>N-cfG6O}WdJzc*7!IeE8b&spM0B;Lt<~Z!OvtkUrv~W3&j>ov}ZUR?Z&Nm%f z-X1&a?mERs?iepzQJFrmf58fLyaVBT`n&Ku``UXTj5qW5p6q#2s0P*R3|V633i&DR z$RmI3kB_Fpr$aIGNl!j?pe_i^pOfCdLM#xUD48$X{_3+wVAd^xD(X{^P|Axi6$K0( zBFM){DRQ+^?Phzu0x3w&Ps?FTLE@y$Zt`atr_5Luh4F{FsDn_*d2>YXZSlfX6{YM`pCf$-;+*_^`gqOj*{8}BW#I5yMgfsiEg{P6?r|VEk%Azm1b|#pQGnkx3lfnJ`k)jq;pV9z zs3Vy2^M6Asce*192*YUXyCvcM_ufFejci9~1{QW#4|cT>XYn@?bP%S7*(~(ZMu8Ej z)0QHPgAVD+#FQNh)AW|%{4a{dC~IJsfb1NM*7i8L#8e&enQnKHF7SfoCOKdnAoz6GG)_XLc zf1b!BvTml+AI{&-e%9-at`pNHNmXJcbKFJc0E5E}r*d~xHgHU=4)$Jp- zjRu46(9UphhM~>4ECZWO!Z1ATnU0ziv9{J~G#1uGBBiM^Y5Z{bohPz0I7embyef_B61B|6 z8_nJ1ap%*;rJ@X2CoK?_tl+s;axl8#WpJe?UoiQH*S)sia)k7Q z$u)HVy`mb~dNi0HhVzgLJeph8c||*pn+l<1?6A8aPbs}~J%SZPDRM>n*KN)e$^y^_esWex7$063~;lP@RU~{yWb? zqu76Wal9^6eYQBFf(e=tNp@c)=uw!^yBITqu5`w3!qFZGo>7n{B-&lDph!>>lqJVx zGF9swcAA5P?haK@llA7jf$5dL=>FdTEC#y&0jg4TwK4hzO<7wx2pZWN*a2)DtiM52 zeD(%LRt|XVY>arc0(v&0MgS922Rv40COq1I*#4nWGcd6Hi?%Yc$75vp&lLRp)-HG& z)bz~E|B#u!p;=69csfxw;^+J4MJa9MY%gN%U|KVc!R*aQ_ z{eREN_^&iNJZ9GaDd`_B7A6)vmhYfqR;K?sA0x{@v;61&&p0y+)B5i{p#Mk1e}HzJ zoOrbV=g_~m+EL%(UmH-gb2R!7fnU$w=%4NU|2V7vhq3%?PV#uP|DKFJ-oMNL?g|6! z>>UJ5_3Zw&4oSWL>d@1(;n50NeZ%trRwnzdSc)O}B{K z$f(ATfq<+03(|tXM6Br-7H30FLA(eoMC}r;-mQ*=d=~c$tU64&LZsrkqQUIDKy_|` zlDe6kIez-rTPifp$7j^n*F*Nok(cpd>d^~lw!70rX@f*)>OH(KSvalMvcNo{!|#!` z@TH1Sq|sSOeg|5e<+}4({uK?8ki$tM%0(SjGLb?!yQjXfWExF*vUo;O%%r?r*}`KP z@g$wr!!Z7qXJmd;n}N{*!iycgdFu{`9c02O(k>BpyOmyvWRzE)4n%;^)aZgadipqFq#%!)U{-O#>W~1~OQbpn-j1l5*^GWCiFQ2!!GrREHJm2jatN1-8+ z({vBFA+^QtP-_;D^7fmLzKxc{<$uK+<=mi`@5Cjy?y}DJ!W^|qxWX2@;`97*&?a|y zqD6S%*sK1~%1n47t>@@XM%557jl(yL_iK0~bUibrl|zmoq{OD8njgDIJD<6EuOJYq ztT9I?s>HlruY0d-C6s)_r)0|~b?y7&6})eGwa6}m@}vkXn>jMOZ^7`a94t2sSa8`i zqeA1O!WV=C8Gkby=ct;(=Z>%e;lo?P-wdmcPYxKPk2XSEkm?=y7@_mAT;WwN0dNy( zhLk7=K!JM_Ja^Z?EJbFi8Yh0&G~lR zSQIzpEC#9jr8LzOIuPFDT`ONKQJYlle8}9Q1jyH`+mcf1HAf>q4C6}*jQGWY5<|IR z>zUB;L)e1kVDrhIMG=4(^LaECDoVJ#iGdVq53M1A_-4wXB;nBHwJ@~SMOabi zi7VJkL?Q_7+pwYZqx7Q^p`IhC3@Q(*kf>ZDnDiU>n-H0tBcvNl+#DL-(a?WqF`gT_ zr=iD!8tNOlrm-EnCoSS({g^n}^*f;~vd*B1=$(bWFJfRe!-%|d(CM1eVH{m#2;vG| zQuA>E?*;$$6M|5hkcqHd5N;(tr0*PJp4)eoboh4w=r0V-8<5H-{KJd($fYaZ>EagH z7=tYUxTAslE2gUw6mT_A8g!75}AJ19$Lqu{sYh{Z$vDZ?xUi($X(p zo4Xe_xM27+coe*QJk#OyUd~&fpM$<^5!3$HM1ExBL+mmsLs{J|!58opND>W{lIvEo zFu_{14Wi?}(W<96%si?vw(86B10{4sz@K1Rk zQbs#`!t((zPpl0A;DF9907G2PXW@nD=f;+U$TRvYvXU6aM{d`?YV&}Q%uES^DAvc3 z=qv1>M9!#NvHY3M6Ir>RDBI4yfa|0cRvenZNf8Y2#F(}v?O;U zq77e%zg>Ehl(Jcx&CLy6emcytJi0N`$I(iJek#;k&^OW?y?dO)%Fd zr?6dW^rCxjeO+PLkX?!lqDPOxuqwY#XRb8|@bcbz-RVcz?~NS1pGU%sc1ZQj&MMK= zYvwu9DEgj;4uhKpKLNR1T~w z#^Dkzg5kueq(R>o7}>^&zJg8O3k^;Alfa$_Q|p$SXPyYTfw4ibp}8Tsfu>baDUUjX zeCF3m&>=v3QsGv&S-f=C;3hY9FQ~)B=AkHN8&xh!c_Ro_FBMvRNc>kg40_n0w>V4h zYCnS?(>$Fy>k!K_-}3Q!y;yPWuhnz=`mv&h^p=;`khZw@a;SXN2Ak-}c@*ED@v=(T zeJsR3FmU2?OIsM*Cksnkt1Dt_cEPCejY6^OsCCykgQ<7+Y0ECOwpHejEF6O?b@3#h zw7FIdweI?->3wffDD2j@mzRxd*eye09QMqdjGF5!N$H%Fc6>uXi(|@-(wyCHF0(7P zKH4L08dG}@_oJbiI?jZ0i~d&mp``6=KSFPzZmfF$!O5TAtMZ=`9bOWF~; zk3bvd7#a|D+mpA-GD(jI`SS%kR3M;ktbBrdCoHx)Q&VNr-5AqTi&>#=rQP>zIjerk znG9{p**Yv^;uf&*d`j6%T5|JpKwR1Q^aF}su}Zm%Y{Ct5VE^jo!_MVRITzl1S?irV ze|@7vfuX#+3~kS5Rn48t9m)BfFAp8ZI$An~Vuv@0yN;k^Gh&Xl>s{DoP-!MUxEmex zt;8(!4X^kgTE9%S$J0>2 z?+S+C&l8OEPsd~velquF!+nP0#hJrz`Ch~I{-}bd2pm>C$!k+9YyhU{BV9sJ~2By1Xu!WS=rxpQ|uu^4`^|?DQv_(Lt}YGGuEY?Vi4@& zl;cr{_3&DiAKI=1tJL-=5 zm35*GO#@R+qLRoH?WM2T36`C=48VNn!))l%$G`w?sWD8$>FtA+V_6@MQ#b|H#+2%D zXERf6{yf#!m!ILF8^AGq=Q2p1#)r$v7XoSCAJZ(Xz~}(IX#?TvgN1LchvnVf?k)W( zG-mr5>zQqdmBrfb{!ADl1ly>`lq&XJAm+QaV8%OI+3Qc&*mwUdW3YP<1rIU%g2Vmm zipFNTmi?Dm38;cJwTik{6@1cm zns;rBY11G~TT)ikT_EDSVY~9~C;GLfJx}NOwB2WFTY4VL|g9uO+#6DHRE=tG{7Y@AI=2cO!Jl;DPa`tjba5=;ZKJk+^`dl|GB<;MhFWFmZ$c_`{$ ziyVb!xn>0yq36VAaSu%o9Y&=(*}G;dz0cZrjXul1B|Vz%T3yY8e82fvIiGAOAgN?s z4=y&9*s>93L&g{U?E|M;#PUl#*Qj=JFM-c=k1%9B#laNX-Z@&(c`X_55PQrGf$SpM z8I=><6V!J@xeT$z?z9yUmQZSgrM>oeY`v@MJ$_l$-!pBnM^2``o4|f31A0=>ljLdX z%+aPgOT>-}4&nD*oc8*~9>w;@u&!}WM^jT{QjXY`+JB}7VSCnOPen7THo zlS4m3-$usvllPlWReACv%zoTxV*oQL>Mo?67}}sKoUl8POtP~b&AhOo&I&oOPe#^9 zfBI-kROL0zw$0yZx3AH>l5Ira0o>q@tdGI(4PI4V(ShL@fu^xc3aBP(UFIMx7}9$t z`&uF@`d9jtYaCT`M3#SWbZ^3E@MDEIYrK4)HiMZz z4n@tk^2?Zoc9GA4&!MWO^Hv0pbO-A#8msxAbFOvLpiac_`L~MF1H%I(f^ZQ?YP=yR zPc$E~A|dsp2JocFz#e|uoK^`XyHp&qrL1qo z2{-!U7}N57>u^0KnrF=M!CRNvAw;k%cSwY*t75JHw4JL{6TUo=FHk<0L4vBciMycb z`+_rMm4DE?w(E2o3uo{ZpzFw5J&5U$rrO&%RC{l$yN-`RKx#^RlH&{?h?Dyz1>OU5 zg@Thamx^ANXn^tu66*=mPjU+-B0oMlmLw&-u`b>s>N?^vL>4ym=+_Ia9Wk;gShfA* zaQs*`@TFlvH=v@Mq^pp*U*Zy|lPA$T$iQNvEiE0$1Qrr`pEC|$>)dfRq~ivD62=aA z-X0vtpEd4xTe2qCx=8Ymt8C!+kzax=afKwh60n1f@b|qFx!r+K*T>#KUtM73Tf$$$ zG)3^|<$Xltw@DiP%DRPC+gs_jH27L%T)b9GmvirF<9~7Z`$fGt{=Pr$yZ>eP?!Eh% zX4wK8fBdWJD<|TU>TWv#{6a3+;|lDW$xsVqfD`PwNh1w(*x~-H-@YUCS8k3EQHK~6 zdP{&r_hJ&W)9Kl`R`)BE%+Xc6U_U z(H9?pBU=nRJia3m)Hg4h1Y7mv&@k`C6YRiieJpZU84V9xy!+LFu6Qo<1@ z;c(P1Xfc`~t{p`!IM8dYMO5E{kCDEap34LoZ>4ff-FxH($ zvIOC+3Wvls#89-y!w^um(Tf>efk)Egu9cjJAB7?5{?J?Z7mGgC=n=XB&YSJ73Perz z#zRe&(8KRAnVHQZQ3Iro)>#4ITYipad-Cd0T3aizc}sh~a74SO9LSrMcnAG$v{C!N zYi?=|(rGUTd!Jd4hF#ANyt;JQ={ypiH3-v9ocs4R?eP{{Z1ioc;a5C1UxBg_ZakX` zYW1rOX(i9J%Pffu8a+7bkQB5{73|HNv&=cJ&Rh#TB5F!vpzUG@;3M)0gPbuY@(S`s z4hQn+KiK||SB_HmxM?OZN*-@gG3RRcQqE?O&fU!2f@$+one*rE0`(dg`K=Ky2#g1k?IQ<2Voel>|- zpIkhMWIz4nVWOq3Z<+{e;F}Mtx4OjfU1?m|B1c|*3DDo1W{JxSgreVJr_Y)jEE@db zcEo2a0P2eIcw*!-$)KP}KKT}u@XGQy~DI6?V=C*8pKYdJilYJ=#!?moJ<8aWU=sj~Ml@-de z&Nowa?ffO36|-xO1;WMp?og~|IDcXz9Tf)Vi8@RufB6uY|2u%Pr3e|Vtoq%*58N7N zpJZb;R7Fi16KFpo;was=_dF^Vza&1K?`CAt7!YIL8W6hg2G4+ad?)#cminDuLmTRV z2tOI02kOLk0RPTMF#Yxn(~qs1Z!u%DDV!OKMJhE17X`neK^%K~DGWV^hO zA_4c{UezO320^Z-6X(< zVPPBF3?F#jzcbp;Apta+4y?Uj)dq4x5Qvr@2WwQ&MhGMWjAwA$1LMzA-u4x0-4bXQ zoti53IlRU|5i>`8Ua)In!te)&ed8cLx$Sm6#ol#mLj;xA&u`91= zQE~lyV2xO5z448BY&BJXs()HD=IaW>2iWKfJML$6MBwO8eYehAymH~eSL$RS`iu8c zJrkbq)hFythu-HH^#3MLU%^|8zvcppPc%;y=hy|L^3h#Se&?P>SR`NA3d)|xF~aX$ zqYDX0`{!{*oK=Bmzy4+dM;ZSDmVtfMzVQU0jQjU}VT25v&DS$1h=2!2!zL^(#rEu| zB6mrdrITC4DV@TthIm9g>*19w})k)u~_YV3jTFr_9grG(EcK?+vMGMLKMFXcC z9h_`4MNqZ0YuDz<-IXmrNXf+?JEx|J^*b#0x_uq6)lAwvj(ecR<*_HvSHF@`h`yXnHf(QnmV;Q!X zdlqIfso4_5p?m`!2W-qgj$x?m-PikT^t2K_xpgKvd*0v9P{jfkQCh3g+uQy}ToK10 zC)bRcSM?%IS`Kqi95XF?5Va6?qaJdOg9WW@N zI~l6xh{?1#Z%$EfTb#@#Y46yn+vzOt`*!}Qmt#)d+*DOd9_2YnV+x?W2HN`ao_@ah zaXyFX`>+$OIoo*C!|9iL{Cjwk)mVvLP&gPoAm zNAE1fme$wvO3G1kJ(R9WkZ_5iTZ8zJjZyDRPRtGt(zC_=myJC7CafvewTycmU>q%| ztEBu9K^u#vZAoTtVaDFkRf0>Q_?;;EFM@ZWW}*i5;jIV-5X!W%ax@i5En%GagO!~o zCyU^w6R0YdJSvYeYcV?L*flR_H4|(QMrE zeooL-%lM1&DP1yOLx7n_ zfcO|bI&iiK(3Euw3y|`VcxK*kS*-U7z)D_+vcGwCL%c`cHO16Xz^sF7)y#WM)+bY+F&{e=Hs=+$)>P=d*HXU> zQRZr_W}*nh=F~L0&7Oje@g|X{3caa<-}x9bQNkCVP-@Rs%K>lvaCY?#P7++}k+3e{ zIDsz>w5zhhWeZ=qV?Ty=wC$G2<{b}?v(v{grk|Jw9QwNX$E^iL&m_hyN)Z)+gyu3s zgz*8&S;;0Ipnf|9?}!02YFZyIWBvkN3+U2tB$=$a8%~#vQ&ul6Rae)R-7Br{y`ub$ zYq0kt=O;U?sN9{KiyH8cc-rDX2%!kQ<-dU>=kwL_Nbn5&P1A(uNKugLJ8+(U9W*er ziS9hxGF-M{GGuUzzrc3)f1c8_&|H}nWt)0EU$vwSu@!#%Q8ZoD>#(pyA=tmYWUx6( zYgIG4iS-{S;odQ;NWnca2;zR^p_l!W{WAe6)purRKgm>C`77EG9ad0zL9!hmyp{yLIa*edj%-94u$qg;fGs-Ecx zhL;bwObjPZ4-;Ta6WWPZ3iX=^_LpRtk$wNq$f>056>=z*NFOE_!pp`uy4Dx z$P{5#4eSGn*I&3%YwYy|tg_|3SB2VPGf_a>XzY%;7*NVUyiz+D`k-*S{J7^Z=t|9@ zJ<9U}@cPoi<@z%EeBNwBsazGP8@kfTj2)UBek*<_c7c$(K%E<^jdnTG)1}j#Chc!E!>IFb=$02uX+#oNt3;HME-dC8z+8A zQS&JMylte8IQQ-q?e5vrID3)cIYk)i0j3$f$P~Sw?l)M$@cO#R-ypsmWqJvWFBII3 z9rxKG5AZ;B$@L20gj50ld*uQCdfZ7H8k0`YuW0tXQ%Vby-; z5U)T_ zW-a6Q_b9-glh=j5v6Y*X^Yl@@^NF^Gb&?bgu4evM%DAf>6;kO$6G5mIv_I?aD^GuF z0mH>3A@95KpPp4Ks%w?&1tiX$rbt%;OwourJGaN>Lf&F8lBri>L*6#qy_dXA3c21F z*jh~o+Qqy|N3x^lZtgcls$5+xuY8lYHd`%LqMr_AqLNBmT5RB*Uffg%4Kd_N-Uaic zCZ~mRBGV#QBL|v7no!P8)jBvuQV>%~br3X*)Nt4PS>9N|aS@y_od%-@Ew0gP#GHcX z4jzxgeL@5HFci<>(aA(3hCg{_r(K1h&76M=64c(|881?@A=eG?^AMd2sDUN^5gm&C zk=b4)(}Z}%B+8=_As#_dbBPw-0)C?MM%<`S$j}w4A3`=O9V*s&%tv=O(tWzoZbm2`$6ipGyyCFWhbz=pE60w0a*k21?U6ljZZKfc^fg> zH8`Ovg$7>bPf~yz6W2gmr8FFNW;r7JGN55Amz{#5XZAjrDASQN`%Q+BS^yv)@tW&F+3AHB({u1s7ZKyHzHM$ z!n>IWuHUi4baaLMx&?c3hy!Q!iqyK zcBSPAx%;?D4&ehP&?^impt%Qj{t#!1A{P&moCTqZ6i!zQ*9p649{yqLMk<80X@j(Z zYW||ME?6$i#6-EnM+A5VXxz9`A1j*js5FD{Z`P}>^ zU1Oxyr@SSN=M{K79@b~5poy37sG-H7HU98BQsDN3)+UI8@fX+u6*~}L;TA!`r1e3` z@3_$sGoe-^PMJVW-%jO*-|P!vrKL9>oT$IOi6VexumS@-JhJ($$LI!8^&AR2X)*zm zLGi>1rQ`Miv8Pw1pCAV2Lq zvk*eajYwKEVgv)NuD}Q8l_kSjiSs2ka8(S!P6}j56GVjy{gkluQE2|o$pPO2Z*w-6 zKh=zeJUn_)UwF=dpk2wo5Wp<_xUg8fWFI5*ZG7e8>tKgtb)_EY-(Esis2ft1eBcvY zpNF}(n_%{sbR)kWC7V>RCEBBS4Z_?>K%|3J6MecE@o14$@sw5=DHOU(Vp1A8sG#M1 zFAG#qpX{m_U}k7jeEF>8a9fIAb9r)2eGbzVdngBV@O0$v#g#l!e~m~Lsn2@Q&*C{n zn6ojlkF#ccra05?i7MDm+k^y$iP3>{2&V-3l^?6^2<-ArRi2pXNTA+-eF$Am` zRg4`bygPa0!QG>n8@WV24xPC&#GDi>%qb?OJtiZU5{B|O@F*5P7B76zFw0%WW;mjx zL$FS*7Os$pDF`s`ORsSPq~%18_172xuBMsuq*k?7jh1mN>{gH)Xq{V5UG)=Q-p4){ zKKG1YzSC!oOZh5cI#3^zkCpeK7tIcw_lXxevnm5RffTknL65iUyGw4@5PJCp4=%s2cUzRVyw4a(T2M%}V(tPc|-9 z>(bN=ZIQR;q|k5npA6R|=0Imwr?vdk8z84iw+JU7i7;PNF7fp{10-7CZeI*A8x)vU z$Y+&B+v@!YsBH(NiULp?VPs%QNf(FXY*fJ^s?n*`y)tZ(FAm|Y38x8+*RgSn+uCTJ z0@^OdJf@7rfjt)MLzo-Cxu;Dw1;prZCA)#2W_rW|&*uW&UZlH2-JSTyL&9~?;>O&m zxUHe0crR?(gp6U%OxCC)sm{Gy9{n4-HQX7G)bsx2hLypUx6nQWyh+e2+&! zYqdebFibtB*fNPcEu4-GVVb_fsHJ6c`eK5}{; znyWrtWcxI>q*|$^X^U|H$2-$tYp;`yaT@p%TbN9p*^TA7<)!92xvQyX^Hm7C$S$IU z`vM_qME#kg)LyarWBo{v#_|KT!0yXjh% zrAJVwkYR0%8y}+lQI@zbDmTzI5N*=w>A|Gr0{?-|HgD*@pozGd-{-dC62&HQqIvWbRdp6K_m6iss;;_aF45#}Lufv$oWxw~sX7J}v030B zbuG#Suu(IBu!54r?!b&XLMi;Ic@LeqR0#>EWTN!5!dO)gUz^)WsZ!Z+>1LG>Dw=y6 znIgn@iKCH+24*@(J83SIvSi=ysM_@j;*_6_iz}`;AsR-ofu98C9UrGTWxG(dOHOi37@W(9}e)IU-l`JAX6B`Y3+0>EuVkJ+BA7b+lbPofR+u16?L-<#V<-c#{Ecv zpWsIMdykhOZuv&|1c>AFg{g&o>`5V$1IU`LG!4}D^-}rstBawcFXIfi*9))ST028ce2AKA2EkDz#_x{v0UXw3p5}1$D#l^V^#rnjq!o z0wr?zS>9K6dMm66RDqr=)0<#3)Bq$vOy34~;+ZCHcCSj2!^G2Or^<94Qs&lH%vdP> zXI=_MDfixVKsCTz1DiO*;x-YJxDy#B`t7+#>dIQxd3WDfU8its82eaMC5Emr(2Fmz9R9H=FR(neo9ke zRS(lgpF@#WC_~*5?>tq(vP{^>?#5ujiwx$lF-7(4@SGpHkJ2*_KJ7Lix?S(aqFsdA zdg+9W;5f3n&2Jpb6|Di2Oi}5vnk|S|Wb0II;ApYcf_c!w0Bz%EI`JLc1h$fGS+rO< z8HR&?;HOK3p%U{qZfl-8<5M&SAI)1o@lfeaSu3lM1g#4OFm!?eCUxctB z&RKXHYGQoMc9KjmJs#uzOcrbN$z0xN&mqDhOUk>k!6P2Jhs=iSuxJQ^2I`2CDHu0*U@*|L7qn5kaDis zA<$a}1Zx5u2%oO3qqE4%q(fGQ$gzaT@jFLxNxo^jpjIhDL+$rH?!r+7c3O&paUxkv zi}E~`#xyJnTCb(`?}a@1ThZTR-gwukx;)&DHz)0{ z&Se`il!OfFFmMpIS`<{SrtQl^WB$P@Q;(OSffKQ7lov@-t(7k9w$-5jdCiF8 z$J#7XgfDB2Q+AvwKNVNc%h7iv4qq7k=ia395iR8m>0SvDr+EdJ9A4w*eb!5Xf&yzE zjH|=1%j)oPKg~_fSc&ez1BtXlKtZ zVd$8wA0cwVEPcO#=7MetkqHsO6s)uHKe6$r6N+}c`D8rZE<-6(IGOSh_r6a23BQ^E zvGAnS&55)?LJ4BdVD`7{j|$84df-QMol>R>j<3#$kTFH3}@Ex2p=Zpsz`d}bb?IxV{;DijT7~w2-fs)xdJ5evYxPIMb*J=x7 z4V$?Ec0^U@F-rUk7?RoRpUn?#>b?7)eQme2gj>#I7T>wWMXQhAl)wC!+vZ-_f7k2N z)~_7xbOr>FxY;{ru6^T)zrT<_d{-h)Z@jQsP9*B$m*y9aYdrI_F9&||^NZ$r%UrQq ztURZ7Kf+FJrI!~Z!lx%Ie9}mKaQKUTd`04QgTrSO2hY~2uwSPxQJoVV6eq8C(x|$2 zQFXsWVTy%r5K9zQJ4XF25+uoDgbIW-LKV#SAHs<8AwH@5kTgNYG>s)CB~@ctRnW*t zb6S-w-+(~*>8EN$)0oZF;Ww~ysnma`4nvb3P{ye@$f_zU zgTa8_;fyjRN_@&9+lMhc8B9rOl)_AnOy{@~C)oq`& z@b})-Int?B+_WwAu2PYKYUCb~(f|_1Km-+;%+NELSqb0JX0@q$=+Fp?KnrWdB!ZFqExm4e0Wo-_ zmL+HI`UXqTALSQ+QxY!uRyU3_YQZdB0muoH=arSRN`++=bYvx2?~@nWmo(_Z0VYSi z;ebPq`oaM!#|+_sU5+{IK-7AunmP3N^n9!OL=JVnsG&#Sr$4F}hV?X~Z`XJ0g$4S< z`XhQlFY<1B6$16J{y)X9MJBHlb6C?ajP%HT@=;mH$nA2sEF6}P$c!(_x!CJ`>tplx zV%HZKBo#pyR)NRy|A}Ttc4T4R*%kjWb(mCjO5@+bryRGQxl^4pK0}am;mtaoOkg=> z@G9%GR*z-_}?hCMsBAxY5+yOg7bQCwu5l>svK?6S#E3H0H1&WGRPFP}=5~xeF zn)!~K!r205s4I=R!jB?w6%Kb);0he1BkCJalW(**BL%KL2Ww7xSK%`!L%O!IB|W}! zg4osBmEsz8V}sXiX*NcRviKTS8A=_0xGnS2fl;>+==rcBvYA_FEWe zd{w$4>@8YL%f>*h9@}mO8)Ppk zY4`t1I5QZGDySG$_%W)WV%#n->>6P{xLl_49H&lkCjSKX%CRmklyO?H3bcTFM!5B_ z)ex?Pwm=S4e!fAxTV8YeuxME&JGS^(Y_<`>)rTs2mL->Gj@w z=zZzez3+RE(@(q>ix+~qHZv(BG$$Ncf8@VU*D0w)uvnE&bOV6v`!!^H$LGnn=3C~}>fAt-$ z`GWl0^JONEZ>l|$((`GjXKwmp&lSFxy)R|n@xGJ!$oo;oTF{t9!U4Y=tx~ZFXu4jG z6?AB_ia|I_NoW!A`Uv%T;b!!zGA@%Y%6L7Qv==%Qj2*^JpNARrdO|Xp(xg6fKIoV) zT@{T)9evPEomuKlW32@0qQr}7Z8zv$wbCVMuW$AT8N zJm>sza^t|)rZAYqysAxXGZiKcoeIR;Gx=l&5_^%g4c-~_ zQ+kZ{rRPC{kGH3X4rk`Y+(Vy>YtO9P5H63$>msX!b@P+OrSa3h6V>9G&0jZcK7BLj z-0(-ke}(igos`n&mA1_e>evE@F=a;m7DgS#jFz%W=V<2@&U<0k9cDUbH0r>b8RaO} zEFj|}7-&LcMSNXj4u_pG7Ij369F8b<=#Ld!=^kn{7$^()^$vreu7}w%%WjWI8A*`@ z3Fz!8I~E6-Q%`XgfoD|3inP6qYXc-GR?29E{}aa1GFIj+;!En1Rg@jCrCb^M)CE+upl$br4U;RgsC z-aQa_4GQRUZUsk1&=)41JfwQpuSg z1QIgswZdtDu8qr`S3vGGlK|PPRNv#+ zt$Wn?s3cxa*XuUX8+GCYy(LKmS5j;6Ht|1?VNk;h-04OUG{V$kzP|qE`be=-%!=(z z{10cC%@Bs?&(z?EVv_46&yjjz)kEeRUzi#i;65+@gfn3^+bdxf_g2y(9dd3Ba+1+f zNqr2FL+`329ud*ECo2Vgau+BI6ksxsM>TNWoLzNz!N)MrH=Lk)dTstnd{lTmf9>y| z`*QzfH~sL^f#<%u=`sjtEAwyXU(YXxdqWeQ@XNhZH|@?plYeRepJve(dcos2ay=xt zM=^z66~>=cTycO@;Z^TwtWQ_1^{xr530|G-sk$quTkn0k!qt6ph-f>TVm+uBi0Uy1lY$kX}9@b9IVpPB_a) zjqJCsbGS_*QLrf>Ink-|?ga}%7XmuPtY4rCdxc87L)`LmHNtSX*>W~ zcLdU**PJ?gy&{Exeqv+9XecrUOBg1UBW<8oRp;CbcLly3p_BP83O#EbP>lodhbvX> z0|lFaj{YQ=IHzvt5a@GJ0P0ZskNy9(^>?pSuWG43uXy=AQ?8p`+s>}auk8ziK93Hs z5mxYATmO|0AF)n08XxTIxTnpDmFF_~a;$uk)G?;?mv}i^i>ouaDM}sJCtixZR4Gg? zd8Cqg!=9=OOW^2dh$rIsYL((k$daq*Rcv*5b!1)iiuh)_DROTmzT%BPop`2lxWuK6 zTt{yyxvuoSl3nyC?BS9pE1#=;H}m((;Ytg>prwB1NMd!X8><>K7nWRFsq zz$QmYJQ*Mm>a23i%_Z!Z!Ybk=B~eC;AkdZUVG*V)FWaRmVLg1%P^7l&x^==<9d|e( zfjz;xL3*2Ft4YF*n88X4@kQ_8M&JI9f;qQ!Mm>?Al-UdrVu8>!WU$3Q;b#(xpO_YkU2|1C+Dns>bImI7wYxCQqrK+oucAghYiVzVaa2 zC*a)xhI~~z1qr^%2Q%wgPMkWjen6+nho@A}q3VnmrmA3NbqIftR2fUx(&`YRs%S+m ziIrp`HMKDN1D-f?g$@Wd3~t9z@p>Hmx0&b-8Z&8^f>i) zZ(ez3tTSkM;iVnd!g_fntor$N-v!O)N7rr`OysY+p~KAXq`QBxaR)x!r=)NAkD>-x zdo-J;_#Agt;QwK4%!GeS67dCuCN+c3UIv-3FCEM|O}P$mqQz`C*ZQ!G=;XPf3)=1FtQ=BD7s5N3heaDAX*ws*E~ zw!gFHg4zq}E~vktVg4wqU^10CO@XqQDbhHmEYrBkvC4T<$-TOJ)7vt;(}$DKm%p4k z+<3CF=v@8i0RE{e@FaZ`mivu##CoP!>hG(D=j6(8AQU=S411bV=ew^6Zjeo8YmwP( zO_|HBV#1&%+87-oM4PM@Vo7dQqe>`R2X_K)%%w3!O52~avk&YvVt>;9fn9(Dz^13e zdqOFR``DpFct;g|uIleq!$7IlY%Rt>Gnrd7AsW^PvCLb>X|!o^H$LB2ez@g!XL*+r#Z*y&U&T|-Gm=S(I{6^2?; zX5+}ziAa}0(O7A&B_?x4s#F4MwOPx`;|`!#eOk+5zM%S4acP0E0Q3X)ySSXX*mR*~ znY1{?pD`EwgX` zb-gc~=8!)QG&!fzsIlf8+RXwEP>D|eUVC?!pt8aAs|>& zJ-ykQ1Qj-wUgdUME^QQa*AVdk0}pY{HI~IG zK4?proZ)4&p93eD9(ta$g%2%A)=kqTB+c~v3$sfaN1Z-(mIV~eR_BTf;E#w|H4Put z?8U5B(Q6No4A|ZBbX^8x9f*{usWRIgtV?PewbQlhZDKqYFRh8yl(xoNOLvv(%1X1P ztUa^Fbd~MC(&tM5mC!a>3wlQ=m3(rvT-7^5@#~di5D7u2SUhPlltVW7$5VXPkoi~@ z9MlXaD`i|lkPHUBV$SN}P9D)`@LyCAD-?Xl0;;1byY*UrF|XZUP)za>D-)aRr3~%K z?9AjcM>Aq398niDqAq4cUCc<-;efN+O8Bd(w95(GBy{K@{$!^wed-&zgUcD}B5_Y{ zSaWfJ9GtD>ye#OHYG?ra(>8Pc-cfoGrG%U`+M{wzW?EakG+ttjz(`?Fn9E?HFv?QA zk|a%t_}Vsc5~cb_!2Seph+e*B>DSf>?iK;MlYlm&px5C`4dt}D|3(ao!dvucZF|Z! z^TaRz@Np*6%H1I9W|#Pir*Bz){ePVUHHD@$9-k2I9eV$le|+%1A9Q}s92?G!$LmX0 z4eg!r%T?3X?0c8Rp|JoQI3NxDl30$+=RE_I#yd>a2=~itEqBrBv$uN$La7%Svcr9;63Ee z$zSO-kNWobpV92s9?(IIeMI}H?lIRRZq5C=t+uU>``lY)%|)&yo;BinW1p;<@1Eyr zmzQcU(rM1ub?VPIe$U$J(kOB}{`z#DW|meHk?X|Ku1RF7RTI~i>5}@SE9usN#gsEp zOCOOnBMQ|ZvC0vn+wU%S3vQi-zhc0ug&k5KwsKu+GmM8Xz4Q`S5vrQhfKo&>G(cdu z57?}FbPjt$f$-q)CdKa7X(M`_4%`q7zb=hd%K;c4$#4hsunlY$fkMu3+Cx2m&bSr# zR`*G_=suotDXw-`&UMnIiMYC5J@_(2bPcjk_DAHqW$tkXeJH<$+6T*NN-2>vZdk zSD3CcU**3dupxLwWNrF-@fQ8&;Em}UGdES=uG?n1!+D2yoB!Uxoyoh>cV>3$A2U2= zdd$B&@M!R{;z!a0x&i&u#zFs6nO|hS(tl+-Q~XtA+Vb?$%<}4+4C3g(iqOjNWtHMm z-BSH>gV1J}9-fkHON*U>dFh!Mp$0Y^W`ttm7}FTY z7=oh7UYOZ{L$5PYlRjGt6EAdV&D`YyfX_i+WmvM=fKp)y2K7*{!Z-&nOg+(JBRKs< z0cSE@7DzhG_JE@_1T#dodUPN=INUQ3Fc~9*!z-1dj9wSPSBX)0`vn62U@&Ab8dU{Q zAc%@!x>&D|at&c7U9HvWcuO!-jbgRaQJPFbxFq-^H2fi<&M;=Xb{Aaf`udf6?okIv zJk_x-fv-<9)qT}ltA!cW3#z-Td(^_w>XX&_>f`!98_qKY_W4Z*S%moE>uFNV?dBu+ zfc25aF@x;lfx<@P?%zJ?m{-ELj$BAd4RI1&kW17=Qg-j%x@abri9w&5Ee2<>ppuqoJL+;cihlzg0Q1Ph<7E4fW$gMXCG^NoYXcD9K-1X)bCVL%;CWkFKDmKPDrP z;+#I8vy4e4qw6ZENLfX(J24hJI8hh7?(`vH@tGfq7k=N9fbA_4jeUPe$2P4xzb4_d zIP@?YWXftc4u#n#S7$s>YpA;#E-9KPv8$T}d}GhOo}aRdIxoI@{qQMmKe!Z(^F7(QOsL%Y}9%t25kGt!x_H@LLkPAxt|qLE%fE|)b9px~p5)s}?{H!HO$ zDWyed;jF-xaI9_}xx#*Bv?q0C<$cj@v4`oy(xdXDQGA14`Dpr3>`?qr;^650&96u= z1zw80l0Dq=8^>=VUztv}1RZH9;)q5{Qpu`xdaRUjWFlkahSE%GGJ%-h5^2e_9BC0> zuB2-!uTEc|x+yJANOhV!Wx){h#oXhXTiW~+O0|xnDq2#tRNf`;suD-&PE_=_C}s9U z6|)n$N({vLR0RB5zn)J;ATc^IV##}{V9P7)!?QG~ttyhHm2xC4!PzPNmR*341$$@?|8aB_MoS|+82_!P}KUrm?sFUu~anZz%pP zG4>GY0vFwnnc<(W;D83VV}F{KMbqO1$U0p1xkz4;TAA){QEhZE_7HWK*)A--Xf!M5 z*1DKv;Y!-$iqo8p;cKrdgxC~!Hj#1j`osI(*=W+uDdW+8cb5Mx>VA`IBtYXy#pK9V z>K)l=#E~7%wZpb-X(8b%VU&Ojd6Ft5CTDGch0hhRqXo)o z?pfDx_=eMOQDUdF@S$jdHtQe~2oq^+{o46M2OEQ~fI*k}IDf3t(J(z9u8oiDnL?HP z=a=5Qn5}LflR5H_a;N$KY3yA9+bGYp(fMX{9oF zEPu*j3wHkJ{YDPZv;R4NK$=hE(P&0`zxVpQ&*!QvW4~)=dM>(9{NvpD2RFk;Gn+N* z4F=sy*~N2T=+FDrb}5@RDv=Ev*%#QZ>C5m+s>HHO=YGsOdkTKP;&(Ibas|)7imW-3 z6~^!IxZ+m_ji|D75B=LH2h=VJT@oIt8Op&=1#iyXoWDD`J8udb!zNLv`OW@jzMPw=YrsixL3fO`xf8 zL@<&X#YA8QvNZG*A`!NeUq~Ag=tt~4KR{s$xr9{af}s6nl9t4>1*-bMN6e+Aup!q z?y%l2-)?iQ4crzGlY^TF#c>O$RR$`>j{4(p4ef#*3e(!O7i>-37HUNO4F!IeNY2-| zT~hhx2D`yN02zA$ZDP&Uq0OPKA*mYL32ghPF~#VPYXjPVh})j%m;~~-f$#0Gv_x|o zY?YY~)-j$Hx*c|Vy^b&bef$EZ(eB6D6$02`=o5jo$R@Ls*{Q5S%bv=LlUbHk=%DQ5 z;vx{J_~Ak(o9OYrLQ6!e%}%rCY^unXPnywa!cLjl2x7rS=PvpyJ+ZfK`}Pum^=J*8 zCGa9)hg*&z5T}r?(_jryPHr1KN!XK;yGh5CN>zQ{?U(GRE{;*t1^rw+!?(1tAeJ_I zd;5C&M3WVq+i3l6Q`S zvmBe3H5)9OiiT%A5G9?`A~r;Ywq`FLazVyc#@33h^=uWBq>=uiggKUl;^tfh=(Fo3 zObVqfg7aPf)G&aa4~~&0)U=-`Iox;;8Mp2(ap~V=dd}JWsYLOoZ?0c6n9YgRT(-Jz z`j+z-#5{7)rP%!g6CdyFXZMv?53TE4dHc2Q@Mk`;sB`G1b(!5CZ)+>}SGwvQ>!ymy z^GbKj{rI*8KC@$>?@L4XvP}cw@_2I@Xa~hJ@1X_5SAzq3OL4aT78Xkl9IpCEKXr5zm8t4QZZ?}hnf>H*-rbo?xNE(c}MUG89YVLaJ z2E(1wF2lE^?^(=C&8*+z%R3f&6TYEP5S_BofPkdV*(>Qx8mElnxN#D$ykvaCj-?br z8M|EphHJtxF@Le>{>$1gLhRk_T0=Vbvg(Q<~!5t6$%`d-x_xDD=xz44AV(m`m?dZO? zx$*D*ZcC$45Z^iSpT9W$#mWAD>Cvw&izw-d*~09f=h%8FHQ-X?z`Yvr6 zJbIF&ZjVt1=OZ58qjFt)M_owMuNQQzH;OUuTEiOTyw;jGL^s6DR~T{i)7flg4xBMF58<}FgdHOR$yYBD7XDFt~of_qM+rcf}P zNAH|UIZ_{wzl5^Xj{;e%8MpTWYHhU9`aDhCq%HNcq@As{@3D*as={$zjS?rwZfy~43$j^Qcyya zEjoo{m{C#Yp?c7aXQ6tGQexZSj;Gs1kX~_F!#K|!AJTTD$e`P#;p_{yedRUA4(|HL z&hmnU+m=qByXBk-4C5P zfhylUC{A>UD_XLZt8$!g(F9Z&I*&MVwYA$x?WM!OOK>obDl??T$j6vh zUl)4tE3~>uML7I_Tmb!X_#&pAt{+4+e7Jsy8a`;Oxzx&TO zuZD(H0Dlk z`!RcAXrj6L%4dG^Z;)tWeOLqj10R|ZcC;kAUc^e{*P4cw89wJuex=5dMQ}IcYAk- z@ArPg`VIN84Aws zGN-SPFx`tb95e~QS8f~Q!2#Z+d*nw1Gd|6hZrZhurUMUDHD~r0DDb8Y>4^PN{Z&-| zTkDmqzmoO8S@|o?X>IxeX9=tBrUMV2Gu9JJ^nv&{Ha6xp=@omR^SK3sE(rLuDTM7g zMD)L5Tej@F=#Gx0|0iGm<{STc=z*tacd>69mGEUfYi<)4{OpsTyzD05?%y%?>o=JB zr{C@0km=L@8vf8~w3gjs{G3n{Ev?y|?cnyRLnCjwgU8iT)IFUhW^opog^U>U;Jf~V zhGo$(^*yww1y3`Pc|wnpCR;Mu1em}9l|Ia(`#s1FR|ikdC^Lh{fEdz^5=_#Ja#VSm z{)5AWyKGJ5BVe1N_n-qis>O?@49;XJ5+Ker%1kr^8TYICWxSx-_-y3+aaq6N{cEMFdvpIS~8uOPCN-35O*dUWTg=VzqR(F$8ACz zrUC&!%q~2z2LbP4@tyswy>yr+{62lZ{HlW(;^ zELER!G7|C4=-QZZ9(S6Y;qv!En`Ul-S14jFAJIJ08 z*+N@#`{T*xeSuuopUVacF(L2E#CY}MLwGAVNgo0$AV28_&m$;0;hgiXf7l_)6d{M? z_jmi*w_@3I*UY|HESwkKzkkD{+pgNsUrz+Phm*-%MT@;Dt(^VVWLr6tDGXgIUbJjr z_YbZg>gY=}QrCLDomV`6-ZF@vaL(Kk>HmUHzCc(mj7j%tpYa4n?#tcZBcbtlqj*F6 z4It=kH&sj*-mMx2dslDV+IxL&V&fje9^-An+e3RApFQ`s#d}uVx%!L2FNW@4eb{is zcrbV{^yB)ESIlfYzVYRar#40-s=r%l_KpfhiVQw)-w$d-jgYb zf(3dH-{LJP9IJ(@5L=*~mM8kCdBDUzT z)T!CS!*VsuM#7U|3wuKRC75Ha(ke9nb!xK79KL{EP%gVx{XnY0-X-wd6jn(!EeSNm z*4m!hbWN&-$iCL>WcF%}W<{D@%huApIWV^|_{l*9pUC&nAs7&t8xw3T)-Pm0*Ue}E z|JU~v*y_SWVWx1rU?@20Nc>69oMP~n<{{s-aJ{;*wo%)-7vH&YBfT|dv)4B|_k3vy zTf(zAOFGp6a|I>>&qCQBKJ&KbruPNx4@4E)XE8rEZ97@oenKg2qusCp zI<>|&m$%O^DWCj*usneT5`*Z_5F)8jaWPwVn_^hb#`~wJ0;V?-0EB<+n!sOT^nPu z1z-|d(O9Jl=dnRmIL9~`6Gl2##e@q>YgINBS`uTU`SmfjZhgEzio>G|gq5AcDqAt! z=+VSQD)jidhJhG6zj{GTSW~<}6&42<#dxT#ry zT}+3iaR^#I$4esIm=Q}RUN_cWbZqZ!<3B7p!B8lyV};G#FmJAxn#@1EWvD)~^3uiKbMIDb{ac1HWVE7w;Xr>!@ZlS%VST zXj(QgdB~S*`rNA7AQ`QWi3_(~_WAW)J)uzcJnLo2&Sd%$an}vEe0BYK+i#h^=)Cv; zx_d*mmN|FlvU(t3fYAqgvLO9WL~}jjo|bKl_rd6)T|#!t+z`s4480C<5E;^tm`VR7?Pm0(#1} zj$$G|+$I+j%5XYWOymwrPOXw|~Aia>pv&$ z3%QaJf7Qu6#(QQjy=C#bi?#30{nL8n*)o}YPC1_qed&^Fef3=Il1eg@@ydPcq;vG> zkt#C-crs(Y*n~E*Rhc;=WMBy5Ugm<2!Sj3~ zVes=qB==Sa=9I4SF?fX^MYC*vx;_6W9Tie39THrf+M3!4Gu*ZnbC_s}xhKn`cAAZ* zHj@|L;PX)G$2KW1>Y*gWpU;A0m=eI_mM{_6*_q%_`5Z{`XFAWp6)TYJpuxh0`alc! z_L@dDN_FiuiS(fY(hF^7FWufdT8w5AI9SpSJ|7$?Fq%dkd_K^f>GJ`DcldmuJ$ycd zLYef3<^Ufa!?nM7Z15PwiOUV23gM{?8_!H+rZRgor!q!0Gm;TCddiUD?CPrXZC}5> z1^R}+1{XYSwMsZr#{}^Xw>gRl52i&vyiiS~hU{UxcM7-CM0>H_?Dfb~Kv*})2Jc_g zppE7lY)Dtz?T)Y`6VggeTsW#YJ^l5m5E}_G;w_&7&Fra=F|*w6_l|_;k2);oPD{6_m~s zkyydWe8zj|4+HJ(3+7U@>bfQbIWjQHKK8}38g^wSP*u2WZVB6C+ykjCvZF0MZ!36t z5adnL?|1qjDQG?*LB>EAJPcmYyt;hqvMp20iW<6aUNB2fBX&9Tl?XG189)g$+F)AY^za8IOGO2hmS&|g&IbMNm$=whoyM;ZXN!`9gLi8hYXW?;p3pt?y z+4J;pZvl?JC{?3e1(2ccG>{unnt2*p zlc01!^^h?mJX};e;%X+FqQ|5#{C}_Yi}I9h%Ko710r!KR2a?mx1G3xl=xaNpaHp*UqPM*Q?5(6ytLDvg8k~Ka~G(*%-72lw>@aTr8gFGTGcN zuOniQyAsZ%X^k|BYRs6j*1gti3cKR*L~@NdkNT?iz*0eynIg$~5IYLD+L`@RP=PYK z2JLoybj!QpNx>Ap{a3kPgTX1T$1(Ub*W;B+v#+Jc@qO`fANe!KV1T$w!-?bZm5nMc zCW5cntAvx0M7RQ1CEq5C)`U!+NJe!{xguZn4mGk;gD>r*(dGdDLXrEf7vch*k`Dw6AVrR z!4OHJ9~Z8Tkf~OMih}+`YECqcRM=!?3X2Ae_caf*n+~MDg(5qqHkhC>vEf~wuWYBz zZpxq`(>CwsAmv6gIZSsC&y55JISSq*#v#$v<4pqr2ZUM{KyMl2&p?_fM~|A#V=xNa zw{N48&-NDh5;z#W=U2hB@gZJG7SKtIM_hy86FK3rKfS6Pzw+gwgH;%|2|#dy#A6Tcer*zLYJsuyBq!LR53?Nh0$ zQ_f_V-y7^^SIiwB>kF|=#%&9xE|AWfUK(|$C*aMT0}smuP2*>Ot81DgLJ;l+_pf|* z6EnB+b6jUIt}__!_3imu_#b$Lfjznlg~9V&VPNpvM|pJ|Ycsrp$+rfs<^ZW=&$nhWKH6zj~k4*(dcIJOOEQ~efn^-{YW-+V=-O0et`Bsj*S%`u*X4Z69D;T~NHNS?0mG57=j z`Dl;kBImYN;zyM_dzZ`~g@Jw)?a@+n)RKiu7xLp4azRota@W~V!TEWOz-YR^^l(F z9KCLS4mUrC8~(#<`Z?4Z9fQ|D)X$-|(>d_^H=2#kK@~{;`hCbK&Z7px)vm?M$e~h~ zt{v6rnCd87J-T&tCm7<_nU;2jvSk|pSwgA!0B;zo7reyJG#ys>RjsP67N=d0aY#WAh^W$m3kNQR}1;8 zg)4Dif8drvRX5;!dY9V~KA@?A!Q1?=y}cXo8@$Em3kLcO!r)#0*Oe>BHnb)V>KeF2 zdRB1d{DGT+&Ec^F@>|MDXw-cUEJpVvAQ7(#i}9%9Q9JY6qmdALzCu)k#J{nq7OR_& zkNq(qO(N_Zqi7oy#i=m_)oL*Tx{&t|w)GYhofv4gww1-i(&09DF@Y74oCnjTVgm3l z$HDZ%Vqysf+PUe`{Hld(6Qe_xV(%)gSu9utb9U*v_4LDJ%XZmjHW`fOrAyE(9F)i4 zeS(TLRa4o7x=$5Rm~CjT-eRSc>8tg!iQav^VlV9rtXjV?vvOr})yOJwa@Eu-QCOv{ z5?5hfAMyq2tHw8s9TqQw&Dt3{%(mRYUDB3Eia3Pg@)P=I;Cy|ZAYRC&#)<(D^^yUb zM{&-tSb=Z16|=X2tkRK9=Q8#bAYQIEXZFJ}JFr}|+!cXa5Q$UB{@(=dEnC8~>SlBB z13kh`4DCj>?Ss8!cjhCXZZ@*T({W|@x?BBM+_Pf&wp73&_nb2~;9Zak%7$ouUE}JN zqUi5mGS|7XX)~tEt9u%2I>MbR<`xWgMYx}vcQIc{d~=H{*S=-*O)FN6_TM^p!#Xv9 z06(at-6QO?6BVto%vPFP!J~dyr3JIEN2i^dxnbtQ*Af2M__uuF)E8A$CbnzfTh zW}RIQqIV}kzBW9NZ_}(9SEkDxDeEY)YLzF~6pj`9NQMmsYLXO6u5rzAl+?#ZYF*kT z)c~1FJxAZk$NU01_4B(j)V6OLwQx;g;abBI;P8t8-xUC$1n`UiAT4ozWSsAa^FPM< zjne!1fIbL=w;!Xo6pM{|OI`f`Cfnef_BW7ivovV_*BT>@anQI|!uDC13kBe5%d-{(;N4GXps$W++LOhR;yCeDy3s>EEgUv}3(YK@%S+|%z4^RGZ#kzr8 z=Wbq~4D+0uYc;!Z$F|SR#Ww}wm}yJ5u(jV@7U7u-C~e>&G0$8=T(q}*h8WyHnoxF* z8fwLK3W1^R5d)ca`XdcAFYPq&!wf;-rIjpvKB|y%OV~<>eE_bo(%ni_Brcr*RP}Iq}J6iaB#$Ql0EJJaYWRTY`JCrYCQP38Lb5We>FtW zz>d@Nh+*6?VVE-PGnfo-(gGcWntd7}&RJXl;eshKTUxQNux1688@}ifdt&(`NyBoi zzxo6rp|Qfr4DfR^WC9m$_$MJEb)nhZCw0B9ydM3~OIQbxtMIxqiak9n?#ViHVm6kO zv!NGM#VBOP$m>v4tiXvUzb&W=VI!VML-1IH27mw&5*V@usRRB%b6+oB zZ@NXk#d(Y8roi=~>th!5$LK5o)|ldMM)3d&8o#ecIUIVT(RS4YZ_OdH~pE9efp}U(!*cf_3)?OpZw^EeObA>Aa^pOzO8l&7gI zS2ilU-G)2MY(aT&!HV+6@+aJ%C|_r}*?n{QcFQ--uUr1h>ZmQ)&^=barf$#{u&PBW z6g^(JRpC3^yl}4aX(69loljt8S5K)R87iQ5p(_#5;NY}{L(Zm(7CX z2fKH`FHzG-qX&>R(_zJO4i2~T@ag4>6?Tw(s`!0AxPF=Td}$|}OSz&&UmW6jr_&uL z6I54W_p0=LN`LZL^U2b^!AlZg2WMy`?L8#540?qC^ zcDM=h7;sCI~6hb?+~-I_!t>VN=Qu=U>Kk{b+?>y(Eo$w^MK zJ0ev))iv;eaPFOYrU0{bm|H(Dh7>iUt~g;IPq`~@Dp<6aGHl{<>Ja!2&UFPJaEwV) z+cq;Hv@RYjvMvsne?c6Gs7hQb6FbAmPt%Mw7UL9#l}6Dezp}1hB5YCG``9&SAslH| zx_B`z@lA^;wst`5lrTrRi6U8qM%voCTX_|2HFYIvO}&limbI|Dr3>XnVo$P^w%NDw z{-URua69rt@I-6}9ASMsVT-C$)k2lCYFtNkWxsRUGuyVPzXJ?=(C?ji;zb1n2euVS zoE(Rop{>#hjWSn%Q-Mk~P0GM{g|dM{MLW}Aj}77$*9574M!Sa9ArngDXpr<{`t>u+ z7=<0Fr@MqJCX@IQwZZgfYSGJpJtZl)sW@(UK?Jlunc_7VV=wkjoDP>UuzBL4H%Kn= z>iqcfK=d5A71}*1f!a|eT{5#$86>xO$~HbgS0y1P`1_-nYG_;Naa)JCy{_55_W0E^ z=-r2-BiHhF3w5`#ox#<%Zu5@8$?g+RS1x7JBt;X6*0!Ze_s9IQx{9)4>MF&X=*k%$ zm$MPrLRW_Y6%W`bMUAMYgRXx;ym|;bR!!MXUQI~81h5-{^O;>^2)B?TZtq2YnDr%< zX;I5Mb#0^<%^zNGRW4=j1oT4+kZ6&sCfMNiw%x223`yr>y!(UaGVQpP8`X6_`!hnS zq0g}lYphCBtmG9#?xvSZo;#T59lb{NRy5X6UQmf^L=Q*07Tu949U#3B@HaKKdzbaW z5NNPem*QV=grE{nhC#5VV?hHU?oWFh2Wm7tDvdxb13wFN6!$aN!;b``!7Sc!m>%{{UUfYCZ9Hgu?9Ap;TV=Xn z`HlN`blS50R;y#-cWeDs2&5My9TT6E-Rw^;vQRROG#CeA>(q4@sTdO)Z_a*=b-C!y(JUsAY*%Xs2lR`@_im7nHfww%6XBh9%+K zol_>wTblc^#He!z9D{oQW3761)xGGypjlNmUM_T z>1e$7F2iXY#jJVilhpTp>g zq-4-L2JPK-ER-Vig~QX!2(_9n`n(jbnSi2Muden;NoYFo*GDq166u~No3$XXt0MkG zva7Z};n-g&m4|lf_ihwvmFgnAiX*Hh-DFQWx4}{JEcvaaY+Ky3+^g0O&UhweP0**e z#nIUuF(%O_pVS{-N6Uw*u+>GnlN~xu?qK8TW4?>E`5j+7tUZav{~jGNa$;y|H!#F-O1f&^qU9~wO7CJdyi33izO{3Aemc5Lk6=x_ za`NH)uzRwcE2sCIol8Z?LO`Y(EgKoYGb#M&L&iUiG`oD1BYYQPLKGKCL6W}#p26#v z%>hE6UE{)C2(|`O&9aSxd?dkmN*UZ$P18kkaSJp9(#MVQ*kRC{v5>9MEm* zBkDfj;UV4VuD7{&+jFzHS6Z1uJ?+M-(KzCZBl(^|fk(ni{MTpn zHSgP0Gb9deI^0G%m|I`&c)j;t8BA%3PX>x zTAz^nalC^Kj8BYpx9xoeqH7AX+m8c|_9Tm5)6bf{*?&2N@MH97l$?~gx>zw#?C`ij{wB_D_0#@v9=hsV)!*bZDK33%i4{as<1ns8) zgPT4W;7%IT=b4wTX=JcBf|~o?OHR^hXO{S#@4WH09wVJaA`UDD##f-by#p6);8y zcbEBm6p$F?QqhoXi0`xd?Au-sC{+V1YyD&%8%FoGx9_v~XS{#^?sDJJ3EMgjfBd4w zu*sXraJImR(6gYs9NnAXZrH%DQS{AmV&6*VMx-TQq18UMRZ}xg&qnjr6W4P8aGFX!KY|AUv&6vV&v2Nqg2vhig#iWoH zLcMk=u8c417$J9MM9`F_ai$ES;hi9{-k%_aGuMz|0fLuqZ+8*gj^o!37tFmHO5i*; z%faYGXx5b6l96I2fnvwG5GBOXbw0>s%?J=3<}d>32@MyTRRNx&u6m%WiZ_Cj#o46C zcz{u?bs6;m2p6{LqO7^)%Ya{a595)*-~z-3-&o;KJz*n;7{r*tIK|e3QniKPzFF+5 zM{62Sj9+8~Sl1oh!|~INMlr`9H$s@cS&y`nat;Ov0wb}G*WifwqK#nVib}ahqde#1 z-%gvhjJn&XTBVppsJ0eS+>2C5>s}hZPot$FClM?r{m_J~A52pf=|+)4@)nj^C0Vy3 z-=aB0d89{(mZ~wQ#peI*GQfF=N_x{UO&L2=N?jW`bLdmTDwp{%4-hAa z4PYtwU|6sTsWz@|c^vD&0YZ%B*lJiM27_%a|2^8rqHjcgAH_ploHFjI`bl_loIuas zqyoBHlJx!4ORx=wTYj{|@v<`dn~ipdg(mw_dlWVHH!AJ+Joni9;8k7eJDU}}{%N~LrBd{Tn^vgZVv{Ll&&f<5}1MZV4Jab+$cKQg~{ z5#9ZCTev*1snKPP${(2om}j=?mDc1P(?|QGy4lMIM>pB)hDa~C6Sj%)N*vR*bKsx* zR`>ngZZMdTuj-Xq%(o#kLv%@{-+|6VzNzQNynO4bp^a;58YOQ&9SvHj!8&PXIrK@` z__q6dq{g__Sxg6816v2Tb?g>({9~y*k_#cz<}Lc#dYrXV7v2{~NR^jQafaYU?pN*g z6H$z)>6#C!ho}$fy-tDQT7)tngdvO0@w!5Bmo&-)wa5GOZ!ewgqWRaQiz7{G=;70< zCe2!kD;N7dxANEJA?RGEZtzD&FBaa?Xm~Ga{j=94M8I>~Y2BId7mKne`8C*flN_ zTZkphAj#0x_|TqtMo5SICHV&KgWDy=0=530*!fqM0v5vhT-9(IVkZuVxTbYMy9Ny- z0swBl`T)$#K%(E>&wG0E5N7)4sK(;35~yIST?>+}H?T@6OxY{iGN$_yIyn%Jf?=x_(D$R&q0 z>c1yTv}78j#(Bx~ra`O21Y6A=FvO<78}Jilidtj|Nn|tTG=@B26INnG%+?3<63GO- z3Jv*Z39^^-lU>JeM|H{Udd!HeREhEiO7nWQZp2C`bC{j-sXEM+N$0?M*&`Ph%)ec| zG)LfGLivbLv#dZIAnLW%yEoRgIwU&h-FiGe^tG?LLc4J2bvO6Mc#@=56jLPbC1tr` zSUwdbM(|G!Iv#2nq#SJ`y*c`(Ryd zhjK+FrGzKb%?YfJp%kqXg_2dt8s$-Zc79wA-cKyhW6DupMQAXYbhqqPvI0RTkK7;{ zf}T7RKu2?3ePP%&@NVhRPi%b*s(eB{UytsGvm zqK^~ujnQF=bX>gxQW-kfJ6EnH1=!k5Zss7$+v%`ZkxJIF?6-x4;M#+9UO(@{C>WFWkD)t9BZ2S5(h~ohUnZdTDJ&A8HL8 z$ofwGN1^A{Ysndp>}e(X&it6tDykMS4BIXKX0b>6B7p0oVVGu12WQ7<^Hy<LN;Tqs0Y9~S<)d*as)zOOCh=Cfr1A`NjXihbw%X>EH z4Cgj9{5)!CJ-Lj5X!xV2cRa^sL`NJ|j1sb6##9I@^6T&U>>50QK*$zq0jzJgzu79Y z>|OTrRf`|N)1PT%FP`pHW1gKC`4xqhv6Zy__HuOK;4%V&noz{gm?b6KaP4cvQ+D$| z72pqnfzNm9Kwc%YZx7R{8o!<}-0k^Je2{ZKrMqnd+=mk&N+y|p#((rz`RBx|mCOBj zd@ zKEI|gzyk{niVo6LWg;U%AgA!1vxG8|aCJu;w~8^0ag6a)wNd?gS>>*G`@nbJ+F4m{ zwbuCDk6=ybf?@cTvMSO8CXs(XhvC=dI4oM)gT|-Bx`lD0r?`Q;jj_J4_L(laPBP9( z_g2Szlj7>h7Ul}(d!D;SstYfQ2UoHkmUhJW1qEqh0jE06*q~mc?vTaUQly8->v3%u zrq|kTd4fxTUVF{tY1> zO5JK!qa3rgU7wW6U9C>}D;pzjPax%L`I{92x$yY#s*_-U~Bk5VO^$xEmC^pQ~BjqX8PXx zXhUU#VH*M~?4Rvx!Ou!lS5e=-C34;O0#*dCeY8BIwC%hODuXKwyM4n*f)oZr!S2a9 z$6qs=B+7P)5vJ;@Bxq}JLhu?bdri9*ST!cSl7F2% zR%vTs)I)AKFSA4jy7B$2^x!C@il2dHQ4BVRfyDQ9XZ%^F>?kpNlOTM8=m?g)e4 zJ65G$fX9|)8uJmZQx5*1cqiNrC=7ecWsiw&qfxco0`|zrPq;wbig6^x$E8!5fo0j7S{J*k%j@U*$8)j)?R94zS&58%Jb`Uxx254<`Ty-{Vd}9302)F(F6v z$@l$h&|^OO!GK(v!izCV+Q{d9Imz6n3;0Q#u2#h{Bd;kvyZPDtZ=1OtDWe$PH{Yf^ ze5GlRB5-i3igQ!jrj}%OGn3Z7?-p^54x!mZZhj`Ed z3O%Mj+tzqQF*M^vlOrv~Aw0DXYSy5{`{7zBzM{RtBu|Gz33qzxh~gu0MYR01ggCc! zS$ZVr3*-jm*me!RPE`~D0X0_Ve@VyJ+pbp-&8fd1%==ZT3Z&^_!?>l7RH>3bjMOAl z@m-hLbkdDMulbiDcb14#>9NFF;;r&-j3`Z{j(XRqL%o;d^Uw%sK5L@uczeGtT9;KP z?QP-Qe&5ZjZ_3=YxJ03YXZu7;F)qnd*T$m5l_MH6cKE`YF&-RQvcyI$ZR0-m1!6gW zQ$j6l|9nk>CXElSLIJydBDcQ@~Qtu&9v z2EB%j`qEm0WQW*ZpVgNwmL(foIChzwEY!GSDswJ_a3_POc5}=>b$H*RRUXt}2>KiJ z*XS?aqjzh1xp0i4cOIgrvJe5ki}9jWL2z_dNy4DF=`disrfSC8_>1@Y9Ux_ja7ut> zGt?pOvz37{x0{a)@|+l?Yinxfm6ME(F!PJwl6qM`XRBHutU+CojS2V$%xPd&j+=3j zky?Sx^q3L{%ErOONi(&iY+^di6k~|UeUz{R1g}PQ@YLMYo!Q@L^+L8)J2uu0P|UYf zj)es-Vq=xm5Q`RIVZ&5`)vf3Nmh(Pe_WSQFJ0Sx_y_Ls+hT#hLFPP+3W4h{Zc03Q+x0Q zcP`D{$=`)mI~$+_Ji6*PErRpsCpswJwG4g7XnVdEtk~8v79fhIuZS3~d1fSRak3qo zR``jQz(d>A`5C~*^RzJx)*&z0OAJ{LUvpQjfv99f#r5ltdb!<7UEX-#1UGR!FCVN>b5eZ zONzwkQnE0^d)9H&I~Uj|W9(S*gTwbVX#3YE&v@Tz*K4e%+nT(qzihu+JTOeYmxtdN zd?25@U*10P0w6!g)=~_bmFPB;NbTu}M{3Z^uJ)cx_+n zVf4$)w(748j^%T`+ZQ^IMuw|!rnBy6w?ptr+Yb`>IP0wry^4a#pE+C4yN80Z)M~BB z0XHKXNH^borsLPHf8ZuHqEzl_nCBlm+&G+o-FTdAwy+cEmaeVX8~wEA*=YLK9HTjm zZeRZP>3qjS0>Oi423-$++wB#5`9y1rZVz~wzD>7z#qtrdTj}}jjurKNhsT{3sQc-q zdOsF^+wL&(NyfX?q4MU`X~#8N`w{pf#FfgDtM$A}HQ?mASe4q%Vs@C%mpCC9 z%0t;gfOLhUJvd~B=pM@ZAjkhqpN~xz0|^aUGN`bRfsPjjnldP{k7C!$E-nfJ9ReN7 zGN`eyq((-K)(T-LC^G0r-yr@*mk`GAqTV4e*RO2IY?=yPudVBd*}1jys?PVeJKFA> zzRG2v^JG5d=_3gxr%}vdm@L5<{@oE2v{pq7-plA8I z&`RIb5ucIaZxsRpwr=>E)XXew_|%MatoRIc4D9&ybaX7*fA`DiTYni7;{WrZR5G_V zc9b!8Rj{?zw~G$hcha{qH{`c5wKD!1BCVp6v9-#d0>6u?s=1Mq89o!;*MOvq z^^MGJO!1k%tV-*<{oTVrNB1SD_OFpLv3ynjOiIMu%9sJ4f#pk!0zMDVzg@ugFBfRy zGcePAm6_<+@R`3f{Qae8qr+!pWc=%(!)In;`b+9h%O7b5*1u){$p3TA-{*g7eS1GJ|98(HDZ0O|`%_~1>ir}C z=V1TR{7?BGYyXVskJUe;`OoJ+HvY8zIsT0BpLzT_v;Ma^{gL_0179QgNA6GCAAA4k z_@kTY%Tr%gzJ9g;?b|=|{h#pq3a7Jy(_d&)a&R{O8+QWwj>dn&^nU}zf5YZq=vBa{ z{VVK__zZtM{Z$n)cW`tPG}CwZ3yf0w|Ekb`iPH+(7~1}Ym@l{({sp&xxBLerzA*gv zuo+od|CtIS{ePN@l(CKJ7X<&3`!e`<^(%@DOnE13;&$+oi?4bx)>vTf3NQ0J01 z>!x6aM(ZZ%pgLmi8s1N4&?@lP(@{uV?7+bB~BB43c=x+;E-Qy9QzY9V+ zkC)(UQ0nMGbHNGVS$Or#Z;jH*e2NXc+4|g?Vit)QV5*3O4W~e^58KI*r>Xkd7syLX z>dMzp0I|>UlydM}bpKRNp;KlC^Rc%`S*&x&AJ5jc5%;Ff(0 z_hNUOTVOmy`V9bOCZF*qj{lYW82`Zae}eOW;XZcyFS7d&?qj3>0@A;^kCC47uV8<1 z-=FAzA^2a^N6*UsMSWkr^mJ^D_+L8y3-gKm&3rP(wv3AI)&{m#{~wgc%J^mY-!w;0 z|HZBUrnx_C@SkYzFS!0^n){1X{>)YrpYe-4{(Xynsr=gu3=9na#`=H0ZU4dgAGyD7 zuKzo{wSU&y4B#UOd3G6$x9Yw0rG{gdtewB z(IH=|fj800u0_N!7IumhTjA)%@W7)iu_T(oAD7CJaQr$O48^tHN z$Rwbw>)J951NWLKR$B`@wEu~ruQly|!_fbO;Qp7`|2Jm)3!7iw{ui_T6}-Qk|8Hjd z0^Prv?W>zs$yV9M{4cU${1d(Z68e7zNl(W}_a8z2XWjd=^#2p&KayW|{vkB_uf_Av z>iPemv_Vg3FQvuCCmqjhcVivXqlr}4Bkp)9FsYFPaYFVu5MX(}oD_)IAOJARpzCY( zU=>0PuSg+F)Uo=`t)yH+&`tzL@)285OnL=sPNRmMUeVa4<>+D{LZf~|Edf)HLUW~bqa5JA}Ub$o+vZnFucXUUgpX1UkSY$54peN{mD3b>9LnAOF+xAB@#(rZUoQCcTfsfWG>d^t zBINU;{By>)^bO-JZQ*wZV0O7D)4D`hFYmi;fA^fPdsT4rt*lV%@uZ?m^5-+9Tl=A> zOtwShq_XGu6Bq3#B4t%Kpsi%m?nRqUhqr6#JgfCdN8x?Dq$=%GmDb_Uk7cdMX5q-2 zrkdg1_GVMpX)$Y!lm4{x1msN=~WS=Z8T@`sG=O6Bj|ab>XHWZ)KwF{h^%#l9e- z(>?c$>C-cdSAzXsE8Y-~G1y94p+cIK4+!rDa@mBkees?T3ghc>^?9{xm;7l8 zZCqPxliD+Hnk(;`a*tS2jh?Ry)J-=#kxM(mS&6vDU82sRmA!2 zB_7>C84GBHm8(@})gu}3rq)_XUwt{;lJN@C3>&f-FwVQL;`+M8B zRbKZ{mO`msb#ld@q)!#g#g{t8vf3`mKNT+f3J>66H-mw%)_N4aUHb!DK9q9WE*2N* zLXEk!=RbmsB7R54xvgS9PL7m)rZ*<#*(%tj78-MRHybv&sS)b0fLw z`tn=gxTr@iUwnu;^P*?@px_qbE#L2Vt2cYW;4OE5D}#P5Gj>g+QXPAQT1`umKCIKv zsGyElFO{N+Ll#cjBeWDBV<0j9Aw*qU!i>-m6rfUW#)t_OMN%naYY+g&9G})OkqK32 ze$LL)7nIZ3%dt7;C1>Vx)?uRVlzI`+&sEe_(AB~tk5?YE5PAyy(B-8N2mcZ-4rmH#h{qXoJh+_GVXTTsWp$cKDRlez=3MCP{-&x0p%eMJ`=!XD7Gf zCI`-)k%4C!U40H}dnLKmbi&<)cko34Gvn`wC|VBs2kUH9%Bkv2#SF8l1SVJGAtqOr z%id>V+<9sf5q?UKr7ur7DMbeyGPHdX_ZZKxZmdYPAN1 zYmiv$UKgcGLz&@(syCSVnNuJ4xWJ}2_n63k4kBzai?iZhQZf^ z9t_Fvhz$qF2UxcxFP!dZ83!@XPnCEG{KUF(r9uSV_|F@$r9|Dm(X_GVDb?7kf)JgN zxW9{YlcTu6p;jS`TV7D&3v>MN6oI0&;-`J5zIGYTEJ$|JKbt?`DTw;Xc%Z`Ei3_7g zr1?|F$6DzmD>C0L`yHIdUvfmB0X^bnzWZi1%#fvwx|=|=c00kgL02t<^>*KDP^9j3 z!?uGSiM?8rHZ|Ql`aMIKPn2i)Rb&q2?c_f8333=Oek2A$J^?dc^Ymeo2UD6tuwW?)7&VTJ`2y4WG+n#ML`~~m z69ZiL5}MgGh|MQou?@{A!n7ece-CoI_0h%4YG{204epJBDSCT!C1{&mI~Nqwo@2={ zP=k?Ou&DXQ@^eJjq9$%3X#IvKpBfp1Ixq7XjSxO(0s9>+RZ*XB!|;}g#W>6mp8n&z zpwZTa6zu5FS1J0n%9b$p2lE0Z;OK5+zA-;9cA1mD?45p@MK5UhG<2}@%B zmRVV&_DtAV5U>+w^@ZNMH4;n~*QnN>QJ_C&hk`-bpc~B8_#aU)YKKNB?bMSl0OvvE z7#9|}a3^!OqR#6b9nxQ%twmO6!c)zVZ(%hHsx|Fw+s@ue0{R^?AzTz4bAFqMtf$N# zhCxtIk!fSr5j2=i^!m5YU{7C3rJ@O;J55@T*U%7K!0X=}WvOHOp52$%K!x{|*OLw; zw~Ke)3_>$M1%cH}yt(XguLTLxR_M;u*ThFcI*Fv$OwOz{(Rj^-z6r0l9Ys+m((l{d zO%{7w<*atH4MYM1p9!Q=x5#EJV;yMkyAAX|(09Qh((2JEZ9ryKU~Mv)GJ!@)2)BDJI8KV&dI zKkN+o867~CAa|kQbN|3JPD=Z!eu}k2OQ9`&@lxgmZiQ%v!ysX*=*gL_WCO_1_RKLU zJUav6TSAj%Uodb@V8zMiB6SwkbVNdvxf0LPq|J5k2&<3lx;txOXPE6jM=(Xa#lX1c zAuI#s!RGs1>8K*(A8YxNI9&De`&2Qe#aq>Cl)u0D>`a0Glz-I+k>!!7pn;QK z%qUY$MJr>01&`jx{5P*uao0xEfhk;!n8=AkYotrBIaJ5zTPdgqCw*9-Z+W{|x+@_u zQxE*(Hy4xc+=Ahvt;ZfL_`lJoR)Ww*(bEPd$9)>0x}wzj7g5MxWWJs9v;G#k19}K~ z^~VT$Z7HgGbi3P2bq9OtdyX&bv1@k~?n1*uf^)=KtI;L6tNp3&D6Cn9O?cU~Isbblz-wdi2hZ+5&#j!7zGZ*Y!4FqF0@5 z*muF`euUn+wQz{#D8B>xs3hh_iyx{v=rxM65bl7BpOPJ4L~u9{lRj~lsR`$Pu{l)e zUg5${2IE%tz<>fbvI}A(3@J3l{}qO+U#I+x-fZ z`}m%W6cx{$lM*O=)>T&vX1S}9uEd|K_8+Jn z<|0d4`m9U&)zM>ZSn~{ZQ8PgvWSr(NLn9y^MK>L~I1=d)srjb(1iOTShRu}UQ3XtI zVzoBk2+L6m6p#m;NK$i3Nu>L%jeyd{hakI&3ez}{3V0{9+f2oOCI`nX`rtkiAB~IC z-o;~8ka7U??8Bnk9(Z{N@N^_`MKTl2O@%A2i`Yg9wtY^DI#y|?PoIQk?Og2?b}`6m;^V&wVI$%Y7#9h6K2Ss_z>QwM)mOew(n>#BD@ViwV=e z;a|T)Dn^M#Bs6>P7YmF2Swn3VxexmjQkUFnQq_{_fJ#1yc_n^B0K!UeV$!b25T#fJ zz#ydzxyZsslj$$0w(xCajnF{Dtq#jaX&OoRbTB*BB+Ue7UumG)3UQ(3KEM z0u2(;u(&l^#NXPIh8j>c%FrJI+wl1tm0^q!`Z(wwp$q#%$He>PV10%Y`9-&H%Q>qq zf3>#-YHiNW7RMqFki=Q2OIqh;PQ4PpnTlnoZ?3CRIsb8?VyPE>}lI!Wl}r+O=9Y<_sOkeTZAevUl< zMJYj{mQ}JsSFR;sh7mU zF%c*O7)+V7jP7UmQ-cUWe!@VK*nn0I=iZOhWSbxnF5K1$X4O(s5$7b=LDTvKk;V#E zuo`Cdys;6-8^`;3w33y^8w$Ncka|!aEw?T&?F}*9Oo;N#NnTUAP3tEPN2N@tF{YPS zQw$RqPtAMTcYw2}j}uxw--=mom#UnxO6%dZQ%>K`T~fwx#S%MmkJfFzgKVO+4Ih*^ zS|UY1G8QK0U=Yz?3LS<`0lvYm!+OG6)jp7%WvZBq3qF=9_wqGH@i25e( zuf|7R!RIAM+j2>I`=P{O&5CrQ@?(#nbD^>|y69Gd92ZZ(+6^@M1y##l%W}u+WZc_* zZaKLxqJ;%}?-q^5bu}+hINS~dl~_xsGS!*m?de>5wR~4!?Iyb)zBb^zI~zN1Zr;?Q zIs~s*K@BdQW)wGZ=#!=W``d)wwn9QO%GxK;X-^<#zhra!BL$Aq+o} zbK3?dF?eEZYIrsXG{OY#4wz9IiH5H{;GKw-7Rn_BXV3tru zoV^SQ@w+%IX@f2hUvFnDrykhV^?LAnPYpaj*LpnD?C&@^)EP6Aug9#<_jJkpk6Guk zvEn#s!lv1s#y~hh<~stb{5Fu^X8V?Yt|yEx8DLb0^CU%ZC9Rz(bM1F<0vqp%Oa~ri zqN&u|ZvZ=y4)i69Sgj92{Qgn8WiyDAmq3S1wBK1iT%kf$Bdl89zZxxrrW{huc`9mN z8m4$m!Rv%Y>dPUlRPL?8^~0)%=jJ+?u}L@*sf1QoSYNZPEu&nPLlu=eVogiNbS-!h zmWkSmi<4~(O21EJtmEY9-1awJcgWmeBza}~D=L2&QU3d4Zr)GG ze&3wKwSoliDO@Hc=+z?1Lw%9%N3E66C_Ofg%`vjuDNpv8!aZG%>~a|I1sc3Fs!aoOa^;&J-k)P0{= zT!+N+W-isA-&vCTPaH1(6Zr!jY0~Gg5f0l;Q6AP_zkySKLK?+L2QR5Dc@O&BCqm(1H2>Vp3M`p>P^o3<^AfGJj1caMlz31X-=55{fMTv1B;s zmbNsVTYJ$~fN#u^ava0jAGInF(YAH)y2iFxcqk2N!v1Tg_DD)bzIYjoJa&((muopW zyW_ct0gam(CJYP(`(z~$GUT+X>(veO(-(R*?pEU8-eO^$Y9$TthgM!OeuRT5jz428 z4DizcSfmCI42k?qSMoeJiiHb4$0KvMt1k|&E%dTq(GvIUlIfV zzJ%|u3?;FEKe#6x$G2CDU%g5-d&6&@bzd}~BKahNVopWKU#nD*PTxXKLZ$EC{KQWC zKw+Z`-M8|ydcJvx)ag~`rDWPBJt-wwEmQA_#Dz4PM6It+;Pu3#O{!ZYdp3J6d)D&4 zZH@@XyRk8AAIJOf(9ID~+<9SXZ_iVL^L5UAt`m8HiAqCC$N9%`7 za?$)st6`>yRHY=2#_`a>5_H@`uDx-AA+C$aSvFp9dyd8H8ubSe0-V@x&jy+XC)*QXbuI;W%LD`ic~K;wH;Z#!n{M zNkJdu<=Pr4oalMzl~`G$J`ah}SvttFdZ2ev?GNY1K%ATt_9}-XoC4`HKiW;`-6iSW zCjh?wO&a_OK=f)jmI&uNPDHPUsrfD6*F;Z5sd$m2QHhCgkE=A8!@3-8_c&i;jd(f^ zeMIUfjp(uGk$M8kO=$Zj5EQipiUasrU{^P(gVK7a}6clSH1t+2V zSfAu=4T#`%t-S(-Xaakt@*AHY3VWxy;*)ufJ3y1eH_-$)^U=rlhP}*$Hd+z4w+Si0 z*rmB}T5Sq&9M1x!YEf5>IHg?+w`{iz^5h}&6eRmUE9#(FRk}Kph`RG)2{oCBIp+@V z4~IV=`~&afZY4Q&bFTMwae}jl=T$=8PY)_tQH*srH@jYUi@|b=KQDz{nZ#_hQoR|z zsmBEHp#+lD!=yOq6BV@p;I5Xd9%zbAE(= zkiPeM>Z}}qR=TMbWQWt~U?ZG#hsj1dg}arDDUz({0Tn|owXwF9rdLlW2j`*%de)_5 zZRpuY;`&C`0$_Q8_J}~~IRm1Et@s-@$pJE2G_*Sv%CcPG^BeDP3Z>uBz1{0RMe^vctwW}8 zvVPkRMiQC14@FwcTF=^(7 zem6@nkx0N0CSs=B-v`wa>sJw#^k*wU&rA;saEoDMkuNq6jcvJTwnRZs9?u}6=!ymI zB#-t`6dd8F@z(-ThK}9i8l#5_zP4P^R7waVtP@-q=kYR-eB`Zv%f+&4&u#+;*=JmJ z)mx14>@Y9scf_VH7_0YflwD1!9F4A&_b!NaW#Uhur@d^!8obs)xunBoQBc}o9CMRx z5x(x-^uajmUXi_E5;)QQwM~{OWUBb;0)Y$JYsB4A;;a1`oHh86_%6C3F3l}{*3&?J-|B0g)t4S9eyAUE>9?(<2ApAc4Xe0->len>gQ0BF*FpTF5q z#MWszZ!n=*F@>gSY*G5)>5IL~XCY>Nu2e*?T`G}W?{gG8!y;}N?bqz5JlQ6LFP&t5 z{Y-Z+-Oo`+ZF2VxONgz;`6YC3KPl4mNKIO@gL5OXpszu`HvdcEpjQD`fu9hoHoWA> z>XG{Mc~Ns!)u&ZQaf7@!QVXkoaalKz!3~)Gl?EjnlvAq>mu5_SKRNrj2fqDs?Y!dr z=~8f0L>%RvES&IFry3Vu1*JMv{%aFVJuz_CU-$&7qYE^)iS%AOj5DS%w3sqjQ&=E@ zzw8>>VCW{9ryExr*B@dn2MU?ndiFKW+eV#>B}*9l^N&a;@KUDJKr1nQ{L)GE388nh z#>do1HHYBp3|nHLiulv_8dku@$1=#$_DBr)OB+%vAP`bIx6O!gku_wV+~;1vl?;t? zDp{^lykXgEo8X_mPsu82`}E6FkQShVROVwJ?Lq1-fpLUW^dy;^VGiWZdpZDNf~I0#snKL)IVh!|Ehp}3L< z3ED@^YQ7T$RuPh;-@MD-FCRE`-J(;=u5q8lPd#EZGgZ;mQ`HxM0~YFAu6+q!Xh$gm z8URvZgp13)B^izMBX&^aLM5AeQk&)qF=$m(?mN3l{|CSFScb$N;I#v}M(U7v&c=5l z55duyF$Xm`-LNj*-@EX;RiaB(;JG=5Yan(e+sk<+Fy%hrp2eOp@436&Z-cDWSRKut zEtg(F6NXxatF3*239)RLk{0;xegpCn6=p#&SO|I1W>jMV@-`^~api+%{x>|(7}PwH zV|Bd_b9wHYw^@hK&~H+H7F*<}G*+u>U7ZeV+5(K4ErwMF3b6ceT#F%|1^C|p+DY!~~ zzazy^!4hi9OPE8YmXOHQErr9B8&&vm@OU?2FA+eoBrB8~<{OnXn^;sRvoQA3Z*IDX zaQ4EZbN9UkafUmyh*;VqflD+t(mP9fhimiDZe|fw?m96wTkNH7Dg(!{<)6%PImHKO zKgwlRDD3v_2Azf7M#fwZ2|?CRoY<3s?1)v=0ZT@_X!X@%)}cZrcC>DWr+M7XAAsD9 z`p)inCI(2NY}X#+pR%WUvT=N9-#Dl|fOvZk@+GUcZ_=t;^-1vND#e0==aZk(}E_V#7$ z9Bj~A0;n4SvVnHan2S+(`)=ZGR(^qnavl{GZ`uvPx^oY8{>o7ZHRK+6KtLV7YzxDn zMnu~%hEt!^Q?V;?FJG`-EBj8ca5$r~ccDrHWlN1!e35G`+`^iDSD-{2*G^K(qfpis zS5_%BRK|Jh(2yABrr?+1G=?tG^h313X}e@RUDD0;BlSmngBeyR_(i6;^uq$@k{9(; zYi0W8?ImrqG57H}7gx8%QB%d;JH-N`Gp}f5_(uL&tS5s=8m)XDDTv+2+R4gy&BhRI zk4+W$`~2aK#k~eKYCS_8N!-8#rPhtevW&Y<8N27%rwg4rELpE(0flD1TDrsXuQXE; z7LJ9$tz!9Yb?$3r2?7N$qlD~rw@RfvU*EkcN~)3e9lAC*q;a!Nn1a zdgiIa0Q?-tvlDhR{p(8CM3@uQ!?TxW*l8&ts7SCu%wAL+Qe4VWD>8sXw5s2qF{(wy zd5Z20I%Ti93Od80+#&cs2ef~vL{ejyFDaczL?q@Z=-D7PvoC8jV^Jl&5@(s}fjFo8 zRw5lz&svLHI%wQ(5vM0fiX0U$w%lZ`b7eN{`JCm|L(jebM7dtTXJz*En`qntz*`8}If-bDnuY;Ua z@}%|_pCtI`qV1(PzC*Sl2y}wss5#@E{KDiSQWzJh!Qy3@V-(?Q6lC-B9%JHTDrRyL zieKl7aL4Hy2QT*1r~nAYvX`Sw0}G#bXz%smR5a>0xVP?d301zbTA<#~ixIm#D~At+ zJx*q3pBC&KUZh5W_js-AUp1tIgW`ifT;(<5{dkX;<(3QnPE=4YT9<8T_VUZX4M%6H zs1AdpXdqtuyH~^pOf0dx?hSjq9l)W|eUQd!U*#^lzRLHWsF8OF>Z7inOd8!tQovB; zpAbFD{+7V^M?HKyvi?uNeTM$opuh6BNIRz8QhT9w-SnH#N!$t0%EOokS8_3GLNIn% zhq$#|NARrFe|+Wnb_(72wM3#V4DT+~6&ob(q&PEr(M0RhuG`FfKBjq<;7d= zRiK1txG<2AJ;mO{4j#BY8-|Z@RAa;*V&>qd_Q0gT{**^cqie=}>%uRxANS;d7*)bU z)8V`;a^KjV?&#vFd)CEv?fm@kJHwfcP zCRSSHoznZ;aa95R~)PBBBRw)f3v)b49KKcr6FXsuIVh@ zk$>_Ic5T-6VYTvcPJ~uMiuU#1cKKJD|AH-=Iy;kyIu9IG|9X*u7Yn`Ld;5b zMr9p)UHltk-kZ#L{>*qHq%JN1h{TW_Q^S;jlNyx>0Tgsz4Y>#5t4o4(bd#uU1VhmB zb|YUUC~mEt)+C8~RkK|FcNA2oE(Oek;VVZgd$~~C8JZ9~a4)SNGRo>!&m^CEv5Z&| zpj1OZ<&MLhE2{Jy8V3Qt)gU(k5!5tIlq)iqj8*s>LMn{i&WGe}u%@}TFgUWl9%(=* zV`n(>UT^jGD^_VJx4G%*Wnz&F0Yq_$E*VCQMe>(hXs!kK6&bAO5e9X*cM)-^2u{06 z_>qPSFwM2&lIysy?wKALWq%(0dep7Rud!X5qqJ#CA zXYXCRy1Tl%y3Ypc>E}elHMheG0QbrWox}9*c{+@~e~}O`RKmmQ45gB8w2E_0({%M6 zA13ZaRaE=5Jg_GMc2}75Se)K)X+mO`4(%pP7}{W(oHdCryk2*#1*k$Hx80)h)SM~g z4UzdJyp_bti{a@0!2U?=*Kl6K-t2T8cc3GvE;(DDd4Ah(V*#X|TYWVj;xn0XZ3=P@ zoGOhE)S7Wac&-e_Yt#k6-;>|*H$1!7Smx6(s= z8eyM?ss?=iir?l&2nB8QJR+MbN9#=mQv)TTH(VxyGDy$tKsoA~NaJqGv$H`7>*QkO z^Eq~Lmv7y8?Mc$;A=ucE5`QOhji{L)ft(9XO^XO^GQTA*JUiWeACIk5;kQE z47RMkgYJW}tSz1ctea;w+&yLPMJAL|>Pjv<*iadG1m%O=2R~Ii>zJ6Vpjc{0{ygvm zwAP&E)XtlbStfc;!Ux4175217@HbSzrjegpy?9KCSYCR&P#U3hhE8!b!sm`_P;sm| z_UeheEQvAbb?se>!j2EY*!)}^OZDo!8l`(Ff|Yee=}7Eo)>c;tTNV4hRVT_DEmcar zQ|CFqMA(D80Bsx9Vhy~02prVzzLb^lYJy^nqGUjfq1fx!G9;$-hE=mmq&5ys4zZ*rn{H~dHIjf2KRFEI zjfsh$y8OU;*458{XarRV@Z4a^Yc9si&ghLUl`M3RuAQ!y6KmwW)X}X!vynsq7q~M% zr9xltZsCqR0f9gwWW8W_9uqcQ#5a!ve06cr!>OS#)f)!w*0Qh(|pUkdlWo z;fbfIp_g77EqLp;s49*)?HTT*_eNRY)&?MNuFRh~cja~6d@(D>K*sm19nopO}bH1XeSFDrINDw~|{UlK+ z<*Mo`rRVwrR%XRT7?WG7UBPrF0mAZYl601uY(jvrRvr7DS@PDHFDIR7G^5#Dinod= z6Bte|XH(9$`Gv=NLM)ytVp`w`UR1=XGzBO=-)SMzbp;L$qON@q-}}BHJ8Rm?Rz5H~ zuo{4ZD47hjjWb`?i9qi%Rhw6TNu{P`XWhFWvmw4nH5zC01)4-HCRES2b2P?cTQ{u< zL$}qQ9tB(OTiyn#kj7!*X5yQYX|Bu`_2=51PqL3yaiZ#OwyP$}>K4vqwZEq05~gcn z4;!*~=#v+=s|d13XfN1;8yc~BY5CO?lUY?&y7qJI&nJ~FMJs%b@AAxtY+nn&(^v)H zof0tdp2A@#Uj8CIER(?K+{c*QdM1S2X(O=?f?FMqk}cQFm(8O`4Oh+c+t}EiEq5({ zBYuQ~0{Jm_Lz=3fU}-P2qU*g>Z>Bd0-D=6H(7==UMiV7_U)YL8Y~BR>L2CeoB{*B&h=dqe}PMs$G`4 z2@~ux8KNn59Rk7mC>xUph5v~Uq7QAI8D+eqBWQxAq3ouvm?XeZs~?@F(P}9p?zx%O z)v~#(vRR#5$&Ob3fyNh`&c4n@iFBmoGz|6c^zQvz;+sBKBXBS}1XMoeX^?2`j-}w= z__q8FFLC>zRbLc*hp3?wVgFw5nD4pd=4Hii#3##&8cKy`L{Wh|1K|=={HOQ3nOs(&%9jvzw>hcz$DNE>A2JkY(Qcz-DB!J z8~tyIxdJ~Eb0r=1O$~JU?HGB%%ftvI>po_A{)8bg z{LEGVJLjD7uWV!>KNqNmp7}A~_U{)1JqwU-{^*(i`Soi#CfdL1V0nZJ03BuqFcXjE zS=jypB`~o*W{dv%VxjvfVPpEM^sje+01p6LnE+oiGXVeqW_o-^0R6$l#s*w70yh3E z^>}1^1UUdQW;)g%x&Sx;(0)vkX8@oCk9TPCS%D;JW&m*UcRunX#Nl7Fvj0m)?SCG$ zKND*oT?k~j{v)yWhu4A2{|FfXvS0rR5cr=U13!=*k7ffQ#YXp6A~oY9lH;$={3FNq zhbGYEKXYtZX#wEEf6cL-baw%AY-b_MCt7Yu{S` zv$C3A(V#@_3X>rp)p=#!pruK+6P1aMM|(MNE4PK^M&}Sq(xeWKWmll zHmP!YyP>a7t8|?pyVO&nD*{NwPq!?~-u|dC`7V6?uh&=TEadLS3|-%&IAnMs(5TDf zfMg_~==Lc|d5Cx-QG>Y18{EqyvSP&b@WVbEAlBj#&5D2Ob|!E7+*NI_A*QuX<#x{# zgwfuSyAs!Y=X(RW$f4mvey!!>&bM?|xw+;7vBQDzX|reAlEDKl<-%DI0N6tKa_8o>PVHA4HIH?j$J(YQqG zH165mJ<){QH7ss{GU+9-<6MFAji(#*sE1dY8+Q)g!_(Hai{&yMB;1poqr__3R_$h+ z!8S{n3u?~tLlzjX<`G)!rDPJZe$4rg29`sWY?7(SiS6qHLX|o2k=yFk+C{1AZt2R2 z>Kp}CP3OU1J-%>#DOYc-N>-X?rjb6TmQrPFMb~`V-IZd33#TXD?!fB)!ZQkj(cgd4 zn(PXaBycmq@7!Uu9j9rvA+Q@E7o=kVLKN0co1^_o>+!4!$_r~Dzk7OY%hg?KUK{5E zz2i=)^3AX|_66nEp6f|9(Whx+Yis1TR4y%?Pk|-F<9Da9`{uDcGE)6SpT-M^yF8fB z7?yg>yAE}0rkz5Tia4?l_fuK2_AHRwi>Uc8qtV#reGc_4<((mK_iWTPrb-*QEGvtm z{pq&dlf^#}hezZ-UBn5at>z*jIY`4TI37gW#+5<>jS;Z0}a*7 z0%3vyi8mG(*QY8pPOJ+q3fkEZ`0qUzBIdP6c*a4eww|LA=*=Av;i@xW%&vwrYn;C{29Ht}@&&G6W# z7>byHrrSy`YN><%&_?f#IR!oP;c7Qd*Qt{|WjD^W#M2i0M#GOg)F+zONgH2L8Labt z_orV}eBv%fHly@t(1PLtwog3run}=)*Ah$EsiidW-TxL?gS6U!ZhN`;{Wv06;Sw>v z`WvmXwVO-#W`k1L49 z*a&V(Ryt0cjTuvA3bxCNrNaxY&j=>msRarqNXv9+iF4dKvWw3CL*XaO7MJc~taDf- zh}~0*4)*G#aU4@(x^N6cy1f!v*wXkivPcyKX1=q-=P#DxAIlkDJweSn;7I6p95`~ zERR$U`5|&%^0sto;89o!-WG~yB%$0`jRa- za$mt}jdi&%J@pJ}R^7fA^t^4mSi(X7(D%(h^D`;*v~cw}jnte;UZ&dpX$oeUamovV<|e|FDBb_RAi>1>ZS&(#1?Lv9oMCHMF)lPfrr^J6sb22> zs0?tD4l2PBY%u~t*0HhOm0j~)e%>_GHpQi&5uzZ^WIZWHVztzaxox?|slYo2(R;@$ z-($#CA%a*d#8B}%Ngc-cO77dDTQ zoK-0r8m*m{u8@JKt_vS)gIAR5D~iIRAXsRE^TuH%kTz;< z4q0PWYQaf@=flE1`CYq8bI^=Z5^=+B{xgY^h~u&T)8dgAB==)BtTC^|AmgHn6IRvA zuAL)`{Z830C_eV1G`+1nSDhl)lH3ghp1Sr^=++k!xtil2ntq;=)L(K3;K^T)20(opMrCr14x_SbU$6;uP9;Q|}?S^T8%^>(M<1 zZv$WQT}5<(UQ+f`A!t-O5TtZ@d2iMMADz&%a%dde=sMKwJYsx9$`54YxotUrAF;m9 z-C1I8YwkW;09SMTFn`tf@(%g@^!&IPMVN5& zfYJaJ=V?!ih&xPPa~+~yeUH%b0#hD(kJ;%1;kqHh_M1U_!`&yefo^*4PwVzNH9aDo zK5#65@^!}2%*f>w#wDU&r5<}{O|YKz(y~Pvps$>4lEnJFx z6c5<#8bxFkahihKdZ(&z5q0Mk37qbhFV)9QZIrGr6j-Hr_X@<1nmk3#HZ!NQ&O`MY z+^ep;=0F83uQU)E=`u{mNm17#YY9MaPd`T!*_8((^w)WAMjbl(Lc(E3B_W9;K#a*N z#N3HB30nJf@7b{{)(@J|rJ!W;#S1&b1OENahF^UJ%21^KA~?; z0=U5T&3)6YydsuZvg}LPYa%LSuh=O6=3Z3q{2+F?t)3Bu*Frs&FZbEq?xR8lW3Z?? z?Onx)zpy}OpM%(6G#zZ!<)l=P896q0vZUkl&))>EAs{U;b<(Wrg|CZ1@bwzyLv4MD zE`)OQLQOA*I+JXTDz@@zK9}2XPV{ZduT5{uXCE+8x{70KL`)ggNn;z~Z0v|$L4Y`u z7QmWUF8^kcjF>EI*+!P;8O?j1G9XHK0v=^J>S=}{arUGFW%0>^Wu@NrhlYCp`N41# zjXoqORGr1BmAV+PSJ$!+R6f&s{!k%X1o_n%(WHW~Wzyi=gz7?m7B6=3#wKqOOWSvk zOS35ym273i1V8iUo+A@flsX9$*E)aI66GiT-e(T>VgC8GFEU7070X2ULjrX-gW@}t z66uosBAN{g{(gbyJqoYiGd{1seZoQ_<&Px7s@J(Q6}NHAZ?CJT^-d%uCFNN(*Au2Y zJKqM_M10%LC|-s@ytU7THv3W^^wc~I#%pcm{TeBhCa8qzA?BTxvx3nHixtK&v7S&ze{C)zK?-iUV&&y1AVT-5wQ_Jr~Mx9+6 zr(%QeW1ZjXndrILpLEFT=-Ip23mFf8olSp-X|`xx#t5RILfEAIM0htzec#g&C{ASN zLf!aOaQ&7UiLB3YZs7wbGT4(3&(QH!_**r-M!fU&4e{CT9i7}$y;oW<+*6qfwDmgB zM2Wq02+={QQPB56$^8lBu680Xruayb$qL8tRPmk+3=FG;$R?|)zIAi=x#eTbV}MO? ztL{{g6Qk{!9*LI@9}p%kKd*{W<>WQGnG23bh1lzJkyf#e*nt07QN@ybaCVGn64&#z zehB#iOGe=1#gTml(JJh!t!~8PlC`{2mN`V%ri)Te3Fz&+3yRof^Z^PFG#fRZ^zzk102d81BfNj6?xZIn=0>Nm~zpEu-E_AC2CPyqAv6{R@((K?GEDbEmv%w6gtqxG&zLZyu*j z44=5ga=39*fW9A>fQJPT-m`l7_S0D&F(G{lSjHe}Oy458xKW9R_mAfhTB<1tlvt{6 z8x*|8xa_n!vl(vnczO}*%zo^Gq36v3r2Cl@3ZnRG_#r5Y4BvrNY! z7YtU#i*8HQ31)A3&@J)Ou_ICNmN+R3pDiwH31gF**9R&)7O}Tw-~0&%6y=#t;@Tyt zWI$B5Lm%A0d{%M3OEeB~HmQ$9Us_vpe<_u{Y z_7caDux;vP`FngWf`Vggm)zTUZ;Sv8W~_SyZ0lV`D`hlFNU8e4Hz$ntaaRZNweb~G z8bu{D7F8P--(~`5a_7Fu-EHfgeOPhrCdh4dsXj?FujZI+oMz}?_*yY|LjDzE4BS*k z>_Za-zfVLO5i)}KOy0h~h3iHC%UVH3TWV$;UM0Ms+^iEaQ^*Afy~SZ{VlX!v2eSAK z#MMY60sPO)(QSB6#79&N!})@|OL;H7-WyFDRwT8X1(YQTm<5!M?Q9q8XNx(CSs3X_ z5vFVv+g8XMr^d>8zYu|Xek1FckXYJJtl3QIF;Z+GEaY7iz!E8uX}Yv73GF*0>V4=W z*)hpEAYRmDB%pk;ReqvY%VwrxbzaXY+2t6%!@qrHYaNfDN4$!Qg>#@m7=Q@CLljTo+6TXG&I;9c(q#WywSR?<>wegY&a%j9Z=}0~^R^Uh zr$oBved@P+p_@9jkgWTSKobH!oyECtQs2f3%;E7AOYkC^IcsoC(LbTikMuK zi%=3iagt+W!s^h}7FlH@JlxO1oBaA^Xk3Fb6P4s-aaITUf|hPfBGV3}p_YUE zQ?X>brh1rE2+{~xb~|i7nUPlc%-T~yEUwXwFGBWo62=)Ksx0TrMj1H7IUge{9klJD z7X(r3c@>DiKINOV3hGh(TCy9<6sok?jU^?nnCtMiS)hE#tKAq9?jemzQY0dK#RO`w z*3k8}aTsB7hOc_22nAerbt?cJTZDY2OZU0_g(6Z9EA{tm6yFSy#P9298U%6W??wcj zT3{o#vUhccpSQ6h;0{ywPhFKn9+)KY3nbKoYxWGbjpD3tD7D;V zR!sAJFl1dpnPJ$7PXa}`b+tXvlY2kfcBA_Y{*&IzWjrqYY@IZ3Gc6gCN!GejXsdvVscBxt9%2wD%{*_YGx;*^ zIfaW!$_B!N!ST;?&c}6)WxpB%N*@%nc!rSW|a7KvHEO*u@aK@lU;oM z+|-HHEL>xsJvQO?uXed4Czeqg0(ONpksNv@+yx$qV*u~^QR7ON>&y! zNy(HX<=EG-(t{F)M7O7ErNNQcvd{@M zTob!%$0?VIc@>aDf=U@y#l`58f;=Q*8eHVwK|nY|CAwphL(=w8aP)P1T{jSc`ja4w z*^wdiJG(wPa$8^04yo$ilTl)E(G!Ryd{(tC<0Wf++fz;u=Q^)Pb{DEm?S8nWjZHD^ zcG3cN@|N>rLMGCqvg}BNC&cq8p(r4MlsokMRL)fLjn!PrMMbwtGrQA73Uzbs699;p zQSzzziFsBm{9aR-1EzG&lA!v^n|-5@lqz>(>@)_P8nGVzp%|b}m{*NrS7=3u zD$ZLo?T=H%XvI0qVxZ5^ZMkq)%e>n>ws(+phko+%bYQcLJ|V5h0TDgp>`NUiYA&H` z)u-YXu}|yhy5}*=b#D+miQd2ZtH+x2%AmQ-@y^- zQ!#gp^t#bX3AwHKrRSN6LIx&t8v?~drmXE`HbTe1{?py&#Ms)8;oO-1vk}orjB1)B zWbDuSMsHVXHNYbV|PAk?MLU zp`jtiU~#uhr)mzDxTS@;o~--h!>Xf_&c(yTHP7l7qxlX#?b9$#tp{t(Lc`rlWmLTadjrHK*%&+1b7`p3=?} z^L@Yg6n1#1yL~4$HkxS$Y%B;anFQ8?{L;sVl1z2;ZTIHe=7p)d(JJjRZFjQNOPU03 zRBHWN3*>dkc&0M&6*=$4@!k{lCZ1A?mVAqT3xuzJ6g%`gzRCo>&Z$QbnX)8Q$hate zHeVANnduCTpt06+geg;v)eL9#kRW_tX+njUx`haiQX2&&8tS_iv`4R+r}N9hlwsuw zF~1xJli$8GqHfphb{8`bLL;2CMTO`G`!2DdAXhfdf5JWE>Qn)v_rVn@ey4G50~e*<2=G; zmOxkXBtFg_6gRB>aQNoX25xl_qDK?KMYSIZ8yUNrg90a`(=+rA_r|^c^E~x92H_dT zXTnQAc3uBcHCD2ooT%6Ui;3Hy7wke3e)$Y)8eth5NE}ss1JD*XQ1(eJms-ilHc8Ht zHzZPHw_8Fl#@x{&5Hvk_2A+q~C_4lfWO4=}w{?oEz@i4ct< zk6Jo#4|*PjuM9W3CFQu!I*{ENU9+M%Q!lu+d)H_31bd>~(O;hsHnC6nu7{`9B5~Bt zex1RDDT*;oO-&v=8IVMRvl58YP2&4NP4!fDLyrz0>h$ZE(!QD%r!<)>_)3M-VD`^iu)!d~;dZtl^5v+nB~NDu;~0;uWfVo4n?%@=7W@yc zH?Nhk-$Z^5+0DQ(FWlhc(2*7x4#VtrDwZ=7wq2CC2!tmd~st_f2aDgdpq-0$#W^{XX=RR z`2oEsF}(D}bSBE}{9Oars;;D8-f}s-jixHR_oUVpZ5fH`kC@V@+Pgg3kIY71&`@oE zTe~ZI;T(be1g}G~v5|^;6u(N;C%6i6wvhA5QU8R;dbWjJ zVxeqoo5N@;K0g^P=W4bNu`r)zf1n3QKg5(ecj@?zQQuHRN#L$U7$*nTJh&5PLac)F z)MQ|lm}K`lEB?-roNm~QUr$sJzE4T z!Y1}b?G4yU>6KJkNM?#mr>F`QO19ygpU19RJpF3*^lQ_n%stoj+E1C5RFhu*RV%z$ z1Gv63bOFN+(0bY-A3H6P=CRY3Hj_59J)#@kE}BmHUwZ^7>qc{9q@v!*okp7oQ8prd z(@chW@4@LBmT4h8BfTZozj|}RQ;XI7g2`> zrJdUBrrKV+8o4HZd&L|<2mR7->1h+`6Wpa6Uw6MEw0`!AUQ6Z_$%(HS`NT+EEE++b zg~@|r1(F()lHWP_dd#bVXHUya6-ik$`%(&8A&JLQ>&&6l#3Rm$EnguEscrFKdvpUSG0g250nf8aONZ4axe341D1V~1_!!2lM$%-q9= zf05cf^<{VFQhqUHbHnSt!eRN?krbifSYxR=!TKuy`~oF_{8Xg#l~?e+>Snxejk|3+ zk-liOe`fs?XZF!BOLC?>QHDJC*t`j{{Ds4#{wP^(8ji_+_PF(xg% zj>V|W4A$vI_0QUBV+)-VtGR479DF;tpjAm25+8dg}?edXTkt>FKZSjSiz?ACFw@CkO35p z?ATX3Z=s`R{1F6jJoPbzVL*0;>uP{^Jw5Wh)nemyrF$1@=@^S-qs@;$4+=kc;`|cL zPLjc9FRh<4#4tSd?fe=Pn`hsHUsTfldXGI1x5H(eadq>BCx_rTNoMKcaqRM^rhe4Q zeytBOx<_c=p1=*RDiw`cWMqgw-F!ZinN}j$s}mLeY}X#VB3}mwE9`ZwUi@GNnQWhq z1Zq^>5ZSwDK7OZXf!d$)lgu!$V6Um&3ie*r^PjD$^K|$Z^4^q9gEb z*j7H!Ogk!E60W)7E|lkChFx{t9`NWphw4-NcirBI-5pKRDtRqk# zZZgWPfAEFdZ`wL$*@ax-X|188+jkAqAYd_18o1)Hp>{mfry^kUCTr~iw-n{4 zrgF=N)&RCo^3C$k#)Osab`WXRD${wZ5^>G^?y7#_;8R$?g2(jm^Sq`lgz-*U@|KPH z#1C`<+f!>bF9gxaG8;Lq(};}hhkDUoJ5*NR#lT+~t+hP|HQH^D^r9E{+Xtq`5xpK9 z!a3QgHX2l~*1dt*`Q(*rvEOjK5&DS@X)wj3!qg@0a(bfHhOaj@F}0EFQ*d0VdL1oK z_}5bm@wjqHB&$=IqY7Q_!ESnYheV&lq2NsTJc}ixrHv3;DUeE&^u-EPNOm5?V8J-QR^U$3#=ocZ42fkV8Of zwD~=!^C_4Bgo+t9tIqd;#%`+kl(`M3Ca2>RGHR<7qf#&x3&p!6G2Qqk^2li z5YmXW>xM1CN+(*+H8`X=ipx85o7e=BD6K06nKR^n><)r}lhCxJB50yiSa4T?fPW$` z-ccM@!KbEX#)vq3rEEvV3@z2oRKUm+S4^qVENPEnJZB_KiM@W(XB8qLnGH&Yvf$V6j2w{-xq z2u$E|xH1v6;}a$1pa?)mbSa|+Mr2x=KJ1Qjjbf>VW?@DkM8>{S|Yrn!k$58(hxYQ z#KBaPRGIk39#+}`GNs>bwuq?FGkax)$(}=xP{S@yF(*h!fwz8$JhRGDiVCY~t?boN zFMt6*(N-&O#0vDR-+cAi-wdHW12K0BYBwbnUM7lR!vu=*j!N`{`*HT>r;LNq?*}~G z&c{ zyl|SFy@+Bwfp{DB=~g8}Z#xFRV)Mh>vU7DPTB#eT!> znAin~X@)Lid8|hD8IAs7;yfXI3@nSUj#b=FoNxi5Sc>&LSF1C0qN)q0t>I8BH4abt zTPh^GKd0ey7ms46E{SeH`?}f-KP%|PE|e3wl|?X=b~`_C&zRjR3%gTmFTfM@y6d3n zUz{f|$oRIGfyZdI(6F`WCgCJ9_mSH3@G3JDUGCvI#c0Z$vi9QLV$v3tpXBxOIfF4g zc4EJn-4hh)?(5U2q_2nU=mYpPBw0`)a|A&&(Rt4z7OSw7LiD-JGlfpn%`lv5aDztu zDD_Sk^cx#qoN-6M$iglnjpMpMU?P8bfxElyXvN41&#R7xZ87uZW@e(ix86Foz3$zv zd-h!Sc}XgVwbcb&8tM5J|Fi4Yd|u|sv-lOvt4491v>Px zU4n;*n2_tNsSfmEnM5=%7I|jfSV_YMj!NfEz*5eagqHlLBuXTRXxex)=1`U`;k-Rf zk)HreyPl5y5M!UuC*c%ZcJ_+mqv|*FvO7C+O?|@l za3G&E{}Q3$B48WW%C5IIxQ6OBK2~lfyaxx-CegO6x>-8;MIxT_ex?5tRIx_R{9Ee_ z@bl?%Jd5Hjn%xzWu(_g>m{@4x1Udt75%19DhAgWMeP(2dOf?DGX?obC0)ye^L5T+u z`}?H zxmAOCs#>h`(Zu((;65sssV;7B8;tAy!$-vrc{_a=UrlDqkY>7GFTdO2D^u!Fh7&=g zEt)+&LbP8|@0fq4qe)b~Ur2%w3ljxB-!|?T_Gwj@j=$mK>Pu8RNJ7-t9j|hoanhqT ztuV12z}Yo!r;=kji>8g0@sjfxLO|E&R^!J3`&eubxX%)@(q&9nnTmQoND76{#poiv z=g2b4<9mtXJKWMRv{h=$*lB@nFGVS3@!mAUG*e7gk{fvi4S}RLp^{CEb_*i1dl>=& z0T$PinW~p4g&qg5Il~@-SBu$7ds=R_nmjbN%!k7My=gk?^nJ@ zo%eec|XOKYgw_o4K>mjT6`=B4g?<(@I^A*ss}N zkKDlC((uLcL$vX3LTR8e`%@+`3-=s(k0WZHkw09k7=*3sLyIC`|Iy-c$56{+#QJM9DQC z!6zu!FI1OXnBSSxH^Hejt;X;CRMEG$295dV>=B8*LnEYR_O>^=XiU}_4T53Hv_O} zcyFWS((Ot{bEN>vnp)!Bm)eNhok$o1`jVr2Ts(2w(X*^c@Ns$CIU$nPC}hTjuQ;EZ zwZ9YX&MBn0jRJm~mx4NFxOK;5xb2Z2bJ&WlxvFel+88f@<@uyZcl({is!W`GRNf`q zgBkw@6>Eh13JUfKwzTuunEn)ADyLW}#{yJKQqYa8r}}8&%ION8OpVw|oK-qEo&BM#ni- z_``xC!4B`d;kz8uyt=R3i%JJ*48;bB>?LH!Q6)xlDC6;Ol;YEBRn&aed9&{7(W*Sqk&w*&{ixOPZ>k(@FFt{k}7Ep#aIr`hsyLXn~UnBPFGyIo7tmtXeYB*&saJyK~F`Zo|j+`a;JL0PqVTf4yY6gHA`RN zuMLy)i$7UfS-x4$&CtP_VK#|EP>9|(mw@gmMJ0tJ=8hCwU?qM};ld1$EiG?K;rGD7 zD$5BMT;e&?ImsYsz6(tFiX~&ziOhpW{XQ|C<1Q(}SD0Oguwls!}-UU78Ym`@GvC$@%V<+WWh}NeRee z2w{;a?`$dXBy*q$+howMU?L(A(7|)2&Z(??}cf~Md*s8l3CP>`8 z6y4$WOa&GarL9hh?-aO7YGa$u#eI4S^5g?A&4ziNs=`-?!XtPNBFMRXUZ5oBG|35M z{w=q5Lzh_5u`vjBe|b(@rtSm3Jtx~;8@fsn zE?dSv)*ZPz_xy>$T2=-Uy4#)kwMJ$wO3H8-%DRA;{vBgT>gnMwBN~p<@QDWFCW#e6Ms=NI6dtX=uu)`Pbb!uc!^<2mwMMg! z9(E_`i`BzGnf*MfWWU8Ok5lD`)79f|`Q8u3cdJB5=dKibClu}M<{e-7kOw5tK1j@v zIj}j(k~+$#g6*c@N?-X{vOP6EggwD|Z&tx9#8mUIv9i!f%<)TU6uSm-}TiQOy||4M1uHa zC>F)~%7f&*-^#-?by3nWLiQKU?4QJQN4HL$*nJoI4zfs2X%yPq^0!GOD0dPR$D!G= z3aUbs$1&LhAJCCB{Zx6;mm?+!>-=c4`%S>KBD{)i@U+qg-uPJU;7kg*icp7QZ6_$H z41OFQFKR^MqGbMtGL=6w-(NE)-Sy4&L@PEYz}ob4VL^UPqu$b3I)gG*e$!jAg>tj` z$_KnYdRdWw1>zcu`)kU6u)k0&iIHid4yGH0N9a7 zh{ey>U+0gPb)ZcaeS?bs8|76X7 zFa1;Fug||){{Q#!ub%%C6$GG-{#~g57gW&y9HD<8gMQ4WUywnMG4`L4LG+Jw3;$=x zpuYi4AYnQhU?Tn4WFI6<51cdnV50#EGXUoRE(&N7B+Lk$|L8Ap&O`%nv;5G9{u?R= z&Gnj*KXnvw|2DCHw1Vuet@b#QicYm zx&ZBu#*bhHKx`}kv<@U@}bP(i32q0c76)atMI{_!)nHjo}Yq;ZHQ&|E-PxyPyJiTmG=<-wmTZ z^uL5Q^xv@!)BvodKZE_8Rz)-j~P!xn%s99l+P+57Cc4|8Sy!wIeWhn0_6z zU#9Vop#I_czqpY=lBQPXAbx8*14FwXGm2IVuuI=TgPxgz2H=EZqM-wrTiAZU78XB0XaVO)>RK6- z8Cp>*DUkox!ejLQBM<}tIx>J~j8j-hSeTZUiG`My1>o;uW&@6lz!4yrVxj-Jgc&&M z8~&xoDD?9lGf;*Rcryb$B|qLkIcA2R_a14$7=UwnK$ihv9{YI&>iW?n;37eQpovV7 zot~BsASVN~S(q4U>8WX%NNH(FAARyy+&bFSKKb=Kd<9rDJ4b1|A)LlhFhG zYX4Fe=mju@f9SCQAlu(%i~t=BFhzgWqhnyCWBEfy3+O#Ufq&JbWdaDy{^&1Imf`X1 z>`y%acKo}HnVyabi2PsmfU=Ju;6G)Itbf`9aE>wkp-0O?$MR==w9Jp=`FnkU?2(b_ zw>E&XY>!ar-)x~}Vg5HVT7duVH$5OO8UNK5dd5F}01P?9Bd^@=ZLqREerf(8V*nnr z|B$h;JwmpB*JEL2{TCT4^CQ^%cRf~S#y|QCFi|l-K2H3m2YBica{rr*j*aONZ2p@J z@W3Or(4Vr$W&SrA9UBYFA7c*0GXu+?HZ#yOKR)vORu-6ukI!L$%IN>}9|Jw>ziET% z&+!1-Wqy2=`mH_&Mi!<&eZauT`fCh1*y#dffp!2ZB1pm1)exBaAbD$R2Y}q}aZ!f` ziCGz0<3Bq0$Auui20kZ?u<+w5!Y|B9$H*^8Cm<+DD=ffAD?~3O%)|<;QQXk~UFGrn zM9^Aaz{F7B+}_a=*vx>RiB?#Mk%doyk&lm6kd2>(K?qpk_}Byl1c3#J^>IV z{o5qu_gv)n#OCw*;3xEM+ox;x6zX#+_O^t90_S)Sul7%TMtwwvYqXuR-Q z+s(RV`q+*AcuQ>Be2(3E#kPFEn96$R@d!GYY8M%+f~hd@TbzE!;j*v?+!IR0z)TpF zZDx0o)swM0{d|bY_QU$jdh)3&2-o*Du zoQ$lCTA-88&R=Fy0j*aD(2MT6YWzLwI7yvXn|@}~?y z2JFgW-Z+}MC(S)Pc9a4ne zbsC;pJAa28KJ%GLD!)9j8-ziLi~Qtf{droE``D+fk1-y~ni4A$zf3^#)tr8xK*L zTn)$VSZKF8&@?uqS1u6)wjZAj>rfcq0353^cvwvz9oQU)?Lrt_?|Qrbvq^&vGb4R6 zG)03hJVf7e-&Ul`mE zVDGClto!e2274fjB-b#XKqZp!c9iX83JG<>d!O>UWfUBaSo0O5uT6oTBe8F=zd{w2 zWIC2q4Dr{a8ww<6BP^}}H4}U{-kJzE1D#{j4PB1Tfo<)02#VhFvwSlURlZS+rFVJ$ zwe)U8I#sz)I7fVKy?~RQxOAt#TSb0Vz+O_J+y{vo+~A^nLt& zqvqUqa2qTw1z-V`DJ@1V#aS^pgZ-tf0j_gTOYT6ShxLrNouX4m4zw`4Ej0@c&+5!< zw%zr9p+5bMy;?)kXpBYFMgEvDEPv(*8w|Q*yuj?QbU`Af2hx`)&9{K*N|yK8G0Kwk zK0$NQsDKBA5U;Yg{OxY5m!vLmaT|C?I4qqwwDSgT#}j6|cZKF^1KuS;S$x7&k80z- zI$=ZZnyvlCtGBjL5Jwl32aFa`C@p;0^V}GeXox$PeDd>jTa**H=)0WsLwr29VE)ut zyTQ0VbN)}RZ+eqyiTMFc+jXb&AgJBJ&8o8-(EJFRM7?el=X2+cq@J;m(2P>_6M|h20z9uzRJ`p?XF<^U*Y$wXOUM*}k zAU>pA#WIkN`WQRX3rV*)RxNjsCyr1FoB=t5B^QyHBP?+s91lHF`8q)PthmV;E|E!v z@Jw2ImYXU_MSGIu@VJ~jZ)3+(79yR8MXH?vM!_PSdjDGiRPYKDCw+YozHo^Jf`tgS zn_r@O^4^e4M6QGLz3OVtQ8=C$jf((9)kn!RiWH^ie`MFw7=`gJsK zzZ#kXPOugb%lBu5_ISc%mH@Q|96-6a?0EJWl{{M#AG7g7drJI={|O8zPQMA%gHLF(7W! zz+`t9pvp+n3xBF^HU@!&5$j{TrFdO5kyJ|1f?1sHk5yG2<{UM`Rj;;1cej}8p!{b1 zk%y7LYoa_4pax;vH~i{U(66H0E=PwkWe-DN(&E(~aUUj#{sL5nWsen25Je59*+1#I zatKTEADtQ<_UV9yU`|laRi|TSatNbm3{}RO)Zx`W-uQ+btmHgXaiJ-*CQWBu5`H`G z;uAS}^(7DTQVJWWnFB$@D?3l-P|jgN9y7myZVa7H{Y%C~j+&#~Ej*qRDhg(0`dQg( zDGyW0zu>V#xue)E%e|qc2Gy-tkmY2a{WYPl2<1xfFpS=ux6WCOrFKqk&4Bp-4lD9vCg|+#k=@>QkTl#TBjW z&=G>BXukF~ax>Z4!5-~tP>oA#WGwg2re$fuWI#d|UIm^DvBA^9N$LucOelb=V<=yr z364pJx=Bm$Q&%l8m%vXFwx}IH@)emXS7q1{3MTZ`4R%} zF-daX{5^oAo&ZZ;YoK{IKqh*LQx|+PWhVxHGG*nTqAvuV%Jn1!ehA&LFW4#HC6TnA zlZ*vz?pH%8hNhWzd3KUQI#0olTZA%e;TgJE)x?E&M^_(&TMAdifI(%N#UtwxJNUgX zBzaYqfbI$_eF$WXcOUr9fu_CYC_=1i`neqPUo+nNgZ?@oS~3THn0cA?z}IL*e`Iwe z6YPh0yp0;4gAhX%bc98w$ZNqPhmOLyrdH+#Ornr@jr_+M662$-9P22RS*Jp{+U}Fh z_yA}7IN@On4fsV)YEuh=Q3w$S6OfVt`M}EBy(t!G3wS&RSR?Pp#v| zTpXr5eZ1Wo!6I#4p`*x{Bs9ak3;`^MZoU~ll7+_?6O3@7KNDJ;vooS%;dx~KVb8&u z_c3aPWPsO3!JBe@6=VHOwb#hZVtJ9y#QHGTGg=2Yi5uHJ&AhpeRO6&w$rWRoAzVfc z+QI<*t+Dt7H&pDE9cWRnWyuj9!o-Ia`M2(L*)tdYL(qR2OwI8w(47@f z7Ogo!d2BGu6Jxa7os`vWR_5*Zb|x}oRNClY&2F7u;}43f54%95=pmV?9 z5I~CxeMVcI;JXPyi#TcRMvq<);zyJ(4r~j~w${ zrLW5ui@M0wA+tFuu#FxTK3!;bD0QpcezCsjmtV`-BX$h66*K#MydJXW2Iut~N#K&1 zpKFw?v>8#X%FL(S=js^L{48|r^9d;aQ6e$&6r&IQ^1g4>V?;$KzTwj>J=n}uO2Jbz zAh|hv(LwV*F_-u0#69O+sh20LTS&{+)KoZjpw2N1!`Ajs(t?lYY$%;WHG*dBTb?~wE{kc#w$T15>wE76q`-lIy?Bt zor@1kxv$MaQd1IpCpqIzhuIUMzu8PvPI3{fQ6$*rbS>-<^G-nm|dMH+q zww525eFJlh;txEeN%1NgGE^n;@wjTCRs>M{o)wj?3tDdYeYONKovEa#9z$r?kO>)hCN7<{0Yq$QjZ7;!BjI`v})rf3|_{MACVx#Sk6cLpbwP zR*Ed6DpCXUji>xszC|VM7sUM9&J~%lY{MJ5aKt06&%|GHkqNc%c|?Dcx+=6eJo13O z8$upq9Fj>tb4;&gkEcjQCe zDEo?z7`^5M!$Xc_Zh|lh0MGrk!fiHK$db?+R)%l{!)8j#(Ud4vdk?aH6fzpj-i%t7 z&cIF#v9Rx+vn5xJNjt%@S@SO5d!};?CYO;c#XJ6v{q~F1-U*Yd+nn9WI+IqFp=qQf zGR9rg-XBKod^or;?j$V+DB zrOM68qu3{VzRfYp!g}DRUgWBG5GJe9!jNqk@}spCir-+p!PEhyuoF`lLhhr43SV#gQc zxbF|HYQ{CCql$X$3BDj?z)cotVGZ39ED}D%}HR> zeHCvMk5XyaYpc!VXhwC@GmCL;Vo%^ZWI|xq(ldTUzAECIk-6lfdp7zcZq~~k3jz8f zx*rLxoCe)>U-8*}os(Lle`xWKmm8cUn{M;Z9S|LEn5~o1FehpUTux^oVUzt9U#rC~ zvTXb};h^cSuH39r&M&+?W|7=<2O8eM6GycWY}IlLhJ?NLg>Qy0$)r{E9=sPv>d~sA zGCS`?GJk|zM!49Mm6d0}TJ@5oA%PWckQ@xi`K-b#1a z0Fhy%kA6Ol8JI84ynmN^y2S2+ZTzrC}w#Sg)hve z*AALj3abOrE?_dw(IL>y#$Em$h&;zfqB~)#YCkT%o?88>rDD{s2{HT7Ozn?rQ@kxqfhVJF6#hELrJThU7pXN-G|9z zZHuKtRAJY+=dUg)OQ^Y`IH@ypO^nFFFq8*{%?=rfq}?^MRH-bp;aczGZ4r2yV~iKt zUa-Kmp~uel#wt5g(eGLBd#%ZfV2D)J|~Ejc?`lf&&=JMrE>rT*k%r-72M9i+Lu zU2r3CAjcS?kq4)F3B8<|n7rv(kMl}wD78M=R~!cz<>*(K!ks~CQ+o~x-Z0=*N=ewEvjcI)Xa^Z>V3aivf=i;vk!iIuN&3t+Gl$0rHco zG`amo#H_f)%%7MNj|!*Y{NSYRVUP0;E}ok^g~g^hnF2p68AR7S17)(Mj5mY`me8-l zbP-+NZ4-E;-Y@M8srmI#a@@4qz=Xvi9jtC(Od@_|%0}HVHQrrjaGOPMSYANkt-6s| zxG)0a2m?10#jvvDUry7`;XU^mqm)B0vUZO{Se@;e?G7H~Tl25CcK8Ou{8?OB-e5J~ zHUy~&*4u)YvSMvLo&qMF=`fL}4q3Csiby7Hm~GQi03^1*7g5Ogxo(aF5}HUS5vWcQ zfd(qK?IGMVusY)D!_Qp(;e_uI{;GrXl;05u@}Rp*W)lrD>`P5H`=S+H^PB>2L|O|C z8K~u*eGlxMt;pA72R($TYBwb+&C+8z!mpdDkeqYTn9&_Nm431+9ugR)Tnn2j9Fu+} zxr5IT6~`&M7Y8{st_vIT5{Tgx1(ZawPJUyMbkwXg_e8T27~tn@AZ%kKIn1y<$4!k$ z0pE$Dt8FZE+#`%@y0djkIt~AGiE$dPAzfq^%|@xRIr&RkbI{_^Jt<@y3zQTyE{Ec% zPsjF+mz7aMyo78cCm`nYKtayUCUtF%X-Wqw&ersVd06bripRO&`z&=XyX|w z<6(j8s=f)%`Cy~fKeXc>f&Z++Zppz8!>RLO0Vr@@0ba1U(Q5B`QE@ujdV?_t+ zuD*%!$kI-)-uW>s()5~2X#Fx+%uRp@Q-p|W+}>!TiaoP+|Mfl2J42RW)Etb27OFcgwCDqd?MST z?|;RU>BQo+7S6EzBT5YtnRmLB)8Uf4QKfYwG+;q5p%Q2{0cagz&Y`UzQ zmAiFv!`O{kcNwA)a$O|f_txiLlPtX1$cPAc-H75AXdM73{31Da6j-2%D~|( zTNtmYONOt{YjAHLz`AP!=BG!vk!{@tzOA`G?Y?=x%by*>yDv>)UDafDi4?uPBJiId zf@id3F>M(N`9UDPJmI;nO%0@1y?Kj#eQ6OsZpdOv&wP1$zNycGAMJX${T#|ec+Zt7 zEQZXNmfSyUQ}b2_zMa|i#?bw+WK%6!RUS|C1`6TYw%i=3w)qZX$Av3tiaXJnqM;5m zg?#AtAqhdM?DC|FhuPG--mn%a4pv~uN`uR2!Z=d0?MC~+f{9uX2id7q$#4p{-kK5N%+Ze3#o=5laV|ZG>AR z4fG~gc`S@G72BbE>6+)!Ey$XI%?@(7A=ds=c1*py#`}4m+RGS|^z6@*8Yry(nbAYA z_jLXSk$yFjoTa!r!|TPU06ic;~AW%&RRX8s~9? z75}e(mS9=$vjG{e6dZ@24UT#YRHzmFEc=ePnQROQUnwM>j+tzx1H0-)kltq{BSX9D zYeH^D!5n%WCJYj|Q@hA5e|*ZRX#0@TdK|e=6whQxYTkFC;j@7;}y;35!~PNypOEHK58yn$BGSoqWMkE z{)krR{(&v?@0L}uw5-o15di{u`7oUYO^a7LoxhZsZrJ68#v>(^TGomU{Wcfmnwr38 zQzIfyq60Yq(3WFW^`xyG82%c%jv#w|)^~CjblF4r*aHZ8JoG^E6bi+jXLVZM7+XC3 z8>S_eLj2{^hDk(!s|w@Y=>wx5_##yt7j-v1&7lo~oJoOv*Nuq|`X@~ysKGy*8yb=~UA0lX@dz%^)#xv6pD}#mPQy(E zo&ti~hONF-*C->$CWm;vQs^QC9~0QX60}G~E0cDrwyx-%S&cu{DodS4P#!X%aLd&f zlVi;7G8wq0UUw%nE|DoQrCmlp2wH(E-LjX(^(NAmY-jHyyyH{%zU#IMqA)!$c+3&D z>i(>iuJ&9;QzeJnb%_fDW!Jt3@nPvnR4a-{)Qwzxrz`ti+vt-=1+^v4MBf%^ivN|a zr^$WI@UnXJehI-Q9Akv#Iy+Y}al9TiYiNr1a=d|xGCgCZ%mlq{!=Z)uJRRJ z5K(1=_{+kf$S7V|keQ9Pe5xG>z4QM_g_8-Lz%fHan6EHcki!!6eaN5aLBQvsI82{R)>QgbAK2cin3VpSmM{(K5X0;fpKKil-xC62WD zomX0m-4{K9TxNGsBw||g6Qhn2{{Y6WYWF0fJP@lAO!@GR8W(OfTU zq*WhDI>4o;o2mGtAN%IMZfMZ(K@;p;9T66P@h9fhRm>|mp?<=qzq_XZcr1{=owCcn z=y7j8|5oA&!P8w;f1CZc>JMpU<48o!4E^NI?9irtuA^<2f0PEkc~Au3rMe?z|CVn) zH0FltZPetV3ZDLZ8|jc3EB` zcT{w*B1)^2r62kem`400nbOKr2RP_K8Y^9Cg{VUWtn9D5tnE-lj4zt( z%i9qb`-efb_4(bxQN5MabiJi{+;vL^;X&p@dB%oZ#zJ{UCPPN!XFV??`Ln+3yIiwt z!bJCgz_(mYM#%)fpcuQ^dA9iIMs<4sDXX+w8gcaLQ*=G`I;SeTp9oBxc-HS5G5Qoe zoXDqGR&*Lt>9`aw*Q;&1XP(WaGX9bMRB@jCW~735(HGm?f3V2-Y_fWXz^7HXi>vQ? ztP`xLaSV*yL%XQ;s+Zo}6i8b!xz}4W<;s;xaa|VB&b_?6a4p`u)H(hp$L>e@BOah= zo$o)m$aQ5BztNqjpxqs)?g{bL^%#L)o08>tjFaJLgcmkl|G|>PrB>;5H8EOyIx*>U z%lO<1wCA{&O9!$N8?@s9~RNlf?x0YNyXvUkqH$R2D?1{s1c3*3q` zJo$_*cxM!Vr-F{$IuW8^NUU^OvGn5gAuy*1FvtrZ!SY=LTG%+fJp*5FooDnVcswf z4qu28i{5&7uxsK4kR})#@g23BSkw_YCy8uq09W^My>W@hVa$EVjn)tF^5)+*V&zBl zoEz0?d<(r1lSX9U2V77PYCO?9z%-h<#tE!Nj@dZ@8r#aN+50wUnuejX96x;)h%AB| zBy#H-Hf;^Y50Cw(F&h0o&P0^>0yq3M8`*=b!Dvttw&YZ5X9gTz64ra0r&47`+SC8g zCeBqq;0KEi^XAzZ%)SV3iw5WXd}&HICV_i@p8Fa+XAx9i71~a25U)6=#7TVjZDGUp zC!%Gtrq*sBu%L|Qfi|+A_6d*U%truWAbv#K6nZluX}mvpQ>&?=A7Oog^ss_tEx?fy zipIl}!Xhv?=?oDgk<=_f^G1DDq9jlb%OjHs%tk39eOvBEO(c2dbH%#AgjVxbw7{?D z=|9*yi98oWvXzj7>ocf4xLcDj<=ldN5{wDs^}{Ov>xaI9M{{hYTtA#HnTRLgqM z;hH>`a}Rl*fr5c$AxzaVo2p~hchyIf>Nzo14l||_i6$tljpwz)zDzzsqHIA{- zsU9@H;J_XYOzn{^`{lsp&VD@XsehY>o?%Segkc)HIeSkA!o}rr8|l)NevA_Xas*Yn zYpvflYFlytwyiI2w%ZAwTw(-SyzPiamC32!Hh!BUYWLlHm9S2vb6hZCsv2hUfwb&L zOP^7~+)LLU+-Z6}uoROSw91gi4Z1g2NYEdVs7=0;Wt5a#X51&Gn8*UXNvKG5fND$X zNM#*3m)i~<*8|=XT0{W#^v9v&HMitt&P&Ag zY3DK~)R|plne4+t-w!9n8!2A`(So6Qo?grA%F5B(v#v;*o)aZv{r5=B^i^nu$+;Ag zrzY7l*U_@%1D>-5=?emHeVo9QDT2u+u`Q98q!DMVkMXqy!OQ!}H23Edr#{-J4^hE* zvs!Fy$!@8{u)Le~jsUCwkD}D(=5-=o1SPD7aCHX9)S_x#@2sLcaKLf-oBxcIOjd$h z!R4)Te_cPK+rCy3r3SOjGLG4|nhjAIs)u{kQQ0n~I%}(#x@Q}CPerl|D+z}`7TvA~ zPZlI))R^9=?eJ{9LdKR1<8b^zvvA(PO(Ip*#B3zh&+CSt`f$ zCz9(xNgksg?=gzkZhF3wl3Ekrej3eb8s=ebc-EK=g3IwCV7^+O(v3piliMgS+0d+? z54Wl1Zdx`Zn!gV9;h1~&w-^&%hp}l0jo#38K7}a5_g0^FlQka0rR?QbN_zQU(jOZr zM`wRnG*v6(ynURxb$Iskq9%Tsm8dERP$TuDzq|`E{1et%m2RkfVzox`V81C=-c9QV zOkVKRQ7RZid9h`icEM@l2VEv8nbG8q%zDXm$~~G2`jZ^gLFt>X%PNoThlzur6K4mx zq9`2W8hQ4~1%9CfQX`p(6aVH{J*(vl&@@bW=tv{1o%V7G=)gU_7-Yl1qik+%w1yE9 z-F7RT-o+$NLI3(!PmEdLUVUZuEMqBgunv8cHl|6s=?%LJf+-<4D2~X}I|_9p_xhU= zq*s3O1}YFGbC$*LA={QC)Dz55`JwVJRDUvwt9!LSHiPDY=(r_QfsL>t$P=O8@Y-{O zpTQgAY2s^>Ul`%j-N`~adI>xB;}iMTJHvX)m1}b40m6Z0rN@jxV@Ri?Ku*sv$h_uD z*()a|G1)?wrniq7SA0?UxvC>|BiWDuTayd(X_xJOZ6jqCDAF1{xZ&R=GoOAJ zO2r(LmhF~A(6=C;z2_&S#hpl08Q|b@I5JvnOy4rSlOE@g=aUb{1y|?F<^fLkS9gI6 zV>syq#;t~?c1xpLZEe?`yMn^k)|bLGr7(_9xm0AlmMWxq>*#8l1KIam7@;sN?h>S; za-BvfB`tLrtt*T}=hp;Ocm0FA-rrqlR1>C8a+|UmLZWo4_z-GtxH0$m=1sKVxp{8J zZ6XEC_}9L%7o}HO(pvImS3_V#C6=6CwCo_hpKiY^@e$+?bqWhh1*Gz?1bfHgL{o=mAkZNPF0w+Qv(&qXmsN)QV2xw%m6ZW zkT7DeW%FlRIzi!bk?BL>vE*Z8WhUOn){^*mx_ghgRyF8*O@bNKFX&||uF6&48P5_} zFauV=hn3SNlW7__{uyY5Fq}-Y*L+0{Ey#>IKb zyqwx?Z(b?(;4^qpZ6~ODa~WBUn>bb`JIrrMoS~f7u2|9*gFm4JDutmzD;<*_)=}lx z!q)Mmym8o%H$PbMoHQ%2Y=vXmuhT~#WD zc-`BxEGt^UC0QT$s)4bRc&MYE_QFCj(iM+BtK%|W|82Jk=aB>sUat9UflT-|t?i!D zsqQ|-5tVe=)b97fg&MiSmex|e?tRF zB`vWlh98M^VK{b9B@SO6g(4wf6nlD~lsZQKn9VK@$*N^6(asc*qfwvP#;xJEe z5`{-NPf0t?>ojSH+mLpugpA=+l9&rZ0BQR6VIIE8O|^EV0)0xyIfe>c zq)?WH8tWq*O|Y88DSqk0jpoU~Q&`=eRE0$d$V&f|l7VLVMnZ^8%eJ>A(MRHO-D6FG znypA6429KdBi1|%RF-5W5QMwf6nPLMl~bC@q3b|;I;zzYv}puLA{`}Dr=MjE{;9K2 zo5p&~?-KQp(jkb!z*2HI1rJ?*S&ZM5o0QwRdTusjkdwbd=s`TCq_WyIXNPIHcfg)h zM;7T%vfVC5d@v!{J*+#wG;Iyedx*@aodMx7hK?E%s6iyw`$<)jmBtR06DA?~Va9gJ z=l7twO7H6pQPMd>zx|9_C6oGG#UwH_=yM3{MZ`du7I9SgaGnSwpry?f(_&|%v7-iB zs5)bUB8Vm?G`W?bCKXqKU>zK<@nkQZu`e*MwfR9==G|7h)`A5v`-jOLl7-{?VwpnP zK3)Qs<8I|1G<;b8G2$hv9qk#xJ?(ucBzO-VU1?%2~d; zYsu2Qs0;(<0YOr2-Nw~#-IgRN#d-Vn#EYd|7Mu|lAQh-DxG9!@I^)z?Ab%N! zCKm==n4$Gxt6&I2y9y|36KdLm z7OGg=(pYq7W;yDe@dcjuVeMf>t~wx_JKR!)EMikVn~v(_w)2Z%rDZ}Xf_gHdal}T5 z6xHtx``2nLYCc5k`2wS*Yj8JJ?bNdgv7Dq4Ts~>yFJsUwPpYFfxUm0*`TLx~b2}J8zt(|fqA+Se2h0OF!Y^^>ciq+No z1c!3^5TUpYaQ2ITH_~~*lLTAfCiLiwGsN_+xTM~`c%TqJ!PS0Hev;Fa%!f#=N0M`C zfA^1bxVR+xAR0_dZGbbiHTe%C{j>HDi5>1A?)pC!78V{BmVfmBlCuAgtNG^}5*!Qy z_^|@`0`YkuG6eGHbv6(aG79`6T)R%-p8lr^i_h-l@y)d-edp8Ds~rs1(0B0x;3|*UmsUiQZ8m82`i|(^`nXikJTOqapMOHEs9B$8(HBPb zd`dM4j2MaJaUAZFBDt^Lzq~cke)?WUP6#T4UM_W&ZiUCu4NsI~P*XWpwPefUp-X~t z0G5{4(mP9}xT$K6<=+x1--Yh33sJStS{|oK4s5+&w?M-mS~B?kN{zZqJ^q=qi9o5} z?Xh(hLPq~j_y2Fn?{f_3kpWxEXA?9)Vt6$pE&*upyCY*x63oqp5X?b%9TG|enBNO?EUWuIQ=m9zd zYbT+IU`2Pa`pY`cMBqT*h-C)DuX=qZS6}M-1ys`K{e|yJ3U^9d!v@+@&GWRhBzdCP zx_+K6Pu-x?BwW7FN+6rR$(t(GpNV)03Qgm7^zjNQIS}KFYib^PXyUiWMh0&;)|^!Y zO6H43Q`!0p>HbvVDg{hExjl(fV@*JsJAatx;0!B`O{$~bcNYV7PDy%(@5l~%hrt&L zYL+YSF}FANn?y>ao!;w;9vVO4Mc|-H*_PCczw-#1&AbV`SbF;o{po_PXLUPlN)Ox}y|eKoVc4j}c+|lHhZuiWw>H zqhQ-$@5*?fLR4@UUvf+#3WZ0KTu9Y6Uw;64KLDTinhXW-d8dKE|5*bV1ULW%6%Cz~ z8JU=bMOgV?xA@augusr&e6M&~jB-=ioDeK?l(8k+_B$SSGKV(9OUKc%2i)T-6y79r zWw3+{{tf(z1O)zXZvA6+D9oS8B&5j1{{;sB7jV#P4Z24#PTIsT%$(yPlqxTGF&%|N z1O^F8ElKYE^#aS|{gK{~z|~J&vCqi~4haSg1qTKHZ)`Ad2mmAsDi9fsgp@@@8C}KD zA-)HSl}*&h@n>L8FD4mt?#wnhyRfR-cVp*(n%e)&Stud!x8GWpU$tUsf6Y5ktv)=` z51=|(9z_&D-u=4uG9Fo+{{y~brTDgKB{L1F>uQUP@2u{Pc;xG9)RHVQ+Vq2mfhtq3 zSmMrwz4&~%2-8MXqCcY-CoTmI?9kfM0e}GB?kU)Zv^UQBNIj{SQ5k8oy@;Af3r6da z-zfxHT7IJ`JDt?p4z$gw9N9ZLdCJs#qTcNX#)wrg6eypqFZ6l zqR=+I<3m0GKQ>>(CIt8x|FjRZf(+B1?itUS-;bE!rNueM6t0alqfv&RuaIugtKPj;HOGGR5(19noA+*}k*sBBm z@t2B8WNjj`Re9ysSLs)hO=uPl8d-@Ei}JYwnU&0n>Q&Sr*yFU7s`Vnz9PAk0+e`WJ zF9%l7D($p*lKn?ZlOPnM*wak0aPt!T6c3>R=(Ur5v&1KEy-d=@|}MgTLL} z3O(Hsmhl9TPuwH+KvKLvh+2yi;+^_`#mOpg>HZorq2l0SRcBW1&J%sf!x%bnZoL_^ z6d+&gJnGq;7Ocoqo!-equ6uTK(I- z9k()H_M(V-X&w?@B*#~<@+oMpQ6*2p%skcAZF=(UWHu1xLgsLL)!Ph5g1H6;GP{Ma z`(`FmepuX#^WS2Kxd*DxZ?=eS8~l(SQHd0#J*;%jiZZkVD`I!Pr@IXg=kf;inQ{n1bP7%-CAlSwhp-_Sn;B}cmzIPDs#W>2DAk=ReYJa?= z9@^>>vy;Wqvk9w>jvfpbjBq6~`$ct}?+euWZ1hkNd3zt4#^08HpbEGOHB>hVtxw~; zZSNK?>0Vk4bEYco_&^(5MX+ikHE{#$m=gjK%Um$bq}+BwRLhhcP4SrXT2TAw(5Km3kHJs?B%c5t^*CEgEzm7Ah5*(?=%JWuz?M$?V-=e(6aZ8G(agz zZdWcIiGoh(-q-T;$eVhc^6^j~M_xpSjjN=@^Vf4H(cHEf#n1MOR*^I1LAV7pDwWAK z7U(U)bAy7O{EIGIW>j$1R$vF1)SIArbf%I7n$NXq+Js!4UDrT>rjI0R# z5=R_2O_&v)6A zFv-U(d@KtbQ?vLH5jktCY_Y28Qf;Tg#Bwbf9WF*E*MpQ{NflN!Kbag_T{%;GZ0? zKUGYlPv?oE^R|ljA0vo3JCcXgo}x)}qU2dYQZNS0tarOu=;NGp8p(aX7WSWpfv}QLeAFw8;H2s<5+~>T z%>u84EUXDPB97|CnJrEq;QXtJ0J^B7e^E$?%06wLZ@#^sA#ecr2n}EcqQZovh%*Qa z^mSuH{FLy)RX!-CaUd!0yelIhQOj055NL=27m+8r+Wc>z_^%ie`L?V5c8dRYqRRk@ z|2CFie~>sng1>L99DIOycZ}a8Qh;sj%hhLt|406u`=luU%>B>c`Tw|2FaQb(3$w@- zvG70c?fU#C<`5(88>|X&BJ)Z;WVc=c=uF$LQ_4h*3z=l2A zIPoGuZTNu2qOCu72jR)TMD_P4EcK_gf`fyD0Y78MfA<;;g#_?vt%k_|SSvHJaLvs3 zo~!>j-%s@SB_tk?=N-0@jV{k_Io-T_p($wJkj0#_v@fh={O9-Bz9XYVB;v0|+C687 zug16f;Ll9A$a5g2Yyv#*4*>Oq)(RkL;OQ#mC8Jp%3Rfze=h1o-`&@_H9|)HX%M}?7 zp*`QvmQ<7r+mHiJ=x-2}h+RtKKdVGL$McQ^C++9*P5x+PesJ-K4m`j>-HoU^YjZ&~ zjPf{|$oTjUX75ln*S#RKM%C9eY-1<1b0ZW?IQt6|wYy{UQn7raD61>ir0=HMe)r3W zHkv%>=kEECc|{k1^XhB2J^gqb!^%vNIbqRk^O_J?{0~y~Nf=1+AM!fV;XB(A67Uad z&-mfEfVhDBsjVRfR*T#r_IH}m1$DUIz{J1U!zAz&@Y7v58#P!icnAl%VCLHWg%UF+ zx5$XfAw~92YKBp$v}W|xm2i7QQY zJ_zX4WZ?Sv%l48E5-{E&dQ_;ohTv*WvS4^!{kUdoDA3`k&JH=GQLtl<(H(@W{B-2y zT`y4F`c#7R-p5|8?y;h>hPty~>&V+DsliNEdSWBTp<|EONnxGGbNH=V5i*{^!tbIv zJVjcj)p)K7Dg6V>jX^nK$w5i(rZ?Mk4xA zK&GuSnGWd(g=8^F8!vu!)$J9gEy!3_Kn8HRn=}T*XxHk6A2S(f;~jmUq|uX}2Y z1|9AU0_d5=^X47|h+(M>St9S4O_0Mydy>d|B_!HRdLS%|?dRyqOiH$6!0|l_%ZM}L zkg4kTyg)G9;PEJE?aZ=d(s41A@pP8F`r`_uP(%59Z>$q*mY%o|;__6QxZX;n0CX@V z<7{=6Uuuj!l~HllBk>{FPxxFLAZ!te>|aOSfbTGXt*P}hFWk;rjR5V>`TISyCfFY* z6El;&@*RahNunbVQ~uNCd#HQvwAoJv6$9UzPwWqb0aTsq+k?kSQp=mbCv0B{_4 zKwJsLA|)b39*OKYzkgqpMivD6?m%St{p^;;@A*sA%oYcO+;?EE_W|hX`dI#dSyC3cCcj#0%9pVI@)U8qwsl_eg3caN>N@Ww_S3I>9ZC#Gm+9TdPR~)s zm^$Qv1~q})SO#uDKvZS?aO~~XBD(8`pTV(#9o=VZQ3`sd=dA{*v>4 zt$>Y(O*~|K9|-w~(!XW`l{nD|FacV>1*yU3z~@B3y~n(gj+%#d6_up2R{JknCSPr= zH+>FL7*tkrOycp!WCUj{}pfu~uem=U$Nm{(NZoO(CJNK4C`FrX_^a| z&nWu7OzFK$Gr2!z=LmOgp{hWbyJEBe9Cv-1x6axg*NefFLy*3s()N<#e!1boX$Z<@ zI!k^-SeEFgDU7^$)>JO-R(Z0M>55Wd8l`hb&zhmlrg`KsU>`T%L9W#4jmD)g_|nRx zZdK_Qe_Ma@a>7BU_4(d^Hbp~%sYIurS0HK5HVNDZMveuavWi%2MN&DG6y^mJOohry zK-V>;`yRq9jXTIODoPZFD;->#<;d%A%tAXT4EfLh#n?MWN47Nq!xK%=6Wg{Y*2GE2 z#>BQdp4c`gwmq>XnAo;$Tl4n4_gU-v@x4FZwR-oeUAwd^bYo#qQK~*{6a@(aAoijIL|01amnmT^Fqdh64>O$ z3S9^l%`ilm>+lxSz=RR=(YyRqrT@AVq$wUHJxw;~oLKtP4h@q{3L|Fx2oq49K`#P2 zK(l8{#cmCC_K8>TE5L4yb-k++Hi+z|>U+^)=TeV=^y@m-mh9-`5xCx|m=(oBW9xyX z4Sz|_lt)h#<<0M)x@1n0{zfW~ly{`2hD7 zUCs9gMfJ~lQ6NPm43qz*5oe+)PNE>E4DaHxjB@H(H%iye_Ewk9A>WByqc2qd3E8zx zrD89UNhcyD7&k!Ps;)VI@hf=bMRGL5mux4fY*~f!zVkN0e#0~lTWhwHrsU`6=c}S< z|3{VtTIQ;ddu$&szITZfn~dsm5CU z-)ju2GUbs;M*4bjV$#0)zIApVe0$d(f}1Z83k2v7C-z^}0B5NQ$)TAHRP+jMTLjtI zAc;~y7#r0&QWYJg=12Suj#r0fg3!01Sz}nNC<|1@6wBuA70wK}~+#eaV0zN3_dwSQYEfh&)_w*e|&J=IQc;v+);<2b1#xG56=TR_N zqoDT-pnyhh)#4eN=<%mF$j?k9<@yIho{#3G_`giNzA*EMMp-_`mjlQiPlAn{Cc$Yq-wjYi| z&ThZLP!&N*mCflQtY=tn3VSf-0QAs*QjbICf zWH`iGBAsxS4MG!6in>fa@Qn0N+^`RbH#jC7{dU1wV4x_L1{h%>Bx_wAqtq9hKxD3Q z@FAa&1=)qvdGV{oi#mtx*=f%Eu^Bfh>Le2zQdm^DQn*ZOvoOTZZ_U7|BSnW3O||sg=gOW+BXLQIN00^+8i- zK+IO!z=t0c`JM!)`9K>HTjakw0s*qWGvXcj)HQ?dQ5P6Zw)9NsCJ5dT4?(X^<58bU zJN(#2%;`5^X>-2~Ff$hT6y66sGNy$mfWK&c#bn#dq%IGSd&lR-a+ZtDpt8Z^SJ`)x zKXW#_@+$RyA!W-F|KPww^oX5fH66#Q(Z)R^#p?Uyx44OLftgSVGcj!DlLv&qoNS+s zkOn^t%6wA%4a<^HzQ`068fel{ejZn*<-tjjhVQLal|~CGQqE^#NKObgEW^5MQ01El zEm{Hbo~b4|&YfXQ9oMQT851bNDexs1ImEWNJFeqE(615bDW5hJkE35uZTur0)_^y{v^qOCJlYv)u^m}KB*v7ldNXR4R z*`E6JX<2w7lMCgB+>IRzh0#^pCIiDBx~RrmOBUq0(c!m8Nhc4mMzUiFnv&^`a6c|t z*IxH?Cz!ctwK>X-9TMV2kfgT>A|8hhQkGr$+KwpAN~^q0En_d`XL^iT{%3|>HMB^h zbb;`ZjnLBm}@#_S9rL|%rOo0st&)=KLId9L;jKs`FcTxxn8oGvF*!$OpzceLGb z2QY46W3}MDPtv-cpxzV8KP7`N3OM6O_-i=KVa|4*tmmfMnW3ksT7EKoG}ZCWSiOd* zjn&2=;#Fcz17jMGu!pq&bHfmN?~^XOa1~{xm3X~;4Z9uh)P@6wRK?X?ei4+T z6oFS`+B1uANH(yR&(8yojN6?p%Z?`HB0A^FAS>YB=UKJQ%&9v6M56>j%@W zWm`A(l?f0!vw{dth4HS(mJ-LNe$>O#?V_K!a-q8`P%p!jMd5^cZ0m<@%kWL1NNHU| z7*!sn#$(auzW*VlTtmHP?!HW-Vfe4kC)B{U~rSaAlO_lF(?HGRJ92D@!sQX2=@sJskqJqBKnENVM74wr@U+ipO~_`GW;8$B;|T*&SZ6?LbB2IKH|*^&C|&>FJ` z#rcCC7NxFIDTUO`?0PrRr!gtrvb(c*c1?o};SP72(DOj`GoK`Ex>{p|3NAMUD_SW7xNH zyS{O7d4mCHm9OoDJKCo=0Fc%mhAQ=14$7FQ}38~ken>T z%`nq%86#3$D{&!>ymY;29Xm;o)TRXIJWsH*zSE%HkG3_=?RnP+zx@q#1g{=TMAq3Z ztFi>|imVd<0+hi!8Gt#dRccn6tKVAQ4{MX=M@fIj?=6q|ln+H5PRK{#fD8ih^-pBu zXEX?@qIM>99l7C(5{V(#!Sx0tu3-Kl@=*2-ySg|v)QH$H|8t-Vt((h(E|%acp*e#g z;|DmB8k@A^irv7Y+p);v=-AP_{t6jJX$8+9F40l78FE8?Js&RW)tDUVQb6?(Syt0v zQZ*P75jn$c#_pDytuc@=?0;cM3`i}Ux9sFl#mIWAKh=|1%C2#kj20My_Z87ho)$vb z>gv`idKzls?5C&#MO>0Hs_&$I3wTkuy9{e2m3`;?biTHe@mwz|anpYA#JAY=f*6Jf zw6)?wx!-(c>Xl~_RI!c5s*>U3tMZeH6iX}z4p_(Y6 z_t^hk@mD6K!-M;Ln20bNb|x<9BD^lMwK-Z>k)5S_(J!emW*|KQHh2$FMR$QnIsu@Z zplpb&L-Mf@#Gmhmg1MJD;h23@L^))Z%w| zT8ubUlfgOl+-CXD3c#YnZUyM@+fKP9223~SzTP0`)nTU$jRz(wy>1H!B~VWkL*vwB zG{J+(6QJK+67l%-xM;7z1Q<1gr&QvTu6OyjmEYUH+kkOd?dSRa- zSbXllDOI?d?|LD$dnN%rJQ0}j?>{IfA9mQ6Q!2_{Fm<7-@A@6AnEO)gnXlB<`EbwM zGH$0CbhZK#Cy5}BCduw_59fuKW3AsnVxaBb^PU0JKTAOq)Ud1RZ*5XaCF)WcU^`IF z!TP3J^}XtThVkL(t0^W~V(WLT1y`Wvnpj&)Fzp5h9Ja!RUB)tDfX@WBdtG%pcONCl z2u>BPTA!CD*eZu#Hp@mu`JB*t;jE>c9wJWwaE-{JcM%{~m8*BEt-3Bqrk ztNk($WjHQV)r~g!{tl(7K=a-NXJ+hMP@^d4dql!Yl|&5$4(20naUyL~VVk5(Ji@VH zJhot^P+So=18{6><+y<_$hb3h-nX53y(-UP7)=%*(rsgvErU@mr5y^~=%d^ByHBN9`}-6Uyv}c!y%5LoNX;!m0XVi8k>T)*}2^+>l1*DCS`TlPmc{yM}b^j*LH#w5RVOb=mdK*kdX@>u+BgIXpph%Na;K z@F23Bfi)?Tvd)aB^7d0tZ;<#02_7Otz{G|0!_hNvABYV-&BRS??j?ZlAYHd+Z17e| zj`>g>W_Z_((<8=ZK*cwpG}+w-osc;JN)S zVyJS{NcisNLd_A8zX%{Fl~FUB8%@Vxm_QTTLfR@pgIzMZz8`Tbs~hQz1h zLEa)R#f#+c`LSq*n|uydN8^eOh3H9vys$fCZz<$knr#FcLe)>ty9KO1)7p8{cQu?~ zryMF8sR~H*3Y3qPQiiFB8;|8wKu_#Y7Jn$AntuILY8Lq(ohXgK9Dj7bPb)zGVCu!{E}Y(f?g?8L#5f}&;?J(N}aM###JTSoU#`OVJzEl z15g(2xLlN{L`IOJ_vWPEbf8n)o$Df{qrEl)_SOi|NuLTZoNux{UH6>5E&EGP;19X8 zv_nk7)~^;G1}-DIfBUH`wA*vWdE>>>PTGfT)(rX|dVPwAc#IA$>SQT>!Gf$#IGPF# ze+~?6--&jZ0R6tdVDF_B`8LKYy>}Qd$|2)GxbE(>kKE*HTzaj%3 z$A6*NWd0(QD7|RhzW5p0Cw~MFjLme#O@k%y|1A0&JpcVg14nYFL+wSQ0jJ29D~d6++Yod z5z59XA25`j$NEzsFhFR2tiQ!B^EUvi{;p=h#iXKYrYn8f`gIXZyD5~t4>r@Qa;B@- zJn19&Jfp~WdkV~8NFX&bIrF!72`m*C8U8#KY+Qv|f>^~}4UO8H92LTMmWn%Oa|vpj zl#k#|FjwQI$GTEKA=ni?!QdScWET1IG?B!D1y5Cj=X~i!zIl}Ocg);i6RrNa2EmA6 zH6eXFFuxqwU3tb}>uMvo1i*OlXt8v#e=w`S*WWtBJD?0KUp(5Yzf}iRtl9%c{6j=} zUT{}a3cmIP_cT9v$ZY5b@dVkNDv^gq>aeDU>J|zmVjBGrgLt*GdPEQE!`^FH+Z`+ro_vM*!?AYP3VQODeip1(Kn%6H3w7NA*@KV~4ZE5`N3;A`CawT0gs5?pFRj_UFpJ* zTZ^agDQOQQL5dd(j>Ki|?1Yi)L;bO6{k!$`UPHqo_M=QEVBJ*GP$v}gTVYXhZs*+r zAt9~XwXG*JtjV$kUd!;s$0=GJwU9|_rXFS9_JeyZ0)XF>79gdi$t^dRA*Ej1<%2`7dx%qo zTum-P4BJex9jvwL_Zj#N!MbXtZVP2JS^5D#3e(waU>)3k=Y-z$Tu(mwA@7A9wo=>J zrxAS``U?;?qZI*tFJp_3!ra(6rIL61+q#*$5h_Yd=assDzM-+VVeaY-zJZ0 zvNfN+`Y7+>m*C!|d$S4rBu7PxZ&j-qIX2w0ug=I*w^my5Vnp_<`%529-uRwgiOnZz zuZKT4X*%^Dg%Cp|_E2@LE1C)S!y57j?3j(jtJe9)#>UstCZZhYD+Hwx*F5*9|NSV5 z6J1Mz#CT`vmmZBISENA6Y_A_2Gl=y3`s4yT^;@vdG9^92H7AM(?s|JnoY+?IO$Yj~ z*)=JP*8=+Rh%LlE9I+`;iB1Xlyoe7T^T1b9i;y4BUtW5bKbl-KQfFK^$lD5GgZh?_I+%v&a*Z3(!|#>v|t2JF7|yCB{qj-8Y`%g87v% zNm@}nR+&sA2hyqtPKoct+&vD-FH#2*K9umzm=-volg#960o9RnVH9=FoEgk|o?f)> z_>tjukT{KrqS8uiowA&ST?ea)2H`5CA4(BXs9&;LQyr(fuM#wh@g0NMTtup|&k;Kj z;|tX;MGJQ_mJ~4N+OCBG!^0=GlGEEUG+D=T)O(u93(4|4x4|O?q*=dcSfLweT2_T_ zfQLV~jpmKVJZcQCEla|UY^9Catf(k6EUtN!DBGhvJFSE%7`IfU8>&ikVayBmHvsf5V#`cXzMm)REdR@4aJl2t7|v8A${r>G|OJ<-%EFkYXP} zL&18BYg8~CM$vEd8AvES(Oqr|T^XWELg=S0YT#x%m8< z80tjiBh(p-f2;iwG0`u$E6{JLk)Ht1d;Ua71l z+O?Z^=ab1gs`g5Vj0u3g!SZTt)icVNKGnS_G0DV5UtY{(P>GP`M2VzkURKys^j0LQ zBT((po|-@KxQ4wZ#Rrygb<;GuV$(IvY00R{R5j*UF2*vmy}EBJ++n~Q>|jF z2sd2-LBe7edlSU-Nuq1SB;%0q3RrP7fVb3>%1 zWaOx=-pLr+CrVx`BG$yEa(p6TMN6Hj6wQ0dY_y6G9dV=maF@B(eh9)z>jf!eOh4th zG)fXe+Q_x0lR#b_(?YwNg8&59Lj-$ z^ViS)yArY7>lvlZ)G2}uikE^sV(rc2FEC$MN_>UPZ=G4o+lTaX>p?HDeYUfLe)X0w z%yH9S-?4`*ets-pEiC-)s~6LB#91bx;#{X^AO7J_h&XLai*r6DXk@@H+B__%mA5)Z z6g?%#Qh?ajZ3?Ya42;1#YLcCh!J`V5cy;nO_rb{WJay8hk=%6>PDXWlr%3v9&>}cB zTJ!fv)6AX8oCAROdH8!LNc!nh6p>F3t2u0!K1qS^rup1*=Oq-c=cD%&H{YZ8!p_41 zC#4pW$&BHEHx;Rb@hvjiqolrIohASCuR46>-_QZ?t*Jt_SUu&}bE60I?nkC<*8I1> zS~-Y*ET7>ibolg4!0G`e#U_?*-4h(2Yop2eUyGiQnJm~tho2jXFb6iXnC@6kmj|-M zuWc_?(Ka7Lo9nz+EXO;=XC&AVLOfvUU@Gvl8y-R0V|vV~-U2U`$DHJNJ3ij)3u5}N z43>xQ-WRYTNV~cne?E;Y)}BY3Rq{=eW5p47ooDd+M{B1RGX))DqH*$iEv2Kp92VP3 z$9%JfMDMbeDkOVsYAy&|SApHJkr~XeZ20@}0qk6P)M8t>XBel6w8=cjD%PFSO z*BE9wLO9b+{6B9@hb@;%rA>>c#QEs%4}TXYNV5M0X6Ac*34rX`LV8mUBvE#5Y)HVd+C}HFM@Mv7m(dssH z_uNH5d%*ywc0zAkvHy5htMA+1G_fn!ox~^^mpP%+YGK+Qj1-55I0EVq zx(?+PfG`wKEC`Ak+3pmC?6|j|T}7-#+rh2K5f%x#T(BnAurOTvn9%MiX7Kfr@be{v zGlWy?^pP9LLO&qwk1;Qt67M3g0`tJ#>8&R%A}<(iR|LZU7-!>Ny)Bb=3&3vpnPYW8 z@F44vkfU!5WVK#F;w@is-i(EEZKa{w!)5VYHytdG`(&il5M4kW-{eZZObtaH?Ldh7 zJ~ofbhLUkVgq9wgCKXWKwAkvc`r*JWmyb~L+0&uL#9P;8=AWc%0~M?-rFS7GSDUjuu&O5;PU zEyVl3DuY_>6b2}L0b|w_dm|`ONjfw6)cg2%z)`NB@jpj@(2oQsXVO~|9=FcqrR36E z6418ImKf;u$OEXt@@GUATyrykvTTGNf>gPy8A2?ZQ>(b zWug~NIQ$l%_22l+k?@RYMRDtBmg9$~{*&LW{0)M!p_Xou-!l96d z0p%?kJy$P+HlO6b8kj*B!*5Oc@X|-I42l> z3rUP0vp*#p2)BXcsquRVVp29w0uu1)uEIvZ{}AR)==jZ@k{;AKMCwyQV1M(HU_z2* z9&p!#@I(KP_^l{qg*WRYSOL)|LSa@-A{sR!**{u+D$a9{n~DK;(zEo zC)ZsyilfEYCd+8%Y#YVhNNW7Kr=8)DS!C3FN(l9Bkv!fzK?hDeI~V|8Rq6tkUd4xi9nl4I@DF>I`L@V(z*(eHizZ8jL*79Z4K|nqcnanq zJP8JnMuU~ITVOFk2ZIT>!2uT4+aK`#KivqtV6`6LE`;R;4tZB{O1EYhOhMim!2t0; zN-Zd8L_@9VV4akqc9=|aZD0}yqF_LtHrV*kb!Cr7SeiBmRv$N<>SK4Tx&K)jl@%O` zJjd{_*+#-uU{zYd0Ptah4nwJ0%ahP}Z~sb-T8n1GF9dAsv+w_z?0^>xXj~2APW#U& zG;ko%>6E(2Oyk7%2LE%@0$Yzo_&-_j-l$fXOjw6iy}{i-z`Fw9ueup@XeuSPMJx{g z)BCSCd+8c_gPRb}VYn^eld1SCWhmo6AS!IlcF_wG5~g)2N;>hT)7KI3wdyl=XVcdS zbEeK*0T2{{-&iA7q&g;v%4E54zDiT98@St}eIN3fLHwMard29HF+<?lmbXs`(4QZT0oe+67G0$5Ivy6UHjh};E2HR%3L z$XhKnXhQ&4;B-J#qLMf`t|D^(jVnxH;AtfpIIh&7!EqHq!fv6C3XUsG;eX?bt~cQO zfA%5p{%0dNt|D^(jVo1Da9pWDgX2p4pSWTJ!|+8G-Q{GZE|Oq&{&F~xW;4ufc+_ieNR_gywYID{9+hO_-RaC6G^8dDczF1Dipas^? z@lZ*|@KX)E_h`C+6 z>X^b?V5dO-bN5n5#ZWJZAZc*=Pj9XR5!fx5V7FAAf+YX*a&P)_IT?*~3|Ny=hb34u z+<3Mcbl&p%H9Qyy3Qh$7(JB(Oqqwy0CWC=Um<_mIE|3RByndn+iN>pjUbgw&c26tN z*D<_fdF(fh;X$57*68~?!A6(Q?ced+IEC3}8^d3UXfX-haof7DayMog!`>PlRr*73cC8v{{t?6BS?43`DK~=RcC6!Geb8R{fOJCzUxzSApN4_{F#2|0= zHoK`2Z2Y9QRA@2m)rdO>W8ur3AxH1iyKn{@#|3u7kF#2_R#PDWka*ZCejL&Ww&-L2 z+*a!is2*ggG$CURU$JnOL$X}#(l_i)ftQC}Ldn^jLS!|*@>bTnaF5i7pQN=a*7t}4 zMS}Kqg@e99n03VUScGa(@TxvHo=(Xyd;mA_ae`?zhQ;TSn0k3&XN*+0^lYboQYL3A zqJ_={hdzweW!9&#wDH@T)ND(0X{zcNl1BfH_Ft1g9j-2xl&@*|{o|OuKY88t56``G z+1b}wE;_^amps^Ds`D9hjnw|iw#}?eUjjixf+jhohp5+|$Q@GS6YicXADis{dX&uk zR>D{-1$iCNNozGGkOFy)Fu#rv9KfL3LhgHY&SvX0`*urOR$rdeQpS2HDbCPYTRz|x zrFpt*{7ilE#bzH(x=e+9-CjErmfNzIwYKyIjKJI+Rt*WzA?Q8nDd9b@&QTnyvdrCv z9CF$lyytCfTpKZqT#C_xZjRuO>UBN_vQXmqlImgZ(hoKABSQvY1yFVfW^K)8P{3s^ zp)Qt^w0V_A5~Z^Yw;kROxI*Ezg4Kemyfyj)o2mX=Y{nW;qmE-& z3Ls1S^FAfVj%ZutdPCM=-Qd1sH$uDCBZ0J1!M>s&+kwk(o!-$0)XGsGsGTUax(5z( z+lm$HU*#K0UlL&Je6NLfFs46Cya3hvxC7eU3l@tmZ4dp>qy&Dmex>}t^sRfUqZk*E z=ZPCga=MbNh1>}uaAyOz5G`{{Nn+CoU4Uy(ctlQ-mR8&0w~+Dxx*Z#9f1q1JxWFQ-6PXq@ZtD*HMPF~w7SgkXZmawdFMqE8qw=7gf*+T--U3x;=-MKy z{bKe_NZK_g_>uJ-kZ44t0}@9${J_>lH9B1v*w&azAbJt&|{Tm0=EY9by>e&H&ikiQnzQp8&0a1*AT6+gJvC^8V_{wltN zeAu)2{GdS~+095mf>(hAkpO5h|SC6G@;tAfD)Xa;B;0}{f zAbl;O!Nbh`j%zbZFA=(1*es|E*t!$*j1k8dXaD;|%y7`9Sj||+B(6qL1v8SIfa%cj zj?izmJwl1Y>}#V<{$uRJ*2(_r7isS8?^A&(i8qDRIwmfeHg<|*i5{>v;$^P9W&33A zv5vyjQG1d!+TPtOiddLrLYG-bx|gQ!qRcPP1yJ!miQvqq&mH)o2FNVwTF~TYuJM96 z6kt}&=7T+>cMv2y~7#Yf05=z)v7 z9d~)l`9HLYbH#X>usz0C)0Mi8N{>06-0j#xL(Pi+P|bOKvq2d8p|co|3!d%0y&EpH zd|cH7z_~vr3kXE)2ES0iiys4a!vHSR5mbZD6rN>EE)2WQl*o{Su=RL->lx?yw2mvj z1$*i|Ia|Ipd+NFwXZomJ`*Tm=I}OxqAUx?$B3WS1oq@=gHdu5=7J;8ALB~Bo6tc)v zVul_pq=4B#@7!Y8S0Op%rrKZpKjR9Id$80~U{$!0k(!q{X-ss(C{F%wns*Q#9;2cXnEN z6-Xk??mvXx&cNJf$TwSKfM0ygv(9@W>jWCN(SWje^vx$O#jRH<0acCX3Be01iYMUN zD#O%@=ibfS`xg}f+8jYXV9xF5uh~iV-M3QDoX5|FUf{g>2=%<$| zwf~{HoF}OFBcKbMTZ%b6Mr{=fn%6%618~2iG;5+6^fMyNqc+p1hRUh``=Zz`R?ir2 zGo0N-i#Ut(0AoM_o87a}c*{N%$8Jh+GG;SFDP}XAcm^o4mnW|9J7~0bIYJwwN@9)d ziEB4SoSxq9yKz;E>9$QjqsW2T+OGjEP^97rSYTCVT63+efE{XxrP+ow*=GI^zOVL_ zAo5%F4#KqN+}W{?{xP;&EVju~2?u+#jQ~%!TXoIoG3|dQf*CazT~;sT7uIhhH+sZj z+Z|YEce>UCvo4HF$F1L3{(!1LC7W6;wX0eM@->YHC9_)KU;DDIGIJJ2)h3oxTmTlp zM&K=L=Q89@Lzv20vkQIaYxU%nQU4;@jKcc128m~92Z78?{q!v})8Oq26ma{eAN~Lt znYu-gU=7ydxfyxN(H=nhryYJ6cS5do`^pw!)eq9ry(zeAdkG`BO&|RWzMZYo(3O>S z;r3h*+Ls)vKI@hSj+rY95#vx%l?L$&r{e7hLjizB;%~KI0L&igp7}yd@jhU8@EDQ; zCFjhHy`h`L1LIH3sSC~4=2}h0d#nd5la0t&i5~XEjIG^y0fx^m^BUycN!j)23B%WRx9TFz&HvV{j z{EPgxCgbt{Qq%HJ1aHtF03s7FQqQJtL3&lcHV;epltkKyRR_m zLRlx(k0AkXLTylpguu?d$9jgz&f>wJL>p=t1QAuH+9@WwHd3?RPnUlm&wabvFaI9s z{nhqzf7gC}dTj3U{W~e>{g)Uj23!bpX)oyWo-!)=swesa-1L2~x%~Sf^HRF${q%7v z_>uYI`}Q(vzv1(mZYk^bexbklp+ooS^mGz%RYPAJLyNt|OkW!eqYC9WBKduAA9HDU zkoW5cyPxm-{px1Zs?$A3vh8G-gQc+>PtWJKrS7+7%?gOxsH#n&LYdbvK&`}*ho5C2 zdE1=}1>|e=qvowS)rtTU`t%7e($d_!WE}nvB@Eyv{xd|09f=O7TAG>e_MoY#DWp*{ z%nk*hZh-3=GB5=hbrBJ+ikmGgFczFRAQbP5C`AR-#+YA-mfO>?43$L5b`zSGXpC=@ z*O32(oZ7joq}&GfHIw*WVZ7ieWY%EjLWqrUxh0fgIWP#bMU4~Y5h62OJW?KskM7FM z+{Ys_OX*MAgu{)uR7+Y&@>g^FwlmSSjP`6LJf)Ht z2GaoJQJTrFSD$u9d&S0swc_!(oo0@oEFI=kzjj45`DqO2}69KS1 z3f1{zpCpc50vfXAzY#v9^YbKiKVlr&kf}3|&Qflw%x%a3PyAA@;!oFtdZDcfUmgR5yrE|>Z^Q^8((GBsD ze>Aw(rXHJSG<3=m3NYl0Q%55z>44vZug=JN;AHc(%dM$baI9HAHDIV;40#F)0OxFT z$Y0hQQkN(W9Yq8JFvd)DizzO8PYCSqNUF07RpQ-Qv9{qcCHSN_mX)qwY7HRU!h&*eeQb(aB{!xopw(R3X zD`CGYFEoz%RMf&{zJxq@jW|fwK*ESNQ)j}@*RrXMEV5t0C#5z{qvi~lGGth9=s=2F zy(l6@p4-2dF@e+e9pcs(b47>)N53hx_Q$g5Pb*(X#+BmWl5w*w?nAQ3ks{q%VJ znG|CWb%R6D`Ynd`X4=7&pMP17Dz-r794^SbAz%L%GG% z-O{?#N`2A!1!f8yEb2c3M8tm-taHv)iS4W3r&kfnY8+kn-RteO62y0;bMVd?5FDc0 zJ22!RMU|gt%M3f*=}KFEp%y@c%I1wwAipL6MNn%KkmDK0EUa5HWD%_>(ZPm?ml0PQ zjiK&i*ozNEOfmMH-dWgw%XhKOF)E|M#pzM6q3!2{2K{O`qE$g`h*Co=A?3Y|MNa-_Bhxcszh1@8f`Qyaj%dh6SS)rr{Q&wLi%G zi*bEvYX;iO8^NUc4}_W1s87D&U1vU|D@}w$c}d`jusIU(7)<7k&`p$TPw0#aug13U z4bP^ge)K_}+7bU+~$R4J@_y!!OzZsa7oaUHn zAz>hFFh)9e5OIVCnEq-51P|gHSpL~=4Yx7s(JEi<^KfU{%x;rD$CuJAX z%SYwKEkfUX+bPFkm(L^5wxU2(@wR?UeZ!x%jSTx<_ z-)@uxB)tlsxyW)0K}_;axndYT5m{diWRvK;0~6;AU0>gRPq4vDWT?uD9ZnKOF6UsA zP%q43!f986Ae6MC(+)fda#hY{JN%RQj657jBa0stoU;iuqQV983l!wEE*yIzbUjA0V#Krg^SO40rhRQ98x0 z(WK$GD1GG;0k77C%crc@Y|id5mOGsab+k8Xm<#+OY5VDPKwddwkI4N%Pk3MSMTb`! zuBWIV2m=g+`5)7e!luTc1vr2KcrcLv4**Dw@epn1JwaSQD)rnbiBZOpBc!D90e?Ya;YqpV_{AwvJSpd#Yp zEnP*3iynnG`m-^1}wHEtYr`_LYApFC+Fya+Fi1^+@9Kn7INM zWehYyx#d&d(f*E=Y;rln=49R5G(;VYZF;zZJgeNMwlD?=maJ;_DohO^>E&i&z7aIm z`R7>hGi)9HjDCNGwyoTxM#EoyY@I1MD-I)!eVq(e+?&hLXdpg(kD%nabNL>-_FNnD zI->dw#@L)jFn%d*SYc@b=+m1`rWZ|vPhVZNqutWlI^XWqin+|} z=q1henr?Ne>}1f{9JC{J4s0X)P1l-qI%QXV8ZDQ=z}Sk$$S9g-y;@b;1K!9$Y(}z@ z+(?bn@og$H!zs!#J`h_-F2Ljc6G`ybZI+71Pk*S3S!|XODfe+g;?}3chEp*Ib`ql| zi3S{(w`*|#Nz$&ivvQ7QP8(%#F4g{@VH_LCbo8+T94(D?|`z|1Zvrdwd*f|2HHb}Y2e zH41hi<}()u0ra2Mimt+BQzjSQz(-M?=9n;zo1USA3msa!^di^1d7Gb&$!s+jn0R3Q2#|J zO6y41Q7RuA6xm2L*PRhQpU|*qwG)?3hzofWmEX#X>m_@ zxOg-(41SV}vBB7{@(40wDiM@&MA&v{lPI!G_?pbX14$kKvHQ#ht9D@$dp14tdQPLSI8sYO*RMoLsH5%A$p4br|L{1wDaww1BXST*ls(K|{_;L(ka0 z)oldwvYXj;O~JJ=T-@LO?L$`*Vb&4_Ytl82GaIOcZAb&(d8};Uf=S#|qaHA&5rUfM zydr`E(At#fvMrZSebDqcLqlHkJ}VRT=LBqgZ29q9P1G!7-y)%C!~SFz@O?m;G*b12 zBDRk)B@AzFMU@QDS#0woijDLp47Cq)ow~q$CIqd+nZH!+0ux^`C16kw_BRw~Zd&#V zC`5Kn&Lw>OXXe?^>^<+_LT=`rglLFD_TmCmS94J5%QxK8(bUMtDrA9~a5~Sv#%LvOzkS>_%KZQ0%aCPpr@eI#{v~VgjlV2c)nq1|f zS-lD}`@MKu>U1oxxQkJx9iI@vE#N9V2>v3iU=0dP%fx&-!H7b5E3f+{pCHYp*X*-{ z(YMEesUqerrKuSOfoO3WP>4mEd)bpK@&J0X2Cz8t- zSdnSTgO}%+bRu@mnByQ&C32=Kgy9Gm{YN+BZj1E5W8o%bO5_E|&%NxTx6FrkFAnMJ(g{#4zleL+#bxcpD z#-=5?`AAdv^F9rouXYT`YTo)d;JwqH#HT+y5-9n3xEBSKRM=HMHveyX} z!8A%%Kk21M*}%qTGP$_5(CK7@lk%PyP4J^t?Tk67WhSb6AR?#%nG$(-grR)B|JRwH zYieepCa{}yE%RM?<-#h1g$jMYvC>DOt z1RHS-2RE(YTsRls4IJ_PP7U76ObXshI+sGS!4lU{8aX|)Zfa&JsQ8Y3r%*vvbcQ&U zvcyPVjn>CQN^f4u>k!;s5;Q>ucMa|^xCD1+a3{FCyF0-hmj8a(FS}Lyt>1gMs=K;h*S+uF zbI3V*Py*>HoX!)N*z+81O zY?G`QSBR!L0esx|X%8QCO3N|>RnEY}XCh%v4k zuomK1B5EIX*!GWdQVM&7GxmOa{}8avbzyOUCqH8Fh7~sLZ&8f6fb4*LQ}L)oW2j2% zh~c^!bw%FHmKFTB*>Ad8ST0GW!cS^<-#s%@^Q5i|Y|D$=^~B2mZEXyj-~sv)kSz)+ zWyeU!Uzv!N9_!Q*noFH25}dwa4PbMUOZFE9k9yy*DXHSUGMp*B;l`*Jf{=D$!GpD( zd!t;LZg%&+4(89cLA%~SkH!jkrlv1O0cs`!;9DcYt4DVh51}yA<@O}laiu^+*pifg*Yg`rm-ZyuX6=?xS`pQh-yt^?x5U)#mHUZG9Mdg-SMe9-VFy^p3W}F~(ziKi9v< zsg}TMzT7VRX-{c^8H}au1e4mEMahjCbZT-LCFFOK1#8RyYu+FvL{7cBOYA}b+2N2q zj8x$u#K5#mxw%&d>~S+Hdz9F_p>VGyCrToEE@(hdVDG};;=Bn(&$t#BSd(jRG8dz< zWsFkfy7b=o6=cFZ)vH|ES5{$w%Qj);A+O6?oqIk-nQa5xtpRi5Oxh~kx}v%&S$a~s zLLDbWdylB?l$w^`EpRC3NsYXwphOp6lyvD^u{~c;v%#Rb4xc+^oPu>n!5>3e{)dx|QaQ~ZpEV=n)+Tz%PT}NtRp-t-_G>J3*XQ($ox}d`>7GBP7XZr-K~D8i z>fD=N!&tnVL7!bwgz;&P)tXB%>V8ef&1ZhvZe$@*2JT_N)(yZQ}O$sao0i za})Manqu?c(U^&1Il0f8O@;Yx4MXu>RmE&!cw<)X);|aboivqaB#X#mv18QFsQEA} z&@ytjEhn?b{{EWG2H-N)NUB&1ZdN@DA^oapKe1MVUAe9E?s9?Wfn8ybhi@Q;A}=P% z{efM9^FsWE`j4=>#7d^Cp^F=KCE$$KSg)ZO`J=XA-c@+W3eVkKiSP^C`opxqew?u- zd)sX16QM;H?U5yHdVW5_FI0$lt)I3EFfUx&29CSg2z3#UEH3lf57+1&zbpJKL#Di# zv4o|iuP{jF0w#CpZF_gaP{rB1MnTSakd+s$m9bt{Ji*u_L`7tPVpxs!tNqb>INxM*> zyJK7q(R@`BRWKrKF)1xi^R5tek7RKHcZ2mfE;(7KdaL?-(}vLq@VS^AJPAE_CLE~h zuqBiswPX77*iMEBZy07&jV@=mSflUbwB)hcEvRR1DDu3}V78C83LVw=n@CDU{kOz^ zjc7}hS8P>e=L;{C$qExcVnHjx$lqbVvrv=Xk%D?Nh0k%4TGaXwJUYIQngg5}`MkxeWwwJ^AVr zMQ1%5Fe}RRlMBP46Ac5?DoUFD(Q*$QJEV9rohUDvN-YD0#cyggi+@I*e=*p?Db!FY zLlj(e+97@2@`~1v&tAwx_vfYKNS2hFa}$`nB4RJWDfKTRo$3pdNTuT8%(Q3zKpN`& zb5lHAE}(D)%Z!ocTe}cx)spG*jjkwRThROfP3Qg9Xhsw!pM4tfpQAds&F*s3FOw9q zqab~N&p`l-FDwu(0~p2`TxrzUGFVQ%%c`zS5NEZMVLl{bWWqUP%jm2?%GoEg{E|xItzi)si&7X9TDGNM71SS zb99|=c8eYUdZYouh`ibS@n-R_^S4yTkmTbS9^JJgrm%;13Uv(}8jAw+C#;>N_I?p+ zgljH!gy&Wduak1x(Yo)Y-MFOjWxPC)ps2zx)JOMzE3+|s%uRX|^&a4)SKsj8qoG~6 zw!pB({XS1Dd%H(V#e->753d+uBvl&1rRT>*AD$QYp-90(WJe+7e&9@^VafZU+ugun zg+DW{M6{+nEPsWS17X_p5AdQ>#RQfj@F-mbZ{s%Kq8r*5{`5|;sL$K=@Bgge=h*L= zcZvlZb(oL^j;~;-(zf9e$z^;97*kbzf^J$|_>d=9aIUhSCfQjqoF`=!sl+}87s`V4 zc{sQK>BlT=uOckmwh6;^yi^~uF1o}f$Ns`Z%<3(8->4ZafAlkhH|3RtD>jC{DC~_nEa_`BAEKI zygw<1&g+e38UkIcMjM$V2_H>*Q9dRVY_nL5WH;8eRa7OJg_{`I3F3UR-%v=YgZW+i zD3wG(hxN+dV&Zc73>Uw>3V4qJJ7GUwPB}4b25q)4<%MbQ7ADAYjlGj?DZB%1M&01) zm7FA3N1)kqD@}O%e%cIrc5UQNXH+pN6;{YhBeGs=hki`>OWTtctpy0uw%`Ew<_fz$ zck;27_SIvzj>((b!sX=DAtrQDNoK=hQQz^y8$aCp8|E%p=31LU9R?*?Su}?x0nrle z=1&T!&zJ@AMLPerih>Oz&N(?V54FMOwy2RIAuDh^8L7f6iLpq$j&z`@Jjcq}8=kcU$9CO_WZz-5s* znx<%l>VmC~4nHMT{+B>j^}t`G(_~@%VBKgkic>Y&7JaM!Zp zb3HbBLBjx2_l-}UfZVPd!IX#XK7`>-dc;)Sfos*h3x(PO8l?J6NYemJoLDLj{2o=S za#Y8-Gk*KD^mlwY?;Nfd2cF}F2eYt(m7bQMiMR%dgNgVSvEPEbl*nphx6R+_ad%Yp zBNpS4YyP6x~r(RO}cnyp|l@NU;fk=Dm+$)v(IbM-&MtNdNr z3qOIExHLFbu|D!{@?wI*mM^WOQX+o1ErQfTyA6_p2oo<5K=ZxB4E06-Sn&dM(9LI1 zXIO>-KbQTZ*cA(KC}23YR?MMQkW?f(5^;daQq8o}pCvndlO>DO6e1sgIULg29i8$B zr_Us<=xkV4xv`{wFy|yytZX(h6}kR-J3KfloMGKq_oZn1o^3vmCYqk)+hyA`chi{0k@Tzigyme%RDgL9uW%g4p7gR>pPwenoZ<=}XI^20V*xV51| z8==KEJQOz(pQkI_zTs2?t-=o%S61gJaW^2*kVzm{YuS%v_iE=0QpF8udI?m82f)>G z?+W(<0^4=7Eo;heKvUL9h9$4#(?Dldi=#QX0_HWq*^TobziD9s5Chuw87hMjqTIs7 zo!B(m>L)oK`!Cc?Gs1!S2oIm*leqqf#p})lDt6fogdD3ZmjvxCu zYI)!3=d5s%ULH698d3ei(L5u-ZZ*y9w7)_po49d5`21tA7Nu9G{7CnkyDQvTUbLL- z&%~#4UN$tVAl`JnI#C|msQkocu924Xa0eRRnTn5kjh-Kqa!UZc{eNUOCivR@sv`2j zYJw?DU69c+JYx{MIcjwf-mC!4iF*Y?O2z_+9HKue`qMwRzYb#Gw{n>(@BAbUr<34C zzCaCBgzRfv%&!8HTz|hQb{6YG_P7{*| zpD9h+T&Q-lCt5@RH6&diQ8?%7Plz0lWsjy2L^czg;gU&m;Eym%azC1(q~38F`Vd_w z*JeD*Mm5zjBXJ&O3|8T%)#cC4SZH}*QT9TGI!O+ZKbP;+>M?|rWUH}Bl9p&|j0>jK znh!lrLAXHUF}Zjwe1A^s4XvKyY&E#XlZ4AG6Hn`X{MWbESE|y+2IL9i1q4w%aUaeu zHr_9bw(Lm1dVAHHYVX0e!_1#Pl`Xl=Zgjkh;8=@q|3C05{~L$$KY$fp9$xPMBksb+ z{(l2j{znGp|I5wVzBX*u8c*Zmo3*XaA{)y9$+aUsfR3AU91A5#WP9Viv-7pn7sK~`qi4eC=Qk1G2DbN?nD@*3_v_A= z*LU#d%Z13>Md$0z#=GV*`RfJKzR1kr}L5g2@f+zm>$q4BYPFS_D!GkeZB8|z2`BUXY)O4%Yc$5 zBqC_4?2zv)Owclr`klo<;Zds{hNs{q(|G=x_)k>4Zq~y3a|#K$DQ$MbRKGCl!4dl) z|3xQh$a(log2zWl86B~Tf;Q;qKbupJ25mJ4Z%nrZQNznHlhR-}r8693T3eJ7x{Geii!jeV#F@u_ zmiUm$4bwa`M^Nk3>7HFN_mdh4>3Vn_yb2p{F0$1Wo!F&ua&a8HSUvNKa{$bci~p${~N)t7)P-3 zpH4Y3t4MT#&$u06A@ry~V?whwe*+7D1ARZI#+BWPex{XEx8u=`^aEP|SAownD&F#M zUOd6WN(4{uXXvYJ^S-~-vLkpGI>NTBA%9kztVer-kELr{m$t5QCKJw5R^yRgFS$x* zzbpRaPlXQw^fbkDa{u1;Nq@UN9(#Wv4s3Vdv~+f<`a>E~j^;O5w-5G%(K@-qHO%U^WkDAWBz9CR7>9(mLQ-rMQaJ?>uR(l*>>>zjd={vPAigJSgC#EHCyE5n)i^ z+>)PG8UZu}!YNJbSN|Y|m)Q_@_POgVsGkDxf2*-nleydoZ2w**4qgrtSbBBTV@8!gmMf|vR1HYwkMau1$a`<_zUN;K_p-t!^ zQ(4{*S0)jyni4K4RC}wjfKqethRE)Nm{>cm>m_A|6v+SAN<-~&0RBiI@%@L&O6M5C z$lC)!p$u8&sgdO)5{lZQv9IY%y=ni!h_A#UOvZmiX!g0t2;Qw~nWR&9nP%^+GU7!!not@Y>V4e)V3I^(ifWtK_;52dk zA8X2{t7d`5QrFQRkJgrF2&D+|`)J*C0{G#&U$Vhy`eH+2G=p**{Ydg3#$d`gd{%12 ziFv6ws|gNw4*a13QO5noU1H%I{L?6hFJV2ucXy|;fch$9mIn0F5>`dL|> zzJY$5`~5lb{f#-@ri{h&^_*t^Hpn-Jhy z=U-DV$gDFX?3N0!~!MWkVpLj_vl>ELdkbdg2 zO8v!zUh(qn_77&rtpE+W(P6r~cQ%0{%k`7!qxve@i=x`zzH=ZY>{^@fq#6ZGSr=T* z_dZ4zKirztv9kQ&bS*hKo~o;rq*%=mS(u8qC@DBgDWrHrZ7}jEOu1zs387WcEWue& zpk2xPUNW_5juBI*k5jfzBNlpA{ZX8-D2h$dN)v1irh~^2vGU%XX3pda z3W`b{JOdQz^THsKhcbs89JL6Z%84v&u>@bJdvU$D`$7Ct6<5D23v}G~{pA#sVB)io z=mm~@EbM?Vika)3HS5mZ)*LSxLh_oB>II7A>TtL7Q z0D((s28WsBCoB37vP02jlT{q{$WbiwZo8cbW8|cQVm8GZm`BU`#oLUZ0@#f5Loi0c znlE^lw~pUwzSGNK;#T_ny;Y8;jv*dTvVCELh*w4v`{7#fQPlsYNNv0)RO`NxrlM#t$-N)uT6%1=bguXk8XrB58vMn@LuFtxgChKX{Z zLyBLpx;yz#Z#3Yy|Fx+m#r{aR=2=GkEeY}BxAKr7dPVe((v`_`nh;`Ln*uZ}iwd5y zOd)yt0~?pA=T&>5-cB-mx_&R?1s4HNA2rZVI{Bb0-f4v-r07w;a`gGoTDh!};O z%A5_N&#-1Cr>1O-xfzZcj~Rp??iG_PXy=YJ!$2xtZZ&@426&vEyxi(w^@{*OD!i?t^yh`nBt@F)lvfvnRZ{J_)Bp4q*VOvr z!tOuTfu#yn7NpWbb*3cK%1MuiN@5ID&=AsK)w+|dFg2OxY@K9hEfNBqk>f6~-1w_z z;S+brZ{DF{_aX~WNRYdLo34le_u8>=KYXtmz05UiPyeDm2xqeI0(N^zwRLofY8-j- zt~QVY?~GJ4jBe$GM0WJBz>63&AYclXv@+r{qvx7_d1KRa;`&Ub@()c9+w`DY8wnbo zJe3Sds%>+jTe|C6Z@>%qtQP}<{RMe`BrGgkFdNeReAlbjUeWQN5c%f@V)h-{Hb=cE zd`nnBG9}d|yO7fEW&OX#qZ{-Q0(F;-{a z_u(v+w9Ay*#`MuBzmq=qkk_1wRl%E?I}XpGf_P#o8Tw3_fPhx%Cz-wjtTO`AHOY9H zfZW%7s@g^7q*3f)V1-LiuK2u7Q0_;+Ho)*AEor7Nxlx}b`c{y2wzX8J#ZA&2KnNH! zf91B5!;e`HpEuCcpbE!Z-;l8i)96i!mH~o*2ES~zBK77n>`3?G(23xukui8%zv6(8 zdD%%hV(jx~WqEXHeeqr`i4Pyu`9nu#WdyN5f2^GZ`E)l+-cV28)BCg=9Vv&sQWDZw z*)`^;+v&vL)f}+x#yY65pD##;dF2EesmJcCRN=ej2F8-~ zEw*W3{fv6fs0)yC-+lPj?wAfWjdh=0Ni&w|H?S2vX^wn3nwA6&!MOl^N7e4!HB&t| z!yqZcE5UySz{*Ej+`Me{$vqtiVFwxUUX%M7AOMeph&cX&?}PIzKBCy*bA3d`(7Ld3 zps70aMW{a4IiD7g_+U*zezVt^9z_eZ;Y}n#L9P2APq_Lbce{%MB*F#>EOyv?$ zmo40;tvQ9H84Vz!Q|6d)qLPW5-FeRTtQSjBE)K_?`$jk2&#Z)-(+z^?_e<3-2 z*}Ros52my}U)IKGi;g?yYr>WV3%e5Fht=Ij0xd_mgXhtIL@l7E;^ zJciqFIJTrP0t9hX>>?K2C?Np0GV-WrPv@W#=?n$hCVlCX9W?gT$o&crns71_SaXe^ z#^Jr?Hv!v~pQ5o(Q@d1nD?Ua4Zuy=EwW6`#EeBhA32iE))MN98D+2xN*j{8e2j|@2 zWRRD>ZT>PMLnbNc1^VapI)2#dqAX`Leu`F2P3(%JTF7R*gJ%o_SESiFzkuTk@ZO8l zIx03BaTGt5IF{sz?d&Rc&t>D>f%Sme#^{_3*8FoipRk5Jpx4$vJ+ei$%6y!S-JbuP+$!h$e zkA?8%tUpK`*t1!ZTd}_`wwtTmg~?*uU4Dn?=?`mER_sdv!v#S*|C`2)$LHD#o_r>- zyUs2AeANQTZaPa@V%el$YY=TnWat=?GPN+Gj9sMqF`2YQ2Z+VC%Kx6RO0T-@BMvtt zaP3Lppk5`Zv0Ag5-#cn-Vo9XaEL%F&AtP5A&z!~wY_B)h6%z@I*UxfE)SiRO*y&Yl zebDZ23HhoAzixtEHWv|Nwq7YWtlR1CGVknFugWnzP-}u8)u7@plHrvT$Cik7YWiw^ zCFN*LYxHe8*X=fS`|MkX<#^TSPb=Y#liVeXcRa|b*Mol8cm!~_do_IvKIR;?mI61S zjK>HqE(a_(vfBBi;aSNGXCjl5w~GkX{2SZ^M8~&_7_*b8Q6tvgHMz`52=gOUR5T^3 zyiz2o@uVL%Gla?RGhOZ_l%9{~8}3s^_tecKe6G7Js(;~z5orWYDT%M8t*4+2Vrr$a zKQ^287zhz)0)e&gswfH4bIj9iD5JY=hQn5V)XSv~u^IBlQi0Ii18b}^u$NJ<5Y##r(=uZF ze_sw1N6eY`rsU$!5XGaF44PT7(s|4VKXtFkBorDqTMdAI{MwiXVu%{G1f{X4^3M=} zKo&%KR*`82`8QhXl;*dMRMc7m)*Lc4mUes$N3y=*pqn?gktt?DatY9MB%hz-EWNWn zQrJ`Vpct@*5iobd_IND%-`3<@#-e zCx=pVJ1)nQ)BLtRL1bETKq&-{~So zTHW`BT6RybvkV;W>`MOoxhI$v_lQS79x?y!&DHm+EW&%_SX*U;IxR$ zx}C73TSXp$Uv0KlQYPy3LKg5gKKOm$_%w)v6RG{ZC8H7NCCM}m)}gQ6K9*>As0s@G zjg3D!Vf2W>We4PCk)nlfR(iFqEtFyz?4)|f;=+&?N6Y`O$2N^sdA>OVG?Dh|lN&!k zk_IUzbeEKSClNci=tHe1Pdck`GkHBVUWkuJ3RPGeKU%=7mGyIF_kB>9-*;;;%^%_fHbZWp?7F7|_U@5j;oX(c``~r0jZC z!R*B$fpExrE1e3q{YBas+(pym>MLOPUdk2MkA6XOTsGUM3R5@r7&QJ_utWCuwdx*% zo@|s0komZFg*A|o@^OVm(=dVGIxTt#F(y9CD1IuiiOTxi;~mv0#s39zlaMorz)V;j z(Q7`f)WL*u(tUgtzN4z!Iqh+18GVX2zI-ykLE|oK0!$64NH(NG#qMADOr4rs33=*ADo+Yf z0z~%j{TslSNAsVbkHG`#@h@VZK!p9^07n(~mPromCKUCoQ325d`|vT0_|tG2*W zt_22NL)|HcADD*y2ZPF|!~0BBG@9!RUg^opTqCayydCXo#2jB{}!N;UvAbdIZ;RRj{x$SVc47D$vE6T)OSF@eyeDTnC zf=Qb)pTV*ezLz5O@N}QJkhr+5`;G;?@$t)6o7?$|BzsXJR7cJ~g91~M*{rtzh+T#F zkXqN(uv1MycmFEj5yjUnu6!;Xmr}WNiA30D#~NFSqh~>Jx+4F}`s2eb_*s4G%W41gLgtYs^N-W&*SN)<+h`|{f(>Y2$H)05|7 z3_)@JQ}FO>2*9~y5%_pd18{>?Vc6O78<ugD8R|vkfns7WJj;nEatR^6r;i!bX5sRa$ zUL9URwVfIj`WOSzq8#fE{CHeLrh1 ziknSoZ~p-fN}F@thow)Q9P=qs}bkz4kIB*dWPm#kSwODs&;wTJjDP&auH zXB+{%KS;mcr01$@PwSjrzFp2_ZT0JjwhXwfN>HC!x5#I9=P>Cxqk8>PstF7jHnp&`;e z^8n>F1+1I=GW6!Pe#dmG?*8bAQl_uMT)bfm^On)>k-p!3b@02_%#IdN!=N*vJIJj{ zJ&y@`oO6roZyQF&z4-ZYK;l_T_x1|Os@H)0IPN2c0jZz%!gf?vfOWM%b4@4Vxjk-> zi2ehyi~?S?f=jP9dB^o0n-7JCCy6+`Gc2bPxI?A(%u`cB3vxpnLYqXdGCK|jKhKBw zBFW~3XivdC*}qcj!YV1h@v_x(PziZiL{5UHW!rA)?swY|ehCTvr#YFx&#VDcz$*Q- z_|i!yFEOHD?}P_*=_9X_lB21H4z=bx-;JS+lIhUiod`nRs)P6m+`2CjyUA-YC@1lu zv@XqI+qv8(e8oLsqStp*ZevN0Pw#p9Akc_AdqEOEiRi0KXjGu*_g^|)j#FJ_)EOA#^7gWkjSuUT{)X~0sG0mI zWp*wr_EYLeVrycP{KA;Zmj@zG`1L=|Wh%!9<$CRrr%IIaCC8VhMhDI}IWp(G4%;sa zHd0iEr{ZKyUkIf%5gsG>TEXeA^KEbyhe0@h=L z`D>axa$FZJC@h^c&k-tO9ZQf2Gq?I&eLMZZ#&&DN#7_I}VVm}O+Y_eUDUF$0;H*w7T7=XbUue zRM4OOunJY7QJ>5-?WHo_|D)K;&=IRBG`A~LHLP%5GfJ3*70eZ|ETel2#P#?Je8YcA zkSiM^zaQAbgn6U%XYVX@#nZw-mgWRky;nz{Gq@{cR~`bD2)m@sGj0UcZf0qIBV3Du|4&I1cB5UI)12vEA(J!5_oziNV=K z7OTh>gUE@Z^1H{o!-K|&@J8qi2!WnI3S9H^4?M}&5x&hqr&X+eDQ4ldUIb0PB-DEc zNx6d`zhLBK(8s2iDfu{`!+v_k&BT%n^U1%B{!OQRnw-}MLv|g z#*0VgZzCKe2hHw}2w%zVfGlSqx?>?Y7JA}i`8~SJbkTXF?JVOz!>h>z4Nvx@BZQgp zUK0v6pahoh5AomO&m?#@G>;Oq6A>Ve{AB;_(ij6eDpinmmo#{oTweEDXbV^smnBj{ z1SF=d$j)(u&Ka_B9ZXK*BdR6-G{(+)FdCHCR&3MfG&h77k!2h`Ad-RfcnF>CBWUM=o2i;-E8YKbK%uu@3A5|W!ZFUvkIG2W9Zfgf%Tlc% zS$rTjhO4MdHD=MRR+S$B6Xx^B>@eW0|+nc{!=OJ+Iw$^nri}oK4oH7gldI;Pk{a zbxQj#b!AHg-3Y;F3NOR#fZPIg%tHD^*G}bSJp!5C6{5CU(Tnf9o_Pg8wj7`x# z*d=AoHK~CsBQrXF(}RJPwz6vRjdX3cqI35wU+0Kuf{2rO?(U-at`+$0c(HhB0v{M8 zk7l3GACtc@4=dA>tmk^hZ#&PBz*Z(g%^aBc?hjSySugGE+%PFVK_7MHZuz-V@WZ@w z>T*1jL@YU`wH9T9@YJ=Y!&yl)GSx2)Czj62zfR=femp3nb$0(WCqO$8Rw$;mO2wZ0 zS;391a3j!nVR*@3*7(SzJ)nDEqET~4m>6N*Ea9keT>PSe;hy4b$^-6O<*6qcsWUj%<@$RSOA1-lTLS5d*fv0 z%vulFz;Vfy`N>xHgy&}(d8u+mcz24nhV63nm~e;nLY7#=@=3+10ONwF>(RmJKM&#r z4;X)p-#?36Be9s7WS?2dDSQ^L=I~`l=L4Z6Cr4YZuQeTx{>P+Gwk1s~wn+_t+eX$~ zsVnG0HZC*78m<5qLA}y!DDnOh?2MrsXxl6Z>4rjzLSVqEKK%2AVZiWBq=W2fOG&dB z{Y7URlm&uqwsmz@I_{I5aex0$)#n8E2A-yhj{=f4-V-+@5k_inKEdDA{@^3OKO#ff@@#sh2R1}b#C_&SNqG6f^RQL1}zB*?E z-yeM3)lKk)Y^ii7qd@V_AZT29!aJ!8!CJ#806hB>XP^LdFJy>DqKzxB@;8 z$>ORMewa!_XC-LZos_=BE^pr^dQk6*^1DP>F3wulEeT7gC1?!g*8?8;{+MOSIFC4# z`k?Jj(m(NQh$4&kds6F0wnkC-Ui>6tJh_p|bO{|`kiC5u3oLX4WjPk~)njo)kL9^r z25Xic+wGa^I7*=Zvl((*LNg~~KDxbesqsBwE~sq6x3(N~Arl#X8em6!Hvn z;D4d5E2rKQ-s2|zo$2(_i)$r8#$m#*m($4zgGQ)BBUQx=EK!DuRpDHvK#6kJN%0!=anE()IaRKcsMf4T7lo4G zoh*!3Yo=6;S3};5m?2q)suW3ZF;!yo4($+v>*_3l=LQ|uPxQ;4mC+WtHItSM=Olyx zbY;XG{Tml)Y7LOo9llg!TnTjIJAkWJgq~_40e)Ow$Nv)*$E+>zYGGnGJaWH4Am_3F zD~qB>wmP*HDNS_C-`Kt)e2fp*RNE6g9X<=NynO7p?64g2dKdjUL}!lm-0kshT*vK{ z2i<8SNWU-d)PEE-nX21hO29r^d*1bs4xGaqX89fA4RubV+czli55M2vyR){_=MkaN z1bTiwH5-;IyU(>P)OIPbzN^lv(YD)48G#=SPF#_A%*p7^C-d-7Itq#hgz2d=&dwkG>tSLhIAdg`)!EJ?6+}eIYQxW_)gk}(SK|Yme z;;Pu4!#L6vkLl|>;GDim_vUu2-Muf+)MFL5xwyX4w3h|4&ixPnKkg5O=;v}LrV>qk zpoY3L{lGOsKymYWDCkBQw&M0MXod^TvmHDjU@pgZ2gFyU)hv`M2RyfX-JW^G7z|yO zd&6ZMfxf853r=eLU9V0c$}r3PP|MGl_ytOYWRU)>g*+*s(CHFKwe?DiL1uhFAI!@JpBNu>-I;mlz)Q{JhMzL z>os*z@L(7(ad!G?vM@ky8F)m~usr4e)xE)+AXq6Gp{FEfu_+J^&0;PaNzZ%UML_=D z9z-+dIlTSu6?&pQ-Ef!)LPXtqGNTGOUF&HU)Ki@20yYckwtjfxkmH+U zm5C*)v}dj+yGmXD86?9J zf+)2(eiFk_9b;+52D{-A4D=1B7`$bZKXxgnu&!snhxB1{&%g3zPRza(fxm|a_ zrt;;HAO3t{&3R>Wk%~K0Eip+?HT~Y^w@Qr^z7elM@{l2hqQeAR&XCC#jOx0NoS$@s z9e1&sTxrlY6>s@IaGUQi^{19{6)7Beg?<)~_tsyq?LEZH-u`60J2Ko7b%lG}>Ev_7 zQaM9Ma8@2McH(NW*igwWqWpO!7#33b&G+<;<&Y3H@l`L}rIv)JLVyE9(W%JsXyn-= zzLTV0j9$^YNw+10&|meX=lBY)ZxHxQZ5ij#G|5(RornagQT-?q6A7O4sxa z$9dvRe9GR@sn0QENc4y+QLlm)KT@idt=x07XBs!8|A4yfD36E&Z4aTjU;VESZe$0e zI*BRWXX9j68A>-SxhMzG{@5=o%p(m0-B-WDj)xHm=g`{E$w)CPx4Xf-Wxcj394|&D zrDgFTY+`k;s^v?L2P=m6^KImtw;$#0vK<5{_X04w?oa1Qxp2<{W=fac<{ek@+9x|P zFN(L}nGic&h$fenGx;2ns3@27q8nAyXR`@eV8;Pv6_n#n@|>G(1L?y5m^4awX0b{o z$N@a+R%HH~BuWN=dRtfToR@VBUCK(%82nc@Uo3-5yY{+L&cQZ=sCd4Jz1n1giy`$b zVP=6Sn%PbcO?g#A5$EH8`?{6J2Gi?XqU`=lhKZo@U;(uH-P&l)&mSI~9p!^EXQ`k( zk{I8*4Qx`+qe7(xkt0iWk%`{3Z&$}P#V58x#ak!+Bt4Z_8S*Z>}kV2WbGDm{Nqg(*4`t+H37%o7GA*^Xm~|zdPJ*IW*0Qsv0AlyHfV5eqoLdhKoYc#Z*%CH zXoP%a#*fHAYC#=1bNje^XpZ42B#4>MIBqwnP)&)hRn)e>*r^nhfA$66>aX6Q%k?}4-7t`&tnuMWS>Wk7Q zZ+V@HP=bU7Z9lxz*BpXNgI%}0@656?0qFU&U@iCeBu^k0j*8E-Y*i7#WB~Amf#H8K zc2+@kMNJmQ-GjTk1jr3ea1HJk3-0a?2@u@f-6goYySuw{al6RySIxsz%{xkB#P!BVNFg_oS8 zr-qf!ex>ax`904h&rFJAbo@F{Ivy)gV6R;%*77OF%XyYe>FBej0^BuyEb!6m%M_%r zYst%gz`lX(6Xz=an^N$z^1Uc74)Y0bs`;N z9~S2HrO(IZAu}2Hf|v}^Yj=kC;RlJ-eTn2p2HVF_SQoFSM_4a{YE^I!0i$1GKRd;! zLFM98W`{-f0vyn5KLz6K|B8mDs|5m!)cp$OijFD1v^h*=Gsdnnk+evXsPv(hhrQ#w z8H#&}I?nW(bY(ZCHY9W3s_UNioR6&DH<8q%TN(0QMjz>#=FB@JYpoCxaYe|4IL`0t z!pzHqb z@7XNaRXdinEVg|fJ9|J;e*MkEWkny4Oi@wY-Tq-Fvt}Rgjl|zxkB-@zNbmN!njSsJ z-;O#{T6WxkBx6nV0~V|se@mWF+yYqL=rfR`R0QhK0pZO1-=t@?lhQ!ngU@Pub;e&E z8&o`x44!DukPqmKru(Xr$LFL|_PV67B9~th?KyixR;0jq6+7TyN8c2j_#3|Xt*L58 z{H}5Vlz7(rYYOnpvqMxgK<4feUW;Hfv0zC3Eq*GmR^vAVkM73rgW-b23^ogHwt-P- z3*l&2iKmB(>v845x+ZN^<@U?=kyzBD144yQ6{aHV@uj}B=e+WCoJ!D9bLF5@iX))m zSc_>kVDDFg>SO_S0hS@k%TIxjw+jpg1wBaGhT`NkAQ<+$y?Q?WGHau|x*M*vAF}W& z0GXB@ND_==XZ;-hJNU54W520JdQy`*%V<4mm{ysMEe~sBOVln<;-L*U?CdsoDv#m7 zjU^#tQeOYx+4LGUH-{QFu+Ofv&t8bJ%b8A{FB-=YSo-~o!{IScZl}t^ksN%5-qX>< z_kBwuhvZ$`yJ~J;iR|CJWiEFPQ`(-Z$u;twD9WkrM|E8_5B?L`9U5o4Y$?`f1N7Vp zW1Fh&t;d#zca_6)}>VVddT#2meYHXgHQq6nHDcXz8f z*e!d*&I-&X-OuMHD9%NzW00R37GEaYKcu=sWm#Npbk9MvHmu=Xq*}tHBm!NotoF=+ zaw0&2x|nX)s?8>$gI-t?lJX6iOz}GU!_q%rKi^tk*AU=+#Q=1mnyTB+E+NYv?5ve& zoGR7Al)8&!MG8@Wkp1+f!!_rzU6iIC!Yxq!YWzW6om?Gc0;|7lrPYHc19cYtondu6 z?++^hM>yKg-EZi~`2~7m$yyrpbSZI3x5a~Uf$RXx3V-(WgeVa))M;tL<0qPqkUnS@ ze@^|`i?1AH-7)55(Pioa)j!J1Brk`5cme?d#u+ro;#1nK3H$q*-?-=#IaU2{M3taX zVMr!(YXIC1)~1BRWA@K0RrZH*SlGCP$gWr_8!aZr+o9)#ku}frsntMUxAZ3F z-fue?&y`yUN}lO|8_UYc)n*KE3K$8vy3C7B0jr!XzsM=gN~ss@kNSQIG=`%s%K#A~ zo5UQwbzB#!mfFvO1sU3dZ=q~$!DF4~<=c{#OKg_(q3Ie1=?Oecz&(v{r;$HlSdy?< z_oh5YdzHxxRfai3biL5Q!S&mN;y5&aqF8$e=+cHryLENgE^NIQ8ua-eJkA|r(_M5* zoB8gVgS^!R7pF;m5JT9S@WRaHjvZ)c1sNH-V^2oSDYs&?ZClS%>jZd(K2&$KHg$@- zoc9el`3ug9@O|zYz%L-QGj^)vcG2jh5^$4uuCvA3=TGVeRK&QAoPh4jxNNdgvY=1y zkO_A;0aZW>hM5eBM#iJL7t$7~35HU&If(~9mCEi)bO0GWfH4~40QYzpR`90eiUlX= zDSs7xo?dXITX+vX*HX0g%H%vvUSP-}GI)qPf8$$b%== zYsY2^Pe7^z0td0U^OYlDu9YYEP*;O4%j0CtK}!LR+)fo+cU!iTV@ZjSLFQADEP=0N zDIA6KE!il}3wNyuc!$6RWlWvQrVk{ErdgpFyS z&U~15;h9I;LP=7p>pkILLxT8eto-KAfwa1<4OEhp4Wu#cGK8(k3vg{AE*w#t;v^^c04?z)w7lqs1>;rmPGhJVMzQ6bLr%7WQ=i=F(5lHPI|JoB4B`;YXOxZvvt{<@%7-_^nBIPNHMRQg;ILp)=5Z1w6{QiHGY$%ibWaZ)1}% zUojLjkEZ^5aw7*nY=#~eMN=3~r><#LY9l9_QDTEy^>=MC0S_3`2mlH9fOZk=-sPgZ z9b-?b^*?U_D8XlR#CwuEWC2cco4 z&hM-;`aAve%RwWhoqSOVyGs674!zE?U`?gn`o6Hqp99mH&p7Xq>Z*Y<2?feCAqo9< zvO)J)G#aHPdBy-8%mFAI`$O)$Kl7O@A(?SH%s`0IgFMuNsNGFc2s6T#y|5>x0yO^J z2vMx$S8hebK&x>LbG!*g5#J(NlRZ_G#B%?g6)zrSPpEb(B3hTTp4uX|_-+1_AUPd>Q$60^nAOpyS-o|Y_gCfm>0HCf zb5ia1&&jWl>#}F7L>95^ct5NmUa=R~;gYD&gC`zEJ(^VnMvE*U1KLsBKS4LM!<&qr zVBF`nG7ap>$~-isZxVzO3kG<=3XvOly3z4KqD1(a--HL>G+87qsbf_&k}zcmCDHEgNE!*~e9@O(>Y;VfWRJRVpbaIfY$?w^`(v_qcs5YtO zzf;>CQK5jF-EUH=SCgf|_+gF#X1Xm&;Q}K}#bpw<^+Xu;IV7UM3MK)|P5Jfwkgx{{ zOXoQ|V&G9MI=1#>#g`$oj`?r2I@CUm`H(WZ&z(Oi3oCxZvJl`Zad4ZqYP~Alr%eC; z&tN4>?__qbId@xih>DJV%l01A3(X=qUthgc0)=u>tHhM9%UXgcFFcmc-pYK;nMidR z>bV~_n-+76bMJ4iWVg8-;RRt9X7iwR-S0LifcIVzFBPPs@RiAgoX=AyA%NI?h5`D- z<`@Tkw6&e}SW~@?u2)OX{91yet84l*HYizWoxXv17LncZ9|}sUg?<(ZAK}qJ9mR9k zu^4e&mS5ggIY3>MMvrRadiD<8;6Xj=XXAsa;k7<6B`q11@#)R|G=!Vc%Xou^9oRc1 zdkUg`sU>%~TDfyUp_RxgGzT{kPh)T~;9GXfv#N@o7?}%G|^Lr^~d#_1*An0^Uf;dD5PX*_B7`ubV0WZm*S1c5ge)EZ@+oq9OlBh zu!nM?Rd5i};59&!@E9XD*%4V%(^c8JGPvZy-d|dKE@Il2lOVDeJsywRG?f3HhAxCr zg4^p))-`XyPUv52DnHgZ?x8crJexpdVJ{Sy0v{_QS#DkLW^fd9dVISBass(8jg{G2 zA5SE1w!^p5EHczjrLF{sR@6|=)&J$&GX@hXEE&Iu6E1~2$rRr*F5uy^Y7n=Oz}hNR zyWO)Xw%c%Xbj|3pw*Az*OiFXxki~mRT%xF-t)5{`T2Qxq>(O^dLkwb<#%m%8+&{Yf+SSP6&`#m{Y6MeB`;x-fv~=(I0V6T zes5L&cu@yDg}`D3{y;t(gbka|nU(P4lwYCD?}*Oj8ne7O+^f=PPyArlzg7o+jptuA z9M{-tO&V0|t~Aw!UGFs<$Bx;ov`N%0S*Y6OVYfqkHatK&Te?0?N5egI!Dr#3F%0R| z0GcP~QOD|5=xE`!!&V9=oAlc%*G4JJEc(jTT!|Df&9<=Bd??4!T|qmTg%wxoleqg~ z@$bCh*eq>cy}vhtcXlp(`tDyI@LZ`~vq0Q&3{dg)SW#UPVqHGEq2Adn5`d-F;Mdkh zg`EvPS_kWt3^rV6;iLMfl&ztkx{8jbuZ;~#8THY_l?bbYYL~+)*rcXwtLN@D;8@u8 zh1uFY&>3qtNtohnC)7D-TNP*LUQ1Yh-`ZMuoypX9+Kyh`Ccss>ibL|hz07kt^y46# zoNoi1N@JtEvQGfAdu!{pRh|H>M^Fihyb^P@d~r3$Lrc}iXouErW94>;P;DBUNvW={ z+=ovi@w_|F#gmGvvYVBtMclvYNKfLldIrvpJZ7PXrZZSMna!j8_h50EzMmD}2C`k$ zE=ZCsiLzc#0aBO)hz@_0oM%T_XCyhqSB}>oGXr;X7m$xg@cioJu3T}lI&NL9XMKGr zERrHW9{d;moWBl6n|0;XtxdB{%YIs89-n`^6V&jEaX;a>6O0FaZ0!iyzJ@M6rnX=7 zfc-abw|#ni7aqVkdON5FALpAV$HwrRJ7JqBAd(IjjVB+q^2j?j{5B37I&2@Vhi7~6 zjZQZ>WrPp#`rBctpivgSMaT#o6|HmoPSV26C;2>hy?hX6iw&~Mv0(!+3^0H^dm5^cL5}_5&dum&y{8lIxv(R!?N8`G36p^mL>MEHQalJdT*v9-1N-igp`Th1S7Y769^^6DtysYiq`aeCw83gc8+6`&_u^c3 zLmYR_ZMdj6O*T7EO0~WeMx;FIW}j|yMuh$~Y+O^bZCHN*U3ISn-*Hr& z6U#`lyh@z3ajrc957If;Hd)<0We@bp6K)!8-k^4_9I{OTH|53W584Hry~W_u4f zVSkr;{DhBBcrDh})Yh&cu1flxeuMfV&00#D*u_FUP{97&8Yudg#5dR-hi{p|?CO-k zt{Lcydpy26hsR65H2tRC?v{Dra88)bJbOvx2hKxV7f*Vqq|q7z71mY?&`ISMB|XtFmtnX zjL*zHaD|-&HAgVkGkLf@xLu^lJK?V0JEZAb)apg}4HAt70J0Aj6O&03Jg9`OEpQ5B}9k!ljid}_O#OM8<# ze$~d+V!(QdrHmEA=Aek5FG`i~momC3kz67CnPW+gwA`$?HVX$V`l>B}p=goCs!sd19yM7IIB)Fvnol^m34ED{ghMB%iUgQDQvnn|> z_UD;}%UvR#86LM4;Z2j*8^Q|kKi?QlR$o5a-Q3I|-}o&}AKsR8Vq9Ae!vjlKmmy?O zx!ycS9#}|=;2!-*={+tv=h}py{XMhq3t2v(55_&9Gq~L@iM>q=&s!i9e4dbQN%80( z9T>W@$OJpw&+xo&n=2P6s}gh6rdrMm(;A)(5`c2Tywgl2V^m7`UIO{Sm-9{elkWOV z3vl%jv;Az8l-QCFo@J;FrWdo16- zEE82>1A5>> zI4bjTld?9!`UP9;7_E>WgDb-=@!eyj(Px^8+I#`WZaR689sRD-VI11Winz{4b^w5Q zROpz6q&TX@OeQm){t8&NF}`zpt11B6-FOb8hGkjz-a88JgsDkXJZZ7-V^%K3NIEy# z5*&{cgc3yydcY6lJ02*t+?42*DnS}q?w@p)rMYOGz=!E|G@Z^*R}9^!?b!elLZv)e zd{=-cQm0ZhlM+vtmF|+OZpKVk+KdOnFY$iok*Nt$#(r7mf0Tt4B+wLL=C0O~fyNDa z-p(R~BKavJ##!E&hGCQb zO^%DkQ)$y<(cK2uuT{)n{@AfB4UmQA#rn3fSeK?^yQQp0u0s#V56IO>;B!po_gqIl zwt%sFsVEqIg_MzIT9rJu2$UhtJA5_wI>|B>Z^@nWs;<-kFAZ(sc~yOCWWeVqwdJc} zC1ms-2Rj2pG2#-W`EQ-$=5Oa;y%!F4kj2`LlCzuG0w5;#Dvo4fa8tgFbWT!c8Potm z?O3Lgg_amNWE@AiDt#(YrOXFZfF zKbE#*&1M&{jcr5MEN?!ul*!+J`Xn+jj9YW&hdn z@CaX?&*MAC?d9|eFC%w~%HZ-{=Nkjp91&X@A7LPWnI&1L2=6^CcrEu~;SM$f57z>?K#UFc&kb(7v94c(eSX1tR|bQioA zF8e1XIhmphX2alz&aAIMR-v;|WBXET?3><05s|84Hk*#F+(n}8xFuyJ(MonzJofjt zjCb!zra?_90iZJK8jNd$2#wFhmL*4 zsWkaF5gJe``4RCi(PIn!`ky-OKlU>Q!SupRvsqbtB63HE5zhm&G9N6F9|<3gzOMM0 zK*$g?nJBZ>MCA!`gg2q~WtsFu?B^ zsmXT*`EX(qnZ!$6OQMu;r%04)r%5&MHXa16Vy z@gyZL|9m_1Vz_Zi)6Z3j!9U9`4Pp~*o_Hl5OPSUHyHhS;jjc*3|1iqYc{&~hs=g)zi%>wCBIq}qd!|bqkWV}i8$#qN6sP1NR={Hky z&`IGc6M$C<8jzcBLwku9k%7Qu*GPAA9yxGhe-9~GXx zlPDqH=U#5q|5VX1*ah7SJs-D1+%dyj+^k_!3Ngr$qDTrF!agPO`*uH>XQ1jU7bij1 z-RwBS$m~qKcsL8(SuQ1#H30p<4&bD)jbsga^?D>**pIjY5(!Y_;tyAPkFrHT=Btfl zsFGG&YL1}=z19hP9N7g^Tq(Sjf7P=A0F}b-O{g(Krs_;rA{W%Wy zwhr@2IsFdH45Vki{Uh{xSgFD^wyYsf0<|cewa9mtb@Le%01VG|HKD9!{pSj6cMqN$ zgVz=U743Eo`g#kI+K0BSLt7{MGDN_?^aQ;=xvyZ3ozl~PWi3dqhP~|FO$wp9EiX5h zE}{Q%5Pq0gP*_voPy=UDXcO90Eq=b{`ktJZ#Cwfc>K4u%eZ5y8g1vX;1Ta3 z?$-C0*(f+5lK{jP@nw^Uwi{`RP~dBY6?FqjWTbUEMW@~!V z;Q6N_N`i0$c%7-t(lo_M*f6kXJE9EcMUdj6qO^L0r~ntlJZ*5+eOYqQ-$YQ89qUm- zh+=r*mgU##47%SBX1;2C@x^|M^L)1BR8~D{YmaG5HBU^K$hG84lE#dZ{jP?1$FCYH zBem#cj6|W(gXGjG1BT%;3sW;npNnGI>JX+>^mREO?dGy`%`A%RgnCGfk{t|!DG_ro zNe}SiTh6**#N0xN8?CJc#qSk~ zybrc~eYu4^%=Z2*Fg{%z6?2mZ(IA~8Xug+{aQ=4)RXQIRyFf%Ao2{|iBMW=r8 zyL{;<0z*o5!by6kkPQ6kz~WtxH5Ffb&I z3OvLKHVvqJ9~%Fk+d4f&LbN|gePBSEE=hl?`~uuLyd4Qtmchwb-ol2&QeRTcFU?a4 z(^VVRtWXR`MaorvYhDZo^j@OZ8cP~ROxQFuwK(;>g`}UAoGuqX@Kk?P{9yGZ(m^=% zF0ejA!rDAvx7y14cO$i`&r@=(Y-5=aTq6bA$|f1t&7AG*u0w0E>CQ)4Xf!x6oU0$v zCnu}>nf~hSk5x`4t2ht*9@`@Sjd&@?yo9F==x&+X0a;W zJ#vV|&qIiA92zqLQ~rt-ESF$O+7@FEt|Q_?w!gIwZoh`1I==5rHEhUk=07V~Q<@`F z6uTp@zbc#eQSW`?aL-N+lgLRz>rAD77@oH8+s% zKb`0v?T5`vV@}0iH=stT8rDcv{<*~(;VSjd%Hjzde^aVjnoJ8nmlzQ$hGd&bASu1H zSW(5ldG6fOY&p)Z&3mS4%`8?MAT(qqmhe3vXT|sMo{TjjFVARc#di0aX#7*WXFP(X zXP_?US3@XzcB&DP8rKiUxl2`=wl$3kyo)*eDVk1jTTbxXpzf^}gY~v5FAOFt8sp&? zZj#JB=h-S(iZ1rPI;ZwGI_clP*9(fwh3)q0x_*CqtCOp{lTyz%6%RCBolPso!WJQ6 zK_rELY9mBiLuSoqWa_sF~Id_yJLBRd?Y;Dwlrm#(D6NBYG0u4$YIR{Xp<6xV{YM zd6k#Ph z6(eE7myw2^4>Tsd0|YfASUa^((@AzGL8C!imu7Q%k2F+^#&3w?!2TwfGDCBFQS3E2 zqJd?k)zDN#q+kAryd$#&XDVn~!lTthz)(;|lHd;o_tnDtzVf#LFJZR$vq_g`<%*}) zB~_h{3m$p`gddSA%YZ(M#%D7-$xU3ZIGat-EvQ0o3NNfsQ;ai=wML%-r#{ndwt(d; zh~;ivS}UU4!denG8{p8RXt7Ej@L^6(oXCNCxvGTSobwJm4UZC-Q_W6P!q4}0+ zKTz#}>|2q5sMWrNzrUjXE`ze09O_H<=M(Jb*r+G^0mXxqIyaRFT*=%gYt z@NXpY9&Z@$bTkTMsWOUWSX|R%C@DXtmP)MCDnok=+S{W2bzC}k(D?H9V8(TYT0}49 z21T~%3h7_O4W)|QLI!P1OIh1Iqrmlbjws1`92~)PVqOedfv5!diz|{w)814vOrSwa zJO@UmSV69k5e@JRxN5fAmw+`<_LaqB(^RX*YCV|dKELcAnx_b2L;*uRp*=#NI{!69 z^aD|w(3}tN8f+R>Y^xPMG?&${<``ocU(+0lP(kQO+T_^#8>c^@l9{!EpB0jGLF*>y z`#3*P>;;@C(Cq2u4+V)7JWhbq-B(G;UXqr5%Zv(J_5Q zu2bx!t*yV>KlqN>&niZte@ZgXe&5CnM?tmLpMM|GJu_>jzyzX?gd1pJF5Z4_9BBW$ zB=4j@o_(imF&VqdY|SsCw^PZg*=laiQDD2Z95#@KVE10lv(2Qkk#8rs+_uyC}Jp;|jkUL~dLXL>jx=}&qBQZj6>C{LF=6q$w zwE#2bIGUXfVhx{@w_(!2W)#`oQ}LVMFe@Ys6w~DhXFZ9RjVLkDNGf?r9f=Q$eS?ig zUY$lQRDo6Qqe5Cxzek;VVQ4}`65IVe9^lt8I7VkQa{7gZjnlHHN>{oM%;xU9*N z^b8n&Vey1QV&^3*Ga}Fi@!%MTki{@~G-c{xbPaUHG-+mL|1ozK3!)$&m^+L`V%NnockK>q|36xjA3Q zXz6?gmw0VD<-~Mf0%a;rp~R1Xzsi)i&ARk6tpLgdbHMBu8DkvdB&u-8C^T5~=1S#d z$Vr?al1*LFP${-mnQBsxFkR^2Lhprt$oWdErTh$1E$J86alI}ADr{1U!U`A&<-*fzHmnjBW0s^Ryb^w~DNM_raq$P1@QnK& zC!zghj&C^I(HFijCq~}~WlLD^4UEPp%}(>e*9Ia7Av`0sUUfA#UGuM$ca_;8zk~cf zJ|Lq+Llyonbn}0R%>O|*b8v8T{SS6C;D585zyE*O&7WrDG(3(z)zu|tf2^p*kKz90 zdbPgzmXsJl~oQ zZeG@oUck|QA1~D(cb`rf_HW=JKi}u)CbkA2B7LvYt@AUxkB57OlFN`GDDsp(e`GkpY8^sI#Q&N*TjClfd29;Il>$gbNT)EctB2 z4{XuX`SEZ7vI9`C1X#-rvwa`0L?FP1|Wz{>(lVpmd?8s|C9hnRVS)Ut4y$v;yj;bN9br8zQccu|vf5?$cz*td{ zV=VspjU@gXMYuqCBNCz8{(08PpJaj9h*2)DNzu_k(E*)9 zm5&`W)kmop328LqH;$4f&mCVDe`ki?tfbuIf-I7*(@+rL34NE4TxAu{<^glVGyq|= zFV28kD(!E`3dXphCQ%{ehTEa^XKHuY+SjCB0mu>v59b3 z<2);w&?B4NP|cXxjwxfVxm`ELbW9HvsfhksM}z;&*-KavhW{x6fF3*kGVOR#7=5I< zzE(L+8_1c=a51Ep)g)cXULIfvNG}28s2t)rh_LcT4y5Y8xSxvmq>kKTC2v`lhcN)% zqUgWYGyA=o2WjVsRmbFRkw@@=!|xO@em>2PLBp)xBH`L91|jN0ntU;DHw;MDcnaLH zjY(3#*mJ}Quk_ip!@q)L1yrAc`K_PJWrYAG3{HD3xWWU4}VPFGqBY<*c)nkq4BeO z->bQ*arXflAyyt9BWGFTnWn?`j*$sV$!Zcustk}kN8mV< zK}=T!V?qf?$Z5{v;=&(cu;w)z=yoeki6fLH|AyopS(01xh5IMISAYxR-V!dsRcVpX zzZSx%fz&fGfLI2bM$tb@0YWg+$}eW#=}bm4qZyn_9W5;(-xJH^(-gBA?g?Cry$o)) z)?ihP;^66v&Hiy3Is7$;!-!yMVN;3pqPu+VVgE%I^K_Cv7b=b4X!8===3&~u3^c+h zYE~&SiM3ImBi2ix&jVE=B8r~vcu;uVMHBI6PeTJ4>&|B(+bp5GXB{Gxv=C0 z?ezSnfsZt%w}1=2<$>=!l@X#=ug;k+Kv9R{_%^RhuFEOv2kre`GJ`?s3U}DN5OWo( za#v6+R7v!V=98kUUujl=&@w~hZd>n76zkWZ6iXDcfUmq{qdY&0$qV)4hylJWg$|v1 zAMqaUQGF`5>w5iu_;(MofzGfDhls;eQ7X$#hb>D?v=`DY%43)VoS~XZ4xS#9XHckO z0-3>rBgPL;D`D!L4zcy)C`~}%LwBz?nFQmRbCga`t&io8!#a3gwJ(~7LYl}08l0CR z&6YvUiH9azp|`Vo(XBva2}k!U6)lY}Dr}d;uZ;x#$u4ByHx+-Dl*N--G8UF)GyjP= zg)iplywN5OkXUV$Z1sJJaacn;`4WP%@%PMfUv>q|gQZgMbLRjJncMj%Tj5uLjmLI< zLf!@SwnWHi#8FsEhmDzIbUq9VWNJnZ!9R5A5euoy1C+h5VpD5~r2tv9wigkq+CnBziRbYL=n!m}498D>dqHIo31%Bz$%J)&6V8}H_y=f&=Qu=gsXI`3hTPBCidm+L=@SD!JD82eTZoD>1MU zj&*hhqb0(!{9Mr>)hUn<6T2DJrtL)?u4S1S8KXgk6lkqX9mwGsv0PXQ)Vu&uaUlOLLS5Ncdv)1S=QAf;_uTV2e7;+O|e@{zUSw__tna&f+ zoXbR+Zu*diMK4TWwvC6pe!ck-FScT~XPhFo0`~239lsXpG=ni@tRHE7+=zx=Do{0F zg6~f=%4+W2f`_U(wtr^y+8S!Pp%%DiQULyL$xYEdf2ZVevW*jOvDT;lq~uTx z;<+z=E=~FRZCyJ+Z{2yXcXR2Iab3x64bffc9{m+M&VSqs?mT-}G;&G|_jUGPpLP=< ze{45bGU+b6r<8QD4Rs%E;oSo$dd;pS7(mv{6 z)DP+i?!(U{Pd+L@@!ow0^7qOA#vYFGh9e)JcAKb}1KW?)85 zxC-S{=QCR6ipd1{C$PrzuNI24-trQg)=#*j+jzm9wQfy@n$Ar-wBNERQOb56bEJf# z`m1rBL{d1N6*0_q>mP5_N&aaCCG_W?C1W~+OLyZ)-+QMa@r{TZWL|;3S<_~>9_Vle z^5U;>chiWHq3yMJ9q=tC44E#Jd&(M_4VVgq?XXIbV3gOgCDJD~yX}csS)1*4cSjK~ z0Nze$pK3Rqp3vP+U+l*)!%ew2Z9KHk?MaCe_icn}6$3m+38L8{l;03}y3BR3Uc}_@ zZvqX}>j4;h8^6j*Dq$UZ)A<(YMI_^yBKJ=n)lmU^P!tEl8-=wQe znRDO!i!yyc(PvWFJj>8eM9lcD%;aw?vyym7HSr(`we0FS=(a|u+8;`a-p#kS)-ngF z0sI}&76UYND(Mhsea0EZv%R1yDFh$NcxKGR&V-(^TZcluJ=NEtPvk^Tb_lkuhmEXR zI$vvZ%mK0*Jh!7=^)RC@v*gX~X@zz56D~wwjt6vxIFti5wIrXFaMkQ}iO+DFh26xM zEa7IfQEl*^btK927tjO>y=AR1J2cRW{+;eCl^m=Hb!OzE{_~nF3_HBB{rj2Se((v3 zrz6VG4( zL|A_H8Yb_0v;AeAgFFqFL;O&%S1C8!AlxTyo>!ZT zcny;`HcK-tD16Et^tjp|))CrY9iMzt^}V%i<^w`$9W)fU{LI-%KDt(R^Kj!A(YvYL zFzdT{B4FY;y>&10cE{)5r2Z^ zM^(@o?RQ$Tdvg=I(R7-Hn@F4-dA};GGOVLNt;qX2j`X9wxUX}o29cSJ(4nfzTpJPN z865J^jT*qbaFo^m;g{Fr+sIoV5&$`*s+74%(=KV7B=^OUi6?7IEZ5htX1MX#lJZLB z?&Dl`E%d0_riQ_d70YjnQoFW7S{`>aHa9iaR+Zry7!4H9C)bkEW1KC-vt_9MEd5fx zqkiHInJnXUX-dj&_Bc1F=-amN(4h~EY}6WYh47*OYt`g4mHgH}O&2j6&g!!-L!Q<> z@UYSFSg(CLi&xR#3;Tn`4PYe55@EW|ML*E&=-4V~tFU>dgxDv~ln1A`v^k*TrBE(y z85eNqcmuimJ5-a8JSFgc&eWoz9Oia$u`>JnSg3H4@6bafXTSkJG|GI}!p*6nyu$sw z1!Gjfmt?n~_(!Lt3W-El`ylOK3ejSF2hlBQ&Z+Y|NWknReYT_Jjmx$>E#$f4` z_A?+dIPN5LjOa)9rsJ5OTYylRZ*5^Z&F+>YoH?k!g%S7?%50{4AM7NTUp2px=n`G% z-0P1xb)?}BN~zH^LlH6d&~H)yt))-_kzo5ImlM*~h=dfS_xHT1Q(!I!2=!b+ZD^jM zEkf^jBSZb!!7QP9UvYB65~r9=PSH7_5i@p&s|NpkEg&#Y|;NR zZGf$1(EtVfen83KC@|~dDjSlYNA9=umzdFQN5ubvXBN88=|xT^OY@Js?RNuFSoPN; zNTWz7zj^M29?7ffMHbjkU(U-c%L6%e7Li*^8Uz)mKB))pIi)MvV{elt7jQ1 zTiv2I_xj{^k7n_Uy+x_t^S6a>p%-f(qg&d=nJ^v>nH1$}lH}RKf?%a^|C$m!Cm8Ty znYel6?K~8z*W@s=_c9gV&F`F5stPmhyR6nYypH0kJ8@8{ErAbI@Wvt_oBMZ87VGK} z*;FkIC+Lwnalgak7saF!YY{KW8?4L1J*jzqG^be6Hw#5-39cv8e@)NK!a`sf+xl}6 zfvORxk;T9n*sU$m%CEm4$O-jG^oz_`g9TeC>M19eQ%!PkU=64t&pGP|s3p$aukgXi z`pG=H&zkDb%ZXiG(!;(ny@jvM(NY(>&+jXJNsrLS@EG&C0Aj?OO%OV%kT<>4*&Awq z^2?*g3~E1Ib>@4h#pC@OkyPqxDB6+XFmza2b>375t=cozbZ<*ak7gPVmoeK$)d(cj zO=kn+Qiu1Iz{95jX%fejMs#!D5+_Hh-Byk<=26=HFff4h5}D|8Y3TpS$m?D34Hsv) z_6!%dnrB3^NCeu!Wpfg3bh76RU%?%xkV8-I$+PaxsCKsh%PFR=v^%Rzq`bEgh+mSMD*IV;x@po+h=(GT7!U6fawxfMRkbkPE@L|%8P91ftku`ai5rb!J zXt^6~?^6m~P5$O^&6j?MUh^{ft8At2@Chs*MQy15D(cg}zBx?g-gN}$oEMA$a4D2>o$9fTaY!=^kvYu+JZogS zx|B>xqPV_9RC$)0v~cGhy)BnK{~0F^{^RV24iUcN^=u1p?%FV*1}NJ!hFgG>8dF@w z=Fo)T|A5pkl;S7q+ynhNL-ECeuzhNYBVC^hXcEq zXdE}*SSp}pToOVRBf3ad#uYPC)7o4)!}s@X&0^P=F`sHKtF0B}rrPxvmEryYYg@Bg zwEH99YLn(Oe6}(eU?gTAqw2T_`IpTm^O4altKWSTZT`9Iuwi(%9rbdBd?*ouhL| zMQ9^?%biG{0#5+;!_~*H#L^7}qUnXWRhaI77E09a#=n&A&{l^Uv6rn!Z~{kQ6Nnkd;Anz7Fq1`m#xi*P@76?5Dl+`9%dpWMGq z{t1ryg{Nglf-60vCK<~~Bok8xEkPP%yD`LsZIXl?Y=DtKWAhu!d|YK7VG{k|Q{!nfGi^mvF)_4=hD{;WsQGZm9> zU7hDMC_(qx8aY5M7`L@r6u^q-`WvgNx#ICx^HzC;D5TP9O>|R;Ia-xG2)NB_C|k`& zE0)~4ZRrmx%R-Sp<()aEQ;v2!FAu)d&i_Q?ws`n8pLB;!@*$1?T!1_4HhE9b{GIw- z76I8YwL~Di_QW@IROXBur*v}%7>K&c^(|kgw72WJzk8d-EAUqyX+F?f8Kzs^T*WIx_4tbwqq8{=Q zuVYe18P3pbjf05g2sH}N{hI|Ad;;*1Wq00oGnoV5nB>kyb*QHK60PT;l~eha-%AMe zB50X-!vuaV6Gd`9)`_8PCrkgEFm2hr)T;APES+$Ud_v_%KLjmbISu1XkgEr!>l;L- z>}hfo5;p|S3oS778`Cfx7rej5pPoN+B?f!P;Jo6?*kQ08lY$Vu%~Ff4pL26?kIOD@ zI(CC-lCk~;3Pzy&$9|bwjGWV-W?9<^E@)3lBzUr33%G$i0JqVhWFv0qp9*{}qEoZ_ zr>{5h7`N)f&3s}(07y*(5zUH57g3Tu+q>uCOeZU#GVHQt!@c)DoSnoG)#ah*fA=7k z9m+)%z$8I4n?>P|8pClI6rJ#SWy)>quE-r`vhAU3D{AW`C=`+$qSq&E)8?SA&S1t! z2a|LV3o}iQXOCC}2zo8F{TE|z8C6NMY>PGxjZ5PVH16*1?(XjH?$Ef)!W|lScXxMp zUAVi$<=cCobI*I@zHwiTv8q;PL}f;1%s(|FGov(~g%|6tt-j{8tt3v7`$lO~`?h2X z&%ikx^y%o=qeI*jRS%7mH>>iD;^QfEc#JczLy5~vD;D*9>uF)lCZ&Zq!*pcNW2d8I!lM;2w{kLe_Hfsv#+fploVxG4!I@hCUl=Eq-fVa72LHMM}nVnNa}_n>jaOhO`B;pwrGISE31 zhZI8Ej1gk`iRJYta=a*dH=1*cN2KMrzlJe<16itWk zhG!doY9#LKv5j-~OW9-zhx5sN$%*F1Myt6ap|Si|4q#0r3mst(1tFbA2k+vQ;Z3o5hEZ$i~u|-fJ#(pJp=`m4$@H~Loj2oir`dfyfu*T2@q*laJdut$@h~oH z#4Q7>C8Iea!YYqx;gTlB8Ky94EZygoN+WAr(%9X)H)ego%RpKfG(Y#S>-hauQO3(o ze=Ivgy)v?;*yQLu=$pq}R@+fuMg*-@i(LG^ghZec5l-IP!mkSO4QP#G72^PPQJ0@Z zEIN{rQ(s&26`!Rpq8aX8r*2Mr+Hn%!kT^h6vHMqi7BQ$PuKSlaHXe2ol@cd7M&NhP zWEMfRDcZ*Ry~_zl7amO2vF5Xk+qlY>R~-99BfZX@jW}K5TvuI^&ZxG?&)1coPB5w) zt%MspF;=Xx02OO=>n&b_YaE?6f@_7jixbb$fU+e5%?5CFL&eV9&OyVdBCLYJ!sxXK zXwBfuVsa;Ih-)2lKPCvmHCZudAgKL~SmKQSN@B;gPYFSqHCiiUd17a&{;ZI}tdTji z3g5o&&1bIDHpI+f3+CRX6EE(d*7MqiqKOi8B*k7J8p_S>eXnia9K}R$ptwm-K}rx} zkO@AgC~ZdcK~DGDGmE}X;;7~b#ID_W1=&XUES(P_JO3#klEr=T0`ehab5O7%RMoeG z??pG{y(?a|Vf)<%SESeEGrLIa;KSHDD`Pa(2)S`->cn-lVKrMdpC}#6?#R5X*Su11 z3El+j-8|qLe{ex&cs^v$0xtCFIxJ9rMKBts&o}Q7_@dH~zsEy4*}wNs0z`@Lm*pRp zXZA#2qa~)qS;guGfcYyk@Ri}Q#m9|@N=aO_`pDDl07+HJxgF*f3e_}`cz&E%1S3G9 z_;W9$d1=_b0*^-07XVG;&FByMxRCe{f3p(Nw^v zv2Dt~s(sh$@(NL*R{jo3%wDZZ=w)%gtq83B4Ndr$L8g&wtYAp^Q= zBL#Yks4({s2S5|L=D?7l8EnC`UQdU77xJ<8n(n_xH~VnW$KY(@2q^+h1d zP&QtQ#wCdx8~ZfQ@XV@ySy^4V|0A;_Pjq69)S{|xqEhSI@hFrlM#jBfXs4Bk(t|It>+tIYe%^bV{Tf@ol>CR_CO zw;H$$0%tLTTX#RCT;Tog5zlXAEBSiu?@U6E1>eww9$`{&&r!A`T%cFl%|iZQ4G0XV z2|IQDA)n#t`E5;C$K8kbHphx~k2OQKc{%cy2RUA~+)|ZNY~sW&qT<0LFdVU(zo*_P zp>}e7eGlfD=DF(m;wkf(ar&G~ns?~d44jjtI@tg)F+1QXb3+Own_gscHQa1^(h;>D zZYh>4Z94ubgW#B5=x|k==j{Kz`@V7RcmVx%ud{&7&@tbB5`Sr4e2|wge#NP5JfCUs zC~xbiqjb%yg-8puXhAOJr0;vzJ3AFqzHFyd?0{KbpV{nrDte3OMu^J(r5ap3= z6$i?bYbi8{waTYSvW$>NC5Ql&YsFp2A48)Fg+XIudatvaT zjX>2$CbEID*Lz0$F}Gd2yr4XzxO+o?I=W5CBU}YPnB)SupwEP}ZDL7Y{Ba<-p<4qk z3#>Xrn((&Xd;IDb*37tf z@qnF&;DC|n8Oao`t3b-oj0t8<{oaN(C5$bqRsv>-57z_S030j$iJWF%_-;PC-m^lUKVw*6(HOzWTMn13-A78F$TFN5{%s;H zE!iZIghI(>O*|5>njf2>8b=XDMP4&e+pt2UZa_RMt&ok9OeMoYQHEDRHl~jYNVFW8 zYTX(cT}NKu+c4ZPT+iF6ZCgHfLT|>t&}y2<+>vpXv~hSXq^EAmI>9P!-~!iDtB_Va zHH>TLOD|ot#ON&epc%Y?`%`v3`6~~6VisfX&w3iM&;zLtc=rM5PQY}E(ZomqHi*@r^_+bgD z?jT^(j5*b5!h&ei6y_I#vHB&$Ijq!6XXdI#j9R=+{wcNik>-yl?nK87tw-M|`A}IA zRkHzpMxQhB#|89)POl2Y71J&m1RMN}QLhUm6MUVzI|Cz2qH?Zf-Maf8e4I%y2?PhU z6t9l8|sB{6eS&zeN3ft3Fd-QrO@=5 zF{QNOsE9~_rb%2gK>p2|`;$q&vzfgzIgBP8Yvoa5_kwu%rlUURR=n2_vx~-u?1T7T z9(jMLY?n98mnVO<ywUm3{RU+HZal#F=a%JeAQ?lwO3BeJqw_U@iz$ok(H<8Kl7F?+&-!<$hth1&HIwggSyi-V;YtG&s8Nq9=GDpxGMCfW+=vs;(MKN9|w3P*@gQGtebDF>VG2x=72c4iSvuSlp4K9lAI)Gy?B;~D z4y~?{`X}J72cI6EWcNsa!WrEA+K33_TKGzaEX%7^``i2-cw1^-4qFwON1yx65^g+` zH|^cPBf-GvnrK8P6d93FJ!RlAv#wb^D|UT~MC|elcO3o5*aKkD${jPUA1=rFHXZ(? zBfzuF1F9?e>zrrSP)*IJWP-th?+hOw+|+>QlEeu{%3XWw^}v4B;YD?SS~P=@ZR^DDs2dFC5-Jqw=XTwt-*? z{3Grti`U;1ZuP(!%( zV)<=nie{yJ1%7lDC zGZh)yau5AUJNzBaQ~~FYMn&=9r2{*&PWYo$=v5YSTwmG-1P>U8X`={FSB~1-J2YKM zFDhSWcNHpWsT&G*@378U@dv-jq#>ebazk~YO5PhyZD$ogkm)to-wtYSaBrr0K02;4 zYLq$Y6C!Hge4HL#5tA+O$feQ%64$NI64llXjtdiB=jIqaSXA3VD4Oc(P|C4Yt98Z= zDfRLaGf6#fp2@@j&CLuvpp_xSk5P)QnrcFOoFo4Dht2(DH?pe-+IlkO_&u~nnL9j~ zyqv`jtJn>VxScqUTTAHlgqe_8VR8yjVUk8(0fxx1C6laJ9;kz=x-Sqf>q!+%*-{NE z#OB&k0aC;npmbtwF)gzAn)K%fAzu%PI+bfhR@gv%hqMEj^9)OD1+|#3H!*As=fyZ)eT#ka!CcP-CQoyi}I%ja%u(3k2SpXhciW-S% zJG4ju!{w?)jluqi@m!w0i<<85DZkkAhAK6f>>X^5lu%#Q{z~;O2Yu&io+EOX5WDIe zJG+XMQH{I$Z@^(c5${rn`x1Pe0mCA^8N?ach-uHTt+jl&9a%>{Hn8`C*&c6gnhH5o zY(m5;I(n4g`(8#j^j&>ylV7N3P(`D9vQY=-(|(wD%-x|`a@O5Osc?8Tde}^|)hs`M z#xtPtNm6cPGl&BS1%q$w08afrWy?%I~Cba4iDHIJm1N4YcBATk? zjM|WnYc&WbHgn1^y}&=J;Mp2l13)HltPB{dhY2=MuE4TceM{7`I9kZT;5X|~RD+hiSi*5S5(VhN(v^=TsH8JRrGhjSD~i zv8>qdh`@Yqd~p{93bnHD_7jVSyR-vLleb1(q7DgKEegL6s^KqJ^eehR9N$_6BtwSo z_9x4(C1q&Ra{4pl$c#&$#Oy2yl{)gSpkziuwE?n}Y1#`47H{t|u6&J$+kcEk^yrww z=^CW4AyST`L&V}=98*QcQfDrcJb z$%^?rc4Ds(b^mO?+_*$AZ8?B8==54s_A(GTAoN{aQvdpb`A6Y|q@JVRcc3I3b?Aai zF{BWIz@b2wKV6Ja2I6>M`5snQ4{XdxDB#FH%+s)ZBc$`2urJRQ1&y#9k6grG8^0~& zA`~CbHyZ?6$RB1z(Nk7l3m84xXS43c(6_s2&{h35lU~ zEg7;aF@;R7#N3`;*gBsr%>P?$0XJ?rtKIql;c(naX@6|33jErFEeX-=1Zt&2tJP|6 zmi(a$W_|k&Ve4Z9XEUK5OQf-TRk}4q(-#lHwi5}#wuJz}R$7CjyKhbJR^{s;lTTlq zP5ac4>pl|Xt$Od^vE*x9$m;-cicqn)cs~%~xcf_EJHcL7Ft;7kIHplwl0;20xo66% zj$Bhkk~Rk|_JZMG7eQMd`46^hibq&CYO6EIt2~Btb0q4~dSFFQq+p$Wdi(Se)SswK z8fNq#IQT21vLkxzG$E9v*0aJ}tWE0CR|u&t*MAAoagjK#BBI5vq1T;5Bw`t}Fjni$ z_ZFosRahG^t$+D6vmV4rxC`B4q5UYun#W?T(n5xRH&ZkdRO=cfHIaOBg`62~P7Mq< zN^QAIKl%J-Zk_V|AI9uIWY^cff7ms8_W!}1DY@Gjf01LhHcmpuj)o5Ac22fmWEsDs zp|On<9y<#w9<89hotUw?shJZVD+41Q?LTV&$fz0U>Ho#5nL6VAL$iIgARu7thNnqQ zPxtj2H7g@49z6>aJsv$h3xoE*6=d|Szd94;|L3BVayB$K(ie5mxA|h^XvLlMt;`Mi zZA`6X6^XRMp(*i{GPWV*ipz>%0BC_|^D-6vgmZzwA`|kCn`f zU)BGZ^TqrbGvNJ;DOC7}^83&585sUEe9f=+>FDsZ|69QH9|6PvW*@&s{BKHua(=>k@DRn$i-CUCI=tcVEYD=` z><7of52S2Qq2VZonN5n7ZM&#J0<1Lo;=-8|kA?3e?{)Bc8PP^d7S8EIl?T3={z|I6==c>i+Xzvkb;(Mixu-vN*D3no(f|D&K}t88QbFRJ%n z4*Y+(|G&(nXJTff`)}W~{tx5-i%=51yNZ8>g{gbx-IWS0q*kLMUEziGZ^@PLrs zCn{@HyCxK8%`dUxd#_n+JWNUixF?ng8@sr)#!O`g!>b0FI+0`xso-Y{?B?Svq2))3 zkrRcv*`eM?>Q0M7h;n4_O*GpMj!X0WwLM!7SN41YtA#q|CX)LmF;>AZeNRR z%0dNaSi|&N>km5TOgoM_>MTFejCNzIB?hW-UY-|0DakH3mid_}RZjC+6t z{02N{0&4+@aiZex4AW84iuZz3c7kBRZTuRMqgI=pn-)&5glF zbB`cfRSR0rrlsH7fXVqq_0+D%g{aD>wIjM$PL9Mn*RZhp@cA$&$YZiubE0yhN^Y@q z0Fqk*Q@iP%-UGwSeKn|obVa-Q{#b=qOCoD|JN@*5zQ9VK5ylHwASt)dFVA7B6h|fY z(pv6OoJ4EI#uBUeT5)4)iHK3IaMPS|#@2us5dXn%{DyR6^ot77AcI4(>|$%N4+I6V zC<=oX!xTg!T+Je}LgL&CFtZ~0(qf*mRz_Hr^A@g^6TcJ61tjpvg-jQk%NnzkqYjlo z=@+`|$?{aJxgDr;BW3$tVR8F{_cQ}+najX8b&sP|)Q^0gwGIj#Q_-i4;X|c-Eo`@x z)t%Aa$jUVC{-WO#5K^eXcN>FNJAQ+g?%Uigm0&uhu9ON0XZn={zHcs<1U_I+M+6r> zir_dvAgBdOhmi+0ECDH25ab4eq>7L=0Cp0K?o)AJZs3e&zrxKL(&9s1fbNJS&wC z6FW$d8KV@%l!3G*?~%r^Wzd@TASXjUL)M1|3EuN{z(Or*l3@WD9vOrBZ~K}crr$oYH+Q#k)(SUwq5tSUqJi=|>DbECbQg38 zgLe~m2=9M$^o$Sz)tbk8l{TsuF^&7xFAj!4Uib*Av#jZbRa#WkQ@^=e(;ShXO;_A> zR5@%0F+mKovS*eqZGZ+FZ}8w|3rtt*67nR}9eP>W<0RBYZ4%<4xoDcn1jK}^3T={| zn9kn`eX!gu3|r2q68h3mM7){fYotXFZw6I~eEd0ByRCp&*Ik!2&3WqFMFi-g1^f!m z{q;CD|zb8o9f+j}5HyM$78Lqh?O7u0Y1GvAftqnDvgU7)CY|YOEOIipy@y=^+kcRs_ zm^DXrVd?jM3iKHs+?%MNbn%mFyek1yYEf4sAuWve!dr>R4FC|NU!CYNSujyCeG{|Y!M;}4|cD~MH5bDxz zw^r_QcJ0@~!j{5?neNFS+YRagK)^PGrc)mqn#iN%W5jz67C08PUh?Erw=up)dI z>s3EGBwW8Lbr`DRB(rHULxI?YgA(y~L{4iu@E|tjKIhj&O`6i@G!e(N(d47_fts|< z=U;LAR;VErS>7O9;dtD==TBRo&6L5Qxxwj!#l~|MhC*+upLlwFx?H2Vu&QqJeJgDv zmT$a|Rrz#-Jn#)TNH zx2;>E`Q~c;cTxv}o$Dnv^W(UJ-Mai55MN1g$6PlJM}z(Zb?Y_d26}xLmij!aqZWqA zirVuuaJHtu-XqXCF^fU#gGhN z=@nMRf7gjX6?#p4bEpcNBR&l8vTb9M0d5ejNyNljmBbn$$9a5eN$3DPbmxhyq&lW} zz;MUJi$KbN95*CUGe4jGUxryi6OxA&fz%pODsigE1w?%QK+YstSPDTzSirFnrF&Ru ze&$^P4}qp0|2vGsRWgu_8lQ2Pavsjz2mhHlRf z(dY_w3B#_yRC-u;BmqL)(y@fK=m{J{1{bMz>zQ?aX0Oo;*RGE>k7?{T{#??|Unx-$V7>%o8n+ZLcDjDs&* z{d{8{k%}HiN&oN;1oQUC*&%&eij#gxb!yX!Eg#~9h?ija&X_JpLn1kR4%E4UkT46B zDR>+~HMIqkfmIL-{ySmefZP&w_jggcgDHM8r^|%3I^az4nEtt9p1;17V2rLXeFS&p z7KnUM07&l|K09Q^ z@&G!eF9L*lU<_Nc?f~c`SZb`e6Z%1CUr4sy>DsHhqNR(6JvOQ54p&bwj6~n&guB%h zs3f!;0l(3_VOtS*G2{vv)*V5-;Su5X*Wp*4-I_K%O1{HF`wG!xYxaKx5HH(2AmD5( zJ~?d;Tpm2$qCcI+sbUf`OLir>NL-Q?j6ylv-0T2(72_4HORyAO3$w)E$?rW*6x9Z3 zBJpApVuQM!(GMD+Q@rBdK(;`EbnfZxpq3xra@c=m(xl6dg*c*g#H#W)oIp3ke1$Iy zrslfnIB#pE7JD^TjL%eD{$K+e-ncetQN>Xe@|YxB1vDr&C{(vO#XGe(32YN_lfTaK zBj+)uBzmPZjhOo2ZozAzdd?>I9L>Z`ppd1O@&+k$_^Dz`(*n!p{*BEYa{k)0Hu;RO z>KmnR-_a)Vr}&4=W*;Ok>6Sb%-1N`Rm3pvx=2RV-ssdI6)XM^d>8+W}`fMJ_PbuAk zkR#n=%R6e1$d3RYDc*u23{!nHeRrzKgX$kvsGUt;At&!Mp9iEPARcG`rV;6~c;#)+ zZw`h|XD=q$;`=vyAF3y_ll_RK;^dZorea0C!Y8$>1XOXschn=m~@g$ zK5T*(sfkGAE_(`LN2aTUpaNsO?o0z$|Hm-Q%JUtgIgREQq8g_u9(Zs?lB)~uG}V3x z=j0?W6S1V3^c1@8Jb!+N^A`PxxRY?b=2Y-Kj3F(mHWlyWN^b{`E{r9&VtvnOhxd7b zkPCw2dW0$oKHFA}pKFi5udBPGd_aAMb4Sv0!-|+8948`8WS^CP`5<7$?mrADqQ9YQ zz8QE^WZ-ay#oU~o@0rI*`&!V6<#pTzfYa#>0X>??r4si@FSAQ^McC@fu^cbLf0p8^Xs+yX>1$Ej0Z07r<>h2}et@b-4n8FBo^z}JC zV$(8t^fUEVJuick!LvxM8~V8EtS(s{^?_DRoUzV$$&d%sn=%1;#fg5kTn?P&O6UhE z!=sjFQh~SAs4+V~qQ1UM>t)O>t%jpT)+8m7oX&{d(Mdz6cXw5g85TXH1u)X(Dwcl1 z{DmPNrj0x&_FUT9tcs7|+?$lVrOD)MqwYD}#fXBk{e5XI23Ez1^Rk165JJ)NFx0T( zkzf}DD#(sOQk{o(=ED5DbB^Z;b;n1j-k8NKD8WGgQ|9C2Uzk3lLO4Lx04BbSs> zVDmT@|DrC#ceSCSuUPJ`0##pcAWNfT2aiGmXd)9n`jPwK3oT?4_a(5)M}xsNM~Hm7 z3olpU=g=cqQjX))KJv9&ZnN5S5C!U@UT3EIi zk%7{W+$|#XJ(3y^3C)*HJap4Xq&nD9o>LTNwFW2YgP>fK`{C+a_lflY60J z(Dq(&P=F!jG2pR?C+;zxcZ6}+={Wl;XerMAPhDb#QJMlwNlW&)zy{nb5(CygGDsDK z7D)5&_bQQ1p)@}qMR^veYUK%HWFd@MiR0`NS~nVufL4Y2E?tc{4{UezVwh39O2}0` zKHqOlIhTc!<-4C#=sT6qUz_HFpkSbi)PjyvBBcZULpLbwx1&BEV_@QD1IPf$Ph#L_ ziBe3cF7ly);z`vFdZs{uJSks-Uky)6yKR97)1o_ITfKx{iB58rs^72pl~;6@IO=J! z`G*cC5wtZo;IiPS3|~w)yPj!A?M%3~w-TQfJu*8+$5mI7*jtY|%=d&t&nH%lSEeHToWLTrA}wxf3F{i6dOfz_pcww zQ^-9j{hL(gxgcmEp}bIS-9!ABZF6mg`FMO~?@x2wOS~~@Na7qk=Kf-`j&z+U$yQg! zL8KH;GITsH={}G&u*ZY&hPYZz*`Nr-@x>F9Idk5Q#-+3GlSG_)5_J~m5dYA;NNYHv zfWR6&Tfa-Sb*Rz;(_RK|VpJ&oSSeImu|#_=rJO84d7`Q`t^ZlC@EK#S-e>WP3_W|V zp4+&pvsX6=FJ-V%d|8n$?2}V1DOdKEH9lcvLJsUvZ!?dnW@t>oHb$zi$t(;pD{NHb z%oi7$V=m-|p`PvWSeYY2L5N88T|wk9Hx?lEd*SG)?3`59Bw5@BYPg%d9lmrn2nv2L z_R!u~^>$uEWpVLHFR?6S)ha+WpDaa-vZxj6=+u}+jA;UO)yBrwu1|M@LYXxaNpPfi zp5loY>+GK@qRuAyq~GfW+L{U8sJlP1O49*Iv(Hi6j$}&^fK|XH{`8K6X|!1Z>84}A zydK@JrQL^S-}d!gjKl0-7N&JiREHaBFh)R|>+x&4DVrCt>zZWgwt(aw4;FsZT(Zbq zK%7W8+6;F>!!)}Sa{D2xM|h~FE92vs2@Q9eWRwL?saszupqiGQJ!UPJcA zR6Myp?a`AjX_FBE_Q^XEk4q6}=-A zXPri5t`R858(T8$Z^2bsF}`RZx%|*;UTzO%yc{zQKgv-($G_dWw6Fo|$J(E5QHlz1 zuBPXd@+`_+ajoOzmp2@bRIxHI3@Fz~t%usE)0(X-p4-;@Ti$bb5u`jh>UXD-(=jRT z|88~qK)Ex9YR2jF@MP2-eIY(H<@B2unHT;ryJ2X6=W)>mQUME(sR7qpj|(_=66B*X9e1%B+=IyHl+hR?R= zRdGAkHR$|Lw_XEXb;b+K6kCtRPtRIjsfI)qiSiSx5upcx{S^Rfn7Yl!t`))o8+^uv z{5T+9uq`xFZ)4eBxfXJDA>CZf)dy2Wr9fZ3<;TQK&1@-7>gx6<>wapv@UQ`x@pC8$Vrb1xC(~kdQ@h@1E|4^)9;G>f{`vr9Xu5$mj0}i z3Mn5$cxELHKImqA3wwxC(7_ZR zFd@AJ+c4xx233+nimNz`#?cl}wuI1rbF7{Kb(e>%$6au>7W(hw%ta4+9gEDk?I1 z1Ftir6tmVq2E|jmvO-U%rSQrs8#S#?3tmVHs&C*9+a;}X^&}> z$k}`gdQ)>Acw4V29~$71BE6_IFnE4)3(T?ZdjBy5Qsfo$4sxgn#8`trH!rH4^l7_Y zf_${C-6$eovZTz!O5~i6YFuM7_N$xg@Gn`?p6q8x=p%9f~Dw+6wP;S|Vef_uVwvwN;9VR(A-?zC(xt&md zco5nx7ZeL+3x4g_Lo3)aOR`RQ5F-yumMom7ppH}Vb3q|La{zOn-jB8lVM@w6Y5Al#n;QQz0$NQAWrDjr3V9o=O^oiHXTkgv2IOBZi21EN8U>w&|HH* zo2tOnO!sC1D2|z^^X9@vc3a-xWghnc-BCh&?>7rZUMBdeX%P&H@t2Q{GDVXJl>;42 zCqc)~ERBdWMOSEDTZ83~dhV4RU>Y~tLTikHFcUC=h;xmG$Q5W!qGab|7m#;VLq`yJ zkW)W>c5!mT#;y)Qn*j!JuhltH*2czA?z6-r!l!(f8pX<(f~LYhF01q(Ci1Qs?V6RR z?W143k#TtM(vkLQPe6Oz^4_Rvb9sC-y+Ky-Rh+^#pX?hUjmOOtllgFCooK$zQuUD> z;=by?9g!S(GvO!j3V%n(llSO!?}+NT&iw%lCCxqbP|ntN^~l5+Q1?#LI-?lpn6mG* z3~XX48{p|-=Fb*4nN77SbTqj$Id{1f*?O;hy%W`LJ8S#hrqy#_#Wq2^~m>-9nK&QW$hpn z%5r#3GT|hJGmm6WuaZnAL1cvhKN>j?n*}tpXNF@SG|W5L4gtp=cI({E7Dpp*IZvZa7ox%fr?Kn1NLnpki} zB;CE#P_a>-?;aq}y;jEnS>KucWge+>l!2O<3s76$iG2RvX5Ka};_00cUOuj~i8B|7 z2}O+*$#(>3n9ka}J}W{rAJsz1@$*@=@n{Ts3`7WaC(=TzM7Xs}%kN!I;PiUKE4bQe zO2?>8m2bmv@TwYjUWpwuhF>Aok@IaVBcx$ka8ni4P!IBeKbZNk(cVUw_iZeE0L3y@ zS4~YjNZMV-apDd_o;)Lkh=Z-`iUdoGBise>-~6ITO4i7_XXmv7O$n$DIF(jt#y`0AF=DeGEAEH`|LPU z)pxm>a<`P)*<2%Cvk^4Fw{d*NEy-Ee-2mcFHgg;;LJ(aEq@ZWo<2`B9nVS%tsa z%7LfUYCzdOuIwKZ8T?r*^G|vYQyDRC(Us(>aql5uOr_!9ih>4$Z zY8K6~DQqCq?iU>WmF!XjdLFw?dr=K_Fslvs@MbFGv3sjec^q%rDsA*jot&V0IW}jM zeHDzpQ4hQtp@+(d;TNO(Q*d;fwzh%0eP=#z01HdQ#EUyxfuAKWE-5LmcJu#^8HP59 zLTpR-m3EP>6AdPWreZgp#oHoy4k4a&RF?bmgvZv{p6nT*TIy@InzqIJ_*@p%8HP;K zpqPg0YbmwzbSpwz0#{unh{eL&-u^a<@L|W_R}aWbOUqVsy_|%#EvE53Dt-ahmBuLp ze0_us--%)Pd6D^fL%NSU)B^fUmcTO6;=G3ROqF6@axsE=dD&K3<8Ard=iSL9u<~E6 z zlICn2WtPD%m=D6d);^=%X}!}d9vx#fJda!({sUj1d&q@tjj|GT#$<5(vG)PwA#QjOU{xs>5yZeyyX1A-<_x_fPepYex^1HrjSx=1Wn@o5Aur z2xk>N7h@!x6NoD-^~)=htIw#R%-U0xhf5<7j!VY2gfTT0Z;$FR#*eeuXXds9tb{hW zJ%fxgef{URe9H(d*gGk}P`4wTh%k7TQ*ZhZi5qin?LaZCd8(w`de|mvxn`E0pQ^=0 z{J*w?)7$DCK%dRK#?6I3Hm5Kc`f3{?maQwQ2}WlRTv$_#F-4OAp`m5veBR%Vp&~fx z^z0F0u|tfkqUo?3vHWH{Oe;J|4g-Ry%DSZC>vZ zb+w=Co|7)Bzt0w9qwM?Ho-yBM`JbWjEUtV{?(5I^%1d&4Mkq*Fx5l6eQGs&@xq`VY z%R@xEt_zrYUUG4*=^%4#vAxD4k2f@J`&D40niOC>Om(ztlc9M3%jU$DQ1l#weg*J@ zsD+ykG&P*idp>8^3U^BiIiVzU4KuW7o%}bj&*CQpa;LIu;e7a3eAH! z78(8EPL^Ea7wqBDNW~IV5E2c>cRwC4y{5R)a6OTPkI;k^6v-@j=}yzhzAA-1V7e;R zU%+KBZ7PrZc|xM1%@eO=nkcR(t1#~RD0Jt0t>-=J<)mgUzWaAiJN9BT`eHIM*q5Z| zG3U;EHcHgLow{bHT9)gi%;bHAmLQx{HO4E1(Xp%!MfG^Uw#` z^b@&rp3D=e!`6I+Swc8~NFPrh^Okd_N5$ppu=R=WudX>97w)o)8tnQGYfdBIp=*H0 z=tI;?!#U$;6T2yaU$bjw%tWLX+B2_<&9ZUl#Wb1dU4E1A01DO!(f(Hqkqv)Sw!a^N>V0V8I zxBV6ZqTbT4hu@f%c+LS_m!eYuIxZ1imyELu4#Fe!@I{&(6GR1JL|PiSLj1r$X9RY9 zJzAk4y@qR-p5C5@Q(0(i>I_ODiOMjY7J*72bW0p1P@r|47HsVaax-Ory9MdT z@6ciCyp+?t8#5|XS`dHPd_459#+#~eNl|{h@!w#1xO={0>$k3zY5UAo?ILjTabI@S z-3NSnc=nvZzSbHyZNl<6G2?sTGIjsVwETc4#o9;6&$9^6Qb`m%(Oi|k0ZE1jG%f3Y zBvG9oz7~Mq=qO7Rx7Bw5zr{BKNRRep+=wa{Djhd3v@(fN!7S=e#z}(hg#KEYN#7X1 zITSId*p3@Lw-*0_y)v3+$6!k2X9UAxG_c87+u?6U61e&;o~BC54__2;Fa)PebzL!y z0;U<+Ew^PEJOiWBQEE3*Db6u-%<>-VgVGNZek@$=%bNbp+xrThM_EDF&(fTZsk6tV zStpIKh9PYC&9C2SBvwXTtCfeUC!jup+jlYmY{vVb+2?_+^5;fUTX`pC^uU0y8{Ya) zL;)L^7%HR$cO?Jt5Y(z-YZ;X7Un|eMW*BF6h)Jwyp1#|H3tTu8f52%2nSpL{K_fr( zD{j)_l0D;xJXn*h;12>JsyZwtG6`uILxS*V3VN41U%9hCR+XEQQYZGS4us#(Szyj5 zq+|e{1Cz9P%JnO6LGpr2;I@O}Z|x(M2R-o-1-*Lm&vXjn1=U5dwe~&lD@B%1FSQHI zvalNpBn^vHv>IATD#d%Xe8p!YO_`veZGHC2E1s>Xg`KS zQn1@HATiULt@jEwunt>rU0uJRolOxN$#E@ca&ofdqRqW?pQMim(S~6z%9;ROlsoz) zw_0$@1H23XXY7@0ZWKcj%^(^R;Q2e)uqwb&6r7Vmnws3Y$2-2#li^t>q;$F;BOJLTp!eXg4L}QQ} z4Ssw@;b{r}>fmm7yBU$8o|5bpbb53E8V)yWvBFDW9~wT!!Bu1XJ;hdV4pVXrJPO-= z<_cfkWBCI&9fzy>Vr(IqG#FK0)%Un~@f0W3^9 zd`&u~O6O~n=~3uJ#3A?V2JPmu`##v-M<*sq+=HAvPf7p%q(@zz1=^mJ26w^9*rGpZY%pBU>da1HWi<XaEv?lv{N5=~|?9Ju#f2j1h4W{dEzGKVr#KDF66dbAd=+O!_Jci1Gh>l(cdSUG|!CHa#zUG zDqJ9AK7n;Ftkr1KY|->qb64Z;(N^O!YvAfZ@}gZEL#PpaL*X3QIZ!|u)vx|ZvUimm zs7e|B7fGlD@^mNN-QO`9ZV??;_1Z^AuhpIj$q!Ok{(Sm4kY~M2Dk$0w;X5LohKJIs z|BP*Q$(6?0Do@U^)4*Rm1Uq&%&U@NDZM0-8J%=P?uI}SM`jXVaQvUB2LCHdqe=7e1 z(ttJmOgE1}`lI%(d#_h`kbRk6Js$AM-*=L?F)ZpT0!Xe7G2EgN%fwr587-K!($(6; z8~7E@#d}X|)>*X~TLYhh?t#1m*@w1QuJx{GpFmuTEwim<=OD{86Wp=3XX&@EB`7vy zKm?2OKm7?@%u^}{rSicgeOA(=YR>i6B>vvF`_H5MC*Rj9MlF^$-gxeL*7A&CHgdTv zeA6DwUY|kk|D4mghjb2X9@t8T?6W2`Ei_r%a=^F9Od~wMj*6a$HdX8)QXBB6f1N>FuIP+ahM`E4v<3KY~=K@;2xf z80>!TtwiYm~sug7XEg!3VVphei@#9u8ltDkoUswYZE~IbZF!1NRB{5O@1<2jJ!rz~W zV@jy@L^63OAYzHKNa;3=+QILxJG}8j7jJWFXDq2YN$oplRxcx$@xCZ10so7&dw|ZQ z*%yUB!Nm4VY(Bxnwr$(CHL-2mwv&nNiEZ1ynfE>W?7h!9_q*Ty*0*{+-Bs1y)la%> zt#m5&tG@}-OGU$IB{MyQ201505>~8WwSeT%?^u$9s0!*h1 zjzA92;-4Q#F?%-qP2#ALypvrF9YhE_Oxljpp>AFmcow$7PL|Z?xK=L>xG8Ku%}#QAS+XxAG&WPUqDaCXD`=UlKG-bFvGB02*%U*T z^ma{m8ZZ@aC!N^F6l?EZ)mhb(OvJ11Nm}c11GiM?;t|KozpIH0j#A&UlX>D%I84{6 z4));To=V5+<3fAAOtXW|gtOA;?jJ-0>M8Zkq5XC2Xw?HMsNA7xr5hIn6ZQiD!(79BLGKKKY(=X>kS_Ir|z%PuOl27F`9>%~?Z$2-*7$*4(joHj-k zby+7<`$l?quj^z5mz}qy#s;kxtE&O$fh-qvY>Y@ zPYL(2apmF#ccsH%#|ZoJdV4gO038$d44m=vYQvdmSdXcrtGu6qd_u{Oy}H{rZ2Y=y zRVrxy+qSXQ=gCmsXIk{e8jewMnRbQgV>UPrKcec!R4;Y|?Gxfy0kHTC4a5??n6>HM z)q)s31^VP3eEb+ThcF2Kg0LTcDCHQFtk}FVzj%JS^I)ShvF;}KPgu;Gxj)NW>rS5? zHGmVRuX9zOg9Ii&ccFRcM3fb0(tE%3GjAZjxn3{AvgQfTZ)oeGXc8qlc&gv5Q3`Xo z+{-#mFPCrKB~4;Akh%gngeFw4X%Bp76Gd~KDNjYe9pYS+ZzHGfb!V023mC;Pjb_?f^ECQ$jjoYDs>8JK4R6#VQ=tY((jSU=Ij_?MI z%Q8`{#K#jL3M#`CD6&=zLA@Fqefe$}$&Kq{0F3(1u(r(B! zRd6{*MjVGbQHn%m+r8#8$Hz0Vu#xiyn>FFYjYmv7pBwbzlr71z`c0&0H2WVA@)nS>gd*GG&Xj@aSj}f+M&lL!M5@1qaZqhm&oX1^ z2oz(Vn}eXWUIa7UYBcDX1zhS`O>y=R6#3W-14$jTKup1!WA#10IpHpzFnosoO$vGk zzV;6!2>+sE`>PWS9SjNfIDDhS@^^EYJ~8q|n(QhO)4n!WxW~5E>)7ZpmrfB%+m)S8 zk^lWUfh$2HXdR=$rrZ?#L4;BoxX$`{@m$b%{?VXRe)XUcrzT602>o<>*LB1N%&(*x zOpMah5W9vbyXXu{m^TWWBqvicRxlOcHRPvQTr_-G>-{u#Gc%XICx1^*;qI`J5Xg_dC^d-nAQpCDd9L#*X49;+bHXve8V_q>mDz_;vMuV)$UqvZOi#Tn){ zL}~D@Xf)EexvlzE1%*h}$mLTt+bnvA1KL@H|G z=4Ct3tWiYjTnBVoPu)m}48==)focCBNeCl zfC2^?o4fR|NzB-9$!V`vzgM%?B$mpm_K3PhsOXKy&B&pu+$~oNhT*v%6XD2B(`0^- zWn#i$&{L3X*z^jPoojJA7+954E5#R}XLzsIo1Z_u=x1lV$m81acVf;wqTbw~b;fiJ zUJ3glbxy>MR=KC(SZCg=c{-{ZVk(KXGgmG;i)Bo~!lxp#S( zev7@0KGQvmnd099^%PQ6a#uFqAYQX`FFgn?rg+o@+-FKjTT z@Usj^%{g!vr-$Z;V)1j_BrO%7Lki-D`U=c31|rZP3YR+)3*w#$PIgSxw01T}Zmg;@R2354yb%3t%m%Uu=slRr@=hDG4GA8&Qyugs>@bQOhe*}Q?iKyo<%>qq z2lFF;@#$C!wQaD1z|tmCDY6%??sK$E3WWCWf&PBKNwpjTs0^Oy8F*a8AU`u*S1bC> zV#>_~n`KxC=I)rUmWHd^cJ4SCw5IB!xr7=V96P=HI(hs zz<02djL?CWMNuHARs7m7Uy2N|%LhDGn6c>{AdTGvV{^V&Dk&F@8XeT0+Qhd>ELi*q zo2Y3prN_Ew*k4!o2rQJ_}1u`F=v4e(Cv-a4Ef(Hu7b#-1d( zF)C5b%nw&4H9y-WSg+LNMVkq8EpjNa3)%UMK-oa!Tu#V5+ptXHyD@6|u#D?)+sw5| z{5i?Kok~e)Il(-m&Vetr?Jc74rH+UGZ#W1j-77gPyjb0VWo$UC)@t*?1V*P&!mv8p zUfV)!Ck)n!gKML#Q*UCw3Cbo+ydUqqv6u7p{brv|oypYmFSUi`o zuyk3zpmx)2xcGnj5_ZX76k&n6;)mPWF(^d`?geZ(I2khoinr=DIEl9#I-A`bDiPF- z3atDXHKRN_GB;~vmGRlBLuIbK*zVZqX@2JkLPA4#r;|Wj$zUK7vybR(eFt3lEgBDX z3kb+jMVPrAZcTYKh6rnA(@hAFio1MNOdQxdgYWES-ZHKZ-F9a}19SEMo7>H{J&*hD z+c^TLi}>%}>grRqwxW5&>rJm;foK+zDl@jDxkBkopNbP?}NMpJ$8bQAkZyHR?sBYjmw^hE7d zBMqk#|X>P`*KI zRI3PKwE0FQMDe>cMWL!<{IFXWM75{JOf+}dZf(cjbWmAbLG3)~1GIDji@s3oGCTV_ zMZeDWUlx3V`*FVVrh=#OG;U#COn*Npd$X2sXGr6QuZvyFGq#qjJOygG^G z6v>e~bQ|he8*NIU;-3>?8ziydsqjjxaezq}ZF~tR;Fp0@eoiKf#8xAiKCc~uhC`d0 zhfjwvcA6~=0iFe&21A&Z(yq|hMa;>~W9Mjiw?9WiBpwMi0`+C=MO1L0FOKL9VDU(Y z`<^u}tdX9-XN)d=)a-gMxVBZQYfc>xHJRyVczoeB)w|*JVRwYFBRL7QwL?@wFGBY^ zalhf2OSa2WmnaP-is+S~%r|nWz6B*0v7y2gEi~hAU%RtKo+6TZb+R>_|8+f`{4y<6 zTV?XsMJ^2zsW@*87txihNOE+E{HGOn=Jog-Gt#1*7^&*8SAd*2(P6hm99J0k0S+Wo z!TR4V=#PKQEc&VemIEmQ?t6XbkwQ^lxeWNrwN^88a}m{z0F* z2BucVf6>x^l4FKXFZ@qv{OMBv6&n8`r2i&O|KY6F@qRG>v84aE3;m~S{nvAt|B|nN zubDoLHPffS{%NY{;RQlI^BQp z;6JzhGb?2JpFH@p75ygGl19+#69@l!yq}z0U(VW6*Xln@{t3nZx|4r_`5&~5 zEdP+gp9J{7iSWOU{Ji9UN?|7E|5sAj{f`u0dSE@UvNz5eK26luN1T%!E9=fZkIqk4ZhJA>Jrrl1F zEN$`|e{ijh>Vx3M=srjqWDIr7;Y?YQ;f-!Ryp`5^gNrGXw3M%uN~Etv<^XS4qPO*& z;*!Uu{8T|wWxGv1mxjN`t9w}0_p_{5#HT64u&#v!%Z;I{f;Gx2m4tC~Vcr8r?RCcG z%v|rmsaq1xw7&V`&CJW(-@*XQD`rr-{=iTSeuhl~-_3`R{U};egAsx*L zafo3Hk%J2qj+TibLp8UIS3FxV8&9g#!A(!Z5tGWGMN`$B=eC2d%d9FekmurT#znKv znay~$-v&M)Jux$4%O?4)b}qDxZ4u*3Ig$_JiisK8VFknrVkU1iUG~~8wm*z7-YE)> zR0HVM=HMlsdY-rojQnqeuE1zs1ls38+N8mu!8~FDp}V12`wA!#tVezx8|{YS2#-v{LB$bY3w{}sT(m*2v*2of@e@#_ zW?m2N9LoeM6x*|80O7M$v+`v{2qU$rkYeD7$^x5Kt?bOC3)OEu)WB ztO;({<#Dr0d+UmC0iTQ&&bK4#~?SNekbAzUkk1WF^Ns zhuPUjV;daVsgI9LMW4fxdV64f`7}%#5G&ewS9H6B8JUjhQ<$^WN?*Q@_i#wq<18Ze zVURbE=}R_K1%NZM`5WO!xyU$&L`$z`1NeNTaM5uH07D-(c&X@EY-FpIc~(2{f)Dbw zxr~Ot^eS-76avVLC83&hfUKt3FEE3p%1I(*bK({7X)j$stj1g6N*@1yUu3lX{pH_l2=7iYEiliSt?$v3>>dzSF$YHc1o3xt8>Yxt zA}se|Is(hZ47S2+brfJmSmSX3nXVvonfy$g1WVzu`5c1g$_qOHPeTfjB4n`nMl~S^ zOJPrg31A{v^3)#%GvO`&Gy%z#6s`yQEKG}>`uW%5;1BlKQb@?~IhP3ow(M5{R0KsH zg`;2!ywab=z`0_=3P7KQ36T&$h`eHP{G$MF#Phycg@Mij-1 z{gXTnCPMg3vgP6id*MC%94;Wf@!Wz;!wYmp9)kZV#GVEhz(w%nxjhQz!h8OC2$Cx; zd<*nhm=*c>q4nJf){=R%+z`_=MT$8(%Aqy0yU4-FJ-*Orty$jB*AvjHd6%6rfvBS;Uy|-Z6lJAhy9c=YDM;GQ)AI`*pE| znMZC-4es4G*gZ?IuE|ST1BxOj*yBQ53!!7wz`&-Q#<4PxJfL%!)P8(TJxcV%b@eMb z^xwqej3+i!gIW3v%}j90(~Opbmh(LaI0pkiSOyaSUam=r<++PLh2&4m2a%KL!cmQ! z0q574rFt0YgH9!|_ZA-y>`bdD_w`3IMatJ}hf)L4YT1Gp5y+;{L-|F8Hr|JP-$9wT z9V%A>RF2@)2?biXnHY+1&~{p-yK_2u0TZOWG5iM+Gc77MnOSjA)I4=dB|6_ks1%X* zDn_Se>C8rTWN|?R)r8Rv-9z(zHhvTBoRA?sHS?dT2jx*>VR*mi6rL5#r#7gq7I#; zU`Qd=p)q#eRXz?`zrs(3P!hA#g2ml#Rvb4`Dw%-6h14Gk_&wP{~C}!6? z-tq!j@Q!IEMHD<~Z|GOm&Dt-!FmsEWE7eh5M}9v(`EX|7bzM2%ayG2_6k@JmcIAOi<8Too6Jk4a}dU`bx1#5IhwOc2Gy|epHR5Pn(Og?|6e*gA@CfBlLk1|*yu*Jd- zSpgGN$Z4nb&_-dt=U*eY;9vbrFi zlG#{)%;;=PKQHTe=e|{(#GRjbF`Kgem{BIIvfA`yyzcz&stv2=x2}8xMg3rT<_>FM zruTh5VHU{f2VWq&eQ!t!j{5@&_0$V#kmrd#e6asHQK1TfX{3at8iI?WpuQksRS(yW zq7urAP?^UGX^=hqR7Ren6AC+l{BTJC9@a)`dCFQU%%tYxgdlN=&({yr@ybo^j%DFg zWri)>>$2PG<50z-%pvkEz{gwDG54ENm6m5eg+Q6UGQvzMRn|&sIxQxlEQ-V2QasPn zqP(GRcG8*R+IIs9Z3TFrd#nVvvF&;Zb;IV;f7jO82>+8G77gqu_@xIDzwl1lLkHF)-A+KJQ zG1(8z9PZ2;^#fYHOwd_Zz&zo~i&^GQmj&OT?<5;Ufl0#nks!zOeh`+1Ah<{-4i2fS z9*Q$nEUObmzOq5&6`Ryj(A4fF-WBb$cns-~wJAAl4A3*`RV+u7vhaIt20Vk6f3S z?stD9ivGmo5=Hdm0TEuJGdL3JE{Gcc zq)}AJ{#g9j#jvXZx9hi?J#YSP*X^Ad*Q3BOc>2k$`!@#08U9<<617&t-PAGul+WP3 z--vg9#n?|xBH3ZPCbsjvOL6I9{=gh^_<_#Z#dBjCEYy9)oRU>xd=juQtTNUJlBX%z z7)K-;1M=DB4zvF1gGGEHi#}dJe}vQ;;ng!{LGCWutnDJ_!k@n#_3HwH94tyHW^jn> zTKt;AHA2kA3)M0YeKz6N>Y3jyo_I<46nYv@i_{AcDKdRKeY=oi|08Q_0vpdbrojNj zZUBh!*A_6jD-74b_Q;}-$acy1o;~o% zED7`(=&4au2l@`b_vB6$bbiBTpC70c&*e7W6D!NJHpZ3gHMtT#Pj5ZwPGugT zJ|RWmEOPUO{{|hCYbKv`uMq{#L&B+pp6TQbb=~|Fe)O!*v zie8Ks<>1d>9_h6FDrD)T8iB0kzLXbkHcn~P;x3Xdnk>}qG%)&epCNsl)ifyADY>Y* z$lt}-#Gi5AaS}6Q0`s*+NekkB#DUmlYLIJFUBrLn4vl~oNG|2J=e+h#N#2;S3gP&k zX1&vK-|GOa^lNN`v4wAYtg=}oyTY8%qPK11=JSf^YnHd;=-bnGCHHRCl91>^ROW(< z!g~5xM5lb|mEjPRyNx<6e&k^Hdku7w>w0XqNx8L0BWcTtcwWSJik2dlu61kt$%%*X zj3d?mfOnxB!+uD73ssv2H!JFZT~UBJggHhyR zTVjgM<$zm+n@p__mxmiRwyio>I@Rt5560dk** z`+ZmLiSe2!VT->ip(xmV81h>B+Q;Dw5+myJt&3a0WA>v}A(OlhcA%z^limh^)L3t@ z9h{ssoMSR0D#Oa3+UF*wJ|@5>v%+tFB~jD}XGkNdg{?036?n1g5aSv3Y%mf7G#AIK zDyc@?OSnl7H}eU%=;4D(f`*uXm;X4gzyAA+u1c%iah#K=v>11SR>Gjq%0k=={Gv<8jk4Z$7wkS}8})>NcqYjN)V&$!dw9!ei;iV-hE1ek`Y;x71btyB5$e3n<}KkUpjy@J}Vo*)5ZdnZna# z!E6fI9hZy|AY&~rnw+2YbX)dyV1eN&UTSJ5kI&D@**6$X7LA&vAF8L; z@5iWJFyWi=SD3*(S{Lt-FV56i-xqcNMyEpCZ-6)RJN;JpOTWJV_I|&3oMqigTAE$& zmOy_pQHGPQfoQDF33DMc{_L$)>~(#9t~0V4& zOcb=8Z{woEFmFu69p+I_ox|H()p5+8ZA{9CmiHA9R|6d#X?(*uOJ^HB`+-l$NRS*L zDoU#}ODn#W);(ek*OZE}YtbgsGniAv)X@FU<+V4X>jt6hG;qXoL%)Zv*TdLr7<|@= zQtTaBP$5iS=!HeIS%0%vaUw}E?Fu1|ZfxoH^eXOO1(z%~SQt3aaS>{33 z?X84R({id872WQ0%&{FX7?b1b8-Sf&865T?2+iPhr;}V4n-d&$*btz7=>q*q(Skx* zOHd+pa@ruhy_ZZNDb{~4Qv5&<3>ggLeY+OhpGRz0^G4r8*^-`))A|GxWnpstXVZVo$hH%u_%lrcfop%Ooomxtw6!fK6xAT`eIAbkn%I?6@*^);v z)vzRD1=0iY{IGfT&!z7V9$Ix*3gf0O#-OpUL=Wl+&NB#{Z<9t3y9_j0@%fn_IjxlH z8*I!op(~QbElu_cX6gr?q)8PAFkd%hm{Y~}CCt(7zKytq?m@W${I6dFiqi0At)xQx zA4zX`^_?LQ#5#Tks>R+<94)cv!UPF7jdkgRq4qZM_@y9Y6~tNV^OBuBu)L}iDX+!1lvZXw=E?Q4>G9^y^Pn*DdRHy?P+6u5dou!AAVRG5 zLN*nYi`cM&q#?bQNU9j;7)y~2VgMd}LRtuc7OxTBm~fhFb_APe(kj^M*^u>?!Z7KH zY$vQPoEC+ZUfU+XBWX3|{ik`ms>rTDTa)=*`Exqj#U^SStTCbKnONt~Ka(A#97p6DYL-4f- zOQvUpK2YrrMt`h%#bw4J?a1(^7p-bfiL$|}PP8$rI|@A8pF3O$Up~u#0YK?j&O3@9 zn~WALi#Qwq2wNL()Pw(>n1ULJYddU-y9&32d+^=#ZHe$MAIS7YRA8sHC$c&Z1F=1D z*FXe=tweO!90@5%haxttCY4#N>e6|9m#sphQQdw!cI`Y|`daeZe8%IU_Lr5Q5+|#` z4fqaIy`F(?cOSe@orAjODkS!NMm! z4CTS4-h)MM;nVUmtj2{Ex}m@r>8K^)_hm%;`MHQP0_+-$2m$kLWRl-f#Ua9k0kv`* zIVK(rhfc$xRM5!~FD(2A9_N&uR(r&rEl2es`|o$iYSr5z0v4c5+skS<@Xy+Ck!c*p zcgv1BK2<_aPN&U|`#tq>&$EO0{9*Ki1<2=QVdi1R>@C7xqMrONy|*dZ zXk`Waa^fjvV|8k373*Z*;<5Tq#;@E)Ra#`I$O~pVX4Z}=d!R{5d?tKl83&~fWs_OL zZ6*VI(HBalfyL0xw6p_Es?C&)SC?Cdgp8MpCGB6f8+p}AQQ0WNeb4kyfUoJMaZ!s$ z@?6hjy#kiwv*ijPRBqG2>=q`+e^dq8SNYXl%<2Mn_OrP~_OtATz)f&0Pfzm_tA_gr z_e%BPR}E4MvLa(UO+Fq&>Vd#YNp?NUK1UsmI{+f&M<)vAj<`W_+OA`?+gH8!s1x1S zL*Nf9nr}3PE>^vGYxk~CxFx(3-Y@go9wRk?C$PZ|_;vvmhI+i_-N1Wdy$So6Fbiqc zms(k6BU-ErM~?f6Y+{}TJ~P0*4zsS?9F93hdRH&oY8$1$xK6lU#1qlax*Bks)B`wJ z`&bLUf;b{z%8ilT?J5qH#?g;1u~7!?+eq!%NF}&aSTrY0MSCNLil;-X(4ruz;3=pm z4ne&UzX_SqgGDF`bq}$kX?4A^W9_VTzaQB|f#`w9?4*P21Y!?G-1Z&Ia*S}OAv^ta z4-hOTIWNzkOvvFv?QRpJ+k8~5&M^DuC*?*1V& z*lkMn5Ej!Npq^QP-tms3*=jQ2&Rx~vuy&A@-zDYEN$BGFf4uMfX z(w9sI$V^TChNM3tM>KASLgO7IPr;qRno10DxU~DR@;OEpMKO;qXfMQx(ImW@PEVwQ zL8~t@O!K&Zfbo>#O4c#yiu~^9mHi!Mo^jh^kri`iai`uZz+K!!{w?E*#a-J&`fbWY zHBZa1J#vjmt7zTeR9~#EButY^E1#NKYq%0Efn=V7sib1S9`>O0OsLR4Q9P zBS1)+i+?US1G{uG4DcJWh*63!|@YTN0Xi463lQdG$$ zo$SC~%xb70N&L7J*xHa(WHuFk{@fhI61dco6z+i^R*b(-i#U60k~`kJ&hCJ^JoAn7 zi?}xHqWbj6s&P-cH(RXCiw8}ZMfLU5=HD!4Rd7jb`kE=)6NXd59#8_uraKC!`a&Q( zO|MQ`(xnsn+}H;AW#ubtw10RX5}!YI&L5U~zUp&BGe{3o%Yhdkr0z zH0~kiAsgu}%PN#tw3$;Y<*Kf=Q@T{wPP^!EDK-jHE$3V2=jKl;oKPis}i znCe!x?@$gFHS1^RF7&9;Ap>gsQu@stkwGxLL@4pm+5%M9hX6-Oao5ov0%&`ZYlz=N z6$Dj?PT{5zI*okh4b;J*1~rq{s-LCK4xiffA7|kXo82-Z2=5k~usK1i}NDWms>fp)6M5_G%gJKcdqvR18S&{Y+0(!pIGIPA_UI$C_nDgA|^RkTF$q9 zZvCvaxGsDR@4O$!`|s)s(K%f;*l14<7P#(L+C!Mnr9J|fPNn>XaS$fR&9c~TIOr#I z#f*&JDZGHsm;-U9Cl)U-#x|6nw=q740AU9Ct)QR8wu&haE2}CcyidFu^`+BJG)>S* z2qdN@vC=?Qk#(4irM_a`TtKB|Aa*uE``Su1PPhQL@22*c6L?d< z+6zQ}8wCgk2*$99bIh1oG%%n_g=ttEg=$!;syFw~s5kdMHX9o2Mw%%A>~gTKFyGLm zbL24S)C7(-H)mgS9>s7qk5hw9beiE> zhNsknm5lbspP4wVxYZYS0(wL3!r{!m zB(bKMCLyumalG`yVQ^yQE_Kt(a_WmTJld<#Uqn}RJ@E37gYeqjmj>dF44-k9XLStF zfrk*&7G-rk4>q!&SLK^v%fqo~KlL0p6G|zVINZTER!|RrUPsOo8|EBl8J3e*0pXgc zmY}oOyZe>p3Q9)}bR)x;%L<|XLV){Y~aMCDaEk)QMHUb4xG zeW(2K{o{PKerpG}`|40}#(J+@-FZBGgbvyCx?zslaESg0e%5-X>88=L)6L04sM7v) z_p9zhL*6Zqwy{@FLW_z>U(gU2e=EtD;511DWn6>SmGdvY&?=wcfzVG{C&L|LNFZOy2!NV9hzJsKuWqlEMogmu5 zQ_kL3)Ew0h^UmA5JIi?4wI`8Cs>E~O)@mp`6!e?lpykJDknyEe)~EP@$EZa#Y{N< zQ}t1`((t6N!8rbTmho@v799neudl{Y4xk={gg_r6K^N)!m4#iI^Vb>+H{71LQ__*G zY<+#*2_H)v^Y3{a=H_$epWHUmF9(p2(|J^no< zu?SbB3*zR?G94IhYbUPyz!pj3!wn(SL1^Feajt07lb`WyI*}5HKQsOUa%?OklR57Z z{@xku7}PuLWA*UIhu}13Uel8`{3*ogq$l~MU8QOwz$)tWA%4j4+}|6vE#@pbD^@#x ze6r8m*!W3sZU;-BN>I(hqFscNN^o~Fs)~wDwJ%id`YBgg)$)q|ntZtFfb`}gg=YUC zDrYAoaOTue*Gpy8p25FCgPlMd4`(1_i(HmYJzT%}G+U~uc%ED>e5(m++>inToiVkdeQnGJ%Gd_MTuFKrD;c%uO6oLSz4TY%mEo44)^lXi#5MJG!f$0KS)p3vsr z6hCJ#_Nr50!I=Hv;~j*sOLKc3qPgB-Kci$aRCwgk2?;1lu6nwrmTt zr@KHWL%lAqvnidjX!Z2>DFbEyqbMg1H<#|WrVbmWm63VZTVF_Aw7Ev+j5&^VD?RUT z?i<)40O=xd>(;IEcD1gY0^$bOt?>%i{+#xu@wnM8C#4s$V^W&p$ayqJAIckiSlDPV z?x#AYwzWhX5{^+z%5+MO6A$H=3nS+=?fS06mx?#Z4e)F5KzKVY8*lOhiLsQ!%%k)p z(<|aJ%CQk5p`qXV0S0Ka^04)(W=pa!;|0IFPyT}3jQ0$n-NEl6<}wDJa?N+hQzkh7&d zc1QhiPd2QbLUyW$(+qHivMzUidP2 zi$zsl(eIddFx(F~FU4->?UrqD+&1eYBUxNQ56}eV<=cZ#5iU3`O&G0~n*1Q$4aT6f}#XVi--zepf$Z-|^%x#dlMOgb<>T_`G|?=lgm0Bd+uko24N z%3*XEDv8I#&HNZQBJ@#*Hu2%KxIAcDH~}6pUc7OATk0je(_m071Apye%tP)==!2F=9F)Jm_4N-4o7HAM*L-9+$DAyvEOP)8ld8~?ajFB0n^`hCtN&3pIb0F#`M%16eet_${3+-3uBDnv zTpv~ScyzYJ$WQDDTzu=ZMV~4BvT;fZ4@-pU^Cj$R9lnTW^979+1^^O?xy8b zlpkniaScW#7>m}x%}y>jHIl~Fo(M!BRFW-$zvB&Y&;^j-eQi~-bq~1vjCY&vSH})6 ziHz%D5{)*O;~u1~(ys>#3-WA5*PTI`%lAwM_=#TRo-S+iN4GN#n1zzP;Dpg{w-z<> z+=3KGtjn>CPifaFvld4<&UuDAEOY|8ZP1Di9GEmF4&T#A(v8KNk@}%W(E5-Pk`_B1 zJW_VjExui(Xs~&~geys#o6aU9?;}=Sp&eSrE$LA(tBaN6RJHZ!1*+~*ZX;dBQv
*Q_qs&3F{w=`xBAS=H+^;ND7m^cw2VT*JUnJg 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

_#52TqxL8WFsNG($mTnLP8ZO3< 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 diff --git a/vendor/ceedling/docs/Unity Summary.pdf b/vendor/ceedling/docs/Unity Summary.pdf deleted file mode 100644 index b1e641987af6c305ca41f325edba5b504de98494..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 218553 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�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 CZ#$k@A}Jr{*VsE0^kQpg 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 config[key] } - @configurator_setup.build_constants_and_accessors(hash, binding()) + @configurator_setup.build_constants_and_accessors(hash, binding()) end end @@ -287,30 +335,30 @@ def build_supplement(config_base, config_more) # flatten our addition hash config_more_flattened = @configurator_builder.flattenify( config_more ) - + # merge our flattened hash with built hash from previous build @project_config_hash.deep_merge!( config_more_flattened ) store_config() # create more constants and accessors @configurator_setup.build_constants_and_accessors(config_more_flattened, binding()) - + # recreate constants & update accessors with new merged, base values config_more.keys.each do |key| hash = { key => config_base[key] } @configurator_setup.build_constants_and_accessors(hash, binding()) end end - - + + def insert_rake_plugins(plugins) plugins.each do |plugin| @project_config_hash[:project_rakefile_component_files] << plugin end end - + ### private ### - + private def collect_path_list( container ) @@ -318,12 +366,17 @@ def collect_path_list( container ) container.each_key { |key| paths << container[key] if (key.to_s =~ /_path(s)?$/) } if (container.class == Hash) return paths.flatten end - + def eval_path_list( paths ) + if paths.kind_of?(Array) + paths = Array.new(paths) + end + paths.flatten.each do |path| path.replace( @system_wrapper.module_eval( path ) ) if (path =~ RUBY_STRING_REPLACEMENT_PATTERN) end end - - + + end + diff --git a/vendor/ceedling/lib/configurator_builder.rb b/vendor/ceedling/lib/ceedling/configurator_builder.rb similarity index 63% rename from vendor/ceedling/lib/configurator_builder.rb rename to vendor/ceedling/lib/ceedling/configurator_builder.rb index 03380ed..f202d8a 100644 --- a/vendor/ceedling/lib/configurator_builder.rb +++ b/vendor/ceedling/lib/ceedling/configurator_builder.rb @@ -1,16 +1,16 @@ require 'rubygems' require 'rake' # for ext() method -require 'file_path_utils' # for class methods -require 'defaults' -require 'constants' # for Verbosity constants class & base file paths +require 'ceedling/file_path_utils' # for class methods +require 'ceedling/defaults' +require 'ceedling/constants' # for Verbosity constants class & base file paths class ConfiguratorBuilder - + constructor :file_system_utils, :file_wrapper, :system_wrapper - - + + def build_global_constants(config) config.each_pair do |key, value| formatted_key = key.to_s.upcase @@ -21,7 +21,7 @@ def build_global_constants(config) end end - + def build_accessor_methods(config, context) config.each_pair do |key, value| # fill configurator object with accessor methods @@ -29,11 +29,11 @@ def build_accessor_methods(config, context) end end - + # create a flattened hash from the original configuration structure def flattenify(config) new_hash = {} - + config.each_key do | parent | # gracefully handle empty top-level entries @@ -54,17 +54,18 @@ def flattenify(config) else new_hash["#{parent.to_s.downcase}".to_sym] = config[parent] end - + end - + return new_hash end - + def populate_defaults(config, defaults) defaults.keys.sort.each do |section| defaults[section].keys.sort.each do |entry| - config[section][entry] = defaults[section][entry].deep_clone if (config[section].nil? or config[section][entry].nil?) + config[section] = {} if config[section].nil? + config[section][entry] = defaults[section][entry].deep_clone if (config[section][entry].nil?) end end end @@ -88,12 +89,14 @@ def set_build_paths(in_hash) [:project_build_tests_root, project_build_tests_root, true ], [:project_build_release_root, project_build_release_root, in_hash[:project_release_build] ], - [:project_test_artifacts_path, File.join(project_build_artifacts_root, TESTS_BASE_PATH), true ], - [:project_test_runners_path, File.join(project_build_tests_root, 'runners'), true ], - [:project_test_results_path, File.join(project_build_tests_root, 'results'), true ], - [:project_test_build_output_path, File.join(project_build_tests_root, 'out'), true ], - [:project_test_build_cache_path, File.join(project_build_tests_root, 'cache'), true ], - [:project_test_dependencies_path, File.join(project_build_tests_root, 'dependencies'), true ], + [:project_test_artifacts_path, File.join(project_build_artifacts_root, TESTS_BASE_PATH), true ], + [:project_test_runners_path, File.join(project_build_tests_root, 'runners'), true ], + [:project_test_results_path, File.join(project_build_tests_root, 'results'), true ], + [:project_test_build_output_path, File.join(project_build_tests_root, 'out'), true ], + [:project_test_build_output_asm_path, File.join(project_build_tests_root, 'out', 'asm'), true ], + [:project_test_build_output_c_path, File.join(project_build_tests_root, 'out', 'c'), true ], + [:project_test_build_cache_path, File.join(project_build_tests_root, 'cache'), true ], + [:project_test_dependencies_path, File.join(project_build_tests_root, 'dependencies'), true ], [:project_release_artifacts_path, File.join(project_build_artifacts_root, RELEASE_BASE_PATH), in_hash[:project_release_build] ], [:project_release_build_cache_path, File.join(project_build_release_root, 'cache'), in_hash[:project_release_build] ], @@ -118,7 +121,7 @@ def set_build_paths(in_hash) build_path_name = path[0] build_path = path[1] build_path_add_condition = path[2] - + # insert path into build paths if associated with true condition out_hash[:project_build_paths] << build_path if build_path_add_condition # set path symbol name and path for each entry in paths array @@ -131,7 +134,7 @@ def set_build_paths(in_hash) def set_force_build_filepaths(in_hash) out_hash = {} - + out_hash[:project_test_force_rebuild_filepath] = File.join( in_hash[:project_test_dependencies_path], 'force_build' ) out_hash[:project_release_force_rebuild_filepath] = File.join( in_hash[:project_release_dependencies_path], 'force_build' ) if (in_hash[:project_release_build]) @@ -141,138 +144,118 @@ def set_force_build_filepaths(in_hash) def set_rakefile_components(in_hash) out_hash = { - :project_rakefile_component_files => - [File.join(CEEDLING_LIB, 'tasks_base.rake'), - File.join(CEEDLING_LIB, 'tasks_filesystem.rake'), - File.join(CEEDLING_LIB, 'tasks_tests.rake'), - File.join(CEEDLING_LIB, 'tasks_vendor.rake'), - File.join(CEEDLING_LIB, 'rules_tests.rake')]} - - out_hash[:project_rakefile_component_files] << File.join(CEEDLING_LIB, 'rules_cmock.rake') if (in_hash[:project_use_mocks]) - out_hash[:project_rakefile_component_files] << File.join(CEEDLING_LIB, 'rules_preprocess.rake') if (in_hash[:project_use_test_preprocessor]) - out_hash[:project_rakefile_component_files] << File.join(CEEDLING_LIB, 'rules_tests_deep_dependencies.rake') if (in_hash[:project_use_deep_dependencies]) - out_hash[:project_rakefile_component_files] << File.join(CEEDLING_LIB, 'tasks_tests_deep_dependencies.rake') if (in_hash[:project_use_deep_dependencies]) - - out_hash[:project_rakefile_component_files] << File.join(CEEDLING_LIB, 'rules_release_deep_dependencies.rake') if (in_hash[:project_release_build] and in_hash[:project_use_deep_dependencies]) - out_hash[:project_rakefile_component_files] << File.join(CEEDLING_LIB, 'rules_release.rake') if (in_hash[:project_release_build]) - out_hash[:project_rakefile_component_files] << File.join(CEEDLING_LIB, 'tasks_release_deep_dependencies.rake') if (in_hash[:project_release_build] and in_hash[:project_use_deep_dependencies]) - out_hash[:project_rakefile_component_files] << File.join(CEEDLING_LIB, 'tasks_release.rake') if (in_hash[:project_release_build]) + :project_rakefile_component_files => + [File.join(CEEDLING_LIB, 'ceedling', 'tasks_base.rake'), + File.join(CEEDLING_LIB, 'ceedling', 'tasks_filesystem.rake'), + File.join(CEEDLING_LIB, 'ceedling', 'tasks_tests.rake'), + File.join(CEEDLING_LIB, 'ceedling', 'tasks_vendor.rake'), + File.join(CEEDLING_LIB, 'ceedling', 'rules_tests.rake')]} + + out_hash[:project_rakefile_component_files] << File.join(CEEDLING_LIB, 'ceedling', 'rules_cmock.rake') if (in_hash[:project_use_mocks]) + out_hash[:project_rakefile_component_files] << File.join(CEEDLING_LIB, 'ceedling', 'rules_preprocess.rake') if (in_hash[:project_use_test_preprocessor]) + out_hash[:project_rakefile_component_files] << File.join(CEEDLING_LIB, 'ceedling', 'rules_tests_deep_dependencies.rake') if (in_hash[:project_use_deep_dependencies]) + out_hash[:project_rakefile_component_files] << File.join(CEEDLING_LIB, 'ceedling', 'tasks_tests_deep_dependencies.rake') if (in_hash[:project_use_deep_dependencies]) + + out_hash[:project_rakefile_component_files] << File.join(CEEDLING_LIB, 'ceedling', 'rules_release_deep_dependencies.rake') if (in_hash[:project_release_build] and in_hash[:project_use_deep_dependencies]) + out_hash[:project_rakefile_component_files] << File.join(CEEDLING_LIB, 'ceedling', 'rules_release.rake') if (in_hash[:project_release_build]) + out_hash[:project_rakefile_component_files] << File.join(CEEDLING_LIB, 'ceedling', 'tasks_release_deep_dependencies.rake') if (in_hash[:project_release_build] and in_hash[:project_use_deep_dependencies]) + out_hash[:project_rakefile_component_files] << File.join(CEEDLING_LIB, 'ceedling', 'tasks_release.rake') if (in_hash[:project_release_build]) return out_hash end - - - def set_library_build_info_filepaths(hash) - - # Notes: - # - Dependency on a change to our input configuration hash is handled elsewhere as it is - # dynamically formed during ceedling's execution - # - Compiled vendor dependencies like cmock.o, unity.o, cexception.o are handled below; - # here we're interested only in ceedling-based code generation dependencies - - ceedling_build_info_filepath = File.join(CEEDLING_RELEASE, 'build.info') - cmock_build_info_filepath = FilePathUtils::form_ceedling_vendor_path('cmock/release', 'build.info') - out_hash = { - :ceedling_build_info_filepath => ceedling_build_info_filepath, - :cmock_build_info_filepath => cmock_build_info_filepath - } - - return out_hash - end - def set_release_target(in_hash) return {} if (not in_hash[:project_release_build]) - + release_target_file = ((in_hash[:release_build_output].nil?) ? (DEFAULT_RELEASE_TARGET_NAME.ext(in_hash[:extension_executable])) : in_hash[:release_build_output]) release_map_file = ((in_hash[:release_build_output].nil?) ? (DEFAULT_RELEASE_TARGET_NAME.ext(in_hash[:extension_map])) : in_hash[:release_build_output].ext(in_hash[:extension_map])) - + return { # tempted to make a helper method in file_path_utils? stop right there, pal. you'll introduce a cyclical dependency :project_release_build_target => File.join(in_hash[:project_build_release_root], release_target_file), :project_release_build_map => File.join(in_hash[:project_build_release_root], release_map_file) } end - + def collect_project_options(in_hash) options = [] - + in_hash[:project_options_paths].each do |path| options << @file_wrapper.directory_listing( File.join(path, '*.yml') ) end - + return { :collection_project_options => options.flatten } end - + def expand_all_path_globs(in_hash) out_hash = {} path_keys = [] - + in_hash.each_key do |key| next if (not key.to_s[0..4] == 'paths') path_keys << key end - + # sorted to provide assured order of traversal in test calls on mocks path_keys.sort.each do |key| out_hash["collection_#{key.to_s}".to_sym] = @file_system_utils.collect_paths( in_hash[key] ) end - + return out_hash end def collect_source_and_include_paths(in_hash) return { - :collection_paths_source_and_include => - ( in_hash[:collection_paths_source] + + :collection_paths_source_and_include => + ( in_hash[:collection_paths_source] + in_hash[:collection_paths_include] ).select {|x| File.directory?(x)} - } + } end def collect_source_include_vendor_paths(in_hash) extra_paths = [] - extra_paths << FilePathUtils::form_ceedling_vendor_path(CEXCEPTION_LIB_PATH) if (in_hash[:project_use_exceptions]) + extra_paths << File.join(in_hash[:cexception_vendor_path], CEXCEPTION_LIB_PATH) if (in_hash[:project_use_exceptions]) return { - :collection_paths_source_include_vendor => - in_hash[:collection_paths_source_and_include] + + :collection_paths_source_include_vendor => + in_hash[:collection_paths_source_and_include] + extra_paths - } + } end def collect_test_support_source_include_paths(in_hash) return { - :collection_paths_test_support_source_include => + :collection_paths_test_support_source_include => (in_hash[:collection_paths_test] + in_hash[:collection_paths_support] + - in_hash[:collection_paths_source] + + in_hash[:collection_paths_source] + in_hash[:collection_paths_include] ).select {|x| File.directory?(x)} - } + } end def collect_vendor_paths(in_hash) return {:collection_paths_vendor => get_vendor_paths(in_hash)} end - + def collect_test_support_source_include_vendor_paths(in_hash) return { - :collection_paths_test_support_source_include_vendor => - in_hash[:collection_paths_test_support_source_include] + - get_vendor_paths(in_hash) - } + :collection_paths_test_support_source_include_vendor => + get_vendor_paths(in_hash) + + in_hash[:collection_paths_test_support_source_include] + } end - - + + def collect_tests(in_hash) all_tests = @file_wrapper.instantiate_file_list @@ -289,12 +272,19 @@ def collect_tests(in_hash) def collect_assembly(in_hash) all_assembly = @file_wrapper.instantiate_file_list - return {:collection_all_assembly => all_assembly} if (not in_hash[:release_build_use_assembly]) - + return {:collection_all_assembly => all_assembly} if ((not in_hash[:release_build_use_assembly]) && (not in_hash[:test_build_use_assembly])) + + # Sprinkle in all assembly files we can find in the source folders in_hash[:collection_paths_source].each do |path| all_assembly.include( File.join(path, "*#{in_hash[:extension_assembly]}") ) end - + + # Also add all assembly files we can find in the support folders + in_hash[:collection_paths_support].each do |path| + all_assembly.include( File.join(path, "*#{in_hash[:extension_assembly]}") ) + end + + # Also add files that we are explicitly adding via :files:assembly: section @file_system_utils.revise_file_list( all_assembly, in_hash[:files_assembly] ) return {:collection_all_assembly => all_assembly} @@ -311,7 +301,7 @@ def collect_source(in_hash) end end @file_system_utils.revise_file_list( all_source, in_hash[:files_source] ) - + return {:collection_all_source => all_source} end @@ -319,34 +309,60 @@ def collect_source(in_hash) def collect_headers(in_hash) all_headers = @file_wrapper.instantiate_file_list - paths = + paths = in_hash[:collection_paths_test] + in_hash[:collection_paths_support] + - in_hash[:collection_paths_source] + + in_hash[:collection_paths_source] + in_hash[:collection_paths_include] - + paths.each do |path| all_headers.include( File.join(path, "*#{in_hash[:extension_header]}") ) end @file_system_utils.revise_file_list( all_headers, in_hash[:files_include] ) - + return {:collection_all_headers => all_headers} end + def collect_release_existing_compilation_input(in_hash) + release_input = @file_wrapper.instantiate_file_list + + paths = + in_hash[:collection_paths_source] + + in_hash[:collection_paths_include] + + paths << File.join(in_hash[:cexception_vendor_path], CEXCEPTION_LIB_PATH) if (in_hash[:project_use_exceptions]) + + paths.each do |path| + release_input.include( File.join(path, "*#{in_hash[:extension_header]}") ) + if File.exists?(path) and not File.directory?(path) + release_input.include( path ) + else + release_input.include( File.join(path, "*#{in_hash[:extension_source]}") ) + end + end + + @file_system_utils.revise_file_list( release_input, in_hash[:files_source] ) + @file_system_utils.revise_file_list( release_input, in_hash[:files_include] ) + # finding assembly files handled explicitly through other means + + return {:collection_release_existing_compilation_input => release_input} + end + + def collect_all_existing_compilation_input(in_hash) all_input = @file_wrapper.instantiate_file_list - paths = - in_hash[:collection_paths_test] + - in_hash[:collection_paths_support] + - in_hash[:collection_paths_source] + + paths = + in_hash[:collection_paths_test] + + in_hash[:collection_paths_support] + + in_hash[:collection_paths_source] + in_hash[:collection_paths_include] + - [FilePathUtils::form_ceedling_vendor_path(UNITY_LIB_PATH)] - - paths << FilePathUtils::form_ceedling_vendor_path(CEXCEPTION_LIB_PATH) if (in_hash[:project_use_exceptions]) - paths << FilePathUtils::form_ceedling_vendor_path(CMOCK_LIB_PATH) if (in_hash[:project_use_mocks]) + [File.join(in_hash[:unity_vendor_path], UNITY_LIB_PATH)] + + paths << File.join(in_hash[:cexception_vendor_path], CEXCEPTION_LIB_PATH) if (in_hash[:project_use_exceptions]) + paths << File.join(in_hash[:cmock_vendor_path], CMOCK_LIB_PATH) if (in_hash[:project_use_mocks]) paths.each do |path| all_input.include( File.join(path, "*#{in_hash[:extension_header]}") ) @@ -354,35 +370,48 @@ def collect_all_existing_compilation_input(in_hash) all_input.include( path ) else all_input.include( File.join(path, "*#{in_hash[:extension_source]}") ) + all_input.include( File.join(path, "*#{in_hash[:extension_assembly]}") ) if (defined?(TEST_BUILD_USE_ASSEMBLY) && TEST_BUILD_USE_ASSEMBLY) end end - + @file_system_utils.revise_file_list( all_input, in_hash[:files_test] ) @file_system_utils.revise_file_list( all_input, in_hash[:files_support] ) @file_system_utils.revise_file_list( all_input, in_hash[:files_source] ) @file_system_utils.revise_file_list( all_input, in_hash[:files_include] ) # finding assembly files handled explicitly through other means - return {:collection_all_existing_compilation_input => all_input} + return {:collection_all_existing_compilation_input => all_input} + end + + + def get_vendor_defines(in_hash) + defines = in_hash[:unity_defines].clone + defines.concat(in_hash[:cmock_defines]) if (in_hash[:project_use_mocks]) + defines.concat(in_hash[:cexception_defines]) if (in_hash[:project_use_exceptions]) + + return defines + end + + + def collect_vendor_defines(in_hash) + return {:collection_defines_vendor => get_vendor_defines(in_hash)} end def collect_test_and_vendor_defines(in_hash) - test_defines = in_hash[:defines_test].clone + defines = in_hash[:defines_test].clone + vendor_defines = get_vendor_defines(in_hash) + defines.concat(vendor_defines) if vendor_defines - test_defines.concat(in_hash[:unity_defines]) - test_defines.concat(in_hash[:cmock_defines]) if (in_hash[:project_use_mocks]) - test_defines.concat(in_hash[:cexception_defines]) if (in_hash[:project_use_exceptions]) - - return {:collection_defines_test_and_vendor => test_defines} + return {:collection_defines_test_and_vendor => defines} end def collect_release_and_vendor_defines(in_hash) release_defines = in_hash[:defines_release].clone - + release_defines.concat(in_hash[:cexception_defines]) if (in_hash[:project_use_exceptions]) - + return {:collection_defines_release_and_vendor => release_defines} end @@ -395,30 +424,39 @@ def collect_release_artifact_extra_link_objects(in_hash) return {:collection_release_artifact_extra_link_objects => objects} end - + def collect_test_fixture_extra_link_objects(in_hash) # Note: Symbols passed to compiler at command line can change Unity and CException behavior / configuration; # we also handle those dependencies elsewhere in compilation dependencies - - objects = [UNITY_C_FILE] - + + sources = [UNITY_C_FILE] + + in_hash[:files_support].each { |file| sources << file } + # we don't include paths here because use of plugins or mixing different compilers may require different build paths - objects << CEXCEPTION_C_FILE if (in_hash[:project_use_exceptions]) - objects << CMOCK_C_FILE if (in_hash[:project_use_mocks]) - + sources << CEXCEPTION_C_FILE if (in_hash[:project_use_exceptions]) + sources << CMOCK_C_FILE if (in_hash[:project_use_mocks]) + # if we're using mocks & a unity helper is defined & that unity helper includes a source file component (not only a header of macros), # then link in the unity_helper object file too - if ( in_hash[:project_use_mocks] and - in_hash[:cmock_unity_helper] and - @file_wrapper.exist?(in_hash[:cmock_unity_helper].ext(in_hash[:extension_source])) ) - objects << File.basename(in_hash[:cmock_unity_helper]) + if ( in_hash[:project_use_mocks] and in_hash[:cmock_unity_helper] ) + in_hash[:cmock_unity_helper].each do |helper| + if @file_wrapper.exist?(helper.ext(in_hash[:extension_source])) + sources << helper + end + end end + # create object files from all the sources + objects = sources.map { |file| File.basename(file) } + # no build paths here so plugins can remap if necessary (i.e. path mapping happens at runtime) objects.map! { |object| object.ext(in_hash[:extension_object]) } - - return { :collection_test_fixture_extra_link_objects => objects } + + return { :collection_all_support => sources, + :collection_test_fixture_extra_link_objects => objects + } end @@ -426,12 +464,12 @@ def collect_test_fixture_extra_link_objects(in_hash) def get_vendor_paths(in_hash) vendor_paths = [] - vendor_paths << FilePathUtils::form_ceedling_vendor_path(UNITY_LIB_PATH) - vendor_paths << FilePathUtils::form_ceedling_vendor_path(CEXCEPTION_LIB_PATH) if (in_hash[:project_use_exceptions]) - vendor_paths << FilePathUtils::form_ceedling_vendor_path(CMOCK_LIB_PATH) if (in_hash[:project_use_mocks]) - vendor_paths << in_hash[:cmock_mock_path] if (in_hash[:project_use_mocks]) + vendor_paths << File.join(in_hash[:unity_vendor_path], UNITY_LIB_PATH) + vendor_paths << File.join(in_hash[:cexception_vendor_path], CEXCEPTION_LIB_PATH) if (in_hash[:project_use_exceptions]) + vendor_paths << File.join(in_hash[:cmock_vendor_path], CMOCK_LIB_PATH) if (in_hash[:project_use_mocks]) + vendor_paths << in_hash[:cmock_mock_path] if (in_hash[:project_use_mocks]) return vendor_paths end - + end diff --git a/vendor/ceedling/lib/ceedling/configurator_plugins.rb b/vendor/ceedling/lib/ceedling/configurator_plugins.rb new file mode 100644 index 0000000..75bcd98 --- /dev/null +++ b/vendor/ceedling/lib/ceedling/configurator_plugins.rb @@ -0,0 +1,131 @@ +require 'ceedling/constants' + +class ConfiguratorPlugins + + constructor :stream_wrapper, :file_wrapper, :system_wrapper + attr_reader :rake_plugins, :script_plugins + + def setup + @rake_plugins = [] + @script_plugins = [] + end + + + def add_load_paths(config) + plugin_paths = {} + + config[:plugins][:enabled].each do |plugin| + config[:plugins][:load_paths].each do |root| + path = File.join(root, plugin) + + is_script_plugin = ( not @file_wrapper.directory_listing( File.join( path, 'lib', '*.rb' ) ).empty? ) + is_rake_plugin = ( not @file_wrapper.directory_listing( File.join( path, '*.rake' ) ).empty? ) + + if is_script_plugin or is_rake_plugin + plugin_paths[(plugin + '_path').to_sym] = path + + if is_script_plugin + @system_wrapper.add_load_path( File.join( path, 'lib') ) + @system_wrapper.add_load_path( File.join( path, 'config') ) + end + break + end + end + end + + return plugin_paths + end + + + # gather up and return .rake filepaths that exist on-disk + def find_rake_plugins(config, plugin_paths) + @rake_plugins = [] + plugins_with_path = [] + + config[:plugins][:enabled].each do |plugin| + if path = plugin_paths[(plugin + '_path').to_sym] + rake_plugin_path = File.join(path, "#{plugin}.rake") + if (@file_wrapper.exist?(rake_plugin_path)) + plugins_with_path << rake_plugin_path + @rake_plugins << plugin + end + end + end + + return plugins_with_path + end + + + # gather up and return just names of .rb classes that exist on-disk + def find_script_plugins(config, plugin_paths) + @script_plugins = [] + + config[:plugins][:enabled].each do |plugin| + if path = plugin_paths[(plugin + '_path').to_sym] + script_plugin_path = File.join(path, "lib", "#{plugin}.rb") + + if @file_wrapper.exist?(script_plugin_path) + @script_plugins << plugin + end + end + end + + return @script_plugins + end + + + # gather up and return configuration .yml filepaths that exist on-disk + def find_config_plugins(config, plugin_paths) + plugins_with_path = [] + + config[:plugins][:enabled].each do |plugin| + if path = plugin_paths[(plugin + '_path').to_sym] + config_plugin_path = File.join(path, "config", "#{plugin}.yml") + + if @file_wrapper.exist?(config_plugin_path) + plugins_with_path << config_plugin_path + end + end + end + + return plugins_with_path + end + + + # gather up and return default .yml filepaths that exist on-disk + def find_plugin_yml_defaults(config, plugin_paths) + defaults_with_path = [] + + config[:plugins][:enabled].each do |plugin| + if path = plugin_paths[(plugin + '_path').to_sym] + default_path = File.join(path, 'config', 'defaults.yml') + + if @file_wrapper.exist?(default_path) + defaults_with_path << default_path + end + end + end + + return defaults_with_path + end + + # gather up and return + def find_plugin_hash_defaults(config, plugin_paths) + defaults_hash= [] + + config[:plugins][:enabled].each do |plugin| + if path = plugin_paths[(plugin + '_path').to_sym] + default_path = File.join(path, "config", "defaults_#{plugin}.rb") + if @file_wrapper.exist?(default_path) + @system_wrapper.require_file( "defaults_#{plugin}.rb") + + object = eval("get_default_config()") + defaults_hash << object + end + end + end + + return defaults_hash + end + +end diff --git a/vendor/ceedling/lib/configurator_setup.rb b/vendor/ceedling/lib/ceedling/configurator_setup.rb similarity index 89% rename from vendor/ceedling/lib/configurator_setup.rb rename to vendor/ceedling/lib/ceedling/configurator_setup.rb index d6cf377..c43bb5c 100644 --- a/vendor/ceedling/lib/configurator_setup.rb +++ b/vendor/ceedling/lib/ceedling/configurator_setup.rb @@ -1,5 +1,5 @@ -# add sort-ability to symbol so we can order keys array in hash for test-ability +# add sort-ability to symbol so we can order keys array in hash for test-ability class Symbol include Comparable @@ -10,25 +10,24 @@ def <=>(other) class ConfiguratorSetup - + constructor :configurator_builder, :configurator_validator, :configurator_plugins, :stream_wrapper - - + + def build_project_config(config, flattened_config) ### flesh out config @configurator_builder.clean(flattened_config) - + ### add to hash values we build up from configuration & file system contents flattened_config.merge!(@configurator_builder.set_build_paths(flattened_config)) flattened_config.merge!(@configurator_builder.set_force_build_filepaths(flattened_config)) flattened_config.merge!(@configurator_builder.set_rakefile_components(flattened_config)) - flattened_config.merge!(@configurator_builder.set_library_build_info_filepaths(flattened_config)) flattened_config.merge!(@configurator_builder.set_release_target(flattened_config)) flattened_config.merge!(@configurator_builder.collect_project_options(flattened_config)) - + ### iterate through all entries in paths section and expand any & all globs to actual paths flattened_config.merge!(@configurator_builder.expand_all_path_globs(flattened_config)) - + flattened_config.merge!(@configurator_builder.collect_vendor_paths(flattened_config)) flattened_config.merge!(@configurator_builder.collect_source_and_include_paths(flattened_config)) flattened_config.merge!(@configurator_builder.collect_source_include_vendor_paths(flattened_config)) @@ -38,7 +37,9 @@ def build_project_config(config, flattened_config) flattened_config.merge!(@configurator_builder.collect_assembly(flattened_config)) flattened_config.merge!(@configurator_builder.collect_source(flattened_config)) flattened_config.merge!(@configurator_builder.collect_headers(flattened_config)) + flattened_config.merge!(@configurator_builder.collect_release_existing_compilation_input(flattened_config)) flattened_config.merge!(@configurator_builder.collect_all_existing_compilation_input(flattened_config)) + flattened_config.merge!(@configurator_builder.collect_vendor_defines(flattened_config)) flattened_config.merge!(@configurator_builder.collect_test_and_vendor_defines(flattened_config)) flattened_config.merge!(@configurator_builder.collect_release_and_vendor_defines(flattened_config)) flattened_config.merge!(@configurator_builder.collect_release_artifact_extra_link_objects(flattened_config)) @@ -47,13 +48,13 @@ def build_project_config(config, flattened_config) return flattened_config end - + def build_constants_and_accessors(config, context) @configurator_builder.build_global_constants(config) @configurator_builder.build_accessor_methods(config, context) end - - + + def validate_required_sections(config) validation = [] validation << @configurator_validator.exists?(config, :project) @@ -76,8 +77,11 @@ def validate_required_section_values(config) def validate_paths(config) validation = [] - validation << @configurator_validator.validate_filepath(config, :project, :build_root) - validation << @configurator_validator.validate_filepath(config, :cmock, :unity_helper) if config[:cmock][:unity_helper] + if config[:cmock][:unity_helper] + config[:cmock][:unity_helper].each do |path| + validation << @configurator_validator.validate_filepath_simple( path, :cmock, :unity_helper ) + end + end config[:project][:options_paths].each do |path| validation << @configurator_validator.validate_filepath_simple( path, :project, :options_paths ) @@ -94,7 +98,7 @@ def validate_paths(config) return false if (validation.include?(false)) return true end - + def validate_tools(config) validation = [] @@ -109,15 +113,15 @@ def validate_tools(config) end def validate_plugins(config) - missing_plugins = - Set.new( config[:plugins][:enabled] ) - - Set.new( @configurator_plugins.rake_plugins ) - + missing_plugins = + Set.new( config[:plugins][:enabled] ) - + Set.new( @configurator_plugins.rake_plugins ) - Set.new( @configurator_plugins.script_plugins ) - + missing_plugins.each do |plugin| @stream_wrapper.stderr_puts("ERROR: Ceedling plugin '#{plugin}' contains no rake or ruby class entry point. (Misspelled or missing files?)") end - + return ( (missing_plugins.size > 0) ? false : true ) end diff --git a/vendor/ceedling/lib/configurator_validator.rb b/vendor/ceedling/lib/ceedling/configurator_validator.rb similarity index 86% rename from vendor/ceedling/lib/configurator_validator.rb rename to vendor/ceedling/lib/ceedling/configurator_validator.rb index 970e6c9..fc02101 100644 --- a/vendor/ceedling/lib/configurator_validator.rb +++ b/vendor/ceedling/lib/ceedling/configurator_validator.rb @@ -1,8 +1,8 @@ require 'rubygems' require 'rake' # for ext() -require 'constants' -require 'tool_executor' # for argument replacement pattern -require 'file_path_utils' # for glob handling class methods +require 'ceedling/constants' +require 'ceedling/tool_executor' # for argument replacement pattern +require 'ceedling/file_path_utils' # for glob handling class methods class ConfiguratorValidator @@ -78,9 +78,18 @@ def validate_filepath(config, *keys) return true if (filepath =~ TOOL_EXECUTOR_ARGUMENT_REPLACEMENT_PATTERN) if (not @file_wrapper.exist?(filepath)) - # no verbosity checking since this is lowest level anyhow & verbosity checking depends on configurator - @stream_wrapper.stderr_puts("ERROR: Config filepath #{format_key_sequence(keys, hash[:depth])}['#{filepath}'] does not exist on disk.") - return false + + # See if we can deal with it internally. + if GENERATED_DIR_PATH.include?(filepath) + # we already made this directory before let's make it again. + FileUtils.mkdir_p File.join(File.dirname(__FILE__), filepath) + @stream_wrapper.stderr_puts("WARNING: Generated filepath #{format_key_sequence(keys, hash[:depth])}['#{filepath}'] does not exist on disk. Recreating") + + else + # no verbosity checking since this is lowest level anyhow & verbosity checking depends on configurator + @stream_wrapper.stderr_puts("ERROR: Config filepath #{format_key_sequence(keys, hash[:depth])}['#{filepath}'] does not exist on disk.") + return false + end end return true diff --git a/vendor/ceedling/lib/ceedling/constants.rb b/vendor/ceedling/lib/ceedling/constants.rb new file mode 100644 index 0000000..19484f0 --- /dev/null +++ b/vendor/ceedling/lib/ceedling/constants.rb @@ -0,0 +1,99 @@ + +class Verbosity + SILENT = 0 # as silent as possible (though there are some messages that must be spit out) + ERRORS = 1 # only errors + COMPLAIN = 2 # spit out errors and warnings/notices + NORMAL = 3 # errors, warnings/notices, standard status messages + OBNOXIOUS = 4 # all messages including extra verbose output (used for lite debugging / verification) + DEBUG = 5 # special extra verbose output for hardcore debugging +end + + +class TestResultsSanityChecks + NONE = 0 # no sanity checking of test results + NORMAL = 1 # perform non-problematic checks + THOROUGH = 2 # perform checks that require inside knowledge of system workings +end + + +class StdErrRedirect + NONE = :none + AUTO = :auto + WIN = :win + UNIX = :unix + TCSH = :tcsh +end + + +class BackgroundExec + NONE = :none + AUTO = :auto + WIN = :win + UNIX = :unix +end + +unless defined?(PROJECT_ROOT) + PROJECT_ROOT = Dir.pwd() +end + +GENERATED_DIR_PATH = [['vendor', 'ceedling'], 'src', "test", ['test', 'support'], 'build'].each{|p| File.join(*p)} + +EXTENSION_WIN_EXE = '.exe' +EXTENSION_NONWIN_EXE = '.out' + + +CEXCEPTION_ROOT_PATH = 'c_exception' +CEXCEPTION_LIB_PATH = "#{CEXCEPTION_ROOT_PATH}/lib" +CEXCEPTION_C_FILE = 'CException.c' +CEXCEPTION_H_FILE = 'CException.h' + +UNITY_ROOT_PATH = 'unity' +UNITY_LIB_PATH = "#{UNITY_ROOT_PATH}/src" +UNITY_C_FILE = 'unity.c' +UNITY_H_FILE = 'unity.h' +UNITY_INTERNALS_H_FILE = 'unity_internals.h' + +CMOCK_ROOT_PATH = 'cmock' +CMOCK_LIB_PATH = "#{CMOCK_ROOT_PATH}/src" +CMOCK_C_FILE = 'cmock.c' +CMOCK_H_FILE = 'cmock.h' + + +DEFAULT_CEEDLING_MAIN_PROJECT_FILE = 'project.yml' unless defined?(DEFAULT_CEEDLING_MAIN_PROJECT_FILE) # main project file +DEFAULT_CEEDLING_USER_PROJECT_FILE = 'user.yml' unless defined?(DEFAULT_CEEDLING_USER_PROJECT_FILE) # supplemental user config file + +INPUT_CONFIGURATION_CACHE_FILE = 'input.yml' unless defined?(INPUT_CONFIGURATION_CACHE_FILE) # input configuration file dump +DEFINES_DEPENDENCY_CACHE_FILE = 'defines_dependency.yml' unless defined?(DEFINES_DEPENDENCY_CACHE_FILE) # preprocessor definitions for files + +TEST_ROOT_NAME = 'test' unless defined?(TEST_ROOT_NAME) +TEST_TASK_ROOT = TEST_ROOT_NAME + ':' unless defined?(TEST_TASK_ROOT) +TEST_SYM = TEST_ROOT_NAME.to_sym unless defined?(TEST_SYM) + +RELEASE_ROOT_NAME = 'release' unless defined?(RELEASE_ROOT_NAME) +RELEASE_TASK_ROOT = RELEASE_ROOT_NAME + ':' unless defined?(RELEASE_TASK_ROOT) +RELEASE_SYM = RELEASE_ROOT_NAME.to_sym unless defined?(RELEASE_SYM) + +REFRESH_ROOT_NAME = 'refresh' unless defined?(REFRESH_ROOT_NAME) +REFRESH_TASK_ROOT = REFRESH_ROOT_NAME + ':' unless defined?(REFRESH_TASK_ROOT) +REFRESH_SYM = REFRESH_ROOT_NAME.to_sym unless defined?(REFRESH_SYM) + +UTILS_ROOT_NAME = 'utils' unless defined?(UTILS_ROOT_NAME) +UTILS_TASK_ROOT = UTILS_ROOT_NAME + ':' unless defined?(UTILS_TASK_ROOT) +UTILS_SYM = UTILS_ROOT_NAME.to_sym unless defined?(UTILS_SYM) + +OPERATION_COMPILE_SYM = :compile unless defined?(OPERATION_COMPILE_SYM) +OPERATION_ASSEMBLE_SYM = :assemble unless defined?(OPERATION_ASSEMBLE_SYM) +OPERATION_LINK_SYM = :link unless defined?(OPERATION_LINK_SYM) + + +RUBY_STRING_REPLACEMENT_PATTERN = /#\{.+\}/ +RUBY_EVAL_REPLACEMENT_PATTERN = /^\{(.+)\}$/ +TOOL_EXECUTOR_ARGUMENT_REPLACEMENT_PATTERN = /(\$\{(\d+)\})/ +TEST_STDOUT_STATISTICS_PATTERN = /\n-+\s*(\d+)\s+Tests\s+(\d+)\s+Failures\s+(\d+)\s+Ignored\s+(OK|FAIL)\s*/i + +NULL_FILE_PATH = '/dev/null' + +TESTS_BASE_PATH = TEST_ROOT_NAME +RELEASE_BASE_PATH = RELEASE_ROOT_NAME + +VENDORS_FILES = %w(unity UnityHelper cmock CException).freeze diff --git a/vendor/ceedling/lib/defaults.rb b/vendor/ceedling/lib/ceedling/defaults.rb similarity index 65% rename from vendor/ceedling/lib/defaults.rb rename to vendor/ceedling/lib/ceedling/defaults.rb index 6254a64..1300a1a 100644 --- a/vendor/ceedling/lib/defaults.rb +++ b/vendor/ceedling/lib/ceedling/defaults.rb @@ -1,37 +1,53 @@ -require 'constants' -require 'system_wrapper' -require 'file_path_utils' +require 'ceedling/constants' +require 'ceedling/system_wrapper' +require 'ceedling/file_path_utils' +#this should be defined already, but not always during system specs +CEEDLING_VENDOR = File.expand_path(File.dirname(__FILE__) + '/../../vendor') unless defined? CEEDLING_VENDOR +CEEDLING_PLUGINS = [] unless defined? CEEDLING_PLUGINS DEFAULT_TEST_COMPILER_TOOL = { - :executable => FilePathUtils.os_executable_ext('gcc').freeze, + :executable => ENV['CC'].nil? ? FilePathUtils.os_executable_ext('gcc').freeze : ENV['CC'].split[0], :name => 'default_test_compiler'.freeze, :stderr_redirect => StdErrRedirect::NONE.freeze, :background_exec => BackgroundExec::NONE.freeze, :optional => false.freeze, :arguments => [ + ENV['CC'].nil? ? "" : ENV['CC'].split[1..-1], + ENV['CPPFLAGS'].nil? ? "" : ENV['CPPFLAGS'].split, {"-I\"$\"" => 'COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR'}.freeze, {"-I\"$\"" => 'COLLECTION_PATHS_TEST_TOOLCHAIN_INCLUDE'}.freeze, {"-D$" => 'COLLECTION_DEFINES_TEST_AND_VENDOR'}.freeze, "-DGNU_COMPILER".freeze, + "-g".freeze, + ENV['CFLAGS'].nil? ? "" : ENV['CFLAGS'].split, "-c \"${1}\"".freeze, "-o \"${2}\"".freeze, - # gcc's list file output options are complex; no use of ${3} parameter in default config + # gcc's list file output options are complex; no use of ${3} parameter in default config + "-MMD".freeze, + "-MF \"${4}\"".freeze, ].freeze } DEFAULT_TEST_LINKER_TOOL = { - :executable => FilePathUtils.os_executable_ext('gcc').freeze, + :executable => ENV['CCLD'].nil? ? FilePathUtils.os_executable_ext('gcc').freeze : ENV['CCLD'].split[0], :name => 'default_test_linker'.freeze, :stderr_redirect => StdErrRedirect::NONE.freeze, :background_exec => BackgroundExec::NONE.freeze, :optional => false.freeze, :arguments => [ + ENV['CCLD'].nil? ? "" : ENV['CCLD'].split[1..-1], + ENV['CFLAGS'].nil? ? "" : ENV['CFLAGS'].split, + ENV['LDFLAGS'].nil? ? "" : ENV['LDFLAGS'].split, "\"${1}\"".freeze, + "${5}".freeze, "-o \"${2}\"".freeze, + "".freeze, + "${4}".freeze, + ENV['LDLIBS'].nil? ? "" : ENV['LDLIBS'].split ].freeze } - + DEFAULT_TEST_FIXTURE_TOOL = { :executable => '${1}'.freeze, :name => 'default_test_fixture'.freeze, @@ -41,114 +57,161 @@ :arguments => [].freeze } - - DEFAULT_TEST_INCLUDES_PREPROCESSOR_TOOL = { - :executable => FilePathUtils.os_executable_ext('cpp').freeze, + :executable => ENV['CC'].nil? ? FilePathUtils.os_executable_ext('gcc').freeze : ENV['CC'].split[0], :name => 'default_test_includes_preprocessor'.freeze, :stderr_redirect => StdErrRedirect::NONE.freeze, :background_exec => BackgroundExec::NONE.freeze, :optional => false.freeze, :arguments => [ + ENV['CC'].nil? ? "" : ENV['CC'].split[1..-1], + ENV['CPPFLAGS'].nil? ? "" : ENV['CPPFLAGS'].split, + '-E'.freeze, # OSX clang '-MM'.freeze, '-MG'.freeze, # avoid some possibility of deep system lib header file complications by omitting vendor paths # if cpp is run on *nix system, escape spaces in paths; if cpp on windows just use the paths collection as is - {"-I\"$\"" => "{SystemWrapper.windows? ? COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE : COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE.map{|path| path.gsub(\/ \/, \'\\\\ \') }}"}.freeze, + # {"-I\"$\"" => "{SystemWrapper.windows? ? COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE : COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE.map{|path| path.gsub(\/ \/, \'\\\\ \') }}"}.freeze, + {"-I\"$\"" => 'COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR'}.freeze, + {"-I\"$\"" => 'COLLECTION_PATHS_TEST_TOOLCHAIN_INCLUDE'}.freeze, {"-D$" => 'COLLECTION_DEFINES_TEST_AND_VENDOR'}.freeze, {"-D$" => 'DEFINES_TEST_PREPROCESS'}.freeze, - "-DGNU_PREPROCESSOR".freeze, - '-w'.freeze, - '-nostdinc'.freeze, + "-DGNU_COMPILER".freeze, # OSX clang + # '-nostdinc'.freeze, # disabled temporarily due to stdio access violations on OSX "\"${1}\"".freeze ].freeze } DEFAULT_TEST_FILE_PREPROCESSOR_TOOL = { - :executable => FilePathUtils.os_executable_ext('gcc').freeze, + :executable => ENV['CC'].nil? ? FilePathUtils.os_executable_ext('gcc').freeze : ENV['CC'].split[0], :name => 'default_test_file_preprocessor'.freeze, :stderr_redirect => StdErrRedirect::NONE.freeze, :background_exec => BackgroundExec::NONE.freeze, :optional => false.freeze, :arguments => [ + ENV['CC'].nil? ? "" : ENV['CC'].split[1..-1], + ENV['CPPFLAGS'].nil? ? "" : ENV['CPPFLAGS'].split, '-E'.freeze, {"-I\"$\"" => 'COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR'}.freeze, {"-I\"$\"" => 'COLLECTION_PATHS_TEST_TOOLCHAIN_INCLUDE'}.freeze, {"-D$" => 'COLLECTION_DEFINES_TEST_AND_VENDOR'}.freeze, {"-D$" => 'DEFINES_TEST_PREPROCESS'}.freeze, - "-DGNU_PREPROCESSOR".freeze, + "-DGNU_COMPILER".freeze, + # '-nostdinc'.freeze, # disabled temporarily due to stdio access violations on OSX "\"${1}\"".freeze, "-o \"${2}\"".freeze ].freeze } -DEFAULT_TEST_DEPENDENCIES_GENERATOR_TOOL = { +DEFAULT_TEST_FILE_PREPROCESSOR_DIRECTIVES_TOOL = { :executable => FilePathUtils.os_executable_ext('gcc').freeze, + :name => 'default_test_file_preprocessor_directives'.freeze, + :stderr_redirect => StdErrRedirect::NONE.freeze, + :background_exec => BackgroundExec::NONE.freeze, + :optional => false.freeze, + :arguments => [ + '-E'.freeze, + {"-I\"$\"" => 'COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR'}.freeze, + {"-I\"$\"" => 'COLLECTION_PATHS_TEST_TOOLCHAIN_INCLUDE'}.freeze, + {"-D$" => 'COLLECTION_DEFINES_TEST_AND_VENDOR'}.freeze, + {"-D$" => 'DEFINES_TEST_PREPROCESS'}.freeze, + "-DGNU_COMPILER".freeze, + '-fdirectives-only'.freeze, + # '-nostdinc'.freeze, # disabled temporarily due to stdio access violations on OSX + "\"${1}\"".freeze, + "-o \"${2}\"".freeze + ].freeze + } + +# Disable the -MD flag for OSX LLVM Clang, since unsupported +if RUBY_PLATFORM =~ /darwin/ && `gcc --version 2> /dev/null` =~ /Apple LLVM version .* \(clang/m # OSX w/LLVM Clang + MD_FLAG = '' # Clang doesn't support the -MD flag +else + MD_FLAG = '-MD' +end + +DEFAULT_TEST_DEPENDENCIES_GENERATOR_TOOL = { + :executable => ENV['CC'].nil? ? FilePathUtils.os_executable_ext('gcc').freeze : ENV['CC'].split[0], :name => 'default_test_dependencies_generator'.freeze, :stderr_redirect => StdErrRedirect::NONE.freeze, :background_exec => BackgroundExec::NONE.freeze, :optional => false.freeze, :arguments => [ + ENV['CC'].nil? ? "" : ENV['CC'].split[1..-1], + ENV['CPPFLAGS'].nil? ? "" : ENV['CPPFLAGS'].split, + '-E'.freeze, {"-I\"$\"" => 'COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR'}.freeze, {"-I\"$\"" => 'COLLECTION_PATHS_TEST_TOOLCHAIN_INCLUDE'}.freeze, - {"-D$" => 'COLLECTION_DEFINES_TEST_AND_VENDOR'}.freeze, - {"-D$" => 'DEFINES_TEST_PREPROCESS'}.freeze, - "-DGNU_PREPROCESSOR".freeze, + {"-D$" => 'COLLECTION_DEFINES_TEST_AND_VENDOR'}.freeze, + {"-D$" => 'DEFINES_TEST_PREPROCESS'}.freeze, + "-DGNU_COMPILER".freeze, "-MT \"${3}\"".freeze, '-MM'.freeze, - '-MD'.freeze, + MD_FLAG.freeze, '-MG'.freeze, "-MF \"${2}\"".freeze, "-c \"${1}\"".freeze, + # '-nostdinc'.freeze, ].freeze } DEFAULT_RELEASE_DEPENDENCIES_GENERATOR_TOOL = { - :executable => FilePathUtils.os_executable_ext('gcc').freeze, + :executable => ENV['CC'].nil? ? FilePathUtils.os_executable_ext('gcc').freeze : ENV['CC'].split[0], :name => 'default_release_dependencies_generator'.freeze, :stderr_redirect => StdErrRedirect::NONE.freeze, :background_exec => BackgroundExec::NONE.freeze, :optional => false.freeze, :arguments => [ + ENV['CC'].nil? ? "" : ENV['CC'].split[1..-1], + ENV['CPPFLAGS'].nil? ? "" : ENV['CPPFLAGS'].split, + '-E'.freeze, {"-I\"$\"" => 'COLLECTION_PATHS_SOURCE_INCLUDE_VENDOR'}.freeze, {"-I\"$\"" => 'COLLECTION_PATHS_RELEASE_TOOLCHAIN_INCLUDE'}.freeze, {"-D$" => 'COLLECTION_DEFINES_RELEASE_AND_VENDOR'}.freeze, {"-D$" => 'DEFINES_RELEASE_PREPROCESS'}.freeze, - "-DGNU_PREPROCESSOR".freeze, + "-DGNU_COMPILER".freeze, "-MT \"${3}\"".freeze, '-MM'.freeze, - '-MD'.freeze, + MD_FLAG.freeze, '-MG'.freeze, "-MF \"${2}\"".freeze, "-c \"${1}\"".freeze, + # '-nostdinc'.freeze, ].freeze } DEFAULT_RELEASE_COMPILER_TOOL = { - :executable => FilePathUtils.os_executable_ext('gcc').freeze, + :executable => ENV['CC'].nil? ? FilePathUtils.os_executable_ext('gcc').freeze : ENV['CC'].split[0], :name => 'default_release_compiler'.freeze, :stderr_redirect => StdErrRedirect::NONE.freeze, :background_exec => BackgroundExec::NONE.freeze, :optional => false.freeze, :arguments => [ + ENV['CC'].nil? ? "" : ENV['CC'].split[1..-1], + ENV['CPPFLAGS'].nil? ? "" : ENV['CPPFLAGS'].split, {"-I\"$\"" => 'COLLECTION_PATHS_SOURCE_INCLUDE_VENDOR'}.freeze, {"-I\"$\"" => 'COLLECTION_PATHS_RELEASE_TOOLCHAIN_INCLUDE'}.freeze, {"-D$" => 'COLLECTION_DEFINES_RELEASE_AND_VENDOR'}.freeze, "-DGNU_COMPILER".freeze, + ENV['CFLAGS'].nil? ? "" : ENV['CFLAGS'].split, "-c \"${1}\"".freeze, "-o \"${2}\"".freeze, - # gcc's list file output options are complex; no use of ${3} parameter in default config + # gcc's list file output options are complex; no use of ${3} parameter in default config + "-MMD".freeze, + "-MF \"${4}\"".freeze, ].freeze } DEFAULT_RELEASE_ASSEMBLER_TOOL = { - :executable => FilePathUtils.os_executable_ext('as').freeze, + :executable => ENV['AS'].nil? ? FilePathUtils.os_executable_ext('as').freeze : ENV['AS'].split[0], :name => 'default_release_assembler'.freeze, :stderr_redirect => StdErrRedirect::NONE.freeze, :background_exec => BackgroundExec::NONE.freeze, :optional => false.freeze, :arguments => [ + ENV['AS'].nil? ? "" : ENV['AS'].split[1..-1], + ENV['ASFLAGS'].nil? ? "" : ENV['ASFLAGS'].split, {"-I\"$\"" => 'COLLECTION_PATHS_SOURCE_AND_INCLUDE'}.freeze, "\"${1}\"".freeze, "-o \"${2}\"".freeze, @@ -156,18 +219,25 @@ } DEFAULT_RELEASE_LINKER_TOOL = { - :executable => FilePathUtils.os_executable_ext('gcc').freeze, + :executable => ENV['CCLD'].nil? ? FilePathUtils.os_executable_ext('gcc').freeze : ENV['CCLD'].split[0], :name => 'default_release_linker'.freeze, :stderr_redirect => StdErrRedirect::NONE.freeze, :background_exec => BackgroundExec::NONE.freeze, :optional => false.freeze, :arguments => [ + ENV['CCLD'].nil? ? "" : ENV['CCLD'].split[1..-1], + ENV['CFLAGS'].nil? ? "" : ENV['CFLAGS'].split, + ENV['LDFLAGS'].nil? ? "" : ENV['LDFLAGS'].split, "\"${1}\"".freeze, + "${5}".freeze, "-o \"${2}\"".freeze, + "".freeze, + "${4}".freeze, + ENV['LDLIBS'].nil? ? "" : ENV['LDLIBS'].split ].freeze } - + DEFAULT_TOOLS_TEST = { :tools => { :test_compiler => DEFAULT_TEST_COMPILER_TOOL, @@ -175,11 +245,12 @@ :test_fixture => DEFAULT_TEST_FIXTURE_TOOL, } } - + DEFAULT_TOOLS_TEST_PREPROCESSORS = { :tools => { :test_includes_preprocessor => DEFAULT_TEST_INCLUDES_PREPROCESSOR_TOOL, :test_file_preprocessor => DEFAULT_TEST_FILE_PREPROCESSOR_TOOL, + :test_file_preprocessor_directives => DEFAULT_TEST_FILE_PREPROCESSOR_DIRECTIVES_TOOL, } } @@ -209,7 +280,7 @@ } } - + DEFAULT_RELEASE_TARGET_NAME = 'project' DEFAULT_CEEDLING_CONFIG = { @@ -220,7 +291,10 @@ :compile_threads => 1, :test_threads => 1, :use_test_preprocessor => false, + :use_preprocessor_directives => false, :use_deep_dependencies => false, + :generate_deep_dependencies => true, # only applicable if use_deep_dependencies is true + :auto_link_deep_dependencies => false, :test_file_prefix => 'test_', :options_paths => [], :release_build => false, @@ -237,10 +311,11 @@ :source => [], # must be populated by user :support => [], :include => [], + :libraries => [], :test_toolchain_include => [], :release_toolchain_include => [], }, - + :files => { :test => [], :source => [], @@ -248,27 +323,38 @@ :support => [], :include => [], }, - + # unlike other top-level entries, environment's value is an array to preserve order :environment => [ # when evaluated, this provides wider text field for rake task comments {:rake_columns => '120'}, ], - + :defines => { :test => [], :test_preprocess => [], :release => [], :release_preprocess => [], + :use_test_definition => false, }, - + + :libraries => { + :flag => '-l${1}', + :path_flag => '-L ${1}', + :test => [], + :test_preprocess => [], + :release => [], + :release_preprocess => [], + }, + :flags => {}, - + :extension => { :header => '.h', :source => '.c', :assembly => '.s', :object => '.o', + :libraries => ['.a','.so'], :executable => ( SystemWrapper.windows? ? EXTENSION_WIN_EXE : EXTENSION_NONWIN_EXE ), :map => '.map', :list => '.lst', @@ -278,14 +364,18 @@ }, :unity => { + :vendor_path => CEEDLING_VENDOR, :defines => [] }, :cmock => { - :defines => [] + :vendor_path => CEEDLING_VENDOR, + :defines => [], + :includes => [] }, :cexception => { + :vendor_path => CEEDLING_VENDOR, :defines => [] }, @@ -301,12 +391,13 @@ # (these can be overridden in project file to add arguments to tools without totally redefining tools) :test_compiler => { :arguments => [] }, :test_linker => { :arguments => [] }, - :test_fixture => { + :test_fixture => { :arguments => [], :link_objects => [], # compiled object files to always be linked in (e.g. cmock.o if using mocks) }, :test_includes_preprocessor => { :arguments => [] }, :test_file_preprocessor => { :arguments => [] }, + :test_file_preprocessor_directives => { :arguments => [] }, :test_dependencies_generator => { :arguments => [] }, :release_compiler => { :arguments => [] }, :release_linker => { :arguments => [] }, @@ -314,12 +405,12 @@ :release_dependencies_generator => { :arguments => [] }, :plugins => { - :load_paths => [], + :load_paths => CEEDLING_PLUGINS, :enabled => [], } }.freeze - + DEFAULT_TESTS_RESULTS_REPORT_TEMPLATE = %q{ % ignored = hash[:results][:counts][:ignored] % failed = hash[:results][:counts][:failed] @@ -327,8 +418,17 @@ % header_prepend = ((hash[:header].length > 0) ? "#{hash[:header]}: " : '') % banner_width = 25 + header_prepend.length # widest message +% if (stdout_count > 0) +<%=@ceedling[:plugin_reportinator].generate_banner(header_prepend + 'TEST OUTPUT')%> +% hash[:results][:stdout].each do |string| +% string[:collection].each do |item| +<%=string[:source][:path]%><%=File::SEPARATOR%><%=string[:source][:file]%>: "<%=item%>" +% end +% end + +% end % if (ignored > 0) -<%=@ceedling[:plugin_reportinator].generate_banner(header_prepend + 'IGNORED UNIT TEST SUMMARY')%> +<%=@ceedling[:plugin_reportinator].generate_banner(header_prepend + 'IGNORED TEST SUMMARY')%> % hash[:results][:ignores].each do |ignore| % ignore[:collection].each do |item| <%=ignore[:source][:path]%><%=File::SEPARATOR%><%=ignore[:source][:file]%>:<%=item[:line]%>:<%=item[:test]%> @@ -342,7 +442,7 @@ % end % if (failed > 0) -<%=@ceedling[:plugin_reportinator].generate_banner(header_prepend + 'FAILED UNIT TEST SUMMARY')%> +<%=@ceedling[:plugin_reportinator].generate_banner(header_prepend + 'FAILED TEST SUMMARY')%> % hash[:results][:failures].each do |failure| % failure[:collection].each do |item| <%=failure[:source][:path]%><%=File::SEPARATOR%><%=failure[:source][:file]%>:<%=item[:line]%>:<%=item[:test]%> @@ -354,19 +454,10 @@ % end % end -% end -% if (stdout_count > 0) -<%=@ceedling[:plugin_reportinator].generate_banner(header_prepend + 'UNIT TEST OTHER OUTPUT')%> -% hash[:results][:stdout].each do |string| -% string[:collection].each do |item| -<%=string[:source][:path]%><%=File::SEPARATOR%><%=string[:source][:file]%>: "<%=item%>" -% end -% end - % end % total_string = hash[:results][:counts][:total].to_s % format_string = "%#{total_string.length}i" -<%=@ceedling[:plugin_reportinator].generate_banner(header_prepend + 'OVERALL UNIT TEST SUMMARY')%> +<%=@ceedling[:plugin_reportinator].generate_banner(header_prepend + 'OVERALL TEST SUMMARY')%> % if (hash[:results][:counts][:total] > 0) TESTED: <%=hash[:results][:counts][:total].to_s%> PASSED: <%=sprintf(format_string, hash[:results][:counts][:passed])%> diff --git a/vendor/ceedling/lib/dependinator.rb b/vendor/ceedling/lib/ceedling/dependinator.rb similarity index 60% rename from vendor/ceedling/lib/dependinator.rb rename to vendor/ceedling/lib/ceedling/dependinator.rb index 061caee..accfe80 100644 --- a/vendor/ceedling/lib/dependinator.rb +++ b/vendor/ceedling/lib/ceedling/dependinator.rb @@ -4,21 +4,24 @@ class Dependinator constructor :configurator, :project_config_manager, :test_includes_extractor, :file_path_utils, :rake_wrapper, :file_wrapper def touch_force_rebuild_files - @file_wrapper.touch( @configurator.project_test_force_rebuild_filepath ) + @file_wrapper.touch( @configurator.project_test_force_rebuild_filepath ) @file_wrapper.touch( @configurator.project_release_force_rebuild_filepath ) if (@configurator.project_release_build) end def load_release_object_deep_dependencies(dependencies_list) - dependencies_list.each { |dependencies_file| @rake_wrapper.load_dependencies( dependencies_file ) } + dependencies_list.each do |dependencies_file| + if File.exists?(dependencies_file) + @rake_wrapper.load_dependencies( dependencies_file ) + end + end end def enhance_release_file_dependencies(files) - files.each do |filepath| + files.each do |filepath| @rake_wrapper[filepath].enhance( [@configurator.project_release_force_rebuild_filepath] ) if (@project_config_manager.release_config_changed) - @rake_wrapper[filepath].enhance( [@configurator.ceedling_build_info_filepath] ) end end @@ -26,28 +29,32 @@ def enhance_release_file_dependencies(files) def load_test_object_deep_dependencies(files_list) dependencies_list = @file_path_utils.form_test_dependencies_filelist(files_list) - dependencies_list.each { |dependencies_file| @rake_wrapper.load_dependencies(dependencies_file) } + dependencies_list.each do |dependencies_file| + if File.exists?(dependencies_file) + @rake_wrapper.load_dependencies(dependencies_file) + end + end end def enhance_runner_dependencies(runner_filepath) - @rake_wrapper[runner_filepath].enhance( [@configurator.project_test_force_rebuild_filepath] ) if (@project_config_manager.test_config_changed) - @rake_wrapper[runner_filepath].enhance( [@configurator.ceedling_build_info_filepath] ) + @rake_wrapper[runner_filepath].enhance( [@configurator.project_test_force_rebuild_filepath] ) if (@project_config_manager.test_config_changed || + @project_config_manager.test_defines_changed) end - + def enhance_shallow_include_lists_dependencies(include_lists) include_lists.each do |include_list_filepath| - @rake_wrapper[include_list_filepath].enhance( [@configurator.project_test_force_rebuild_filepath] ) if (@project_config_manager.test_config_changed) - @rake_wrapper[include_list_filepath].enhance( [@configurator.ceedling_build_info_filepath] ) + @rake_wrapper[include_list_filepath].enhance( [@configurator.project_test_force_rebuild_filepath] ) if (@project_config_manager.test_config_changed || + @project_config_manager.test_defines_changed) end end def enhance_preprocesed_file_dependencies(files) files.each do |filepath| - @rake_wrapper[filepath].enhance( [@configurator.project_test_force_rebuild_filepath] ) if (@project_config_manager.test_config_changed) - @rake_wrapper[filepath].enhance( [@configurator.ceedling_build_info_filepath] ) + @rake_wrapper[filepath].enhance( [@configurator.project_test_force_rebuild_filepath] ) if (@project_config_manager.test_config_changed || + @project_config_manager.test_defines_changed) end end @@ -55,38 +62,36 @@ def enhance_preprocesed_file_dependencies(files) def enhance_mock_dependencies(mocks_list) # if input configuration or ceedling changes, make sure these guys get rebuilt mocks_list.each do |mock_filepath| - @rake_wrapper[mock_filepath].enhance( [@configurator.project_test_force_rebuild_filepath] ) if (@project_config_manager.test_config_changed) - @rake_wrapper[mock_filepath].enhance( [@configurator.cmock_unity_helper] ) if (@configurator.cmock_unity_helper) - @rake_wrapper[mock_filepath].enhance( [@configurator.ceedling_build_info_filepath] ) - @rake_wrapper[mock_filepath].enhance( [@configurator.cmock_build_info_filepath] ) + @rake_wrapper[mock_filepath].enhance( [@configurator.project_test_force_rebuild_filepath] ) if (@project_config_manager.test_config_changed || + @project_config_manager.test_defines_changed) + @rake_wrapper[mock_filepath].enhance( @configurator.cmock_unity_helper ) if (@configurator.cmock_unity_helper) end end def enhance_dependencies_dependencies(dependencies) dependencies.each do |dependencies_filepath| - @rake_wrapper[dependencies_filepath].enhance( [@configurator.project_test_force_rebuild_filepath] ) if (@project_config_manager.test_config_changed) - @rake_wrapper[dependencies_filepath].enhance( [@configurator.ceedling_build_info_filepath] ) + @rake_wrapper[dependencies_filepath].enhance( [@configurator.project_test_force_rebuild_filepath] ) if (@project_config_manager.test_config_changed || + @project_config_manager.test_defines_changed) end end def enhance_test_build_object_dependencies(objects) objects.each do |object_filepath| - @rake_wrapper[object_filepath].enhance( [@configurator.project_test_force_rebuild_filepath] ) if (@project_config_manager.test_config_changed) - @rake_wrapper[object_filepath].enhance( [@configurator.ceedling_build_info_filepath] ) + @rake_wrapper[object_filepath].enhance( [@configurator.project_test_force_rebuild_filepath] ) if (@project_config_manager.test_config_changed || + @project_config_manager.test_defines_changed) end end - + def enhance_results_dependencies(result_filepath) - @rake_wrapper[result_filepath].enhance( [@configurator.project_test_force_rebuild_filepath] ) if (@project_config_manager.test_config_changed) - @rake_wrapper[result_filepath].enhance( [@configurator.ceedling_build_info_filepath] ) + @rake_wrapper[result_filepath].enhance( [@configurator.project_test_force_rebuild_filepath] ) if @project_config_manager.test_config_changed end - def setup_test_executable_dependencies(test, objects) - @rake_wrapper.create_file_task( @file_path_utils.form_test_executable_filepath(test), objects) + def enhance_test_executable_dependencies(test, objects) + @rake_wrapper[ @file_path_utils.form_test_executable_filepath(test) ].enhance( objects ) end end diff --git a/vendor/ceedling/lib/erb_wrapper.rb b/vendor/ceedling/lib/ceedling/erb_wrapper.rb similarity index 100% rename from vendor/ceedling/lib/erb_wrapper.rb rename to vendor/ceedling/lib/ceedling/erb_wrapper.rb diff --git a/vendor/ceedling/lib/file_finder.rb b/vendor/ceedling/lib/ceedling/file_finder.rb similarity index 64% rename from vendor/ceedling/lib/file_finder.rb rename to vendor/ceedling/lib/ceedling/file_finder.rb index f9a7cfe..53775b7 100644 --- a/vendor/ceedling/lib/file_finder.rb +++ b/vendor/ceedling/lib/ceedling/file_finder.rb @@ -1,14 +1,17 @@ require 'rubygems' require 'rake' # for adding ext() method to string +require 'thread' + class FileFinder + SEMAPHORE = Mutex.new constructor :configurator, :file_finder_helper, :cacheinator, :file_path_utils, :file_wrapper, :yaml_wrapper def prepare_search_sources - @all_test_source_and_header_file_collection = + @all_test_source_and_header_file_collection = @configurator.collection_all_tests + - @configurator.collection_all_source + + @configurator.collection_all_source + @configurator.collection_all_headers end @@ -25,19 +28,19 @@ def find_header_file(mock_file) def find_header_input_for_mock_file(mock_file) found_path = find_header_file(mock_file) mock_input = found_path - + if (@configurator.project_use_test_preprocessor) mock_input = @cacheinator.diff_cached_test_file( @file_path_utils.form_preprocessed_file_filepath( found_path ) ) end - + return mock_input end - + def find_source_from_test(test, complain) test_prefix = @configurator.project_test_file_prefix source_paths = @configurator.collection_all_source - + source = File.basename(test).sub(/#{test_prefix}/, '') # we don't blow up if a test file has no corresponding source file @@ -49,31 +52,31 @@ def find_test_from_runner_path(runner_path) extension_source = @configurator.extension_source test_file = File.basename(runner_path).sub(/#{@configurator.test_runner_file_suffix}#{'\\'+extension_source}/, extension_source) - + found_path = @file_finder_helper.find_file_in_collection(test_file, @configurator.collection_all_tests, :error) return found_path end - + def find_test_input_for_runner_file(runner_path) found_path = find_test_from_runner_path(runner_path) runner_input = found_path - + if (@configurator.project_use_test_preprocessor) runner_input = @cacheinator.diff_cached_test_file( @file_path_utils.form_preprocessed_file_filepath( found_path ) ) end - + return runner_input end - + def find_test_from_file_path(file_path) test_file = File.basename(file_path).ext(@configurator.extension_source) - + found_path = @file_finder_helper.find_file_in_collection(test_file, @configurator.collection_all_tests, :error) - - return found_path + + return found_path end @@ -81,52 +84,66 @@ def find_test_or_source_or_header_file(file_path) file = File.basename(file_path) return @file_finder_helper.find_file_in_collection(file, @all_test_source_and_header_file_collection, :error) end - - - def find_compilation_input_file(file_path, complain=:error) + + + def find_compilation_input_file(file_path, complain=:error, release=false) found_file = nil - + source_file = File.basename(file_path).ext(@configurator.extension_source) # We only collect files that already exist when we start up. # FileLists can produce undesired results for dynamically generated files depending on when they're accessed. # So collect mocks and runners separately and right now. - if (source_file =~ /#{@configurator.test_runner_file_suffix}/) - found_file = - @file_finder_helper.find_file_in_collection( - source_file, - @file_wrapper.directory_listing( File.join(@configurator.project_test_runners_path, '*') ), - complain) - - elsif (@configurator.project_use_mocks and (source_file =~ /#{@configurator.cmock_mock_prefix}/)) - found_file = - @file_finder_helper.find_file_in_collection( - source_file, - @file_wrapper.directory_listing( File.join(@configurator.cmock_mock_path, '*') ), - complain) - - else - found_file = - @file_finder_helper.find_file_in_collection( - source_file, - @configurator.collection_all_existing_compilation_input, - complain) - end + SEMAPHORE.synchronize { + + if (source_file =~ /#{@configurator.test_runner_file_suffix}/) + found_file = + @file_finder_helper.find_file_in_collection( + source_file, + @file_wrapper.directory_listing( File.join(@configurator.project_test_runners_path, '*') ), + complain) + + elsif (@configurator.project_use_mocks and (source_file =~ /#{@configurator.cmock_mock_prefix}/)) + found_file = + @file_finder_helper.find_file_in_collection( + source_file, + @file_wrapper.directory_listing( File.join(@configurator.cmock_mock_path, '*') ), + complain) + + elsif release + found_file = + @file_finder_helper.find_file_in_collection( + source_file, + @configurator.collection_release_existing_compilation_input, + complain) + else + temp_complain = (defined?(TEST_BUILD_USE_ASSEMBLY) && TEST_BUILD_USE_ASSEMBLY) ? :ignore : complain + found_file = + @file_finder_helper.find_file_in_collection( + source_file, + @configurator.collection_all_existing_compilation_input, + temp_complain) + found_file ||= find_assembly_file(file_path, false) if (defined?(TEST_BUILD_USE_ASSEMBLY) && TEST_BUILD_USE_ASSEMBLY) + end + } return found_file end - + def find_source_file(file_path, complain) source_file = File.basename(file_path).ext(@configurator.extension_source) return @file_finder_helper.find_file_in_collection(source_file, @configurator.collection_all_source, complain) end - - def find_assembly_file(file_path) + + def find_assembly_file(file_path, complain = :error) assembly_file = File.basename(file_path).ext(@configurator.extension_assembly) - return @file_finder_helper.find_file_in_collection(assembly_file, @configurator.collection_all_assembly, :error) + return @file_finder_helper.find_file_in_collection(assembly_file, @configurator.collection_all_assembly, complain) + end + + def find_file_from_list(file_path, file_list, complain) + return @file_finder_helper.find_file_in_collection(file_path, file_list, complain) end - end diff --git a/vendor/ceedling/lib/file_finder_helper.rb b/vendor/ceedling/lib/ceedling/file_finder_helper.rb similarity index 81% rename from vendor/ceedling/lib/file_finder_helper.rb rename to vendor/ceedling/lib/ceedling/file_finder_helper.rb index 487f0fe..a168e5c 100644 --- a/vendor/ceedling/lib/file_finder_helper.rb +++ b/vendor/ceedling/lib/ceedling/file_finder_helper.rb @@ -1,5 +1,5 @@ require 'fileutils' -require 'constants' # for Verbosity enumeration +require 'ceedling/constants' # for Verbosity enumeration class FileFinderHelper @@ -25,10 +25,12 @@ def find_file_in_collection(file_name, file_list, complain, extra_message="") end - case (complain) - when :error then blow_up(file_name, extra_message) if (file_to_find.nil?) - when :warn then gripe(file_name, extra_message) if (file_to_find.nil?) - #when :ignore then + if file_to_find.nil? + case (complain) + when :error then blow_up(file_name, extra_message) + when :warn then gripe(file_name, extra_message) + #when :ignore then + end end return file_to_find diff --git a/vendor/ceedling/lib/file_path_utils.rb b/vendor/ceedling/lib/ceedling/file_path_utils.rb similarity index 74% rename from vendor/ceedling/lib/file_path_utils.rb rename to vendor/ceedling/lib/ceedling/file_path_utils.rb index 747c7b5..89a28ba 100644 --- a/vendor/ceedling/lib/file_path_utils.rb +++ b/vendor/ceedling/lib/ceedling/file_path_utils.rb @@ -1,7 +1,7 @@ require 'rubygems' require 'rake' # for ext() require 'fileutils' -require 'system_wrapper' +require 'ceedling/system_wrapper' # global utility methods (for plugins, project files, etc.) def ceedling_form_filepath(destination_path, original_filepath, new_extension=nil) @@ -19,12 +19,13 @@ class FilePathUtils ######### class methods ########## - # standardize path to use '/' path separator & begin with './' & have no trailing path separator + # standardize path to use '/' path separator & have no trailing path separator def self.standardize(path) - path.strip! - path.gsub!(/\\/, '/') - path.gsub!(/^((\+|-):)?\.\//, '') - path.chomp!('/') + if path.is_a? String + path.strip! + path.gsub!(/\\/, '/') + path.chomp!('/') + end return path end @@ -37,20 +38,20 @@ def self.os_executable_ext(executable) # note: slightly different than File.dirname in that /files/foo remains /files/foo and does not become /files def self.extract_path(path) path = path.sub(/^(\+|-):/, '') - + # find first occurrence of path separator followed by directory glob specifier: *, ?, {, }, [, ] find_index = (path =~ GLOB_MATCHER) - + # no changes needed (lop off final path separator) return path.chomp('/') if (find_index.nil?) - + # extract up to first glob specifier path = path[0..(find_index-1)] - + # lop off everything up to and including final path separator find_index = path.rindex('/') return path[0..(find_index-1)] if (not find_index.nil?) - + # return string up to first glob specifier if no path separator found return path end @@ -59,12 +60,12 @@ def self.extract_path(path) def self.add_path?(path) return (path =~ /^-:/).nil? end - + # get path (and glob) lopping off optional +: / -: prefixed aggregation modifiers def self.extract_path_no_aggregation_operators(path) return path.sub(/^(\+|-):/, '') end - + # all the globs that may be in a path string work fine with one exception; # to recurse through all subdirectories, the glob is dir/**/** but our paths use # convention of only dir/** @@ -73,25 +74,21 @@ def self.reform_glob(path) return path + '/**' end - def self.form_ceedling_vendor_path(*filepaths) - return File.join( CEEDLING_VENDOR, filepaths ) - end - ######### instance methods ########## def form_temp_path(filepath, prefix='') - return File.join( @configurator.project_temp_path, prefix + File.basename(filepath) ) + return File.join( @configurator.project_temp_path, prefix + File.basename(filepath) ) end - + ### release ### def form_release_build_cache_path(filepath) - return File.join( @configurator.project_release_build_cache_path, File.basename(filepath) ) + return File.join( @configurator.project_release_build_cache_path, File.basename(filepath) ) end - + def form_release_dependencies_filepath(filepath) return File.join( @configurator.project_release_dependencies_path, File.basename(filepath).ext(@configurator.extension_dependencies) ) end - + def form_release_build_c_object_filepath(filepath) return File.join( @configurator.project_release_build_output_c_path, File.basename(filepath).ext(@configurator.extension_object) ) end @@ -111,16 +108,20 @@ def form_release_build_asm_objects_filelist(files) def form_release_build_c_list_filepath(filepath) return File.join( @configurator.project_release_build_output_c_path, File.basename(filepath).ext(@configurator.extension_list) ) end - + def form_release_dependencies_filelist(files) return (@file_wrapper.instantiate_file_list(files)).pathmap("#{@configurator.project_release_dependencies_path}/%n#{@configurator.extension_dependencies}") end - + ### tests ### def form_test_build_cache_path(filepath) - return File.join( @configurator.project_test_build_cache_path, File.basename(filepath) ) + return File.join( @configurator.project_test_build_cache_path, File.basename(filepath) ) + end + + def form_test_dependencies_filepath(filepath) + return File.join( @configurator.project_test_dependencies_path, File.basename(filepath).ext(@configurator.extension_dependencies) ) end - + def form_pass_results_filepath(filepath) return File.join( @configurator.project_test_results_path, File.basename(filepath).ext(@configurator.extension_testpass) ) end @@ -138,15 +139,19 @@ def form_test_filepath_from_runner(filepath) end def form_runner_object_filepath_from_test(filepath) - return (form_test_build_object_filepath(filepath)).sub(/(#{@configurator.extension_object})$/, "#{@configurator.test_runner_file_suffix}\\1") + return (form_test_build_c_object_filepath(filepath)).sub(/(#{@configurator.extension_object})$/, "#{@configurator.test_runner_file_suffix}\\1") end - def form_test_build_object_filepath(filepath) - return File.join( @configurator.project_test_build_output_path, File.basename(filepath).ext(@configurator.extension_object) ) + def form_test_build_c_object_filepath(filepath) + return File.join( @configurator.project_test_build_output_c_path, File.basename(filepath).ext(@configurator.extension_object) ) + end + + def form_test_build_asm_object_filepath(filepath) + return File.join( @configurator.project_test_build_output_asm_path, File.basename(filepath).ext(@configurator.extension_object) ) end def form_test_executable_filepath(filepath) - return File.join( @configurator.project_test_build_output_path, File.basename(filepath).ext(@configurator.extension_executable) ) + return File.join( @configurator.project_test_build_output_path, File.basename(filepath).ext(@configurator.extension_executable) ) end def form_test_build_map_filepath(filepath) @@ -158,32 +163,40 @@ def form_test_build_list_filepath(filepath) end def form_preprocessed_file_filepath(filepath) - return File.join( @configurator.project_test_preprocess_files_path, File.basename(filepath) ) + return File.join( @configurator.project_test_preprocess_files_path, File.basename(filepath) ) end def form_preprocessed_includes_list_filepath(filepath) - return File.join( @configurator.project_test_preprocess_includes_path, File.basename(filepath) ) + return File.join( @configurator.project_test_preprocess_includes_path, File.basename(filepath) ) end def form_test_build_objects_filelist(sources) - return (@file_wrapper.instantiate_file_list(sources)).pathmap("#{@configurator.project_test_build_output_path}/%n#{@configurator.extension_object}") + return (@file_wrapper.instantiate_file_list(sources)).pathmap("#{@configurator.project_test_build_output_c_path}/%n#{@configurator.extension_object}") end - + def form_preprocessed_mockable_headers_filelist(mocks) - # pathmapping note: "%{#{@configurator.cmock_mock_prefix},}n" replaces mock_prefix with nothing (signified by absence of anything after comma inside replacement brackets) - return (@file_wrapper.instantiate_file_list(mocks)).pathmap("#{@configurator.project_test_preprocess_files_path}/%{#{@configurator.cmock_mock_prefix},}n#{@configurator.extension_header}") + list = @file_wrapper.instantiate_file_list(mocks) + headers = list.map do |file| + module_name = File.basename(file).sub(/^#{@configurator.cmock_mock_prefix}/, '').sub(/\.[a-zA-Z]+$/,'') + "#{@configurator.project_test_preprocess_files_path}/#{module_name}#{@configurator.extension_header}" + end + return headers end def form_mocks_source_filelist(mocks) - return (@file_wrapper.instantiate_file_list(mocks)).pathmap("#{@configurator.cmock_mock_path}/%n#{@configurator.extension_source}") + list = (@file_wrapper.instantiate_file_list(mocks)) + sources = list.map{|file| "#{@configurator.cmock_mock_path}/#{file}#{@configurator.extension_source}"} + return sources end def form_test_dependencies_filelist(files) - return (@file_wrapper.instantiate_file_list(files)).pathmap("#{@configurator.project_test_dependencies_path}/%n#{@configurator.extension_dependencies}") + list = @file_wrapper.instantiate_file_list(files) + return list.pathmap("#{@configurator.project_test_dependencies_path}/%n#{@configurator.extension_dependencies}") end def form_pass_results_filelist(path, files) - return (@file_wrapper.instantiate_file_list(files)).pathmap("#{path}/%n#{@configurator.extension_testpass}") + list = @file_wrapper.instantiate_file_list(files) + return list.pathmap("#{path}/%n#{@configurator.extension_testpass}") end end diff --git a/vendor/ceedling/lib/file_system_utils.rb b/vendor/ceedling/lib/ceedling/file_system_utils.rb similarity index 98% rename from vendor/ceedling/lib/file_system_utils.rb rename to vendor/ceedling/lib/ceedling/file_system_utils.rb index 6ba454b..97e5856 100644 --- a/vendor/ceedling/lib/file_system_utils.rb +++ b/vendor/ceedling/lib/ceedling/file_system_utils.rb @@ -2,7 +2,7 @@ require 'rake' require 'set' require 'fileutils' -require 'file_path_utils.rb' +require 'ceedling/file_path_utils' class FileSystemUtils diff --git a/vendor/ceedling/lib/file_system_wrapper.rb b/vendor/ceedling/lib/ceedling/file_system_wrapper.rb similarity index 100% rename from vendor/ceedling/lib/file_system_wrapper.rb rename to vendor/ceedling/lib/ceedling/file_system_wrapper.rb diff --git a/vendor/ceedling/lib/file_wrapper.rb b/vendor/ceedling/lib/ceedling/file_wrapper.rb similarity index 79% rename from vendor/ceedling/lib/file_wrapper.rb rename to vendor/ceedling/lib/ceedling/file_wrapper.rb index 55411d1..9e5a909 100644 --- a/vendor/ceedling/lib/file_wrapper.rb +++ b/vendor/ceedling/lib/ceedling/file_wrapper.rb @@ -1,7 +1,7 @@ require 'rubygems' require 'rake' # for FileList -require 'constants' require 'fileutils' +require 'ceedling/constants' class FileWrapper @@ -29,25 +29,25 @@ def dirname(path) end def directory_listing(glob) - return Dir.glob(glob) + return Dir.glob(glob, File::FNM_PATHNAME) end def rm_f(filepath, options={}) - FileUtils.rm_f(filepath, options) + FileUtils.rm_f(filepath, **options) end def rm_r(filepath, options={}) - FileUtils.rm_r(filepath, options={}) + FileUtils.rm_r(filepath, **options={}) end - + def cp(source, destination, options={}) - FileUtils.cp(source, destination, options) + FileUtils.cp(source, destination, **options) end def compare(from, to) return FileUtils.compare_file(from, to) end - + def open(filepath, flags) File.open(filepath, flags) do |file| yield(file) @@ -59,13 +59,13 @@ def read(filepath) end def touch(filepath, options={}) - FileUtils.touch(filepath, options) + FileUtils.touch(filepath, **options) end def write(filepath, contents, flags='w') File.open(filepath, flags) do |file| file.write(contents) - end + end end def readlines(filepath) @@ -76,4 +76,8 @@ def instantiate_file_list(files=[]) return FileList.new(files) end + def mkdir(folder) + return FileUtils.mkdir_p(folder) + end + end diff --git a/vendor/ceedling/lib/flaginator.rb b/vendor/ceedling/lib/ceedling/flaginator.rb similarity index 57% rename from vendor/ceedling/lib/flaginator.rb rename to vendor/ceedling/lib/ceedling/flaginator.rb index 0693447..31d62c4 100644 --- a/vendor/ceedling/lib/flaginator.rb +++ b/vendor/ceedling/lib/ceedling/flaginator.rb @@ -1,12 +1,14 @@ require 'rubygems' require 'rake' # for ext() require 'fileutils' -require 'constants' +require 'ceedling/constants' # :flags: # :release: # :compile: +# :'test_.+' +# - -pedantic # add '-pedantic' to every test file # :*: # add '-foo' to compilation of all files not main.c # - -foo # :main: # add '-Wall' to compilation of main.c @@ -17,38 +19,56 @@ # - --bar # - --baz +def partition(hash, &predicate) + hash.partition(&predicate).map(&:to_h) +end class Flaginator constructor :configurator + def get_flag(hash, file_name) + file_key = file_name.to_sym + + # 1. try literals + literals, magic = partition(hash) { |k, v| k.to_s =~ /^\w+$/ } + return literals[file_key] if literals.include?(file_key) + + any, regex = partition(magic) { |k, v| (k == :'*') || (k == :'.*') } # glob or regex wild card + + # 2. try regexes + find_res = regex.find { |k, v| file_name =~ /^#{k.to_s}$/ } + return find_res[1] if find_res + + # 3. try anything + find_res = any.find { |k, v| file_name =~ /.*/ } + return find_res[1] if find_res + + # 4. well, we've tried + return [] + end + def flag_down( operation, context, file ) # create configurator accessor method accessor = ('flags_' + context.to_s).to_sym - + # create simple filename key from whatever filename provided + file_name = File.basename( file ).ext('') file_key = File.basename( file ).ext('').to_sym - + # if no entry in configuration for flags for this context, bail out return [] if not @configurator.respond_to?( accessor ) - + # get flags sub hash associated with this context flags = @configurator.send( accessor ) # if operation not represented in flags hash, bail out return [] if not flags.include?( operation ) - + # redefine flags to sub hash associated with the operation flags = flags[operation] - - # if our file is in the flags hash, extract the array of flags - if (flags.include?( file_key )) then return flags[file_key] - # if our file isn't in the flags hash, but there is default for all other files, extract array of flags - elsif (flags.include?( :* )) then return flags[:*] - end - # fall through: flags were specified but none applying to present file - return [] + return get_flag(flags, file_name) end end diff --git a/vendor/ceedling/lib/generator.rb b/vendor/ceedling/lib/ceedling/generator.rb similarity index 77% rename from vendor/ceedling/lib/generator.rb rename to vendor/ceedling/lib/ceedling/generator.rb index 7eaf0d3..0b89024 100644 --- a/vendor/ceedling/lib/generator.rb +++ b/vendor/ceedling/lib/ceedling/generator.rb @@ -1,5 +1,4 @@ -require 'constants' - +require 'ceedling/constants' class Generator @@ -20,6 +19,7 @@ class Generator def generate_shallow_includes_list(context, file) + @streaminator.stdout_puts("Generating include list for #{File.basename(file)}...", Verbosity::NORMAL) @preprocessinator.preprocess_shallow_includes(file) end @@ -30,21 +30,22 @@ def generate_preprocessed_file(context, file) def generate_dependencies_file(tool, context, source, object, dependencies) @streaminator.stdout_puts("Generating dependencies for #{File.basename(source)}...", Verbosity::NORMAL) - - command = + + command = @tool_executor.build_command_line( tool, + [], # extra per-file command line parameters source, dependencies, object) - + @tool_executor.exec( command[:line], command[:options] ) end def generate_mock(context, header_filepath) arg_hash = {:header_file => header_filepath, :context => context} @plugin_manager.pre_mock_generate( arg_hash ) - + begin @cmock_builder.cmock.setup_mocks( arg_hash[:header_file] ) rescue @@ -58,61 +59,79 @@ def generate_mock(context, header_filepath) def generate_test_runner(context, test_filepath, runner_filepath) arg_hash = {:context => context, :test_file => test_filepath, :runner_file => runner_filepath} @plugin_manager.pre_runner_generate(arg_hash) - + # collect info we need module_name = File.basename(arg_hash[:test_file]) test_cases = @generator_test_runner.find_test_cases( @file_finder.find_test_from_runner_path(runner_filepath) ) mock_list = @test_includes_extractor.lookup_raw_mock_list(arg_hash[:test_file]) @streaminator.stdout_puts("Generating runner for #{module_name}...", Verbosity::NORMAL) - + + test_file_includes = [] # Empty list for now, since apparently unused + # build runner file begin - @generator_test_runner.generate(module_name, runner_filepath, test_cases, mock_list) + @generator_test_runner.generate(module_name, runner_filepath, test_cases, mock_list, test_file_includes) rescue raise ensure - @plugin_manager.post_runner_generate(arg_hash) + @plugin_manager.post_runner_generate(arg_hash) end end - def generate_object_file(tool, context, source, object, list='') + def generate_object_file(tool, operation, context, source, object, list='', dependencies='') shell_result = {} - arg_hash = {:tool => tool, :context => context, :source => source, :object => object, :list => list} + arg_hash = {:tool => tool, :operation => operation, :context => context, :source => source, :object => object, :list => list, :dependencies => dependencies} @plugin_manager.pre_compile_execute(arg_hash) @streaminator.stdout_puts("Compiling #{File.basename(arg_hash[:source])}...", Verbosity::NORMAL) command = @tool_executor.build_command_line( arg_hash[:tool], + @flaginator.flag_down( operation, context, source ), arg_hash[:source], arg_hash[:object], arg_hash[:list], - @flaginator.flag_down( OPERATION_COMPILE_SYM, context, source ) ) + arg_hash[:dependencies]) + + @streaminator.stdout_puts("Command: #{command}", Verbosity::DEBUG) begin shell_result = @tool_executor.exec( command[:line], command[:options] ) rescue ShellExecutionException => ex shell_result = ex.shell_result - raise '' + raise ex ensure + arg_hash[:shell_command] = command[:line] arg_hash[:shell_result] = shell_result @plugin_manager.post_compile_execute(arg_hash) end end - def generate_executable_file(tool, context, objects, executable, map='') + def generate_executable_file(tool, context, objects, executable, map='', libraries=[], libpaths=[]) shell_result = {} - arg_hash = {:tool => tool, :context => context, :objects => objects, :executable => executable, :map => map} + arg_hash = { :tool => tool, + :context => context, + :objects => objects, + :executable => executable, + :map => map, + :libraries => libraries, + :libpaths => libpaths + } + @plugin_manager.pre_link_execute(arg_hash) - + @streaminator.stdout_puts("Linking #{File.basename(arg_hash[:executable])}...", Verbosity::NORMAL) command = @tool_executor.build_command_line( arg_hash[:tool], + @flaginator.flag_down( OPERATION_LINK_SYM, context, executable ), arg_hash[:objects], arg_hash[:executable], arg_hash[:map], - @flaginator.flag_down( OPERATION_LINK_SYM, context, executable ) ) - + arg_hash[:libraries], + arg_hash[:libpaths] + ) + @streaminator.stdout_puts("Command: #{command}", Verbosity::DEBUG) + begin shell_result = @tool_executor.exec( command[:line], command[:options] ) rescue ShellExecutionException => ex @@ -120,13 +139,13 @@ def generate_executable_file(tool, context, objects, executable, map='') "NOTICE: If the linker reports missing symbols, the following may be to blame:\n" + " 1. Test lacks #include statements corresponding to needed source files.\n" + " 2. Project search paths do not contain source files corresponding to #include statements in the test.\n" - + if (@configurator.project_use_mocks) notice += " 3. Test does not #include needed mocks.\n\n" else notice += "\n" end - + @streaminator.stderr_puts(notice, Verbosity::COMPLAIN) shell_result = ex.shell_result raise '' @@ -139,26 +158,29 @@ def generate_executable_file(tool, context, objects, executable, map='') def generate_test_results(tool, context, executable, result) arg_hash = {:tool => tool, :context => context, :executable => executable, :result_file => result} @plugin_manager.pre_test_fixture_execute(arg_hash) - + @streaminator.stdout_puts("Running #{File.basename(arg_hash[:executable])}...", Verbosity::NORMAL) - + # Unity's exit code is equivalent to the number of failed tests, so we tell @tool_executor not to fail out if there are failures # so that we can run all tests and collect all results - command = @tool_executor.build_command_line(arg_hash[:tool], arg_hash[:executable]) + command = @tool_executor.build_command_line(arg_hash[:tool], [], arg_hash[:executable]) + @streaminator.stdout_puts("Command: #{command}", Verbosity::DEBUG) command[:options][:boom] = false shell_result = @tool_executor.exec( command[:line], command[:options] ) - + + #Don't Let The Failure Count Make Us Believe Things Aren't Working + shell_result[:exit_code] = 0 @generator_helper.test_results_error_handler(executable, shell_result) - + processed = @generator_test_results.process_and_write_results( shell_result, arg_hash[:result_file], @file_finder.find_test_from_file_path(arg_hash[:executable]) ) - + arg_hash[:result_file] = processed[:result_file] arg_hash[:results] = processed[:results] arg_hash[:shell_result] = shell_result # for raw output display if no plugins for formatted display - + @plugin_manager.post_test_fixture_execute(arg_hash) end - + end diff --git a/vendor/ceedling/lib/generator_helper.rb b/vendor/ceedling/lib/ceedling/generator_helper.rb similarity index 98% rename from vendor/ceedling/lib/generator_helper.rb rename to vendor/ceedling/lib/ceedling/generator_helper.rb index 481c226..3431560 100644 --- a/vendor/ceedling/lib/generator_helper.rb +++ b/vendor/ceedling/lib/ceedling/generator_helper.rb @@ -1,4 +1,4 @@ -require 'constants' +require 'ceedling/constants' class GeneratorHelper diff --git a/vendor/ceedling/lib/generator_test_results.rb b/vendor/ceedling/lib/ceedling/generator_test_results.rb similarity index 61% rename from vendor/ceedling/lib/generator_test_results.rb rename to vendor/ceedling/lib/ceedling/generator_test_results.rb index 71d63f2..3af2d72 100644 --- a/vendor/ceedling/lib/generator_test_results.rb +++ b/vendor/ceedling/lib/ceedling/generator_test_results.rb @@ -1,60 +1,61 @@ require 'rubygems' require 'rake' # for .ext() -require 'constants' +require 'ceedling/constants' - class GeneratorTestResults constructor :configurator, :generator_test_results_sanity_checker, :yaml_wrapper - + def process_and_write_results(unity_shell_result, results_file, test_file) - output_file = results_file - + output_file = results_file + results = get_results_structure - + results[:source][:path] = File.dirname(test_file) results[:source][:file] = File.basename(test_file) - + results[:time] = unity_shell_result[:time] unless unity_shell_result[:time].nil? + # process test statistics if (unity_shell_result[:output] =~ TEST_STDOUT_STATISTICS_PATTERN) - results[:counts][:total] = $1.to_i - results[:counts][:failed] = $2.to_i + results[:counts][:total] = $1.to_i + results[:counts][:failed] = $2.to_i results[:counts][:ignored] = $3.to_i - results[:counts][:passed] = (results[:counts][:total] - results[:counts][:failed] - results[:counts][:ignored]) + results[:counts][:passed] = (results[:counts][:total] - results[:counts][:failed] - results[:counts][:ignored]) end # remove test statistics lines output_string = unity_shell_result[:output].sub(TEST_STDOUT_STATISTICS_PATTERN, '') - - # bust up the output into individual lines - raw_unity_lines = output_string.split(/\n|\r\n/) - - raw_unity_lines.each do |line| + + output_string.lines do |line| # process unity output case line when /(:IGNORE)/ elements = extract_line_elements(line, results[:source][:file]) - results[:ignores] << elements[0] - results[:stdout] << elements[1] if (!elements[1].nil?) + results[:ignores] << elements[0] + results[:stdout] << elements[1] if (!elements[1].nil?) when /(:PASS$)/ elements = extract_line_elements(line, results[:source][:file]) results[:successes] << elements[0] - results[:stdout] << elements[1] if (!elements[1].nil?) + results[:stdout] << elements[1] if (!elements[1].nil?) + when /(:PASS \(.* ms\)$)/ + elements = extract_line_elements(line, results[:source][:file]) + results[:successes] << elements[0] + results[:stdout] << elements[1] if (!elements[1].nil?) when /(:FAIL)/ elements = extract_line_elements(line, results[:source][:file]) - results[:failures] << elements[0] - results[:stdout] << elements[1] if (!elements[1].nil?) + results[:failures] << elements[0] + results[:stdout] << elements[1] if (!elements[1].nil?) else # collect up all other results[:stdout] << line.chomp end end - + @generator_test_results_sanity_checker.verify(results, unity_shell_result[:exit_code]) - + output_file = results_file.ext(@configurator.extension_testfail) if (results[:counts][:failed] > 0) - + @yaml_wrapper.dump(output_file, results) - + return { :result_file => output_file, :result => results } end @@ -68,22 +69,32 @@ def get_results_structure :ignores => [], :counts => {:total => 0, :passed => 0, :failed => 0, :ignored => 0}, :stdout => [], + :time => 0.0 } end - + def extract_line_elements(line, filename) # handle anything preceding filename in line as extra output to be collected stdout = nil stdout_regex = /(.+)#{Regexp.escape(filename)}.+/i - + unity_test_time = 0 + if (line =~ stdout_regex) stdout = $1.clone line.sub!(/#{Regexp.escape(stdout)}/, '') end - + # collect up test results minus and extra output elements = (line.strip.split(':'))[1..-1] - return {:test => elements[1], :line => elements[0].to_i, :message => (elements[3..-1].join(':')).strip}, stdout + + # find timestamp if available + if (elements[-1] =~ / \((\d*(?:\.\d*)?) ms\)/) + unity_test_time = $1.to_f / 1000 + elements[-1].sub!(/ \((\d*(?:\.\d*)?) ms\)/, '') + end + + return {:test => elements[1], :line => elements[0].to_i, :message => (elements[3..-1].join(':')).strip, :unity_test_time => unity_test_time}, stdout if elements.size >= 3 + return {:test => '???', :line => -1, :message => nil, :unity_test_time => unity_test_time} #fallback safe option. TODO better handling end end diff --git a/vendor/ceedling/lib/generator_test_results_sanity_checker.rb b/vendor/ceedling/lib/ceedling/generator_test_results_sanity_checker.rb similarity index 70% rename from vendor/ceedling/lib/generator_test_results_sanity_checker.rb rename to vendor/ceedling/lib/ceedling/generator_test_results_sanity_checker.rb index 9f1b65c..0b51832 100644 --- a/vendor/ceedling/lib/generator_test_results_sanity_checker.rb +++ b/vendor/ceedling/lib/ceedling/generator_test_results_sanity_checker.rb @@ -1,6 +1,6 @@ -require 'constants' require 'rubygems' require 'rake' # for ext() method +require 'ceedling/constants' class GeneratorTestResultsSanityChecker @@ -11,8 +11,9 @@ def verify(results, unity_exit_code) # do no sanity checking if it's disabled return if (@configurator.sanity_checks == TestResultsSanityChecks::NONE) - - ceedling_ignores_count = results[:ignores].size + raise "results nil or empty" if results.nil? || results.empty? + + ceedling_ignores_count = results[:ignores].size ceedling_failures_count = results[:failures].size ceedling_tests_summation = (ceedling_ignores_count + ceedling_failures_count + results[:successes].size) @@ -46,17 +47,19 @@ def verify(results, unity_exit_code) private def sanity_check_warning(file, message) - notice = "\n" + - "ERROR: Internal sanity check for test fixture '#{file.ext(@configurator.extension_executable)}' finds that #{message}\n" + - " Possible causes:\n" + - " 1. Your test + source dereferenced a null pointer.\n" + - " 2. Your test + source indexed past the end of a buffer.\n" + - " 3. Your test + source committed a memory access violation.\n" + - " 4. Your test fixture produced an exit code of 0 despite execution ending prematurely.\n" + - " Sanity check failures of test results are usually a symptom of interrupted test execution.\n\n" - - @streaminator.stderr_puts( notice ) - raise + unless defined?(CEEDLING_IGNORE_SANITY_CHECK) + notice = "\n" + + "ERROR: Internal sanity check for test fixture '#{file.ext(@configurator.extension_executable)}' finds that #{message}\n" + + " Possible causes:\n" + + " 1. Your test + source dereferenced a null pointer.\n" + + " 2. Your test + source indexed past the end of a buffer.\n" + + " 3. Your test + source committed a memory access violation.\n" + + " 4. Your test fixture produced an exit code of 0 despite execution ending prematurely.\n" + + " Sanity check failures of test results are usually a symptom of interrupted test execution.\n\n" + + @streaminator.stderr_puts( notice ) + raise + end end end diff --git a/vendor/ceedling/lib/ceedling/generator_test_runner.rb b/vendor/ceedling/lib/ceedling/generator_test_runner.rb new file mode 100644 index 0000000..79ed714 --- /dev/null +++ b/vendor/ceedling/lib/ceedling/generator_test_runner.rb @@ -0,0 +1,58 @@ + +class GeneratorTestRunner + + constructor :configurator, :file_path_utils, :file_wrapper + + def find_test_cases(test_file) + + #Pull in Unity's Test Runner Generator + require 'generate_test_runner.rb' + @test_runner_generator ||= UnityTestRunnerGenerator.new( @configurator.get_runner_config ) + + if (@configurator.project_use_test_preprocessor) + + #redirect to use the preprocessor file if we're doing that sort of thing + pre_test_file = @file_path_utils.form_preprocessed_file_filepath(test_file) + + #actually look for the tests using Unity's test runner generator + contents = @file_wrapper.read(pre_test_file) + tests_and_line_numbers = @test_runner_generator.find_tests(contents) + @test_runner_generator.find_setup_and_teardown(contents) + + #look up the line numbers in the original file + source_lines = @file_wrapper.read(test_file).split("\n") + 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 + end + end + else + #Just look for the tests using Unity's test runner generator + contents = @file_wrapper.read(test_file) + tests_and_line_numbers = @test_runner_generator.find_tests(contents) + @test_runner_generator.find_setup_and_teardown(contents) + end + + return tests_and_line_numbers + end + + def generate(module_name, runner_filepath, test_cases, mock_list, test_file_includes=[]) + require 'generate_test_runner.rb' + + header_extension = @configurator.extension_header + + #actually build the test runner using Unity's test runner generator + #(there is no need to use preprocessor here because we've already looked up test cases and are passing them in here) + @test_runner_generator ||= UnityTestRunnerGenerator.new( @configurator.get_runner_config ) + @test_runner_generator.generate( module_name, + runner_filepath, + test_cases, + mock_list.map{|f| File.basename(f,'.*')+header_extension}, + test_file_includes.map{|f| File.basename(f,'.*')+header_extension}) + end +end diff --git a/vendor/ceedling/lib/loginator.rb b/vendor/ceedling/lib/ceedling/loginator.rb similarity index 100% rename from vendor/ceedling/lib/loginator.rb rename to vendor/ceedling/lib/ceedling/loginator.rb diff --git a/vendor/ceedling/lib/makefile.rb b/vendor/ceedling/lib/ceedling/makefile.rb similarity index 100% rename from vendor/ceedling/lib/makefile.rb rename to vendor/ceedling/lib/ceedling/makefile.rb diff --git a/vendor/ceedling/lib/objects.yml b/vendor/ceedling/lib/ceedling/objects.yml similarity index 88% rename from vendor/ceedling/lib/objects.yml rename to vendor/ceedling/lib/ceedling/objects.yml index a6f189b..43bbc06 100644 --- a/vendor/ceedling/lib/objects.yml +++ b/vendor/ceedling/lib/ceedling/objects.yml @@ -17,11 +17,11 @@ reportinator: rake_utils: compose: - - rake_wrapper + - rake_wrapper system_utils: compose: - - system_wrapper + - system_wrapper file_path_utils: compose: @@ -41,7 +41,9 @@ project_file_loader: project_config_manager: compose: - cacheinator + - configurator - yaml_wrapper + - file_wrapper cacheinator: compose: @@ -172,6 +174,7 @@ task_invoker: - dependinator - rake_utils - rake_wrapper + - project_config_manager flaginator: compose: @@ -200,13 +203,13 @@ generator_helper: generator_test_results: compose: - - configurator + - configurator - generator_test_results_sanity_checker - - yaml_wrapper + - yaml_wrapper generator_test_results_sanity_checker: compose: - - configurator + - configurator - streaminator generator_test_runner: @@ -220,43 +223,46 @@ dependinator: - configurator - project_config_manager - test_includes_extractor - - file_path_utils + - file_path_utils - rake_wrapper - file_wrapper preprocessinator: compose: - - preprocessinator_helper + - preprocessinator_helper - preprocessinator_includes_handler - preprocessinator_file_handler - - task_invoker + - task_invoker - file_path_utils - yaml_wrapper + - project_config_manager + - configurator preprocessinator_helper: - compose: - - configurator - - test_includes_extractor - - task_invoker - - file_finder - - file_path_utils + compose: + - configurator + - test_includes_extractor + - task_invoker + - file_finder + - file_path_utils preprocessinator_includes_handler: compose: - - configurator - - tool_executor - - task_invoker - - file_path_utils - - yaml_wrapper - - file_wrapper + - configurator + - tool_executor + - task_invoker + - file_path_utils + - yaml_wrapper + - file_wrapper + - file_finder preprocessinator_file_handler: compose: - preprocessinator_extractor - - configurator - - tool_executor + - configurator + - tool_executor - file_path_utils - - file_wrapper + - file_wrapper preprocessinator_extractor: diff --git a/vendor/ceedling/lib/par_map.rb b/vendor/ceedling/lib/ceedling/par_map.rb similarity index 100% rename from vendor/ceedling/lib/par_map.rb rename to vendor/ceedling/lib/ceedling/par_map.rb diff --git a/vendor/ceedling/lib/plugin.rb b/vendor/ceedling/lib/ceedling/plugin.rb similarity index 97% rename from vendor/ceedling/lib/plugin.rb rename to vendor/ceedling/lib/ceedling/plugin.rb index adce7ac..f20b3a3 100644 --- a/vendor/ceedling/lib/plugin.rb +++ b/vendor/ceedling/lib/ceedling/plugin.rb @@ -64,8 +64,8 @@ def pre_test_fixture_execute(arg_hash); end def post_test_fixture_execute(arg_hash); end # test task - def pre_test; end - def post_test; end + def pre_test(test); end + def post_test(test); end # release task def pre_release; end diff --git a/vendor/ceedling/lib/plugin_builder.rb b/vendor/ceedling/lib/ceedling/plugin_builder.rb similarity index 98% rename from vendor/ceedling/lib/plugin_builder.rb rename to vendor/ceedling/lib/ceedling/plugin_builder.rb index e86d321..1269141 100644 --- a/vendor/ceedling/lib/plugin_builder.rb +++ b/vendor/ceedling/lib/ceedling/plugin_builder.rb @@ -1,4 +1,4 @@ -require 'plugin' +require 'ceedling/plugin' class PluginBuilder diff --git a/vendor/ceedling/lib/plugin_manager.rb b/vendor/ceedling/lib/ceedling/plugin_manager.rb similarity index 90% rename from vendor/ceedling/lib/plugin_manager.rb rename to vendor/ceedling/lib/ceedling/plugin_manager.rb index 699e6b8..0468f2f 100644 --- a/vendor/ceedling/lib/plugin_manager.rb +++ b/vendor/ceedling/lib/ceedling/plugin_manager.rb @@ -1,5 +1,4 @@ -require 'constants' -require 'set' +require 'ceedling/constants' class PluginManager @@ -9,19 +8,19 @@ def setup @build_fail_registry = [] @plugin_objects = [] # so we can preserve order end - + def load_plugin_scripts(script_plugins, system_objects) environment = [] - + script_plugins.each do |plugin| # protect against instantiating object multiple times due to processing config multiple times (option files, etc) - next if (@plugin_manager_helper.include?(@plugin_objects, plugin)) + next if (@plugin_manager_helper.include?(@plugin_objects, plugin)) begin @system_wrapper.require_file( "#{plugin}.rb" ) object = @plugin_manager_helper.instantiate_plugin_script( camelize(plugin), system_objects, plugin ) @plugin_objects << object environment += object.environment - + # add plugins to hash of all system objects system_objects[plugin.downcase.to_sym] = object rescue @@ -29,28 +28,28 @@ def load_plugin_scripts(script_plugins, system_objects) raise end end - + yield( { :environment => environment } ) if (environment.size > 0) end - + def plugins_failed? return (@build_fail_registry.size > 0) end - + def print_plugin_failures if (@build_fail_registry.size > 0) report = @reportinator.generate_banner('BUILD FAILURE SUMMARY') - + @build_fail_registry.each do |failure| report += "#{' - ' if (@build_fail_registry.size > 1)}#{failure}\n" end - + report += "\n" - + @streaminator.stderr_puts(report, Verbosity::ERRORS) - end + end end - + def register_build_failure(message) @build_fail_registry << message if (message and not message.empty?) end @@ -76,19 +75,20 @@ def post_test_fixture_execute(arg_hash) execute_plugins(:post_test_fixture_execute, arg_hash) end - def pre_test; execute_plugins(:pre_test); end - def post_test; execute_plugins(:post_test); end + def pre_test(test); execute_plugins(:pre_test, test); end + def post_test(test); execute_plugins(:post_test, test); end def pre_release; execute_plugins(:pre_release); end def post_release; execute_plugins(:post_release); end - + def pre_build; execute_plugins(:pre_build); end def post_build; execute_plugins(:post_build); end - + def post_error; execute_plugins(:post_error); end + def summary; execute_plugins(:summary); end - + private #################################### - + def camelize(underscored_name) return underscored_name.gsub(/(_|^)([a-z0-9])/) {$2.upcase} end @@ -96,7 +96,7 @@ def camelize(underscored_name) def execute_plugins(method, *args) @plugin_objects.each do |plugin| begin - plugin.send(method, *args) + plugin.send(method, *args) if plugin.respond_to?(method) rescue puts "Exception raised in plugin: #{plugin.name}, in method #{method}" raise diff --git a/vendor/ceedling/lib/plugin_manager_helper.rb b/vendor/ceedling/lib/ceedling/plugin_manager_helper.rb similarity index 100% rename from vendor/ceedling/lib/plugin_manager_helper.rb rename to vendor/ceedling/lib/ceedling/plugin_manager_helper.rb diff --git a/vendor/ceedling/lib/plugin_reportinator.rb b/vendor/ceedling/lib/ceedling/plugin_reportinator.rb similarity index 94% rename from vendor/ceedling/lib/plugin_reportinator.rb rename to vendor/ceedling/lib/ceedling/plugin_reportinator.rb index b08801a..8d83727 100644 --- a/vendor/ceedling/lib/plugin_reportinator.rb +++ b/vendor/ceedling/lib/ceedling/plugin_reportinator.rb @@ -1,5 +1,5 @@ -require 'constants' -require 'defaults' +require 'ceedling/constants' +require 'ceedling/defaults' class PluginReportinator @@ -68,8 +68,9 @@ def get_results_structure :failures => [], :ignores => [], :stdout => [], - :counts => {:total => 0, :passed => 0, :failed => 0, :ignored => 0, :stdout => 0} + :counts => {:total => 0, :passed => 0, :failed => 0, :ignored => 0, :stdout => 0}, + :time => 0.0 } end -end \ No newline at end of file +end diff --git a/vendor/ceedling/lib/plugin_reportinator_helper.rb b/vendor/ceedling/lib/ceedling/plugin_reportinator_helper.rb similarity index 96% rename from vendor/ceedling/lib/plugin_reportinator_helper.rb rename to vendor/ceedling/lib/ceedling/plugin_reportinator_helper.rb index c30a833..322a530 100644 --- a/vendor/ceedling/lib/plugin_reportinator_helper.rb +++ b/vendor/ceedling/lib/ceedling/plugin_reportinator_helper.rb @@ -1,8 +1,7 @@ -require 'constants' require 'erb' require 'rubygems' require 'rake' # for ext() - +require 'ceedling/constants' class PluginReportinatorHelper @@ -31,7 +30,6 @@ def fetch_results(results_path, options) def process_results(aggregate_results, results) return if (results.empty?) - aggregate_results[:successes] << { :source => results[:source].clone, :collection => results[:successes].clone } if (results[:successes].size > 0) aggregate_results[:failures] << { :source => results[:source].clone, :collection => results[:failures].clone } if (results[:failures].size > 0) aggregate_results[:ignores] << { :source => results[:source].clone, :collection => results[:ignores].clone } if (results[:ignores].size > 0) @@ -41,6 +39,7 @@ def process_results(aggregate_results, results) aggregate_results[:counts][:failed] += results[:counts][:failed] aggregate_results[:counts][:ignored] += results[:counts][:ignored] aggregate_results[:counts][:stdout] += results[:stdout].size + aggregate_results[:time] += results[:time] end @@ -49,4 +48,4 @@ def run_report(stream, template, hash, verbosity) @streaminator.stream_puts(stream, output.result(binding()), verbosity) end -end \ No newline at end of file +end diff --git a/vendor/ceedling/lib/ceedling/preprocessinator.rb b/vendor/ceedling/lib/ceedling/preprocessinator.rb new file mode 100644 index 0000000..52d82ca --- /dev/null +++ b/vendor/ceedling/lib/ceedling/preprocessinator.rb @@ -0,0 +1,56 @@ + +class Preprocessinator + + constructor :preprocessinator_helper, :preprocessinator_includes_handler, :preprocessinator_file_handler, :task_invoker, :file_path_utils, :yaml_wrapper, :project_config_manager, :configurator + + + def setup + # fashion ourselves callbacks @preprocessinator_helper can use + @preprocess_includes_proc = Proc.new { |filepath| self.preprocess_shallow_includes(filepath) } + @preprocess_mock_file_proc = Proc.new { |filepath| self.preprocess_file(filepath) } + @preprocess_test_file_directives_proc = Proc.new { |filepath| self.preprocess_file_directives(filepath) } + @preprocess_test_file_proc = Proc.new { |filepath| self.preprocess_file(filepath) } + end + + def preprocess_shallow_source_includes(test) + @preprocessinator_helper.preprocess_source_includes(test) + end + + def preprocess_test_and_invoke_test_mocks(test) + @preprocessinator_helper.preprocess_includes(test, @preprocess_includes_proc) + + mocks_list = @preprocessinator_helper.assemble_mocks_list(test) + + @project_config_manager.process_test_defines_change(mocks_list) + + @preprocessinator_helper.preprocess_mockable_headers(mocks_list, @preprocess_mock_file_proc) + + @task_invoker.invoke_test_mocks(mocks_list) + + if (@configurator.project_use_preprocessor_directives) + @preprocessinator_helper.preprocess_test_file(test, @preprocess_test_file_directives_proc) + else + @preprocessinator_helper.preprocess_test_file(test, @preprocess_test_file_proc) + end + + return mocks_list + end + + def preprocess_shallow_includes(filepath) + includes = @preprocessinator_includes_handler.extract_includes(filepath) + + @preprocessinator_includes_handler.write_shallow_includes_list( + @file_path_utils.form_preprocessed_includes_list_filepath(filepath), includes) + end + + def preprocess_file(filepath) + @preprocessinator_includes_handler.invoke_shallow_includes_list(filepath) + @preprocessinator_file_handler.preprocess_file( filepath, @yaml_wrapper.load(@file_path_utils.form_preprocessed_includes_list_filepath(filepath)) ) + end + + def preprocess_file_directives(filepath) + @preprocessinator_includes_handler.invoke_shallow_includes_list( filepath ) + @preprocessinator_file_handler.preprocess_file_directives( filepath, + @yaml_wrapper.load( @file_path_utils.form_preprocessed_includes_list_filepath( filepath ) ) ) + end +end diff --git a/vendor/ceedling/lib/preprocessinator_extractor.rb b/vendor/ceedling/lib/ceedling/preprocessinator_extractor.rb similarity index 52% rename from vendor/ceedling/lib/preprocessinator_extractor.rb rename to vendor/ceedling/lib/ceedling/preprocessinator_extractor.rb index fd53a91..62026e1 100644 --- a/vendor/ceedling/lib/preprocessinator_extractor.rb +++ b/vendor/ceedling/lib/ceedling/preprocessinator_extractor.rb @@ -16,13 +16,38 @@ def extract_base_file_from_preprocessed_expansion(filepath) lines = [] File.readlines(filepath).each do |line| - if found_file and not line.match(not_pragma) + line.encode!('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '') + if found_file and not line =~ not_pragma lines << line else found_file = false end - found_file = true if line.match(pattern) + found_file = true if line =~ pattern + end + + return lines + end + + def extract_base_file_from_preprocessed_directives(filepath) + # preprocessing by way of toolchain preprocessor eliminates directives only + # like #ifdef's and leave other code + + # iterate through all lines and only get last chunk of file after a last + # '#'line containing file name of our filepath + + base_name = File.basename(filepath) + pattern = /^#.*(\s|\/|\\|\")#{Regexp.escape(base_name)}/ + found_file = false # have we found the file we care about? + + lines = [] + File.readlines(filepath).each do |line| + line.encode!('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '') + lines << line + + if line =~ pattern + lines = [] + end end return lines diff --git a/vendor/ceedling/lib/ceedling/preprocessinator_file_handler.rb b/vendor/ceedling/lib/ceedling/preprocessinator_file_handler.rb new file mode 100644 index 0000000..978fa0d --- /dev/null +++ b/vendor/ceedling/lib/ceedling/preprocessinator_file_handler.rb @@ -0,0 +1,34 @@ + + +class PreprocessinatorFileHandler + + constructor :preprocessinator_extractor, :configurator, :tool_executor, :file_path_utils, :file_wrapper + + + def preprocess_file(filepath, includes) + preprocessed_filepath = @file_path_utils.form_preprocessed_file_filepath(filepath) + + command = @tool_executor.build_command_line(@configurator.tools_test_file_preprocessor, [], filepath, preprocessed_filepath) + @tool_executor.exec(command[:line], command[:options]) + + contents = @preprocessinator_extractor.extract_base_file_from_preprocessed_expansion(preprocessed_filepath) + + includes.each{|include| contents.unshift("#include \"#{include}\"")} + + @file_wrapper.write(preprocessed_filepath, contents.join("\n")) + end + + def preprocess_file_directives(filepath, includes) + preprocessed_filepath = @file_path_utils.form_preprocessed_file_filepath(filepath) + + command = @tool_executor.build_command_line(@configurator.tools_test_file_preprocessor_directives, [], filepath, preprocessed_filepath) + @tool_executor.exec(command[:line], command[:options]) + + contents = @preprocessinator_extractor.extract_base_file_from_preprocessed_directives(preprocessed_filepath) + + includes.each{|include| contents.unshift("#include \"#{include}\"")} + + @file_wrapper.write(preprocessed_filepath, contents.join("\n")) + end + +end diff --git a/vendor/ceedling/lib/preprocessinator_helper.rb b/vendor/ceedling/lib/ceedling/preprocessinator_helper.rb similarity index 89% rename from vendor/ceedling/lib/preprocessinator_helper.rb rename to vendor/ceedling/lib/ceedling/preprocessinator_helper.rb index 174f86d..4bbda67 100644 --- a/vendor/ceedling/lib/preprocessinator_helper.rb +++ b/vendor/ceedling/lib/ceedling/preprocessinator_helper.rb @@ -1,7 +1,7 @@ class PreprocessinatorHelper - + constructor :configurator, :test_includes_extractor, :task_invoker, :file_finder, :file_path_utils @@ -11,8 +11,12 @@ def preprocess_includes(test, preprocess_includes_proc) preprocess_includes_proc.call( @file_finder.find_test_from_file_path(preprocessed_includes_list) ) @test_includes_extractor.parse_includes_list(preprocessed_includes_list) else - @test_includes_extractor.parse_test_file(test) - end + @test_includes_extractor.parse_test_file(test) + end + end + + def preprocess_source_includes(test) + @test_includes_extractor.parse_test_file_source_include(test) end def assemble_mocks_list(test) @@ -29,10 +33,10 @@ def preprocess_mockable_headers(mock_list, preprocess_file_proc) def preprocess_test_file(test, preprocess_file_proc) return if (!@configurator.project_use_test_preprocessor) - + preprocess_file_proc.call(test) end - + private ############################ def preprocess_files_smartly(file_list, preprocess_file_proc) diff --git a/vendor/ceedling/lib/ceedling/preprocessinator_includes_handler.rb b/vendor/ceedling/lib/ceedling/preprocessinator_includes_handler.rb new file mode 100644 index 0000000..8b89c0b --- /dev/null +++ b/vendor/ceedling/lib/ceedling/preprocessinator_includes_handler.rb @@ -0,0 +1,189 @@ + + +class PreprocessinatorIncludesHandler + + constructor :configurator, :tool_executor, :task_invoker, :file_path_utils, :yaml_wrapper, :file_wrapper, :file_finder + @@makefile_cache = {} + + # shallow includes: only those headers a source file explicitly includes + + def invoke_shallow_includes_list(filepath) + @task_invoker.invoke_test_shallow_include_lists( [@file_path_utils.form_preprocessed_includes_list_filepath(filepath)] ) + end + + ## + # Ask the preprocessor for a make-style dependency rule of only the headers + # the source file immediately includes. + # + # === Arguments + # +filepath+ _String_:: Path to the test file to process. + # + # === Return + # _String_:: The text of the dependency rule generated by the preprocessor. + def form_shallow_dependencies_rule(filepath) + if @@makefile_cache.has_key?(filepath) + return @@makefile_cache[filepath] + end + # change filename (prefix of '_') to prevent preprocessor from finding + # include files in temp directory containing file it's scanning + temp_filepath = @file_path_utils.form_temp_path(filepath, '_') + + # read the file and replace all include statements with a decorated version + # (decorating the names creates file names that don't exist, thus preventing + # the preprocessor from snaking out and discovering the entire include path + # that winds through the code). The decorated filenames indicate files that + # are included directly by the test file. + contents = @file_wrapper.read(filepath) + + if !contents.valid_encoding? + contents = contents.encode("UTF-16be", :invalid=>:replace, :replace=>"?").encode('UTF-8') + end + + contents.gsub!( /^\s*#include\s+[\"<]\s*(\S+)\s*[\">]/, "#include \"\\1\"\n#include \"@@@@\\1\"" ) + contents.gsub!( /^\s*TEST_FILE\(\s*\"\s*(\S+)\s*\"\s*\)/, "#include \"\\1\"\n#include \"@@@@\\1\"") + @file_wrapper.write( temp_filepath, contents ) + + # extract the make-style dependency rule telling the preprocessor to + # ignore the fact that it can't find the included files + command = @tool_executor.build_command_line(@configurator.tools_test_includes_preprocessor, [], temp_filepath) + shell_result = @tool_executor.exec(command[:line], command[:options]) + + @@makefile_cache[filepath] = shell_result[:output] + return shell_result[:output] + end + + ## + # Extract the headers that are directly included by a source file using the + # provided, annotated Make dependency rule. + # + # === Arguments + # +filepath+ _String_:: C source or header file to extract includes for. + # + # === Return + # _Array_ of _String_:: Array of the direct dependencies for the source file. + def extract_includes(filepath) + to_process = [filepath] + ignore_list = [] + list = [] + all_mocks = [] + + include_paths = @configurator.project_config_hash[:collection_paths_include] + include_paths = [] if include_paths.nil? + include_paths.map! {|path| File.expand_path(path)} + + while to_process.length > 0 + target = to_process.shift() + ignore_list << target + new_deps, new_to_process, all_mocks = extract_includes_helper(target, include_paths, ignore_list, all_mocks) + list += new_deps + to_process += new_to_process + if !@configurator.project_config_hash[:project_auto_link_deep_dependencies] + break + else + list = list.uniq() + to_process = to_process.uniq() + end + end + + return list + end + + def extract_includes_helper(filepath, include_paths, ignore_list, mocks) + # Extract the dependencies from the make rule + make_rule = self.form_shallow_dependencies_rule(filepath) + target_file = make_rule.split[0].gsub(':', '').gsub('\\','/') + base = File.basename(target_file, File.extname(target_file)) + make_rule_dependencies = make_rule.gsub(/.*\b#{Regexp.escape(base)}\S*/, '').gsub(/\\$/, '') + + # Extract the headers dependencies from the make rule + hdr_ext = @configurator.extension_header + headers_dependencies = make_rule_dependencies.split.find_all {|path| path.end_with?(hdr_ext) }.uniq + headers_dependencies.map! {|hdr| hdr.gsub('\\','/') } + full_path_headers_dependencies = extract_full_path_dependencies(headers_dependencies) + + # Extract the sources dependencies from the make rule + src_ext = @configurator.extension_source + sources_dependencies = make_rule_dependencies.split.find_all {|path| path.end_with?(src_ext) }.uniq + sources_dependencies.map! {|src| src.gsub('\\','/') } + full_path_sources_dependencies = extract_full_path_dependencies(sources_dependencies) + + list = full_path_headers_dependencies + full_path_sources_dependencies + + mock_prefix = @configurator.project_config_hash[:cmock_mock_prefix] + # Creating list of mocks + mocks += full_path_headers_dependencies.find_all do |header| + File.basename(header) =~ /^#{mock_prefix}.*$/ + end.compact + + # ignore real file when both mock and real file exist + mocks.each do |mock| + list.each do |filename| + if File.basename(filename) == File.basename(mock).sub(mock_prefix, '') + ignore_list << filename + end + end + end.compact + + # Filtering list of final includes to only include mocks and anything that is NOT in the ignore_list + list = list.select do |item| + mocks.include? item or !(ignore_list.any? { |ignore_item| !item.match(/^(.*\/)?#{Regexp.escape(ignore_item)}$/).nil? }) + end + + to_process = [] + + if @configurator.project_config_hash[:project_auto_link_deep_dependencies] + # Creating list of headers that should be recursively pre-processed + # Skipping mocks and vendor headers + headers_to_deep_link = full_path_headers_dependencies.select do |hdr| + !(mocks.include? hdr) and (hdr.match(/^(.*\/)(#{VENDORS_FILES.join('|')}) + #{Regexp.escape(hdr_ext)}$/).nil?) + end + headers_to_deep_link.map! {|hdr| File.expand_path(hdr) } + headers_to_deep_link.compact! + + headers_to_deep_link.each do |hdr| + if (ignore_list.none? {|ignore_header| hdr.match(/^(.*\/)?#{Regexp.escape(ignore_header)}$/)} and + include_paths.none? {|include_path| hdr =~ /^#{include_path}\.*/}) + if File.exist?(hdr) + to_process << hdr + src = @file_finder.find_compilation_input_file(hdr, :ignore) + to_process << src if src + end + end + end + end + + return list, to_process, mocks + + end + + def write_shallow_includes_list(filepath, list) + @yaml_wrapper.dump(filepath, list) + end + + private + + def extract_full_path_dependencies(dependencies) + # Separate the real files form the annotated ones and remove the '@@@@' + annotated_files, real_files = dependencies.partition {|file| file =~ /^@@@@/} + annotated_files.map! {|file| file.gsub('@@@@','') } + # Matching annotated_files values against real_files to ensure that + # annotated_files contain full path entries (as returned by make rule) + annotated_files.map! {|file| real_files.find {|real| !real.match(/^(.*\/)?#{Regexp.escape(file)}$/).nil?}} + annotated_files = annotated_files.compact + + # Find which of our annotated files are "real" dependencies. This is + # intended to weed out dependencies that have been removed due to build + # options defined in the project yaml and/or in the files themselves. + return annotated_files.find_all do |annotated_file| + # find the index of the "real" file that matches the annotated one. + idx = real_files.find_index do |real_file| + real_file =~ /^(.*\/)?#{Regexp.escape(annotated_file)}$/ + end + # If we found a real file, delete it from the array and return it, + # otherwise return nil. Since nil is falsy this has the effect of making + # find_all return only the annotated filess for which a real file was + # found/deleted + idx ? real_files.delete_at(idx) : nil + end.compact + end +end diff --git a/vendor/ceedling/lib/ceedling/project_config_manager.rb b/vendor/ceedling/lib/ceedling/project_config_manager.rb new file mode 100644 index 0000000..ed7a73b --- /dev/null +++ b/vendor/ceedling/lib/ceedling/project_config_manager.rb @@ -0,0 +1,52 @@ +require 'ceedling/constants' + + +class ProjectConfigManager + + attr_reader :options_files, :release_config_changed, :test_config_changed, :test_defines_changed + attr_accessor :config_hash + + constructor :cacheinator, :configurator, :yaml_wrapper, :file_wrapper + + + def setup + @options_files = [] + @release_config_changed = false + @test_config_changed = false + @test_defines_changed = false + end + + + def merge_options(config_hash, option_filepath) + @options_files << File.basename( option_filepath ) + config_hash.deep_merge!( @yaml_wrapper.load( option_filepath ) ) + end + + + def filter_internal_sources(sources) + filtered_sources = sources.clone + filtered_sources.delete_if { |item| item =~ /#{CMOCK_MOCK_PREFIX}.+#{Regexp.escape(EXTENSION_SOURCE)}$/ } + filtered_sources.delete_if { |item| item =~ /#{VENDORS_FILES.map{|source| '\b' + Regexp.escape(source.ext(EXTENSION_SOURCE)) + '\b'}.join('|')}$/ } + return filtered_sources + end + + def process_release_config_change + # has project configuration changed since last release build + @release_config_changed = @cacheinator.diff_cached_release_config?( @config_hash ) + end + + + def process_test_config_change + # has project configuration changed since last test build + @test_config_changed = @cacheinator.diff_cached_test_config?( @config_hash ) + end + + def process_test_defines_change(files) + # has definitions changed since last test build + @test_defines_changed = @cacheinator.diff_cached_test_defines?( files ) + if @test_defines_changed + # update timestamp for rake task prerequisites + @file_wrapper.touch( @configurator.project_test_force_rebuild_filepath, :mtime => Time.now + 10 ) + end + end +end diff --git a/vendor/ceedling/lib/project_file_loader.rb b/vendor/ceedling/lib/ceedling/project_file_loader.rb similarity index 55% rename from vendor/ceedling/lib/project_file_loader.rb rename to vendor/ceedling/lib/ceedling/project_file_loader.rb index b0ef8c5..bf5dcd4 100644 --- a/vendor/ceedling/lib/project_file_loader.rb +++ b/vendor/ceedling/lib/ceedling/project_file_loader.rb @@ -1,4 +1,4 @@ -require 'constants' +require 'ceedling/constants' class ProjectFileLoader @@ -9,9 +9,11 @@ class ProjectFileLoader def setup @main_file = nil + @mixin_files = [] @user_file = nil - + @main_project_filepath = '' + @mixin_project_filepaths = [] @user_project_filepath = '' end @@ -19,17 +21,27 @@ def setup def find_project_files # first go hunting for optional user project file by looking for environment variable and then default location on disk user_filepath = @system_wrapper.env_get('CEEDLING_USER_PROJECT_FILE') - + if ( not user_filepath.nil? and @file_wrapper.exist?(user_filepath) ) @user_project_filepath = user_filepath elsif (@file_wrapper.exist?(DEFAULT_CEEDLING_USER_PROJECT_FILE)) @user_project_filepath = DEFAULT_CEEDLING_USER_PROJECT_FILE end - + + # next check for mixin project files by looking for environment variable + mixin_filepaths = @system_wrapper.env_get('CEEDLING_MIXIN_PROJECT_FILES') + if ( not mixin_filepaths.nil? ) + mixin_filepaths.split(File::PATH_SEPARATOR).each do |filepath| + if ( @file_wrapper.exist?(filepath) ) + @mixin_project_filepaths.push(filepath) + end + end + end + # next check for main project file by looking for environment variable and then default location on disk; # blow up if we don't find this guy -- like, he's so totally important main_filepath = @system_wrapper.env_get('CEEDLING_MAIN_PROJECT_FILE') - + if ( not main_filepath.nil? and @file_wrapper.exist?(main_filepath) ) @main_project_filepath = main_filepath elsif (@file_wrapper.exist?(DEFAULT_CEEDLING_MAIN_PROJECT_FILE)) @@ -40,25 +52,48 @@ def find_project_files @stream_wrapper.stderr_puts('Found no Ceedling project file (*.yml)') raise end - + @main_file = File.basename( @main_project_filepath ) + @mixin_project_filepaths.each do |filepath| + @mixin_files.push(File.basename( filepath )) + end @user_file = File.basename( @user_project_filepath ) if ( not @user_project_filepath.empty? ) end + def yaml_merger(y1, y2) + o1 = y1 + y2.each_pair do |k,v| + if o1[k].nil? + o1[k] = v + else + if (o1[k].instance_of? Hash) + o1[k] = yaml_merger(o1[k], v) + elsif (o1[k].instance_of? Array) + o1[k] += v + else + o1[k] = v + end + end + end + return o1 + end def load_project_config - config_hash = {} - - # if there's no user project file, then just provide hash from project file - if (@user_project_filepath.empty?) - config_hash = @yaml_wrapper.load(@main_project_filepath) - # if there is a user project file, load it too and merge it on top of the project file, - # superseding anything that's common between them - else - config_hash = (@yaml_wrapper.load(@main_project_filepath)).merge(@yaml_wrapper.load(@user_project_filepath)) + config_hash = @yaml_wrapper.load(@main_project_filepath) + + # if there are mixin project files, then use them + @mixin_project_filepaths.each do |filepath| + mixin = @yaml_wrapper.load(filepath) + config_hash = yaml_merger( config_hash, mixin ) end - + + # if there's a user project file, then use it + if ( not @user_project_filepath.empty? ) + user_hash = @yaml_wrapper.load(@user_project_filepath) + config_hash = yaml_merger( config_hash, user_hash ) + end + return config_hash end - + end diff --git a/vendor/ceedling/lib/rake_utils.rb b/vendor/ceedling/lib/ceedling/rake_utils.rb similarity index 100% rename from vendor/ceedling/lib/rake_utils.rb rename to vendor/ceedling/lib/ceedling/rake_utils.rb diff --git a/vendor/ceedling/lib/rake_wrapper.rb b/vendor/ceedling/lib/ceedling/rake_wrapper.rb similarity index 86% rename from vendor/ceedling/lib/rake_wrapper.rb rename to vendor/ceedling/lib/ceedling/rake_wrapper.rb index 3469365..15e4796 100644 --- a/vendor/ceedling/lib/rake_wrapper.rb +++ b/vendor/ceedling/lib/ceedling/rake_wrapper.rb @@ -1,6 +1,6 @@ require 'rubygems' require 'rake' -require 'makefile' # our replacement for rake's make-style dependency loader +require 'ceedling/makefile' # our replacement for rake's make-style dependency loader include Rake::DSL if defined?(Rake::DSL) diff --git a/vendor/ceedling/lib/rakefile.rb b/vendor/ceedling/lib/ceedling/rakefile.rb similarity index 65% rename from vendor/ceedling/lib/rakefile.rb rename to vendor/ceedling/lib/ceedling/rakefile.rb index 153c0bd..1bcb824 100644 --- a/vendor/ceedling/lib/rakefile.rb +++ b/vendor/ceedling/lib/ceedling/rakefile.rb @@ -1,7 +1,7 @@ require 'fileutils' # get directory containing this here file, back up one directory, and expand to full path -CEEDLING_ROOT = File.expand_path(File.dirname(__FILE__) + '/..') +CEEDLING_ROOT = File.expand_path(File.dirname(__FILE__) + '/../..') CEEDLING_LIB = File.join(CEEDLING_ROOT, 'lib') CEEDLING_VENDOR = File.join(CEEDLING_ROOT, 'vendor') CEEDLING_RELEASE = File.join(CEEDLING_ROOT, 'release') @@ -9,23 +9,28 @@ $LOAD_PATH.unshift( CEEDLING_LIB ) $LOAD_PATH.unshift( File.join(CEEDLING_VENDOR, 'unity/auto') ) $LOAD_PATH.unshift( File.join(CEEDLING_VENDOR, 'diy/lib') ) -$LOAD_PATH.unshift( File.join(CEEDLING_VENDOR, 'constructor/lib') ) $LOAD_PATH.unshift( File.join(CEEDLING_VENDOR, 'cmock/lib') ) -$LOAD_PATH.unshift( File.join(CEEDLING_VENDOR, 'deep_merge/lib') ) require 'rake' +#Let's make sure we remember the task descriptions in case we need them +Rake::TaskManager.record_task_metadata = true + require 'diy' require 'constructor' -require 'constants' -require 'target_loader' +require 'ceedling/constants' +require 'ceedling/target_loader' # construct all our objects -@ceedling = DIY::Context.from_yaml( File.read( File.join(CEEDLING_LIB, 'objects.yml') ) ) +# ensure load path contains all libraries needed first +lib_ceedling_load_path_temp = File.join(CEEDLING_LIB, 'ceedling') +$LOAD_PATH.unshift( lib_ceedling_load_path_temp ) +@ceedling = DIY::Context.from_yaml( File.read( File.join(lib_ceedling_load_path_temp, 'objects.yml') ) ) @ceedling.build_everything - +# now that all objects are built, delete 'lib/ceedling' from load path +$LOAD_PATH.delete(lib_ceedling_load_path_temp) # one-stop shopping for all our setup and such after construction @ceedling[:setupinator].ceedling = @ceedling @@ -54,6 +59,9 @@ # end block always executed following rake run END { + $stdout.flush unless $stdout.nil? + $stderr.flush unless $stderr.nil? + # cache our input configurations to use in comparison upon next execution @ceedling[:cacheinator].cache_test_config( @ceedling[:setupinator].config_hash ) if (@ceedling[:task_invoker].test_invoked?) @ceedling[:cacheinator].cache_release_config( @ceedling[:setupinator].config_hash ) if (@ceedling[:task_invoker].release_invoked?) @@ -63,12 +71,15 @@ @ceedling[:file_wrapper].rm_f( @ceedling[:file_wrapper].directory_listing( File.join(@ceedling[:configurator].project_temp_path, '*') )) end - # only perform these final steps if we got here without runtime exceptions or errors - if (@ceedling[:system_wrapper].ruby_success) + # only perform these final steps if we got here without runtime exceptions or errors + if (@ceedling[:system_wrapper].ruby_success) # tell all our plugins the build is done and process results - @ceedling[:plugin_manager].post_build - @ceedling[:plugin_manager].print_plugin_failures - exit(1) if (@ceedling[:plugin_manager].plugins_failed?) - end + @ceedling[:plugin_manager].post_build + @ceedling[:plugin_manager].print_plugin_failures + exit(1) if (@ceedling[:plugin_manager].plugins_failed? && !@ceedling[:setupinator].config_hash[:graceful_fail]) + else + puts "ERROR: Ceedling Failed" + @ceedling[:plugin_manager].post_error + end } diff --git a/vendor/ceedling/lib/ceedling/release_invoker.rb b/vendor/ceedling/lib/ceedling/release_invoker.rb new file mode 100644 index 0000000..19bbca7 --- /dev/null +++ b/vendor/ceedling/lib/ceedling/release_invoker.rb @@ -0,0 +1,98 @@ +require 'ceedling/constants' + + +class ReleaseInvoker + + constructor :configurator, :release_invoker_helper, :build_invoker_utils, :dependinator, :task_invoker, :file_path_utils, :file_wrapper + + + def setup_and_invoke_c_objects( c_files ) + objects = @file_path_utils.form_release_build_c_objects_filelist( c_files ) + + begin + @release_invoker_helper.process_deep_dependencies( @file_path_utils.form_release_dependencies_filelist( c_files ) ) + + @dependinator.enhance_release_file_dependencies( objects ) + @task_invoker.invoke_release_objects( objects ) + rescue => e + @build_invoker_utils.process_exception( e, RELEASE_SYM, false ) + end + + return objects + end + + + def setup_and_invoke_asm_objects( asm_files ) + objects = @file_path_utils.form_release_build_asm_objects_filelist( asm_files ) + + begin + @dependinator.enhance_release_file_dependencies( objects ) + @task_invoker.invoke_release_objects( objects ) + rescue => e + @build_invoker_utils.process_exception( e, RELEASE_SYM, false ) + end + + return objects + end + + + def refresh_c_deep_dependencies + return if (not @configurator.project_use_deep_dependencies) + + @file_wrapper.rm_f( + @file_wrapper.directory_listing( + File.join( @configurator.project_release_dependencies_path, '*' + @configurator.extension_dependencies ) ) ) + + @release_invoker_helper.process_deep_dependencies( + @file_path_utils.form_release_dependencies_filelist( + @configurator.collection_all_source ) ) + end + + + def artifactinate( *files ) + files.flatten.each do |file| + @file_wrapper.cp( file, @configurator.project_release_artifacts_path ) if @file_wrapper.exist?( file ) + end + end + + def convert_libraries_to_arguments(libraries) + args = ((libraries || []) + ((defined? LIBRARIES_SYSTEM) ? LIBRARIES_SYSTEM : [])).flatten + if (defined? LIBRARIES_FLAG) + args.map! {|v| LIBRARIES_FLAG.gsub(/\$\{1\}/, v) } + end + return args + end + + def get_library_paths_to_arguments() + paths = (defined? PATHS_LIBRARIES) ? (PATHS_LIBRARIES || []).clone : [] + if (defined? LIBRARIES_PATH_FLAG) + paths.map! {|v| LIBRARIES_PATH_FLAG.gsub(/\$\{1\}/, v) } + end + return paths + end + + def sort_objects_and_libraries(both) + extension = if ((defined? EXTENSION_SUBPROJECTS) && (defined? EXTENSION_LIBRARIES)) + extension_libraries = if (EXTENSION_LIBRARIES.class == Array) + EXTENSION_LIBRARIES.join(")|(?:\\") + else + EXTENSION_LIBRARIES + end + "(?:\\#{EXTENSION_SUBPROJECTS})|(?:\\#{extension_libraries})" + elsif (defined? EXTENSION_SUBPROJECTS) + "\\#{EXTENSION_SUBPROJECTS}" + elsif (defined? EXTENSION_LIBRARIES) + if (EXTENSION_LIBRARIES.class == Array) + "(?:\\#{EXTENSION_LIBRARIES.join(")|(?:\\")})" + else + "\\#{EXTENSION_LIBRARIES}" + end + else + "\\.LIBRARY" + end + sorted_objects = both.group_by {|v| v.match(/.+#{extension}$/) ? :libraries : :objects } + libraries = sorted_objects[:libraries] || [] + objects = sorted_objects[:objects] || [] + return objects, libraries + end +end diff --git a/vendor/ceedling/lib/release_invoker_helper.rb b/vendor/ceedling/lib/ceedling/release_invoker_helper.rb similarity index 57% rename from vendor/ceedling/lib/release_invoker_helper.rb rename to vendor/ceedling/lib/ceedling/release_invoker_helper.rb index 8257aab..f83a2a5 100644 --- a/vendor/ceedling/lib/release_invoker_helper.rb +++ b/vendor/ceedling/lib/ceedling/release_invoker_helper.rb @@ -8,8 +8,11 @@ class ReleaseInvokerHelper def process_deep_dependencies(dependencies_list) return if (not @configurator.project_use_deep_dependencies) - @dependinator.enhance_release_file_dependencies( dependencies_list ) - @task_invoker.invoke_release_dependencies_files( dependencies_list ) + if @configurator.project_generate_deep_dependencies + @dependinator.enhance_release_file_dependencies( dependencies_list ) + @task_invoker.invoke_release_dependencies_files( dependencies_list ) + end + @dependinator.load_release_object_deep_dependencies( dependencies_list ) end diff --git a/vendor/ceedling/lib/ceedling/reportinator.rb b/vendor/ceedling/lib/ceedling/reportinator.rb new file mode 100644 index 0000000..0f583d0 --- /dev/null +++ b/vendor/ceedling/lib/ceedling/reportinator.rb @@ -0,0 +1,26 @@ +## +# Pretifies reports +class Reportinator + + ## + # Generates a banner for a message based on the length of the message or a + # given width. + # ==== Attributes + # + # * _message_: The message to put. + # * _width_: The width of the message. If nil the size of the banner is + # determined by the length of the message. + # + # ==== Examples + # + # rp = Reportinator.new + # rp.generate_banner("Hello world!") => "------------\nHello world!\n------------\n" + # rp.generate_banner("Hello world!", 3) => "---\nHello world!\n---\n" + # + # + def generate_banner(message, width=nil) + dash_count = ((width.nil?) ? message.strip.length : width) + return "#{'-' * dash_count}\n#{message}\n#{'-' * dash_count}\n" + end + +end diff --git a/vendor/ceedling/lib/rules_cmock.rake b/vendor/ceedling/lib/ceedling/rules_cmock.rake similarity index 74% rename from vendor/ceedling/lib/rules_cmock.rake rename to vendor/ceedling/lib/ceedling/rules_cmock.rake index 1e2da05..70ddcbc 100644 --- a/vendor/ceedling/lib/rules_cmock.rake +++ b/vendor/ceedling/lib/ceedling/rules_cmock.rake @@ -1,6 +1,6 @@ -rule(/#{CMOCK_MOCK_PREFIX}.+#{'\\'+EXTENSION_SOURCE}$/ => [ +rule(/#{CMOCK_MOCK_PREFIX}[^\/\\]+#{'\\'+EXTENSION_SOURCE}$/ => [ proc do |task_name| @ceedling[:file_finder].find_header_input_for_mock_file(task_name) end diff --git a/vendor/ceedling/lib/rules_preprocess.rake b/vendor/ceedling/lib/ceedling/rules_preprocess.rake similarity index 100% rename from vendor/ceedling/lib/rules_preprocess.rake rename to vendor/ceedling/lib/ceedling/rules_preprocess.rake diff --git a/vendor/ceedling/lib/rules_release.rake b/vendor/ceedling/lib/ceedling/rules_release.rake similarity index 59% rename from vendor/ceedling/lib/rules_release.rake rename to vendor/ceedling/lib/ceedling/rules_release.rake index 00326ab..4a583bd 100644 --- a/vendor/ceedling/lib/rules_release.rake +++ b/vendor/ceedling/lib/ceedling/rules_release.rake @@ -1,16 +1,28 @@ -RELEASE_COMPILE_TASK_ROOT = RELEASE_TASK_ROOT + 'compile:' -RELEASE_ASSEMBLE_TASK_ROOT = RELEASE_TASK_ROOT + 'assemble:' +RELEASE_COMPILE_TASK_ROOT = RELEASE_TASK_ROOT + 'compile:' unless defined?(RELEASE_COMPILE_TASK_ROOT) +RELEASE_ASSEMBLE_TASK_ROOT = RELEASE_TASK_ROOT + 'assemble:' unless defined?(RELEASE_ASSEMBLE_TASK_ROOT) +# If GCC and Releasing a Library, Update Tools to Automatically Have Necessary Tags +if (TOOLS_RELEASE_COMPILER[:executable] == DEFAULT_RELEASE_COMPILER_TOOL[:executable]) + if (File.extname(PROJECT_RELEASE_BUILD_TARGET) == '.so') + TOOLS_RELEASE_COMPILER[:arguments] << "-fPIC" unless TOOLS_RELEASE_COMPILER[:arguments].include?("-fPIC") + TOOLS_RELEASE_LINKER[:arguments] << "-shared" unless TOOLS_RELEASE_LINKER[:arguments].include?("-shared") + elsif (File.extname(PROJECT_RELEASE_BUILD_TARGET) == '.a') + TOOLS_RELEASE_COMPILER[:arguments] << "-fPIC" unless TOOLS_RELEASE_COMPILER[:arguments].include?("-fPIC") + TOOLS_RELEASE_LINKER[:executable] = 'ar' + TOOLS_RELEASE_LINKER[:arguments] = ['rcs', '${2}', '${1}'].compact + end +end if (RELEASE_BUILD_USE_ASSEMBLY) rule(/#{PROJECT_RELEASE_BUILD_OUTPUT_ASM_PATH}\/#{'.+\\'+EXTENSION_OBJECT}$/ => [ proc do |task_name| @ceedling[:file_finder].find_assembly_file(task_name) - end + end ]) do |object| @ceedling[:generator].generate_object_file( TOOLS_RELEASE_ASSEMBLER, + OPERATION_ASSEMBLE_SYM, RELEASE_SYM, object.source, object.name ) @@ -20,26 +32,34 @@ end rule(/#{PROJECT_RELEASE_BUILD_OUTPUT_C_PATH}\/#{'.+\\'+EXTENSION_OBJECT}$/ => [ proc do |task_name| - @ceedling[:file_finder].find_compilation_input_file(task_name) - end + @ceedling[:file_finder].find_compilation_input_file(task_name, :error, true) + end ]) do |object| @ceedling[:generator].generate_object_file( TOOLS_RELEASE_COMPILER, + OPERATION_COMPILE_SYM, RELEASE_SYM, object.source, object.name, - @ceedling[:file_path_utils].form_release_build_c_list_filepath( object.name ) ) + @ceedling[:file_path_utils].form_release_build_c_list_filepath( object.name ), + @ceedling[:file_path_utils].form_release_dependencies_filepath( object.name ) ) end rule(/#{PROJECT_RELEASE_BUILD_TARGET}/) do |bin_file| - map_file = @ceedling[:configurator].project_release_build_map + objects, libraries = @ceedling[:release_invoker].sort_objects_and_libraries(bin_file.prerequisites) + tool = TOOLS_RELEASE_LINKER.clone + lib_args = @ceedling[:release_invoker].convert_libraries_to_arguments(libraries) + lib_paths = @ceedling[:release_invoker].get_library_paths_to_arguments() + map_file = @ceedling[:configurator].project_release_build_map @ceedling[:generator].generate_executable_file( - TOOLS_RELEASE_LINKER, + tool, RELEASE_SYM, - bin_file.prerequisites, + objects, bin_file.name, - map_file ) + map_file, + lib_args, + lib_paths ) @ceedling[:release_invoker].artifactinate( bin_file.name, map_file, @ceedling[:configurator].release_build_artifacts ) end @@ -59,7 +79,7 @@ namespace RELEASE_SYM do @ceedling[:release_invoker].setup_and_invoke_c_objects( [compile.source] ) end end - + if (RELEASE_BUILD_USE_ASSEMBLY) namespace :assemble do rule(/^#{RELEASE_ASSEMBLE_TASK_ROOT}\S+#{'\\'+EXTENSION_ASSEMBLY}$/ => [ # assemble task names by regex diff --git a/vendor/ceedling/lib/rules_release_deep_dependencies.rake b/vendor/ceedling/lib/ceedling/rules_release_deep_dependencies.rake similarity index 95% rename from vendor/ceedling/lib/rules_release_deep_dependencies.rake rename to vendor/ceedling/lib/ceedling/rules_release_deep_dependencies.rake index dd8fb84..9550783 100644 --- a/vendor/ceedling/lib/rules_release_deep_dependencies.rake +++ b/vendor/ceedling/lib/ceedling/rules_release_deep_dependencies.rake @@ -2,7 +2,7 @@ rule(/#{PROJECT_RELEASE_DEPENDENCIES_PATH}\/#{'.+\\'+EXTENSION_DEPENDENCIES}$/ => [ proc do |task_name| - @ceedling[:file_finder].find_compilation_input_file(task_name) + @ceedling[:file_finder].find_compilation_input_file(task_name, :error, true) end ]) do |dep| @ceedling[:generator].generate_dependencies_file( diff --git a/vendor/ceedling/lib/rules_tests.rake b/vendor/ceedling/lib/ceedling/rules_tests.rake similarity index 63% rename from vendor/ceedling/lib/rules_tests.rake rename to vendor/ceedling/lib/ceedling/rules_tests.rake index 3cc1a3d..61e15e2 100644 --- a/vendor/ceedling/lib/rules_tests.rake +++ b/vendor/ceedling/lib/ceedling/rules_tests.rake @@ -8,28 +8,42 @@ rule(/#{PROJECT_TEST_FILE_PREFIX}#{'.+'+TEST_RUNNER_FILE_SUFFIX}#{'\\'+EXTENSION @ceedling[:generator].generate_test_runner(TEST_SYM, runner.source, runner.name) end - -rule(/#{PROJECT_TEST_BUILD_OUTPUT_PATH}\/#{'.+\\'+EXTENSION_OBJECT}$/ => [ +rule(/#{PROJECT_TEST_BUILD_OUTPUT_C_PATH}\/#{'.+\\'+EXTENSION_OBJECT}$/ => [ proc do |task_name| @ceedling[:file_finder].find_compilation_input_file(task_name) end ]) do |object| - @ceedling[:generator].generate_object_file( - TOOLS_TEST_COMPILER, - TEST_SYM, - object.source, - object.name, - @ceedling[:file_path_utils].form_test_build_list_filepath( object.name ) ) + if (File.basename(object.source) =~ /#{EXTENSION_SOURCE}$/) + @ceedling[:generator].generate_object_file( + TOOLS_TEST_COMPILER, + OPERATION_COMPILE_SYM, + TEST_SYM, + object.source, + object.name, + @ceedling[:file_path_utils].form_test_build_list_filepath( object.name ), + @ceedling[:file_path_utils].form_test_dependencies_filepath( object.name )) + elsif (defined?(TEST_BUILD_USE_ASSEMBLY) && TEST_BUILD_USE_ASSEMBLY) + @ceedling[:generator].generate_object_file( + TOOLS_TEST_ASSEMBLER, + OPERATION_ASSEMBLE_SYM, + TEST_SYM, + object.source, + object.name ) + end end rule(/#{PROJECT_TEST_BUILD_OUTPUT_PATH}\/#{'.+\\'+EXTENSION_EXECUTABLE}$/) do |bin_file| + lib_args = @ceedling[:test_invoker].convert_libraries_to_arguments() + lib_paths = @ceedling[:test_invoker].get_library_paths_to_arguments() @ceedling[:generator].generate_executable_file( TOOLS_TEST_LINKER, TEST_SYM, bin_file.prerequisites, bin_file.name, - @ceedling[:file_path_utils].form_test_build_map_filepath( bin_file.name ) ) + @ceedling[:file_path_utils].form_test_build_map_filepath( bin_file.name ), + lib_args, + lib_paths ) end @@ -44,7 +58,7 @@ end namespace TEST_SYM do # use rules to increase efficiency for large projects (instead of iterating through all sources and creating defined tasks) - + rule(/^#{TEST_TASK_ROOT}\S+$/ => [ # test task names by regex proc do |task_name| test = task_name.sub(/#{TEST_TASK_ROOT}/, '') @@ -52,7 +66,7 @@ namespace TEST_SYM do @ceedling[:file_finder].find_test_from_file_path(test) end ]) do |test| - @ceedling[:rake_wrapper][:directories].invoke + @ceedling[:rake_wrapper][:test_deps].invoke @ceedling[:test_invoker].setup_and_invoke([test.source]) end end diff --git a/vendor/ceedling/lib/rules_tests_deep_dependencies.rake b/vendor/ceedling/lib/ceedling/rules_tests_deep_dependencies.rake similarity index 79% rename from vendor/ceedling/lib/rules_tests_deep_dependencies.rake rename to vendor/ceedling/lib/ceedling/rules_tests_deep_dependencies.rake index d282b43..7175ee3 100644 --- a/vendor/ceedling/lib/rules_tests_deep_dependencies.rake +++ b/vendor/ceedling/lib/ceedling/rules_tests_deep_dependencies.rake @@ -3,13 +3,13 @@ rule(/#{PROJECT_TEST_DEPENDENCIES_PATH}\/#{'.+\\'+EXTENSION_DEPENDENCIES}$/ => [ proc do |task_name| @ceedling[:file_finder].find_compilation_input_file(task_name) - end + end ]) do |dep| @ceedling[:generator].generate_dependencies_file( TOOLS_TEST_DEPENDENCIES_GENERATOR, TEST_SYM, dep.source, - @ceedling[:file_path_utils].form_test_build_object_filepath(dep.source), + @ceedling[:file_path_utils].form_test_build_c_object_filepath(dep.source), dep.name) end diff --git a/vendor/ceedling/lib/setupinator.rb b/vendor/ceedling/lib/ceedling/setupinator.rb similarity index 94% rename from vendor/ceedling/lib/setupinator.rb rename to vendor/ceedling/lib/ceedling/setupinator.rb index 14e31aa..ea78fd9 100644 --- a/vendor/ceedling/lib/setupinator.rb +++ b/vendor/ceedling/lib/ceedling/setupinator.rb @@ -21,10 +21,12 @@ def do_setup(config_hash) # note: configurator modifies the cmock section of the hash with a couple defaults to tie # project together - the modified hash is used to build cmock object @ceedling[:configurator].populate_defaults( config_hash ) + @ceedling[:configurator].populate_unity_defaults( config_hash ) @ceedling[:configurator].populate_cmock_defaults( config_hash ) @ceedling[:configurator].find_and_merge_plugins( config_hash ) - @ceedling[:configurator].tools_setup( config_hash ) + @ceedling[:configurator].merge_imports( config_hash ) @ceedling[:configurator].eval_environment_variables( config_hash ) + @ceedling[:configurator].tools_setup( config_hash ) @ceedling[:configurator].eval_paths( config_hash ) @ceedling[:configurator].standardize_paths( config_hash ) @ceedling[:configurator].validate( config_hash ) diff --git a/vendor/ceedling/lib/stream_wrapper.rb b/vendor/ceedling/lib/ceedling/stream_wrapper.rb similarity index 54% rename from vendor/ceedling/lib/stream_wrapper.rb rename to vendor/ceedling/lib/ceedling/stream_wrapper.rb index 33d3c10..7e16052 100644 --- a/vendor/ceedling/lib/stream_wrapper.rb +++ b/vendor/ceedling/lib/ceedling/stream_wrapper.rb @@ -1,8 +1,16 @@ class StreamWrapper + def stdout_override(&fnc) + @stdout_overide_fnc = fnc + end + def stdout_puts(string) - $stdout.puts(string) + if @stdout_overide_fnc + @stdout_overide_fnc.call(string) + else + $stdout.puts(string) + end end def stdout_flush diff --git a/vendor/ceedling/lib/streaminator.rb b/vendor/ceedling/lib/ceedling/streaminator.rb similarity index 97% rename from vendor/ceedling/lib/streaminator.rb rename to vendor/ceedling/lib/ceedling/streaminator.rb index abbc9b8..b8dcd07 100644 --- a/vendor/ceedling/lib/streaminator.rb +++ b/vendor/ceedling/lib/ceedling/streaminator.rb @@ -1,8 +1,7 @@ +require 'ceedling/constants' class Streaminator - require 'constants' - constructor :streaminator_helper, :verbosinator, :loginator, :stream_wrapper # for those objects for whom the configurator has already been instantiated, diff --git a/vendor/ceedling/lib/streaminator_helper.rb b/vendor/ceedling/lib/ceedling/streaminator_helper.rb similarity index 100% rename from vendor/ceedling/lib/streaminator_helper.rb rename to vendor/ceedling/lib/ceedling/streaminator_helper.rb diff --git a/vendor/ceedling/lib/system_utils.rb b/vendor/ceedling/lib/ceedling/system_utils.rb similarity index 80% rename from vendor/ceedling/lib/system_utils.rb rename to vendor/ceedling/lib/ceedling/system_utils.rb index cb5216b..477aba4 100644 --- a/vendor/ceedling/lib/system_utils.rb +++ b/vendor/ceedling/lib/ceedling/system_utils.rb @@ -6,14 +6,20 @@ def deep_clone end +## +# Class containing system utility funcions. class SystemUtils constructor :system_wrapper + ## + # Sets up the class. def setup @tcsh_shell = nil end + ## + # Checks the system shell to see if it a tcsh shell. def tcsh_shell? # once run a single time, return state determined at that execution return @tcsh_shell if not @tcsh_shell.nil? @@ -28,5 +34,4 @@ def tcsh_shell? return @tcsh_shell end - end diff --git a/vendor/ceedling/lib/system_wrapper.rb b/vendor/ceedling/lib/ceedling/system_wrapper.rb similarity index 71% rename from vendor/ceedling/lib/system_wrapper.rb rename to vendor/ceedling/lib/ceedling/system_wrapper.rb index 1cccba2..2b0f1ed 100644 --- a/vendor/ceedling/lib/system_wrapper.rb +++ b/vendor/ceedling/lib/ceedling/system_wrapper.rb @@ -12,7 +12,7 @@ def self.windows? def windows? return SystemWrapper.windows? end - + def module_eval(string) return Object.module_eval("\"" + string + "\"") end @@ -32,7 +32,7 @@ def cmdline_args def env_set(name, value) ENV[name] = value end - + def env_get(name) return ENV[name] end @@ -41,36 +41,40 @@ def time_now return Time.now.asctime end - def shell_backticks(command) + def shell_backticks(command, boom = true) + retval = `#{command}`.freeze + $exit_code = ($?.exitstatus).freeze if boom return { - :output => `#{command}`.freeze, + :output => retval.freeze, :exit_code => ($?.exitstatus).freeze } end - def shell_system(command) + def shell_system(command, boom = true) system( command ) + $exit_code = ($?.exitstatus).freeze if boom return { - :output => ''.freeze, + :output => "".freeze, :exit_code => ($?.exitstatus).freeze } end - + def add_load_path(path) $LOAD_PATH.unshift(path) end - + def require_file(path) require(path) end def ruby_success - return ($!.nil? || $!.is_a?(SystemExit) && $!.success?) + # We are successful if we've never had an exit code that went boom (either because it's empty or it was 0) + return ($exit_code.nil? || ($exit_code == 0)) && ($!.nil? || $!.is_a?(SystemExit) && $!.success?) end def constants_include?(item) # forcing to strings provides consistency across Ruby versions return Object.constants.map{|constant| constant.to_s}.include?(item.to_s) end - + end diff --git a/vendor/ceedling/lib/target_loader.rb b/vendor/ceedling/lib/ceedling/target_loader.rb similarity index 87% rename from vendor/ceedling/lib/target_loader.rb rename to vendor/ceedling/lib/ceedling/target_loader.rb index 0402dc3..7fbc095 100644 --- a/vendor/ceedling/lib/target_loader.rb +++ b/vendor/ceedling/lib/ceedling/target_loader.rb @@ -13,10 +13,10 @@ def self.inspect(config, target_name=nil) targets = config[:targets] unless targets[:targets_directory] - raise NoDirectory("No targets directory specified.") + raise NoDirectory.new("No targets directory specified.") end unless targets[:default_target] - raise NoDefault("No default target specified.") + raise NoDefault.new("No default target specified.") end target_path = lambda {|name| File.join(targets[:targets_directory], name + ".yml")} diff --git a/vendor/ceedling/lib/task_invoker.rb b/vendor/ceedling/lib/ceedling/task_invoker.rb similarity index 53% rename from vendor/ceedling/lib/task_invoker.rb rename to vendor/ceedling/lib/ceedling/task_invoker.rb index c69f2a6..7bfabbb 100644 --- a/vendor/ceedling/lib/task_invoker.rb +++ b/vendor/ceedling/lib/ceedling/task_invoker.rb @@ -1,12 +1,15 @@ -require "par_map" +require 'ceedling/par_map' class TaskInvoker - constructor :dependinator, :rake_utils, :rake_wrapper + attr_accessor :first_run + + constructor :dependinator, :rake_utils, :rake_wrapper, :project_config_manager def setup @test_regexs = [/^#{TEST_ROOT_NAME}:/] @release_regexs = [/^#{RELEASE_ROOT_NAME}(:|$)/] + @first_run = true end def add_test_task_regex(regex) @@ -43,30 +46,60 @@ def invoked?(regex) return @rake_utils.task_invoked?(regex) end - + def reset_rake_task_for_changed_defines(file) + if !(file =~ /#{VENDORS_FILES.map{|ignore| '\b' + ignore.ext(File.extname(file)) + '\b'}.join('|')}$/) + @rake_wrapper[file].clear_actions if @first_run == false && @project_config_manager.test_defines_changed + @rake_wrapper[file].reenable if @first_run == false && @project_config_manager.test_defines_changed + end + end + def invoke_test_mocks(mocks) @dependinator.enhance_mock_dependencies( mocks ) - mocks.each { |mock| @rake_wrapper[mock].invoke } + mocks.each { |mock| + reset_rake_task_for_changed_defines( mock ) + @rake_wrapper[mock].invoke + } end def invoke_test_runner(runner) @dependinator.enhance_runner_dependencies( runner ) + reset_rake_task_for_changed_defines( runner ) @rake_wrapper[runner].invoke end def invoke_test_shallow_include_lists(files) @dependinator.enhance_shallow_include_lists_dependencies( files ) - files.each { |file| @rake_wrapper[file].invoke } + par_map(PROJECT_COMPILE_THREADS, files) do |file| + reset_rake_task_for_changed_defines( file ) + @rake_wrapper[file].invoke + end end def invoke_test_preprocessed_files(files) @dependinator.enhance_preprocesed_file_dependencies( files ) - files.each { |file| @rake_wrapper[file].invoke } + par_map(PROJECT_COMPILE_THREADS, files) do |file| + reset_rake_task_for_changed_defines( file ) + @rake_wrapper[file].invoke + end end def invoke_test_dependencies_files(files) @dependinator.enhance_dependencies_dependencies( files ) - files.each { |file| @rake_wrapper[file].invoke } + par_map(PROJECT_COMPILE_THREADS, files) do |file| + reset_rake_task_for_changed_defines( file ) + @rake_wrapper[file].invoke + end + end + + def invoke_test_objects(objects) + par_map(PROJECT_COMPILE_THREADS, objects) do |object| + reset_rake_task_for_changed_defines( object ) + @rake_wrapper[object].invoke + end + end + + def invoke_test_executable(file) + @rake_wrapper[file].invoke end def invoke_test_results(result) @@ -76,13 +109,13 @@ def invoke_test_results(result) def invoke_release_dependencies_files(files) par_map(PROJECT_COMPILE_THREADS, files) do |file| - @rake_wrapper[file].invoke + @rake_wrapper[file].invoke end end def invoke_release_objects(objects) par_map(PROJECT_COMPILE_THREADS, objects) do |object| - @rake_wrapper[object].invoke + @rake_wrapper[object].invoke end end diff --git a/vendor/ceedling/lib/tasks_base.rake b/vendor/ceedling/lib/ceedling/tasks_base.rake similarity index 56% rename from vendor/ceedling/lib/tasks_base.rake rename to vendor/ceedling/lib/ceedling/tasks_base.rake index e87174e..a35cde7 100644 --- a/vendor/ceedling/lib/tasks_base.rake +++ b/vendor/ceedling/lib/ceedling/tasks_base.rake @@ -1,38 +1,26 @@ -require 'constants' -require 'file_path_utils' - +require 'ceedling/constants' +require 'ceedling/file_path_utils' +require 'ceedling/version' desc "Display build environment version info." task :version do - tools = [ - [' Ceedling', CEEDLING_ROOT], - ['CException', File.join( CEEDLING_VENDOR, CEXCEPTION_ROOT_PATH)], - [' CMock', File.join( CEEDLING_VENDOR, CMOCK_ROOT_PATH)], - [' Unity', File.join( CEEDLING_VENDOR, UNITY_ROOT_PATH)], - ] - - tools.each do |tool| - name = tool[0] - base_path = tool[1] - - version_string = @ceedling[:file_wrapper].read( File.join(base_path, 'release', 'version.info') ).strip - build_string = @ceedling[:file_wrapper].read( File.join(base_path, 'release', 'build.info') ).strip - puts "#{name}:: #{version_string.empty? ? '#.#.' : (version_string + '.')}#{build_string.empty? ? '?' : build_string}" - end + puts " Ceedling:: #{Ceedling::Version::CEEDLING}" + puts " Unity:: #{Ceedling::Version::UNITY}" + puts " CMock:: #{Ceedling::Version::CMOCK}" + puts " CException:: #{Ceedling::Version::CEXCEPTION}" end - desc "Set verbose output (silent:[#{Verbosity::SILENT}] - obnoxious:[#{Verbosity::OBNOXIOUS}])." task :verbosity, :level do |t, args| verbosity_level = args.level.to_i - + if (PROJECT_USE_MOCKS) # don't store verbosity level in setupinator's config hash, use a copy; # otherwise, the input configuration will change and trigger entire project rebuilds hash = @ceedling[:setupinator].config_hash[:cmock].clone hash[:verbosity] = verbosity_level - @ceedling[:cmock_builder].manufacture( hash ) + @ceedling[:cmock_builder].manufacture( hash ) end @ceedling[:configurator].project_verbosity = verbosity_level @@ -41,13 +29,11 @@ task :verbosity, :level do |t, args| verbose( ((verbosity_level >= Verbosity::OBNOXIOUS) ? true : false) ) end - desc "Enable logging" task :logging do @ceedling[:configurator].project_logging = true end - # non advertised debug task task :debug do Rake::Task[:verbosity].invoke(Verbosity::DEBUG) @@ -55,41 +41,67 @@ task :debug do @ceedling[:configurator].project_debug = true end - # non advertised sanity checking task task :sanity_checks, :level do |t, args| check_level = args.level.to_i @ceedling[:configurator].sanity_checks = check_level end +# non advertised catch for calling upgrade in the wrong place +task :upgrade do + puts "WARNING: You're currently IN your project directory. Take a step out and try" + puts "again if you'd like to perform an upgrade." +end # list expanded environment variables if (not ENVIRONMENT.empty?) desc "List all configured environment variables." task :environment do + env_list = [] ENVIRONMENT.each do |env| env.each_key do |key| name = key.to_s.upcase - puts " - #{name}: \"#{env[key]}\"" + env_list.push(" - #{name}: \"#{env[key]}\"") end - end + end + env_list.sort.each do |env_line| + puts env_line + end end end - namespace :options do COLLECTION_PROJECT_OPTIONS.each do |option_path| option = File.basename(option_path, '.yml') desc "Merge #{option} project options." - task option.downcase.to_sym do - # @ceedling[:setupinator].reset_defaults( @ceedling[:setupinator].config_hash ) + task option.to_sym do hash = @ceedling[:project_config_manager].merge_options( @ceedling[:setupinator].config_hash, option_path ) @ceedling[:setupinator].do_setup( hash ) + if @ceedling[:configurator].project_release_build + load(File.join(CEEDLING_LIB, 'ceedling', 'rules_release.rake')) + end end end + # This is to give nice errors when typing options + rule /^options:.*/ do |t, args| + filename = t.to_s.split(':')[-1] + '.yml' + filelist = COLLECTION_PROJECT_OPTIONS.map{|s| File.basename(s) } + @ceedling[:file_finder].find_file_from_list(filename, filelist, :error) + end + + # This will output the fully-merged tools options to their own project.yml file + desc "Export tools options to a new project file" + task :export, :filename do |t, args| + outfile = args.filename || 'tools.yml' + toolcfg = {} + @ceedling[:configurator].project_config_hash.each_pair do |k,v| + toolcfg[k] = v if (k.to_s[0..5] == 'tools_') + end + File.open(outfile,'w') {|f| f << toolcfg.to_yaml({:indentation => 2})} + end end diff --git a/vendor/ceedling/lib/tasks_filesystem.rake b/vendor/ceedling/lib/ceedling/tasks_filesystem.rake similarity index 61% rename from vendor/ceedling/lib/tasks_filesystem.rake rename to vendor/ceedling/lib/ceedling/tasks_filesystem.rake index f8048e6..7b950ca 100644 --- a/vendor/ceedling/lib/tasks_filesystem.rake +++ b/vendor/ceedling/lib/ceedling/tasks_filesystem.rake @@ -18,6 +18,9 @@ CLOBBER.include(File.join(PROJECT_BUILD_RELEASE_ROOT, '**/*')) CLOBBER.include(File.join(PROJECT_LOG_PATH, '**/*')) CLOBBER.include(File.join(PROJECT_TEMP_PATH, '**/*')) +# just in case they're using git, let's make sure we allow them to preserved the build directory if desired. +CLOBBER.exclude(File.join(TESTS_BASE_PATH), '**/.gitkeep') + # because of cmock config, mock path can optionally exist apart from standard test build paths CLOBBER.include(File.join(CMOCK_MOCK_PATH, '*')) @@ -30,54 +33,73 @@ task(:clean) do if (not @ceedling[:task_invoker].invoked?(/^clobber$/)) @ceedling[:streaminator].stdout_puts("\nCleaning build artifacts...\n(For large projects, this task may take a long time to complete)\n\n") end - CLEAN.each { |fn| REMOVE_FILE_PROC.call(fn) } + begin + CLEAN.each { |fn| REMOVE_FILE_PROC.call(fn) } + rescue + end end # redefine clobber so we can override how it advertises itself desc "Delete all generated files (and build artifacts)." task(:clobber => [:clean]) do @ceedling[:streaminator].stdout_puts("\nClobbering all generated files...\n(For large projects, this task may take a long time to complete)\n\n") - CLOBBER.each { |fn| REMOVE_FILE_PROC.call(fn) } + begin + CLOBBER.each { |fn| REMOVE_FILE_PROC.call(fn) } + @ceedling[:rake_wrapper][:directories].invoke + @ceedling[:dependinator].touch_force_rebuild_files + rescue + end end - +# create a directory task for each of the paths, so we know how to build them PROJECT_BUILD_PATHS.each { |path| directory(path) } -# create directories that hold build output and generated files & touching rebuild dependency sources -task(:directories => PROJECT_BUILD_PATHS) { @ceedling[:dependinator].touch_force_rebuild_files } +# create a single directory task which verifies all the others get built +task :directories => PROJECT_BUILD_PATHS +# when the force file doesn't exist, it probably means we clobbered or are on a fresh +# install. In either case, stuff was deleted, so assume we want to rebuild it all +file @ceedling[:configurator].project_test_force_rebuild_filepath do + unless File.exists?(@ceedling[:configurator].project_test_force_rebuild_filepath) + @ceedling[:dependinator].touch_force_rebuild_files + end +end # list paths discovered at load time namespace :paths do - - paths = @ceedling[:setupinator].config_hash[:paths] - paths.each_key do |section| - name = section.to_s.downcase + standard_paths = ['test','source','include'] + paths = @ceedling[:setupinator].config_hash[:paths].keys.map{|n| n.to_s.downcase} + paths = (paths + standard_paths).uniq + paths.each do |name| path_list = Object.const_get("COLLECTION_PATHS_#{name.upcase}") - - if (path_list.size != 0) + + if (path_list.size != 0) || (standard_paths.include?(name)) desc "List all collected #{name} paths." task(name.to_sym) { puts "#{name} paths:"; path_list.sort.each {|path| puts " - #{path}" } } end end - + end # list files & file counts discovered at load time namespace :files do - + categories = [ - ['test', COLLECTION_ALL_TESTS], - ['source', COLLECTION_ALL_SOURCE], - ['header', COLLECTION_ALL_HEADERS] - ] - categories << ['assembly', COLLECTION_ALL_ASSEMBLY] if (RELEASE_BUILD_USE_ASSEMBLY) - + ['test', COLLECTION_ALL_TESTS], + ['source', COLLECTION_ALL_SOURCE], + ['include', COLLECTION_ALL_HEADERS], + ['support', COLLECTION_ALL_SUPPORT] + ] + + using_assembly = (defined?(TEST_BUILD_USE_ASSEMBLY) && TEST_BUILD_USE_ASSEMBLY) || + (defined?(RELEASE_BUILD_USE_ASSEMBLY) && RELEASE_BUILD_USE_ASSEMBLY) + categories << ['assembly', COLLECTION_ALL_ASSEMBLY] if using_assembly + categories.each do |category| name = category[0] collection = category[1] - + desc "List all collected #{name} files." task(name.to_sym) do puts "#{name} files:" @@ -85,7 +107,7 @@ namespace :files do puts "file count: #{collection.size}" end end - + end diff --git a/vendor/ceedling/lib/tasks_release.rake b/vendor/ceedling/lib/ceedling/tasks_release.rake similarity index 77% rename from vendor/ceedling/lib/tasks_release.rake rename to vendor/ceedling/lib/ceedling/tasks_release.rake index c0e0ef1..b313b2f 100644 --- a/vendor/ceedling/lib/tasks_release.rake +++ b/vendor/ceedling/lib/ceedling/tasks_release.rake @@ -1,5 +1,5 @@ -require 'constants' -require 'file_path_utils' +require 'ceedling/constants' +require 'ceedling/file_path_utils' desc "Build release target." @@ -19,7 +19,9 @@ task RELEASE_SYM => [:directories] do # if assembler use isn't enabled, COLLECTION_ALL_ASSEMBLY is empty array & nothing happens core_objects.concat( @ceedling[:release_invoker].setup_and_invoke_asm_objects( COLLECTION_ALL_ASSEMBLY ) ) - file( PROJECT_RELEASE_BUILD_TARGET => (core_objects + extra_objects) ) + # if we're using libraries, we need to add those to our collection as well + library_objects = (defined? LIBRARIES_RELEASE && !LIBRARIES_RELEASE.empty?) ? LIBRARIES_RELEASE.flatten.compact : [] + file( PROJECT_RELEASE_BUILD_TARGET => (core_objects + extra_objects + library_objects) ) Rake::Task[PROJECT_RELEASE_BUILD_TARGET].invoke ensure @ceedling[:plugin_manager].post_release diff --git a/vendor/ceedling/lib/tasks_release_deep_dependencies.rake b/vendor/ceedling/lib/ceedling/tasks_release_deep_dependencies.rake similarity index 80% rename from vendor/ceedling/lib/tasks_release_deep_dependencies.rake rename to vendor/ceedling/lib/ceedling/tasks_release_deep_dependencies.rake index 01faded..db2be5f 100644 --- a/vendor/ceedling/lib/tasks_release_deep_dependencies.rake +++ b/vendor/ceedling/lib/ceedling/tasks_release_deep_dependencies.rake @@ -1,4 +1,4 @@ -require 'constants' +require 'ceedling/constants' namespace REFRESH_SYM do diff --git a/vendor/ceedling/lib/tasks_tests.rake b/vendor/ceedling/lib/ceedling/tasks_tests.rake similarity index 72% rename from vendor/ceedling/lib/tasks_tests.rake rename to vendor/ceedling/lib/ceedling/tasks_tests.rake index a6b8414..6c51ebc 100644 --- a/vendor/ceedling/lib/tasks_tests.rake +++ b/vendor/ceedling/lib/ceedling/tasks_tests.rake @@ -1,10 +1,15 @@ -require 'constants' +require 'ceedling/constants' +task :test_deps => [:directories] + +task :test => [:test_deps] do + Rake.application['test:all'].invoke +end namespace TEST_SYM do - - desc "Run all unit tests." - task :all => [:directories] do + + desc "Run all unit tests (also just 'test' works)." + task :all => [:test_deps] do @ceedling[:test_invoker].setup_and_invoke(COLLECTION_ALL_TESTS) end @@ -13,21 +18,26 @@ namespace TEST_SYM do message = "\nOops! '#{TEST_ROOT_NAME}:*' isn't a real task. " + "Use a real test or source file name (no path) in place of the wildcard.\n" + "Example: rake #{TEST_ROOT_NAME}:foo.c\n\n" - + @ceedling[:streaminator].stdout_puts( message ) end - + desc "Run tests for changed files." - task :delta => [:directories] do + task :delta => [:test_deps] do @ceedling[:test_invoker].setup_and_invoke(COLLECTION_ALL_TESTS, TEST_SYM, {:force_run => false}) end - + + desc "Just build tests without running." + task :build_only => [:test_deps] do + @ceedling[:test_invoker].setup_and_invoke(COLLECTION_ALL_TESTS, TEST_SYM, {:build_only => true}) + end + desc "Run tests by matching regular expression pattern." - task :pattern, [:regex] => [:directories] do |t, args| + task :pattern, [:regex] => [:test_deps] do |t, args| matches = [] - + COLLECTION_ALL_TESTS.each { |test| matches << test if (test =~ /#{args.regex}/) } - + if (matches.size > 0) @ceedling[:test_invoker].setup_and_invoke(matches, TEST_SYM, {:force_run => false}) else @@ -36,11 +46,11 @@ namespace TEST_SYM do end desc "Run tests whose test path contains [dir] or [dir] substring." - task :path, [:dir] => [:directories] do |t, args| + task :path, [:dir] => [:test_deps] do |t, args| matches = [] - + COLLECTION_ALL_TESTS.each { |test| matches << test if File.dirname(test).include?(args.dir.gsub(/\\/, '/')) } - + if (matches.size > 0) @ceedling[:test_invoker].setup_and_invoke(matches, TEST_SYM, {:force_run => false}) else diff --git a/vendor/ceedling/lib/tasks_tests_deep_dependencies.rake b/vendor/ceedling/lib/ceedling/tasks_tests_deep_dependencies.rake similarity index 79% rename from vendor/ceedling/lib/tasks_tests_deep_dependencies.rake rename to vendor/ceedling/lib/ceedling/tasks_tests_deep_dependencies.rake index 67d6ce5..f899407 100644 --- a/vendor/ceedling/lib/tasks_tests_deep_dependencies.rake +++ b/vendor/ceedling/lib/ceedling/tasks_tests_deep_dependencies.rake @@ -1,4 +1,4 @@ -require 'constants' +require 'ceedling/constants' namespace REFRESH_SYM do diff --git a/vendor/ceedling/lib/ceedling/tasks_vendor.rake b/vendor/ceedling/lib/ceedling/tasks_vendor.rake new file mode 100644 index 0000000..63c2ca5 --- /dev/null +++ b/vendor/ceedling/lib/ceedling/tasks_vendor.rake @@ -0,0 +1,35 @@ +require 'ceedling/constants' +require 'ceedling/file_path_utils' + +# create file dependencies to ensure C-based components of vendor tools are recompiled when they are updated with new versions +# forming these explicitly rather than depend on auxiliary dependencies so all scenarios are explicitly covered + +file( @ceedling[:file_path_utils].form_test_build_c_object_filepath( UNITY_C_FILE ) => [ + File.join( UNITY_VENDOR_PATH, UNITY_LIB_PATH, UNITY_C_FILE ), + File.join( UNITY_VENDOR_PATH, UNITY_LIB_PATH, UNITY_H_FILE ), + File.join( UNITY_VENDOR_PATH, UNITY_LIB_PATH, UNITY_INTERNALS_H_FILE ) ] + ) + + +if (PROJECT_USE_MOCKS) +file( @ceedling[:file_path_utils].form_test_build_c_object_filepath( CMOCK_C_FILE ) => [ + File.join( CMOCK_VENDOR_PATH, CMOCK_LIB_PATH, CMOCK_C_FILE ), + File.join( CMOCK_VENDOR_PATH, CMOCK_LIB_PATH, CMOCK_H_FILE ) ] + ) +end + + +if (PROJECT_USE_EXCEPTIONS) +file( @ceedling[:file_path_utils].form_test_build_c_object_filepath( CEXCEPTION_C_FILE ) => [ + File.join( CEXCEPTION_VENDOR_PATH, CEXCEPTION_LIB_PATH, CEXCEPTION_C_FILE ), + File.join( CEXCEPTION_VENDOR_PATH, CEXCEPTION_LIB_PATH, CEXCEPTION_H_FILE ) ] + ) +end + + +if (PROJECT_USE_EXCEPTIONS and PROJECT_RELEASE_BUILD) +file( @ceedling[:file_path_utils].form_release_build_c_object_filepath( CEXCEPTION_C_FILE ) => [ + File.join( CEXCEPTION_VENDOR_PATH, CEXCEPTION_LIB_PATH, CEXCEPTION_C_FILE ), + File.join( CEXCEPTION_VENDOR_PATH, CEXCEPTION_LIB_PATH, CEXCEPTION_H_FILE ) ] + ) +end diff --git a/vendor/ceedling/lib/test_includes_extractor.rb b/vendor/ceedling/lib/ceedling/test_includes_extractor.rb similarity index 68% rename from vendor/ceedling/lib/test_includes_extractor.rb rename to vendor/ceedling/lib/ceedling/test_includes_extractor.rb index 35f7c53..393b0be 100644 --- a/vendor/ceedling/lib/test_includes_extractor.rb +++ b/vendor/ceedling/lib/ceedling/test_includes_extractor.rb @@ -3,7 +3,6 @@ class TestIncludesExtractor constructor :configurator, :yaml_wrapper, :file_wrapper - def setup @includes = {} @mocks = {} @@ -20,22 +19,27 @@ def parse_test_file(test) gather_and_store_includes( test, extract_from_file(test) ) end + # open, scan for, and sort & store includes of test file + def parse_test_file_source_include(test) + return extract_source_include_from_file(test) + end + # mocks with no file extension def lookup_raw_mock_list(test) file_key = form_file_key(test) return [] if @mocks[file_key].nil? return @mocks[file_key] end - + # includes with file extension def lookup_includes_list(file) file_key = form_file_key(file) return [] if (@includes[file_key]).nil? return @includes[file_key] end - + private ################################# - + def form_file_key(filepath) return File.basename(filepath).to_sym end @@ -43,39 +47,65 @@ def form_file_key(filepath) def extract_from_file(file) includes = [] header_extension = @configurator.extension_header - + contents = @file_wrapper.read(file) # remove line comments contents = contents.gsub(/\/\/.*$/, '') # remove block comments contents = contents.gsub(/\/\*.*?\*\//m, '') - + contents.split("\n").each do |line| # look for include statement scan_results = line.scan(/#include\s+\"\s*(.+#{'\\'+header_extension})\s*\"/) - + + includes << scan_results[0][0] if (scan_results.size > 0) + + # look for TEST_FILE statement + scan_results = line.scan(/TEST_FILE\(\s*\"\s*(.+\.\w+)\s*\"\s*\)/) + includes << scan_results[0][0] if (scan_results.size > 0) end - + return includes.uniq end + def extract_source_include_from_file(file) + source_includes = [] + source_extension = @configurator.extension_source + + contents = @file_wrapper.read(file) + + # remove line comments + contents = contents.gsub(/\/\/.*$/, '') + # remove block comments + contents = contents.gsub(/\/\*.*?\*\//m, '') + + contents.split("\n").each do |line| + # look for include statement + scan_results = line.scan(/#include\s+\"\s*(.+#{'\\'+source_extension})\s*\"/) + + source_includes << scan_results[0][0] if (scan_results.size > 0) + end + + return source_includes.uniq + end + def gather_and_store_includes(file, includes) mock_prefix = @configurator.cmock_mock_prefix header_extension = @configurator.extension_header file_key = form_file_key(file) @mocks[file_key] = [] - + # add includes to lookup hash @includes[file_key] = includes - - includes.each do |include_file| + + includes.each do |include_file| # check if include is a mock scan_results = include_file.scan(/(#{mock_prefix}.+)#{'\\'+header_extension}/) # add mock to lookup hash @mocks[file_key] << scan_results[0][0] if (scan_results.size > 0) end end - + end diff --git a/vendor/ceedling/lib/ceedling/test_invoker.rb b/vendor/ceedling/lib/ceedling/test_invoker.rb new file mode 100644 index 0000000..ae686a1 --- /dev/null +++ b/vendor/ceedling/lib/ceedling/test_invoker.rb @@ -0,0 +1,165 @@ +require 'ceedling/constants' + + +class TestInvoker + + attr_reader :sources, :tests, :mocks + + constructor :configurator, + :test_invoker_helper, + :plugin_manager, + :streaminator, + :preprocessinator, + :task_invoker, + :dependinator, + :project_config_manager, + :build_invoker_utils, + :file_path_utils, + :file_wrapper + + def setup + @sources = [] + @tests = [] + @mocks = [] + end + + + # Convert libraries configuration form YAML configuration + # into a string that can be given to the compiler. + def convert_libraries_to_arguments() + args = ((@configurator.project_config_hash[:libraries_test] || []) + ((defined? LIBRARIES_SYSTEM) ? LIBRARIES_SYSTEM : [])).flatten + if (defined? LIBRARIES_FLAG) + args.map! {|v| LIBRARIES_FLAG.gsub(/\$\{1\}/, v) } + end + return args + end + + def get_library_paths_to_arguments() + paths = (defined? PATHS_LIBRARIES) ? (PATHS_LIBRARIES || []).clone : [] + if (defined? LIBRARIES_PATH_FLAG) + paths.map! {|v| LIBRARIES_PATH_FLAG.gsub(/\$\{1\}/, v) } + end + return paths + end + + def setup_and_invoke(tests, context=TEST_SYM, options={:force_run => true, :build_only => false}) + + @tests = tests + + @project_config_manager.process_test_config_change + + @tests.each do |test| + # announce beginning of test run + header = "Test '#{File.basename(test)}'" + @streaminator.stdout_puts("\n\n#{header}\n#{'-' * header.length}") + + begin + @plugin_manager.pre_test( test ) + test_name ="#{File.basename(test)}".chomp('.c') + def_test_key="defines_#{test_name.downcase}" + + if @configurator.project_config_hash.has_key?(def_test_key.to_sym) || @configurator.defines_use_test_definition + defs_bkp = Array.new(COLLECTION_DEFINES_TEST_AND_VENDOR) + tst_defs_cfg = Array.new(defs_bkp) + if @configurator.project_config_hash.has_key?(def_test_key.to_sym) + tst_defs_cfg.replace(@configurator.project_config_hash[def_test_key.to_sym]) + tst_defs_cfg .concat(COLLECTION_DEFINES_VENDOR) if COLLECTION_DEFINES_VENDOR + end + if @configurator.defines_use_test_definition + tst_defs_cfg << File.basename(test, ".*").strip.upcase.sub(/@.*$/, "") + end + COLLECTION_DEFINES_TEST_AND_VENDOR.replace(tst_defs_cfg) + end + + # redefine the project out path and preprocessor defines + if @configurator.project_config_hash.has_key?(def_test_key.to_sym) + @streaminator.stdout_puts("Updating test definitions for #{test_name}", Verbosity::NORMAL) + orig_path = @configurator.project_test_build_output_path + @configurator.project_config_hash[:project_test_build_output_path] = File.join(@configurator.project_test_build_output_path, test_name) + @file_wrapper.mkdir(@configurator.project_test_build_output_path) + end + + # collect up test fixture pieces & parts + runner = @file_path_utils.form_runner_filepath_from_test( test ) + mock_list = @preprocessinator.preprocess_test_and_invoke_test_mocks( test ) + sources = @test_invoker_helper.extract_sources( test ) + extras = @configurator.collection_test_fixture_extra_link_objects + core = [test] + mock_list + sources + objects = @file_path_utils.form_test_build_objects_filelist( [runner] + core + extras ).uniq + results_pass = @file_path_utils.form_pass_results_filepath( test ) + results_fail = @file_path_utils.form_fail_results_filepath( test ) + + # identify all the objects shall not be linked and then remove them from objects list. + no_link_objects = @file_path_utils.form_test_build_objects_filelist(@preprocessinator.preprocess_shallow_source_includes( test )) + objects = objects.uniq - no_link_objects + + @project_config_manager.process_test_defines_change(@project_config_manager.filter_internal_sources(sources)) + + # clean results files so we have a missing file with which to kick off rake's dependency rules + @test_invoker_helper.clean_results( {:pass => results_pass, :fail => results_fail}, options ) + + # load up auxiliary dependencies so deep changes cause rebuilding appropriately + @test_invoker_helper.process_deep_dependencies( core ) do |dependencies_list| + @dependinator.load_test_object_deep_dependencies( dependencies_list ) + end + + # tell rake to create test runner if needed + @task_invoker.invoke_test_runner( runner ) + + # enhance object file dependencies to capture externalities influencing regeneration + @dependinator.enhance_test_build_object_dependencies( objects ) + + # associate object files with executable + @dependinator.enhance_test_executable_dependencies( test, objects ) + + # build test objects + @task_invoker.invoke_test_objects( objects ) + + # if the option build_only has been specified, build only the executable + # but don't run the test + if (options[:build_only]) + executable = @file_path_utils.form_test_executable_filepath( test ) + @task_invoker.invoke_test_executable( executable ) + else + # 3, 2, 1... launch + @task_invoker.invoke_test_results( results_pass ) + end + rescue => e + @build_invoker_utils.process_exception( e, context ) + ensure + @plugin_manager.post_test( test ) + # restore the project test defines + if @configurator.project_config_hash.has_key?(def_test_key.to_sym) || @configurator.defines_use_test_definition + COLLECTION_DEFINES_TEST_AND_VENDOR.replace(defs_bkp) + if @configurator.project_config_hash.has_key?(def_test_key.to_sym) + @configurator.project_config_hash[:project_test_build_output_path] = orig_path + @streaminator.stdout_puts("Restored defines and build path to standard", Verbosity::NORMAL) + end + end + end + + # store away what's been processed + @mocks.concat( mock_list ) + @sources.concat( sources ) + + @task_invoker.first_run = false + end + + # post-process collected mock list + @mocks.uniq! + + # post-process collected sources list + @sources.uniq! + end + + + def refresh_deep_dependencies + @file_wrapper.rm_f( + @file_wrapper.directory_listing( + File.join( @configurator.project_test_dependencies_path, '*' + @configurator.extension_dependencies ) ) ) + + @test_invoker_helper.process_deep_dependencies( + @configurator.collection_all_tests + @configurator.collection_all_source ) + end + +end diff --git a/vendor/ceedling/lib/test_invoker_helper.rb b/vendor/ceedling/lib/ceedling/test_invoker_helper.rb similarity index 82% rename from vendor/ceedling/lib/test_invoker_helper.rb rename to vendor/ceedling/lib/ceedling/test_invoker_helper.rb index 001608e..403d93e 100644 --- a/vendor/ceedling/lib/test_invoker_helper.rb +++ b/vendor/ceedling/lib/ceedling/test_invoker_helper.rb @@ -11,8 +11,12 @@ def clean_results(results, options) def process_deep_dependencies(files) return if (not @configurator.project_use_deep_dependencies) - dependencies_list = @file_path_utils.form_test_dependencies_filelist( files ) - @task_invoker.invoke_test_dependencies_files( dependencies_list ) + dependencies_list = @file_path_utils.form_test_dependencies_filelist( files ).uniq + + if @configurator.project_generate_deep_dependencies + @task_invoker.invoke_test_dependencies_files( dependencies_list ) + end + yield( dependencies_list ) if block_given? end diff --git a/vendor/ceedling/lib/tool_executor.rb b/vendor/ceedling/lib/ceedling/tool_executor.rb similarity index 84% rename from vendor/ceedling/lib/tool_executor.rb rename to vendor/ceedling/lib/ceedling/tool_executor.rb index f4bccc4..0ab5ddc 100644 --- a/vendor/ceedling/lib/tool_executor.rb +++ b/vendor/ceedling/lib/ceedling/tool_executor.rb @@ -1,4 +1,5 @@ -require 'constants' +require 'ceedling/constants' +require 'benchmark' class ShellExecutionException < RuntimeError attr_reader :shell_result @@ -17,25 +18,31 @@ def setup end # build up a command line from yaml provided config - def build_command_line(tool_config, *args) + + # @param extra_params is an array of parameters to append to executable + def build_command_line(tool_config, extra_params, *args) @tool_name = tool_config[:name] @executable = tool_config[:executable] command = {} - # basic premise is to iterate top to bottom through arguments using '$' as + # basic premise is to iterate top to bottom through arguments using '$' as # a string replacement indicator to expand globals or inline yaml arrays # into command line arguments via substitution strings + # executable must be quoted if it includes spaces (common on windows) + executable = @tool_executor_helper.osify_path_separators( expandify_element(@executable, *args) ) + executable = "\"#{executable}\"" if executable.include?(' ') command[:line] = [ - @tool_executor_helper.osify_path_separators( expandify_element(@executable, *args) ), + executable, + extra_params.join(' ').strip, build_arguments(tool_config[:arguments], *args), - ].join(' ').strip + ].reject{|s| s.nil? || s.empty?}.join(' ').strip command[:options] = { :stderr_redirect => @tool_executor_helper.stderr_redirection(tool_config, @configurator.project_logging), :background_exec => tool_config[:background_exec] } - + return command end @@ -45,7 +52,6 @@ def exec(command, options={}, args=[]) options[:boom] = true if (options[:boom].nil?) options[:stderr_redirect] = StdErrRedirect::NONE if (options[:stderr_redirect].nil?) options[:background_exec] = BackgroundExec::NONE if (options[:background_exec].nil?) - # build command line command_line = [ @tool_executor_helper.background_exec_cmdline_prepend( options ), @@ -55,33 +61,44 @@ def exec(command, options={}, args=[]) @tool_executor_helper.background_exec_cmdline_append( options ), ].flatten.compact.join(' ') + @streaminator.stderr_puts("Verbose: #{__method__.to_s}(): #{command_line}", Verbosity::DEBUG) + shell_result = {} - + # depending on background exec option, we shell out differently - if (options[:background_exec] != BackgroundExec::NONE) - shell_result = @system_wrapper.shell_system( command_line ) - else - shell_result = @system_wrapper.shell_backticks( command_line ) + time = Benchmark.realtime do + if (options[:background_exec] != BackgroundExec::NONE) + shell_result = @system_wrapper.shell_system( command_line, options[:boom] ) + else + shell_result = @system_wrapper.shell_backticks( command_line, options[:boom] ) + end end - + shell_result[:time] = time + + #scrub the string for illegal output + unless shell_result[:output].nil? + shell_result[:output] = shell_result[:output].scrub if "".respond_to?(:scrub) + shell_result[:output].gsub!(/\033\[\d\dm/,'') + end + @tool_executor_helper.print_happy_results( command_line, shell_result, options[:boom] ) @tool_executor_helper.print_error_results( command_line, shell_result, options[:boom] ) - + # go boom if exit code isn't 0 (but in some cases we don't want a non-0 exit code to raise) raise ShellExecutionException.new(shell_result) if ((shell_result[:exit_code] != 0) and options[:boom]) - + return shell_result end - + private ############################# - + def build_arguments(config, *args) build_string = '' - + return nil if (config.nil?) - + # iterate through each argument # the yaml blob array needs to be flattened so that yaml substitution @@ -89,7 +106,7 @@ def build_arguments(config, *args) # dereferenced config.flatten.each do |element| argument = '' - + case(element) # if we find a simple string then look for string replacement operators # and expand with the parameters in this method's argument list @@ -101,7 +118,7 @@ def build_arguments(config, *args) build_string.concat("#{argument} ") if (argument.length > 0) end - + build_string.strip! return build_string if (build_string.length > 0) return nil @@ -126,7 +143,7 @@ def expandify_element(element, *args) match = /#{Regexp.escape($1)}/ to_process = args[args_index] end - + # simple string argument: replace escaped '\$' and strip element.sub!(/\\\$/, '$') element.strip! @@ -148,11 +165,11 @@ def expandify_element(element, *args) if (build_string =~ RUBY_STRING_REPLACEMENT_PATTERN) build_string.replace(@system_wrapper.module_eval(build_string)) end - + return build_string.strip end - + # handle argument hash: keys are substitution strings, values are data to be expanded within substitution strings def dehashify_argument_elements(hash) build_string = '' @@ -167,10 +184,10 @@ def dehashify_argument_elements(hash) @streaminator.stderr_puts("ERROR: Tool '#{@tool_name}' could not expand nil elements for substitution string '#{substitution}'.", Verbosity::ERRORS) raise end - + # array-ify expansion input if only a single string expansion = ((expand.class == String) ? [expand] : expand) - + expansion.each do |item| # code eval substitution if (item =~ RUBY_EVAL_REPLACEMENT_PATTERN) @@ -191,13 +208,13 @@ def dehashify_argument_elements(hash) elements << item elsif (item.class == String) @streaminator.stderr_puts("ERROR: Tool '#{@tool_name}' cannot expand nonexistent value '#{item}' for substitution string '#{substitution}'.", Verbosity::ERRORS) - raise + raise else @streaminator.stderr_puts("ERROR: Tool '#{@tool_name}' cannot expand value having type '#{item.class}' for substitution string '#{substitution}'.", Verbosity::ERRORS) - raise + raise end end - + # expand elements (whether string or array) into substitution string & replace escaped '\$' elements.flatten! elements.each do |element| diff --git a/vendor/ceedling/lib/tool_executor_helper.rb b/vendor/ceedling/lib/ceedling/tool_executor_helper.rb similarity index 63% rename from vendor/ceedling/lib/tool_executor_helper.rb rename to vendor/ceedling/lib/ceedling/tool_executor_helper.rb index c2ccaa3..de4cafe 100644 --- a/vendor/ceedling/lib/tool_executor_helper.rb +++ b/vendor/ceedling/lib/ceedling/tool_executor_helper.rb @@ -1,25 +1,41 @@ -require 'constants' # for Verbosity enumeration & $stderr redirect enumeration +require 'ceedling/constants' # for Verbosity enumeration & $stderr redirect enumeration +## +# Helper functions for the tool executor class ToolExecutorHelper constructor :streaminator, :system_utils, :system_wrapper + ## + # Returns the stderr redirection based on the config and logging. + # ==== Attributes + # + # * _tool_config_: A hash containing config information. + # * _logging_: A boolean representing if logging is enabled or not. + # def stderr_redirection(tool_config, logging) # if there's no logging enabled, return :stderr_redirect unmodified return tool_config[:stderr_redirect] if (not logging) - + # if there is logging enabled but the redirect is a custom value (not enum), return the custom string return tool_config[:stderr_redirect] if (tool_config[:stderr_redirect].class == String) - + # if logging is enabled but there's no custom string, return the AUTO enumeration so $stderr goes into the log return StdErrRedirect::AUTO end + + ## + # Returns the background execution prepend based on the config. + # ==== Attributes + # + # * _tool_config_: A hash containing config information. + # def background_exec_cmdline_prepend(tool_config) - return nil if (tool_config[:background_exec].nil?) - + return nil if (tool_config.nil? || tool_config[:background_exec].nil?) + config_exec = tool_config[:background_exec] - + if ((config_exec == BackgroundExec::AUTO) and (@system_wrapper.windows?)) return 'start' end @@ -31,26 +47,37 @@ def background_exec_cmdline_prepend(tool_config) return nil end + + ## + # Modifies an executables path based on platform. + # ==== Attributes + # + # * _executable_: The executable's path. + # def osify_path_separators(executable) return executable.gsub(/\//, '\\') if (@system_wrapper.windows?) return executable end - + + ## + # Returns the stderr redirect append based on the config. + # ==== Attributes + # + # * _tool_config_: A hash containing config information. + # def stderr_redirect_cmdline_append(tool_config) - return nil if (tool_config[:stderr_redirect].nil?) - + return nil if (tool_config.nil? || tool_config[:stderr_redirect].nil?) + config_redirect = tool_config[:stderr_redirect] redirect = StdErrRedirect::NONE - + if (config_redirect == StdErrRedirect::AUTO) if (@system_wrapper.windows?) redirect = StdErrRedirect::WIN + elsif (@system_utils.tcsh_shell?) + redirect = StdErrRedirect::TCSH else - if (@system_utils.tcsh_shell?) - redirect = StdErrRedirect::TCSH - else - redirect = StdErrRedirect::UNIX - end + redirect = StdErrRedirect::UNIX end end @@ -64,11 +91,17 @@ def stderr_redirect_cmdline_append(tool_config) end end + ## + # Returns the background execution append based on the config. + # ==== Attributes + # + # * _tool_config_: A hash containing config information. + # def background_exec_cmdline_append(tool_config) - return nil if (tool_config[:background_exec].nil?) + return nil if (tool_config.nil? || tool_config[:background_exec].nil?) config_exec = tool_config[:background_exec] - + # if :auto & windows, then we already prepended 'start' and should append nothing return nil if ((config_exec == BackgroundExec::AUTO) and (@system_wrapper.windows?)) @@ -77,26 +110,43 @@ def background_exec_cmdline_append(tool_config) # if explicitly Unix, then append '&' return '&' if (config_exec == BackgroundExec::UNIX) - + + # * _command_str_: A hash containing config information. # all other cases, including :none, :win, & anything unrecognized, append nothing return nil end - # if command succeeded and we have verbosity cranked up, spill our guts + ## + # Outputs success results if command succeeded and we have verbosity cranked up. + # ==== Attributes + # + # * _command_str_: The command ran. + # * _shell_results_: The outputs of the command including exit code and + # output. + # * _boom_: A boolean representing if a non zero result is erroneous. + # def print_happy_results(command_str, shell_result, boom=true) if ((shell_result[:exit_code] == 0) or ((shell_result[:exit_code] != 0) and not boom)) output = "> Shell executed command:\n" - output += "#{command_str}\n" + output += "'#{command_str}'\n" output += "> Produced output:\n" if (not shell_result[:output].empty?) output += "#{shell_result[:output].strip}\n" if (not shell_result[:output].empty?) output += "> And exited with status: [#{shell_result[:exit_code]}].\n" if (shell_result[:exit_code] != 0) output += "\n" - + @streaminator.stdout_puts(output, Verbosity::OBNOXIOUS) end end - # if command failed and we have verbosity set to minimum error level, spill our guts + ## + # Outputs failures results if command failed and we have verbosity set to minimum error level. + # ==== Attributes + # + # * _command_str_: The command ran. + # * _shell_results_: The outputs of the command including exit code and + # output. + # * _boom_: A boolean representing if a non zero result is erroneous. + # def print_error_results(command_str, shell_result, boom=true) if ((shell_result[:exit_code] != 0) and boom) output = "ERROR: Shell command failed.\n" @@ -111,5 +161,4 @@ def print_error_results(command_str, shell_result, boom=true) @streaminator.stderr_puts(output, Verbosity::ERRORS) end end - end diff --git a/vendor/ceedling/lib/verbosinator.rb b/vendor/ceedling/lib/ceedling/verbosinator.rb similarity index 100% rename from vendor/ceedling/lib/verbosinator.rb rename to vendor/ceedling/lib/ceedling/verbosinator.rb diff --git a/vendor/ceedling/lib/ceedling/version.rb b/vendor/ceedling/lib/ceedling/version.rb index 8f17e87..ebda10b 100644 --- a/vendor/ceedling/lib/ceedling/version.rb +++ b/vendor/ceedling/lib/ceedling/version.rb @@ -1,16 +1,54 @@ + # @private module Ceedling module Version - # @private - GEM = "0.13.0.rc4" + { "UNITY" => File.join("unity","src","unity.h"), + "CMOCK" => File.join("cmock","src","cmock.h"), + "CEXCEPTION" => File.join("c_exception","lib","CException.h") + }.each_pair do |name, path| + # Check for local or global version of vendor directory in order to look up versions + path1 = File.expand_path( File.join("..","..","vendor",path) ) + path2 = File.expand_path( File.join(File.dirname(__FILE__),"..","..","vendor",path) ) + filename = if (File.exists?(path1)) + path1 + elsif (File.exists?(path2)) + path2 + elsif File.exists?(CEEDLING_VENDOR) + path3 = File.expand_path( File.join(CEEDLING_VENDOR,path) ) + if (File.exists?(path3)) + path3 + else + basepath = File.join( CEEDLING_VENDOR, path.split(/\\\//)[0], 'release') + begin + [ @ceedling[:file_wrapper].read( File.join(base_path, 'release', 'version.info') ).strip, + @ceedling[:file_wrapper].read( File.join(base_path, 'release', 'build.info') ).strip ].join('.') + rescue + "#{name}" + end + end + else + module_eval("#{name} = 'unknown'") + continue + end + + # Actually look up the versions + a = [0,0,0] + begin + File.readlines(filename).each do |line| + ["VERSION_MAJOR", "VERSION_MINOR", "VERSION_BUILD"].each_with_index do |field, i| + m = line.match(/#{name}_#{field}\s+(\d+)/) + a[i] = m[1] unless (m.nil?) + end + end + rescue + abort("Can't collect data for vendor component: \"#{filename}\" . \nPlease check your setup.") + end + + # splat it to return the final value + eval("#{name} = '#{a.join(".")}'") + end - # @private + GEM = "0.31.1" CEEDLING = GEM - # @private - CEXCEPTION = "1.2.17" - # @private - CMOCK = "2.0.215" - # @private - UNITY = "2.1.0" end end diff --git a/vendor/ceedling/lib/ceedling/version.rb.erb b/vendor/ceedling/lib/ceedling/version.rb.erb deleted file mode 100644 index 09af231..0000000 --- a/vendor/ceedling/lib/ceedling/version.rb.erb +++ /dev/null @@ -1,16 +0,0 @@ -# @private -module Ceedling - module Version - # @private - GEM = "0.11.2" - - # @private - CEEDLING = "<%= versions["CEEDLING"] %>" - # @private - CEXCEPTION = "<%= versions["CEXCEPTION"] %>" - # @private - CMOCK = "<%= versions["CMOCK"] %>" - # @private - UNITY = "<%= versions["UNITY"] %>" - end -end diff --git a/vendor/ceedling/lib/yaml_wrapper.rb b/vendor/ceedling/lib/ceedling/yaml_wrapper.rb similarity index 72% rename from vendor/ceedling/lib/yaml_wrapper.rb rename to vendor/ceedling/lib/ceedling/yaml_wrapper.rb index 77cef59..00ece51 100644 --- a/vendor/ceedling/lib/yaml_wrapper.rb +++ b/vendor/ceedling/lib/ceedling/yaml_wrapper.rb @@ -1,10 +1,11 @@ require 'yaml' +require 'erb' class YamlWrapper def load(filepath) - return YAML.load(File.read(filepath)) + return YAML.load(ERB.new(File.read(filepath)).result) end def dump(filepath, structure) diff --git a/vendor/ceedling/lib/configurator_plugins.rb b/vendor/ceedling/lib/configurator_plugins.rb deleted file mode 100644 index 19e4060..0000000 --- a/vendor/ceedling/lib/configurator_plugins.rb +++ /dev/null @@ -1,124 +0,0 @@ -require 'constants' - -class ConfiguratorPlugins - - constructor :stream_wrapper, :file_wrapper, :system_wrapper - attr_reader :rake_plugins, :script_plugins - - def setup - @rake_plugins = [] - @script_plugins = [] - end - - - def add_load_paths(config) - plugin_paths = {} - - config[:plugins][:load_paths].each do |root| - @system_wrapper.add_load_path( root ) if ( not @file_wrapper.directory_listing( File.join( root, '*.rb' ) ).empty? ) - - config[:plugins][:enabled].each do |plugin| - path = File.join(root, plugin, "lib") - old_path = File.join( root, plugin ) - - if ( not @file_wrapper.directory_listing( File.join( path, '*.rb' ) ).empty? ) - plugin_paths[(plugin + '_path').to_sym] = path - @system_wrapper.add_load_path( path ) - elsif ( not @file_wrapper.directory_listing( File.join( old_path, '*.rb' ) ).empty? ) - plugin_paths[(plugin + '_path').to_sym] = old_path - @system_wrapper.add_load_path( old_path ) - end - end - end - - return plugin_paths - end - - - # gather up and return .rake filepaths that exist on-disk - def find_rake_plugins(config) - plugins_with_path = [] - - config[:plugins][:load_paths].each do |root| - config[:plugins][:enabled].each do |plugin| - rake_plugin_path = File.join(root, plugin, "#{plugin}.rake") - if (@file_wrapper.exist?(rake_plugin_path)) - plugins_with_path << rake_plugin_path - @rake_plugins << plugin - end - end - end - - return plugins_with_path - end - - - # gather up and return just names of .rb classes that exist on-disk - def find_script_plugins(config) - config[:plugins][:load_paths].each do |root| - config[:plugins][:enabled].each do |plugin| - script_plugin_path = File.join(root, plugin, "lib", "#{plugin}.rb") - - # Add the old path here to support legacy style. Eventaully remove. - old_script_plugin_path = File.join(root, plugin, "#{plugin}.rb") - - if @file_wrapper.exist?(script_plugin_path) or @file_wrapper.exist?(old_script_plugin_path) - @script_plugins << plugin - end - - # Print depreciation warning. - if @file_wrapper.exist?(old_script_plugin_path) - $stderr.puts "WARNING: Depreciated plugin style used in #{plugin}. Use new directory structure!" - end - end - end - - return @script_plugins - end - - - # gather up and return configuration .yml filepaths that exist on-disk - def find_config_plugins(config) - plugins_with_path = [] - - config[:plugins][:load_paths].each do |root| - config[:plugins][:enabled].each do |plugin| - config_plugin_path = File.join(root, plugin, "config", "#{plugin}.yml") - - # Add the old path here to support legacy style. Eventaully remove. - old_config_plugin_path = File.join(root, plugin, "#{plugin}.yml") - - if @file_wrapper.exist?(config_plugin_path) - plugins_with_path << config_plugin_path - elsif @file_wrapper.exist?(old_config_plugin_path) - # there's a warning printed for this in find_script_plugins - plugins_with_path << old_config_plugin_path - end - end - end - - return plugins_with_path - end - - - # gather up and return default .yml filepaths that exist on-disk - def find_plugin_defaults(config) - defaults_with_path = [] - - config[:plugins][:load_paths].each do |root| - config[:plugins][:enabled].each do |plugin| - default_path = File.join(root, plugin, 'config', 'defaults.yml') - old_default_path = File.join(root, plugin, 'defaults.yml') - - if @file_wrapper.exist?(default_path) - defaults_with_path << default_path - elsif @file_wrapper.exist?(old_default_path) - defaults_with_path << old_default_path - end - end - end - - return defaults_with_path - end - -end diff --git a/vendor/ceedling/lib/constants.rb b/vendor/ceedling/lib/constants.rb deleted file mode 100644 index c7fd9ca..0000000 --- a/vendor/ceedling/lib/constants.rb +++ /dev/null @@ -1,91 +0,0 @@ - -class Verbosity - SILENT = 0 # as silent as possible (though there are some messages that must be spit out) - ERRORS = 1 # only errors - COMPLAIN = 2 # spit out errors and warnings/notices - NORMAL = 3 # errors, warnings/notices, standard status messages - OBNOXIOUS = 4 # all messages including extra verbose output (used for lite debugging / verification) - DEBUG = 5 # special extra verbose output for hardcore debugging -end - - -class TestResultsSanityChecks - NONE = 0 # no sanity checking of test results - NORMAL = 1 # perform non-problematic checks - THOROUGH = 2 # perform checks that require inside knowledge of system workings -end - - -class StdErrRedirect - NONE = :none - AUTO = :auto - WIN = :win - UNIX = :unix - TCSH = :tcsh -end - - -class BackgroundExec - NONE = :none - AUTO = :auto - WIN = :win - UNIX = :unix -end - - -EXTENSION_WIN_EXE = '.exe' -EXTENSION_NONWIN_EXE = '.out' - - -CEXCEPTION_ROOT_PATH = 'c_exception' -CEXCEPTION_LIB_PATH = "#{CEXCEPTION_ROOT_PATH}/lib" -CEXCEPTION_C_FILE = 'CException.c' -CEXCEPTION_H_FILE = 'CException.h' - -UNITY_ROOT_PATH = 'unity' -UNITY_LIB_PATH = "#{UNITY_ROOT_PATH}/src" -UNITY_C_FILE = 'unity.c' -UNITY_H_FILE = 'unity.h' -UNITY_INTERNALS_H_FILE = 'unity_internals.h' - -CMOCK_ROOT_PATH = 'cmock' -CMOCK_LIB_PATH = "#{CMOCK_ROOT_PATH}/src" -CMOCK_C_FILE = 'cmock.c' -CMOCK_H_FILE = 'cmock.h' - - -DEFAULT_CEEDLING_MAIN_PROJECT_FILE = 'project.yml' # main project file -DEFAULT_CEEDLING_USER_PROJECT_FILE = 'user.yml' # supplemental user config file - -INPUT_CONFIGURATION_CACHE_FILE = 'input.yml' # input configuration file dump - - -TEST_ROOT_NAME = 'test' -TEST_TASK_ROOT = TEST_ROOT_NAME + ':' -TEST_SYM = TEST_ROOT_NAME.to_sym - -RELEASE_ROOT_NAME = 'release' -RELEASE_TASK_ROOT = RELEASE_ROOT_NAME + ':' -RELEASE_SYM = RELEASE_ROOT_NAME.to_sym - -REFRESH_ROOT_NAME = 'refresh' -REFRESH_TASK_ROOT = REFRESH_ROOT_NAME + ':' -REFRESH_SYM = REFRESH_ROOT_NAME.to_sym - -UTILS_ROOT_NAME = 'utils' -UTILS_TASK_ROOT = UTILS_ROOT_NAME + ':' -UTILS_SYM = UTILS_ROOT_NAME.to_sym - -OPERATION_COMPILE_SYM = :compile -OPERATION_LINK_SYM = :link - - -RUBY_STRING_REPLACEMENT_PATTERN = /#\{.+\}/ -RUBY_EVAL_REPLACEMENT_PATTERN = /^\{(.+)\}$/ -TOOL_EXECUTOR_ARGUMENT_REPLACEMENT_PATTERN = /(\$\{(\d+)\})/ -TEST_STDOUT_STATISTICS_PATTERN = /-+\s+(\d+)\s+Tests\s+(\d+)\s+Failures\s+(\d+)\s+Ignored\s+(OK|FAIL)\s*/i - -NULL_FILE_PATH = '/dev/null' - -TESTS_BASE_PATH = TEST_ROOT_NAME -RELEASE_BASE_PATH = RELEASE_ROOT_NAME diff --git a/vendor/ceedling/lib/generator_test_runner.rb b/vendor/ceedling/lib/generator_test_runner.rb deleted file mode 100644 index bc01e5a..0000000 --- a/vendor/ceedling/lib/generator_test_runner.rb +++ /dev/null @@ -1,63 +0,0 @@ - -class GeneratorTestRunner - - constructor :configurator, :file_path_utils, :file_wrapper - - def find_test_cases(test_file) - tests = [] - tests_and_line_numbers = [] - lines = [] - - # if we don't have preprocessor assistance, do some basic preprocessing of our own - if (not @configurator.project_use_test_preprocessor) - source = @file_wrapper.read(test_file) - - # remove line comments - source = source.gsub(/\/\/.*$/, '') - # remove block comments - source = source.gsub(/\/\*.*?\*\//m, '') - - # treat preprocessor directives as a logical line - lines = source.split(/(^\s*\#.*$) | (;|\{|\}) /x) # match ;, {, and } as end of lines - # otherwise, read the preprocessed file raw - else - lines = @file_wrapper.read( @file_path_utils.form_preprocessed_file_filepath(test_file) ).split(/;|\{|\}/) - end - - # step 1. find test functions in (possibly preprocessed) file - # (note that lines are not broken up at end of lines) - lines.each do |line| - if (line =~ /^\s*void\s+((T|t)est.*)\s*\(\s*(void)?\s*\)/m) - tests << ($1.strip) - end - end - - # step 2. associate test functions with line numbers in (non-preprocessed) original file - # (note that this time we must scan file contents broken up by end of lines) - raw_lines = @file_wrapper.read(test_file).split("\n") - raw_index = 0 - - tests.each do |test| - raw_lines[raw_index..-1].each_with_index do |line, index| - # test function might be declared across lines; look for it by its name followed - # by a few tell-tale signs - if (line =~ /#{test}\s*($|\(|\()/) - raw_index += (index + 1) - tests_and_line_numbers << {:test => test, :line_number => raw_index} - break - end - end - end - - return tests_and_line_numbers - end - - def generate(module_name, runner_filepath, test_cases, mock_list) - require 'generate_test_runner.rb' - @test_runner_generator ||= UnityTestRunnerGenerator.new( @configurator.get_runner_config ) - @test_runner_generator.generate( module_name, - runner_filepath, - test_cases, - mock_list) - end -end diff --git a/vendor/ceedling/lib/preprocessinator.rb b/vendor/ceedling/lib/preprocessinator.rb deleted file mode 100644 index e5c46c3..0000000 --- a/vendor/ceedling/lib/preprocessinator.rb +++ /dev/null @@ -1,43 +0,0 @@ - -class Preprocessinator - - attr_reader :preprocess_file_proc - - constructor :preprocessinator_helper, :preprocessinator_includes_handler, :preprocessinator_file_handler, :task_invoker, :file_path_utils, :yaml_wrapper - - - def setup - # fashion ourselves callbacks @preprocessinator_helper can use - @preprocess_includes_proc = Proc.new { |filepath| self.preprocess_shallow_includes(filepath) } - @preprocess_file_proc = Proc.new { |filepath| self.preprocess_file(filepath) } - end - - - def preprocess_test_and_invoke_test_mocks(test) - @preprocessinator_helper.preprocess_includes(test, @preprocess_includes_proc) - - mocks_list = @preprocessinator_helper.assemble_mocks_list(test) - - @preprocessinator_helper.preprocess_mockable_headers(mocks_list, @preprocess_file_proc) - - @task_invoker.invoke_test_mocks(mocks_list) - - @preprocessinator_helper.preprocess_test_file(test, @preprocess_file_proc) - - return mocks_list - end - - def preprocess_shallow_includes(filepath) - dependencies_rule = @preprocessinator_includes_handler.form_shallow_dependencies_rule(filepath) - includes = @preprocessinator_includes_handler.extract_shallow_includes(dependencies_rule) - - @preprocessinator_includes_handler.write_shallow_includes_list( - @file_path_utils.form_preprocessed_includes_list_filepath(filepath), includes) - end - - def preprocess_file(filepath) - @preprocessinator_includes_handler.invoke_shallow_includes_list(filepath) - @preprocessinator_file_handler.preprocess_file( filepath, @yaml_wrapper.load(@file_path_utils.form_preprocessed_includes_list_filepath(filepath)) ) - end - -end diff --git a/vendor/ceedling/lib/preprocessinator_file_handler.rb b/vendor/ceedling/lib/preprocessinator_file_handler.rb deleted file mode 100644 index 65020ed..0000000 --- a/vendor/ceedling/lib/preprocessinator_file_handler.rb +++ /dev/null @@ -1,21 +0,0 @@ - - -class PreprocessinatorFileHandler - - constructor :preprocessinator_extractor, :configurator, :tool_executor, :file_path_utils, :file_wrapper - - - def preprocess_file(filepath, includes) - preprocessed_filepath = @file_path_utils.form_preprocessed_file_filepath(filepath) - - command = @tool_executor.build_command_line(@configurator.tools_test_file_preprocessor, filepath, preprocessed_filepath) - @tool_executor.exec(command[:line], command[:options]) - - contents = @preprocessinator_extractor.extract_base_file_from_preprocessed_expansion(preprocessed_filepath) - - includes.each{|include| contents.unshift("#include \"#{include}\"")} - - @file_wrapper.write(preprocessed_filepath, contents.join("\n")) - end - -end diff --git a/vendor/ceedling/lib/preprocessinator_includes_handler.rb b/vendor/ceedling/lib/preprocessinator_includes_handler.rb deleted file mode 100644 index 6199e4c..0000000 --- a/vendor/ceedling/lib/preprocessinator_includes_handler.rb +++ /dev/null @@ -1,55 +0,0 @@ - - -class PreprocessinatorIncludesHandler - - constructor :configurator, :tool_executor, :task_invoker, :file_path_utils, :yaml_wrapper, :file_wrapper - - # shallow includes: only those headers a source file explicitly includes - - def invoke_shallow_includes_list(filepath) - @task_invoker.invoke_test_shallow_include_lists( [@file_path_utils.form_preprocessed_includes_list_filepath(filepath)] ) - end - - # ask the preprocessor for a make-style dependency rule of only the headers the source file immediately includes - def form_shallow_dependencies_rule(filepath) - # change filename (prefix of '_') to prevent preprocessor from finding include files in temp directory containing file it's scanning - temp_filepath = @file_path_utils.form_temp_path(filepath, '_') - - # read the file and replace all include statements with a decorated version - # (decorating the names creates file names that don't exist, thus preventing the preprocessor - # from snaking out and discovering the entire include path that winds through the code) - contents = @file_wrapper.read(filepath) - contents.gsub!( /#include\s+\"\s*(\S+)\s*\"/, "#include \"\\1\"\n#include \"@@@@\\1\"" ) - @file_wrapper.write( temp_filepath, contents ) - - # extract the make-style dependency rule telling the preprocessor to - # ignore the fact that it can't find the included files - command = @tool_executor.build_command_line(@configurator.tools_test_includes_preprocessor, temp_filepath) - shell_result = @tool_executor.exec(command[:line], command[:options]) - - return shell_result[:output] - end - - # headers only; ignore any crazy .c includes - def extract_shallow_includes(make_rule) - list = [] - header_extension = @configurator.extension_header - - headers = make_rule.scan(/(\S+#{'\\'+header_extension})/).flatten # escape slashes before dot file extension - headers.uniq! - headers.map! { |header| header.sub(/(@@@@)|(.+\/)/, '') } - headers.sort! - - headers.each_with_index do |header, index| - break if (headers.size == (index-1)) - list << header if (header == headers[index + 1]) - end - - return list - end - - def write_shallow_includes_list(filepath, list) - @yaml_wrapper.dump(filepath, list) - end - -end diff --git a/vendor/ceedling/lib/project_config_manager.rb b/vendor/ceedling/lib/project_config_manager.rb deleted file mode 100644 index 3599689..0000000 --- a/vendor/ceedling/lib/project_config_manager.rb +++ /dev/null @@ -1,38 +0,0 @@ -require 'constants' - - -class ProjectConfigManager - - attr_reader :options_files, :release_config_changed, :test_config_changed - attr_accessor :config_hash - - constructor :cacheinator, :yaml_wrapper - - - def setup - @options_files = [] - @release_config_changed = false - @test_config_changed = false - end - - - def merge_options(config_hash, option_filepath) - @options_files << File.basename( option_filepath ) - config_hash.deep_merge( @yaml_wrapper.load( option_filepath ) ) - return config_hash - end - - - - def process_release_config_change - # has project configuration changed since last release build - @release_config_changed = @cacheinator.diff_cached_release_config?( @config_hash ) - end - - - def process_test_config_change - # has project configuration changed since last test build - @test_config_changed = @cacheinator.diff_cached_test_config?( @config_hash ) - end - -end diff --git a/vendor/ceedling/lib/release_invoker.rb b/vendor/ceedling/lib/release_invoker.rb deleted file mode 100644 index d51bf9b..0000000 --- a/vendor/ceedling/lib/release_invoker.rb +++ /dev/null @@ -1,58 +0,0 @@ -require 'constants' - - -class ReleaseInvoker - - constructor :configurator, :release_invoker_helper, :build_invoker_utils, :dependinator, :task_invoker, :file_path_utils, :file_wrapper - - - def setup_and_invoke_c_objects( c_files ) - objects = @file_path_utils.form_release_build_c_objects_filelist( c_files ) - - begin - @release_invoker_helper.process_deep_dependencies( @file_path_utils.form_release_dependencies_filelist( c_files ) ) - - @dependinator.enhance_release_file_dependencies( objects ) - @task_invoker.invoke_release_objects( objects ) - rescue => e - @build_invoker_utils.process_exception( e, RELEASE_SYM, false ) - end - - return objects - end - - - def setup_and_invoke_asm_objects( asm_files ) - objects = @file_path_utils.form_release_build_asm_objects_filelist( asm_files ) - - begin - @dependinator.enhance_release_file_dependencies( objects ) - @task_invoker.invoke_release_objects( objects ) - rescue => e - @build_invoker_utils.process_exception( e, RELEASE_SYM, false ) - end - - return objects - end - - - def refresh_c_deep_dependencies - return if (not @configurator.project_use_deep_dependencies) - - @file_wrapper.rm_f( - @file_wrapper.directory_listing( - File.join( @configurator.project_release_dependencies_path, '*' + @configurator.extension_dependencies ) ) ) - - @release_invoker_helper.process_deep_dependencies( - @file_path_utils.form_release_dependencies_filelist( - @configurator.collection_all_source ) ) - end - - - def artifactinate( *files ) - files.flatten.each do |file| - @file_wrapper.cp( file, @configurator.project_release_artifacts_path ) if @file_wrapper.exist?( file ) - end - end - -end diff --git a/vendor/ceedling/lib/reportinator.rb b/vendor/ceedling/lib/reportinator.rb deleted file mode 100644 index a41e9a0..0000000 --- a/vendor/ceedling/lib/reportinator.rb +++ /dev/null @@ -1,9 +0,0 @@ - -class Reportinator - - def generate_banner(message, width=nil) - dash_count = ((width.nil?) ? message.strip.length : width) - return "#{'-' * dash_count}\n#{message}\n#{'-' * dash_count}\n" - end - -end diff --git a/vendor/ceedling/lib/tasks_vendor.rake b/vendor/ceedling/lib/tasks_vendor.rake deleted file mode 100644 index 0d07154..0000000 --- a/vendor/ceedling/lib/tasks_vendor.rake +++ /dev/null @@ -1,36 +0,0 @@ -require 'constants' -require 'file_path_utils' - -# create file dependencies to ensure C-based components of vendor tools are recompiled when they are updated with new versions -# forming these explicitly rather than depend on auxiliary dependencies so all scenarios are explicitly covered - -file( @ceedling[:file_path_utils].form_test_build_object_filepath( UNITY_C_FILE ) => [ - FilePathUtils.form_ceedling_vendor_path( UNITY_LIB_PATH, UNITY_C_FILE ), - FilePathUtils.form_ceedling_vendor_path( UNITY_LIB_PATH, UNITY_H_FILE ), - FilePathUtils.form_ceedling_vendor_path( UNITY_LIB_PATH, UNITY_INTERNALS_H_FILE ) ] - ) - - -if (PROJECT_USE_MOCKS) -file( @ceedling[:file_path_utils].form_test_build_object_filepath( CMOCK_C_FILE ) => [ - FilePathUtils.form_ceedling_vendor_path( CMOCK_LIB_PATH, CMOCK_C_FILE ), - FilePathUtils.form_ceedling_vendor_path( CMOCK_LIB_PATH, CMOCK_H_FILE ) ] - ) -end - - -if (PROJECT_USE_EXCEPTIONS) -file( @ceedling[:file_path_utils].form_test_build_object_filepath( CEXCEPTION_C_FILE ) => [ - FilePathUtils.form_ceedling_vendor_path( CEXCEPTION_LIB_PATH, CEXCEPTION_C_FILE ), - FilePathUtils.form_ceedling_vendor_path( CEXCEPTION_LIB_PATH, CEXCEPTION_H_FILE ) ] - ) -end - - -if (PROJECT_USE_EXCEPTIONS and PROJECT_RELEASE_BUILD) -file( @ceedling[:file_path_utils].form_release_build_c_object_filepath( CEXCEPTION_C_FILE ) => [ - FilePathUtils.form_ceedling_vendor_path( CEXCEPTION_LIB_PATH, CEXCEPTION_C_FILE ), - FilePathUtils.form_ceedling_vendor_path( CEXCEPTION_LIB_PATH, CEXCEPTION_H_FILE ) ] - ) -end - diff --git a/vendor/ceedling/lib/test_invoker.rb b/vendor/ceedling/lib/test_invoker.rb deleted file mode 100644 index a7a41ee..0000000 --- a/vendor/ceedling/lib/test_invoker.rb +++ /dev/null @@ -1,97 +0,0 @@ -require 'constants' - - -class TestInvoker - - attr_reader :sources, :tests, :mocks - - constructor :configurator, - :test_invoker_helper, - :plugin_manager, - :streaminator, - :preprocessinator, - :task_invoker, - :dependinator, - :project_config_manager, - :build_invoker_utils, - :file_path_utils, - :file_wrapper - - def setup - @sources = [] - @tests = [] - @mocks = [] - end - - def setup_and_invoke(tests, context=TEST_SYM, options={:force_run => true}) - - @tests = tests - - @project_config_manager.process_test_config_change - - @tests.each do |test| - # announce beginning of test run - header = "Test '#{File.basename(test)}'" - @streaminator.stdout_puts("\n\n#{header}\n#{'-' * header.length}") - - begin - @plugin_manager.pre_test - - # collect up test fixture pieces & parts - runner = @file_path_utils.form_runner_filepath_from_test( test ) - mock_list = @preprocessinator.preprocess_test_and_invoke_test_mocks( test ) - sources = @test_invoker_helper.extract_sources( test ) - extras = @configurator.collection_test_fixture_extra_link_objects - core = [test] + mock_list + sources - objects = @file_path_utils.form_test_build_objects_filelist( [runner] + core + extras ) - results_pass = @file_path_utils.form_pass_results_filepath( test ) - results_fail = @file_path_utils.form_fail_results_filepath( test ) - - # clean results files so we have a missing file with which to kick off rake's dependency rules - @test_invoker_helper.clean_results( {:pass => results_pass, :fail => results_fail}, options ) - - # load up auxiliary dependencies so deep changes cause rebuilding appropriately - @test_invoker_helper.process_deep_dependencies( core ) do |dependencies_list| - @dependinator.load_test_object_deep_dependencies( dependencies_list ) - end - - # tell rake to create test runner if needed - @task_invoker.invoke_test_runner( runner ) - - # enhance object file dependencies to capture externalities influencing regeneration - @dependinator.enhance_test_build_object_dependencies( objects ) - - # associate object files with executable - @dependinator.setup_test_executable_dependencies( test, objects ) - - # 3, 2, 1... launch - @task_invoker.invoke_test_results( results_pass ) - rescue => e - @build_invoker_utils.process_exception( e, context ) - ensure - @plugin_manager.post_test - end - - # store away what's been processed - @mocks.concat( mock_list ) - @sources.concat( sources ) - end - - # post-process collected mock list - @mocks.uniq! - - # post-process collected sources list - @sources.uniq! - end - - - def refresh_deep_dependencies - @file_wrapper.rm_f( - @file_wrapper.directory_listing( - File.join( @configurator.project_test_dependencies_path, '*' + @configurator.extension_dependencies ) ) ) - - @test_invoker_helper.process_deep_dependencies( - @configurator.collection_all_tests + @configurator.collection_all_source ) - end - -end diff --git a/vendor/ceedling/plugins/beep/README.md b/vendor/ceedling/plugins/beep/README.md new file mode 100644 index 0000000..e59d881 --- /dev/null +++ b/vendor/ceedling/plugins/beep/README.md @@ -0,0 +1,22 @@ +ceedling-beep +============= + +This is a simple plugin that just beeps at the end of a build and/or test sequence. Are you getting too distracted surfing +the internet, chatting with coworkers, or swordfighting while it's building or testing? The friendly beep will let you know +it's time to pay attention again. + +This plugin has very few configuration options. At this time it can beep on completion of a task and/or on an error condition. +For each of these, you can configure the method that it should beep. + +``` +:tools: + :beep_on_done: :bell + :beep_on_error: :bell +``` + +Each of these have the following options: + + - :bell - this option uses the ASCII bell character out stdout + - :speaker_test - this uses the linux speaker-test command if installed + +Very likely, we'll be adding to this list if people find this to be useful. diff --git a/vendor/ceedling/plugins/beep/lib/beep.rb b/vendor/ceedling/plugins/beep/lib/beep.rb new file mode 100644 index 0000000..6a6d01a --- /dev/null +++ b/vendor/ceedling/plugins/beep/lib/beep.rb @@ -0,0 +1,40 @@ +require 'ceedling/plugin' +require 'ceedling/constants' + +class Beep < Plugin + + attr_reader :config + + def setup + @config = { + :on_done => ((defined? TOOLS_BEEP_ON_DONE) ? TOOLS_BEEP_ON_DONE : :bell ), + :on_error => ((defined? TOOLS_BEEP_ON_ERROR) ? TOOLS_BEEP_ON_ERROR : :bell ), + } + end + + def post_build + beep @config[:on_done] + end + + def post_error + beep @config[:on_error] + end + + private + + def beep(method = :none) + case method + when :bell + if (SystemWrapper.windows?) + puts "echo '\007'" + else + puts "echo -ne '\007'" + end + when :speaker_test + `speaker-test -t sine -f 1000 -l 1` + else + #do nothing with illegal or :none + end + end +end + diff --git a/vendor/ceedling/plugins/bullseye/README.md b/vendor/ceedling/plugins/bullseye/README.md new file mode 100644 index 0000000..ab0b53b --- /dev/null +++ b/vendor/ceedling/plugins/bullseye/README.md @@ -0,0 +1,76 @@ +ceedling-bullseye +================= + +# Plugin Overview + +Plugin for integrating Bullseye code coverage tool into Ceedling projects. +This plugin requires a working license to Bullseye code coverage tools. The tools +must be within the path or the path should be added to the environment in the +`project.yml file`. + +## Configuration + +The bullseye plugin supports configuration options via your `project.yml` provided +by Ceedling. The following is a typical configuration example: + +``` +:bullseye: + :auto_license: TRUE +:plugins: + :bullseye_lib_path: [] +:paths: + :bullseye_toolchain_include: [] + +:tools: + :bullseye_instrumentation: + :executable: covc + :arguments: + - '--file $': ENVIRONMENT_COVFILE + - -q + - ${1} + :bullseye_compiler: + :executable: gcc + :arguments: + - -g + - -I"$": COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR + - -I"$": COLLECTION_PATHS_BULLSEYE_TOOLCHAIN_INCLUDE + - -D$: COLLECTION_DEFINES_TEST_AND_VENDOR + - -DBULLSEYE_COMPILER + - -c "${1}" + - -o "${2}" + :bullseye_linker: + :executable: gcc + :arguments: + - ${1} + - -o ${2} + - -L$: PLUGINS_BULLSEYE_LIB_PATH + - -lcov + :bullseye_fixture: + :executable: ${1} + :bullseye_report_covsrc: + :executable: covsrc + :arguments: + - '--file $': ENVIRONMENT_COVFILE + - -q + - -w140 + :bullseye_report_covfn: + :executable: covfn + :stderr_redirect: :auto + :arguments: + - '--file $': ENVIRONMENT_COVFILE + - --width 120 + - --no-source + - '"${1}"' + :bullseye_browser: + :executable: CoverageBrowser + :background_exec: :auto + :optional: TRUE + :arguments: + - '"$"': ENVIRONMENT_COVFILE +``` + +## Example Usage + +```sh +ceedling bullseye:all utils:bullseye +``` diff --git a/vendor/ceedling/plugins/bullseye/bullseye.rake b/vendor/ceedling/plugins/bullseye/bullseye.rake index 5ee4ff4..11073e7 100644 --- a/vendor/ceedling/plugins/bullseye/bullseye.rake +++ b/vendor/ceedling/plugins/bullseye/bullseye.rake @@ -1,4 +1,3 @@ - directory(BULLSEYE_BUILD_OUTPUT_PATH) directory(BULLSEYE_RESULTS_PATH) directory(BULLSEYE_ARTIFACTS_PATH) @@ -9,21 +8,23 @@ CLEAN.include(File.join(BULLSEYE_RESULTS_PATH, '*')) CLEAN.include(File.join(BULLSEYE_DEPENDENCIES_PATH, '*')) CLOBBER.include(File.join(BULLSEYE_BUILD_PATH, '**/*')) - +PLUGINS_BULLSEYE_LIB_PATH = 'C:\\tools\\BullseyeCoverage\\lib' if not defined?(PLUGINS_BULLSEYE_LIB_PATH) rule(/#{BULLSEYE_BUILD_OUTPUT_PATH}\/#{'.+\\'+EXTENSION_OBJECT}$/ => [ - proc do |task_name| - @ceedling[:file_finder].find_compilation_input_file(task_name) - end - ]) do |object| + proc do |task_name| + @ceedling[:file_finder].find_compilation_input_file(task_name) + end + ]) do |object| - if (File.basename(object.source) =~ /^(#{PROJECT_TEST_FILE_PREFIX}|#{CMOCK_MOCK_PREFIX}|#{BULLSEYE_IGNORE_SOURCES.join('|')})/i) + if File.basename(object.source) =~ /^(#{PROJECT_TEST_FILE_PREFIX}|#{CMOCK_MOCK_PREFIX}|#{BULLSEYE_IGNORE_SOURCES.join('|')})/i @ceedling[:generator].generate_object_file( TOOLS_BULLSEYE_COMPILER, + OPERATION_COMPILE_SYM, BULLSEYE_SYM, object.source, object.name, - @ceedling[:file_path_utils].form_test_build_list_filepath( object.name ) ) + @ceedling[:file_path_utils].form_test_build_list_filepath(object.name) + ) else @ceedling[BULLSEYE_SYM].generate_coverage_object_file(object.source, object.name) end @@ -31,44 +32,50 @@ rule(/#{BULLSEYE_BUILD_OUTPUT_PATH}\/#{'.+\\'+EXTENSION_OBJECT}$/ => [ end rule(/#{BULLSEYE_BUILD_OUTPUT_PATH}\/#{'.+\\'+EXTENSION_EXECUTABLE}$/) do |bin_file| + lib_args = @ceedling[:test_invoker].convert_libraries_to_arguments() + lib_paths = @ceedling[:test_invoker].get_library_paths_to_arguments() @ceedling[:generator].generate_executable_file( TOOLS_BULLSEYE_LINKER, BULLSEYE_SYM, bin_file.prerequisites, bin_file.name, - @ceedling[:file_path_utils].form_test_build_map_filepath(bin_file.name)) + @ceedling[:file_path_utils].form_test_build_map_filepath(bin_file.name), + lib_args, + lib_paths + ) end rule(/#{BULLSEYE_RESULTS_PATH}\/#{'.+\\'+EXTENSION_TESTPASS}$/ => [ - proc do |task_name| - @ceedling[:file_path_utils].form_test_executable_filepath(task_name) - end - ]) do |test_result| + proc do |task_name| + @ceedling[:file_path_utils].form_test_executable_filepath(task_name) + end + ]) do |test_result| @ceedling[:generator].generate_test_results(TOOLS_BULLSEYE_FIXTURE, BULLSEYE_SYM, test_result.source, test_result.name) end rule(/#{BULLSEYE_DEPENDENCIES_PATH}\/#{'.+\\'+EXTENSION_DEPENDENCIES}$/ => [ - proc do |task_name| - @ceedling[:file_finder].find_compilation_input_file(task_name) - end - ]) do |dep| + proc do |task_name| + @ceedling[:file_finder].find_compilation_input_file(task_name) + end + ]) do |dep| @ceedling[:generator].generate_dependencies_file( TOOLS_TEST_DEPENDENCIES_GENERATOR, BULLSEYE_SYM, dep.source, File.join(BULLSEYE_BUILD_OUTPUT_PATH, File.basename(dep.source).ext(EXTENSION_OBJECT) ), - dep.name) + dep.name + ) end task :directories => [BULLSEYE_BUILD_OUTPUT_PATH, BULLSEYE_RESULTS_PATH, BULLSEYE_DEPENDENCIES_PATH, BULLSEYE_ARTIFACTS_PATH] namespace BULLSEYE_SYM do + task source_coverage: COLLECTION_ALL_SOURCE.pathmap("#{BULLSEYE_BUILD_OUTPUT_PATH}/%n#{@ceedling[:configurator].extension_object}") - task :source_coverage => COLLECTION_ALL_SOURCE.pathmap("#{BULLSEYE_BUILD_OUTPUT_PATH}/%n#{@ceedling[:configurator].extension_object}") - - desc "Run code coverage for all tests" - task :all => [:directories] do + desc 'Run code coverage for all tests' + task all: [:test_deps] do @ceedling[:configurator].replace_flattened_config(@ceedling[BULLSEYE_SYM].config) + @ceedling[BULLSEYE_SYM].enableBullseye(true) @ceedling[:test_invoker].setup_and_invoke(COLLECTION_ALL_TESTS, BULLSEYE_SYM) @ceedling[:configurator].restore_config end @@ -78,62 +85,66 @@ namespace BULLSEYE_SYM do message = "\nOops! '#{BULLSEYE_ROOT_NAME}:*' isn't a real task. " + "Use a real test or source file name (no path) in place of the wildcard.\n" + "Example: rake #{BULLSEYE_ROOT_NAME}:foo.c\n\n" - + @ceedling[:streaminator].stdout_puts( message ) end - - desc "Run tests by matching regular expression pattern." - task :pattern, [:regex] => [:directories] do |t, args| + + desc 'Run tests by matching regular expression pattern.' + task :pattern, [:regex] => [:test_deps] do |_t, args| matches = [] - + COLLECTION_ALL_TESTS.each do |test| matches << test if test =~ /#{args.regex}/ end - - if (matches.size > 0) + + if !matches.empty? @ceedling[:configurator].replace_flattened_config(@ceedling[BULLSEYE_SYM].config) - @ceedling[:test_invoker].setup_and_invoke(matches, BULLSEYE_SYM, {:force_run => false}) + @ceedling[BULLSEYE_SYM].enableBullseye(true) + @ceedling[:test_invoker].setup_and_invoke(matches, BULLSEYE_SYM, force_run: false) @ceedling[:configurator].restore_config else @ceedling[:streaminator].stdout_puts("\nFound no tests matching pattern /#{args.regex}/.") end end - desc "Run tests whose test path contains [dir] or [dir] substring." - task :path, [:dir] => [:directories] do |t, args| + desc 'Run tests whose test path contains [dir] or [dir] substring.' + task :path, [:dir] => [:test_deps] do |_t, args| matches = [] - + COLLECTION_ALL_TESTS.each do |test| - matches << test if File.dirname(test).include?(args.dir.gsub(/\\/, '/')) + matches << test if File.dirname(test).include?(args.dir.tr('\\', '/')) end - - if (matches.size > 0) + + if !matches.empty? @ceedling[:configurator].replace_flattened_config(@ceedling[BULLSEYE_SYM].config) - @ceedling[:test_invoker].setup_and_invoke(matches, BULLSEYE_SYM, {:force_run => false}) + @ceedling[BULLSEYE_SYM].enableBullseye(true) + @ceedling[:test_invoker].setup_and_invoke(matches, BULLSEYE_SYM, force_run: false) @ceedling[:configurator].restore_config else @ceedling[:streaminator].stdout_puts("\nFound no tests including the given path or path component.") end end - desc "Run code coverage for changed files" - task :delta => [:directories] do + desc 'Run code coverage for changed files' + task delta: [:test_deps] do @ceedling[:configurator].replace_flattened_config(@ceedling[BULLSEYE_SYM].config) + @ceedling[BULLSEYE_SYM].enableBullseye(true) @ceedling[:test_invoker].setup_and_invoke(COLLECTION_ALL_TESTS, BULLSEYE_SYM, {:force_run => false}) @ceedling[:configurator].restore_config end - + # use a rule to increase efficiency for large projects # bullseye test tasks by regex rule(/^#{BULLSEYE_TASK_ROOT}\S+$/ => [ proc do |task_name| test = task_name.sub(/#{BULLSEYE_TASK_ROOT}/, '') - test = "#{PROJECT_TEST_FILE_PREFIX}#{test}" if not (test.start_with?(PROJECT_TEST_FILE_PREFIX)) + test = "#{PROJECT_TEST_FILE_PREFIX}#{test}" unless test.start_with?(PROJECT_TEST_FILE_PREFIX) @ceedling[:file_finder].find_test_from_file_path(test) end ]) do |test| - @ceedling[:rake_wrapper][:directories].invoke + @ceedling[:rake_wrapper][:test_deps].invoke @ceedling[:configurator].replace_flattened_config(@ceedling[BULLSEYE_SYM].config) + @ceedling[BULLSEYE_SYM].enableBullseye(true) @ceedling[:test_invoker].setup_and_invoke([test.source], BULLSEYE_SYM) @ceedling[:configurator].restore_config end @@ -144,6 +155,7 @@ if PROJECT_USE_DEEP_DEPENDENCIES namespace REFRESH_SYM do task BULLSEYE_SYM do @ceedling[:configurator].replace_flattened_config(@ceedling[BULLSEYE_SYM].config) + @ceedling[BULLSEYE_SYM].enableBullseye(true) @ceedling[:test_invoker].refresh_deep_dependencies @ceedling[:configurator].restore_config end @@ -151,12 +163,11 @@ end end namespace UTILS_SYM do - + desc "Open Bullseye code coverage browser" task BULLSEYE_SYM do - command = @ceedling[:tool_executor].build_command_line(TOOLS_BULLSEYE_BROWSER) + command = @ceedling[:tool_executor].build_command_line(TOOLS_BULLSEYE_BROWSER, []) @ceedling[:tool_executor].exec(command[:line], command[:options]) end - -end +end diff --git a/vendor/ceedling/plugins/bullseye/config/defaults.yml b/vendor/ceedling/plugins/bullseye/config/defaults.yml index b4f0783..ed261d8 100644 --- a/vendor/ceedling/plugins/bullseye/config/defaults.yml +++ b/vendor/ceedling/plugins/bullseye/config/defaults.yml @@ -1,5 +1,9 @@ --- +:bullseye: + :auto_license: TRUE +:plugins: + :bullseye_lib_path: [] :paths: :bullseye_toolchain_include: [] diff --git a/vendor/ceedling/plugins/bullseye/lib/bullseye.rb b/vendor/ceedling/plugins/bullseye/lib/bullseye.rb index 02149c4..ffa444a 100644 --- a/vendor/ceedling/plugins/bullseye/lib/bullseye.rb +++ b/vendor/ceedling/plugins/bullseye/lib/bullseye.rb @@ -1,5 +1,5 @@ -require 'plugin' -require 'constants' +require 'ceedling/plugin' +require 'ceedling/constants' BULLSEYE_ROOT_NAME = 'bullseye' BULLSEYE_TASK_ROOT = BULLSEYE_ROOT_NAME + ':' @@ -41,10 +41,11 @@ def generate_coverage_object_file(source, object) compile_command = @ceedling[:tool_executor].build_command_line( TOOLS_BULLSEYE_COMPILER, + @ceedling[:flaginator].flag_down( OPERATION_COMPILE_SYM, BULLSEYE_SYM, source ), source, object, @ceedling[:file_path_utils].form_test_build_list_filepath( object ) ) - coverage_command = @ceedling[:tool_executor].build_command_line(TOOLS_BULLSEYE_INSTRUMENTATION, compile_command[:line] ) + coverage_command = @ceedling[:tool_executor].build_command_line(TOOLS_BULLSEYE_INSTRUMENTATION, [], compile_command[:line] ) shell_result = @ceedling[:tool_executor].exec( coverage_command[:line], coverage_command[:options] ) @@ -59,7 +60,7 @@ def post_test_fixture_execute(arg_hash) @result_list << arg_hash[:result_file] end end - + def post_build return if (not @ceedling[:task_invoker].invoked?(/^#{BULLSEYE_TASK_ROOT}/)) @@ -79,7 +80,7 @@ def post_build # coverage results return if (verify_coverage_file() == false) if (@ceedling[:task_invoker].invoked?(/^#{BULLSEYE_TASK_ROOT}(all|delta)/)) - command = @ceedling[:tool_executor].build_command_line(TOOLS_BULLSEYE_REPORT_COVSRC) + command = @ceedling[:tool_executor].build_command_line(TOOLS_BULLSEYE_REPORT_COVSRC, []) shell_result = @ceedling[:tool_executor].exec(command[:line], command[:options]) report_coverage_results_all(shell_result[:output]) else @@ -105,7 +106,25 @@ def summary shell_result = @ceedling[:tool_executor].exec(command[:line], command[:options]) report_coverage_results_all(shell_result[:output]) end + + def enableBullseye(enable) + if BULLSEYE_AUTO_LICENSE + if (enable) + args = ['push', 'on'] + @ceedling[:streaminator].stdout_puts("Enabling Bullseye") + else + args = ['pop'] + @ceedling[:streaminator].stdout_puts("Reverting Bullseye to previous state") + end + args.each do |arg| + command = @ceedling[:tool_executor].build_command_line(TOOLS_BULLSEYE_BUILD_ENABLE_DISABLE, [], arg) + shell_result = @ceedling[:tool_executor].exec(command[:line], command[:options]) + end + + end + end + private ################################### def report_coverage_results_all(coverage) @@ -137,7 +156,7 @@ def report_per_function_coverage_results(sources) coverage_sources.delete_if {|item| item =~ /#{BULLSEYE_IGNORE_SOURCES.join('|')}#{EXTENSION_SOURCE}$/} coverage_sources.each do |source| - command = @ceedling[:tool_executor].build_command_line(TOOLS_BULLSEYE_REPORT_COVFN, source) + command = @ceedling[:tool_executor].build_command_line(TOOLS_BULLSEYE_REPORT_COVFN, [], source) shell_results = @ceedling[:tool_executor].exec(command[:line], command[:options]) coverage_results = shell_results[:output].deep_clone coverage_results.sub!(/.*\n.*\n/,'') # Remove the Bullseye tool banner @@ -168,5 +187,8 @@ def verify_coverage_file # end blocks always executed following rake run END { # cache our input configurations to use in comparison upon next execution - @ceedling[:cacheinator].cache_test_config( @ceedling[:setupinator].config_hash ) if (@ceedling[:task_invoker].invoked?(/^#{BULLSEYE_TASK_ROOT}/)) + if (@ceedling[:task_invoker].invoked?(/^#{BULLSEYE_TASK_ROOT}/)) + @ceedling[:cacheinator].cache_test_config( @ceedling[:setupinator].config_hash ) + @ceedling[BULLSEYE_SYM].enableBullseye(false) + end } diff --git a/vendor/ceedling/plugins/bullseye/readme.txt b/vendor/ceedling/plugins/bullseye/readme.txt deleted file mode 100644 index e69de29..0000000 diff --git a/vendor/ceedling/plugins/colour_report/README.md b/vendor/ceedling/plugins/colour_report/README.md new file mode 100644 index 0000000..4e0fcd4 --- /dev/null +++ b/vendor/ceedling/plugins/colour_report/README.md @@ -0,0 +1,20 @@ +ceedling-colour-report +====================== + +## Overview + +The colour_report replaces the normal ceedling "pretty" output with +a colorized variant, in order to make the results easier to read from +a standard command line. This is very useful on developer machines, but +can occasionally cause problems with parsing on CI servers. + +## Setup + +Enable the plugin in your project.yml by adding `colour_report` +to the list of enabled plugins. + +``` YAML +:plugins: + :enabled: + - colour_report +``` diff --git a/vendor/ceedling/plugins/colour_report/lib/colour_report.rb b/vendor/ceedling/plugins/colour_report/lib/colour_report.rb new file mode 100644 index 0000000..1211eab --- /dev/null +++ b/vendor/ceedling/plugins/colour_report/lib/colour_report.rb @@ -0,0 +1,16 @@ +require 'ceedling/plugin' +require 'ceedling/streaminator' +require 'ceedling/constants' + +class ColourReport < Plugin + + def setup + @ceedling[:stream_wrapper].stdout_override(&ColourReport.method(:colour_stdout)) + end + + def self.colour_stdout(string) + require 'colour_reporter.rb' + report string + end + +end diff --git a/vendor/ceedling/plugins/command_hooks/README.md b/vendor/ceedling/plugins/command_hooks/README.md new file mode 100644 index 0000000..8ac64af --- /dev/null +++ b/vendor/ceedling/plugins/command_hooks/README.md @@ -0,0 +1,53 @@ +ceedling-command-hooks +====================== + +Plugin for easily calling command line tools at various points in the build process + +Define any of these sections in :tools: to provide additional hooks to be called on demand: + +``` + :pre_mock_generate + :post_mock_generate + :pre_runner_generate + :post_runner_generate + :pre_compile_execute + :post_compile_execute + :pre_link_execute + :post_link_execute + :pre_test_fixture_execute + :pre_test + :post_test + :pre_release + :post_release + :pre_build + :post_build +``` + +Each of these tools can support an :executable string and an :arguments list, like so: + +``` +:tools: + :post_link_execute: + :executable: objcopy.exe + :arguments: + - ${1} #This is replaced with the executable name + - output.srec + - --strip-all +``` + +You may also specify an array of executables to be called in a particular place, like so: + +``` +:tools: + :post_test: + - :executable: echo + :arguments: "${1} was glorious!" + - :executable: echo + :arguments: + - it kinda made me cry a little. + - you? +``` + +Please note that it varies which arguments are being parsed down to the +hooks. For now see `command_hooks.rb` to figure out which suits you best. +Happy Tweaking! diff --git a/vendor/ceedling/plugins/command_hooks/lib/command_hooks.rb b/vendor/ceedling/plugins/command_hooks/lib/command_hooks.rb new file mode 100644 index 0000000..4bf8b53 --- /dev/null +++ b/vendor/ceedling/plugins/command_hooks/lib/command_hooks.rb @@ -0,0 +1,92 @@ +require 'ceedling/plugin' +require 'ceedling/constants' +class CommandHooks < Plugin + + attr_reader :config + + def setup + @config = { + :pre_mock_generate => ((defined? TOOLS_PRE_MOCK_GENERATE) ? TOOLS_PRE_MOCK_GENERATE : nil ), + :post_mock_generate => ((defined? TOOLS_POST_MOCK_GENERATE) ? TOOLS_POST_MOCK_GENERATE : nil ), + :pre_runner_generate => ((defined? TOOLS_PRE_RUNNER_GENERATE) ? TOOLS_PRE_RUNNER_GENERATE : nil ), + :post_runner_generate => ((defined? TOOLS_POST_RUNNER_GENERATE) ? TOOLS_POST_RUNNER_GENERATE : nil ), + :pre_compile_execute => ((defined? TOOLS_PRE_COMPILE_EXECUTE) ? TOOLS_PRE_COMPILE_EXECUTE : nil ), + :post_compile_execute => ((defined? TOOLS_POST_COMPILE_EXECUTE) ? TOOLS_POST_COMPILE_EXECUTE : nil ), + :pre_link_execute => ((defined? TOOLS_PRE_LINK_EXECUTE) ? TOOLS_PRE_LINK_EXECUTE : nil ), + :post_link_execute => ((defined? TOOLS_POST_LINK_EXECUTE) ? TOOLS_POST_LINK_EXECUTE : nil ), + :pre_test_fixture_execute => ((defined? TOOLS_PRE_TEST_FIXTURE_EXECUTE) ? TOOLS_PRE_TEST_FIXTURE_EXECUTE : nil ), + :post_test_fixture_execute => ((defined? TOOLS_POST_TEST_FIXTURE_EXECUTE) ? TOOLS_POST_TEST_FIXTURE_EXECUTE : nil ), + :pre_test => ((defined? TOOLS_PRE_TEST) ? TOOLS_PRE_TEST : nil ), + :post_test => ((defined? TOOLS_POST_TEST) ? TOOLS_POST_TEST : nil ), + :pre_release => ((defined? TOOLS_PRE_RELEASE) ? TOOLS_PRE_RELEASE : nil ), + :post_release => ((defined? TOOLS_POST_RELEASE) ? TOOLS_POST_RELEASE : nil ), + :pre_build => ((defined? TOOLS_PRE_BUILD) ? TOOLS_PRE_BUILD : nil ), + :post_build => ((defined? TOOLS_POST_BUILD) ? TOOLS_POST_BUILD : nil ), + :post_error => ((defined? TOOLS_POST_ERROR) ? TOOLS_POST_ERROR : nil ), + } + @plugin_root = File.expand_path(File.join(File.dirname(__FILE__), '..')) + end + + def pre_mock_generate(arg_hash); run_hook(:pre_mock_generate, arg_hash[:header_file] ); end + def post_mock_generate(arg_hash); run_hook(:post_mock_generate, arg_hash[:header_file] ); end + def pre_runner_generate(arg_hash); run_hook(:pre_runner_generate, arg_hash[:source ] ); end + def post_runner_generate(arg_hash); run_hook(:post_runner_generate, arg_hash[:runner_file] ); end + def pre_compile_execute(arg_hash); run_hook(:pre_compile_execute, arg_hash[:source_file] ); end + def post_compile_execute(arg_hash); run_hook(:post_compile_execute, arg_hash[:object_file] ); end + def pre_link_execute(arg_hash); run_hook(:pre_link_execute, arg_hash[:executable] ); end + def post_link_execute(arg_hash); run_hook(:post_link_execute, arg_hash[:executable] ); end + def pre_test_fixture_execute(arg_hash); run_hook(:pre_test_fixture_execute, arg_hash[:executable] ); end + def post_test_fixture_execute(arg_hash); run_hook(:post_test_fixture_execute, arg_hash[:executable] ); end + def pre_test(test); run_hook(:pre_test, test ); end + def post_test(test); run_hook(:post_test, test ); end + def pre_release; run_hook(:pre_release ); end + def post_release; run_hook(:post_release ); end + def pre_build; run_hook(:pre_build ); end + def post_build; run_hook(:post_build ); end + def post_error; run_hook(:post_error ); end + + private + + ## + # Run a hook if its available. + # + # :args: + # - hook: Name of the hook to run + # - name: Name of file (default: "") + # + # :return: + # shell_result. + # + def run_hook_step(hook, name="") + if (hook[:executable]) + # Handle argument replacemant ({$1}), and get commandline + cmd = @ceedling[:tool_executor].build_command_line( hook, [], name ) + shell_result = @ceedling[:tool_executor].exec(cmd[:line], cmd[:options]) + end + end + + ## + # Run a hook if its available. + # + # If __which_hook__ is an array, run each of them sequentially. + # + # :args: + # - which_hook: Name of the hook to run + # - name: Name of file + # + def run_hook(which_hook, name="") + if (@config[which_hook]) + @ceedling[:streaminator].stdout_puts("Running Hook #{which_hook}...", Verbosity::NORMAL) + if (@config[which_hook].is_a? Array) + @config[which_hook].each do |hook| + run_hook_step(hook, name) + end + elsif (@config[which_hook].is_a? Hash) + run_hook_step( @config[which_hook], name ) + else + @ceedling[:streaminator].stdout_puts("Hook #{which_hook} was poorly formed", Verbosity::COMPLAINT) + end + end + end +end + diff --git a/vendor/ceedling/plugins/compile_commands_json/README.md b/vendor/ceedling/plugins/compile_commands_json/README.md new file mode 100644 index 0000000..ea80b73 --- /dev/null +++ b/vendor/ceedling/plugins/compile_commands_json/README.md @@ -0,0 +1,29 @@ +compile_commands_json +===================== + +## Overview + +Syntax highlighting and code completion are hard. Historically each editor or IDE has implemented their own and then competed amongst themselves to offer the best experience for developers. Often developers would still to an IDE that felt cumbersome and slow just because it had the best syntax highlighting on the market. If doing it for one language is hard (and it is) imagine doing it for dozens of them. Imagine a full stack developer who has to work with CSS, HTML, JavaScript and some Ruby - they need excellent support in all those languages which just made things even harder. + +In June of 2016, Microsoft with Red Hat and Codenvy got together to create a standard called the Language Server Protocol (LSP). The idea was simple, by standardising on one protocol, all the IDEs and editors out there would only have to support LSP, and not have custom plugins for each language. In turn, the backend code that actually does the highlighting can be written once and used by any IDE that supports LSP. Many editors already support it such as Sublime Text, vim and emacs. This means that if you're using a crufty old IDE or worse, you're using a shiny new editor without code completion, then this could be just the upgrade you're looking for! + +For C and C++ projects, many people use the `clangd` backend. So that it can do things like "go to definition", `clangd` needs to know how to build the project so that it can figure out all the pieces to the puzzle. There are manual tools such as `bear` which can be run with `gcc` or `clang` to extract this information it has a big limitation in that if run with `ceedling release` you won't get any auto completion for Unity and you'll also get error messages reported by your IDE because of what it perceives as missing headers. If you do the same with `ceedling test` now you get Unity but you might miss things that are only seen in the release build. + +This plugin resolves that issue. As it is run by Ceedling, it has access to all the build information it needs to create the perfect `compile_commands.json`. Once enabled, this plugin will generate that file and place it in `./build/artifacts/compile_commands.json`. `clangd` will search your project for this file, but it is easier to symlink it into the root directory (for example `ln -s ./build/artifacts/compile_commands.json`. + +For more information on LSP and to find out if your editor supports it, check out https://langserver.org/ + +## Setup + +Enable the plugin in your project.yml by adding `compile_commands_json` to the list +of enabled plugins. + +``` YAML +:plugins: + :enabled: + - compile_commands_json +``` + +## Configuration + +There is no additional configuration necessary to run this plugin. diff --git a/vendor/ceedling/plugins/compile_commands_json/lib/compile_commands_json.rb b/vendor/ceedling/plugins/compile_commands_json/lib/compile_commands_json.rb new file mode 100644 index 0000000..269cea4 --- /dev/null +++ b/vendor/ceedling/plugins/compile_commands_json/lib/compile_commands_json.rb @@ -0,0 +1,35 @@ +require 'ceedling/plugin' +require 'ceedling/constants' +require 'json' + +class CompileCommandsJson < Plugin + def setup + @fullpath = File.join(PROJECT_BUILD_ARTIFACTS_ROOT, "compile_commands.json") + @database = if (File.exists?(@fullpath)) + JSON.parse( File.read(@fullpath) ) + else + [] + end + end + + def post_compile_execute(arg_hash) + + # Create the new Entry + value = { + "directory" => Dir.pwd, + "command" => arg_hash[:shell_command], + "file" => arg_hash[:source] + } + + # Determine if we're updating an existing file description or adding a new one + index = @database.index {|h| h["file"] == arg_hash[:source]} + if index + @database[index] = value + else + @database << value + end + + # Update the Actual compile_commands.json file + File.open(@fullpath,'w') {|f| f << JSON.pretty_generate(@database)} + end +end diff --git a/vendor/ceedling/plugins/dependencies/README.md b/vendor/ceedling/plugins/dependencies/README.md new file mode 100644 index 0000000..256467d --- /dev/null +++ b/vendor/ceedling/plugins/dependencies/README.md @@ -0,0 +1,254 @@ +ceedling-dependencies +===================== + +Plugin for supporting release dependencies. It's rare for an embedded project to +be built completely free of other libraries and modules. Some of these may be +standard internal libraries. Some of these may be 3rd party libraries. In either +case, they become part of the project's ecosystem. + +This plugin is intended to make that relationship easier. It allows you to specify +a source for dependencies. If required, it will automatically grab the appropriate +version of that dependency. + +Most 3rd party libraries have a method of building already in place. While we'd +love to convert the world to a place where everything downloads with a test suite +in Ceedling, that's not likely to happen anytime soon. Until then, this plugin +will allow the developer to specify what calls Ceedling should make to oversee +the build process of those third party utilities. Are they using Make? CMake? A +custom series of scripts that only a mad scientist could possibly understand? No +matter. Ceedling has you covered. Just specify what should be called, and Ceedling +will make it happen whenever it notices that the output artifacts are missing. + +Output artifacts? Sure! Things like static and dynamic libraries, or folders +containing header files that might want to be included by your release project. + +So how does all this magic work? + +First, you need to add the `:dependencies` plugin to your list. Then, we'll add a new +section called :dependencies. There, you can list as many dependencies as you desire. Each +has a series of fields which help Ceedling to understand your needs. Many of them are +optional. If you don't need that feature, just don't include it! In the end, it'll look +something like this: + +``` +:dependencies: + :libraries: + - :name: WolfSSL + :source_path: third_party/wolfssl/source + :build_path: third_party/wolfssl/build + :artifact_path: third_party/wolfssl/install + :fetch: + :method: :zip + :source: \\shared_drive\third_party_libs\wolfssl\wolfssl-4.2.0.zip + :environment: + - CFLAGS+=-DWOLFSSL_DTLS_ALLOW_FUTURE + :build: + - "autoreconf -i" + - "./configure --enable-tls13 --enable-singlethreaded" + - make + - make install + :artifacts: + :static_libraries: + - lib/wolfssl.a + :dynamic_libraries: + - lib/wolfssl.so + :includes: + - include/** +``` + +Let's take a deeper look at each of these features. + +The Starting Dash & Name +------------------------ + +Yes, that opening dash tells the dependencies plugin that the rest of these fields +belong to our first dependency. If we had a second dependency, we'd have another +dash, lined up with the first, and followed by all the fields indented again. + +By convention, we use the `:name` field as the first field for each tool. Ceedling +honestly doesn't care which order the fields are given... but as humans, it makes +it easier for us to see the name of each dependency with starting dash. + +The name field is only used to print progress while we're running Ceedling. You may +call the name of the field whatever you wish. + +Working Folders +--------------- + +The `:source_path` field allows us to specify where the source code for each of our +dependencies is stored. If fetching the dependency from elsewhere, it will be fetched +to this location. All commands to build this dependency will be executed from +this location (override this by specifying a `:build_path`). Finally, the output +artifacts will be referenced to this location (override this by specifying a `:artifact_path`) + +If unspecified, the `:source_path` will be `dependencies\dep_name` where `dep_name` +is the name specified in `:name` above (with special characters removed). It's best, +though, if you specify exactly where you want your dependencies to live. + +If the dependency is directly included in your project (you've specified `:none` as the +`:method` for fetching), then `:source_path` should be where your Ceedling can find the +source for your dependency in you repo. + +All artifacts are relative to the `:artifact_path` (which defaults to be the same as +`:source_path`) + +Fetching Dependencies +--------------------- + +The `:dependencies` plugin supports the ability to automatically fetch your dependencies +for you... using some common methods of fetching source. This section contains only a +couple of fields: + +- `:method` -- This is the method that this dependency is fetched. + - `:none` -- This tells Ceedling that the code is already included in the project. + - `:zip` -- This tells Ceedling that we want to unpack a zip file to our source path. + - `:git` -- This tells Ceedling that we want to clone a git repo to our source path. + - `:svn` -- This tells Ceedling that we want to checkout a subversion repo to our source path. + - `:custom` -- This tells Ceedling that we want to use a custom command or commands to fetch the code. +- `:source` -- This is the path or url to fetch code when using the zip or git method. +- `:tag`/`:branch` -- This is the specific tag or branch that you wish to retrieve (git only. optional). +- `:hash` -- This is the specific SHA1 hash you want to fetch (git only. optional, requires a deep clone). +- `:revision` -- This is the specific revision you want to fetch (svn only. optional). +- `:executable` -- This is a list of commands to execute when using the `:custom` method + + +Environment Variables +--------------------- + +Many build systems support customization through environment variables. By specifying +an array of environment variables, Ceedling will customize the shell environment before +calling the build process. + +Environment variables may be specified in three ways. Let's look at one of each: + +``` + :environment: + - ARCHITECTURE=ARM9 + - CFLAGS+=-DADD_AWESOMENESS + - CFLAGS-=-DWASTE +``` + +In the first example, you see the most straightforward method. The environment variable +`ARCHITECTURE` is set to the value `ARM9`. That's it. Simple. + +The next two options modify an existing symbol. In the first one, we use `+=`, which tells +Ceedling to add the define `ADD_AWESOMENESS` to the environment variable `CFLAGS`. The second +tells Ceedling to remove the define `WASTE` from the same environment variable. + +There are a couple of things to note here. + +First, when adding to a variable, Ceedling has no way of knowing +what delimiter you are expecting. In this example you can see we manually added some whitespace. +If we had been modifying `PATH` instead, we might have had to use a `:` on a unux or `;` on +Windows. + +Second, removing an argument will have no effect on the argument if that argument isn't found +precisely. It's case sensitive and the entire string must match. If symbol doesn't already exist, +it WILL after executing this command... however it will be assigned to nothing. + +Building Dependencies +--------------------- + +The heart of the `:dependencies` plugin is the ability for you, the developer, to specify the +build process for each of your dependencies. You will need to have any required tools installed +before using this feature. + +The steps are specified as an array of strings. Ceedling will execute those steps in the order +specified, moving from step to step unless an error is encountered. By the end of the process, +the artifacts should have been created by your process... otherwise an error will be produced. + +Artifacts +--------- + +These are the outputs of the build process. There are there types of artifacts. Any dependency +may have none or some of these. Calling out these files tells Ceedling that they are important. +Your dependency's build process may produce many other files... but these are the files that +Ceedling understands it needs to act on. + +### `static_libraries` + +Specifying one or more static libraries will tell Ceedling where it should find static libraries +output by your build process. These libraries are automatically added to the list of dependencies +and will be linked with the rest of your code to produce the final release. + +If any of these libraries don't exist, Ceedling will trigger your build process in order for it +to produce them. + +### `dynamic_libraries` + +Specifying one or more dynamic libraries will tell Ceedling where it should find dynamic libraries +output by your build process. These libraries are automatically copied to the same folder as your +final release binary. + +If any of these libraries don't exist, Ceedling will trigger your build process in order for it +to produce them. + +### `includes` + +Often when libraries are built, the same process will output a collection of includes so that +your release code knows how to interact with that library. It's the public API for that library. +By specifying the directories that will contain these includes (don't specify the files themselves, +Ceedling only needs the directories), Ceedling is able to automatically add these to its internal +include list. This allows these files to be used while building your release code, as well we making +them mockable during unit testing. + +### `source` + +It's possible that your external dependency will just produce additional C files as its output. +In this case, Ceedling is able to automatically add these to its internal source list. This allows +these files to be used while building your release code. + +Tasks +----- + +Once configured correctly, the `:dependencies` plugin should integrate seamlessly into your +workflow and you shouldn't have to think about it. In the real world, that doesn't always happen. +Here are a number of tasks that are added or modified by this plugin. + +### `ceedling dependencies:clean` + +This can be issued in order to completely remove the dependency from its source path. On the +next build, it will be refetched and rebuilt from scratch. This can also apply to a particular +dependency. For example, by specifying `dependencies:clean:DepName`. + +### `ceedling dependencies:fetch` + +This can be issued in order to fetch each dependency from its origin. This will have no effect on +dependencies that don't have fetch instructions specified. This can also apply to a particular +dependency. For example, by specifying `dependencies:fetch:DepName`. + +### `ceedling dependencies:make` + +This will force the dependencies to all build. This should happen automatically when a release +has been triggered... but if you're just getting your dependency configured at this moment, you +may want to just use this feature instead. A single dependency can also be built by specifying its +name, like `dependencies:make:MyTunaBoat`. + +### `ceedling dependencies:deploy` + +This will force any dynamic libraries produced by your dependencies to be copied to your release +build directory... just in case you clobbered them. + +### `paths:include` + +Maybe you want to verify that all the include paths are correct. If you query Ceedling with this +request, it will list all the header file paths that it's found, including those produced by +dependencies. + +### `files:include` + +Maybe you want to take that query further and actually get a list of ALL the header files +Ceedling has found, including those belonging to your dependencies. + +Testing +======= + +Hopefully all your dependencies are fully tested... but we can't always depend on that. +In the event that they are tested with Ceedling, you'll probably want to consider using +the `:subprojects` plugin instead of this one. The purpose of this plugin is to pull in +third party code for release... and to provide a mockable interface for Ceedling to use +during its tests of other modules. + +If that's what you're after... you've found the right plugin! + +Happy Testing! diff --git a/vendor/ceedling/plugins/dependencies/config/defaults.yml b/vendor/ceedling/plugins/dependencies/config/defaults.yml new file mode 100644 index 0000000..0415f8e --- /dev/null +++ b/vendor/ceedling/plugins/dependencies/config/defaults.yml @@ -0,0 +1,5 @@ +--- +:dependencies: + :libraries: [] + +... diff --git a/vendor/ceedling/plugins/dependencies/dependencies.rake b/vendor/ceedling/plugins/dependencies/dependencies.rake new file mode 100644 index 0000000..08a1a48 --- /dev/null +++ b/vendor/ceedling/plugins/dependencies/dependencies.rake @@ -0,0 +1,147 @@ + +DEPENDENCIES_LIBRARIES.each do |deplib| + + # Look up the name of this dependency library + deplib_name = @ceedling[DEPENDENCIES_SYM].get_name(deplib) + + # Make sure the required working directories exists + # (don't worry about the subdirectories. That's the job of the dep's build tool) + paths = @ceedling[DEPENDENCIES_SYM].get_working_paths(deplib) + paths.each {|path| directory(path) } + task :directories => paths + + all_deps = @ceedling[DEPENDENCIES_SYM].get_static_libraries_for_dependency(deplib) + + @ceedling[DEPENDENCIES_SYM].get_dynamic_libraries_for_dependency(deplib) + + @ceedling[DEPENDENCIES_SYM].get_include_directories_for_dependency(deplib) + + @ceedling[DEPENDENCIES_SYM].get_source_files_for_dependency(deplib) + + # Add a rule for building the actual libraries from dependency list + (@ceedling[DEPENDENCIES_SYM].get_static_libraries_for_dependency(deplib) + + @ceedling[DEPENDENCIES_SYM].get_dynamic_libraries_for_dependency(deplib) + ).each do |libpath| + file libpath do |filetask| + path = filetask.name + + # We double-check that it doesn't already exist, because this process sometimes + # produces multiple files, but they may have already been flagged as invoked + unless (File.exists?(path)) + + # Set Environment Variables, Fetch, and Build + @ceedling[DEPENDENCIES_SYM].set_env_if_required(path) + @ceedling[DEPENDENCIES_SYM].fetch_if_required(path) + @ceedling[DEPENDENCIES_SYM].build_if_required(path) + end + end + end + + # Add a rule for building the source and includes from dependency list + (@ceedling[DEPENDENCIES_SYM].get_include_directories_for_dependency(deplib) + + @ceedling[DEPENDENCIES_SYM].get_source_files_for_dependency(deplib) + ).each do |libpath| + task libpath do |filetask| + path = filetask.name + + unless (File.file?(path) || File.directory?(path)) + + # Set Environment Variables, Fetch, and Build + @ceedling[DEPENDENCIES_SYM].set_env_if_required(path) + @ceedling[DEPENDENCIES_SYM].fetch_if_required(path) + @ceedling[DEPENDENCIES_SYM].build_if_required(path) + end + end + end + + # Give ourselves a way to trigger individual dependencies + namespace DEPENDENCIES_SYM do + namespace :deploy do + # Add task to directly just build this dependency + task(deplib_name => @ceedling[DEPENDENCIES_SYM].get_dynamic_libraries_for_dependency(deplib)) do |t,args| + @ceedling[DEPENDENCIES_SYM].deploy_if_required(deplib_name) + end + end + + namespace :make do + # Add task to directly just build this dependency + task(deplib_name => all_deps) + end + + namespace :clean do + # Add task to directly clobber this dependency + task(deplib_name) do + @ceedling[DEPENDENCIES_SYM].clean_if_required(deplib_name) + end + end + + namespace :fetch do + # Add task to directly clobber this dependency + task(deplib_name) do + @ceedling[DEPENDENCIES_SYM].fetch_if_required(deplib_name) + end + end + end + + # Add source files to our list of things to build during release + source_files = @ceedling[DEPENDENCIES_SYM].get_source_files_for_dependency(deplib) + task PROJECT_RELEASE_BUILD_TARGET => source_files + + # Finally, add the static libraries to our RELEASE build dependency list + static_libs = @ceedling[DEPENDENCIES_SYM].get_static_libraries_for_dependency(deplib) + task RELEASE_SYM => static_libs + + # Add the dynamic libraries to our RELEASE task dependency list so that they will be copied automatically + dynamic_libs = @ceedling[DEPENDENCIES_SYM].get_dynamic_libraries_for_dependency(deplib) + task RELEASE_SYM => dynamic_libs + + # Add the include dirs / files to our list of dependencies for release + headers = @ceedling[DEPENDENCIES_SYM].get_include_directories_for_dependency(deplib) + task RELEASE_SYM => headers + + # Paths to Libraries need to be Added to the Lib Path List + all_libs = static_libs + dynamic_libs + PATHS_LIBRARIES ||= [] + all_libs.each {|lib| PATHS_LIBRARIES << File.dirname(lib) } + PATHS_LIBRARIES.uniq! + PATHS_LIBRARIES.reject!{|s| s.empty?} + + # Libraries Need to be Added to the Library List + LIBRARIES_SYSTEM ||= [] + all_libs.each {|lib| LIBRARIES_SYSTEM << File.basename(lib,'.*').sub(/^lib/,'') } + LIBRARIES_SYSTEM.uniq! + LIBRARIES_SYSTEM.reject!{|s| s.empty?} +end + +# Add any artifact:include or :source folders to our release & test includes paths so linking and mocking work. +@ceedling[DEPENDENCIES_SYM].add_headers_and_sources() + +# Add tasks for building or cleaning ALL depencies +namespace DEPENDENCIES_SYM do + desc "Deploy missing dependencies." + task :deploy => DEPENDENCIES_LIBRARIES.map{|deplib| "#{DEPENDENCIES_SYM}:deploy:#{@ceedling[DEPENDENCIES_SYM].get_name(deplib)}"} + + desc "Build any missing dependencies." + task :make => DEPENDENCIES_LIBRARIES.map{|deplib| "#{DEPENDENCIES_SYM}:make:#{@ceedling[DEPENDENCIES_SYM].get_name(deplib)}"} + + desc "Clean all dependencies." + task :clean => DEPENDENCIES_LIBRARIES.map{|deplib| "#{DEPENDENCIES_SYM}:clean:#{@ceedling[DEPENDENCIES_SYM].get_name(deplib)}"} + + desc "Fetch all dependencies." + task :fetch => DEPENDENCIES_LIBRARIES.map{|deplib| "#{DEPENDENCIES_SYM}:fetch:#{@ceedling[DEPENDENCIES_SYM].get_name(deplib)}"} +end + +namespace :files do + desc "List all collected dependency libraries." + task :dependencies do + puts "dependency files:" + deps = [] + DEPENDENCIES_LIBRARIES.each do |deplib| + deps << @ceedling[DEPENDENCIES_SYM].get_static_libraries_for_dependency(deplib) + deps << @ceedling[DEPENDENCIES_SYM].get_dynamic_libraries_for_dependency(deplib) + end + deps.flatten! + deps.sort.each {|dep| puts " - #{dep}"} + puts "file count: #{deps.size}" + end +end + +# Make sure that we build dependencies before attempting to tackle any of the unit tests +Rake::Task[:test_deps].enhance ['dependencies:make'] diff --git a/vendor/ceedling/plugins/dependencies/lib/dependencies.rb b/vendor/ceedling/plugins/dependencies/lib/dependencies.rb new file mode 100644 index 0000000..fc8ae99 --- /dev/null +++ b/vendor/ceedling/plugins/dependencies/lib/dependencies.rb @@ -0,0 +1,237 @@ +require 'ceedling/plugin' +require 'ceedling/constants' + +DEPENDENCIES_ROOT_NAME = 'dependencies' +DEPENDENCIES_TASK_ROOT = DEPENDENCIES_ROOT_NAME + ':' +DEPENDENCIES_SYM = DEPENDENCIES_ROOT_NAME.to_sym + +class Dependencies < Plugin + + def setup + @plugin_root = File.expand_path(File.join(File.dirname(__FILE__), '..')) + + # Set up a fast way to look up dependencies by name or static lib path + @dependencies = {} + @dynamic_libraries = [] + DEPENDENCIES_LIBRARIES.each do |deplib| + + @dependencies[ deplib[:name] ] = deplib.clone + all_deps = get_static_libraries_for_dependency(deplib) + + get_dynamic_libraries_for_dependency(deplib) + + get_include_directories_for_dependency(deplib) + + get_source_files_for_dependency(deplib) + all_deps.each do |key| + @dependencies[key] = @dependencies[ deplib[:name] ] + end + + @dynamic_libraries += get_dynamic_libraries_for_dependency(deplib) + end + end + + def config + updates = { + :collection_paths_include => COLLECTION_PATHS_INCLUDE, + :collection_all_headers => COLLECTION_ALL_HEADERS, + } + + @ceedling[DEPENDENCIES_SYM].get_include_directories_for_dependency(deplib).each do |incpath| + updates[:collection_paths_include] << incpath + Dir[ File.join(incpath, "*#{EXTENSION_HEADER}") ].each do |f| + updates[:collection_all_headers] << f + end + end + + return updates + end + + def get_name(deplib) + raise "Each dependency must have a name!" if deplib[:name].nil? + return deplib[:name].gsub(/\W*/,'') + end + + def get_source_path(deplib) + return deplib[:source_path] || File.join('dependencies', get_name(deplib)) + end + + def get_build_path(deplib) + return deplib[:build_path] || deplib[:source_path] || File.join('dependencies', get_name(deplib)) + end + + def get_artifact_path(deplib) + return deplib[:artifact_path] || deplib[:source_path] || File.join('dependencies', get_name(deplib)) + end + + def get_working_paths(deplib) + paths = [deplib[:source_path], deplib[:build_path], deplib[:artifact_paths]].compact.uniq + paths = [ File.join('dependencies', get_name(deplib)) ] if (paths.empty?) + return paths + end + + def get_static_libraries_for_dependency(deplib) + (deplib[:artifacts][:static_libraries] || []).map {|path| File.join(get_artifact_path(deplib), path)} + end + + def get_dynamic_libraries_for_dependency(deplib) + (deplib[:artifacts][:dynamic_libraries] || []).map {|path| File.join(get_artifact_path(deplib), path)} + end + + def get_source_files_for_dependency(deplib) + (deplib[:artifacts][:source] || []).map {|path| File.join(get_artifact_path(deplib), path)} + end + + def get_include_directories_for_dependency(deplib) + paths = (deplib[:artifacts][:includes] || []).map {|path| File.join(get_artifact_path(deplib), path)} + @ceedling[:file_system_utils].collect_paths(paths) + end + + def set_env_if_required(lib_path) + blob = @dependencies[lib_path] + raise "Could not find dependency '#{lib_path}'" if blob.nil? + return if (blob[:environment].nil?) + return if (blob[:environment].empty?) + + blob[:environment].each do |e| + m = e.match(/^(\w+)\s*(\+?\-?=)\s*(.*)$/) + unless m.nil? + case m[2] + when "+=" + ENV[m[1]] = (ENV[m[1]] || "") + m[3] + when "-=" + ENV[m[1]] = (ENV[m[1]] || "").gsub(m[3],'') + else + ENV[m[1]] = m[3] + end + end + end + end + + def fetch_if_required(lib_path) + blob = @dependencies[lib_path] + raise "Could not find dependency '#{lib_path}'" if blob.nil? + return if (blob[:fetch].nil?) + return if (blob[:fetch][:method].nil?) + return if (directory(blob[:source_path]) && !Dir.empty?(blob[:source_path])) + + steps = case blob[:fetch][:method] + when :none + return + when :zip + [ "gzip -d #{blob[:fetch][:source]}" ] + when :git + branch = blob[:fetch][:tag] || blob[:fetch][:branch] || '' + branch = ("-b " + branch) unless branch.empty? + unless blob[:fetch][:hash].nil? + # Do a deep clone to ensure the commit we want is available + retval = [ "git clone #{branch} #{blob[:fetch][:source]} ." ] + # Checkout the specified commit + retval << "git checkout #{blob[:fetch][:hash]}" + else + # Do a thin clone + retval = [ "git clone #{branch} --depth 1 #{blob[:fetch][:source]} ." ] + end + when :svn + revision = blob[:fetch][:revision] || '' + revision = ("--revision " + branch) unless branch.empty? + retval = [ "svn checkout #{revision} #{blob[:fetch][:source]} ." ] + retval + when :custom + blob[:fetch][:executable] + else + raise "Unknown fetch method '#{blob[:fetch][:method].to_s}' for dependency '#{blob[:name]}'" + end + + # Perform the actual fetching + @ceedling[:streaminator].stdout_puts("Fetching dependency #{blob[:name]}...", Verbosity::NORMAL) + Dir.chdir(get_source_path(blob)) do + steps.each do |step| + @ceedling[:tool_executor].exec( step ) + end + end + end + + def build_if_required(lib_path) + blob = @dependencies[lib_path] + raise "Could not find dependency '#{lib_path}'" if blob.nil? + + # We don't clean anything unless we know how to fetch a new copy + if (blob[:build].nil? || blob[:build].empty?) + @ceedling[:streaminator].stdout_puts("Nothing to build for dependency #{blob[:name]}", Verbosity::NORMAL) + return + end + + # Perform the build + @ceedling[:streaminator].stdout_puts("Building dependency #{blob[:name]}...", Verbosity::NORMAL) + Dir.chdir(get_build_path(blob)) do + blob[:build].each do |step| + @ceedling[:tool_executor].exec( step ) + end + end + end + + def clean_if_required(lib_path) + blob = @dependencies[lib_path] + raise "Could not find dependency '#{lib_path}'" if blob.nil? + + # We don't clean anything unless we know how to fetch a new copy + if (blob[:fetch].nil? || blob[:fetch][:method].nil? || (blob[:fetch][:method] == :none)) + @ceedling[:streaminator].stdout_puts("Nothing to clean for dependency #{blob[:name]}", Verbosity::NORMAL) + return + end + + # Perform the actual Cleaning + @ceedling[:streaminator].stdout_puts("Cleaning dependency #{blob[:name]}...", Verbosity::NORMAL) + get_working_paths(blob).each do |path| + FileUtils.rm_rf(path) if File.directory?(path) + end + end + + def deploy_if_required(lib_path) + blob = @dependencies[lib_path] + raise "Could not find dependency '#{lib_path}'" if blob.nil? + + # We don't need to deploy anything if there isn't anything to deploy + if (blob[:artifacts].nil? || blob[:artifacts][:dynamic_libraries].nil? || blob[:artifacts][:dynamic_libraries].empty?) + @ceedling[:streaminator].stdout_puts("Nothing to deploy for dependency #{blob[:name]}", Verbosity::NORMAL) + return + end + + # Perform the actual Deploying + @ceedling[:streaminator].stdout_puts("Deploying dependency #{blob[:name]}...", Verbosity::NORMAL) + FileUtils.cp( lib_path, File.dirname(PROJECT_RELEASE_BUILD_TARGET) ) + end + + def add_headers_and_sources() + # Search for header file paths and files to add to our collections + DEPENDENCIES_LIBRARIES.each do |deplib| + get_include_directories_for_dependency(deplib).each do |header| + cfg = @ceedling[:configurator].project_config_hash + cfg[:collection_paths_include] << header + cfg[:collection_paths_source_and_include] << header + cfg[:collection_paths_test_support_source_include] << header + cfg[:collection_paths_test_support_source_include_vendor] << header + cfg[:collection_paths_release_toolchain_include] << header + Dir[ File.join(header, "*#{EXTENSION_HEADER}") ].each do |f| + cfg[:collection_all_headers] << f + end + end + + get_source_files_for_dependency(deplib).each do |source| + cfg = @ceedling[:configurator].project_config_hash + cfg[:collection_paths_source_and_include] << source + cfg[:collection_paths_test_support_source_include] << source + cfg[:collection_paths_test_support_source_include_vendor] << source + cfg[:collection_paths_release_toolchain_include] << source + Dir[ File.join(source, "*#{EXTENSION_SOURCE}") ].each do |f| + cfg[:collection_all_source] << f + end + end + end + + # Make all these updated files findable by Ceedling + @ceedling[:file_finder].prepare_search_sources() + end +end + +# end blocks always executed following rake run +END { +} diff --git a/vendor/ceedling/plugins/fake_function_framework/README.md b/vendor/ceedling/plugins/fake_function_framework/README.md new file mode 100644 index 0000000..8042775 --- /dev/null +++ b/vendor/ceedling/plugins/fake_function_framework/README.md @@ -0,0 +1,250 @@ +# A Fake Function Framework Plug-in for Ceedling + +This is a plug-in for [Ceedling](https://github.com/ThrowTheSwitch/Ceedling) to use the [Fake Function Framework](https://github.com/meekrosoft/fff) for mocking instead of CMock. + +Using fff provides less strict mocking than CMock, and allows for more loosely-coupled tests. +And, when tests fail -- since you get the actual line number of the failure -- it's a lot easier to figure out what went wrong. + +## Installing the plug-in + +To use the plugin you need to 1) get the contents of this repo and 2) configure your project to use it. + +### Get the source + +The easiest way to get the source is to just clone this repo into the Ceedling plugin folder for your existing Ceedling project. +(Don't have a Ceedling project already? [Here are instructions to create one.](http://www.electronvector.com/blog/try-embedded-test-driven-development-right-now-with-ceedling)) +From within `/vendor/ceedling/plugins`, run: + +`git clone https://github.com/ElectronVector/fake_function_framework.git` + +This will create a new folder named `fake_function_framework` in the plugins folder. + +### Enable the plug-in. + +The plug-in is enabled from within your project.yml file. + +In the `:plugins` configuration, add `fake_function_framework` to the list of enabled plugins: + +```yaml +:plugins: + :load_paths: + - vendor/ceedling/plugins + :enabled: + - stdout_pretty_tests_report + - module_generator + - fake_function_framework +``` +*Note that you could put the plugin source in some other loaction. +In that case you'd need to add a new path the `:load_paths`.* + +## How to use it + +You use fff with Ceedling the same way you used to use CMock. +Modules can still be generated with the default module generator: `rake module:create[my_module]`. +If you want to "mock" `some_module.h` in your tests, just `#include "mock_some_module.h"`. +This creates a fake function for each of the functions defined in `some_module.h`. + +The name of each fake is the original function name with an appended `_fake`. +For example, if we're generating fakes for a stack module with `push` and `pop` functions, we would have the fakes `push_fake` and `pop_fake`. +These fakes are linked into our test executable so that any time our unit under test calls `push` or `pop` our fakes are called instead. + +Each of these fakes is actually a structure containing information about how the function was called, and what it might return. +We can use Unity to inspect these fakes in our tests, and verify the interactions of our units. +There is also a global structure named `fff` which we can use to check the sequence of calls. + +The fakes can also be configured to return particular values, so you can exercise the unit under test however you want. + +The examples below explain how to use fff to test a variety of module interactions. +Each example uses fakes for a "display" module, created from a display.h file with `#include "mock_display.h"`. The `display.h` file must exist and must contain the prototypes for the functions to be faked. + +### Test that a function was called once + +```c +void +test_whenTheDeviceIsReset_thenTheStatusLedIsTurnedOff() +{ + // When + event_deviceReset(); + + // Then + TEST_ASSERT_EQUAL(1, display_turnOffStatusLed_fake.call_count); +} +``` + +### Test that a function was NOT called + +```c +void +test_whenThePowerReadingIsLessThan5_thenTheStatusLedIsNotTurnedOn(void) +{ + // When + event_powerReadingUpdate(4); + + // Then + TEST_ASSERT_EQUAL(0, display_turnOnStatusLed_fake.call_count); +} +``` + +## Test that a single function was called with the correct argument + +```c +void +test_whenTheVolumeKnobIsMaxed_thenVolumeDisplayIsSetTo11(void) +{ + // When + event_volumeKnobMaxed(); + + // Then + TEST_ASSERT_EQUAL(1, display_setVolume_fake.call_count); + TEST_ASSERT_EQUAL(11, display_setVolume_fake.arg0_val); +} +``` + +## Test that calls are made in a particular sequence + +```c +void +test_whenTheModeSelectButtonIsPressed_thenTheDisplayModeIsCycled(void) +{ + // When + event_modeSelectButtonPressed(); + event_modeSelectButtonPressed(); + event_modeSelectButtonPressed(); + + // Then + TEST_ASSERT_EQUAL_PTR((void*)display_setModeToMinimum, fff.call_history[0]); + TEST_ASSERT_EQUAL_PTR((void*)display_setModeToMaximum, fff.call_history[1]); + TEST_ASSERT_EQUAL_PTR((void*)display_setModeToAverage, fff.call_history[2]); +} +``` + +## Fake a return value from a function + +```c +void +test_givenTheDisplayHasAnError_whenTheDeviceIsPoweredOn_thenTheDisplayIsPoweredDown(void) +{ + // Given + display_isError_fake.return_val = true; + + // When + event_devicePoweredOn(); + + // Then + TEST_ASSERT_EQUAL(1, display_powerDown_fake.call_count); +} +``` + +## Fake a function with a value returned by reference + +```c +void +test_givenTheUserHasTypedSleep_whenItIsTimeToCheckTheKeyboard_theDisplayIsPoweredDown(void) +{ + // Given + char mockedEntry[] = "sleep"; + void return_mock_value(char * entry, int length) + { + if (length > strlen(mockedEntry)) + { + strncpy(entry, mockedEntry, length); + } + } + display_getKeyboardEntry_fake.custom_fake = return_mock_value; + + // When + event_keyboardCheckTimerExpired(); + + // Then + TEST_ASSERT_EQUAL(1, display_powerDown_fake.call_count); +} +``` + +## Fake a function with a function pointer parameter + +``` +void +test_givenNewDataIsAvailable_whenTheDisplayHasUpdated_thenTheEventIsComplete(void) +{ + // A mock function for capturing the callback handler function pointer. + void(*registeredCallback)(void) = 0; + void mock_display_updateData(int data, void(*callback)(void)) + { + //Save the callback function. + registeredCallback = callback; + } + display_updateData_fake.custom_fake = mock_display_updateData; + + // Given + event_newDataAvailable(10); + + // When + if (registeredCallback != 0) + { + registeredCallback(); + } + + // Then + TEST_ASSERT_EQUAL(true, eventProcessor_isLastEventComplete()); +} +``` + +## Helper macros + +For convenience, there are also some helper macros that create new Unity-style asserts: + +- `TEST_ASSERT_CALLED(function)`: Asserts that a function was called once. +- `TEST_ASSERT_NOT_CALLED(function)`: Asserts that a function was never called. +- `TEST_ASSERT_CALLED_TIMES(times, function)`: Asserts that a function was called a particular number of times. +- `TEST_ASSERT_CALLED_IN_ORDER(order, function)`: Asserts that a function was called in a particular order. + +Here's how you might use one of these instead of simply checking the call_count value: + +```c +void +test_whenTheDeviceIsReset_thenTheStatusLedIsTurnedOff() +{ + // When + event_deviceReset(); + + // Then + // This how to directly use fff... + TEST_ASSERT_EQUAL(1, display_turnOffStatusLed_fake.call_count); + // ...and this is how to use the helper macro. + TEST_ASSERT_CALLED(display_turnOffStatusLed); +} +``` + +## Test setup + +All of the fake functions, and any fff global state are all reset automatically between each test. + +## CMock configuration + +Use still use some of the CMock configuration options for setting things like the mock prefix, and for including additional header files in the mock files. + +```yaml +:cmock: + :mock_prefix: mock_ + :includes: + - + :includes_h_pre_orig_header: + - + :includes_h_post_orig_header: + - + :includes_c_pre_header: + - + :includes_c_post_header: +``` + +## Running the tests + +There are unit and integration tests for the plug-in itself. +These are run with the default `rake` task. +The integration test runs the tests for the example project in examples/fff_example. +For the integration tests to succeed, this repository must be placed in a Ceedling tree in the plugins folder. + +## More examples + +There is an example project in examples/fff_example. +It shows how to use the plug-in with some full-size examples. diff --git a/vendor/ceedling/plugins/fake_function_framework/Rakefile b/vendor/ceedling/plugins/fake_function_framework/Rakefile new file mode 100644 index 0000000..bc55941 --- /dev/null +++ b/vendor/ceedling/plugins/fake_function_framework/Rakefile @@ -0,0 +1,19 @@ +require 'rake' +require 'rspec/core/rake_task' + +desc "Run all rspecs" +RSpec::Core::RakeTask.new(:spec) do |t| + t.pattern = Dir.glob('spec/**/*_spec.rb') + t.rspec_opts = '--format documentation' + # t.rspec_opts << ' more options' +end + +desc "Run integration test on example" +task :integration_test do + chdir("./examples/fff_example") do + sh "rake clobber" + sh "rake test:all" + end +end + +task :default => [:spec, :integration_test] \ No newline at end of file diff --git a/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/project.yml b/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/project.yml new file mode 100644 index 0000000..6bda222 --- /dev/null +++ b/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/project.yml @@ -0,0 +1,71 @@ +--- + +# Notes: +# Sample project C code is not presently written to produce a release artifact. +# As such, release build options are disabled. +# This sample, therefore, only demonstrates running a collection of unit tests. + +:project: + :use_exceptions: FALSE + :use_test_preprocessor: TRUE + :use_auxiliary_dependencies: TRUE + :build_root: build +# :release_build: TRUE + :test_file_prefix: test_ + +#:release_build: +# :output: MyApp.out +# :use_assembly: FALSE + +:environment: + +:extension: + :executable: .out + +:paths: + :test: + - +:test/** + :source: + - src/** + :support: + +:defines: + # in order to add common defines: + # 1) remove the trailing [] from the :common: section + # 2) add entries to the :common: section (e.g. :test: has TEST defined) + :commmon: &common_defines [] + :test: + - *common_defines + - TEST + :test_preprocess: + - *common_defines + - TEST + +:cmock: + :mock_prefix: mock_ + :when_no_prototypes: :warn + :enforce_strict_ordering: TRUE + :plugins: + - :ignore + - :callback + :treat_as: + uint8: HEX8 + uint16: HEX16 + uint32: UINT32 + int8: INT8 + bool: UINT8 + +#:tools: +# Ceedling defaults to using gcc for compiling, linking, etc. +# As [:tools] is blank, gcc will be used (so long as it's in your system path) +# See documentation to configure a given toolchain for use + +:plugins: + :load_paths: + # This change from the default is for running Ceedling out of another folder. + - ../../../../plugins + :enabled: + - stdout_pretty_tests_report + - module_generator + - fake_function_framework +... diff --git a/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/rakefile.rb b/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/rakefile.rb new file mode 100644 index 0000000..e484d5f --- /dev/null +++ b/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/rakefile.rb @@ -0,0 +1,7 @@ +# This change from the default is for running Ceedling out of another folder. +PROJECT_CEEDLING_ROOT = "../../../.." +load "#{PROJECT_CEEDLING_ROOT}/lib/ceedling.rb" + +Ceedling.load_project + +task :default => %w[ test:all release ] diff --git a/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/bar.c b/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/bar.c new file mode 100644 index 0000000..6a40323 --- /dev/null +++ b/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/bar.c @@ -0,0 +1 @@ +#include "bar.h" diff --git a/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/bar.h b/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/bar.h new file mode 100644 index 0000000..febc586 --- /dev/null +++ b/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/bar.h @@ -0,0 +1,14 @@ +#ifndef bar_H +#define bar_H + +#include "custom_types.h" + +void bar_turn_on(void); +void bar_print_message(const char * message); +void bar_print_message_formatted(const char * format, ...); +void bar_numbers(int one, int two, char three); +void bar_const_test(const char * a, char * const b, const int c); +custom_t bar_needs_custom_type(void); +const char * bar_return_const_ptr(int one); + +#endif // bar_H diff --git a/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/custom_types.h b/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/custom_types.h new file mode 100644 index 0000000..b426b32 --- /dev/null +++ b/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/custom_types.h @@ -0,0 +1,6 @@ +#ifndef custom_types_H +#define custom_types_H + +typedef int custom_t; + +#endif diff --git a/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/display.c b/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/display.c new file mode 100644 index 0000000..2f03449 --- /dev/null +++ b/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/display.c @@ -0,0 +1,7 @@ +#include +#include "display.h" + +void display_turnOffStatusLed(void) +{ + printf("Display: Status LED off"); +} \ No newline at end of file diff --git a/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/display.h b/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/display.h new file mode 100644 index 0000000..def2996 --- /dev/null +++ b/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/display.h @@ -0,0 +1,16 @@ +#include + +void display_turnOffStatusLed(void); +void display_turnOnStatusLed(void); +void display_setVolume(int level); +void display_setModeToMinimum(void); +void display_setModeToMaximum(void); +void display_setModeToAverage(void); +bool display_isError(void); +void display_powerDown(void); +void display_updateData(int data, void(*updateCompleteCallback)(void)); + +/* + The entry is returned (up to `length` bytes) in the provided `entry` buffer. +*/ +void display_getKeyboardEntry(char * entry, int length); diff --git a/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/event_processor.c b/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/event_processor.c new file mode 100644 index 0000000..916a923 --- /dev/null +++ b/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/event_processor.c @@ -0,0 +1,93 @@ +/* + This module implements some business logic to test. + + Signal events by calling the functions on the module. +*/ + +#include +#include +#include "event_processor.h" +#include "display.h" + +void event_deviceReset(void) +{ + //printf ("Device reset\n"); + display_turnOffStatusLed(); +} + +void event_volumeKnobMaxed(void) +{ + display_setVolume(11); +} + +void event_powerReadingUpdate(int powerReading) +{ + if (powerReading >= 5) + { + display_turnOnStatusLed(); + } +} + +void event_modeSelectButtonPressed(void) +{ + static int mode = 0; + + if (mode == 0) + { + display_setModeToMinimum(); + mode++; + } + else if (mode == 1) + { + display_setModeToMaximum(); + mode++; + } + else if (mode == 2) + { + display_setModeToAverage(); + mode++; + } + else + { + mode = 0; + } +} + +void event_devicePoweredOn(void) +{ + if (display_isError()) + { + display_powerDown(); + } +} + +void event_keyboardCheckTimerExpired(void) +{ + char userEntry[100]; + + display_getKeyboardEntry(userEntry, 100); + + if (strcmp(userEntry, "sleep") == 0) + { + display_powerDown(); + } +} + +static bool event_lastComplete = false; + +/* Function called when the display update is complete. */ +static void displayUpdateComplete(void) +{ + event_lastComplete = true; +} + +void event_newDataAvailable(int data) +{ + event_lastComplete = false; + display_updateData(data, displayUpdateComplete); +} + +bool eventProcessor_isLastEventComplete(void) +{ + return event_lastComplete; +} diff --git a/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/event_processor.h b/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/event_processor.h new file mode 100644 index 0000000..a79e68c --- /dev/null +++ b/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/event_processor.h @@ -0,0 +1,11 @@ +#include + +void event_deviceReset(void); +void event_volumeKnobMaxed(void); +void event_powerReadingUpdate(int powerReading); +void event_modeSelectButtonPressed(void); +void event_devicePoweredOn(void); +void event_keyboardCheckTimerExpired(void); +void event_newDataAvailable(int data); + +bool eventProcessor_isLastEventComplete(void); diff --git a/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/foo.c b/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/foo.c new file mode 100644 index 0000000..c05b115 --- /dev/null +++ b/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/foo.c @@ -0,0 +1,16 @@ +#include "foo.h" +#include "bar.h" +#include "subfolder/zzz.h" + +void foo_turn_on(void) { + bar_turn_on(); + zzz_sleep(1, "sleepy"); +} + +void foo_print_message(const char * message) { + bar_print_message(message); +} + +void foo_print_special_message(void) { + bar_print_message_formatted("The numbers are %d, %d and %d", 1, 2, 3); +} diff --git a/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/foo.h b/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/foo.h new file mode 100644 index 0000000..3fea699 --- /dev/null +++ b/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/foo.h @@ -0,0 +1,8 @@ +#ifndef foo_H +#define foo_H + +void foo_turn_on(void); +void foo_print_message(const char * message); +void foo_print_special_message(void); + +#endif // foo_H diff --git a/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/subfolder/zzz.c b/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/subfolder/zzz.c new file mode 100644 index 0000000..85f370e --- /dev/null +++ b/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/subfolder/zzz.c @@ -0,0 +1 @@ +#include "zzz.h" diff --git a/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/subfolder/zzz.h b/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/subfolder/zzz.h new file mode 100644 index 0000000..32c5294 --- /dev/null +++ b/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/subfolder/zzz.h @@ -0,0 +1,6 @@ +#ifndef zzz_H +#define zzz_H + +int zzz_sleep(int time, char * name); + +#endif // zzz_H diff --git a/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/test/test_event_processor.c b/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/test/test_event_processor.c new file mode 100644 index 0000000..9f99944 --- /dev/null +++ b/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/test/test_event_processor.c @@ -0,0 +1,155 @@ +#include "unity.h" +#include "event_processor.h" +#include "mock_display.h" +#include + +void setUp (void) +{ +} + +void tearDown (void) +{ +} +/* + Test that a single function was called. +*/ +void +test_whenTheDeviceIsReset_thenTheStatusLedIsTurnedOff() +{ + // When + event_deviceReset(); + + // Then + TEST_ASSERT_EQUAL(1, display_turnOffStatusLed_fake.call_count); + // or use the helper macro... + TEST_ASSERT_CALLED(display_turnOffStatusLed); +} + +/* + Test that a single function is NOT called. +*/ +void +test_whenThePowerReadingIsLessThan5_thenTheStatusLedIsNotTurnedOn(void) +{ + // When + event_powerReadingUpdate(4); + + // Then + TEST_ASSERT_EQUAL(0, display_turnOnStatusLed_fake.call_count); + // or use the helper macro... + TEST_ASSERT_NOT_CALLED(display_turnOffStatusLed); +} + +/* + Test that a single function was called with the correct arugment. +*/ +void +test_whenTheVolumeKnobIsMaxed_thenVolumeDisplayIsSetTo11(void) +{ + // When + event_volumeKnobMaxed(); + + // Then + TEST_ASSERT_EQUAL(1, display_setVolume_fake.call_count); + // or use the helper macro... + TEST_ASSERT_CALLED(display_setVolume); + TEST_ASSERT_EQUAL(11, display_setVolume_fake.arg0_val); +} + +/* + Test a sequence of calls. +*/ + +void +test_whenTheModeSelectButtonIsPressed_thenTheDisplayModeIsCycled(void) +{ + // When + event_modeSelectButtonPressed(); + event_modeSelectButtonPressed(); + event_modeSelectButtonPressed(); + + // Then + TEST_ASSERT_EQUAL_PTR((void *)display_setModeToMinimum, fff.call_history[0]); + TEST_ASSERT_EQUAL_PTR((void *)display_setModeToMaximum, fff.call_history[1]); + TEST_ASSERT_EQUAL_PTR((void *)display_setModeToAverage, fff.call_history[2]); + // or use the helper macros... + TEST_ASSERT_CALLED_IN_ORDER(0, display_setModeToMinimum); + TEST_ASSERT_CALLED_IN_ORDER(1, display_setModeToMaximum); + TEST_ASSERT_CALLED_IN_ORDER(2, display_setModeToAverage); +} + +/* + Mock a return value from a function. +*/ +void +test_givenTheDisplayHasAnError_whenTheDeviceIsPoweredOn_thenTheDisplayIsPoweredDown(void) +{ + // Given + display_isError_fake.return_val = true; + + // When + event_devicePoweredOn(); + + // Then + TEST_ASSERT_EQUAL(1, display_powerDown_fake.call_count); + // or use the helper macro... + TEST_ASSERT_CALLED(display_powerDown); +} + +/* + Mock a sequence of calls with return values. +*/ + +/* + Mocking a function with a value returned by reference. +*/ +void +test_givenTheUserHasTypedSleep_whenItIsTimeToCheckTheKeyboard_theDisplayIsPoweredDown(void) +{ + // Given + char mockedEntry[] = "sleep"; + void return_mock_value(char * entry, int length) + { + if (length > strlen(mockedEntry)) + { + strncpy(entry, mockedEntry, length); + } + } + display_getKeyboardEntry_fake.custom_fake = return_mock_value; + + // When + event_keyboardCheckTimerExpired(); + + // Then + TEST_ASSERT_EQUAL(1, display_powerDown_fake.call_count); + // or use the helper macro... + TEST_ASSERT_CALLED(display_powerDown); +} + +/* + Mock a function with a function pointer parameter. +*/ +void +test_givenNewDataIsAvailable_whenTheDisplayHasUpdated_thenTheEventIsComplete(void) +{ + // A mock function for capturing the callback handler function pointer. + void(*registeredCallback)(void) = 0; + void mock_display_updateData(int data, void(*callback)(void)) + { + //Save the callback function. + registeredCallback = callback; + } + display_updateData_fake.custom_fake = mock_display_updateData; + + // Given + event_newDataAvailable(10); + + // When + if (registeredCallback != 0) + { + registeredCallback(); + } + + // Then + TEST_ASSERT_EQUAL(true, eventProcessor_isLastEventComplete()); +} diff --git a/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/test/test_foo.c b/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/test/test_foo.c new file mode 100644 index 0000000..12dd61a --- /dev/null +++ b/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/test/test_foo.c @@ -0,0 +1,47 @@ +#include "unity.h" +#include "foo.h" +#include "mock_bar.h" +#include "mock_zzz.h" + +void setUp(void) +{ +} + +void tearDown(void) +{ +} + +void test_foo(void) +{ + //When + foo_turn_on(); + + //Then + TEST_ASSERT_EQUAL(1, bar_turn_on_fake.call_count); + TEST_ASSERT_EQUAL(1, zzz_sleep_fake.call_count); + TEST_ASSERT_EQUAL_STRING("sleepy", zzz_sleep_fake.arg1_val); +} + +void test_foo_again(void) +{ + //When + foo_turn_on(); + + //Then + TEST_ASSERT_EQUAL(1, bar_turn_on_fake.call_count); +} + +void test_foo_mock_with_const(void) +{ + foo_print_message("123"); + + TEST_ASSERT_EQUAL(1, bar_print_message_fake.call_count); + TEST_ASSERT_EQUAL_STRING("123", bar_print_message_fake.arg0_val); +} + +void test_foo_mock_with_variable_args(void) +{ + foo_print_special_message(); + TEST_ASSERT_EQUAL(1, bar_print_message_formatted_fake.call_count); + TEST_ASSERT_EQUAL_STRING("The numbers are %d, %d and %d", bar_print_message_formatted_fake.arg0_val); +} diff --git a/vendor/ceedling/plugins/fake_function_framework/lib/fake_function_framework.rb b/vendor/ceedling/plugins/fake_function_framework/lib/fake_function_framework.rb new file mode 100644 index 0000000..51a90b3 --- /dev/null +++ b/vendor/ceedling/plugins/fake_function_framework/lib/fake_function_framework.rb @@ -0,0 +1,87 @@ +require 'ceedling/plugin' +require 'fff_mock_generator' + +class FakeFunctionFramework < Plugin + + # Set up Ceedling to use this plugin. + def setup + # Get the location of this plugin. + @plugin_root = File.expand_path(File.join(File.dirname(__FILE__), '..')) + puts "Using fake function framework (fff)..." + + # Switch out the cmock_builder with our own. + @ceedling[:cmock_builder].cmock = FffMockGeneratorForCMock.new(@ceedling[:setupinator].config_hash[:cmock]) + + # Add the path to fff.h to the include paths. + COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR << "#{@plugin_root}/vendor/fff" + COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR << "#{@plugin_root}/src" + end + + def post_runner_generate(arg_hash) + # After the test runner file has been created, append the FFF globals + # definition to the end of the test runner. These globals will be shared by + # all mocks linked into the test. + File.open(arg_hash[:runner_file], 'a') do |f| + f.puts + f.puts "//=======Defintions of FFF variables=====" + f.puts %{#include "fff.h"} + f.puts "DEFINE_FFF_GLOBALS;" + end + end + +end # class FakeFunctionFramework + +class FffMockGeneratorForCMock + + def initialize(options=nil) + @cm_config = CMockConfig.new(options) + @cm_parser = CMockHeaderParser.new(@cm_config) + @silent = (@cm_config.verbosity < 2) + + # These are the additional files to include in the mock files. + @includes_h_pre_orig_header = (@cm_config.includes || @cm_config.includes_h_pre_orig_header || []).map{|h| h =~ /" + output.puts %{#include "fff.h"} + output.puts %{#include "#{mock_name}.h"} + end + + def self.write_function_definitions(parsed_header, output) + write_function_macros("DEFINE", parsed_header, output) + end + + def self.write_control_function_definitions(mock_name, parsed_header, output) + output.puts "void #{mock_name}_Init(void)" + output.puts "{" + # In the init function, reset the FFF globals. These are used for things + # like the call history. + output.puts " FFF_RESET_HISTORY();" + + # Also, reset all of the fakes. + if parsed_header[:functions] + parsed_header[:functions].each do |function| + output.puts " RESET_FAKE(#{function[:name]})" + end + end + output.puts "}" + output.puts "void #{mock_name}_Verify(void)" + output.puts "{" + output.puts "}" + output.puts "void #{mock_name}_Destroy(void)" + output.puts "{" + output.puts "}" + end + +# Shared functions. + + def self.write_extra_includes(includes, output) + if includes + includes.each {|inc| output.puts "#include #{inc}\n"} + end + end + + def self.write_function_macros(macro_type, parsed_header, output) + return unless parsed_header.key?(:functions) + parsed_header[:functions].each do |function| + name = function[:name] + return_type = function[:return][:type] + if function.has_key? :modifier + # Prepend any modifier. If there isn't one, trim any leading whitespace. + return_type = "#{function[:modifier]} #{return_type}".lstrip + end + arg_count = function[:args].size + + # Check for variable arguments. + var_arg_suffix = "" + if function[:var_arg] + # If there are are variable arguments, then we need to add this argument + # to the count, update the suffix that will get added to the macro. + arg_count += 1 + var_arg_suffix = "_VARARG" + end + + # Generate the correct macro. + if return_type == 'void' + output.print "#{macro_type}_FAKE_VOID_FUNC#{arg_count}#{var_arg_suffix}(#{name}" + else + output.print "#{macro_type}_FAKE_VALUE_FUNC#{arg_count}#{var_arg_suffix}(#{return_type}, #{name}" + end + + # Append each argument type. + function[:args].each do |arg| + output.print ", " + if arg[:const?] + output.print "const " + end + output.print "#{arg[:type]}" + end + + # If this argument list ends with a variable argument, add it here at the end. + if function[:var_arg] + output.print ", ..." + end + + # Close the declaration. + output.puts ");" + end + end + +end diff --git a/vendor/ceedling/plugins/fake_function_framework/spec/fff_mock_header_generator_spec.rb b/vendor/ceedling/plugins/fake_function_framework/spec/fff_mock_header_generator_spec.rb new file mode 100644 index 0000000..e6ac11d --- /dev/null +++ b/vendor/ceedling/plugins/fake_function_framework/spec/fff_mock_header_generator_spec.rb @@ -0,0 +1,304 @@ +require 'stringio' +require 'fff_mock_generator.rb' +require 'header_generator.rb' + +# Test the contents of the .h file created for the mock. +describe "FffMockGenerator.create_mock_header" do + + context "when there is nothing to mock," do + let(:mock_header) { + parsed_header = {} + FffMockGenerator.create_mock_header("display", "mock_display", parsed_header) + } + it "then the generated header file starts with an opening include guard" do + expect(mock_header).to start_with( + "#ifndef mock_display_H\n" + + "#define mock_display_H") + end + it "then the generated file ends with a closing include guard" do + expect(mock_header).to end_with( + "#endif // mock_display_H\n") + end + it "then the generated file includes the fff header" do + expect(mock_header).to include( + %{#include "fff.h"\n}) + end + it "then the generated file has a prototype for the init function" do + expect(mock_header).to include( + "void mock_display_Init(void);") + end + it "then the generated file has a prototype for the verify function" do + expect(mock_header).to include( + "void mock_display_Verify(void);") + end + it "then the generated file has a prototype for the destroy function" do + expect(mock_header).to include( + "void mock_display_Destroy(void);") + end + end + + context "when there is a function with no args and a void return," do + let(:mock_header) { + parsed_header = create_cmock_style_parsed_header( + [{:name => 'display_turnOffStatusLed', :return_type => 'void'}]) + FffMockGenerator.create_mock_header("display", "mock_display", parsed_header) + } + it "then the generated header file starts with an opening include guard" do + expect(mock_header).to start_with( + "#ifndef mock_display_H\n" + + "#define mock_display_H") + end + it "then the generated header file contains a fake function declaration" do + expect(mock_header).to include( + "DECLARE_FAKE_VOID_FUNC0(display_turnOffStatusLed);" + ) + end + it "then the generated file ends with a closing include guard" do + expect(mock_header).to end_with( + "#endif // mock_display_H\n") + end + end + + context "when there is a function with no args and a bool return," do + let(:mock_header) { + parsed_header = create_cmock_style_parsed_header( + [{:name => 'display_isError', :return_type => 'bool'}]) + FffMockGenerator.create_mock_header("display", "mock_display", parsed_header) + } + it "then the generated file contains the fake function declaration" do + expect(mock_header).to include( + "DECLARE_FAKE_VALUE_FUNC0(bool, display_isError);" + ) + end + end + + context "when there is a function with no args and an int return," do + let(:mock_header) { + parsed_header = create_cmock_style_parsed_header( + [{:name => 'display_isError', :return_type => 'int'}]) + FffMockGenerator.create_mock_header("display", "mock_display", parsed_header) + } + it "then the generated file contains the fake function declaration" do + expect(mock_header).to include( + "DECLARE_FAKE_VALUE_FUNC0(int, display_isError);" + ) + end + end + + context "when there is a function with args and a void return," do + let(:mock_header) { + parsed_header = create_cmock_style_parsed_header( + [{:name => 'display_setVolume', :return_type => 'void', :args => ['int']}]) + FffMockGenerator.create_mock_header("display", "mock_display", parsed_header) + } + it "then the generated file contains the fake function declaration" do + expect(mock_header).to include( + "DECLARE_FAKE_VOID_FUNC1(display_setVolume, int);" + ) + end + end + + context "when there is a function with args and a value return," do + let(:mock_header) { + parsed_header = create_cmock_style_parsed_header( + [{:name => 'a_function', :return_type => 'int', :args => ['char *']}]) + FffMockGenerator.create_mock_header("display", "mock_display", parsed_header) + } + it "then the generated file contains the fake function declaration" do + expect(mock_header).to include( + "FAKE_VALUE_FUNC1(int, a_function, char *);" + ) + end + end + + context "when there is a function with many args and a void return," do + let(:mock_header) { + parsed_header = create_cmock_style_parsed_header( + [{:name => 'a_function', :return_type => 'void', + :args => ['int', 'char *', 'int', 'int', 'bool', 'applesauce']}]) + FffMockGenerator.create_mock_header("display", "mock_display", parsed_header) + } + it "then the generated file contains the fake function declaration" do + expect(mock_header).to include( + "DECLARE_FAKE_VOID_FUNC6(a_function, int, char *, int, int, bool, applesauce);" + ) + end + end + + context "when there are multiple functions," do + let(:mock_header) { + parsed_header = create_cmock_style_parsed_header( + [ {:name => 'a_function', :return_type => 'int', :args => ['char *']}, + {:name => 'another_function', :return_type => 'void'}, + {:name => 'three', :return_type => 'bool', :args => ['float', 'int']} + ]) + FffMockGenerator.create_mock_header("display", "mock_display", parsed_header) + } + it "then the generated file contains the first fake function declaration" do + expect(mock_header).to include( + "DECLARE_FAKE_VALUE_FUNC1(int, a_function, char *);" + ) + end + it "then the generated file contains the second fake function declaration" do + expect(mock_header).to include( + "DECLARE_FAKE_VOID_FUNC0(another_function);" + ) + end + it "then the generated file contains the third fake function declaration" do + expect(mock_header).to include( + "DECLARE_FAKE_VALUE_FUNC2(bool, three, float, int);" + ) + end + end + + context "when there is a typedef," do + let(:mock_header) { + parsed_header = create_cmock_style_parsed_header( + nil, ["typedef void (*displayCompleteCallback) (void);"]) + FffMockGenerator.create_mock_header("display", "mock_display", parsed_header) + } + it "then the generated file contains the typedef" do + expect(mock_header).to include( + "typedef void (*displayCompleteCallback) (void);" + ) + end + end + + context "when there is a void function with variable arguments" do + let(:mock_header){ + parsed_header = {} + parsed_header[:functions] = [{ + :name => "function_with_var_args", + :return => {:type => "void"}, + :var_arg => "...", + :args => [{:type => 'char *'}] + }] + FffMockGenerator.create_mock_header("display", "mock_display", parsed_header) + } + it "then the generated file contains the vararg declaration" do + expect(mock_header).to include( + "DECLARE_FAKE_VOID_FUNC2_VARARG(function_with_var_args, char *, ...)" + ) + end + end + + context "when there is a function with a return value and variable arguments" do + let(:mock_header){ + parsed_header = {} + parsed_header[:functions] = [{ + :name => "function_with_var_args", + :return => {:type => "int"}, + :var_arg => "...", + :args => [{:type => 'char *'}] + }] + FffMockGenerator.create_mock_header("display", "mock_display", parsed_header) + } + it "then the generated file contains the vararg declaration" do + expect(mock_header).to include( + "DECLARE_FAKE_VALUE_FUNC2_VARARG(int, function_with_var_args, char *, ...)" + ) + end + end + + context "when there is a void function with variable arguments and " + + "additional arguments" do + let(:mock_header){ + parsed_header = {} + parsed_header[:functions] = [{ + :name => "function_with_var_args", + :return => {:type => "void"}, + :var_arg => "...", + :args => [{:type => 'char *'}, {:type => 'int'}] + }] + FffMockGenerator.create_mock_header("display", "mock_display", parsed_header) + } + it "then the generated file contains the vararg declaration" do + expect(mock_header).to include( + "DECLARE_FAKE_VOID_FUNC3_VARARG(function_with_var_args, char *, int, ...)" + ) + end + end + + context "when there is a function with a pointer to a const value" do + let(:mock_header){ + parsed_header = {} + parsed_header[:functions] = [{ + :name => "const_test_function", + :return => {:type => "void"}, + :args => [{:type => "char *", :name => "a", :ptr? => false, :const? => true}, + {:type => "char *", :name => "b", :ptr? => false, :const? => false}] + }] + FffMockGenerator.create_mock_header("display", "mock_display", parsed_header) + } + it "then the generated file contains the correct const argument in the declaration" do + expect(mock_header).to include( + "DECLARE_FAKE_VOID_FUNC2(const_test_function, const char *, char *)" + ) + end + end + + context "when there is a function that returns a const pointer" do + let(:mock_header){ + parsed_header = {} + parsed_header[:functions] = [{ + :name => "return_const_pointer_test_function", + :modifier => "const", + :return => {:type => "char *" }, + :args => [{:type => "int", :name => "a"}] + }] + FffMockGenerator.create_mock_header("display", "mock_display", parsed_header) + } + it "then the generated file contains the correct const return value in the declaration" do + expect(mock_header).to include( + "DECLARE_FAKE_VALUE_FUNC1(const char *, return_const_pointer_test_function, int)" + ) + end + end + + context "when there is a function that returns a const int" do + let(:mock_header){ + parsed_header = {} + parsed_header[:functions] = [{ + :name => "return_const_int_test_function", + :modifier => "const", + :return => {:type => "int" }, + :args => [] + }] + FffMockGenerator.create_mock_header("display", "mock_display", parsed_header) + } + it "then the generated file contains the correct const return value in the declaration" do + expect(mock_header).to include( + "DECLARE_FAKE_VALUE_FUNC0(const int, return_const_int_test_function)" + ) + end + end + + context "when there are pre-includes" do + let(:mock_header) { + parsed_header = {} + FffMockGenerator.create_mock_header("display", "mock_display", parsed_header, + [%{"another_header.h"}]) + } + it "then they are included before the other files" do + expect(mock_header).to include( + %{#include "another_header.h"\n} + + %{#include "fff.h"} + ) + end + end + + context "when there are post-includes" do + let(:mock_header) { + parsed_header = {} + FffMockGenerator.create_mock_header("display", "mock_display", parsed_header, + nil, [%{"another_header.h"}]) + } + it "then they are included after the other files" do + expect(mock_header).to include( + %{#include "display.h"\n} + + %{#include "another_header.h"\n} + ) + end + end + +end diff --git a/vendor/ceedling/plugins/fake_function_framework/spec/fff_mock_source_generator_spec.rb b/vendor/ceedling/plugins/fake_function_framework/spec/fff_mock_source_generator_spec.rb new file mode 100644 index 0000000..364f852 --- /dev/null +++ b/vendor/ceedling/plugins/fake_function_framework/spec/fff_mock_source_generator_spec.rb @@ -0,0 +1,149 @@ +require 'stringio' +require 'fff_mock_generator.rb' + +# Test the contents of the .c file created for the mock. +describe "FffMockGenerator.create_mock_source" do + + context "when there is nothing to mock," do + let(:mock_source) { + parsed_header = {} + FffMockGenerator.create_mock_source("mock_my_module", parsed_header) + } + it "then the generated file includes the fff header" do + expect(mock_source).to include( + # fff.h also requires including string.h + %{#include \n} + + %{#include "fff.h"} + ) + end + it "then the generated file includes the mock header" do + expect(mock_source).to include( + %{#include "mock_my_module.h"\n} + ) + end + it "then the generated file defines the init function" do + expect(mock_source).to include( + "void mock_my_module_Init(void)\n" + + "{\n" + + " FFF_RESET_HISTORY();\n" + + "}" + ) + end + it "then the generated file defines the verify function" do + expect(mock_source).to include( + "void mock_my_module_Verify(void)\n" + + "{\n" + + "}" + ) + end + it "then the generated file defines the destroy function" do + expect(mock_source).to include( + "void mock_my_module_Destroy(void)\n" + + "{\n" + + "}" + ) + end + end + + context "when there are multiple functions," do + let(:mock_source) { + parsed_header = create_cmock_style_parsed_header( + [ {:name => 'a_function', :return_type => 'int', :args => ['char *']}, + {:name => 'another_function', :return_type => 'void'}, + {:name => 'three', :return_type => 'bool', :args => ['float', 'int']} + ]) + FffMockGenerator.create_mock_source("mock_display", parsed_header) + } + it "then the generated file contains the first fake function definition" do + expect(mock_source).to include( + "DEFINE_FAKE_VALUE_FUNC1(int, a_function, char *);" + ) + end + it "then the generated file contains the second fake function definition" do + expect(mock_source).to include( + "DEFINE_FAKE_VOID_FUNC0(another_function);" + ) + end + it "then the generated file contains the third fake function definition" do + expect(mock_source).to include( + "DEFINE_FAKE_VALUE_FUNC2(bool, three, float, int);" + ) + end + it "then the init function resets all of the fakes" do + expect(mock_source).to include( + "void mock_display_Init(void)\n" + + "{\n" + + " FFF_RESET_HISTORY();\n" + + " RESET_FAKE(a_function)\n" + + " RESET_FAKE(another_function)\n" + + " RESET_FAKE(three)\n" + + "}" + ) + end + end + + context "when there is a void function with variable arguments and " + + "additional arguments" do + let(:mock_source){ + parsed_header = {} + parsed_header[:functions] = [{ + :name => "function_with_var_args", + :return => {:type => "void"}, + :var_arg => "...", + :args => [{:type => 'char *'}, {:type => 'int'}] + }] + FffMockGenerator.create_mock_source("mock_display", parsed_header) + } + it "then the generated file contains the vararg definition" do + expect(mock_source).to include( + "DEFINE_FAKE_VOID_FUNC3_VARARG(function_with_var_args, char *, int, ...)" + ) + end + end + + context "when there is a function with a pointer to a const value" do + let(:mock_source){ + parsed_header = {} + parsed_header[:functions] = [{ + :name => "const_test_function", + :return => {:type => "void"}, + :args => [{:type => "char *", :name => "a", :ptr? => false, :const? => true}, + {:type => "char *", :name => "b", :ptr? => false, :const? => false}] + }] + FffMockGenerator.create_mock_source("mock_display", parsed_header) + } + it "then the generated file contains the correct const argument in the declaration" do + expect(mock_source).to include( + "DEFINE_FAKE_VOID_FUNC2(const_test_function, const char *, char *)" + ) + end + end + + context "when there are pre-includes" do + let(:mock_source) { + parsed_source = {} + FffMockGenerator.create_mock_source("mock_display", parsed_source, + [%{"another_header.h"}]) + } + it "then they are included before the other files" do + expect(mock_source).to include( + %{#include "another_header.h"\n} + + %{#include } + ) + end + end + + context "when there are post-includes" do + let(:mock_source) { + parsed_source = {} + FffMockGenerator.create_mock_source("mock_display", parsed_source, + nil, [%{"another_header.h"}]) + } + it "then they are included before the other files" do + expect(mock_source).to include( + %{#include "mock_display.h"\n} + + %{#include "another_header.h"\n} + ) + end + end +end \ No newline at end of file diff --git a/vendor/ceedling/plugins/fake_function_framework/spec/header_generator.rb b/vendor/ceedling/plugins/fake_function_framework/spec/header_generator.rb new file mode 100644 index 0000000..cda2784 --- /dev/null +++ b/vendor/ceedling/plugins/fake_function_framework/spec/header_generator.rb @@ -0,0 +1,51 @@ +# Create a CMock-style parsed header hash. This the type of hash created by +# CMock when parsing header files for automock generation. It contains all of +# includes, typedefs and functions (with return types and arguments) parsed from +# the header file. +def create_cmock_style_parsed_header(functions, typedefs = nil) + parsed_header = { + :includes => nil, + :functions => [], + :typedefs => [] + } + + # Add the typedefs. + if typedefs + typedefs.each do |typedef| + parsed_header[:typedefs] << typedef + end + end + + # Add the functions. + if functions + functions.each do |function| + # Build the array of arguments. + args = [] + if function.key?(:args) + function[:args].each do |arg| + args << { + :type => arg + } + end + end + parsed_header[:functions] << { + :name => function[:name], + :modifier => "", + :return => { + :type => function[:return_type], + :name => "cmock_to_return", + :ptr? => false, + :const? => false, + :str => "void cmock_to_return", + :void? => true + }, + :var_arg => nil, + :args_string => "void", + :args => args, + :args_call => "", + :contains_ptr? => false + } + end + end + parsed_header +end \ No newline at end of file diff --git a/vendor/ceedling/plugins/fake_function_framework/spec/spec_helper.rb b/vendor/ceedling/plugins/fake_function_framework/spec/spec_helper.rb new file mode 100644 index 0000000..25dc80a --- /dev/null +++ b/vendor/ceedling/plugins/fake_function_framework/spec/spec_helper.rb @@ -0,0 +1,96 @@ +# This file was generated by the `rspec --init` command. Conventionally, all +# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. +# The generated `.rspec` file contains `--require spec_helper` which will cause +# this file to always be loaded, without a need to explicitly require it in any +# files. +# +# Given that it is always loaded, you are encouraged to keep this file as +# light-weight as possible. Requiring heavyweight dependencies from this file +# will add to the boot time of your test suite on EVERY test run, even for an +# individual file that may not need all of that loaded. Instead, consider making +# a separate helper file that requires the additional dependencies and performs +# the additional setup, and require it from the spec files that actually need +# it. +# +# The `.rspec` file also contains a few flags that are not defaults but that +# users commonly want. +# +# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration +RSpec.configure do |config| + # rspec-expectations config goes here. You can use an alternate + # assertion/expectation library such as wrong or the stdlib/minitest + # assertions if you prefer. + config.expect_with :rspec do |expectations| + # This option will default to `true` in RSpec 4. It makes the `description` + # and `failure_message` of custom matchers include text for helper methods + # defined using `chain`, e.g.: + # be_bigger_than(2).and_smaller_than(4).description + # # => "be bigger than 2 and smaller than 4" + # ...rather than: + # # => "be bigger than 2" + expectations.include_chain_clauses_in_custom_matcher_descriptions = true + end + + # rspec-mocks config goes here. You can use an alternate test double + # library (such as bogus or mocha) by changing the `mock_with` option here. + config.mock_with :rspec do |mocks| + # Prevents you from mocking or stubbing a method that does not exist on + # a real object. This is generally recommended, and will default to + # `true` in RSpec 4. + mocks.verify_partial_doubles = true + end + +# The settings below are suggested to provide a good initial experience +# with RSpec, but feel free to customize to your heart's content. +=begin + # These two settings work together to allow you to limit a spec run + # to individual examples or groups you care about by tagging them with + # `:focus` metadata. When nothing is tagged with `:focus`, all examples + # get run. + config.filter_run :focus + config.run_all_when_everything_filtered = true + + # Allows RSpec to persist some state between runs in order to support + # the `--only-failures` and `--next-failure` CLI options. We recommend + # you configure your source control system to ignore this file. + config.example_status_persistence_file_path = "spec/examples.txt" + + # Limits the available syntax to the non-monkey patched syntax that is + # recommended. For more details, see: + # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/ + # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ + # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode + config.disable_monkey_patching! + + # This setting enables warnings. It's recommended, but in some cases may + # be too noisy due to issues in dependencies. + config.warnings = true + + # Many RSpec users commonly either run the entire suite or an individual + # file, and it's useful to allow more verbose output when running an + # individual spec file. + if config.files_to_run.one? + # Use the documentation formatter for detailed output, + # unless a formatter has already been configured + # (e.g. via a command-line flag). + config.default_formatter = 'doc' + end + + # Print the 10 slowest examples and example groups at the + # end of the spec run, to help surface which specs are running + # particularly slow. + config.profile_examples = 10 + + # Run specs in random order to surface order dependencies. If you find an + # order dependency and want to debug it, you can fix the order by providing + # the seed, which is printed after each run. + # --seed 1234 + config.order = :random + + # Seed global randomization in this process using the `--seed` CLI option. + # Setting this allows you to use `--seed` to deterministically reproduce + # test failures related to randomization by passing the same `--seed` value + # as the one that triggered the failure. + Kernel.srand config.seed +=end +end diff --git a/vendor/ceedling/plugins/fake_function_framework/src/fff_unity_helper.h b/vendor/ceedling/plugins/fake_function_framework/src/fff_unity_helper.h new file mode 100644 index 0000000..de3db44 --- /dev/null +++ b/vendor/ceedling/plugins/fake_function_framework/src/fff_unity_helper.h @@ -0,0 +1,33 @@ +#ifndef fff_unity_helper_H +#define fff_unity_helper_H + +/* + FFF helper macros for Unity. +*/ + +/* + Fail if the function was not called the expected number of times. +*/ +#define TEST_ASSERT_CALLED_TIMES(times_, function_) \ + TEST_ASSERT_EQUAL_MESSAGE(times_, \ + function_ ## _fake.call_count, \ + "Function " #function_ " called the incorrect number of times.") +/* + Fail if the function was not called exactly once. +*/ +#define TEST_ASSERT_CALLED(function_) TEST_ASSERT_CALLED_TIMES(1, function_) + +/* + Fail if the function was called 1 or more times. +*/ +#define TEST_ASSERT_NOT_CALLED(function_) TEST_ASSERT_CALLED_TIMES(0, function_) + +/* + Fail if the function was not called in this particular order. +*/ +#define TEST_ASSERT_CALLED_IN_ORDER(order_, function_) \ + TEST_ASSERT_EQUAL_PTR_MESSAGE((void *) function_, \ + fff.call_history[order_], \ + "Function " #function_ " not called in order " #order_ ) + +#endif \ No newline at end of file diff --git a/vendor/ceedling/plugins/gcov/README.md b/vendor/ceedling/plugins/gcov/README.md new file mode 100644 index 0000000..b144e3b --- /dev/null +++ b/vendor/ceedling/plugins/gcov/README.md @@ -0,0 +1,433 @@ +ceedling-gcov +============= + +# Plugin Overview + +Plugin for integrating GNU GCov code coverage tool into Ceedling projects. +Currently only designed for the gcov command (like LCOV for example). In the +future we could configure this to work with other code coverage tools. + +This plugin currently uses [gcovr](https://www.gcovr.com/) and / or +[ReportGenerator](https://danielpalme.github.io/ReportGenerator/) +as utilities to generate HTML, XML, JSON, or Text reports. The normal gcov +plugin _must_ be run first for these reports to generate. + +## Installation + +gcovr can be installed via pip like so: + +```sh +pip install gcovr +``` + +ReportGenerator can be installed via .NET Core like so: + +```sh +dotnet tool install -g dotnet-reportgenerator-globaltool +``` + +It is not required to install both `gcovr` and `ReportGenerator`. Either utility +may be installed to create reports. + +## Configuration + +The gcov plugin supports configuration options via your `project.yml` provided +by Ceedling. + +### Utilities + +Gcovr and / or ReportGenerator may be enabled to create coverage reports. + +```yaml +:gcov: + :utilities: + - gcovr # Use gcovr to create the specified reports (default). + - ReportGenerator # Use ReportGenerator to create the specified reports. +``` + +### Reports + +Various reports are available and may be enabled with the following +configuration item. See the specific report sections in this README +for additional options and information. All generated reports will be found in `build/artifacts/gcov`. + +```yaml +:gcov: + # Specify one or more reports to generate. + # Defaults to HtmlBasic. + :reports: + # Make an HTML summary report. + # Supported utilities: gcovr, ReportGenerator + - HtmlBasic + + # Make an HTML report with line by line coverage of each source file. + # Supported utilities: gcovr, ReportGenerator + - HtmlDetailed + + # Make a Text report, which may be output to the console with gcovr or a file in both gcovr and ReportGenerator. + # Supported utilities: gcovr, ReportGenerator + - Text + + # Make a Cobertura XML report. + # Supported utilities: gcovr, ReportGenerator + - Cobertura + + # Make a SonarQube XML report. + # Supported utilities: gcovr, ReportGenerator + - SonarQube + + # Make a JSON report. + # Supported utilities: gcovr + - JSON + + # Make a detailed HTML report with CSS and JavaScript included in every HTML page. Useful for build servers. + # Supported utilities: ReportGenerator + - HtmlInline + + # Make a detailed HTML report with a light theme and CSS and JavaScript included in every HTML page for Azure DevOps. + # Supported utilities: ReportGenerator + - HtmlInlineAzure + + # Make a detailed HTML report with a dark theme and CSS and JavaScript included in every HTML page for Azure DevOps. + # Supported utilities: ReportGenerator + - HtmlInlineAzureDark + + # Make a single HTML file containing a chart with historic coverage information. + # Supported utilities: ReportGenerator + - HtmlChart + + # Make a detailed HTML report in a single file. + # Supported utilities: ReportGenerator + - MHtml + + # Make SVG and PNG files that show line and / or branch coverage information. + # Supported utilities: ReportGenerator + - Badges + + # Make a single CSV file containing coverage information per file. + # Supported utilities: ReportGenerator + - CsvSummary + + # Make a single TEX file containing a summary for all files and detailed reports for each files. + # Supported utilities: ReportGenerator + - Latex + + # Make a single TEX file containing a summary for all files. + # Supported utilities: ReportGenerator + - LatexSummary + + # Make a single PNG file containing a chart with historic coverage information. + # Supported utilities: ReportGenerator + - PngChart + + # Command line output interpreted by TeamCity. + # Supported utilities: ReportGenerator + - TeamCitySummary + + # Make a text file in lcov format. + # Supported utilities: ReportGenerator + - lcov + + # Make a XML file containing a summary for all classes and detailed reports for each class. + # Supported utilities: ReportGenerator + - Xml + + # Make a single XML file containing a summary for all files. + # Supported utilities: ReportGenerator + - XmlSummary +``` + +### Gcovr HTML Reports + +Generation of Gcovr HTML reports may be modified with the following configuration items. + +```yaml +:gcov: + # Set to 'true' to enable HTML reports or set to 'false' to disable. + # Defaults to enabled. (gcovr --html) + # Deprecated - See the :reports: configuration option. + :html_report: [true|false] + + # Gcovr supports generating two types of HTML reports. Use 'basic' to create + # an HTML report with only the overall file information. Use 'detailed' to create + # an HTML report with line by line coverage of each source file. + # Defaults to 'basic'. Set to 'detailed' for (gcovr --html-details). + # Deprecated - See the :reports: configuration option. + :html_report_type: [basic|detailed] + + + :gcovr: + # HTML report filename. + :html_artifact_filename: + + # Use 'title' as title for the HTML report. + # Default is 'Head'. (gcovr --html-title) + :html_title: + + # If the coverage is below MEDIUM, the value is marked as low coverage in the HTML report. + # MEDIUM has to be lower than or equal to value of html_high_threshold. + # If MEDIUM is equal to value of html_high_threshold the report has only high and low coverage. + # Default is 75.0. (gcovr --html-medium-threshold) + :html_medium_threshold: 75 + + # If the coverage is below HIGH, the value is marked as medium coverage in the HTML report. + # HIGH has to be greater than or equal to value of html_medium_threshold. + # If HIGH is equal to value of html_medium_threshold the report has only high and low coverage. + # Default is 90.0. (gcovr -html-high-threshold) + :html_high_threshold: 90 + + # Set to 'true' to use absolute paths to link the 'detailed' reports. + # Defaults to relative links. (gcovr --html-absolute-paths) + :html_absolute_paths: [true|false] + + # Override the declared HTML report encoding. Defaults to UTF-8. (gcovr --html-encoding) + :html_encoding: <html_encoding> +``` + +### Cobertura XML Reports + +Generation of Cobertura XML reports may be modified with the following configuration items. + +```yaml +:gcov: + # Set to 'true' to enable Cobertura XML reports or set to 'false' to disable. + # Defaults to disabled. (gcovr --xml) + # Deprecated - See the :reports: configuration option. + :xml_report: [true|false] + + + :gcovr: + # Set to 'true' to pretty-print the Cobertura XML report, otherwise set to 'false'. + # Defaults to disabled. (gcovr --xml-pretty) + :xml_pretty: [true|false] + :cobertura_pretty: [true|false] + + # Cobertura XML report filename. + :xml_artifact_filename: <output> + :cobertura_artifact_filename: <output> +``` + +### SonarQube XML Reports + +Generation of SonarQube XML reports may be modified with the following configuration items. + +```yaml +:gcov: + :gcovr: + # SonarQube XML report filename. + :sonarqube_artifact_filename: <output> +``` + +### JSON Reports + +Generation of JSON reports may be modified with the following configuration items. + +```yaml +:gcov: + :gcovr: + # Set to 'true' to pretty-print the JSON report, otherwise set 'false'. + # Defaults to disabled. (gcovr --json-pretty) + :json_pretty: [true|false] + + # JSON report filename. + :json_artifact_filename: <output> +``` + +### Text Reports + +Generation of text reports may be modified with the following configuration items. +Text reports may be printed to the console or output to a file. + +```yaml +:gcov: + :gcovr: + # Text report filename. + # The text report is printed to the console when no filename is provided. + :text_artifact_filename: <output> +``` + +### Common Report Options + +There are a number of options to control which files are considered part of +the coverage report. Most often, we only care about coverage on our source code, and not +on tests or automatically generated mocks, runners, etc. However, there are times +where this isn't true... or there are times where we've moved ceedling's directory +structure so that the project file isn't at the root of the project anymore. In these +cases, you may need to tweak `report_include`, `report_exclude`, and `exclude_directories`. + +One important note about `report_root`: gcovr will take only a single root folder, unlike +Ceedling's ability to take as many as you like. So you will need to choose a folder which is +a superset of ALL the folders you want, and then use the include or exclude options to set up +patterns of files to pay attention to or ignore. It's not ideal, but it works. + +Finally, there are a number of settings which can be specified to adjust the +default behaviors of gcovr: + +```yaml +:gcov: + :gcovr: + # The root directory of your source files. Defaults to ".", the current directory. + # File names are reported relative to this root. The report_root is the default report_include. + :report_root: "." + + # Load the specified configuration file. + # Defaults to gcovr.cfg in the report_root directory. (gcovr --config) + :config_file: <config_file> + + # Exit with a status of 2 if the total line coverage is less than MIN. + # Can be ORed with exit status of 'fail_under_branch' option. (gcovr --fail-under-line) + :fail_under_line: 30 + + # Exit with a status of 4 if the total branch coverage is less than MIN. + # Can be ORed with exit status of 'fail_under_line' option. (gcovr --fail-under-branch) + :fail_under_branch: 30 + + # Select the source file encoding. + # Defaults to the system default encoding (UTF-8). (gcovr --source-encoding) + :source_encoding: <source_encoding> + + # Report the branch coverage instead of the line coverage. For text report only. (gcovr --branches). + :branches: [true|false] + + # Sort entries by increasing number of uncovered lines. + # For text and HTML report. (gcovr --sort-uncovered) + :sort_uncovered: [true|false] + + # Sort entries by increasing percentage of uncovered lines. + # For text and HTML report. (gcovr --sort-percentage) + :sort_percentage: [true|false] + + # Print a small report to stdout with line & branch percentage coverage. + # This is in addition to other reports. (gcovr --print-summary). + :print_summary: [true|false] + + # Keep only source files that match this filter. (gcovr --filter). + :report_include: "^src" + + # Exclude source files that match this filter. (gcovr --exclude). + :report_exclude: "^vendor.*|^build.*|^test.*|^lib.*" + + # Keep only gcov data files that match this filter. (gcovr --gcov-filter). + :gcov_filter: <gcov_filter> + + # Exclude gcov data files that match this filter. (gcovr --gcov-exclude). + :gcov_exclude: <gcov_exclude> + + # Exclude directories that match this regex while searching + # raw coverage files. (gcovr --exclude-directories). + :exclude_directories: <exclude_dirs> + + # Use a particular gcov executable. (gcovr --gcov-executable). + :gcov_executable: <gcov_cmd> + + # Exclude branch coverage from lines without useful + # source code. (gcovr --exclude-unreachable-branches). + :exclude_unreachable_branches: [true|false] + + # For branch coverage, exclude branches that the compiler + # generates for exception handling. (gcovr --exclude-throw-branches). + :exclude_throw_branches: [true|false] + + # Use existing gcov files for analysis. Default: False. (gcovr --use-gcov-files) + :use_gcov_files: [true|false] + + # Skip lines with parse errors in GCOV files instead of + # exiting with an error. (gcovr --gcov-ignore-parse-errors). + :gcov_ignore_parse_errors: [true|false] + + # Override normal working directory detection. (gcovr --object-directory) + :object_directory: <objdir> + + # Keep gcov files after processing. (gcovr --keep). + :keep: [true|false] + + # Delete gcda files after processing. (gcovr --delete). + :delete: [true|false] + + # Set the number of threads to use in parallel. (gcovr -j). + :num_parallel_threads: <num_threads> + + # When scanning the code coverage, if any files are found that do not have + # associated coverage data, the command will abort with an error message. + :abort_on_uncovered: true + + # When using the ``abort_on_uncovered`` option, the files in this list will not + # trigger a failure. + # Ceedling globs described in the Ceedling packet ``Path`` section can be used + # when directories are placed on the list. Globs are limited to matching directories + # and not files. + :uncovered_ignore_list: [] +``` + +### ReportGenerator Configuration + +The ReportGenerator utility may be configured with the following configuration items. +All generated reports may be found in `build/artifacts/gcov/ReportGenerator`. + +```yaml +:gcov: + :report_generator: + # Optional directory for storing persistent coverage information. + # Can be used in future reports to show coverage evolution. + :history_directory: <history_directory> + + # Optional plugin files for custom reports or custom history storage (separated by semicolon). + :plugins: CustomReports.dll + + # Optional list of assemblies that should be included or excluded in the report (separated by semicolon).. + # Exclusion filters take precedence over inclusion filters. + # Wildcards are allowed, but not regular expressions. + :assembly_filters: "+Included;-Excluded" + + # Optional list of classes that should be included or excluded in the report (separated by semicolon).. + # Exclusion filters take precedence over inclusion filters. + # Wildcards are allowed, but not regular expressions. + :class_filters: "+Included;-Excluded" + + # Optional list of files that should be included or excluded in the report (separated by semicolon).. + # Exclusion filters take precedence over inclusion filters. + # Wildcards are allowed, but not regular expressions. + :file_filters: "-./vendor/*;-./build/*;-./test/*;-./lib/*;+./src/*" + + # The verbosity level of the log messages. + # Values: Verbose, Info, Warning, Error, Off + :verbosity: Warning + + # Optional tag or build version. + :tag: <tag> + + # Optional list of one or more regular expressions to exclude gcov notes files that match these filters. + :gcov_exclude: + - <exclude_regex1> + - <exclude_regex2> + + # Optionally use a particular gcov executable. Defaults to gcov. + :gcov_executable: <gcov_cmd> + + # Optionally set the number of threads to use in parallel. Defaults to 1. + :num_parallel_threads: <num_threads> + + # Optional list of one or more command line arguments to pass to Report Generator. + # Useful for configuring Risk Hotspots and Other Settings. + # https://github.com/danielpalme/ReportGenerator/wiki/Settings + :custom_args: + - <custom_arg1> + - <custom_arg2> +``` + +## Example Usage + +```sh +ceedling gcov:all utils:gcov +``` + +## To-Do list + +- Generate overall report (combined statistics from all files with coverage) + +## Citations + +Most of the comment text which describes the options was taken from the +[Gcovr User Guide](https://www.gcovr.com/en/stable/guide.html) and the +[ReportGenerator Wiki](https://github.com/danielpalme/ReportGenerator/wiki). +The text is repeated here to provide the most accurate option functionality. diff --git a/vendor/ceedling/plugins/gcov/template.erb b/vendor/ceedling/plugins/gcov/assets/template.erb similarity index 80% rename from vendor/ceedling/plugins/gcov/template.erb rename to vendor/ceedling/plugins/gcov/assets/template.erb index a6d6929..5e5a174 100644 --- a/vendor/ceedling/plugins/gcov/template.erb +++ b/vendor/ceedling/plugins/gcov/assets/template.erb @@ -1,7 +1,7 @@ % function_string = hash[:coverage][:functions].to_s % branch_string = hash[:coverage][:branches].to_s % format_string = "%#{[function_string.length, branch_string.length].max}i" -<%=@ceedling[:plugin_reportinator].generate_banner("#{BULLSEYE_ROOT_NAME.upcase}: CODE COVERAGE SUMMARY")%> +<%=@ceedling[:plugin_reportinator].generate_banner("#{GCOV_ROOT_NAME.upcase}: CODE COVERAGE SUMMARY")%> % if (!hash[:coverage][:functions].nil?) FUNCTIONS: <%=sprintf(format_string, hash[:coverage][:functions])%>% % else diff --git a/vendor/ceedling/plugins/gcov/config/defaults_gcov.rb b/vendor/ceedling/plugins/gcov/config/defaults_gcov.rb new file mode 100644 index 0000000..e3ce340 --- /dev/null +++ b/vendor/ceedling/plugins/gcov/config/defaults_gcov.rb @@ -0,0 +1,118 @@ + +DEFAULT_GCOV_COMPILER_TOOL = { + :executable => ENV['CC'].nil? ? FilePathUtils.os_executable_ext('gcc').freeze : ENV['CC'].split[0], + :name => 'default_gcov_compiler'.freeze, + :stderr_redirect => StdErrRedirect::NONE.freeze, + :background_exec => BackgroundExec::NONE.freeze, + :optional => false.freeze, + :arguments => [ + "-g".freeze, + "-fprofile-arcs".freeze, + "-ftest-coverage".freeze, + ENV['CC'].nil? ? "" : ENV['CC'].split[1..-1], + ENV['CPPFLAGS'].nil? ? "" : ENV['CPPFLAGS'].split, + {"-I\"$\"" => 'COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR'}.freeze, + {"-I\"$\"" => 'COLLECTION_PATHS_TEST_TOOLCHAIN_INCLUDE'}.freeze, + {"-D$" => 'COLLECTION_DEFINES_TEST_AND_VENDOR'}.freeze, + "-DGCOV_COMPILER".freeze, + "-DCODE_COVERAGE".freeze, + ENV['CFLAGS'].nil? ? "" : ENV['CFLAGS'].split, + "-c \"${1}\"".freeze, + "-o \"${2}\"".freeze + ].freeze + } + + +DEFAULT_GCOV_LINKER_TOOL = { + :executable => ENV['CCLD'].nil? ? FilePathUtils.os_executable_ext('gcc').freeze : ENV['CCLD'].split[0], + :name => 'default_gcov_linker'.freeze, + :stderr_redirect => StdErrRedirect::NONE.freeze, + :background_exec => BackgroundExec::NONE.freeze, + :optional => false.freeze, + :arguments => [ + "-g".freeze, + "-fprofile-arcs".freeze, + "-ftest-coverage".freeze, + ENV['CCLD'].nil? ? "" : ENV['CCLD'].split[1..-1], + ENV['CFLAGS'].nil? ? "" : ENV['CFLAGS'].split, + ENV['LDFLAGS'].nil? ? "" : ENV['LDFLAGS'].split, + "\"${1}\"".freeze, + "-o \"${2}\"".freeze, + "${4}".freeze, + "${5}".freeze, + ENV['LDLIBS'].nil? ? "" : ENV['LDLIBS'].split + ].freeze + } + +DEFAULT_GCOV_FIXTURE_TOOL = { + :executable => '${1}'.freeze, + :name => 'default_gcov_fixture'.freeze, + :stderr_redirect => StdErrRedirect::NONE.freeze, + :background_exec => BackgroundExec::NONE.freeze, + :optional => false.freeze, + :arguments => [].freeze + } + +DEFAULT_GCOV_REPORT_TOOL = { + :executable => ENV['GCOV'].nil? ? FilePathUtils.os_executable_ext('gcov').freeze : ENV['GCOV'].split[0], + :name => 'default_gcov_report'.freeze, + :stderr_redirect => StdErrRedirect::NONE.freeze, + :background_exec => BackgroundExec::NONE.freeze, + :optional => false.freeze, + :arguments => [ + "-n".freeze, + "-p".freeze, + "-b".freeze, + {"-o \"$\"" => 'GCOV_BUILD_OUTPUT_PATH'}.freeze, + "\"${1}\"".freeze + ].freeze + } + +DEFAULT_GCOV_GCOV_POST_REPORT_TOOL = { + :executable => ENV['GCOV'].nil? ? FilePathUtils.os_executable_ext('gcov').freeze : ENV['GCOV'].split[0], + :name => 'default_gcov_gcov_post_report'.freeze, + :stderr_redirect => StdErrRedirect::NONE.freeze, + :background_exec => BackgroundExec::NONE.freeze, + :optional => true.freeze, + :arguments => [ + "-b".freeze, + "-c".freeze, + "-r".freeze, + "-x".freeze, + "${1}".freeze + ].freeze + } + +DEFAULT_GCOV_GCOVR_POST_REPORT_TOOL = { + :executable => 'gcovr'.freeze, + :name => 'default_gcov_gcovr_post_report'.freeze, + :stderr_redirect => StdErrRedirect::NONE.freeze, + :background_exec => BackgroundExec::NONE.freeze, + :optional => true.freeze, + :arguments => [ + "${1}".freeze + ].freeze + } + +DEFAULT_GCOV_REPORTGENERATOR_POST_REPORT = { + :executable => 'reportgenerator'.freeze, + :name => 'default_gcov_reportgenerator_post_report'.freeze, + :stderr_redirect => StdErrRedirect::NONE.freeze, + :background_exec => BackgroundExec::NONE.freeze, + :optional => true.freeze, + :arguments => [ + "${1}".freeze + ].freeze + } + +def get_default_config + return :tools => { + :gcov_compiler => DEFAULT_GCOV_COMPILER_TOOL, + :gcov_linker => DEFAULT_GCOV_LINKER_TOOL, + :gcov_fixture => DEFAULT_GCOV_FIXTURE_TOOL, + :gcov_report => DEFAULT_GCOV_REPORT_TOOL, + :gcov_gcov_post_report => DEFAULT_GCOV_GCOV_POST_REPORT_TOOL, + :gcov_gcovr_post_report => DEFAULT_GCOV_GCOVR_POST_REPORT_TOOL, + :gcov_reportgenerator_post_report => DEFAULT_GCOV_REPORTGENERATOR_POST_REPORT + } +end diff --git a/vendor/ceedling/plugins/gcov/defaults.yml b/vendor/ceedling/plugins/gcov/defaults.yml deleted file mode 100644 index 78be972..0000000 --- a/vendor/ceedling/plugins/gcov/defaults.yml +++ /dev/null @@ -1,34 +0,0 @@ ---- - -:tools: - :gcov_compiler: - :executable: gcc - :arguments: - - -g - - -fprofile-arcs - - -ftest-coverage - - -I"$": COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR - - -I"$": COLLECTION_PATHS_TEST_TOOLCHAIN_INCLUDE - - -D$: COLLECTION_DEFINES_TEST_AND_VENDOR - - -DGCOV_COMPILER - - -c "${1}" - - -o "${2}" - :gcov_linker: - :executable: gcc - :arguments: - - -fprofile-arcs - - -ftest-coverage - - ${1} - - -o ${2} - :gcov_fixture: - :executable: ${1} - :gcov_report: - :executable: gcov - :arguments: - - -n - - -p - - -b - - -o "$": GCOV_BUILD_OUTPUT_PATH - - "\"${1}\"" - -... diff --git a/vendor/ceedling/plugins/gcov/gcov.rake b/vendor/ceedling/plugins/gcov/gcov.rake index 197a064..1467564 100644 --- a/vendor/ceedling/plugins/gcov/gcov.rake +++ b/vendor/ceedling/plugins/gcov/gcov.rake @@ -1,3 +1,5 @@ +require 'reportgenerator_reportinator' +require 'gcovr_reportinator' directory(GCOV_BUILD_OUTPUT_PATH) directory(GCOV_RESULTS_PATH) @@ -6,147 +8,202 @@ directory(GCOV_DEPENDENCIES_PATH) CLEAN.include(File.join(GCOV_BUILD_OUTPUT_PATH, '*')) CLEAN.include(File.join(GCOV_RESULTS_PATH, '*')) +CLEAN.include(File.join(GCOV_ARTIFACTS_PATH, '*')) CLEAN.include(File.join(GCOV_DEPENDENCIES_PATH, '*')) CLOBBER.include(File.join(GCOV_BUILD_PATH, '**/*')) +rule(/#{GCOV_BUILD_OUTPUT_PATH}\/#{'.+\\' + EXTENSION_OBJECT}$/ => [ + proc do |task_name| + @ceedling[:file_finder].find_compilation_input_file(task_name) + end + ]) do |object| -rule(/#{GCOV_BUILD_OUTPUT_PATH}\/#{'.+\\'+EXTENSION_OBJECT}$/ => [ - proc do |task_name| - @ceedling[:file_finder].find_compilation_input_file(task_name) - end - ]) do |object| - - if (File.basename(object.source) =~ /^(#{PROJECT_TEST_FILE_PREFIX}|#{CMOCK_MOCK_PREFIX}|#{GCOV_IGNORE_SOURCES.join('|')})/i) + if File.basename(object.source) =~ /^(#{PROJECT_TEST_FILE_PREFIX}|#{CMOCK_MOCK_PREFIX})|(#{VENDORS_FILES.map{|source| '\b' + source + '\b'}.join('|')})/ @ceedling[:generator].generate_object_file( TOOLS_GCOV_COMPILER, + OPERATION_COMPILE_SYM, GCOV_SYM, object.source, object.name, - @ceedling[:file_path_utils].form_test_build_list_filepath( object.name ) ) + @ceedling[:file_path_utils].form_test_build_list_filepath(object.name) + ) else @ceedling[GCOV_SYM].generate_coverage_object_file(object.source, object.name) end - end -rule(/#{GCOV_BUILD_OUTPUT_PATH}\/#{'.+\\'+EXTENSION_EXECUTABLE}$/) do |bin_file| +rule(/#{GCOV_BUILD_OUTPUT_PATH}\/#{'.+\\' + EXTENSION_EXECUTABLE}$/) do |bin_file| + lib_args = @ceedling[:test_invoker].convert_libraries_to_arguments() + lib_paths = @ceedling[:test_invoker].get_library_paths_to_arguments() @ceedling[:generator].generate_executable_file( TOOLS_GCOV_LINKER, GCOV_SYM, bin_file.prerequisites, bin_file.name, - @ceedling[:file_path_utils].form_test_build_map_filepath(bin_file.name)) + @ceedling[:file_path_utils].form_test_build_map_filepath(bin_file.name), + lib_args, + lib_paths + ) end -rule(/#{GCOV_RESULTS_PATH}\/#{'.+\\'+EXTENSION_TESTPASS}$/ => [ - proc do |task_name| - @ceedling[:file_path_utils].form_test_executable_filepath(task_name) - end - ]) do |test_result| +rule(/#{GCOV_RESULTS_PATH}\/#{'.+\\' + EXTENSION_TESTPASS}$/ => [ + proc do |task_name| + @ceedling[:file_path_utils].form_test_executable_filepath(task_name) + end + ]) do |test_result| @ceedling[:generator].generate_test_results(TOOLS_GCOV_FIXTURE, GCOV_SYM, test_result.source, test_result.name) end -rule(/#{GCOV_DEPENDENCIES_PATH}\/#{'.+\\'+EXTENSION_DEPENDENCIES}$/ => [ - proc do |task_name| - @ceedling[:file_finder].find_compilation_input_file(task_name) - end - ]) do |dep| +rule(/#{GCOV_DEPENDENCIES_PATH}\/#{'.+\\' + EXTENSION_DEPENDENCIES}$/ => [ + proc do |task_name| + @ceedling[:file_finder].find_compilation_input_file(task_name) + end + ]) do |dep| @ceedling[:generator].generate_dependencies_file( TOOLS_TEST_DEPENDENCIES_GENERATOR, GCOV_SYM, dep.source, - File.join(GCOV_BUILD_OUTPUT_PATH, File.basename(dep.source).ext(EXTENSION_OBJECT) ), - dep.name) + File.join(GCOV_BUILD_OUTPUT_PATH, File.basename(dep.source).ext(EXTENSION_OBJECT)), + dep.name + ) end -task :directories => [GCOV_BUILD_OUTPUT_PATH, GCOV_RESULTS_PATH, GCOV_DEPENDENCIES_PATH, GCOV_ARTIFACTS_PATH] +task directories: [GCOV_BUILD_OUTPUT_PATH, GCOV_RESULTS_PATH, GCOV_DEPENDENCIES_PATH, GCOV_ARTIFACTS_PATH] namespace GCOV_SYM do + task source_coverage: COLLECTION_ALL_SOURCE.pathmap("#{GCOV_BUILD_OUTPUT_PATH}/%n#{@ceedling[:configurator].extension_object}") - task :source_coverage => COLLECTION_ALL_SOURCE.pathmap("#{GCOV_BUILD_OUTPUT_PATH}/%n#{@ceedling[:configurator].extension_object}") - - desc "Run code coverage for all tests" - task :all => [:directories] do + desc 'Run code coverage for all tests' + task all: [:test_deps] do @ceedling[:configurator].replace_flattened_config(@ceedling[GCOV_SYM].config) @ceedling[:test_invoker].setup_and_invoke(COLLECTION_ALL_TESTS, GCOV_SYM) @ceedling[:configurator].restore_config end - desc "Run single test w/ coverage ([*] real test or source file name, no path)." + desc 'Run single test w/ coverage ([*] real test or source file name, no path).' task :* do - message = "\nOops! '#{GCOV_ROOT_NAME}:*' isn't a real task. " + - "Use a real test or source file name (no path) in place of the wildcard.\n" + + message = "\nOops! '#{GCOV_ROOT_NAME}:*' isn't a real task. " \ + "Use a real test or source file name (no path) in place of the wildcard.\n" \ "Example: rake #{GCOV_ROOT_NAME}:foo.c\n\n" - - @ceedling[:streaminator].stdout_puts( message ) + + @ceedling[:streaminator].stdout_puts(message) end - - desc "Run tests by matching regular expression pattern." - task :pattern, [:regex] => [:directories] do |t, args| + + desc 'Run tests by matching regular expression pattern.' + task :pattern, [:regex] => [:test_deps] do |_t, args| matches = [] - + COLLECTION_ALL_TESTS.each do |test| matches << test if test =~ /#{args.regex}/ end - - if (matches.size > 0) + + if !matches.empty? @ceedling[:configurator].replace_flattened_config(@ceedling[GCOV_SYM].config) - @ceedling[:test_invoker].setup_and_invoke(matches, GCOV_SYM, {:force_run => false}) + @ceedling[:test_invoker].setup_and_invoke(matches, GCOV_SYM, force_run: false) @ceedling[:configurator].restore_config else @ceedling[:streaminator].stdout_puts("\nFound no tests matching pattern /#{args.regex}/.") end end - desc "Run tests whose test path contains [dir] or [dir] substring." - task :path, [:dir] => [:directories] do |t, args| + desc 'Run tests whose test path contains [dir] or [dir] substring.' + task :path, [:dir] => [:test_deps] do |_t, args| matches = [] - + COLLECTION_ALL_TESTS.each do |test| - matches << test if File.dirname(test).include?(args.dir.gsub(/\\/, '/')) + matches << test if File.dirname(test).include?(args.dir.tr('\\', '/')) end - - if (matches.size > 0) + + if !matches.empty? @ceedling[:configurator].replace_flattened_config(@ceedling[GCOV_SYM].config) - @ceedling[:test_invoker].setup_and_invoke(matches, GCOV_SYM, {:force_run => false}) + @ceedling[:test_invoker].setup_and_invoke(matches, GCOV_SYM, force_run: false) @ceedling[:configurator].restore_config else @ceedling[:streaminator].stdout_puts("\nFound no tests including the given path or path component.") end end - desc "Run code coverage for changed files" - task :delta => [:directories] do + desc 'Run code coverage for changed files' + task delta: [:test_deps] do @ceedling[:configurator].replace_flattened_config(@ceedling[GCOV_SYM].config) - @ceedling[:test_invoker].setup_and_invoke(COLLECTION_ALL_TESTS, GCOV_SYM, {:force_run => false}) + @ceedling[:test_invoker].setup_and_invoke(COLLECTION_ALL_TESTS, GCOV_SYM, force_run: false) @ceedling[:configurator].restore_config end - + # use a rule to increase efficiency for large projects # gcov test tasks by regex rule(/^#{GCOV_TASK_ROOT}\S+$/ => [ - proc do |task_name| - test = task_name.sub(/#{GCOV_TASK_ROOT}/, '') - test = "#{PROJECT_TEST_FILE_PREFIX}#{test}" if not (test.start_with?(PROJECT_TEST_FILE_PREFIX)) - @ceedling[:file_finder].find_test_from_file_path(test) - end - ]) do |test| - @ceedling[:rake_wrapper][:directories].invoke + proc do |task_name| + test = task_name.sub(/#{GCOV_TASK_ROOT}/, '') + test = "#{PROJECT_TEST_FILE_PREFIX}#{test}" unless test.start_with?(PROJECT_TEST_FILE_PREFIX) + @ceedling[:file_finder].find_test_from_file_path(test) + end + ]) do |test| + @ceedling[:rake_wrapper][:test_deps].invoke @ceedling[:configurator].replace_flattened_config(@ceedling[GCOV_SYM].config) @ceedling[:test_invoker].setup_and_invoke([test.source], GCOV_SYM) @ceedling[:configurator].restore_config end - end if PROJECT_USE_DEEP_DEPENDENCIES -namespace REFRESH_SYM do - task GCOV_SYM do - @ceedling[:configurator].replace_flattened_config(@ceedling[GCOV_SYM].config) - @ceedling[:test_invoker].refresh_deep_dependencies - @ceedling[:configurator].restore_config + namespace REFRESH_SYM do + task GCOV_SYM do + @ceedling[:configurator].replace_flattened_config(@ceedling[GCOV_SYM].config) + @ceedling[:test_invoker].refresh_deep_dependencies + @ceedling[:configurator].restore_config + end end end -end +namespace UTILS_SYM do + # Report Creation Utilities + UTILITY_NAME_GCOVR = "gcovr" + UTILITY_NAME_REPORT_GENERATOR = "ReportGenerator" + UTILITY_NAMES = [UTILITY_NAME_GCOVR, UTILITY_NAME_REPORT_GENERATOR] + + # Returns true is the given utility is enabled, otherwise returns false. + def is_utility_enabled(opts, utility_name) + return !(opts.nil?) && !(opts[:gcov_utilities].nil?) && (opts[:gcov_utilities].map(&:upcase).include? utility_name.upcase) + end + + + desc "Create gcov code coverage html/xml/json/text report(s). (Note: Must run 'ceedling gcov' first)." + task GCOV_SYM do + # Get the gcov options from project.yml. + opts = @ceedling[:configurator].project_config_hash + + # Create the artifacts output directory. + if !File.directory? GCOV_ARTIFACTS_PATH + FileUtils.mkdir_p GCOV_ARTIFACTS_PATH + end + + # Remove unsupported reporting utilities. + if !(opts[:gcov_utilities].nil?) + opts[:gcov_utilities].reject! { |item| !(UTILITY_NAMES.map(&:upcase).include? item.upcase) } + end + + # Default to gcovr when no reporting utilities are specified. + if opts[:gcov_utilities].nil? || opts[:gcov_utilities].empty? + opts[:gcov_utilities] = [UTILITY_NAME_GCOVR] + end + + if opts[:gcov_reports].nil? + opts[:gcov_reports] = [] + end + + gcovr_reportinator = GcovrReportinator.new(@ceedling) + gcovr_reportinator.support_deprecated_options(opts) + + if is_utility_enabled(opts, UTILITY_NAME_GCOVR) + gcovr_reportinator.make_reports(opts) + end + + if is_utility_enabled(opts, UTILITY_NAME_REPORT_GENERATOR) + reportgenerator_reportinator = ReportGeneratorReportinator.new(@ceedling) + reportgenerator_reportinator.make_reports(opts) + end + + end +end diff --git a/vendor/ceedling/plugins/gcov/gcov.rb b/vendor/ceedling/plugins/gcov/gcov.rb deleted file mode 100644 index d34ceca..0000000 --- a/vendor/ceedling/plugins/gcov/gcov.rb +++ /dev/null @@ -1,128 +0,0 @@ -require 'plugin' -require 'constants' - -GCOV_ROOT_NAME = 'gcov' -GCOV_TASK_ROOT = GCOV_ROOT_NAME + ':' -GCOV_SYM = GCOV_ROOT_NAME.to_sym - -GCOV_BUILD_PATH = "#{PROJECT_BUILD_ROOT}/#{GCOV_ROOT_NAME}" -GCOV_BUILD_OUTPUT_PATH = "#{GCOV_BUILD_PATH}/out" -GCOV_RESULTS_PATH = "#{GCOV_BUILD_PATH}/results" -GCOV_DEPENDENCIES_PATH = "#{GCOV_BUILD_PATH}/dependencies" -GCOV_ARTIFACTS_PATH = "#{PROJECT_BUILD_ARTIFACTS_ROOT}/#{GCOV_ROOT_NAME}" - -GCOV_IGNORE_SOURCES = ['unity', 'cmock', 'cexception'] - - -class Gcov < Plugin - - attr_reader :config - - def setup - @result_list = [] - - @config = { - :project_test_build_output_path => GCOV_BUILD_OUTPUT_PATH, - :project_test_results_path => GCOV_RESULTS_PATH, - :project_test_dependencies_path => GCOV_DEPENDENCIES_PATH, - :defines_test => DEFINES_TEST + ['CODE_COVERAGE'], - :collection_defines_test_and_vendor => COLLECTION_DEFINES_TEST_AND_VENDOR + ['CODE_COVERAGE'] - } - - @coverage_template_all = @ceedling[:file_wrapper].read( File.join( PLUGINS_GCOV_PATH, 'template.erb') ) - end - - def generate_coverage_object_file(source, object) - compile_command = - @ceedling[:tool_executor].build_command_line( - TOOLS_GCOV_COMPILER, - source, - object, - @ceedling[:file_path_utils].form_test_build_list_filepath( object ) ) - @ceedling[:streaminator].stdout_puts("Compiling #{File.basename(source)} with coverage...") - @ceedling[:tool_executor].exec( compile_command[:line], compile_command[:options] ) - end - - def post_test_fixture_execute(arg_hash) - result_file = arg_hash[:result_file] - - if ((result_file =~ /#{GCOV_RESULTS_PATH}/) and (not @result_list.include?(result_file))) - @result_list << arg_hash[:result_file] - end - end - - def post_build - return if (not @ceedling[:task_invoker].invoked?(/^#{GCOV_TASK_ROOT}/)) - - # test results - results = @ceedling[:plugin_reportinator].assemble_test_results(@result_list) - hash = { - :header => GCOV_ROOT_NAME.upcase, - :results => results - } - - @ceedling[:plugin_reportinator].run_test_results_report(hash) do - message = '' - message = 'Unit test failures.' if (results[:counts][:failed] > 0) - message - end - - if (@ceedling[:task_invoker].invoked?(/^#{GCOV_TASK_ROOT}(all|delta)/)) - report_coverage_results_summary(@ceedling[:test_invoker].sources) - else - report_per_file_coverage_results(@ceedling[:test_invoker].sources) - end - end - - def summary - result_list = @ceedling[:file_path_utils].form_pass_results_filelist( GCOV_RESULTS_PATH, COLLECTION_ALL_TESTS ) - - # test results - # get test results for only those tests in our configuration and of those only tests with results on disk - hash = { - :header => GCOV_ROOT_NAME.upcase, - :results => @ceedling[:plugin_reportinator].assemble_test_results(result_list, {:boom => false}) - } - - @ceedling[:plugin_reportinator].run_test_results_report(hash) - - # coverage results - # command = @ceedling[:tool_executor].build_command_line(TOOLS_GCOV_REPORT_COVSRC) - # shell_result = @ceedling[:tool_executor].exec(command[:line], command[:options]) - # report_coverage_results_all(shell_result[:output]) - end - - private ################################### - - def report_coverage_results_summary(sources) - - end - - def report_per_file_coverage_results(sources) - banner = @ceedling[:plugin_reportinator].generate_banner "#{GCOV_ROOT_NAME.upcase}: CODE COVERAGE SUMMARY" - @ceedling[:streaminator].stdout_puts "\n" + banner - - coverage_sources = sources.clone - coverage_sources.delete_if {|item| item =~ /#{CMOCK_MOCK_PREFIX}.+#{EXTENSION_SOURCE}$/} - coverage_sources.delete_if {|item| item =~ /#{GCOV_IGNORE_SOURCES.join('|')}#{EXTENSION_SOURCE}$/} - - coverage_sources.each do |source| - basename = File.basename(source) - command = @ceedling[:tool_executor].build_command_line(TOOLS_GCOV_REPORT, basename) - shell_results = @ceedling[:tool_executor].exec(command[:line], command[:options]) - coverage_results = shell_results[:output] - - if (coverage_results.strip =~ /(File\s+'#{Regexp.escape(source)}'.+$)/m) - report = ((($1.lines.to_a)[1..-1])).map{|line| basename + ' ' + line}.join('') - @ceedling[:streaminator].stdout_puts(report + "\n\n") - end - end - end - -end - -# end blocks always executed following rake run -END { - # cache our input configurations to use in comparison upon next execution - @ceedling[:cacheinator].cache_test_config( @ceedling[:setupinator].config_hash ) if (@ceedling[:task_invoker].invoked?(/^#{GCOV_TASK_ROOT}/)) -} diff --git a/vendor/ceedling/plugins/gcov/lib/gcov.rb b/vendor/ceedling/plugins/gcov/lib/gcov.rb new file mode 100644 index 0000000..30c6326 --- /dev/null +++ b/vendor/ceedling/plugins/gcov/lib/gcov.rb @@ -0,0 +1,136 @@ +require 'ceedling/plugin' +require 'ceedling/constants' +require 'gcov_constants' + +class Gcov < Plugin + attr_reader :config + + def setup + @result_list = [] + + @config = { + project_test_build_output_path: GCOV_BUILD_OUTPUT_PATH, + project_test_build_output_c_path: GCOV_BUILD_OUTPUT_PATH, + project_test_results_path: GCOV_RESULTS_PATH, + project_test_dependencies_path: GCOV_DEPENDENCIES_PATH, + defines_test: DEFINES_TEST + ['CODE_COVERAGE'], + gcov_html_report_filter: GCOV_FILTER_EXCLUDE + } + + @plugin_root = File.expand_path(File.join(File.dirname(__FILE__), '..')) + @coverage_template_all = @ceedling[:file_wrapper].read(File.join(@plugin_root, 'assets/template.erb')) + end + + def generate_coverage_object_file(source, object) + lib_args = @ceedling[:test_invoker].convert_libraries_to_arguments() + compile_command = + @ceedling[:tool_executor].build_command_line( + TOOLS_GCOV_COMPILER, + @ceedling[:flaginator].flag_down(OPERATION_COMPILE_SYM, GCOV_SYM, source), + source, + object, + @ceedling[:file_path_utils].form_test_build_list_filepath(object), + lib_args + ) + @ceedling[:streaminator].stdout_puts("Compiling #{File.basename(source)} with coverage...") + @ceedling[:tool_executor].exec(compile_command[:line], compile_command[:options]) + end + + def post_test_fixture_execute(arg_hash) + result_file = arg_hash[:result_file] + + if (result_file =~ /#{GCOV_RESULTS_PATH}/) && !@result_list.include?(result_file) + @result_list << arg_hash[:result_file] + end + end + + def post_build + return unless @ceedling[:task_invoker].invoked?(/^#{GCOV_TASK_ROOT}/) + + # test results + results = @ceedling[:plugin_reportinator].assemble_test_results(@result_list) + hash = { + header: GCOV_ROOT_NAME.upcase, + results: results + } + + @ceedling[:plugin_reportinator].run_test_results_report(hash) do + message = '' + message = 'Unit test failures.' if results[:counts][:failed] > 0 + message + end + + report_per_file_coverage_results(@ceedling[:test_invoker].sources) + end + + def summary + result_list = @ceedling[:file_path_utils].form_pass_results_filelist(GCOV_RESULTS_PATH, COLLECTION_ALL_TESTS) + + # test results + # get test results for only those tests in our configuration and of those only tests with results on disk + hash = { + header: GCOV_ROOT_NAME.upcase, + results: @ceedling[:plugin_reportinator].assemble_test_results(result_list, boom: false) + } + + @ceedling[:plugin_reportinator].run_test_results_report(hash) + end + + private ################################### + + def report_per_file_coverage_results(sources) + banner = @ceedling[:plugin_reportinator].generate_banner "#{GCOV_ROOT_NAME.upcase}: CODE COVERAGE SUMMARY" + @ceedling[:streaminator].stdout_puts "\n" + banner + + coverage_sources = @ceedling[:project_config_manager].filter_internal_sources(sources) + coverage_sources.each do |source| + basename = File.basename(source) + command = @ceedling[:tool_executor].build_command_line(TOOLS_GCOV_REPORT, [], [basename]) + shell_results = @ceedling[:tool_executor].exec(command[:line], command[:options]) + coverage_results = shell_results[:output] + + if coverage_results.strip =~ /(File\s+'#{Regexp.escape(source)}'.+$)/m + report = Regexp.last_match(1).lines.to_a[1..-1].map { |line| basename + ' ' + line }.join('') + @ceedling[:streaminator].stdout_puts(report + "\n\n") + end + end + + ignore_path_list = @ceedling[:file_system_utils].collect_paths(@ceedling[:configurator].project_config_hash[:gcov_uncovered_ignore_list] || []) + ignore_uncovered_list = @ceedling[:file_wrapper].instantiate_file_list + ignore_path_list.each do |path| + if File.exists?(path) and not File.directory?(path) + ignore_uncovered_list.include(path) + else + ignore_uncovered_list.include(File.join(path, "*#{EXTENSION_SOURCE}")) + end + end + + found_uncovered = false + COLLECTION_ALL_SOURCE.each do |source| + unless coverage_sources.include?(source) + v = Verbosity::DEBUG + msg = "Could not find coverage results for " + source + if ignore_uncovered_list.include?(source) + msg += " [IGNORED]" + else + found_uncovered = true + v = Verbosity::NORMAL + end + msg += "\n" + @ceedling[:streaminator].stdout_puts(msg, v) + end + end + if found_uncovered + if @ceedling[:configurator].project_config_hash[:gcov_abort_on_uncovered] + @ceedling[:streaminator].stderr_puts("There were files with no coverage results: aborting.\n") + exit(-1) + end + end + end +end + +# end blocks always executed following rake run +END { + # cache our input configurations to use in comparison upon next execution + @ceedling[:cacheinator].cache_test_config(@ceedling[:setupinator].config_hash) if @ceedling[:task_invoker].invoked?(/^#{GCOV_TASK_ROOT}/) +} diff --git a/vendor/ceedling/plugins/gcov/lib/gcov_constants.rb b/vendor/ceedling/plugins/gcov/lib/gcov_constants.rb new file mode 100644 index 0000000..74c9bbd --- /dev/null +++ b/vendor/ceedling/plugins/gcov/lib/gcov_constants.rb @@ -0,0 +1,48 @@ + +GCOV_ROOT_NAME = 'gcov'.freeze +GCOV_TASK_ROOT = GCOV_ROOT_NAME + ':' +GCOV_SYM = GCOV_ROOT_NAME.to_sym + +GCOV_BUILD_PATH = File.join(PROJECT_BUILD_ROOT, GCOV_ROOT_NAME) +GCOV_BUILD_OUTPUT_PATH = File.join(GCOV_BUILD_PATH, "out") +GCOV_RESULTS_PATH = File.join(GCOV_BUILD_PATH, "results") +GCOV_DEPENDENCIES_PATH = File.join(GCOV_BUILD_PATH, "dependencies") +GCOV_ARTIFACTS_PATH = File.join(PROJECT_BUILD_ARTIFACTS_ROOT, GCOV_ROOT_NAME) +GCOV_REPORT_GENERATOR_PATH = File.join(GCOV_ARTIFACTS_PATH, "ReportGenerator") + +GCOV_ARTIFACTS_FILE_HTML = File.join(GCOV_ARTIFACTS_PATH, "GcovCoverageResults.html") +GCOV_ARTIFACTS_FILE_COBERTURA = File.join(GCOV_ARTIFACTS_PATH, "GcovCoverageCobertura.xml") +GCOV_ARTIFACTS_FILE_SONARQUBE = File.join(GCOV_ARTIFACTS_PATH, "GcovCoverageSonarQube.xml") +GCOV_ARTIFACTS_FILE_JSON = File.join(GCOV_ARTIFACTS_PATH, "GcovCoverage.json") + +GCOV_FILTER_EXCLUDE_PATHS = ['vendor', 'build', 'test', 'lib'] + +# gcovr supports regular expressions. +GCOV_FILTER_EXCLUDE = GCOV_FILTER_EXCLUDE_PATHS.map{|path| '^'.concat(*path).concat('.*')}.join('|') + +# ReportGenerator supports text with wildcard characters. +GCOV_REPORT_GENERATOR_FILE_FILTERS = GCOV_FILTER_EXCLUDE_PATHS.map{|path| File.join('-.', *path, '*')}.join(';') + +# Report Types +class ReportTypes + HTML_BASIC = "HtmlBasic" + HTML_DETAILED = "HtmlDetailed" + HTML_CHART = "HtmlChart" + HTML_INLINE = "HtmlInline" + HTML_INLINE_AZURE = "HtmlInlineAzure" + HTML_INLINE_AZURE_DARK = "HtmlInlineAzureDark" + MHTML = "MHtml" + TEXT = "Text" + COBERTURA = "Cobertura" + SONARQUBE = "SonarQube" + JSON = "JSON" + BADGES = "Badges" + CSV_SUMMARY = "CsvSummary" + LATEX = "Latex" + LATEX_SUMMARY = "LatexSummary" + PNG_CHART = "PngChart" + TEAM_CITY_SUMMARY = "TeamCitySummary" + LCOV = "lcov" + XML = "Xml" + XML_SUMMARY = "XmlSummary" +end diff --git a/vendor/ceedling/plugins/gcov/lib/gcovr_reportinator.rb b/vendor/ceedling/plugins/gcov/lib/gcovr_reportinator.rb new file mode 100644 index 0000000..5317c5d --- /dev/null +++ b/vendor/ceedling/plugins/gcov/lib/gcovr_reportinator.rb @@ -0,0 +1,331 @@ +require 'reportinator_helper' + +class GcovrReportinator + + def initialize(system_objects) + @ceedling = system_objects + @reportinator_helper = ReportinatorHelper.new + end + + + # Generate the gcovr report(s) specified in the options. + def make_reports(opts) + # Get the gcovr version number. + gcovr_version_info = get_gcovr_version() + + # Build the common gcovr arguments. + args_common = args_builder_common(opts) + + if ((gcovr_version_info[0] == 4) && (gcovr_version_info[1] >= 2)) || (gcovr_version_info[0] > 4) + # gcovr version 4.2 and later supports generating multiple reports with a single call. + args = args_common + args += args_builder_cobertura(opts, false) + args += args_builder_sonarqube(opts, false) + args += args_builder_json(opts, true) + # As of gcovr version 4.2, the --html argument must appear last. + args += args_builder_html(opts, false) + + print "Creating gcov results report(s) in '#{GCOV_ARTIFACTS_PATH}'... " + STDOUT.flush + + # Generate the report(s). + run(args) + else + # gcovr version 4.1 and earlier supports HTML and Cobertura XML reports. + # It does not support SonarQube and JSON reports. + # Reports must also be generated separately. + args_cobertura = args_builder_cobertura(opts, true) + args_html = args_builder_html(opts, true) + + if args_html.length > 0 + print "Creating a gcov HTML report in '#{GCOV_ARTIFACTS_PATH}'... " + STDOUT.flush + + # Generate the HTML report. + run(args_common + args_html) + end + + if args_cobertura.length > 0 + print "Creating a gcov XML report in '#{GCOV_ARTIFACTS_PATH}'... " + STDOUT.flush + + # Generate the Cobertura XML report. + run(args_common + args_cobertura) + end + end + + # Determine if the gcovr text report is enabled. Defaults to disabled. + if is_report_enabled(opts, ReportTypes::TEXT) + make_text_report(opts, args_common) + end + end + + + def support_deprecated_options(opts) + # Support deprecated :html_report: and ":html_report_type: basic" options. + if !is_report_enabled(opts, ReportTypes::HTML_BASIC) && (opts[:gcov_html_report] || (opts[:gcov_html_report_type].is_a? String) && (opts[:gcov_html_report_type].casecmp("basic") == 0)) + opts[:gcov_reports].push(ReportTypes::HTML_BASIC) + end + + # Support deprecated ":html_report_type: detailed" option. + if !is_report_enabled(opts, ReportTypes::HTML_DETAILED) && (opts[:gcov_html_report_type].is_a? String) && (opts[:gcov_html_report_type].casecmp("detailed") == 0) + opts[:gcov_reports].push(ReportTypes::HTML_DETAILED) + end + + # Support deprecated :xml_report: option. + if opts[:gcov_xml_report] + opts[:gcov_reports].push(ReportTypes::COBERTURA) + end + + # Default to HTML basic report when no report types are defined. + if opts[:gcov_reports].empty? && opts[:gcov_html_report_type].nil? && opts[:gcov_xml_report].nil? + opts[:gcov_reports] = [ReportTypes::HTML_BASIC] + + puts "In your project.yml, define one or more of the" + puts "following to specify which reports to generate." + puts "For now, creating only an #{ReportTypes::HTML_BASIC} report." + puts "" + puts ":gcov:" + puts " :reports:" + puts " - #{ReportTypes::HTML_BASIC}" + puts " - #{ReportTypes::HTML_DETAILED}" + puts " - #{ReportTypes::TEXT}" + puts " - #{ReportTypes::COBERTURA}" + puts " - #{ReportTypes::SONARQUBE}" + puts " - #{ReportTypes::JSON}" + puts "" + end + end + + + private + + GCOVR_SETTING_PREFIX = "gcov_gcovr" + + # Build the gcovr report generation common arguments. + def args_builder_common(opts) + gcovr_opts = get_opts(opts) + + args = "" + args += "--root \"#{gcovr_opts[:report_root] || '.'}\" " + args += "--config \"#{gcovr_opts[:config_file]}\" " unless gcovr_opts[:config_file].nil? + args += "--filter \"#{gcovr_opts[:report_include]}\" " unless gcovr_opts[:report_include].nil? + args += "--exclude \"#{gcovr_opts[:report_exclude] || GCOV_FILTER_EXCLUDE}\" " + args += "--gcov-filter \"#{gcovr_opts[:gcov_filter]}\" " unless gcovr_opts[:gcov_filter].nil? + args += "--gcov-exclude \"#{gcovr_opts[:gcov_exclude]}\" " unless gcovr_opts[:gcov_exclude].nil? + args += "--exclude-directories \"#{gcovr_opts[:exclude_directories]}\" " unless gcovr_opts[:exclude_directories].nil? + args += "--branches " if gcovr_opts[:branches].nil? || gcovr_opts[:branches] # Defaults to enabled. + args += "--sort-uncovered " if gcovr_opts[:sort_uncovered] + args += "--sort-percentage " if gcovr_opts[:sort_percentage].nil? || gcovr_opts[:sort_percentage] # Defaults to enabled. + args += "--print-summary " if gcovr_opts[:print_summary] + args += "--gcov-executable \"#{gcovr_opts[:gcov_executable]}\" " unless gcovr_opts[:gcov_executable].nil? + args += "--exclude-unreachable-branches " if gcovr_opts[:exclude_unreachable_branches] + args += "--exclude-throw-branches " if gcovr_opts[:exclude_throw_branches] + args += "--use-gcov-files " if gcovr_opts[:use_gcov_files] + args += "--gcov-ignore-parse-errors " if gcovr_opts[:gcov_ignore_parse_errors] + args += "--keep " if gcovr_opts[:keep] + args += "--delete " if gcovr_opts[:delete] + args += "-j #{gcovr_opts[:num_parallel_threads]} " if !(gcovr_opts[:num_parallel_threads].nil?) && (gcovr_opts[:num_parallel_threads].is_a? Integer) + + [:fail_under_line, :fail_under_branch, :source_encoding, :object_directory].each do |opt| + unless gcovr_opts[opt].nil? + + value = gcovr_opts[opt] + if (opt == :fail_under_line) || (opt == :fail_under_branch) + if not value.is_a? Integer + puts "Option value #{opt} has to be an integer" + value = nil + elsif (value < 0) || (value > 100) + puts "Option value #{opt} has to be a percentage from 0 to 100" + value = nil + end + end + args += "--#{opt.to_s.gsub('_','-')} #{value} " unless value.nil? + end + end + + return args + end + + + # Build the gcovr Cobertura XML report generation arguments. + def args_builder_cobertura(opts, use_output_option=false) + gcovr_opts = get_opts(opts) + args = "" + + # Determine if the Cobertura XML report is enabled. Defaults to disabled. + if is_report_enabled(opts, ReportTypes::COBERTURA) + # Determine the Cobertura XML report file name. + artifacts_file_cobertura = GCOV_ARTIFACTS_FILE_COBERTURA + if !(gcovr_opts[:cobertura_artifact_filename].nil?) + artifacts_file_cobertura = File.join(GCOV_ARTIFACTS_PATH, gcovr_opts[:cobertura_artifact_filename]) + elsif !(gcovr_opts[:xml_artifact_filename].nil?) + artifacts_file_cobertura = File.join(GCOV_ARTIFACTS_PATH, gcovr_opts[:xml_artifact_filename]) + end + + args += "--xml-pretty " if gcovr_opts[:xml_pretty] || gcovr_opts[:cobertura_pretty] + args += "--xml #{use_output_option ? "--output " : ""} \"#{artifacts_file_cobertura}\" " + end + + return args + end + + + # Build the gcovr SonarQube report generation arguments. + def args_builder_sonarqube(opts, use_output_option=false) + gcovr_opts = get_opts(opts) + args = "" + + # Determine if the gcovr SonarQube XML report is enabled. Defaults to disabled. + if is_report_enabled(opts, ReportTypes::SONARQUBE) + # Determine the SonarQube XML report file name. + artifacts_file_sonarqube = GCOV_ARTIFACTS_FILE_SONARQUBE + if !(gcovr_opts[:sonarqube_artifact_filename].nil?) + artifacts_file_sonarqube = File.join(GCOV_ARTIFACTS_PATH, gcovr_opts[:sonarqube_artifact_filename]) + end + + args += "--sonarqube #{use_output_option ? "--output " : ""} \"#{artifacts_file_sonarqube}\" " + end + + return args + end + + + # Build the gcovr JSON report generation arguments. + def args_builder_json(opts, use_output_option=false) + gcovr_opts = get_opts(opts) + args = "" + + # Determine if the gcovr JSON report is enabled. Defaults to disabled. + if is_report_enabled(opts, ReportTypes::JSON) + # Determine the JSON report file name. + artifacts_file_json = GCOV_ARTIFACTS_FILE_JSON + if !(gcovr_opts[:json_artifact_filename].nil?) + artifacts_file_json = File.join(GCOV_ARTIFACTS_PATH, gcovr_opts[:json_artifact_filename]) + end + + args += "--json-pretty " if gcovr_opts[:json_pretty] + # Note: In gcovr 4.2, the JSON report is output only when the --output option is specified. + # Hopefully we can remove --output after a future gcovr release. + args += "--json #{use_output_option ? "--output " : ""} \"#{artifacts_file_json}\" " + end + + return args + end + + + # Build the gcovr HTML report generation arguments. + def args_builder_html(opts, use_output_option=false) + gcovr_opts = get_opts(opts) + args = "" + + # Determine if the gcovr HTML report is enabled. Defaults to enabled. + html_enabled = (opts[:gcov_html_report].nil? && opts[:gcov_reports].empty?) || + is_report_enabled(opts, ReportTypes::HTML_BASIC) || + is_report_enabled(opts, ReportTypes::HTML_DETAILED) + + if html_enabled + # Determine the HTML report file name. + artifacts_file_html = GCOV_ARTIFACTS_FILE_HTML + if !(gcovr_opts[:html_artifact_filename].nil?) + artifacts_file_html = File.join(GCOV_ARTIFACTS_PATH, gcovr_opts[:html_artifact_filename]) + end + + is_html_report_type_detailed = (opts[:gcov_html_report_type].is_a? String) && (opts[:gcov_html_report_type].casecmp("detailed") == 0) + + args += "--html-details " if is_html_report_type_detailed || is_report_enabled(opts, ReportTypes::HTML_DETAILED) + args += "--html-title \"#{gcovr_opts[:html_title]}\" " unless gcovr_opts[:html_title].nil? + args += "--html-absolute-paths " if !(gcovr_opts[:html_absolute_paths].nil?) && gcovr_opts[:html_absolute_paths] + args += "--html-encoding \"#{gcovr_opts[:html_encoding]}\" " unless gcovr_opts[:html_encoding].nil? + + [:html_medium_threshold, :html_high_threshold].each do |opt| + args += "--#{opt.to_s.gsub('_','-')} #{gcovr_opts[opt]} " unless gcovr_opts[opt].nil? + end + + # The following option must be appended last for gcovr version <= 4.2 to properly work. + args += "--html #{use_output_option ? "--output " : ""} \"#{artifacts_file_html}\" " + end + + return args + end + + + # Generate a gcovr text report. + def make_text_report(opts, args_common) + gcovr_opts = get_opts(opts) + args_text = "" + message_text = "Creating a gcov text report" + + if !(gcovr_opts[:text_artifact_filename].nil?) + artifacts_file_txt = File.join(GCOV_ARTIFACTS_PATH, gcovr_opts[:text_artifact_filename]) + args_text += "--output \"#{artifacts_file_txt}\" " + message_text += " in '#{GCOV_ARTIFACTS_PATH}'... " + else + message_text += "... " + end + + print message_text + STDOUT.flush + + # Generate the text report. + run(args_common + args_text) + end + + + # Get the gcovr options from the project options. + def get_opts(opts) + return opts[GCOVR_SETTING_PREFIX.to_sym] || {} + end + + + # Run gcovr with the given arguments. + def run(args) + begin + command = @ceedling[:tool_executor].build_command_line(TOOLS_GCOV_GCOVR_POST_REPORT, [], args) + shell_result = @ceedling[:tool_executor].exec(command[:line], command[:options]) + @reportinator_helper.print_shell_result(shell_result) + rescue + # handle any unforeseen issues with called tool + exitcode = $?.exitstatus + show_gcovr_message(exitcode) + exit(exitcode) + end + end + + + # Get the gcovr version number as components. + # Returns [major, minor]. + def get_gcovr_version() + version_number_major = 0 + version_number_minor = 0 + + command = @ceedling[:tool_executor].build_command_line(TOOLS_GCOV_GCOVR_POST_REPORT, [], "--version") + shell_result = @ceedling[:tool_executor].exec(command[:line], command[:options]) + version_number_match_data = shell_result[:output].match(/gcovr ([0-9]+)\.([0-9]+)/) + + if !(version_number_match_data.nil?) && !(version_number_match_data[1].nil?) && !(version_number_match_data[2].nil?) + version_number_major = version_number_match_data[1].to_i + version_number_minor = version_number_match_data[2].to_i + end + + return version_number_major, version_number_minor + end + + + # Show a more human-friendly message on gcovr return code + def show_gcovr_message(exitcode) + if ((exitcode & 2) == 2) + puts "The line coverage is less than the minimum" + end + if ((exitcode & 4) == 4) + puts "The branch coverage is less than the minimum" + end + end + + + # Returns true if the given report type is enabled, otherwise returns false. + def is_report_enabled(opts, report_type) + return !(opts.nil?) && !(opts[:gcov_reports].nil?) && (opts[:gcov_reports].map(&:upcase).include? report_type.upcase) + end + +end diff --git a/vendor/ceedling/plugins/gcov/lib/reportgenerator_reportinator.rb b/vendor/ceedling/plugins/gcov/lib/reportgenerator_reportinator.rb new file mode 100644 index 0000000..d4a885c --- /dev/null +++ b/vendor/ceedling/plugins/gcov/lib/reportgenerator_reportinator.rb @@ -0,0 +1,195 @@ +require 'benchmark' +require 'reportinator_helper' + +class ReportGeneratorReportinator + + def initialize(system_objects) + @ceedling = system_objects + @reportinator_helper = ReportinatorHelper.new + end + + + # Generate the ReportGenerator report(s) specified in the options. + def make_reports(opts) + shell_result = nil + total_time = Benchmark.realtime do + rg_opts = get_opts(opts) + + print "Creating gcov results report(s) with ReportGenerator in '#{GCOV_REPORT_GENERATOR_PATH}'... " + STDOUT.flush + + # Cleanup any existing .gcov files to avoid reporting old coverage results. + for gcov_file in Dir.glob("*.gcov") + File.delete(gcov_file) + end + + # Use a custom gcov executable, if specified. + GCOV_TOOL_CONFIG[:executable] = rg_opts[:gcov_executable] unless rg_opts[:gcov_executable].nil? + + # Avoid running gcov on the mock, test, unity, and cexception gcov notes files to save time. + gcno_exclude_str = "#{opts[:cmock_mock_prefix]}.*" + gcno_exclude_str += "|#{opts[:project_test_file_prefix]}.*" + gcno_exclude_str += "|#{VENDORS_FILES.join('|')}" + + # Avoid running gcov on custom specified .gcno files. + if !(rg_opts.nil?) && !(rg_opts[:gcov_exclude].nil?) && !(rg_opts[:gcov_exclude].empty?) + for gcno_exclude_expression in rg_opts[:gcov_exclude] + if !(gcno_exclude_expression.nil?) && !(gcno_exclude_expression.empty?) + # We want to filter .gcno files, not .gcov files. + # We will generate .gcov files from .gcno files. + gcno_exclude_expression = gcno_exclude_expression.chomp("\\.gcov") + gcno_exclude_expression = gcno_exclude_expression.chomp(".gcov") + # The .gcno extension will be added later as we create the regex. + gcno_exclude_expression = gcno_exclude_expression.chomp("\\.gcno") + gcno_exclude_expression = gcno_exclude_expression.chomp(".gcno") + # Append the custom expression. + gcno_exclude_str += "|#{gcno_exclude_expression}" + end + end + end + + gcno_exclude_regex = /(\/|\\)(#{gcno_exclude_str})\.gcno/ + + # Generate .gcov files by running gcov on gcov notes files (*.gcno). + for gcno_filepath in Dir.glob(File.join(GCOV_BUILD_PATH, "**", "*.gcno")) + match_data = gcno_filepath.match(gcno_exclude_regex) + if match_data.nil? || (match_data[1].nil? && match_data[1].nil?) + # Ensure there is a matching gcov data file. + if File.file?(gcno_filepath.gsub(".gcno", ".gcda")) + run_gcov("\"#{gcno_filepath}\"") + end + end + end + + if Dir.glob("*.gcov").length > 0 + # Build the command line arguments. + args = args_builder(opts) + + # Generate the report(s). + shell_result = run(args) + else + puts "\nWarning: No matching .gcno coverage files found." + end + + # Cleanup .gcov files. + for gcov_file in Dir.glob("*.gcov") + File.delete(gcov_file) + end + end + + if shell_result + shell_result[:time] = total_time + @reportinator_helper.print_shell_result(shell_result) + end + end + + + private + + # A dictionary of report types defined in this plugin to ReportGenerator report types. + REPORT_TYPE_TO_REPORT_GENERATOR_REPORT_NAME = { + ReportTypes::HTML_BASIC.upcase => "HtmlSummary", + ReportTypes::HTML_DETAILED.upcase => "Html", + ReportTypes::HTML_CHART.upcase => "HtmlChart", + ReportTypes::HTML_INLINE.upcase => "HtmlInline", + ReportTypes::HTML_INLINE_AZURE.upcase => "HtmlInline_AzurePipelines", + ReportTypes::HTML_INLINE_AZURE_DARK.upcase => "HtmlInline_AzurePipelines_Dark", + ReportTypes::MHTML.upcase => "MHtml", + ReportTypes::TEXT.upcase => "TextSummary", + ReportTypes::COBERTURA.upcase => "Cobertura", + ReportTypes::SONARQUBE.upcase => "SonarQube", + ReportTypes::BADGES.upcase => "Badges", + ReportTypes::CSV_SUMMARY.upcase => "CsvSummary", + ReportTypes::LATEX.upcase => "Latex", + ReportTypes::LATEX_SUMMARY.upcase => "LatexSummary", + ReportTypes::PNG_CHART.upcase => "PngChart", + ReportTypes::TEAM_CITY_SUMMARY.upcase => "TeamCitySummary", + ReportTypes::LCOV.upcase => "lcov", + ReportTypes::XML.upcase => "Xml", + ReportTypes::XML_SUMMARY.upcase => "XmlSummary", + } + + REPORT_GENERATOR_SETTING_PREFIX = "gcov_report_generator" + + # Deep clone the gcov tool config, so we can modify it locally if specified via options. + GCOV_TOOL_CONFIG = Marshal.load(Marshal.dump(TOOLS_GCOV_GCOV_POST_REPORT)) + + # Build the ReportGenerator arguments. + def args_builder(opts) + rg_opts = get_opts(opts) + report_type_count = 0 + + args = "" + args += "\"-reports:*.gcov\" " + args += "\"-targetdir:\"#{GCOV_REPORT_GENERATOR_PATH}\"\" " + + # Build the report types argument. + if !(opts.nil?) && !(opts[:gcov_reports].nil?) && !(opts[:gcov_reports].empty?) + args += "\"-reporttypes:" + + for report_type in opts[:gcov_reports] + rg_report_type = REPORT_TYPE_TO_REPORT_GENERATOR_REPORT_NAME[report_type.upcase] + if !(rg_report_type.nil?) + args += rg_report_type + ";" + report_type_count = report_type_count + 1 + end + end + + # Removing trailing ';' after the last report type. + args = args.chomp(";") + + # Append a space seperator after the report type. + args += "\" " + end + + # Build the source directories argument. + args += "\"-sourcedirs:.;" + if !(opts[:collection_paths_source].nil?) + args += opts[:collection_paths_source].join(';') + end + args = args.chomp(";") + args += "\" " + + args += "\"-historydir:#{rg_opts[:history_directory]}\" " unless rg_opts[:history_directory].nil? + args += "\"-plugins:#{rg_opts[:plugins]}\" " unless rg_opts[:plugins].nil? + args += "\"-assemblyfilters:#{rg_opts[:assembly_filters]}\" " unless rg_opts[:assembly_filters].nil? + args += "\"-classfilters:#{rg_opts[:class_filters]}\" " unless rg_opts[:class_filters].nil? + file_filters = rg_opts[:file_filters] || @ceedling[:tool_executor_helper].osify_path_separators(GCOV_REPORT_GENERATOR_FILE_FILTERS) + args += "\"-filefilters:#{file_filters}\" " + args += "\"-verbosity:#{rg_opts[:verbosity] || "Warning"}\" " + args += "\"-tag:#{rg_opts[:tag]}\" " unless rg_opts[:tag].nil? + args += "\"settings:createSubdirectoryForAllReportTypes=true\" " unless report_type_count <= 1 + args += "\"settings:numberOfReportsParsedInParallel=#{rg_opts[:num_parallel_threads]}\" " unless rg_opts[:num_parallel_threads].nil? + args += "\"settings:numberOfReportsMergedInParallel=#{rg_opts[:num_parallel_threads]}\" " unless rg_opts[:num_parallel_threads].nil? + + # Append custom arguments. + if !(rg_opts[:custom_args].nil?) && !(rg_opts[:custom_args].empty?) + for custom_arg in rg_opts[:custom_args] + args += "\"#{custom_arg}\" " unless custom_arg.nil? || custom_arg.empty? + end + end + + return args + end + + + # Get the ReportGenerator options from the project options. + def get_opts(opts) + return opts[REPORT_GENERATOR_SETTING_PREFIX.to_sym] || {} + end + + + # Run ReportGenerator with the given arguments. + def run(args) + command = @ceedling[:tool_executor].build_command_line(TOOLS_GCOV_REPORTGENERATOR_POST_REPORT, [], args) + return @ceedling[:tool_executor].exec(command[:line], command[:options]) + end + + + # Run gcov with the given arguments. + def run_gcov(args) + command = @ceedling[:tool_executor].build_command_line(GCOV_TOOL_CONFIG, [], args) + return @ceedling[:tool_executor].exec(command[:line], command[:options]) + end + +end diff --git a/vendor/ceedling/plugins/gcov/lib/reportinator_helper.rb b/vendor/ceedling/plugins/gcov/lib/reportinator_helper.rb new file mode 100644 index 0000000..92617fb --- /dev/null +++ b/vendor/ceedling/plugins/gcov/lib/reportinator_helper.rb @@ -0,0 +1,15 @@ + +class ReportinatorHelper + + # Output the shell result to the console. + def print_shell_result(shell_result) + if !(shell_result.nil?) + puts "Done in %.3f seconds." % shell_result[:time] + + if !(shell_result[:output].nil?) && (shell_result[:output].length > 0) + puts shell_result[:output] + end + end + end + +end diff --git a/vendor/ceedling/plugins/gcov/readme.txt b/vendor/ceedling/plugins/gcov/readme.txt deleted file mode 100644 index e69de29..0000000 diff --git a/vendor/ceedling/plugins/json_tests_report/README.md b/vendor/ceedling/plugins/json_tests_report/README.md new file mode 100644 index 0000000..8e5a1e5 --- /dev/null +++ b/vendor/ceedling/plugins/json_tests_report/README.md @@ -0,0 +1,36 @@ +json_tests_report +================= + +## Overview + +The json_tests_report plugin creates a JSON file of test results, which is +handy for Continuous Integration build servers or as input into other +reporting tools. The JSON file is output to the appropriate +`<build_root>/artifacts/` directory (e.g. `artifacts/test/` for test tasks, +`artifacts/gcov/` for gcov, or `artifacts/bullseye/` for bullseye runs). + +## Setup + +Enable the plugin in your project.yml by adding `json_tests_report` to the list +of enabled plugins. + +``` YAML +:plugins: + :enabled: + - json_tests_report +``` + +## Configuration + +Optionally configure the output / artifact filename in your project.yml with +the `artifact_filename` configuration option. The default filename is +`report.json`. + +You can also configure the path that this artifact is stored. This can be done +by setting `path`. The default is that it will be placed in a subfolder under +the `build` directory. + +``` YAML +:json_tests_report: + :artifact_filename: report_spectuluarly.json +``` diff --git a/vendor/ceedling/plugins/json_tests_report/lib/json_tests_report.rb b/vendor/ceedling/plugins/json_tests_report/lib/json_tests_report.rb new file mode 100644 index 0000000..e7023db --- /dev/null +++ b/vendor/ceedling/plugins/json_tests_report/lib/json_tests_report.rb @@ -0,0 +1,83 @@ +require 'ceedling/plugin' +require 'ceedling/constants' +require 'json' + +class JsonTestsReport < Plugin + def setup + @results_list = {} + @test_counter = 0 + end + + def post_test_fixture_execute(arg_hash) + context = arg_hash[:context] + + @results_list[context] = [] if @results_list[context].nil? + + @results_list[context] << arg_hash[:result_file] + end + + def post_build + @results_list.each_key do |context| + results = @ceedling[:plugin_reportinator].assemble_test_results(@results_list[context]) + + artifact_filename = @ceedling[:configurator].project_config_hash[:json_tests_report_artifact_filename] || 'report.json' + artifact_fullpath = @ceedling[:configurator].project_config_hash[:json_tests_report_path] || File.join(PROJECT_BUILD_ARTIFACTS_ROOT, context.to_s) + file_path = File.join(artifact_fullpath, artifact_filename) + + @ceedling[:file_wrapper].open(file_path, 'w') do |f| + @test_counter = 1 + + json = { + "FailedTests" => write_failures(results[:failures]), + "PassedTests" => write_tests(results[:successes]), + "IgnoredTests" => write_tests(results[:ignores]), + "Summary" => write_statistics(results[:counts]) + } + + f << JSON.pretty_generate(json) + end + end + end + + private + + def write_failures(results) + retval = [] + results.each do |result| + result[:collection].each do |item| + @test_counter += 1 + retval << { + "file" => File.join(result[:source][:path], result[:source][:file]), + "test" => item[:test], + "line" => item[:line], + "message" => item[:message] + } + end + end + return retval.uniq + end + + def write_tests(results) + retval = [] + results.each do |result| + result[:collection].each do |item| + @test_counter += 1 + retval << { + "file" => File.join(result[:source][:path], result[:source][:file]), + "test" => item[:test] + } + end + end + return retval + end + + def write_statistics(counts) + return { + "total_tests" => counts[:total], + "passed" => (counts[:total] - counts[:ignored] - counts[:failed]), + "ignored" => counts[:ignored], + "failures" => counts[:failed] + } + end + +end diff --git a/vendor/ceedling/plugins/junit_tests_report/README.md b/vendor/ceedling/plugins/junit_tests_report/README.md new file mode 100644 index 0000000..1259fd6 --- /dev/null +++ b/vendor/ceedling/plugins/junit_tests_report/README.md @@ -0,0 +1,36 @@ +junit_tests_report +==================== + +## Overview + +The junit_tests_report plugin creates an XML file of test results in JUnit +format, which is handy for Continuous Integration build servers or as input +into other reporting tools. The XML file is output to the appropriate +`<build_root>/artifacts/` directory (e.g. `artifacts/test/` for test tasks, +`artifacts/gcov/` for gcov, or `artifacts/bullseye/` for bullseye runs). + +## Setup + +Enable the plugin in your project.yml by adding `junit_tests_report` +to the list of enabled plugins. + +``` YAML +:plugins: + :enabled: + - junit_tests_report +``` + +## Configuration + +Optionally configure the output / artifact filename in your project.yml with +the `artifact_filename` configuration option. The default filename is +`report.xml`. + +You can also configure the path that this artifact is stored. This can be done +by setting `path`. The default is that it will be placed in a subfolder under +the `build` directory. + +``` YAML +:junit_tests_report: + :artifact_filename: report_junit.xml +``` diff --git a/vendor/ceedling/plugins/junit_tests_report/lib/junit_tests_report.rb b/vendor/ceedling/plugins/junit_tests_report/lib/junit_tests_report.rb new file mode 100644 index 0000000..3104393 --- /dev/null +++ b/vendor/ceedling/plugins/junit_tests_report/lib/junit_tests_report.rb @@ -0,0 +1,134 @@ +require 'ceedling/plugin' +require 'ceedling/constants' + +class JunitTestsReport < Plugin + + def setup + @results_list = {} + @test_counter = 0 + @time_result = [] + end + + def post_test_fixture_execute(arg_hash) + context = arg_hash[:context] + + @results_list[context] = [] if (@results_list[context].nil?) + + @results_list[context] << arg_hash[:result_file] + @time_result << arg_hash[:shell_result][:time] + + end + + def post_build + @results_list.each_key do |context| + results = @ceedling[:plugin_reportinator].assemble_test_results(@results_list[context]) + + artifact_filename = @ceedling[:configurator].project_config_hash[:junit_tests_report_artifact_filename] || 'report.xml' + artifact_fullpath = @ceedling[:configurator].project_config_hash[:junit_tests_report_path] || File.join(PROJECT_BUILD_ARTIFACTS_ROOT, context.to_s) + file_path = File.join(artifact_fullpath, artifact_filename) + + @ceedling[:file_wrapper].open( file_path, 'w' ) do |f| + @testsuite_counter = 0 + @testcase_counter = 0 + suites = reorganise_results( results ) + + write_header( results, f ) + suites.each{|suite| write_suite( suite, f ) } + write_footer( f ) + end + end + end + + private + + def write_header( results, stream ) + results[:counts][:time] = @time_result.reduce(0, :+) + stream.puts '<?xml version="1.0" encoding="utf-8" ?>' + stream.puts('<testsuites tests="%<total>d" failures="%<failed>d" time="%<time>.3f">' % results[:counts]) + end + + def write_footer( stream ) + stream.puts '</testsuites>' + end + + def reorganise_results( results ) + # Reorganise the output by test suite instead of by result + suites = Hash.new{ |h,k| h[k] = {collection: [], total: 0, success: 0, failed: 0, ignored: 0, errors: 0, stdout: []} } + results[:successes].each do |result| + source = result[:source] + name = source[:file].sub(/\..{1,4}$/, "") + suites[name][:collection] += result[:collection].map{|test| test.merge(result: :success)} + suites[name][:total] += result[:collection].length + suites[name][:success] += result[:collection].length + end + results[:failures].each do |result| + source = result[:source] + name = source[:file].sub(/\..{1,4}$/, "") + suites[name][:collection] += result[:collection].map{|test| test.merge(result: :failed)} + suites[name][:total] += result[:collection].length + suites[name][:failed] += result[:collection].length + end + results[:ignores].each do |result| + source = result[:source] + name = source[:file].sub(/\..{1,4}$/, "") + suites[name][:collection] += result[:collection].map{|test| test.merge(result: :ignored)} + suites[name][:total] += result[:collection].length + suites[name][:ignored] += result[:collection].length + end + results[:stdout].each do |result| + source = result[:source] + name = source[:file].sub(/\..{1,4}$/, "") + suites[name][:stdout] += result[:collection] + end + suites.map{|name, data| data.merge(name: name) } + end + + def write_suite( suite, stream ) + suite[:time] = @time_result.shift + stream.puts(' <testsuite name="%<name>s" tests="%<total>d" failures="%<failed>d" skipped="%<ignored>d" errors="%<errors>d" time="%<time>.3f">' % suite) + + suite[:collection].each do |test| + write_test( test, stream ) + end + + unless suite[:stdout].empty? + stream.puts(' <system-out>') + suite[:stdout].each do |line| + line.gsub!(/&/, '&') + line.gsub!(/</, '<') + line.gsub!(/>/, '>') + line.gsub!(/"/, '"') + line.gsub!(/'/, ''') + stream.puts(line) + end + stream.puts(' </system-out>') + end + + stream.puts(' </testsuite>') + end + + def write_test( test, stream ) + test[:test].gsub!(/&/, '&') + test[:test].gsub!(/</, '<') + test[:test].gsub!(/>/, '>') + test[:test].gsub!(/"/, '"') + test[:test].gsub!(/'/, ''') + + case test[:result] + when :success + stream.puts(' <testcase name="%<test>s" time="%<unity_test_time>.3f"/>' % test) + when :failed + stream.puts(' <testcase name="%<test>s" time="%<unity_test_time>.3f">' % test) + if test[:message].empty? + stream.puts(' <failure />') + else + stream.puts(' <failure message="%s" />' % test[:message]) + end + stream.puts(' </testcase>') + when :ignored + stream.puts(' <testcase name="%<test>s" time="%<unity_test_time>.3f">' % test) + stream.puts(' <skipped />') + stream.puts(' </testcase>') + end + end +end diff --git a/vendor/ceedling/plugins/module_generator/README.md b/vendor/ceedling/plugins/module_generator/README.md new file mode 100644 index 0000000..a3c2c7a --- /dev/null +++ b/vendor/ceedling/plugins/module_generator/README.md @@ -0,0 +1,119 @@ +ceedling-module-generator +========================= + +## Overview + +The module_generator plugin adds a pair of new commands to Ceedling, allowing +you to make or remove modules according to predefined templates. WIth a single call, +Ceedling can generate a source, header, and test file for a new module. If given a +pattern, it can even create a series of submodules to support specific design patterns. +Finally, it can just as easily remove related modules, avoiding the need to delete +each individually. + +Let's say, for example, that you want to create a single module named `MadScience`. + +``` +ceedling module:create[MadScience] +``` + +It says we're speaking to the module plugin, and we want to create a new module. The +name of that module is between the brackets. It will keep this case, unless you have +specified a different default (see configuration). It will create three files: +`MadScience.c`, `MadScience.h`, and `TestMadScience.c`. *NOTE* that it is important that +there are no spaces between the brackets. We know, it's annoying... but it's the rules. + +You can also create an entire pattern of files. To do that, just add a second argument +to the pattern ID. Something like this: + +``` +ceedling module:create[SecretLair,mch] +``` + +In this example, we'd create 9 files total: 3 headers, 3 source files, and 3 test files. These +files would be named `SecretLairModel`, `SecretLairConductor`, and `SecretLairHardware`. Isn't +that nice? + +Similarly, you can create stubs for all functions in a header file just by making a single call +to your handy `stub` feature, like this: + +``` +ceedling module:stub[SecretLair] +``` + +This call will look in SecretLair.h and will generate a file SecretLair.c that contains a stub +for each function declared in the header! Even better, if SecretLair.c already exists, it will +add only new functions, leaving your existing calls alone so that it doesn't cause any problems. + +## Configuration + +Enable the plugin in your project.yml by adding `module_generator` +to the list of enabled plugins. + +Then, like much of Ceedling, you can just run as-is with the defaults, or you can override those +defaults for your own needs. For example, new source and header files will be automatically +placed in the `src/` folder while tests will go in the `test/` folder. That's great if your project +follows the default ceedling structure... but what if you have a different structure? + +``` +:module_generator: + :project_root: ./ + :source_root: source/ + :inc_root: includes/ + :test_root: tests/ +``` + +Now I've redirected the location where modules are going to be generated. + +### Includes + +You can make it so that all of your files are generated with a standard include list. This is done +by adding to the `:includes` array. For example: + +``` +:module_generator: + :includes: + :tst: + - defs.h + - board.h + :src: + - board.h +``` + +### Boilerplates + +You can specify the actual boilerplate used for each of your files. This is the handy place to +put that corporate copyright notice (or maybe a copyleft notice, if that's your perference?) + +``` +:module_generator: + :boilerplates: | + /*************************** + * This file is Awesome. * + * That is All. * + ***************************/ +``` + +### Test Defines + +You can specify the "#ifdef TEST" at the top of the test files with a custom define. +This example will put a "#ifdef CEEDLING_TEST" at the top of the test files. + +``` +:module_generator: + :test_define: CEEDLING_TEST +``` + +### Naming Convention + +Finally, you can force a particular naming convention. Even if someone calls the generator +with something like `MyNewModule`, if they have the naming convention set to `:caps`, it will +generate files like `MY_NEW_MODULE.c`. This keeps everyone on your team behaving the same way. + +Your options are as follows: + + - `:bumpy` - BumpyFilesLooksLikeSo + - `:camel` - camelFilesAreSimilarButStartLow + - `:snake` - snake_case_is_all_lower_and_uses_underscores + - `:caps` - CAPS_FEELS_LIKE_YOU_ARE_SCREAMING + + diff --git a/vendor/ceedling/plugins/module_generator/lib/module_generator.rb b/vendor/ceedling/plugins/module_generator/lib/module_generator.rb index c41783c..d14288c 100644 --- a/vendor/ceedling/plugins/module_generator/lib/module_generator.rb +++ b/vendor/ceedling/plugins/module_generator/lib/module_generator.rb @@ -1,5 +1,5 @@ -require 'plugin' -require 'constants' +require 'ceedling/plugin' +require 'ceedling/constants' require 'erb' require 'fileutils' @@ -7,138 +7,74 @@ class ModuleGenerator < Plugin attr_reader :config - def setup - - #---- New module templates - - @test_template = (<<-EOS).left_margin - #include "unity.h" - <%if defined?(MODULE_GENERATOR_TEST_INCLUDES) && (MODULE_GENERATOR_TEST_INCLUDES.class == Array) && !MODULE_GENERATOR_TEST_INCLUDES.empty?%> - <%MODULE_GENERATOR_TEST_INCLUDES.each do |header_file|%> - #include "<%=header_file%>" - <%end%> - <%end%> - #include "<%=@context[:headername]%>" - - void setUp(void) - { - } - - void tearDown(void) - { - } - - void test_<%=name%>_needs_to_be_implemented(void) - { - <%="\t"%>TEST_IGNORE_MESSAGE("Implement me!"); - } - EOS - - @source_template = (<<-EOS).left_margin - <%if defined?(MODULE_GENERATOR_SOURCE_INCLUDES) && (MODULE_GENERATOR_SOURCE_INCLUDES.class == Array) && !MODULE_GENERATOR_SOURCE_INCLUDES.empty?%> - <%MODULE_GENERATOR_SOURCE_INCLUDES.each do |header_file|%> - #include "<%=header_file%>" - <%end%> - <%end%> - #include "<%=@context[:headername]%>" - EOS - - @header_template = (<<-EOS).left_margin - #ifndef <%=@context[:name]%>_H - #define <%=@context[:name]%>_H - - <%if defined?(MODULE_GENERATOR_HEADER_INCLUDES) && (MODULE_GENERATOR_HEADER_INCLUDES.class == Array) && !MODULE_GENERATOR_HEADER_INCLUDES.empty?%> - <%MODULE_GENERATOR_HEADER_INCLUDES.each do |header_file|%> - #include "<%=header_file%>" - <%end%> - <%end%> - - #endif // <%=@context[:name]%>_H - EOS - end + def create(module_name, optz={}) - def create(path, optz={}) - - extract_context(path, optz) - - if !optz.nil? && (optz[:destroy] == true) - @ceedling[:streaminator].stdout_puts "Destroying '#{path}'..." - @files.each do |file| - if File.exist?(file[:path]) - @ceedling[:streaminator].stdout_puts "File #{file[:path]} deleted" - else - @ceedling[:streaminator].stdout_puts "File #{file[:path]} does not exist!" - end - end - exit + require "generate_module.rb" #From Unity Scripts + + if ((!optz.nil?) && (optz[:destroy])) + UnityModuleGenerator.new( divine_options(optz) ).destroy(module_name) + else + UnityModuleGenerator.new( divine_options(optz) ).generate(module_name) end + end - @ceedling[:streaminator].stdout_puts "Generating '#{path}'..." + def stub_from_header(module_name, optz={}) + require "cmock.rb" #From CMock + stuboptz = divine_options(optz) + pathname = optz[:path_inc] || optz[:path_src] || "src" + filename = File.expand_path(optz[:module_root_path], File.join(pathname, module_name + ".h")) + CMock.new(stuboptz).setup_skeletons(filename) + end - [File.dirname(@files[0][:path]), File.dirname(@files[1][:path])].each do |dir| - makedirs(dir, {:verbose => true}) - end + private + + def divine_options(optz={}) + unity_generator_options = + { + :path_src => ((defined? MODULE_GENERATOR_SOURCE_ROOT ) ? MODULE_GENERATOR_SOURCE_ROOT.gsub('\\', '/').sub(/^\//, '').sub(/\/$/, '') : "src" ), + :path_inc => ((defined? MODULE_GENERATOR_INC_ROOT ) ? + MODULE_GENERATOR_INC_ROOT.gsub('\\', '/').sub(/^\//, '').sub(/\/$/, '') + : (defined? MODULE_GENERATOR_SOURCE_ROOT ) ? + MODULE_GENERATOR_SOURCE_ROOT.gsub('\\', '/').sub(/^\//, '').sub(/\/$/, '') + : "src" ), + :path_tst => ((defined? MODULE_GENERATOR_TEST_ROOT ) ? MODULE_GENERATOR_TEST_ROOT.gsub( '\\', '/').sub(/^\//, '').sub(/\/$/, '') : "test" ), + :pattern => optz[:pattern], + :test_prefix => ((defined? PROJECT_TEST_FILE_PREFIX ) ? PROJECT_TEST_FILE_PREFIX : "Test" ), + :mock_prefix => ((defined? CMOCK_MOCK_PREFIX ) ? CMOCK_MOCK_PREFIX : "Mock" ), + :includes => ((defined? MODULE_GENERATOR_INCLUDES ) ? MODULE_GENERATOR_INCLUDES : {} ), + :boilerplates => ((defined? MODULE_GENERATOR_BOILERPLATES) ? MODULE_GENERATOR_BOILERPLATES : {} ), + :naming => ((defined? MODULE_GENERATOR_NAMING ) ? MODULE_GENERATOR_NAMING : nil ), + :update_svn => ((defined? MODULE_GENERATOR_UPDATE_SVN ) ? MODULE_GENERATOR_UPDATE_SVN : false ), + :skeleton_path=> ((defined? MODULE_GENERATOR_SOURCE_ROOT ) ? MODULE_GENERATOR_SOURCE_ROOT.gsub('\\', '/').sub(/^\//, '').sub(/\/$/, '') : "src" ), + :test_define => ((defined? MODULE_GENERATOR_TEST_DEFINE ) ? MODULE_GENERATOR_TEST_DEFINE : "TEST" ), + } - # define_name = headername.gsub(/\.h$/, '_H').upcase + # Read Boilerplate template file. + if (defined? MODULE_GENERATOR_BOILERPLATE_FILES) - @files[0][:template] = @test_template - @files[1][:template] = @source_template - @files[2][:template] = @header_template + bf = MODULE_GENERATOR_BOILERPLATE_FILES - @files.each do |file| - if File.exist?(file[:path]) - @ceedling[:streaminator].stdout_puts "File #{file[:path]} already exists!" - else - File.open(file[:path], 'w') do |new_file| - new_file << ERB.new(file[:template], 0, "<>").result(binding) - end - @ceedling[:streaminator].stdout_puts "File #{file[:path]} created" + if !bf[:src].nil? && File.exists?(bf[:src]) + unity_generator_options[:boilerplates][:src] = File.read(bf[:src]) end - end - end - - private - - def extract_context(path, optz={}) - if (!defined?(MODULE_GENERATOR_PROJECT_ROOT) || - !defined?(MODULE_GENERATOR_SOURCE_ROOT) || - !defined?(MODULE_GENERATOR_TEST_ROOT)) - raise "You must have ':module_generator:project_root:', ':module_generator:source_root:' and ':module_generator:test_root:' defined in your Ceedling configuration file" + if !bf[:inc].nil? && File.exists?(bf[:inc]) + unity_generator_options[:boilerplates][:inc] = File.read(bf[:inc]) + end + + if !bf[:tst].nil? && File.exists?(bf[:tst]) + unity_generator_options[:boilerplates][:tst] = File.read(bf[:tst]) + end end - - @context = {} - @context[:paths] = { - :base => @ceedling[:file_wrapper].get_expanded_path(MODULE_GENERATOR_PROJECT_ROOT).gsub('\\', '/').sub(/^\//, '').sub(/\/$/, ''), - :src => MODULE_GENERATOR_SOURCE_ROOT.gsub('\\', '/').sub(/^\//, '').sub(/\/$/, ''), - :test => MODULE_GENERATOR_TEST_ROOT.gsub('\\', '/').sub(/^\//, '').sub(/\/$/, '') - } + # If using "create[<module_root>:<module_name>]" option from command line. + unless optz[:module_root_path].to_s.empty? + unity_generator_options[:path_src] = File.join(optz[:module_root_path], unity_generator_options[:path_src]) + unity_generator_options[:path_inc] = File.join(optz[:module_root_path], unity_generator_options[:path_inc]) + unity_generator_options[:path_tst] = File.join(optz[:module_root_path], unity_generator_options[:path_tst]) + end - location = File.dirname(path.gsub('\\', '/')) - location.sub!(/^\/?#{@context[:paths][:base]}\/?/i, '') - location.sub!(/^\/?#{@context[:paths][:src]}\/?/i, '') - location.sub!(/^\/?#{@context[:paths][:test]}\/?/i, '') - - @context[:location] = location - - @context[:name] = File.basename(path).sub(/\.[ch]$/, '') - - # p @context[:name] - - @context[:testname] = "test_#{@context[:name]}.c" - @context[:sourcename] = "#{@context[:name]}.c" - @context[:headername] = "#{@context[:name]}.h" - - # p @context - - @files = [ - {:path => File.join(MODULE_GENERATOR_PROJECT_ROOT, @context[:paths][:test], location, @context[:testname])}, - {:path => File.join(MODULE_GENERATOR_PROJECT_ROOT, @context[:paths][:src], location, @context[:sourcename])}, - {:path => File.join(MODULE_GENERATOR_PROJECT_ROOT, @context[:paths][:src], location, @context[:headername])} - ] - - # p @files + return unity_generator_options end - -end \ No newline at end of file + +end diff --git a/vendor/ceedling/plugins/module_generator/module_generator.rake b/vendor/ceedling/plugins/module_generator/module_generator.rake index 731a08e..f4ed9f1 100644 --- a/vendor/ceedling/plugins/module_generator/module_generator.rake +++ b/vendor/ceedling/plugins/module_generator/module_generator.rake @@ -1,14 +1,62 @@ namespace :module do + module_root_separator = ":" desc "Generate module (source, header and test files)" - task :create, :module_path do |t, args| - @ceedling[:module_generator].create(args[:module_path]) + task :create, :module_path do |t, args| + files = [args[:module_path]] + (args.extras || []) + optz = { :module_root_path => "" } + ["dh", "dih", "mch", "mvp", "src", "test"].each do |pat| + p = files.delete(pat) + optz[:pattern] = p unless p.nil? + end + files.each do |v| + module_root_path, module_name = v.split(module_root_separator, 2) + if module_name + optz[:module_root_path] = module_root_path + v = module_name + end + if (v =~ /^test_?/i) + # If the name of the file starts with test, automatically treat it as one + @ceedling[:module_generator].create(v.sub(/^test_?/i,''), optz.merge({:pattern => 'test'})) + else + # Otherwise, go through the normal procedure + @ceedling[:module_generator].create(v, optz) + end + end + end + + desc "Generate module stubs from header" + task :stub, :module_path do |t, args| + files = [args[:module_path]] + (args.extras || []) + optz = { :module_root_path => "" } + files.each do |v| + module_root_path, module_name = v.split(module_root_separator, 2) + if module_name + optz[:module_root_path] = module_root_path + v = module_name + end + # Otherwise, go through the normal procedure + @ceedling[:module_generator].stub_from_header(v, optz) + end end desc "Destroy module (source, header and test files)" task :destroy, :module_path do |t, args| - @ceedling[:module_generator].create(args[:module_path], {:destroy => true}) + files = [args[:module_path]] + (args.extras || []) + optz = { :destroy => true, :module_root_path => "" } + ["dh", "dih", "mch", "mvp", "src", "test"].each do |pat| + p = files.delete(pat) + optz[:pattern] = p unless p.nil? + end + files.each do |v| + module_root_path, module_name = v.split(module_root_separator, 2) + if module_name + optz[:module_root_path] = module_root_path + v = module_name + end + @ceedling[:module_generator].create(v, optz) + end end - + end diff --git a/vendor/ceedling/plugins/raw_output_report/README.md b/vendor/ceedling/plugins/raw_output_report/README.md new file mode 100644 index 0000000..330e87d --- /dev/null +++ b/vendor/ceedling/plugins/raw_output_report/README.md @@ -0,0 +1,19 @@ +ceedling-raw-output-report +========================== + +## Overview + +The raw-output-report allows you to capture all the output from the called +tools in a single document, so you can trace back through it later. This is +useful for debugging... but can eat through memory quickly if left running. + +## Setup + +Enable the plugin in your project.yml by adding `raw_output_report` +to the list of enabled plugins. + +``` YAML +:plugins: + :enabled: + - raw_output_report +``` diff --git a/vendor/ceedling/plugins/raw_output_report/lib/raw_output_report.rb b/vendor/ceedling/plugins/raw_output_report/lib/raw_output_report.rb new file mode 100644 index 0000000..014e677 --- /dev/null +++ b/vendor/ceedling/plugins/raw_output_report/lib/raw_output_report.rb @@ -0,0 +1,41 @@ +require 'ceedling/plugin' +require 'ceedling/constants' + +class RawOutputReport < Plugin + def setup + @log_paths = {} + end + + def post_test_fixture_execute(arg_hash) + output = strip_output(arg_hash[:shell_result][:output]) + write_raw_output_log(arg_hash, output) + end + + private + + def strip_output(raw_output) + output = "" + raw_output.each_line do |line| + next if line =~ /^\n$/ + next if line =~ /^.*:\d+:.*:(IGNORE|PASS|FAIL)/ + return output if line =~/^-----------------------\n$/ + output << line + end + end + def write_raw_output_log(arg_hash, output) + logging = generate_log_path(arg_hash) + @ceedling[:file_wrapper].write(logging[:path], output , logging[:flags]) unless logging.nil? + end + + def generate_log_path(arg_hash) + f_name = File.basename(arg_hash[:result_file], '.pass') + base_path = File.join(PROJECT_BUILD_ARTIFACTS_ROOT, arg_hash[:context].to_s) + file_path = File.join(base_path, f_name + '.log') + + if @ceedling[:file_wrapper].exist?(base_path) + return { path: file_path, flags: 'w' } + end + + nil + end +end diff --git a/vendor/ceedling/plugins/stdout_gtestlike_tests_report/README.md b/vendor/ceedling/plugins/stdout_gtestlike_tests_report/README.md new file mode 100644 index 0000000..9ab6084 --- /dev/null +++ b/vendor/ceedling/plugins/stdout_gtestlike_tests_report/README.md @@ -0,0 +1,19 @@ +ceedling-stdout-gtestlike-tests-report +====================== + +## Overview + +The stdout_gtestlike_tests_report replaces the normal ceedling "pretty" output with +a variant that resembles the output of gtest. This is most helpful when trying to +integrate into an IDE or CI that is meant to work with google test. + +## Setup + +Enable the plugin in your project.yml by adding `stdout_gtestlike_tests_report` +to the list of enabled plugins. + +``` YAML +:plugins: + :enabled: + - stdout_gtestlike_tests_report +``` diff --git a/vendor/ceedling/plugins/stdout_gtestlike_tests_report/assets/template.erb b/vendor/ceedling/plugins/stdout_gtestlike_tests_report/assets/template.erb new file mode 100644 index 0000000..fb8e3b1 --- /dev/null +++ b/vendor/ceedling/plugins/stdout_gtestlike_tests_report/assets/template.erb @@ -0,0 +1,84 @@ +% ignored = hash[:results][:counts][:ignored] +% failed = hash[:results][:counts][:failed] +% stdout_count = hash[:results][:counts][:stdout] +% header_prepend = ((hash[:header].length > 0) ? "#{hash[:header]}: " : '') +% banner_width = 25 + header_prepend.length # widest message +% results = {} +% hash[:results][:successes].each do |testresult| +% results[ testresult[:source][:file] ] = testresult[:collection] +% results[ testresult[:source][:file] ].length.times do |i| +% results[ testresult[:source][:file] ][i][:pass] = true +% end +% end +% hash[:results][:ignores].each do |testresult| +% if (results[ testresult[:source][:file] ].nil?) +% results[ testresult[:source][:file] ] = testresult[:collection] +% else +% results[ testresult[:source][:file] ] += testresult[:collection] +% end +% results[ testresult[:source][:file] ].length.times do |i| +% results[ testresult[:source][:file] ][i][:pass] = true +% end +% end +% hash[:results][:failures].each do |testresult| +% if (results[ testresult[:source][:file] ].nil?) +% results[ testresult[:source][:file] ] = testresult[:collection] +% else +% results[ testresult[:source][:file] ] += testresult[:collection] +% end +% end + + +[==========] Running <%=hash[:results][:counts][:total].to_s%> tests from <%=results.length.to_s%> test cases. +[----------] Global test environment set-up. +% results.each_pair do |modulename, moduledetails| +[----------] <%=moduledetails.length.to_s%> tests from <%=modulename%> +% moduledetails.each do |item| +[ RUN ] <%=modulename%>.<%=item[:test]%> +% if (not item[:pass]) +% if (not item[:message].empty?) +<%=modulename%>(<%=item[:line]%>): error: <%=item[:message]%> + +% m = item[:message].match(/Expected\s+(.*)\s+Was\s+([^\.]*)\./) +% if m.nil? + Actual: FALSE + Expected: TRUE +% else + Actual: <%=m[2]%> + Expected: <%=m[1]%> +% end +% else +<%=modulename%>(<%=item[:line]%>): fail: <%=item[:message]%> + Actual: FALSE + Expected: TRUE +% end +[ FAILED ] <%=modulename%>.<%=item[:test]%> (0 ms) +% else +[ OK ] <%=modulename%>.<%=item[:test]%> (0 ms) +% end +% end +[----------] <%=moduledetails.length.to_s%> tests from <%=modulename%> (0 ms total) +% end + +% if (hash[:results][:counts][:total] > 0) +[----------] Global test environment tear-down. +[==========] <%=hash[:results][:counts][:total].to_s%> tests from <%=hash[:results][:stdout].length.to_s%> test cases ran. +[ PASSED ] <%=hash[:results][:counts][:passed].to_s%> tests. +% if (failed == 0) +[ FAILED ] 0 tests. + + 0 FAILED TESTS +% else +[ FAILED ] <%=failed.to_s%> tests, listed below: +% hash[:results][:failures].each do |failure| +% failure[:collection].each do |item| +[ FAILED ] <%=failure[:source][:file]%>.<%=item[:test]%> +% end +% end +% end + + <%=failed.to_s%> FAILED TESTS +% else + +No tests executed. +% end diff --git a/vendor/ceedling/plugins/stdout_gtestlike_tests_report/assets/template.erb copy b/vendor/ceedling/plugins/stdout_gtestlike_tests_report/assets/template.erb copy new file mode 100644 index 0000000..a90f495 --- /dev/null +++ b/vendor/ceedling/plugins/stdout_gtestlike_tests_report/assets/template.erb copy @@ -0,0 +1,59 @@ +% ignored = hash[:results][:counts][:ignored] +% failed = hash[:results][:counts][:failed] +% stdout_count = hash[:results][:counts][:stdout] +% header_prepend = ((hash[:header].length > 0) ? "#{hash[:header]}: " : '') +% banner_width = 25 + header_prepend.length # widest message + + +% if (stdout_count > 0) +[==========] Running <%=hash[:results][:counts][:total].to_s%> tests from <%=hash[:results][:stdout].length.to_s%> test cases. +[----------] Global test environment set-up. +% end +% if (failed > 0) +% hash[:results][:failures].each do |failure| +[----------] <%=failure[:collection].length.to_s%> tests from <%=failure[:source][:file]%> +% failure[:collection].each do |item| +[ RUN ] <%=failure[:source][:file]%>.<%=item[:test]%> +% if (not item[:message].empty?) +<%=failure[:source][:file]%>(<%=item[:line]%>): error: <%=item[:message]%> + +% m = item[:message].match(/Expected\s+(.*)\s+Was\s+([^\.]*)\./) +% if m.nil? + Actual: FALSE + Expected: TRUE +% else + Actual: <%=m[2]%> + Expected: <%=m[1]%> +% end +% else +<%=failure[:source][:file]%>(<%=item[:line]%>): fail: <%=item[:message]%> + Actual: FALSE + Expected: TRUE +% end +[ FAILED ] <%=failure[:source][:file]%>.<%=item[:test]%> (0 ms) +% end +[----------] <%=failure[:collection].length.to_s%> tests from <%=failure[:source][:file]%> (0 ms total) +% end +% end +% if (hash[:results][:counts][:total] > 0) +[----------] Global test environment tear-down. +[==========] <%=hash[:results][:counts][:total].to_s%> tests from <%=hash[:results][:stdout].length.to_s%> test cases ran. +[ PASSED ] <%=hash[:results][:counts][:passed].to_s%> tests. +% if (failed == 0) +[ FAILED ] 0 tests. + + 0 FAILED TESTS +% else +[ FAILED ] <%=failed.to_s%> tests, listed below: +% hash[:results][:failures].each do |failure| +% failure[:collection].each do |item| +[ FAILED ] <%=failure[:source][:file]%>.<%=item[:test]%> +% end +% end + + <%=failed.to_s%> FAILED TESTS +% end +% else + +No tests executed. +% end diff --git a/vendor/ceedling/plugins/stdout_gtestlike_tests_report/config/stdout_gtestlike_tests_report.yml b/vendor/ceedling/plugins/stdout_gtestlike_tests_report/config/stdout_gtestlike_tests_report.yml new file mode 100644 index 0000000..c25acf5 --- /dev/null +++ b/vendor/ceedling/plugins/stdout_gtestlike_tests_report/config/stdout_gtestlike_tests_report.yml @@ -0,0 +1,4 @@ +--- +:plugins: + # tell Ceedling we got results display taken care of + :display_raw_test_results: FALSE diff --git a/vendor/ceedling/plugins/stdout_gtestlike_tests_report/lib/stdout_gtestlike_tests_report.rb b/vendor/ceedling/plugins/stdout_gtestlike_tests_report/lib/stdout_gtestlike_tests_report.rb new file mode 100644 index 0000000..a51438a --- /dev/null +++ b/vendor/ceedling/plugins/stdout_gtestlike_tests_report/lib/stdout_gtestlike_tests_report.rb @@ -0,0 +1,43 @@ +require 'ceedling/plugin' +require 'ceedling/defaults' + +class StdoutGtestlikeTestsReport < Plugin + + def setup + @result_list = [] + @plugin_root = File.expand_path(File.join(File.dirname(__FILE__), '..')) + template = @ceedling[:file_wrapper].read(File.join(@plugin_root, 'assets/template.erb')) + @ceedling[:plugin_reportinator].register_test_results_template( template ) + end + + def post_test_fixture_execute(arg_hash) + return if not (arg_hash[:context] == TEST_SYM) + + @result_list << arg_hash[:result_file] + end + + def post_build + return if not (@ceedling[:task_invoker].test_invoked?) + + results = @ceedling[:plugin_reportinator].assemble_test_results(@result_list) + hash = { + :header => '', + :results => results + } + + @ceedling[:plugin_reportinator].run_test_results_report(hash) + end + + def summary + result_list = @ceedling[:file_path_utils].form_pass_results_filelist( PROJECT_TEST_RESULTS_PATH, COLLECTION_ALL_TESTS ) + + # get test results for only those tests in our configuration and of those only tests with results on disk + hash = { + :header => '', + :results => @ceedling[:plugin_reportinator].assemble_test_results(result_list, {:boom => false}) + } + + @ceedling[:plugin_reportinator].run_test_results_report(hash) + end + +end diff --git a/vendor/ceedling/plugins/stdout_ide_tests_report/README.md b/vendor/ceedling/plugins/stdout_ide_tests_report/README.md new file mode 100644 index 0000000..ed6c655 --- /dev/null +++ b/vendor/ceedling/plugins/stdout_ide_tests_report/README.md @@ -0,0 +1,18 @@ +ceedling-stdout-ide-tests-report +================================ + +## Overview + +The stdout_ide_tests_report replaces the normal ceedling "pretty" output with +a simplified variant intended to be easily parseable. + +## Setup + +Enable the plugin in your project.yml by adding `stdout_ide_tests_report` +to the list of enabled plugins. + +``` YAML +:plugins: + :enabled: + - stdout_ide_tests_report +``` diff --git a/vendor/ceedling/plugins/stdout_ide_tests_report/lib/stdout_ide_tests_report.rb b/vendor/ceedling/plugins/stdout_ide_tests_report/lib/stdout_ide_tests_report.rb index 61db062..48b3e81 100644 --- a/vendor/ceedling/plugins/stdout_ide_tests_report/lib/stdout_ide_tests_report.rb +++ b/vendor/ceedling/plugins/stdout_ide_tests_report/lib/stdout_ide_tests_report.rb @@ -1,27 +1,27 @@ -require 'plugin' -require 'defaults' +require 'ceedling/plugin' +require 'ceedling/defaults' class StdoutIdeTestsReport < Plugin - + def setup @result_list = [] end - + def post_test_fixture_execute(arg_hash) return if not (arg_hash[:context] == TEST_SYM) @result_list << arg_hash[:result_file] end - + def post_build return if (not @ceedling[:task_invoker].test_invoked?) - + results = @ceedling[:plugin_reportinator].assemble_test_results(@result_list) hash = { :header => '', :results => results } - + @ceedling[:plugin_reportinator].run_test_results_report(hash) do message = '' message = 'Unit test failures.' if (hash[:results][:counts][:failed] > 0) @@ -41,4 +41,4 @@ def summary @ceedling[:plugin_reportinator].run_test_results_report(hash) end -end \ No newline at end of file +end diff --git a/vendor/ceedling/plugins/stdout_pretty_tests_report/README.md b/vendor/ceedling/plugins/stdout_pretty_tests_report/README.md new file mode 100644 index 0000000..7e1be23 --- /dev/null +++ b/vendor/ceedling/plugins/stdout_pretty_tests_report/README.md @@ -0,0 +1,20 @@ +ceedling-pretty-tests-report +============================ + +## Overview + +The stdout_pretty_tests_report is the default output of ceedling. Instead of +showing most of the raw output of CMock, Ceedling, etc., it shows a simplified +view. It also creates a nice summary at the end of execution which groups the +results into ignored and failed tests. + +## Setup + +Enable the plugin in your project.yml by adding `stdout_pretty_tests_report` +to the list of enabled plugins. + +``` YAML +:plugins: + :enabled: + - stdout_pretty_tests_report +``` diff --git a/vendor/ceedling/plugins/stdout_pretty_tests_report/assets/template.erb b/vendor/ceedling/plugins/stdout_pretty_tests_report/assets/template.erb index 4c9fb46..52b29f7 100644 --- a/vendor/ceedling/plugins/stdout_pretty_tests_report/assets/template.erb +++ b/vendor/ceedling/plugins/stdout_pretty_tests_report/assets/template.erb @@ -4,8 +4,18 @@ % header_prepend = ((hash[:header].length > 0) ? "#{hash[:header]}: " : '') % banner_width = 25 + header_prepend.length # widest message +% if (stdout_count > 0) +<%=@ceedling[:plugin_reportinator].generate_banner(header_prepend + 'TEST OUTPUT')%> +% hash[:results][:stdout].each do |string| +[<%=string[:source][:file]%>] +% string[:collection].each do |item| + - "<%=item%>" +% end + +% end +% end % if (ignored > 0) -<%=@ceedling[:plugin_reportinator].generate_banner(header_prepend + 'IGNORED UNIT TEST SUMMARY')%> +<%=@ceedling[:plugin_reportinator].generate_banner(header_prepend + 'IGNORED TEST SUMMARY')%> % hash[:results][:ignores].each do |ignore| [<%=ignore[:source][:file]%>] % ignore[:collection].each do |item| @@ -20,7 +30,7 @@ % end % end % if (failed > 0) -<%=@ceedling[:plugin_reportinator].generate_banner(header_prepend + 'FAILED UNIT TEST SUMMARY')%> +<%=@ceedling[:plugin_reportinator].generate_banner(header_prepend + 'FAILED TEST SUMMARY')%> % hash[:results][:failures].each do |failure| [<%=failure[:source][:file]%>] % failure[:collection].each do |item| @@ -32,21 +42,11 @@ % end % end -% end -% end -% if (stdout_count > 0) -<%=@ceedling[:plugin_reportinator].generate_banner(header_prepend + 'UNIT TEST OTHER OUTPUT')%> -% hash[:results][:stdout].each do |string| -[<%=string[:source][:file]%>] -% string[:collection].each do |item| - - "<%=item%>" -% end - % end % end % total_string = hash[:results][:counts][:total].to_s % format_string = "%#{total_string.length}i" -<%=@ceedling[:plugin_reportinator].generate_banner(header_prepend + 'OVERALL UNIT TEST SUMMARY')%> +<%=@ceedling[:plugin_reportinator].generate_banner(header_prepend + 'OVERALL TEST SUMMARY')%> % if (hash[:results][:counts][:total] > 0) TESTED: <%=hash[:results][:counts][:total].to_s%> PASSED: <%=sprintf(format_string, hash[:results][:counts][:passed])%> diff --git a/vendor/ceedling/plugins/stdout_pretty_tests_report/lib/stdout_pretty_tests_report.rb b/vendor/ceedling/plugins/stdout_pretty_tests_report/lib/stdout_pretty_tests_report.rb index 1e50faf..018388f 100644 --- a/vendor/ceedling/plugins/stdout_pretty_tests_report/lib/stdout_pretty_tests_report.rb +++ b/vendor/ceedling/plugins/stdout_pretty_tests_report/lib/stdout_pretty_tests_report.rb @@ -1,5 +1,5 @@ -require 'plugin' -require 'defaults' +require 'ceedling/plugin' +require 'ceedling/defaults' class StdoutPrettyTestsReport < Plugin @@ -44,4 +44,4 @@ def summary @ceedling[:plugin_reportinator].run_test_results_report(hash) end -end \ No newline at end of file +end diff --git a/vendor/ceedling/plugins/subprojects/README.md b/vendor/ceedling/plugins/subprojects/README.md new file mode 100644 index 0000000..e51a4e6 --- /dev/null +++ b/vendor/ceedling/plugins/subprojects/README.md @@ -0,0 +1,63 @@ +ceedling-subprojects +==================== + +Plugin for supporting subprojects that are built as static libraries. It continues to support +dependency tracking, without getting confused between your main project files and your +subproject files. It accepts different compiler flags and linker flags, allowing you to +optimize for your situation. + +First, you're going to want to add the extension to your list of known extensions: + +``` +:extension: + :subprojects: '.a' +``` + +Define a new section called :subprojects. There, you can list as many subprojects +as you may need under the :paths key. For each, you specify a unique place to build +and a unique name. + +``` +:subprojects: + :paths: + - :name: libprojectA + :source: + - ./subprojectA/first/dir + - ./subprojectA/second/dir + :include: + - ./subprojectA/include/dir + :build_root: ./subprojectA/build/dir + :defines: + - DEFINE_JUST_FOR_THIS_FILE + - AND_ANOTHER + - :name: libprojectB + :source: + - ./subprojectB/only/dir + :include: + - ./subprojectB/first/include/dir + - ./subprojectB/second/include/dir + :build_root: ./subprojectB/build/dir + :defines: [] #none for this one +``` + +You can specify the compiler and linker, just as you would a release build: + +``` +:tools: + :subprojects_compiler: + :executable: gcc + :arguments: + - -g + - -I"$": COLLECTION_PATHS_SUBPROJECTS + - -D$: COLLECTION_DEFINES_SUBPROJECTS + - -c "${1}" + - -o "${2}" + :subprojects_linker: + :executable: ar + :arguments: + - rcs + - ${2} + - ${1} +``` + +That's all there is to it! Happy Hacking! diff --git a/vendor/ceedling/plugins/subprojects/config/defaults.yml b/vendor/ceedling/plugins/subprojects/config/defaults.yml new file mode 100644 index 0000000..1045a59 --- /dev/null +++ b/vendor/ceedling/plugins/subprojects/config/defaults.yml @@ -0,0 +1,33 @@ +--- +#:extension: +# :subprojects: '.a' + +:subprojects: + :paths: [] +# - :name: subprojectA +# :source: +# - ./first/subproject/dir +# - ./second/subproject/dir +# :include: +# - ./first/include/dir +# :build_root: ./subproject/build/dir +# :defines: +# - FIRST_DEFINE + +:tools: + :subprojects_compiler: + :executable: gcc + :arguments: + - -g + - -I"$": COLLECTION_PATHS_SUBPROJECTS + - -D$: COLLECTION_DEFINES_SUBPROJECTS + - -c "${1}" + - -o "${2}" + :subprojects_linker: + :executable: ar + :arguments: + - rcs + - ${2} + - ${1} + +... diff --git a/vendor/ceedling/plugins/subprojects/lib/subprojects.rb b/vendor/ceedling/plugins/subprojects/lib/subprojects.rb new file mode 100644 index 0000000..559251e --- /dev/null +++ b/vendor/ceedling/plugins/subprojects/lib/subprojects.rb @@ -0,0 +1,92 @@ +require 'ceedling/plugin' +require 'ceedling/constants' + +SUBPROJECTS_ROOT_NAME = 'subprojects' +SUBPROJECTS_TASK_ROOT = SUBPROJECTS_ROOT_NAME + ':' +SUBPROJECTS_SYM = SUBPROJECTS_ROOT_NAME.to_sym + +class Subprojects < Plugin + + def setup + @plugin_root = File.expand_path(File.join(File.dirname(__FILE__), '..')) + + # Add to the test paths + SUBPROJECTS_PATHS.each do |subproj| + subproj[:source].each do |path| + COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR << path + end + subproj[:include].each do |path| + COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR << path + end + end + + # Gather information about the subprojects + @subprojects = {} + @subproject_lookup_by_path = {} + SUBPROJECTS_PATHS.each do |subproj| + @subprojects[ subproj[:name] ] = subproj.clone + @subprojects[ subproj[:name] ][:c] = [] + @subprojects[ subproj[:name] ][:asm] = [] + subproj[:source].each do |path| + search_path = "#{path[-1].match(/\\|\//) ? path : "#{path}/"}*#{EXTENSION_SOURCE}" + @subprojects[ subproj[:name] ][:c] += Dir[search_path] + if (EXTENSION_ASSEMBLY && !EXTENSION_ASSEMBLY.empty?) + search_path = "#{path[-1].match(/\\|\//) ? path : "#{path}/"}*#{EXTENSION_ASSEMBLY}" + @subprojects[ subproj[:name] ][:asm] += Dir[search_path] + end + end + @subproject_lookup_by_path[ subproj[:build_root] ] = subproj[:name] + end + end + + def find_my_project( c_file, file_type = :c ) + @subprojects.each_pair do |subprojname, subproj| + return subprojname if (subproj[file_type].include?(c_file)) + end + end + + def find_my_paths( c_file, file_type = :c ) + @subprojects.each_pair do |subprojname, subproj| + return (subproj[:source] + (subproj[:include] || [])) if (subproj[file_type].include?(c_file)) + end + return [] + end + + def find_my_defines( c_file, file_type = :c ) + @subprojects.each_pair do |subprojname, subproj| + return (subproj[:defines] || []) if (subproj[file_type].include?(c_file)) + end + return [] + end + + def list_all_object_files_for_subproject( lib_name ) + subproj = File.basename(lib_name, EXTENSION_SUBPROJECTS) + objpath = "#{@subprojects[subproj][:build_root]}/out/c" + bbb = @subprojects[subproj][:c].map{|f| "#{objpath}/#{File.basename(f,EXTENSION_SOURCE)}#{EXTENSION_OBJECT}" } + bbb + end + + def find_library_source_file_for_object( obj_name ) + cname = "#{File.basename(obj_name, EXTENSION_OBJECT)}#{EXTENSION_SOURCE}" + dname = File.dirname(obj_name)[0..-7] + pname = @subproject_lookup_by_path[dname] + return @ceedling[:file_finder].find_file_from_list(cname, @subprojects[pname][:c], :error) + end + + def find_library_assembly_file_for_object( obj_name ) + cname = "#{File.basename(obj_name, EXTENSION_OBJECT)}#{EXTENSION_ASEMBLY}" + dname = File.dirname(obj_name)[0..-7] + pname = @subproject_lookup_by_path[dname] + return @ceedling[:file_finder].find_file_from_list(cname, @subprojects[pname][:asm], :error) + end + + def replace_constant(constant, new_value) + Object.send(:remove_const, constant.to_sym) if (Object.const_defined? constant) + Object.const_set(constant, new_value) + end + +end + +# end blocks always executed following rake run +END { +} diff --git a/vendor/ceedling/plugins/subprojects/subprojects.rake b/vendor/ceedling/plugins/subprojects/subprojects.rake new file mode 100644 index 0000000..0025c3e --- /dev/null +++ b/vendor/ceedling/plugins/subprojects/subprojects.rake @@ -0,0 +1,78 @@ + + +SUBPROJECTS_PATHS.each do |subproj| + + subproj_source = subproj[:source] + subproj_include = subproj[:include] + subproj_name = subproj[:name] + subproj_build_root = subproj[:build_root] + subproj_build_out = "#{subproj[:build_root]}/out" + subproj_build_c = "#{subproj[:build_root]}/out/c" + subproj_build_asm = "#{subproj[:build_root]}/out/asm" + subproj_directories = [ subproj_build_root, subproj_build_out, subproj_build_c, subproj_build_asm ] + + subproj_directories.each do |subdir| + directory(subdir) + end + + CLEAN.include(File.join(subproj_build_root, '*')) + CLEAN.include(File.join(subproj_build_out, '*')) + + CLOBBER.include(File.join(subproj_build_root, '**/*')) + + # Add a rule for building the actual static library from our object files + rule(/#{subproj_build_root}#{'.+\\'+EXTENSION_SUBPROJECTS}$/ => [ + proc do |task_name| + @ceedling[SUBPROJECTS_SYM].list_all_object_files_for_subproject(task_name) + end + ]) do |bin_file| + @ceedling[:generator].generate_executable_file( + TOOLS_SUBPROJECTS_LINKER, + SUBPROJECTS_SYM, + bin_file.prerequisites, + bin_file.name, + @ceedling[:file_path_utils].form_test_build_map_filepath(bin_file.name)) + end + + # Add a rule for building object files from assembly files to link into a library + if (RELEASE_BUILD_USE_ASSEMBLY) + rule(/#{subproj_build_asm}#{'.+\\'+EXTENSION_OBJECT}$/ => [ + proc do |task_name| + @ceedling[SUBPROJECTS_SYM].find_library_assembly_file_for_object(task_name) + end + ]) do |object| + @ceedling[SUBPROJECTS_SYM].replace_constant(:COLLECTION_PATHS_SUBPROJECTS, @ceedling[SUBPROJECTS_SYM].find_my_paths(object.source, :asm)) + @ceedling[SUBPROJECTS_SYM].replace_constant(:COLLECTION_DEFINES_SUBPROJECTS, @ceedling[SUBPROJECTS_SYM].find_my_defines(object.source, :asm)) + @ceedling[:generator].generate_object_file( + TOOLS_SUBPROJECTS_ASSEMBLER, + OPERATION_ASSEMBLE_SYM, + SUBPROJECTS_SYM, + object.source, + object.name ) + end + end + + # Add a rule for building object files from C files to link into a library + rule(/#{subproj_build_c}#{'.+\\'+EXTENSION_OBJECT}$/ => [ + proc do |task_name| + @ceedling[SUBPROJECTS_SYM].find_library_source_file_for_object(task_name) + end + ]) do |object| + @ceedling[SUBPROJECTS_SYM].replace_constant(:COLLECTION_PATHS_SUBPROJECTS, @ceedling[SUBPROJECTS_SYM].find_my_paths(object.source, :c)) + @ceedling[SUBPROJECTS_SYM].replace_constant(:COLLECTION_DEFINES_SUBPROJECTS, @ceedling[SUBPROJECTS_SYM].find_my_defines(object.source, :c)) + @ceedling[:generator].generate_object_file( + TOOLS_SUBPROJECTS_COMPILER, + OPERATION_COMPILE_SYM, + SUBPROJECTS_SYM, + object.source, + object.name, + @ceedling[:file_path_utils].form_release_build_c_list_filepath( object.name ) ) + end + + # Add the subdirectories involved to our list of those that should be autogenerated + task :directories => subproj_directories.clone + + # Finally, add the static library to our RELEASE build dependency list + task RELEASE_SYM => ["#{subproj_build_root}/#{subproj_name}#{EXTENSION_SUBPROJECTS}"] +end + diff --git a/vendor/ceedling/plugins/teamcity_tests_report/README.md b/vendor/ceedling/plugins/teamcity_tests_report/README.md new file mode 100644 index 0000000..9fcda7d --- /dev/null +++ b/vendor/ceedling/plugins/teamcity_tests_report/README.md @@ -0,0 +1,18 @@ +ceedling-teamcity-tests-report +============================== + +## Overview + +The teamcity_tests_report replaces the normal ceedling "pretty" output with +a version that has results tagged to be consumed with the teamcity CI server. + +## Setup + +Enable the plugin in your project.yml by adding `teamcity_tests_report` +to the list of enabled plugins. + +``` YAML +:plugins: + :enabled: + - teamcity_tests_report +``` diff --git a/vendor/ceedling/plugins/teamcity_tests_report/config/teamcity_tests_report.yml b/vendor/ceedling/plugins/teamcity_tests_report/config/teamcity_tests_report.yml new file mode 100644 index 0000000..c25acf5 --- /dev/null +++ b/vendor/ceedling/plugins/teamcity_tests_report/config/teamcity_tests_report.yml @@ -0,0 +1,4 @@ +--- +:plugins: + # tell Ceedling we got results display taken care of + :display_raw_test_results: FALSE diff --git a/vendor/ceedling/plugins/teamcity_tests_report/lib/teamcity_tests_report.rb b/vendor/ceedling/plugins/teamcity_tests_report/lib/teamcity_tests_report.rb new file mode 100644 index 0000000..33d8548 --- /dev/null +++ b/vendor/ceedling/plugins/teamcity_tests_report/lib/teamcity_tests_report.rb @@ -0,0 +1,57 @@ +require 'ceedling/plugin' +require 'ceedling/defaults' + +class TeamcityTestsReport < Plugin + + def setup + @suite_started = nil + @output_enabled = !defined?(TEAMCITY_BUILD) || TEAMCITY_BUILD + end + + def escape(string) + string.gsub(/['|\[\]]/, '|\0').gsub('\r', '|r').gsub('\n', '|n') + end + + def pre_test(test) + teamcity_message "testSuiteStarted name='#{File.basename(test, '.c')}'" + @suite_started = Time.now + end + + def post_test(test) + teamcity_message "testSuiteFinished name='#{File.basename(test, '.c')}'" + end + + def post_test_fixture_execute(arg_hash) + duration = (Time.now - @suite_started) * 1000 + results = @ceedling[:plugin_reportinator].assemble_test_results([arg_hash[:result_file]]) + avg_duration = (duration / [1, results[:counts][:passed] + results[:counts][:failed]].max).round + + results[:successes].each do |success| + success[:collection].each do |test| + teamcity_message "testStarted name='#{test[:test]}'" + teamcity_message "testFinished name='#{test[:test]}' duration='#{avg_duration}'" + end + end + + results[:failures].each do |failure| + failure[:collection].each do |test| + teamcity_message "testStarted name='#{test[:test]}'" + teamcity_message "testFailed name='#{test[:test]}' message='#{escape(test[:message])}' details='File: #{failure[:source][:path]}/#{failure[:source][:file]} Line: #{test[:line]}'" + teamcity_message "testFinished name='#{test[:test]}' duration='#{avg_duration}'" + end + end + + results[:ignores].each do |failure| + failure[:collection].each do |test| + teamcity_message "testIgnored name='#{test[:test]}' message='#{escape(test[:message])}'" + end + end + + # We ignore stdout + end + + def teamcity_message(content) + puts "##teamcity[#{content}]" unless !@output_enabled + end + +end diff --git a/vendor/ceedling/plugins/warnings_report/README.md b/vendor/ceedling/plugins/warnings_report/README.md new file mode 100644 index 0000000..fd7fae5 --- /dev/null +++ b/vendor/ceedling/plugins/warnings_report/README.md @@ -0,0 +1,19 @@ +warnings-report +=============== + +## Overview + +The warnings_report captures all warnings throughout the build process +and collects them into a single report at the end of execution. It places all +of this into a warnings file in the output artifact directory. + +## Setup + +Enable the plugin in your project.yml by adding `warnings_report` +to the list of enabled plugins. + +``` YAML +:plugins: + :enabled: + - warnings_report +``` diff --git a/vendor/ceedling/plugins/warnings_report/lib/warnings_report.rb b/vendor/ceedling/plugins/warnings_report/lib/warnings_report.rb new file mode 100644 index 0000000..d4f43fb --- /dev/null +++ b/vendor/ceedling/plugins/warnings_report/lib/warnings_report.rb @@ -0,0 +1,69 @@ +require 'ceedling/plugin' +require 'ceedling/constants' + +class WarningsReport < Plugin + def setup + @stderr_redirect = nil + @log_paths = {} + end + + def pre_compile_execute(arg_hash) + # at beginning of compile, override tool's stderr_redirect so we can parse $stderr + $stdout + set_stderr_redirect(arg_hash) + end + + def post_compile_execute(arg_hash) + # after compilation, grab output for parsing/logging, restore stderr_redirect, log warning if it exists + output = arg_hash[:shell_result][:output] + restore_stderr_redirect(arg_hash) + write_warning_log(arg_hash[:context], output) + end + + def pre_link_execute(arg_hash) + # at beginning of link, override tool's stderr_redirect so we can parse $stderr + $stdout + set_stderr_redirect(arg_hash) + end + + def post_link_execute(arg_hash) + # after linking, grab output for parsing/logging, restore stderr_redirect, log warning if it exists + output = arg_hash[:shell_result][:output] + restore_stderr_redirect(arg_hash) + write_warning_log(arg_hash[:context], output) + end + + private + + def set_stderr_redirect(hash) + @stderr_redirect = hash[:tool][:stderr_redirect] + hash[:tool][:stderr_redirect] = StdErrRedirect::AUTO + end + + def restore_stderr_redirect(hash) + hash[:tool][:stderr_redirect] = @stderr_redirect + end + + def write_warning_log(context, output) + # if $stderr/$stdout contain "warning", log it + if output =~ /warning/i + # generate a log path & file io write flags + logging = generate_log_path(context) + @ceedling[:file_wrapper].write(logging[:path], output + "\n", logging[:flags]) unless logging.nil? + end + end + + def generate_log_path(context) + # if path has already been generated, return it & 'append' file io flags (append to log) + return { path: @log_paths[context], flags: 'a' } unless @log_paths[context].nil? + + # first time through, generate path & 'write' file io flags (create new log) + base_path = File.join(PROJECT_BUILD_ARTIFACTS_ROOT, context.to_s) + file_path = File.join(base_path, 'warnings.log') + + if @ceedling[:file_wrapper].exist?(base_path) + @log_paths[context] = file_path + return { path: file_path, flags: 'w' } + end + + nil + end +end diff --git a/vendor/ceedling/plugins/warnings_report/warnings_report.rb b/vendor/ceedling/plugins/warnings_report/warnings_report.rb deleted file mode 100644 index 6f1a266..0000000 --- a/vendor/ceedling/plugins/warnings_report/warnings_report.rb +++ /dev/null @@ -1,71 +0,0 @@ -require 'plugin' -require 'constants' - -class WarningsReport < Plugin - - def setup - @stderr_redirect = nil - @log_paths = {} - end - - def pre_compile_execute( arg_hash ) - # at beginning of compile, override tool's stderr_redirect so we can parse $stderr + $stdout - set_stderr_redirect( arg_hash ) - end - - def post_compile_execute( arg_hash ) - # after compilation, grab output for parsing/logging, restore stderr_redirect, log warning if it exists - output = arg_hash[:shell_result][:output] - restore_stderr_redirect( arg_hash ) - write_warning_log( arg_hash[:context], output ) - end - - def pre_link_execute( arg_hash ) - # at beginning of link, override tool's stderr_redirect so we can parse $stderr + $stdout - set_stderr_redirect( arg_hash ) - end - - def post_link_execute( arg_hash ) - # after linking, grab output for parsing/logging, restore stderr_redirect, log warning if it exists - output = arg_hash[:shell_result][:output] - restore_stderr_redirect( arg_hash ) - write_warning_log( arg_hash[:context], output ) - end - - private - - def set_stderr_redirect( hash ) - @stderr_redirect = hash[:tool][:stderr_redirect] - hash[:tool][:stderr_redirect] = StdErrRedirect::AUTO - end - - def restore_stderr_redirect( hash ) - hash[:tool][:stderr_redirect] = @stderr_redirect - end - - def write_warning_log( context, output ) - # if $stderr/$stdout contain "warning", log it - if (output =~ /warning/i) - # generate a log path & file io write flags - logging = generate_log_path( context ) - @ceedling[:file_wrapper].write( logging[:path], output + "\n", logging[:flags] ) if (not logging.nil?) - end - end - - def generate_log_path( context ) - # if path has already been generated, return it & 'append' file io flags (append to log) - return { :path => @log_paths[context], :flags => 'a' } if (not @log_paths[context].nil?) - - # first time through, generate path & 'write' file io flags (create new log) - base_path = File.join( PROJECT_BUILD_ARTIFACTS_ROOT, context.to_s ) - file_path = File.join( base_path, 'warnings.log' ) - - if (@ceedling[:file_wrapper].exist?( base_path )) - @log_paths[context] = file_path - return { :path => file_path, :flags => 'w' } - end - - return nil - end - -end \ No newline at end of file diff --git a/vendor/ceedling/plugins/xml_tests_report/README.md b/vendor/ceedling/plugins/xml_tests_report/README.md new file mode 100644 index 0000000..6200c7d --- /dev/null +++ b/vendor/ceedling/plugins/xml_tests_report/README.md @@ -0,0 +1,36 @@ +xml_tests_report +================ + +## Overview + +The xml_tests_report plugin creates an XML file of test results in xUnit +format, which is handy for Continuous Integration build servers or as input +into other reporting tools. The XML file is output to the appropriate +`<build_root>/artifacts/` directory (e.g. `artifacts/test/` for test tasks, +`artifacts/gcov/` for gcov, or `artifacts/bullseye/` for bullseye runs). + +## Setup + +Enable the plugin in your project.yml by adding `xml_tests_report` to the list +of enabled plugins. + +``` YAML +:plugins: + :enabled: + - xml_tests_report +``` + +## Configuration + +Optionally configure the output / artifact filename in your project.yml with +the `artifact_filename` configuration option. The default filename is +`report.xml`. + +You can also configure the path that this artifact is stored. This can be done +by setting `path`. The default is that it will be placed in a subfolder under +the `build` directory. + +``` YAML +:xml_tests_report: + :artifact_filename: report_xunit.xml +``` diff --git a/vendor/ceedling/plugins/xml_tests_report/lib/xml_tests_report.rb b/vendor/ceedling/plugins/xml_tests_report/lib/xml_tests_report.rb new file mode 100644 index 0000000..ed4e996 --- /dev/null +++ b/vendor/ceedling/plugins/xml_tests_report/lib/xml_tests_report.rb @@ -0,0 +1,110 @@ +require 'ceedling/plugin' +require 'ceedling/constants' + +class XmlTestsReport < Plugin + def setup + @results_list = {} + @test_counter = 0 + end + + def post_test_fixture_execute(arg_hash) + context = arg_hash[:context] + + @results_list[context] = [] if @results_list[context].nil? + + @results_list[context] << arg_hash[:result_file] + end + + def post_build + @results_list.each_key do |context| + results = @ceedling[:plugin_reportinator].assemble_test_results(@results_list[context]) + + artifact_filename = @ceedling[:configurator].project_config_hash[:xml_tests_report_artifact_filename] || 'report.xml' + artifact_fullpath = @ceedling[:configurator].project_config_hash[:xml_tests_report_path] || File.join(PROJECT_BUILD_ARTIFACTS_ROOT, context.to_s) + file_path = File.join(artifact_fullpath, artifact_filename) + + @ceedling[:file_wrapper].open(file_path, 'w') do |f| + @test_counter = 1 + write_results(results, f) + end + end + end + + private + + def write_results(results, stream) + write_header(stream) + write_failures(results[:failures], stream) + write_tests(results[:successes], stream, 'SuccessfulTests') + write_tests(results[:ignores], stream, 'IgnoredTests') + write_statistics(results[:counts], stream) + write_footer(stream) + end + + def write_header(stream) + stream.puts "<?xml version='1.0' encoding='utf-8' ?>" + stream.puts '<TestRun>' + end + + def write_failures(results, stream) + if results.size.zero? + stream.puts "\t<FailedTests/>" + return + end + + stream.puts "\t<FailedTests>" + + results.each do |result| + result[:collection].each do |item| + filename = File.join(result[:source][:path], result[:source][:file]) + + stream.puts "\t\t<Test id=\"#{@test_counter}\">" + stream.puts "\t\t\t<Name>#{filename}::#{item[:test]}</Name>" + stream.puts "\t\t\t<FailureType>Assertion</FailureType>" + stream.puts "\t\t\t<Location>" + stream.puts "\t\t\t\t<File>#{filename}</File>" + stream.puts "\t\t\t\t<Line>#{item[:line]}</Line>" + stream.puts "\t\t\t</Location>" + stream.puts "\t\t\t<Message>#{item[:message]}</Message>" + stream.puts "\t\t</Test>" + @test_counter += 1 + end + end + + stream.puts "\t</FailedTests>" + end + + def write_tests(results, stream, tag) + if results.size.zero? + stream.puts "\t<#{tag}/>" + return + end + + stream.puts "\t<#{tag}>" + + results.each do |result| + result[:collection].each do |item| + stream.puts "\t\t<Test id=\"#{@test_counter}\">" + stream.puts "\t\t\t<Name>#{File.join(result[:source][:path], result[:source][:file])}::#{item[:test]}</Name>" + stream.puts "\t\t</Test>" + @test_counter += 1 + end + end + + stream.puts "\t</#{tag}>" + end + + def write_statistics(counts, stream) + stream.puts "\t<Statistics>" + stream.puts "\t\t<Tests>#{counts[:total]}</Tests>" + stream.puts "\t\t<Ignores>#{counts[:ignored]}</Ignores>" + stream.puts "\t\t<FailuresTotal>#{counts[:failed]}</FailuresTotal>" + stream.puts "\t\t<Errors>0</Errors>" + stream.puts "\t\t<Failures>#{counts[:failed]}</Failures>" + stream.puts "\t</Statistics>" + end + + def write_footer(stream) + stream.puts '</TestRun>' + end +end diff --git a/vendor/ceedling/plugins/xml_tests_report/xml_tests_report.rb b/vendor/ceedling/plugins/xml_tests_report/xml_tests_report.rb deleted file mode 100644 index 97881a4..0000000 --- a/vendor/ceedling/plugins/xml_tests_report/xml_tests_report.rb +++ /dev/null @@ -1,110 +0,0 @@ -require 'plugin' -require 'constants' - -class XmlTestsReport < Plugin - - def setup - @results_list = {} - @test_counter = 0 - end - - def post_test_fixture_execute(arg_hash) - context = arg_hash[:context] - - @results_list[context] = [] if (@results_list[context].nil?) - - @results_list[context] << arg_hash[:result_file] - end - - def post_build - @results_list.each_key do |context| - results = @ceedling[:plugin_reportinator].assemble_test_results(@results_list[context]) - - file_path = File.join( PROJECT_BUILD_ARTIFACTS_ROOT, context.to_s, 'report.xml' ) - - @ceedling[:file_wrapper].open( file_path, 'w' ) do |f| - @test_counter = 1 - write_results( results, f ) - end - end - end - - private - - def write_results( results, stream ) - write_header( stream ) - write_failures( results[:failures], stream ) - write_tests( results[:successes], stream, 'SuccessfulTests' ) - write_tests( results[:ignores], stream, 'IgnoredTests' ) - write_statistics( results[:counts], stream ) - write_footer( stream ) - end - - def write_header( stream ) - stream.puts "<?xml version='1.0' encoding='utf-8' ?>" - stream.puts "<TestRun>" - end - - def write_failures( results, stream ) - if (results.size == 0) - stream.puts "\t<FailedTests/>" - return - end - - stream.puts "\t<FailedTests>" - - results.each do |result| - result[:collection].each do |item| - filename = File.join( result[:source][:path], result[:source][:file] ) - - stream.puts "\t\t<FailedTest id=\"#{@test_counter}\">" - stream.puts "\t\t\t<Name>#{filename}::#{item[:test]}</Name>" - stream.puts "\t\t\t<FailureType>Assertion</FailureType>" - stream.puts "\t\t\t<Location>" - stream.puts "\t\t\t\t<File>#{filename}</File>" - stream.puts "\t\t\t\t<Line>#{item[:line]}</Line>" - stream.puts "\t\t\t</Location>" - stream.puts "\t\t\t<Message>#{item[:message]}</Message>" - stream.puts "\t\t</Test>" - @test_counter += 1 - end - end - - stream.puts "\t</FailedTests>" - end - - def write_tests( results, stream, tag ) - if (results.size == 0) - stream.puts "\t<#{tag}/>" - return - end - - stream.puts "\t<#{tag}>" - - results.each do |result| - result[:collection].each do |item| - stream.puts "\t\t<Test id=\"#{@test_counter}\">" - stream.puts "\t\t\t<Name>#{File.join( result[:source][:path], result[:source][:file] )}::#{item[:test]}</Name>" - stream.puts "\t\t</Test>" - @test_counter += 1 - end - end - - stream.puts "\t</#{tag}>" - end - - def write_statistics( counts, stream ) - stream.puts "\t<Statistics>" - stream.puts "\t\t<Tests>#{counts[:total]}</Tests>" - stream.puts "\t\t<Ignores>#{counts[:ignored]}</Ignores>" - stream.puts "\t\t<FailuresTotal>#{counts[:failed]}</FailuresTotal>" - stream.puts "\t\t<Errors>0</Errors>" - stream.puts "\t\t<Failures>#{counts[:failed]}</Failures>" - stream.puts "\t</Statistics>" - end - - def write_footer( stream ) - stream.puts "</TestRun>" - end - -end \ No newline at end of file diff --git a/vendor/ceedling/release/build.info b/vendor/ceedling/release/build.info deleted file mode 100644 index d41688c..0000000 --- a/vendor/ceedling/release/build.info +++ /dev/null @@ -1,2 +0,0 @@ -226 - diff --git a/vendor/ceedling/release/version.info b/vendor/ceedling/release/version.info deleted file mode 100644 index 688abaa..0000000 --- a/vendor/ceedling/release/version.info +++ /dev/null @@ -1 +0,0 @@ -0.10 \ No newline at end of file diff --git a/vendor/ceedling/vendor/c_exception/lib/CException.c b/vendor/ceedling/vendor/c_exception/lib/CException.c index 97e1b41..fdff8f4 100644 --- a/vendor/ceedling/vendor/c_exception/lib/CException.c +++ b/vendor/ceedling/vendor/c_exception/lib/CException.c @@ -1,6 +1,9 @@ #include "CException.h" -volatile CEXCEPTION_FRAME_T CExceptionFrames[CEXCEPTION_NUM_ID] = { 0 }; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" +volatile CEXCEPTION_FRAME_T CExceptionFrames[CEXCEPTION_NUM_ID] = {{ 0 }}; +#pragma GCC diagnostic pop //------------------------------------------------------------------------------------------ // Throw @@ -13,14 +16,14 @@ void Throw(CEXCEPTION_T ExceptionID) { longjmp(*CExceptionFrames[MY_ID].pFrame, 1); } - CEXCEPTION_NO_CATCH_HANDLER(MY_ID); + CEXCEPTION_NO_CATCH_HANDLER(ExceptionID); } //------------------------------------------------------------------------------------------ // Explanation of what it's all for: //------------------------------------------------------------------------------------------ /* -#define Try +#define Try { <- give us some local scope. most compilers are happy with this jmp_buf *PrevFrame, NewFrame; <- prev frame points to the last try block's frame. new frame gets created on stack for this Try block unsigned int MY_ID = CEXCEPTION_GET_ID; <- look up this task's id for use in frame array. always 0 if single-tasking @@ -30,12 +33,12 @@ void Throw(CEXCEPTION_T ExceptionID) if (setjmp(NewFrame) == 0) { <- do setjmp. it returns 1 if longjump called, otherwise 0 if (&PrevFrame) <- this is here to force proper scoping. it requires braces or a single line to be but after Try, otherwise won't compile. This is always true at this point. -#define Catch(e) +#define Catch(e) else { } <- this also forces proper scoping. Without this they could stick their own 'else' in and it would get ugly CExceptionFrames[MY_ID].Exception = CEXCEPTION_NONE; <- no errors happened, so just set the exception id to NONE (in case it was corrupted) - } + } else <- an exception occurred - { e = CExceptionFrames[MY_ID].Exception; e=e;} <- assign the caught exception id to the variable passed in. + { e = CExceptionFrames[MY_ID].Exception; e=e;} <- assign the caught exception id to the variable passed in. CExceptionFrames[MY_ID].pFrame = PrevFrame; <- make the pointer in the array point at the previous frame again, as if NewFrame never existed. } <- finish off that local scope we created to have our own variables if (CExceptionFrames[CEXCEPTION_GET_ID].Exception != CEXCEPTION_NONE) <- start the actual 'catch' processing if we have an exception id saved away diff --git a/vendor/ceedling/vendor/c_exception/lib/CException.h b/vendor/ceedling/vendor/c_exception/lib/CException.h index 7e37429..be9e186 100644 --- a/vendor/ceedling/vendor/c_exception/lib/CException.h +++ b/vendor/ceedling/vendor/c_exception/lib/CException.h @@ -9,6 +9,11 @@ extern "C" #endif +#define CEXCEPTION_VERSION_MAJOR 1 +#define CEXCEPTION_VERSION_MINOR 3 +#define CEXCEPTION_VERSION_BUILD 3 +#define CEXCEPTION_VERSION ((CEXCEPTION_VERSION_MAJOR << 16) | (CEXCEPTION_VERSION_MINOR << 8) | CEXCEPTION_VERSION_BUILD) + //To Use CException, you have a number of options: //1. Just include it and run with the defaults //2. Define any of the following symbols at the command line to override them @@ -44,6 +49,20 @@ extern "C" #define CEXCEPTION_NO_CATCH_HANDLER(id) #endif +//These hooks allow you to inject custom code into places, particularly useful for saving and restoring additional state +#ifndef CEXCEPTION_HOOK_START_TRY +#define CEXCEPTION_HOOK_START_TRY +#endif +#ifndef CEXCEPTION_HOOK_HAPPY_TRY +#define CEXCEPTION_HOOK_HAPPY_TRY +#endif +#ifndef CEXCEPTION_HOOK_AFTER_TRY +#define CEXCEPTION_HOOK_AFTER_TRY +#endif +#ifndef CEXCEPTION_HOOK_START_CATCH +#define CEXCEPTION_HOOK_START_CATCH +#endif + //exception frame structures typedef struct { jmp_buf* pFrame; @@ -58,26 +77,36 @@ extern volatile CEXCEPTION_FRAME_T CExceptionFrames[]; { \ jmp_buf *PrevFrame, NewFrame; \ unsigned int MY_ID = CEXCEPTION_GET_ID; \ - PrevFrame = CExceptionFrames[CEXCEPTION_GET_ID].pFrame; \ + PrevFrame = CExceptionFrames[MY_ID].pFrame; \ CExceptionFrames[MY_ID].pFrame = (jmp_buf*)(&NewFrame); \ CExceptionFrames[MY_ID].Exception = CEXCEPTION_NONE; \ + CEXCEPTION_HOOK_START_TRY; \ if (setjmp(NewFrame) == 0) { \ - if (&PrevFrame) + if (1) //Catch (see C file for explanation) #define Catch(e) \ else { } \ CExceptionFrames[MY_ID].Exception = CEXCEPTION_NONE; \ + CEXCEPTION_HOOK_HAPPY_TRY; \ } \ else \ - { e = CExceptionFrames[MY_ID].Exception; e=e; } \ + { \ + e = CExceptionFrames[MY_ID].Exception; \ + (void)e; \ + CEXCEPTION_HOOK_START_CATCH; \ + } \ CExceptionFrames[MY_ID].pFrame = PrevFrame; \ + CEXCEPTION_HOOK_AFTER_TRY; \ } \ if (CExceptionFrames[CEXCEPTION_GET_ID].Exception != CEXCEPTION_NONE) //Throw an Error void Throw(CEXCEPTION_T ExceptionID); +//Just exit the Try block and skip the Catch. +#define ExitTry() Throw(CEXCEPTION_NONE) + #ifdef __cplusplus } // extern "C" #endif diff --git a/vendor/ceedling/vendor/c_exception/lib/meson.build b/vendor/ceedling/vendor/c_exception/lib/meson.build new file mode 100644 index 0000000..2770122 --- /dev/null +++ b/vendor/ceedling/vendor/c_exception/lib/meson.build @@ -0,0 +1,11 @@ +# +# build script written by : Michael Brockus. +# github repo author: Mark VanderVoord. +# +# license: MIT +# +cexception_dir = include_directories('.') + +cexception_lib = static_library(meson.project_name(), + files('CException.c'), + include_directories : cexception_dir) diff --git a/vendor/ceedling/vendor/c_exception/release/build.info b/vendor/ceedling/vendor/c_exception/release/build.info deleted file mode 100644 index b5794c5..0000000 --- a/vendor/ceedling/vendor/c_exception/release/build.info +++ /dev/null @@ -1,2 +0,0 @@ -16 - diff --git a/vendor/ceedling/vendor/c_exception/release/version.info b/vendor/ceedling/vendor/c_exception/release/version.info deleted file mode 100644 index f99e724..0000000 --- a/vendor/ceedling/vendor/c_exception/release/version.info +++ /dev/null @@ -1,2 +0,0 @@ -1.2 - diff --git a/vendor/ceedling/vendor/cmock/config/production_environment.rb b/vendor/ceedling/vendor/cmock/config/production_environment.rb index 915582b..082b63f 100644 --- a/vendor/ceedling/vendor/cmock/config/production_environment.rb +++ b/vendor/ceedling/vendor/cmock/config/production_environment.rb @@ -2,13 +2,11 @@ # CMock Project - Automatic Mock Generation for C # Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams # [Released under MIT License. Please refer to license.txt for details] -# ========================================== - +# ========================================== + # Setup our load path: -[ - 'lib', +[ + 'lib' ].each do |dir| - $LOAD_PATH.unshift( File.join( File.expand_path(File.dirname(__FILE__)) + '/../', dir) ) + $:.unshift(File.join(__dir__ + '/../', dir)) end - - diff --git a/vendor/ceedling/vendor/cmock/config/test_environment.rb b/vendor/ceedling/vendor/cmock/config/test_environment.rb index 442e110..aeae3a3 100644 --- a/vendor/ceedling/vendor/cmock/config/test_environment.rb +++ b/vendor/ceedling/vendor/cmock/config/test_environment.rb @@ -2,15 +2,15 @@ # CMock Project - Automatic Mock Generation for C # Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams # [Released under MIT License. Please refer to license.txt for details] -# ========================================== +# ========================================== # Setup our load path: -[ - 'lib', - 'vendor/behaviors/lib', - 'vendor/hardmock/lib', - 'vendor/unity/auto/', - 'test/system/' +[ + './lib', + './vendor/behaviors/lib', + './vendor/hardmock/lib', + './vendor/unity/auto/', + './test/system/' ].each do |dir| - $LOAD_PATH.unshift( File.join( File.expand_path(File.dirname(__FILE__) + "/../"), dir) ) + $:.unshift(File.join(File.expand_path(File.dirname(__FILE__) + '/../'), dir)) end diff --git a/vendor/ceedling/vendor/cmock/lib/cmock.rb b/vendor/ceedling/vendor/cmock/lib/cmock.rb index e332351..72f8641 100644 --- a/vendor/ceedling/vendor/cmock/lib/cmock.rb +++ b/vendor/ceedling/vendor/cmock/lib/cmock.rb @@ -2,64 +2,110 @@ # CMock Project - Automatic Mock Generation for C # Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams # [Released under MIT License. Please refer to license.txt for details] -# ========================================== +# ========================================== -[ "../config/production_environment", - "cmock_header_parser", - "cmock_generator", - "cmock_file_writer", - "cmock_config", - "cmock_plugin_manager", - "cmock_generator_utils", - "cmock_unityhelper_parser"].each {|req| require "#{File.expand_path(File.dirname(__FILE__))}/#{req}"} +['../config/production_environment', + 'cmock_header_parser', + 'cmock_generator', + 'cmock_file_writer', + 'cmock_config', + 'cmock_plugin_manager', + 'cmock_generator_utils', + 'cmock_unityhelper_parser'].each { |req| require "#{__dir__}/#{req}" } class CMock - - def initialize(options=nil) - cm_config = CMockConfig.new(options) + def initialize(options = nil) + cm_config = CMockConfig.new(options) cm_unityhelper = CMockUnityHelperParser.new(cm_config) cm_writer = CMockFileWriter.new(cm_config) - cm_gen_utils = CMockGeneratorUtils.new(cm_config, {:unity_helper => cm_unityhelper}) + cm_gen_utils = CMockGeneratorUtils.new(cm_config, + :unity_helper => cm_unityhelper) cm_gen_plugins = CMockPluginManager.new(cm_config, cm_gen_utils) @cm_parser = CMockHeaderParser.new(cm_config) - @cm_generator = CMockGenerator.new(cm_config, cm_writer, cm_gen_utils, cm_gen_plugins) + @cm_generator = CMockGenerator.new(cm_config, cm_writer, cm_gen_utils, + cm_gen_plugins) @silent = (cm_config.verbosity < 2) end - - def setup_mocks(files) + + def setup_mocks(files, folder = nil) [files].flatten.each do |src| - generate_mock src + generate_mock(src, folder) + end + end + + def setup_skeletons(files) + [files].flatten.each do |src| + generate_skeleton src end end private ############################### - def generate_mock(src) - name = File.basename(src, '.h') + def generate_mock(src, folder) + name = File.basename(src, '.*') + ext = File.extname(src) puts "Creating mock for #{name}..." unless @silent - @cm_generator.create_mock(name, @cm_parser.parse(name, File.read(src))) + @cm_generator.create_mock(name, @cm_parser.parse(name, File.read(src)), ext, folder) + end + + def generate_skeleton(src) + name = File.basename(src, '.*') + puts "Creating skeleton for #{name}..." unless @silent + @cm_generator.create_skeleton(name, @cm_parser.parse(name, File.read(src))) end end - # Command Line Support ############################### - -if ($0 == __FILE__) +def option_maker(options, key, val) + options ||= {} + options[key.to_sym] = + if val.chr == ':' + val[1..-1].to_sym + elsif val.include? ';' + val.split(';') + elsif val == 'true' + true + elsif val == 'false' + false + elsif val =~ /^\d+$/ + val.to_i + else + val + end + options +end + +# Command Line Support ############################### + +if $0 == __FILE__ usage = "usage: ruby #{__FILE__} (-oOptionsFile) File(s)ToMock" - - if (!ARGV[0]) + + unless ARGV[0] puts usage exit 1 end - - options = nil + + options = {} filelist = [] ARGV.each do |arg| - if (arg =~ /^-o(\w*)/) - options = arg.gsub(/^-o/,'') + if arg =~ /^-o\"?([a-zA-Z0-9@._\\\/:\s]+)\"?/ + options.merge! CMockConfig.load_config_file_from_yaml(arg.gsub(/^-o/, '')) + elsif arg == '--skeleton' + options[:skeleton] = true + elsif arg =~ /^--strippables=\"?(.*)\"?/ + # --strippables are dealt with separately since the user is allowed to + # enter any valid regular expression as argument + options = option_maker(options, 'strippables', Regexp.last_match(1)) + elsif arg =~ /^--([a-zA-Z0-9._\\\/:\s]+)=\"?([a-zA-Z0-9._\-\\\/:\s\;]*)\"?/x + options = option_maker(options, Regexp.last_match(1), + Regexp.last_match(2)) else filelist << arg end end - - CMock.new(options).setup_mocks(filelist) -end \ No newline at end of file + + if options[:skeleton] + CMock.new(options).setup_skeletons(filelist) + else + CMock.new(options).setup_mocks(filelist) + end +end diff --git a/vendor/ceedling/vendor/cmock/lib/cmock_config.rb b/vendor/ceedling/vendor/cmock/lib/cmock_config.rb index ed9864b..716a0c5 100644 --- a/vendor/ceedling/vendor/cmock/lib/cmock_config.rb +++ b/vendor/ceedling/vendor/cmock/lib/cmock_config.rb @@ -2,87 +2,128 @@ # CMock Project - Automatic Mock Generation for C # Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams # [Released under MIT License. Please refer to license.txt for details] -# ========================================== +# ========================================== class CMockConfig - - CMockDefaultOptions = - { - :framework => :unity, - :mock_path => 'mocks', - :mock_prefix => 'Mock', - :plugins => [], - :strippables => ['(?:__attribute__\s*\(+.*?\)+)'], - :attributes => ['__ramfunc', '__irq', '__fiq', 'register', 'extern'], - :c_calling_conventions => ['__stdcall', '__cdecl', '__fastcall'], - :enforce_strict_ordering => false, - :unity_helper_path => false, - :treat_as => {}, - :treat_as_void => [], - :memcmp_if_unknown => true, - :when_no_prototypes => :warn, #the options being :ignore, :warn, or :error - :when_ptr => :compare_data, #the options being :compare_ptr, :compare_data, or :smart - :verbosity => 2, #the options being 0 errors only, 1 warnings and errors, 2 normal info, 3 verbose - :treat_externs => :exclude, #the options being :include or :exclude - :ignore => :args_and_calls, #the options being :args_and_calls or :args_only - :callback_include_count => true, - :callback_after_arg_check => false, - :includes => nil, - :includes_h_pre_orig_header => nil, - :includes_h_post_orig_header => nil, - :includes_c_pre_header => nil, - :includes_c_post_header => nil - } - - def initialize(options=nil) - case(options) - when NilClass then options = CMockDefaultOptions.clone - when String then options = CMockDefaultOptions.clone.merge(load_config_file_from_yaml(options)) - when Hash then options = CMockDefaultOptions.clone.merge(options) - else raise "If you specify arguments, it should be a filename or a hash of options" + CMOCK_DEFAULT_OPTIONS = + { + :framework => :unity, + :mock_path => 'mocks', + :mock_prefix => 'Mock', + :mock_suffix => '', + :skeleton_path => '', + :weak => '', + :subdir => nil, + :plugins => [], + :strippables => ['(?:__attribute__\s*\(+.*?\)+)'], + :attributes => %w[__ramfunc __irq __fiq register extern], + :c_calling_conventions => %w[__stdcall __cdecl __fastcall], + :enforce_strict_ordering => false, + :fail_on_unexpected_calls => true, + :unity_helper_path => false, + :treat_as => {}, + :treat_as_array => {}, + :treat_as_void => [], + :memcmp_if_unknown => true, + :when_no_prototypes => :warn, # the options being :ignore, :warn, or :error + :when_ptr => :compare_data, # the options being :compare_ptr, :compare_data, or :smart + :verbosity => 2, # the options being 0 errors only, 1 warnings and errors, 2 normal info, 3 verbose + :treat_externs => :exclude, # the options being :include or :exclude + :treat_inlines => :exclude, # the options being :include or :exclude + :callback_include_count => true, + :callback_after_arg_check => false, + :includes => nil, + :includes_h_pre_orig_header => nil, + :includes_h_post_orig_header => nil, + :includes_c_pre_header => nil, + :includes_c_post_header => nil, + :orig_header_include_fmt => '#include "%s"', + :array_size_type => [], + :array_size_name => 'size|len', + :skeleton => false, + :exclude_setjmp_h => false, + + # Format to look for inline functions. + # This is a combination of "static" and "inline" keywords ("static inline", "inline static", "inline", "static") + # There are several possibilities: + # - sometimes they appear together, sometimes individually, + # - The keywords can appear before or after the return type (this is a compiler warning but people do weird stuff), + # so we check for word boundaries when searching for them + # - We first remove "static inline" combinations and boil down to single inline or static statements + :inline_function_patterns => ['(static\s+inline|inline\s+static)\s*', '(\bstatic\b|\binline\b)\s*'] # Last part (\s*) is just to remove whitespaces (only to prettify the output) + }.freeze + + def initialize(options = nil) + case options + when NilClass then options = CMOCK_DEFAULT_OPTIONS.dup + when String then options = CMOCK_DEFAULT_OPTIONS.dup.merge(load_config_file_from_yaml(options)) + when Hash then options = CMOCK_DEFAULT_OPTIONS.dup.merge(options) + else raise 'If you specify arguments, it should be a filename or a hash of options' end - - #do some quick type verification - [:plugins, :attributes, :treat_as_void].each do |opt| - unless (options[opt].class == Array) + + # do some quick type verification + %i[plugins attributes treat_as_void].each do |opt| + unless options[opt].class == Array options[opt] = [] - puts "WARNING: :#{opt.to_s} should be an array." unless (options[:verbosity] < 1) + puts "WARNING: :#{opt} should be an array." unless options[:verbosity] < 1 end end - [:includes, :includes_h_pre_orig_header, :includes_h_post_orig_header, :includes_c_pre_header, :includes_c_post_header].each do |opt| - unless (options[opt].nil? or (options[opt].class == Array)) + %i[includes includes_h_pre_orig_header includes_h_post_orig_header includes_c_pre_header includes_c_post_header].each do |opt| + unless options[opt].nil? || (options[opt].class == Array) options[opt] = [] - puts "WARNING: :#{opt.to_s} should be an array." unless (options[:verbosity] < 1) + puts "WARNING: :#{opt} should be an array." unless options[:verbosity] < 1 end end options[:unity_helper_path] ||= options[:unity_helper] + options[:unity_helper_path] = [options[:unity_helper_path]] if options[:unity_helper_path].is_a? String + + if options[:unity_helper_path] + require 'pathname' + includes1 = options[:includes_c_post_header] || [] + includes2 = options[:unity_helper_path].map do |path| + Pathname(path).relative_path_from(Pathname(options[:mock_path])).to_s + end + options[:includes_c_post_header] = (includes1 + includes2).uniq + end + options[:plugins].compact! - options[:plugins].map! {|p| p.to_sym} + options[:plugins].map!(&:to_sym) @options = options - - treat_as_map = standard_treat_as_map()#.clone + + treat_as_map = standard_treat_as_map # .clone treat_as_map.merge!(@options[:treat_as]) @options[:treat_as] = treat_as_map - - @options.each_key { |key| eval("def #{key.to_s}() return @options[:#{key.to_s}] end") } + + @options.each_key do |key| + unless methods.include?(key) + eval("def #{key}() return @options[:#{key}] end") + end + end + end + + def load_config_file_from_yaml(yaml_filename) + self.class.load_config_file_from_yaml yaml_filename end - - def load_config_file_from_yaml yaml_filename + + def self.load_config_file_from_yaml(yaml_filename) require 'yaml' require 'fileutils' YAML.load_file(yaml_filename)[:cmock] end - - def set_path(path) - @src_path = path + + def path(new_path) + @src_path = new_path end - + def load_unity_helper - return File.new(@options[:unity_helper_path]).read if (@options[:unity_helper_path]) - return nil + return nil unless @options[:unity_helper_path] + + @options[:unity_helper_path].inject('') do |unity_helper, filename| + unity_helper + "\n" + File.new(filename).read + end end - def standard_treat_as_map + def standard_treat_as_map { 'int' => 'INT', 'char' => 'INT8', @@ -107,7 +148,9 @@ def standard_treat_as_map 'uint32_t' => 'HEX32', 'UINT32' => 'HEX32', 'UINT32_T' => 'HEX32', - 'void*' => 'PTR', + 'void*' => 'HEX8_ARRAY', + 'void const*' => 'HEX8_ARRAY', + 'const void*' => 'HEX8_ARRAY', 'unsigned short' => 'HEX16', 'uint16' => 'HEX16', 'uint16_t' => 'HEX16', @@ -119,6 +162,8 @@ def standard_treat_as_map 'UINT8' => 'HEX8', 'UINT8_T' => 'HEX8', 'char*' => 'STRING', + 'char const*' => 'STRING', + 'const char*' => 'STRING', 'pCHAR' => 'STRING', 'cstring' => 'STRING', 'CSTRING' => 'STRING', diff --git a/vendor/ceedling/vendor/cmock/lib/cmock_file_writer.rb b/vendor/ceedling/vendor/cmock/lib/cmock_file_writer.rb index 63faee5..f30c44b 100644 --- a/vendor/ceedling/vendor/cmock/lib/cmock_file_writer.rb +++ b/vendor/ceedling/vendor/cmock/lib/cmock_file_writer.rb @@ -2,32 +2,46 @@ # CMock Project - Automatic Mock Generation for C # Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams # [Released under MIT License. Please refer to license.txt for details] -# ========================================== +# ========================================== class CMockFileWriter - attr_reader :config def initialize(config) @config = config end - def create_file(filename) + def create_subdir(subdir) + require 'fileutils' + FileUtils.mkdir_p "#{@config.mock_path}/" unless Dir.exist?("#{@config.mock_path}/") + FileUtils.mkdir_p "#{@config.mock_path}/#{subdir + '/' if subdir}" if subdir && !Dir.exist?("#{@config.mock_path}/#{subdir + '/' if subdir}") + end + + def create_file(filename, subdir) raise "Where's the block of data to create?" unless block_given? - full_file_name_temp = "#{@config.mock_path}/#{filename}.new" - full_file_name_done = "#{@config.mock_path}/#{filename}" + + full_file_name_temp = "#{@config.mock_path}/#{subdir + '/' if subdir}#{filename}.new" + full_file_name_done = "#{@config.mock_path}/#{subdir + '/' if subdir}#{filename}" File.open(full_file_name_temp, 'w') do |file| yield(file, filename) end update_file(full_file_name_done, full_file_name_temp) end - + + def append_file(filename, subdir) + raise "Where's the block of data to create?" unless block_given? + + full_file_name = "#{@config.skeleton_path}/#{subdir + '/' if subdir}#{filename}" + File.open(full_file_name, 'a') do |file| + yield(file, filename) + end + end + private ################################### - + def update_file(dest, src) require 'fileutils' - FileUtils.rm(dest) if (File.exist?(dest)) - FileUtils.cp(src, dest) - FileUtils.rm(src) + FileUtils.rm(dest, :force => true) + FileUtils.mv(src, dest) end end diff --git a/vendor/ceedling/vendor/cmock/lib/cmock_generator.rb b/vendor/ceedling/vendor/cmock/lib/cmock_generator.rb index 7cd0eea..6ed5110 100644 --- a/vendor/ceedling/vendor/cmock/lib/cmock_generator.rb +++ b/vendor/ceedling/vendor/cmock/lib/cmock_generator.rb @@ -2,118 +2,232 @@ # CMock Project - Automatic Mock Generation for C # Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams # [Released under MIT License. Please refer to license.txt for details] -# ========================================== - -$here = File.dirname __FILE__ +# ========================================== class CMockGenerator + attr_accessor :config, :file_writer, :module_name, :module_ext, :clean_mock_name, :mock_name, :utils, :plugins, :weak, :ordered - attr_accessor :config, :file_writer, :module_name, :mock_name, :utils, :plugins, :ordered - def initialize(config, file_writer, utils, plugins) @file_writer = file_writer @utils = utils @plugins = plugins @config = config @prefix = @config.mock_prefix - @ordered = @config.enforce_strict_ordering - @framework = @config.framework.to_s - - @includes_h_pre_orig_header = (@config.includes || @config.includes_h_pre_orig_header || []).map{|h| h =~ /</ ? h : "\"#{h}\""} - @includes_h_post_orig_header = (@config.includes_h_post_orig_header || []).map{|h| h =~ /</ ? h : "\"#{h}\""} - @includes_c_pre_header = (@config.includes_c_pre_header || []).map{|h| h =~ /</ ? h : "\"#{h}\""} - @includes_c_post_header = (@config.includes_c_post_header || []).map{|h| h =~ /</ ? h : "\"#{h}\""} - end - - def create_mock(module_name, parsed_stuff) - @module_name = module_name - @mock_name = @prefix + @module_name - create_mock_header_file(parsed_stuff) - create_mock_source_file(parsed_stuff) - end - + @suffix = @config.mock_suffix + @weak = @config.weak + @include_inline = @config.treat_inlines + @ordered = @config.enforce_strict_ordering + @framework = @config.framework.to_s + @fail_on_unexpected_calls = @config.fail_on_unexpected_calls + @exclude_setjmp_h = @config.exclude_setjmp_h + @subdir = @config.subdir + + @includes_h_pre_orig_header = (@config.includes || @config.includes_h_pre_orig_header || []).map { |h| h =~ /</ ? h : "\"#{h}\"" } + @includes_h_post_orig_header = (@config.includes_h_post_orig_header || []).map { |h| h =~ /</ ? h : "\"#{h}\"" } + @includes_c_pre_header = (@config.includes_c_pre_header || []).map { |h| h =~ /</ ? h : "\"#{h}\"" } + @includes_c_post_header = (@config.includes_c_post_header || []).map { |h| h =~ /</ ? h : "\"#{h}\"" } + + here = File.dirname __FILE__ + unity_path_in_ceedling = "#{here}/../../unity" # path to Unity from within Ceedling + unity_path_in_cmock = "#{here}/../vendor/unity" # path to Unity from within CMock + # path to Unity as specified by env var + unity_path_in_env = ENV.key?('UNITY_DIR') ? File.expand_path(ENV.fetch('UNITY_DIR')) : nil + + if unity_path_in_env && File.exist?(unity_path_in_env) + require "#{unity_path_in_env}/auto/type_sanitizer" + elsif File.exist? unity_path_in_ceedling + require "#{unity_path_in_ceedling}/auto/type_sanitizer" + elsif File.exist? unity_path_in_cmock + require "#{unity_path_in_cmock}/auto/type_sanitizer" + else + raise 'Failed to find an instance of Unity to pull in type_sanitizer module!' + end + end + + def create_mock(module_name, parsed_stuff, module_ext = nil, folder = nil) + # determine the name for our new mock + mock_name = @prefix + module_name + @suffix + + # determine the folder our mock will reside + mock_folder = if folder && @subdir + File.join(@subdir, folder) + elsif @subdir + @subdir + else + folder + end + + # adds a trailing slash to the folder output + mock_folder = File.join(mock_folder, '') if mock_folder + + # create out mock project from incoming data + mock_project = { + :module_name => module_name, + :module_ext => (module_ext || '.h'), + :mock_name => mock_name, + :clean_name => TypeSanitizer.sanitize_c_identifier(mock_name), + :folder => mock_folder, + :parsed_stuff => parsed_stuff, + :skeleton => false + } + + create_mock_subdir(mock_project) + create_mock_header_file(mock_project) + create_mock_source_file(mock_project) + end + + def create_skeleton(module_name, parsed_stuff) + mock_project = { + :module_name => module_name, + :module_ext => '.h', + :parsed_stuff => parsed_stuff, + :skeleton => true + } + + create_skeleton_source_file(mock_project) + end + private if $ThisIsOnlyATest.nil? ############################## - - def create_mock_header_file(parsed_stuff) - @file_writer.create_file(@mock_name + ".h") do |file, filename| - create_mock_header_header(file, filename) - create_mock_header_service_call_declarations(file) - create_typedefs(file, parsed_stuff[:typedefs]) - parsed_stuff[:functions].each do |function| + + def create_mock_subdir(mock_project) + @file_writer.create_subdir(mock_project[:folder]) + end + + def create_using_statement(file, function) + file << "using namespace #{function[:namespace].join('::')};\n" unless function[:namespace].empty? + end + + def create_mock_header_file(mock_project) + if @include_inline == :include + @file_writer.create_file(mock_project[:module_name] + (mock_project[:module_ext]), mock_project[:folder]) do |file, _filename| + file << mock_project[:parsed_stuff][:normalized_source] + end + end + + @file_writer.create_file(mock_project[:mock_name] + mock_project[:module_ext], mock_project[:folder]) do |file, filename| + create_mock_header_header(file, filename, mock_project) + create_mock_header_service_call_declarations(file, mock_project) + create_typedefs(file, mock_project) + mock_project[:parsed_stuff][:functions].each do |function| + create_using_statement(file, function) file << @plugins.run(:mock_function_declarations, function) end create_mock_header_footer(file) end end - def create_mock_source_file(parsed_stuff) - @file_writer.create_file(@mock_name + ".c") do |file, filename| - create_source_header_section(file, filename) - create_instance_structure(file, parsed_stuff[:functions]) + def create_mock_source_file(mock_project) + @file_writer.create_file(mock_project[:mock_name] + '.c', mock_project[:folder]) do |file, filename| + create_source_header_section(file, filename, mock_project) + create_instance_structure(file, mock_project) create_extern_declarations(file) - create_mock_verify_function(file, parsed_stuff[:functions]) - create_mock_init_function(file) - create_mock_destroy_function(file, parsed_stuff[:functions]) - parsed_stuff[:functions].each do |function| + create_mock_verify_function(file, mock_project) + create_mock_init_function(file, mock_project) + create_mock_destroy_function(file, mock_project) + mock_project[:parsed_stuff][:functions].each do |function| create_mock_implementation(file, function) create_mock_interfaces(file, function) end end end - - def create_mock_header_header(file, filename) - define_name = filename.gsub(/\.h/, "_h").upcase - orig_filename = filename.gsub(@config.mock_prefix, "") + + def create_skeleton_source_file(mock_project) + filename = "#{@config.mock_path}/#{@subdir + '/' if @subdir}#{mock_project[:module_name]}.c" + existing = File.exist?(filename) ? File.read(filename) : '' + @file_writer.append_file(mock_project[:module_name] + '.c', @subdir) do |file, fullname| + blank_project = mock_project.clone + blank_project[:parsed_stuff] = { :functions => [] } + create_source_header_section(file, fullname, blank_project) if existing.empty? + mock_project[:parsed_stuff][:functions].each do |function| + create_function_skeleton(file, function, existing) + end + end + end + + def create_mock_header_header(file, _filename, mock_project) + define_name = mock_project[:clean_name].upcase + orig_filename = (mock_project[:folder] || '') + mock_project[:module_name] + mock_project[:module_ext] file << "/* AUTOGENERATED FILE. DO NOT EDIT. */\n" - file << "#ifndef _#{define_name}\n" - file << "#define _#{define_name}\n\n" - @includes_h_pre_orig_header.each {|inc| file << "#include #{inc}\n"} - file << "#include \"#{orig_filename}\"\n" - @includes_h_post_orig_header.each {|inc| file << "#include #{inc}\n"} + file << "#ifndef _#{define_name}_H\n" + file << "#define _#{define_name}_H\n\n" + file << "#include \"#{@framework}.h\"\n" + @includes_h_pre_orig_header.each { |inc| file << "#include #{inc}\n" } + file << @config.orig_header_include_fmt.gsub(/%s/, orig_filename.to_s) + "\n" + @includes_h_post_orig_header.each { |inc| file << "#include #{inc}\n" } plugin_includes = @plugins.run(:include_files) - file << plugin_includes if (!plugin_includes.empty?) + file << plugin_includes unless plugin_includes.empty? + file << "\n" + file << "/* Ignore the following warnings, since we are copying code */\n" + file << "#if defined(__GNUC__) && !defined(__ICC) && !defined(__TMS470__)\n" + file << "#if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ > 6 || (__GNUC_MINOR__ == 6 && __GNUC_PATCHLEVEL__ > 0)))\n" + file << "#pragma GCC diagnostic push\n" + file << "#endif\n" + file << "#if !defined(__clang__)\n" + file << "#pragma GCC diagnostic ignored \"-Wpragmas\"\n" + file << "#endif\n" + file << "#pragma GCC diagnostic ignored \"-Wunknown-pragmas\"\n" + file << "#pragma GCC diagnostic ignored \"-Wduplicate-decl-specifier\"\n" + file << "#endif\n" file << "\n" end - - def create_typedefs(file, typedefs) + + def create_typedefs(file, mock_project) file << "\n" - typedefs.each {|typedef| file << "#{typedef}\n" } + mock_project[:parsed_stuff][:typedefs].each { |typedef| file << "#{typedef}\n" } file << "\n\n" end - def create_mock_header_service_call_declarations(file) - file << "void #{@mock_name}_Init(void);\n" - file << "void #{@mock_name}_Destroy(void);\n" - file << "void #{@mock_name}_Verify(void);\n\n" + def create_mock_header_service_call_declarations(file, mock_project) + file << "void #{mock_project[:clean_name]}_Init(void);\n" + file << "void #{mock_project[:clean_name]}_Destroy(void);\n" + file << "void #{mock_project[:clean_name]}_Verify(void);\n\n" end def create_mock_header_footer(header) - header << "\n#endif\n" + header << "\n" + header << "#if defined(__GNUC__) && !defined(__ICC) && !defined(__TMS470__)\n" + header << "#if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ > 6 || (__GNUC_MINOR__ == 6 && __GNUC_PATCHLEVEL__ > 0)))\n" + header << "#pragma GCC diagnostic pop\n" + header << "#endif\n" + header << "#endif\n" + header << "\n" + header << "#endif\n" end - - def create_source_header_section(file, filename) - header_file = filename.gsub(".c",".h") - file << "/* AUTOGENERATED FILE. DO NOT EDIT. */\n" + + def create_source_header_section(file, filename, mock_project) + header_file = (mock_project[:folder] || '') + filename.gsub('.c', mock_project[:module_ext]) + file << "/* AUTOGENERATED FILE. DO NOT EDIT. */\n" unless mock_project[:parsed_stuff][:functions].empty? file << "#include <string.h>\n" file << "#include <stdlib.h>\n" - file << "#include <setjmp.h>\n" - file << "#include \"#{@framework}.h\"\n" + unless @exclude_setjmp_h + file << "#include <setjmp.h>\n" + end file << "#include \"cmock.h\"\n" - @includes_c_pre_header.each {|inc| file << "#include #{inc}\n"} + @includes_c_pre_header.each { |inc| file << "#include #{inc}\n" } file << "#include \"#{header_file}\"\n" - @includes_c_post_header.each {|inc| file << "#include #{inc}\n"} + @includes_c_post_header.each { |inc| file << "#include #{inc}\n" } + file << "\n" + strs = [] + mock_project[:parsed_stuff][:functions].each do |func| + strs << func[:name] + func[:args].each { |arg| strs << arg[:name] } + end + strs.uniq.sort.each do |str| + file << "static const char* CMockString_#{str} = \"#{str}\";\n" + end file << "\n" end - - def create_instance_structure(file, functions) - functions.each do |function| + + def create_instance_structure(file, mock_project) + functions = mock_project[:parsed_stuff][:functions] + functions.each do |function| file << "typedef struct _CMOCK_#{function[:name]}_CALL_INSTANCE\n{\n" file << " UNITY_LINE_TYPE LineNumber;\n" file << @plugins.run(:instance_typedefs, function) file << "\n} CMOCK_#{function[:name]}_CALL_INSTANCE;\n\n" end - file << "static struct #{@mock_name}Instance\n{\n" - if (functions.size == 0) + file << "static struct #{mock_project[:clean_name]}Instance\n{\n" + if functions.empty? file << " unsigned char placeHolder;\n" end functions.each do |function| @@ -122,73 +236,133 @@ def create_instance_structure(file, functions) end file << "} Mock;\n\n" end - + def create_extern_declarations(file) - file << "extern jmp_buf AbortFrame;\n" - if (@ordered) + unless @exclude_setjmp_h + file << "extern jmp_buf AbortFrame;\n" + end + if @ordered file << "extern int GlobalExpectCount;\n" file << "extern int GlobalVerifyOrder;\n" end file << "\n" end - - def create_mock_verify_function(file, functions) - file << "void #{@mock_name}_Verify(void)\n{\n" - verifications = functions.collect {|function| @plugins.run(:mock_verify, function)}.join - file << " UNITY_LINE_TYPE cmock_line = TEST_LINE_NUM;\n" unless verifications.empty? - file << verifications + + def create_mock_verify_function(file, mock_project) + file << "void #{mock_project[:clean_name]}_Verify(void)\n{\n" + verifications = mock_project[:parsed_stuff][:functions].collect do |function| + v = @plugins.run(:mock_verify, function) + v.empty? ? v : [" call_instance = Mock.#{function[:name]}_CallInstance;\n", v] + end.join + unless verifications.empty? + file << " UNITY_LINE_TYPE cmock_line = TEST_LINE_NUM;\n" + file << " CMOCK_MEM_INDEX_TYPE call_instance;\n" + file << verifications + end file << "}\n\n" end - - def create_mock_init_function(file) - file << "void #{@mock_name}_Init(void)\n{\n" - file << " #{@mock_name}_Destroy();\n" + + def create_mock_init_function(file, mock_project) + file << "void #{mock_project[:clean_name]}_Init(void)\n{\n" + file << " #{mock_project[:clean_name]}_Destroy();\n" file << "}\n\n" end - - def create_mock_destroy_function(file, functions) - file << "void #{@mock_name}_Destroy(void)\n{\n" + + def create_mock_destroy_function(file, mock_project) + file << "void #{mock_project[:clean_name]}_Destroy(void)\n{\n" file << " CMock_Guts_MemFreeAll();\n" file << " memset(&Mock, 0, sizeof(Mock));\n" - file << functions.collect {|function| @plugins.run(:mock_destroy, function)}.join - if (@ordered) + file << mock_project[:parsed_stuff][:functions].collect { |function| @plugins.run(:mock_destroy, function) }.join + + unless @fail_on_unexpected_calls + file << mock_project[:parsed_stuff][:functions].collect { |function| @plugins.run(:mock_ignore, function) }.join + end + + if @ordered file << " GlobalExpectCount = 0;\n" file << " GlobalVerifyOrder = 0;\n" end file << "}\n\n" end - - def create_mock_implementation(file, function) - # prepare return value and arguments + + def create_mock_implementation(file, function) + # prepare return value and arguments function_mod_and_rettype = (function[:modifier].empty? ? '' : "#{function[:modifier]} ") + (function[:return][:type]) + (function[:c_calling_convention] ? " #{function[:c_calling_convention]}" : '') args_string = function[:args_string] - args_string += (", " + function[:var_arg]) unless (function[:var_arg].nil?) - + args_string += (', ' + function[:var_arg]) unless function[:var_arg].nil? + + # Encapsulate in namespace(s) if applicable + function[:namespace].each do |ns| + file << "namespace #{ns} {\n" + end + + # Determine class prefix (if any) + cls_pre = '' + unless function[:class].nil? + cls_pre = "#{function[:class]}::" + end + # Create mock function - file << "#{function_mod_and_rettype} #{function[:name]}(#{args_string})\n" + unless @weak.empty? + file << "#if defined (__IAR_SYSTEMS_ICC__)\n" + file << "#pragma weak #{function[:unscoped_name]}\n" + file << "#else\n" + file << "#{function_mod_and_rettype} #{function[:unscoped_name]}(#{args_string}) #{weak};\n" + file << "#endif\n\n" + end + file << "#{function_mod_and_rettype} #{cls_pre}#{function[:unscoped_name]}(#{args_string})\n" file << "{\n" file << " UNITY_LINE_TYPE cmock_line = TEST_LINE_NUM;\n" - file << " CMOCK_#{function[:name]}_CALL_INSTANCE* cmock_call_instance = (CMOCK_#{function[:name]}_CALL_INSTANCE*)CMock_Guts_GetAddressFor(Mock.#{function[:name]}_CallInstance);\n" + file << " CMOCK_#{function[:name]}_CALL_INSTANCE* cmock_call_instance;\n" + file << " UNITY_SET_DETAIL(CMockString_#{function[:name]});\n" + file << " cmock_call_instance = (CMOCK_#{function[:name]}_CALL_INSTANCE*)CMock_Guts_GetAddressFor(Mock.#{function[:name]}_CallInstance);\n" file << " Mock.#{function[:name]}_CallInstance = CMock_Guts_MemNext(Mock.#{function[:name]}_CallInstance);\n" file << @plugins.run(:mock_implementation_precheck, function) - file << " UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, \"Function '#{function[:name]}' called more times than expected.\");\n" + file << " UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringCalledMore);\n" file << " cmock_line = cmock_call_instance->LineNumber;\n" - if (@ordered) + if @ordered file << " if (cmock_call_instance->CallOrder > ++GlobalVerifyOrder)\n" - file << " UNITY_TEST_FAIL(cmock_line, \"Function '#{function[:name]}' called earlier than expected.\");\n" + file << " UNITY_TEST_FAIL(cmock_line, CMockStringCalledEarly);\n" file << " if (cmock_call_instance->CallOrder < GlobalVerifyOrder)\n" - file << " UNITY_TEST_FAIL(cmock_line, \"Function '#{function[:name]}' called later than expected.\");\n" - # file << " UNITY_TEST_ASSERT((cmock_call_instance->CallOrder == ++GlobalVerifyOrder), cmock_line, \"Out of order function calls. Function '#{function[:name]}'\");\n" + file << " UNITY_TEST_FAIL(cmock_line, CMockStringCalledLate);\n" end file << @plugins.run(:mock_implementation, function) - file << " return cmock_call_instance->ReturnVal;\n" unless (function[:return][:void?]) - file << "}\n\n" + file << " UNITY_CLR_DETAILS();\n" + file << " return cmock_call_instance->ReturnVal;\n" unless function[:return][:void?] + file << "}\n" + + # Close any namespace(s) opened above + function[:namespace].each do + file << "}\n" + end + + file << "\n" end - + def create_mock_interfaces(file, function) file << @utils.code_add_argument_loader(function) file << @plugins.run(:mock_interfaces, function) end + + def create_function_skeleton(file, function, existing) + # prepare return value and arguments + function_mod_and_rettype = (function[:modifier].empty? ? '' : "#{function[:modifier]} ") + + (function[:return][:type]) + + (function[:c_calling_convention] ? " #{function[:c_calling_convention]}" : '') + args_string = function[:args_string] + args_string += (', ' + function[:var_arg]) unless function[:var_arg].nil? + + decl = "#{function_mod_and_rettype} #{function[:name]}(#{args_string})" + + return if existing.include?(decl) + + file << "#{decl}\n" + file << "{\n" + file << " /*TODO: Implement Me!*/\n" + function[:args].each { |arg| file << " (void)#{arg[:name]};\n" } + file << " return (#{(function[:return][:type])})0;\n" unless function[:return][:void?] + file << "}\n\n" + end end diff --git a/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_array.rb b/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_array.rb index 25045a2..a9864ab 100644 --- a/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_array.rb +++ b/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_array.rb @@ -2,10 +2,9 @@ # CMock Project - Automatic Mock Generation for C # Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams # [Released under MIT License. Please refer to license.txt for details] -# ========================================== +# ========================================== class CMockGeneratorPluginArray - attr_reader :priority attr_accessor :config, :utils, :unity_helper, :ordered def initialize(config, utils) @@ -18,40 +17,47 @@ def initialize(config, utils) end def instance_typedefs(function) - function[:args].inject("") do |all, arg| - (arg[:ptr?]) ? all + " int Expected_#{arg[:name]}_Depth;\n" : all + function[:args].inject('') do |all, arg| + arg[:ptr?] ? all + " int Expected_#{arg[:name]}_Depth;\n" : all end end def mock_function_declarations(function) return nil unless function[:contains_ptr?] - args_call = function[:args].map{|m| m[:ptr?] ? "#{m[:name]}, #{m[:name]}_Depth" : "#{m[:name]}"}.join(', ') - args_string = function[:args].map{|m| m[:ptr?] ? "#{m[:type]} #{m[:name]}, int #{m[:name]}_Depth" : "#{m[:type]} #{m[:name]}"}.join(', ') - if (function[:return][:void?]) - return "#define #{function[:name]}_ExpectWithArray(#{args_call}) #{function[:name]}_CMockExpectWithArray(__LINE__, #{args_call})\n" + + + args_call = function[:args].map { |m| m[:ptr?] ? "#{m[:name]}, #{m[:name]}_Depth" : (m[:name]).to_s }.join(', ') + args_string = function[:args].map do |m| + type = @utils.arg_type_with_const(m) + m[:ptr?] ? "#{type} #{m[:name]}, int #{m[:name]}_Depth" : "#{type} #{m[:name]}" + end.join(', ') + if function[:return][:void?] + return "#define #{function[:name]}_ExpectWithArray(#{args_call}) #{function[:name]}_CMockExpectWithArray(__LINE__, #{args_call})\n" \ "void #{function[:name]}_CMockExpectWithArray(UNITY_LINE_TYPE cmock_line, #{args_string});\n" else - return "#define #{function[:name]}_ExpectWithArrayAndReturn(#{args_call}, cmock_retval) #{function[:name]}_CMockExpectWithArrayAndReturn(__LINE__, #{args_call}, cmock_retval)\n" + + return "#define #{function[:name]}_ExpectWithArrayAndReturn(#{args_call}, cmock_retval) #{function[:name]}_CMockExpectWithArrayAndReturn(__LINE__, #{args_call}, cmock_retval)\n" \ "void #{function[:name]}_CMockExpectWithArrayAndReturn(UNITY_LINE_TYPE cmock_line, #{args_string}, #{function[:return][:str]});\n" end end def mock_interfaces(function) return nil unless function[:contains_ptr?] + lines = [] func_name = function[:name] - args_string = function[:args].map{|m| m[:ptr?] ? "#{m[:type]} #{m[:name]}, int #{m[:name]}_Depth" : "#{m[:type]} #{m[:name]}"}.join(', ') - call_string = function[:args].map{|m| m[:ptr?] ? "#{m[:name]}, #{m[:name]}_Depth" : m[:name]}.join(', ') - if (function[:return][:void?]) - lines << "void #{func_name}_CMockExpectWithArray(UNITY_LINE_TYPE cmock_line, #{args_string})\n" - else - lines << "void #{func_name}_CMockExpectWithArrayAndReturn(UNITY_LINE_TYPE cmock_line, #{args_string}, #{function[:return][:str]})\n" - end + args_string = function[:args].map do |m| + type = @utils.arg_type_with_const(m) + m[:ptr?] ? "#{type} #{m[:name]}, int #{m[:name]}_Depth" : "#{type} #{m[:name]}" + end.join(', ') + call_string = function[:args].map { |m| m[:ptr?] ? "#{m[:name]}, #{m[:name]}_Depth" : m[:name] }.join(', ') + lines << if function[:return][:void?] + "void #{func_name}_CMockExpectWithArray(UNITY_LINE_TYPE cmock_line, #{args_string})\n" + else + "void #{func_name}_CMockExpectWithArrayAndReturn(UNITY_LINE_TYPE cmock_line, #{args_string}, #{function[:return][:str]})\n" + end lines << "{\n" lines << @utils.code_add_base_expectation(func_name) lines << " CMockExpectParameters_#{func_name}(cmock_call_instance, #{call_string});\n" - lines << " cmock_call_instance->ReturnVal = cmock_to_return;\n" unless (function[:return][:void?]) + lines << " cmock_call_instance->ReturnVal = cmock_to_return;\n" unless function[:return][:void?] lines << "}\n\n" end - end diff --git a/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_callback.rb b/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_callback.rb index f66539c..6ba8e9b 100644 --- a/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_callback.rb +++ b/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_callback.rb @@ -2,77 +2,87 @@ # CMock Project - Automatic Mock Generation for C # Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams # [Released under MIT License. Please refer to license.txt for details] -# ========================================== +# ========================================== class CMockGeneratorPluginCallback - attr_accessor :include_count attr_reader :priority attr_reader :config, :utils - + def initialize(config, utils) @config = config @utils = utils @priority = 6 - + @include_count = @config.callback_include_count - if (@config.callback_after_arg_check) - alias :mock_implementation :mock_implementation_for_callbacks - alias :mock_implementation_precheck :nothing - else - alias :mock_implementation_precheck :mock_implementation_for_callbacks - alias :mock_implementation :nothing - end end def instance_structure(function) func_name = function[:name] - " CMOCK_#{func_name}_CALLBACK #{func_name}_CallbackFunctionPointer;\n" + + " char #{func_name}_CallbackBool;\n" \ + " CMOCK_#{func_name}_CALLBACK #{func_name}_CallbackFunctionPointer;\n" \ " int #{func_name}_CallbackCalls;\n" end def mock_function_declarations(function) func_name = function[:name] - return_type = function[:return][:const?] ? "const #{function[:return][:type]}" : function[:return][:type] + return_type = function[:return][:type] + action = @config.callback_after_arg_check ? 'AddCallback' : 'Stub' style = (@include_count ? 1 : 0) | (function[:args].empty? ? 0 : 2) - styles = [ "void", "int cmock_num_calls", function[:args_string], "#{function[:args_string]}, int cmock_num_calls" ] - "typedef #{return_type} (* CMOCK_#{func_name}_CALLBACK)(#{styles[style]});\nvoid #{func_name}_StubWithCallback(CMOCK_#{func_name}_CALLBACK Callback);\n" + styles = ['void', 'int cmock_num_calls', function[:args_string], "#{function[:args_string]}, int cmock_num_calls"] + "typedef #{return_type} (* CMOCK_#{func_name}_CALLBACK)(#{styles[style]});\n" \ + "void #{func_name}_AddCallback(CMOCK_#{func_name}_CALLBACK Callback);\n" \ + "void #{func_name}_Stub(CMOCK_#{func_name}_CALLBACK Callback);\n" \ + "#define #{func_name}_StubWithCallback #{func_name}_#{action}\n" end - def mock_implementation_for_callbacks(function) - func_name = function[:name] - style = (@include_count ? 1 : 0) | (function[:args].empty? ? 0 : 2) | (function[:return][:void?] ? 0 : 4) - " if (Mock.#{func_name}_CallbackFunctionPointer != NULL)\n {\n" + - case(style) - when 0 then " Mock.#{func_name}_CallbackFunctionPointer();\n return;\n }\n" - when 1 then " Mock.#{func_name}_CallbackFunctionPointer(Mock.#{func_name}_CallbackCalls++);\n return;\n }\n" - when 2 then " Mock.#{func_name}_CallbackFunctionPointer(#{function[:args].map{|m| m[:name]}.join(', ')});\n return;\n }\n" - when 3 then " Mock.#{func_name}_CallbackFunctionPointer(#{function[:args].map{|m| m[:name]}.join(', ')}, Mock.#{func_name}_CallbackCalls++);\n return;\n }\n" - when 4 then " return Mock.#{func_name}_CallbackFunctionPointer();\n }\n" - when 5 then " return Mock.#{func_name}_CallbackFunctionPointer(Mock.#{func_name}_CallbackCalls++);\n }\n" - when 6 then " return Mock.#{func_name}_CallbackFunctionPointer(#{function[:args].map{|m| m[:name]}.join(', ')});\n }\n" - when 7 then " return Mock.#{func_name}_CallbackFunctionPointer(#{function[:args].map{|m| m[:name]}.join(', ')}, Mock.#{func_name}_CallbackCalls++);\n }\n" - end + def generate_call(function) + args = function[:args].map { |m| m[:name] } + args << "Mock.#{function[:name]}_CallbackCalls++" if @include_count + "Mock.#{function[:name]}_CallbackFunctionPointer(#{args.join(', ')})" end - - def nothing(function) - return "" + + def mock_implementation(function) + " if (Mock.#{function[:name]}_CallbackFunctionPointer != NULL)\n {\n" + + if function[:return][:void?] + " #{generate_call(function)};\n }\n" + else + " cmock_call_instance->ReturnVal = #{generate_call(function)};\n }\n" + end + end + + def mock_implementation_precheck(function) + " if (!Mock.#{function[:name]}_CallbackBool &&\n" \ + " Mock.#{function[:name]}_CallbackFunctionPointer != NULL)\n {\n" + + if function[:return][:void?] + " #{generate_call(function)};\n" \ + " UNITY_CLR_DETAILS();\n" \ + " return;\n }\n" + else + " #{function[:return][:type]} cmock_cb_ret = #{generate_call(function)};\n" \ + " UNITY_CLR_DETAILS();\n" \ + " return cmock_cb_ret;\n }\n" + end end def mock_interfaces(function) func_name = function[:name] - "void #{func_name}_StubWithCallback(CMOCK_#{func_name}_CALLBACK Callback)\n{\n" + - " Mock.#{func_name}_CallbackFunctionPointer = Callback;\n}\n\n" + has_ignore = @config.plugins.include? :ignore + lines = '' + lines << "void #{func_name}_AddCallback(CMOCK_#{func_name}_CALLBACK Callback)\n{\n" + lines << " Mock.#{func_name}_IgnoreBool = (char)0;\n" if has_ignore + lines << " Mock.#{func_name}_CallbackBool = (char)1;\n" + lines << " Mock.#{func_name}_CallbackFunctionPointer = Callback;\n}\n\n" + lines << "void #{func_name}_Stub(CMOCK_#{func_name}_CALLBACK Callback)\n{\n" + lines << " Mock.#{func_name}_IgnoreBool = (char)0;\n" if has_ignore + lines << " Mock.#{func_name}_CallbackBool = (char)0;\n" + lines << " Mock.#{func_name}_CallbackFunctionPointer = Callback;\n}\n\n" end - def mock_destroy(function) - " Mock.#{function[:name]}_CallbackFunctionPointer = NULL;\n" + - " Mock.#{function[:name]}_CallbackCalls = 0;\n" - end - def mock_verify(function) func_name = function[:name] - " if (Mock.#{func_name}_CallbackFunctionPointer != NULL)\n Mock.#{func_name}_CallInstance = CMOCK_GUTS_NONE;\n" + " if (Mock.#{func_name}_CallbackFunctionPointer != NULL)\n {\n" \ + " call_instance = CMOCK_GUTS_NONE;\n" \ + " (void)call_instance;\n }\n" end - end diff --git a/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_cexception.rb b/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_cexception.rb index fdf31db..7e2d7b6 100644 --- a/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_cexception.rb +++ b/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_cexception.rb @@ -2,50 +2,49 @@ # CMock Project - Automatic Mock Generation for C # Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams # [Released under MIT License. Please refer to license.txt for details] -# ========================================== +# ========================================== class CMockGeneratorPluginCexception - attr_reader :priority attr_reader :config, :utils - + def initialize(config, utils) @config = config @utils = utils @priority = 7 + raise 'Error: cexception is not supported without setjmp support' if @config.exclude_setjmp_h end def include_files - return "#include \"CException.h\"\n" + "#include \"CException.h\"\n" end - def instance_typedefs(function) + def instance_typedefs(_function) " CEXCEPTION_T ExceptionToThrow;\n" end - + def mock_function_declarations(function) - if (function[:args_string] == "void") - return "#define #{function[:name]}_ExpectAndThrow(cmock_to_throw) #{function[:name]}_CMockExpectAndThrow(__LINE__, cmock_to_throw)\n" + + if function[:args_string] == 'void' + "#define #{function[:name]}_ExpectAndThrow(cmock_to_throw) #{function[:name]}_CMockExpectAndThrow(__LINE__, cmock_to_throw)\n" \ "void #{function[:name]}_CMockExpectAndThrow(UNITY_LINE_TYPE cmock_line, CEXCEPTION_T cmock_to_throw);\n" else - return "#define #{function[:name]}_ExpectAndThrow(#{function[:args_call]}, cmock_to_throw) #{function[:name]}_CMockExpectAndThrow(__LINE__, #{function[:args_call]}, cmock_to_throw)\n" + + "#define #{function[:name]}_ExpectAndThrow(#{function[:args_call]}, cmock_to_throw) #{function[:name]}_CMockExpectAndThrow(__LINE__, #{function[:args_call]}, cmock_to_throw)\n" \ "void #{function[:name]}_CMockExpectAndThrow(UNITY_LINE_TYPE cmock_line, #{function[:args_string]}, CEXCEPTION_T cmock_to_throw);\n" end end - def mock_implementation(function) - " if (cmock_call_instance->ExceptionToThrow != CEXCEPTION_NONE)\n {\n" + - " Throw(cmock_call_instance->ExceptionToThrow);\n }\n" + def mock_implementation(_function) + " if (cmock_call_instance->ExceptionToThrow != CEXCEPTION_NONE)\n {\n" \ + " UNITY_CLR_DETAILS();\n" \ + " Throw(cmock_call_instance->ExceptionToThrow);\n }\n" end def mock_interfaces(function) - arg_insert = (function[:args_string] == "void") ? "" : "#{function[:args_string]}, " - call_string = function[:args].map{|m| m[:name]}.join(', ') - [ "void #{function[:name]}_CMockExpectAndThrow(UNITY_LINE_TYPE cmock_line, #{arg_insert}CEXCEPTION_T cmock_to_throw)\n{\n", - @utils.code_add_base_expectation(function[:name]), - @utils.code_call_argument_loader(function), - " cmock_call_instance->ExceptionToThrow = cmock_to_throw;\n", - "}\n\n" ].join + arg_insert = function[:args_string] == 'void' ? '' : "#{function[:args_string]}, " + ["void #{function[:name]}_CMockExpectAndThrow(UNITY_LINE_TYPE cmock_line, #{arg_insert}CEXCEPTION_T cmock_to_throw)\n{\n", + @utils.code_add_base_expectation(function[:name]), + @utils.code_call_argument_loader(function), + " cmock_call_instance->ExceptionToThrow = cmock_to_throw;\n", + "}\n\n"].join end - end diff --git a/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_expect.rb b/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_expect.rb index 5651cd9..3a79c1a 100644 --- a/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_expect.rb +++ b/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_expect.rb @@ -2,10 +2,9 @@ # CMock Project - Automatic Mock Generation for C # Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams # [Released under MIT License. Please refer to license.txt for details] -# ========================================== +# ========================================== class CMockGeneratorPluginExpect - attr_reader :priority attr_accessor :config, :utils, :unity_helper, :ordered @@ -16,71 +15,86 @@ def initialize(config, utils) @utils = utils @unity_helper = @utils.helpers[:unity_helper] @priority = 5 + + if @config.plugins.include? :expect_any_args + alias :mock_implementation :mock_implementation_might_check_args + else + alias :mock_implementation :mock_implementation_always_check_args + end end - + def instance_typedefs(function) - lines = "" - lines << " #{function[:return][:type]} ReturnVal;\n" unless (function[:return][:void?]) - lines << " int CallOrder;\n" if (@ordered) + lines = '' + lines << " #{function[:return][:type]} ReturnVal;\n" unless function[:return][:void?] + lines << " int CallOrder;\n" if @ordered function[:args].each do |arg| lines << " #{arg[:type]} Expected_#{arg[:name]};\n" end lines end - + def mock_function_declarations(function) - if (function[:args].empty?) - if (function[:return][:void?]) - return "#define #{function[:name]}_Expect() #{function[:name]}_CMockExpect(__LINE__)\n" + + if function[:args].empty? + if function[:return][:void?] + "#define #{function[:name]}_Expect() #{function[:name]}_CMockExpect(__LINE__)\n" \ "void #{function[:name]}_CMockExpect(UNITY_LINE_TYPE cmock_line);\n" else - return "#define #{function[:name]}_ExpectAndReturn(cmock_retval) #{function[:name]}_CMockExpectAndReturn(__LINE__, cmock_retval)\n" + + "#define #{function[:name]}_ExpectAndReturn(cmock_retval) #{function[:name]}_CMockExpectAndReturn(__LINE__, cmock_retval)\n" \ "void #{function[:name]}_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]});\n" end - else - if (function[:return][:void?]) - return "#define #{function[:name]}_Expect(#{function[:args_call]}) #{function[:name]}_CMockExpect(__LINE__, #{function[:args_call]})\n" + - "void #{function[:name]}_CMockExpect(UNITY_LINE_TYPE cmock_line, #{function[:args_string]});\n" - else - return "#define #{function[:name]}_ExpectAndReturn(#{function[:args_call]}, cmock_retval) #{function[:name]}_CMockExpectAndReturn(__LINE__, #{function[:args_call]}, cmock_retval)\n" + - "void #{function[:name]}_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:args_string]}, #{function[:return][:str]});\n" - end + elsif function[:return][:void?] + "#define #{function[:name]}_Expect(#{function[:args_call]}) #{function[:name]}_CMockExpect(__LINE__, #{function[:args_call]})\n" \ + "void #{function[:name]}_CMockExpect(UNITY_LINE_TYPE cmock_line, #{function[:args_string]});\n" + else + "#define #{function[:name]}_ExpectAndReturn(#{function[:args_call]}, cmock_retval) #{function[:name]}_CMockExpectAndReturn(__LINE__, #{function[:args_call]}, cmock_retval)\n" \ + "void #{function[:name]}_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:args_string]}, #{function[:return][:str]});\n" + end + end + + def mock_implementation_always_check_args(function) + lines = '' + function[:args].each do |arg| + lines << @utils.code_verify_an_arg_expectation(function, arg) end + lines end - - def mock_implementation(function) - lines = "" + + def mock_implementation_might_check_args(function) + return '' if function[:args].empty? + + lines = " if (!cmock_call_instance->ExpectAnyArgsBool)\n {\n" function[:args].each do |arg| lines << @utils.code_verify_an_arg_expectation(function, arg) end + lines << " }\n" lines end - + def mock_interfaces(function) - lines = "" + lines = '' func_name = function[:name] - if (function[:return][:void?]) - if (function[:args_string] == "void") - lines << "void #{func_name}_CMockExpect(UNITY_LINE_TYPE cmock_line)\n{\n" - else - lines << "void #{func_name}_CMockExpect(UNITY_LINE_TYPE cmock_line, #{function[:args_string]})\n{\n" - end - else - if (function[:args_string] == "void") - lines << "void #{func_name}_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]})\n{\n" - else - lines << "void #{func_name}_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:args_string]}, #{function[:return][:str]})\n{\n" - end - end + lines << if function[:return][:void?] + if function[:args_string] == 'void' + "void #{func_name}_CMockExpect(UNITY_LINE_TYPE cmock_line)\n{\n" + else + "void #{func_name}_CMockExpect(UNITY_LINE_TYPE cmock_line, #{function[:args_string]})\n{\n" + end + elsif function[:args_string] == 'void' + "void #{func_name}_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]})\n{\n" + else + "void #{func_name}_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:args_string]}, #{function[:return][:str]})\n{\n" + end lines << @utils.code_add_base_expectation(func_name) lines << @utils.code_call_argument_loader(function) - lines << @utils.code_assign_argument_quickly("cmock_call_instance->ReturnVal", function[:return]) unless (function[:return][:void?]) + lines << @utils.code_assign_argument_quickly('cmock_call_instance->ReturnVal', function[:return]) unless function[:return][:void?] lines << "}\n\n" end - + def mock_verify(function) - func_name = function[:name] - " UNITY_TEST_ASSERT(CMOCK_GUTS_NONE == Mock.#{func_name}_CallInstance, cmock_line, \"Function '#{func_name}' called less times than expected.\");\n" + " if (CMOCK_GUTS_NONE != call_instance)\n" \ + " {\n" \ + " UNITY_SET_DETAIL(CMockString_#{function[:name]});\n" \ + " UNITY_TEST_FAIL(cmock_line, CMockStringCalledLess);\n" \ + " }\n" end - end diff --git a/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_expect_any_args.rb b/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_expect_any_args.rb new file mode 100644 index 0000000..0fc88e1 --- /dev/null +++ b/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_expect_any_args.rb @@ -0,0 +1,50 @@ +# ========================================== +# CMock Project - Automatic Mock Generation for C +# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams +# [Released under MIT License. Please refer to license.txt for details] +# ========================================== + +class CMockGeneratorPluginExpectAnyArgs + attr_reader :priority + attr_reader :config, :utils + + def initialize(config, utils) + @config = config + @utils = utils + @priority = 3 + end + + def instance_typedefs(_function) + " char ExpectAnyArgsBool;\n" + end + + def mock_function_declarations(function) + if function[:args].empty? + '' + elsif function[:return][:void?] + "#define #{function[:name]}_ExpectAnyArgs() #{function[:name]}_CMockExpectAnyArgs(__LINE__)\n" \ + "void #{function[:name]}_CMockExpectAnyArgs(UNITY_LINE_TYPE cmock_line);\n" + else + "#define #{function[:name]}_ExpectAnyArgsAndReturn(cmock_retval) #{function[:name]}_CMockExpectAnyArgsAndReturn(__LINE__, cmock_retval)\n" \ + "void #{function[:name]}_CMockExpectAnyArgsAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]});\n" + end + end + + def mock_interfaces(function) + lines = '' + unless function[:args].empty? + lines << if function[:return][:void?] + "void #{function[:name]}_CMockExpectAnyArgs(UNITY_LINE_TYPE cmock_line)\n{\n" + else + "void #{function[:name]}_CMockExpectAnyArgsAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]})\n{\n" + end + lines << @utils.code_add_base_expectation(function[:name], true) + unless function[:return][:void?] + lines << " cmock_call_instance->ReturnVal = cmock_to_return;\n" + end + lines << " cmock_call_instance->ExpectAnyArgsBool = (char)1;\n" + lines << "}\n\n" + end + lines + end +end diff --git a/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_ignore.rb b/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_ignore.rb index e81de3c..b292f3d 100644 --- a/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_ignore.rb +++ b/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_ignore.rb @@ -2,94 +2,87 @@ # CMock Project - Automatic Mock Generation for C # Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams # [Released under MIT License. Please refer to license.txt for details] -# ========================================== +# ========================================== class CMockGeneratorPluginIgnore - attr_reader :priority attr_reader :config, :utils - + def initialize(config, utils) @config = config - if (@config.ignore == :args_and_calls) - alias :mock_implementation_precheck :mock_implementation_for_ignores - alias :mock_implementation :nothing - alias :mock_verify :mock_conditionally_verify_counts - else - alias :mock_implementation :mock_implementation_for_ignores - alias :mock_implementation_precheck :nothing - alias :mock_verify :nothing - end @utils = utils @priority = 2 end - + def instance_structure(function) - if (function[:return][:void?]) - " int #{function[:name]}_IgnoreBool;\n" + if function[:return][:void?] + " char #{function[:name]}_IgnoreBool;\n" else - " int #{function[:name]}_IgnoreBool;\n #{function[:return][:type]} #{function[:name]}_FinalReturn;\n" + " char #{function[:name]}_IgnoreBool;\n #{function[:return][:type]} #{function[:name]}_FinalReturn;\n" end end - + def mock_function_declarations(function) - if (function[:return][:void?]) - if (@config.ignore == :args_only) - return "#define #{function[:name]}_Ignore() #{function[:name]}_CMockIgnore(__LINE__)\n" + - "void #{function[:name]}_CMockIgnore(UNITY_LINE_TYPE cmock_line);\n" - else - return "#define #{function[:name]}_Ignore() #{function[:name]}_CMockIgnore()\n" + - "void #{function[:name]}_CMockIgnore(void);\n" - end - else - return "#define #{function[:name]}_IgnoreAndReturn(cmock_retval) #{function[:name]}_CMockIgnoreAndReturn(__LINE__, cmock_retval)\n" + - "void #{function[:name]}_CMockIgnoreAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]});\n" - end + lines = if function[:return][:void?] + "#define #{function[:name]}_Ignore() #{function[:name]}_CMockIgnore()\n" \ + "void #{function[:name]}_CMockIgnore(void);\n" + else + "#define #{function[:name]}_IgnoreAndReturn(cmock_retval) #{function[:name]}_CMockIgnoreAndReturn(__LINE__, cmock_retval)\n" \ + "void #{function[:name]}_CMockIgnoreAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]});\n" + end + + # Add stop ignore function. it does not matter if there are any args + lines << "#define #{function[:name]}_StopIgnore() #{function[:name]}_CMockStopIgnore()\n" \ + "void #{function[:name]}_CMockStopIgnore(void);\n" + lines end - - def mock_implementation_for_ignores(function) - lines = " if (Mock.#{function[:name]}_IgnoreBool)\n {\n" - if (function[:return][:void?]) + + def mock_implementation_precheck(function) + lines = " if (Mock.#{function[:name]}_IgnoreBool)\n {\n" + lines << " UNITY_CLR_DETAILS();\n" + if function[:return][:void?] lines << " return;\n }\n" else - retval = function[:return].merge( { :name => "cmock_call_instance->ReturnVal"} ) + retval = function[:return].merge(:name => 'cmock_call_instance->ReturnVal') lines << " if (cmock_call_instance == NULL)\n return Mock.#{function[:name]}_FinalReturn;\n" - lines << " " + @utils.code_assign_argument_quickly("Mock.#{function[:name]}_FinalReturn", retval) unless (retval[:void?]) + lines << ' ' + @utils.code_assign_argument_quickly("Mock.#{function[:name]}_FinalReturn", retval) unless retval[:void?] lines << " return cmock_call_instance->ReturnVal;\n }\n" end lines end - + def mock_interfaces(function) - lines = "" - args_only = (@config.ignore == :args_only) - if (function[:return][:void?]) - if (args_only) - lines << "void #{function[:name]}_CMockIgnore(UNITY_LINE_TYPE cmock_line)\n{\n" - else - lines << "void #{function[:name]}_CMockIgnore(void)\n{\n" - end - else - lines << "void #{function[:name]}_CMockIgnoreAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]})\n{\n" - end - if (args_only) - lines << @utils.code_add_base_expectation(function[:name], true) - elsif (!function[:return][:void?]) + lines = '' + lines << if function[:return][:void?] + "void #{function[:name]}_CMockIgnore(void)\n{\n" + else + "void #{function[:name]}_CMockIgnoreAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]})\n{\n" + end + unless function[:return][:void?] lines << @utils.code_add_base_expectation(function[:name], false) end - unless (function[:return][:void?]) + unless function[:return][:void?] lines << " cmock_call_instance->ReturnVal = cmock_to_return;\n" end - lines << " Mock.#{function[:name]}_IgnoreBool = (int)1;\n" + lines << " Mock.#{function[:name]}_IgnoreBool = (char)1;\n" + lines << "}\n\n" + + # Add stop ignore function. it does not matter if there are any args + lines << "void #{function[:name]}_CMockStopIgnore(void)\n{\n" + unless function[:return][:void?] + lines << " if(Mock.#{function[:name]}_IgnoreBool)\n" + lines << " Mock.#{function[:name]}_CallInstance = CMock_Guts_MemNext(Mock.#{function[:name]}_CallInstance);\n" + end + lines << " Mock.#{function[:name]}_IgnoreBool = (char)0;\n" lines << "}\n\n" end - def mock_conditionally_verify_counts(function) - func_name = function[:name] - " if (Mock.#{func_name}_IgnoreBool)\n Mock.#{func_name}_CallInstance = CMOCK_GUTS_NONE;\n" + def mock_ignore(function) + " Mock.#{function[:name]}_IgnoreBool = (char) 1;\n" end - - def nothing(function) - return "" + + def mock_verify(function) + func_name = function[:name] + " if (Mock.#{func_name}_IgnoreBool)\n call_instance = CMOCK_GUTS_NONE;\n" end end diff --git a/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_ignore_arg.rb b/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_ignore_arg.rb new file mode 100644 index 0000000..d55e84c --- /dev/null +++ b/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_ignore_arg.rb @@ -0,0 +1,42 @@ +class CMockGeneratorPluginIgnoreArg + attr_reader :priority + attr_accessor :utils + + def initialize(_config, utils) + @utils = utils + @priority = 10 + end + + def instance_typedefs(function) + lines = '' + function[:args].each do |arg| + lines << " char IgnoreArg_#{arg[:name]};\n" + end + lines + end + + def mock_function_declarations(function) + lines = '' + function[:args].each do |arg| + lines << "#define #{function[:name]}_IgnoreArg_#{arg[:name]}()" + lines << " #{function[:name]}_CMockIgnoreArg_#{arg[:name]}(__LINE__)\n" + lines << "void #{function[:name]}_CMockIgnoreArg_#{arg[:name]}(UNITY_LINE_TYPE cmock_line);\n" + end + lines + end + + def mock_interfaces(function) + lines = [] + func_name = function[:name] + function[:args].each do |arg| + lines << "void #{func_name}_CMockIgnoreArg_#{arg[:name]}(UNITY_LINE_TYPE cmock_line)\n" + lines << "{\n" + lines << " CMOCK_#{func_name}_CALL_INSTANCE* cmock_call_instance = " \ + "(CMOCK_#{func_name}_CALL_INSTANCE*)CMock_Guts_GetAddressFor(CMock_Guts_MemEndOfChain(Mock.#{func_name}_CallInstance));\n" + lines << " UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringIgnPreExp);\n" + lines << " cmock_call_instance->IgnoreArg_#{arg[:name]} = 1;\n" + lines << "}\n\n" + end + lines + end +end diff --git a/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_ignore_stateless.rb b/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_ignore_stateless.rb new file mode 100644 index 0000000..9196ede --- /dev/null +++ b/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_ignore_stateless.rb @@ -0,0 +1,85 @@ +# ========================================== +# CMock Project - Automatic Mock Generation for C +# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams +# [Released under MIT License. Please refer to license.txt for details] +# ========================================== + +class CMockGeneratorPluginIgnoreStateless + attr_reader :priority + attr_reader :config, :utils + + def initialize(config, utils) + @config = config + @utils = utils + @priority = 2 + end + + def instance_structure(function) + if function[:return][:void?] + " char #{function[:name]}_IgnoreBool;\n" + else + " char #{function[:name]}_IgnoreBool;\n #{function[:return][:type]} #{function[:name]}_FinalReturn;\n" + end + end + + def mock_function_declarations(function) + lines = if function[:return][:void?] + "#define #{function[:name]}_Ignore() #{function[:name]}_CMockIgnore()\n" \ + "void #{function[:name]}_CMockIgnore(void);\n" + else + "#define #{function[:name]}_IgnoreAndReturn(cmock_retval) #{function[:name]}_CMockIgnoreAndReturn(cmock_retval)\n" \ + "void #{function[:name]}_CMockIgnoreAndReturn(#{function[:return][:str]});\n" + end + + # Add stop ignore function. it does not matter if there are any args + lines << "#define #{function[:name]}_StopIgnore() #{function[:name]}_CMockStopIgnore()\n" \ + "void #{function[:name]}_CMockStopIgnore(void);\n" + lines + end + + def mock_implementation_precheck(function) + lines = " if (Mock.#{function[:name]}_IgnoreBool)\n {\n" + lines << " UNITY_CLR_DETAILS();\n" + if function[:return][:void?] + lines << " return;\n }\n" + else + retval = function[:return].merge(:name => 'cmock_call_instance->ReturnVal') + lines << " if (cmock_call_instance == NULL)\n return Mock.#{function[:name]}_FinalReturn;\n" + lines << ' ' + @utils.code_assign_argument_quickly("Mock.#{function[:name]}_FinalReturn", retval) unless retval[:void?] + lines << " return cmock_call_instance->ReturnVal;\n }\n" + end + lines + end + + # this function is adjusted + def mock_interfaces(function) + lines = '' + lines << if function[:return][:void?] + "void #{function[:name]}_CMockIgnore(void)\n{\n" + else + "void #{function[:name]}_CMockIgnoreAndReturn(#{function[:return][:str]})\n{\n" + end + unless function[:return][:void?] + lines << " Mock.#{function[:name]}_CallInstance = CMOCK_GUTS_NONE;\n" + lines << " Mock.#{function[:name]}_FinalReturn = cmock_to_return;\n" + end + lines << " Mock.#{function[:name]}_IgnoreBool = (char)1;\n" + lines << "}\n\n" + + # Add stop ignore function. it does not matter if there are any args + lines << "void #{function[:name]}_CMockStopIgnore(void)\n{\n" + lines << " Mock.#{function[:name]}_IgnoreBool = (char)0;\n" + lines << "}\n\n" + + lines + end + + def mock_ignore(function) + " Mock.#{function[:name]}_IgnoreBool = (char)1;\n" + end + + def mock_verify(function) + func_name = function[:name] + " if (Mock.#{func_name}_IgnoreBool)\n call_instance = CMOCK_GUTS_NONE;\n" + end +end diff --git a/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_return_thru_ptr.rb b/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_return_thru_ptr.rb new file mode 100644 index 0000000..96b2003 --- /dev/null +++ b/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_return_thru_ptr.rb @@ -0,0 +1,79 @@ +class CMockGeneratorPluginReturnThruPtr + attr_reader :priority + attr_accessor :utils + + def initialize(_config, utils) + @utils = utils + @priority = 9 + end + + def instance_typedefs(function) + lines = '' + function[:args].each do |arg| + next unless @utils.ptr_or_str?(arg[:type]) && !(arg[:const?]) + + lines << " char ReturnThruPtr_#{arg[:name]}_Used;\n" + lines << " #{arg[:type]} ReturnThruPtr_#{arg[:name]}_Val;\n" + lines << " size_t ReturnThruPtr_#{arg[:name]}_Size;\n" + end + lines + end + + def mock_function_declarations(function) + lines = '' + function[:args].each do |arg| + next unless @utils.ptr_or_str?(arg[:type]) && !(arg[:const?]) + + lines << "#define #{function[:name]}_ReturnThruPtr_#{arg[:name]}(#{arg[:name]})" + # If the pointer type actually contains an asterisk, we can do sizeof the type (super safe), otherwise + # we need to do a sizeof the dereferenced pointer (which could be a problem if give the wrong size + lines << if arg[:type][-1] == '*' + " #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(__LINE__, #{arg[:name]}, sizeof(#{arg[:type][0..-2]}))\n" + else + " #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(__LINE__, #{arg[:name]}, sizeof(*#{arg[:name]}))\n" + end + lines << "#define #{function[:name]}_ReturnArrayThruPtr_#{arg[:name]}(#{arg[:name]}, cmock_len)" + lines << " #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(__LINE__, #{arg[:name]}, cmock_len * sizeof(*#{arg[:name]}))\n" + lines << "#define #{function[:name]}_ReturnMemThruPtr_#{arg[:name]}(#{arg[:name]}, cmock_size)" + lines << " #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(__LINE__, #{arg[:name]}, cmock_size)\n" + lines << "void #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(UNITY_LINE_TYPE cmock_line, #{arg[:type]} #{arg[:name]}, size_t cmock_size);\n" + end + lines + end + + def mock_interfaces(function) + lines = [] + func_name = function[:name] + function[:args].each do |arg| + arg_name = arg[:name] + next unless @utils.ptr_or_str?(arg[:type]) && !(arg[:const?]) + + lines << "void #{func_name}_CMockReturnMemThruPtr_#{arg_name}(UNITY_LINE_TYPE cmock_line, #{arg[:type]} #{arg_name}, size_t cmock_size)\n" + lines << "{\n" + lines << " CMOCK_#{func_name}_CALL_INSTANCE* cmock_call_instance = " \ + "(CMOCK_#{func_name}_CALL_INSTANCE*)CMock_Guts_GetAddressFor(CMock_Guts_MemEndOfChain(Mock.#{func_name}_CallInstance));\n" + lines << " UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringPtrPreExp);\n" + lines << " cmock_call_instance->ReturnThruPtr_#{arg_name}_Used = 1;\n" + lines << " cmock_call_instance->ReturnThruPtr_#{arg_name}_Val = #{arg_name};\n" + lines << " cmock_call_instance->ReturnThruPtr_#{arg_name}_Size = cmock_size;\n" + lines << "}\n\n" + end + lines + end + + def mock_implementation(function) + lines = [] + function[:args].each do |arg| + arg_name = arg[:name] + next unless @utils.ptr_or_str?(arg[:type]) && !(arg[:const?]) + + lines << " if (cmock_call_instance->ReturnThruPtr_#{arg_name}_Used)\n" + lines << " {\n" + lines << " UNITY_TEST_ASSERT_NOT_NULL(#{arg_name}, cmock_line, CMockStringPtrIsNULL);\n" + lines << " memcpy((void*)#{arg_name}, (void*)cmock_call_instance->ReturnThruPtr_#{arg_name}_Val,\n" + lines << " cmock_call_instance->ReturnThruPtr_#{arg_name}_Size);\n" + lines << " }\n" + end + lines + end +end diff --git a/vendor/ceedling/vendor/cmock/lib/cmock_generator_utils.rb b/vendor/ceedling/vendor/cmock/lib/cmock_generator_utils.rb index 4444979..ecbc37e 100644 --- a/vendor/ceedling/vendor/cmock/lib/cmock_generator_utils.rb +++ b/vendor/ceedling/vendor/cmock/lib/cmock_generator_utils.rb @@ -2,176 +2,249 @@ # CMock Project - Automatic Mock Generation for C # Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams # [Released under MIT License. Please refer to license.txt for details] -# ========================================== +# ========================================== class CMockGeneratorUtils - attr_accessor :config, :helpers, :ordered, :ptr_handling, :arrays, :cexception - def initialize(config, helpers={}) + def initialize(config, helpers = {}) @config = config @ptr_handling = @config.when_ptr @ordered = @config.enforce_strict_ordering @arrays = @config.plugins.include? :array @cexception = @config.plugins.include? :cexception - @treat_as = @config.treat_as - @helpers = helpers - - if (@arrays) - case(@ptr_handling) - when :smart then alias :code_verify_an_arg_expectation :code_verify_an_arg_expectation_with_smart_arrays - when :compare_data then alias :code_verify_an_arg_expectation :code_verify_an_arg_expectation_with_normal_arrays - when :compare_ptr then raise "ERROR: the array plugin doesn't enjoy working with :compare_ptr only. Disable one option." + @expect_any = @config.plugins.include? :expect_any_args + @return_thru_ptr = @config.plugins.include? :return_thru_ptr + @ignore_arg = @config.plugins.include? :ignore_arg + @ignore = @config.plugins.include? :ignore + @ignore_stateless = @config.plugins.include? :ignore_stateless + @treat_as = @config.treat_as + @helpers = helpers + end + + def self.arg_type_with_const(arg) + # Restore any "const" that was removed in header parsing + if arg[:type].include?('*') + arg[:const_ptr?] ? "#{arg[:type]} const" : arg[:type] + else + arg[:const?] ? "const #{arg[:type]}" : arg[:type] + end + end + + def arg_type_with_const(arg) + self.class.arg_type_with_const(arg) + end + + def code_verify_an_arg_expectation(function, arg) + if @arrays + case @ptr_handling + when :smart then code_verify_an_arg_expectation_with_smart_arrays(function, arg) + when :compare_data then code_verify_an_arg_expectation_with_normal_arrays(function, arg) + when :compare_ptr then raise "ERROR: the array plugin doesn't enjoy working with :compare_ptr only. Disable one option." end else - alias :code_verify_an_arg_expectation :code_verify_an_arg_expectation_with_no_arrays + code_verify_an_arg_expectation_with_no_arrays(function, arg) end end - - def code_add_base_expectation(func_name, global_ordering_supported=true) + + def code_add_base_expectation(func_name, global_ordering_supported = true) lines = " CMOCK_MEM_INDEX_TYPE cmock_guts_index = CMock_Guts_MemNew(sizeof(CMOCK_#{func_name}_CALL_INSTANCE));\n" lines << " CMOCK_#{func_name}_CALL_INSTANCE* cmock_call_instance = (CMOCK_#{func_name}_CALL_INSTANCE*)CMock_Guts_GetAddressFor(cmock_guts_index);\n" - lines << " UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, \"CMock has run out of memory. Please allocate more.\");\n" + lines << " UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringOutOfMemory);\n" + lines << " memset(cmock_call_instance, 0, sizeof(*cmock_call_instance));\n" lines << " Mock.#{func_name}_CallInstance = CMock_Guts_MemChain(Mock.#{func_name}_CallInstance, cmock_guts_index);\n" + lines << " Mock.#{func_name}_IgnoreBool = (char)0;\n" if @ignore || @ignore_stateless lines << " cmock_call_instance->LineNumber = cmock_line;\n" - lines << " cmock_call_instance->CallOrder = ++GlobalExpectCount;\n" if (@ordered and global_ordering_supported) - lines << " cmock_call_instance->ExceptionToThrow = CEXCEPTION_NONE;\n" if (@cexception) + lines << " cmock_call_instance->CallOrder = ++GlobalExpectCount;\n" if @ordered && global_ordering_supported + lines << " cmock_call_instance->ExceptionToThrow = CEXCEPTION_NONE;\n" if @cexception + lines << " cmock_call_instance->ExpectAnyArgsBool = (char)0;\n" if @expect_any lines end - - def code_add_an_arg_expectation(arg, depth=1) + + def code_add_an_arg_expectation(arg, depth = 1) lines = code_assign_argument_quickly("cmock_call_instance->Expected_#{arg[:name]}", arg) - lines << " cmock_call_instance->Expected_#{arg[:name]}_Depth = #{arg[:name]}_Depth;\n" if (@arrays and (depth.class == String)) + lines << " cmock_call_instance->Expected_#{arg[:name]}_Depth = #{arg[:name]}_Depth;\n" if @arrays && (depth.class == String) + lines << " cmock_call_instance->IgnoreArg_#{arg[:name]} = 0;\n" if @ignore_arg + lines << " cmock_call_instance->ReturnThruPtr_#{arg[:name]}_Used = 0;\n" if @return_thru_ptr && ptr_or_str?(arg[:type]) && !(arg[:const?]) lines end - - def code_assign_argument_quickly(dest, arg) - if (arg[:ptr?] or @treat_as.include?(arg[:type])) - " #{dest} = #{arg[:const?] ? "(#{arg[:type]})" : ''}#{arg[:name]};\n" + + def code_assign_argument_quickly(dest, arg) + if arg[:ptr?] || @treat_as.include?(arg[:type]) + " #{dest} = #{arg[:name]};\n" else - " memcpy(&#{dest}, &#{arg[:name]}, sizeof(#{arg[:type]}));\n" + assert_expr = "sizeof(#{arg[:name]}) == sizeof(#{arg[:type]}) ? 1 : -1" + comment = "/* add #{arg[:type]} to :treat_as_array if this causes an error */" + " memcpy((void*)(&#{dest}), (void*)(&#{arg[:name]}),\n" \ + " sizeof(#{arg[:type]}[#{assert_expr}])); #{comment}\n" end end - + def code_add_argument_loader(function) - if (function[:args_string] != "void") - if (@arrays) - args_string = function[:args].map do |m| - const_str = m[ :const? ] ? 'const ' : '' - m[:ptr?] ? "#{const_str}#{m[:type]} #{m[:name]}, int #{m[:name]}_Depth" : "#{const_str}#{m[:type]} #{m[:name]}" + if function[:args_string] != 'void' + if @arrays + args_string = function[:args].map do |m| + type = arg_type_with_const(m) + m[:ptr?] ? "#{type} #{m[:name]}, int #{m[:name]}_Depth" : "#{type} #{m[:name]}" end.join(', ') - "void CMockExpectParameters_#{function[:name]}(CMOCK_#{function[:name]}_CALL_INSTANCE* cmock_call_instance, #{args_string})\n{\n" + - function[:args].inject("") { |all, arg| all + code_add_an_arg_expectation(arg, (arg[:ptr?] ? "#{arg[:name]}_Depth" : 1) ) } + - "}\n\n" + "void CMockExpectParameters_#{function[:name]}(CMOCK_#{function[:name]}_CALL_INSTANCE* cmock_call_instance, #{args_string});\n" \ + "void CMockExpectParameters_#{function[:name]}(CMOCK_#{function[:name]}_CALL_INSTANCE* cmock_call_instance, #{args_string})\n{\n" + + function[:args].inject('') { |all, arg| all + code_add_an_arg_expectation(arg, (arg[:ptr?] ? "#{arg[:name]}_Depth" : 1)) } + + "}\n\n" else - "void CMockExpectParameters_#{function[:name]}(CMOCK_#{function[:name]}_CALL_INSTANCE* cmock_call_instance, #{function[:args_string]})\n{\n" + - function[:args].inject("") { |all, arg| all + code_add_an_arg_expectation(arg) } + - "}\n\n" + "void CMockExpectParameters_#{function[:name]}(CMOCK_#{function[:name]}_CALL_INSTANCE* cmock_call_instance, #{function[:args_string]});\n" \ + "void CMockExpectParameters_#{function[:name]}(CMOCK_#{function[:name]}_CALL_INSTANCE* cmock_call_instance, #{function[:args_string]})\n{\n" + + function[:args].inject('') { |all, arg| all + code_add_an_arg_expectation(arg) } + + "}\n\n" end else - "" + '' end end - + def code_call_argument_loader(function) - if (function[:args_string] != "void") + if function[:args_string] != 'void' args = function[:args].map do |m| - (@arrays and m[:ptr?]) ? "#{m[:name]}, 1" : m[:name] + if @arrays && m[:ptr?] && !(m[:array_data?]) + "#{m[:name]}, 1" + elsif @arrays && m[:array_size?] + "#{m[:name]}, #{m[:name]}" + else + m[:name] + end end - " CMockExpectParameters_#{function[:name]}(cmock_call_instance, #{args.join(', ')});\n" + " CMockExpectParameters_#{function[:name]}(cmock_call_instance, #{args.join(', ')});\n" else - "" + '' end end - - #private ###################### - - def lookup_expect_type(function, arg) + + def ptr_or_str?(arg_type) + (arg_type.include?('*') || + @treat_as.fetch(arg_type, '').include?('*')) + end + + # private ###################### + + def lookup_expect_type(_function, arg) c_type = arg[:type] arg_name = arg[:name] - expected = "cmock_call_instance->Expected_#{arg_name}" - unity_func = if ((arg[:ptr?]) and ((c_type =~ /\*\*/) or (@ptr_handling == :compare_ptr))) + expected = "cmock_call_instance->Expected_#{arg_name}" + ignore = "cmock_call_instance->IgnoreArg_#{arg_name}" + unity_func = if (arg[:ptr?]) && ((c_type =~ /\*\*/) || (@ptr_handling == :compare_ptr)) ['UNITY_TEST_ASSERT_EQUAL_PTR', ''] else - (@helpers.nil? or @helpers[:unity_helper].nil?) ? ["UNITY_TEST_ASSERT_EQUAL",''] : @helpers[:unity_helper].get_helper(c_type) + @helpers.nil? || @helpers[:unity_helper].nil? ? ['UNITY_TEST_ASSERT_EQUAL', ''] : @helpers[:unity_helper].get_helper(c_type) end - unity_msg = "Function '#{function[:name]}' called with unexpected value for argument '#{arg_name}'." - return c_type, arg_name, expected, unity_func[0], unity_func[1], unity_msg + [c_type, arg_name, expected, ignore, unity_func[0], unity_func[1]] end - + def code_verify_an_arg_expectation_with_no_arrays(function, arg) - c_type, arg_name, expected, unity_func, pre, unity_msg = lookup_expect_type(function, arg) - case(unity_func) - when "UNITY_TEST_ASSERT_EQUAL_MEMORY" - c_type_local = c_type.gsub(/\*$/,'') - return " UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type_local}), cmock_line, \"#{unity_msg}\");\n" - when "UNITY_TEST_ASSERT_EQUAL_MEMORY" - [ " if (#{pre}#{expected} == NULL)", - " { UNITY_TEST_ASSERT_NULL(#{pre}#{arg_name}, cmock_line, \"Expected NULL. #{unity_msg}\"); }", - " else", - " { UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type.sub('*','')}), cmock_line, \"#{unity_msg}\"); }\n"].join("\n") - when /_ARRAY/ - [ " if (#{pre}#{expected} == NULL)", - " { UNITY_TEST_ASSERT_NULL(#{pre}#{arg_name}, cmock_line, \"Expected NULL. #{unity_msg}\"); }", - " else", - " { #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, 1, cmock_line, \"#{unity_msg}\"); }\n"].join("\n") + c_type, arg_name, expected, ignore, unity_func, pre = lookup_expect_type(function, arg) + lines = '' + lines << " if (!#{ignore})\n" if @ignore_arg + lines << " {\n" + lines << " UNITY_SET_DETAILS(CMockString_#{function[:name]},CMockString_#{arg_name});\n" + case unity_func + when 'UNITY_TEST_ASSERT_EQUAL_MEMORY' + c_type_local = c_type.gsub(/\*$/, '') + lines << " UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type_local}), cmock_line, CMockStringMismatch);\n" + when 'UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY' + if pre == '&' + lines << " UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type.sub('*', '')}), cmock_line, CMockStringMismatch);\n" else - return " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, \"#{unity_msg}\");\n" - end + lines << " if (#{pre}#{expected} == NULL)\n" + lines << " { UNITY_TEST_ASSERT_NULL(#{pre}#{arg_name}, cmock_line, CMockStringExpNULL); }\n" + lines << " else\n" + lines << " { UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type.sub('*', '')}), cmock_line, CMockStringMismatch); }\n" + end + when /_ARRAY/ + if pre == '&' + lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, 1, cmock_line, CMockStringMismatch);\n" + else + lines << " if (#{pre}#{expected} == NULL)\n" + lines << " { UNITY_TEST_ASSERT_NULL(#{pre}#{arg_name}, cmock_line, CMockStringExpNULL); }\n" + lines << " else\n" + lines << " { #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, 1, cmock_line, CMockStringMismatch); }\n" + end + else + lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, CMockStringMismatch);\n" + end + lines << " }\n" + lines end - + def code_verify_an_arg_expectation_with_normal_arrays(function, arg) - c_type, arg_name, expected, unity_func, pre, unity_msg = lookup_expect_type(function, arg) - depth_name = (arg[:ptr?]) ? "cmock_call_instance->Expected_#{arg_name}_Depth" : 1 - case(unity_func) - when "UNITY_TEST_ASSERT_EQUAL_MEMORY" - c_type_local = c_type.gsub(/\*$/,'') - return " UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type_local}), cmock_line, \"#{unity_msg}\");\n" - when "UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY" - [ " if (#{pre}#{expected} == NULL)", - " { UNITY_TEST_ASSERT_NULL(#{pre}#{arg_name}, cmock_line, \"Expected NULL. #{unity_msg}\"); }", - " else", - " { UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type.sub('*','')}), #{depth_name}, cmock_line, \"#{unity_msg}\"); }\n"].compact.join("\n") - when /_ARRAY/ - if (pre == '&') - " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, #{depth_name}, cmock_line, \"#{unity_msg}\");\n" - else - [ " if (#{pre}#{expected} == NULL)", - " { UNITY_TEST_ASSERT_NULL(#{pre}#{arg_name}, cmock_line, \"Expected NULL. #{unity_msg}\"); }", - " else", - " { #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, #{depth_name}, cmock_line, \"#{unity_msg}\"); }\n"].compact.join("\n") - end + c_type, arg_name, expected, ignore, unity_func, pre = lookup_expect_type(function, arg) + depth_name = arg[:ptr?] ? "cmock_call_instance->Expected_#{arg_name}_Depth" : 1 + lines = '' + lines << " if (!#{ignore})\n" if @ignore_arg + lines << " {\n" + lines << " UNITY_SET_DETAILS(CMockString_#{function[:name]},CMockString_#{arg_name});\n" + case unity_func + when 'UNITY_TEST_ASSERT_EQUAL_MEMORY' + c_type_local = c_type.gsub(/\*$/, '') + lines << " UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type_local}), cmock_line, CMockStringMismatch);\n" + when 'UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY' + if pre == '&' + lines << " UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type.sub('*', '')}), cmock_line, CMockStringMismatch);\n" + else + lines << " if (#{pre}#{expected} == NULL)\n" + lines << " { UNITY_TEST_ASSERT_NULL(#{pre}#{arg_name}, cmock_line, CMockStringExpNULL); }\n" + lines << " else\n" + lines << " { UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type.sub('*', '')}), #{depth_name}, cmock_line, CMockStringMismatch); }\n" + end + when /_ARRAY/ + if pre == '&' + lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, #{depth_name}, cmock_line, CMockStringMismatch);\n" else - return " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, \"#{unity_msg}\");\n" + lines << " if (#{pre}#{expected} == NULL)\n" + lines << " { UNITY_TEST_ASSERT_NULL(#{pre}#{arg_name}, cmock_line, CMockStringExpNULL); }\n" + lines << " else\n" + lines << " { #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, #{depth_name}, cmock_line, CMockStringMismatch); }\n" + end + else + lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, CMockStringMismatch);\n" end + lines << " }\n" + lines end - + def code_verify_an_arg_expectation_with_smart_arrays(function, arg) - c_type, arg_name, expected, unity_func, pre, unity_msg = lookup_expect_type(function, arg) - depth_name = (arg[:ptr?]) ? "cmock_call_instance->Expected_#{arg_name}_Depth" : 1 - case(unity_func) - when "UNITY_TEST_ASSERT_EQUAL_MEMORY" - c_type_local = c_type.gsub(/\*$/,'') - return " UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type_local}), cmock_line, \"#{unity_msg}\");\n" - when "UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY" - [ " if (#{pre}#{expected} == NULL)", - " { UNITY_TEST_ASSERT_NULL(#{arg_name}, cmock_line, \"Expected NULL. #{unity_msg}\"); }", - ((depth_name != 1) ? " else if (#{depth_name} == 0)\n { UNITY_TEST_ASSERT_EQUAL_PTR(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, \"#{unity_msg}\"); }" : nil), - " else", - " { UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type.sub('*','')}), #{depth_name}, cmock_line, \"#{unity_msg}\"); }\n"].compact.join("\n") - when /_ARRAY/ - if (pre == '&') - " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, #{depth_name}, cmock_line, \"#{unity_msg}\");\n" - else - [ " if (#{pre}#{expected} == NULL)", - " { UNITY_TEST_ASSERT_NULL(#{pre}#{arg_name}, cmock_line, \"Expected NULL. #{unity_msg}\"); }", - ((depth_name != 1) ? " else if (#{depth_name} == 0)\n { UNITY_TEST_ASSERT_EQUAL_PTR(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, \"#{unity_msg}\"); }" : nil), - " else", - " { #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, #{depth_name}, cmock_line, \"#{unity_msg}\"); }\n"].compact.join("\n") - end + c_type, arg_name, expected, ignore, unity_func, pre = lookup_expect_type(function, arg) + depth_name = arg[:ptr?] ? "cmock_call_instance->Expected_#{arg_name}_Depth" : 1 + lines = '' + lines << " if (!#{ignore})\n" if @ignore_arg + lines << " {\n" + lines << " UNITY_SET_DETAILS(CMockString_#{function[:name]},CMockString_#{arg_name});\n" + case unity_func + when 'UNITY_TEST_ASSERT_EQUAL_MEMORY' + c_type_local = c_type.gsub(/\*$/, '') + lines << " UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type_local}), cmock_line, CMockStringMismatch);\n" + when 'UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY' + if pre == '&' + lines << " UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type.sub('*', '')}), #{depth_name}, cmock_line, CMockStringMismatch);\n" else - return " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, \"#{unity_msg}\");\n" + lines << " if (#{pre}#{expected} == NULL)\n" + lines << " { UNITY_TEST_ASSERT_NULL(#{arg_name}, cmock_line, CMockStringExpNULL); }\n" + lines << (depth_name != 1 ? " else if (#{depth_name} == 0)\n { UNITY_TEST_ASSERT_EQUAL_PTR(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, CMockStringMismatch); }\n" : '') + lines << " else\n" + lines << " { UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type.sub('*', '')}), #{depth_name}, cmock_line, CMockStringMismatch); }\n" + end + when /_ARRAY/ + if pre == '&' + lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, #{depth_name}, cmock_line, CMockStringMismatch);\n" + else + lines << " if (#{pre}#{expected} == NULL)\n" + lines << " { UNITY_TEST_ASSERT_NULL(#{pre}#{arg_name}, cmock_line, CMockStringExpNULL); }\n" + lines << (depth_name != 1 ? " else if (#{depth_name} == 0)\n { UNITY_TEST_ASSERT_EQUAL_PTR(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, CMockStringMismatch); }\n" : '') + lines << " else\n" + lines << " { #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, #{depth_name}, cmock_line, CMockStringMismatch); }\n" + end + else + lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, CMockStringMismatch);\n" end + lines << " }\n" + lines end - -end \ No newline at end of file +end diff --git a/vendor/ceedling/vendor/cmock/lib/cmock_header_parser.rb b/vendor/ceedling/vendor/cmock/lib/cmock_header_parser.rb index 864e4c7..9730bf4 100644 --- a/vendor/ceedling/vendor/cmock/lib/cmock_header_parser.rb +++ b/vendor/ceedling/vendor/cmock/lib/cmock_header_parser.rb @@ -2,276 +2,622 @@ # CMock Project - Automatic Mock Generation for C # Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams # [Released under MIT License. Please refer to license.txt for details] -# ========================================== +# ========================================== class CMockHeaderParser + attr_accessor :funcs, :c_attr_noconst, :c_attributes, :treat_as_void, :treat_externs, :treat_inlines, :inline_function_patterns - attr_accessor :funcs, :c_attributes, :treat_as_void, :treat_externs - def initialize(cfg) - @funcs = [] @c_strippables = cfg.strippables - @c_attributes = (['const'] + cfg.attributes).uniq + @c_attr_noconst = cfg.attributes.uniq - ['const'] + @c_attributes = ['const'] + c_attr_noconst @c_calling_conventions = cfg.c_calling_conventions.uniq + @treat_as_array = cfg.treat_as_array @treat_as_void = (['void'] + cfg.treat_as_void).uniq - @declaration_parse_matcher = /([\d\w\s\*\(\),\[\]]+??)\(([\d\w\s\*\(\),\.\[\]+-]*)\)$/m - @standards = (['int','short','char','long','unsigned','signed'] + cfg.treat_as.keys).uniq + @function_declaration_parse_base_match = '([\w\s\*\(\),\[\]]+??)\(([\w\s\*\(\),\.\[\]+\-\/]*)\)' + @declaration_parse_matcher = /#{@function_declaration_parse_base_match}$/m + @standards = (%w[int short char long unsigned signed] + cfg.treat_as.keys).uniq + @array_size_name = cfg.array_size_name + @array_size_type = (%w[int size_t] + cfg.array_size_type).uniq @when_no_prototypes = cfg.when_no_prototypes @local_as_void = @treat_as_void @verbosity = cfg.verbosity @treat_externs = cfg.treat_externs - @c_strippables += ['extern'] if (@treat_externs == :include) #we'll need to remove the attribute if we're allowing externs + @treat_inlines = cfg.treat_inlines + @inline_function_patterns = cfg.inline_function_patterns + @c_strippables += ['extern'] if @treat_externs == :include # we'll need to remove the attribute if we're allowing externs + @c_strippables += ['inline'] if @treat_inlines == :include # we'll need to remove the attribute if we're allowing inlines end - + def parse(name, source) - @module_name = name.gsub(/\W/,'') - @typedefs = [] - @funcs = [] + parse_project = { + :module_name => name.gsub(/\W/, ''), + :typedefs => [], + :functions => [], + :normalized_source => nil + } + function_names = [] - - parse_functions( import_source(source) ).map do |decl| - func = parse_declaration(decl) - unless (function_names.include? func[:name]) - @funcs << func + + all_funcs = parse_functions(import_source(source, parse_project)).map { |item| [item] } + all_funcs += parse_cpp_functions(import_source(source, parse_project, true)) + all_funcs.map do |decl| + func = parse_declaration(parse_project, *decl) + unless function_names.include? func[:name] + parse_project[:functions] << func function_names << func[:name] end end - + + parse_project[:normalized_source] = if @treat_inlines == :include + transform_inline_functions(source) + else + '' + end + { :includes => nil, - :functions => @funcs, - :typedefs => @typedefs - } + :functions => parse_project[:functions], + :typedefs => parse_project[:typedefs], + :normalized_source => parse_project[:normalized_source] } end - + private if $ThisIsOnlyATest.nil? ################ - - def import_source(source) + + # Remove C/C++ comments from a string + # +source+:: String which will have the comments removed + def remove_comments_from_source(source) + # 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) + end + + def remove_nested_pairs_of_braces(source) + # remove nested pairs of braces because no function declarations will be inside of them (leave outer pair for function definition detection) + if RUBY_VERSION.split('.')[0].to_i > 1 + # we assign a string first because (no joke) if Ruby 1.9.3 sees this line as a regex, it will crash. + r = '\\{([^\\{\\}]*|\\g<0>)*\\}' + source.gsub!(/#{r}/m, '{ }') + else + while source.gsub!(/\{[^\{\}]*\{[^\{\}]*\}[^\{\}]*\}/m, '{ }') + end + end + + source + end + + # Return the number of pairs of braces/square brackets in the function provided by the user + # +source+:: String containing the function to be processed + def count_number_of_pairs_of_braces_in_function(source) + is_function_start_found = false + curr_level = 0 + total_pairs = 0 + + source.each_char do |c| + if c == '{' + curr_level += 1 + total_pairs += 1 + is_function_start_found = true + elsif c == '}' + curr_level -= 1 + end + + break if is_function_start_found && curr_level == 0 # We reached the end of the inline function body + end + + if curr_level != 0 + total_pairs = 0 # Something is fishy about this source, not enough closing braces? + end + + total_pairs + end + + # Transform inline functions to regular functions in the source by the user + # +source+:: String containing the source to be processed + def transform_inline_functions(source) + inline_function_regex_formats = [] + square_bracket_pair_regex_format = /\{[^\{\}]*\}/ # Regex to match one whole block enclosed by two square brackets + + # Convert user provided string patterns to regex + # Use word bounderies before and after the user regex to limit matching to actual word iso part of a word + @inline_function_patterns.each do |user_format_string| + user_regex = Regexp.new(user_format_string) + word_boundary_before_user_regex = /\b/ + cleanup_spaces_after_user_regex = /[ ]*\b/ + inline_function_regex_formats << Regexp.new(word_boundary_before_user_regex.source + user_regex.source + cleanup_spaces_after_user_regex.source) + end + + # let's clean up the encoding in case they've done anything weird with the characters we might find + source = source.force_encoding('ISO-8859-1').encode('utf-8', :replace => nil) + + # Comments can contain words that will trigger the parser (static|inline|<user_defined_static_keyword>) + remove_comments_from_source(source) + + # smush multiline macros into single line (checking for continuation character at end of line '\') + # If the user uses a macro to declare an inline function, + # smushing the macros makes it easier to recognize them as a macro and if required, + # remove them later on in this function + source.gsub!(/\s*\\\s*/m, ' ') + + # Just looking for static|inline in the gsub is a bit too aggressive (functions that are named like this, ...), so we try to be a bit smarter + # Instead, look for an inline pattern (f.e. "static inline") and parse it. + # Below is a small explanation on how the general mechanism works: + # - Everything before the match should just be copied, we don't want + # to touch anything but the inline functions. + # - Remove the implementation of the inline function (this is enclosed + # in square brackets) and replace it with ";" to complete the + # transformation to normal/non-inline function. + # To ensure proper removal of the function body, we count the number of square-bracket pairs + # and remove the pairs one-by-one. + # - Copy everything after the inline function implementation and start the parsing of the next inline function + # There are ofcourse some special cases (inline macro declarations, inline function declarations, ...) which are handled and explained below + inline_function_regex_formats.each do |format| + inspected_source = '' + regex_matched = false + loop do + inline_function_match = source.match(/#{format}/) # Search for inline function declaration + + if inline_function_match.nil? # No inline functions so nothing to do + # Join pre and post match stripped parts for the next inline function detection regex + source = inspected_source + source if regex_matched == true + break + end + + regex_matched = true + # 1. Determine if we are dealing with a user defined macro to declare inline functions + # If the end of the pre-match string is a macro-declaration-like string, + # we are dealing with a user defined macro to declare inline functions + if /(#define\s*)\z/ =~ inline_function_match.pre_match + # Remove the macro from the source + stripped_pre_match = inline_function_match.pre_match.sub(/(#define\s*)\z/, '') + stripped_post_match = inline_function_match.post_match.sub(/\A(.*[\n]?)/, '') + inspected_source += stripped_pre_match + source = stripped_post_match + next + end + + # 2. Determine if we are dealing with an inline function declaration iso function definition + # If the start of the post-match string is a function-declaration-like string (something ending with semicolon after the function arguments), + # we are dealing with a inline function declaration + if /\A#{@function_declaration_parse_base_match}\s*;/m =~ inline_function_match.post_match + # Only remove the inline part from the function declaration, leaving the function declaration won't do any harm + inspected_source += inline_function_match.pre_match + source = inline_function_match.post_match + next + end + + # 3. If we get here, we found an inline function declaration AND inline function body. + # Remove the function body to transform it into a 'normal' function declaration. + if /\A#{@function_declaration_parse_base_match}\s*\{/m =~ inline_function_match.post_match + total_pairs_to_remove = count_number_of_pairs_of_braces_in_function(inline_function_match.post_match) + + break if total_pairs_to_remove == 0 # Bad source? + + inline_function_stripped = inline_function_match.post_match + + total_pairs_to_remove.times do + inline_function_stripped.sub!(/\s*#{square_bracket_pair_regex_format}/, ';') # Remove inline implementation (+ some whitespace because it's prettier) + end + inspected_source += inline_function_match.pre_match + source = inline_function_stripped + next + end + + # 4. If we get here, it means the regex match, but it is not related to the function (ex. static variable in header) + # Leave this code as it is. + inspected_source += inline_function_match.pre_match + inline_function_match[0] + source = inline_function_match.post_match + end + end + + source + end + + def import_source(source, parse_project, cpp = false) + # let's clean up the encoding in case they've done anything weird with the characters we might find + source = source.force_encoding('ISO-8859-1').encode('utf-8', :replace => nil) # void must be void for cmock _ExpectAndReturn calls to process properly, not some weird typedef which equates to void # to a certain extent, this action assumes we're chewing on pre-processed header files, otherwise we'll most likely just get stuff from @treat_as_void @local_as_void = @treat_as_void - void_types = source.scan(/typedef\s+(?:\(\s*)?void(?:\s*\))?\s+([\w\d]+)\s*;/) + void_types = source.scan(/typedef\s+(?:\(\s*)?void(?:\s*\))?\s+([\w]+)\s*;/) if void_types @local_as_void += void_types.flatten.uniq.compact end - + + # If user wants to mock inline functions, + # remove the (user specific) inline keywords before removing anything else to avoid missing an inline function + if @treat_inlines == :include + @inline_function_patterns.each do |user_format_string| + source.gsub!(/#{user_format_string}/, '') # remove user defined inline function patterns + end + end + # smush multiline macros into single line (checking for continuation character at end of line '\') source.gsub!(/\s*\\\s*/m, ' ') - - #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) + + remove_comments_from_source(source) # remove assembler pragma sections source.gsub!(/^\s*#\s*pragma\s+asm\s+.*?#\s*pragma\s+endasm/m, '') - + # remove gcc's __attribute__ tags - source.gsub(/__attrbute__\s*\(\(\.*\)\)/, '') - - # remove preprocessor statements and extern "C" + source.gsub!(/__attribute(?:__)?\s*\(\(+.*\)\)+/, '') + + # remove preprocessor statements and extern "C" source.gsub!(/^\s*#.*/, '') - source.gsub!(/extern\s+\"C\"\s+\{/, '') - + source.gsub!(/extern\s+\"C\"\s*\{/, '') + # enums, unions, structs, and typedefs can all contain things (e.g. function pointers) that parse like function prototypes, so yank them # forward declared structs are removed before struct definitions so they don't mess up real thing later. we leave structs keywords in function prototypes source.gsub!(/^[\w\s]*struct[^;\{\}\(\)]+;/m, '') # remove forward declared structs - source.gsub!(/^[\w\s]*(enum|union|struct|typepdef)[\w\s]*\{[^\}]+\}[\w\s\*\,]*;/m, '') # remove struct, union, and enum definitions and typedefs with braces - source.gsub!(/(\W)(?:register|auto|static|restrict)(\W)/, '\1\2') # remove problem keywords + source.gsub!(/^[\w\s]*(enum|union|struct|typedef)[\w\s]*\{[^\}]+\}[\w\s\*\,]*;/m, '') # remove struct, union, and enum definitions and typedefs with braces + # remove problem keywords + source.gsub!(/(\W)(?:register|auto|restrict)(\W)/, '\1\2') + source.gsub!(/(\W)(?:static)(\W)/, '\1\2') unless cpp + source.gsub!(/\s*=\s*['"a-zA-Z0-9_\.]+\s*/, '') # remove default value statements from argument lists - source.gsub!(/^(?:[\w\s]*\W)?typedef\W.*/, '') # remove typedef statements - source.gsub!(/(^|\W+)(?:#{@c_strippables.join('|')})(?=$|\W+)/,'\1') unless @c_strippables.empty? # remove known attributes slated to be stripped - - #scan for functions which return function pointers, because they are a pain - source.gsub!(/([\w\s\*]+)\(*\(\s*\*([\w\s\*]+)\s*\(([\w\s\*,]*)\)\)\s*\(([\w\s\*,]*)\)\)*/) do |m| - functype = "cmock_#{@module_name}_func_ptr#{@typedefs.size + 1}" - @typedefs << "typedef #{$1.strip}(*#{functype})(#{$4});" - "#{functype} #{$2.strip}(#{$3});" + source.gsub!(/^(?:[\w\s]*\W)?typedef\W[^;]*/m, '') # remove typedef statements + source.gsub!(/\)(\w)/, ') \1') # add space between parenthese and alphanumeric + source.gsub!(/(^|\W+)(?:#{@c_strippables.join('|')})(?=$|\W+)/, '\1') unless @c_strippables.empty? # remove known attributes slated to be stripped + + # scan standalone function pointers and remove them, because they can just be ignored + source.gsub!(/\w+\s*\(\s*\*\s*\w+\s*\)\s*\([^)]*\)\s*;/, ';') + + # scan for functions which return function pointers, because they are a pain + source.gsub!(/([\w\s\*]+)\(*\(\s*\*([\w\s\*]+)\s*\(([\w\s\*,]*)\)\)\s*\(([\w\s\*,]*)\)\)*/) do |_m| + functype = "cmock_#{parse_project[:module_name]}_func_ptr#{parse_project[:typedefs].size + 1}" + unless cpp # only collect once + parse_project[:typedefs] << "typedef #{Regexp.last_match(1).strip}(*#{functype})(#{Regexp.last_match(4)});" + "#{functype} #{Regexp.last_match(2).strip}(#{Regexp.last_match(3)});" + end + end + + source = remove_nested_pairs_of_braces(source) unless cpp + + if @treat_inlines == :include + # Functions having "{ }" at this point are/were inline functions, + # User wants them in so 'disguise' them as normal functions with the ";" + source.gsub!('{ }', ';') end - - #drop extra white space to make the rest go faster + + # remove function definitions by stripping off the arguments right now + source.gsub!(/\([^\)]*\)\s*\{[^\}]*\}/m, ';') + + # drop extra white space to make the rest go faster source.gsub!(/^\s+/, '') # remove extra white space from beginning of line source.gsub!(/\s+$/, '') # remove extra white space from end of line source.gsub!(/\s*\(\s*/, '(') # remove extra white space from before left parens source.gsub!(/\s*\)\s*/, ')') # remove extra white space from before right parens source.gsub!(/\s+/, ' ') # remove remaining extra white space - - #split lines on semicolons and remove things that are obviously not what we are looking for + + # split lines on semicolons and remove things that are obviously not what we are looking for src_lines = source.split(/\s*;\s*/) - src_lines.delete_if {|line| line.strip.length == 0} # remove blank lines - src_lines.delete_if {|line| !(line =~ /[\w\s\*]+\(+\s*\*[\*\s]*[\w\s]+(?:\[[\w\s]*\]\s*)+\)+\s*\((?:[\w\s\*]*,?)*\s*\)/).nil?} #remove function pointer arrays - if (@treat_externs == :include) - src_lines.delete_if {|line| !(line =~ /(?:^|\s+)(?:inline)\s+/).nil?} # remove inline functions - else - src_lines.delete_if {|line| !(line =~ /(?:^|\s+)(?:extern|inline)\s+/).nil?} # remove inline and extern functions + src_lines = src_lines.uniq unless cpp # must retain closing braces for class/namespace + src_lines.delete_if { |line| line.strip.empty? } # remove blank lines + src_lines.delete_if { |line| !(line =~ /[\w\s\*]+\(+\s*\*[\*\s]*[\w\s]+(?:\[[\w\s]*\]\s*)+\)+\s*\((?:[\w\s\*]*,?)*\s*\)/).nil? } # remove function pointer arrays + + unless @treat_externs == :include + src_lines.delete_if { |line| !(line =~ /(?:^|\s+)(?:extern)\s+/).nil? } # remove extern functions + end + + unless @treat_inlines == :include + src_lines.delete_if { |line| !(line =~ /(?:^|\s+)(?:inline)\s+/).nil? } # remove inline functions end + + src_lines.delete_if(&:empty?) # drop empty lines + end + + # Rudimentary C++ parser - does not handle all situations - e.g.: + # * A namespace function appears after a class with private members (should be parsed) + # * Anonymous namespace (shouldn't parse anything - no matter how nested - within it) + # * A class nested within another class + def parse_cpp_functions(source) + funcs = [] + + ns = [] + pub = false + source.each do |line| + # Search for namespace, class, opening and closing braces + line.scan(/(?:(?:\b(?:namespace|class)\s+(?:\S+)\s*)?{)|}/).each do |item| + if item == '}' + ns.pop + else + token = item.strip.sub(/\s+/, ' ') + ns << token + + pub = false if token.start_with? 'class' + pub = true if token.start_with? 'namespace' + end + end + + pub = true if line =~ /public:/ + pub = false if line =~ /private:/ || line =~ /protected:/ + + # ignore non-public and non-static + next unless pub + next unless line =~ /\bstatic\b/ + + line.sub!(/^.*static/, '') + next unless line =~ @declaration_parse_matcher + + tmp = ns.reject { |item| item == '{' } + + # Identify class name, if any + cls = nil + if tmp[-1].start_with? 'class ' + cls = tmp.pop.sub(/class (\S+) {/, '\1') + end + + # Assemble list of namespaces + tmp.each { |item| item.sub!(/(?:namespace|class) (\S+) {/, '\1') } + + funcs << [line.strip.gsub(/\s+/, ' '), tmp, cls] + end + funcs end def parse_functions(source) funcs = [] - source.each {|line| funcs << line.strip.gsub(/\s+/, ' ') if (line =~ @declaration_parse_matcher)} + source.each { |line| funcs << line.strip.gsub(/\s+/, ' ') if line =~ @declaration_parse_matcher } if funcs.empty? case @when_no_prototypes - when :error - raise "ERROR: No function prototypes found!" - when :warn - puts "WARNING: No function prototypes found!" unless (@verbosity < 1) + when :error + raise 'ERROR: No function prototypes found!' + when :warn + puts 'WARNING: No function prototypes found!' unless @verbosity < 1 end end - return funcs + funcs end - + + def parse_type_and_name(arg) + # Split up words and remove known attributes. For pointer types, make sure + # to remove 'const' only when it applies to the pointer itself, not when it + # applies to the type pointed to. For non-pointer types, remove any + # occurrence of 'const'. + arg.gsub!(/(\w)\*/, '\1 *') # pull asterisks away from preceding word + arg.gsub!(/\*(\w)/, '* \1') # pull asterisks away from following word + arg_array = arg.split + arg_info = divine_ptr_and_const(arg) + arg_info[:name] = arg_array[-1] + + attributes = arg.include?('*') ? @c_attr_noconst : @c_attributes + attr_array = [] + type_array = [] + + arg_array[0..-2].each do |word| + if attributes.include?(word) + attr_array << word + elsif @c_calling_conventions.include?(word) + arg_info[:c_calling_convention] = word + else + type_array << word + end + end + + if arg_info[:const_ptr?] + attr_array << 'const' + type_array.delete_at(type_array.rindex('const')) + end + + arg_info[:modifier] = attr_array.join(' ') + arg_info[:type] = type_array.join(' ').gsub(/\s+\*/, '*') # remove space before asterisks + arg_info + end + def parse_args(arg_list) args = [] arg_list.split(',').each do |arg| - arg.strip! - return args if (arg =~ /^\s*((\.\.\.)|(void))\s*$/) # we're done if we reach void by itself or ... - arg_array = arg.split - arg_elements = arg_array - @c_attributes # split up words and remove known attributes - args << { :type => (arg_type =arg_elements[0..-2].join(' ')), - :name => arg_elements[-1], - :ptr? => divine_ptr(arg_type), - :const? => arg_array.include?('const') - } + arg.strip! + return args if arg =~ /^\s*((\.\.\.)|(void))\s*$/ # we're done if we reach void by itself or ... + + arg_info = parse_type_and_name(arg) + arg_info.delete(:modifier) # don't care about this + arg_info.delete(:c_calling_convention) # don't care about this + + # in C, array arguments implicitly degrade to pointers + # make the translation explicit here to simplify later logic + if @treat_as_array[arg_info[:type]] && !(arg_info[:ptr?]) + arg_info[:type] = "#{@treat_as_array[arg_info[:type]]}*" + arg_info[:type] = "const #{arg_info[:type]}" if arg_info[:const?] + arg_info[:ptr?] = true + end + + args << arg_info + end + + # Try to find array pair in parameters following this pattern : <type> * <name>, <@array_size_type> <@array_size_name> + args.each_with_index do |val, index| + next_index = index + 1 + next unless args.length > next_index + + if (val[:ptr?] == true) && args[next_index][:name].match(@array_size_name) && @array_size_type.include?(args[next_index][:type]) + val[:array_data?] = true + args[next_index][:array_size?] = true + end end - return args + + args end - def divine_ptr(arg_type) - return false unless arg_type.include? '*' - return false if arg_type.gsub(/(const|char|\*|\s)+/,'').empty? - return true + def divine_ptr(arg) + return false unless arg.include? '*' + # treat "const char *" and similar as a string, not a pointer + return false if /(^|\s)(const\s+)?char(\s+const)?\s*\*(?!.*\*)/ =~ arg + + true end - def clean_args(arg_list) - if ((@local_as_void.include?(arg_list.strip)) or (arg_list.empty?)) - return 'void' + def divine_const(arg) + # a non-pointer arg containing "const" is a constant + # an arg containing "const" before the last * is a pointer to a constant + if arg.include?('*') ? (/(^|\s|\*)const(\s(\w|\s)*)?\*(?!.*\*)/ =~ arg) : (/(^|\s)const(\s|$)/ =~ arg) + true else - c=0 - arg_list.gsub!(/(\w+)(?:\s*\[[\s\d\w+-]*\])+/,'*\1') # magically turn brackets into asterisks - arg_list.gsub!(/\s+\*/,'*') # remove space to place asterisks with type (where they belong) - arg_list.gsub!(/\*(\w)/,'* \1') # pull asterisks away from arg to place asterisks with type (where they belong) - - #scan argument list for function pointers and replace them with custom types - arg_list.gsub!(/([\w\s\*]+)\(+\s*\*[\*\s]*([\w\s]*)\s*\)+\s*\(((?:[\w\s\*]*,?)*)\s*\)*/) do |m| - - functype = "cmock_#{@module_name}_func_ptr#{@typedefs.size + 1}" - funcret = $1.strip - funcname = $2.strip - funcargs = $3.strip + false + end + end + + def divine_ptr_and_const(arg) + divination = {} + + divination[:ptr?] = divine_ptr(arg) + divination[:const?] = divine_const(arg) + + # an arg containing "const" after the last * is a constant pointer + divination[:const_ptr?] = /\*(?!.*\*)\s*const(\s|$)/ =~ arg ? true : false + + divination + end + + def clean_args(arg_list, parse_project) + if @local_as_void.include?(arg_list.strip) || arg_list.empty? + 'void' + else + c = 0 + # magically turn brackets into asterisks, also match for parentheses that come from macros + arg_list.gsub!(/(\w+)(?:\s*\[[^\[\]]*\])+/, '*\1') + # remove space to place asterisks with type (where they belong) + arg_list.gsub!(/\s+\*/, '*') + # pull asterisks away from arg to place asterisks with type (where they belong) + arg_list.gsub!(/\*(\w)/, '* \1') + + # scan argument list for function pointers and replace them with custom types + arg_list.gsub!(/([\w\s\*]+)\(+\s*\*[\*\s]*([\w\s]*)\s*\)+\s*\(((?:[\w\s\*]*,?)*)\s*\)*/) do |_m| + functype = "cmock_#{parse_project[:module_name]}_func_ptr#{parse_project[:typedefs].size + 1}" + funcret = Regexp.last_match(1).strip + funcname = Regexp.last_match(2).strip + funcargs = Regexp.last_match(3).strip + funconst = '' + if funcname.include? 'const' + funcname.gsub!('const', '').strip! + funconst = 'const ' + end + parse_project[:typedefs] << "typedef #{funcret}(*#{functype})(#{funcargs});" + funcname = "cmock_arg#{c += 1}" if funcname.empty? + "#{functype} #{funconst}#{funcname}" + end + + # scan argument list for function pointers with shorthand notation and replace them with custom types + arg_list.gsub!(/([\w\s\*]+)+\s+(\w+)\s*\(((?:[\w\s\*]*,?)*)\s*\)*/) do |_m| + functype = "cmock_#{parse_project[:module_name]}_func_ptr#{parse_project[:typedefs].size + 1}" + funcret = Regexp.last_match(1).strip + funcname = Regexp.last_match(2).strip + funcargs = Regexp.last_match(3).strip funconst = '' - if (funcname.include? 'const') - funcname.gsub!('const','').strip! + if funcname.include? 'const' + funcname.gsub!('const', '').strip! funconst = 'const ' end - @typedefs << "typedef #{funcret}(*#{functype})(#{funcargs});" - funcname = "cmock_arg#{c+=1}" if (funcname.empty?) + parse_project[:typedefs] << "typedef #{funcret}(*#{functype})(#{funcargs});" + funcname = "cmock_arg#{c += 1}" if funcname.empty? "#{functype} #{funconst}#{funcname}" end - - #automatically name unnamed arguments (those that only had a type) - arg_list.split(/\s*,\s*/).map { |arg| + + # automatically name unnamed arguments (those that only had a type) + arg_list.split(/\s*,\s*/).map do |arg| parts = (arg.split - ['struct', 'union', 'enum', 'const', 'const*']) - if ((parts.size < 2) or (parts[-1][-1].chr == '*') or (@standards.include?(parts[-1]))) - "#{arg} cmock_arg#{c+=1}" + if (parts.size < 2) || (parts[-1][-1].chr == '*') || @standards.include?(parts[-1]) + "#{arg} cmock_arg#{c += 1}" else arg end - }.join(', ') + end.join(', ') end end - - def parse_declaration(declaration) + + def parse_declaration(parse_project, declaration, namespace = [], classname = nil) decl = {} - + decl[:namespace] = namespace + decl[:class] = classname + regex_match = @declaration_parse_matcher.match(declaration) - raise "Failed parsing function declaration: '#{declaration}'" if regex_match.nil? - - #grab argument list + raise "Failed parsing function declaration: '#{declaration}'" if regex_match.nil? + + # grab argument list args = regex_match[2].strip - #process function attributes, return type, and name - descriptors = regex_match[1] - descriptors.gsub!(/\s+\*/,'*') #remove space to place asterisks with return type (where they belong) - descriptors.gsub!(/\*(\w)/,'* \1') #pull asterisks away from function name to place asterisks with return type (where they belong) - descriptors = descriptors.split #array of all descriptor strings - - #grab name - decl[:name] = descriptors[-1] #snag name as last array item - - #build attribute and return type strings - decl[:modifier] = [] - rettype = [] - descriptors[0..-2].each do |word| - if @c_attributes.include?(word) - decl[:modifier] << word - elsif @c_calling_conventions.include?(word) - decl[:c_calling_convention] = word - else - rettype << word - end + # process function attributes, return type, and name + parsed = parse_type_and_name(regex_match[1]) + + # Record original name without scope prefix + decl[:unscoped_name] = parsed[:name] + + # Prefix name with namespace scope (if any) and then class + decl[:name] = namespace.join('_') + unless classname.nil? + decl[:name] << '_' unless decl[:name].empty? + decl[:name] << classname end - decl[:modifier] = decl[:modifier].join(' ') - rettype = rettype.join(' ') - rettype = 'void' if (@local_as_void.include?(rettype.strip)) - decl[:return] = { :type => rettype, - :name => 'cmock_to_return', - :ptr? => divine_ptr(rettype), - :const? => rettype.split(/\s/).include?('const'), - :str => "#{rettype} cmock_to_return", - :void? => (rettype == 'void') - } - - #remove default argument statements from mock definitions + # Add original name to complete fully scoped name + decl[:name] << '_' unless decl[:name].empty? + decl[:name] << decl[:unscoped_name] + + decl[:modifier] = parsed[:modifier] + unless parsed[:c_calling_convention].nil? + decl[:c_calling_convention] = parsed[:c_calling_convention] + end + + rettype = parsed[:type] + rettype = 'void' if @local_as_void.include?(rettype.strip) + decl[:return] = { :type => rettype, + :name => 'cmock_to_return', + :str => "#{rettype} cmock_to_return", + :void? => (rettype == 'void'), + :ptr? => parsed[:ptr?] || false, + :const? => parsed[:const?] || false, + :const_ptr? => parsed[:const_ptr?] || false } + + # remove default argument statements from mock definitions args.gsub!(/=\s*[a-zA-Z0-9_\.]+\s*/, ' ') - - #check for var args - if (args =~ /\.\.\./) - decl[:var_arg] = args.match( /[\w\s]*\.\.\./ ).to_s.strip - if (args =~ /\,[\w\s]*\.\.\./) - args = args.gsub!(/\,[\w\s]*\.\.\./,'') - else - args = 'void' - end + + # check for var args + if args =~ /\.\.\./ + decl[:var_arg] = args.match(/[\w\s]*\.\.\./).to_s.strip + args = if args =~ /\,[\w\s]*\.\.\./ + args.gsub!(/\,[\w\s]*\.\.\./, '') + else + 'void' + end else decl[:var_arg] = nil end - args = clean_args(args) + args = clean_args(args, parse_project) decl[:args_string] = args decl[:args] = parse_args(args) - decl[:args_call] = decl[:args].map{|a| a[:name]}.join(', ') - decl[:contains_ptr?] = decl[:args].inject(false) {|ptr, arg| arg[:ptr?] ? true : ptr } - - if (decl[:return][:type].nil? or decl[:name].nil? or decl[:args].nil? or - decl[:return][:type].empty? or decl[:name].empty?) - raise "Failed Parsing Declaration Prototype!\n" + - " declaration: '#{declaration}'\n" + - " modifier: '#{decl[:modifier]}'\n" + - " return: #{prototype_inspect_hash(decl[:return])}\n" + - " function: '#{decl[:name]}'\n" + - " args: #{prototype_inspect_array_of_hashes(decl[:args])}\n" + decl[:args_call] = decl[:args].map { |a| a[:name] }.join(', ') + decl[:contains_ptr?] = decl[:args].inject(false) { |ptr, arg| arg[:ptr?] ? true : ptr } + + if decl[:return][:type].nil? || decl[:name].nil? || decl[:args].nil? || + decl[:return][:type].empty? || decl[:name].empty? + raise "Failed Parsing Declaration Prototype!\n" \ + " declaration: '#{declaration}'\n" \ + " modifier: '#{decl[:modifier]}'\n" \ + " return: #{prototype_inspect_hash(decl[:return])}\n" \ + " function: '#{decl[:name]}'\n" \ + " args: #{prototype_inspect_array_of_hashes(decl[:args])}\n" end - return decl + decl end def prototype_inspect_hash(hash) pairs = [] - hash.each_pair { |name, value| pairs << ":#{name} => #{"'" if (value.class == String)}#{value}#{"'" if (value.class == String)}" } - return "{#{pairs.join(', ')}}" + hash.each_pair { |name, value| pairs << ":#{name} => #{"'" if value.class == String}#{value}#{"'" if value.class == String}" } + "{#{pairs.join(', ')}}" end def prototype_inspect_array_of_hashes(array) hashes = [] array.each { |hash| hashes << prototype_inspect_hash(hash) } - case (array.size) + case array.size when 0 - return "[]" + return '[]' when 1 return "[#{hashes[0]}]" else return "[\n #{hashes.join("\n ")}\n ]\n" end end - end diff --git a/vendor/ceedling/vendor/cmock/lib/cmock_plugin_manager.rb b/vendor/ceedling/vendor/cmock/lib/cmock_plugin_manager.rb index eb8f9e8..342014e 100644 --- a/vendor/ceedling/vendor/cmock/lib/cmock_plugin_manager.rb +++ b/vendor/ceedling/vendor/cmock/lib/cmock_plugin_manager.rb @@ -2,39 +2,49 @@ # CMock Project - Automatic Mock Generation for C # Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams # [Released under MIT License. Please refer to license.txt for details] -# ========================================== +# ========================================== class CMockPluginManager - attr_accessor :plugins - + def initialize(config, utils) @plugins = [] plugins_to_load = [:expect, config.plugins].flatten.uniq.compact plugins_to_load.each do |plugin| plugin_name = plugin.to_s - object_name = "CMockGeneratorPlugin" + camelize(plugin_name) - begin - unless (Object.const_defined? object_name) - require "#{File.expand_path(File.dirname(__FILE__))}/cmock_generator_plugin_#{plugin_name.downcase}.rb" - end - @plugins << eval("#{object_name}.new(config, utils)") - rescue - raise "ERROR: CMock unable to load plugin '#{plugin_name}'" - end + object_name = 'CMockGeneratorPlugin' + camelize(plugin_name) + self.class.mutex.synchronize { load_plugin(plugin_name, object_name, config, utils) } end - @plugins.sort! {|a,b| a.priority <=> b.priority } + @plugins.sort! { |a, b| a.priority <=> b.priority } end - - def run(method, args=nil) + + def run(method, args = nil) if args.nil? - return @plugins.collect{ |plugin| plugin.send(method) if plugin.respond_to?(method) }.flatten.join + @plugins.collect { |plugin| plugin.send(method) if plugin.respond_to?(method) }.flatten.join else - return @plugins.collect{ |plugin| plugin.send(method, args) if plugin.respond_to?(method) }.flatten.join + @plugins.collect { |plugin| plugin.send(method, args) if plugin.respond_to?(method) }.flatten.join end end - + def camelize(lower_case_and_underscored_word) - lower_case_and_underscored_word.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase } + lower_case_and_underscored_word.gsub(/\/(.?)/) { '::' + Regexp.last_match(1).upcase }.gsub(/(^|_)(.)/) { Regexp.last_match(2).upcase } + end + + def self.mutex + @mutex ||= Mutex.new + end + + private + + def load_plugin(plugin_name, object_name, config, utils) + unless Object.const_defined? object_name + file_name = "#{__dir__}/cmock_generator_plugin_#{plugin_name.downcase}.rb" + require file_name + end + class_name = Object.const_get(object_name) + @plugins << class_name.new(config, utils) + rescue StandardError + file_name = "#{__dir__}/cmock_generator_plugin_#{plugin_name.downcase}.rb" + raise "ERROR: CMock unable to load plugin '#{plugin_name}' '#{object_name}' #{file_name}" end end diff --git a/vendor/ceedling/vendor/cmock/lib/cmock_unityhelper_parser.rb b/vendor/ceedling/vendor/cmock/lib/cmock_unityhelper_parser.rb index c22db7a..9f4beb7 100644 --- a/vendor/ceedling/vendor/cmock/lib/cmock_unityhelper_parser.rb +++ b/vendor/ceedling/vendor/cmock/lib/cmock_unityhelper_parser.rb @@ -2,74 +2,76 @@ # CMock Project - Automatic Mock Generation for C # Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams # [Released under MIT License. Please refer to license.txt for details] -# ========================================== +# ========================================== class CMockUnityHelperParser - attr_accessor :c_types - + def initialize(config) @config = config @fallback = @config.plugins.include?(:array) ? 'UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY' : 'UNITY_TEST_ASSERT_EQUAL_MEMORY' - @c_types = map_C_types.merge(import_source) + @c_types = map_c_types.merge(import_source) end def get_helper(ctype) - lookup = ctype.gsub(/(?:^|(\S?)(\s*)|(\W))const(?:$|(\s*)(\S)|(\W))/,'\1\3\5\6').strip.gsub(/\s+/,'_') - return [@c_types[lookup], ''] if (@c_types[lookup]) - if (lookup =~ /\*$/) - lookup = lookup.gsub(/\*$/,'') - return [@c_types[lookup], '*'] if (@c_types[lookup]) + lookup = ctype.gsub(/(?:^|(\S?)(\s*)|(\W))const(?:$|(\s*)(\S)|(\W))/, '\1\3\5\6').strip.gsub(/\s+/, '_') + return [@c_types[lookup], ''] if @c_types[lookup] + + if lookup =~ /\*$/ + lookup = lookup.gsub(/\*$/, '') + return [@c_types[lookup], '*'] if @c_types[lookup] else - lookup = lookup + '*' - return [@c_types[lookup], '&'] if (@c_types[lookup]) + lookup += '*' + return [@c_types[lookup], '&'] if @c_types[lookup] end - return ['UNITY_TEST_ASSERT_EQUAL_PTR', ''] if (ctype =~ /cmock_\w+_ptr\d+/) + return ['UNITY_TEST_ASSERT_EQUAL_PTR', ''] if ctype =~ /cmock_\w+_ptr\d+/ raise("Don't know how to test #{ctype} and memory tests are disabled!") unless @config.memcmp_if_unknown - return (lookup =~ /\*$/) ? [@fallback, '&'] : [@fallback, ''] + + lookup =~ /\*$/ ? [@fallback, '&'] : [@fallback, ''] end - + private ########################### - - def map_C_types + + def map_c_types c_types = {} @config.treat_as.each_pair do |ctype, expecttype| - c_type = ctype.gsub(/\s+/,'_') - if (expecttype =~ /\*/) - c_types[c_type] = "UNITY_TEST_ASSERT_EQUAL_#{expecttype.gsub(/\*/,'')}_ARRAY" + c_type = ctype.gsub(/\s+/, '_') + if expecttype =~ /\*/ + c_types[c_type] = "UNITY_TEST_ASSERT_EQUAL_#{expecttype.delete('*')}_ARRAY" else c_types[c_type] = "UNITY_TEST_ASSERT_EQUAL_#{expecttype}" - c_types[c_type+'*'] ||= "UNITY_TEST_ASSERT_EQUAL_#{expecttype}_ARRAY" + c_types[c_type + '*'] ||= "UNITY_TEST_ASSERT_EQUAL_#{expecttype}_ARRAY" end end c_types end - + def import_source source = @config.load_unity_helper return {} if source.nil? + c_types = {} - source = source.gsub(/\/\/.*$/, '') #remove line comments - source = source.gsub(/\/\*.*?\*\//m, '') #remove block comments - - #scan for comparison helpers - match_regex = Regexp.new('^\s*#define\s+(UNITY_TEST_ASSERT_EQUAL_(\w+))\s*\(' + Array.new(4,'\s*\w+\s*').join(',') + '\)') + source = source.gsub(/\/\/.*$/, '') # remove line comments + source = source.gsub(/\/\*.*?\*\//m, '') # remove block comments + + # scan for comparison helpers + match_regex = Regexp.new('^\s*#define\s+(UNITY_TEST_ASSERT_EQUAL_(\w+))\s*\(' + Array.new(4, '\s*\w+\s*').join(',') + '\)') pairs = source.scan(match_regex).flatten.compact - (pairs.size/2).times do |i| - expect = pairs[i*2] - ctype = pairs[(i*2)+1] - c_types[ctype] = expect unless expect.include?("_ARRAY") + (pairs.size / 2).times do |i| + expect = pairs[i * 2] + ctype = pairs[(i * 2) + 1] + c_types[ctype] = expect unless expect.include?('_ARRAY') end - - #scan for array variants of those helpers - match_regex = Regexp.new('^\s*#define\s+(UNITY_TEST_ASSERT_EQUAL_(\w+_ARRAY))\s*\(' + Array.new(5,'\s*\w+\s*').join(',') + '\)') + + # scan for array variants of those helpers + match_regex = Regexp.new('^\s*#define\s+(UNITY_TEST_ASSERT_EQUAL_(\w+_ARRAY))\s*\(' + Array.new(5, '\s*\w+\s*').join(',') + '\)') pairs = source.scan(match_regex).flatten.compact - (pairs.size/2).times do |i| - expect = pairs[i*2] - ctype = pairs[(i*2)+1] - c_types[ctype.gsub('_ARRAY','*')] = expect + (pairs.size / 2).times do |i| + expect = pairs[i * 2] + ctype = pairs[(i * 2) + 1] + c_types[ctype.gsub('_ARRAY', '*')] = expect end - + c_types end end diff --git a/vendor/ceedling/vendor/cmock/release/build.info b/vendor/ceedling/vendor/cmock/release/build.info deleted file mode 100644 index 1f25cde..0000000 --- a/vendor/ceedling/vendor/cmock/release/build.info +++ /dev/null @@ -1,2 +0,0 @@ -212 - diff --git a/vendor/ceedling/vendor/cmock/release/version.info b/vendor/ceedling/vendor/cmock/release/version.info deleted file mode 100644 index 0d71c08..0000000 --- a/vendor/ceedling/vendor/cmock/release/version.info +++ /dev/null @@ -1,2 +0,0 @@ -2.0 - diff --git a/vendor/ceedling/vendor/cmock/src/cmock.c b/vendor/ceedling/vendor/cmock/src/cmock.c index 558e19a..88f2c2b 100644 --- a/vendor/ceedling/vendor/cmock/src/cmock.c +++ b/vendor/ceedling/vendor/cmock/src/cmock.c @@ -4,75 +4,63 @@ [Released under MIT License. Please refer to license.txt for details] ========================================== */ -#include "unity.h" #include "cmock.h" -//define CMOCK_MEM_DYNAMIC to grab memory as needed with malloc -//when you do that, CMOCK_MEM_SIZE is used for incremental size instead of total -#ifdef CMOCK_MEM_STATIC -#undef CMOCK_MEM_DYNAMIC -#endif - -#ifdef CMOCK_MEM_DYNAMIC -#include <stdlib.h> -#endif - -//this is used internally during pointer arithmetic. make sure this type is the same size as the target's pointer type -#ifndef CMOCK_MEM_PTR_AS_INT -#define CMOCK_MEM_PTR_AS_INT unsigned long -#endif - -//0 for no alignment, 1 for 16-bit, 2 for 32-bit, 3 for 64-bit -#ifndef CMOCK_MEM_ALIGN -#define CMOCK_MEM_ALIGN (2) -#endif - -//amount of memory to allow cmock to use in its internal heap -#ifndef CMOCK_MEM_SIZE -#define CMOCK_MEM_SIZE (32768) -#endif - -//automatically calculated defs for easier reading -#define CMOCK_MEM_ALIGN_SIZE (1u << CMOCK_MEM_ALIGN) -#define CMOCK_MEM_ALIGN_MASK (CMOCK_MEM_ALIGN_SIZE - 1) -#define CMOCK_MEM_INDEX_SIZE ((sizeof(CMOCK_MEM_INDEX_TYPE) > CMOCK_MEM_ALIGN_SIZE) ? sizeof(CMOCK_MEM_INDEX_TYPE) : CMOCK_MEM_ALIGN_SIZE) - -//private variables +/* public constants to be used by mocks */ +const char* CMockStringOutOfMemory = "CMock has run out of memory. Please allocate more."; +const char* CMockStringCalledMore = "Called more times than expected."; +const char* CMockStringCalledLess = "Called fewer times than expected."; +const char* CMockStringCalledEarly = "Called earlier than expected."; +const char* CMockStringCalledLate = "Called later than expected."; +const char* CMockStringCallOrder = "Called out of order."; +const char* CMockStringIgnPreExp = "IgnoreArg called before Expect."; +const char* CMockStringPtrPreExp = "ReturnThruPtr called before Expect."; +const char* CMockStringPtrIsNULL = "Pointer is NULL."; +const char* CMockStringExpNULL = "Expected NULL."; +const char* CMockStringMismatch = "Function called with unexpected argument value."; + +/* private variables */ #ifdef CMOCK_MEM_DYNAMIC static unsigned char* CMock_Guts_Buffer = NULL; static CMOCK_MEM_INDEX_TYPE CMock_Guts_BufferSize = CMOCK_MEM_ALIGN_SIZE; -static CMOCK_MEM_INDEX_TYPE CMock_Guts_FreePtr; +static CMOCK_MEM_INDEX_TYPE CMock_Guts_FreePtr = CMOCK_MEM_ALIGN_SIZE; #else static unsigned char CMock_Guts_Buffer[CMOCK_MEM_SIZE + CMOCK_MEM_ALIGN_SIZE]; static CMOCK_MEM_INDEX_TYPE CMock_Guts_BufferSize = CMOCK_MEM_SIZE + CMOCK_MEM_ALIGN_SIZE; -static CMOCK_MEM_INDEX_TYPE CMock_Guts_FreePtr; +static CMOCK_MEM_INDEX_TYPE CMock_Guts_FreePtr = CMOCK_MEM_ALIGN_SIZE; #endif -//------------------------------------------------------- -// CMock_Guts_MemNew -//------------------------------------------------------- + +/*------------------------------------------------------- + * CMock_Guts_MemNew + *-------------------------------------------------------*/ CMOCK_MEM_INDEX_TYPE CMock_Guts_MemNew(CMOCK_MEM_INDEX_TYPE size) { CMOCK_MEM_INDEX_TYPE index; - //verify arguments valid (we must be allocating space for at least 1 byte, and the existing chain must be in memory somewhere) + /* verify arguments valid (we must be allocating space for at least 1 byte, and the existing chain must be in memory somewhere) */ if (size < 1) return CMOCK_GUTS_NONE; - //verify we have enough room + /* verify we have enough room */ size = size + CMOCK_MEM_INDEX_SIZE; if (size & CMOCK_MEM_ALIGN_MASK) size = (size + CMOCK_MEM_ALIGN_MASK) & ~CMOCK_MEM_ALIGN_MASK; if ((CMock_Guts_BufferSize - CMock_Guts_FreePtr) < size) { -#ifdef CMOCK_MEM_DYNAMIC - CMock_Guts_BufferSize += CMOCK_MEM_SIZE + size; - CMock_Guts_Buffer = realloc(CMock_Guts_Buffer, CMock_Guts_BufferSize); - if (CMock_Guts_Buffer == NULL) -#endif //yes that if will continue to the return below if TRUE - return CMOCK_GUTS_NONE; +#ifndef CMOCK_MEM_DYNAMIC + return CMOCK_GUTS_NONE; /* nothing we can do; our static buffer is out of memory */ +#else + /* our dynamic buffer does not have enough room; request more via realloc() */ + CMOCK_MEM_INDEX_TYPE new_buffersize = CMock_Guts_BufferSize + CMOCK_MEM_SIZE + size; + unsigned char* new_buffer = realloc(CMock_Guts_Buffer, (size_t)new_buffersize); + if (new_buffer == NULL) + return CMOCK_GUTS_NONE; /* realloc() failed; out of memory */ + CMock_Guts_Buffer = new_buffer; + CMock_Guts_BufferSize = new_buffersize; +#endif } - //determine where we're putting this new block, and init its pointer to be the end of the line + /* determine where we're putting this new block, and init its pointer to be the end of the line */ index = CMock_Guts_FreePtr + CMOCK_MEM_INDEX_SIZE; *(CMOCK_MEM_INDEX_TYPE*)(&CMock_Guts_Buffer[CMock_Guts_FreePtr]) = CMOCK_GUTS_NONE; CMock_Guts_FreePtr += size; @@ -80,9 +68,9 @@ CMOCK_MEM_INDEX_TYPE CMock_Guts_MemNew(CMOCK_MEM_INDEX_TYPE size) return index; } -//------------------------------------------------------- -// CMock_Guts_MemChain -//------------------------------------------------------- +/*------------------------------------------------------- + * CMock_Guts_MemChain + *-------------------------------------------------------*/ CMOCK_MEM_INDEX_TYPE CMock_Guts_MemChain(CMOCK_MEM_INDEX_TYPE root_index, CMOCK_MEM_INDEX_TYPE obj_index) { CMOCK_MEM_INDEX_TYPE index; @@ -92,12 +80,12 @@ CMOCK_MEM_INDEX_TYPE CMock_Guts_MemChain(CMOCK_MEM_INDEX_TYPE root_index, CMOCK_ if (root_index == CMOCK_GUTS_NONE) { - //if there is no root currently, we return this object as the root of the chain + /* if there is no root currently, we return this object as the root of the chain */ return obj_index; } else { - //reject illegal nodes + /* reject illegal nodes */ if ((root_index < CMOCK_MEM_ALIGN_SIZE) || (root_index >= CMock_Guts_FreePtr)) { return CMOCK_GUTS_NONE; @@ -106,11 +94,11 @@ CMOCK_MEM_INDEX_TYPE CMock_Guts_MemChain(CMOCK_MEM_INDEX_TYPE root_index, CMOCK_ { return CMOCK_GUTS_NONE; } - + root = (void*)(&CMock_Guts_Buffer[root_index]); obj = (void*)(&CMock_Guts_Buffer[obj_index]); - //find the end of the existing chain and add us + /* find the end of the existing chain and add us */ next = root; do { index = *(CMOCK_MEM_INDEX_TYPE*)((CMOCK_MEM_PTR_AS_INT)next - CMOCK_MEM_INDEX_SIZE); @@ -119,26 +107,26 @@ CMOCK_MEM_INDEX_TYPE CMock_Guts_MemChain(CMOCK_MEM_INDEX_TYPE root_index, CMOCK_ if (index > 0) next = (void*)(&CMock_Guts_Buffer[index]); } while (index > 0); - *(CMOCK_MEM_INDEX_TYPE*)((CMOCK_MEM_PTR_AS_INT)next - CMOCK_MEM_INDEX_SIZE) = ((CMOCK_MEM_PTR_AS_INT)obj - (CMOCK_MEM_PTR_AS_INT)CMock_Guts_Buffer); + *(CMOCK_MEM_INDEX_TYPE*)((CMOCK_MEM_PTR_AS_INT)next - CMOCK_MEM_INDEX_SIZE) = (CMOCK_MEM_INDEX_TYPE)((CMOCK_MEM_PTR_AS_INT)obj - (CMOCK_MEM_PTR_AS_INT)CMock_Guts_Buffer); return root_index; } } -//------------------------------------------------------- -// CMock_Guts_MemNext -//------------------------------------------------------- +/*------------------------------------------------------- + * CMock_Guts_MemNext + *-------------------------------------------------------*/ CMOCK_MEM_INDEX_TYPE CMock_Guts_MemNext(CMOCK_MEM_INDEX_TYPE previous_item_index) { CMOCK_MEM_INDEX_TYPE index; void* previous_item; - //There is nothing "next" if the pointer isn't from our buffer + /* There is nothing "next" if the pointer isn't from our buffer */ if ((previous_item_index < CMOCK_MEM_ALIGN_SIZE) || (previous_item_index >= CMock_Guts_FreePtr)) return CMOCK_GUTS_NONE; previous_item = (void*)(&CMock_Guts_Buffer[previous_item_index]); - //if the pointer is good, then use it to look up the next index - //(we know the first element always goes in zero, so NEXT must always be > 1) + /* if the pointer is good, then use it to look up the next index + * (we know the first element always goes in zero, so NEXT must always be > 1) */ index = *(CMOCK_MEM_INDEX_TYPE*)((CMOCK_MEM_PTR_AS_INT)previous_item - CMOCK_MEM_INDEX_SIZE); if ((index > 1) && (index < CMock_Guts_FreePtr)) return index; @@ -146,9 +134,27 @@ CMOCK_MEM_INDEX_TYPE CMock_Guts_MemNext(CMOCK_MEM_INDEX_TYPE previous_item_index return CMOCK_GUTS_NONE; } -//------------------------------------------------------- -// CMock_GetAddressFor -//------------------------------------------------------- +/*------------------------------------------------------- + * CMock_Guts_MemEndOfChain + *-------------------------------------------------------*/ +CMOCK_MEM_INDEX_TYPE CMock_Guts_MemEndOfChain(CMOCK_MEM_INDEX_TYPE root_index) +{ + CMOCK_MEM_INDEX_TYPE index = root_index; + CMOCK_MEM_INDEX_TYPE next_index; + + for (next_index = root_index; + next_index != CMOCK_GUTS_NONE; + next_index = CMock_Guts_MemNext(index)) + { + index = next_index; + } + + return index; +} + +/*------------------------------------------------------- + * CMock_GetAddressFor + *-------------------------------------------------------*/ void* CMock_Guts_GetAddressFor(CMOCK_MEM_INDEX_TYPE index) { if ((index >= CMOCK_MEM_ALIGN_SIZE) && (index < CMock_Guts_FreePtr)) @@ -161,26 +167,50 @@ void* CMock_Guts_GetAddressFor(CMOCK_MEM_INDEX_TYPE index) } } -//------------------------------------------------------- -// CMock_Guts_MemBytesFree -//------------------------------------------------------- +/*------------------------------------------------------- + * CMock_Guts_MemBytesCapacity + *-------------------------------------------------------*/ +CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesCapacity(void) +{ + return (sizeof(CMock_Guts_Buffer) - CMOCK_MEM_ALIGN_SIZE); +} + +/*------------------------------------------------------- + * CMock_Guts_MemBytesFree + *-------------------------------------------------------*/ CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesFree(void) { return CMock_Guts_BufferSize - CMock_Guts_FreePtr; } -//------------------------------------------------------- -// CMock_Guts_MemBytesUsed -//------------------------------------------------------- +/*------------------------------------------------------- + * CMock_Guts_MemBytesUsed + *-------------------------------------------------------*/ CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesUsed(void) { return CMock_Guts_FreePtr - CMOCK_MEM_ALIGN_SIZE; } -//------------------------------------------------------- -// CMock_Guts_MemFreeAll -//------------------------------------------------------- +/*------------------------------------------------------- + * CMock_Guts_MemFreeAll + *-------------------------------------------------------*/ void CMock_Guts_MemFreeAll(void) { - CMock_Guts_FreePtr = CMOCK_MEM_ALIGN_SIZE; //skip the very beginning + CMock_Guts_FreePtr = CMOCK_MEM_ALIGN_SIZE; /* skip the very beginning */ } + +/*------------------------------------------------------- + * CMock_Guts_MemFreeFinal + *-------------------------------------------------------*/ +void CMock_Guts_MemFreeFinal(void) +{ + CMock_Guts_FreePtr = CMOCK_MEM_ALIGN_SIZE; +#ifdef CMOCK_MEM_DYNAMIC + if (CMock_Guts_Buffer) + { + free(CMock_Guts_Buffer); + CMock_Guts_Buffer = NULL; + } +#endif +} + diff --git a/vendor/ceedling/vendor/cmock/src/cmock.h b/vendor/ceedling/vendor/cmock/src/cmock.h index a43e9e0..45bab18 100644 --- a/vendor/ceedling/vendor/cmock/src/cmock.h +++ b/vendor/ceedling/vendor/cmock/src/cmock.h @@ -7,24 +7,41 @@ #ifndef CMOCK_FRAMEWORK_H #define CMOCK_FRAMEWORK_H -//should be big enough to index full range of CMOCK_MEM_MAX +#include "cmock_internals.h" + +#define CMOCK_VERSION_MAJOR 2 +#define CMOCK_VERSION_MINOR 5 +#define CMOCK_VERSION_BUILD 4 +#define CMOCK_VERSION ((CMOCK_VERSION_MAJOR << 16) | (CMOCK_VERSION_MINOR << 8) | CMOCK_VERSION_BUILD) + +/* should be big enough to index full range of CMOCK_MEM_MAX */ #ifndef CMOCK_MEM_INDEX_TYPE -#define CMOCK_MEM_INDEX_TYPE unsigned int +#include <stddef.h> +#define CMOCK_MEM_INDEX_TYPE size_t #endif -#define CMOCK_GUTS_NONE (0) +#define CMOCK_GUTS_NONE (0) + +#if defined __GNUC__ +# define CMOCK_FUNCTION_ATTR(a) __attribute__((a)) +#else +# define CMOCK_FUNCTION_ATTR(a) /* ignore */ +#endif -//------------------------------------------------------- -// Memory API -//------------------------------------------------------- +/*------------------------------------------------------- + * Memory API + *-------------------------------------------------------*/ CMOCK_MEM_INDEX_TYPE CMock_Guts_MemNew(CMOCK_MEM_INDEX_TYPE size); CMOCK_MEM_INDEX_TYPE CMock_Guts_MemChain(CMOCK_MEM_INDEX_TYPE root_index, CMOCK_MEM_INDEX_TYPE obj_index); -CMOCK_MEM_INDEX_TYPE CMock_Guts_MemNext(CMOCK_MEM_INDEX_TYPE previous_item_index); +CMOCK_MEM_INDEX_TYPE CMock_Guts_MemNext(CMOCK_MEM_INDEX_TYPE previous_item_index) CMOCK_FUNCTION_ATTR(pure); +CMOCK_MEM_INDEX_TYPE CMock_Guts_MemEndOfChain(CMOCK_MEM_INDEX_TYPE root_index) CMOCK_FUNCTION_ATTR(pure); -void* CMock_Guts_GetAddressFor(CMOCK_MEM_INDEX_TYPE index); +void* CMock_Guts_GetAddressFor(CMOCK_MEM_INDEX_TYPE index) CMOCK_FUNCTION_ATTR(pure); -CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesFree(void); -CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesUsed(void); +CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesCapacity(void) CMOCK_FUNCTION_ATTR(const); +CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesFree(void) CMOCK_FUNCTION_ATTR(pure); +CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesUsed(void) CMOCK_FUNCTION_ATTR(pure); void CMock_Guts_MemFreeAll(void); +void CMock_Guts_MemFreeFinal(void); -#endif //CMOCK_FRAMEWORK +#endif /* end of CMOCK_FRAMEWORK_H */ diff --git a/vendor/ceedling/vendor/cmock/src/cmock_internals.h b/vendor/ceedling/vendor/cmock/src/cmock_internals.h new file mode 100644 index 0000000..56fb33b --- /dev/null +++ b/vendor/ceedling/vendor/cmock/src/cmock_internals.h @@ -0,0 +1,91 @@ +/* ========================================== + CMock Project - Automatic Mock Generation for C + Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams + [Released under MIT License. Please refer to license.txt for details] +========================================== */ + +#ifndef CMOCK_FRAMEWORK_INTERNALS_H +#define CMOCK_FRAMEWORK_INTERNALS_H + +#include "unity.h" + +/* These are constants that the generated mocks have access to */ +extern const char* CMockStringOutOfMemory; +extern const char* CMockStringCalledMore; +extern const char* CMockStringCalledLess; +extern const char* CMockStringCalledEarly; +extern const char* CMockStringCalledLate; +extern const char* CMockStringCallOrder; +extern const char* CMockStringIgnPreExp; +extern const char* CMockStringPtrPreExp; +extern const char* CMockStringPtrIsNULL; +extern const char* CMockStringExpNULL; +extern const char* CMockStringMismatch; + +/* define CMOCK_MEM_DYNAMIC to grab memory as needed with malloc + * when you do that, CMOCK_MEM_SIZE is used for incremental size instead of total */ +#ifdef CMOCK_MEM_STATIC +#undef CMOCK_MEM_DYNAMIC +#endif + +#ifdef CMOCK_MEM_DYNAMIC +#include <stdlib.h> +#endif + +/* this is used internally during pointer arithmetic. make sure this type is the same size as the target's pointer type */ +#ifndef CMOCK_MEM_PTR_AS_INT +#ifdef UNITY_POINTER_WIDTH +#ifdef UNITY_INT_WIDTH +#if UNITY_POINTER_WIDTH == UNITY_INT_WIDTH +#define CMOCK_MEM_PTR_AS_INT unsigned int +#endif +#endif +#endif +#endif + +#ifndef CMOCK_MEM_PTR_AS_INT +#ifdef UNITY_POINTER_WIDTH +#ifdef UNITY_LONG_WIDTH +#if UNITY_POINTER_WIDTH == UNITY_LONG_WIDTH +#define CMOCK_MEM_PTR_AS_INT unsigned long +#endif +#if UNITY_POINTER_WIDTH > UNITY_LONG_WIDTH +#define CMOCK_MEM_PTR_AS_INT unsigned long long +#endif +#endif +#endif +#endif + +#ifndef CMOCK_MEM_PTR_AS_INT +#define CMOCK_MEM_PTR_AS_INT unsigned long +#endif + +/* 0 for no alignment, 1 for 16-bit, 2 for 32-bit, 3 for 64-bit */ +#ifndef CMOCK_MEM_ALIGN + #ifdef UNITY_LONG_WIDTH + #if (UNITY_LONG_WIDTH == 16) + #define CMOCK_MEM_ALIGN (1) + #elif (UNITY_LONG_WIDTH == 32) + #define CMOCK_MEM_ALIGN (2) + #elif (UNITY_LONG_WIDTH == 64) + #define CMOCK_MEM_ALIGN (3) + #else + #define CMOCK_MEM_ALIGN (2) + #endif + #else + #define CMOCK_MEM_ALIGN (2) + #endif +#endif + +/* amount of memory to allow cmock to use in its internal heap */ +#ifndef CMOCK_MEM_SIZE +#define CMOCK_MEM_SIZE (32768) +#endif + +/* automatically calculated defs for easier reading */ +#define CMOCK_MEM_ALIGN_SIZE (CMOCK_MEM_INDEX_TYPE)(1u << CMOCK_MEM_ALIGN) +#define CMOCK_MEM_ALIGN_MASK (CMOCK_MEM_INDEX_TYPE)(CMOCK_MEM_ALIGN_SIZE - 1) +#define CMOCK_MEM_INDEX_SIZE (CMOCK_MEM_INDEX_TYPE)(CMOCK_MEM_PTR_AS_INT)((sizeof(CMOCK_MEM_INDEX_TYPE) > CMOCK_MEM_ALIGN_SIZE) ? sizeof(CMOCK_MEM_INDEX_TYPE) : CMOCK_MEM_ALIGN_SIZE) + + +#endif /* end of CMOCK_FRAMEWORK_INTERNALS_H */ diff --git a/vendor/ceedling/vendor/cmock/src/meson.build b/vendor/ceedling/vendor/cmock/src/meson.build new file mode 100644 index 0000000..c03c4e5 --- /dev/null +++ b/vendor/ceedling/vendor/cmock/src/meson.build @@ -0,0 +1,12 @@ +# +# build script written by : Michael Brockus. +# github repo author: Mike Karlesky, Mark VanderVoord, Greg Williams. +# +# license: MIT +# +cmock_dir = include_directories('.') + +cmock_lib = static_library(meson.project_name(), + files('cmock.c'), + dependencies: [unity_dep], + include_directories: cmock_dir) diff --git a/vendor/ceedling/vendor/constructor/lib/constructor.rb b/vendor/ceedling/vendor/constructor/lib/constructor.rb deleted file mode 100644 index 87eb6dd..0000000 --- a/vendor/ceedling/vendor/constructor/lib/constructor.rb +++ /dev/null @@ -1,127 +0,0 @@ -CONSTRUCTOR_VERSION = '1.0.4' #:nodoc:# - -class Class #:nodoc:# - def constructor(*attrs, &block) - call_block = '' - if block_given? - @constructor_block = block - call_block = 'self.instance_eval(&self.class.constructor_block)' - end - # Look for embedded options in the listing: - opts = attrs.find { |a| a.kind_of?(Hash) and attrs.delete(a) } - do_acc = opts.nil? ? false : opts[:accessors] == true - do_reader = opts.nil? ? false : opts[:readers] == true - require_args = opts.nil? ? true : opts[:strict] != false - super_args = opts.nil? ? nil : opts[:super] - - # Incorporate superclass's constructor keys, if our superclass - if superclass.constructor_keys - similar_keys = superclass.constructor_keys & attrs - raise "Base class already has keys #{similar_keys.inspect}" unless similar_keys.empty? - attrs = [attrs,superclass.constructor_keys].flatten - end - # Generate ivar assigner code lines - assigns = '' - attrs.each do |k| - assigns += "@#{k.to_s} = args[:#{k.to_s}]\n" - end - - # If accessors option is on, declare accessors for the attributes: - if do_acc - add_accessors = "attr_accessor " + attrs.reject {|x| superclass.constructor_keys.include?(x.to_sym)}.map {|x| ":#{x.to_s}"}.join(',') - #add_accessors = "attr_accessor " + attrs.map {|x| ":#{x.to_s}"}.join(',') - self.class_eval add_accessors - end - - # If readers option is on, declare readers for the attributes: - if do_reader - self.class_eval "attr_reader " + attrs.reject {|x| superclass.constructor_keys.include?(x.to_sym)}.map {|x| ":#{x.to_s}"}.join(',') - end - - # If user supplied super-constructor hints: - super_call = '' - if super_args - list = super_args.map do |a| - case a - when String - %|"#{a}"| - when Symbol - %|:#{a}| - end - end - super_call = %|super(#{list.join(',')})| - end - - # If strict is on, define the constructor argument validator method, - # and setup the initializer to invoke the validator method. - # Otherwise, insert lax code into the initializer. - validation_code = "return if args.nil?" - if require_args - self.class_eval do - def _validate_constructor_args(args) - # First, make sure we've got args of some kind - unless args and args.keys and args.keys.size > 0 - raise ConstructorArgumentError.new(self.class.constructor_keys) - end - # Scan for missing keys in the argument hash - a_keys = args.keys - missing = [] - self.class.constructor_keys.each do |ck| - unless a_keys.member?(ck) - missing << ck - end - a_keys.delete(ck) # Delete inbound keys as we address them - end - if missing.size > 0 || a_keys.size > 0 - raise ConstructorArgumentError.new(missing,a_keys) - end - end - end - # Setup the code to insert into the initializer: - validation_code = "_validate_constructor_args args " - end - - # Generate the initializer code - self.class_eval %{ - def initialize(args=nil) - #{super_call} - #{validation_code} - #{assigns} - setup if respond_to?(:setup) - #{call_block} - end - } - - # Remember our constructor keys - @_ctor_keys = attrs - end - - # Access the constructor keys for this class - def constructor_keys; @_ctor_keys ||=[]; end - - def constructor_block #:nodoc:# - @constructor_block - end - -end - -# Fancy validation exception, based on missing and extraneous keys. -class ConstructorArgumentError < RuntimeError #:nodoc:# - def initialize(missing,rejected=[]) - err_msg = '' - if missing.size > 0 - err_msg = "Missing constructor args [#{missing.join(',')}]" - end - if rejected.size > 0 - # Some inbound keys were not addressed earlier; this means they're unwanted - if err_msg - err_msg << "; " # Appending to earlier message about missing items - else - err_msg = '' - end - # Enumerate the rejected key names - err_msg << "Rejected constructor args [#{rejected.join(',')}]" - end - super err_msg - end -end diff --git a/vendor/ceedling/vendor/constructor/lib/constructor_struct.rb b/vendor/ceedling/vendor/constructor/lib/constructor_struct.rb deleted file mode 100644 index e97ff62..0000000 --- a/vendor/ceedling/vendor/constructor/lib/constructor_struct.rb +++ /dev/null @@ -1,33 +0,0 @@ -class ConstructorStruct - def self.new(*accessors, &block) - defaults = {:accessors => true, :strict => false} - - accessor_names = accessors.dup - if accessors.last.is_a? Hash - accessor_names.pop - user_opts = accessors.last - user_opts.delete(:accessors) - defaults.each do |k,v| - user_opts[k] ||= v - end - else - accessors << defaults - end - - Class.new do - constructor *accessors - - class_eval(&block) if block - - comparator_code = accessor_names.map { |fname| "self.#{fname} == o.#{fname}" }.join(" && ") - eval %| - def ==(o) - (self.class == o.class) && #{comparator_code} - end - def eql?(o) - (self.class == o.class) && #{comparator_code} - end - | - end - end -end diff --git a/vendor/ceedling/vendor/deep_merge/lib/deep_merge.rb b/vendor/ceedling/vendor/deep_merge/lib/deep_merge.rb deleted file mode 100644 index 4c4b761..0000000 --- a/vendor/ceedling/vendor/deep_merge/lib/deep_merge.rb +++ /dev/null @@ -1,211 +0,0 @@ -module DeepMerge - - MAJOR_VERSION = 0 - MINOR_VERSION = 1 - FIX_VERSION = 0 - VERSION = "#{MAJOR_VERSION}.#{MINOR_VERSION}.#{FIX_VERSION}" - - class InvalidParameter < StandardError; end - - DEFAULT_FIELD_KNOCKOUT_PREFIX = '--' - - module DeepMergeHash - # ko_hash_merge! will merge and knockout elements prefixed with DEFAULT_FIELD_KNOCKOUT_PREFIX - def ko_deep_merge!(source, options = {}) - default_opts = {:knockout_prefix => "--", :preserve_unmergeables => false} - DeepMerge::deep_merge!(source, self, default_opts.merge(options)) - end - - # deep_merge! will merge and overwrite any unmergeables in destination hash - def deep_merge!(source, options = {}) - default_opts = {:preserve_unmergeables => false} - DeepMerge::deep_merge!(source, self, default_opts.merge(options)) - end - - # deep_merge will merge and skip any unmergeables in destination hash - def deep_merge(source, options = {}) - default_opts = {:preserve_unmergeables => true} - DeepMerge::deep_merge!(source, self, default_opts.merge(options)) - end - - end # DeepMergeHashExt - - # Deep Merge core documentation. - # deep_merge! method permits merging of arbitrary child elements. The two top level - # elements must be hashes. These hashes can contain unlimited (to stack limit) levels - # of child elements. These child elements to not have to be of the same types. - # Where child elements are of the same type, deep_merge will attempt to merge them together. - # Where child elements are not of the same type, deep_merge will skip or optionally overwrite - # the destination element with the contents of the source element at that level. - # So if you have two hashes like this: - # source = {:x => [1,2,3], :y => 2} - # dest = {:x => [4,5,'6'], :y => [7,8,9]} - # dest.deep_merge!(source) - # Results: {:x => [1,2,3,4,5,'6'], :y => 2} - # By default, "deep_merge!" will overwrite any unmergeables and merge everything else. - # To avoid this, use "deep_merge" (no bang/exclamation mark) - # - # Options: - # Options are specified in the last parameter passed, which should be in hash format: - # hash.deep_merge!({:x => [1,2]}, {:knockout_prefix => '--'}) - # :preserve_unmergeables DEFAULT: false - # Set to true to skip any unmergeable elements from source - # :knockout_prefix DEFAULT: nil - # Set to string value to signify prefix which deletes elements from existing element - # :sort_merged_arrays DEFAULT: false - # Set to true to sort all arrays that are merged together - # :unpack_arrays DEFAULT: nil - # Set to string value to run "Array::join" then "String::split" against all arrays - # :merge_debug DEFAULT: false - # Set to true to get console output of merge process for debugging - # - # Selected Options Details: - # :knockout_prefix => The purpose of this is to provide a way to remove elements - # from existing Hash by specifying them in a special way in incoming hash - # source = {:x => ['--1', '2']} - # dest = {:x => ['1', '3']} - # dest.ko_deep_merge!(source) - # Results: {:x => ['2','3']} - # Additionally, if the knockout_prefix is passed alone as a string, it will cause - # the entire element to be removed: - # source = {:x => '--'} - # dest = {:x => [1,2,3]} - # dest.ko_deep_merge!(source) - # Results: {:x => ""} - # :unpack_arrays => The purpose of this is to permit compound elements to be passed - # in as strings and to be converted into discrete array elements - # irsource = {:x => ['1,2,3', '4']} - # dest = {:x => ['5','6','7,8']} - # dest.deep_merge!(source, {:unpack_arrays => ','}) - # Results: {:x => ['1','2','3','4','5','6','7','8'} - # Why: If receiving data from an HTML form, this makes it easy for a checkbox - # to pass multiple values from within a single HTML element - # - # There are many tests for this library - and you can learn more about the features - # and usages of deep_merge! by just browsing the test examples - def DeepMerge.deep_merge!(source, dest, options = {}) - # turn on this line for stdout debugging text - merge_debug = options[:merge_debug] || false - overwrite_unmergeable = !options[:preserve_unmergeables] - knockout_prefix = options[:knockout_prefix] || nil - if knockout_prefix == "" then raise InvalidParameter, "knockout_prefix cannot be an empty string in deep_merge!"; end - if knockout_prefix && !overwrite_unmergeable then raise InvalidParameter, "overwrite_unmergeable must be true if knockout_prefix is specified in deep_merge!"; end - # if present: we will split and join arrays on this char before merging - array_split_char = options[:unpack_arrays] || false - # request that we sort together any arrays when they are merged - sort_merged_arrays = options[:sort_merged_arrays] || false - di = options[:debug_indent] || '' - # do nothing if source is nil - if source.nil? || (source.respond_to?(:blank?) && source.blank?) then return dest; end - # if dest doesn't exist, then simply copy source to it - if dest.nil? && overwrite_unmergeable then dest = source; return dest; end - - puts "#{di}Source class: #{source.class.inspect} :: Dest class: #{dest.class.inspect}" if merge_debug - if source.kind_of?(Hash) - puts "#{di}Hashes: #{source.inspect} :: #{dest.inspect}" if merge_debug - source.each do |src_key, src_value| - if dest.kind_of?(Hash) - puts "#{di} looping: #{src_key.inspect} => #{src_value.inspect} :: #{dest.inspect}" if merge_debug - if not dest[src_key].nil? - puts "#{di} ==>merging: #{src_key.inspect} => #{src_value.inspect} :: #{dest[src_key].inspect}" if merge_debug - dest[src_key] = deep_merge!(src_value, dest[src_key], options.merge(:debug_indent => di + ' ')) - else # dest[src_key] doesn't exist so we want to create and overwrite it (but we do this via deep_merge!) - puts "#{di} ==>merging over: #{src_key.inspect} => #{src_value.inspect}" if merge_debug - # note: we rescue here b/c some classes respond to "dup" but don't implement it (Numeric, TrueClass, FalseClass, NilClass among maybe others) - begin - src_dup = src_value.dup # we dup src_value if possible because we're going to merge into it (since dest is empty) - rescue TypeError - src_dup = src_value - end - dest[src_key] = deep_merge!(src_value, src_dup, options.merge(:debug_indent => di + ' ')) - end - else # dest isn't a hash, so we overwrite it completely (if permitted) - if overwrite_unmergeable - puts "#{di} overwriting dest: #{src_key.inspect} => #{src_value.inspect} -over-> #{dest.inspect}" if merge_debug - dest = overwrite_unmergeables(source, dest, options) - end - end - end - elsif source.kind_of?(Array) - puts "#{di}Arrays: #{source.inspect} :: #{dest.inspect}" if merge_debug - # if we are instructed, join/split any source arrays before processing - if array_split_char - puts "#{di} split/join on source: #{source.inspect}" if merge_debug - source = source.join(array_split_char).split(array_split_char) - if dest.kind_of?(Array) then dest = dest.join(array_split_char).split(array_split_char); end - end - # if there's a naked knockout_prefix in source, that means we are to truncate dest - if source.index(knockout_prefix) then dest = clear_or_nil(dest); source.delete(knockout_prefix); end - if dest.kind_of?(Array) - if knockout_prefix - print "#{di} knocking out: " if merge_debug - # remove knockout prefix items from both source and dest - source.delete_if do |ko_item| - retval = false - item = ko_item.respond_to?(:gsub) ? ko_item.gsub(%r{^#{knockout_prefix}}, "") : ko_item - if item != ko_item - print "#{ko_item} - " if merge_debug - dest.delete(item) - dest.delete(ko_item) - retval = true - end - retval - end - puts if merge_debug - end - puts "#{di} merging arrays: #{source.inspect} :: #{dest.inspect}" if merge_debug - dest = dest | source - if sort_merged_arrays then dest.sort!; end - elsif overwrite_unmergeable - puts "#{di} overwriting dest: #{source.inspect} -over-> #{dest.inspect}" if merge_debug - dest = overwrite_unmergeables(source, dest, options) - end - else # src_hash is not an array or hash, so we'll have to overwrite dest - puts "#{di}Others: #{source.inspect} :: #{dest.inspect}" if merge_debug - dest = overwrite_unmergeables(source, dest, options) - end - puts "#{di}Returning #{dest.inspect}" if merge_debug - dest - end # deep_merge! - - # allows deep_merge! to uniformly handle overwriting of unmergeable entities - def DeepMerge::overwrite_unmergeables(source, dest, options) - merge_debug = options[:merge_debug] || false - overwrite_unmergeable = !options[:preserve_unmergeables] - knockout_prefix = options[:knockout_prefix] || false - di = options[:debug_indent] || '' - if knockout_prefix && overwrite_unmergeable - if source.kind_of?(String) # remove knockout string from source before overwriting dest - src_tmp = source.gsub(%r{^#{knockout_prefix}},"") - elsif source.kind_of?(Array) # remove all knockout elements before overwriting dest - src_tmp = source.delete_if {|ko_item| ko_item.kind_of?(String) && ko_item.match(%r{^#{knockout_prefix}}) } - else - src_tmp = source - end - if src_tmp == source # if we didn't find a knockout_prefix then we just overwrite dest - puts "#{di}#{src_tmp.inspect} -over-> #{dest.inspect}" if merge_debug - dest = src_tmp - else # if we do find a knockout_prefix, then we just delete dest - puts "#{di}\"\" -over-> #{dest.inspect}" if merge_debug - dest = "" - end - elsif overwrite_unmergeable - dest = source - end - dest - end - - def DeepMerge::clear_or_nil(obj) - if obj.respond_to?(:clear) - obj.clear - else - obj = nil - end - obj - end - -end # module DeepMerge - -class Hash - include DeepMerge::DeepMergeHash -end diff --git a/vendor/ceedling/vendor/unity/auto/colour_prompt.rb b/vendor/ceedling/vendor/unity/auto/colour_prompt.rb index 81003dd..85cbfd8 100644 --- a/vendor/ceedling/vendor/unity/auto/colour_prompt.rb +++ b/vendor/ceedling/vendor/unity/auto/colour_prompt.rb @@ -2,93 +2,118 @@ # 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] -# ========================================== +# ========================================== -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) - 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, :default then 37 - else - 30 + + def posix_colour(colour) + # ANSI Escape Codes - Foreground colors + # | Code | Color | + # | 39 | Default foreground color | + # | 30 | Black | + # | 31 | Red | + # | 32 | Green | + # | 33 | Yellow | + # | 34 | Blue | + # | 35 | Magenta | + # | 36 | Cyan | + # | 37 | Light gray | + # | 90 | Dark gray | + # | 91 | Light red | + # | 92 | Light green | + # | 93 | Light yellow | + # | 94 | Light blue | + # | 95 | Light magenta | + # | 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 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 +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 +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 diff --git a/vendor/ceedling/vendor/unity/auto/colour_reporter.rb b/vendor/ceedling/vendor/unity/auto/colour_reporter.rb index 5aa1d27..1c3bc21 100644 --- a/vendor/ceedling/vendor/unity/auto/colour_reporter.rb +++ b/vendor/ceedling/vendor/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" +require_relative '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 \ No newline at end of file +end diff --git a/vendor/ceedling/vendor/unity/auto/generate_config.yml b/vendor/ceedling/vendor/unity/auto/generate_config.yml new file mode 100644 index 0000000..4a5e474 --- /dev/null +++ b/vendor/ceedling/vendor/unity/auto/generate_config.yml @@ -0,0 +1,36 @@ +#this is a sample configuration file for generate_module +#you would use it by calling generate_module with the -ygenerate_config.yml option +#files like this are useful for customizing generate_module to your environment +:generate_module: + :defaults: + #these defaults are used in place of any missing options at the command line + :path_src: ../src/ + :path_inc: ../src/ + :path_tst: ../test/ + :update_svn: true + :includes: + #use [] for no additional includes, otherwise list the includes on separate lines + :src: + - Defs.h + - Board.h + :inc: [] + :tst: + - Defs.h + - Board.h + - Exception.h + :boilerplates: + #these are inserted at the top of generated files. + #just comment out or remove if not desired. + #use %1$s where you would like the file name to appear (path/extension not included) + :src: | + //------------------------------------------- + // %1$s.c + //------------------------------------------- + :inc: | + //------------------------------------------- + // %1$s.h + //------------------------------------------- + :tst: | + //------------------------------------------- + // Test%1$s.c : Units tests for %1$s.c + //------------------------------------------- diff --git a/vendor/ceedling/vendor/unity/auto/generate_module.rb b/vendor/ceedling/vendor/unity/auto/generate_module.rb index 3db1a98..0a88bec 100644 --- a/vendor/ceedling/vendor/unity/auto/generate_module.rb +++ b/vendor/ceedling/vendor/unity/auto/generate_module.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] -# ========================================== +# ========================================== # This script creates all the files with start code necessary for a new module. # A simple module only requires a source file, header file, and test file. @@ -10,47 +10,13 @@ require 'rubygems' require 'fileutils' +require 'pathname' + +# TEMPLATE_TST +TEMPLATE_TST ||= '#ifdef TEST + +#include "unity.h" -HERE = File.expand_path(File.dirname(__FILE__)) + '/' - -#help text when requested -HELP_TEXT = [ "\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 single source module. (DEFAULT)", - " -d destroy module instead of creating it.", - " -u update subversion too (requires subversion command line)", - " -y\"my.yml\" selects a different yaml config file for module generation", - "" ].join("\n") - -#Built in patterns -PATTERNS = { 'src' => {'' => { :inc => [] } }, - 'dh' => {'Driver' => { :inc => ['%1$sHardware.h'] }, - 'Hardware' => { :inc => [] } - }, - 'dih' => {'Driver' => { :inc => ['%1$sHardware.h', '%1$sInterrupt.h'] }, - 'Interrupt'=> { :inc => ['%1$sHardware.h'] }, - 'Hardware' => { :inc => [] } - }, - 'mch' => {'Model' => { :inc => [] }, - 'Conductor'=> { :inc => ['%1$sModel.h', '%1$sHardware.h'] }, - 'Hardware' => { :inc => [] } - }, - 'mvp' => {'Model' => { :inc => [] }, - 'Presenter'=> { :inc => ['%1$sModel.h', '%1$sView.h'] }, - 'View' => { :inc => [] } - } - } - -#TEMPLATE_TST -TEMPLATE_TST = %q[#include "unity.h" %2$s#include "%1$s.h" void setUp(void) @@ -61,142 +27,287 @@ { } -void test_%1$s_NeedToImplement(void) +void test_%4$s_NeedToImplement(void) { - TEST_IGNORE(); + TEST_IGNORE_MESSAGE("Need to Implement %1$s"); } -] - -#TEMPLATE_SRC -TEMPLATE_SRC = %q[%2$s#include "%1$s.h" -] - -#TEMPLATE_INC -TEMPLATE_INC = %q[#ifndef _%3$s_H -#define _%3$s_H%2$s - -#endif // _%3$s_H -] - -# Parse the command line parameters. -ARGV.each do |arg| - case(arg) - when /^-d/ then @destroy = true - when /^-u/ then @update_svn = true - when /^-p(\w+)/ then @pattern = $1 - when /^-s(.+)/ then @path_src = $1 - when /^-i(.+)/ then @path_inc = $1 - when /^-t(.+)/ then @path_tst = $1 - when /^-y(.+)/ then @yaml_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)/ - puts HELP_TEXT - exit - else - raise "ERROR: Unknown option specified '#{arg}'" + +#endif // TEST +'.freeze + +# TEMPLATE_SRC +TEMPLATE_SRC ||= '%2$s#include "%1$s.h" +'.freeze + +# 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) + @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' + end + + # Create default file paths if none were provided + @options[:path_src] = "#{__dir__}/../src/" if @options[:path_src].nil? + @options[:path_inc] = @options[:path_src] if @options[:path_inc].nil? + @options[:path_tst] = "#{__dir__}/../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 -end -raise "ERROR: You must have a Module name specified! (use option -h for help)" if @module_name.nil? - -#load yaml file if one was requested -if @yaml_config - require 'yaml' - cfg = YAML.load_file(HERE + @yaml_config)[:generate_module] - @path_src = cfg[:defaults][:path_src] if @path_src.nil? - @path_inc = cfg[:defaults][:path_inc] if @path_inc.nil? - @path_tst = cfg[:defaults][:path_tst] if @path_tst.nil? - @update_svn = cfg[:defaults][:update_svn] if @update_svn.nil? - @extra_inc = cfg[:includes] - @boilerplates = cfg[:boilerplates] -else - @boilerplates = {} -end -# Create default file paths if none were provided -@path_src = HERE + "../src/" if @path_src.nil? -@path_inc = @path_src if @path_inc.nil? -@path_tst = HERE + "../test/" if @path_tst.nil? -@path_src += '/' unless (@path_src[-1] == 47) -@path_inc += '/' unless (@path_inc[-1] == 47) -@path_tst += '/' unless (@path_tst[-1] == 47) -@pattern = 'src' if @pattern.nil? -@includes = { :src => [], :inc => [], :tst => [] } -@includes.merge!(@extra_inc) unless @extra_inc.nil? - -#create triad definition -TRIAD = [ { :ext => '.c', :path => @path_src, :template => TEMPLATE_SRC, :inc => :src, :boilerplate => @boilerplates[:src] }, - { :ext => '.h', :path => @path_inc, :template => TEMPLATE_INC, :inc => :inc, :boilerplate => @boilerplates[:inc] }, - { :ext => '.c', :path => @path_tst+'Test', :template => TEMPLATE_TST, :inc => :tst, :boilerplate => @boilerplates[:tst] }, - ] - -#prepare the pattern for use -@patterns = PATTERNS[@pattern.downcase] -raise "ERROR: The design pattern specified isn't one that I recognize!" if @patterns.nil? - -# Assemble the path/names of the files we need to work with. -files = [] -TRIAD.each do |triad| - @patterns.each_pair do |pattern_file, pattern_traits| - files << { - :path => "#{triad[:path]}#{@module_name}#{pattern_file}#{triad[:ext]}", - :name => "#{@module_name}#{pattern_file}", - :template => triad[:template], - :boilerplate => triad[:boilerplate], - :includes => case(triad[:inc]) - when :src then @includes[:src] | pattern_traits[:inc].map{|f| f % [@module_name]} - when :inc then @includes[:inc] - when :tst then @includes[:tst] | pattern_traits[:inc].map{|f| "Mock#{f}"% [@module_name]} - end + ############################ + def self.default_options + { + pattern: 'src', + includes: { + src: [], + inc: [], + tst: [] + }, + update_svn: false, + boilerplates: {}, + test_prefix: 'Test', + mock_prefix: 'Mock' } end -end -# destroy files if that was what was requested -if @destroy - files.each do |filespec| - file = filespec[:path] - if File.exist?(file) - if @update_svn - `svn delete \"#{file}\" --force` - puts "File #{file} deleted and removed from source control" + ############################ + def self.grab_config(config_file) + 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 + options + end + + ############################ + 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 + 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] }] + + # 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 + triad.select! { |v| v[:inc] == :tst } if pattern == 'test' + + # Assemble the path/names of the files we need to work with. + files = [] + triad.each do |cfg| + patterns.each_pair do |pattern_file, pattern_traits| + 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| 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 + + files + end + + ############################ + def neutralize_filename(name, start_cap = true) + return name if name.empty? + name = name.split(/(?:\s+|_|(?=[A-Z][a-z]))|(?<=[a-z])(?=[A-Z])/).map { |v| v.capitalize }.join('_') + name = name[0].downcase + name[1..-1] unless start_cap + return name + end + + ############################ + def create_filename(part1, part2 = '') + name = part2.empty? ? part1 : part1 + '_' + part2 + case (@options[:naming]) + when 'bumpy' then neutralize_filename(name,false).delete('_') + when 'camel' then neutralize_filename(name).delete('_') + when 'snake' then neutralize_filename(name).downcase + when 'caps' then neutralize_filename(name).upcase + else name + end + end + + ############################ + def generate(module_name, pattern = nil) + files = files_to_operate_on(module_name, pattern) + + # Abort if all of the module files already exist + all_files_exist = true + files.each do |file| + 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| + # 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) + 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 { |ff| "#include \"#{ff}\"\n" }.join, + file[:name].upcase.gsub(/-/, '_'), + file[:name].gsub(/-/, '_')]) + end + if @options[:update_svn] + `svn add \"#{file[:path]}\"` + 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!" + end else - FileUtils.remove(file) - puts "File #{file} deleted" + puts "File #{file[:path]} created" end - else - puts "File #{file} does not exist so cannot be removed." end + puts 'Generate Complete' end - puts "Destroy Complete" - exit -end -#Abort if any module already exists -files.each do |file| - raise "ERROR: File #{file[:name]} already exists. Exiting." if File.exist?(file[:path]) + ############################ + def destroy(module_name, pattern = nil) + files_to_operate_on(module_name, pattern).each do |filespec| + file = filespec[:path] + if File.exist?(file) + if @options[:update_svn] + `svn delete \"#{file}\" --force` + puts "File #{file} deleted and removed from source control" + else + FileUtils.remove(file) + puts "File #{file} deleted" + end + else + puts "File #{file} does not exist so cannot be removed." + end + end + puts 'Destroy Complete' + end end -# Create Source Modules -files.each_with_index do |file, i| - File.open(file[:path], 'w') do |f| - f.write(file[:boilerplate] % [file[:name]]) unless file[:boilerplate].nil? - f.write(file[:template] % [ file[:name], - file[:includes].map{|f| "#include \"#{f}\"\n"}.join, - file[:name].upcase ] - ) - end - if (@update_svn) - `svn add \"#{file[:path]}\"` - if $?.exitstatus == 0 - puts "File #{file[:path]} created and added to source control" +############################ +# Handle As Command Line If Called That Way +if $0 == __FILE__ + destroy = false + 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] = 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 - puts "File #{file[:path]} created but FAILED adding to source control!" + raise "ERROR: Unknown option specified '#{arg}'" end + end + + 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.', + ' 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 + UnityModuleGenerator.new(options).destroy(module_name) else - puts "File #{file[:path]} created" + UnityModuleGenerator.new(options).generate(module_name) end -end -puts 'Generate Complete' +end diff --git a/vendor/ceedling/vendor/unity/auto/generate_test_runner.rb b/vendor/ceedling/vendor/unity/auto/generate_test_runner.rb index 0e05dfa..d1d8f91 100644 --- a/vendor/ceedling/vendor/unity/auto/generate_test_runner.rb +++ b/vendor/ceedling/vendor/unity/auto/generate_test_runner.rb @@ -2,312 +2,510 @@ # 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] -# ========================================== - -File.expand_path(File.join(File.dirname(__FILE__),'colour_prompt')) +# ========================================== class UnityTestRunnerGenerator - def initialize(options = nil) - @options = { :includes => [], :plugins => [], :framework => :unity } - 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" + @options = UnityTestRunnerGenerator.default_options + case options + when NilClass + @options + when String + @options.merge!(UnityTestRunnerGenerator.grab_config(options)) + when Hash + # Check if some of these have been specified + @options[:has_setup] = !options[:setup_name].nil? + @options[:has_teardown] = !options[:teardown_name].nil? + @options[:has_suite_setup] = !options[:suite_setup].nil? + @options[:has_suite_teardown] = !options[:suite_teardown].nil? + @options.merge!(options) + else + raise 'If you specify arguments, it should be a filename or a hash of options' end + require_relative 'type_sanitizer' end - + + def self.default_options + { + includes: [], + defines: [], + plugins: [], + framework: :unity, + test_prefix: 'test|spec|should', + mock_prefix: 'Mock', + mock_suffix: '', + setup_name: 'setUp', + teardown_name: 'tearDown', + test_reset_name: 'resetTest', + test_verify_name: 'verifyTest', + main_name: 'main', # set to :auto to automatically generate each time + main_export_decl: '', + cmdline_args: false, + omit_begin_end: false, + use_param_tests: false, + include_extensions: '(?:hpp|hh|H|h)', + source_extensions: '(?:cpp|cc|ino|C|c)' + } + end + def self.grab_config(config_file) - options = { :includes => [], :plugins => [], :framework => :unity } - 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[:unity] : yaml_guts[:cmock]) + 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 - File.open(input_file, 'r') do |input| - tests = find_tests(input) - testfile_includes = find_includes(input) - used_mocks = find_mocks(testfile_includes) - end - #build runner file - generate(input_file, output_file, tests, used_mocks) - - #determine which files were used to return them + # pull required data from source file + source = File.read(input_file) + 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)/ } + find_setup_and_teardown(source) + + # build runner file + generate(input_file, output_file, tests, used_mocks, testfile_includes) + + # 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) + + def generate(input_file, output_file, tests, used_mocks, testfile_includes) File.open(output_file, 'w') do |output| - create_header(output, used_mocks) + 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_reset(output, used_mocks) - create_main(output, input_file, tests) + create_setup(output) + create_teardown(output) + create_suite_setup(output) + create_suite_teardown(output) + create_reset(output) + create_run_test(output) unless tests.empty? + create_args_wrappers(output, tests) + create_main(output, input_file, tests, 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 - - def find_tests(input_file) - tests_raw = [] - tests_args = [] + + def find_tests(source) tests_and_line_numbers = [] - - input_file.rewind - source_raw = input_file.read - source_scrubbed = source_raw.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+(test.*?)\s*\(\s*(.*)\s*\)/ - arguments = $1 - name = $2 - call = $3 - args = nil - if (@options[:use_param_tests] and !arguments.empty?) - args = [] - arguments.scan(/\s*TEST_CASE\s*\((.*)\)\s*$/) {|a| args << a[0]} + + # contains characters which will be substituted from within strings, doing + # this prevents these characters from interfering with scrubbers + # @ is not a valid C character, so there should be no clashes with files genuinely containing these markers + substring_subs = { '{' => '@co@', '}' => '@cc@', ';' => '@ss@', '/' => '@fs@' } + substring_re = Regexp.union(substring_subs.keys) + substring_unsubs = substring_subs.invert # the inverse map will be used to fix the strings afterwords + substring_unsubs['@quote@'] = '\\"' + substring_unsubs['@apos@'] = '\\\'' + substring_unre = Regexp.union(substring_unsubs.keys) + source_scrubbed = source.clone + source_scrubbed = source_scrubbed.gsub(/\\"/, '@quote@') # hide escaped quotes to allow capture of the full string/char + source_scrubbed = source_scrubbed.gsub(/\\'/, '@apos@') # hide escaped apostrophes to allow capture of the full string/char + source_scrubbed = source_scrubbed.gsub(/("[^"\n]*")|('[^'\n]*')/) { |s| s.gsub(substring_re, substring_subs) } # temporarily hide problematic characters within strings + source_scrubbed = source_scrubbed.gsub(/\/\/(?:.+\/\*|\*(?:$|[^\/])).*$/, '') # remove line comments that comment out the start of blocks + source_scrubbed = source_scrubbed.gsub(/\/\*.*?\*\//m, '') # remove block comments + source_scrubbed = source_scrubbed.gsub(/\/\/.*$/, '') # remove line comments (all that remain) + lines = source_scrubbed.split(/(^\s*\#.*$) | (;|\{|\}) /x) # Treat preprocessor directives as a logical line. Match ;, {, and } as end of lines + .map { |line| line.gsub(substring_unre, substring_unsubs) } # unhide the problematic characters previously removed + + lines.each_with_index do |line, _index| + # find tests + next unless line =~ /^((?:\s*(?:TEST_CASE|TEST_RANGE)\s*\(.*?\)\s*)*)\s*void\s+((?:#{@options[:test_prefix]}).*)\s*\(\s*(.*)\s*\)/m + + 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] } + + arguments.scan(/\s*TEST_RANGE\s*\((.*)\)\s*$/).flatten.each do |range_str| + args += range_str.scan(/\[\s*(-?\d+.?\d*),\s*(-?\d+.?\d*),\s*(-?\d+.?\d*)\s*\]/).map do |arg_values_str| + arg_values_str.map do |arg_value_str| + arg_value_str.include?('.') ? arg_value_str.to_f : arg_value_str.to_i + end + end.map do |arg_values| + (arg_values[0]..arg_values[1]).step(arg_values[2]).to_a + end.reduce do |result, arg_range_expanded| + result.product(arg_range_expanded) + end.map do |arg_combinations| + arg_combinations.flatten.join(', ') + end end - tests_and_line_numbers << { :test => name, :args => args, :call => call, :line_number => 0 } - tests_args = [] end + + tests_and_line_numbers << { test: name, args: args, call: call, params: params, line_number: 0 } end - #determine line numbers and create tests to run - source_lines = source_raw.split("\n") - source_index = 0; + tests_and_line_numbers.uniq! { |v| v[:test] } + + # determine line numbers and create tests to run + source_lines = source.split("\n") + 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 =~ /\s+#{tests_and_line_numbers[i][:test]}(?:\s|\()/ + + 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(input_file) - input_file.rewind - - #read in file - source = input_file.read - - #remove comments (block and line, in three steps to ensure correct precedence) + def find_includes(source) + # 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!(/\/\*.*?\*\//m, '') # remove block comments source.gsub!(/\/\/.*$/, '') # remove line comments (all that remain) - - #parse out includes - return source.scan(/^\s*#include\s+\"\s*(.+)\.[hH]\s*\"/).flatten + + # parse out includes + includes = { + local: source.scan(/^\s*#include\s+\"\s*(.+\.#{@options[:include_extensions]})\s*\"/).flatten, + system: source.scan(/^\s*#include\s+<\s*(.+)\s*>/).flatten.map { |inc| "<#{inc}>" }, + linkonly: source.scan(/^TEST_FILE\(\s*\"\s*(.+\.#{@options[:source_extensions]})\s*\"/).flatten + } + includes end - + def find_mocks(includes) mock_headers = [] - includes.each do |include_file| - mock_headers << File.basename(include_file) if (include_file =~ /^mock/i) + includes.each do |include_path| + include_file = File.basename(include_path) + mock_headers << include_path if include_file =~ /^#{@options[:mock_prefix]}.*#{@options[:mock_suffix]}\.h$/i end - return mock_headers + mock_headers end - - def create_header(output, mocks) + + def find_setup_and_teardown(source) + @options[:has_setup] = source =~ /void\s+#{@options[:setup_name]}\s*\(/ + @options[:has_teardown] = source =~ /void\s+#{@options[:teardown_name]}\s*\(/ + @options[:has_suite_setup] ||= (source =~ /void\s+suiteSetUp\s*\(/) + @options[:has_suite_teardown] ||= (source =~ /int\s+suiteTearDown\s*\(int\s+([a-zA-Z0-9_])+\s*\)/) + end + + 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?) - @options[:includes].flatten.uniq.compact.each do |inc| - output.puts("#include #{inc.include?('<') ? inc : "\"#{inc.gsub('.h','')}.h\""}") + output.puts("\n/*=======Automagically Detected Files To Include=====*/") + output.puts("#include \"#{@options[:framework]}.h\"") + output.puts('#include "cmock.h"') unless mocks.empty? + if @options[:defines] && !@options[:defines].empty? + @options[:defines].each { |d| output.puts("#ifndef #{d}\n#define #{d}\n#endif /* #{d} */") } end - output.puts('#include <setjmp.h>') - output.puts('#include <stdio.h>') - output.puts('#include "CException.h"') if @options[:plugins].include?(:cexception) - mocks.each do |mock| - output.puts("#include \"#{mock.gsub('.h','')}.h\"") + 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}\""}") + end + testfile_includes.each do |inc| + output.puts("#include #{inc.include?('<') ? inc : "\"#{inc}\""}") + end end - if @options[:enforce_strict_ordering] - output.puts('') - output.puts('int GlobalExpectCount;') - output.puts('int GlobalVerifyOrder;') - output.puts('char* GlobalOrderError;') + mocks.each do |mock| + output.puts("#include \"#{mock}\"") 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) - output.puts("\n//=======External Functions This Runner Calls=====") - output.puts("extern void setUp(void);") - output.puts("extern void tearDown(void);") + + 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);") + output.puts("\n#ifdef __cplusplus\nextern \"C\"\n{\n#endif") if @options[:externc] tests.each do |test| output.puts("extern void #{test[:test]}(#{test[:call] || 'void'});") end + output.puts("#ifdef __cplusplus\n}\n#endif") if @options[:externc] output.puts('') end - - def create_mock_management(output, mocks) - unless (mocks.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.each do |mock| - output.puts(" #{mock}_Init();") - end - output.puts("}\n") - output.puts("static void CMock_Verify(void)") - output.puts("{") - mocks.each do |mock| - output.puts(" #{mock}_Verify();") - end - output.puts("}\n") + def create_mock_management(output, mock_headers) + 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| - output.puts(" #{mock}_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 int 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 + 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 - 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_Destroy(void)') + output.puts('{') + mocks.each do |mock| + mock_clean = TypeSanitizer.sanitize_c_identifier(mock) + output.puts(" #{mock_clean}_Destroy();") end - end - - def create_runtest(output, used_mocks) - cexception = @options[:plugins].include? :cexception - 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(TestFunc, TestLineNum#{va_args1}) \\") - output.puts("{ \\") - output.puts(" Unity.CurrentTestName = #TestFunc#{va_args2.empty? ? '' : " \"(\" ##{va_args2} \")\""}; \\") - output.puts(" Unity.CurrentTestLineNumber = TestLineNum; \\") - output.puts(" Unity.NumberOfTests++; \\") - output.puts(" if (TEST_PROTECT()) \\") - output.puts(" { \\") - output.puts(" CEXCEPTION_T e; \\") if cexception - output.puts(" Try { \\") if cexception - output.puts(" CMock_Init(); \\") unless (used_mocks.empty?) - output.puts(" setUp(); \\") - output.puts(" TestFunc(#{va_args2}); \\") - output.puts(" CMock_Verify(); \\") unless (used_mocks.empty?) - output.puts(" } Catch(e) { TEST_ASSERT_EQUAL_HEX32_MESSAGE(CEXCEPTION_NONE, e, \"Unhandled Exception!\"); } \\") if cexception - output.puts(" } \\") - output.puts(" CMock_Destroy(); \\") unless (used_mocks.empty?) - output.puts(" if (TEST_PROTECT() && !TEST_IS_IGNORED) \\") - output.puts(" { \\") - output.puts(" tearDown(); \\") - output.puts(" } \\") - output.puts(" UnityConcludeTest(); \\") output.puts("}\n") end - - def create_reset(output, used_mocks) - output.puts("\n//=======Test Reset Option=====") - output.puts("void resetTest()") - output.puts("{") - output.puts(" CMock_Verify();") unless (used_mocks.empty?) - output.puts(" CMock_Destroy();") unless (used_mocks.empty?) - output.puts(" tearDown();") - output.puts(" CMock_Init();") unless (used_mocks.empty?) - output.puts(" setUp();") - output.puts("}") + + def create_setup(output) + return if @options[:has_setup] + + output.puts("\n/*=======Setup (stub)=====*/") + output.puts("void #{@options[:setup_name]}(void) {}") + end + + def create_teardown(output) + return if @options[:has_teardown] + + output.puts("\n/*=======Teardown (stub)=====*/") + output.puts("void #{@options[:teardown_name]}(void) {}") + end + + def create_suite_setup(output) + return if @options[:suite_setup].nil? + + output.puts("\n/*=======Suite Setup=====*/") + output.puts('void suiteSetUp(void)') + output.puts('{') + output.puts(@options[:suite_setup]) + output.puts('}') end - - def create_main(output, filename, tests) - output.puts("\n\n//=======MAIN=====") - output.puts("int main(void)") - output.puts("{") - output.puts(" suite_setup();") unless @options[:suite_setup].nil? - output.puts(" Unity.TestFile = \"#{filename}\";") - output.puts(" UnityBegin();") - if (@options[:use_param_tests]) + + def create_suite_teardown(output) + return if @options[:suite_teardown].nil? + + output.puts("\n/*=======Suite Teardown=====*/") + output.puts('int suiteTearDown(int num_failures)') + output.puts('{') + output.puts(@options[:suite_teardown]) + output.puts('}') + end + + def create_reset(output) + output.puts("\n/*=======Test Reset Options=====*/") + output.puts("void #{@options[:test_reset_name]}(void);") + output.puts("void #{@options[:test_reset_name]}(void)") + output.puts('{') + output.puts(" #{@options[:teardown_name]}();") + output.puts(' CMock_Verify();') + output.puts(' CMock_Destroy();') + output.puts(' CMock_Init();') + output.puts(" #{@options[:setup_name]}();") + output.puts('}') + output.puts("void #{@options[:test_verify_name]}(void);") + output.puts("void #{@options[:test_verify_name]}(void)") + output.puts('{') + output.puts(' CMock_Verify();') + output.puts('}') + end + + def create_run_test(output) + require 'erb' + template = ERB.new(File.read(File.join(__dir__, 'run_test.erb')), nil, '<>') + output.puts("\n" + template.result(binding)) + end + + def create_args_wrappers(output, tests) + return unless @options[:use_param_tests] + + output.puts("\n/*=======Parameterized Test Wrappers=====*/") + tests.each do |test| + next if test[:args].nil? || test[:args].empty? + + test[:args].each.with_index(1) do |args, idx| + output.puts("static void runner_args#{idx}_#{test[:test]}(void)") + output.puts('{') + output.puts(" #{test[:test]}(#{args});") + output.puts("}\n") + end + end + end + + def create_main(output, filename, tests, used_mocks) + output.puts("\n/*=======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();') tests.each do |test| - if ((test[:args].nil?) or (test[:args].empty?)) - output.puts(" RUN_TEST(#{test[:test]}, #{test[:line_number]}, RUN_TEST_NO_ARGS);") + if (!@options[:use_param_tests]) || test[:args].nil? || test[:args].empty? + output.puts(" UnityPrint(\" #{test[:test]}\");") + output.puts(' UNITY_PRINT_EOL();') else - test[:args].each {|args| output.puts(" RUN_TEST(#{test[:test]}, #{test[:line_number]}, #{args});")} + test[:args].each do |args| + output.puts(" UnityPrint(\" #{test[:test]}(#{args})\");") + output.puts(' UNITY_PRINT_EOL();') + end end end + output.puts(' return 0;') + output.puts(' }') + output.puts(' return parse_status;') + output.puts(' }') + else + main_return = @options[:omit_begin_end] ? 'void' : 'int' + if main_name != 'main' + output.puts("#{@options[:main_export_decl]} #{main_return} #{main_name}(void);") + end + output.puts("#{main_return} #{main_name}(void)") + output.puts('{') + end + output.puts(' suiteSetUp();') if @options[:has_suite_setup] + if @options[:omit_begin_end] + output.puts(" UnitySetTestFile(\"#{filename.gsub(/\\/, '\\\\\\')}\");") + else + output.puts(" UnityBegin(\"#{filename.gsub(/\\/, '\\\\\\')}\");") + end + tests.each do |test| + if (!@options[:use_param_tests]) || test[:args].nil? || test[:args].empty? + output.puts(" run_test(#{test[:test]}, \"#{test[:test]}\", #{test[:line_number]});") + else + test[:args].each.with_index(1) do |args, idx| + wrapper = "runner_args#{idx}_#{test[:test]}" + testname = "#{test[:test]}(#{args})".dump + output.puts(" run_test(#{wrapper}, #{testname}, #{test[:line_number]});") + end + end + end + output.puts + output.puts(' CMock_Guts_MemFreeFinal();') unless used_mocks.empty? + if @options[:has_suite_teardown] + if @options[:omit_begin_end] + output.puts(' (void) suite_teardown(0);') + else + output.puts(' return suiteTearDown(UnityEnd());') + end else - tests.each { |test| output.puts(" RUN_TEST(#{test[:test]}, #{test[:line_number]});") } + output.puts(' return UnityEnd();') unless @options[:omit_begin_end] end - output.puts() - output.puts(" return #{@options[:suite_teardown].nil? ? "" : "suite_teardown"}(UnityEnd());") - output.puts("}") + 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. */') + output.puts("#ifndef _#{filename}") + output.puts("#define _#{filename}\n\n") + 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}\""}") + end + testfile_includes.each do |inc| + output.puts("#include #{inc.include?('<') ? inc : "\"#{inc}\""}") + end + output.puts "\n" + tests.each do |test| + if test[:params].nil? || test[:params].empty? + output.puts("void #{test[:test]}(void);") + else + output.puts("void #{test[:test]}(#{test[:params]});") + end + end + output.puts("#endif\n\n") end end +if $0 == __FILE__ + options = { includes: [] } -if ($0 == __FILE__) - options = { :includes => [] } - yaml_file = nil - - #parse out all the options first - ARGV.reject! do |arg| - case(arg) - when '-cexception' - options[:plugins] = [:cexception]; true - when /\.*\.yml/ - options = UnityTestRunnerGenerator.grab_config(arg); true - else false + # 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[Regexp.last_match(1).to_sym] = Regexp.last_match(2) + true + when /\.*\.(?:hpp|hh|H|h)$/ + options[:includes] << arg + true + else false end - end - - #make sure there is at least one parameter left (the input file) - if !ARGV[0] - puts ["usage: ruby #{__FILE__} (yaml) (options) input_test_file output_test_runner (includes)", - " blah.yml - will use config options in the yml file (see docs)", - " -cexception - include cexception support"].join("\n") + end + + # 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', + ' -externc - add extern "C" for cpp 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', + ' --test_reset_name="" - redefine resetTest func name to something else', + ' --test_verify_name="" - redefine verifyTest func name to something else', + ' --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)', + ' --omit_begin_end=1 - omit calls to UnityBegin and UnityEnd (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]) - - #everything else is an include file - options[:includes] ||= (ARGV.slice(2..-1).flatten.compact) if (ARGV.size > 2) - + + # 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 diff --git a/vendor/ceedling/vendor/unity/auto/parse_output.rb b/vendor/ceedling/vendor/unity/auto/parse_output.rb new file mode 100644 index 0000000..d72c6e8 --- /dev/null +++ b/vendor/ceedling/vendor/unity/auto/parse_output.rb @@ -0,0 +1,322 @@ +#============================================================ +# 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 Linux builds use the following: +# make | tee Output.txt +# +# This script can handle the following output formats: +# - normal output (raw unity) +# - fixture output (unity_fixture.h/.c) +# - fixture output with verbose flag set ("-v") +# +# 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 +#============================================================ + +# Parser class for handling the input file +class ParseOutput + def initialize + # internal data + @class_name_idx = 0 + @path_delim = nil + + # xml output related + @xml_out = false + @array_list = false + + # current suite name and statistics + @test_suite = nil + @total_tests = 0 + @test_passed = 0 + @test_failed = 0 + @test_ignored = 0 + 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 + end + + # Pushes the suite info as xml to the array list, which will be written later + def push_xml_output_suite_info + # Insert opening tag at front + heading = '<testsuite name="Unity" tests="' + @total_tests.to_s + '" failures="' + @test_failed.to_s + '"' + ' skips="' + @test_ignored.to_s + '">' + @array_list.insert(0, heading) + # Push back the closing tag + @array_list.push '</testsuite>' + end + + # Pushes xml output data to the array list, which will be written later + def push_xml_output_passed(test_name) + @array_list.push ' <testcase classname="' + @test_suite + '" name="' + test_name + '"/>' + end + + # Pushes xml output data to the array list, which will be written later + def push_xml_output_failed(test_name, reason) + @array_list.push ' <testcase classname="' + @test_suite + '" name="' + test_name + '">' + @array_list.push ' <failure type="ASSERT FAILED">' + reason + '</failure>' + @array_list.push ' </testcase>' + end + + # Pushes xml output data to the array list, which will be written later + def push_xml_output_ignored(test_name, reason) + @array_list.push ' <testcase classname="' + @test_suite + '" name="' + test_name + '">' + @array_list.push ' <skipped type="TEST IGNORED">' + reason + '</skipped>' + @array_list.push ' </testcase>' + 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) + # Split the path name + test_name = test_suite_name.split(@path_delim) + + # Remove the extension and extract the base_name + base_name = test_name[test_name.size - 1].split('.')[0] + + # Return if the test suite hasn't changed + return unless base_name.to_s != @test_suite.to_s + + @test_suite = base_name + printf "New Test: %s\n", @test_suite + end + + # Prepares the line for verbose fixture output ("-v") + def prepare_fixture_line(line) + line = line.sub('IGNORE_TEST(', '') + line = line.sub('TEST(', '') + line = line.sub(')', ',') + line = line.chomp + array = line.split(',') + array.map { |x| x.to_s.lstrip.chomp } + 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) + class_name = array[0] + test_name = array[1] + test_suite_verify(class_name) + printf "%-40s PASS\n", test_name + + push_xml_output_passed(test_name) if @xml_out + end + + # Test was flagged as having failed so format the output. + # This is using the Unity fixture output and not the original Unity output. + def test_failed_unity_fixture(array) + class_name = array[0] + test_name = array[1] + test_suite_verify(class_name) + reason_array = array[2].split(':') + reason = reason_array[-1].lstrip.chomp + ' at line: ' + reason_array[-4] + + printf "%-40s FAILED\n", test_name + + push_xml_output_failed(test_name, reason) if @xml_out + end + + # Test was flagged as being ignored so format the output. + # This is using the Unity fixture output and not the original Unity output. + def test_ignored_unity_fixture(array) + class_name = array[0] + test_name = array[1] + reason = 'No reason given' + if array.size > 2 + reason_array = array[2].split(':') + tmp_reason = reason_array[-1].lstrip.chomp + reason = tmp_reason == 'IGNORE' ? 'No reason given' : tmp_reason + end + test_suite_verify(class_name) + printf "%-40s IGNORED\n", test_name + + push_xml_output_ignored(test_name, reason) if @xml_out + 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_idx]) + printf "%-40s PASS\n", test_name + + return unless @xml_out + + push_xml_output_passed(test_name) if @xml_out + 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.lstrip + ' at line: ' + array[last_item - 3] + class_name = array[@class_name_idx] + + if test_name.start_with? 'TEST(' + array2 = test_name.split(' ') + + test_suite = array2[0].sub('TEST(', '') + test_suite = test_suite.sub(',', '') + class_name = test_suite + + test_name = array2[1].sub(')', '') + end + + test_suite_verify(class_name) + printf "%-40s FAILED\n", test_name + + push_xml_output_failed(test_name, reason) if @xml_out + end + + # Test was flagged as being ignored so format the output + def test_ignored(array) + last_item = array.length - 1 + test_name = array[last_item - 2] + reason = array[last_item].chomp.lstrip + class_name = array[@class_name_idx] + + if test_name.start_with? 'TEST(' + array2 = test_name.split(' ') + + test_suite = array2[0].sub('TEST(', '') + test_suite = test_suite.sub(',', '') + class_name = test_suite + + test_name = array2[1].sub(')', '') + end + + test_suite_verify(class_name) + printf "%-40s IGNORED\n", test_name + + push_xml_output_ignored(test_name, reason) if @xml_out + end + + # Adjusts the os specific members according to the current path style + # (Windows or Unix based) + def detect_os_specifics(line) + if line.include? '\\' + # Windows X:\Y\Z + @class_name_idx = 1 + @path_delim = '\\' + else + # Unix Based /X/Y/Z + @class_name_idx = 0 + @path_delim = '/' + end + end + + # Main function used to parse the file that was captured. + def process(file_name) + @array_list = [] + + puts 'Parsing file: ' + file_name + + @test_passed = 0 + @test_failed = 0 + @test_ignored = 0 + puts '' + puts '=================== RESULTS =====================' + puts '' + File.open(file_name).each do |line| + # Typical test lines look like these: + # ---------------------------------------------------- + # 1. normal output: + # <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 + # + # 2. fixture output + # <path>/<test_file>.c:63:TEST(<test_group>, <test_function>):FAIL: Expected 0x00001234 Was 0x00005A5A + # <path>/<test_file>.c:36:TEST(<test_group>, <test_function>):IGNORE + # Note: "PASS" information won't be generated in this mode + # + # 3. fixture output with verbose information ("-v") + # TEST(<test_group, <test_file>)<path>/<test_file>:168::FAIL: Expected 0x8D Was 0x8C + # TEST(<test_group>, <test_file>)<path>/<test_file>:22::IGNORE: This Test Was Ignored On Purpose + # IGNORE_TEST(<test_group, <test_file>) + # TEST(<test_group, <test_file>) PASS + # + # Note: Where path is different on Unix vs Windows devices (Windows leads with a drive letter)! + detect_os_specifics(line) + 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. + next unless (line_array.size >= 4) || (line.start_with? 'TEST(') || (line.start_with? 'IGNORE_TEST(') + + # check if the output is fixture output (with verbose flag "-v") + if (line.start_with? 'TEST(') || (line.start_with? 'IGNORE_TEST(') + line_array = prepare_fixture_line(line) + if line.include? ' PASS' + test_passed_unity_fixture(line_array) + @test_passed += 1 + elsif line.include? 'FAIL' + test_failed_unity_fixture(line_array) + @test_failed += 1 + elsif line.include? 'IGNORE' + test_ignored_unity_fixture(line_array) + @test_ignored += 1 + end + # normal output / fixture output (without verbose "-v") + elsif line.include? ':PASS' + test_passed(line_array) + @test_passed += 1 + elsif line.include? ':FAIL' + test_failed(line_array) + @test_failed += 1 + elsif line.include? ':IGNORE:' + test_ignored(line_array) + @test_ignored += 1 + elsif line.include? ':IGNORE' + line_array.push('No reason given') + test_ignored(line_array) + @test_ignored += 1 + end + @total_tests = @test_passed + @test_failed + @test_ignored + end + puts '' + puts '=================== SUMMARY =====================' + puts '' + puts 'Tests Passed : ' + @test_passed.to_s + puts 'Tests Failed : ' + @test_failed.to_s + puts 'Tests Ignored : ' + @test_ignored.to_s + + return unless @xml_out + + # push information about the suite + push_xml_output_suite_info + # write xml output file + 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 |arg| + if arg == '-xml' + parse_my_file.set_xml_output + else + parse_my_file.process(arg) + break + end + end +end diff --git a/vendor/ceedling/vendor/unity/auto/run_test.erb b/vendor/ceedling/vendor/unity/auto/run_test.erb new file mode 100644 index 0000000..f91b566 --- /dev/null +++ b/vendor/ceedling/vendor/unity/auto/run_test.erb @@ -0,0 +1,37 @@ +/*=======Test Runner Used To Run Each Test=====*/ +static void run_test(UnityTestFunction func, const char* name, UNITY_LINE_TYPE line_num) +{ + Unity.CurrentTestName = name; + Unity.CurrentTestLineNumber = line_num; +#ifdef UNITY_USE_COMMAND_LINE_ARGS + if (!UnityTestMatches()) + return; +#endif + Unity.NumberOfTests++; + UNITY_CLR_DETAILS(); + UNITY_EXEC_TIME_START(); + CMock_Init(); + if (TEST_PROTECT()) + { +<% if @options[:plugins].include?(:cexception) %> + CEXCEPTION_T e; + Try { + <%= @options[:setup_name] %>(); + func(); + } Catch(e) { + TEST_ASSERT_EQUAL_HEX32_MESSAGE(CEXCEPTION_NONE, e, "Unhandled Exception!"); + } +<% else %> + <%= @options[:setup_name] %>(); + func(); +<% end %> + } + if (TEST_PROTECT()) + { + <%= @options[:teardown_name] %>(); + CMock_Verify(); + } + CMock_Destroy(); + UNITY_EXEC_TIME_STOP(); + UnityConcludeTest(); +} diff --git a/vendor/ceedling/vendor/unity/auto/stylize_as_junit.rb b/vendor/ceedling/vendor/unity/auto/stylize_as_junit.rb new file mode 100644 index 0000000..e01f791 --- /dev/null +++ b/vendor/ceedling/vendor/unity/auto/stylize_as_junit.rb @@ -0,0 +1,251 @@ +#!/usr/bin/ruby +# +# unity_to_junit.rb +# +require 'fileutils' +require 'optparse' +require 'ostruct' +require 'set' + +require 'pp' + +VERSION = 1.0 + +class ArgvParser + # + # Return a structure describing the options. + # + def self.parse(args) + # 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' + + opts = OptionParser.new do |o| + o.banner = 'Usage: unity_to_junit.rb [options]' + + o.separator '' + o.separator 'Specific options:' + + o.on('-r', '--results <dir>', 'Look for Unity Results files here.') do |results| + # puts "results #{results}" + options.results_dir = results + end + + o.on('-p', '--root_path <path>', 'Prepend this path to files in results.') do |root_path| + options.root_path = root_path + end + + o.on('-o', '--output <filename>', 'XML file to generate.') do |out_file| + # puts "out_file: #{out_file}" + options.out_file = out_file + end + + o.separator '' + o.separator 'Common options:' + + # No argument, shows at tail. This will print an options summary. + o.on_tail('-h', '--help', 'Show this message') do + puts o + exit + end + + # Another typical switch to print the version. + o.on_tail('--version', 'Show version') do + puts "unity_to_junit.rb version #{VERSION}" + exit + end + end + + opts.parse!(args) + options + end +end + +class UnityToJUnit + include FileUtils::Verbose + attr_reader :report, :total_tests, :failures, :ignored + attr_writer :targets, :root, :out_file + + def initialize + @report = '' + @unit_name = '' + end + + def run + # Clean up result file names + 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) + results.each do |result_file| + 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, '.*') + + 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) + f.close + end + + 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' + + exit 1 + end + + protected + + def get_details(_result_file, lines) + results = results_structure + lines.each do |line| + 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 + results + end + + def parse_test_summary(summary) + 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 + + private + + 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) + stream.puts "<?xml version='1.0' encoding='utf-8' ?>" + end + + def write_suites_header(stream) + stream.puts '<testsuites>' + end + + 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) + result = results[:failures] + 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\">" + stream.puts "\t\t\t<failure message=\"#{item[:message]}\" type=\"Assertion\"/>" + stream.puts "\t\t\t<system-err> [File] #{filename} [Line] #{item[:line]} </system-err>" + stream.puts "\t\t</testcase>" + end + end + + def write_tests(results, stream) + result = results[:successes] + result.each do |item| + stream.puts "\t\t<testcase classname=\"#{@unit_name}\" name=\"#{item[:test]}\" time=\"0\" />" + end + end + + def write_ignored(results, stream) + result = results[:ignores] + result.each do |item| + filename = File.join(results[:source][:path], File.basename(results[:source][:file], '.*')) + puts "Writing ignored tests for test harness: #{filename}" + stream.puts "\t\t<testcase classname=\"#{@unit_name}\" name=\"#{item[:test]}\" time=\"0\">" + stream.puts "\t\t\t<skipped message=\"#{item[:message]}\" type=\"Assertion\"/>" + stream.puts "\t\t\t<system-err> [File] #{filename} [Line] #{item[:line]} </system-err>" + stream.puts "\t\t</testcase>" + end + end + + def write_suite_footer(stream) + stream.puts "\t</testsuite>" + end + + def write_suites_footer(stream) + stream.puts '</testsuites>' + end +end + +if $0 == __FILE__ + # parse out the command options + options = ArgvParser.parse(ARGV) + + # create an instance to work with + utj = UnityToJUnit.new + begin + # 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.targets = results + + # set the root path + utj.root = options.root_path + + # set the output XML file name + # puts "Output File from options: #{options.out_file}" + utj.out_file = options.out_file + + # run the summarizer + puts utj.run + rescue StandardError => e + utj.usage e.message + end +end diff --git a/vendor/ceedling/vendor/unity/auto/test_file_filter.rb b/vendor/ceedling/vendor/unity/auto/test_file_filter.rb index 3dbc26a..5c3a79f 100644 --- a/vendor/ceedling/vendor/unity/auto/test_file_filter.rb +++ b/vendor/ceedling/vendor/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 unless @all_files + return 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 diff --git a/vendor/ceedling/vendor/unity/auto/type_sanitizer.rb b/vendor/ceedling/vendor/unity/auto/type_sanitizer.rb new file mode 100644 index 0000000..dafb882 --- /dev/null +++ b/vendor/ceedling/vendor/unity/auto/type_sanitizer.rb @@ -0,0 +1,6 @@ +module TypeSanitizer + def self.sanitize_c_identifier(unsanitized) + # convert filename to valid C identifier by replacing invalid chars with '_' + unsanitized.gsub(/[-\/\\\.\,\s]/, '_') + end +end diff --git a/vendor/ceedling/vendor/unity/auto/unity_test_summary.py b/vendor/ceedling/vendor/unity/auto/unity_test_summary.py new file mode 100644 index 0000000..00c0da8 --- /dev/null +++ b/vendor/ceedling/vendor/unity/auto/unity_test_summary.py @@ -0,0 +1,139 @@ +#! python3 +# ========================================== +# Unity Project - A Test Framework for C +# Copyright (c) 2015 Alexander Mueller / XelaRellum@web.de +# [Released under MIT License. Please refer to license.txt for details] +# Based on the ruby script by Mike Karlesky, Mark VanderVoord, Greg Williams +# ========================================== +import sys +import os +import re +from glob import glob + +class UnityTestSummary: + def __init__(self): + self.report = '' + self.total_tests = 0 + self.failures = 0 + self.ignored = 0 + + def run(self): + # Clean up result file names + results = [] + for target in self.targets: + results.append(target.replace('\\', '/')) + + # Dig through each result file, looking for details on pass/fail: + failure_output = [] + ignore_output = [] + + for result_file in results: + lines = list(map(lambda line: line.rstrip(), open(result_file, "r").read().split('\n'))) + if len(lines) == 0: + raise Exception("Empty test result file: %s" % result_file) + + details = self.get_details(result_file, lines) + failures = details['failures'] + ignores = details['ignores'] + if len(failures) > 0: failure_output.append('\n'.join(failures)) + if len(ignores) > 0: ignore_output.append('n'.join(ignores)) + tests,failures,ignored = self.parse_test_summary('\n'.join(lines)) + self.total_tests += tests + self.failures += failures + self.ignored += ignored + + if self.ignored > 0: + self.report += "\n" + self.report += "--------------------------\n" + self.report += "UNITY IGNORED TEST SUMMARY\n" + self.report += "--------------------------\n" + self.report += "\n".join(ignore_output) + + if self.failures > 0: + self.report += "\n" + self.report += "--------------------------\n" + self.report += "UNITY FAILED TEST SUMMARY\n" + self.report += "--------------------------\n" + self.report += '\n'.join(failure_output) + + self.report += "\n" + self.report += "--------------------------\n" + self.report += "OVERALL UNITY TEST SUMMARY\n" + self.report += "--------------------------\n" + self.report += "{total_tests} TOTAL TESTS {failures} TOTAL FAILURES {ignored} IGNORED\n".format(total_tests = self.total_tests, failures=self.failures, ignored=self.ignored) + self.report += "\n" + + return self.report + + def set_targets(self, target_array): + self.targets = target_array + + def set_root_path(self, path): + self.root = path + + def usage(self, err_msg=None): + print("\nERROR: ") + if err_msg: + print(err_msg) + print("\nUsage: unity_test_summary.py result_file_directory/ root_path/") + print(" result_file_directory - The location of your results files.") + print(" Defaults to current directory if not specified.") + print(" Should end in / if specified.") + print(" root_path - Helpful for producing more verbose output if using relative paths.") + sys.exit(1) + + def get_details(self, result_file, lines): + results = { 'failures': [], 'ignores': [], 'successes': [] } + for line in lines: + parts = line.split(':') + if len(parts) == 5: + src_file,src_line,test_name,status,msg = parts + elif len(parts) == 4: + src_file,src_line,test_name,status = parts + msg = '' + else: + continue + if len(self.root) > 0: + line_out = "%s%s" % (self.root, line) + else: + line_out = line + if status == 'IGNORE': + results['ignores'].append(line_out) + elif status == 'FAIL': + results['failures'].append(line_out) + elif status == 'PASS': + results['successes'].append(line_out) + return results + + def parse_test_summary(self, summary): + m = re.search(r"([0-9]+) Tests ([0-9]+) Failures ([0-9]+) Ignored", summary) + if not m: + raise Exception("Couldn't parse test results: %s" % summary) + + return int(m.group(1)), int(m.group(2)), int(m.group(3)) + + +if __name__ == '__main__': + uts = UnityTestSummary() + try: + #look in the specified or current directory for result files + if len(sys.argv) > 1: + targets_dir = sys.argv[1] + else: + targets_dir = './' + targets = list(map(lambda x: x.replace('\\', '/'), glob(targets_dir + '**/*.test*', recursive=True))) + if len(targets) == 0: + raise Exception("No *.testpass or *.testfail files found in '%s'" % targets_dir) + uts.set_targets(targets) + + #set the root path + if len(sys.argv) > 2: + root_path = sys.argv[2] + else: + root_path = os.path.split(__file__)[0] + uts.set_root_path(root_path) + + #run the summarizer + print(uts.run()) + except Exception as e: + uts.usage(e) diff --git a/vendor/ceedling/vendor/unity/auto/unity_test_summary.rb b/vendor/ceedling/vendor/unity/auto/unity_test_summary.rb index 67f7a02..b3fe8a6 100644 --- a/vendor/ceedling/vendor/unity/auto/unity_test_summary.rb +++ b/vendor/ceedling/vendor/unity/auto/unity_test_summary.rb @@ -2,9 +2,9 @@ # 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] -# ========================================== +# ========================================== -#!/usr/bin/ruby +# !/usr/bin/ruby # # unity_test_summary.rb # @@ -15,37 +15,37 @@ class UnityTestSummary include FileUtils::Verbose attr_reader :report, :total_tests, :failures, :ignored - - def initialize + attr_writer :targets, :root + + 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(/\\/,'/')} - - # Dig through each result file, looking for details on pass/fail: + 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 @report += "\n" @report += "--------------------------\n" @@ -53,7 +53,7 @@ def run @report += "--------------------------\n" @report += ignore_output.flatten.join("\n") end - + if @failures > 0 @report += "\n" @report += "--------------------------\n" @@ -61,7 +61,7 @@ def run @report += "--------------------------\n" @report += failure_output.flatten.join("\n") end - + @report += "\n" @report += "--------------------------\n" @report += "OVERALL UNITY TEST SUMMARY\n" @@ -69,71 +69,67 @@ def run @report += "#{@total_tests} TOTAL TESTS #{@failures} TOTAL FAILURES #{@ignored} IGNORED\n" @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 and (@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 - end + raise "Couldn't parse test results: #{summary}" unless summary.find { |v| v =~ /(\d+) Tests (\d+) Failures (\d+) Ignored/ } - def here; File.expand_path(File.dirname(__FILE__)); end - + [Regexp.last_match(1).to_i, Regexp.last_match(2).to_i, Regexp.last_match(3).to_i] + end end if $0 == __FILE__ - uts = UnityTestSummary.new + + # 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 + uts = UnityTestSummary.new(opts) + begin - #look in the specified or current directory for result files - ARGV[0] ||= './' - targets = "#{ARGV[0].gsub(/\\/, '/')}*.test*" + # look in the specified or current directory for result files + args[0] ||= './' + targets = "#{ARGV[0].tr('\\', '/')}**/*.test*" results = Dir[targets] - raise "No *.testpass or *.testfail files found in '#{targets}'" if results.empty? - uts.set_targets(results) - - #set the root path - ARGV[1] ||= File.expand_path(File.dirname(__FILE__)) + '/' - uts.set_root_path(ARGV[1]) - - #run the summarizer + + raise "No *.testpass, *.testfail, or *.testresults files found in '#{targets}'" if results.empty? + + uts.targets = results + + # set the root path + args[1] ||= Dir.pwd + '/' + uts.root = ARGV[1] + + # run the summarizer puts uts.run - rescue Exception => e + rescue StandardError => e uts.usage e.message end end diff --git a/vendor/ceedling/vendor/unity/auto/unity_to_junit.py b/vendor/ceedling/vendor/unity/auto/unity_to_junit.py new file mode 100644 index 0000000..71dd568 --- /dev/null +++ b/vendor/ceedling/vendor/unity/auto/unity_to_junit.py @@ -0,0 +1,146 @@ +import sys +import os +from glob import glob + +from pyparsing import * +from junit_xml import TestSuite, TestCase + + +class UnityTestSummary: + def __init__(self): + self.report = '' + self.total_tests = 0 + self.failures = 0 + self.ignored = 0 + self.targets = 0 + self.root = None + self.test_suites = dict() + + def run(self): + # Clean up result file names + results = [] + for target in self.targets: + results.append(target.replace('\\', '/')) + + # Dig through each result file, looking for details on pass/fail: + for result_file in results: + lines = list(map(lambda line: line.rstrip(), open(result_file, "r").read().split('\n'))) + if len(lines) == 0: + raise Exception("Empty test result file: %s" % result_file) + + # define an expression for your file reference + entry_one = Combine( + oneOf(list(alphas)) + ':/' + + Word(alphanums + '_-./')) + + entry_two = Word(printables + ' ', excludeChars=':') + entry = entry_one | entry_two + + delimiter = Literal(':').suppress() + tc_result_line = Group(entry.setResultsName('tc_file_name') + delimiter + entry.setResultsName( + 'tc_line_nr') + delimiter + entry.setResultsName('tc_name') + delimiter + entry.setResultsName( + 'tc_status') + Optional( + delimiter + entry.setResultsName('tc_msg'))).setResultsName("tc_line") + + eol = LineEnd().suppress() + sol = LineStart().suppress() + blank_line = sol + eol + + tc_summary_line = Group(Word(nums).setResultsName("num_of_tests") + "Tests" + Word(nums).setResultsName( + "num_of_fail") + "Failures" + Word(nums).setResultsName("num_of_ignore") + "Ignored").setResultsName( + "tc_summary") + tc_end_line = Or(Literal("FAIL"), Literal('Ok')).setResultsName("tc_result") + + # run it and see... + pp1 = tc_result_line | Optional(tc_summary_line | tc_end_line) + pp1.ignore(blank_line | OneOrMore("-")) + + result = list() + for l in lines: + result.append((pp1.parseString(l)).asDict()) + # delete empty results + result = filter(None, result) + + tc_list = list() + for r in result: + if 'tc_line' in r: + tmp_tc_line = r['tc_line'] + + # get only the file name which will be used as the classname + file_name = tmp_tc_line['tc_file_name'].split('\\').pop().split('/').pop().rsplit('.', 1)[0] + tmp_tc = TestCase(name=tmp_tc_line['tc_name'], classname=file_name) + if 'tc_status' in tmp_tc_line: + if str(tmp_tc_line['tc_status']) == 'IGNORE': + if 'tc_msg' in tmp_tc_line: + tmp_tc.add_skipped_info(message=tmp_tc_line['tc_msg'], + output=r'[File]={0}, [Line]={1}'.format( + tmp_tc_line['tc_file_name'], tmp_tc_line['tc_line_nr'])) + else: + tmp_tc.add_skipped_info(message=" ") + elif str(tmp_tc_line['tc_status']) == 'FAIL': + if 'tc_msg' in tmp_tc_line: + tmp_tc.add_failure_info(message=tmp_tc_line['tc_msg'], + output=r'[File]={0}, [Line]={1}'.format( + tmp_tc_line['tc_file_name'], tmp_tc_line['tc_line_nr'])) + else: + tmp_tc.add_failure_info(message=" ") + + tc_list.append((str(result_file), tmp_tc)) + + for k, v in tc_list: + try: + self.test_suites[k].append(v) + except KeyError: + self.test_suites[k] = [v] + ts = [] + for suite_name in self.test_suites: + ts.append(TestSuite(suite_name, self.test_suites[suite_name])) + + with open('result.xml', 'w') as f: + TestSuite.to_file(f, ts, prettyprint='True', encoding='utf-8') + + return self.report + + def set_targets(self, target_array): + self.targets = target_array + + def set_root_path(self, path): + self.root = path + + @staticmethod + def usage(err_msg=None): + print("\nERROR: ") + if err_msg: + print(err_msg) + print("\nUsage: unity_test_summary.py result_file_directory/ root_path/") + print(" result_file_directory - The location of your results files.") + print(" Defaults to current directory if not specified.") + print(" Should end in / if specified.") + print(" root_path - Helpful for producing more verbose output if using relative paths.") + sys.exit(1) + + +if __name__ == '__main__': + uts = UnityTestSummary() + try: + # look in the specified or current directory for result files + if len(sys.argv) > 1: + targets_dir = sys.argv[1] + else: + targets_dir = './' + targets = list(map(lambda x: x.replace('\\', '/'), glob(targets_dir + '*.test*'))) + if len(targets) == 0: + raise Exception("No *.testpass or *.testfail files found in '%s'" % targets_dir) + uts.set_targets(targets) + + # set the root path + if len(sys.argv) > 2: + root_path = sys.argv[2] + else: + root_path = os.path.split(__file__)[0] + uts.set_root_path(root_path) + + # run the summarizer + print(uts.run()) + except Exception as e: + UnityTestSummary.usage(e) diff --git a/vendor/ceedling/vendor/unity/release/build.info b/vendor/ceedling/vendor/unity/release/build.info deleted file mode 100644 index 7871b21..0000000 --- a/vendor/ceedling/vendor/unity/release/build.info +++ /dev/null @@ -1,2 +0,0 @@ -118 - diff --git a/vendor/ceedling/vendor/unity/release/version.info b/vendor/ceedling/vendor/unity/release/version.info deleted file mode 100644 index 6b2d349..0000000 --- a/vendor/ceedling/vendor/unity/release/version.info +++ /dev/null @@ -1,2 +0,0 @@ -2.1.0 - diff --git a/vendor/ceedling/vendor/unity/src/meson.build b/vendor/ceedling/vendor/unity/src/meson.build new file mode 100644 index 0000000..1c7b426 --- /dev/null +++ b/vendor/ceedling/vendor/unity/src/meson.build @@ -0,0 +1,11 @@ +# +# build script written by : Michael Brockus. +# github repo author: Mike Karlesky, Mark VanderVoord, Greg Williams. +# +# license: MIT +# +unity_dir = include_directories('.') + +unity_lib = static_library(meson.project_name(), + files('unity.c'), + include_directories: unity_dir) diff --git a/vendor/ceedling/vendor/unity/src/unity.c b/vendor/ceedling/vendor/unity/src/unity.c index 82a9fb7..764a42b 100644 --- a/vendor/ceedling/vendor/unity/src/unity.c +++ b/vendor/ceedling/vendor/unity/src/unity.c @@ -1,56 +1,132 @@ -/* ========================================== +/* ========================================================================= Unity Project - A Test Framework for C - Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams + Copyright (c) 2007-21 Mike Karlesky, Mark VanderVoord, Greg Williams [Released under MIT License. Please refer to license.txt for details] -========================================== */ +============================================================================ */ #include "unity.h" -#include <stdio.h> -#include <string.h> - -#define UNITY_FAIL_AND_BAIL { Unity.CurrentTestFailed = 1; UNITY_OUTPUT_CHAR('\n'); longjmp(Unity.AbortFrame, 1); } -#define UNITY_IGNORE_AND_BAIL { Unity.CurrentTestIgnored = 1; UNITY_OUTPUT_CHAR('\n'); longjmp(Unity.AbortFrame, 1); } -/// return prematurely if we are already in failure or ignore state -#define UNITY_SKIP_EXECUTION { if ((Unity.CurrentTestFailed != 0) || (Unity.CurrentTestIgnored != 0)) {return;} } -#define UNITY_PRINT_EOL { UNITY_OUTPUT_CHAR('\n'); } - -struct _Unity Unity = { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , { 0 } }; - -const char* UnityStrNull = "NULL"; -const char* UnityStrSpacer = ". "; -const char* UnityStrExpected = " Expected "; -const char* UnityStrWas = " Was "; -const char* UnityStrTo = " To "; -const char* UnityStrElement = " Element "; -const char* UnityStrByte = " Byte "; -const char* UnityStrMemory = " Memory Mismatch."; -const char* UnityStrDelta = " Values Not Within Delta "; -const char* UnityStrPointless= " You Asked Me To Compare Nothing, Which Was Pointless."; -const char* UnityStrNullPointerForExpected= " Expected pointer to be NULL"; -const char* UnityStrNullPointerForActual = " Actual pointer was NULL"; - -// compiler-generic print formatting masks -const _U_UINT UnitySizeMask[] = -{ - 255u, // 0xFF - 65535u, // 0xFFFF - 65535u, - 4294967295u, // 0xFFFFFFFF - 4294967295u, - 4294967295u, - 4294967295u -#ifdef UNITY_SUPPORT_64 - ,0xFFFFFFFFFFFFFFFF +#include <stddef.h> + +#ifdef AVR +#include <avr/pgmspace.h> +#else +#define PROGMEM +#endif + +/* If omitted from header, declare overrideable prototypes here so they're ready for use */ +#ifdef UNITY_OMIT_OUTPUT_CHAR_HEADER_DECLARATION +void UNITY_OUTPUT_CHAR(int); +#endif + +/* Helpful macros for us to use here in Assert functions */ +#define UNITY_FAIL_AND_BAIL { Unity.CurrentTestFailed = 1; UNITY_OUTPUT_FLUSH(); TEST_ABORT(); } +#define UNITY_IGNORE_AND_BAIL { Unity.CurrentTestIgnored = 1; UNITY_OUTPUT_FLUSH(); TEST_ABORT(); } +#define RETURN_IF_FAIL_OR_IGNORE if (Unity.CurrentTestFailed || Unity.CurrentTestIgnored) TEST_ABORT() + +struct UNITY_STORAGE_T Unity; + +#ifdef UNITY_OUTPUT_COLOR +const char PROGMEM UnityStrOk[] = "\033[42mOK\033[00m"; +const char PROGMEM UnityStrPass[] = "\033[42mPASS\033[00m"; +const char PROGMEM UnityStrFail[] = "\033[41mFAIL\033[00m"; +const char PROGMEM UnityStrIgnore[] = "\033[43mIGNORE\033[00m"; +#else +const char PROGMEM UnityStrOk[] = "OK"; +const char PROGMEM UnityStrPass[] = "PASS"; +const char PROGMEM UnityStrFail[] = "FAIL"; +const char PROGMEM UnityStrIgnore[] = "IGNORE"; +#endif +static const char PROGMEM UnityStrNull[] = "NULL"; +static const char PROGMEM UnityStrSpacer[] = ". "; +static const char PROGMEM UnityStrExpected[] = " Expected "; +static const char PROGMEM UnityStrWas[] = " Was "; +static const char PROGMEM UnityStrGt[] = " to be greater than "; +static const char PROGMEM UnityStrLt[] = " to be less than "; +static const char PROGMEM UnityStrOrEqual[] = "or equal to "; +static const char PROGMEM UnityStrNotEqual[] = " to be not equal to "; +static const char PROGMEM UnityStrElement[] = " Element "; +static const char PROGMEM UnityStrByte[] = " Byte "; +static const char PROGMEM UnityStrMemory[] = " Memory Mismatch."; +static const char PROGMEM UnityStrDelta[] = " Values Not Within Delta "; +static const char PROGMEM UnityStrPointless[] = " You Asked Me To Compare Nothing, Which Was Pointless."; +static const char PROGMEM UnityStrNullPointerForExpected[] = " Expected pointer to be NULL"; +static const char PROGMEM UnityStrNullPointerForActual[] = " Actual pointer was NULL"; +#ifndef UNITY_EXCLUDE_FLOAT +static const char PROGMEM UnityStrNot[] = "Not "; +static const char PROGMEM UnityStrInf[] = "Infinity"; +static const char PROGMEM UnityStrNegInf[] = "Negative Infinity"; +static const char PROGMEM UnityStrNaN[] = "NaN"; +static const char PROGMEM UnityStrDet[] = "Determinate"; +static const char PROGMEM UnityStrInvalidFloatTrait[] = "Invalid Float Trait"; #endif -}; +const char PROGMEM UnityStrErrShorthand[] = "Unity Shorthand Support Disabled"; +const char PROGMEM UnityStrErrFloat[] = "Unity Floating Point Disabled"; +const char PROGMEM UnityStrErrDouble[] = "Unity Double Precision Disabled"; +const char PROGMEM UnityStrErr64[] = "Unity 64-bit Support Disabled"; +static const char PROGMEM UnityStrBreaker[] = "-----------------------"; +static const char PROGMEM UnityStrResultsTests[] = " Tests "; +static const char PROGMEM UnityStrResultsFailures[] = " Failures "; +static const char PROGMEM UnityStrResultsIgnored[] = " Ignored "; +#ifndef UNITY_EXCLUDE_DETAILS +static const char PROGMEM UnityStrDetail1Name[] = UNITY_DETAIL1_NAME " "; +static const char PROGMEM UnityStrDetail2Name[] = " " UNITY_DETAIL2_NAME " "; +#endif +/*----------------------------------------------- + * Pretty Printers & Test Result Output Handlers + *-----------------------------------------------*/ + +/*-----------------------------------------------*/ +/* Local helper function to print characters. */ +static void UnityPrintChar(const char* pch) +{ + /* printable characters plus CR & LF are printed */ + if ((*pch <= 126) && (*pch >= 32)) + { + UNITY_OUTPUT_CHAR(*pch); + } + /* write escaped carriage returns */ + else if (*pch == 13) + { + UNITY_OUTPUT_CHAR('\\'); + UNITY_OUTPUT_CHAR('r'); + } + /* write escaped line feeds */ + else if (*pch == 10) + { + UNITY_OUTPUT_CHAR('\\'); + UNITY_OUTPUT_CHAR('n'); + } + /* unprintable characters are shown as codes */ + else + { + UNITY_OUTPUT_CHAR('\\'); + UNITY_OUTPUT_CHAR('x'); + UnityPrintNumberHex((UNITY_UINT)*pch, 2); + } +} + +/*-----------------------------------------------*/ +/* Local helper function to print ANSI escape strings e.g. "\033[42m". */ +#ifdef UNITY_OUTPUT_COLOR +static UNITY_UINT UnityPrintAnsiEscapeString(const char* string) +{ + const char* pch = string; + UNITY_UINT count = 0; -void UnityPrintFail(void); -void UnityPrintOk(void); + while (*pch && (*pch != 'm')) + { + UNITY_OUTPUT_CHAR(*pch); + pch++; + count++; + } + UNITY_OUTPUT_CHAR('m'); + count++; -//----------------------------------------------- -// Pretty Printers & Test Result Output Handlers -//----------------------------------------------- + return count; +} +#endif +/*-----------------------------------------------*/ void UnityPrint(const char* string) { const char* pch = string; @@ -59,121 +135,157 @@ void UnityPrint(const char* string) { while (*pch) { - // printable characters plus CR & LF are printed +#ifdef UNITY_OUTPUT_COLOR + /* print ANSI escape code */ + if ((*pch == 27) && (*(pch + 1) == '[')) + { + pch += UnityPrintAnsiEscapeString(pch); + continue; + } +#endif + UnityPrintChar(pch); + pch++; + } + } +} +/*-----------------------------------------------*/ +void UnityPrintLen(const char* string, const UNITY_UINT32 length) +{ + const char* pch = string; + + if (pch != NULL) + { + while (*pch && ((UNITY_UINT32)(pch - string) < length)) + { + /* printable characters plus CR & LF are printed */ if ((*pch <= 126) && (*pch >= 32)) { UNITY_OUTPUT_CHAR(*pch); } - //write escaped carriage returns + /* write escaped carriage returns */ else if (*pch == 13) { UNITY_OUTPUT_CHAR('\\'); UNITY_OUTPUT_CHAR('r'); } - //write escaped line feeds + /* write escaped line feeds */ else if (*pch == 10) { UNITY_OUTPUT_CHAR('\\'); UNITY_OUTPUT_CHAR('n'); } - // unprintable characters are shown as codes + /* unprintable characters are shown as codes */ else { UNITY_OUTPUT_CHAR('\\'); - UnityPrintNumberHex((_U_SINT)*pch, 2); + UNITY_OUTPUT_CHAR('x'); + UnityPrintNumberHex((UNITY_UINT)*pch, 2); } pch++; } } } -//----------------------------------------------- -void UnityPrintNumberByStyle(const _U_SINT number, const UNITY_DISPLAY_STYLE_T style) +/*-----------------------------------------------*/ +void UnityPrintNumberByStyle(const UNITY_INT number, const UNITY_DISPLAY_STYLE_T style) { if ((style & UNITY_DISPLAY_RANGE_INT) == UNITY_DISPLAY_RANGE_INT) { - UnityPrintNumber(number); + if (style == UNITY_DISPLAY_STYLE_CHAR) + { + /* printable characters plus CR & LF are printed */ + UNITY_OUTPUT_CHAR('\''); + if ((number <= 126) && (number >= 32)) + { + UNITY_OUTPUT_CHAR((int)number); + } + /* write escaped carriage returns */ + else if (number == 13) + { + UNITY_OUTPUT_CHAR('\\'); + UNITY_OUTPUT_CHAR('r'); + } + /* write escaped line feeds */ + else if (number == 10) + { + UNITY_OUTPUT_CHAR('\\'); + UNITY_OUTPUT_CHAR('n'); + } + /* unprintable characters are shown as codes */ + else + { + UNITY_OUTPUT_CHAR('\\'); + UNITY_OUTPUT_CHAR('x'); + UnityPrintNumberHex((UNITY_UINT)number, 2); + } + UNITY_OUTPUT_CHAR('\''); + } + else + { + UnityPrintNumber(number); + } } else if ((style & UNITY_DISPLAY_RANGE_UINT) == UNITY_DISPLAY_RANGE_UINT) { - UnityPrintNumberUnsigned( (_U_UINT)number & UnitySizeMask[((_U_UINT)style & (_U_UINT)0x0F) - 1] ); + UnityPrintNumberUnsigned((UNITY_UINT)number); } else { - UnityPrintNumberHex((_U_UINT)number, (style & 0x000F) << 1); + UNITY_OUTPUT_CHAR('0'); + UNITY_OUTPUT_CHAR('x'); + UnityPrintNumberHex((UNITY_UINT)number, (char)((style & 0xF) * 2)); } } -//----------------------------------------------- -/// basically do an itoa using as little ram as possible -void UnityPrintNumber(const _U_SINT number_to_print) +/*-----------------------------------------------*/ +void UnityPrintNumber(const UNITY_INT number_to_print) { - _U_SINT divisor = 1; - _U_SINT next_divisor; - _U_SINT number = number_to_print; + UNITY_UINT number = (UNITY_UINT)number_to_print; - if (number < 0) + if (number_to_print < 0) { + /* A negative number, including MIN negative */ UNITY_OUTPUT_CHAR('-'); - number = -number; - } - - // figure out initial divisor - while (number / divisor > 9) - { - next_divisor = divisor * 10; - if (next_divisor > divisor) - divisor = next_divisor; - else - break; - } - - // now mod and print, then divide divisor - do - { - UNITY_OUTPUT_CHAR((char)('0' + (number / divisor % 10))); - divisor /= 10; + number = (~number) + 1; } - while (divisor > 0); + UnityPrintNumberUnsigned(number); } -//----------------------------------------------- -/// basically do an itoa using as little ram as possible -void UnityPrintNumberUnsigned(const _U_UINT number) +/*----------------------------------------------- + * basically do an itoa using as little ram as possible */ +void UnityPrintNumberUnsigned(const UNITY_UINT number) { - _U_UINT divisor = 1; - _U_UINT next_divisor; + UNITY_UINT divisor = 1; - // figure out initial divisor + /* figure out initial divisor */ while (number / divisor > 9) { - next_divisor = divisor * 10; - if (next_divisor > divisor) - divisor = next_divisor; - else - break; + divisor *= 10; } - // now mod and print, then divide divisor + /* now mod and print, then divide divisor */ do { UNITY_OUTPUT_CHAR((char)('0' + (number / divisor % 10))); divisor /= 10; - } - while (divisor > 0); + } while (divisor > 0); } -//----------------------------------------------- -void UnityPrintNumberHex(const _U_UINT number, const char nibbles_to_print) +/*-----------------------------------------------*/ +void UnityPrintNumberHex(const UNITY_UINT number, const char nibbles_to_print) { - _U_UINT nibble; + int nibble; char nibbles = nibbles_to_print; - UNITY_OUTPUT_CHAR('0'); - UNITY_OUTPUT_CHAR('x'); + + if ((unsigned)nibbles > UNITY_MAX_NIBBLES) + { + nibbles = UNITY_MAX_NIBBLES; + } while (nibbles > 0) { - nibble = (number >> (--nibbles << 2)) & 0x0000000F; + nibbles--; + nibble = (int)(number >> (nibbles * 4)) & 0x0F; if (nibble <= 9) { UNITY_OUTPUT_CHAR((char)('0' + nibble)); @@ -185,11 +297,11 @@ void UnityPrintNumberHex(const _U_UINT number, const char nibbles_to_print) } } -//----------------------------------------------- -void UnityPrintMask(const _U_UINT mask, const _U_UINT number) +/*-----------------------------------------------*/ +void UnityPrintMask(const UNITY_UINT mask, const UNITY_UINT number) { - _U_UINT current_bit = (_U_UINT)1 << (UNITY_INT_WIDTH - 1); - _US32 i; + UNITY_UINT current_bit = (UNITY_UINT)1 << (UNITY_INT_WIDTH - 1); + UNITY_INT32 i; for (i = 0; i < UNITY_INT_WIDTH; i++) { @@ -212,47 +324,220 @@ void UnityPrintMask(const _U_UINT mask, const _U_UINT number) } } -//----------------------------------------------- -#ifdef UNITY_FLOAT_VERBOSE -void UnityPrintFloat(_UF number) +/*-----------------------------------------------*/ +#ifndef UNITY_EXCLUDE_FLOAT_PRINT +/* + * This function prints a floating-point value in a format similar to + * printf("%.7g") on a single-precision machine or printf("%.9g") on a + * double-precision machine. The 7th digit won't always be totally correct + * in single-precision operation (for that level of accuracy, a more + * complicated algorithm would be needed). + */ +void UnityPrintFloat(const UNITY_DOUBLE input_number) { - char TempBuffer[32]; - sprintf(TempBuffer, "%.6f", number); - UnityPrint(TempBuffer); -} +#ifdef UNITY_INCLUDE_DOUBLE + static const int sig_digits = 9; + static const UNITY_INT32 min_scaled = 100000000; + static const UNITY_INT32 max_scaled = 1000000000; +#else + static const int sig_digits = 7; + static const UNITY_INT32 min_scaled = 1000000; + static const UNITY_INT32 max_scaled = 10000000; #endif -//----------------------------------------------- + UNITY_DOUBLE number = input_number; -void UnityPrintFail(void) -{ - UnityPrint("FAIL"); -} + /* print minus sign (does not handle negative zero) */ + if (number < 0.0f) + { + UNITY_OUTPUT_CHAR('-'); + number = -number; + } -void UnityPrintOk(void) -{ - UnityPrint("OK"); + /* handle zero, NaN, and +/- infinity */ + if (number == 0.0f) + { + UnityPrint("0"); + } + else if (isnan(number)) + { + UnityPrint("nan"); + } + else if (isinf(number)) + { + UnityPrint("inf"); + } + else + { + UNITY_INT32 n_int = 0, n; + int exponent = 0; + int decimals, digits; + char buf[16] = {0}; + + /* + * Scale up or down by powers of 10. To minimize rounding error, + * start with a factor/divisor of 10^10, which is the largest + * power of 10 that can be represented exactly. Finally, compute + * (exactly) the remaining power of 10 and perform one more + * multiplication or division. + */ + if (number < 1.0f) + { + UNITY_DOUBLE factor = 1.0f; + + while (number < (UNITY_DOUBLE)max_scaled / 1e10f) { number *= 1e10f; exponent -= 10; } + while (number * factor < (UNITY_DOUBLE)min_scaled) { factor *= 10.0f; exponent--; } + + number *= factor; + } + else if (number > (UNITY_DOUBLE)max_scaled) + { + UNITY_DOUBLE divisor = 1.0f; + + while (number > (UNITY_DOUBLE)min_scaled * 1e10f) { number /= 1e10f; exponent += 10; } + while (number / divisor > (UNITY_DOUBLE)max_scaled) { divisor *= 10.0f; exponent++; } + + number /= divisor; + } + else + { + /* + * In this range, we can split off the integer part before + * doing any multiplications. This reduces rounding error by + * freeing up significant bits in the fractional part. + */ + UNITY_DOUBLE factor = 1.0f; + n_int = (UNITY_INT32)number; + number -= (UNITY_DOUBLE)n_int; + + while (n_int < min_scaled) { n_int *= 10; factor *= 10.0f; exponent--; } + + number *= factor; + } + + /* round to nearest integer */ + n = ((UNITY_INT32)(number + number) + 1) / 2; + +#ifndef UNITY_ROUND_TIES_AWAY_FROM_ZERO + /* round to even if exactly between two integers */ + if ((n & 1) && (((UNITY_DOUBLE)n - number) == 0.5f)) + n--; +#endif + + n += n_int; + + if (n >= max_scaled) + { + n = min_scaled; + exponent++; + } + + /* determine where to place decimal point */ + decimals = ((exponent <= 0) && (exponent >= -(sig_digits + 3))) ? (-exponent) : (sig_digits - 1); + exponent += decimals; + + /* truncate trailing zeroes after decimal point */ + while ((decimals > 0) && ((n % 10) == 0)) + { + n /= 10; + decimals--; + } + + /* build up buffer in reverse order */ + digits = 0; + while ((n != 0) || (digits <= decimals)) + { + buf[digits++] = (char)('0' + n % 10); + n /= 10; + } + while (digits > 0) + { + if (digits == decimals) { UNITY_OUTPUT_CHAR('.'); } + UNITY_OUTPUT_CHAR(buf[--digits]); + } + + /* print exponent if needed */ + if (exponent != 0) + { + UNITY_OUTPUT_CHAR('e'); + + if (exponent < 0) + { + UNITY_OUTPUT_CHAR('-'); + exponent = -exponent; + } + else + { + UNITY_OUTPUT_CHAR('+'); + } + + digits = 0; + while ((exponent != 0) || (digits < 2)) + { + buf[digits++] = (char)('0' + exponent % 10); + exponent /= 10; + } + while (digits > 0) + { + UNITY_OUTPUT_CHAR(buf[--digits]); + } + } + } } +#endif /* ! UNITY_EXCLUDE_FLOAT_PRINT */ -//----------------------------------------------- -void UnityTestResultsBegin(const char* file, const UNITY_LINE_TYPE line) +/*-----------------------------------------------*/ +static void UnityTestResultsBegin(const char* file, const UNITY_LINE_TYPE line) { +#ifdef UNITY_OUTPUT_FOR_ECLIPSE + UNITY_OUTPUT_CHAR('('); + UnityPrint(file); + UNITY_OUTPUT_CHAR(':'); + UnityPrintNumber((UNITY_INT)line); + UNITY_OUTPUT_CHAR(')'); + UNITY_OUTPUT_CHAR(' '); + UnityPrint(Unity.CurrentTestName); + UNITY_OUTPUT_CHAR(':'); +#else +#ifdef UNITY_OUTPUT_FOR_IAR_WORKBENCH + UnityPrint("<SRCREF line="); + UnityPrintNumber((UNITY_INT)line); + UnityPrint(" file=\""); + UnityPrint(file); + UNITY_OUTPUT_CHAR('"'); + UNITY_OUTPUT_CHAR('>'); + UnityPrint(Unity.CurrentTestName); + UnityPrint("</SRCREF> "); +#else +#ifdef UNITY_OUTPUT_FOR_QT_CREATOR + UnityPrint("file://"); + UnityPrint(file); + UNITY_OUTPUT_CHAR(':'); + UnityPrintNumber((UNITY_INT)line); + UNITY_OUTPUT_CHAR(' '); + UnityPrint(Unity.CurrentTestName); + UNITY_OUTPUT_CHAR(':'); +#else UnityPrint(file); UNITY_OUTPUT_CHAR(':'); - UnityPrintNumber(line); + UnityPrintNumber((UNITY_INT)line); UNITY_OUTPUT_CHAR(':'); UnityPrint(Unity.CurrentTestName); UNITY_OUTPUT_CHAR(':'); +#endif +#endif +#endif } -//----------------------------------------------- -void UnityTestResultsFailBegin(const UNITY_LINE_TYPE line) +/*-----------------------------------------------*/ +static void UnityTestResultsFailBegin(const UNITY_LINE_TYPE line) { UnityTestResultsBegin(Unity.TestFile, line); - UnityPrint("FAIL:"); + UnityPrint(UnityStrFail); + UNITY_OUTPUT_CHAR(':'); } -//----------------------------------------------- +/*-----------------------------------------------*/ void UnityConcludeTest(void) { if (Unity.CurrentTestIgnored) @@ -262,8 +547,7 @@ void UnityConcludeTest(void) else if (!Unity.CurrentTestFailed) { UnityTestResultsBegin(Unity.TestFile, Unity.CurrentTestLineNumber); - UnityPrint("PASS"); - UNITY_PRINT_EOL; + UnityPrint(UnityStrPass); } else { @@ -272,20 +556,40 @@ void UnityConcludeTest(void) Unity.CurrentTestFailed = 0; Unity.CurrentTestIgnored = 0; + UNITY_PRINT_EXEC_TIME(); + UNITY_PRINT_EOL(); + UNITY_FLUSH_CALL(); } -//----------------------------------------------- -void UnityAddMsgIfSpecified(const char* msg) +/*-----------------------------------------------*/ +static void UnityAddMsgIfSpecified(const char* msg) { if (msg) { UnityPrint(UnityStrSpacer); + +#ifdef UNITY_PRINT_TEST_CONTEXT + UNITY_PRINT_TEST_CONTEXT(); +#endif +#ifndef UNITY_EXCLUDE_DETAILS + if (Unity.CurrentDetail1) + { + UnityPrint(UnityStrDetail1Name); + UnityPrint(Unity.CurrentDetail1); + if (Unity.CurrentDetail2) + { + UnityPrint(UnityStrDetail2Name); + UnityPrint(Unity.CurrentDetail2); + } + UnityPrint(UnityStrSpacer); + } +#endif UnityPrint(msg); } } -//----------------------------------------------- -void UnityPrintExpectedAndActualStrings(const char* expected, const char* actual) +/*-----------------------------------------------*/ +static void UnityPrintExpectedAndActualStrings(const char* expected, const char* actual) { UnityPrint(UnityStrExpected); if (expected != NULL) @@ -296,7 +600,7 @@ void UnityPrintExpectedAndActualStrings(const char* expected, const char* actual } else { - UnityPrint(UnityStrNull); + UnityPrint(UnityStrNull); } UnityPrint(UnityStrWas); if (actual != NULL) @@ -307,74 +611,106 @@ void UnityPrintExpectedAndActualStrings(const char* expected, const char* actual } else { - UnityPrint(UnityStrNull); + UnityPrint(UnityStrNull); + } +} + +/*-----------------------------------------------*/ +static void UnityPrintExpectedAndActualStringsLen(const char* expected, + const char* actual, + const UNITY_UINT32 length) +{ + UnityPrint(UnityStrExpected); + if (expected != NULL) + { + UNITY_OUTPUT_CHAR('\''); + UnityPrintLen(expected, length); + UNITY_OUTPUT_CHAR('\''); + } + else + { + UnityPrint(UnityStrNull); + } + UnityPrint(UnityStrWas); + if (actual != NULL) + { + UNITY_OUTPUT_CHAR('\''); + UnityPrintLen(actual, length); + UNITY_OUTPUT_CHAR('\''); + } + else + { + UnityPrint(UnityStrNull); } } -//----------------------------------------------- -// Assertion & Control Helpers -//----------------------------------------------- +/*----------------------------------------------- + * Assertion & Control Helpers + *-----------------------------------------------*/ -int UnityCheckArraysForNull(const void* expected, const void* actual, const UNITY_LINE_TYPE lineNumber, const char* msg) +/*-----------------------------------------------*/ +static int UnityIsOneArrayNull(UNITY_INTERNAL_PTR expected, + UNITY_INTERNAL_PTR actual, + const UNITY_LINE_TYPE lineNumber, + const char* msg) { - //return true if they are both NULL - if ((expected == NULL) && (actual == NULL)) - return 1; - - //throw error if just expected is NULL + /* Both are NULL or same pointer */ + if (expected == actual) { return 0; } + + /* print and return true if just expected is NULL */ if (expected == NULL) { UnityTestResultsFailBegin(lineNumber); UnityPrint(UnityStrNullPointerForExpected); UnityAddMsgIfSpecified(msg); - UNITY_FAIL_AND_BAIL; + return 1; } - //throw error if just actual is NULL + /* print and return true if just actual is NULL */ if (actual == NULL) { UnityTestResultsFailBegin(lineNumber); UnityPrint(UnityStrNullPointerForActual); UnityAddMsgIfSpecified(msg); - UNITY_FAIL_AND_BAIL; + return 1; } - - //return false if neither is NULL - return 0; + + return 0; /* return false if neither is NULL */ } -//----------------------------------------------- -// Assertion Functions -//----------------------------------------------- +/*----------------------------------------------- + * Assertion Functions + *-----------------------------------------------*/ -void UnityAssertBits(const _U_SINT mask, - const _U_SINT expected, - const _U_SINT actual, +/*-----------------------------------------------*/ +void UnityAssertBits(const UNITY_INT mask, + const UNITY_INT expected, + const UNITY_INT actual, const char* msg, const UNITY_LINE_TYPE lineNumber) { - UNITY_SKIP_EXECUTION; - + RETURN_IF_FAIL_OR_IGNORE; + if ((mask & expected) != (mask & actual)) { UnityTestResultsFailBegin(lineNumber); UnityPrint(UnityStrExpected); - UnityPrintMask(mask, expected); + UnityPrintMask((UNITY_UINT)mask, (UNITY_UINT)expected); UnityPrint(UnityStrWas); - UnityPrintMask(mask, actual); + UnityPrintMask((UNITY_UINT)mask, (UNITY_UINT)actual); UnityAddMsgIfSpecified(msg); UNITY_FAIL_AND_BAIL; } } -//----------------------------------------------- -void UnityAssertEqualNumber(const _U_SINT expected, - const _U_SINT actual, +/*-----------------------------------------------*/ +void UnityAssertEqualNumber(const UNITY_INT expected, + const UNITY_INT actual, const char* msg, const UNITY_LINE_TYPE lineNumber, const UNITY_DISPLAY_STYLE_T style) { - UNITY_SKIP_EXECUTION; + RETURN_IF_FAIL_OR_IGNORE; if (expected != actual) { @@ -388,338 +724,494 @@ void UnityAssertEqualNumber(const _U_SINT expected, } } -//----------------------------------------------- -void UnityAssertEqualIntArray(const _U_SINT* expected, - const _U_SINT* actual, - const _UU32 num_elements, - const char* msg, - const UNITY_LINE_TYPE lineNumber, - const UNITY_DISPLAY_STYLE_T style) +/*-----------------------------------------------*/ +void UnityAssertGreaterOrLessOrEqualNumber(const UNITY_INT threshold, + const UNITY_INT actual, + const UNITY_COMPARISON_T compare, + const char *msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style) { - _UU32 elements = num_elements; - const _US8* ptr_exp = (_US8*)expected; - const _US8* ptr_act = (_US8*)actual; + int failed = 0; + RETURN_IF_FAIL_OR_IGNORE; - UNITY_SKIP_EXECUTION; - - if (elements == 0) + if ((threshold == actual) && (compare & UNITY_EQUAL_TO)) { return; } + if ((threshold == actual)) { failed = 1; } + + if ((style & UNITY_DISPLAY_RANGE_INT) == UNITY_DISPLAY_RANGE_INT) + { + if ((actual > threshold) && (compare & UNITY_SMALLER_THAN)) { failed = 1; } + if ((actual < threshold) && (compare & UNITY_GREATER_THAN)) { failed = 1; } + } + else /* UINT or HEX */ + { + if (((UNITY_UINT)actual > (UNITY_UINT)threshold) && (compare & UNITY_SMALLER_THAN)) { failed = 1; } + if (((UNITY_UINT)actual < (UNITY_UINT)threshold) && (compare & UNITY_GREATER_THAN)) { failed = 1; } + } + + if (failed) { UnityTestResultsFailBegin(lineNumber); - UnityPrint(UnityStrPointless); + UnityPrint(UnityStrExpected); + UnityPrintNumberByStyle(actual, style); + if (compare & UNITY_GREATER_THAN) { UnityPrint(UnityStrGt); } + if (compare & UNITY_SMALLER_THAN) { UnityPrint(UnityStrLt); } + if (compare & UNITY_EQUAL_TO) { UnityPrint(UnityStrOrEqual); } + if (compare == UNITY_NOT_EQUAL) { UnityPrint(UnityStrNotEqual); } + UnityPrintNumberByStyle(threshold, style); UnityAddMsgIfSpecified(msg); UNITY_FAIL_AND_BAIL; } - - if (UnityCheckArraysForNull((void*)expected, (void*)actual, lineNumber, msg) == 1) - return; +} + +#define UnityPrintPointlessAndBail() \ +{ \ + UnityTestResultsFailBegin(lineNumber); \ + UnityPrint(UnityStrPointless); \ + UnityAddMsgIfSpecified(msg); \ + UNITY_FAIL_AND_BAIL; } + +/*-----------------------------------------------*/ +void UnityAssertEqualIntArray(UNITY_INTERNAL_PTR expected, + UNITY_INTERNAL_PTR actual, + const UNITY_UINT32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style, + const UNITY_FLAGS_T flags) +{ + UNITY_UINT32 elements = num_elements; + unsigned int length = style & 0xF; + unsigned int increment = 0; + + RETURN_IF_FAIL_OR_IGNORE; - switch(style) + if (num_elements == 0) { - case UNITY_DISPLAY_STYLE_HEX8: - case UNITY_DISPLAY_STYLE_INT8: - case UNITY_DISPLAY_STYLE_UINT8: - while (elements--) - { - if (*ptr_exp != *ptr_act) - { - UnityTestResultsFailBegin(lineNumber); - UnityPrint(UnityStrElement); - UnityPrintNumberByStyle((num_elements - elements - 1), UNITY_DISPLAY_STYLE_UINT); - UnityPrint(UnityStrExpected); - UnityPrintNumberByStyle(*ptr_exp, style); - UnityPrint(UnityStrWas); - UnityPrintNumberByStyle(*ptr_act, style); - UnityAddMsgIfSpecified(msg); - UNITY_FAIL_AND_BAIL; - } - ptr_exp += 1; - ptr_act += 1; - } - break; - case UNITY_DISPLAY_STYLE_HEX16: - case UNITY_DISPLAY_STYLE_INT16: - case UNITY_DISPLAY_STYLE_UINT16: - while (elements--) - { - if (*(_US16*)ptr_exp != *(_US16*)ptr_act) - { - UnityTestResultsFailBegin(lineNumber); - UnityPrint(UnityStrElement); - UnityPrintNumberByStyle((num_elements - elements - 1), UNITY_DISPLAY_STYLE_UINT); - UnityPrint(UnityStrExpected); - UnityPrintNumberByStyle(*(_US16*)ptr_exp, style); - UnityPrint(UnityStrWas); - UnityPrintNumberByStyle(*(_US16*)ptr_act, style); - UnityAddMsgIfSpecified(msg); - UNITY_FAIL_AND_BAIL; - } - ptr_exp += 2; - ptr_act += 2; - } - break; -#ifdef UNITY_SUPPORT_64 - case UNITY_DISPLAY_STYLE_HEX64: - case UNITY_DISPLAY_STYLE_INT64: - case UNITY_DISPLAY_STYLE_UINT64: - while (elements--) - { - if (*(_US64*)ptr_exp != *(_US64*)ptr_act) - { - UnityTestResultsFailBegin(lineNumber); - UnityPrint(UnityStrElement); - UnityPrintNumberByStyle((num_elements - elements - 1), UNITY_DISPLAY_STYLE_UINT); - UnityPrint(UnityStrExpected); - UnityPrintNumberByStyle(*(_US64*)ptr_exp, style); - UnityPrint(UnityStrWas); - UnityPrintNumberByStyle(*(_US64*)ptr_act, style); - UnityAddMsgIfSpecified(msg); - UNITY_FAIL_AND_BAIL; - } - ptr_exp += 8; - ptr_act += 8; - } - break; -#endif - default: - while (elements--) - { - if (*(_US32*)ptr_exp != *(_US32*)ptr_act) - { - UnityTestResultsFailBegin(lineNumber); - UnityPrint(UnityStrElement); - UnityPrintNumberByStyle((num_elements - elements - 1), UNITY_DISPLAY_STYLE_UINT); - UnityPrint(UnityStrExpected); - UnityPrintNumberByStyle(*(_US32*)ptr_exp, style); - UnityPrint(UnityStrWas); - UnityPrintNumberByStyle(*(_US32*)ptr_act, style); - UnityAddMsgIfSpecified(msg); - UNITY_FAIL_AND_BAIL; - } - ptr_exp += 4; - ptr_act += 4; - } - break; + UnityPrintPointlessAndBail(); } -} -//----------------------------------------------- -#ifndef UNITY_EXCLUDE_FLOAT -void UnityAssertEqualFloatArray(const _UF* expected, - const _UF* actual, - const _UU32 num_elements, - const char* msg, - const UNITY_LINE_TYPE lineNumber) -{ - _UU32 elements = num_elements; - const _UF* ptr_expected = expected; - const _UF* ptr_actual = actual; - _UF diff, tol; + if (expected == actual) + { + return; /* Both are NULL or same pointer */ + } - UNITY_SKIP_EXECUTION; - - if (elements == 0) + if (UnityIsOneArrayNull(expected, actual, lineNumber, msg)) { - UnityTestResultsFailBegin(lineNumber); - UnityPrint(UnityStrPointless); - UnityAddMsgIfSpecified(msg); UNITY_FAIL_AND_BAIL; } - - if (UnityCheckArraysForNull((void*)expected, (void*)actual, lineNumber, msg) == 1) - return; - while (elements--) + while ((elements > 0) && (elements--)) { - diff = *ptr_expected - *ptr_actual; - if (diff < 0.0) - diff = 0.0 - diff; - tol = UNITY_FLOAT_PRECISION * *ptr_expected; - if (tol < 0.0) - tol = 0.0 - tol; - if (diff > tol) + UNITY_INT expect_val; + UNITY_INT actual_val; + + switch (length) { - UnityTestResultsFailBegin(lineNumber); - UnityPrint(UnityStrElement); - UnityPrintNumberByStyle((num_elements - elements - 1), UNITY_DISPLAY_STYLE_UINT); -#ifdef UNITY_FLOAT_VERBOSE + case 1: + expect_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT8*)expected; + actual_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT8*)actual; + increment = sizeof(UNITY_INT8); + break; + + case 2: + expect_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT16*)expected; + actual_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT16*)actual; + increment = sizeof(UNITY_INT16); + 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; + increment = sizeof(UNITY_INT64); + break; +#endif + + default: /* default is length 4 bytes */ + case 4: + expect_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT32*)expected; + actual_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT32*)actual; + increment = sizeof(UNITY_INT32); + length = 4; + break; + } + + if (expect_val != actual_val) + { + if ((style & UNITY_DISPLAY_RANGE_UINT) && (length < (UNITY_INT_WIDTH / 8))) + { /* For UINT, remove sign extension (padding 1's) from signed type casts above */ + UNITY_INT mask = 1; + mask = (mask << 8 * length) - 1; + expect_val &= mask; + actual_val &= mask; + } + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrElement); + UnityPrintNumberUnsigned(num_elements - elements - 1); UnityPrint(UnityStrExpected); - UnityPrintFloat(*ptr_expected); + UnityPrintNumberByStyle(expect_val, style); UnityPrint(UnityStrWas); - UnityPrintFloat(*ptr_actual); + UnityPrintNumberByStyle(actual_val, style); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } + /* Walk through array by incrementing the pointers */ + if (flags == UNITY_ARRAY_TO_ARRAY) + { + expected = (UNITY_INTERNAL_PTR)((const char*)expected + increment); + } + actual = (UNITY_INTERNAL_PTR)((const char*)actual + increment); + } +} + +/*-----------------------------------------------*/ +#ifndef UNITY_EXCLUDE_FLOAT +/* Wrap this define in a function with variable types as float or double */ +#define UNITY_FLOAT_OR_DOUBLE_WITHIN(delta, expected, actual, diff) \ + if (isinf(expected) && isinf(actual) && (((expected) < 0) == ((actual) < 0))) return 1; \ + if (UNITY_NAN_CHECK) return 1; \ + (diff) = (actual) - (expected); \ + if ((diff) < 0) (diff) = -(diff); \ + if ((delta) < 0) (delta) = -(delta); \ + return !(isnan(diff) || isinf(diff) || ((diff) > (delta))) + /* This first part of this condition will catch any NaN or Infinite values */ +#ifndef UNITY_NAN_NOT_EQUAL_NAN + #define UNITY_NAN_CHECK isnan(expected) && isnan(actual) #else - UnityPrint(UnityStrDelta); + #define UNITY_NAN_CHECK 0 #endif + +#ifndef UNITY_EXCLUDE_FLOAT_PRINT + #define UNITY_PRINT_EXPECTED_AND_ACTUAL_FLOAT(expected, actual) \ + { \ + UnityPrint(UnityStrExpected); \ + UnityPrintFloat(expected); \ + UnityPrint(UnityStrWas); \ + UnityPrintFloat(actual); } +#else + #define UNITY_PRINT_EXPECTED_AND_ACTUAL_FLOAT(expected, actual) \ + UnityPrint(UnityStrDelta) +#endif /* UNITY_EXCLUDE_FLOAT_PRINT */ + +/*-----------------------------------------------*/ +static int UnityFloatsWithin(UNITY_FLOAT delta, UNITY_FLOAT expected, UNITY_FLOAT actual) +{ + UNITY_FLOAT diff; + UNITY_FLOAT_OR_DOUBLE_WITHIN(delta, expected, actual, diff); +} + +/*-----------------------------------------------*/ +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_FLAGS_T flags) +{ + UNITY_UINT32 elements = num_elements; + UNITY_PTR_ATTRIBUTE const UNITY_FLOAT* ptr_expected = expected; + UNITY_PTR_ATTRIBUTE const UNITY_FLOAT* ptr_actual = actual; + + RETURN_IF_FAIL_OR_IGNORE; + + if (elements == 0) + { + UnityPrintPointlessAndBail(); + } + + if (expected == actual) + { + return; /* Both are NULL or same pointer */ + } + + if (UnityIsOneArrayNull((UNITY_INTERNAL_PTR)expected, (UNITY_INTERNAL_PTR)actual, lineNumber, msg)) + { + UNITY_FAIL_AND_BAIL; + } + + while (elements--) + { + if (!UnityFloatsWithin(*ptr_expected * UNITY_FLOAT_PRECISION, *ptr_expected, *ptr_actual)) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrElement); + UnityPrintNumberUnsigned(num_elements - elements - 1); + UNITY_PRINT_EXPECTED_AND_ACTUAL_FLOAT((UNITY_DOUBLE)*ptr_expected, (UNITY_DOUBLE)*ptr_actual); UnityAddMsgIfSpecified(msg); UNITY_FAIL_AND_BAIL; } - ptr_expected++; + if (flags == UNITY_ARRAY_TO_ARRAY) + { + ptr_expected++; + } ptr_actual++; } } -//----------------------------------------------- -void UnityAssertFloatsWithin(const _UF delta, - const _UF expected, - const _UF actual, +/*-----------------------------------------------*/ +void UnityAssertFloatsWithin(const UNITY_FLOAT delta, + const UNITY_FLOAT expected, + const UNITY_FLOAT actual, const char* msg, const UNITY_LINE_TYPE lineNumber) { - _UF diff = actual - expected; - _UF pos_delta = delta; + RETURN_IF_FAIL_OR_IGNORE; + - UNITY_SKIP_EXECUTION; - - if (diff < 0) + if (!UnityFloatsWithin(delta, expected, actual)) { - diff = 0.0f - diff; + UnityTestResultsFailBegin(lineNumber); + UNITY_PRINT_EXPECTED_AND_ACTUAL_FLOAT((UNITY_DOUBLE)expected, (UNITY_DOUBLE)actual); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; } - if (pos_delta < 0) +} + +/*-----------------------------------------------*/ +void UnityAssertFloatSpecial(const UNITY_FLOAT actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_FLOAT_TRAIT_T style) +{ + const char* trait_names[] = {UnityStrInf, UnityStrNegInf, UnityStrNaN, UnityStrDet}; + UNITY_INT should_be_trait = ((UNITY_INT)style & 1); + UNITY_INT is_trait = !should_be_trait; + UNITY_INT trait_index = (UNITY_INT)(style >> 1); + + RETURN_IF_FAIL_OR_IGNORE; + + switch (style) { - pos_delta = 0.0f - pos_delta; + case UNITY_FLOAT_IS_INF: + case UNITY_FLOAT_IS_NOT_INF: + is_trait = isinf(actual) && (actual > 0); + break; + case UNITY_FLOAT_IS_NEG_INF: + case UNITY_FLOAT_IS_NOT_NEG_INF: + is_trait = isinf(actual) && (actual < 0); + break; + + case UNITY_FLOAT_IS_NAN: + case UNITY_FLOAT_IS_NOT_NAN: + is_trait = isnan(actual) ? 1 : 0; + break; + + case UNITY_FLOAT_IS_DET: /* A determinate number is non infinite and not NaN. */ + case UNITY_FLOAT_IS_NOT_DET: + is_trait = !isinf(actual) && !isnan(actual); + break; + + default: /* including UNITY_FLOAT_INVALID_TRAIT */ + trait_index = 0; + trait_names[0] = UnityStrInvalidFloatTrait; + break; } - if (pos_delta < diff) + if (is_trait != should_be_trait) { UnityTestResultsFailBegin(lineNumber); -#ifdef UNITY_FLOAT_VERBOSE UnityPrint(UnityStrExpected); - UnityPrintFloat(expected); + if (!should_be_trait) + { + UnityPrint(UnityStrNot); + } + UnityPrint(trait_names[trait_index]); UnityPrint(UnityStrWas); - UnityPrintFloat(actual); +#ifndef UNITY_EXCLUDE_FLOAT_PRINT + UnityPrintFloat((UNITY_DOUBLE)actual); #else - UnityPrint(UnityStrDelta); + if (should_be_trait) + { + UnityPrint(UnityStrNot); + } + UnityPrint(trait_names[trait_index]); #endif UnityAddMsgIfSpecified(msg); UNITY_FAIL_AND_BAIL; } } -#endif //not UNITY_EXCLUDE_FLOAT +#endif /* not UNITY_EXCLUDE_FLOAT */ -//----------------------------------------------- +/*-----------------------------------------------*/ #ifndef UNITY_EXCLUDE_DOUBLE -void UnityAssertEqualDoubleArray(const _UD* expected, - const _UD* actual, - const _UU32 num_elements, +static int UnityDoublesWithin(UNITY_DOUBLE delta, UNITY_DOUBLE expected, UNITY_DOUBLE actual) +{ + UNITY_DOUBLE diff; + UNITY_FLOAT_OR_DOUBLE_WITHIN(delta, expected, actual, diff); +} + +/*-----------------------------------------------*/ +void UnityAssertEqualDoubleArray(UNITY_PTR_ATTRIBUTE const UNITY_DOUBLE* expected, + 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) { - _UU32 elements = num_elements; - const _UD* ptr_expected = expected; - const _UD* ptr_actual = actual; - _UD diff, tol; + UNITY_UINT32 elements = num_elements; + UNITY_PTR_ATTRIBUTE const UNITY_DOUBLE* ptr_expected = expected; + UNITY_PTR_ATTRIBUTE const UNITY_DOUBLE* ptr_actual = actual; + + RETURN_IF_FAIL_OR_IGNORE; - UNITY_SKIP_EXECUTION; - if (elements == 0) { - UnityTestResultsFailBegin(lineNumber); - UnityPrint(UnityStrPointless); - UnityAddMsgIfSpecified(msg); + UnityPrintPointlessAndBail(); + } + + if (expected == 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 (UnityCheckArraysForNull((void*)expected, (void*)actual, lineNumber, msg) == 1) - return; while (elements--) { - diff = *ptr_expected - *ptr_actual; - if (diff < 0.0) - diff = 0.0 - diff; - tol = UNITY_DOUBLE_PRECISION * *ptr_expected; - if (tol < 0.0) - tol = 0.0 - tol; - if (diff > tol) + if (!UnityDoublesWithin(*ptr_expected * UNITY_DOUBLE_PRECISION, *ptr_expected, *ptr_actual)) { UnityTestResultsFailBegin(lineNumber); UnityPrint(UnityStrElement); - UnityPrintNumberByStyle((num_elements - elements - 1), UNITY_DISPLAY_STYLE_UINT); -#ifdef UNITY_DOUBLE_VERBOSE - UnityPrint(UnityStrExpected); - UnityPrintFloat((float)(*ptr_expected)); - UnityPrint(UnityStrWas); - UnityPrintFloat((float)(*ptr_actual)); -#else - UnityPrint(UnityStrDelta); -#endif + UnityPrintNumberUnsigned(num_elements - elements - 1); + UNITY_PRINT_EXPECTED_AND_ACTUAL_FLOAT(*ptr_expected, *ptr_actual); UnityAddMsgIfSpecified(msg); UNITY_FAIL_AND_BAIL; } - ptr_expected++; + if (flags == UNITY_ARRAY_TO_ARRAY) + { + ptr_expected++; + } ptr_actual++; } } -//----------------------------------------------- -void UnityAssertDoublesWithin(const _UD delta, - const _UD expected, - const _UD actual, +/*-----------------------------------------------*/ +void UnityAssertDoublesWithin(const UNITY_DOUBLE delta, + const UNITY_DOUBLE expected, + const UNITY_DOUBLE actual, const char* msg, const UNITY_LINE_TYPE lineNumber) { - _UD diff = actual - expected; - _UD pos_delta = delta; + RETURN_IF_FAIL_OR_IGNORE; - UNITY_SKIP_EXECUTION; - - if (diff < 0) + if (!UnityDoublesWithin(delta, expected, actual)) { - diff = 0.0f - diff; + UnityTestResultsFailBegin(lineNumber); + UNITY_PRINT_EXPECTED_AND_ACTUAL_FLOAT(expected, actual); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; } - if (pos_delta < 0) +} + +/*-----------------------------------------------*/ +void UnityAssertDoubleSpecial(const UNITY_DOUBLE actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_FLOAT_TRAIT_T style) +{ + const char* trait_names[] = {UnityStrInf, UnityStrNegInf, UnityStrNaN, UnityStrDet}; + UNITY_INT should_be_trait = ((UNITY_INT)style & 1); + UNITY_INT is_trait = !should_be_trait; + UNITY_INT trait_index = (UNITY_INT)(style >> 1); + + RETURN_IF_FAIL_OR_IGNORE; + + switch (style) { - pos_delta = 0.0f - pos_delta; + case UNITY_FLOAT_IS_INF: + case UNITY_FLOAT_IS_NOT_INF: + is_trait = isinf(actual) && (actual > 0); + break; + case UNITY_FLOAT_IS_NEG_INF: + case UNITY_FLOAT_IS_NOT_NEG_INF: + is_trait = isinf(actual) && (actual < 0); + break; + + case UNITY_FLOAT_IS_NAN: + case UNITY_FLOAT_IS_NOT_NAN: + is_trait = isnan(actual) ? 1 : 0; + break; + + case UNITY_FLOAT_IS_DET: /* A determinate number is non infinite and not NaN. */ + case UNITY_FLOAT_IS_NOT_DET: + is_trait = !isinf(actual) && !isnan(actual); + break; + + default: /* including UNITY_FLOAT_INVALID_TRAIT */ + trait_index = 0; + trait_names[0] = UnityStrInvalidFloatTrait; + break; } - if (pos_delta < diff) + if (is_trait != should_be_trait) { UnityTestResultsFailBegin(lineNumber); -#ifdef UNITY_DOUBLE_VERBOSE UnityPrint(UnityStrExpected); - UnityPrintFloat((float)expected); + if (!should_be_trait) + { + UnityPrint(UnityStrNot); + } + UnityPrint(trait_names[trait_index]); UnityPrint(UnityStrWas); - UnityPrintFloat((float)actual); +#ifndef UNITY_EXCLUDE_FLOAT_PRINT + UnityPrintFloat(actual); #else - UnityPrint(UnityStrDelta); + if (should_be_trait) + { + UnityPrint(UnityStrNot); + } + UnityPrint(trait_names[trait_index]); #endif UnityAddMsgIfSpecified(msg); UNITY_FAIL_AND_BAIL; } } -#endif // not UNITY_EXCLUDE_DOUBLE +#endif /* not UNITY_EXCLUDE_DOUBLE */ -//----------------------------------------------- -void UnityAssertNumbersWithin( const _U_SINT delta, - const _U_SINT expected, - const _U_SINT actual, - const char* msg, - const UNITY_LINE_TYPE lineNumber, - const UNITY_DISPLAY_STYLE_T style) +/*-----------------------------------------------*/ +void UnityAssertNumbersWithin(const UNITY_UINT delta, + const UNITY_INT expected, + const UNITY_INT actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style) { - UNITY_SKIP_EXECUTION; - + RETURN_IF_FAIL_OR_IGNORE; + if ((style & UNITY_DISPLAY_RANGE_INT) == UNITY_DISPLAY_RANGE_INT) { if (actual > expected) - Unity.CurrentTestFailed = ((actual - expected) > delta); + { + Unity.CurrentTestFailed = (((UNITY_UINT)actual - (UNITY_UINT)expected) > delta); + } else - Unity.CurrentTestFailed = ((expected - actual) > delta); + { + Unity.CurrentTestFailed = (((UNITY_UINT)expected - (UNITY_UINT)actual) > delta); + } } else { - if ((_U_UINT)actual > (_U_UINT)expected) - Unity.CurrentTestFailed = ((_U_UINT)(actual - expected) > (_U_UINT)delta); + if ((UNITY_UINT)actual > (UNITY_UINT)expected) + { + Unity.CurrentTestFailed = (((UNITY_UINT)actual - (UNITY_UINT)expected) > delta); + } else - Unity.CurrentTestFailed = ((_U_UINT)(expected - actual) > (_U_UINT)delta); + { + Unity.CurrentTestFailed = (((UNITY_UINT)expected - (UNITY_UINT)actual) > delta); + } } if (Unity.CurrentTestFailed) { UnityTestResultsFailBegin(lineNumber); UnityPrint(UnityStrDelta); - UnityPrintNumberByStyle(delta, style); + UnityPrintNumberByStyle((UNITY_INT)delta, style); UnityPrint(UnityStrExpected); UnityPrintNumberByStyle(expected, style); UnityPrint(UnityStrWas); @@ -729,17 +1221,137 @@ void UnityAssertNumbersWithin( const _U_SINT delta, } } -//----------------------------------------------- +/*-----------------------------------------------*/ +void UnityAssertNumbersArrayWithin(const UNITY_UINT delta, + UNITY_INTERNAL_PTR expected, + UNITY_INTERNAL_PTR actual, + const UNITY_UINT32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style, + const UNITY_FLAGS_T flags) +{ + UNITY_UINT32 elements = num_elements; + unsigned int length = style & 0xF; + unsigned int increment = 0; + + RETURN_IF_FAIL_OR_IGNORE; + + if (num_elements == 0) + { + UnityPrintPointlessAndBail(); + } + + if (expected == actual) + { + return; /* Both are NULL or same pointer */ + } + + if (UnityIsOneArrayNull(expected, actual, lineNumber, msg)) + { + UNITY_FAIL_AND_BAIL; + } + + while ((elements > 0) && (elements--)) + { + UNITY_INT expect_val; + UNITY_INT actual_val; + + switch (length) + { + case 1: + expect_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT8*)expected; + actual_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT8*)actual; + increment = sizeof(UNITY_INT8); + break; + + case 2: + expect_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT16*)expected; + actual_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT16*)actual; + increment = sizeof(UNITY_INT16); + 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; + increment = sizeof(UNITY_INT64); + break; +#endif + + default: /* default is length 4 bytes */ + case 4: + expect_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT32*)expected; + actual_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT32*)actual; + increment = sizeof(UNITY_INT32); + length = 4; + break; + } + + if ((style & UNITY_DISPLAY_RANGE_INT) == UNITY_DISPLAY_RANGE_INT) + { + if (actual_val > expect_val) + { + Unity.CurrentTestFailed = (((UNITY_UINT)actual_val - (UNITY_UINT)expect_val) > delta); + } + else + { + Unity.CurrentTestFailed = (((UNITY_UINT)expect_val - (UNITY_UINT)actual_val) > delta); + } + } + else + { + if ((UNITY_UINT)actual_val > (UNITY_UINT)expect_val) + { + Unity.CurrentTestFailed = (((UNITY_UINT)actual_val - (UNITY_UINT)expect_val) > delta); + } + else + { + Unity.CurrentTestFailed = (((UNITY_UINT)expect_val - (UNITY_UINT)actual_val) > delta); + } + } + + if (Unity.CurrentTestFailed) + { + if ((style & UNITY_DISPLAY_RANGE_UINT) && (length < (UNITY_INT_WIDTH / 8))) + { /* For UINT, remove sign extension (padding 1's) from signed type casts above */ + UNITY_INT mask = 1; + mask = (mask << 8 * length) - 1; + expect_val &= mask; + actual_val &= mask; + } + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrDelta); + UnityPrintNumberByStyle((UNITY_INT)delta, style); + UnityPrint(UnityStrElement); + UnityPrintNumberUnsigned(num_elements - elements - 1); + UnityPrint(UnityStrExpected); + UnityPrintNumberByStyle(expect_val, style); + UnityPrint(UnityStrWas); + UnityPrintNumberByStyle(actual_val, style); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } + /* Walk through array by incrementing the pointers */ + if (flags == UNITY_ARRAY_TO_ARRAY) + { + expected = (UNITY_INTERNAL_PTR)((const char*)expected + increment); + } + actual = (UNITY_INTERNAL_PTR)((const char*)actual + increment); + } +} + +/*-----------------------------------------------*/ void UnityAssertEqualString(const char* expected, const char* actual, const char* msg, const UNITY_LINE_TYPE lineNumber) { - _UU32 i; + UNITY_UINT32 i; - UNITY_SKIP_EXECUTION; - - // if both pointers not null compare the strings + RETURN_IF_FAIL_OR_IGNORE; + + /* if both pointers not null compare the strings */ if (expected && actual) { for (i = 0; expected[i] || actual[i]; i++) @@ -752,7 +1364,7 @@ void UnityAssertEqualString(const char* expected, } } else - { // handle case of one pointers being null (if both null, test should pass) + { /* handle case of one pointers being null (if both null, test should pass) */ if (expected != actual) { Unity.CurrentTestFailed = 1; @@ -761,44 +1373,103 @@ void UnityAssertEqualString(const char* expected, if (Unity.CurrentTestFailed) { - UnityTestResultsFailBegin(lineNumber); - UnityPrintExpectedAndActualStrings(expected, actual); - UnityAddMsgIfSpecified(msg); - UNITY_FAIL_AND_BAIL; + UnityTestResultsFailBegin(lineNumber); + UnityPrintExpectedAndActualStrings(expected, actual); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; } } -//----------------------------------------------- -void UnityAssertEqualStringArray( const char** expected, - const char** actual, - const _UU32 num_elements, - const char* msg, - const UNITY_LINE_TYPE lineNumber) +/*-----------------------------------------------*/ +void UnityAssertEqualStringLen(const char* expected, + const char* actual, + const UNITY_UINT32 length, + const char* msg, + const UNITY_LINE_TYPE lineNumber) { - _UU32 i, j = 0; - - UNITY_SKIP_EXECUTION; - - // if no elements, it's an error - if (num_elements == 0) + UNITY_UINT32 i; + + RETURN_IF_FAIL_OR_IGNORE; + + /* if both pointers not null compare the strings */ + if (expected && actual) + { + for (i = 0; (i < length) && (expected[i] || actual[i]); i++) + { + if (expected[i] != actual[i]) + { + Unity.CurrentTestFailed = 1; + break; + } + } + } + else + { /* handle case of one pointers being null (if both null, test should pass) */ + if (expected != actual) + { + Unity.CurrentTestFailed = 1; + } + } + + if (Unity.CurrentTestFailed) { UnityTestResultsFailBegin(lineNumber); - UnityPrint(UnityStrPointless); + UnityPrintExpectedAndActualStringsLen(expected, actual, length); UnityAddMsgIfSpecified(msg); UNITY_FAIL_AND_BAIL; } +} + +/*-----------------------------------------------*/ +void UnityAssertEqualStringArray(UNITY_INTERNAL_PTR expected, + const char** actual, + const UNITY_UINT32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_FLAGS_T flags) +{ + UNITY_UINT32 i = 0; + UNITY_UINT32 j = 0; + const char* expd = NULL; + const char* act = NULL; + + RETURN_IF_FAIL_OR_IGNORE; + + /* if no elements, it's an error */ + if (num_elements == 0) + { + UnityPrintPointlessAndBail(); + } + + 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) + { + expd = (const char*)expected; + } - if (UnityCheckArraysForNull((void*)expected, (void*)actual, lineNumber, msg) == 1) - return; - do { - // if both pointers not null compare the strings - if (expected[j] && actual[j]) + act = actual[j]; + if (flags == UNITY_ARRAY_TO_ARRAY) + { + expd = ((const char* const*)expected)[j]; + } + + /* if both pointers not null compare the strings */ + if (expd && act) { - for (i = 0; expected[j][i] || actual[j][i]; i++) + for (i = 0; expd[i] || act[i]; i++) { - if (expected[j][i] != actual[j][i]) + if (expd[i] != act[i]) { Unity.CurrentTestFailed = 1; break; @@ -806,8 +1477,8 @@ void UnityAssertEqualStringArray( const char** expected, } } else - { // handle case of one pointers being null (if both null, test should pass) - if (expected[j] != actual[j]) + { /* handle case of one pointers being null (if both null, test should pass) */ + if (expd != act) { Unity.CurrentTestFailed = 1; } @@ -819,44 +1490,48 @@ void UnityAssertEqualStringArray( const char** expected, if (num_elements > 1) { UnityPrint(UnityStrElement); - UnityPrintNumberByStyle((num_elements - j - 1), UNITY_DISPLAY_STYLE_UINT); + UnityPrintNumberUnsigned(j); } - UnityPrintExpectedAndActualStrings((const char*)(expected[j]), (const char*)(actual[j])); + UnityPrintExpectedAndActualStrings(expd, act); UnityAddMsgIfSpecified(msg); UNITY_FAIL_AND_BAIL; - } + } } while (++j < num_elements); } -//----------------------------------------------- -void UnityAssertEqualMemory( const void* expected, - const void* actual, - const _UU32 length, - const _UU32 num_elements, - const char* msg, - const UNITY_LINE_TYPE lineNumber) +/*-----------------------------------------------*/ +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_FLAGS_T flags) { - unsigned char* ptr_exp = (unsigned char*)expected; - unsigned char* ptr_act = (unsigned char*)actual; - _UU32 elements = num_elements; - _UU32 bytes; + 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; + UNITY_UINT32 elements = num_elements; + UNITY_UINT32 bytes; + + RETURN_IF_FAIL_OR_IGNORE; - UNITY_SKIP_EXECUTION; - if ((elements == 0) || (length == 0)) { - UnityTestResultsFailBegin(lineNumber); - UnityPrint(UnityStrPointless); - UnityAddMsgIfSpecified(msg); + UnityPrintPointlessAndBail(); + } + + if (expected == actual) + { + return; /* Both are NULL or same pointer */ + } + + if (UnityIsOneArrayNull(expected, actual, lineNumber, msg)) + { UNITY_FAIL_AND_BAIL; } - if (UnityCheckArraysForNull((void*)expected, (void*)actual, lineNumber, msg) == 1) - return; - while (elements--) { - ///////////////////////////////////// bytes = length; while (bytes--) { @@ -867,10 +1542,10 @@ void UnityAssertEqualMemory( const void* expected, if (num_elements > 1) { UnityPrint(UnityStrElement); - UnityPrintNumberByStyle((num_elements - elements - 1), UNITY_DISPLAY_STYLE_UINT); + UnityPrintNumberUnsigned(num_elements - elements - 1); } UnityPrint(UnityStrByte); - UnityPrintNumberByStyle((length - bytes - 1), UNITY_DISPLAY_STYLE_UINT); + UnityPrintNumberUnsigned(length - bytes - 1); UnityPrint(UnityStrExpected); UnityPrintNumberByStyle(*ptr_exp, UNITY_DISPLAY_STYLE_HEX8); UnityPrint(UnityStrWas); @@ -878,102 +1553,558 @@ void UnityAssertEqualMemory( const void* expected, UnityAddMsgIfSpecified(msg); UNITY_FAIL_AND_BAIL; } - ptr_exp += 1; - ptr_act += 1; + ptr_exp++; + ptr_act++; + } + if (flags == UNITY_ARRAY_TO_VAL) + { + ptr_exp = (UNITY_PTR_ATTRIBUTE const unsigned char*)expected; } - ///////////////////////////////////// - } } -//----------------------------------------------- -// Control Functions -//----------------------------------------------- +/*-----------------------------------------------*/ +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 + +/*----------------------------------------------- + * printf helper function + *-----------------------------------------------*/ +#ifdef UNITY_INCLUDE_PRINT_FORMATTED +static void UnityPrintFVA(const char* format, va_list va) +{ + const char* pch = format; + if (pch != NULL) + { + while (*pch) + { + /* format identification character */ + if (*pch == '%') + { + pch++; + + if (pch != NULL) + { + switch (*pch) + { + case 'd': + case 'i': + { + const int number = va_arg(va, int); + UnityPrintNumber((UNITY_INT)number); + break; + } +#ifndef UNITY_EXCLUDE_FLOAT_PRINT + case 'f': + case 'g': + { + const double number = va_arg(va, double); + UnityPrintFloat((UNITY_DOUBLE)number); + break; + } +#endif + case 'u': + { + const unsigned int number = va_arg(va, unsigned int); + UnityPrintNumberUnsigned((UNITY_UINT)number); + break; + } + case 'b': + { + const unsigned int number = va_arg(va, unsigned int); + const UNITY_UINT mask = (UNITY_UINT)0 - (UNITY_UINT)1; + UNITY_OUTPUT_CHAR('0'); + UNITY_OUTPUT_CHAR('b'); + UnityPrintMask(mask, (UNITY_UINT)number); + break; + } + case 'x': + case 'X': + case 'p': + { + const unsigned int number = va_arg(va, unsigned int); + UNITY_OUTPUT_CHAR('0'); + UNITY_OUTPUT_CHAR('x'); + UnityPrintNumberHex((UNITY_UINT)number, 8); + break; + } + case 'c': + { + const int ch = va_arg(va, int); + UnityPrintChar((const char *)&ch); + break; + } + case 's': + { + const char * string = va_arg(va, const char *); + UnityPrint(string); + break; + } + case '%': + { + UnityPrintChar(pch); + break; + } + default: + { + /* print the unknown format character */ + UNITY_OUTPUT_CHAR('%'); + UnityPrintChar(pch); + break; + } + } + } + } +#ifdef UNITY_OUTPUT_COLOR + /* print ANSI escape code */ + else if ((*pch == 27) && (*(pch + 1) == '[')) + { + pch += UnityPrintAnsiEscapeString(pch); + continue; + } +#endif + else if (*pch == '\n') + { + UNITY_PRINT_EOL(); + } + else + { + UnityPrintChar(pch); + } + + pch++; + } + } +} + +void UnityPrintF(const UNITY_LINE_TYPE line, const char* format, ...) +{ + UnityTestResultsBegin(Unity.TestFile, line); + UnityPrint("INFO"); + if(format != NULL) + { + UnityPrint(": "); + va_list va; + va_start(va, format); + UnityPrintFVA(format, va); + va_end(va); + } + UNITY_PRINT_EOL(); +} +#endif /* ! UNITY_INCLUDE_PRINT_FORMATTED */ + + +/*----------------------------------------------- + * Control Functions + *-----------------------------------------------*/ + +/*-----------------------------------------------*/ void UnityFail(const char* msg, const UNITY_LINE_TYPE line) { - UNITY_SKIP_EXECUTION; + RETURN_IF_FAIL_OR_IGNORE; UnityTestResultsBegin(Unity.TestFile, line); - UnityPrintFail(); + UnityPrint(UnityStrFail); if (msg != NULL) { - UNITY_OUTPUT_CHAR(':'); - if (msg[0] != ' ') - { - UNITY_OUTPUT_CHAR(' '); - } - UnityPrint(msg); + UNITY_OUTPUT_CHAR(':'); + +#ifdef UNITY_PRINT_TEST_CONTEXT + UNITY_PRINT_TEST_CONTEXT(); +#endif +#ifndef UNITY_EXCLUDE_DETAILS + if (Unity.CurrentDetail1) + { + UnityPrint(UnityStrDetail1Name); + UnityPrint(Unity.CurrentDetail1); + if (Unity.CurrentDetail2) + { + UnityPrint(UnityStrDetail2Name); + UnityPrint(Unity.CurrentDetail2); + } + UnityPrint(UnityStrSpacer); + } +#endif + if (msg[0] != ' ') + { + UNITY_OUTPUT_CHAR(' '); + } + UnityPrint(msg); } + UNITY_FAIL_AND_BAIL; } -//----------------------------------------------- +/*-----------------------------------------------*/ void UnityIgnore(const char* msg, const UNITY_LINE_TYPE line) { - UNITY_SKIP_EXECUTION; + RETURN_IF_FAIL_OR_IGNORE; UnityTestResultsBegin(Unity.TestFile, line); - UnityPrint("IGNORE"); + UnityPrint(UnityStrIgnore); + if (msg != NULL) + { + UNITY_OUTPUT_CHAR(':'); + UNITY_OUTPUT_CHAR(' '); + UnityPrint(msg); + } + UNITY_IGNORE_AND_BAIL; +} + +/*-----------------------------------------------*/ +void UnityMessage(const char* msg, const UNITY_LINE_TYPE line) +{ + UnityTestResultsBegin(Unity.TestFile, line); + UnityPrint("INFO"); if (msg != NULL) { UNITY_OUTPUT_CHAR(':'); UNITY_OUTPUT_CHAR(' '); UnityPrint(msg); } - UNITY_IGNORE_AND_BAIL; + UNITY_PRINT_EOL(); } -//----------------------------------------------- -void setUp(void); -void tearDown(void); +/*-----------------------------------------------*/ +/* If we have not defined our own test runner, then include our default test runner to make life easier */ +#ifndef UNITY_SKIP_DEFAULT_RUNNER void UnityDefaultTestRun(UnityTestFunction Func, const char* FuncName, const int FuncLineNum) { Unity.CurrentTestName = FuncName; - Unity.CurrentTestLineNumber = FuncLineNum; - Unity.NumberOfTests++; + Unity.CurrentTestLineNumber = (UNITY_LINE_TYPE)FuncLineNum; + Unity.NumberOfTests++; + UNITY_CLR_DETAILS(); + UNITY_EXEC_TIME_START(); if (TEST_PROTECT()) { setUp(); Func(); } - if (TEST_PROTECT() && !(Unity.CurrentTestIgnored)) + if (TEST_PROTECT()) { tearDown(); } + UNITY_EXEC_TIME_STOP(); UnityConcludeTest(); } +#endif + +/*-----------------------------------------------*/ +void UnitySetTestFile(const char* filename) +{ + Unity.TestFile = filename; +} -//----------------------------------------------- -void UnityBegin(void) +/*-----------------------------------------------*/ +void UnityBegin(const char* filename) { + Unity.TestFile = filename; + Unity.CurrentTestName = NULL; + Unity.CurrentTestLineNumber = 0; Unity.NumberOfTests = 0; Unity.TestFailures = 0; Unity.TestIgnores = 0; Unity.CurrentTestFailed = 0; Unity.CurrentTestIgnored = 0; + + UNITY_CLR_DETAILS(); + UNITY_OUTPUT_START(); } -//----------------------------------------------- +/*-----------------------------------------------*/ int UnityEnd(void) { - UnityPrint("-----------------------"); - UNITY_PRINT_EOL; - UnityPrintNumber(Unity.NumberOfTests); - UnityPrint(" Tests "); - UnityPrintNumber(Unity.TestFailures); - UnityPrint(" Failures "); - UnityPrintNumber(Unity.TestIgnores); - UnityPrint(" Ignored"); - UNITY_PRINT_EOL; + UNITY_PRINT_EOL(); + UnityPrint(UnityStrBreaker); + UNITY_PRINT_EOL(); + UnityPrintNumber((UNITY_INT)(Unity.NumberOfTests)); + UnityPrint(UnityStrResultsTests); + UnityPrintNumber((UNITY_INT)(Unity.TestFailures)); + UnityPrint(UnityStrResultsFailures); + UnityPrintNumber((UNITY_INT)(Unity.TestIgnores)); + UnityPrint(UnityStrResultsIgnored); + UNITY_PRINT_EOL(); if (Unity.TestFailures == 0U) { - UnityPrintOk(); + UnityPrint(UnityStrOk); + } + else + { + UnityPrint(UnityStrFail); +#ifdef UNITY_DIFFERENTIATE_FINAL_FAIL + UNITY_OUTPUT_CHAR('E'); UNITY_OUTPUT_CHAR('D'); +#endif + } + UNITY_PRINT_EOL(); + UNITY_FLUSH_CALL(); + UNITY_OUTPUT_COMPLETE(); + return (int)(Unity.TestFailures); +} + +/*----------------------------------------------- + * Command Line Argument Support + *-----------------------------------------------*/ +#ifdef UNITY_USE_COMMAND_LINE_ARGS + +char* UnityOptionIncludeNamed = NULL; +char* UnityOptionExcludeNamed = NULL; +int UnityVerbosity = 1; + +/*-----------------------------------------------*/ +int UnityParseOptions(int argc, char** argv) +{ + int i; + UnityOptionIncludeNamed = NULL; + UnityOptionExcludeNamed = NULL; + + for (i = 1; i < argc; i++) + { + if (argv[i][0] == '-') + { + switch (argv[i][1]) + { + case 'l': /* list tests */ + return -1; + case 'n': /* include tests with name including this string */ + case 'f': /* an alias for -n */ + if (argv[i][2] == '=') + { + UnityOptionIncludeNamed = &argv[i][3]; + } + else if (++i < argc) + { + UnityOptionIncludeNamed = argv[i]; + } + else + { + UnityPrint("ERROR: No Test String to Include Matches For"); + UNITY_PRINT_EOL(); + return 1; + } + break; + case 'q': /* quiet */ + UnityVerbosity = 0; + break; + case 'v': /* verbose */ + UnityVerbosity = 2; + break; + case 'x': /* exclude tests with name including this string */ + if (argv[i][2] == '=') + { + UnityOptionExcludeNamed = &argv[i][3]; + } + else if (++i < argc) + { + UnityOptionExcludeNamed = argv[i]; + } + else + { + UnityPrint("ERROR: No Test String to Exclude Matches For"); + UNITY_PRINT_EOL(); + return 1; + } + break; + default: + UnityPrint("ERROR: Unknown Option "); + UNITY_OUTPUT_CHAR(argv[i][1]); + UNITY_PRINT_EOL(); + return 1; + } + } + } + + return 0; +} + +/*-----------------------------------------------*/ +int IsStringInBiggerString(const char* longstring, const char* shortstring) +{ + const char* lptr = longstring; + const char* sptr = shortstring; + const char* lnext = lptr; + + if (*sptr == '*') + { + return 1; + } + + while (*lptr) + { + lnext = lptr + 1; + + /* If they current bytes match, go on to the next bytes */ + while (*lptr && *sptr && (*lptr == *sptr)) + { + lptr++; + sptr++; + + /* We're done if we match the entire string or up to a wildcard */ + if (*sptr == '*') + return 1; + if (*sptr == ',') + return 1; + if (*sptr == '"') + return 1; + if (*sptr == '\'') + return 1; + if (*sptr == ':') + return 2; + if (*sptr == 0) + return 1; + } + + /* Otherwise we start in the long pointer 1 character further and try again */ + lptr = lnext; + sptr = shortstring; + } + + return 0; +} + +/*-----------------------------------------------*/ +int UnityStringArgumentMatches(const char* str) +{ + int retval; + const char* ptr1; + const char* ptr2; + const char* ptrf; + + /* Go through the options and get the substrings for matching one at a time */ + ptr1 = str; + while (ptr1[0] != 0) + { + if ((ptr1[0] == '"') || (ptr1[0] == '\'')) + { + ptr1++; + } + + /* look for the start of the next partial */ + ptr2 = ptr1; + ptrf = 0; + do + { + ptr2++; + if ((ptr2[0] == ':') && (ptr2[1] != 0) && (ptr2[0] != '\'') && (ptr2[0] != '"') && (ptr2[0] != ',')) + { + ptrf = &ptr2[1]; + } + } while ((ptr2[0] != 0) && (ptr2[0] != '\'') && (ptr2[0] != '"') && (ptr2[0] != ',')); + + while ((ptr2[0] != 0) && ((ptr2[0] == ':') || (ptr2[0] == '\'') || (ptr2[0] == '"') || (ptr2[0] == ','))) + { + ptr2++; + } + + /* done if complete filename match */ + retval = IsStringInBiggerString(Unity.TestFile, ptr1); + if (retval == 1) + { + return retval; + } + + /* done if testname match after filename partial match */ + if ((retval == 2) && (ptrf != 0)) + { + if (IsStringInBiggerString(Unity.CurrentTestName, ptrf)) + { + return 1; + } + } + + /* done if complete testname match */ + if (IsStringInBiggerString(Unity.CurrentTestName, ptr1) == 1) + { + return 1; + } + + ptr1 = ptr2; + } + + /* we couldn't find a match for any substrings */ + return 0; +} + +/*-----------------------------------------------*/ +int UnityTestMatches(void) +{ + /* Check if this test name matches the included test pattern */ + int retval; + if (UnityOptionIncludeNamed) + { + retval = UnityStringArgumentMatches(UnityOptionIncludeNamed); } else { - UnityPrintFail(); + retval = 1; } - UNITY_PRINT_EOL; - return Unity.TestFailures; + + /* Check if this test name matches the excluded test pattern */ + if (UnityOptionExcludeNamed) + { + if (UnityStringArgumentMatches(UnityOptionExcludeNamed)) + { + retval = 0; + } + } + + return retval; } + +#endif /* UNITY_USE_COMMAND_LINE_ARGS */ +/*-----------------------------------------------*/ diff --git a/vendor/ceedling/vendor/unity/src/unity.h b/vendor/ceedling/vendor/unity/src/unity.h index 0b6887c..338df0b 100644 --- a/vendor/ceedling/vendor/unity/src/unity.h +++ b/vendor/ceedling/vendor/unity/src/unity.h @@ -1,232 +1,661 @@ /* ========================================== Unity Project - A Test Framework for C - Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams + Copyright (c) 2007-21 Mike Karlesky, Mark VanderVoord, Greg Williams [Released under MIT License. Please refer to license.txt for details] ========================================== */ #ifndef UNITY_FRAMEWORK_H #define UNITY_FRAMEWORK_H - #define UNITY -#include "unity_internals.h" - -//------------------------------------------------------- -// Configuration Options -//------------------------------------------------------- - -// Integers -// - Unity assumes 32 bit integers by default -// - If your compiler treats ints of a different size, define UNITY_INT_WIDTH - -// Floats -// - define UNITY_EXCLUDE_FLOAT to disallow floating point comparisons -// - define UNITY_FLOAT_PRECISION to specify the precision to use when doing TEST_ASSERT_EQUAL_FLOAT -// - define UNITY_FLOAT_TYPE to specify doubles instead of single precision floats -// - define UNITY_FLOAT_VERBOSE to print floating point values in errors (uses sprintf) -// - define UNITY_INCLUDE_DOUBLE to allow double floating point comparisons -// - define UNITY_EXCLUDE_DOUBLE to disallow double floating point comparisons (default) -// - define UNITY_DOUBLE_PRECISION to specify the precision to use when doing TEST_ASSERT_EQUAL_DOUBLE -// - define UNITY_DOUBLE_TYPE to specify something other than double -// - define UNITY_DOUBLE_VERBOSE to print floating point values in errors (uses sprintf) - -// Output -// - by default, Unity prints to standard out with putchar. define UNITY_OUTPUT_CHAR(a) with a different function if desired - -// Optimization -// - by default, line numbers are stored in unsigned shorts. Define UNITY_LINE_TYPE with a different type if your files are huge -// - by default, test and failure counters are unsigned shorts. Define UNITY_COUNTER_TYPE with a different type if you want to save space or have more than 65535 Tests. - -// Test Cases -// - define UNITY_SUPPORT_TEST_CASES to include the TEST_CASE macro, though really it's mostly about the runner generator script +#define UNITY_VERSION_MAJOR 2 +#define UNITY_VERSION_MINOR 5 +#define UNITY_VERSION_BUILD 4 +#define UNITY_VERSION ((UNITY_VERSION_MAJOR << 16) | (UNITY_VERSION_MINOR << 8) | UNITY_VERSION_BUILD) -// Parameterized Tests -// - you'll want to create a define of TEST_CASE(...) which basically evaluates to nothing - -//------------------------------------------------------- -// Test Running Macros -//------------------------------------------------------- - -#define TEST_PROTECT() (setjmp(Unity.AbortFrame) == 0) - -#define TEST_ABORT() {longjmp(Unity.AbortFrame, 1);} - -#ifndef RUN_TEST -#define RUN_TEST(func, line_num) UnityDefaultTestRun(func, #func, line_num) +#ifdef __cplusplus +extern "C" +{ #endif -#define TEST_LINE_NUM (Unity.CurrentTestLineNumber) -#define TEST_IS_IGNORED (Unity.CurrentTestIgnored) - -//------------------------------------------------------- -// Basic Fail and Ignore -//------------------------------------------------------- +#include "unity_internals.h" -#define TEST_FAIL_MESSAGE(message) UNITY_TEST_FAIL(__LINE__, message) +/*------------------------------------------------------- + * Test Setup / Teardown + *-------------------------------------------------------*/ + +/* These functions are intended to be called before and after each test. + * If using unity directly, these will need to be provided for each test + * executable built. If you are using the test runner generator and/or + * Ceedling, these are optional. */ +void setUp(void); +void tearDown(void); + +/* These functions are intended to be called at the beginning and end of an + * entire test suite. suiteTearDown() is passed the number of tests that + * failed, and its return value becomes the exit code of main(). If using + * Unity directly, you're in charge of calling these if they are desired. + * If using Ceedling or the test runner generator, these will be called + * automatically if they exist. */ +void suiteSetUp(void); +int suiteTearDown(int num_failures); + +/*------------------------------------------------------- + * Test Reset and Verify + *-------------------------------------------------------*/ + +/* These functions are intended to be called before during tests in order + * to support complex test loops, etc. Both are NOT built into Unity. Instead + * the test runner generator will create them. resetTest will run teardown and + * setup again, verifying any end-of-test needs between. verifyTest will only + * run the verification. */ +void resetTest(void); +void verifyTest(void); + +/*------------------------------------------------------- + * Configuration Options + *------------------------------------------------------- + * All options described below should be passed as a compiler flag to all files using Unity. If you must add #defines, place them BEFORE the #include above. + + * Integers/longs/pointers + * - Unity attempts to automatically discover your integer sizes + * - define UNITY_EXCLUDE_STDINT_H to stop attempting to look in <stdint.h> + * - define UNITY_EXCLUDE_LIMITS_H to stop attempting to look in <limits.h> + * - If you cannot use the automatic methods above, you can force Unity by using these options: + * - define UNITY_SUPPORT_64 + * - set UNITY_INT_WIDTH + * - set UNITY_LONG_WIDTH + * - set UNITY_POINTER_WIDTH + + * Floats + * - define UNITY_EXCLUDE_FLOAT to disallow floating point comparisons + * - define UNITY_FLOAT_PRECISION to specify the precision to use when doing TEST_ASSERT_EQUAL_FLOAT + * - define UNITY_FLOAT_TYPE to specify doubles instead of single precision floats + * - define UNITY_INCLUDE_DOUBLE to allow double floating point comparisons + * - define UNITY_EXCLUDE_DOUBLE to disallow double floating point comparisons (default) + * - define UNITY_DOUBLE_PRECISION to specify the precision to use when doing TEST_ASSERT_EQUAL_DOUBLE + * - define UNITY_DOUBLE_TYPE to specify something other than double + * - define UNITY_EXCLUDE_FLOAT_PRINT to trim binary size, won't print floating point values in errors + + * Output + * - by default, Unity prints to standard out with putchar. define UNITY_OUTPUT_CHAR(a) with a different function if desired + * - define UNITY_DIFFERENTIATE_FINAL_FAIL to print FAILED (vs. FAIL) at test end summary - for automated search for failure + + * Optimization + * - by default, line numbers are stored in unsigned shorts. Define UNITY_LINE_TYPE with a different type if your files are huge + * - by default, test and failure counters are unsigned shorts. Define UNITY_COUNTER_TYPE with a different type if you want to save space or have more than 65535 Tests. + + * Test Cases + * - define UNITY_SUPPORT_TEST_CASES to include the TEST_CASE macro, though really it's mostly about the runner generator script + + * Parameterized Tests + * - you'll want to create a define of TEST_CASE(...) which basically evaluates to nothing + + * Tests with Arguments + * - you'll want to define UNITY_USE_COMMAND_LINE_ARGS if you have the test runner passing arguments to Unity + + *------------------------------------------------------- + * Basic Fail and Ignore + *-------------------------------------------------------*/ + +#define TEST_FAIL_MESSAGE(message) UNITY_TEST_FAIL(__LINE__, (message)) #define TEST_FAIL() UNITY_TEST_FAIL(__LINE__, NULL) -#define TEST_IGNORE_MESSAGE(message) UNITY_TEST_IGNORE(__LINE__, message) +#define TEST_IGNORE_MESSAGE(message) UNITY_TEST_IGNORE(__LINE__, (message)) #define TEST_IGNORE() UNITY_TEST_IGNORE(__LINE__, NULL) +#define TEST_MESSAGE(message) UnityMessage((message), __LINE__) #define TEST_ONLY() +#ifdef UNITY_INCLUDE_PRINT_FORMATTED +#define TEST_PRINTF(message, ...) UnityPrintF(__LINE__, (message), __VA_ARGS__) +#endif + +/* It is not necessary for you to call PASS. A PASS condition is assumed if nothing fails. + * This method allows you to abort a test immediately with a PASS state, ignoring the remainder of the test. */ +#define TEST_PASS() TEST_ABORT() +#define TEST_PASS_MESSAGE(message) do { UnityMessage((message), __LINE__); TEST_ABORT(); } while(0) -//------------------------------------------------------- -// Test Asserts (simple) -//------------------------------------------------------- +/* 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) -//Boolean +/*------------------------------------------------------- + * Test Asserts (simple) + *-------------------------------------------------------*/ + +/* Boolean */ #define TEST_ASSERT(condition) UNITY_TEST_ASSERT( (condition), __LINE__, " Expression Evaluated To FALSE") #define TEST_ASSERT_TRUE(condition) UNITY_TEST_ASSERT( (condition), __LINE__, " Expected TRUE Was FALSE") #define TEST_ASSERT_UNLESS(condition) UNITY_TEST_ASSERT( !(condition), __LINE__, " Expression Evaluated To TRUE") #define TEST_ASSERT_FALSE(condition) UNITY_TEST_ASSERT( !(condition), __LINE__, " Expected FALSE Was TRUE") #define TEST_ASSERT_NULL(pointer) UNITY_TEST_ASSERT_NULL( (pointer), __LINE__, " Expected NULL") #define TEST_ASSERT_NOT_NULL(pointer) UNITY_TEST_ASSERT_NOT_NULL((pointer), __LINE__, " Expected Non-NULL") +#define TEST_ASSERT_EMPTY(pointer) UNITY_TEST_ASSERT_EMPTY( (pointer), __LINE__, " Expected Empty") +#define TEST_ASSERT_NOT_EMPTY(pointer) UNITY_TEST_ASSERT_NOT_EMPTY((pointer), __LINE__, " Expected Non-Empty") -//Integers (of all sizes) +/* Integers (of all sizes) */ #define TEST_ASSERT_EQUAL_INT(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, NULL) #define TEST_ASSERT_EQUAL_INT8(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT8((expected), (actual), __LINE__, NULL) #define TEST_ASSERT_EQUAL_INT16(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT16((expected), (actual), __LINE__, NULL) #define TEST_ASSERT_EQUAL_INT32(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT32((expected), (actual), __LINE__, NULL) #define TEST_ASSERT_EQUAL_INT64(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT64((expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_EQUAL(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_NOT_EQUAL(expected, actual) UNITY_TEST_ASSERT(((expected) != (actual)), __LINE__, " Expected Not-Equal") #define TEST_ASSERT_EQUAL_UINT(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT( (expected), (actual), __LINE__, NULL) #define TEST_ASSERT_EQUAL_UINT8(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT8( (expected), (actual), __LINE__, NULL) #define TEST_ASSERT_EQUAL_UINT16(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT16( (expected), (actual), __LINE__, NULL) #define TEST_ASSERT_EQUAL_UINT32(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT32( (expected), (actual), __LINE__, NULL) #define TEST_ASSERT_EQUAL_UINT64(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT64( (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_size_t(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT((expected), (actual), __LINE__, NULL) #define TEST_ASSERT_EQUAL_HEX(expected, actual) UNITY_TEST_ASSERT_EQUAL_HEX32((expected), (actual), __LINE__, NULL) #define TEST_ASSERT_EQUAL_HEX8(expected, actual) UNITY_TEST_ASSERT_EQUAL_HEX8( (expected), (actual), __LINE__, NULL) #define TEST_ASSERT_EQUAL_HEX16(expected, actual) UNITY_TEST_ASSERT_EQUAL_HEX16((expected), (actual), __LINE__, NULL) #define TEST_ASSERT_EQUAL_HEX32(expected, actual) UNITY_TEST_ASSERT_EQUAL_HEX32((expected), (actual), __LINE__, NULL) #define TEST_ASSERT_EQUAL_HEX64(expected, actual) UNITY_TEST_ASSERT_EQUAL_HEX64((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_CHAR(expected, actual) UNITY_TEST_ASSERT_EQUAL_CHAR((expected), (actual), __LINE__, NULL) #define TEST_ASSERT_BITS(mask, expected, actual) UNITY_TEST_ASSERT_BITS((mask), (expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_BITS_HIGH(mask, actual) UNITY_TEST_ASSERT_BITS((mask), (_UU32)(-1), (actual), __LINE__, NULL) -#define TEST_ASSERT_BITS_LOW(mask, actual) UNITY_TEST_ASSERT_BITS((mask), (_UU32)(0), (actual), __LINE__, NULL) -#define TEST_ASSERT_BIT_HIGH(bit, actual) UNITY_TEST_ASSERT_BITS(((_UU32)1 << bit), (_UU32)(-1), (actual), __LINE__, NULL) -#define TEST_ASSERT_BIT_LOW(bit, actual) UNITY_TEST_ASSERT_BITS(((_UU32)1 << bit), (_UU32)(0), (actual), __LINE__, NULL) - -//Integer Ranges (of all sizes) -#define TEST_ASSERT_INT_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_INT_WITHIN(delta, expected, actual, __LINE__, NULL) -#define TEST_ASSERT_UINT_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT_WITHIN(delta, expected, actual, __LINE__, NULL) -#define TEST_ASSERT_HEX_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX32_WITHIN(delta, expected, actual, __LINE__, NULL) -#define TEST_ASSERT_HEX8_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX8_WITHIN(delta, expected, actual, __LINE__, NULL) -#define TEST_ASSERT_HEX16_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX16_WITHIN(delta, expected, actual, __LINE__, NULL) -#define TEST_ASSERT_HEX32_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX32_WITHIN(delta, expected, actual, __LINE__, NULL) -#define TEST_ASSERT_HEX64_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX64_WITHIN(delta, expected, actual, __LINE__, NULL) - -//Structs and Strings +#define TEST_ASSERT_BITS_HIGH(mask, actual) UNITY_TEST_ASSERT_BITS((mask), (UNITY_UINT)(-1), (actual), __LINE__, NULL) +#define TEST_ASSERT_BITS_LOW(mask, actual) UNITY_TEST_ASSERT_BITS((mask), (UNITY_UINT)(0), (actual), __LINE__, NULL) +#define TEST_ASSERT_BIT_HIGH(bit, actual) UNITY_TEST_ASSERT_BITS(((UNITY_UINT)1 << (bit)), (UNITY_UINT)(-1), (actual), __LINE__, NULL) +#define TEST_ASSERT_BIT_LOW(bit, actual) UNITY_TEST_ASSERT_BITS(((UNITY_UINT)1 << (bit)), (UNITY_UINT)(0), (actual), __LINE__, NULL) + +/* Integer Not Equal To (of all sizes) */ +#define TEST_ASSERT_NOT_EQUAL_INT(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_INT8(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_INT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_INT16(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_INT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_INT32(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_INT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_INT64(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_INT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_UINT(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_UINT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_UINT8(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_UINT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_UINT16(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_UINT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_UINT32(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_UINT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_UINT64(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_UINT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_size_t(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_UINT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_HEX8(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_HEX8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_HEX16(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_HEX16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_HEX32(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_HEX32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_HEX64(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_HEX64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_CHAR(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_CHAR((threshold), (actual), __LINE__, NULL) + +/* Integer Greater Than/ Less Than (of all sizes) */ +#define TEST_ASSERT_GREATER_THAN(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_INT(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_INT8(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_INT16(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_INT32(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_INT64(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_UINT(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_UINT8(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_UINT16(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_UINT32(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_UINT64(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_size_t(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_HEX8(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_HEX8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_HEX16(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_HEX16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_HEX32(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_HEX32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_HEX64(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_HEX64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_CHAR(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_CHAR((threshold), (actual), __LINE__, NULL) + +#define TEST_ASSERT_LESS_THAN(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_INT(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_INT8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_INT16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_INT32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_INT64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_UINT(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_UINT8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_UINT16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_UINT32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_UINT64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_size_t(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_HEX8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_HEX8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_HEX16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_HEX16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_HEX32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_HEX32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_HEX64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_HEX64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_CHAR(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_CHAR((threshold), (actual), __LINE__, NULL) + +#define TEST_ASSERT_GREATER_OR_EQUAL(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT8(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT16(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT32(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT64(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT8(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT16(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT32(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT64(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_size_t(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX8(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX16(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX32(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX64(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_CHAR(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_CHAR((threshold), (actual), __LINE__, NULL) + +#define TEST_ASSERT_LESS_OR_EQUAL(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_INT(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_INT8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_INT16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_INT32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_INT64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_size_t(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_CHAR(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_CHAR((threshold), (actual), __LINE__, NULL) + +/* Integer Ranges (of all sizes) */ +#define TEST_ASSERT_INT_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_INT_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_INT8_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_INT8_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_INT16_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_INT16_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_INT32_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_INT32_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_INT64_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_INT64_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_UINT_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_UINT8_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT8_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_UINT16_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT16_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_UINT32_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT32_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_UINT64_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT64_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_size_t_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_HEX_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX32_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_HEX8_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX8_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_HEX16_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX16_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_HEX32_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX32_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_HEX64_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX64_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_CHAR_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_CHAR_WITHIN((delta), (expected), (actual), __LINE__, NULL) + +/* Integer Array Ranges (of all sizes) */ +#define TEST_ASSERT_INT_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_INT_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_INT8_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_INT8_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_INT16_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_INT16_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_INT32_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_INT32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_INT64_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_INT64_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_UINT_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_UINT_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_UINT8_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_UINT8_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_UINT16_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_UINT16_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_UINT32_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_UINT32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_UINT64_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_UINT64_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_size_t_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_UINT_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_HEX_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_HEX32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_HEX8_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_HEX8_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_HEX16_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_HEX16_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_HEX32_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_HEX32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_HEX64_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_HEX64_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_CHAR_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_CHAR_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) + + +/* Structs and Strings */ #define TEST_ASSERT_EQUAL_PTR(expected, actual) UNITY_TEST_ASSERT_EQUAL_PTR((expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_STRING(expected, actual) UNITY_TEST_ASSERT_EQUAL_STRING(expected, actual, __LINE__, NULL) -#define TEST_ASSERT_EQUAL_MEMORY(expected, actual, len) UNITY_TEST_ASSERT_EQUAL_MEMORY(expected, actual, len, __LINE__, NULL) - -//Arrays -#define TEST_ASSERT_EQUAL_INT_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_INT_ARRAY(expected, actual, num_elements, __LINE__, NULL) -#define TEST_ASSERT_EQUAL_INT8_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_INT8_ARRAY(expected, actual, num_elements, __LINE__, NULL) -#define TEST_ASSERT_EQUAL_INT16_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_INT16_ARRAY(expected, actual, num_elements, __LINE__, NULL) -#define TEST_ASSERT_EQUAL_INT32_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_INT32_ARRAY(expected, actual, num_elements, __LINE__, NULL) -#define TEST_ASSERT_EQUAL_INT64_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_INT64_ARRAY(expected, actual, num_elements, __LINE__, NULL) -#define TEST_ASSERT_EQUAL_UINT_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT_ARRAY(expected, actual, num_elements, __LINE__, NULL) -#define TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, actual, num_elements, __LINE__, NULL) -#define TEST_ASSERT_EQUAL_UINT16_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT16_ARRAY(expected, actual, num_elements, __LINE__, NULL) -#define TEST_ASSERT_EQUAL_UINT32_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT32_ARRAY(expected, actual, num_elements, __LINE__, NULL) -#define TEST_ASSERT_EQUAL_UINT64_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT64_ARRAY(expected, actual, num_elements, __LINE__, NULL) -#define TEST_ASSERT_EQUAL_HEX_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY(expected, actual, num_elements, __LINE__, NULL) -#define TEST_ASSERT_EQUAL_HEX8_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX8_ARRAY(expected, actual, num_elements, __LINE__, NULL) -#define TEST_ASSERT_EQUAL_HEX16_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX16_ARRAY(expected, actual, num_elements, __LINE__, NULL) -#define TEST_ASSERT_EQUAL_HEX32_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY(expected, actual, num_elements, __LINE__, NULL) -#define TEST_ASSERT_EQUAL_HEX64_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX64_ARRAY(expected, actual, num_elements, __LINE__, NULL) -#define TEST_ASSERT_EQUAL_PTR_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_PTR_ARRAY(expected, actual, num_elements, __LINE__, NULL) -#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) - -//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) - -//Double (If Enabled) -#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) - - -//------------------------------------------------------- -// Test Asserts (with additional messages) -//------------------------------------------------------- - -//Boolean -#define TEST_ASSERT_MESSAGE(condition, message) UNITY_TEST_ASSERT( (condition), __LINE__, message) -#define TEST_ASSERT_TRUE_MESSAGE(condition, message) UNITY_TEST_ASSERT( (condition), __LINE__, message) -#define TEST_ASSERT_UNLESS_MESSAGE(condition, message) UNITY_TEST_ASSERT( !(condition), __LINE__, message) -#define TEST_ASSERT_FALSE_MESSAGE(condition, message) UNITY_TEST_ASSERT( !(condition), __LINE__, message) -#define TEST_ASSERT_NULL_MESSAGE(pointer, message) UNITY_TEST_ASSERT_NULL( (pointer), __LINE__, message) -#define TEST_ASSERT_NOT_NULL_MESSAGE(pointer, message) UNITY_TEST_ASSERT_NOT_NULL((pointer), __LINE__, message) - -//Integers (of all sizes) -#define TEST_ASSERT_EQUAL_INT_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, message) -#define TEST_ASSERT_EQUAL_INT8_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT8((expected), (actual), __LINE__, message) -#define TEST_ASSERT_EQUAL_INT16_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT16((expected), (actual), __LINE__, message) -#define TEST_ASSERT_EQUAL_INT32_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT32((expected), (actual), __LINE__, message) -#define TEST_ASSERT_EQUAL_INT64_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT64((expected), (actual), __LINE__, message) +#define TEST_ASSERT_EQUAL_STRING(expected, actual) UNITY_TEST_ASSERT_EQUAL_STRING((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_STRING_LEN(expected, actual, len) UNITY_TEST_ASSERT_EQUAL_STRING_LEN((expected), (actual), (len), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_MEMORY(expected, actual, len) UNITY_TEST_ASSERT_EQUAL_MEMORY((expected), (actual), (len), __LINE__, NULL) + +/* Arrays */ +#define TEST_ASSERT_EQUAL_INT_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_INT_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_INT8_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_INT8_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_INT16_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_INT16_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_INT32_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_INT32_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_INT64_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_INT64_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_UINT_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT8_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_UINT16_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT16_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_UINT32_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT32_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_UINT64_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT64_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_size_t_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_HEX_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_HEX8_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX8_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_HEX16_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX16_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_HEX32_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_HEX64_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX64_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_PTR_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_PTR_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#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) +#define TEST_ASSERT_EQUAL_CHAR_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_CHAR_ARRAY((expected), (actual), (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_size_t(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_UINT((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) +#define TEST_ASSERT_EACH_EQUAL_CHAR(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_CHAR((expected), (actual), (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) +#define TEST_ASSERT_FLOAT_IS_DETERMINATE(actual) UNITY_TEST_ASSERT_FLOAT_IS_DETERMINATE((actual), __LINE__, NULL) +#define TEST_ASSERT_FLOAT_IS_NOT_INF(actual) UNITY_TEST_ASSERT_FLOAT_IS_NOT_INF((actual), __LINE__, NULL) +#define TEST_ASSERT_FLOAT_IS_NOT_NEG_INF(actual) UNITY_TEST_ASSERT_FLOAT_IS_NOT_NEG_INF((actual), __LINE__, NULL) +#define TEST_ASSERT_FLOAT_IS_NOT_NAN(actual) UNITY_TEST_ASSERT_FLOAT_IS_NOT_NAN((actual), __LINE__, NULL) +#define TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE(actual) UNITY_TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE((actual), __LINE__, NULL) + +/* Double (If Enabled) */ +#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) +#define TEST_ASSERT_DOUBLE_IS_DETERMINATE(actual) UNITY_TEST_ASSERT_DOUBLE_IS_DETERMINATE((actual), __LINE__, NULL) +#define TEST_ASSERT_DOUBLE_IS_NOT_INF(actual) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_INF((actual), __LINE__, NULL) +#define TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF(actual) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF((actual), __LINE__, NULL) +#define TEST_ASSERT_DOUBLE_IS_NOT_NAN(actual) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NAN((actual), __LINE__, NULL) +#define TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE(actual) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE((actual), __LINE__, NULL) + +/* Shorthand */ +#ifdef UNITY_SHORTHAND_AS_OLD +#define TEST_ASSERT_EQUAL(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL(expected, actual) UNITY_TEST_ASSERT(((expected) != (actual)), __LINE__, " Expected Not-Equal") +#endif +#ifdef UNITY_SHORTHAND_AS_INT +#define TEST_ASSERT_EQUAL(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL(expected, actual) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand) +#endif +#ifdef UNITY_SHORTHAND_AS_MEM +#define TEST_ASSERT_EQUAL(expected, actual) UNITY_TEST_ASSERT_EQUAL_MEMORY((&expected), (&actual), sizeof(expected), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL(expected, actual) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand) +#endif +#ifdef UNITY_SHORTHAND_AS_RAW +#define TEST_ASSERT_EQUAL(expected, actual) UNITY_TEST_ASSERT(((expected) == (actual)), __LINE__, " Expected Equal") +#define TEST_ASSERT_NOT_EQUAL(expected, actual) UNITY_TEST_ASSERT(((expected) != (actual)), __LINE__, " Expected Not-Equal") +#endif +#ifdef UNITY_SHORTHAND_AS_NONE +#define TEST_ASSERT_EQUAL(expected, actual) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand) +#define TEST_ASSERT_NOT_EQUAL(expected, actual) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand) +#endif + +/*------------------------------------------------------- + * Test Asserts (with additional messages) + *-------------------------------------------------------*/ + +/* Boolean */ +#define TEST_ASSERT_MESSAGE(condition, message) UNITY_TEST_ASSERT( (condition), __LINE__, (message)) +#define TEST_ASSERT_TRUE_MESSAGE(condition, message) UNITY_TEST_ASSERT( (condition), __LINE__, (message)) +#define TEST_ASSERT_UNLESS_MESSAGE(condition, message) UNITY_TEST_ASSERT( !(condition), __LINE__, (message)) +#define TEST_ASSERT_FALSE_MESSAGE(condition, message) UNITY_TEST_ASSERT( !(condition), __LINE__, (message)) +#define TEST_ASSERT_NULL_MESSAGE(pointer, message) UNITY_TEST_ASSERT_NULL( (pointer), __LINE__, (message)) +#define TEST_ASSERT_NOT_NULL_MESSAGE(pointer, message) UNITY_TEST_ASSERT_NOT_NULL((pointer), __LINE__, (message)) +#define TEST_ASSERT_EMPTY_MESSAGE(pointer, message) UNITY_TEST_ASSERT_EMPTY( (pointer), __LINE__, (message)) +#define TEST_ASSERT_NOT_EMPTY_MESSAGE(pointer, message) UNITY_TEST_ASSERT_NOT_EMPTY((pointer), __LINE__, (message)) + +/* Integers (of all sizes) */ +#define TEST_ASSERT_EQUAL_INT_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_INT8_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT8((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_INT16_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT16((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_INT32_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT32((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_INT64_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT64((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_UINT_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT( (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT8( (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_UINT16_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT16( (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_UINT32_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT32( (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_UINT64_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT64( (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_size_t_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT( (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_HEX_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX32((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_HEX8_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX8( (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_HEX16_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX16((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_HEX32_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX32((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_HEX64_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX64((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_BITS_MESSAGE(mask, expected, actual, message) UNITY_TEST_ASSERT_BITS((mask), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_BITS_HIGH_MESSAGE(mask, actual, message) UNITY_TEST_ASSERT_BITS((mask), (UNITY_UINT32)(-1), (actual), __LINE__, (message)) +#define TEST_ASSERT_BITS_LOW_MESSAGE(mask, actual, message) UNITY_TEST_ASSERT_BITS((mask), (UNITY_UINT32)(0), (actual), __LINE__, (message)) +#define TEST_ASSERT_BIT_HIGH_MESSAGE(bit, actual, message) UNITY_TEST_ASSERT_BITS(((UNITY_UINT32)1 << (bit)), (UNITY_UINT32)(-1), (actual), __LINE__, (message)) +#define TEST_ASSERT_BIT_LOW_MESSAGE(bit, actual, message) UNITY_TEST_ASSERT_BITS(((UNITY_UINT32)1 << (bit)), (UNITY_UINT32)(0), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_CHAR_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_CHAR((expected), (actual), __LINE__, (message)) + +/* Integer Not Equal To (of all sizes) */ +#define TEST_ASSERT_NOT_EQUAL_INT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_INT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_INT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_INT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_INT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_INT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_INT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_INT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_INT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_UINT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_UINT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_UINT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_UINT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_UINT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_UINT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_UINT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_UINT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_UINT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_UINT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_size_t_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_UINT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_HEX8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_HEX8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_HEX16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_HEX16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_HEX32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_HEX32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_HEX64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_HEX64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_CHAR_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_CHAR((threshold), (actual), __LINE__, (message)) + + +/* Integer Greater Than/ Less Than (of all sizes) */ +#define TEST_ASSERT_GREATER_THAN_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_INT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_INT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_INT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_INT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_INT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_UINT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_UINT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_UINT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_UINT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_UINT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_size_t_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_HEX8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_HEX8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_HEX16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_HEX16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_HEX32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_HEX32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_HEX64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_HEX64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_CHAR_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_CHAR((threshold), (actual), __LINE__, (message)) + +#define TEST_ASSERT_LESS_THAN_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_INT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_INT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_INT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_INT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_INT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_UINT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_UINT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_UINT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_UINT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_UINT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_size_t_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_HEX8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_HEX8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_HEX16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_HEX16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_HEX32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_HEX32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_HEX64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_HEX64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_CHAR_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_CHAR((threshold), (actual), __LINE__, (message)) + +#define TEST_ASSERT_GREATER_OR_EQUAL_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_size_t_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_CHAR_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_CHAR((threshold), (actual), __LINE__, (message)) + +#define TEST_ASSERT_LESS_OR_EQUAL_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_INT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_INT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_INT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_INT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_INT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_size_t_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_CHAR_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_CHAR((threshold), (actual), __LINE__, (message)) + +/* Integer Ranges (of all sizes) */ +#define TEST_ASSERT_INT_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_INT_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_INT8_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_INT8_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_INT16_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_INT16_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_INT32_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_INT32_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_INT64_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_INT64_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_UINT_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_UINT8_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT8_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_UINT16_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT16_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_UINT32_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT32_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_UINT64_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT64_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_size_t_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_HEX_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX32_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_HEX8_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX8_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_HEX16_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX16_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_HEX32_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX32_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_HEX64_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX64_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_CHAR_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_CHAR_WITHIN((delta), (expected), (actual), __LINE__, (message)) + +/* Integer Array Ranges (of all sizes) */ +#define TEST_ASSERT_INT_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_INT_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_INT8_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_INT8_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_INT16_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_INT16_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_INT32_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_INT32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_INT64_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_INT64_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_UINT_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_UINT_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_UINT8_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_UINT8_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_UINT16_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_UINT16_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_UINT32_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_UINT32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_UINT64_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_UINT64_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_size_t_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_UINT_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_HEX_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_HEX32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_HEX8_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_HEX8_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_HEX16_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_HEX16_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_HEX32_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_HEX32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_HEX64_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_HEX64_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_CHAR_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_CHAR_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) + + +/* Structs and Strings */ +#define TEST_ASSERT_EQUAL_PTR_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_PTR((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_STRING((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_STRING_LEN_MESSAGE(expected, actual, len, message) UNITY_TEST_ASSERT_EQUAL_STRING_LEN((expected), (actual), (len), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_MEMORY_MESSAGE(expected, actual, len, message) UNITY_TEST_ASSERT_EQUAL_MEMORY((expected), (actual), (len), __LINE__, (message)) + +/* Arrays */ +#define TEST_ASSERT_EQUAL_INT_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_INT_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_INT8_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_INT8_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_INT16_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_INT16_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_INT32_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_INT32_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_INT64_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_INT64_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_UINT_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_UINT8_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT8_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_UINT16_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT16_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_UINT32_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT32_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_UINT64_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT64_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_size_t_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_HEX_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_HEX8_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX8_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_HEX16_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX16_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_HEX32_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_HEX64_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX64_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_PTR_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_PTR_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#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)) +#define TEST_ASSERT_EQUAL_CHAR_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_CHAR_ARRAY((expected), (actual), (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_size_t_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_UINT((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_HEX_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_HEX32((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_HEX8_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_HEX8((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_HEX16_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_HEX16((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_HEX32_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_HEX32((expected), (actual), (num_elements), __LINE__, (message)) +#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)) +#define TEST_ASSERT_EACH_EQUAL_CHAR_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_CHAR((expected), (actual), (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)) +#define TEST_ASSERT_FLOAT_IS_DETERMINATE_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_DETERMINATE((actual), __LINE__, (message)) +#define TEST_ASSERT_FLOAT_IS_NOT_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_NOT_INF((actual), __LINE__, (message)) +#define TEST_ASSERT_FLOAT_IS_NOT_NEG_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_NOT_NEG_INF((actual), __LINE__, (message)) +#define TEST_ASSERT_FLOAT_IS_NOT_NAN_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_NOT_NAN((actual), __LINE__, (message)) +#define TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE((actual), __LINE__, (message)) + +/* Double (If Enabled) */ +#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)) +#define TEST_ASSERT_DOUBLE_IS_DETERMINATE_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_DETERMINATE((actual), __LINE__, (message)) +#define TEST_ASSERT_DOUBLE_IS_NOT_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_INF((actual), __LINE__, (message)) +#define TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF((actual), __LINE__, (message)) +#define TEST_ASSERT_DOUBLE_IS_NOT_NAN_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NAN((actual), __LINE__, (message)) +#define TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE((actual), __LINE__, (message)) + +/* Shorthand */ +#ifdef UNITY_SHORTHAND_AS_OLD +#define TEST_ASSERT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT(((expected) != (actual)), __LINE__, (message)) +#endif +#ifdef UNITY_SHORTHAND_AS_INT #define TEST_ASSERT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, message) -#define TEST_ASSERT_NOT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT(((expected) != (actual)), __LINE__, message) -#define TEST_ASSERT_EQUAL_UINT_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT( (expected), (actual), __LINE__, message) -#define TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT8( (expected), (actual), __LINE__, message) -#define TEST_ASSERT_EQUAL_UINT16_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT16( (expected), (actual), __LINE__, message) -#define TEST_ASSERT_EQUAL_UINT32_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT32( (expected), (actual), __LINE__, message) -#define TEST_ASSERT_EQUAL_UINT64_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT64( (expected), (actual), __LINE__, message) -#define TEST_ASSERT_EQUAL_HEX_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX32((expected), (actual), __LINE__, message) -#define TEST_ASSERT_EQUAL_HEX8_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX8( (expected), (actual), __LINE__, message) -#define TEST_ASSERT_EQUAL_HEX16_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX16((expected), (actual), __LINE__, message) -#define TEST_ASSERT_EQUAL_HEX32_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX32((expected), (actual), __LINE__, message) -#define TEST_ASSERT_EQUAL_HEX64_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX64((expected), (actual), __LINE__, message) -#define TEST_ASSERT_BITS_MESSAGE(mask, expected, actual, message) UNITY_TEST_ASSERT_BITS((mask), (expected), (actual), __LINE__, message) -#define TEST_ASSERT_BITS_HIGH_MESSAGE(mask, actual, message) UNITY_TEST_ASSERT_BITS((mask), (_UU32)(-1), (actual), __LINE__, message) -#define TEST_ASSERT_BITS_LOW_MESSAGE(mask, actual, message) UNITY_TEST_ASSERT_BITS((mask), (_UU32)(0), (actual), __LINE__, message) -#define TEST_ASSERT_BIT_HIGH_MESSAGE(bit, actual, message) UNITY_TEST_ASSERT_BITS(((_UU32)1 << bit), (_UU32)(-1), (actual), __LINE__, message) -#define TEST_ASSERT_BIT_LOW_MESSAGE(bit, actual, message) UNITY_TEST_ASSERT_BITS(((_UU32)1 << bit), (_UU32)(0), (actual), __LINE__, message) - -//Integer Ranges (of all sizes) -#define TEST_ASSERT_INT_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_INT_WITHIN(delta, expected, actual, __LINE__, message) -#define TEST_ASSERT_UINT_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT_WITHIN(delta, expected, actual, __LINE__, message) -#define TEST_ASSERT_HEX_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX32_WITHIN(delta, expected, actual, __LINE__, message) -#define TEST_ASSERT_HEX8_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX8_WITHIN(delta, expected, actual, __LINE__, message) -#define TEST_ASSERT_HEX16_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX16_WITHIN(delta, expected, actual, __LINE__, message) -#define TEST_ASSERT_HEX32_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX32_WITHIN(delta, expected, actual, __LINE__, message) -#define TEST_ASSERT_HEX64_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX64_WITHIN(delta, expected, actual, __LINE__, message) - -//Structs and Strings -#define TEST_ASSERT_EQUAL_PTR_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_PTR(expected, actual, __LINE__, message) -#define TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_STRING(expected, actual, __LINE__, message) -#define TEST_ASSERT_EQUAL_MEMORY_MESSAGE(expected, actual, len, message) UNITY_TEST_ASSERT_EQUAL_MEMORY(expected, actual, len, __LINE__, message) - -//Arrays -#define TEST_ASSERT_EQUAL_INT_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_INT_ARRAY(expected, actual, num_elements, __LINE__, message) -#define TEST_ASSERT_EQUAL_INT8_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_INT8_ARRAY(expected, actual, num_elements, __LINE__, message) -#define TEST_ASSERT_EQUAL_INT16_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_INT16_ARRAY(expected, actual, num_elements, __LINE__, message) -#define TEST_ASSERT_EQUAL_INT32_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_INT32_ARRAY(expected, actual, num_elements, __LINE__, message) -#define TEST_ASSERT_EQUAL_INT64_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_INT64_ARRAY(expected, actual, num_elements, __LINE__, message) -#define TEST_ASSERT_EQUAL_UINT_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT_ARRAY(expected, actual, num_elements, __LINE__, message) -#define TEST_ASSERT_EQUAL_UINT8_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, actual, num_elements, __LINE__, message) -#define TEST_ASSERT_EQUAL_UINT16_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT16_ARRAY(expected, actual, num_elements, __LINE__, message) -#define TEST_ASSERT_EQUAL_UINT32_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT32_ARRAY(expected, actual, num_elements, __LINE__, message) -#define TEST_ASSERT_EQUAL_UINT64_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT64_ARRAY(expected, actual, num_elements, __LINE__, message) -#define TEST_ASSERT_EQUAL_HEX_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY(expected, actual, num_elements, __LINE__, message) -#define TEST_ASSERT_EQUAL_HEX8_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX8_ARRAY(expected, actual, num_elements, __LINE__, message) -#define TEST_ASSERT_EQUAL_HEX16_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX16_ARRAY(expected, actual, num_elements, __LINE__, message) -#define TEST_ASSERT_EQUAL_HEX32_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY(expected, actual, num_elements, __LINE__, message) -#define TEST_ASSERT_EQUAL_HEX64_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX64_ARRAY(expected, actual, num_elements, __LINE__, message) -#define TEST_ASSERT_EQUAL_PTR_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_PTR_ARRAY(expected, actual, num_elements, __LINE__, message) -#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) - -//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) - -//Double (If Enabled) -#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_NOT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand) +#endif +#ifdef UNITY_SHORTHAND_AS_MEM +#define TEST_ASSERT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_MEMORY((&expected), (&actual), sizeof(expected), __LINE__, message) +#define TEST_ASSERT_NOT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand) +#endif +#ifdef UNITY_SHORTHAND_AS_RAW +#define TEST_ASSERT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT(((expected) == (actual)), __LINE__, message) +#define TEST_ASSERT_NOT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT(((expected) != (actual)), __LINE__, message) +#endif +#ifdef UNITY_SHORTHAND_AS_NONE +#define TEST_ASSERT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand) +#define TEST_ASSERT_NOT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand) +#endif +/* end of UNITY_FRAMEWORK_H */ +#ifdef __cplusplus +} +#endif #endif diff --git a/vendor/ceedling/vendor/unity/src/unity_internals.h b/vendor/ceedling/vendor/unity/src/unity_internals.h index 9bf19fe..2c91b6d 100644 --- a/vendor/ceedling/vendor/unity/src/unity_internals.h +++ b/vendor/ceedling/vendor/unity/src/unity_internals.h @@ -1,31 +1,75 @@ /* ========================================== Unity Project - A Test Framework for C - Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams + Copyright (c) 2007-21 Mike Karlesky, Mark VanderVoord, Greg Williams [Released under MIT License. Please refer to license.txt for details] ========================================== */ #ifndef UNITY_INTERNALS_H #define UNITY_INTERNALS_H -#include <stdio.h> +#ifdef UNITY_INCLUDE_CONFIG_H +#include "unity_config.h" +#endif + +#ifndef UNITY_EXCLUDE_SETJMP_H #include <setjmp.h> +#endif -//stdint.h is often automatically included. -//Unity uses it to guess at the sizes of integer types, etc. -#ifdef UNITY_USE_LIMITS_H -#include <limits.h> +#ifndef UNITY_EXCLUDE_MATH_H +#include <math.h> +#endif + +#ifndef UNITY_EXCLUDE_STDDEF_H +#include <stddef.h> #endif + +#ifdef UNITY_INCLUDE_PRINT_FORMATTED +#include <stdarg.h> +#endif + +/* Unity Attempts to Auto-Detect Integer Types + * Attempt 1: UINT_MAX, ULONG_MAX in <limits.h>, or default to 32 bits + * Attempt 2: UINTPTR_MAX in <stdint.h>, or default to same size as long + * The user may override any of these derived constants: + * UNITY_INT_WIDTH, UNITY_LONG_WIDTH, UNITY_POINTER_WIDTH */ #ifndef UNITY_EXCLUDE_STDINT_H #include <stdint.h> #endif -//------------------------------------------------------- -// Guess Widths If Not Specified -//------------------------------------------------------- +#ifndef UNITY_EXCLUDE_LIMITS_H +#include <limits.h> +#endif + +#if defined(__GNUC__) || defined(__clang__) + #define UNITY_FUNCTION_ATTR(a) __attribute__((a)) +#else + #define UNITY_FUNCTION_ATTR(a) /* ignore */ +#endif + +#ifndef UNITY_NORETURN + #if defined(__cplusplus) + #if __cplusplus >= 201103L + #define UNITY_NORETURN [[ noreturn ]] + #endif + #elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L + #include <stdnoreturn.h> + #define UNITY_NORETURN noreturn + #endif +#endif +#ifndef UNITY_NORETURN + #define UNITY_NORETURN UNITY_FUNCTION_ATTR(noreturn) +#endif + +/*------------------------------------------------------- + * Guess Widths If Not Specified + *-------------------------------------------------------*/ -// If the INT Width hasn't been specified, -// We first try to guess based on UINT_MAX (if it exists) -// Otherwise we fall back on assuming 32-bit +/* Determine the size of an int, if not already specified. + * We cannot use sizeof(int), because it is not yet defined + * at this stage in the translation of the C program. + * Also sizeof(int) does return the size in addressable units on all platforms, + * which may not necessarily be the size in bytes. + * Therefore, infer it from UINT_MAX if possible. */ #ifndef UNITY_INT_WIDTH #ifdef UINT_MAX #if (UINT_MAX == 0xFFFF) @@ -34,20 +78,13 @@ #define UNITY_INT_WIDTH (32) #elif (UINT_MAX == 0xFFFFFFFFFFFFFFFF) #define UNITY_INT_WIDTH (64) - #ifndef UNITY_SUPPORT_64 - #define UNITY_SUPPORT_64 - #endif - #else - #define UNITY_INT_WIDTH (32) #endif - #else + #else /* Set to default */ #define UNITY_INT_WIDTH (32) - #endif + #endif /* UINT_MAX */ #endif -// If the Long Width hasn't been specified, -// We first try to guess based on ULONG_MAX (if it exists) -// Otherwise we fall back on assuming 32-bit +/* Determine the size of a long, if not already specified. */ #ifndef UNITY_LONG_WIDTH #ifdef ULONG_MAX #if (ULONG_MAX == 0xFFFF) @@ -56,20 +93,13 @@ #define UNITY_LONG_WIDTH (32) #elif (ULONG_MAX == 0xFFFFFFFFFFFFFFFF) #define UNITY_LONG_WIDTH (64) - #else - #define UNITY_LONG_WIDTH (32) - #ifndef UNITY_SUPPORT_64 - #define UNITY_SUPPORT_64 - #endif #endif - #else + #else /* Set to default */ #define UNITY_LONG_WIDTH (32) - #endif + #endif /* ULONG_MAX */ #endif -// If the Pointer Width hasn't been specified, -// We first try to guess based on INTPTR_MAX (if it exists) -// Otherwise we fall back on assuming 32-bit +/* Determine the size of a pointer, if not already specified. */ #ifndef UNITY_POINTER_WIDTH #ifdef UINTPTR_MAX #if (UINTPTR_MAX <= 0xFFFF) @@ -78,202 +108,304 @@ #define UNITY_POINTER_WIDTH (32) #elif (UINTPTR_MAX <= 0xFFFFFFFFFFFFFFFF) #define UNITY_POINTER_WIDTH (64) - #ifndef UNITY_SUPPORT_64 - #define UNITY_SUPPORT_64 - #endif - #endif - #endif -#endif -#ifndef UNITY_POINTER_WIDTH - #ifdef INTPTR_MAX - #if (INTPTR_MAX <= 0x7FFF) - #define UNITY_POINTER_WIDTH (16) - #elif (INTPTR_MAX <= 0x7FFFFFFF) - #define UNITY_POINTER_WIDTH (32) - #elif (INTPTR_MAX <= 0x7FFFFFFFFFFFFFFF) - #define UNITY_POINTER_WIDTH (64) - #ifndef UNITY_SUPPORT_64 - #define UNITY_SUPPORT_64 - #endif #endif - #endif -#endif -#ifndef UNITY_POINTER_WIDTH - #define UNITY_POINTER_WIDTH (32) + #else /* Set to default */ + #define UNITY_POINTER_WIDTH UNITY_LONG_WIDTH + #endif /* UINTPTR_MAX */ #endif -//------------------------------------------------------- -// Int Support -//------------------------------------------------------- +/*------------------------------------------------------- + * Int Support (Define types based on detected sizes) + *-------------------------------------------------------*/ #if (UNITY_INT_WIDTH == 32) - typedef unsigned char _UU8; - typedef unsigned short _UU16; - typedef unsigned int _UU32; - typedef signed char _US8; - typedef signed short _US16; - typedef signed int _US32; + typedef unsigned char UNITY_UINT8; + typedef unsigned short UNITY_UINT16; + typedef unsigned int UNITY_UINT32; + typedef signed char UNITY_INT8; + typedef signed short UNITY_INT16; + typedef signed int UNITY_INT32; #elif (UNITY_INT_WIDTH == 16) - typedef unsigned char _UU8; - typedef unsigned int _UU16; - typedef unsigned long _UU32; - typedef signed char _US8; - typedef signed int _US16; - typedef signed long _US32; + typedef unsigned char UNITY_UINT8; + typedef unsigned int UNITY_UINT16; + typedef unsigned long UNITY_UINT32; + typedef signed char UNITY_INT8; + typedef signed int UNITY_INT16; + typedef signed long UNITY_INT32; #else #error Invalid UNITY_INT_WIDTH specified! (16 or 32 are supported) #endif -//------------------------------------------------------- -// 64-bit Support -//------------------------------------------------------- +/*------------------------------------------------------- + * 64-bit Support + *-------------------------------------------------------*/ +/* Auto-detect 64 Bit Support */ #ifndef UNITY_SUPPORT_64 + #if UNITY_LONG_WIDTH == 64 || UNITY_POINTER_WIDTH == 64 + #define UNITY_SUPPORT_64 + #endif +#endif -//No 64-bit Support -typedef _UU32 _U_UINT; -typedef _US32 _U_SINT; - -#else - -//64-bit Support -#if (UNITY_LONG_WIDTH == 32) - typedef unsigned long long _UU64; - typedef signed long long _US64; -#elif (UNITY_LONG_WIDTH == 64) - typedef unsigned long _UU64; - typedef signed long _US64; +/* 64-Bit Support Dependent Configuration */ +#ifndef UNITY_SUPPORT_64 + /* No 64-bit Support */ + typedef UNITY_UINT32 UNITY_UINT; + typedef UNITY_INT32 UNITY_INT; + #define UNITY_MAX_NIBBLES (8) /* Maximum number of nibbles in a UNITY_(U)INT */ #else + /* 64-bit Support */ + #if (UNITY_LONG_WIDTH == 32) + typedef unsigned long long UNITY_UINT64; + typedef signed long long UNITY_INT64; + #elif (UNITY_LONG_WIDTH == 64) + typedef unsigned long UNITY_UINT64; + typedef signed long UNITY_INT64; + #else #error Invalid UNITY_LONG_WIDTH specified! (32 or 64 are supported) + #endif + typedef UNITY_UINT64 UNITY_UINT; + typedef UNITY_INT64 UNITY_INT; + #define UNITY_MAX_NIBBLES (16) /* Maximum number of nibbles in a UNITY_(U)INT */ #endif -typedef _UU64 _U_UINT; -typedef _US64 _U_SINT; - -#endif - -//------------------------------------------------------- -// Pointer Support -//------------------------------------------------------- -#ifndef UNITY_POINTER_WIDTH -#define UNITY_POINTER_WIDTH (32) -#endif /* UNITY_POINTER_WIDTH */ +/*------------------------------------------------------- + * Pointer Support + *-------------------------------------------------------*/ #if (UNITY_POINTER_WIDTH == 32) - typedef _UU32 _UP; -#define UNITY_DISPLAY_STYLE_POINTER UNITY_DISPLAY_STYLE_HEX32 + #define UNITY_PTR_TO_INT UNITY_INT32 + #define UNITY_DISPLAY_STYLE_POINTER UNITY_DISPLAY_STYLE_HEX32 #elif (UNITY_POINTER_WIDTH == 64) -#ifndef UNITY_SUPPORT_64 -#error "You've Specified 64-bit pointers without enabling 64-bit Support. Define UNITY_SUPPORT_64" -#endif - typedef _UU64 _UP; -#define UNITY_DISPLAY_STYLE_POINTER UNITY_DISPLAY_STYLE_HEX64 + #define UNITY_PTR_TO_INT UNITY_INT64 + #define UNITY_DISPLAY_STYLE_POINTER UNITY_DISPLAY_STYLE_HEX64 #elif (UNITY_POINTER_WIDTH == 16) - typedef _UU16 _UP; -#define UNITY_DISPLAY_STYLE_POINTER UNITY_DISPLAY_STYLE_HEX16 + #define UNITY_PTR_TO_INT UNITY_INT16 + #define UNITY_DISPLAY_STYLE_POINTER UNITY_DISPLAY_STYLE_HEX16 #else - #error Invalid UNITY_POINTER_WIDTH specified! (16, 32 or 64 are supported) + #error Invalid UNITY_POINTER_WIDTH specified! (16, 32 or 64 are supported) +#endif + +#ifndef UNITY_PTR_ATTRIBUTE + #define UNITY_PTR_ATTRIBUTE +#endif + +#ifndef UNITY_INTERNAL_PTR + #define UNITY_INTERNAL_PTR UNITY_PTR_ATTRIBUTE const void* #endif -//------------------------------------------------------- -// Float Support -//------------------------------------------------------- +/*------------------------------------------------------- + * Float Support + *-------------------------------------------------------*/ -#ifdef UNITY_EXCLUDE_FLOAT +#ifdef UNITY_EXCLUDE_FLOAT -//No Floating Point Support -#undef UNITY_FLOAT_PRECISION -#undef UNITY_FLOAT_TYPE -#undef UNITY_FLOAT_VERBOSE +/* No Floating Point Support */ +#ifndef UNITY_EXCLUDE_DOUBLE +#define UNITY_EXCLUDE_DOUBLE /* Remove double when excluding float support */ +#endif +#ifndef UNITY_EXCLUDE_FLOAT_PRINT +#define UNITY_EXCLUDE_FLOAT_PRINT +#endif #else -//Floating Point Support +/* Floating Point Support */ #ifndef UNITY_FLOAT_PRECISION #define UNITY_FLOAT_PRECISION (0.00001f) #endif #ifndef UNITY_FLOAT_TYPE #define UNITY_FLOAT_TYPE float #endif -typedef UNITY_FLOAT_TYPE _UF; - +typedef UNITY_FLOAT_TYPE UNITY_FLOAT; + +/* isinf & isnan macros should be provided by math.h */ +#ifndef isinf +/* The value of Inf - Inf is NaN */ +#define isinf(n) (isnan((n) - (n)) && !isnan(n)) #endif -//------------------------------------------------------- -// Double Float Support -//------------------------------------------------------- +#ifndef isnan +/* NaN is the only floating point value that does NOT equal itself. + * Therefore if n != n, then it is NaN. */ +#define isnan(n) ((n != n) ? 1 : 0) +#endif -//unlike FLOAT, we DON'T include by default -#ifndef UNITY_EXCLUDE_DOUBLE -#ifndef UNITY_INCLUDE_DOUBLE -#define UNITY_EXCLUDE_DOUBLE #endif + +/*------------------------------------------------------- + * Double Float Support + *-------------------------------------------------------*/ + +/* unlike float, we DON'T include by default */ +#if defined(UNITY_EXCLUDE_DOUBLE) || !defined(UNITY_INCLUDE_DOUBLE) + + /* No Floating Point Support */ + #ifndef UNITY_EXCLUDE_DOUBLE + #define UNITY_EXCLUDE_DOUBLE + #else + #undef UNITY_INCLUDE_DOUBLE + #endif + + #ifndef UNITY_EXCLUDE_FLOAT + #ifndef UNITY_DOUBLE_TYPE + #define UNITY_DOUBLE_TYPE double + #endif + typedef UNITY_FLOAT UNITY_DOUBLE; + /* For parameter in UnityPrintFloat(UNITY_DOUBLE), which aliases to double or float */ + #endif + +#else + + /* Double Floating Point Support */ + #ifndef UNITY_DOUBLE_PRECISION + #define UNITY_DOUBLE_PRECISION (1e-12) + #endif + + #ifndef UNITY_DOUBLE_TYPE + #define UNITY_DOUBLE_TYPE double + #endif + typedef UNITY_DOUBLE_TYPE UNITY_DOUBLE; + #endif -#ifdef UNITY_EXCLUDE_DOUBLE +/*------------------------------------------------------- + * Output Method: stdout (DEFAULT) + *-------------------------------------------------------*/ +#ifndef UNITY_OUTPUT_CHAR + /* Default to using putchar, which is defined in stdio.h */ + #include <stdio.h> + #define UNITY_OUTPUT_CHAR(a) (void)putchar(a) +#else + /* If defined as something else, make sure we declare it here so it's ready for use */ + #ifdef UNITY_OUTPUT_CHAR_HEADER_DECLARATION + extern void UNITY_OUTPUT_CHAR_HEADER_DECLARATION; + #endif +#endif -//No Floating Point Support -#undef UNITY_DOUBLE_PRECISION -#undef UNITY_DOUBLE_TYPE -#undef UNITY_DOUBLE_VERBOSE +#ifndef UNITY_OUTPUT_FLUSH + #ifdef UNITY_USE_FLUSH_STDOUT + /* We want to use the stdout flush utility */ + #include <stdio.h> + #define UNITY_OUTPUT_FLUSH() (void)fflush(stdout) + #else + /* We've specified nothing, therefore flush should just be ignored */ + #define UNITY_OUTPUT_FLUSH() + #endif +#else + /* If defined as something else, make sure we declare it here so it's ready for use */ + #ifdef UNITY_OUTPUT_FLUSH_HEADER_DECLARATION + extern void UNITY_OUTPUT_FLUSH_HEADER_DECLARATION; + #endif +#endif +#ifndef UNITY_OUTPUT_FLUSH +#define UNITY_FLUSH_CALL() #else +#define UNITY_FLUSH_CALL() UNITY_OUTPUT_FLUSH() +#endif + +#ifndef UNITY_PRINT_EOL +#define UNITY_PRINT_EOL() UNITY_OUTPUT_CHAR('\n') +#endif -//Floating Point Support -#ifndef UNITY_DOUBLE_PRECISION -#define UNITY_DOUBLE_PRECISION (1e-12f) +#ifndef UNITY_OUTPUT_START +#define UNITY_OUTPUT_START() #endif -#ifndef UNITY_DOUBLE_TYPE -#define UNITY_DOUBLE_TYPE double + +#ifndef UNITY_OUTPUT_COMPLETE +#define UNITY_OUTPUT_COMPLETE() #endif -typedef UNITY_DOUBLE_TYPE _UD; - + +#ifdef UNITY_INCLUDE_EXEC_TIME + #if !defined(UNITY_EXEC_TIME_START) && \ + !defined(UNITY_EXEC_TIME_STOP) && \ + !defined(UNITY_PRINT_EXEC_TIME) && \ + !defined(UNITY_TIME_TYPE) + /* If none any of these macros are defined then try to provide a default implementation */ + + #if defined(UNITY_CLOCK_MS) + /* This is a simple way to get a default implementation on platforms that support getting a millisecond counter */ + #define UNITY_TIME_TYPE UNITY_UINT + #define UNITY_EXEC_TIME_START() Unity.CurrentTestStartTime = UNITY_CLOCK_MS() + #define UNITY_EXEC_TIME_STOP() Unity.CurrentTestStopTime = UNITY_CLOCK_MS() + #define UNITY_PRINT_EXEC_TIME() { \ + UNITY_UINT execTimeMs = (Unity.CurrentTestStopTime - Unity.CurrentTestStartTime); \ + UnityPrint(" ("); \ + UnityPrintNumberUnsigned(execTimeMs); \ + UnityPrint(" ms)"); \ + } + #elif defined(_WIN32) + #include <time.h> + #define UNITY_TIME_TYPE clock_t + #define UNITY_GET_TIME(t) t = (clock_t)((clock() * 1000) / CLOCKS_PER_SEC) + #define UNITY_EXEC_TIME_START() UNITY_GET_TIME(Unity.CurrentTestStartTime) + #define UNITY_EXEC_TIME_STOP() UNITY_GET_TIME(Unity.CurrentTestStopTime) + #define UNITY_PRINT_EXEC_TIME() { \ + UNITY_UINT execTimeMs = (Unity.CurrentTestStopTime - Unity.CurrentTestStartTime); \ + UnityPrint(" ("); \ + UnityPrintNumberUnsigned(execTimeMs); \ + UnityPrint(" ms)"); \ + } + #elif defined(__unix__) || defined(__APPLE__) + #include <time.h> + #define UNITY_TIME_TYPE struct timespec + #define UNITY_GET_TIME(t) clock_gettime(CLOCK_MONOTONIC, &t) + #define UNITY_EXEC_TIME_START() UNITY_GET_TIME(Unity.CurrentTestStartTime) + #define UNITY_EXEC_TIME_STOP() UNITY_GET_TIME(Unity.CurrentTestStopTime) + #define UNITY_PRINT_EXEC_TIME() { \ + UNITY_UINT execTimeMs = ((Unity.CurrentTestStopTime.tv_sec - Unity.CurrentTestStartTime.tv_sec) * 1000L); \ + execTimeMs += ((Unity.CurrentTestStopTime.tv_nsec - Unity.CurrentTestStartTime.tv_nsec) / 1000000L); \ + UnityPrint(" ("); \ + UnityPrintNumberUnsigned(execTimeMs); \ + UnityPrint(" ms)"); \ + } + #endif + #endif #endif -//------------------------------------------------------- -// Output Method -//------------------------------------------------------- +#ifndef UNITY_EXEC_TIME_START +#define UNITY_EXEC_TIME_START() do{}while(0) +#endif -#ifndef UNITY_OUTPUT_CHAR -//Default to using putchar, which is defined in stdio.h above -#define UNITY_OUTPUT_CHAR(a) putchar(a) -#else -//If defined as something else, make sure we declare it here so it's ready for use -extern int UNITY_OUTPUT_CHAR(int); +#ifndef UNITY_EXEC_TIME_STOP +#define UNITY_EXEC_TIME_STOP() do{}while(0) #endif -//------------------------------------------------------- -// Footprint -//------------------------------------------------------- +#ifndef UNITY_TIME_TYPE +#define UNITY_TIME_TYPE UNITY_UINT +#endif + +#ifndef UNITY_PRINT_EXEC_TIME +#define UNITY_PRINT_EXEC_TIME() do{}while(0) +#endif + +/*------------------------------------------------------- + * Footprint + *-------------------------------------------------------*/ #ifndef UNITY_LINE_TYPE -#define UNITY_LINE_TYPE _U_UINT +#define UNITY_LINE_TYPE UNITY_UINT #endif #ifndef UNITY_COUNTER_TYPE -#define UNITY_COUNTER_TYPE _U_UINT +#define UNITY_COUNTER_TYPE UNITY_UINT #endif -//------------------------------------------------------- -// Internal Structs Needed -//------------------------------------------------------- +/*------------------------------------------------------- + * Internal Structs Needed + *-------------------------------------------------------*/ typedef void (*UnityTestFunction)(void); #define UNITY_DISPLAY_RANGE_INT (0x10) #define UNITY_DISPLAY_RANGE_UINT (0x20) #define UNITY_DISPLAY_RANGE_HEX (0x40) -#define UNITY_DISPLAY_RANGE_AUTO (0x80) +#define UNITY_DISPLAY_RANGE_CHAR (0x80) typedef enum { -#if (UNITY_INT_WIDTH == 16) - UNITY_DISPLAY_STYLE_INT = 2 + UNITY_DISPLAY_RANGE_INT + UNITY_DISPLAY_RANGE_AUTO, -#elif (UNITY_INT_WIDTH == 32) - UNITY_DISPLAY_STYLE_INT = 4 + UNITY_DISPLAY_RANGE_INT + UNITY_DISPLAY_RANGE_AUTO, -#elif (UNITY_INT_WIDTH == 64) - UNITY_DISPLAY_STYLE_INT = 8 + UNITY_DISPLAY_RANGE_INT + UNITY_DISPLAY_RANGE_AUTO, -#endif + UNITY_DISPLAY_STYLE_INT = (UNITY_INT_WIDTH / 8) + UNITY_DISPLAY_RANGE_INT, UNITY_DISPLAY_STYLE_INT8 = 1 + UNITY_DISPLAY_RANGE_INT, UNITY_DISPLAY_STYLE_INT16 = 2 + UNITY_DISPLAY_RANGE_INT, UNITY_DISPLAY_STYLE_INT32 = 4 + UNITY_DISPLAY_RANGE_INT, @@ -281,91 +413,179 @@ typedef enum UNITY_DISPLAY_STYLE_INT64 = 8 + UNITY_DISPLAY_RANGE_INT, #endif -#if (UNITY_INT_WIDTH == 16) - UNITY_DISPLAY_STYLE_UINT = 2 + UNITY_DISPLAY_RANGE_UINT + UNITY_DISPLAY_RANGE_AUTO, -#elif (UNITY_INT_WIDTH == 32) - UNITY_DISPLAY_STYLE_UINT = 4 + UNITY_DISPLAY_RANGE_UINT + UNITY_DISPLAY_RANGE_AUTO, -#elif (UNITY_INT_WIDTH == 64) - UNITY_DISPLAY_STYLE_UINT = 8 + UNITY_DISPLAY_RANGE_UINT + UNITY_DISPLAY_RANGE_AUTO, -#endif + UNITY_DISPLAY_STYLE_UINT = (UNITY_INT_WIDTH / 8) + UNITY_DISPLAY_RANGE_UINT, UNITY_DISPLAY_STYLE_UINT8 = 1 + UNITY_DISPLAY_RANGE_UINT, UNITY_DISPLAY_STYLE_UINT16 = 2 + UNITY_DISPLAY_RANGE_UINT, UNITY_DISPLAY_STYLE_UINT32 = 4 + UNITY_DISPLAY_RANGE_UINT, #ifdef UNITY_SUPPORT_64 UNITY_DISPLAY_STYLE_UINT64 = 8 + UNITY_DISPLAY_RANGE_UINT, #endif + UNITY_DISPLAY_STYLE_HEX8 = 1 + UNITY_DISPLAY_RANGE_HEX, UNITY_DISPLAY_STYLE_HEX16 = 2 + UNITY_DISPLAY_RANGE_HEX, UNITY_DISPLAY_STYLE_HEX32 = 4 + UNITY_DISPLAY_RANGE_HEX, #ifdef UNITY_SUPPORT_64 UNITY_DISPLAY_STYLE_HEX64 = 8 + UNITY_DISPLAY_RANGE_HEX, #endif + + UNITY_DISPLAY_STYLE_CHAR = 1 + UNITY_DISPLAY_RANGE_CHAR + UNITY_DISPLAY_RANGE_INT, + UNITY_DISPLAY_STYLE_UNKNOWN } UNITY_DISPLAY_STYLE_T; -struct _Unity +typedef enum +{ + UNITY_WITHIN = 0x0, + UNITY_EQUAL_TO = 0x1, + UNITY_GREATER_THAN = 0x2, + UNITY_GREATER_OR_EQUAL = 0x2 + UNITY_EQUAL_TO, + UNITY_SMALLER_THAN = 0x4, + UNITY_SMALLER_OR_EQUAL = 0x4 + UNITY_EQUAL_TO, + UNITY_NOT_EQUAL = 0x0, + UNITY_UNKNOWN +} UNITY_COMPARISON_T; + +#ifndef UNITY_EXCLUDE_FLOAT +typedef enum UNITY_FLOAT_TRAIT +{ + UNITY_FLOAT_IS_NOT_INF = 0, + UNITY_FLOAT_IS_INF, + UNITY_FLOAT_IS_NOT_NEG_INF, + UNITY_FLOAT_IS_NEG_INF, + UNITY_FLOAT_IS_NOT_NAN, + UNITY_FLOAT_IS_NAN, + UNITY_FLOAT_IS_NOT_DET, + UNITY_FLOAT_IS_DET, + UNITY_FLOAT_INVALID_TRAIT +} UNITY_FLOAT_TRAIT_T; +#endif + +typedef enum +{ + UNITY_ARRAY_TO_VAL = 0, + UNITY_ARRAY_TO_ARRAY, + UNITY_ARRAY_UNKNOWN +} UNITY_FLAGS_T; + +struct UNITY_STORAGE_T { const char* TestFile; const char* CurrentTestName; +#ifndef UNITY_EXCLUDE_DETAILS + const char* CurrentDetail1; + const char* CurrentDetail2; +#endif UNITY_LINE_TYPE CurrentTestLineNumber; UNITY_COUNTER_TYPE NumberOfTests; UNITY_COUNTER_TYPE TestFailures; UNITY_COUNTER_TYPE TestIgnores; UNITY_COUNTER_TYPE CurrentTestFailed; UNITY_COUNTER_TYPE CurrentTestIgnored; +#ifdef UNITY_INCLUDE_EXEC_TIME + UNITY_TIME_TYPE CurrentTestStartTime; + UNITY_TIME_TYPE CurrentTestStopTime; +#endif +#ifndef UNITY_EXCLUDE_SETJMP_H jmp_buf AbortFrame; +#endif }; -extern struct _Unity Unity; +extern struct UNITY_STORAGE_T Unity; -//------------------------------------------------------- -// Test Suite Management -//------------------------------------------------------- +/*------------------------------------------------------- + * Test Suite Management + *-------------------------------------------------------*/ -void UnityBegin(void); +void UnityBegin(const char* filename); int UnityEnd(void); +void UnitySetTestFile(const char* filename); void UnityConcludeTest(void); + +#ifndef RUN_TEST void UnityDefaultTestRun(UnityTestFunction Func, const char* FuncName, const int FuncLineNum); +#else +#define UNITY_SKIP_DEFAULT_RUNNER +#endif -//------------------------------------------------------- -// Test Output -//------------------------------------------------------- +/*------------------------------------------------------- + * Details Support + *-------------------------------------------------------*/ + +#ifdef UNITY_EXCLUDE_DETAILS +#define UNITY_CLR_DETAILS() +#define UNITY_SET_DETAIL(d1) +#define UNITY_SET_DETAILS(d1,d2) +#else +#define UNITY_CLR_DETAILS() { Unity.CurrentDetail1 = 0; Unity.CurrentDetail2 = 0; } +#define UNITY_SET_DETAIL(d1) { Unity.CurrentDetail1 = (d1); Unity.CurrentDetail2 = 0; } +#define UNITY_SET_DETAILS(d1,d2) { Unity.CurrentDetail1 = (d1); Unity.CurrentDetail2 = (d2); } + +#ifndef UNITY_DETAIL1_NAME +#define UNITY_DETAIL1_NAME "Function" +#endif + +#ifndef UNITY_DETAIL2_NAME +#define UNITY_DETAIL2_NAME "Argument" +#endif +#endif + +#ifdef UNITY_PRINT_TEST_CONTEXT +void UNITY_PRINT_TEST_CONTEXT(void); +#endif + +/*------------------------------------------------------- + * Test Output + *-------------------------------------------------------*/ void UnityPrint(const char* string); -void UnityPrintMask(const _U_UINT mask, const _U_UINT number); -void UnityPrintNumberByStyle(const _U_SINT number, const UNITY_DISPLAY_STYLE_T style); -void UnityPrintNumber(const _U_SINT number); -void UnityPrintNumberUnsigned(const _U_UINT number); -void UnityPrintNumberHex(const _U_UINT number, const char nibbles); - -#ifdef UNITY_FLOAT_VERBOSE -void UnityPrintFloat(const _UF number); -#endif - -//------------------------------------------------------- -// Test Assertion Fuctions -//------------------------------------------------------- -// Use the macros below this section instead of calling -// these directly. The macros have a consistent naming -// convention and will pull in file and line information -// for you. - -void UnityAssertEqualNumber(const _U_SINT expected, - const _U_SINT actual, + +#ifdef UNITY_INCLUDE_PRINT_FORMATTED +void UnityPrintF(const UNITY_LINE_TYPE line, const char* format, ...); +#endif + +void UnityPrintLen(const char* string, const UNITY_UINT32 length); +void UnityPrintMask(const UNITY_UINT mask, const UNITY_UINT number); +void UnityPrintNumberByStyle(const UNITY_INT number, const UNITY_DISPLAY_STYLE_T style); +void UnityPrintNumber(const UNITY_INT number_to_print); +void UnityPrintNumberUnsigned(const UNITY_UINT number); +void UnityPrintNumberHex(const UNITY_UINT number, const char nibbles_to_print); + +#ifndef UNITY_EXCLUDE_FLOAT_PRINT +void UnityPrintFloat(const UNITY_DOUBLE input_number); +#endif + +/*------------------------------------------------------- + * Test Assertion Functions + *------------------------------------------------------- + * Use the macros below this section instead of calling + * these directly. The macros have a consistent naming + * convention and will pull in file and line information + * for you. */ + +void UnityAssertEqualNumber(const UNITY_INT expected, + const UNITY_INT actual, const char* msg, const UNITY_LINE_TYPE lineNumber, const UNITY_DISPLAY_STYLE_T style); -void UnityAssertEqualIntArray(const _U_SINT* expected, - const _U_SINT* actual, - const _UU32 num_elements, +void UnityAssertGreaterOrLessOrEqualNumber(const UNITY_INT threshold, + const UNITY_INT actual, + const UNITY_COMPARISON_T compare, + const char *msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style); + +void UnityAssertEqualIntArray(UNITY_INTERNAL_PTR expected, + UNITY_INTERNAL_PTR actual, + 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 _U_SINT mask, - const _U_SINT expected, - const _U_SINT actual, +void UnityAssertBits(const UNITY_INT mask, + const UNITY_INT expected, + const UNITY_INT actual, const char* msg, const UNITY_LINE_TYPE lineNumber); @@ -374,139 +594,460 @@ void UnityAssertEqualString(const char* expected, const char* msg, const UNITY_LINE_TYPE lineNumber); -void UnityAssertEqualStringArray( const char** expected, +void UnityAssertEqualStringLen(const char* expected, + const char* actual, + const UNITY_UINT32 length, + const char* msg, + const UNITY_LINE_TYPE lineNumber); + +void UnityAssertEqualStringArray( UNITY_INTERNAL_PTR expected, const char** actual, - const _UU32 num_elements, + 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( const void* expected, - const void* actual, - const _UU32 length, - const _UU32 num_elements, +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 _U_SINT delta, - const _U_SINT expected, - const _U_SINT actual, +void UnityAssertNumbersWithin(const UNITY_UINT delta, + const UNITY_INT expected, + const UNITY_INT actual, const char* msg, const UNITY_LINE_TYPE lineNumber, const UNITY_DISPLAY_STYLE_T style); +void UnityAssertNumbersArrayWithin(const UNITY_UINT delta, + UNITY_INTERNAL_PTR expected, + UNITY_INTERNAL_PTR actual, + const UNITY_UINT32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style, + const UNITY_FLAGS_T flags); + +#ifndef UNITY_EXCLUDE_SETJMP_H +UNITY_NORETURN void UnityFail(const char* message, const UNITY_LINE_TYPE line); +UNITY_NORETURN void UnityIgnore(const char* message, const UNITY_LINE_TYPE line); +#else void UnityFail(const char* message, const UNITY_LINE_TYPE line); - void UnityIgnore(const char* message, const UNITY_LINE_TYPE line); +#endif + +void UnityMessage(const char* message, const UNITY_LINE_TYPE line); #ifndef UNITY_EXCLUDE_FLOAT -void UnityAssertFloatsWithin(const _UF delta, - const _UF expected, - const _UF actual, +void UnityAssertFloatsWithin(const UNITY_FLOAT delta, + const UNITY_FLOAT expected, + const UNITY_FLOAT actual, const char* msg, const UNITY_LINE_TYPE lineNumber); -void UnityAssertEqualFloatArray(const _UF* expected, - const _UF* actual, - const _UU32 num_elements, +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, + const UNITY_LINE_TYPE lineNumber, + const UNITY_FLOAT_TRAIT_T style); #endif #ifndef UNITY_EXCLUDE_DOUBLE -void UnityAssertDoublesWithin(const _UD delta, - const _UD expected, - const _UD actual, +void UnityAssertDoublesWithin(const UNITY_DOUBLE delta, + const UNITY_DOUBLE expected, + const UNITY_DOUBLE actual, const char* msg, const UNITY_LINE_TYPE lineNumber); -void UnityAssertEqualDoubleArray(const _UD* expected, - const _UD* actual, - const _UU32 num_elements, +void UnityAssertEqualDoubleArray(UNITY_PTR_ATTRIBUTE const UNITY_DOUBLE* expected, + UNITY_PTR_ATTRIBUTE const UNITY_DOUBLE* actual, + const UNITY_UINT32 num_elements, const char* msg, - const UNITY_LINE_TYPE lineNumber); -#endif - -//------------------------------------------------------- -// Basic Fail and Ignore -//------------------------------------------------------- - -#define UNITY_TEST_FAIL(line, message) UnityFail( (message), (UNITY_LINE_TYPE)line); -#define UNITY_TEST_IGNORE(line, message) UnityIgnore( (message), (UNITY_LINE_TYPE)line); - -//------------------------------------------------------- -// Test Asserts -//------------------------------------------------------- - -#define UNITY_TEST_ASSERT(condition, line, message) if (condition) {} else {UNITY_TEST_FAIL((UNITY_LINE_TYPE)line, message);} -#define UNITY_TEST_ASSERT_NULL(pointer, line, message) UNITY_TEST_ASSERT(((pointer) == NULL), (UNITY_LINE_TYPE)line, message) -#define UNITY_TEST_ASSERT_NOT_NULL(pointer, line, message) UNITY_TEST_ASSERT(((pointer) != NULL), (UNITY_LINE_TYPE)line, message) - -#define UNITY_TEST_ASSERT_EQUAL_INT(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_INT) -#define UNITY_TEST_ASSERT_EQUAL_INT8(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(_US8 )(expected), (_U_SINT)(_US8 )(actual), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_INT) -#define UNITY_TEST_ASSERT_EQUAL_INT16(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(_US16)(expected), (_U_SINT)(_US16)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_INT) -#define UNITY_TEST_ASSERT_EQUAL_INT32(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(_US32)(expected), (_U_SINT)(_US32)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_INT) -#define UNITY_TEST_ASSERT_EQUAL_UINT(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_UINT) -#define UNITY_TEST_ASSERT_EQUAL_UINT8(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(_US8 )(expected), (_U_SINT)(_US8 )(actual), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_UINT) -#define UNITY_TEST_ASSERT_EQUAL_UINT16(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(_US16)(expected), (_U_SINT)(_US16)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_UINT) -#define UNITY_TEST_ASSERT_EQUAL_UINT32(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(_US32)(expected), (_U_SINT)(_US32)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_UINT) -#define UNITY_TEST_ASSERT_EQUAL_HEX8(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(_US8 )(expected), (_U_SINT)(_US8 )(actual), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_HEX8) -#define UNITY_TEST_ASSERT_EQUAL_HEX16(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(_US16)(expected), (_U_SINT)(_US16)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_HEX16) -#define UNITY_TEST_ASSERT_EQUAL_HEX32(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(_US32)(expected), (_U_SINT)(_US32)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_HEX32) -#define UNITY_TEST_ASSERT_BITS(mask, expected, actual, line, message) UnityAssertBits((_U_SINT)(mask), (_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)line) - -#define UNITY_TEST_ASSERT_INT_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((_U_SINT)(delta), (_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_INT) -#define UNITY_TEST_ASSERT_UINT_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((_U_SINT)(delta), (_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_UINT) -#define UNITY_TEST_ASSERT_HEX8_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((_U_SINT)(_U_UINT)(_UU8 )(delta), (_U_SINT)(_U_UINT)(_UU8 )(expected), (_U_SINT)(_U_UINT)(_UU8 )(actual), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_HEX8) -#define UNITY_TEST_ASSERT_HEX16_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((_U_SINT)(_U_UINT)(_UU16)(delta), (_U_SINT)(_U_UINT)(_UU16)(expected), (_U_SINT)(_U_UINT)(_UU16)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_HEX16) -#define UNITY_TEST_ASSERT_HEX32_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((_U_SINT)(_U_UINT)(_UU32)(delta), (_U_SINT)(_U_UINT)(_UU32)(expected), (_U_SINT)(_U_UINT)(_UU32)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_HEX32) - -#define UNITY_TEST_ASSERT_EQUAL_PTR(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(_UP)(expected), (_U_SINT)(_UP)(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_MEMORY(expected, actual, len, line, message) UnityAssertEqualMemory((void*)(expected), (void*)(actual), (_UU32)(len), 1, (message), (UNITY_LINE_TYPE)line) - -#define UNITY_TEST_ASSERT_EQUAL_INT_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((const _U_SINT*)(expected), (const _U_SINT*)(actual), (_UU32)(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((const _U_SINT*)(expected), (const _U_SINT*)(actual), (_UU32)(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((const _U_SINT*)(expected), (const _U_SINT*)(actual), (_UU32)(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((const _U_SINT*)(expected), (const _U_SINT*)(actual), (_UU32)(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((const _U_SINT*)(expected), (const _U_SINT*)(actual), (_UU32)(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((const _U_SINT*)(expected), (const _U_SINT*)(actual), (_UU32)(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((const _U_SINT*)(expected), (const _U_SINT*)(actual), (_UU32)(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((const _U_SINT*)(expected), (const _U_SINT*)(actual), (_UU32)(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((const _U_SINT*)(expected), (const _U_SINT*)(actual), (_UU32)(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((const _U_SINT*)(expected), (const _U_SINT*)(actual), (_UU32)(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((const _U_SINT*)(expected), (const _U_SINT*)(actual), (_UU32)(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((const _U_SINT*)(_UP*)(expected), (const _U_SINT*)(_UP*)(actual), (_UU32)(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), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)line) -#define UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY(expected, actual, len, num_elements, line, message) UnityAssertEqualMemory((void*)(expected), (void*)(actual), (_UU32)(len), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)line) + const UNITY_LINE_TYPE lineNumber, + const UNITY_FLAGS_T flags); + +void UnityAssertDoubleSpecial(const UNITY_DOUBLE actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_FLOAT_TRAIT_T style); +#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 + *-------------------------------------------------------*/ + +extern const char UnityStrOk[]; +extern const char UnityStrPass[]; +extern const char UnityStrFail[]; +extern const char UnityStrIgnore[]; + +extern const char UnityStrErrFloat[]; +extern const char UnityStrErrDouble[]; +extern const char UnityStrErr64[]; +extern const char UnityStrErrShorthand[]; + +/*------------------------------------------------------- + * Test Running Macros + *-------------------------------------------------------*/ + +#ifndef UNITY_EXCLUDE_SETJMP_H +#define TEST_PROTECT() (setjmp(Unity.AbortFrame) == 0) +#define TEST_ABORT() longjmp(Unity.AbortFrame, 1) +#else +#define TEST_PROTECT() 1 +#define TEST_ABORT() return +#endif + +/* This tricky series of macros gives us an optional line argument to treat it as RUN_TEST(func, num=__LINE__) */ +#ifndef RUN_TEST +#ifdef __STDC_VERSION__ +#if __STDC_VERSION__ >= 199901L +#define UNITY_SUPPORT_VARIADIC_MACROS +#endif +#endif +#ifdef UNITY_SUPPORT_VARIADIC_MACROS +#define RUN_TEST(...) RUN_TEST_AT_LINE(__VA_ARGS__, __LINE__, throwaway) +#define RUN_TEST_AT_LINE(func, line, ...) UnityDefaultTestRun(func, #func, line) +#endif +#endif + +/* If we can't do the tricky version, we'll just have to require them to always include the line number */ +#ifndef RUN_TEST +#ifdef CMOCK +#define RUN_TEST(func, num) UnityDefaultTestRun(func, #func, num) +#else +#define RUN_TEST(func) UnityDefaultTestRun(func, #func, __LINE__) +#endif +#endif + +#define TEST_LINE_NUM (Unity.CurrentTestLineNumber) +#define TEST_IS_IGNORED (Unity.CurrentTestIgnored) +#define UNITY_NEW_TEST(a) \ + Unity.CurrentTestName = (a); \ + Unity.CurrentTestLineNumber = (UNITY_LINE_TYPE)(__LINE__); \ + Unity.NumberOfTests++; + +#ifndef UNITY_BEGIN +#define UNITY_BEGIN() UnityBegin(__FILE__) +#endif + +#ifndef UNITY_END +#define UNITY_END() UnityEnd() +#endif + +#ifndef UNITY_SHORTHAND_AS_INT +#ifndef UNITY_SHORTHAND_AS_MEM +#ifndef UNITY_SHORTHAND_AS_NONE +#ifndef UNITY_SHORTHAND_AS_RAW +#define UNITY_SHORTHAND_AS_OLD +#endif +#endif +#endif +#endif + +/*----------------------------------------------- + * Command Line Argument Support + *-----------------------------------------------*/ + +#ifdef UNITY_USE_COMMAND_LINE_ARGS +int UnityParseOptions(int argc, char** argv); +int UnityTestMatches(void); +#endif + +/*------------------------------------------------------- + * Basic Fail and Ignore + *-------------------------------------------------------*/ + +#define UNITY_TEST_FAIL(line, message) UnityFail( (message), (UNITY_LINE_TYPE)(line)) +#define UNITY_TEST_IGNORE(line, message) UnityIgnore( (message), (UNITY_LINE_TYPE)(line)) + +/*------------------------------------------------------- + * Test Asserts + *-------------------------------------------------------*/ + +#define UNITY_TEST_ASSERT(condition, line, message) do {if (condition) {} else {UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), (message));}} while(0) +#define UNITY_TEST_ASSERT_NULL(pointer, line, message) UNITY_TEST_ASSERT(((pointer) == NULL), (UNITY_LINE_TYPE)(line), (message)) +#define UNITY_TEST_ASSERT_NOT_NULL(pointer, line, message) UNITY_TEST_ASSERT(((pointer) != NULL), (UNITY_LINE_TYPE)(line), (message)) +#define UNITY_TEST_ASSERT_EMPTY(pointer, line, message) UNITY_TEST_ASSERT(((pointer[0]) == 0), (UNITY_LINE_TYPE)(line), (message)) +#define UNITY_TEST_ASSERT_NOT_EMPTY(pointer, line, message) UNITY_TEST_ASSERT(((pointer[0]) != 0), (UNITY_LINE_TYPE)(line), (message)) + +#define UNITY_TEST_ASSERT_EQUAL_INT(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) +#define UNITY_TEST_ASSERT_EQUAL_INT8(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_INT8 )(expected), (UNITY_INT)(UNITY_INT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) +#define UNITY_TEST_ASSERT_EQUAL_INT16(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_INT16)(expected), (UNITY_INT)(UNITY_INT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) +#define UNITY_TEST_ASSERT_EQUAL_INT32(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_INT32)(expected), (UNITY_INT)(UNITY_INT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) +#define UNITY_TEST_ASSERT_EQUAL_UINT(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) +#define UNITY_TEST_ASSERT_EQUAL_UINT8(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_UINT8 )(expected), (UNITY_INT)(UNITY_UINT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) +#define UNITY_TEST_ASSERT_EQUAL_UINT16(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_UINT16)(expected), (UNITY_INT)(UNITY_UINT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) +#define UNITY_TEST_ASSERT_EQUAL_UINT32(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_UINT32)(expected), (UNITY_INT)(UNITY_UINT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) +#define UNITY_TEST_ASSERT_EQUAL_HEX8(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_INT8 )(expected), (UNITY_INT)(UNITY_INT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) +#define UNITY_TEST_ASSERT_EQUAL_HEX16(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_INT16)(expected), (UNITY_INT)(UNITY_INT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) +#define UNITY_TEST_ASSERT_EQUAL_HEX32(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_INT32)(expected), (UNITY_INT)(UNITY_INT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) +#define UNITY_TEST_ASSERT_EQUAL_CHAR(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_INT8 )(expected), (UNITY_INT)(UNITY_INT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR) +#define UNITY_TEST_ASSERT_BITS(mask, expected, actual, line, message) UnityAssertBits((UNITY_INT)(mask), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line)) + +#define UNITY_TEST_ASSERT_NOT_EQUAL_INT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) +#define UNITY_TEST_ASSERT_NOT_EQUAL_INT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) +#define UNITY_TEST_ASSERT_NOT_EQUAL_INT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT16)(threshold), (UNITY_INT)(UNITY_INT16)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) +#define UNITY_TEST_ASSERT_NOT_EQUAL_INT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT32)(threshold), (UNITY_INT)(UNITY_INT32)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) +#define UNITY_TEST_ASSERT_NOT_EQUAL_UINT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) +#define UNITY_TEST_ASSERT_NOT_EQUAL_UINT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) +#define UNITY_TEST_ASSERT_NOT_EQUAL_UINT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) +#define UNITY_TEST_ASSERT_NOT_EQUAL_UINT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) +#define UNITY_TEST_ASSERT_NOT_EQUAL_HEX8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) +#define UNITY_TEST_ASSERT_NOT_EQUAL_HEX16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) +#define UNITY_TEST_ASSERT_NOT_EQUAL_HEX32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) +#define UNITY_TEST_ASSERT_NOT_EQUAL_CHAR(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR) + +#define UNITY_TEST_ASSERT_GREATER_THAN_INT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) +#define UNITY_TEST_ASSERT_GREATER_THAN_INT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) +#define UNITY_TEST_ASSERT_GREATER_THAN_INT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT16)(threshold), (UNITY_INT)(UNITY_INT16)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) +#define UNITY_TEST_ASSERT_GREATER_THAN_INT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT32)(threshold), (UNITY_INT)(UNITY_INT32)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) +#define UNITY_TEST_ASSERT_GREATER_THAN_UINT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) +#define UNITY_TEST_ASSERT_GREATER_THAN_UINT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) +#define UNITY_TEST_ASSERT_GREATER_THAN_UINT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) +#define UNITY_TEST_ASSERT_GREATER_THAN_UINT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) +#define UNITY_TEST_ASSERT_GREATER_THAN_HEX8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) +#define UNITY_TEST_ASSERT_GREATER_THAN_HEX16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) +#define UNITY_TEST_ASSERT_GREATER_THAN_HEX32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) +#define UNITY_TEST_ASSERT_GREATER_THAN_CHAR(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR) + +#define UNITY_TEST_ASSERT_SMALLER_THAN_INT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) +#define UNITY_TEST_ASSERT_SMALLER_THAN_INT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) +#define UNITY_TEST_ASSERT_SMALLER_THAN_INT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT16)(threshold), (UNITY_INT)(UNITY_INT16)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) +#define UNITY_TEST_ASSERT_SMALLER_THAN_INT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT32)(threshold), (UNITY_INT)(UNITY_INT32)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) +#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) +#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) +#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) +#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) +#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) +#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) +#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) +#define UNITY_TEST_ASSERT_SMALLER_THAN_CHAR(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR) + +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT) (threshold), (UNITY_INT) (actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 ) (threshold), (UNITY_INT)(UNITY_INT8 ) (actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT16) (threshold), (UNITY_INT)(UNITY_INT16) (actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT32) (threshold), (UNITY_INT)(UNITY_INT32) (actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT) (threshold), (UNITY_INT) (actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_CHAR(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 ) (threshold), (UNITY_INT)(UNITY_INT8 ) (actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR) + +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT) (threshold), (UNITY_INT) (actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 ) (actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT16)(threshold), (UNITY_INT)(UNITY_INT16) (actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT32)(threshold), (UNITY_INT)(UNITY_INT32) (actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT) (threshold), (UNITY_INT) (actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_CHAR(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 ) (actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR) + +#define UNITY_TEST_ASSERT_INT_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin( (delta), (UNITY_INT) (expected), (UNITY_INT) (actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) +#define UNITY_TEST_ASSERT_INT8_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT8 )(delta), (UNITY_INT)(UNITY_INT8 ) (expected), (UNITY_INT)(UNITY_INT8 ) (actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) +#define UNITY_TEST_ASSERT_INT16_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT16)(delta), (UNITY_INT)(UNITY_INT16) (expected), (UNITY_INT)(UNITY_INT16) (actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) +#define UNITY_TEST_ASSERT_INT32_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT32)(delta), (UNITY_INT)(UNITY_INT32) (expected), (UNITY_INT)(UNITY_INT32) (actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) +#define UNITY_TEST_ASSERT_UINT_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin( (delta), (UNITY_INT) (expected), (UNITY_INT) (actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) +#define UNITY_TEST_ASSERT_UINT8_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT8 )(delta), (UNITY_INT)(UNITY_UINT)(UNITY_UINT8 )(expected), (UNITY_INT)(UNITY_UINT)(UNITY_UINT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) +#define UNITY_TEST_ASSERT_UINT16_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT16)(delta), (UNITY_INT)(UNITY_UINT)(UNITY_UINT16)(expected), (UNITY_INT)(UNITY_UINT)(UNITY_UINT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) +#define UNITY_TEST_ASSERT_UINT32_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT32)(delta), (UNITY_INT)(UNITY_UINT)(UNITY_UINT32)(expected), (UNITY_INT)(UNITY_UINT)(UNITY_UINT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) +#define UNITY_TEST_ASSERT_HEX8_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT8 )(delta), (UNITY_INT)(UNITY_UINT)(UNITY_UINT8 )(expected), (UNITY_INT)(UNITY_UINT)(UNITY_UINT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) +#define UNITY_TEST_ASSERT_HEX16_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT16)(delta), (UNITY_INT)(UNITY_UINT)(UNITY_UINT16)(expected), (UNITY_INT)(UNITY_UINT)(UNITY_UINT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) +#define UNITY_TEST_ASSERT_HEX32_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT32)(delta), (UNITY_INT)(UNITY_UINT)(UNITY_UINT32)(expected), (UNITY_INT)(UNITY_UINT)(UNITY_UINT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) +#define UNITY_TEST_ASSERT_CHAR_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT8 )(delta), (UNITY_INT)(UNITY_INT8 ) (expected), (UNITY_INT)(UNITY_INT8 ) (actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR) + +#define UNITY_TEST_ASSERT_INT_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin( (delta), (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_INT8_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT8 )(delta), (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_INT16_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT16)(delta), (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_INT32_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT32)(delta), (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_UINT_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin( (delta), (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_UINT8_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT16)(delta), (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_UINT16_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT16)(delta), (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_UINT32_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT32)(delta), (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_HEX8_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT8 )(delta), (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_HEX16_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT16)(delta), (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_HEX32_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT32)(delta), (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_CHAR_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT8 )(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR, UNITY_ARRAY_TO_ARRAY) + + +#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), 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_EQUAL_CHAR_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_CHAR, UNITY_ARRAY_TO_ARRAY) + +#define UNITY_TEST_ASSERT_EACH_EQUAL_INT(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT) (expected), (UNITY_INT_WIDTH / 8)), (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), (UNITY_INT_WIDTH / 8)), (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), (UNITY_POINTER_WIDTH / 8)), (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) +#define UNITY_TEST_ASSERT_EACH_EQUAL_CHAR(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_CHAR, UNITY_ARRAY_TO_VAL) #ifdef UNITY_SUPPORT_64 -#define UNITY_TEST_ASSERT_EQUAL_INT64(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_INT64) -#define UNITY_TEST_ASSERT_EQUAL_UINT64(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_UINT64) -#define UNITY_TEST_ASSERT_EQUAL_HEX64(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_HEX64) -#define UNITY_TEST_ASSERT_EQUAL_INT64_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((const _U_SINT*)(expected), (const _U_SINT*)(actual), (_UU32)(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((const _U_SINT*)(expected), (const _U_SINT*)(actual), (_UU32)(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((const _U_SINT*)(expected), (const _U_SINT*)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_HEX64) -#define UNITY_TEST_ASSERT_HEX64_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((_U_SINT)(delta), (_U_SINT)(expected), (_U_SINT)(actual), NULL, (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_HEX64) +#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, 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_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_UINT64(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_UINT64)(expected), 8), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64, UNITY_ARRAY_TO_VAL) +#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_VAL) +#define UNITY_TEST_ASSERT_INT64_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((delta), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) +#define UNITY_TEST_ASSERT_UINT64_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((delta), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) +#define UNITY_TEST_ASSERT_HEX64_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((delta), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) +#define UNITY_TEST_ASSERT_NOT_EQUAL_INT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) +#define UNITY_TEST_ASSERT_NOT_EQUAL_UINT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) +#define UNITY_TEST_ASSERT_NOT_EQUAL_HEX64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) +#define UNITY_TEST_ASSERT_GREATER_THAN_INT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) +#define UNITY_TEST_ASSERT_GREATER_THAN_UINT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) +#define UNITY_TEST_ASSERT_GREATER_THAN_HEX64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) +#define UNITY_TEST_ASSERT_SMALLER_THAN_INT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) +#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) +#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) +#define UNITY_TEST_ASSERT_INT64_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT64)(delta), (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_UINT64_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT64)(delta), (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_HEX64_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT64)(delta), (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) +#else +#define UNITY_TEST_ASSERT_EQUAL_INT64(expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_EQUAL_UINT64(expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_EQUAL_HEX64(expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_EQUAL_INT64_ARRAY(expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_EQUAL_UINT64_ARRAY(expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_EQUAL_HEX64_ARRAY(expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_INT64_WITHIN(delta, expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_UINT64_WITHIN(delta, expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_HEX64_WITHIN(delta, expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_GREATER_THAN_INT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_GREATER_THAN_UINT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_GREATER_THAN_HEX64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_SMALLER_THAN_INT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_INT64_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_UINT64_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_HEX64_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) #endif #ifdef UNITY_EXCLUDE_FLOAT -#define UNITY_TEST_ASSERT_FLOAT_WITHIN(delta, expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)line, "Unity Floating Point Disabled") -#define UNITY_TEST_ASSERT_EQUAL_FLOAT(expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)line, "Unity Floating Point Disabled") -#define UNITY_TEST_ASSERT_EQUAL_FLOAT_ARRAY(expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)line, "Unity Floating Point Disabled") +#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) +#define UNITY_TEST_ASSERT_FLOAT_IS_DETERMINATE(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) +#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) +#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_NEG_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) +#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_NAN(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) +#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) #else -#define UNITY_TEST_ASSERT_FLOAT_WITHIN(delta, expected, actual, line, message) UnityAssertFloatsWithin((_UF)(delta), (_UF)(expected), (_UF)(actual), (message), (UNITY_LINE_TYPE)line) -#define UNITY_TEST_ASSERT_EQUAL_FLOAT(expected, actual, line, message) UNITY_TEST_ASSERT_FLOAT_WITHIN((_UF)(expected) * (_UF)UNITY_FLOAT_PRECISION, (_UF)expected, (_UF)actual, (UNITY_LINE_TYPE)line, message) -#define UNITY_TEST_ASSERT_EQUAL_FLOAT_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualFloatArray((_UF*)(expected), (_UF*)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)line) +#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), 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) +#define UNITY_TEST_ASSERT_FLOAT_IS_DETERMINATE(actual, line, message) UnityAssertFloatSpecial((UNITY_FLOAT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_DET) +#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_INF(actual, line, message) UnityAssertFloatSpecial((UNITY_FLOAT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_INF) +#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_NEG_INF(actual, line, message) UnityAssertFloatSpecial((UNITY_FLOAT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_NEG_INF) +#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_NAN(actual, line, message) UnityAssertFloatSpecial((UNITY_FLOAT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_NAN) +#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE(actual, line, message) UnityAssertFloatSpecial((UNITY_FLOAT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_DET) #endif #ifdef UNITY_EXCLUDE_DOUBLE -#define UNITY_TEST_ASSERT_DOUBLE_WITHIN(delta, expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)line, "Unity Double Precision Disabled") -#define UNITY_TEST_ASSERT_EQUAL_DOUBLE(expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)line, "Unity Double Precision Disabled") -#define UNITY_TEST_ASSERT_EQUAL_DOUBLE_ARRAY(expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)line, "Unity Double Precision Disabled") +#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) +#define UNITY_TEST_ASSERT_DOUBLE_IS_DETERMINATE(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NAN(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) #else -#define UNITY_TEST_ASSERT_DOUBLE_WITHIN(delta, expected, actual, line, message) UnityAssertDoublesWithin((_UD)(delta), (_UD)(expected), (_UD)(actual), (message), (UNITY_LINE_TYPE)line) -#define UNITY_TEST_ASSERT_EQUAL_DOUBLE(expected, actual, line, message) UNITY_TEST_ASSERT_DOUBLE_WITHIN((_UF)(expected) * (_UD)UNITY_DOUBLE_PRECISION, (_UD)expected, (_UD)actual, (UNITY_LINE_TYPE)line, message) -#define UNITY_TEST_ASSERT_EQUAL_DOUBLE_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualDoubleArray((_UD*)(expected), (_UD*)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)line) +#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), 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) +#define UNITY_TEST_ASSERT_DOUBLE_IS_DETERMINATE(actual, line, message) UnityAssertDoubleSpecial((UNITY_DOUBLE)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_DET) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_INF(actual, line, message) UnityAssertDoubleSpecial((UNITY_DOUBLE)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_INF) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF(actual, line, message) UnityAssertDoubleSpecial((UNITY_DOUBLE)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_NEG_INF) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NAN(actual, line, message) UnityAssertDoubleSpecial((UNITY_DOUBLE)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_NAN) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE(actual, line, message) UnityAssertDoubleSpecial((UNITY_DOUBLE)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_DET) #endif +/* End of UNITY_INTERNALS_H */ #endif From b631da4f838234ee1858a32e0aaebd439165a377 Mon Sep 17 00:00:00 2001 From: Paul Jacobson <20469645+pajacobson@users.noreply.github.com> Date: Sun, 4 Dec 2022 18:04:58 +1100 Subject: [PATCH 05/22] Update for mdb --- test/simulation/sim_test_fixture.rb | 39 ++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/test/simulation/sim_test_fixture.rb b/test/simulation/sim_test_fixture.rb index a859a0d..be0b9c8 100644 --- a/test/simulation/sim_test_fixture.rb +++ b/test/simulation/sim_test_fixture.rb @@ -1,8 +1,35 @@ -OUT_FILE = "test/simulation/out.txt" -File.delete OUT_FILE if File.exists? OUT_FILE -IO.popen("sim30 test/simulation/sim_instructions.txt") -sleep 1 -if File.exists? OUT_FILE +# OUT_FILE = "test/simulation/out.txt" +# File.delete OUT_FILE if File.exists? OUT_FILE +# IO.popen("sim30 test/simulation/sim_instructions.txt") +# sleep 1 +# if File.exists? OUT_FILE +# file_contents = File.read OUT_FILE +# print file_contents +# end + +require 'rbconfig' + +OUT_FILE = "./test/simulation/out.txt" + +File.delete OUT_FILE if File.exists? OUT_FILE + +# this_os = RbConfig::CONFIG['host_os'] + +# if (this_os =~ /mswin|mingw|cygwin/) + # var = IO.popen("c:\\Program Files (x86)\\Microchip\\MPLABX\\mplab_ide\\bin>mdb.bat ./test/simulation/sim_instructions.txt > " + OUT_FILE) +# elsif (this_os =~ /darwin1[[:digit:]]/) +var = IO.popen("/Applications/microchip/mplabx/v6.05/mplab_platform/bin/mdb.sh ./test/simulation/sim_instructions.txt") + # var = "/Applications/microchip/mplabx/v6.05/mplab_platform/bin/mdb.sh ./test/simulation/sim_instructions.txt" +# end + +result = var.readlines +Process.waitall + + +if File.exists? OUT_FILE file_contents = File.read OUT_FILE print file_contents -end \ No newline at end of file +else + print result + +end From 567576d00fa78d6820da32e97ad0a50b5184209a Mon Sep 17 00:00:00 2001 From: Paul Jacobson <20469645+pajacobson@users.noreply.github.com> Date: Wed, 7 Dec 2022 14:39:12 +1100 Subject: [PATCH 06/22] Updates to test_fixture --- .gitignore | 1 + README.md | 24 +++++++++++ project.yml | 15 ++++--- test/simulation/sim_instructions.txt | 15 ++----- test/simulation/sim_test_fixture.rb | 61 +++++++++++++++++----------- 5 files changed, 74 insertions(+), 42 deletions(-) diff --git a/.gitignore b/.gitignore index e69de29..e43b0f9 100644 --- a/.gitignore +++ b/.gitignore @@ -0,0 +1 @@ +.DS_Store diff --git a/README.md b/README.md index 7e70feb..a43e7f6 100644 --- a/README.md +++ b/README.md @@ -18,4 +18,28 @@ Edit: 11/01/2021 * You only need to change XC16 compiler path (line 34) inside "project.yml" file to yours. +Edit: 2022-12-07 + +* Ceedling updated to 0.31.1 +* Update Simulation configuration located in test/simulation + +- sim_test_fixture.rd +sim_test_fixture.rd now programs and runs the test binary. +Changes eliminate the need for "sleep" and "wait" timeouts and breakpoints. + +- sim_instructions.txt +This file should only include configuration for the device - Device, HWTool and "set". +Running commands - Program, Reset, Run, Wait, Sleep, Quit - should not be used. + +- project.yml + +```yaml + :test_fixture: + :executable: ruby + :name: "Microchip simulator test fixture" + :stderr_redirect: :win #inform Ceedling what model of $stderr capture to use + :arguments: + - test/simulation/sim_test_fixture.rb + - ${1} +``` diff --git a/project.yml b/project.yml index 418ff15..4bf15fb 100644 --- a/project.yml +++ b/project.yml @@ -26,7 +26,8 @@ :environment: - :mcu: 24HJ128GP202 - - :homedir: /User/directory + - :xc: XC16 + - :xcvers: v2.00 :extension: :executable: .out @@ -40,7 +41,7 @@ :support: - test/support :include: - - /Applications/microchip/xc16/v2.00/support/PIC24H/h/ + - /Applications/microchip/#{ENV['XC']}/#{ENV['XCVERS']}/support/PIC24H/h/ :defines: # in order to add common defines: @@ -101,20 +102,22 @@ # - -Os # This works only with paid XC16 compiler versions # - -mlarge-code # - -mlarge-arrays - - -mdfp=#{ENV['HOMEDIR']}/.mchp_packs/Microchip/dsPIC33F-GP-MC_DFP/1.3.64/xc16 + #- -mdfp=#{ENV['HOMEDIR']}/.mchp_packs/Microchip/dsPIC33F-GP-MC_DFP/1.3.64/xc16 :test_linker: :executable: xc16-gcc :arguments: - -mcpu=#{ENV['MCU']} - ${1} - - -o "./build/test/TestBuild.out" - - -Wl,-Tp24HJ128GP202.gld + - -o ${2} + - -Wl,-Tp#{ENV['MCU']}.gld,--heap=0 + :test_fixture: :executable: ruby :name: "Microchip simulator test fixture" - :stderr_redirect: :auto #inform Ceedling what model of $stderr capture to use + :stderr_redirect: :win #inform Ceedling what model of $stderr capture to use :arguments: - test/simulation/sim_test_fixture.rb + - ${1} :release_compiler: :executable: xc16-gcc diff --git a/test/simulation/sim_instructions.txt b/test/simulation/sim_instructions.txt index 0659778..5fa7931 100644 --- a/test/simulation/sim_instructions.txt +++ b/test/simulation/sim_instructions.txt @@ -1,17 +1,8 @@ Device PIC24HJ128GP202 Hwtool SIM -set uart1io.output file -set uart1io.outputfile ./test/simulation/out.txt +set uart1io.output window set uart1io.uartioenabled true - - -program ./build/test/TestBuild.out -Reset -Sleep 100 -Run - -# Wait for mdb to write results to outputfile. -Wait 500 -Quit +# Only Device and HWTool and "set" options should be added to this file. +# sim_test_fixture.rb handles loading, programming and running test code. diff --git a/test/simulation/sim_test_fixture.rb b/test/simulation/sim_test_fixture.rb index be0b9c8..6813420 100644 --- a/test/simulation/sim_test_fixture.rb +++ b/test/simulation/sim_test_fixture.rb @@ -1,35 +1,48 @@ -# OUT_FILE = "test/simulation/out.txt" -# File.delete OUT_FILE if File.exists? OUT_FILE -# IO.popen("sim30 test/simulation/sim_instructions.txt") -# sleep 1 -# if File.exists? OUT_FILE -# file_contents = File.read OUT_FILE -# print file_contents -# end +require 'open3' -require 'rbconfig' +MDB = "/Applications/microchip/mplabx/v6.05/mplab_platform/bin/mdb.sh" +SCRIPT_FILE = "./test/simulation/sim_instructions.txt" -OUT_FILE = "./test/simulation/out.txt" +test_file = ARGV[0] -File.delete OUT_FILE if File.exists? OUT_FILE +stdin, stdout, stderr, wait_thr = Open3.popen3(MDB, SCRIPT_FILE) -# this_os = RbConfig::CONFIG['host_os'] +stdin.puts("Program " + test_file) +stdin.puts("Run") -# if (this_os =~ /mswin|mingw|cygwin/) - # var = IO.popen("c:\\Program Files (x86)\\Microchip\\MPLABX\\mplab_ide\\bin>mdb.bat ./test/simulation/sim_instructions.txt > " + OUT_FILE) -# elsif (this_os =~ /darwin1[[:digit:]]/) -var = IO.popen("/Applications/microchip/mplabx/v6.05/mplab_platform/bin/mdb.sh ./test/simulation/sim_instructions.txt") - # var = "/Applications/microchip/mplabx/v6.05/mplab_platform/bin/mdb.sh ./test/simulation/sim_instructions.txt" -# end +result = [] + +# Send Quit when test completion, unexpected termination +# or file not found appears on STDOUT +stdout.each do |line| + result = result + [line] + if line.match(/(^(?:OK|FAIL)\n)|(^Stop.*)|(^File.*)/) + stdin.puts("Quit") + end +end + +# consume stderr messages +errors = stderr.readlines -result = var.readlines Process.waitall +# strio out command prompt +result = result.map {|s| s.gsub(/^>/, "")} + +# find the test results +test_start = result.find_index { |line| line.match(/^.*\:(?:FAIL|PASS|IGNORE)/) } +test_status = result.find_index { |line| line.match(/^(?:OK|FAIL)\n/) } -if File.exists? OUT_FILE - file_contents = File.read OUT_FILE - print file_contents -else - print result +# start and last will be missing if code causes an Exception +if test_start & test_status + result = result[test_start , (test_status - test_start) + 1] +end + +# Play back results and errors +result.each do | line | + STDOUT.print line +end +errors.each do | line | + STDERR.print line end From 765ba7c2f21474f1eecf28b2f1464872626fec30 Mon Sep 17 00:00:00 2001 From: Paul Jacobson <20469645+pajacobson@users.noreply.github.com> Date: Wed, 7 Dec 2022 15:04:55 +1100 Subject: [PATCH 07/22] Note XC version --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a43e7f6..7db76f4 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Edit: 11/01/2021 * You only need to change XC16 compiler path (line 34) inside "project.yml" file to yours. Edit: 2022-12-07 - +* Update to use XC16 v2.00 * Ceedling updated to 0.31.1 * Update Simulation configuration located in test/simulation From 89f69948b8898d9a36577e4cb3bbd6ca1c8bdbfe Mon Sep 17 00:00:00 2001 From: Paul Jacobson <20469645+pajacobson@users.noreply.github.com> Date: Wed, 7 Dec 2022 15:05:35 +1100 Subject: [PATCH 08/22] Use environment to set paths, compiler --- project.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/project.yml b/project.yml index 4bf15fb..518a15a 100644 --- a/project.yml +++ b/project.yml @@ -25,9 +25,11 @@ # :use_assembly: FALSE :environment: - - :mcu: 24HJ128GP202 + - :mcfolder: /Applications/microchip - :xc: XC16 - :xcvers: v2.00 + - :xcbin: xc16-gcc + - :mcu: 24HJ128GP202 :extension: :executable: .out @@ -41,7 +43,7 @@ :support: - test/support :include: - - /Applications/microchip/#{ENV['XC']}/#{ENV['XCVERS']}/support/PIC24H/h/ + - "#{ENV['MCFOLDER']}/#{ENV['XC']}/#{ENV['XCVERS']}/support/PIC24H/h/" :defines: # in order to add common defines: @@ -88,7 +90,7 @@ :tools: :test_compiler: - :executable: xc16-gcc + :executable: "#{ENV['MCFOLDER']}/#{ENV['XC']}/#{ENV['XCVERS']}/bin/#{ENV['XCBIN']}" :arguments: - -mcpu=#{ENV['MCU']} - -x c @@ -102,9 +104,8 @@ # - -Os # This works only with paid XC16 compiler versions # - -mlarge-code # - -mlarge-arrays - #- -mdfp=#{ENV['HOMEDIR']}/.mchp_packs/Microchip/dsPIC33F-GP-MC_DFP/1.3.64/xc16 :test_linker: - :executable: xc16-gcc + :executable: "#{ENV['MCFOLDER']}/#{ENV['XC']}/#{ENV['XCVERS']}/bin/#{ENV['XCBIN']}" :arguments: - -mcpu=#{ENV['MCU']} - ${1} @@ -120,7 +121,7 @@ - ${1} :release_compiler: - :executable: xc16-gcc + :executable: "#{ENV['MCFOLDER']}/#{ENV['XC']}/#{ENV['XCVERS']}/bin/#{ENV['XCBIN']}" :arguments: - -mcpu=#{ENV['MCU']} - -x c @@ -136,7 +137,7 @@ # - -mlarge-code # - -mlarge-arrays :release_linker: - :executable: xc16-gcc + :executable: "#{ENV['MCFOLDER']}/#{ENV['XC']}/#{ENV['XCVERS']}/bin/#{ENV['XCBIN']}" :arguments: - -mcpu=#{ENV['MCU']} - ${1} From eb7f299852beca9ba7ce7c74495bcb3133a26759 Mon Sep 17 00:00:00 2001 From: Paul Jacobson <20469645+pajacobson@users.noreply.github.com> Date: Thu, 8 Dec 2022 14:22:08 +1100 Subject: [PATCH 09/22] Updated files --- project.yml | 67 ++++++++++++++++----------- test/simulation/sim_configuration.txt | 8 ++++ test/simulation/sim_test_fixture.rb | 36 +++++++------- test/support/UnityHelper.c | 6 +++ test/support/UnityHelper.h | 6 +++ test/support/unity_config.h | 7 +++ test/test_gpio_access.c | 2 + test/test_led_control.c | 1 + test/test_main.c | 1 + test/test_system.c | 3 ++ 10 files changed, 89 insertions(+), 48 deletions(-) create mode 100644 test/simulation/sim_configuration.txt create mode 100644 test/support/UnityHelper.c create mode 100644 test/support/UnityHelper.h create mode 100644 test/support/unity_config.h diff --git a/project.yml b/project.yml index 518a15a..bb1a968 100644 --- a/project.yml +++ b/project.yml @@ -10,9 +10,9 @@ :use_test_preprocessor: TRUE :use_auxiliary_dependencies: TRUE :build_root: build - :release_build: FALSE +# :release_build: TRUE :test_file_prefix: test_ - :which_ceedling: vendor/ceedling + :which_ceedling: gem :ceedling_version: 0.31.1 :default_tasks: - test:all @@ -20,16 +20,15 @@ #:test_build: # :use_assembly: TRUE -# :release_build: -# :output: MyApp.out -# :use_assembly: FALSE +#:release_build: +# :output: MyApp.out +# :use_assembly: FALSE :environment: - - :mcfolder: /Applications/microchip - - :xc: XC16 - - :xcvers: v2.00 - - :xcbin: xc16-gcc - - :mcu: 24HJ128GP202 + # - :mch_root: "/Applications/microchip" + # - :mplabx_vers: "v6.05" + # - :xc: "xc16" + # - :xc_version: "v2.00" :extension: :executable: .out @@ -43,7 +42,9 @@ :support: - test/support :include: - - "#{ENV['MCFOLDER']}/#{ENV['XC']}/#{ENV['XCVERS']}/support/PIC24H/h/" + - "/Applications/microchip/xc16/v2.00/support/PIC24H/h/" + #- "C:/ProgramFiles/Microchip/xc16/v1.61/support/PIC24H/h/" + :defines: # in order to add common defines: @@ -59,10 +60,15 @@ :test: - *common_defines - TEST + :test_preprocess: - *common_defines - TEST +:unity: + :defines: + - UNITY_INCLUDE_CONFIG_H + :cmock: :mock_prefix: mock_ :when_no_prototypes: :warn @@ -87,16 +93,22 @@ :html_medium_threshold: 75 :html_high_threshold: 90 +#:tools: +# Ceedling defaults to using gcc for compiling, linking, etc. +# As [:tools] is blank, gcc will be used (so long as it's in your system path) +# See documentation to configure a given toolchain for use :tools: :test_compiler: - :executable: "#{ENV['MCFOLDER']}/#{ENV['XC']}/#{ENV['XCVERS']}/bin/#{ENV['XCBIN']}" + :executable: xc16-gcc :arguments: - - -mcpu=#{ENV['MCU']} + - -mcpu=24HJ128GP202 - -x c - -c - "${1}" - -o "${2}" + - -D_DEBUG + - -D__MPLAB_DEBUGGER_SIMULATOR=1 - -D$: COLLECTION_DEFINES_TEST_AND_VENDOR - -I"$": COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR - -Wall @@ -105,25 +117,27 @@ # - -mlarge-code # - -mlarge-arrays :test_linker: - :executable: "#{ENV['MCFOLDER']}/#{ENV['XC']}/#{ENV['XCVERS']}/bin/#{ENV['XCBIN']}" + :executable: xc16-gcc :arguments: - - -mcpu=#{ENV['MCU']} + - -mcpu=24HJ128GP202 - ${1} - -o ${2} - - -Wl,-Tp#{ENV['MCU']}.gld,--heap=0 + - -Wl,-Tp24HJ128GP202.gld,--heap=0, + --defsym=__MPLAB_BUILD=1,--defsym=__MPLAB_DEBUG=1, + --defsym=__DEBUG=1,-D__DEBUG=__DEBUG,--defsym=__MPLAB_DEBUGGER_SIMULATOR=1 :test_fixture: :executable: ruby :name: "Microchip simulator test fixture" - :stderr_redirect: :win #inform Ceedling what model of $stderr capture to use + :stderr_redirect: :auto #inform Ceedling what model of $stderr capture to use :arguments: - test/simulation/sim_test_fixture.rb - ${1} :release_compiler: - :executable: "#{ENV['MCFOLDER']}/#{ENV['XC']}/#{ENV['XCVERS']}/bin/#{ENV['XCBIN']}" + :executable: xc16-gcc :arguments: - - -mcpu=#{ENV['MCU']} + - -mcpu=24HJ128GP202 - -x c - -c - "${1}" @@ -136,17 +150,15 @@ # - -Os # This works only with paid XC16 compiler versions # - -mlarge-code # - -mlarge-arrays + :release_linker: - :executable: "#{ENV['MCFOLDER']}/#{ENV['XC']}/#{ENV['XCVERS']}/bin/#{ENV['XCBIN']}" + :executable: xc16-gcc :arguments: - - -mcpu=#{ENV['MCU']} + - -mcpu=24HJ128GP202 - ${1} - -o "${2}" - - -Wl,-Tp#{ENV['MCU']}.gld,-Map=./build/release/MyApp.map,--report-mem -#:tools: -# Ceedling defaults to using gcc for compiling, linking, etc. -# As [:tools] is blank, gcc will be used (so long as it's in your system path) -# See documentation to configure a given toolchain for use + - -Wl,-Tp24HJ128GP202.gld,-Map=./build/release/MyPicApp.map,--report-mem + # LIBRARIES # These libraries are automatically injected into the build process. Those specified as @@ -162,9 +174,8 @@ :plugins: :load_paths: - - vendor/ceedling/plugins + - "#{Ceedling.load_path}" :enabled: - stdout_pretty_tests_report - module_generator - - raw_output_report ... diff --git a/test/simulation/sim_configuration.txt b/test/simulation/sim_configuration.txt new file mode 100644 index 0000000..5fa7931 --- /dev/null +++ b/test/simulation/sim_configuration.txt @@ -0,0 +1,8 @@ +Device PIC24HJ128GP202 +Hwtool SIM + +set uart1io.output window +set uart1io.uartioenabled true + +# Only Device and HWTool and "set" options should be added to this file. +# sim_test_fixture.rb handles loading, programming and running test code. diff --git a/test/simulation/sim_test_fixture.rb b/test/simulation/sim_test_fixture.rb index 6813420..3590b49 100644 --- a/test/simulation/sim_test_fixture.rb +++ b/test/simulation/sim_test_fixture.rb @@ -1,48 +1,44 @@ require 'open3' -MDB = "/Applications/microchip/mplabx/v6.05/mplab_platform/bin/mdb.sh" -SCRIPT_FILE = "./test/simulation/sim_instructions.txt" +MDB = "mdb.sh" # or "mdb" + +CONFIG_FILE = "./test/simulation/sim_configuration.txt" test_file = ARGV[0] -stdin, stdout, stderr, wait_thr = Open3.popen3(MDB, SCRIPT_FILE) +stdin, stdout, stderr, wait_thr = Open3.popen3(MDB, CONFIG_FILE) stdin.puts("Program " + test_file) +stdin.puts("Break UnityHelperDeadLoop") stdin.puts("Run") -result = [] - -# Send Quit when test completion, unexpected termination -# or file not found appears on STDOUT -stdout.each do |line| - result = result + [line] - if line.match(/(^(?:OK|FAIL)\n)|(^Stop.*)|(^File.*)/) - stdin.puts("Quit") - end -end +# Failsafe: exit after 30 seconds if SIM does not halt +stdin.puts("Wait 30000") +stdin.puts("Quit") -# consume stderr messages -errors = stderr.readlines +# Filter out tedious MDB Java logr and NetBeans errors +errors = stderr.readlines.reject { | line | line.match(/(logr|dumb|Preferences)/)} +result = stdout.readlines Process.waitall -# strio out command prompt +# Remove stray command prompts result = result.map {|s| s.gsub(/^>/, "")} -# find the test results +# find the test results block test_start = result.find_index { |line| line.match(/^.*\:(?:FAIL|PASS|IGNORE)/) } test_status = result.find_index { |line| line.match(/^(?:OK|FAIL)\n/) } # start and last will be missing if code causes an Exception -if test_start & test_status +if (test_start != nil) & (test_status != nil) result = result[test_start , (test_status - test_start) + 1] end -# Play back results and errors +# Play back cleaned results and errors result.each do | line | STDOUT.print line end errors.each do | line | - STDERR.print line + STDOUT.print line end diff --git a/test/support/UnityHelper.c b/test/support/UnityHelper.c new file mode 100644 index 0000000..10bf07f --- /dev/null +++ b/test/support/UnityHelper.c @@ -0,0 +1,6 @@ +#include "UnityHelper.h" + +void UnityHelperDeadLoop(void){ + while(0){}; +} + diff --git a/test/support/UnityHelper.h b/test/support/UnityHelper.h new file mode 100644 index 0000000..20391f6 --- /dev/null +++ b/test/support/UnityHelper.h @@ -0,0 +1,6 @@ +#ifndef UNITY_HELPER_H +#define UNITY_HELPER_H + +void UnityHelperDeadLoop(void); + +#endif diff --git a/test/support/unity_config.h b/test/support/unity_config.h new file mode 100644 index 0000000..eebfca0 --- /dev/null +++ b/test/support/unity_config.h @@ -0,0 +1,7 @@ +#ifndef UNITY_CONFIG_H +#define UNITY_CONFIG_H +#include "UnityHelper.h" + +#define UNITY_OUTPUT_COMPLETE() UnityHelperDeadLoop() + +#endif diff --git a/test/test_gpio_access.c b/test/test_gpio_access.c index 0f65a59..385695d 100644 --- a/test/test_gpio_access.c +++ b/test/test_gpio_access.c @@ -1,4 +1,5 @@ #include "unity.h" +#include "UnityHelper.h" #include "gpio_access.h" #include "p24HJ128GP202.h" #include <string.h> // for memset() @@ -177,6 +178,7 @@ void test_GPIO_ClearBit_should_clear_the_corresponding_SFR_bit_for_B3(void) void test_GPIO_ClearBit_should_clear_the_corresponding_SFR_bit_for_B4(void) { + TEST_FAIL(); // Create initial condition LATBbits.LATB4 = 1; // Call function under test diff --git a/test/test_led_control.c b/test/test_led_control.c index 0b59357..b9a2459 100644 --- a/test/test_led_control.c +++ b/test/test_led_control.c @@ -1,4 +1,5 @@ #include "unity.h" +#include "UnityHelper.h" #include "led_control.h" #include "mock_gpio_access.h" diff --git a/test/test_main.c b/test/test_main.c index 96c0ff6..1ca323c 100644 --- a/test/test_main.c +++ b/test/test_main.c @@ -1,4 +1,5 @@ #include "unity.h" +#include "UnityHelper.h" #include "main.h" #include "mock_system.h" #include "mock_led_control.h" diff --git a/test/test_system.c b/test/test_system.c index ade3073..b5efc22 100644 --- a/test/test_system.c +++ b/test/test_system.c @@ -1,4 +1,5 @@ #include "unity.h" +#include "UnityHelper.h" #include "system.h" void setUp(void) @@ -12,4 +13,6 @@ void tearDown(void) void test_ShouldAbortApp_should_return_false_for_now(void) { TEST_ASSERT_FALSE(ShouldAbortApp()); + } + From e026a24231303cdd875872ba0bb37317c9b8c817 Mon Sep 17 00:00:00 2001 From: Paul Jacobson <20469645+pajacobson@users.noreply.github.com> Date: Thu, 8 Dec 2022 14:22:54 +1100 Subject: [PATCH 10/22] Remove vendor --- ceedling | 3 - test/simulation/out.txt | 4 - test/simulation/sim_instructions.txt | 8 - vendor/ceedling/bin/ceedling | 350 --- vendor/ceedling/lib/ceedling.rb | 99 - .../lib/ceedling/build_invoker_utils.rb | 39 - vendor/ceedling/lib/ceedling/cacheinator.rb | 47 - .../lib/ceedling/cacheinator_helper.rb | 35 - vendor/ceedling/lib/ceedling/cmock_builder.rb | 15 - vendor/ceedling/lib/ceedling/configurator.rb | 382 --- .../lib/ceedling/configurator_builder.rb | 475 ---- .../lib/ceedling/configurator_plugins.rb | 131 - .../lib/ceedling/configurator_setup.rb | 128 - .../lib/ceedling/configurator_validator.rb | 193 -- vendor/ceedling/lib/ceedling/constants.rb | 99 - vendor/ceedling/lib/ceedling/defaults.rb | 471 ---- vendor/ceedling/lib/ceedling/dependinator.rb | 97 - vendor/ceedling/lib/ceedling/erb_wrapper.rb | 9 - vendor/ceedling/lib/ceedling/file_finder.rb | 149 -- .../lib/ceedling/file_finder_helper.rb | 56 - .../ceedling/lib/ceedling/file_path_utils.rb | 202 -- .../lib/ceedling/file_system_utils.rb | 69 - .../lib/ceedling/file_system_wrapper.rb | 10 - vendor/ceedling/lib/ceedling/file_wrapper.rb | 83 - vendor/ceedling/lib/ceedling/flaginator.rb | 74 - vendor/ceedling/lib/ceedling/generator.rb | 186 -- .../ceedling/lib/ceedling/generator_helper.rb | 40 - .../lib/ceedling/generator_test_results.rb | 100 - .../generator_test_results_sanity_checker.rb | 65 - .../lib/ceedling/generator_test_runner.rb | 58 - vendor/ceedling/lib/ceedling/loginator.rb | 31 - vendor/ceedling/lib/ceedling/makefile.rb | 46 - vendor/ceedling/lib/ceedling/objects.yml | 313 --- vendor/ceedling/lib/ceedling/par_map.rb | 19 - vendor/ceedling/lib/ceedling/plugin.rb | 80 - .../ceedling/lib/ceedling/plugin_builder.rb | 53 - .../ceedling/lib/ceedling/plugin_manager.rb | 107 - .../lib/ceedling/plugin_manager_helper.rb | 19 - .../lib/ceedling/plugin_reportinator.rb | 76 - .../ceedling/plugin_reportinator_helper.rb | 51 - .../ceedling/lib/ceedling/preprocessinator.rb | 56 - .../ceedling/preprocessinator_extractor.rb | 55 - .../ceedling/preprocessinator_file_handler.rb | 34 - .../lib/ceedling/preprocessinator_helper.rb | 50 - .../preprocessinator_includes_handler.rb | 189 -- .../lib/ceedling/project_config_manager.rb | 52 - .../lib/ceedling/project_file_loader.rb | 99 - vendor/ceedling/lib/ceedling/rake_utils.rb | 17 - vendor/ceedling/lib/ceedling/rake_wrapper.rb | 33 - vendor/ceedling/lib/ceedling/rakefile.rb | 85 - .../ceedling/lib/ceedling/release_invoker.rb | 98 - .../lib/ceedling/release_invoker_helper.rb | 19 - vendor/ceedling/lib/ceedling/reportinator.rb | 26 - vendor/ceedling/lib/ceedling/rules_cmock.rake | 9 - .../lib/ceedling/rules_preprocess.rake | 26 - .../ceedling/lib/ceedling/rules_release.rake | 99 - .../rules_release_deep_dependencies.rake | 15 - vendor/ceedling/lib/ceedling/rules_tests.rake | 73 - .../rules_tests_deep_dependencies.rake | 15 - vendor/ceedling/lib/ceedling/setupinator.rb | 53 - .../ceedling/lib/ceedling/stream_wrapper.rb | 28 - vendor/ceedling/lib/ceedling/streaminator.rb | 40 - .../lib/ceedling/streaminator_helper.rb | 15 - vendor/ceedling/lib/ceedling/system_utils.rb | 37 - .../ceedling/lib/ceedling/system_wrapper.rb | 80 - vendor/ceedling/lib/ceedling/target_loader.rb | 38 - vendor/ceedling/lib/ceedling/task_invoker.rb | 122 - vendor/ceedling/lib/ceedling/tasks_base.rake | 116 - .../lib/ceedling/tasks_filesystem.rake | 113 - .../ceedling/lib/ceedling/tasks_release.rake | 30 - .../tasks_release_deep_dependencies.rake | 9 - vendor/ceedling/lib/ceedling/tasks_tests.rake | 62 - .../tasks_tests_deep_dependencies.rake | 9 - .../ceedling/lib/ceedling/tasks_vendor.rake | 35 - .../lib/ceedling/test_includes_extractor.rb | 111 - vendor/ceedling/lib/ceedling/test_invoker.rb | 165 -- .../lib/ceedling/test_invoker_helper.rb | 32 - vendor/ceedling/lib/ceedling/tool_executor.rb | 229 -- .../lib/ceedling/tool_executor_helper.rb | 164 -- vendor/ceedling/lib/ceedling/verbosinator.rb | 10 - vendor/ceedling/lib/ceedling/version.rb | 54 - vendor/ceedling/lib/ceedling/yaml_wrapper.rb | 17 - vendor/ceedling/plugins/beep/README.md | 22 - vendor/ceedling/plugins/beep/lib/beep.rb | 40 - vendor/ceedling/plugins/bullseye/README.md | 76 - .../plugins/bullseye/assets/template.erb | 15 - .../ceedling/plugins/bullseye/bullseye.rake | 173 -- .../plugins/bullseye/config/defaults.yml | 57 - .../ceedling/plugins/bullseye/lib/bullseye.rb | 194 -- .../ceedling/plugins/colour_report/README.md | 20 - .../colour_report/lib/colour_report.rb | 16 - .../ceedling/plugins/command_hooks/README.md | 53 - .../command_hooks/lib/command_hooks.rb | 92 - .../plugins/compile_commands_json/README.md | 29 - .../lib/compile_commands_json.rb | 35 - .../ceedling/plugins/dependencies/README.md | 254 -- .../plugins/dependencies/config/defaults.yml | 5 - .../plugins/dependencies/dependencies.rake | 147 -- .../plugins/dependencies/lib/dependencies.rb | 237 -- .../plugins/fake_function_framework/README.md | 250 -- .../plugins/fake_function_framework/Rakefile | 19 - .../examples/fff_example/project.yml | 71 - .../examples/fff_example/rakefile.rb | 7 - .../examples/fff_example/src/bar.c | 1 - .../examples/fff_example/src/bar.h | 14 - .../examples/fff_example/src/custom_types.h | 6 - .../examples/fff_example/src/display.c | 7 - .../examples/fff_example/src/display.h | 16 - .../fff_example/src/event_processor.c | 93 - .../fff_example/src/event_processor.h | 11 - .../examples/fff_example/src/foo.c | 16 - .../examples/fff_example/src/foo.h | 8 - .../examples/fff_example/src/subfolder/zzz.c | 1 - .../examples/fff_example/src/subfolder/zzz.h | 6 - .../fff_example/test/test_event_processor.c | 155 -- .../examples/fff_example/test/test_foo.c | 47 - .../lib/fake_function_framework.rb | 87 - .../lib/fff_mock_generator.rb | 163 -- .../spec/fff_mock_header_generator_spec.rb | 304 --- .../spec/fff_mock_source_generator_spec.rb | 149 -- .../spec/header_generator.rb | 51 - .../spec/spec_helper.rb | 96 - .../src/fff_unity_helper.h | 33 - vendor/ceedling/plugins/gcov/README.md | 433 ---- .../ceedling/plugins/gcov/assets/template.erb | 15 - .../plugins/gcov/config/defaults_gcov.rb | 118 - vendor/ceedling/plugins/gcov/gcov.rake | 209 -- vendor/ceedling/plugins/gcov/lib/gcov.rb | 136 -- .../plugins/gcov/lib/gcov_constants.rb | 48 - .../plugins/gcov/lib/gcovr_reportinator.rb | 331 --- .../gcov/lib/reportgenerator_reportinator.rb | 195 -- .../plugins/gcov/lib/reportinator_helper.rb | 15 - .../plugins/json_tests_report/README.md | 36 - .../lib/json_tests_report.rb | 83 - .../plugins/junit_tests_report/README.md | 36 - .../lib/junit_tests_report.rb | 134 -- .../plugins/module_generator/README.md | 119 - .../config/module_generator.yml | 4 - .../module_generator/lib/module_generator.rb | 80 - .../module_generator/module_generator.rake | 62 - .../plugins/raw_output_report/README.md | 19 - .../lib/raw_output_report.rb | 41 - .../stdout_gtestlike_tests_report/README.md | 19 - .../assets/template.erb | 84 - .../assets/template.erb copy | 59 - .../config/stdout_gtestlike_tests_report.yml | 4 - .../lib/stdout_gtestlike_tests_report.rb | 43 - .../plugins/stdout_ide_tests_report/README.md | 18 - .../config/stdout_ide_tests_report.yml | 4 - .../lib/stdout_ide_tests_report.rb | 44 - .../stdout_pretty_tests_report/README.md | 20 - .../assets/template.erb | 59 - .../config/stdout_pretty_tests_report.yml | 4 - .../lib/stdout_pretty_tests_report.rb | 47 - vendor/ceedling/plugins/subprojects/README.md | 63 - .../plugins/subprojects/config/defaults.yml | 33 - .../plugins/subprojects/lib/subprojects.rb | 92 - .../plugins/subprojects/subprojects.rake | 78 - .../plugins/teamcity_tests_report/README.md | 18 - .../config/teamcity_tests_report.yml | 4 - .../lib/teamcity_tests_report.rb | 57 - .../plugins/warnings_report/README.md | 19 - .../warnings_report/lib/warnings_report.rb | 69 - .../plugins/xml_tests_report/README.md | 36 - .../xml_tests_report/lib/xml_tests_report.rb | 110 - .../vendor/c_exception/lib/CException.c | 46 - .../vendor/c_exception/lib/CException.h | 115 - .../vendor/c_exception/lib/meson.build | 11 - .../cmock/config/production_environment.rb | 12 - .../vendor/cmock/config/test_environment.rb | 16 - vendor/ceedling/vendor/cmock/lib/cmock.rb | 111 - .../ceedling/vendor/cmock/lib/cmock_config.rb | 174 -- .../vendor/cmock/lib/cmock_file_writer.rb | 47 - .../vendor/cmock/lib/cmock_generator.rb | 368 --- .../cmock/lib/cmock_generator_plugin_array.rb | 63 - .../lib/cmock_generator_plugin_callback.rb | 88 - .../lib/cmock_generator_plugin_cexception.rb | 50 - .../lib/cmock_generator_plugin_expect.rb | 100 - .../cmock_generator_plugin_expect_any_args.rb | 50 - .../lib/cmock_generator_plugin_ignore.rb | 88 - .../lib/cmock_generator_plugin_ignore_arg.rb | 42 - ...cmock_generator_plugin_ignore_stateless.rb | 85 - .../cmock_generator_plugin_return_thru_ptr.rb | 79 - .../vendor/cmock/lib/cmock_generator_utils.rb | 250 -- .../vendor/cmock/lib/cmock_header_parser.rb | 623 ----- .../vendor/cmock/lib/cmock_plugin_manager.rb | 50 - .../cmock/lib/cmock_unityhelper_parser.rb | 77 - vendor/ceedling/vendor/cmock/src/cmock.c | 216 -- vendor/ceedling/vendor/cmock/src/cmock.h | 47 - .../vendor/cmock/src/cmock_internals.h | 91 - vendor/ceedling/vendor/cmock/src/meson.build | 12 - vendor/ceedling/vendor/diy/lib/diy.rb | 403 ---- vendor/ceedling/vendor/diy/lib/diy/factory.rb | 36 - .../vendor/unity/auto/colour_prompt.rb | 119 - .../vendor/unity/auto/colour_reporter.rb | 39 - .../vendor/unity/auto/generate_config.yml | 36 - .../vendor/unity/auto/generate_module.rb | 313 --- .../vendor/unity/auto/generate_test_runner.rb | 511 ---- .../vendor/unity/auto/parse_output.rb | 322 --- .../ceedling/vendor/unity/auto/run_test.erb | 37 - .../vendor/unity/auto/stylize_as_junit.rb | 251 -- .../vendor/unity/auto/test_file_filter.rb | 25 - .../vendor/unity/auto/type_sanitizer.rb | 6 - .../vendor/unity/auto/unity_test_summary.py | 139 -- .../vendor/unity/auto/unity_test_summary.rb | 135 -- .../vendor/unity/auto/unity_to_junit.py | 146 -- vendor/ceedling/vendor/unity/src/meson.build | 11 - vendor/ceedling/vendor/unity/src/unity.c | 2110 ----------------- vendor/ceedling/vendor/unity/src/unity.h | 661 ------ .../vendor/unity/src/unity_internals.h | 1053 -------- 210 files changed, 22529 deletions(-) delete mode 100755 ceedling delete mode 100644 test/simulation/out.txt delete mode 100644 test/simulation/sim_instructions.txt delete mode 100755 vendor/ceedling/bin/ceedling delete mode 100644 vendor/ceedling/lib/ceedling.rb delete mode 100644 vendor/ceedling/lib/ceedling/build_invoker_utils.rb delete mode 100644 vendor/ceedling/lib/ceedling/cacheinator.rb delete mode 100644 vendor/ceedling/lib/ceedling/cacheinator_helper.rb delete mode 100644 vendor/ceedling/lib/ceedling/cmock_builder.rb delete mode 100644 vendor/ceedling/lib/ceedling/configurator.rb delete mode 100644 vendor/ceedling/lib/ceedling/configurator_builder.rb delete mode 100644 vendor/ceedling/lib/ceedling/configurator_plugins.rb delete mode 100644 vendor/ceedling/lib/ceedling/configurator_setup.rb delete mode 100644 vendor/ceedling/lib/ceedling/configurator_validator.rb delete mode 100644 vendor/ceedling/lib/ceedling/constants.rb delete mode 100644 vendor/ceedling/lib/ceedling/defaults.rb delete mode 100644 vendor/ceedling/lib/ceedling/dependinator.rb delete mode 100644 vendor/ceedling/lib/ceedling/erb_wrapper.rb delete mode 100644 vendor/ceedling/lib/ceedling/file_finder.rb delete mode 100644 vendor/ceedling/lib/ceedling/file_finder_helper.rb delete mode 100644 vendor/ceedling/lib/ceedling/file_path_utils.rb delete mode 100644 vendor/ceedling/lib/ceedling/file_system_utils.rb delete mode 100644 vendor/ceedling/lib/ceedling/file_system_wrapper.rb delete mode 100644 vendor/ceedling/lib/ceedling/file_wrapper.rb delete mode 100644 vendor/ceedling/lib/ceedling/flaginator.rb delete mode 100644 vendor/ceedling/lib/ceedling/generator.rb delete mode 100644 vendor/ceedling/lib/ceedling/generator_helper.rb delete mode 100644 vendor/ceedling/lib/ceedling/generator_test_results.rb delete mode 100644 vendor/ceedling/lib/ceedling/generator_test_results_sanity_checker.rb delete mode 100644 vendor/ceedling/lib/ceedling/generator_test_runner.rb delete mode 100644 vendor/ceedling/lib/ceedling/loginator.rb delete mode 100644 vendor/ceedling/lib/ceedling/makefile.rb delete mode 100644 vendor/ceedling/lib/ceedling/objects.yml delete mode 100644 vendor/ceedling/lib/ceedling/par_map.rb delete mode 100644 vendor/ceedling/lib/ceedling/plugin.rb delete mode 100644 vendor/ceedling/lib/ceedling/plugin_builder.rb delete mode 100644 vendor/ceedling/lib/ceedling/plugin_manager.rb delete mode 100644 vendor/ceedling/lib/ceedling/plugin_manager_helper.rb delete mode 100644 vendor/ceedling/lib/ceedling/plugin_reportinator.rb delete mode 100644 vendor/ceedling/lib/ceedling/plugin_reportinator_helper.rb delete mode 100644 vendor/ceedling/lib/ceedling/preprocessinator.rb delete mode 100644 vendor/ceedling/lib/ceedling/preprocessinator_extractor.rb delete mode 100644 vendor/ceedling/lib/ceedling/preprocessinator_file_handler.rb delete mode 100644 vendor/ceedling/lib/ceedling/preprocessinator_helper.rb delete mode 100644 vendor/ceedling/lib/ceedling/preprocessinator_includes_handler.rb delete mode 100644 vendor/ceedling/lib/ceedling/project_config_manager.rb delete mode 100644 vendor/ceedling/lib/ceedling/project_file_loader.rb delete mode 100644 vendor/ceedling/lib/ceedling/rake_utils.rb delete mode 100644 vendor/ceedling/lib/ceedling/rake_wrapper.rb delete mode 100644 vendor/ceedling/lib/ceedling/rakefile.rb delete mode 100644 vendor/ceedling/lib/ceedling/release_invoker.rb delete mode 100644 vendor/ceedling/lib/ceedling/release_invoker_helper.rb delete mode 100644 vendor/ceedling/lib/ceedling/reportinator.rb delete mode 100644 vendor/ceedling/lib/ceedling/rules_cmock.rake delete mode 100644 vendor/ceedling/lib/ceedling/rules_preprocess.rake delete mode 100644 vendor/ceedling/lib/ceedling/rules_release.rake delete mode 100644 vendor/ceedling/lib/ceedling/rules_release_deep_dependencies.rake delete mode 100644 vendor/ceedling/lib/ceedling/rules_tests.rake delete mode 100644 vendor/ceedling/lib/ceedling/rules_tests_deep_dependencies.rake delete mode 100644 vendor/ceedling/lib/ceedling/setupinator.rb delete mode 100644 vendor/ceedling/lib/ceedling/stream_wrapper.rb delete mode 100644 vendor/ceedling/lib/ceedling/streaminator.rb delete mode 100644 vendor/ceedling/lib/ceedling/streaminator_helper.rb delete mode 100644 vendor/ceedling/lib/ceedling/system_utils.rb delete mode 100644 vendor/ceedling/lib/ceedling/system_wrapper.rb delete mode 100644 vendor/ceedling/lib/ceedling/target_loader.rb delete mode 100644 vendor/ceedling/lib/ceedling/task_invoker.rb delete mode 100644 vendor/ceedling/lib/ceedling/tasks_base.rake delete mode 100644 vendor/ceedling/lib/ceedling/tasks_filesystem.rake delete mode 100644 vendor/ceedling/lib/ceedling/tasks_release.rake delete mode 100644 vendor/ceedling/lib/ceedling/tasks_release_deep_dependencies.rake delete mode 100644 vendor/ceedling/lib/ceedling/tasks_tests.rake delete mode 100644 vendor/ceedling/lib/ceedling/tasks_tests_deep_dependencies.rake delete mode 100644 vendor/ceedling/lib/ceedling/tasks_vendor.rake delete mode 100644 vendor/ceedling/lib/ceedling/test_includes_extractor.rb delete mode 100644 vendor/ceedling/lib/ceedling/test_invoker.rb delete mode 100644 vendor/ceedling/lib/ceedling/test_invoker_helper.rb delete mode 100644 vendor/ceedling/lib/ceedling/tool_executor.rb delete mode 100644 vendor/ceedling/lib/ceedling/tool_executor_helper.rb delete mode 100644 vendor/ceedling/lib/ceedling/verbosinator.rb delete mode 100644 vendor/ceedling/lib/ceedling/version.rb delete mode 100644 vendor/ceedling/lib/ceedling/yaml_wrapper.rb delete mode 100644 vendor/ceedling/plugins/beep/README.md delete mode 100644 vendor/ceedling/plugins/beep/lib/beep.rb delete mode 100644 vendor/ceedling/plugins/bullseye/README.md delete mode 100644 vendor/ceedling/plugins/bullseye/assets/template.erb delete mode 100644 vendor/ceedling/plugins/bullseye/bullseye.rake delete mode 100644 vendor/ceedling/plugins/bullseye/config/defaults.yml delete mode 100644 vendor/ceedling/plugins/bullseye/lib/bullseye.rb delete mode 100644 vendor/ceedling/plugins/colour_report/README.md delete mode 100644 vendor/ceedling/plugins/colour_report/lib/colour_report.rb delete mode 100644 vendor/ceedling/plugins/command_hooks/README.md delete mode 100644 vendor/ceedling/plugins/command_hooks/lib/command_hooks.rb delete mode 100644 vendor/ceedling/plugins/compile_commands_json/README.md delete mode 100644 vendor/ceedling/plugins/compile_commands_json/lib/compile_commands_json.rb delete mode 100644 vendor/ceedling/plugins/dependencies/README.md delete mode 100644 vendor/ceedling/plugins/dependencies/config/defaults.yml delete mode 100644 vendor/ceedling/plugins/dependencies/dependencies.rake delete mode 100644 vendor/ceedling/plugins/dependencies/lib/dependencies.rb delete mode 100644 vendor/ceedling/plugins/fake_function_framework/README.md delete mode 100644 vendor/ceedling/plugins/fake_function_framework/Rakefile delete mode 100644 vendor/ceedling/plugins/fake_function_framework/examples/fff_example/project.yml delete mode 100644 vendor/ceedling/plugins/fake_function_framework/examples/fff_example/rakefile.rb delete mode 100644 vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/bar.c delete mode 100644 vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/bar.h delete mode 100644 vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/custom_types.h delete mode 100644 vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/display.c delete mode 100644 vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/display.h delete mode 100644 vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/event_processor.c delete mode 100644 vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/event_processor.h delete mode 100644 vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/foo.c delete mode 100644 vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/foo.h delete mode 100644 vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/subfolder/zzz.c delete mode 100644 vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/subfolder/zzz.h delete mode 100644 vendor/ceedling/plugins/fake_function_framework/examples/fff_example/test/test_event_processor.c delete mode 100644 vendor/ceedling/plugins/fake_function_framework/examples/fff_example/test/test_foo.c delete mode 100644 vendor/ceedling/plugins/fake_function_framework/lib/fake_function_framework.rb delete mode 100644 vendor/ceedling/plugins/fake_function_framework/lib/fff_mock_generator.rb delete mode 100644 vendor/ceedling/plugins/fake_function_framework/spec/fff_mock_header_generator_spec.rb delete mode 100644 vendor/ceedling/plugins/fake_function_framework/spec/fff_mock_source_generator_spec.rb delete mode 100644 vendor/ceedling/plugins/fake_function_framework/spec/header_generator.rb delete mode 100644 vendor/ceedling/plugins/fake_function_framework/spec/spec_helper.rb delete mode 100644 vendor/ceedling/plugins/fake_function_framework/src/fff_unity_helper.h delete mode 100644 vendor/ceedling/plugins/gcov/README.md delete mode 100644 vendor/ceedling/plugins/gcov/assets/template.erb delete mode 100644 vendor/ceedling/plugins/gcov/config/defaults_gcov.rb delete mode 100644 vendor/ceedling/plugins/gcov/gcov.rake delete mode 100644 vendor/ceedling/plugins/gcov/lib/gcov.rb delete mode 100644 vendor/ceedling/plugins/gcov/lib/gcov_constants.rb delete mode 100644 vendor/ceedling/plugins/gcov/lib/gcovr_reportinator.rb delete mode 100644 vendor/ceedling/plugins/gcov/lib/reportgenerator_reportinator.rb delete mode 100644 vendor/ceedling/plugins/gcov/lib/reportinator_helper.rb delete mode 100644 vendor/ceedling/plugins/json_tests_report/README.md delete mode 100644 vendor/ceedling/plugins/json_tests_report/lib/json_tests_report.rb delete mode 100644 vendor/ceedling/plugins/junit_tests_report/README.md delete mode 100644 vendor/ceedling/plugins/junit_tests_report/lib/junit_tests_report.rb delete mode 100644 vendor/ceedling/plugins/module_generator/README.md delete mode 100644 vendor/ceedling/plugins/module_generator/config/module_generator.yml delete mode 100644 vendor/ceedling/plugins/module_generator/lib/module_generator.rb delete mode 100644 vendor/ceedling/plugins/module_generator/module_generator.rake delete mode 100644 vendor/ceedling/plugins/raw_output_report/README.md delete mode 100644 vendor/ceedling/plugins/raw_output_report/lib/raw_output_report.rb delete mode 100644 vendor/ceedling/plugins/stdout_gtestlike_tests_report/README.md delete mode 100644 vendor/ceedling/plugins/stdout_gtestlike_tests_report/assets/template.erb delete mode 100644 vendor/ceedling/plugins/stdout_gtestlike_tests_report/assets/template.erb copy delete mode 100644 vendor/ceedling/plugins/stdout_gtestlike_tests_report/config/stdout_gtestlike_tests_report.yml delete mode 100644 vendor/ceedling/plugins/stdout_gtestlike_tests_report/lib/stdout_gtestlike_tests_report.rb delete mode 100644 vendor/ceedling/plugins/stdout_ide_tests_report/README.md delete mode 100644 vendor/ceedling/plugins/stdout_ide_tests_report/config/stdout_ide_tests_report.yml delete mode 100644 vendor/ceedling/plugins/stdout_ide_tests_report/lib/stdout_ide_tests_report.rb delete mode 100644 vendor/ceedling/plugins/stdout_pretty_tests_report/README.md delete mode 100644 vendor/ceedling/plugins/stdout_pretty_tests_report/assets/template.erb delete mode 100644 vendor/ceedling/plugins/stdout_pretty_tests_report/config/stdout_pretty_tests_report.yml delete mode 100644 vendor/ceedling/plugins/stdout_pretty_tests_report/lib/stdout_pretty_tests_report.rb delete mode 100644 vendor/ceedling/plugins/subprojects/README.md delete mode 100644 vendor/ceedling/plugins/subprojects/config/defaults.yml delete mode 100644 vendor/ceedling/plugins/subprojects/lib/subprojects.rb delete mode 100644 vendor/ceedling/plugins/subprojects/subprojects.rake delete mode 100644 vendor/ceedling/plugins/teamcity_tests_report/README.md delete mode 100644 vendor/ceedling/plugins/teamcity_tests_report/config/teamcity_tests_report.yml delete mode 100644 vendor/ceedling/plugins/teamcity_tests_report/lib/teamcity_tests_report.rb delete mode 100644 vendor/ceedling/plugins/warnings_report/README.md delete mode 100644 vendor/ceedling/plugins/warnings_report/lib/warnings_report.rb delete mode 100644 vendor/ceedling/plugins/xml_tests_report/README.md delete mode 100644 vendor/ceedling/plugins/xml_tests_report/lib/xml_tests_report.rb delete mode 100644 vendor/ceedling/vendor/c_exception/lib/CException.c delete mode 100644 vendor/ceedling/vendor/c_exception/lib/CException.h delete mode 100644 vendor/ceedling/vendor/c_exception/lib/meson.build delete mode 100644 vendor/ceedling/vendor/cmock/config/production_environment.rb delete mode 100644 vendor/ceedling/vendor/cmock/config/test_environment.rb delete mode 100644 vendor/ceedling/vendor/cmock/lib/cmock.rb delete mode 100644 vendor/ceedling/vendor/cmock/lib/cmock_config.rb delete mode 100644 vendor/ceedling/vendor/cmock/lib/cmock_file_writer.rb delete mode 100644 vendor/ceedling/vendor/cmock/lib/cmock_generator.rb delete mode 100644 vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_array.rb delete mode 100644 vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_callback.rb delete mode 100644 vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_cexception.rb delete mode 100644 vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_expect.rb delete mode 100644 vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_expect_any_args.rb delete mode 100644 vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_ignore.rb delete mode 100644 vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_ignore_arg.rb delete mode 100644 vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_ignore_stateless.rb delete mode 100644 vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_return_thru_ptr.rb delete mode 100644 vendor/ceedling/vendor/cmock/lib/cmock_generator_utils.rb delete mode 100644 vendor/ceedling/vendor/cmock/lib/cmock_header_parser.rb delete mode 100644 vendor/ceedling/vendor/cmock/lib/cmock_plugin_manager.rb delete mode 100644 vendor/ceedling/vendor/cmock/lib/cmock_unityhelper_parser.rb delete mode 100644 vendor/ceedling/vendor/cmock/src/cmock.c delete mode 100644 vendor/ceedling/vendor/cmock/src/cmock.h delete mode 100644 vendor/ceedling/vendor/cmock/src/cmock_internals.h delete mode 100644 vendor/ceedling/vendor/cmock/src/meson.build delete mode 100644 vendor/ceedling/vendor/diy/lib/diy.rb delete mode 100644 vendor/ceedling/vendor/diy/lib/diy/factory.rb delete mode 100644 vendor/ceedling/vendor/unity/auto/colour_prompt.rb delete mode 100644 vendor/ceedling/vendor/unity/auto/colour_reporter.rb delete mode 100644 vendor/ceedling/vendor/unity/auto/generate_config.yml delete mode 100644 vendor/ceedling/vendor/unity/auto/generate_module.rb delete mode 100644 vendor/ceedling/vendor/unity/auto/generate_test_runner.rb delete mode 100644 vendor/ceedling/vendor/unity/auto/parse_output.rb delete mode 100644 vendor/ceedling/vendor/unity/auto/run_test.erb delete mode 100644 vendor/ceedling/vendor/unity/auto/stylize_as_junit.rb delete mode 100644 vendor/ceedling/vendor/unity/auto/test_file_filter.rb delete mode 100644 vendor/ceedling/vendor/unity/auto/type_sanitizer.rb delete mode 100644 vendor/ceedling/vendor/unity/auto/unity_test_summary.py delete mode 100644 vendor/ceedling/vendor/unity/auto/unity_test_summary.rb delete mode 100644 vendor/ceedling/vendor/unity/auto/unity_to_junit.py delete mode 100644 vendor/ceedling/vendor/unity/src/meson.build delete mode 100644 vendor/ceedling/vendor/unity/src/unity.c delete mode 100644 vendor/ceedling/vendor/unity/src/unity.h delete mode 100644 vendor/ceedling/vendor/unity/src/unity_internals.h diff --git a/ceedling b/ceedling deleted file mode 100755 index 5393085..0000000 --- a/ceedling +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -ruby vendor/ceedling/bin/ceedling $* diff --git a/test/simulation/out.txt b/test/simulation/out.txt deleted file mode 100644 index 6a3ad8f..0000000 --- a/test/simulation/out.txt +++ /dev/null @@ -1,4 +0,0 @@ -test_system.c:12:test_ShouldAbortApp_should_return_false_for_now:PASS ------------------------ -1 Tests 0 Failures 0 Ignored -OK diff --git a/test/simulation/sim_instructions.txt b/test/simulation/sim_instructions.txt deleted file mode 100644 index 5fa7931..0000000 --- a/test/simulation/sim_instructions.txt +++ /dev/null @@ -1,8 +0,0 @@ -Device PIC24HJ128GP202 -Hwtool SIM - -set uart1io.output window -set uart1io.uartioenabled true - -# Only Device and HWTool and "set" options should be added to this file. -# sim_test_fixture.rb handles loading, programming and running test code. diff --git a/vendor/ceedling/bin/ceedling b/vendor/ceedling/bin/ceedling deleted file mode 100755 index d110f3d..0000000 --- a/vendor/ceedling/bin/ceedling +++ /dev/null @@ -1,350 +0,0 @@ -#!/usr/bin/env ruby - -#these are always used -require 'rubygems' -require 'fileutils' - -# Check for the main project file (either the one defined in the ENV or the default) -main_filepath = ENV['CEEDLING_MAIN_PROJECT_FILE'] -project_found = (!main_filepath.nil? && File.exists?(main_filepath)) -if (!project_found) - main_filepath = "project.yml" - project_found = File.exists?(main_filepath) -end - -def is_windows? - return ((RbConfig::CONFIG['host_os'] =~ /mswin|mingw/) ? true : false) if defined?(RbConfig) - return ((Config::CONFIG['host_os'] =~ /mswin|mingw/) ? true : false) -end - -unless (project_found) -#===================================== We Do Not Have A Project ================================================ - - puts "Welcome to Ceedling!" - require 'thor' - - def here - File.dirname(__FILE__) + "/.." - end - - class CeedlingTasks < Thor - include Thor::Actions - - desc "new PROJECT_NAME", "create a new ceedling project" - method_option :docs, :type => :boolean, :default => false, :desc => "Add docs in project vendor directory" - method_option :local, :type => :boolean, :default => false, :desc => "Create a copy of Ceedling in the project vendor directory" - method_option :gitignore, :type => :boolean, :default => false, :desc => "Create a gitignore file for ignoring ceedling generated files" - method_option :no_configs, :type => :boolean, :default => false, :desc => "Don't install starter configuration files" - method_option :noconfigs, :type => :boolean, :default => false - - #deprecated: - method_option :no_docs, :type => :boolean, :default => false - method_option :nodocs, :type => :boolean, :default => false - method_option :as_gem, :type => :boolean, :default => false - method_option :asgem, :type => :boolean, :default => false - method_option :with_ignore, :type => :boolean, :default => false - method_option :withignore, :type => :boolean, :default => false - def new(name, silent = false) - copy_assets_and_create_structure(name, silent, false, options) - end - - desc "upgrade PROJECT_NAME", "upgrade ceedling for a project (not req'd if gem used)" - def upgrade(name, silent = false) - as_local = true - begin - require "yaml" - as_local = (YAML.load_file(File.join(name, "project.yml"))[:project][:which_ceedling] != 'gem') - rescue - raise "ERROR: Could not find valid project file '#{yaml_path}'" - end - found_docs = File.exists?( File.join(name, "docs", "CeedlingPacket.md") ) - copy_assets_and_create_structure(name, silent, true, {:upgrade => true, :no_configs => true, :local => as_local, :docs => found_docs}) - end - - no_commands do - def copy_assets_and_create_structure(name, silent=false, force=false, options = {}) - - puts "WARNING: --no_docs deprecated. It is now the default. Specify -docs if you want docs installed." if (options[:no_docs] || options[:nodocs]) - puts "WARNING: --as_gem deprecated. It is now the default. Specify -local if you want ceedling installed to this project." if (options[:as_gem] || options[:asgem]) - puts "WARNING: --with_ignore deprecated. It is now called -gitignore" if (options[:with_ignore] || options[:with_ignore]) - - use_docs = options[:docs] || false - use_configs = !(options[:no_configs] || options[:noconfigs] || false) - use_gem = !(options[:local]) - use_ignore = options[:gitignore] || false - is_upgrade = options[:upgrade] || false - - ceedling_path = File.join(name, 'vendor', 'ceedling') - source_path = File.join(name, 'src') - test_path = File.join(name, 'test') - test_support_path = File.join(name, 'test/support') - - # If it's not an upgrade, make sure we have the paths we expect - if (!is_upgrade) - [source_path, test_path, test_support_path].each do |d| - FileUtils.mkdir_p d - end - end - - # Genarate gitkeep in test support path - FileUtils.touch(File.join(test_support_path, '.gitkeep')) - - # If documentation requested, create a place to dump them and do so - doc_path = "" - if use_docs - doc_path = use_gem ? File.join(name, 'docs') : File.join(ceedling_path, 'docs') - FileUtils.mkdir_p doc_path - - in_doc_path = lambda {|f| File.join(doc_path, f)} - - # Add documentation from main projects to list - doc_files = {} - ['docs','vendor/unity/docs','vendor/cmock/docs','vendor/cexception/docs'].each do |p| - Dir[ File.expand_path(File.join(here, p, '*.md')) ].each do |f| - doc_files[ File.basename(f) ] = f unless(doc_files.include? f) - end - end - - # Add documentation from plugins to list - Dir[ File.join(here, 'plugins/**/README.md') ].each do |plugin_path| - k = "plugin_" + plugin_path.split(/\\|\//)[-2] + ".md" - doc_files[ k ] = File.expand_path(plugin_path) - end - - # Copy all documentation - doc_files.each_pair do |k, v| - copy_file(v, in_doc_path.call(k), :force => force) - end - end - - # If installed locally to project, copy ceedling, unity, cmock, & supports to vendor - unless use_gem - FileUtils.mkdir_p ceedling_path - - #copy full folders from ceedling gem into project - %w{plugins lib bin}.map do |f| - {:src => f, :dst => File.join(ceedling_path, f)} - end.each do |f| - directory(f[:src], f[:dst], :force => force) - end - - # mark ceedling as an executable - File.chmod(0755, File.join(ceedling_path, 'bin', 'ceedling')) unless is_windows? - - #copy necessary subcomponents from ceedling gem into project - sub_components = [ - {:src => 'vendor/c_exception/lib/', :dst => 'vendor/c_exception/lib'}, - {:src => 'vendor/cmock/config/', :dst => 'vendor/cmock/config'}, - {:src => 'vendor/cmock/lib/', :dst => 'vendor/cmock/lib'}, - {:src => 'vendor/cmock/src/', :dst => 'vendor/cmock/src'}, - {:src => 'vendor/diy/lib', :dst => 'vendor/diy/lib'}, - {:src => 'vendor/unity/auto/', :dst => 'vendor/unity/auto'}, - {:src => 'vendor/unity/src/', :dst => 'vendor/unity/src'}, - ] - - sub_components.each do |c| - directory(c[:src], File.join(ceedling_path, c[:dst]), :force => force) - end - end - - # We're copying in a configuration file if we haven't said not to - if (use_configs) - dst_yaml = File.join(name, 'project.yml') - src_yaml = if use_gem - File.join(here, 'assets', 'project_as_gem.yml') - else - if is_windows? - copy_file(File.join('assets', 'ceedling.cmd'), File.join(name, 'ceedling.cmd'), :force => force) - else - copy_file(File.join('assets', 'ceedling'), File.join(name, 'ceedling'), :force => force) - File.chmod(0755, File.join(name, 'ceedling')) - end - File.join(here, 'assets', 'project_with_guts.yml') - end - - # Perform the actual clone of the config file, while updating the version - File.open(dst_yaml,'w') do |dst| - require File.expand_path(File.join(File.dirname(__FILE__),"..","lib","ceedling","version.rb")) - dst << File.read(src_yaml).gsub(":ceedling_version: '?'",":ceedling_version: #{Ceedling::Version::CEEDLING}") - puts " create #{dst_yaml}" - end - end - - # Copy the gitignore file if requested - if (use_ignore) - copy_file(File.join('assets', 'default_gitignore'), File.join(name, '.gitignore'), :force => force) - end - - unless silent - puts "\n" - puts "Project '#{name}' #{force ? "upgraded" : "created"}!" - puts " - Tool documentation is located in #{doc_path}" if use_docs - puts " - Execute 'ceedling help' from #{name} to view available test & build tasks" - puts '' - end - end - end - - desc "examples", "list available example projects" - def examples() - puts "Available sample projects:" - FileUtils.cd(File.join(here, "examples")) do - Dir["*"].each {|proj| puts " #{proj}"} - end - end - - desc "example PROJ_NAME [DEST]", "new specified example project (in DEST, if specified)" - def example(proj_name, dest=nil) - if dest.nil? then dest = proj_name end - - copy_assets_and_create_structure(dest, true, false, {:local=>true, :docs=>true}) - - dest_src = File.join(dest,'src') - dest_test = File.join(dest,'test') - dest_project = File.join(dest,'project.yml') - - directory "examples/#{proj_name}/src", dest_src - directory "examples/#{proj_name}/test", dest_test - remove_file dest_project - copy_file "examples/#{proj_name}/project.yml", dest_project - - puts "\n" - puts "Example project '#{proj_name}' created!" - puts " - Tool documentation is located in vendor/ceedling/docs" - puts " - Execute 'ceedling help' to view available test & build tasks" - puts '' - end - - desc "version", "return the version of the tools installed" - def version() - require File.expand_path(File.join(File.dirname(__FILE__),"..","lib","ceedling","version.rb")) - puts " Ceedling:: #{Ceedling::Version::CEEDLING}" - puts " CMock:: #{Ceedling::Version::CMOCK}" - puts " Unity:: #{Ceedling::Version::UNITY}" - puts " CException:: #{Ceedling::Version::CEXCEPTION}" - end - end - - if (ARGV[0] =~ /^\-T$/) - puts "\n(No Project Detected, Therefore Showing Options to Create Projects)" - CeedlingTasks.tasks.each_pair do |k,v| - puts v.usage.ljust(25,' ') + v.description - end - puts "\n" - else - CeedlingTasks.source_root here - CeedlingTasks.start - end - -#===================================== We Have A Project Already ================================================ -else - require 'yaml' - require 'rbconfig' - - #determine platform - platform = begin - case(RbConfig::CONFIG['host_os']) - when /mswin|mingw|cygwin/i - :mswin - when /darwin/ - :osx - else - :linux - end - rescue - :linux - end - - #create our default meta-runner option set - options = { - :pretest => nil, - :args => [], - :add_path => [], - :path_connector => (platform == :mswin) ? ";" : ":", - :graceful_fail => false, - :which_ceedling => (Dir.exists?("vendor/ceedling") ? "vendor/ceedling" : 'gem'), - :default_tasks => [ 'test:all' ], - :list_tasks => false - } - - #guess that we need a special script file first if it exists - if (platform == :mswin) - options[:pretest] = File.exists?("#{ platform.to_s }_setup.bat") ? "#{ platform.to_s }_setup.bat" : nil - else - options[:pretest] = File.exists?("#{ platform.to_s }_setup.sh") ? "source #{ platform.to_s }_setup.sh" : nil - end - - #merge in project settings if they can be found here - yaml_options = YAML.load_file(main_filepath) - if (yaml_options[:paths]) - options[:add_path] = yaml_options[:paths][:tools] || [] - else - options[:add_path] = [] - end - options[:graceful_fail] = yaml_options[:graceful_fail] if yaml_options[:graceful_fail] - options[:which_ceedling] = yaml_options[:project][:which_ceedling] if (yaml_options[:project] && yaml_options[:project][:which_ceedling]) - options[:default_tasks] = yaml_options[:default_tasks] if yaml_options[:default_tasks] - - #sort through command line options - ARGV.each do |v| - case(v) - when /^(?:new|examples?|templates?)$/ - puts "\nOops. You called ceedling with argument '#{v}'.\n" + - " This is an operation that will create a new project... \n" + - " but it looks like you're already in a project. If you really \n" + - " want to do this, try moving to an empty folder.\n\n" - abort - when /^help$/ - options[:list_tasks] = true - when /^-T$/ - options[:list_tasks] = true - when /^--tasks$/ - options[:list_tasks] = true - when /^project:(\w+)/ - ENV['CEEDLING_USER_PROJECT_FILE'] = "#{$1}.yml" - else - options[:args].push(v) - end - end - - #add to the path - if (options[:add_path] && !options[:add_path].empty?) - path = ENV["PATH"] - options[:add_path].each do |p| - f = File.expand_path(File.dirname(__FILE__),p) - path = (f + options[:path_connector] + path) unless path.include? f - end - ENV["PATH"] = path - end - - # Load Ceedling (either through the rakefile OR directly) - if (File.exists?("rakefile.rb")) - load 'rakefile.rb' - else - if (options[:which_ceedling] == 'gem') - require 'ceedling' - else - load "#{options[:which_ceedling]}/lib/ceedling.rb" - end - Ceedling.load_project - end - - Rake.application.standard_exception_handling do - if options[:list_tasks] - # Display helpful task list when requested. This required us to dig into Rake internals a bit - Rake.application.define_singleton_method(:name=) {|n| @name = n} - Rake.application.name = 'ceedling' - Rake.application.options.show_tasks = :tasks - Rake.application.options.show_task_pattern = /^(?!.*build).*$/ - Rake.application.display_tasks_and_comments() - else - task :default => options[:default_tasks] - - # Run our Tasks! - Rake.application.collect_command_line_tasks(options[:args]) - Rake.application.top_level - end - end - true -#=================================================================================================================== -end diff --git a/vendor/ceedling/lib/ceedling.rb b/vendor/ceedling/lib/ceedling.rb deleted file mode 100644 index 7f34002..0000000 --- a/vendor/ceedling/lib/ceedling.rb +++ /dev/null @@ -1,99 +0,0 @@ -## -# This module defines the interface for interacting with and loading a project -# with Ceedling. -module Ceedling - ## - # Returns the location where the gem is installed. - # === Return - # _String_ - The location where the gem lives. - def self.location - File.join( File.dirname(__FILE__), '..') - end - - ## - # Return the path to the "built-in" plugins. - # === Return - # _String_ - The path where the default plugins live. - def self.load_path - File.join( self.location, 'plugins') - end - - ## - # Return the path to the Ceedling Rakefile - # === Return - # _String_ - def self.rakefile - File.join( self.location, 'lib', 'ceedling', 'rakefile.rb' ) - end - - ## - # This method selects the project file that Ceedling will use by setting the - # CEEDLING_MAIN_PROJECT_FILE environment variable before loading the ceedling - # rakefile. A path supplied as an argument to this method will override the - # current value of the environment variable. If no path is supplied as an - # argument then the existing value of the environment variable is used. If - # the environment variable has not been set and no argument has been supplied - # then a default path of './project.yml' will be used. - # - # === Arguments - # +options+ _Hash_:: - # A hash containing the options for ceedling. Currently the following - # options are supported: - # * +config+ - The path to the project YAML configuration file. - # * +root+ - The root of the project directory. - # * +prefix+ - A prefix to prepend to plugin names in order to determine the - # corresponding gem name. - # * +plugins+ - The list of ceedling plugins to load - def self.load_project(options = {}) - # Make sure our path to the yaml file is setup - if options.has_key? :config - ENV['CEEDLING_MAIN_PROJECT_FILE'] = options[:config] - elsif ENV['CEEDLING_MAIN_PROJECT_FILE'].nil? - ENV['CEEDLING_MAIN_PROJECT_FILE'] = './project.yml' - end - - # Register the plugins - if options.has_key? :plugins - options[:plugins].each do |plugin| - register_plugin( plugin, options[:prefix] ) - end - end - - # Define the root of the project if specified - Object.const_set('PROJECT_ROOT', options[:root]) if options.has_key? :root - - # Load ceedling - load "#{self.rakefile}" - end - - ## - # Register a plugin for ceedling to use when a project is loaded. This method - # *must* be called prior to calling the _load_project_ method. - # - # This method is intended to be used for loading plugins distributed via the - # RubyGems mechanism. As such, the following gem structure is assumed for - # plugins. - # - # * The gem name must be prefixed with 'ceedling-' followed by the plugin - # name (ex. 'ceedling-bullseye') - # - # * The contents of the plugin must be isntalled into a subdirectory of - # the gem with the same name as the plugin (ex. 'bullseye/') - # - # === Arguments - # +name+ _String_:: The name of the plugin to load. - # +prefix+ _String_:: - # (optional, default = nil) The prefix to use for the full gem name. - def self.register_plugin(name, prefix=nil) - # Figure out the full name of the gem and location - prefix ||= 'ceedling-' - gem_name = prefix + name - gem_dir = Gem::Specification.find_by_name(gem_name).gem_dir() - - # Register the plugin with Ceedling - require 'ceedling/defaults' - DEFAULT_CEEDLING_CONFIG[:plugins][:enabled] << name - DEFAULT_CEEDLING_CONFIG[:plugins][:load_paths] << gem_dir - end -end - diff --git a/vendor/ceedling/lib/ceedling/build_invoker_utils.rb b/vendor/ceedling/lib/ceedling/build_invoker_utils.rb deleted file mode 100644 index 5727bca..0000000 --- a/vendor/ceedling/lib/ceedling/build_invoker_utils.rb +++ /dev/null @@ -1,39 +0,0 @@ -require 'ceedling/constants' - -## -# Utilities for raiser and reporting errors during building. -class BuildInvokerUtils - - constructor :configurator, :streaminator - - ## - # Processes exceptions and tries to display a useful message for the user. - # - # ==== Attributes - # - # * _exception_: The exception given by a rescue statement. - # * _context_: A symbol representing where in the build the exception - # occurs. - # * _test_build_: A bool to signify if the exception occurred while building - # from test or source. - # - def process_exception(exception, context, test_build=true) - if (exception.message =~ /Don't know how to build task '(.+)'/i) - error_header = "ERROR: Rake could not find file referenced in source" - error_header += " or test" if (test_build) - error_header += ": '#{$1}'. Possible stale dependency." - - @streaminator.stderr_puts( error_header ) - - if (@configurator.project_use_deep_dependencies) - help_message = "Try fixing #include statements or adding missing file. Then run '#{REFRESH_TASK_ROOT}#{context.to_s}' task and try again." - @streaminator.stderr_puts( help_message ) - end - - raise '' - else - raise exception - end - end - -end diff --git a/vendor/ceedling/lib/ceedling/cacheinator.rb b/vendor/ceedling/lib/ceedling/cacheinator.rb deleted file mode 100644 index 519a4aa..0000000 --- a/vendor/ceedling/lib/ceedling/cacheinator.rb +++ /dev/null @@ -1,47 +0,0 @@ - -class Cacheinator - - constructor :cacheinator_helper, :file_path_utils, :file_wrapper, :yaml_wrapper - - def cache_test_config(hash) - @yaml_wrapper.dump( @file_path_utils.form_test_build_cache_path( INPUT_CONFIGURATION_CACHE_FILE), hash ) - end - - def cache_release_config(hash) - @yaml_wrapper.dump( @file_path_utils.form_release_build_cache_path( INPUT_CONFIGURATION_CACHE_FILE ), hash ) - end - - - def diff_cached_test_file( filepath ) - cached_filepath = @file_path_utils.form_test_build_cache_path( filepath ) - - if (@file_wrapper.exist?( cached_filepath ) and (!@file_wrapper.compare( filepath, cached_filepath ))) - @file_wrapper.cp(filepath, cached_filepath, {:preserve => false}) - return filepath - elsif (!@file_wrapper.exist?( cached_filepath )) - @file_wrapper.cp(filepath, cached_filepath, {:preserve => false}) - return filepath - end - - return cached_filepath - end - - def diff_cached_test_config?(hash) - cached_filepath = @file_path_utils.form_test_build_cache_path(INPUT_CONFIGURATION_CACHE_FILE) - - return @cacheinator_helper.diff_cached_config?( cached_filepath, hash ) - end - - def diff_cached_test_defines?(files) - cached_filepath = @file_path_utils.form_test_build_cache_path(DEFINES_DEPENDENCY_CACHE_FILE) - - return @cacheinator_helper.diff_cached_defines?( cached_filepath, files ) - end - - def diff_cached_release_config?(hash) - cached_filepath = @file_path_utils.form_release_build_cache_path(INPUT_CONFIGURATION_CACHE_FILE) - - return @cacheinator_helper.diff_cached_config?( cached_filepath, hash ) - end - -end diff --git a/vendor/ceedling/lib/ceedling/cacheinator_helper.rb b/vendor/ceedling/lib/ceedling/cacheinator_helper.rb deleted file mode 100644 index 14e8a6e..0000000 --- a/vendor/ceedling/lib/ceedling/cacheinator_helper.rb +++ /dev/null @@ -1,35 +0,0 @@ - -class CacheinatorHelper - - constructor :file_wrapper, :yaml_wrapper - - def diff_cached_config?(cached_filepath, hash) - return false if ( not @file_wrapper.exist?(cached_filepath) ) - return true if (@yaml_wrapper.load(cached_filepath) != hash) - return false - end - - def diff_cached_defines?(cached_filepath, files) - changed_defines = false - current_defines = COLLECTION_DEFINES_TEST_AND_VENDOR.reject(&:empty?) - - current_dependencies = Hash[files.collect { |source| [source, current_defines.dup] }] - if not @file_wrapper.exist?(cached_filepath) - @yaml_wrapper.dump(cached_filepath, current_dependencies) - return changed_defines - end - - dependencies = @yaml_wrapper.load(cached_filepath) - common_dependencies = current_dependencies.select { |file, defines| dependencies.has_key?(file) } - - if dependencies.values_at(*common_dependencies.keys) != common_dependencies.values - changed_defines = true - end - - dependencies.merge!(current_dependencies) - @yaml_wrapper.dump(cached_filepath, dependencies) - - return changed_defines - end - -end diff --git a/vendor/ceedling/lib/ceedling/cmock_builder.rb b/vendor/ceedling/lib/ceedling/cmock_builder.rb deleted file mode 100644 index 4a74aa8..0000000 --- a/vendor/ceedling/lib/ceedling/cmock_builder.rb +++ /dev/null @@ -1,15 +0,0 @@ -require 'cmock' - -class CmockBuilder - - attr_accessor :cmock - - def setup - @cmock = nil - end - - def manufacture(cmock_config) - @cmock = CMock.new(cmock_config) - end - -end diff --git a/vendor/ceedling/lib/ceedling/configurator.rb b/vendor/ceedling/lib/ceedling/configurator.rb deleted file mode 100644 index 0ae4d04..0000000 --- a/vendor/ceedling/lib/ceedling/configurator.rb +++ /dev/null @@ -1,382 +0,0 @@ -require 'ceedling/defaults' -require 'ceedling/constants' -require 'ceedling/file_path_utils' -require 'deep_merge' - - - -class Configurator - - attr_reader :project_config_hash, :script_plugins, :rake_plugins - attr_accessor :project_logging, :project_debug, :project_verbosity, :sanity_checks - - constructor(:configurator_setup, :configurator_builder, :configurator_plugins, :cmock_builder, :yaml_wrapper, :system_wrapper) do - @project_logging = false - @project_debug = false - @project_verbosity = Verbosity::NORMAL - @sanity_checks = TestResultsSanityChecks::NORMAL - end - - def setup - # special copy of cmock config to provide to cmock for construction - @cmock_config_hash = {} - - # note: project_config_hash is an instance variable so constants and accessors created - # in eval() statements in build() have something of proper scope and persistence to reference - @project_config_hash = {} - @project_config_hash_backup = {} - - @script_plugins = [] - @rake_plugins = [] - end - - - def replace_flattened_config(config) - @project_config_hash.merge!(config) - @configurator_setup.build_constants_and_accessors(@project_config_hash, binding()) - end - - - def store_config - @project_config_hash_backup = @project_config_hash.clone - end - - - def restore_config - @project_config_hash = @project_config_hash_backup - @configurator_setup.build_constants_and_accessors(@project_config_hash, binding()) - end - - - def reset_defaults(config) - [:test_compiler, - :test_linker, - :test_fixture, - :test_includes_preprocessor, - :test_file_preprocessor, - :test_file_preprocessor_directives, - :test_dependencies_generator, - :release_compiler, - :release_assembler, - :release_linker, - :release_dependencies_generator].each do |tool| - config[:tools].delete(tool) if (not (config[:tools][tool].nil?)) - end - end - - - # The default values defined in defaults.rb (eg. DEFAULT_TOOLS_TEST) are populated - # into @param config - def populate_defaults(config) - new_config = DEFAULT_CEEDLING_CONFIG.deep_clone - new_config.deep_merge!(config) - config.replace(new_config) - - @configurator_builder.populate_defaults( config, DEFAULT_TOOLS_TEST ) - @configurator_builder.populate_defaults( config, DEFAULT_TOOLS_TEST_PREPROCESSORS ) if (config[:project][:use_test_preprocessor]) - @configurator_builder.populate_defaults( config, DEFAULT_TOOLS_TEST_DEPENDENCIES ) if (config[:project][:use_deep_dependencies]) - - @configurator_builder.populate_defaults( config, DEFAULT_TOOLS_RELEASE ) if (config[:project][:release_build]) - @configurator_builder.populate_defaults( config, DEFAULT_TOOLS_RELEASE_ASSEMBLER ) if (config[:project][:release_build] and config[:release_build][:use_assembly]) - @configurator_builder.populate_defaults( config, DEFAULT_TOOLS_RELEASE_DEPENDENCIES ) if (config[:project][:release_build] and config[:project][:use_deep_dependencies]) - end - - - def populate_unity_defaults(config) - unity = config[:unity] || {} - @runner_config = unity.merge(@runner_config || config[:test_runner] || {}) - end - - def populate_cmock_defaults(config) - # cmock has its own internal defaults handling, but we need to set these specific values - # so they're present for the build environment to access; - # note: these need to end up in the hash given to initialize cmock for this to be successful - cmock = config[:cmock] || {} - - # yes, we're duplicating the default mock_prefix in cmock, but it's because we need CMOCK_MOCK_PREFIX always available in Ceedling's environment - cmock[:mock_prefix] = 'Mock' if (cmock[:mock_prefix].nil?) - - # just because strict ordering is the way to go - cmock[:enforce_strict_ordering] = true if (cmock[:enforce_strict_ordering].nil?) - - cmock[:mock_path] = File.join(config[:project][:build_root], TESTS_BASE_PATH, 'mocks') if (cmock[:mock_path].nil?) - cmock[:verbosity] = @project_verbosity if (cmock[:verbosity].nil?) - - cmock[:plugins] = [] if (cmock[:plugins].nil?) - cmock[:plugins].map! { |plugin| plugin.to_sym } - cmock[:plugins] << (:cexception) if (!cmock[:plugins].include?(:cexception) and (config[:project][:use_exceptions])) - cmock[:plugins].uniq! - - cmock[:unity_helper] = false if (cmock[:unity_helper].nil?) - - if (cmock[:unity_helper]) - cmock[:unity_helper] = [cmock[:unity_helper]] if cmock[:unity_helper].is_a? String - cmock[:includes] += cmock[:unity_helper].map{|helper| File.basename(helper) } - cmock[:includes].uniq! - end - - @runner_config = cmock.merge(@runner_config || config[:test_runner] || {}) - - @cmock_builder.manufacture(cmock) - end - - - def get_runner_config - @runner_config - end - - - # grab tool names from yaml and insert into tool structures so available for error messages - # set up default values - def tools_setup(config) - config[:tools].each_key do |name| - tool = config[:tools][name] - - # populate name if not given - tool[:name] = name.to_s if (tool[:name].nil?) - - # handle inline ruby string substitution in executable - if (tool[:executable] =~ RUBY_STRING_REPLACEMENT_PATTERN) - tool[:executable].replace(@system_wrapper.module_eval(tool[:executable])) - end - - # populate stderr redirect option - tool[:stderr_redirect] = StdErrRedirect::NONE if (tool[:stderr_redirect].nil?) - - # populate background execution option - tool[:background_exec] = BackgroundExec::NONE if (tool[:background_exec].nil?) - - # populate optional option to control verification of executable in search paths - tool[:optional] = false if (tool[:optional].nil?) - end - end - - - def tools_supplement_arguments(config) - tools_name_prefix = 'tools_' - config[:tools].each_key do |name| - tool = @project_config_hash[(tools_name_prefix + name.to_s).to_sym] - - # smoosh in extra arguments if specified at top-level of config (useful for plugins & default gcc tools) - # arguments are squirted in at _end_ of list - top_level_tool = (tools_name_prefix + name.to_s).to_sym - if (not config[top_level_tool].nil?) - # adding and flattening is not a good idea: might over-flatten if there's array nesting in tool args - tool[:arguments].concat config[top_level_tool][:arguments] - end - end - end - - - def find_and_merge_plugins(config) - # plugins must be loaded before generic path evaluation & magic that happen later; - # perform path magic here as discrete step - config[:plugins][:load_paths].each do |path| - path.replace(@system_wrapper.module_eval(path)) if (path =~ RUBY_STRING_REPLACEMENT_PATTERN) - FilePathUtils::standardize(path) - end - - config[:plugins][:load_paths] << FilePathUtils::standardize(Ceedling.load_path) - config[:plugins][:load_paths].uniq! - - paths_hash = @configurator_plugins.add_load_paths(config) - - @rake_plugins = @configurator_plugins.find_rake_plugins(config, paths_hash) - @script_plugins = @configurator_plugins.find_script_plugins(config, paths_hash) - config_plugins = @configurator_plugins.find_config_plugins(config, paths_hash) - plugin_yml_defaults = @configurator_plugins.find_plugin_yml_defaults(config, paths_hash) - plugin_hash_defaults = @configurator_plugins.find_plugin_hash_defaults(config, paths_hash) - - config_plugins.each do |plugin| - plugin_config = @yaml_wrapper.load(plugin) - config.deep_merge(plugin_config) - end - - plugin_yml_defaults.each do |defaults| - @configurator_builder.populate_defaults( config, @yaml_wrapper.load(defaults) ) - end - - plugin_hash_defaults.each do |defaults| - @configurator_builder.populate_defaults( config, defaults ) - end - - # special plugin setting for results printing - config[:plugins][:display_raw_test_results] = true if (config[:plugins][:display_raw_test_results].nil?) - - paths_hash.each_pair { |name, path| config[:plugins][name] = path } - end - - - def merge_imports(config) - if config[:import] - if config[:import].is_a? Array - until config[:import].empty? - path = config[:import].shift - path = @system_wrapper.module_eval(path) if (path =~ RUBY_STRING_REPLACEMENT_PATTERN) - config.deep_merge!(@yaml_wrapper.load(path)) - end - else - config[:import].each_value do |path| - if !path.nil? - path = @system_wrapper.module_eval(path) if (path =~ RUBY_STRING_REPLACEMENT_PATTERN) - config.deep_merge!(@yaml_wrapper.load(path)) - end - end - end - end - config.delete(:import) - end - - - def eval_environment_variables(config) - config[:environment].each do |hash| - key = hash.keys[0] - value = hash[key] - items = [] - - interstitial = ((key == :path) ? File::PATH_SEPARATOR : '') - items = ((value.class == Array) ? hash[key] : [value]) - - items.each do |item| - if item.is_a? String and item =~ RUBY_STRING_REPLACEMENT_PATTERN - item.replace( @system_wrapper.module_eval( item ) ) - end - end - hash[key] = items.join( interstitial ) - - @system_wrapper.env_set( key.to_s.upcase, hash[key] ) - end - end - - - def eval_paths(config) - # [:plugins]:[load_paths] already handled - - paths = [ # individual paths that don't follow convention processed below - config[:project][:build_root], - config[:release_build][:artifacts]] - - eval_path_list( paths ) - - config[:paths].each_pair { |collection, paths| eval_path_list( paths ) } - - config[:files].each_pair { |collection, files| eval_path_list( files ) } - - # all other paths at secondary hash key level processed by convention: - # ex. [:toplevel][:foo_path] & [:toplevel][:bar_paths] are evaluated - config.each_pair { |parent, child| eval_path_list( collect_path_list( child ) ) } - end - - - def standardize_paths(config) - # [:plugins]:[load_paths] already handled - - paths = [ # individual paths that don't follow convention processed below - config[:project][:build_root], - config[:release_build][:artifacts]] # cmock path in case it was explicitly set in config - - paths.flatten.each { |path| FilePathUtils::standardize( path ) } - - config[:paths].each_pair do |collection, paths| - # ensure that list is an array (i.e. handle case of list being a single string, - # or a multidimensional array) - config[:paths][collection] = [paths].flatten.map{|path| FilePathUtils::standardize( path )} - end - - config[:files].each_pair { |collection, files| files.each{ |path| FilePathUtils::standardize( path ) } } - - config[:tools].each_pair { |tool, config| FilePathUtils::standardize( config[:executable] ) if (config.include? :executable) } - - # all other paths at secondary hash key level processed by convention: - # ex. [:toplevel][:foo_path] & [:toplevel][:bar_paths] are standardized - config.each_pair do |parent, child| - collect_path_list( child ).each { |path| FilePathUtils::standardize( path ) } - end - end - - - def validate(config) - # collect felonies and go straight to jail - raise if (not @configurator_setup.validate_required_sections( config )) - - # collect all misdemeanors, everybody on probation - blotter = [] - blotter << @configurator_setup.validate_required_section_values( config ) - blotter << @configurator_setup.validate_paths( config ) - blotter << @configurator_setup.validate_tools( config ) - blotter << @configurator_setup.validate_plugins( config ) - - raise if (blotter.include?( false )) - end - - - # create constants and accessors (attached to this object) from given hash - def build(config, *keys) - # create flattened & expanded configuration hash - built_config = @configurator_setup.build_project_config( config, @configurator_builder.flattenify( config ) ) - - @project_config_hash = built_config.clone - store_config() - - @configurator_setup.build_constants_and_accessors(built_config, binding()) - - # top-level keys disappear when we flatten, so create global constants & accessors to any specified keys - keys.each do |key| - hash = { key => config[key] } - @configurator_setup.build_constants_and_accessors(hash, binding()) - end - end - - - # add to constants and accessors as post build step - def build_supplement(config_base, config_more) - # merge in our post-build additions to base configuration hash - config_base.deep_merge!( config_more ) - - # flatten our addition hash - config_more_flattened = @configurator_builder.flattenify( config_more ) - - # merge our flattened hash with built hash from previous build - @project_config_hash.deep_merge!( config_more_flattened ) - store_config() - - # create more constants and accessors - @configurator_setup.build_constants_and_accessors(config_more_flattened, binding()) - - # recreate constants & update accessors with new merged, base values - config_more.keys.each do |key| - hash = { key => config_base[key] } - @configurator_setup.build_constants_and_accessors(hash, binding()) - end - end - - - def insert_rake_plugins(plugins) - plugins.each do |plugin| - @project_config_hash[:project_rakefile_component_files] << plugin - end - end - - ### private ### - - private - - def collect_path_list( container ) - paths = [] - container.each_key { |key| paths << container[key] if (key.to_s =~ /_path(s)?$/) } if (container.class == Hash) - return paths.flatten - end - - def eval_path_list( paths ) - if paths.kind_of?(Array) - paths = Array.new(paths) - end - - paths.flatten.each do |path| - path.replace( @system_wrapper.module_eval( path ) ) if (path =~ RUBY_STRING_REPLACEMENT_PATTERN) - end - end - - -end - diff --git a/vendor/ceedling/lib/ceedling/configurator_builder.rb b/vendor/ceedling/lib/ceedling/configurator_builder.rb deleted file mode 100644 index f202d8a..0000000 --- a/vendor/ceedling/lib/ceedling/configurator_builder.rb +++ /dev/null @@ -1,475 +0,0 @@ -require 'rubygems' -require 'rake' # for ext() method -require 'ceedling/file_path_utils' # for class methods -require 'ceedling/defaults' -require 'ceedling/constants' # for Verbosity constants class & base file paths - - - -class ConfiguratorBuilder - - constructor :file_system_utils, :file_wrapper, :system_wrapper - - - def build_global_constants(config) - config.each_pair do |key, value| - formatted_key = key.to_s.upcase - # undefine global constant if it already exists - Object.send(:remove_const, formatted_key.to_sym) if @system_wrapper.constants_include?(formatted_key) - # create global constant - Object.module_eval("#{formatted_key} = value") - end - end - - - def build_accessor_methods(config, context) - config.each_pair do |key, value| - # fill configurator object with accessor methods - eval("def #{key.to_s.downcase}() return @project_config_hash[:#{key.to_s}] end", context) - end - end - - - # create a flattened hash from the original configuration structure - def flattenify(config) - new_hash = {} - - config.each_key do | parent | - - # gracefully handle empty top-level entries - next if (config[parent].nil?) - - case config[parent] - when Array - config[parent].each do |hash| - key = "#{parent.to_s.downcase}_#{hash.keys[0].to_s.downcase}".to_sym - new_hash[key] = hash[hash.keys[0]] - end - when Hash - config[parent].each_pair do | child, value | - key = "#{parent.to_s.downcase}_#{child.to_s.downcase}".to_sym - new_hash[key] = value - end - # handle entries with no children, only values - else - new_hash["#{parent.to_s.downcase}".to_sym] = config[parent] - end - - end - - return new_hash - end - - - def populate_defaults(config, defaults) - defaults.keys.sort.each do |section| - defaults[section].keys.sort.each do |entry| - config[section] = {} if config[section].nil? - config[section][entry] = defaults[section][entry].deep_clone if (config[section][entry].nil?) - end - end - end - - - def clean(in_hash) - # ensure that include files inserted into test runners have file extensions & proper ones at that - in_hash[:test_runner_includes].map!{|include| include.ext(in_hash[:extension_header])} - end - - - def set_build_paths(in_hash) - out_hash = {} - - project_build_artifacts_root = File.join(in_hash[:project_build_root], 'artifacts') - project_build_tests_root = File.join(in_hash[:project_build_root], TESTS_BASE_PATH) - project_build_release_root = File.join(in_hash[:project_build_root], RELEASE_BASE_PATH) - - paths = [ - [:project_build_artifacts_root, project_build_artifacts_root, true ], - [:project_build_tests_root, project_build_tests_root, true ], - [:project_build_release_root, project_build_release_root, in_hash[:project_release_build] ], - - [:project_test_artifacts_path, File.join(project_build_artifacts_root, TESTS_BASE_PATH), true ], - [:project_test_runners_path, File.join(project_build_tests_root, 'runners'), true ], - [:project_test_results_path, File.join(project_build_tests_root, 'results'), true ], - [:project_test_build_output_path, File.join(project_build_tests_root, 'out'), true ], - [:project_test_build_output_asm_path, File.join(project_build_tests_root, 'out', 'asm'), true ], - [:project_test_build_output_c_path, File.join(project_build_tests_root, 'out', 'c'), true ], - [:project_test_build_cache_path, File.join(project_build_tests_root, 'cache'), true ], - [:project_test_dependencies_path, File.join(project_build_tests_root, 'dependencies'), true ], - - [:project_release_artifacts_path, File.join(project_build_artifacts_root, RELEASE_BASE_PATH), in_hash[:project_release_build] ], - [:project_release_build_cache_path, File.join(project_build_release_root, 'cache'), in_hash[:project_release_build] ], - [:project_release_build_output_path, File.join(project_build_release_root, 'out'), in_hash[:project_release_build] ], - [:project_release_build_output_asm_path, File.join(project_build_release_root, 'out', 'asm'), in_hash[:project_release_build] ], - [:project_release_build_output_c_path, File.join(project_build_release_root, 'out', 'c'), in_hash[:project_release_build] ], - [:project_release_dependencies_path, File.join(project_build_release_root, 'dependencies'), in_hash[:project_release_build] ], - - [:project_log_path, File.join(in_hash[:project_build_root], 'logs'), true ], - [:project_temp_path, File.join(in_hash[:project_build_root], 'temp'), true ], - - [:project_test_preprocess_includes_path, File.join(project_build_tests_root, 'preprocess/includes'), in_hash[:project_use_test_preprocessor] ], - [:project_test_preprocess_files_path, File.join(project_build_tests_root, 'preprocess/files'), in_hash[:project_use_test_preprocessor] ], - ] - - out_hash[:project_build_paths] = [] - - # fetch already set mock path - out_hash[:project_build_paths] << in_hash[:cmock_mock_path] if (in_hash[:project_use_mocks]) - - paths.each do |path| - build_path_name = path[0] - build_path = path[1] - build_path_add_condition = path[2] - - # insert path into build paths if associated with true condition - out_hash[:project_build_paths] << build_path if build_path_add_condition - # set path symbol name and path for each entry in paths array - out_hash[build_path_name] = build_path - end - - return out_hash - end - - - def set_force_build_filepaths(in_hash) - out_hash = {} - - out_hash[:project_test_force_rebuild_filepath] = File.join( in_hash[:project_test_dependencies_path], 'force_build' ) - out_hash[:project_release_force_rebuild_filepath] = File.join( in_hash[:project_release_dependencies_path], 'force_build' ) if (in_hash[:project_release_build]) - - return out_hash - end - - - def set_rakefile_components(in_hash) - out_hash = { - :project_rakefile_component_files => - [File.join(CEEDLING_LIB, 'ceedling', 'tasks_base.rake'), - File.join(CEEDLING_LIB, 'ceedling', 'tasks_filesystem.rake'), - File.join(CEEDLING_LIB, 'ceedling', 'tasks_tests.rake'), - File.join(CEEDLING_LIB, 'ceedling', 'tasks_vendor.rake'), - File.join(CEEDLING_LIB, 'ceedling', 'rules_tests.rake')]} - - out_hash[:project_rakefile_component_files] << File.join(CEEDLING_LIB, 'ceedling', 'rules_cmock.rake') if (in_hash[:project_use_mocks]) - out_hash[:project_rakefile_component_files] << File.join(CEEDLING_LIB, 'ceedling', 'rules_preprocess.rake') if (in_hash[:project_use_test_preprocessor]) - out_hash[:project_rakefile_component_files] << File.join(CEEDLING_LIB, 'ceedling', 'rules_tests_deep_dependencies.rake') if (in_hash[:project_use_deep_dependencies]) - out_hash[:project_rakefile_component_files] << File.join(CEEDLING_LIB, 'ceedling', 'tasks_tests_deep_dependencies.rake') if (in_hash[:project_use_deep_dependencies]) - - out_hash[:project_rakefile_component_files] << File.join(CEEDLING_LIB, 'ceedling', 'rules_release_deep_dependencies.rake') if (in_hash[:project_release_build] and in_hash[:project_use_deep_dependencies]) - out_hash[:project_rakefile_component_files] << File.join(CEEDLING_LIB, 'ceedling', 'rules_release.rake') if (in_hash[:project_release_build]) - out_hash[:project_rakefile_component_files] << File.join(CEEDLING_LIB, 'ceedling', 'tasks_release_deep_dependencies.rake') if (in_hash[:project_release_build] and in_hash[:project_use_deep_dependencies]) - out_hash[:project_rakefile_component_files] << File.join(CEEDLING_LIB, 'ceedling', 'tasks_release.rake') if (in_hash[:project_release_build]) - - return out_hash - end - - - def set_release_target(in_hash) - return {} if (not in_hash[:project_release_build]) - - release_target_file = ((in_hash[:release_build_output].nil?) ? (DEFAULT_RELEASE_TARGET_NAME.ext(in_hash[:extension_executable])) : in_hash[:release_build_output]) - release_map_file = ((in_hash[:release_build_output].nil?) ? (DEFAULT_RELEASE_TARGET_NAME.ext(in_hash[:extension_map])) : in_hash[:release_build_output].ext(in_hash[:extension_map])) - - return { - # tempted to make a helper method in file_path_utils? stop right there, pal. you'll introduce a cyclical dependency - :project_release_build_target => File.join(in_hash[:project_build_release_root], release_target_file), - :project_release_build_map => File.join(in_hash[:project_build_release_root], release_map_file) - } - end - - - def collect_project_options(in_hash) - options = [] - - in_hash[:project_options_paths].each do |path| - options << @file_wrapper.directory_listing( File.join(path, '*.yml') ) - end - - return { - :collection_project_options => options.flatten - } - end - - - def expand_all_path_globs(in_hash) - out_hash = {} - path_keys = [] - - in_hash.each_key do |key| - next if (not key.to_s[0..4] == 'paths') - path_keys << key - end - - # sorted to provide assured order of traversal in test calls on mocks - path_keys.sort.each do |key| - out_hash["collection_#{key.to_s}".to_sym] = @file_system_utils.collect_paths( in_hash[key] ) - end - - return out_hash - end - - - def collect_source_and_include_paths(in_hash) - return { - :collection_paths_source_and_include => - ( in_hash[:collection_paths_source] + - in_hash[:collection_paths_include] ).select {|x| File.directory?(x)} - } - end - - - def collect_source_include_vendor_paths(in_hash) - extra_paths = [] - extra_paths << File.join(in_hash[:cexception_vendor_path], CEXCEPTION_LIB_PATH) if (in_hash[:project_use_exceptions]) - - return { - :collection_paths_source_include_vendor => - in_hash[:collection_paths_source_and_include] + - extra_paths - } - end - - - def collect_test_support_source_include_paths(in_hash) - return { - :collection_paths_test_support_source_include => - (in_hash[:collection_paths_test] + - in_hash[:collection_paths_support] + - in_hash[:collection_paths_source] + - in_hash[:collection_paths_include] ).select {|x| File.directory?(x)} - } - end - - - def collect_vendor_paths(in_hash) - return {:collection_paths_vendor => get_vendor_paths(in_hash)} - end - - - def collect_test_support_source_include_vendor_paths(in_hash) - return { - :collection_paths_test_support_source_include_vendor => - get_vendor_paths(in_hash) + - in_hash[:collection_paths_test_support_source_include] - } - end - - - def collect_tests(in_hash) - all_tests = @file_wrapper.instantiate_file_list - - in_hash[:collection_paths_test].each do |path| - all_tests.include( File.join(path, "#{in_hash[:project_test_file_prefix]}*#{in_hash[:extension_source]}") ) - end - - @file_system_utils.revise_file_list( all_tests, in_hash[:files_test] ) - - return {:collection_all_tests => all_tests} - end - - - def collect_assembly(in_hash) - all_assembly = @file_wrapper.instantiate_file_list - - return {:collection_all_assembly => all_assembly} if ((not in_hash[:release_build_use_assembly]) && (not in_hash[:test_build_use_assembly])) - - # Sprinkle in all assembly files we can find in the source folders - in_hash[:collection_paths_source].each do |path| - all_assembly.include( File.join(path, "*#{in_hash[:extension_assembly]}") ) - end - - # Also add all assembly files we can find in the support folders - in_hash[:collection_paths_support].each do |path| - all_assembly.include( File.join(path, "*#{in_hash[:extension_assembly]}") ) - end - - # Also add files that we are explicitly adding via :files:assembly: section - @file_system_utils.revise_file_list( all_assembly, in_hash[:files_assembly] ) - - return {:collection_all_assembly => all_assembly} - end - - - def collect_source(in_hash) - all_source = @file_wrapper.instantiate_file_list - in_hash[:collection_paths_source].each do |path| - if File.exists?(path) and not File.directory?(path) - all_source.include( path ) - else - all_source.include( File.join(path, "*#{in_hash[:extension_source]}") ) - end - end - @file_system_utils.revise_file_list( all_source, in_hash[:files_source] ) - - return {:collection_all_source => all_source} - end - - - def collect_headers(in_hash) - all_headers = @file_wrapper.instantiate_file_list - - paths = - in_hash[:collection_paths_test] + - in_hash[:collection_paths_support] + - in_hash[:collection_paths_source] + - in_hash[:collection_paths_include] - - paths.each do |path| - all_headers.include( File.join(path, "*#{in_hash[:extension_header]}") ) - end - - @file_system_utils.revise_file_list( all_headers, in_hash[:files_include] ) - - return {:collection_all_headers => all_headers} - end - - - def collect_release_existing_compilation_input(in_hash) - release_input = @file_wrapper.instantiate_file_list - - paths = - in_hash[:collection_paths_source] + - in_hash[:collection_paths_include] - - paths << File.join(in_hash[:cexception_vendor_path], CEXCEPTION_LIB_PATH) if (in_hash[:project_use_exceptions]) - - paths.each do |path| - release_input.include( File.join(path, "*#{in_hash[:extension_header]}") ) - if File.exists?(path) and not File.directory?(path) - release_input.include( path ) - else - release_input.include( File.join(path, "*#{in_hash[:extension_source]}") ) - end - end - - @file_system_utils.revise_file_list( release_input, in_hash[:files_source] ) - @file_system_utils.revise_file_list( release_input, in_hash[:files_include] ) - # finding assembly files handled explicitly through other means - - return {:collection_release_existing_compilation_input => release_input} - end - - - def collect_all_existing_compilation_input(in_hash) - all_input = @file_wrapper.instantiate_file_list - - paths = - in_hash[:collection_paths_test] + - in_hash[:collection_paths_support] + - in_hash[:collection_paths_source] + - in_hash[:collection_paths_include] + - [File.join(in_hash[:unity_vendor_path], UNITY_LIB_PATH)] - - paths << File.join(in_hash[:cexception_vendor_path], CEXCEPTION_LIB_PATH) if (in_hash[:project_use_exceptions]) - paths << File.join(in_hash[:cmock_vendor_path], CMOCK_LIB_PATH) if (in_hash[:project_use_mocks]) - - paths.each do |path| - all_input.include( File.join(path, "*#{in_hash[:extension_header]}") ) - if File.exists?(path) and not File.directory?(path) - all_input.include( path ) - else - all_input.include( File.join(path, "*#{in_hash[:extension_source]}") ) - all_input.include( File.join(path, "*#{in_hash[:extension_assembly]}") ) if (defined?(TEST_BUILD_USE_ASSEMBLY) && TEST_BUILD_USE_ASSEMBLY) - end - end - - @file_system_utils.revise_file_list( all_input, in_hash[:files_test] ) - @file_system_utils.revise_file_list( all_input, in_hash[:files_support] ) - @file_system_utils.revise_file_list( all_input, in_hash[:files_source] ) - @file_system_utils.revise_file_list( all_input, in_hash[:files_include] ) - # finding assembly files handled explicitly through other means - - return {:collection_all_existing_compilation_input => all_input} - end - - - def get_vendor_defines(in_hash) - defines = in_hash[:unity_defines].clone - defines.concat(in_hash[:cmock_defines]) if (in_hash[:project_use_mocks]) - defines.concat(in_hash[:cexception_defines]) if (in_hash[:project_use_exceptions]) - - return defines - end - - - def collect_vendor_defines(in_hash) - return {:collection_defines_vendor => get_vendor_defines(in_hash)} - end - - - def collect_test_and_vendor_defines(in_hash) - defines = in_hash[:defines_test].clone - vendor_defines = get_vendor_defines(in_hash) - defines.concat(vendor_defines) if vendor_defines - - return {:collection_defines_test_and_vendor => defines} - end - - - def collect_release_and_vendor_defines(in_hash) - release_defines = in_hash[:defines_release].clone - - release_defines.concat(in_hash[:cexception_defines]) if (in_hash[:project_use_exceptions]) - - return {:collection_defines_release_and_vendor => release_defines} - end - - - def collect_release_artifact_extra_link_objects(in_hash) - objects = [] - - # no build paths here so plugins can remap if necessary (i.e. path mapping happens at runtime) - objects << CEXCEPTION_C_FILE.ext( in_hash[:extension_object] ) if (in_hash[:project_use_exceptions]) - - return {:collection_release_artifact_extra_link_objects => objects} - end - - - def collect_test_fixture_extra_link_objects(in_hash) - # Note: Symbols passed to compiler at command line can change Unity and CException behavior / configuration; - # we also handle those dependencies elsewhere in compilation dependencies - - sources = [UNITY_C_FILE] - - in_hash[:files_support].each { |file| sources << file } - - # we don't include paths here because use of plugins or mixing different compilers may require different build paths - sources << CEXCEPTION_C_FILE if (in_hash[:project_use_exceptions]) - sources << CMOCK_C_FILE if (in_hash[:project_use_mocks]) - - # if we're using mocks & a unity helper is defined & that unity helper includes a source file component (not only a header of macros), - # then link in the unity_helper object file too - if ( in_hash[:project_use_mocks] and in_hash[:cmock_unity_helper] ) - in_hash[:cmock_unity_helper].each do |helper| - if @file_wrapper.exist?(helper.ext(in_hash[:extension_source])) - sources << helper - end - end - end - - # create object files from all the sources - objects = sources.map { |file| File.basename(file) } - - # no build paths here so plugins can remap if necessary (i.e. path mapping happens at runtime) - objects.map! { |object| object.ext(in_hash[:extension_object]) } - - return { :collection_all_support => sources, - :collection_test_fixture_extra_link_objects => objects - } - end - - - private - - def get_vendor_paths(in_hash) - vendor_paths = [] - vendor_paths << File.join(in_hash[:unity_vendor_path], UNITY_LIB_PATH) - vendor_paths << File.join(in_hash[:cexception_vendor_path], CEXCEPTION_LIB_PATH) if (in_hash[:project_use_exceptions]) - vendor_paths << File.join(in_hash[:cmock_vendor_path], CMOCK_LIB_PATH) if (in_hash[:project_use_mocks]) - vendor_paths << in_hash[:cmock_mock_path] if (in_hash[:project_use_mocks]) - - return vendor_paths - end - -end diff --git a/vendor/ceedling/lib/ceedling/configurator_plugins.rb b/vendor/ceedling/lib/ceedling/configurator_plugins.rb deleted file mode 100644 index 75bcd98..0000000 --- a/vendor/ceedling/lib/ceedling/configurator_plugins.rb +++ /dev/null @@ -1,131 +0,0 @@ -require 'ceedling/constants' - -class ConfiguratorPlugins - - constructor :stream_wrapper, :file_wrapper, :system_wrapper - attr_reader :rake_plugins, :script_plugins - - def setup - @rake_plugins = [] - @script_plugins = [] - end - - - def add_load_paths(config) - plugin_paths = {} - - config[:plugins][:enabled].each do |plugin| - config[:plugins][:load_paths].each do |root| - path = File.join(root, plugin) - - is_script_plugin = ( not @file_wrapper.directory_listing( File.join( path, 'lib', '*.rb' ) ).empty? ) - is_rake_plugin = ( not @file_wrapper.directory_listing( File.join( path, '*.rake' ) ).empty? ) - - if is_script_plugin or is_rake_plugin - plugin_paths[(plugin + '_path').to_sym] = path - - if is_script_plugin - @system_wrapper.add_load_path( File.join( path, 'lib') ) - @system_wrapper.add_load_path( File.join( path, 'config') ) - end - break - end - end - end - - return plugin_paths - end - - - # gather up and return .rake filepaths that exist on-disk - def find_rake_plugins(config, plugin_paths) - @rake_plugins = [] - plugins_with_path = [] - - config[:plugins][:enabled].each do |plugin| - if path = plugin_paths[(plugin + '_path').to_sym] - rake_plugin_path = File.join(path, "#{plugin}.rake") - if (@file_wrapper.exist?(rake_plugin_path)) - plugins_with_path << rake_plugin_path - @rake_plugins << plugin - end - end - end - - return plugins_with_path - end - - - # gather up and return just names of .rb classes that exist on-disk - def find_script_plugins(config, plugin_paths) - @script_plugins = [] - - config[:plugins][:enabled].each do |plugin| - if path = plugin_paths[(plugin + '_path').to_sym] - script_plugin_path = File.join(path, "lib", "#{plugin}.rb") - - if @file_wrapper.exist?(script_plugin_path) - @script_plugins << plugin - end - end - end - - return @script_plugins - end - - - # gather up and return configuration .yml filepaths that exist on-disk - def find_config_plugins(config, plugin_paths) - plugins_with_path = [] - - config[:plugins][:enabled].each do |plugin| - if path = plugin_paths[(plugin + '_path').to_sym] - config_plugin_path = File.join(path, "config", "#{plugin}.yml") - - if @file_wrapper.exist?(config_plugin_path) - plugins_with_path << config_plugin_path - end - end - end - - return plugins_with_path - end - - - # gather up and return default .yml filepaths that exist on-disk - def find_plugin_yml_defaults(config, plugin_paths) - defaults_with_path = [] - - config[:plugins][:enabled].each do |plugin| - if path = plugin_paths[(plugin + '_path').to_sym] - default_path = File.join(path, 'config', 'defaults.yml') - - if @file_wrapper.exist?(default_path) - defaults_with_path << default_path - end - end - end - - return defaults_with_path - end - - # gather up and return - def find_plugin_hash_defaults(config, plugin_paths) - defaults_hash= [] - - config[:plugins][:enabled].each do |plugin| - if path = plugin_paths[(plugin + '_path').to_sym] - default_path = File.join(path, "config", "defaults_#{plugin}.rb") - if @file_wrapper.exist?(default_path) - @system_wrapper.require_file( "defaults_#{plugin}.rb") - - object = eval("get_default_config()") - defaults_hash << object - end - end - end - - return defaults_hash - end - -end diff --git a/vendor/ceedling/lib/ceedling/configurator_setup.rb b/vendor/ceedling/lib/ceedling/configurator_setup.rb deleted file mode 100644 index c43bb5c..0000000 --- a/vendor/ceedling/lib/ceedling/configurator_setup.rb +++ /dev/null @@ -1,128 +0,0 @@ - -# add sort-ability to symbol so we can order keys array in hash for test-ability -class Symbol - include Comparable - - def <=>(other) - self.to_s <=> other.to_s - end -end - - -class ConfiguratorSetup - - constructor :configurator_builder, :configurator_validator, :configurator_plugins, :stream_wrapper - - - def build_project_config(config, flattened_config) - ### flesh out config - @configurator_builder.clean(flattened_config) - - ### add to hash values we build up from configuration & file system contents - flattened_config.merge!(@configurator_builder.set_build_paths(flattened_config)) - flattened_config.merge!(@configurator_builder.set_force_build_filepaths(flattened_config)) - flattened_config.merge!(@configurator_builder.set_rakefile_components(flattened_config)) - flattened_config.merge!(@configurator_builder.set_release_target(flattened_config)) - flattened_config.merge!(@configurator_builder.collect_project_options(flattened_config)) - - ### iterate through all entries in paths section and expand any & all globs to actual paths - flattened_config.merge!(@configurator_builder.expand_all_path_globs(flattened_config)) - - flattened_config.merge!(@configurator_builder.collect_vendor_paths(flattened_config)) - flattened_config.merge!(@configurator_builder.collect_source_and_include_paths(flattened_config)) - flattened_config.merge!(@configurator_builder.collect_source_include_vendor_paths(flattened_config)) - flattened_config.merge!(@configurator_builder.collect_test_support_source_include_paths(flattened_config)) - flattened_config.merge!(@configurator_builder.collect_test_support_source_include_vendor_paths(flattened_config)) - flattened_config.merge!(@configurator_builder.collect_tests(flattened_config)) - flattened_config.merge!(@configurator_builder.collect_assembly(flattened_config)) - flattened_config.merge!(@configurator_builder.collect_source(flattened_config)) - flattened_config.merge!(@configurator_builder.collect_headers(flattened_config)) - flattened_config.merge!(@configurator_builder.collect_release_existing_compilation_input(flattened_config)) - flattened_config.merge!(@configurator_builder.collect_all_existing_compilation_input(flattened_config)) - flattened_config.merge!(@configurator_builder.collect_vendor_defines(flattened_config)) - flattened_config.merge!(@configurator_builder.collect_test_and_vendor_defines(flattened_config)) - flattened_config.merge!(@configurator_builder.collect_release_and_vendor_defines(flattened_config)) - flattened_config.merge!(@configurator_builder.collect_release_artifact_extra_link_objects(flattened_config)) - flattened_config.merge!(@configurator_builder.collect_test_fixture_extra_link_objects(flattened_config)) - - return flattened_config - end - - - def build_constants_and_accessors(config, context) - @configurator_builder.build_global_constants(config) - @configurator_builder.build_accessor_methods(config, context) - end - - - def validate_required_sections(config) - validation = [] - validation << @configurator_validator.exists?(config, :project) - validation << @configurator_validator.exists?(config, :paths) - - return false if (validation.include?(false)) - return true - end - - def validate_required_section_values(config) - validation = [] - validation << @configurator_validator.exists?(config, :project, :build_root) - validation << @configurator_validator.exists?(config, :paths, :test) - validation << @configurator_validator.exists?(config, :paths, :source) - - return false if (validation.include?(false)) - return true - end - - def validate_paths(config) - validation = [] - - if config[:cmock][:unity_helper] - config[:cmock][:unity_helper].each do |path| - validation << @configurator_validator.validate_filepath_simple( path, :cmock, :unity_helper ) - end - end - - config[:project][:options_paths].each do |path| - validation << @configurator_validator.validate_filepath_simple( path, :project, :options_paths ) - end - - config[:plugins][:load_paths].each do |path| - validation << @configurator_validator.validate_filepath_simple( path, :plugins, :load_paths ) - end - - config[:paths].keys.sort.each do |key| - validation << @configurator_validator.validate_path_list(config, :paths, key) - end - - return false if (validation.include?(false)) - return true - end - - def validate_tools(config) - validation = [] - - config[:tools].keys.sort.each do |key| - validation << @configurator_validator.exists?(config, :tools, key, :executable) - validation << @configurator_validator.validate_executable_filepath(config, :tools, key, :executable) if (not config[:tools][key][:optional]) - validation << @configurator_validator.validate_tool_stderr_redirect(config, :tools, key) - end - - return false if (validation.include?(false)) - return true - end - - def validate_plugins(config) - missing_plugins = - Set.new( config[:plugins][:enabled] ) - - Set.new( @configurator_plugins.rake_plugins ) - - Set.new( @configurator_plugins.script_plugins ) - - missing_plugins.each do |plugin| - @stream_wrapper.stderr_puts("ERROR: Ceedling plugin '#{plugin}' contains no rake or ruby class entry point. (Misspelled or missing files?)") - end - - return ( (missing_plugins.size > 0) ? false : true ) - end - -end diff --git a/vendor/ceedling/lib/ceedling/configurator_validator.rb b/vendor/ceedling/lib/ceedling/configurator_validator.rb deleted file mode 100644 index fc02101..0000000 --- a/vendor/ceedling/lib/ceedling/configurator_validator.rb +++ /dev/null @@ -1,193 +0,0 @@ -require 'rubygems' -require 'rake' # for ext() -require 'ceedling/constants' -require 'ceedling/tool_executor' # for argument replacement pattern -require 'ceedling/file_path_utils' # for glob handling class methods - - -class ConfiguratorValidator - - constructor :file_wrapper, :stream_wrapper, :system_wrapper - - # walk into config hash verify existence of data at key depth - def exists?(config, *keys) - hash = retrieve_value(config, keys) - exist = !hash[:value].nil? - - if (not exist) - # no verbosity checking since this is lowest level anyhow & verbosity checking depends on configurator - @stream_wrapper.stderr_puts("ERROR: Required config file entry #{format_key_sequence(keys, hash[:depth])} does not exist.") - end - - return exist - end - - - # walk into config hash. verify directory path(s) at given key depth - def validate_path_list(config, *keys) - hash = retrieve_value(config, keys) - list = hash[:value] - - # return early if we couldn't walk into hash and find a value - return false if (list.nil?) - - path_list = [] - exist = true - - case list - when String then path_list << list - when Array then path_list = list - end - - path_list.each do |path| - base_path = FilePathUtils::extract_path(path) # lop off add/subtract notation & glob specifiers - - if (not @file_wrapper.exist?(base_path)) - # no verbosity checking since this is lowest level anyhow & verbosity checking depends on configurator - @stream_wrapper.stderr_puts("ERROR: Config path #{format_key_sequence(keys, hash[:depth])}['#{base_path}'] does not exist on disk.") - exist = false - end - end - - return exist - end - - - # simple path verification - def validate_filepath_simple(path, *keys) - validate_path = path - - if (not @file_wrapper.exist?(validate_path)) - # no verbosity checking since this is lowest level anyhow & verbosity checking depends on configurator - @stream_wrapper.stderr_puts("ERROR: Config path '#{validate_path}' associated with #{format_key_sequence(keys, keys.size)} does not exist on disk.") - return false - end - - return true - end - - # walk into config hash. verify specified file exists. - def validate_filepath(config, *keys) - hash = retrieve_value(config, keys) - filepath = hash[:value] - - # return early if we couldn't walk into hash and find a value - return false if (filepath.nil?) - - # skip everything if we've got an argument replacement pattern - return true if (filepath =~ TOOL_EXECUTOR_ARGUMENT_REPLACEMENT_PATTERN) - - if (not @file_wrapper.exist?(filepath)) - - # See if we can deal with it internally. - if GENERATED_DIR_PATH.include?(filepath) - # we already made this directory before let's make it again. - FileUtils.mkdir_p File.join(File.dirname(__FILE__), filepath) - @stream_wrapper.stderr_puts("WARNING: Generated filepath #{format_key_sequence(keys, hash[:depth])}['#{filepath}'] does not exist on disk. Recreating") - - else - # no verbosity checking since this is lowest level anyhow & verbosity checking depends on configurator - @stream_wrapper.stderr_puts("ERROR: Config filepath #{format_key_sequence(keys, hash[:depth])}['#{filepath}'] does not exist on disk.") - return false - end - end - - return true - end - - # walk into config hash. verify specified file exists. - def validate_executable_filepath(config, *keys) - exe_extension = config[:extension][:executable] - hash = retrieve_value(config, keys) - filepath = hash[:value] - - # return early if we couldn't walk into hash and find a value - return false if (filepath.nil?) - - # skip everything if we've got an argument replacement pattern - return true if (filepath =~ TOOL_EXECUTOR_ARGUMENT_REPLACEMENT_PATTERN) - - # if there's no path included, verify file exists somewhere in system search paths - if (not filepath.include?('/')) - exists = false - - @system_wrapper.search_paths.each do |path| - if (@file_wrapper.exist?( File.join(path, filepath)) ) - exists = true - break - end - - if (@file_wrapper.exist?( (File.join(path, filepath)).ext( exe_extension ) )) - exists = true - break - elsif (@system_wrapper.windows? and @file_wrapper.exist?( (File.join(path, filepath)).ext( EXTENSION_WIN_EXE ) )) - exists = true - break - end - end - - if (not exists) - # no verbosity checking since this is lowest level anyhow & verbosity checking depends on configurator - @stream_wrapper.stderr_puts("ERROR: Config filepath #{format_key_sequence(keys, hash[:depth])}['#{filepath}'] does not exist in system search paths.") - return false - end - - # if there is a path included, check that explicit filepath exists - else - if (not @file_wrapper.exist?(filepath)) - # no verbosity checking since this is lowest level anyhow & verbosity checking depends on configurator - @stream_wrapper.stderr_puts("ERROR: Config filepath #{format_key_sequence(keys, hash[:depth])}['#{filepath}'] does not exist on disk.") - return false - end - end - - return true - end - - def validate_tool_stderr_redirect(config, tools, tool) - redirect = config[tools][tool][:stderr_redirect] - if (redirect.class == Symbol) - # map constants and force to array of strings for runtime universality across ruby versions - if (not StdErrRedirect.constants.map{|constant| constant.to_s}.include?(redirect.to_s.upcase)) - error = "ERROR: [:#{tools}][:#{tool}][:stderr_redirect][:#{redirect}] is not a recognized option " + - "{#{StdErrRedirect.constants.map{|constant| ':' + constant.to_s.downcase}.join(', ')}}." - @stream_wrapper.stderr_puts(error) - return false - end - end - - return true - end - - private ######################################### - - - def retrieve_value(config, keys) - value = nil - hash = config - depth = 0 - - # walk into hash & extract value at requested key sequence - keys.each do |symbol| - depth += 1 - if (not hash[symbol].nil?) - hash = hash[symbol] - value = hash - else - value = nil - break - end - end - - return {:value => value, :depth => depth} - end - - - def format_key_sequence(keys, depth) - walked_keys = keys.slice(0, depth) - formatted_keys = walked_keys.map{|key| "[:#{key.to_s}]"} - - return formatted_keys.join - end - -end diff --git a/vendor/ceedling/lib/ceedling/constants.rb b/vendor/ceedling/lib/ceedling/constants.rb deleted file mode 100644 index 19484f0..0000000 --- a/vendor/ceedling/lib/ceedling/constants.rb +++ /dev/null @@ -1,99 +0,0 @@ - -class Verbosity - SILENT = 0 # as silent as possible (though there are some messages that must be spit out) - ERRORS = 1 # only errors - COMPLAIN = 2 # spit out errors and warnings/notices - NORMAL = 3 # errors, warnings/notices, standard status messages - OBNOXIOUS = 4 # all messages including extra verbose output (used for lite debugging / verification) - DEBUG = 5 # special extra verbose output for hardcore debugging -end - - -class TestResultsSanityChecks - NONE = 0 # no sanity checking of test results - NORMAL = 1 # perform non-problematic checks - THOROUGH = 2 # perform checks that require inside knowledge of system workings -end - - -class StdErrRedirect - NONE = :none - AUTO = :auto - WIN = :win - UNIX = :unix - TCSH = :tcsh -end - - -class BackgroundExec - NONE = :none - AUTO = :auto - WIN = :win - UNIX = :unix -end - -unless defined?(PROJECT_ROOT) - PROJECT_ROOT = Dir.pwd() -end - -GENERATED_DIR_PATH = [['vendor', 'ceedling'], 'src', "test", ['test', 'support'], 'build'].each{|p| File.join(*p)} - -EXTENSION_WIN_EXE = '.exe' -EXTENSION_NONWIN_EXE = '.out' - - -CEXCEPTION_ROOT_PATH = 'c_exception' -CEXCEPTION_LIB_PATH = "#{CEXCEPTION_ROOT_PATH}/lib" -CEXCEPTION_C_FILE = 'CException.c' -CEXCEPTION_H_FILE = 'CException.h' - -UNITY_ROOT_PATH = 'unity' -UNITY_LIB_PATH = "#{UNITY_ROOT_PATH}/src" -UNITY_C_FILE = 'unity.c' -UNITY_H_FILE = 'unity.h' -UNITY_INTERNALS_H_FILE = 'unity_internals.h' - -CMOCK_ROOT_PATH = 'cmock' -CMOCK_LIB_PATH = "#{CMOCK_ROOT_PATH}/src" -CMOCK_C_FILE = 'cmock.c' -CMOCK_H_FILE = 'cmock.h' - - -DEFAULT_CEEDLING_MAIN_PROJECT_FILE = 'project.yml' unless defined?(DEFAULT_CEEDLING_MAIN_PROJECT_FILE) # main project file -DEFAULT_CEEDLING_USER_PROJECT_FILE = 'user.yml' unless defined?(DEFAULT_CEEDLING_USER_PROJECT_FILE) # supplemental user config file - -INPUT_CONFIGURATION_CACHE_FILE = 'input.yml' unless defined?(INPUT_CONFIGURATION_CACHE_FILE) # input configuration file dump -DEFINES_DEPENDENCY_CACHE_FILE = 'defines_dependency.yml' unless defined?(DEFINES_DEPENDENCY_CACHE_FILE) # preprocessor definitions for files - -TEST_ROOT_NAME = 'test' unless defined?(TEST_ROOT_NAME) -TEST_TASK_ROOT = TEST_ROOT_NAME + ':' unless defined?(TEST_TASK_ROOT) -TEST_SYM = TEST_ROOT_NAME.to_sym unless defined?(TEST_SYM) - -RELEASE_ROOT_NAME = 'release' unless defined?(RELEASE_ROOT_NAME) -RELEASE_TASK_ROOT = RELEASE_ROOT_NAME + ':' unless defined?(RELEASE_TASK_ROOT) -RELEASE_SYM = RELEASE_ROOT_NAME.to_sym unless defined?(RELEASE_SYM) - -REFRESH_ROOT_NAME = 'refresh' unless defined?(REFRESH_ROOT_NAME) -REFRESH_TASK_ROOT = REFRESH_ROOT_NAME + ':' unless defined?(REFRESH_TASK_ROOT) -REFRESH_SYM = REFRESH_ROOT_NAME.to_sym unless defined?(REFRESH_SYM) - -UTILS_ROOT_NAME = 'utils' unless defined?(UTILS_ROOT_NAME) -UTILS_TASK_ROOT = UTILS_ROOT_NAME + ':' unless defined?(UTILS_TASK_ROOT) -UTILS_SYM = UTILS_ROOT_NAME.to_sym unless defined?(UTILS_SYM) - -OPERATION_COMPILE_SYM = :compile unless defined?(OPERATION_COMPILE_SYM) -OPERATION_ASSEMBLE_SYM = :assemble unless defined?(OPERATION_ASSEMBLE_SYM) -OPERATION_LINK_SYM = :link unless defined?(OPERATION_LINK_SYM) - - -RUBY_STRING_REPLACEMENT_PATTERN = /#\{.+\}/ -RUBY_EVAL_REPLACEMENT_PATTERN = /^\{(.+)\}$/ -TOOL_EXECUTOR_ARGUMENT_REPLACEMENT_PATTERN = /(\$\{(\d+)\})/ -TEST_STDOUT_STATISTICS_PATTERN = /\n-+\s*(\d+)\s+Tests\s+(\d+)\s+Failures\s+(\d+)\s+Ignored\s+(OK|FAIL)\s*/i - -NULL_FILE_PATH = '/dev/null' - -TESTS_BASE_PATH = TEST_ROOT_NAME -RELEASE_BASE_PATH = RELEASE_ROOT_NAME - -VENDORS_FILES = %w(unity UnityHelper cmock CException).freeze diff --git a/vendor/ceedling/lib/ceedling/defaults.rb b/vendor/ceedling/lib/ceedling/defaults.rb deleted file mode 100644 index 1300a1a..0000000 --- a/vendor/ceedling/lib/ceedling/defaults.rb +++ /dev/null @@ -1,471 +0,0 @@ -require 'ceedling/constants' -require 'ceedling/system_wrapper' -require 'ceedling/file_path_utils' - -#this should be defined already, but not always during system specs -CEEDLING_VENDOR = File.expand_path(File.dirname(__FILE__) + '/../../vendor') unless defined? CEEDLING_VENDOR -CEEDLING_PLUGINS = [] unless defined? CEEDLING_PLUGINS - -DEFAULT_TEST_COMPILER_TOOL = { - :executable => ENV['CC'].nil? ? FilePathUtils.os_executable_ext('gcc').freeze : ENV['CC'].split[0], - :name => 'default_test_compiler'.freeze, - :stderr_redirect => StdErrRedirect::NONE.freeze, - :background_exec => BackgroundExec::NONE.freeze, - :optional => false.freeze, - :arguments => [ - ENV['CC'].nil? ? "" : ENV['CC'].split[1..-1], - ENV['CPPFLAGS'].nil? ? "" : ENV['CPPFLAGS'].split, - {"-I\"$\"" => 'COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR'}.freeze, - {"-I\"$\"" => 'COLLECTION_PATHS_TEST_TOOLCHAIN_INCLUDE'}.freeze, - {"-D$" => 'COLLECTION_DEFINES_TEST_AND_VENDOR'}.freeze, - "-DGNU_COMPILER".freeze, - "-g".freeze, - ENV['CFLAGS'].nil? ? "" : ENV['CFLAGS'].split, - "-c \"${1}\"".freeze, - "-o \"${2}\"".freeze, - # gcc's list file output options are complex; no use of ${3} parameter in default config - "-MMD".freeze, - "-MF \"${4}\"".freeze, - ].freeze - } - -DEFAULT_TEST_LINKER_TOOL = { - :executable => ENV['CCLD'].nil? ? FilePathUtils.os_executable_ext('gcc').freeze : ENV['CCLD'].split[0], - :name => 'default_test_linker'.freeze, - :stderr_redirect => StdErrRedirect::NONE.freeze, - :background_exec => BackgroundExec::NONE.freeze, - :optional => false.freeze, - :arguments => [ - ENV['CCLD'].nil? ? "" : ENV['CCLD'].split[1..-1], - ENV['CFLAGS'].nil? ? "" : ENV['CFLAGS'].split, - ENV['LDFLAGS'].nil? ? "" : ENV['LDFLAGS'].split, - "\"${1}\"".freeze, - "${5}".freeze, - "-o \"${2}\"".freeze, - "".freeze, - "${4}".freeze, - ENV['LDLIBS'].nil? ? "" : ENV['LDLIBS'].split - ].freeze - } - -DEFAULT_TEST_FIXTURE_TOOL = { - :executable => '${1}'.freeze, - :name => 'default_test_fixture'.freeze, - :stderr_redirect => StdErrRedirect::AUTO.freeze, - :background_exec => BackgroundExec::NONE.freeze, - :optional => false.freeze, - :arguments => [].freeze - } - -DEFAULT_TEST_INCLUDES_PREPROCESSOR_TOOL = { - :executable => ENV['CC'].nil? ? FilePathUtils.os_executable_ext('gcc').freeze : ENV['CC'].split[0], - :name => 'default_test_includes_preprocessor'.freeze, - :stderr_redirect => StdErrRedirect::NONE.freeze, - :background_exec => BackgroundExec::NONE.freeze, - :optional => false.freeze, - :arguments => [ - ENV['CC'].nil? ? "" : ENV['CC'].split[1..-1], - ENV['CPPFLAGS'].nil? ? "" : ENV['CPPFLAGS'].split, - '-E'.freeze, # OSX clang - '-MM'.freeze, - '-MG'.freeze, - # avoid some possibility of deep system lib header file complications by omitting vendor paths - # if cpp is run on *nix system, escape spaces in paths; if cpp on windows just use the paths collection as is - # {"-I\"$\"" => "{SystemWrapper.windows? ? COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE : COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE.map{|path| path.gsub(\/ \/, \'\\\\ \') }}"}.freeze, - {"-I\"$\"" => 'COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR'}.freeze, - {"-I\"$\"" => 'COLLECTION_PATHS_TEST_TOOLCHAIN_INCLUDE'}.freeze, - {"-D$" => 'COLLECTION_DEFINES_TEST_AND_VENDOR'}.freeze, - {"-D$" => 'DEFINES_TEST_PREPROCESS'}.freeze, - "-DGNU_COMPILER".freeze, # OSX clang - # '-nostdinc'.freeze, # disabled temporarily due to stdio access violations on OSX - "\"${1}\"".freeze - ].freeze - } - -DEFAULT_TEST_FILE_PREPROCESSOR_TOOL = { - :executable => ENV['CC'].nil? ? FilePathUtils.os_executable_ext('gcc').freeze : ENV['CC'].split[0], - :name => 'default_test_file_preprocessor'.freeze, - :stderr_redirect => StdErrRedirect::NONE.freeze, - :background_exec => BackgroundExec::NONE.freeze, - :optional => false.freeze, - :arguments => [ - ENV['CC'].nil? ? "" : ENV['CC'].split[1..-1], - ENV['CPPFLAGS'].nil? ? "" : ENV['CPPFLAGS'].split, - '-E'.freeze, - {"-I\"$\"" => 'COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR'}.freeze, - {"-I\"$\"" => 'COLLECTION_PATHS_TEST_TOOLCHAIN_INCLUDE'}.freeze, - {"-D$" => 'COLLECTION_DEFINES_TEST_AND_VENDOR'}.freeze, - {"-D$" => 'DEFINES_TEST_PREPROCESS'}.freeze, - "-DGNU_COMPILER".freeze, - # '-nostdinc'.freeze, # disabled temporarily due to stdio access violations on OSX - "\"${1}\"".freeze, - "-o \"${2}\"".freeze - ].freeze - } - -DEFAULT_TEST_FILE_PREPROCESSOR_DIRECTIVES_TOOL = { - :executable => FilePathUtils.os_executable_ext('gcc').freeze, - :name => 'default_test_file_preprocessor_directives'.freeze, - :stderr_redirect => StdErrRedirect::NONE.freeze, - :background_exec => BackgroundExec::NONE.freeze, - :optional => false.freeze, - :arguments => [ - '-E'.freeze, - {"-I\"$\"" => 'COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR'}.freeze, - {"-I\"$\"" => 'COLLECTION_PATHS_TEST_TOOLCHAIN_INCLUDE'}.freeze, - {"-D$" => 'COLLECTION_DEFINES_TEST_AND_VENDOR'}.freeze, - {"-D$" => 'DEFINES_TEST_PREPROCESS'}.freeze, - "-DGNU_COMPILER".freeze, - '-fdirectives-only'.freeze, - # '-nostdinc'.freeze, # disabled temporarily due to stdio access violations on OSX - "\"${1}\"".freeze, - "-o \"${2}\"".freeze - ].freeze - } - -# Disable the -MD flag for OSX LLVM Clang, since unsupported -if RUBY_PLATFORM =~ /darwin/ && `gcc --version 2> /dev/null` =~ /Apple LLVM version .* \(clang/m # OSX w/LLVM Clang - MD_FLAG = '' # Clang doesn't support the -MD flag -else - MD_FLAG = '-MD' -end - -DEFAULT_TEST_DEPENDENCIES_GENERATOR_TOOL = { - :executable => ENV['CC'].nil? ? FilePathUtils.os_executable_ext('gcc').freeze : ENV['CC'].split[0], - :name => 'default_test_dependencies_generator'.freeze, - :stderr_redirect => StdErrRedirect::NONE.freeze, - :background_exec => BackgroundExec::NONE.freeze, - :optional => false.freeze, - :arguments => [ - ENV['CC'].nil? ? "" : ENV['CC'].split[1..-1], - ENV['CPPFLAGS'].nil? ? "" : ENV['CPPFLAGS'].split, - '-E'.freeze, - {"-I\"$\"" => 'COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR'}.freeze, - {"-I\"$\"" => 'COLLECTION_PATHS_TEST_TOOLCHAIN_INCLUDE'}.freeze, - {"-D$" => 'COLLECTION_DEFINES_TEST_AND_VENDOR'}.freeze, - {"-D$" => 'DEFINES_TEST_PREPROCESS'}.freeze, - "-DGNU_COMPILER".freeze, - "-MT \"${3}\"".freeze, - '-MM'.freeze, - MD_FLAG.freeze, - '-MG'.freeze, - "-MF \"${2}\"".freeze, - "-c \"${1}\"".freeze, - # '-nostdinc'.freeze, - ].freeze - } - -DEFAULT_RELEASE_DEPENDENCIES_GENERATOR_TOOL = { - :executable => ENV['CC'].nil? ? FilePathUtils.os_executable_ext('gcc').freeze : ENV['CC'].split[0], - :name => 'default_release_dependencies_generator'.freeze, - :stderr_redirect => StdErrRedirect::NONE.freeze, - :background_exec => BackgroundExec::NONE.freeze, - :optional => false.freeze, - :arguments => [ - ENV['CC'].nil? ? "" : ENV['CC'].split[1..-1], - ENV['CPPFLAGS'].nil? ? "" : ENV['CPPFLAGS'].split, - '-E'.freeze, - {"-I\"$\"" => 'COLLECTION_PATHS_SOURCE_INCLUDE_VENDOR'}.freeze, - {"-I\"$\"" => 'COLLECTION_PATHS_RELEASE_TOOLCHAIN_INCLUDE'}.freeze, - {"-D$" => 'COLLECTION_DEFINES_RELEASE_AND_VENDOR'}.freeze, - {"-D$" => 'DEFINES_RELEASE_PREPROCESS'}.freeze, - "-DGNU_COMPILER".freeze, - "-MT \"${3}\"".freeze, - '-MM'.freeze, - MD_FLAG.freeze, - '-MG'.freeze, - "-MF \"${2}\"".freeze, - "-c \"${1}\"".freeze, - # '-nostdinc'.freeze, - ].freeze - } - - -DEFAULT_RELEASE_COMPILER_TOOL = { - :executable => ENV['CC'].nil? ? FilePathUtils.os_executable_ext('gcc').freeze : ENV['CC'].split[0], - :name => 'default_release_compiler'.freeze, - :stderr_redirect => StdErrRedirect::NONE.freeze, - :background_exec => BackgroundExec::NONE.freeze, - :optional => false.freeze, - :arguments => [ - ENV['CC'].nil? ? "" : ENV['CC'].split[1..-1], - ENV['CPPFLAGS'].nil? ? "" : ENV['CPPFLAGS'].split, - {"-I\"$\"" => 'COLLECTION_PATHS_SOURCE_INCLUDE_VENDOR'}.freeze, - {"-I\"$\"" => 'COLLECTION_PATHS_RELEASE_TOOLCHAIN_INCLUDE'}.freeze, - {"-D$" => 'COLLECTION_DEFINES_RELEASE_AND_VENDOR'}.freeze, - "-DGNU_COMPILER".freeze, - ENV['CFLAGS'].nil? ? "" : ENV['CFLAGS'].split, - "-c \"${1}\"".freeze, - "-o \"${2}\"".freeze, - # gcc's list file output options are complex; no use of ${3} parameter in default config - "-MMD".freeze, - "-MF \"${4}\"".freeze, - ].freeze - } - -DEFAULT_RELEASE_ASSEMBLER_TOOL = { - :executable => ENV['AS'].nil? ? FilePathUtils.os_executable_ext('as').freeze : ENV['AS'].split[0], - :name => 'default_release_assembler'.freeze, - :stderr_redirect => StdErrRedirect::NONE.freeze, - :background_exec => BackgroundExec::NONE.freeze, - :optional => false.freeze, - :arguments => [ - ENV['AS'].nil? ? "" : ENV['AS'].split[1..-1], - ENV['ASFLAGS'].nil? ? "" : ENV['ASFLAGS'].split, - {"-I\"$\"" => 'COLLECTION_PATHS_SOURCE_AND_INCLUDE'}.freeze, - "\"${1}\"".freeze, - "-o \"${2}\"".freeze, - ].freeze - } - -DEFAULT_RELEASE_LINKER_TOOL = { - :executable => ENV['CCLD'].nil? ? FilePathUtils.os_executable_ext('gcc').freeze : ENV['CCLD'].split[0], - :name => 'default_release_linker'.freeze, - :stderr_redirect => StdErrRedirect::NONE.freeze, - :background_exec => BackgroundExec::NONE.freeze, - :optional => false.freeze, - :arguments => [ - ENV['CCLD'].nil? ? "" : ENV['CCLD'].split[1..-1], - ENV['CFLAGS'].nil? ? "" : ENV['CFLAGS'].split, - ENV['LDFLAGS'].nil? ? "" : ENV['LDFLAGS'].split, - "\"${1}\"".freeze, - "${5}".freeze, - "-o \"${2}\"".freeze, - "".freeze, - "${4}".freeze, - ENV['LDLIBS'].nil? ? "" : ENV['LDLIBS'].split - ].freeze - } - - -DEFAULT_TOOLS_TEST = { - :tools => { - :test_compiler => DEFAULT_TEST_COMPILER_TOOL, - :test_linker => DEFAULT_TEST_LINKER_TOOL, - :test_fixture => DEFAULT_TEST_FIXTURE_TOOL, - } - } - -DEFAULT_TOOLS_TEST_PREPROCESSORS = { - :tools => { - :test_includes_preprocessor => DEFAULT_TEST_INCLUDES_PREPROCESSOR_TOOL, - :test_file_preprocessor => DEFAULT_TEST_FILE_PREPROCESSOR_TOOL, - :test_file_preprocessor_directives => DEFAULT_TEST_FILE_PREPROCESSOR_DIRECTIVES_TOOL, - } - } - -DEFAULT_TOOLS_TEST_DEPENDENCIES = { - :tools => { - :test_dependencies_generator => DEFAULT_TEST_DEPENDENCIES_GENERATOR_TOOL, - } - } - - -DEFAULT_TOOLS_RELEASE = { - :tools => { - :release_compiler => DEFAULT_RELEASE_COMPILER_TOOL, - :release_linker => DEFAULT_RELEASE_LINKER_TOOL, - } - } - -DEFAULT_TOOLS_RELEASE_ASSEMBLER = { - :tools => { - :release_assembler => DEFAULT_RELEASE_ASSEMBLER_TOOL, - } - } - -DEFAULT_TOOLS_RELEASE_DEPENDENCIES = { - :tools => { - :release_dependencies_generator => DEFAULT_RELEASE_DEPENDENCIES_GENERATOR_TOOL, - } - } - - -DEFAULT_RELEASE_TARGET_NAME = 'project' - -DEFAULT_CEEDLING_CONFIG = { - :project => { - # :build_root must be set by user - :use_exceptions => true, - :use_mocks => true, - :compile_threads => 1, - :test_threads => 1, - :use_test_preprocessor => false, - :use_preprocessor_directives => false, - :use_deep_dependencies => false, - :generate_deep_dependencies => true, # only applicable if use_deep_dependencies is true - :auto_link_deep_dependencies => false, - :test_file_prefix => 'test_', - :options_paths => [], - :release_build => false, - }, - - :release_build => { - # :output is set while building configuration -- allows smart default system-dependent file extension handling - :use_assembly => false, - :artifacts => [], - }, - - :paths => { - :test => [], # must be populated by user - :source => [], # must be populated by user - :support => [], - :include => [], - :libraries => [], - :test_toolchain_include => [], - :release_toolchain_include => [], - }, - - :files => { - :test => [], - :source => [], - :assembly => [], - :support => [], - :include => [], - }, - - # unlike other top-level entries, environment's value is an array to preserve order - :environment => [ - # when evaluated, this provides wider text field for rake task comments - {:rake_columns => '120'}, - ], - - :defines => { - :test => [], - :test_preprocess => [], - :release => [], - :release_preprocess => [], - :use_test_definition => false, - }, - - :libraries => { - :flag => '-l${1}', - :path_flag => '-L ${1}', - :test => [], - :test_preprocess => [], - :release => [], - :release_preprocess => [], - }, - - :flags => {}, - - :extension => { - :header => '.h', - :source => '.c', - :assembly => '.s', - :object => '.o', - :libraries => ['.a','.so'], - :executable => ( SystemWrapper.windows? ? EXTENSION_WIN_EXE : EXTENSION_NONWIN_EXE ), - :map => '.map', - :list => '.lst', - :testpass => '.pass', - :testfail => '.fail', - :dependencies => '.d', - }, - - :unity => { - :vendor_path => CEEDLING_VENDOR, - :defines => [] - }, - - :cmock => { - :vendor_path => CEEDLING_VENDOR, - :defines => [], - :includes => [] - }, - - :cexception => { - :vendor_path => CEEDLING_VENDOR, - :defines => [] - }, - - :test_runner => { - :includes => [], - :file_suffix => '_runner', - }, - - # all tools populated while building up config structure - :tools => {}, - - # empty argument lists for default tools - # (these can be overridden in project file to add arguments to tools without totally redefining tools) - :test_compiler => { :arguments => [] }, - :test_linker => { :arguments => [] }, - :test_fixture => { - :arguments => [], - :link_objects => [], # compiled object files to always be linked in (e.g. cmock.o if using mocks) - }, - :test_includes_preprocessor => { :arguments => [] }, - :test_file_preprocessor => { :arguments => [] }, - :test_file_preprocessor_directives => { :arguments => [] }, - :test_dependencies_generator => { :arguments => [] }, - :release_compiler => { :arguments => [] }, - :release_linker => { :arguments => [] }, - :release_assembler => { :arguments => [] }, - :release_dependencies_generator => { :arguments => [] }, - - :plugins => { - :load_paths => CEEDLING_PLUGINS, - :enabled => [], - } - }.freeze - - -DEFAULT_TESTS_RESULTS_REPORT_TEMPLATE = %q{ -% ignored = hash[:results][:counts][:ignored] -% failed = hash[:results][:counts][:failed] -% stdout_count = hash[:results][:counts][:stdout] -% header_prepend = ((hash[:header].length > 0) ? "#{hash[:header]}: " : '') -% banner_width = 25 + header_prepend.length # widest message - -% if (stdout_count > 0) -<%=@ceedling[:plugin_reportinator].generate_banner(header_prepend + 'TEST OUTPUT')%> -% hash[:results][:stdout].each do |string| -% string[:collection].each do |item| -<%=string[:source][:path]%><%=File::SEPARATOR%><%=string[:source][:file]%>: "<%=item%>" -% end -% end - -% end -% if (ignored > 0) -<%=@ceedling[:plugin_reportinator].generate_banner(header_prepend + 'IGNORED TEST SUMMARY')%> -% hash[:results][:ignores].each do |ignore| -% ignore[:collection].each do |item| -<%=ignore[:source][:path]%><%=File::SEPARATOR%><%=ignore[:source][:file]%>:<%=item[:line]%>:<%=item[:test]%> -% if (item[:message].length > 0) -: "<%=item[:message]%>" -% else -<%="\n"%> -% end -% end -% end - -% end -% if (failed > 0) -<%=@ceedling[:plugin_reportinator].generate_banner(header_prepend + 'FAILED TEST SUMMARY')%> -% hash[:results][:failures].each do |failure| -% failure[:collection].each do |item| -<%=failure[:source][:path]%><%=File::SEPARATOR%><%=failure[:source][:file]%>:<%=item[:line]%>:<%=item[:test]%> -% if (item[:message].length > 0) -: "<%=item[:message]%>" -% else -<%="\n"%> -% end -% end -% end - -% end -% total_string = hash[:results][:counts][:total].to_s -% format_string = "%#{total_string.length}i" -<%=@ceedling[:plugin_reportinator].generate_banner(header_prepend + 'OVERALL TEST SUMMARY')%> -% if (hash[:results][:counts][:total] > 0) -TESTED: <%=hash[:results][:counts][:total].to_s%> -PASSED: <%=sprintf(format_string, hash[:results][:counts][:passed])%> -FAILED: <%=sprintf(format_string, failed)%> -IGNORED: <%=sprintf(format_string, ignored)%> -% else - -No tests executed. -% end - -} diff --git a/vendor/ceedling/lib/ceedling/dependinator.rb b/vendor/ceedling/lib/ceedling/dependinator.rb deleted file mode 100644 index accfe80..0000000 --- a/vendor/ceedling/lib/ceedling/dependinator.rb +++ /dev/null @@ -1,97 +0,0 @@ - -class Dependinator - - constructor :configurator, :project_config_manager, :test_includes_extractor, :file_path_utils, :rake_wrapper, :file_wrapper - - def touch_force_rebuild_files - @file_wrapper.touch( @configurator.project_test_force_rebuild_filepath ) - @file_wrapper.touch( @configurator.project_release_force_rebuild_filepath ) if (@configurator.project_release_build) - end - - - - def load_release_object_deep_dependencies(dependencies_list) - dependencies_list.each do |dependencies_file| - if File.exists?(dependencies_file) - @rake_wrapper.load_dependencies( dependencies_file ) - end - end - end - - - def enhance_release_file_dependencies(files) - files.each do |filepath| - @rake_wrapper[filepath].enhance( [@configurator.project_release_force_rebuild_filepath] ) if (@project_config_manager.release_config_changed) - end - end - - - - def load_test_object_deep_dependencies(files_list) - dependencies_list = @file_path_utils.form_test_dependencies_filelist(files_list) - dependencies_list.each do |dependencies_file| - if File.exists?(dependencies_file) - @rake_wrapper.load_dependencies(dependencies_file) - end - end - end - - - def enhance_runner_dependencies(runner_filepath) - @rake_wrapper[runner_filepath].enhance( [@configurator.project_test_force_rebuild_filepath] ) if (@project_config_manager.test_config_changed || - @project_config_manager.test_defines_changed) - end - - - def enhance_shallow_include_lists_dependencies(include_lists) - include_lists.each do |include_list_filepath| - @rake_wrapper[include_list_filepath].enhance( [@configurator.project_test_force_rebuild_filepath] ) if (@project_config_manager.test_config_changed || - @project_config_manager.test_defines_changed) - end - end - - - def enhance_preprocesed_file_dependencies(files) - files.each do |filepath| - @rake_wrapper[filepath].enhance( [@configurator.project_test_force_rebuild_filepath] ) if (@project_config_manager.test_config_changed || - @project_config_manager.test_defines_changed) - end - end - - - def enhance_mock_dependencies(mocks_list) - # if input configuration or ceedling changes, make sure these guys get rebuilt - mocks_list.each do |mock_filepath| - @rake_wrapper[mock_filepath].enhance( [@configurator.project_test_force_rebuild_filepath] ) if (@project_config_manager.test_config_changed || - @project_config_manager.test_defines_changed) - @rake_wrapper[mock_filepath].enhance( @configurator.cmock_unity_helper ) if (@configurator.cmock_unity_helper) - end - end - - - def enhance_dependencies_dependencies(dependencies) - dependencies.each do |dependencies_filepath| - @rake_wrapper[dependencies_filepath].enhance( [@configurator.project_test_force_rebuild_filepath] ) if (@project_config_manager.test_config_changed || - @project_config_manager.test_defines_changed) - end - end - - - def enhance_test_build_object_dependencies(objects) - objects.each do |object_filepath| - @rake_wrapper[object_filepath].enhance( [@configurator.project_test_force_rebuild_filepath] ) if (@project_config_manager.test_config_changed || - @project_config_manager.test_defines_changed) - end - end - - - def enhance_results_dependencies(result_filepath) - @rake_wrapper[result_filepath].enhance( [@configurator.project_test_force_rebuild_filepath] ) if @project_config_manager.test_config_changed - end - - - def enhance_test_executable_dependencies(test, objects) - @rake_wrapper[ @file_path_utils.form_test_executable_filepath(test) ].enhance( objects ) - end - -end diff --git a/vendor/ceedling/lib/ceedling/erb_wrapper.rb b/vendor/ceedling/lib/ceedling/erb_wrapper.rb deleted file mode 100644 index 8d70b6d..0000000 --- a/vendor/ceedling/lib/ceedling/erb_wrapper.rb +++ /dev/null @@ -1,9 +0,0 @@ -require 'erb' - -class ErbWrapper - def generate_file(template, data, output_file) - File.open(output_file, "w") do |f| - f << ERB.new(template, 0, "<>").result(binding) - end - end -end \ No newline at end of file diff --git a/vendor/ceedling/lib/ceedling/file_finder.rb b/vendor/ceedling/lib/ceedling/file_finder.rb deleted file mode 100644 index 53775b7..0000000 --- a/vendor/ceedling/lib/ceedling/file_finder.rb +++ /dev/null @@ -1,149 +0,0 @@ -require 'rubygems' -require 'rake' # for adding ext() method to string -require 'thread' - - -class FileFinder - SEMAPHORE = Mutex.new - - constructor :configurator, :file_finder_helper, :cacheinator, :file_path_utils, :file_wrapper, :yaml_wrapper - - def prepare_search_sources - @all_test_source_and_header_file_collection = - @configurator.collection_all_tests + - @configurator.collection_all_source + - @configurator.collection_all_headers - end - - - def find_header_file(mock_file) - header = File.basename(mock_file).sub(/#{@configurator.cmock_mock_prefix}/, '').ext(@configurator.extension_header) - - found_path = @file_finder_helper.find_file_in_collection(header, @configurator.collection_all_headers, :error) - - return found_path - end - - - def find_header_input_for_mock_file(mock_file) - found_path = find_header_file(mock_file) - mock_input = found_path - - if (@configurator.project_use_test_preprocessor) - mock_input = @cacheinator.diff_cached_test_file( @file_path_utils.form_preprocessed_file_filepath( found_path ) ) - end - - return mock_input - end - - - def find_source_from_test(test, complain) - test_prefix = @configurator.project_test_file_prefix - source_paths = @configurator.collection_all_source - - source = File.basename(test).sub(/#{test_prefix}/, '') - - # we don't blow up if a test file has no corresponding source file - return @file_finder_helper.find_file_in_collection(source, source_paths, complain) - end - - - def find_test_from_runner_path(runner_path) - extension_source = @configurator.extension_source - - test_file = File.basename(runner_path).sub(/#{@configurator.test_runner_file_suffix}#{'\\'+extension_source}/, extension_source) - - found_path = @file_finder_helper.find_file_in_collection(test_file, @configurator.collection_all_tests, :error) - - return found_path - end - - - def find_test_input_for_runner_file(runner_path) - found_path = find_test_from_runner_path(runner_path) - runner_input = found_path - - if (@configurator.project_use_test_preprocessor) - runner_input = @cacheinator.diff_cached_test_file( @file_path_utils.form_preprocessed_file_filepath( found_path ) ) - end - - return runner_input - end - - - def find_test_from_file_path(file_path) - test_file = File.basename(file_path).ext(@configurator.extension_source) - - found_path = @file_finder_helper.find_file_in_collection(test_file, @configurator.collection_all_tests, :error) - - return found_path - end - - - def find_test_or_source_or_header_file(file_path) - file = File.basename(file_path) - return @file_finder_helper.find_file_in_collection(file, @all_test_source_and_header_file_collection, :error) - end - - - def find_compilation_input_file(file_path, complain=:error, release=false) - found_file = nil - - source_file = File.basename(file_path).ext(@configurator.extension_source) - - # We only collect files that already exist when we start up. - # FileLists can produce undesired results for dynamically generated files depending on when they're accessed. - # So collect mocks and runners separately and right now. - - SEMAPHORE.synchronize { - - if (source_file =~ /#{@configurator.test_runner_file_suffix}/) - found_file = - @file_finder_helper.find_file_in_collection( - source_file, - @file_wrapper.directory_listing( File.join(@configurator.project_test_runners_path, '*') ), - complain) - - elsif (@configurator.project_use_mocks and (source_file =~ /#{@configurator.cmock_mock_prefix}/)) - found_file = - @file_finder_helper.find_file_in_collection( - source_file, - @file_wrapper.directory_listing( File.join(@configurator.cmock_mock_path, '*') ), - complain) - - elsif release - found_file = - @file_finder_helper.find_file_in_collection( - source_file, - @configurator.collection_release_existing_compilation_input, - complain) - else - temp_complain = (defined?(TEST_BUILD_USE_ASSEMBLY) && TEST_BUILD_USE_ASSEMBLY) ? :ignore : complain - found_file = - @file_finder_helper.find_file_in_collection( - source_file, - @configurator.collection_all_existing_compilation_input, - temp_complain) - found_file ||= find_assembly_file(file_path, false) if (defined?(TEST_BUILD_USE_ASSEMBLY) && TEST_BUILD_USE_ASSEMBLY) - end - } - return found_file - end - - - def find_source_file(file_path, complain) - source_file = File.basename(file_path).ext(@configurator.extension_source) - return @file_finder_helper.find_file_in_collection(source_file, @configurator.collection_all_source, complain) - end - - - def find_assembly_file(file_path, complain = :error) - assembly_file = File.basename(file_path).ext(@configurator.extension_assembly) - return @file_finder_helper.find_file_in_collection(assembly_file, @configurator.collection_all_assembly, complain) - end - - def find_file_from_list(file_path, file_list, complain) - return @file_finder_helper.find_file_in_collection(file_path, file_list, complain) - end -end - diff --git a/vendor/ceedling/lib/ceedling/file_finder_helper.rb b/vendor/ceedling/lib/ceedling/file_finder_helper.rb deleted file mode 100644 index a168e5c..0000000 --- a/vendor/ceedling/lib/ceedling/file_finder_helper.rb +++ /dev/null @@ -1,56 +0,0 @@ -require 'fileutils' -require 'ceedling/constants' # for Verbosity enumeration - -class FileFinderHelper - - constructor :streaminator - - - def find_file_in_collection(file_name, file_list, complain, extra_message="") - file_to_find = nil - - file_list.each do |item| - base_file = File.basename(item) - - # case insensitive comparison - if (base_file.casecmp(file_name) == 0) - # case sensitive check - if (base_file == file_name) - file_to_find = item - break - else - blow_up(file_name, "However, a filename having different capitalization was found: '#{item}'.") - end - end - - end - - if file_to_find.nil? - case (complain) - when :error then blow_up(file_name, extra_message) - when :warn then gripe(file_name, extra_message) - #when :ignore then - end - end - - return file_to_find - end - - private - - def blow_up(file_name, extra_message="") - error = "ERROR: Found no file '#{file_name}' in search paths." - error += ' ' if (extra_message.length > 0) - @streaminator.stderr_puts(error + extra_message, Verbosity::ERRORS) - raise - end - - def gripe(file_name, extra_message="") - warning = "WARNING: Found no file '#{file_name}' in search paths." - warning += ' ' if (extra_message.length > 0) - @streaminator.stderr_puts(warning + extra_message, Verbosity::COMPLAIN) - end - -end - - diff --git a/vendor/ceedling/lib/ceedling/file_path_utils.rb b/vendor/ceedling/lib/ceedling/file_path_utils.rb deleted file mode 100644 index 89a28ba..0000000 --- a/vendor/ceedling/lib/ceedling/file_path_utils.rb +++ /dev/null @@ -1,202 +0,0 @@ -require 'rubygems' -require 'rake' # for ext() -require 'fileutils' -require 'ceedling/system_wrapper' - -# global utility methods (for plugins, project files, etc.) -def ceedling_form_filepath(destination_path, original_filepath, new_extension=nil) - filename = File.basename(original_filepath) - filename.replace(filename.ext(new_extension)) if (!new_extension.nil?) - return File.join( destination_path.gsub(/\\/, '/'), filename ) -end - -class FilePathUtils - - GLOB_MATCHER = /[\*\?\{\}\[\]]/ - - constructor :configurator, :file_wrapper - - - ######### class methods ########## - - # standardize path to use '/' path separator & have no trailing path separator - def self.standardize(path) - if path.is_a? String - path.strip! - path.gsub!(/\\/, '/') - path.chomp!('/') - end - return path - end - - def self.os_executable_ext(executable) - return executable.ext('.exe') if SystemWrapper.windows? - return executable - end - - # extract directory path from between optional add/subtract aggregation modifiers and up to glob specifiers - # note: slightly different than File.dirname in that /files/foo remains /files/foo and does not become /files - def self.extract_path(path) - path = path.sub(/^(\+|-):/, '') - - # find first occurrence of path separator followed by directory glob specifier: *, ?, {, }, [, ] - find_index = (path =~ GLOB_MATCHER) - - # no changes needed (lop off final path separator) - return path.chomp('/') if (find_index.nil?) - - # extract up to first glob specifier - path = path[0..(find_index-1)] - - # lop off everything up to and including final path separator - find_index = path.rindex('/') - return path[0..(find_index-1)] if (not find_index.nil?) - - # return string up to first glob specifier if no path separator found - return path - end - - # return whether the given path is to be aggregated (no aggregation modifier defaults to same as +:) - def self.add_path?(path) - return (path =~ /^-:/).nil? - end - - # get path (and glob) lopping off optional +: / -: prefixed aggregation modifiers - def self.extract_path_no_aggregation_operators(path) - return path.sub(/^(\+|-):/, '') - end - - # all the globs that may be in a path string work fine with one exception; - # to recurse through all subdirectories, the glob is dir/**/** but our paths use - # convention of only dir/** - def self.reform_glob(path) - return path if (path =~ /\/\*\*$/).nil? - return path + '/**' - end - - ######### instance methods ########## - - def form_temp_path(filepath, prefix='') - return File.join( @configurator.project_temp_path, prefix + File.basename(filepath) ) - end - - ### release ### - def form_release_build_cache_path(filepath) - return File.join( @configurator.project_release_build_cache_path, File.basename(filepath) ) - end - - def form_release_dependencies_filepath(filepath) - return File.join( @configurator.project_release_dependencies_path, File.basename(filepath).ext(@configurator.extension_dependencies) ) - end - - def form_release_build_c_object_filepath(filepath) - return File.join( @configurator.project_release_build_output_c_path, File.basename(filepath).ext(@configurator.extension_object) ) - end - - def form_release_build_asm_object_filepath(filepath) - return File.join( @configurator.project_release_build_output_asm_path, File.basename(filepath).ext(@configurator.extension_object) ) - end - - def form_release_build_c_objects_filelist(files) - return (@file_wrapper.instantiate_file_list(files)).pathmap("#{@configurator.project_release_build_output_c_path}/%n#{@configurator.extension_object}") - end - - def form_release_build_asm_objects_filelist(files) - return (@file_wrapper.instantiate_file_list(files)).pathmap("#{@configurator.project_release_build_output_asm_path}/%n#{@configurator.extension_object}") - end - - def form_release_build_c_list_filepath(filepath) - return File.join( @configurator.project_release_build_output_c_path, File.basename(filepath).ext(@configurator.extension_list) ) - end - - def form_release_dependencies_filelist(files) - return (@file_wrapper.instantiate_file_list(files)).pathmap("#{@configurator.project_release_dependencies_path}/%n#{@configurator.extension_dependencies}") - end - - ### tests ### - def form_test_build_cache_path(filepath) - return File.join( @configurator.project_test_build_cache_path, File.basename(filepath) ) - end - - def form_test_dependencies_filepath(filepath) - return File.join( @configurator.project_test_dependencies_path, File.basename(filepath).ext(@configurator.extension_dependencies) ) - end - - def form_pass_results_filepath(filepath) - return File.join( @configurator.project_test_results_path, File.basename(filepath).ext(@configurator.extension_testpass) ) - end - - def form_fail_results_filepath(filepath) - return File.join( @configurator.project_test_results_path, File.basename(filepath).ext(@configurator.extension_testfail) ) - end - - def form_runner_filepath_from_test(filepath) - return File.join( @configurator.project_test_runners_path, File.basename(filepath, @configurator.extension_source)) + @configurator.test_runner_file_suffix + @configurator.extension_source - end - - def form_test_filepath_from_runner(filepath) - return filepath.sub(/#{TEST_RUNNER_FILE_SUFFIX}/, '') - end - - def form_runner_object_filepath_from_test(filepath) - return (form_test_build_c_object_filepath(filepath)).sub(/(#{@configurator.extension_object})$/, "#{@configurator.test_runner_file_suffix}\\1") - end - - def form_test_build_c_object_filepath(filepath) - return File.join( @configurator.project_test_build_output_c_path, File.basename(filepath).ext(@configurator.extension_object) ) - end - - def form_test_build_asm_object_filepath(filepath) - return File.join( @configurator.project_test_build_output_asm_path, File.basename(filepath).ext(@configurator.extension_object) ) - end - - def form_test_executable_filepath(filepath) - return File.join( @configurator.project_test_build_output_path, File.basename(filepath).ext(@configurator.extension_executable) ) - end - - def form_test_build_map_filepath(filepath) - return File.join( @configurator.project_test_build_output_path, File.basename(filepath).ext(@configurator.extension_map) ) - end - - def form_test_build_list_filepath(filepath) - return File.join( @configurator.project_test_build_output_path, File.basename(filepath).ext(@configurator.extension_list) ) - end - - def form_preprocessed_file_filepath(filepath) - return File.join( @configurator.project_test_preprocess_files_path, File.basename(filepath) ) - end - - def form_preprocessed_includes_list_filepath(filepath) - return File.join( @configurator.project_test_preprocess_includes_path, File.basename(filepath) ) - end - - def form_test_build_objects_filelist(sources) - return (@file_wrapper.instantiate_file_list(sources)).pathmap("#{@configurator.project_test_build_output_c_path}/%n#{@configurator.extension_object}") - end - - def form_preprocessed_mockable_headers_filelist(mocks) - list = @file_wrapper.instantiate_file_list(mocks) - headers = list.map do |file| - module_name = File.basename(file).sub(/^#{@configurator.cmock_mock_prefix}/, '').sub(/\.[a-zA-Z]+$/,'') - "#{@configurator.project_test_preprocess_files_path}/#{module_name}#{@configurator.extension_header}" - end - return headers - end - - def form_mocks_source_filelist(mocks) - list = (@file_wrapper.instantiate_file_list(mocks)) - sources = list.map{|file| "#{@configurator.cmock_mock_path}/#{file}#{@configurator.extension_source}"} - return sources - end - - def form_test_dependencies_filelist(files) - list = @file_wrapper.instantiate_file_list(files) - return list.pathmap("#{@configurator.project_test_dependencies_path}/%n#{@configurator.extension_dependencies}") - end - - def form_pass_results_filelist(path, files) - list = @file_wrapper.instantiate_file_list(files) - return list.pathmap("#{path}/%n#{@configurator.extension_testpass}") - end - -end diff --git a/vendor/ceedling/lib/ceedling/file_system_utils.rb b/vendor/ceedling/lib/ceedling/file_system_utils.rb deleted file mode 100644 index 97e5856..0000000 --- a/vendor/ceedling/lib/ceedling/file_system_utils.rb +++ /dev/null @@ -1,69 +0,0 @@ -require 'rubygems' -require 'rake' -require 'set' -require 'fileutils' -require 'ceedling/file_path_utils' - - -class FileSystemUtils - - constructor :file_wrapper - - # build up path list from input of one or more strings or arrays of (+/-) paths & globs - def collect_paths(*paths) - raw = [] # all paths and globs - plus = Set.new # all paths to expand and add - minus = Set.new # all paths to remove from plus set - - # assemble all globs and simple paths, reforming our glob notation to ruby globs - paths.each do |paths_container| - case (paths_container) - when String then raw << (FilePathUtils::reform_glob(paths_container)) - when Array then paths_container.each {|path| raw << (FilePathUtils::reform_glob(path))} - else raise "Don't know how to handle #{paths_container.class}" - end - end - - # iterate through each path and glob - raw.each do |path| - - dirs = [] # container for only (expanded) paths - - # if a glob, expand it and slurp up all non-file paths - if path.include?('*') - # grab base directory only if globs are snug up to final path separator - if (path =~ /\/\*+$/) - dirs << FilePathUtils.extract_path(path) - end - - # grab expanded sub-directory globs - expanded = @file_wrapper.directory_listing( FilePathUtils.extract_path_no_aggregation_operators(path) ) - expanded.each do |entry| - dirs << entry if @file_wrapper.directory?(entry) - end - - # else just grab simple path - # note: we could just run this through glob expansion but such an - # approach doesn't handle a path not yet on disk) - else - dirs << FilePathUtils.extract_path_no_aggregation_operators(path) - end - - # add dirs to the appropriate set based on path aggregation modifier if present - FilePathUtils.add_path?(path) ? plus.merge(dirs) : minus.merge(dirs) - end - - return (plus - minus).to_a.uniq - end - - - # given a file list, add to it or remove from it - def revise_file_list(list, revisions) - revisions.each do |revision| - # include or exclude file or glob to file list - file = FilePathUtils.extract_path_no_aggregation_operators( revision ) - FilePathUtils.add_path?(revision) ? list.include(file) : list.exclude(file) - end - end - -end diff --git a/vendor/ceedling/lib/ceedling/file_system_wrapper.rb b/vendor/ceedling/lib/ceedling/file_system_wrapper.rb deleted file mode 100644 index 807cbd2..0000000 --- a/vendor/ceedling/lib/ceedling/file_system_wrapper.rb +++ /dev/null @@ -1,10 +0,0 @@ - -class FileSystemWrapper - - def cd(path) - FileUtils.cd path do - yield - end - end - -end \ No newline at end of file diff --git a/vendor/ceedling/lib/ceedling/file_wrapper.rb b/vendor/ceedling/lib/ceedling/file_wrapper.rb deleted file mode 100644 index 9e5a909..0000000 --- a/vendor/ceedling/lib/ceedling/file_wrapper.rb +++ /dev/null @@ -1,83 +0,0 @@ -require 'rubygems' -require 'rake' # for FileList -require 'fileutils' -require 'ceedling/constants' - - -class FileWrapper - - def get_expanded_path(path) - return File.expand_path(path) - end - - def basename(path, extension=nil) - return File.basename(path, extension) if extension - return File.basename(path) - end - - def exist?(filepath) - return true if (filepath == NULL_FILE_PATH) - return File.exist?(filepath) - end - - def directory?(path) - return File.directory?(path) - end - - def dirname(path) - return File.dirname(path) - end - - def directory_listing(glob) - return Dir.glob(glob, File::FNM_PATHNAME) - end - - def rm_f(filepath, options={}) - FileUtils.rm_f(filepath, **options) - end - - def rm_r(filepath, options={}) - FileUtils.rm_r(filepath, **options={}) - end - - def cp(source, destination, options={}) - FileUtils.cp(source, destination, **options) - end - - def compare(from, to) - return FileUtils.compare_file(from, to) - end - - def open(filepath, flags) - File.open(filepath, flags) do |file| - yield(file) - end - end - - def read(filepath) - return File.read(filepath) - end - - def touch(filepath, options={}) - FileUtils.touch(filepath, **options) - end - - def write(filepath, contents, flags='w') - File.open(filepath, flags) do |file| - file.write(contents) - end - end - - def readlines(filepath) - return File.readlines(filepath) - end - - def instantiate_file_list(files=[]) - return FileList.new(files) - end - - def mkdir(folder) - return FileUtils.mkdir_p(folder) - end - -end diff --git a/vendor/ceedling/lib/ceedling/flaginator.rb b/vendor/ceedling/lib/ceedling/flaginator.rb deleted file mode 100644 index 31d62c4..0000000 --- a/vendor/ceedling/lib/ceedling/flaginator.rb +++ /dev/null @@ -1,74 +0,0 @@ -require 'rubygems' -require 'rake' # for ext() -require 'fileutils' -require 'ceedling/constants' - - -# :flags: -# :release: -# :compile: -# :'test_.+' -# - -pedantic # add '-pedantic' to every test file -# :*: # add '-foo' to compilation of all files not main.c -# - -foo -# :main: # add '-Wall' to compilation of main.c -# - -Wall -# :test: -# :link: -# :test_main: # add '--bar --baz' to linking of test_main.exe -# - --bar -# - --baz - -def partition(hash, &predicate) - hash.partition(&predicate).map(&:to_h) -end - -class Flaginator - - constructor :configurator - - def get_flag(hash, file_name) - file_key = file_name.to_sym - - # 1. try literals - literals, magic = partition(hash) { |k, v| k.to_s =~ /^\w+$/ } - return literals[file_key] if literals.include?(file_key) - - any, regex = partition(magic) { |k, v| (k == :'*') || (k == :'.*') } # glob or regex wild card - - # 2. try regexes - find_res = regex.find { |k, v| file_name =~ /^#{k.to_s}$/ } - return find_res[1] if find_res - - # 3. try anything - find_res = any.find { |k, v| file_name =~ /.*/ } - return find_res[1] if find_res - - # 4. well, we've tried - return [] - end - - def flag_down( operation, context, file ) - # create configurator accessor method - accessor = ('flags_' + context.to_s).to_sym - - # create simple filename key from whatever filename provided - file_name = File.basename( file ).ext('') - file_key = File.basename( file ).ext('').to_sym - - # if no entry in configuration for flags for this context, bail out - return [] if not @configurator.respond_to?( accessor ) - - # get flags sub hash associated with this context - flags = @configurator.send( accessor ) - - # if operation not represented in flags hash, bail out - return [] if not flags.include?( operation ) - - # redefine flags to sub hash associated with the operation - flags = flags[operation] - - return get_flag(flags, file_name) - end - -end diff --git a/vendor/ceedling/lib/ceedling/generator.rb b/vendor/ceedling/lib/ceedling/generator.rb deleted file mode 100644 index 0b89024..0000000 --- a/vendor/ceedling/lib/ceedling/generator.rb +++ /dev/null @@ -1,186 +0,0 @@ -require 'ceedling/constants' - -class Generator - - constructor :configurator, - :generator_helper, - :preprocessinator, - :cmock_builder, - :generator_test_runner, - :generator_test_results, - :flaginator, - :test_includes_extractor, - :tool_executor, - :file_finder, - :file_path_utils, - :streaminator, - :plugin_manager, - :file_wrapper - - - def generate_shallow_includes_list(context, file) - @streaminator.stdout_puts("Generating include list for #{File.basename(file)}...", Verbosity::NORMAL) - @preprocessinator.preprocess_shallow_includes(file) - end - - def generate_preprocessed_file(context, file) - @streaminator.stdout_puts("Preprocessing #{File.basename(file)}...", Verbosity::NORMAL) - @preprocessinator.preprocess_file(file) - end - - def generate_dependencies_file(tool, context, source, object, dependencies) - @streaminator.stdout_puts("Generating dependencies for #{File.basename(source)}...", Verbosity::NORMAL) - - command = - @tool_executor.build_command_line( - tool, - [], # extra per-file command line parameters - source, - dependencies, - object) - - @tool_executor.exec( command[:line], command[:options] ) - end - - def generate_mock(context, header_filepath) - arg_hash = {:header_file => header_filepath, :context => context} - @plugin_manager.pre_mock_generate( arg_hash ) - - begin - @cmock_builder.cmock.setup_mocks( arg_hash[:header_file] ) - rescue - raise - ensure - @plugin_manager.post_mock_generate( arg_hash ) - end - end - - # test_filepath may be either preprocessed test file or original test file - def generate_test_runner(context, test_filepath, runner_filepath) - arg_hash = {:context => context, :test_file => test_filepath, :runner_file => runner_filepath} - @plugin_manager.pre_runner_generate(arg_hash) - - # collect info we need - module_name = File.basename(arg_hash[:test_file]) - test_cases = @generator_test_runner.find_test_cases( @file_finder.find_test_from_runner_path(runner_filepath) ) - mock_list = @test_includes_extractor.lookup_raw_mock_list(arg_hash[:test_file]) - - @streaminator.stdout_puts("Generating runner for #{module_name}...", Verbosity::NORMAL) - - test_file_includes = [] # Empty list for now, since apparently unused - - # build runner file - begin - @generator_test_runner.generate(module_name, runner_filepath, test_cases, mock_list, test_file_includes) - rescue - raise - ensure - @plugin_manager.post_runner_generate(arg_hash) - end - end - - def generate_object_file(tool, operation, context, source, object, list='', dependencies='') - shell_result = {} - arg_hash = {:tool => tool, :operation => operation, :context => context, :source => source, :object => object, :list => list, :dependencies => dependencies} - @plugin_manager.pre_compile_execute(arg_hash) - - @streaminator.stdout_puts("Compiling #{File.basename(arg_hash[:source])}...", Verbosity::NORMAL) - command = - @tool_executor.build_command_line( arg_hash[:tool], - @flaginator.flag_down( operation, context, source ), - arg_hash[:source], - arg_hash[:object], - arg_hash[:list], - arg_hash[:dependencies]) - - @streaminator.stdout_puts("Command: #{command}", Verbosity::DEBUG) - - begin - shell_result = @tool_executor.exec( command[:line], command[:options] ) - rescue ShellExecutionException => ex - shell_result = ex.shell_result - raise ex - ensure - arg_hash[:shell_command] = command[:line] - arg_hash[:shell_result] = shell_result - @plugin_manager.post_compile_execute(arg_hash) - end - end - - def generate_executable_file(tool, context, objects, executable, map='', libraries=[], libpaths=[]) - shell_result = {} - arg_hash = { :tool => tool, - :context => context, - :objects => objects, - :executable => executable, - :map => map, - :libraries => libraries, - :libpaths => libpaths - } - - @plugin_manager.pre_link_execute(arg_hash) - - @streaminator.stdout_puts("Linking #{File.basename(arg_hash[:executable])}...", Verbosity::NORMAL) - command = - @tool_executor.build_command_line( arg_hash[:tool], - @flaginator.flag_down( OPERATION_LINK_SYM, context, executable ), - arg_hash[:objects], - arg_hash[:executable], - arg_hash[:map], - arg_hash[:libraries], - arg_hash[:libpaths] - ) - @streaminator.stdout_puts("Command: #{command}", Verbosity::DEBUG) - - begin - shell_result = @tool_executor.exec( command[:line], command[:options] ) - rescue ShellExecutionException => ex - notice = "\n" + - "NOTICE: If the linker reports missing symbols, the following may be to blame:\n" + - " 1. Test lacks #include statements corresponding to needed source files.\n" + - " 2. Project search paths do not contain source files corresponding to #include statements in the test.\n" - - if (@configurator.project_use_mocks) - notice += " 3. Test does not #include needed mocks.\n\n" - else - notice += "\n" - end - - @streaminator.stderr_puts(notice, Verbosity::COMPLAIN) - shell_result = ex.shell_result - raise '' - ensure - arg_hash[:shell_result] = shell_result - @plugin_manager.post_link_execute(arg_hash) - end - end - - def generate_test_results(tool, context, executable, result) - arg_hash = {:tool => tool, :context => context, :executable => executable, :result_file => result} - @plugin_manager.pre_test_fixture_execute(arg_hash) - - @streaminator.stdout_puts("Running #{File.basename(arg_hash[:executable])}...", Verbosity::NORMAL) - - # Unity's exit code is equivalent to the number of failed tests, so we tell @tool_executor not to fail out if there are failures - # so that we can run all tests and collect all results - command = @tool_executor.build_command_line(arg_hash[:tool], [], arg_hash[:executable]) - @streaminator.stdout_puts("Command: #{command}", Verbosity::DEBUG) - command[:options][:boom] = false - shell_result = @tool_executor.exec( command[:line], command[:options] ) - - #Don't Let The Failure Count Make Us Believe Things Aren't Working - shell_result[:exit_code] = 0 - @generator_helper.test_results_error_handler(executable, shell_result) - - processed = @generator_test_results.process_and_write_results( shell_result, - arg_hash[:result_file], - @file_finder.find_test_from_file_path(arg_hash[:executable]) ) - - arg_hash[:result_file] = processed[:result_file] - arg_hash[:results] = processed[:results] - arg_hash[:shell_result] = shell_result # for raw output display if no plugins for formatted display - - @plugin_manager.post_test_fixture_execute(arg_hash) - end - -end diff --git a/vendor/ceedling/lib/ceedling/generator_helper.rb b/vendor/ceedling/lib/ceedling/generator_helper.rb deleted file mode 100644 index 3431560..0000000 --- a/vendor/ceedling/lib/ceedling/generator_helper.rb +++ /dev/null @@ -1,40 +0,0 @@ -require 'ceedling/constants' - - -class GeneratorHelper - - constructor :streaminator - - - def test_results_error_handler(executable, shell_result) - notice = '' - error = false - - if (shell_result[:output].nil? or shell_result[:output].strip.empty?) - error = true - # mirror style of generic tool_executor failure output - notice = "\n" + - "ERROR: Test executable \"#{File.basename(executable)}\" failed.\n" + - "> Produced no output to $stdout.\n" - elsif ((shell_result[:output] =~ TEST_STDOUT_STATISTICS_PATTERN).nil?) - error = true - # mirror style of generic tool_executor failure output - notice = "\n" + - "ERROR: Test executable \"#{File.basename(executable)}\" failed.\n" + - "> Produced no final test result counts in $stdout:\n" + - "#{shell_result[:output].strip}\n" - end - - if (error) - # since we told the tool executor to ignore the exit code, handle it explicitly here - notice += "> And exited with status: [#{shell_result[:exit_code]}] (count of failed tests).\n" if (shell_result[:exit_code] != nil) - notice += "> And then likely crashed.\n" if (shell_result[:exit_code] == nil) - - notice += "> This is often a symptom of a bad memory access in source or test code.\n\n" - - @streaminator.stderr_puts(notice, Verbosity::COMPLAIN) - raise - end - end - -end diff --git a/vendor/ceedling/lib/ceedling/generator_test_results.rb b/vendor/ceedling/lib/ceedling/generator_test_results.rb deleted file mode 100644 index 3af2d72..0000000 --- a/vendor/ceedling/lib/ceedling/generator_test_results.rb +++ /dev/null @@ -1,100 +0,0 @@ -require 'rubygems' -require 'rake' # for .ext() -require 'ceedling/constants' - -class GeneratorTestResults - - constructor :configurator, :generator_test_results_sanity_checker, :yaml_wrapper - - def process_and_write_results(unity_shell_result, results_file, test_file) - output_file = results_file - - results = get_results_structure - - results[:source][:path] = File.dirname(test_file) - results[:source][:file] = File.basename(test_file) - results[:time] = unity_shell_result[:time] unless unity_shell_result[:time].nil? - - # process test statistics - if (unity_shell_result[:output] =~ TEST_STDOUT_STATISTICS_PATTERN) - results[:counts][:total] = $1.to_i - results[:counts][:failed] = $2.to_i - results[:counts][:ignored] = $3.to_i - results[:counts][:passed] = (results[:counts][:total] - results[:counts][:failed] - results[:counts][:ignored]) - end - - # remove test statistics lines - output_string = unity_shell_result[:output].sub(TEST_STDOUT_STATISTICS_PATTERN, '') - - output_string.lines do |line| - # process unity output - case line - when /(:IGNORE)/ - elements = extract_line_elements(line, results[:source][:file]) - results[:ignores] << elements[0] - results[:stdout] << elements[1] if (!elements[1].nil?) - when /(:PASS$)/ - elements = extract_line_elements(line, results[:source][:file]) - results[:successes] << elements[0] - results[:stdout] << elements[1] if (!elements[1].nil?) - when /(:PASS \(.* ms\)$)/ - elements = extract_line_elements(line, results[:source][:file]) - results[:successes] << elements[0] - results[:stdout] << elements[1] if (!elements[1].nil?) - when /(:FAIL)/ - elements = extract_line_elements(line, results[:source][:file]) - results[:failures] << elements[0] - results[:stdout] << elements[1] if (!elements[1].nil?) - else # collect up all other - results[:stdout] << line.chomp - end - end - - @generator_test_results_sanity_checker.verify(results, unity_shell_result[:exit_code]) - - output_file = results_file.ext(@configurator.extension_testfail) if (results[:counts][:failed] > 0) - - @yaml_wrapper.dump(output_file, results) - - return { :result_file => output_file, :result => results } - end - - private - - def get_results_structure - return { - :source => {:path => '', :file => ''}, - :successes => [], - :failures => [], - :ignores => [], - :counts => {:total => 0, :passed => 0, :failed => 0, :ignored => 0}, - :stdout => [], - :time => 0.0 - } - end - - def extract_line_elements(line, filename) - # handle anything preceding filename in line as extra output to be collected - stdout = nil - stdout_regex = /(.+)#{Regexp.escape(filename)}.+/i - unity_test_time = 0 - - if (line =~ stdout_regex) - stdout = $1.clone - line.sub!(/#{Regexp.escape(stdout)}/, '') - end - - # collect up test results minus and extra output - elements = (line.strip.split(':'))[1..-1] - - # find timestamp if available - if (elements[-1] =~ / \((\d*(?:\.\d*)?) ms\)/) - unity_test_time = $1.to_f / 1000 - elements[-1].sub!(/ \((\d*(?:\.\d*)?) ms\)/, '') - end - - return {:test => elements[1], :line => elements[0].to_i, :message => (elements[3..-1].join(':')).strip, :unity_test_time => unity_test_time}, stdout if elements.size >= 3 - return {:test => '???', :line => -1, :message => nil, :unity_test_time => unity_test_time} #fallback safe option. TODO better handling - end - -end diff --git a/vendor/ceedling/lib/ceedling/generator_test_results_sanity_checker.rb b/vendor/ceedling/lib/ceedling/generator_test_results_sanity_checker.rb deleted file mode 100644 index 0b51832..0000000 --- a/vendor/ceedling/lib/ceedling/generator_test_results_sanity_checker.rb +++ /dev/null @@ -1,65 +0,0 @@ -require 'rubygems' -require 'rake' # for ext() method -require 'ceedling/constants' - - -class GeneratorTestResultsSanityChecker - - constructor :configurator, :streaminator - - def verify(results, unity_exit_code) - - # do no sanity checking if it's disabled - return if (@configurator.sanity_checks == TestResultsSanityChecks::NONE) - raise "results nil or empty" if results.nil? || results.empty? - - ceedling_ignores_count = results[:ignores].size - ceedling_failures_count = results[:failures].size - ceedling_tests_summation = (ceedling_ignores_count + ceedling_failures_count + results[:successes].size) - - # Exit code handling is not a sanity check that can always be performed because - # command line simulators may or may not pass through Unity's exit code - if (@configurator.sanity_checks >= TestResultsSanityChecks::THOROUGH) - # many platforms limit exit codes to a maximum of 255 - if ((ceedling_failures_count != unity_exit_code) and (unity_exit_code < 255)) - sanity_check_warning(results[:source][:file], "Unity's exit code (#{unity_exit_code}) does not match Ceedling's summation of failed test cases (#{ceedling_failures_count}).") - end - - if ((ceedling_failures_count < 255) and (unity_exit_code == 255)) - sanity_check_warning(results[:source][:file], "Ceedling's summation of failed test cases (#{ceedling_failures_count}) is less than Unity's exit code (255 or more).") - end - end - - if (ceedling_ignores_count != results[:counts][:ignored]) - sanity_check_warning(results[:source][:file], "Unity's final ignore count (#{results[:counts][:ignored]}) does not match Ceedling's summation of ignored test cases (#{ceedling_ignores_count}).") - end - - if (ceedling_failures_count != results[:counts][:failed]) - sanity_check_warning(results[:source][:file], "Unity's final fail count (#{results[:counts][:failed]}) does not match Ceedling's summation of failed test cases (#{ceedling_failures_count}).") - end - - if (ceedling_tests_summation != results[:counts][:total]) - sanity_check_warning(results[:source][:file], "Unity's final test count (#{results[:counts][:total]}) does not match Ceedling's summation of all test cases (#{ceedling_tests_summation}).") - end - - end - - private - - def sanity_check_warning(file, message) - unless defined?(CEEDLING_IGNORE_SANITY_CHECK) - notice = "\n" + - "ERROR: Internal sanity check for test fixture '#{file.ext(@configurator.extension_executable)}' finds that #{message}\n" + - " Possible causes:\n" + - " 1. Your test + source dereferenced a null pointer.\n" + - " 2. Your test + source indexed past the end of a buffer.\n" + - " 3. Your test + source committed a memory access violation.\n" + - " 4. Your test fixture produced an exit code of 0 despite execution ending prematurely.\n" + - " Sanity check failures of test results are usually a symptom of interrupted test execution.\n\n" - - @streaminator.stderr_puts( notice ) - raise - end - end - -end diff --git a/vendor/ceedling/lib/ceedling/generator_test_runner.rb b/vendor/ceedling/lib/ceedling/generator_test_runner.rb deleted file mode 100644 index 79ed714..0000000 --- a/vendor/ceedling/lib/ceedling/generator_test_runner.rb +++ /dev/null @@ -1,58 +0,0 @@ - -class GeneratorTestRunner - - constructor :configurator, :file_path_utils, :file_wrapper - - def find_test_cases(test_file) - - #Pull in Unity's Test Runner Generator - require 'generate_test_runner.rb' - @test_runner_generator ||= UnityTestRunnerGenerator.new( @configurator.get_runner_config ) - - if (@configurator.project_use_test_preprocessor) - - #redirect to use the preprocessor file if we're doing that sort of thing - pre_test_file = @file_path_utils.form_preprocessed_file_filepath(test_file) - - #actually look for the tests using Unity's test runner generator - contents = @file_wrapper.read(pre_test_file) - tests_and_line_numbers = @test_runner_generator.find_tests(contents) - @test_runner_generator.find_setup_and_teardown(contents) - - #look up the line numbers in the original file - source_lines = @file_wrapper.read(test_file).split("\n") - 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 - end - end - else - #Just look for the tests using Unity's test runner generator - contents = @file_wrapper.read(test_file) - tests_and_line_numbers = @test_runner_generator.find_tests(contents) - @test_runner_generator.find_setup_and_teardown(contents) - end - - return tests_and_line_numbers - end - - def generate(module_name, runner_filepath, test_cases, mock_list, test_file_includes=[]) - require 'generate_test_runner.rb' - - header_extension = @configurator.extension_header - - #actually build the test runner using Unity's test runner generator - #(there is no need to use preprocessor here because we've already looked up test cases and are passing them in here) - @test_runner_generator ||= UnityTestRunnerGenerator.new( @configurator.get_runner_config ) - @test_runner_generator.generate( module_name, - runner_filepath, - test_cases, - mock_list.map{|f| File.basename(f,'.*')+header_extension}, - test_file_includes.map{|f| File.basename(f,'.*')+header_extension}) - end -end diff --git a/vendor/ceedling/lib/ceedling/loginator.rb b/vendor/ceedling/lib/ceedling/loginator.rb deleted file mode 100644 index 92276e1..0000000 --- a/vendor/ceedling/lib/ceedling/loginator.rb +++ /dev/null @@ -1,31 +0,0 @@ - -class Loginator - - constructor :configurator, :project_file_loader, :project_config_manager, :file_wrapper, :system_wrapper - - - def setup_log_filepath - config_files = [] - config_files << @project_file_loader.main_file - config_files << @project_file_loader.user_file - config_files.concat( @project_config_manager.options_files ) - config_files.compact! - config_files.map! { |file| file.ext('') } - - log_name = config_files.join( '_' ) - - @project_log_filepath = File.join( @configurator.project_log_path, log_name.ext('.log') ) - end - - - def log(string, heading=nil) - return if (not @configurator.project_logging) - - output = "\n[#{@system_wrapper.time_now}]" - output += " :: #{heading}" if (not heading.nil?) - output += "\n#{string.strip}\n" - - @file_wrapper.write(@project_log_filepath, output, 'a') - end - -end diff --git a/vendor/ceedling/lib/ceedling/makefile.rb b/vendor/ceedling/lib/ceedling/makefile.rb deleted file mode 100644 index c3d7496..0000000 --- a/vendor/ceedling/lib/ceedling/makefile.rb +++ /dev/null @@ -1,46 +0,0 @@ - -# modified version of Rake's provided make-style dependency loader -# customizations: -# (1) handles windows drives in paths -- colons don't confuse task demarcation -# (2) handles spaces in directory paths - -module Rake - - # Makefile loader to be used with the import file loader. - class MakefileLoader - - # Load the makefile dependencies in +fn+. - def load(fn) - open(fn) do |mf| - lines = mf.read - lines.gsub!(/#[^\n]*\n/m, "") # remove comments - lines.gsub!(/\\\n/, ' ') # string together line continuations into single line - lines.split("\n").each do |line| - process_line(line) - end - end - end - - private - - # Process one logical line of makefile data. - def process_line(line) - # split on presence of task demaractor followed by space (i.e don't get confused by a colon in a win path) - file_tasks, args = line.split(/:\s/) - - return if args.nil? - - # split at non-escaped space boundary between files (i.e. escaped spaces in paths are left alone) - dependents = args.split(/\b\s+/) - # replace escaped spaces and clean up any extra whitespace - dependents.map! { |path| path.gsub(/\\ /, ' ').strip } - - file_tasks.strip.split.each do |file_task| - file file_task => dependents - end - end - end - - # Install the handler - Rake.application.add_loader('mf', MakefileLoader.new) -end diff --git a/vendor/ceedling/lib/ceedling/objects.yml b/vendor/ceedling/lib/ceedling/objects.yml deleted file mode 100644 index 43bbc06..0000000 --- a/vendor/ceedling/lib/ceedling/objects.yml +++ /dev/null @@ -1,313 +0,0 @@ - -file_wrapper: - -file_system_wrapper: - -stream_wrapper: - -rake_wrapper: - -yaml_wrapper: - -system_wrapper: - -cmock_builder: - -reportinator: - -rake_utils: - compose: - - rake_wrapper - -system_utils: - compose: - - system_wrapper - -file_path_utils: - compose: - - configurator - - file_wrapper - -file_system_utils: - compose: file_wrapper - -project_file_loader: - compose: - - yaml_wrapper - - stream_wrapper - - system_wrapper - - file_wrapper - -project_config_manager: - compose: - - cacheinator - - configurator - - yaml_wrapper - - file_wrapper - -cacheinator: - compose: - - cacheinator_helper - - file_path_utils - - file_wrapper - - yaml_wrapper - -cacheinator_helper: - compose: - - file_wrapper - - yaml_wrapper - -tool_executor: - compose: - - configurator - - tool_executor_helper - - streaminator - - system_wrapper - -tool_executor_helper: - compose: - - streaminator - - system_utils - - system_wrapper - -configurator: - compose: - - configurator_setup - - configurator_plugins - - configurator_builder - - cmock_builder - - yaml_wrapper - - system_wrapper - -configurator_setup: - compose: - - configurator_builder - - configurator_validator - - configurator_plugins - - stream_wrapper - -configurator_plugins: - compose: - - stream_wrapper - - file_wrapper - - system_wrapper - -configurator_validator: - compose: - - file_wrapper - - stream_wrapper - - system_wrapper - -configurator_builder: - compose: - - file_system_utils - - file_wrapper - - system_wrapper - -loginator: - compose: - - configurator - - project_file_loader - - project_config_manager - - file_wrapper - - system_wrapper - -streaminator: - compose: - - streaminator_helper - - verbosinator - - loginator - - stream_wrapper - -streaminator_helper: - -setupinator: - -plugin_builder: - -plugin_manager: - compose: - - configurator - - plugin_manager_helper - - streaminator - - reportinator - - system_wrapper - -plugin_manager_helper: - -plugin_reportinator: - compose: - - plugin_reportinator_helper - - plugin_manager - - reportinator - -plugin_reportinator_helper: - compose: - - configurator - - streaminator - - yaml_wrapper - - file_wrapper - -verbosinator: - compose: configurator - -file_finder: - compose: - - configurator - - file_finder_helper - - cacheinator - - file_path_utils - - file_wrapper - - yaml_wrapper - -file_finder_helper: - compose: streaminator - -test_includes_extractor: - compose: - - configurator - - yaml_wrapper - - file_wrapper - -task_invoker: - compose: - - dependinator - - rake_utils - - rake_wrapper - - project_config_manager - -flaginator: - compose: - - configurator - -generator: - compose: - - configurator - - generator_helper - - preprocessinator - - cmock_builder - - generator_test_runner - - generator_test_results - - flaginator - - test_includes_extractor - - tool_executor - - file_finder - - file_path_utils - - streaminator - - plugin_manager - - file_wrapper - -generator_helper: - compose: - - streaminator - -generator_test_results: - compose: - - configurator - - generator_test_results_sanity_checker - - yaml_wrapper - -generator_test_results_sanity_checker: - compose: - - configurator - - streaminator - -generator_test_runner: - compose: - - configurator - - file_path_utils - - file_wrapper - -dependinator: - compose: - - configurator - - project_config_manager - - test_includes_extractor - - file_path_utils - - rake_wrapper - - file_wrapper - -preprocessinator: - compose: - - preprocessinator_helper - - preprocessinator_includes_handler - - preprocessinator_file_handler - - task_invoker - - file_path_utils - - yaml_wrapper - - project_config_manager - - configurator - -preprocessinator_helper: - compose: - - configurator - - test_includes_extractor - - task_invoker - - file_finder - - file_path_utils - -preprocessinator_includes_handler: - compose: - - configurator - - tool_executor - - task_invoker - - file_path_utils - - yaml_wrapper - - file_wrapper - - file_finder - -preprocessinator_file_handler: - compose: - - preprocessinator_extractor - - configurator - - tool_executor - - file_path_utils - - file_wrapper - -preprocessinator_extractor: - -test_invoker: - compose: - - configurator - - test_invoker_helper - - plugin_manager - - streaminator - - preprocessinator - - task_invoker - - dependinator - - project_config_manager - - build_invoker_utils - - file_path_utils - - file_wrapper - -test_invoker_helper: - compose: - - configurator - - task_invoker - - test_includes_extractor - - file_finder - - file_path_utils - - file_wrapper - -release_invoker: - compose: - - configurator - - release_invoker_helper - - build_invoker_utils - - dependinator - - task_invoker - - file_path_utils - - file_wrapper - -release_invoker_helper: - compose: - - configurator - - dependinator - - task_invoker - -build_invoker_utils: - compose: - - configurator - - streaminator - -erb_wrapper: diff --git a/vendor/ceedling/lib/ceedling/par_map.rb b/vendor/ceedling/lib/ceedling/par_map.rb deleted file mode 100644 index 98198a2..0000000 --- a/vendor/ceedling/lib/ceedling/par_map.rb +++ /dev/null @@ -1,19 +0,0 @@ - - -def par_map(n, things, &block) - queue = Queue.new - things.each { |thing| queue << thing } - threads = (1..n).collect do - Thread.new do - begin - while true - yield queue.pop(true) - end - rescue ThreadError - - end - end - end - threads.each { |t| t.join } -end - diff --git a/vendor/ceedling/lib/ceedling/plugin.rb b/vendor/ceedling/lib/ceedling/plugin.rb deleted file mode 100644 index f20b3a3..0000000 --- a/vendor/ceedling/lib/ceedling/plugin.rb +++ /dev/null @@ -1,80 +0,0 @@ - -class String - # reformat a multiline string to have given number of whitespace columns; - # helpful for formatting heredocs - def left_margin(margin=0) - non_whitespace_column = 0 - new_lines = [] - - # find first line with non-whitespace and count left columns of whitespace - self.each_line do |line| - if (line =~ /^\s*\S/) - non_whitespace_column = $&.length - 1 - break - end - end - - # iterate through each line, chopping off leftmost whitespace columns and add back the desired whitespace margin - self.each_line do |line| - columns = [] - margin.times{columns << ' '} - # handle special case of line being narrower than width to be lopped off - if (non_whitespace_column < line.length) - new_lines << "#{columns.join}#{line[non_whitespace_column..-1]}" - else - new_lines << "\n" - end - end - - return new_lines.join - end -end - -class Plugin - attr_reader :name, :environment - attr_accessor :plugin_objects - - def initialize(system_objects, name) - @environment = [] - @ceedling = system_objects - @name = name - self.setup - end - - def setup; end - - # mock generation - def pre_mock_generate(arg_hash); end - def post_mock_generate(arg_hash); end - - # test runner generation - def pre_runner_generate(arg_hash); end - def post_runner_generate(arg_hash); end - - # compilation (test or source) - def pre_compile_execute(arg_hash); end - def post_compile_execute(arg_hash); end - - # linking (test or source) - def pre_link_execute(arg_hash); end - def post_link_execute(arg_hash); end - - # test fixture execution - def pre_test_fixture_execute(arg_hash); end - def post_test_fixture_execute(arg_hash); end - - # test task - def pre_test(test); end - def post_test(test); end - - # release task - def pre_release; end - def post_release; end - - # whole shebang (any use of Ceedling) - def pre_build; end - def post_build; end - - def summary; end - -end diff --git a/vendor/ceedling/lib/ceedling/plugin_builder.rb b/vendor/ceedling/lib/ceedling/plugin_builder.rb deleted file mode 100644 index 1269141..0000000 --- a/vendor/ceedling/lib/ceedling/plugin_builder.rb +++ /dev/null @@ -1,53 +0,0 @@ -require 'ceedling/plugin' - -class PluginBuilder - - attr_accessor :plugin_objects - - def construct_plugin(plugin_name, object_map_yaml, system_objects) - # @streaminator.stdout_puts("Constructing plugin #{plugin_name}...", Verbosity::OBNOXIOUS) - object_map = {} - @plugin_objects = {} - @system_objects = system_objects - - if object_map_yaml - @object_map = YAML.load(object_map_yaml) - @object_map.each_key do |obj| - construct_object(obj) - end - else - raise "Invalid object map for plugin #{plugin_name}!" - end - - return @plugin_objects - end - - private - - def camelize(underscored_name) - return underscored_name.gsub(/(_|^)([a-z0-9])/) {$2.upcase} - end - - def construct_object(obj) - if @plugin_objects[obj].nil? - if @object_map[obj] && @object_map[obj]['compose'] - @object_map[obj]['compose'].each do |dep| - construct_object(dep) - end - end - build_object(obj) - end - end - - def build_object(new_object) - if @plugin_objects[new_object.to_sym].nil? - # @streaminator.stdout_puts("Building plugin object #{new_object}", Verbosity::OBNOXIOUS) - require new_object - class_name = camelize(new_object) - new_instance = eval("#{class_name}.new(@system_objects, class_name.to_s)") - new_instance.plugin_objects = @plugin_objects - @plugin_objects[new_object.to_sym] = new_instance - end - end - -end \ No newline at end of file diff --git a/vendor/ceedling/lib/ceedling/plugin_manager.rb b/vendor/ceedling/lib/ceedling/plugin_manager.rb deleted file mode 100644 index 0468f2f..0000000 --- a/vendor/ceedling/lib/ceedling/plugin_manager.rb +++ /dev/null @@ -1,107 +0,0 @@ -require 'ceedling/constants' - -class PluginManager - - constructor :configurator, :plugin_manager_helper, :streaminator, :reportinator, :system_wrapper - - def setup - @build_fail_registry = [] - @plugin_objects = [] # so we can preserve order - end - - def load_plugin_scripts(script_plugins, system_objects) - environment = [] - - script_plugins.each do |plugin| - # protect against instantiating object multiple times due to processing config multiple times (option files, etc) - next if (@plugin_manager_helper.include?(@plugin_objects, plugin)) - begin - @system_wrapper.require_file( "#{plugin}.rb" ) - object = @plugin_manager_helper.instantiate_plugin_script( camelize(plugin), system_objects, plugin ) - @plugin_objects << object - environment += object.environment - - # add plugins to hash of all system objects - system_objects[plugin.downcase.to_sym] = object - rescue - puts "Exception raised while trying to load plugin: #{plugin}" - raise - end - end - - yield( { :environment => environment } ) if (environment.size > 0) - end - - def plugins_failed? - return (@build_fail_registry.size > 0) - end - - def print_plugin_failures - if (@build_fail_registry.size > 0) - report = @reportinator.generate_banner('BUILD FAILURE SUMMARY') - - @build_fail_registry.each do |failure| - report += "#{' - ' if (@build_fail_registry.size > 1)}#{failure}\n" - end - - report += "\n" - - @streaminator.stderr_puts(report, Verbosity::ERRORS) - end - end - - def register_build_failure(message) - @build_fail_registry << message if (message and not message.empty?) - end - - #### execute all plugin methods #### - - def pre_mock_generate(arg_hash); execute_plugins(:pre_mock_generate, arg_hash); end - def post_mock_generate(arg_hash); execute_plugins(:post_mock_generate, arg_hash); end - - def pre_runner_generate(arg_hash); execute_plugins(:pre_runner_generate, arg_hash); end - def post_runner_generate(arg_hash); execute_plugins(:post_runner_generate, arg_hash); end - - def pre_compile_execute(arg_hash); execute_plugins(:pre_compile_execute, arg_hash); end - def post_compile_execute(arg_hash); execute_plugins(:post_compile_execute, arg_hash); end - - def pre_link_execute(arg_hash); execute_plugins(:pre_link_execute, arg_hash); end - def post_link_execute(arg_hash); execute_plugins(:post_link_execute, arg_hash); end - - def pre_test_fixture_execute(arg_hash); execute_plugins(:pre_test_fixture_execute, arg_hash); end - def post_test_fixture_execute(arg_hash) - # special arbitration: raw test results are printed or taken over by plugins handling the job - @streaminator.stdout_puts(arg_hash[:shell_result][:output]) if (@configurator.plugins_display_raw_test_results) - execute_plugins(:post_test_fixture_execute, arg_hash) - end - - def pre_test(test); execute_plugins(:pre_test, test); end - def post_test(test); execute_plugins(:post_test, test); end - - def pre_release; execute_plugins(:pre_release); end - def post_release; execute_plugins(:post_release); end - - def pre_build; execute_plugins(:pre_build); end - def post_build; execute_plugins(:post_build); end - def post_error; execute_plugins(:post_error); end - - def summary; execute_plugins(:summary); end - - private #################################### - - def camelize(underscored_name) - return underscored_name.gsub(/(_|^)([a-z0-9])/) {$2.upcase} - end - - def execute_plugins(method, *args) - @plugin_objects.each do |plugin| - begin - plugin.send(method, *args) if plugin.respond_to?(method) - rescue - puts "Exception raised in plugin: #{plugin.name}, in method #{method}" - raise - end - end - end - -end diff --git a/vendor/ceedling/lib/ceedling/plugin_manager_helper.rb b/vendor/ceedling/lib/ceedling/plugin_manager_helper.rb deleted file mode 100644 index b18248a..0000000 --- a/vendor/ceedling/lib/ceedling/plugin_manager_helper.rb +++ /dev/null @@ -1,19 +0,0 @@ - -class PluginManagerHelper - - def include?(plugins, name) - include = false - plugins.each do |plugin| - if (plugin.name == name) - include = true - break - end - end - return include - end - - def instantiate_plugin_script(plugin, system_objects, name) - return eval("#{plugin}.new(system_objects, name)") - end - -end diff --git a/vendor/ceedling/lib/ceedling/plugin_reportinator.rb b/vendor/ceedling/lib/ceedling/plugin_reportinator.rb deleted file mode 100644 index 8d83727..0000000 --- a/vendor/ceedling/lib/ceedling/plugin_reportinator.rb +++ /dev/null @@ -1,76 +0,0 @@ -require 'ceedling/constants' -require 'ceedling/defaults' - -class PluginReportinator - - constructor :plugin_reportinator_helper, :plugin_manager, :reportinator - - def setup - @test_results_template = nil - end - - - def set_system_objects(system_objects) - @plugin_reportinator_helper.ceedling = system_objects - end - - - def fetch_results(results_path, test, options={:boom => false}) - return @plugin_reportinator_helper.fetch_results( File.join(results_path, test), options ) - end - - - def generate_banner(message) - return @reportinator.generate_banner(message) - end - - - def assemble_test_results(results_list, options={:boom => false}) - aggregated_results = get_results_structure - - results_list.each do |result_path| - results = @plugin_reportinator_helper.fetch_results( result_path, options ) - @plugin_reportinator_helper.process_results(aggregated_results, results) - end - - return aggregated_results - end - - - def register_test_results_template(template) - @test_results_template = template if (@test_results_template.nil?) - end - - - def run_test_results_report(hash, verbosity=Verbosity::NORMAL, &block) - run_report( $stdout, - ((@test_results_template.nil?) ? DEFAULT_TESTS_RESULTS_REPORT_TEMPLATE : @test_results_template), - hash, - verbosity, - &block ) - end - - - def run_report(stream, template, hash=nil, verbosity=Verbosity::NORMAL) - failure = nil - failure = yield() if block_given? - - @plugin_manager.register_build_failure( failure ) - - @plugin_reportinator_helper.run_report( stream, template, hash, verbosity ) - end - - private ############################### - - def get_results_structure - return { - :successes => [], - :failures => [], - :ignores => [], - :stdout => [], - :counts => {:total => 0, :passed => 0, :failed => 0, :ignored => 0, :stdout => 0}, - :time => 0.0 - } - end - -end diff --git a/vendor/ceedling/lib/ceedling/plugin_reportinator_helper.rb b/vendor/ceedling/lib/ceedling/plugin_reportinator_helper.rb deleted file mode 100644 index 322a530..0000000 --- a/vendor/ceedling/lib/ceedling/plugin_reportinator_helper.rb +++ /dev/null @@ -1,51 +0,0 @@ -require 'erb' -require 'rubygems' -require 'rake' # for ext() -require 'ceedling/constants' - -class PluginReportinatorHelper - - attr_writer :ceedling - - constructor :configurator, :streaminator, :yaml_wrapper, :file_wrapper - - def fetch_results(results_path, options) - pass_path = File.join(results_path.ext( @configurator.extension_testpass )) - fail_path = File.join(results_path.ext( @configurator.extension_testfail )) - - if (@file_wrapper.exist?(fail_path)) - return @yaml_wrapper.load(fail_path) - elsif (@file_wrapper.exist?(pass_path)) - return @yaml_wrapper.load(pass_path) - else - if (options[:boom]) - @streaminator.stderr_puts("Could find no test results for '#{File.basename(results_path).ext(@configurator.extension_source)}'", Verbosity::ERRORS) - raise - end - end - - return {} - end - - - def process_results(aggregate_results, results) - return if (results.empty?) - aggregate_results[:successes] << { :source => results[:source].clone, :collection => results[:successes].clone } if (results[:successes].size > 0) - aggregate_results[:failures] << { :source => results[:source].clone, :collection => results[:failures].clone } if (results[:failures].size > 0) - aggregate_results[:ignores] << { :source => results[:source].clone, :collection => results[:ignores].clone } if (results[:ignores].size > 0) - aggregate_results[:stdout] << { :source => results[:source].clone, :collection => results[:stdout].clone } if (results[:stdout].size > 0) - aggregate_results[:counts][:total] += results[:counts][:total] - aggregate_results[:counts][:passed] += results[:counts][:passed] - aggregate_results[:counts][:failed] += results[:counts][:failed] - aggregate_results[:counts][:ignored] += results[:counts][:ignored] - aggregate_results[:counts][:stdout] += results[:stdout].size - aggregate_results[:time] += results[:time] - end - - - def run_report(stream, template, hash, verbosity) - output = ERB.new(template, 0, "%<>") - @streaminator.stream_puts(stream, output.result(binding()), verbosity) - end - -end diff --git a/vendor/ceedling/lib/ceedling/preprocessinator.rb b/vendor/ceedling/lib/ceedling/preprocessinator.rb deleted file mode 100644 index 52d82ca..0000000 --- a/vendor/ceedling/lib/ceedling/preprocessinator.rb +++ /dev/null @@ -1,56 +0,0 @@ - -class Preprocessinator - - constructor :preprocessinator_helper, :preprocessinator_includes_handler, :preprocessinator_file_handler, :task_invoker, :file_path_utils, :yaml_wrapper, :project_config_manager, :configurator - - - def setup - # fashion ourselves callbacks @preprocessinator_helper can use - @preprocess_includes_proc = Proc.new { |filepath| self.preprocess_shallow_includes(filepath) } - @preprocess_mock_file_proc = Proc.new { |filepath| self.preprocess_file(filepath) } - @preprocess_test_file_directives_proc = Proc.new { |filepath| self.preprocess_file_directives(filepath) } - @preprocess_test_file_proc = Proc.new { |filepath| self.preprocess_file(filepath) } - end - - def preprocess_shallow_source_includes(test) - @preprocessinator_helper.preprocess_source_includes(test) - end - - def preprocess_test_and_invoke_test_mocks(test) - @preprocessinator_helper.preprocess_includes(test, @preprocess_includes_proc) - - mocks_list = @preprocessinator_helper.assemble_mocks_list(test) - - @project_config_manager.process_test_defines_change(mocks_list) - - @preprocessinator_helper.preprocess_mockable_headers(mocks_list, @preprocess_mock_file_proc) - - @task_invoker.invoke_test_mocks(mocks_list) - - if (@configurator.project_use_preprocessor_directives) - @preprocessinator_helper.preprocess_test_file(test, @preprocess_test_file_directives_proc) - else - @preprocessinator_helper.preprocess_test_file(test, @preprocess_test_file_proc) - end - - return mocks_list - end - - def preprocess_shallow_includes(filepath) - includes = @preprocessinator_includes_handler.extract_includes(filepath) - - @preprocessinator_includes_handler.write_shallow_includes_list( - @file_path_utils.form_preprocessed_includes_list_filepath(filepath), includes) - end - - def preprocess_file(filepath) - @preprocessinator_includes_handler.invoke_shallow_includes_list(filepath) - @preprocessinator_file_handler.preprocess_file( filepath, @yaml_wrapper.load(@file_path_utils.form_preprocessed_includes_list_filepath(filepath)) ) - end - - def preprocess_file_directives(filepath) - @preprocessinator_includes_handler.invoke_shallow_includes_list( filepath ) - @preprocessinator_file_handler.preprocess_file_directives( filepath, - @yaml_wrapper.load( @file_path_utils.form_preprocessed_includes_list_filepath( filepath ) ) ) - end -end diff --git a/vendor/ceedling/lib/ceedling/preprocessinator_extractor.rb b/vendor/ceedling/lib/ceedling/preprocessinator_extractor.rb deleted file mode 100644 index 62026e1..0000000 --- a/vendor/ceedling/lib/ceedling/preprocessinator_extractor.rb +++ /dev/null @@ -1,55 +0,0 @@ -class PreprocessinatorExtractor - def extract_base_file_from_preprocessed_expansion(filepath) - # preprocessing by way of toolchain preprocessor expands macros, eliminates - # comments, strips out #ifdef code, etc. however, it also expands in place - # each #include'd file. so, we must extract only the lines of the file - # that belong to the file originally preprocessed - - # iterate through all lines and alternate between extract and ignore modes - # all lines between a '#'line containing file name of our filepath and the - # next '#'line should be extracted - - base_name = File.basename(filepath) - not_pragma = /^#(?!pragma\b)/ # preprocessor directive that's not a #pragma - pattern = /^#.*(\s|\/|\\|\")#{Regexp.escape(base_name)}/ - found_file = false # have we found the file we care about? - - lines = [] - File.readlines(filepath).each do |line| - line.encode!('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '') - if found_file and not line =~ not_pragma - lines << line - else - found_file = false - end - - found_file = true if line =~ pattern - end - - return lines - end - - def extract_base_file_from_preprocessed_directives(filepath) - # preprocessing by way of toolchain preprocessor eliminates directives only - # like #ifdef's and leave other code - - # iterate through all lines and only get last chunk of file after a last - # '#'line containing file name of our filepath - - base_name = File.basename(filepath) - pattern = /^#.*(\s|\/|\\|\")#{Regexp.escape(base_name)}/ - found_file = false # have we found the file we care about? - - lines = [] - File.readlines(filepath).each do |line| - line.encode!('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '') - lines << line - - if line =~ pattern - lines = [] - end - end - - return lines - end -end diff --git a/vendor/ceedling/lib/ceedling/preprocessinator_file_handler.rb b/vendor/ceedling/lib/ceedling/preprocessinator_file_handler.rb deleted file mode 100644 index 978fa0d..0000000 --- a/vendor/ceedling/lib/ceedling/preprocessinator_file_handler.rb +++ /dev/null @@ -1,34 +0,0 @@ - - -class PreprocessinatorFileHandler - - constructor :preprocessinator_extractor, :configurator, :tool_executor, :file_path_utils, :file_wrapper - - - def preprocess_file(filepath, includes) - preprocessed_filepath = @file_path_utils.form_preprocessed_file_filepath(filepath) - - command = @tool_executor.build_command_line(@configurator.tools_test_file_preprocessor, [], filepath, preprocessed_filepath) - @tool_executor.exec(command[:line], command[:options]) - - contents = @preprocessinator_extractor.extract_base_file_from_preprocessed_expansion(preprocessed_filepath) - - includes.each{|include| contents.unshift("#include \"#{include}\"")} - - @file_wrapper.write(preprocessed_filepath, contents.join("\n")) - end - - def preprocess_file_directives(filepath, includes) - preprocessed_filepath = @file_path_utils.form_preprocessed_file_filepath(filepath) - - command = @tool_executor.build_command_line(@configurator.tools_test_file_preprocessor_directives, [], filepath, preprocessed_filepath) - @tool_executor.exec(command[:line], command[:options]) - - contents = @preprocessinator_extractor.extract_base_file_from_preprocessed_directives(preprocessed_filepath) - - includes.each{|include| contents.unshift("#include \"#{include}\"")} - - @file_wrapper.write(preprocessed_filepath, contents.join("\n")) - end - -end diff --git a/vendor/ceedling/lib/ceedling/preprocessinator_helper.rb b/vendor/ceedling/lib/ceedling/preprocessinator_helper.rb deleted file mode 100644 index 4bbda67..0000000 --- a/vendor/ceedling/lib/ceedling/preprocessinator_helper.rb +++ /dev/null @@ -1,50 +0,0 @@ - - -class PreprocessinatorHelper - - constructor :configurator, :test_includes_extractor, :task_invoker, :file_finder, :file_path_utils - - - def preprocess_includes(test, preprocess_includes_proc) - if (@configurator.project_use_test_preprocessor) - preprocessed_includes_list = @file_path_utils.form_preprocessed_includes_list_filepath(test) - preprocess_includes_proc.call( @file_finder.find_test_from_file_path(preprocessed_includes_list) ) - @test_includes_extractor.parse_includes_list(preprocessed_includes_list) - else - @test_includes_extractor.parse_test_file(test) - end - end - - def preprocess_source_includes(test) - @test_includes_extractor.parse_test_file_source_include(test) - end - - def assemble_mocks_list(test) - return @file_path_utils.form_mocks_source_filelist( @test_includes_extractor.lookup_raw_mock_list(test) ) - end - - def preprocess_mockable_headers(mock_list, preprocess_file_proc) - if (@configurator.project_use_test_preprocessor) - preprocess_files_smartly( - @file_path_utils.form_preprocessed_mockable_headers_filelist(mock_list), - preprocess_file_proc ) { |file| @file_finder.find_header_file(file) } - end - end - - def preprocess_test_file(test, preprocess_file_proc) - return if (!@configurator.project_use_test_preprocessor) - - preprocess_file_proc.call(test) - end - - private ############################ - - def preprocess_files_smartly(file_list, preprocess_file_proc) - if (@configurator.project_use_deep_dependencies) - @task_invoker.invoke_test_preprocessed_files(file_list) - else - file_list.each { |file| preprocess_file_proc.call( yield(file) ) } - end - end - -end diff --git a/vendor/ceedling/lib/ceedling/preprocessinator_includes_handler.rb b/vendor/ceedling/lib/ceedling/preprocessinator_includes_handler.rb deleted file mode 100644 index 8b89c0b..0000000 --- a/vendor/ceedling/lib/ceedling/preprocessinator_includes_handler.rb +++ /dev/null @@ -1,189 +0,0 @@ - - -class PreprocessinatorIncludesHandler - - constructor :configurator, :tool_executor, :task_invoker, :file_path_utils, :yaml_wrapper, :file_wrapper, :file_finder - @@makefile_cache = {} - - # shallow includes: only those headers a source file explicitly includes - - def invoke_shallow_includes_list(filepath) - @task_invoker.invoke_test_shallow_include_lists( [@file_path_utils.form_preprocessed_includes_list_filepath(filepath)] ) - end - - ## - # Ask the preprocessor for a make-style dependency rule of only the headers - # the source file immediately includes. - # - # === Arguments - # +filepath+ _String_:: Path to the test file to process. - # - # === Return - # _String_:: The text of the dependency rule generated by the preprocessor. - def form_shallow_dependencies_rule(filepath) - if @@makefile_cache.has_key?(filepath) - return @@makefile_cache[filepath] - end - # change filename (prefix of '_') to prevent preprocessor from finding - # include files in temp directory containing file it's scanning - temp_filepath = @file_path_utils.form_temp_path(filepath, '_') - - # read the file and replace all include statements with a decorated version - # (decorating the names creates file names that don't exist, thus preventing - # the preprocessor from snaking out and discovering the entire include path - # that winds through the code). The decorated filenames indicate files that - # are included directly by the test file. - contents = @file_wrapper.read(filepath) - - if !contents.valid_encoding? - contents = contents.encode("UTF-16be", :invalid=>:replace, :replace=>"?").encode('UTF-8') - end - - contents.gsub!( /^\s*#include\s+[\"<]\s*(\S+)\s*[\">]/, "#include \"\\1\"\n#include \"@@@@\\1\"" ) - contents.gsub!( /^\s*TEST_FILE\(\s*\"\s*(\S+)\s*\"\s*\)/, "#include \"\\1\"\n#include \"@@@@\\1\"") - @file_wrapper.write( temp_filepath, contents ) - - # extract the make-style dependency rule telling the preprocessor to - # ignore the fact that it can't find the included files - command = @tool_executor.build_command_line(@configurator.tools_test_includes_preprocessor, [], temp_filepath) - shell_result = @tool_executor.exec(command[:line], command[:options]) - - @@makefile_cache[filepath] = shell_result[:output] - return shell_result[:output] - end - - ## - # Extract the headers that are directly included by a source file using the - # provided, annotated Make dependency rule. - # - # === Arguments - # +filepath+ _String_:: C source or header file to extract includes for. - # - # === Return - # _Array_ of _String_:: Array of the direct dependencies for the source file. - def extract_includes(filepath) - to_process = [filepath] - ignore_list = [] - list = [] - all_mocks = [] - - include_paths = @configurator.project_config_hash[:collection_paths_include] - include_paths = [] if include_paths.nil? - include_paths.map! {|path| File.expand_path(path)} - - while to_process.length > 0 - target = to_process.shift() - ignore_list << target - new_deps, new_to_process, all_mocks = extract_includes_helper(target, include_paths, ignore_list, all_mocks) - list += new_deps - to_process += new_to_process - if !@configurator.project_config_hash[:project_auto_link_deep_dependencies] - break - else - list = list.uniq() - to_process = to_process.uniq() - end - end - - return list - end - - def extract_includes_helper(filepath, include_paths, ignore_list, mocks) - # Extract the dependencies from the make rule - make_rule = self.form_shallow_dependencies_rule(filepath) - target_file = make_rule.split[0].gsub(':', '').gsub('\\','/') - base = File.basename(target_file, File.extname(target_file)) - make_rule_dependencies = make_rule.gsub(/.*\b#{Regexp.escape(base)}\S*/, '').gsub(/\\$/, '') - - # Extract the headers dependencies from the make rule - hdr_ext = @configurator.extension_header - headers_dependencies = make_rule_dependencies.split.find_all {|path| path.end_with?(hdr_ext) }.uniq - headers_dependencies.map! {|hdr| hdr.gsub('\\','/') } - full_path_headers_dependencies = extract_full_path_dependencies(headers_dependencies) - - # Extract the sources dependencies from the make rule - src_ext = @configurator.extension_source - sources_dependencies = make_rule_dependencies.split.find_all {|path| path.end_with?(src_ext) }.uniq - sources_dependencies.map! {|src| src.gsub('\\','/') } - full_path_sources_dependencies = extract_full_path_dependencies(sources_dependencies) - - list = full_path_headers_dependencies + full_path_sources_dependencies - - mock_prefix = @configurator.project_config_hash[:cmock_mock_prefix] - # Creating list of mocks - mocks += full_path_headers_dependencies.find_all do |header| - File.basename(header) =~ /^#{mock_prefix}.*$/ - end.compact - - # ignore real file when both mock and real file exist - mocks.each do |mock| - list.each do |filename| - if File.basename(filename) == File.basename(mock).sub(mock_prefix, '') - ignore_list << filename - end - end - end.compact - - # Filtering list of final includes to only include mocks and anything that is NOT in the ignore_list - list = list.select do |item| - mocks.include? item or !(ignore_list.any? { |ignore_item| !item.match(/^(.*\/)?#{Regexp.escape(ignore_item)}$/).nil? }) - end - - to_process = [] - - if @configurator.project_config_hash[:project_auto_link_deep_dependencies] - # Creating list of headers that should be recursively pre-processed - # Skipping mocks and vendor headers - headers_to_deep_link = full_path_headers_dependencies.select do |hdr| - !(mocks.include? hdr) and (hdr.match(/^(.*\/)(#{VENDORS_FILES.join('|')}) + #{Regexp.escape(hdr_ext)}$/).nil?) - end - headers_to_deep_link.map! {|hdr| File.expand_path(hdr) } - headers_to_deep_link.compact! - - headers_to_deep_link.each do |hdr| - if (ignore_list.none? {|ignore_header| hdr.match(/^(.*\/)?#{Regexp.escape(ignore_header)}$/)} and - include_paths.none? {|include_path| hdr =~ /^#{include_path}\.*/}) - if File.exist?(hdr) - to_process << hdr - src = @file_finder.find_compilation_input_file(hdr, :ignore) - to_process << src if src - end - end - end - end - - return list, to_process, mocks - - end - - def write_shallow_includes_list(filepath, list) - @yaml_wrapper.dump(filepath, list) - end - - private - - def extract_full_path_dependencies(dependencies) - # Separate the real files form the annotated ones and remove the '@@@@' - annotated_files, real_files = dependencies.partition {|file| file =~ /^@@@@/} - annotated_files.map! {|file| file.gsub('@@@@','') } - # Matching annotated_files values against real_files to ensure that - # annotated_files contain full path entries (as returned by make rule) - annotated_files.map! {|file| real_files.find {|real| !real.match(/^(.*\/)?#{Regexp.escape(file)}$/).nil?}} - annotated_files = annotated_files.compact - - # Find which of our annotated files are "real" dependencies. This is - # intended to weed out dependencies that have been removed due to build - # options defined in the project yaml and/or in the files themselves. - return annotated_files.find_all do |annotated_file| - # find the index of the "real" file that matches the annotated one. - idx = real_files.find_index do |real_file| - real_file =~ /^(.*\/)?#{Regexp.escape(annotated_file)}$/ - end - # If we found a real file, delete it from the array and return it, - # otherwise return nil. Since nil is falsy this has the effect of making - # find_all return only the annotated filess for which a real file was - # found/deleted - idx ? real_files.delete_at(idx) : nil - end.compact - end -end diff --git a/vendor/ceedling/lib/ceedling/project_config_manager.rb b/vendor/ceedling/lib/ceedling/project_config_manager.rb deleted file mode 100644 index ed7a73b..0000000 --- a/vendor/ceedling/lib/ceedling/project_config_manager.rb +++ /dev/null @@ -1,52 +0,0 @@ -require 'ceedling/constants' - - -class ProjectConfigManager - - attr_reader :options_files, :release_config_changed, :test_config_changed, :test_defines_changed - attr_accessor :config_hash - - constructor :cacheinator, :configurator, :yaml_wrapper, :file_wrapper - - - def setup - @options_files = [] - @release_config_changed = false - @test_config_changed = false - @test_defines_changed = false - end - - - def merge_options(config_hash, option_filepath) - @options_files << File.basename( option_filepath ) - config_hash.deep_merge!( @yaml_wrapper.load( option_filepath ) ) - end - - - def filter_internal_sources(sources) - filtered_sources = sources.clone - filtered_sources.delete_if { |item| item =~ /#{CMOCK_MOCK_PREFIX}.+#{Regexp.escape(EXTENSION_SOURCE)}$/ } - filtered_sources.delete_if { |item| item =~ /#{VENDORS_FILES.map{|source| '\b' + Regexp.escape(source.ext(EXTENSION_SOURCE)) + '\b'}.join('|')}$/ } - return filtered_sources - end - - def process_release_config_change - # has project configuration changed since last release build - @release_config_changed = @cacheinator.diff_cached_release_config?( @config_hash ) - end - - - def process_test_config_change - # has project configuration changed since last test build - @test_config_changed = @cacheinator.diff_cached_test_config?( @config_hash ) - end - - def process_test_defines_change(files) - # has definitions changed since last test build - @test_defines_changed = @cacheinator.diff_cached_test_defines?( files ) - if @test_defines_changed - # update timestamp for rake task prerequisites - @file_wrapper.touch( @configurator.project_test_force_rebuild_filepath, :mtime => Time.now + 10 ) - end - end -end diff --git a/vendor/ceedling/lib/ceedling/project_file_loader.rb b/vendor/ceedling/lib/ceedling/project_file_loader.rb deleted file mode 100644 index bf5dcd4..0000000 --- a/vendor/ceedling/lib/ceedling/project_file_loader.rb +++ /dev/null @@ -1,99 +0,0 @@ -require 'ceedling/constants' - - -class ProjectFileLoader - - attr_reader :main_file, :user_file - - constructor :yaml_wrapper, :stream_wrapper, :system_wrapper, :file_wrapper - - def setup - @main_file = nil - @mixin_files = [] - @user_file = nil - - @main_project_filepath = '' - @mixin_project_filepaths = [] - @user_project_filepath = '' - end - - - def find_project_files - # first go hunting for optional user project file by looking for environment variable and then default location on disk - user_filepath = @system_wrapper.env_get('CEEDLING_USER_PROJECT_FILE') - - if ( not user_filepath.nil? and @file_wrapper.exist?(user_filepath) ) - @user_project_filepath = user_filepath - elsif (@file_wrapper.exist?(DEFAULT_CEEDLING_USER_PROJECT_FILE)) - @user_project_filepath = DEFAULT_CEEDLING_USER_PROJECT_FILE - end - - # next check for mixin project files by looking for environment variable - mixin_filepaths = @system_wrapper.env_get('CEEDLING_MIXIN_PROJECT_FILES') - if ( not mixin_filepaths.nil? ) - mixin_filepaths.split(File::PATH_SEPARATOR).each do |filepath| - if ( @file_wrapper.exist?(filepath) ) - @mixin_project_filepaths.push(filepath) - end - end - end - - # next check for main project file by looking for environment variable and then default location on disk; - # blow up if we don't find this guy -- like, he's so totally important - main_filepath = @system_wrapper.env_get('CEEDLING_MAIN_PROJECT_FILE') - - if ( not main_filepath.nil? and @file_wrapper.exist?(main_filepath) ) - @main_project_filepath = main_filepath - elsif (@file_wrapper.exist?(DEFAULT_CEEDLING_MAIN_PROJECT_FILE)) - @main_project_filepath = DEFAULT_CEEDLING_MAIN_PROJECT_FILE - else - # no verbosity checking since this is lowest level reporting anyhow & - # verbosity checking depends on configurator which in turns needs this class (circular dependency) - @stream_wrapper.stderr_puts('Found no Ceedling project file (*.yml)') - raise - end - - @main_file = File.basename( @main_project_filepath ) - @mixin_project_filepaths.each do |filepath| - @mixin_files.push(File.basename( filepath )) - end - @user_file = File.basename( @user_project_filepath ) if ( not @user_project_filepath.empty? ) - end - - def yaml_merger(y1, y2) - o1 = y1 - y2.each_pair do |k,v| - if o1[k].nil? - o1[k] = v - else - if (o1[k].instance_of? Hash) - o1[k] = yaml_merger(o1[k], v) - elsif (o1[k].instance_of? Array) - o1[k] += v - else - o1[k] = v - end - end - end - return o1 - end - - def load_project_config - config_hash = @yaml_wrapper.load(@main_project_filepath) - - # if there are mixin project files, then use them - @mixin_project_filepaths.each do |filepath| - mixin = @yaml_wrapper.load(filepath) - config_hash = yaml_merger( config_hash, mixin ) - end - - # if there's a user project file, then use it - if ( not @user_project_filepath.empty? ) - user_hash = @yaml_wrapper.load(@user_project_filepath) - config_hash = yaml_merger( config_hash, user_hash ) - end - - return config_hash - end - -end diff --git a/vendor/ceedling/lib/ceedling/rake_utils.rb b/vendor/ceedling/lib/ceedling/rake_utils.rb deleted file mode 100644 index 3f667c8..0000000 --- a/vendor/ceedling/lib/ceedling/rake_utils.rb +++ /dev/null @@ -1,17 +0,0 @@ - -class RakeUtils - - constructor :rake_wrapper - - def task_invoked?(task_regex) - task_invoked = false - @rake_wrapper.task_list.each do |task| - if ((task.already_invoked) and (task.to_s =~ task_regex)) - task_invoked = true - break - end - end - return task_invoked - end - -end diff --git a/vendor/ceedling/lib/ceedling/rake_wrapper.rb b/vendor/ceedling/lib/ceedling/rake_wrapper.rb deleted file mode 100644 index 15e4796..0000000 --- a/vendor/ceedling/lib/ceedling/rake_wrapper.rb +++ /dev/null @@ -1,33 +0,0 @@ -require 'rubygems' -require 'rake' -require 'ceedling/makefile' # our replacement for rake's make-style dependency loader - -include Rake::DSL if defined?(Rake::DSL) - -class Rake::Task - attr_reader :already_invoked -end - -class RakeWrapper - - def initialize - @makefile_loader = Rake::MakefileLoader.new # use our custom replacement noted above - end - - def [](task) - return Rake::Task[task] - end - - def task_list - return Rake::Task.tasks - end - - def create_file_task(file_task, dependencies) - file(file_task => dependencies) - end - - def load_dependencies(dependencies_path) - @makefile_loader.load(dependencies_path) - end - -end diff --git a/vendor/ceedling/lib/ceedling/rakefile.rb b/vendor/ceedling/lib/ceedling/rakefile.rb deleted file mode 100644 index 1bcb824..0000000 --- a/vendor/ceedling/lib/ceedling/rakefile.rb +++ /dev/null @@ -1,85 +0,0 @@ -require 'fileutils' - -# get directory containing this here file, back up one directory, and expand to full path -CEEDLING_ROOT = File.expand_path(File.dirname(__FILE__) + '/../..') -CEEDLING_LIB = File.join(CEEDLING_ROOT, 'lib') -CEEDLING_VENDOR = File.join(CEEDLING_ROOT, 'vendor') -CEEDLING_RELEASE = File.join(CEEDLING_ROOT, 'release') - -$LOAD_PATH.unshift( CEEDLING_LIB ) -$LOAD_PATH.unshift( File.join(CEEDLING_VENDOR, 'unity/auto') ) -$LOAD_PATH.unshift( File.join(CEEDLING_VENDOR, 'diy/lib') ) -$LOAD_PATH.unshift( File.join(CEEDLING_VENDOR, 'cmock/lib') ) - -require 'rake' - -#Let's make sure we remember the task descriptions in case we need them -Rake::TaskManager.record_task_metadata = true - -require 'diy' -require 'constructor' - -require 'ceedling/constants' -require 'ceedling/target_loader' - - -# construct all our objects -# ensure load path contains all libraries needed first -lib_ceedling_load_path_temp = File.join(CEEDLING_LIB, 'ceedling') -$LOAD_PATH.unshift( lib_ceedling_load_path_temp ) -@ceedling = DIY::Context.from_yaml( File.read( File.join(lib_ceedling_load_path_temp, 'objects.yml') ) ) -@ceedling.build_everything -# now that all objects are built, delete 'lib/ceedling' from load path -$LOAD_PATH.delete(lib_ceedling_load_path_temp) -# one-stop shopping for all our setup and such after construction -@ceedling[:setupinator].ceedling = @ceedling - -project_config = - begin - cfg = @ceedling[:setupinator].load_project_files - TargetLoader.inspect(cfg, ENV['TARGET']) - rescue TargetLoader::NoTargets - cfg - rescue TargetLoader::RequestReload - @ceedling[:setupinator].load_project_files - end - -@ceedling[:setupinator].do_setup( project_config ) - - -# tell all our plugins we're about to do something -@ceedling[:plugin_manager].pre_build - -# load rakefile component files (*.rake) -PROJECT_RAKEFILE_COMPONENT_FILES.each { |component| load(component) } - -# tell rake to shut up by default (overridden in verbosity / debug tasks as appropriate) -verbose(false) - - -# end block always executed following rake run -END { - $stdout.flush unless $stdout.nil? - $stderr.flush unless $stderr.nil? - - # cache our input configurations to use in comparison upon next execution - @ceedling[:cacheinator].cache_test_config( @ceedling[:setupinator].config_hash ) if (@ceedling[:task_invoker].test_invoked?) - @ceedling[:cacheinator].cache_release_config( @ceedling[:setupinator].config_hash ) if (@ceedling[:task_invoker].release_invoked?) - - # delete all temp files unless we're in debug mode - if (not @ceedling[:configurator].project_debug) - @ceedling[:file_wrapper].rm_f( @ceedling[:file_wrapper].directory_listing( File.join(@ceedling[:configurator].project_temp_path, '*') )) - end - - # only perform these final steps if we got here without runtime exceptions or errors - if (@ceedling[:system_wrapper].ruby_success) - - # tell all our plugins the build is done and process results - @ceedling[:plugin_manager].post_build - @ceedling[:plugin_manager].print_plugin_failures - exit(1) if (@ceedling[:plugin_manager].plugins_failed? && !@ceedling[:setupinator].config_hash[:graceful_fail]) - else - puts "ERROR: Ceedling Failed" - @ceedling[:plugin_manager].post_error - end -} diff --git a/vendor/ceedling/lib/ceedling/release_invoker.rb b/vendor/ceedling/lib/ceedling/release_invoker.rb deleted file mode 100644 index 19bbca7..0000000 --- a/vendor/ceedling/lib/ceedling/release_invoker.rb +++ /dev/null @@ -1,98 +0,0 @@ -require 'ceedling/constants' - - -class ReleaseInvoker - - constructor :configurator, :release_invoker_helper, :build_invoker_utils, :dependinator, :task_invoker, :file_path_utils, :file_wrapper - - - def setup_and_invoke_c_objects( c_files ) - objects = @file_path_utils.form_release_build_c_objects_filelist( c_files ) - - begin - @release_invoker_helper.process_deep_dependencies( @file_path_utils.form_release_dependencies_filelist( c_files ) ) - - @dependinator.enhance_release_file_dependencies( objects ) - @task_invoker.invoke_release_objects( objects ) - rescue => e - @build_invoker_utils.process_exception( e, RELEASE_SYM, false ) - end - - return objects - end - - - def setup_and_invoke_asm_objects( asm_files ) - objects = @file_path_utils.form_release_build_asm_objects_filelist( asm_files ) - - begin - @dependinator.enhance_release_file_dependencies( objects ) - @task_invoker.invoke_release_objects( objects ) - rescue => e - @build_invoker_utils.process_exception( e, RELEASE_SYM, false ) - end - - return objects - end - - - def refresh_c_deep_dependencies - return if (not @configurator.project_use_deep_dependencies) - - @file_wrapper.rm_f( - @file_wrapper.directory_listing( - File.join( @configurator.project_release_dependencies_path, '*' + @configurator.extension_dependencies ) ) ) - - @release_invoker_helper.process_deep_dependencies( - @file_path_utils.form_release_dependencies_filelist( - @configurator.collection_all_source ) ) - end - - - def artifactinate( *files ) - files.flatten.each do |file| - @file_wrapper.cp( file, @configurator.project_release_artifacts_path ) if @file_wrapper.exist?( file ) - end - end - - def convert_libraries_to_arguments(libraries) - args = ((libraries || []) + ((defined? LIBRARIES_SYSTEM) ? LIBRARIES_SYSTEM : [])).flatten - if (defined? LIBRARIES_FLAG) - args.map! {|v| LIBRARIES_FLAG.gsub(/\$\{1\}/, v) } - end - return args - end - - def get_library_paths_to_arguments() - paths = (defined? PATHS_LIBRARIES) ? (PATHS_LIBRARIES || []).clone : [] - if (defined? LIBRARIES_PATH_FLAG) - paths.map! {|v| LIBRARIES_PATH_FLAG.gsub(/\$\{1\}/, v) } - end - return paths - end - - def sort_objects_and_libraries(both) - extension = if ((defined? EXTENSION_SUBPROJECTS) && (defined? EXTENSION_LIBRARIES)) - extension_libraries = if (EXTENSION_LIBRARIES.class == Array) - EXTENSION_LIBRARIES.join(")|(?:\\") - else - EXTENSION_LIBRARIES - end - "(?:\\#{EXTENSION_SUBPROJECTS})|(?:\\#{extension_libraries})" - elsif (defined? EXTENSION_SUBPROJECTS) - "\\#{EXTENSION_SUBPROJECTS}" - elsif (defined? EXTENSION_LIBRARIES) - if (EXTENSION_LIBRARIES.class == Array) - "(?:\\#{EXTENSION_LIBRARIES.join(")|(?:\\")})" - else - "\\#{EXTENSION_LIBRARIES}" - end - else - "\\.LIBRARY" - end - sorted_objects = both.group_by {|v| v.match(/.+#{extension}$/) ? :libraries : :objects } - libraries = sorted_objects[:libraries] || [] - objects = sorted_objects[:objects] || [] - return objects, libraries - end -end diff --git a/vendor/ceedling/lib/ceedling/release_invoker_helper.rb b/vendor/ceedling/lib/ceedling/release_invoker_helper.rb deleted file mode 100644 index f83a2a5..0000000 --- a/vendor/ceedling/lib/ceedling/release_invoker_helper.rb +++ /dev/null @@ -1,19 +0,0 @@ - - -class ReleaseInvokerHelper - - constructor :configurator, :dependinator, :task_invoker - - - def process_deep_dependencies(dependencies_list) - return if (not @configurator.project_use_deep_dependencies) - - if @configurator.project_generate_deep_dependencies - @dependinator.enhance_release_file_dependencies( dependencies_list ) - @task_invoker.invoke_release_dependencies_files( dependencies_list ) - end - - @dependinator.load_release_object_deep_dependencies( dependencies_list ) - end - -end diff --git a/vendor/ceedling/lib/ceedling/reportinator.rb b/vendor/ceedling/lib/ceedling/reportinator.rb deleted file mode 100644 index 0f583d0..0000000 --- a/vendor/ceedling/lib/ceedling/reportinator.rb +++ /dev/null @@ -1,26 +0,0 @@ -## -# Pretifies reports -class Reportinator - - ## - # Generates a banner for a message based on the length of the message or a - # given width. - # ==== Attributes - # - # * _message_: The message to put. - # * _width_: The width of the message. If nil the size of the banner is - # determined by the length of the message. - # - # ==== Examples - # - # rp = Reportinator.new - # rp.generate_banner("Hello world!") => "------------\nHello world!\n------------\n" - # rp.generate_banner("Hello world!", 3) => "---\nHello world!\n---\n" - # - # - def generate_banner(message, width=nil) - dash_count = ((width.nil?) ? message.strip.length : width) - return "#{'-' * dash_count}\n#{message}\n#{'-' * dash_count}\n" - end - -end diff --git a/vendor/ceedling/lib/ceedling/rules_cmock.rake b/vendor/ceedling/lib/ceedling/rules_cmock.rake deleted file mode 100644 index 70ddcbc..0000000 --- a/vendor/ceedling/lib/ceedling/rules_cmock.rake +++ /dev/null @@ -1,9 +0,0 @@ - - -rule(/#{CMOCK_MOCK_PREFIX}[^\/\\]+#{'\\'+EXTENSION_SOURCE}$/ => [ - proc do |task_name| - @ceedling[:file_finder].find_header_input_for_mock_file(task_name) - end - ]) do |mock| - @ceedling[:generator].generate_mock(TEST_SYM, mock.source) -end diff --git a/vendor/ceedling/lib/ceedling/rules_preprocess.rake b/vendor/ceedling/lib/ceedling/rules_preprocess.rake deleted file mode 100644 index c291112..0000000 --- a/vendor/ceedling/lib/ceedling/rules_preprocess.rake +++ /dev/null @@ -1,26 +0,0 @@ - - -# invocations against this rule should only happen when enhanced dependencies are enabled; -# otherwise, dependency tracking will be too shallow and preprocessed files could intermittently -# fail to be updated when they actually need to be. -rule(/#{PROJECT_TEST_PREPROCESS_FILES_PATH}\/.+/ => [ - proc do |task_name| - @ceedling[:file_finder].find_test_or_source_or_header_file(task_name) - end - ]) do |file| - if (not @ceedling[:configurator].project_use_deep_dependencies) - raise 'ERROR: Ceedling preprocessing rule invoked though neccessary auxiliary dependency support not enabled.' - end - @ceedling[:generator].generate_preprocessed_file(TEST_SYM, file.source) -end - - -# invocations against this rule can always happen as there are no deeper dependencies to consider -rule(/#{PROJECT_TEST_PREPROCESS_INCLUDES_PATH}\/.+/ => [ - proc do |task_name| - @ceedling[:file_finder].find_test_or_source_or_header_file(task_name) - end - ]) do |file| - @ceedling[:generator].generate_shallow_includes_list(TEST_SYM, file.source) -end - diff --git a/vendor/ceedling/lib/ceedling/rules_release.rake b/vendor/ceedling/lib/ceedling/rules_release.rake deleted file mode 100644 index 4a583bd..0000000 --- a/vendor/ceedling/lib/ceedling/rules_release.rake +++ /dev/null @@ -1,99 +0,0 @@ - -RELEASE_COMPILE_TASK_ROOT = RELEASE_TASK_ROOT + 'compile:' unless defined?(RELEASE_COMPILE_TASK_ROOT) -RELEASE_ASSEMBLE_TASK_ROOT = RELEASE_TASK_ROOT + 'assemble:' unless defined?(RELEASE_ASSEMBLE_TASK_ROOT) - -# If GCC and Releasing a Library, Update Tools to Automatically Have Necessary Tags -if (TOOLS_RELEASE_COMPILER[:executable] == DEFAULT_RELEASE_COMPILER_TOOL[:executable]) - if (File.extname(PROJECT_RELEASE_BUILD_TARGET) == '.so') - TOOLS_RELEASE_COMPILER[:arguments] << "-fPIC" unless TOOLS_RELEASE_COMPILER[:arguments].include?("-fPIC") - TOOLS_RELEASE_LINKER[:arguments] << "-shared" unless TOOLS_RELEASE_LINKER[:arguments].include?("-shared") - elsif (File.extname(PROJECT_RELEASE_BUILD_TARGET) == '.a') - TOOLS_RELEASE_COMPILER[:arguments] << "-fPIC" unless TOOLS_RELEASE_COMPILER[:arguments].include?("-fPIC") - TOOLS_RELEASE_LINKER[:executable] = 'ar' - TOOLS_RELEASE_LINKER[:arguments] = ['rcs', '${2}', '${1}'].compact - end -end - -if (RELEASE_BUILD_USE_ASSEMBLY) -rule(/#{PROJECT_RELEASE_BUILD_OUTPUT_ASM_PATH}\/#{'.+\\'+EXTENSION_OBJECT}$/ => [ - proc do |task_name| - @ceedling[:file_finder].find_assembly_file(task_name) - end - ]) do |object| - @ceedling[:generator].generate_object_file( - TOOLS_RELEASE_ASSEMBLER, - OPERATION_ASSEMBLE_SYM, - RELEASE_SYM, - object.source, - object.name ) -end -end - - -rule(/#{PROJECT_RELEASE_BUILD_OUTPUT_C_PATH}\/#{'.+\\'+EXTENSION_OBJECT}$/ => [ - proc do |task_name| - @ceedling[:file_finder].find_compilation_input_file(task_name, :error, true) - end - ]) do |object| - @ceedling[:generator].generate_object_file( - TOOLS_RELEASE_COMPILER, - OPERATION_COMPILE_SYM, - RELEASE_SYM, - object.source, - object.name, - @ceedling[:file_path_utils].form_release_build_c_list_filepath( object.name ), - @ceedling[:file_path_utils].form_release_dependencies_filepath( object.name ) ) -end - - -rule(/#{PROJECT_RELEASE_BUILD_TARGET}/) do |bin_file| - objects, libraries = @ceedling[:release_invoker].sort_objects_and_libraries(bin_file.prerequisites) - tool = TOOLS_RELEASE_LINKER.clone - lib_args = @ceedling[:release_invoker].convert_libraries_to_arguments(libraries) - lib_paths = @ceedling[:release_invoker].get_library_paths_to_arguments() - map_file = @ceedling[:configurator].project_release_build_map - @ceedling[:generator].generate_executable_file( - tool, - RELEASE_SYM, - objects, - bin_file.name, - map_file, - lib_args, - lib_paths ) - @ceedling[:release_invoker].artifactinate( bin_file.name, map_file, @ceedling[:configurator].release_build_artifacts ) -end - - -namespace RELEASE_SYM do - # use rules to increase efficiency for large projects (instead of iterating through all sources and creating defined tasks) - - namespace :compile do - rule(/^#{RELEASE_COMPILE_TASK_ROOT}\S+#{'\\'+EXTENSION_SOURCE}$/ => [ # compile task names by regex - proc do |task_name| - source = task_name.sub(/#{RELEASE_COMPILE_TASK_ROOT}/, '') - @ceedling[:file_finder].find_source_file(source, :error) - end - ]) do |compile| - @ceedling[:rake_wrapper][:directories].invoke - @ceedling[:project_config_manager].process_release_config_change - @ceedling[:release_invoker].setup_and_invoke_c_objects( [compile.source] ) - end - end - - if (RELEASE_BUILD_USE_ASSEMBLY) - namespace :assemble do - rule(/^#{RELEASE_ASSEMBLE_TASK_ROOT}\S+#{'\\'+EXTENSION_ASSEMBLY}$/ => [ # assemble task names by regex - proc do |task_name| - source = task_name.sub(/#{RELEASE_ASSEMBLE_TASK_ROOT}/, '') - @ceedling[:file_finder].find_assembly_file(source) - end - ]) do |assemble| - @ceedling[:rake_wrapper][:directories].invoke - @ceedling[:project_config_manager].process_release_config_change - @ceedling[:release_invoker].setup_and_invoke_asm_objects( [assemble.source] ) - end - end - end - -end - diff --git a/vendor/ceedling/lib/ceedling/rules_release_deep_dependencies.rake b/vendor/ceedling/lib/ceedling/rules_release_deep_dependencies.rake deleted file mode 100644 index 9550783..0000000 --- a/vendor/ceedling/lib/ceedling/rules_release_deep_dependencies.rake +++ /dev/null @@ -1,15 +0,0 @@ - - -rule(/#{PROJECT_RELEASE_DEPENDENCIES_PATH}\/#{'.+\\'+EXTENSION_DEPENDENCIES}$/ => [ - proc do |task_name| - @ceedling[:file_finder].find_compilation_input_file(task_name, :error, true) - end - ]) do |dep| - @ceedling[:generator].generate_dependencies_file( - TOOLS_RELEASE_DEPENDENCIES_GENERATOR, - RELEASE_SYM, - dep.source, - @ceedling[:file_path_utils].form_release_build_c_object_filepath(dep.source), - dep.name) -end - diff --git a/vendor/ceedling/lib/ceedling/rules_tests.rake b/vendor/ceedling/lib/ceedling/rules_tests.rake deleted file mode 100644 index 61e15e2..0000000 --- a/vendor/ceedling/lib/ceedling/rules_tests.rake +++ /dev/null @@ -1,73 +0,0 @@ - - -rule(/#{PROJECT_TEST_FILE_PREFIX}#{'.+'+TEST_RUNNER_FILE_SUFFIX}#{'\\'+EXTENSION_SOURCE}$/ => [ - proc do |task_name| - @ceedling[:file_finder].find_test_input_for_runner_file(task_name) - end - ]) do |runner| - @ceedling[:generator].generate_test_runner(TEST_SYM, runner.source, runner.name) -end - -rule(/#{PROJECT_TEST_BUILD_OUTPUT_C_PATH}\/#{'.+\\'+EXTENSION_OBJECT}$/ => [ - proc do |task_name| - @ceedling[:file_finder].find_compilation_input_file(task_name) - end - ]) do |object| - if (File.basename(object.source) =~ /#{EXTENSION_SOURCE}$/) - @ceedling[:generator].generate_object_file( - TOOLS_TEST_COMPILER, - OPERATION_COMPILE_SYM, - TEST_SYM, - object.source, - object.name, - @ceedling[:file_path_utils].form_test_build_list_filepath( object.name ), - @ceedling[:file_path_utils].form_test_dependencies_filepath( object.name )) - elsif (defined?(TEST_BUILD_USE_ASSEMBLY) && TEST_BUILD_USE_ASSEMBLY) - @ceedling[:generator].generate_object_file( - TOOLS_TEST_ASSEMBLER, - OPERATION_ASSEMBLE_SYM, - TEST_SYM, - object.source, - object.name ) - end -end - - -rule(/#{PROJECT_TEST_BUILD_OUTPUT_PATH}\/#{'.+\\'+EXTENSION_EXECUTABLE}$/) do |bin_file| - lib_args = @ceedling[:test_invoker].convert_libraries_to_arguments() - lib_paths = @ceedling[:test_invoker].get_library_paths_to_arguments() - @ceedling[:generator].generate_executable_file( - TOOLS_TEST_LINKER, - TEST_SYM, - bin_file.prerequisites, - bin_file.name, - @ceedling[:file_path_utils].form_test_build_map_filepath( bin_file.name ), - lib_args, - lib_paths ) -end - - -rule(/#{PROJECT_TEST_RESULTS_PATH}\/#{'.+\\'+EXTENSION_TESTPASS}$/ => [ - proc do |task_name| - @ceedling[:file_path_utils].form_test_executable_filepath(task_name) - end - ]) do |test_result| - @ceedling[:generator].generate_test_results(TOOLS_TEST_FIXTURE, TEST_SYM, test_result.source, test_result.name) -end - - -namespace TEST_SYM do - # use rules to increase efficiency for large projects (instead of iterating through all sources and creating defined tasks) - - rule(/^#{TEST_TASK_ROOT}\S+$/ => [ # test task names by regex - proc do |task_name| - test = task_name.sub(/#{TEST_TASK_ROOT}/, '') - test = "#{PROJECT_TEST_FILE_PREFIX}#{test}" if not (test.start_with?(PROJECT_TEST_FILE_PREFIX)) - @ceedling[:file_finder].find_test_from_file_path(test) - end - ]) do |test| - @ceedling[:rake_wrapper][:test_deps].invoke - @ceedling[:test_invoker].setup_and_invoke([test.source]) - end -end - diff --git a/vendor/ceedling/lib/ceedling/rules_tests_deep_dependencies.rake b/vendor/ceedling/lib/ceedling/rules_tests_deep_dependencies.rake deleted file mode 100644 index 7175ee3..0000000 --- a/vendor/ceedling/lib/ceedling/rules_tests_deep_dependencies.rake +++ /dev/null @@ -1,15 +0,0 @@ - - -rule(/#{PROJECT_TEST_DEPENDENCIES_PATH}\/#{'.+\\'+EXTENSION_DEPENDENCIES}$/ => [ - proc do |task_name| - @ceedling[:file_finder].find_compilation_input_file(task_name) - end - ]) do |dep| - @ceedling[:generator].generate_dependencies_file( - TOOLS_TEST_DEPENDENCIES_GENERATOR, - TEST_SYM, - dep.source, - @ceedling[:file_path_utils].form_test_build_c_object_filepath(dep.source), - dep.name) -end - diff --git a/vendor/ceedling/lib/ceedling/setupinator.rb b/vendor/ceedling/lib/ceedling/setupinator.rb deleted file mode 100644 index ea78fd9..0000000 --- a/vendor/ceedling/lib/ceedling/setupinator.rb +++ /dev/null @@ -1,53 +0,0 @@ - -class Setupinator - - attr_reader :config_hash - attr_writer :ceedling - - def setup - @ceedling = {} - @config_hash = {} - end - - def load_project_files - @ceedling[:project_file_loader].find_project_files - return @ceedling[:project_file_loader].load_project_config - end - - def do_setup(config_hash) - @config_hash = config_hash - - # load up all the constants and accessors our rake files, objects, & external scripts will need; - # note: configurator modifies the cmock section of the hash with a couple defaults to tie - # project together - the modified hash is used to build cmock object - @ceedling[:configurator].populate_defaults( config_hash ) - @ceedling[:configurator].populate_unity_defaults( config_hash ) - @ceedling[:configurator].populate_cmock_defaults( config_hash ) - @ceedling[:configurator].find_and_merge_plugins( config_hash ) - @ceedling[:configurator].merge_imports( config_hash ) - @ceedling[:configurator].eval_environment_variables( config_hash ) - @ceedling[:configurator].tools_setup( config_hash ) - @ceedling[:configurator].eval_paths( config_hash ) - @ceedling[:configurator].standardize_paths( config_hash ) - @ceedling[:configurator].validate( config_hash ) - @ceedling[:configurator].build( config_hash, :environment ) - - @ceedling[:configurator].insert_rake_plugins( @ceedling[:configurator].rake_plugins ) - @ceedling[:configurator].tools_supplement_arguments( config_hash ) - - # merge in any environment variables plugins specify, after the main build - @ceedling[:plugin_manager].load_plugin_scripts( @ceedling[:configurator].script_plugins, @ceedling ) do |env| - @ceedling[:configurator].eval_environment_variables( env ) - @ceedling[:configurator].build_supplement( config_hash, env ) - end - - @ceedling[:plugin_reportinator].set_system_objects( @ceedling ) - @ceedling[:file_finder].prepare_search_sources - @ceedling[:loginator].setup_log_filepath - @ceedling[:project_config_manager].config_hash = config_hash - end - - def reset_defaults(config_hash) - @ceedling[:configurator].reset_defaults( config_hash ) - end -end diff --git a/vendor/ceedling/lib/ceedling/stream_wrapper.rb b/vendor/ceedling/lib/ceedling/stream_wrapper.rb deleted file mode 100644 index 7e16052..0000000 --- a/vendor/ceedling/lib/ceedling/stream_wrapper.rb +++ /dev/null @@ -1,28 +0,0 @@ - -class StreamWrapper - - def stdout_override(&fnc) - @stdout_overide_fnc = fnc - end - - def stdout_puts(string) - if @stdout_overide_fnc - @stdout_overide_fnc.call(string) - else - $stdout.puts(string) - end - end - - def stdout_flush - $stdout.flush - end - - def stderr_puts(string) - $stderr.puts(string) - end - - def stderr_flush - $stderr.flush - end - -end diff --git a/vendor/ceedling/lib/ceedling/streaminator.rb b/vendor/ceedling/lib/ceedling/streaminator.rb deleted file mode 100644 index b8dcd07..0000000 --- a/vendor/ceedling/lib/ceedling/streaminator.rb +++ /dev/null @@ -1,40 +0,0 @@ -require 'ceedling/constants' - -class Streaminator - - constructor :streaminator_helper, :verbosinator, :loginator, :stream_wrapper - - # for those objects for whom the configurator has already been instantiated, - # Streaminator is a convenience object for handling verbosity and writing to the std streams - - def stdout_puts(string, verbosity=Verbosity::NORMAL) - if (@verbosinator.should_output?(verbosity)) - @stream_wrapper.stdout_puts(string) - @stream_wrapper.stdout_flush - end - - # write to log as though Verbosity::OBNOXIOUS - @loginator.log( string, @streaminator_helper.extract_name($stdout) ) - end - - def stderr_puts(string, verbosity=Verbosity::NORMAL) - if (@verbosinator.should_output?(verbosity)) - @stream_wrapper.stderr_puts(string) - @stream_wrapper.stderr_flush - end - - # write to log as though Verbosity::OBNOXIOUS - @loginator.log( string, @streaminator_helper.extract_name($stderr) ) - end - - def stream_puts(stream, string, verbosity=Verbosity::NORMAL) - if (@verbosinator.should_output?(verbosity)) - stream.puts(string) - stream.flush - end - - # write to log as though Verbosity::OBNOXIOUS - @loginator.log( string, @streaminator_helper.extract_name(stream) ) - end - -end diff --git a/vendor/ceedling/lib/ceedling/streaminator_helper.rb b/vendor/ceedling/lib/ceedling/streaminator_helper.rb deleted file mode 100644 index 9fb5cc0..0000000 --- a/vendor/ceedling/lib/ceedling/streaminator_helper.rb +++ /dev/null @@ -1,15 +0,0 @@ - -class StreaminatorHelper - - def extract_name(stream) - name = case (stream.fileno) - when 0 then '#<IO:$stdin>' - when 1 then '#<IO:$stdout>' - when 2 then '#<IO:$stderr>' - else stream.inspect - end - - return name - end - -end diff --git a/vendor/ceedling/lib/ceedling/system_utils.rb b/vendor/ceedling/lib/ceedling/system_utils.rb deleted file mode 100644 index 477aba4..0000000 --- a/vendor/ceedling/lib/ceedling/system_utils.rb +++ /dev/null @@ -1,37 +0,0 @@ - -class Object - def deep_clone - Marshal::load(Marshal.dump(self)) - end -end - - -## -# Class containing system utility funcions. -class SystemUtils - - constructor :system_wrapper - - ## - # Sets up the class. - def setup - @tcsh_shell = nil - end - - ## - # Checks the system shell to see if it a tcsh shell. - def tcsh_shell? - # once run a single time, return state determined at that execution - return @tcsh_shell if not @tcsh_shell.nil? - - result = @system_wrapper.shell_backticks('echo $version') - - if ((result[:exit_code] == 0) and (result[:output].strip =~ /^tcsh/)) - @tcsh_shell = true - else - @tcsh_shell = false - end - - return @tcsh_shell - end -end diff --git a/vendor/ceedling/lib/ceedling/system_wrapper.rb b/vendor/ceedling/lib/ceedling/system_wrapper.rb deleted file mode 100644 index 2b0f1ed..0000000 --- a/vendor/ceedling/lib/ceedling/system_wrapper.rb +++ /dev/null @@ -1,80 +0,0 @@ -require 'rbconfig' - -class SystemWrapper - - # static method for use in defaults - def self.windows? - return ((RbConfig::CONFIG['host_os'] =~ /mswin|mingw/) ? true : false) if defined?(RbConfig) - return ((Config::CONFIG['host_os'] =~ /mswin|mingw/) ? true : false) - end - - # class method so as to be mockable for tests - def windows? - return SystemWrapper.windows? - end - - def module_eval(string) - return Object.module_eval("\"" + string + "\"") - end - - def eval(string) - return eval(string) - end - - def search_paths - return ENV['PATH'].split(File::PATH_SEPARATOR) - end - - def cmdline_args - return ARGV - end - - def env_set(name, value) - ENV[name] = value - end - - def env_get(name) - return ENV[name] - end - - def time_now - return Time.now.asctime - end - - def shell_backticks(command, boom = true) - retval = `#{command}`.freeze - $exit_code = ($?.exitstatus).freeze if boom - return { - :output => retval.freeze, - :exit_code => ($?.exitstatus).freeze - } - end - - def shell_system(command, boom = true) - system( command ) - $exit_code = ($?.exitstatus).freeze if boom - return { - :output => "".freeze, - :exit_code => ($?.exitstatus).freeze - } - end - - def add_load_path(path) - $LOAD_PATH.unshift(path) - end - - def require_file(path) - require(path) - end - - def ruby_success - # We are successful if we've never had an exit code that went boom (either because it's empty or it was 0) - return ($exit_code.nil? || ($exit_code == 0)) && ($!.nil? || $!.is_a?(SystemExit) && $!.success?) - end - - def constants_include?(item) - # forcing to strings provides consistency across Ruby versions - return Object.constants.map{|constant| constant.to_s}.include?(item.to_s) - end - -end diff --git a/vendor/ceedling/lib/ceedling/target_loader.rb b/vendor/ceedling/lib/ceedling/target_loader.rb deleted file mode 100644 index 7fbc095..0000000 --- a/vendor/ceedling/lib/ceedling/target_loader.rb +++ /dev/null @@ -1,38 +0,0 @@ -module TargetLoader - class NoTargets < Exception; end - class NoDirectory < Exception; end - class NoDefault < Exception; end - class NoSuchTarget < Exception; end - - class RequestReload < Exception; end - - def self.inspect(config, target_name=nil) - unless config[:targets] - raise NoTargets - end - - targets = config[:targets] - unless targets[:targets_directory] - raise NoDirectory.new("No targets directory specified.") - end - unless targets[:default_target] - raise NoDefault.new("No default target specified.") - end - - target_path = lambda {|name| File.join(targets[:targets_directory], name + ".yml")} - - target = if target_name - target_path.call(target_name) - else - target_path.call(targets[:default_target]) - end - - unless File.exists? target - raise NoSuchTarget.new("No such target: #{target}") - end - - ENV['CEEDLING_MAIN_PROJECT_FILE'] = target - - raise RequestReload - end -end diff --git a/vendor/ceedling/lib/ceedling/task_invoker.rb b/vendor/ceedling/lib/ceedling/task_invoker.rb deleted file mode 100644 index 7bfabbb..0000000 --- a/vendor/ceedling/lib/ceedling/task_invoker.rb +++ /dev/null @@ -1,122 +0,0 @@ -require 'ceedling/par_map' - -class TaskInvoker - - attr_accessor :first_run - - constructor :dependinator, :rake_utils, :rake_wrapper, :project_config_manager - - def setup - @test_regexs = [/^#{TEST_ROOT_NAME}:/] - @release_regexs = [/^#{RELEASE_ROOT_NAME}(:|$)/] - @first_run = true - end - - def add_test_task_regex(regex) - @test_regexs << regex - end - - def add_release_task_regex(regex) - @release_regexs << regex - end - - def test_invoked? - invoked = false - - @test_regexs.each do |regex| - invoked = true if (@rake_utils.task_invoked?(regex)) - break if invoked - end - - return invoked - end - - def release_invoked? - invoked = false - - @release_regexs.each do |regex| - invoked = true if (@rake_utils.task_invoked?(regex)) - break if invoked - end - - return invoked - end - - def invoked?(regex) - return @rake_utils.task_invoked?(regex) - end - - def reset_rake_task_for_changed_defines(file) - if !(file =~ /#{VENDORS_FILES.map{|ignore| '\b' + ignore.ext(File.extname(file)) + '\b'}.join('|')}$/) - @rake_wrapper[file].clear_actions if @first_run == false && @project_config_manager.test_defines_changed - @rake_wrapper[file].reenable if @first_run == false && @project_config_manager.test_defines_changed - end - end - - def invoke_test_mocks(mocks) - @dependinator.enhance_mock_dependencies( mocks ) - mocks.each { |mock| - reset_rake_task_for_changed_defines( mock ) - @rake_wrapper[mock].invoke - } - end - - def invoke_test_runner(runner) - @dependinator.enhance_runner_dependencies( runner ) - reset_rake_task_for_changed_defines( runner ) - @rake_wrapper[runner].invoke - end - - def invoke_test_shallow_include_lists(files) - @dependinator.enhance_shallow_include_lists_dependencies( files ) - par_map(PROJECT_COMPILE_THREADS, files) do |file| - reset_rake_task_for_changed_defines( file ) - @rake_wrapper[file].invoke - end - end - - def invoke_test_preprocessed_files(files) - @dependinator.enhance_preprocesed_file_dependencies( files ) - par_map(PROJECT_COMPILE_THREADS, files) do |file| - reset_rake_task_for_changed_defines( file ) - @rake_wrapper[file].invoke - end - end - - def invoke_test_dependencies_files(files) - @dependinator.enhance_dependencies_dependencies( files ) - par_map(PROJECT_COMPILE_THREADS, files) do |file| - reset_rake_task_for_changed_defines( file ) - @rake_wrapper[file].invoke - end - end - - def invoke_test_objects(objects) - par_map(PROJECT_COMPILE_THREADS, objects) do |object| - reset_rake_task_for_changed_defines( object ) - @rake_wrapper[object].invoke - end - end - - def invoke_test_executable(file) - @rake_wrapper[file].invoke - end - - def invoke_test_results(result) - @dependinator.enhance_results_dependencies( result ) - @rake_wrapper[result].invoke - end - - def invoke_release_dependencies_files(files) - par_map(PROJECT_COMPILE_THREADS, files) do |file| - @rake_wrapper[file].invoke - end - end - - def invoke_release_objects(objects) - par_map(PROJECT_COMPILE_THREADS, objects) do |object| - @rake_wrapper[object].invoke - end - end - -end diff --git a/vendor/ceedling/lib/ceedling/tasks_base.rake b/vendor/ceedling/lib/ceedling/tasks_base.rake deleted file mode 100644 index a35cde7..0000000 --- a/vendor/ceedling/lib/ceedling/tasks_base.rake +++ /dev/null @@ -1,116 +0,0 @@ -require 'ceedling/constants' -require 'ceedling/file_path_utils' -require 'ceedling/version' - -desc "Display build environment version info." -task :version do - puts " Ceedling:: #{Ceedling::Version::CEEDLING}" - puts " Unity:: #{Ceedling::Version::UNITY}" - puts " CMock:: #{Ceedling::Version::CMOCK}" - puts " CException:: #{Ceedling::Version::CEXCEPTION}" -end - -desc "Set verbose output (silent:[#{Verbosity::SILENT}] - obnoxious:[#{Verbosity::OBNOXIOUS}])." -task :verbosity, :level do |t, args| - verbosity_level = args.level.to_i - - if (PROJECT_USE_MOCKS) - # don't store verbosity level in setupinator's config hash, use a copy; - # otherwise, the input configuration will change and trigger entire project rebuilds - hash = @ceedling[:setupinator].config_hash[:cmock].clone - hash[:verbosity] = verbosity_level - - @ceedling[:cmock_builder].manufacture( hash ) - end - - @ceedling[:configurator].project_verbosity = verbosity_level - - # control rake's verbosity with new setting - verbose( ((verbosity_level >= Verbosity::OBNOXIOUS) ? true : false) ) -end - -desc "Enable logging" -task :logging do - @ceedling[:configurator].project_logging = true -end - -# non advertised debug task -task :debug do - Rake::Task[:verbosity].invoke(Verbosity::DEBUG) - Rake.application.options.trace = true - @ceedling[:configurator].project_debug = true -end - -# non advertised sanity checking task -task :sanity_checks, :level do |t, args| - check_level = args.level.to_i - @ceedling[:configurator].sanity_checks = check_level -end - -# non advertised catch for calling upgrade in the wrong place -task :upgrade do - puts "WARNING: You're currently IN your project directory. Take a step out and try" - puts "again if you'd like to perform an upgrade." -end - -# list expanded environment variables -if (not ENVIRONMENT.empty?) -desc "List all configured environment variables." -task :environment do - env_list = [] - ENVIRONMENT.each do |env| - env.each_key do |key| - name = key.to_s.upcase - env_list.push(" - #{name}: \"#{env[key]}\"") - end - end - env_list.sort.each do |env_line| - puts env_line - end -end -end - -namespace :options do - - COLLECTION_PROJECT_OPTIONS.each do |option_path| - option = File.basename(option_path, '.yml') - - desc "Merge #{option} project options." - task option.to_sym do - hash = @ceedling[:project_config_manager].merge_options( @ceedling[:setupinator].config_hash, option_path ) - @ceedling[:setupinator].do_setup( hash ) - if @ceedling[:configurator].project_release_build - load(File.join(CEEDLING_LIB, 'ceedling', 'rules_release.rake')) - end - end - end - - # This is to give nice errors when typing options - rule /^options:.*/ do |t, args| - filename = t.to_s.split(':')[-1] + '.yml' - filelist = COLLECTION_PROJECT_OPTIONS.map{|s| File.basename(s) } - @ceedling[:file_finder].find_file_from_list(filename, filelist, :error) - end - - # This will output the fully-merged tools options to their own project.yml file - desc "Export tools options to a new project file" - task :export, :filename do |t, args| - outfile = args.filename || 'tools.yml' - toolcfg = {} - @ceedling[:configurator].project_config_hash.each_pair do |k,v| - toolcfg[k] = v if (k.to_s[0..5] == 'tools_') - end - File.open(outfile,'w') {|f| f << toolcfg.to_yaml({:indentation => 2})} - end -end - - -# do not present task if there's no plugins -if (not PLUGINS_ENABLED.empty?) -desc "Execute plugin result summaries (no build triggering)." -task :summary do - @ceedling[:plugin_manager].summary - puts "\nNOTE: Summaries may be out of date with project sources.\n\n" -end -end - diff --git a/vendor/ceedling/lib/ceedling/tasks_filesystem.rake b/vendor/ceedling/lib/ceedling/tasks_filesystem.rake deleted file mode 100644 index 7b950ca..0000000 --- a/vendor/ceedling/lib/ceedling/tasks_filesystem.rake +++ /dev/null @@ -1,113 +0,0 @@ - -# rather than require 'rake/clean' & try to override, we replicate for finer control -CLEAN = Rake::FileList["**/*~", "**/*.bak"] -CLOBBER = Rake::FileList.new - -CLEAN.clear_exclude.exclude { |fn| fn.pathmap("%f") == 'core' && File.directory?(fn) } - -CLEAN.include(File.join(PROJECT_TEST_BUILD_OUTPUT_PATH, '*')) -CLEAN.include(File.join(PROJECT_TEST_RESULTS_PATH, '*')) -CLEAN.include(File.join(PROJECT_TEST_DEPENDENCIES_PATH, '*')) -CLEAN.include(File.join(PROJECT_BUILD_RELEASE_ROOT, '*.*')) -CLEAN.include(File.join(PROJECT_RELEASE_BUILD_OUTPUT_PATH, '*')) -CLEAN.include(File.join(PROJECT_RELEASE_DEPENDENCIES_PATH, '*')) - -CLOBBER.include(File.join(PROJECT_BUILD_ARTIFACTS_ROOT, '**/*')) -CLOBBER.include(File.join(PROJECT_BUILD_TESTS_ROOT, '**/*')) -CLOBBER.include(File.join(PROJECT_BUILD_RELEASE_ROOT, '**/*')) -CLOBBER.include(File.join(PROJECT_LOG_PATH, '**/*')) -CLOBBER.include(File.join(PROJECT_TEMP_PATH, '**/*')) - -# just in case they're using git, let's make sure we allow them to preserved the build directory if desired. -CLOBBER.exclude(File.join(TESTS_BASE_PATH), '**/.gitkeep') - -# because of cmock config, mock path can optionally exist apart from standard test build paths -CLOBBER.include(File.join(CMOCK_MOCK_PATH, '*')) - -REMOVE_FILE_PROC = Proc.new { |fn| rm_r fn rescue nil } - -# redefine clean so we can override how it advertises itself -desc "Delete all build artifacts and temporary products." -task(:clean) do - # because :clean is a prerequisite for :clobber, intelligently display the progress message - if (not @ceedling[:task_invoker].invoked?(/^clobber$/)) - @ceedling[:streaminator].stdout_puts("\nCleaning build artifacts...\n(For large projects, this task may take a long time to complete)\n\n") - end - begin - CLEAN.each { |fn| REMOVE_FILE_PROC.call(fn) } - rescue - end -end - -# redefine clobber so we can override how it advertises itself -desc "Delete all generated files (and build artifacts)." -task(:clobber => [:clean]) do - @ceedling[:streaminator].stdout_puts("\nClobbering all generated files...\n(For large projects, this task may take a long time to complete)\n\n") - begin - CLOBBER.each { |fn| REMOVE_FILE_PROC.call(fn) } - @ceedling[:rake_wrapper][:directories].invoke - @ceedling[:dependinator].touch_force_rebuild_files - rescue - end -end - -# create a directory task for each of the paths, so we know how to build them -PROJECT_BUILD_PATHS.each { |path| directory(path) } - -# create a single directory task which verifies all the others get built -task :directories => PROJECT_BUILD_PATHS - -# when the force file doesn't exist, it probably means we clobbered or are on a fresh -# install. In either case, stuff was deleted, so assume we want to rebuild it all -file @ceedling[:configurator].project_test_force_rebuild_filepath do - unless File.exists?(@ceedling[:configurator].project_test_force_rebuild_filepath) - @ceedling[:dependinator].touch_force_rebuild_files - end -end - -# list paths discovered at load time -namespace :paths do - standard_paths = ['test','source','include'] - paths = @ceedling[:setupinator].config_hash[:paths].keys.map{|n| n.to_s.downcase} - paths = (paths + standard_paths).uniq - paths.each do |name| - path_list = Object.const_get("COLLECTION_PATHS_#{name.upcase}") - - if (path_list.size != 0) || (standard_paths.include?(name)) - desc "List all collected #{name} paths." - task(name.to_sym) { puts "#{name} paths:"; path_list.sort.each {|path| puts " - #{path}" } } - end - end - -end - - -# list files & file counts discovered at load time -namespace :files do - - categories = [ - ['test', COLLECTION_ALL_TESTS], - ['source', COLLECTION_ALL_SOURCE], - ['include', COLLECTION_ALL_HEADERS], - ['support', COLLECTION_ALL_SUPPORT] - ] - - using_assembly = (defined?(TEST_BUILD_USE_ASSEMBLY) && TEST_BUILD_USE_ASSEMBLY) || - (defined?(RELEASE_BUILD_USE_ASSEMBLY) && RELEASE_BUILD_USE_ASSEMBLY) - categories << ['assembly', COLLECTION_ALL_ASSEMBLY] if using_assembly - - categories.each do |category| - name = category[0] - collection = category[1] - - desc "List all collected #{name} files." - task(name.to_sym) do - puts "#{name} files:" - collection.sort.each { |filepath| puts " - #{filepath}" } - puts "file count: #{collection.size}" - end - end - -end - - diff --git a/vendor/ceedling/lib/ceedling/tasks_release.rake b/vendor/ceedling/lib/ceedling/tasks_release.rake deleted file mode 100644 index b313b2f..0000000 --- a/vendor/ceedling/lib/ceedling/tasks_release.rake +++ /dev/null @@ -1,30 +0,0 @@ -require 'ceedling/constants' -require 'ceedling/file_path_utils' - - -desc "Build release target." -task RELEASE_SYM => [:directories] do - header = "Release build '#{File.basename(PROJECT_RELEASE_BUILD_TARGET)}'" - @ceedling[:streaminator].stdout_puts("\n\n#{header}\n#{'-' * header.length}") - - begin - @ceedling[:plugin_manager].pre_release - - core_objects = [] - extra_objects = @ceedling[:file_path_utils].form_release_build_c_objects_filelist( COLLECTION_RELEASE_ARTIFACT_EXTRA_LINK_OBJECTS ) - - @ceedling[:project_config_manager].process_release_config_change - core_objects.concat( @ceedling[:release_invoker].setup_and_invoke_c_objects( COLLECTION_ALL_SOURCE ) ) - - # if assembler use isn't enabled, COLLECTION_ALL_ASSEMBLY is empty array & nothing happens - core_objects.concat( @ceedling[:release_invoker].setup_and_invoke_asm_objects( COLLECTION_ALL_ASSEMBLY ) ) - - # if we're using libraries, we need to add those to our collection as well - library_objects = (defined? LIBRARIES_RELEASE && !LIBRARIES_RELEASE.empty?) ? LIBRARIES_RELEASE.flatten.compact : [] - file( PROJECT_RELEASE_BUILD_TARGET => (core_objects + extra_objects + library_objects) ) - Rake::Task[PROJECT_RELEASE_BUILD_TARGET].invoke - ensure - @ceedling[:plugin_manager].post_release - end -end - diff --git a/vendor/ceedling/lib/ceedling/tasks_release_deep_dependencies.rake b/vendor/ceedling/lib/ceedling/tasks_release_deep_dependencies.rake deleted file mode 100644 index db2be5f..0000000 --- a/vendor/ceedling/lib/ceedling/tasks_release_deep_dependencies.rake +++ /dev/null @@ -1,9 +0,0 @@ -require 'ceedling/constants' - -namespace REFRESH_SYM do - - task RELEASE_SYM do - @ceedling[:release_invoker].refresh_c_deep_dependencies - end - -end diff --git a/vendor/ceedling/lib/ceedling/tasks_tests.rake b/vendor/ceedling/lib/ceedling/tasks_tests.rake deleted file mode 100644 index 6c51ebc..0000000 --- a/vendor/ceedling/lib/ceedling/tasks_tests.rake +++ /dev/null @@ -1,62 +0,0 @@ -require 'ceedling/constants' - -task :test_deps => [:directories] - -task :test => [:test_deps] do - Rake.application['test:all'].invoke -end - -namespace TEST_SYM do - - desc "Run all unit tests (also just 'test' works)." - task :all => [:test_deps] do - @ceedling[:test_invoker].setup_and_invoke(COLLECTION_ALL_TESTS) - end - - desc "Run single test ([*] real test or source file name, no path)." - task :* do - message = "\nOops! '#{TEST_ROOT_NAME}:*' isn't a real task. " + - "Use a real test or source file name (no path) in place of the wildcard.\n" + - "Example: rake #{TEST_ROOT_NAME}:foo.c\n\n" - - @ceedling[:streaminator].stdout_puts( message ) - end - - desc "Run tests for changed files." - task :delta => [:test_deps] do - @ceedling[:test_invoker].setup_and_invoke(COLLECTION_ALL_TESTS, TEST_SYM, {:force_run => false}) - end - - desc "Just build tests without running." - task :build_only => [:test_deps] do - @ceedling[:test_invoker].setup_and_invoke(COLLECTION_ALL_TESTS, TEST_SYM, {:build_only => true}) - end - - desc "Run tests by matching regular expression pattern." - task :pattern, [:regex] => [:test_deps] do |t, args| - matches = [] - - COLLECTION_ALL_TESTS.each { |test| matches << test if (test =~ /#{args.regex}/) } - - if (matches.size > 0) - @ceedling[:test_invoker].setup_and_invoke(matches, TEST_SYM, {:force_run => false}) - else - @ceedling[:streaminator].stdout_puts("\nFound no tests matching pattern /#{args.regex}/.") - end - end - - desc "Run tests whose test path contains [dir] or [dir] substring." - task :path, [:dir] => [:test_deps] do |t, args| - matches = [] - - COLLECTION_ALL_TESTS.each { |test| matches << test if File.dirname(test).include?(args.dir.gsub(/\\/, '/')) } - - if (matches.size > 0) - @ceedling[:test_invoker].setup_and_invoke(matches, TEST_SYM, {:force_run => false}) - else - @ceedling[:streaminator].stdout_puts("\nFound no tests including the given path or path component.") - end - end - -end - diff --git a/vendor/ceedling/lib/ceedling/tasks_tests_deep_dependencies.rake b/vendor/ceedling/lib/ceedling/tasks_tests_deep_dependencies.rake deleted file mode 100644 index f899407..0000000 --- a/vendor/ceedling/lib/ceedling/tasks_tests_deep_dependencies.rake +++ /dev/null @@ -1,9 +0,0 @@ -require 'ceedling/constants' - -namespace REFRESH_SYM do - - task TEST_SYM do - @ceedling[:test_invoker].refresh_deep_dependencies - end - -end diff --git a/vendor/ceedling/lib/ceedling/tasks_vendor.rake b/vendor/ceedling/lib/ceedling/tasks_vendor.rake deleted file mode 100644 index 63c2ca5..0000000 --- a/vendor/ceedling/lib/ceedling/tasks_vendor.rake +++ /dev/null @@ -1,35 +0,0 @@ -require 'ceedling/constants' -require 'ceedling/file_path_utils' - -# create file dependencies to ensure C-based components of vendor tools are recompiled when they are updated with new versions -# forming these explicitly rather than depend on auxiliary dependencies so all scenarios are explicitly covered - -file( @ceedling[:file_path_utils].form_test_build_c_object_filepath( UNITY_C_FILE ) => [ - File.join( UNITY_VENDOR_PATH, UNITY_LIB_PATH, UNITY_C_FILE ), - File.join( UNITY_VENDOR_PATH, UNITY_LIB_PATH, UNITY_H_FILE ), - File.join( UNITY_VENDOR_PATH, UNITY_LIB_PATH, UNITY_INTERNALS_H_FILE ) ] - ) - - -if (PROJECT_USE_MOCKS) -file( @ceedling[:file_path_utils].form_test_build_c_object_filepath( CMOCK_C_FILE ) => [ - File.join( CMOCK_VENDOR_PATH, CMOCK_LIB_PATH, CMOCK_C_FILE ), - File.join( CMOCK_VENDOR_PATH, CMOCK_LIB_PATH, CMOCK_H_FILE ) ] - ) -end - - -if (PROJECT_USE_EXCEPTIONS) -file( @ceedling[:file_path_utils].form_test_build_c_object_filepath( CEXCEPTION_C_FILE ) => [ - File.join( CEXCEPTION_VENDOR_PATH, CEXCEPTION_LIB_PATH, CEXCEPTION_C_FILE ), - File.join( CEXCEPTION_VENDOR_PATH, CEXCEPTION_LIB_PATH, CEXCEPTION_H_FILE ) ] - ) -end - - -if (PROJECT_USE_EXCEPTIONS and PROJECT_RELEASE_BUILD) -file( @ceedling[:file_path_utils].form_release_build_c_object_filepath( CEXCEPTION_C_FILE ) => [ - File.join( CEXCEPTION_VENDOR_PATH, CEXCEPTION_LIB_PATH, CEXCEPTION_C_FILE ), - File.join( CEXCEPTION_VENDOR_PATH, CEXCEPTION_LIB_PATH, CEXCEPTION_H_FILE ) ] - ) -end diff --git a/vendor/ceedling/lib/ceedling/test_includes_extractor.rb b/vendor/ceedling/lib/ceedling/test_includes_extractor.rb deleted file mode 100644 index 393b0be..0000000 --- a/vendor/ceedling/lib/ceedling/test_includes_extractor.rb +++ /dev/null @@ -1,111 +0,0 @@ - -class TestIncludesExtractor - - constructor :configurator, :yaml_wrapper, :file_wrapper - - def setup - @includes = {} - @mocks = {} - end - - - # for includes_list file, slurp up array from yaml file and sort & store includes - def parse_includes_list(includes_list) - gather_and_store_includes( includes_list, @yaml_wrapper.load(includes_list) ) - end - - # open, scan for, and sort & store includes of test file - def parse_test_file(test) - gather_and_store_includes( test, extract_from_file(test) ) - end - - # open, scan for, and sort & store includes of test file - def parse_test_file_source_include(test) - return extract_source_include_from_file(test) - end - - # mocks with no file extension - def lookup_raw_mock_list(test) - file_key = form_file_key(test) - return [] if @mocks[file_key].nil? - return @mocks[file_key] - end - - # includes with file extension - def lookup_includes_list(file) - file_key = form_file_key(file) - return [] if (@includes[file_key]).nil? - return @includes[file_key] - end - - private ################################# - - def form_file_key(filepath) - return File.basename(filepath).to_sym - end - - def extract_from_file(file) - includes = [] - header_extension = @configurator.extension_header - - contents = @file_wrapper.read(file) - - # remove line comments - contents = contents.gsub(/\/\/.*$/, '') - # remove block comments - contents = contents.gsub(/\/\*.*?\*\//m, '') - - contents.split("\n").each do |line| - # look for include statement - scan_results = line.scan(/#include\s+\"\s*(.+#{'\\'+header_extension})\s*\"/) - - includes << scan_results[0][0] if (scan_results.size > 0) - - # look for TEST_FILE statement - scan_results = line.scan(/TEST_FILE\(\s*\"\s*(.+\.\w+)\s*\"\s*\)/) - - includes << scan_results[0][0] if (scan_results.size > 0) - end - - return includes.uniq - end - - def extract_source_include_from_file(file) - source_includes = [] - source_extension = @configurator.extension_source - - contents = @file_wrapper.read(file) - - # remove line comments - contents = contents.gsub(/\/\/.*$/, '') - # remove block comments - contents = contents.gsub(/\/\*.*?\*\//m, '') - - contents.split("\n").each do |line| - # look for include statement - scan_results = line.scan(/#include\s+\"\s*(.+#{'\\'+source_extension})\s*\"/) - - source_includes << scan_results[0][0] if (scan_results.size > 0) - end - - return source_includes.uniq - end - - def gather_and_store_includes(file, includes) - mock_prefix = @configurator.cmock_mock_prefix - header_extension = @configurator.extension_header - file_key = form_file_key(file) - @mocks[file_key] = [] - - # add includes to lookup hash - @includes[file_key] = includes - - includes.each do |include_file| - # check if include is a mock - scan_results = include_file.scan(/(#{mock_prefix}.+)#{'\\'+header_extension}/) - # add mock to lookup hash - @mocks[file_key] << scan_results[0][0] if (scan_results.size > 0) - end - end - -end diff --git a/vendor/ceedling/lib/ceedling/test_invoker.rb b/vendor/ceedling/lib/ceedling/test_invoker.rb deleted file mode 100644 index ae686a1..0000000 --- a/vendor/ceedling/lib/ceedling/test_invoker.rb +++ /dev/null @@ -1,165 +0,0 @@ -require 'ceedling/constants' - - -class TestInvoker - - attr_reader :sources, :tests, :mocks - - constructor :configurator, - :test_invoker_helper, - :plugin_manager, - :streaminator, - :preprocessinator, - :task_invoker, - :dependinator, - :project_config_manager, - :build_invoker_utils, - :file_path_utils, - :file_wrapper - - def setup - @sources = [] - @tests = [] - @mocks = [] - end - - - # Convert libraries configuration form YAML configuration - # into a string that can be given to the compiler. - def convert_libraries_to_arguments() - args = ((@configurator.project_config_hash[:libraries_test] || []) + ((defined? LIBRARIES_SYSTEM) ? LIBRARIES_SYSTEM : [])).flatten - if (defined? LIBRARIES_FLAG) - args.map! {|v| LIBRARIES_FLAG.gsub(/\$\{1\}/, v) } - end - return args - end - - def get_library_paths_to_arguments() - paths = (defined? PATHS_LIBRARIES) ? (PATHS_LIBRARIES || []).clone : [] - if (defined? LIBRARIES_PATH_FLAG) - paths.map! {|v| LIBRARIES_PATH_FLAG.gsub(/\$\{1\}/, v) } - end - return paths - end - - def setup_and_invoke(tests, context=TEST_SYM, options={:force_run => true, :build_only => false}) - - @tests = tests - - @project_config_manager.process_test_config_change - - @tests.each do |test| - # announce beginning of test run - header = "Test '#{File.basename(test)}'" - @streaminator.stdout_puts("\n\n#{header}\n#{'-' * header.length}") - - begin - @plugin_manager.pre_test( test ) - test_name ="#{File.basename(test)}".chomp('.c') - def_test_key="defines_#{test_name.downcase}" - - if @configurator.project_config_hash.has_key?(def_test_key.to_sym) || @configurator.defines_use_test_definition - defs_bkp = Array.new(COLLECTION_DEFINES_TEST_AND_VENDOR) - tst_defs_cfg = Array.new(defs_bkp) - if @configurator.project_config_hash.has_key?(def_test_key.to_sym) - tst_defs_cfg.replace(@configurator.project_config_hash[def_test_key.to_sym]) - tst_defs_cfg .concat(COLLECTION_DEFINES_VENDOR) if COLLECTION_DEFINES_VENDOR - end - if @configurator.defines_use_test_definition - tst_defs_cfg << File.basename(test, ".*").strip.upcase.sub(/@.*$/, "") - end - COLLECTION_DEFINES_TEST_AND_VENDOR.replace(tst_defs_cfg) - end - - # redefine the project out path and preprocessor defines - if @configurator.project_config_hash.has_key?(def_test_key.to_sym) - @streaminator.stdout_puts("Updating test definitions for #{test_name}", Verbosity::NORMAL) - orig_path = @configurator.project_test_build_output_path - @configurator.project_config_hash[:project_test_build_output_path] = File.join(@configurator.project_test_build_output_path, test_name) - @file_wrapper.mkdir(@configurator.project_test_build_output_path) - end - - # collect up test fixture pieces & parts - runner = @file_path_utils.form_runner_filepath_from_test( test ) - mock_list = @preprocessinator.preprocess_test_and_invoke_test_mocks( test ) - sources = @test_invoker_helper.extract_sources( test ) - extras = @configurator.collection_test_fixture_extra_link_objects - core = [test] + mock_list + sources - objects = @file_path_utils.form_test_build_objects_filelist( [runner] + core + extras ).uniq - results_pass = @file_path_utils.form_pass_results_filepath( test ) - results_fail = @file_path_utils.form_fail_results_filepath( test ) - - # identify all the objects shall not be linked and then remove them from objects list. - no_link_objects = @file_path_utils.form_test_build_objects_filelist(@preprocessinator.preprocess_shallow_source_includes( test )) - objects = objects.uniq - no_link_objects - - @project_config_manager.process_test_defines_change(@project_config_manager.filter_internal_sources(sources)) - - # clean results files so we have a missing file with which to kick off rake's dependency rules - @test_invoker_helper.clean_results( {:pass => results_pass, :fail => results_fail}, options ) - - # load up auxiliary dependencies so deep changes cause rebuilding appropriately - @test_invoker_helper.process_deep_dependencies( core ) do |dependencies_list| - @dependinator.load_test_object_deep_dependencies( dependencies_list ) - end - - # tell rake to create test runner if needed - @task_invoker.invoke_test_runner( runner ) - - # enhance object file dependencies to capture externalities influencing regeneration - @dependinator.enhance_test_build_object_dependencies( objects ) - - # associate object files with executable - @dependinator.enhance_test_executable_dependencies( test, objects ) - - # build test objects - @task_invoker.invoke_test_objects( objects ) - - # if the option build_only has been specified, build only the executable - # but don't run the test - if (options[:build_only]) - executable = @file_path_utils.form_test_executable_filepath( test ) - @task_invoker.invoke_test_executable( executable ) - else - # 3, 2, 1... launch - @task_invoker.invoke_test_results( results_pass ) - end - rescue => e - @build_invoker_utils.process_exception( e, context ) - ensure - @plugin_manager.post_test( test ) - # restore the project test defines - if @configurator.project_config_hash.has_key?(def_test_key.to_sym) || @configurator.defines_use_test_definition - COLLECTION_DEFINES_TEST_AND_VENDOR.replace(defs_bkp) - if @configurator.project_config_hash.has_key?(def_test_key.to_sym) - @configurator.project_config_hash[:project_test_build_output_path] = orig_path - @streaminator.stdout_puts("Restored defines and build path to standard", Verbosity::NORMAL) - end - end - end - - # store away what's been processed - @mocks.concat( mock_list ) - @sources.concat( sources ) - - @task_invoker.first_run = false - end - - # post-process collected mock list - @mocks.uniq! - - # post-process collected sources list - @sources.uniq! - end - - - def refresh_deep_dependencies - @file_wrapper.rm_f( - @file_wrapper.directory_listing( - File.join( @configurator.project_test_dependencies_path, '*' + @configurator.extension_dependencies ) ) ) - - @test_invoker_helper.process_deep_dependencies( - @configurator.collection_all_tests + @configurator.collection_all_source ) - end - -end diff --git a/vendor/ceedling/lib/ceedling/test_invoker_helper.rb b/vendor/ceedling/lib/ceedling/test_invoker_helper.rb deleted file mode 100644 index 403d93e..0000000 --- a/vendor/ceedling/lib/ceedling/test_invoker_helper.rb +++ /dev/null @@ -1,32 +0,0 @@ - -class TestInvokerHelper - - constructor :configurator, :task_invoker, :test_includes_extractor, :file_finder, :file_path_utils, :file_wrapper - - def clean_results(results, options) - @file_wrapper.rm_f( results[:fail] ) - @file_wrapper.rm_f( results[:pass] ) if (options[:force_run]) - end - - def process_deep_dependencies(files) - return if (not @configurator.project_use_deep_dependencies) - - dependencies_list = @file_path_utils.form_test_dependencies_filelist( files ).uniq - - if @configurator.project_generate_deep_dependencies - @task_invoker.invoke_test_dependencies_files( dependencies_list ) - end - - yield( dependencies_list ) if block_given? - end - - def extract_sources(test) - sources = [] - includes = @test_includes_extractor.lookup_includes_list(test) - - includes.each { |include| sources << @file_finder.find_compilation_input_file(include, :ignore) } - - return sources.compact - end - -end diff --git a/vendor/ceedling/lib/ceedling/tool_executor.rb b/vendor/ceedling/lib/ceedling/tool_executor.rb deleted file mode 100644 index 0ab5ddc..0000000 --- a/vendor/ceedling/lib/ceedling/tool_executor.rb +++ /dev/null @@ -1,229 +0,0 @@ -require 'ceedling/constants' -require 'benchmark' - -class ShellExecutionException < RuntimeError - attr_reader :shell_result - def initialize(shell_result) - @shell_result = shell_result - end -end - -class ToolExecutor - - constructor :configurator, :tool_executor_helper, :streaminator, :system_wrapper - - def setup - @tool_name = '' - @executable = '' - end - - # build up a command line from yaml provided config - - # @param extra_params is an array of parameters to append to executable - def build_command_line(tool_config, extra_params, *args) - @tool_name = tool_config[:name] - @executable = tool_config[:executable] - - command = {} - - # basic premise is to iterate top to bottom through arguments using '$' as - # a string replacement indicator to expand globals or inline yaml arrays - # into command line arguments via substitution strings - # executable must be quoted if it includes spaces (common on windows) - executable = @tool_executor_helper.osify_path_separators( expandify_element(@executable, *args) ) - executable = "\"#{executable}\"" if executable.include?(' ') - command[:line] = [ - executable, - extra_params.join(' ').strip, - build_arguments(tool_config[:arguments], *args), - ].reject{|s| s.nil? || s.empty?}.join(' ').strip - - command[:options] = { - :stderr_redirect => @tool_executor_helper.stderr_redirection(tool_config, @configurator.project_logging), - :background_exec => tool_config[:background_exec] - } - - return command - end - - - # shell out, execute command, and return response - def exec(command, options={}, args=[]) - options[:boom] = true if (options[:boom].nil?) - options[:stderr_redirect] = StdErrRedirect::NONE if (options[:stderr_redirect].nil?) - options[:background_exec] = BackgroundExec::NONE if (options[:background_exec].nil?) - # build command line - command_line = [ - @tool_executor_helper.background_exec_cmdline_prepend( options ), - command.strip, - args, - @tool_executor_helper.stderr_redirect_cmdline_append( options ), - @tool_executor_helper.background_exec_cmdline_append( options ), - ].flatten.compact.join(' ') - - @streaminator.stderr_puts("Verbose: #{__method__.to_s}(): #{command_line}", Verbosity::DEBUG) - - shell_result = {} - - # depending on background exec option, we shell out differently - time = Benchmark.realtime do - if (options[:background_exec] != BackgroundExec::NONE) - shell_result = @system_wrapper.shell_system( command_line, options[:boom] ) - else - shell_result = @system_wrapper.shell_backticks( command_line, options[:boom] ) - end - end - shell_result[:time] = time - - #scrub the string for illegal output - unless shell_result[:output].nil? - shell_result[:output] = shell_result[:output].scrub if "".respond_to?(:scrub) - shell_result[:output].gsub!(/\033\[\d\dm/,'') - end - - @tool_executor_helper.print_happy_results( command_line, shell_result, options[:boom] ) - @tool_executor_helper.print_error_results( command_line, shell_result, options[:boom] ) - - # go boom if exit code isn't 0 (but in some cases we don't want a non-0 exit code to raise) - raise ShellExecutionException.new(shell_result) if ((shell_result[:exit_code] != 0) and options[:boom]) - - return shell_result - end - - - private ############################# - - - def build_arguments(config, *args) - build_string = '' - - return nil if (config.nil?) - - # iterate through each argument - - # the yaml blob array needs to be flattened so that yaml substitution - # is handled correctly, since it creates a nested array when an anchor is - # dereferenced - config.flatten.each do |element| - argument = '' - - case(element) - # if we find a simple string then look for string replacement operators - # and expand with the parameters in this method's argument list - when String then argument = expandify_element(element, *args) - # if we find a hash, then we grab the key as a substitution string and expand the - # hash's value(s) within that substitution string - when Hash then argument = dehashify_argument_elements(element) - end - - build_string.concat("#{argument} ") if (argument.length > 0) - end - - build_string.strip! - return build_string if (build_string.length > 0) - return nil - end - - - # handle simple text string argument & argument array string replacement operators - def expandify_element(element, *args) - match = // - to_process = nil - args_index = 0 - - # handle ${#} input replacement - if (element =~ TOOL_EXECUTOR_ARGUMENT_REPLACEMENT_PATTERN) - args_index = ($2.to_i - 1) - - if (args.nil? or args[args_index].nil?) - @streaminator.stderr_puts("ERROR: Tool '#{@tool_name}' expected valid argument data to accompany replacement operator #{$1}.", Verbosity::ERRORS) - raise - end - - match = /#{Regexp.escape($1)}/ - to_process = args[args_index] - end - - # simple string argument: replace escaped '\$' and strip - element.sub!(/\\\$/, '$') - element.strip! - - # handle inline ruby execution - if (element =~ RUBY_EVAL_REPLACEMENT_PATTERN) - element.replace(eval($1)) - end - - build_string = '' - - # handle array or anything else passed into method to be expanded in place of replacement operators - case (to_process) - when Array then to_process.each {|value| build_string.concat( "#{element.sub(match, value.to_s)} " ) } if (to_process.size > 0) - else build_string.concat( element.sub(match, to_process.to_s) ) - end - - # handle inline ruby string substitution - if (build_string =~ RUBY_STRING_REPLACEMENT_PATTERN) - build_string.replace(@system_wrapper.module_eval(build_string)) - end - - return build_string.strip - end - - - # handle argument hash: keys are substitution strings, values are data to be expanded within substitution strings - def dehashify_argument_elements(hash) - build_string = '' - elements = [] - - # grab the substitution string (hash key) - substitution = hash.keys[0].to_s - # grab the string(s) to squirt into the substitution string (hash value) - expand = hash[hash.keys[0]] - - if (expand.nil?) - @streaminator.stderr_puts("ERROR: Tool '#{@tool_name}' could not expand nil elements for substitution string '#{substitution}'.", Verbosity::ERRORS) - raise - end - - # array-ify expansion input if only a single string - expansion = ((expand.class == String) ? [expand] : expand) - - expansion.each do |item| - # code eval substitution - if (item =~ RUBY_EVAL_REPLACEMENT_PATTERN) - elements << eval($1) - # string eval substitution - elsif (item =~ RUBY_STRING_REPLACEMENT_PATTERN) - elements << @system_wrapper.module_eval(item) - # global constants - elsif (@system_wrapper.constants_include?(item)) - const = Object.const_get(item) - if (const.nil?) - @streaminator.stderr_puts("ERROR: Tool '#{@tool_name}' found constant '#{item}' to be nil.", Verbosity::ERRORS) - raise - else - elements << const - end - elsif (item.class == Array) - elements << item - elsif (item.class == String) - @streaminator.stderr_puts("ERROR: Tool '#{@tool_name}' cannot expand nonexistent value '#{item}' for substitution string '#{substitution}'.", Verbosity::ERRORS) - raise - else - @streaminator.stderr_puts("ERROR: Tool '#{@tool_name}' cannot expand value having type '#{item.class}' for substitution string '#{substitution}'.", Verbosity::ERRORS) - raise - end - end - - # expand elements (whether string or array) into substitution string & replace escaped '\$' - elements.flatten! - elements.each do |element| - build_string.concat( substitution.sub(/([^\\]*)\$/, "\\1#{element}") ) # don't replace escaped '\$' but allow us to replace just a lonesome '$' - build_string.gsub!(/\\\$/, '$') - build_string.concat(' ') - end - - return build_string.strip - end - -end diff --git a/vendor/ceedling/lib/ceedling/tool_executor_helper.rb b/vendor/ceedling/lib/ceedling/tool_executor_helper.rb deleted file mode 100644 index de4cafe..0000000 --- a/vendor/ceedling/lib/ceedling/tool_executor_helper.rb +++ /dev/null @@ -1,164 +0,0 @@ -require 'ceedling/constants' # for Verbosity enumeration & $stderr redirect enumeration - -## -# Helper functions for the tool executor -class ToolExecutorHelper - - constructor :streaminator, :system_utils, :system_wrapper - - ## - # Returns the stderr redirection based on the config and logging. - # ==== Attributes - # - # * _tool_config_: A hash containing config information. - # * _logging_: A boolean representing if logging is enabled or not. - # - def stderr_redirection(tool_config, logging) - # if there's no logging enabled, return :stderr_redirect unmodified - return tool_config[:stderr_redirect] if (not logging) - - # if there is logging enabled but the redirect is a custom value (not enum), return the custom string - return tool_config[:stderr_redirect] if (tool_config[:stderr_redirect].class == String) - - # if logging is enabled but there's no custom string, return the AUTO enumeration so $stderr goes into the log - return StdErrRedirect::AUTO - end - - - ## - # Returns the background execution prepend based on the config. - # ==== Attributes - # - # * _tool_config_: A hash containing config information. - # - def background_exec_cmdline_prepend(tool_config) - return nil if (tool_config.nil? || tool_config[:background_exec].nil?) - - config_exec = tool_config[:background_exec] - - if ((config_exec == BackgroundExec::AUTO) and (@system_wrapper.windows?)) - return 'start' - end - - if (config_exec == BackgroundExec::WIN) - return 'start' - end - - return nil - end - - - ## - # Modifies an executables path based on platform. - # ==== Attributes - # - # * _executable_: The executable's path. - # - def osify_path_separators(executable) - return executable.gsub(/\//, '\\') if (@system_wrapper.windows?) - return executable - end - - ## - # Returns the stderr redirect append based on the config. - # ==== Attributes - # - # * _tool_config_: A hash containing config information. - # - def stderr_redirect_cmdline_append(tool_config) - return nil if (tool_config.nil? || tool_config[:stderr_redirect].nil?) - - config_redirect = tool_config[:stderr_redirect] - redirect = StdErrRedirect::NONE - - if (config_redirect == StdErrRedirect::AUTO) - if (@system_wrapper.windows?) - redirect = StdErrRedirect::WIN - elsif (@system_utils.tcsh_shell?) - redirect = StdErrRedirect::TCSH - else - redirect = StdErrRedirect::UNIX - end - end - - case redirect - # we may need more complicated processing after some learning with various environments - when StdErrRedirect::NONE then nil - when StdErrRedirect::WIN then '2>&1' - when StdErrRedirect::UNIX then '2>&1' - when StdErrRedirect::TCSH then '|&' - else redirect.to_s - end - end - - ## - # Returns the background execution append based on the config. - # ==== Attributes - # - # * _tool_config_: A hash containing config information. - # - def background_exec_cmdline_append(tool_config) - return nil if (tool_config.nil? || tool_config[:background_exec].nil?) - - config_exec = tool_config[:background_exec] - - # if :auto & windows, then we already prepended 'start' and should append nothing - return nil if ((config_exec == BackgroundExec::AUTO) and (@system_wrapper.windows?)) - - # if :auto & not windows, then we append standard '&' - return '&' if ((config_exec == BackgroundExec::AUTO) and (not @system_wrapper.windows?)) - - # if explicitly Unix, then append '&' - return '&' if (config_exec == BackgroundExec::UNIX) - - # * _command_str_: A hash containing config information. - # all other cases, including :none, :win, & anything unrecognized, append nothing - return nil - end - - ## - # Outputs success results if command succeeded and we have verbosity cranked up. - # ==== Attributes - # - # * _command_str_: The command ran. - # * _shell_results_: The outputs of the command including exit code and - # output. - # * _boom_: A boolean representing if a non zero result is erroneous. - # - def print_happy_results(command_str, shell_result, boom=true) - if ((shell_result[:exit_code] == 0) or ((shell_result[:exit_code] != 0) and not boom)) - output = "> Shell executed command:\n" - output += "'#{command_str}'\n" - output += "> Produced output:\n" if (not shell_result[:output].empty?) - output += "#{shell_result[:output].strip}\n" if (not shell_result[:output].empty?) - output += "> And exited with status: [#{shell_result[:exit_code]}].\n" if (shell_result[:exit_code] != 0) - output += "\n" - - @streaminator.stdout_puts(output, Verbosity::OBNOXIOUS) - end - end - - ## - # Outputs failures results if command failed and we have verbosity set to minimum error level. - # ==== Attributes - # - # * _command_str_: The command ran. - # * _shell_results_: The outputs of the command including exit code and - # output. - # * _boom_: A boolean representing if a non zero result is erroneous. - # - def print_error_results(command_str, shell_result, boom=true) - if ((shell_result[:exit_code] != 0) and boom) - output = "ERROR: Shell command failed.\n" - output += "> Shell executed command:\n" - output += "'#{command_str}'\n" - output += "> Produced output:\n" if (not shell_result[:output].empty?) - output += "#{shell_result[:output].strip}\n" if (not shell_result[:output].empty?) - output += "> And exited with status: [#{shell_result[:exit_code]}].\n" if (shell_result[:exit_code] != nil) - output += "> And then likely crashed.\n" if (shell_result[:exit_code] == nil) - output += "\n" - - @streaminator.stderr_puts(output, Verbosity::ERRORS) - end - end -end diff --git a/vendor/ceedling/lib/ceedling/verbosinator.rb b/vendor/ceedling/lib/ceedling/verbosinator.rb deleted file mode 100644 index e8ed38d..0000000 --- a/vendor/ceedling/lib/ceedling/verbosinator.rb +++ /dev/null @@ -1,10 +0,0 @@ - -class Verbosinator - - constructor :configurator - - def should_output?(level) - return (level <= @configurator.project_verbosity) - end - -end diff --git a/vendor/ceedling/lib/ceedling/version.rb b/vendor/ceedling/lib/ceedling/version.rb deleted file mode 100644 index ebda10b..0000000 --- a/vendor/ceedling/lib/ceedling/version.rb +++ /dev/null @@ -1,54 +0,0 @@ - -# @private -module Ceedling - module Version - { "UNITY" => File.join("unity","src","unity.h"), - "CMOCK" => File.join("cmock","src","cmock.h"), - "CEXCEPTION" => File.join("c_exception","lib","CException.h") - }.each_pair do |name, path| - # Check for local or global version of vendor directory in order to look up versions - path1 = File.expand_path( File.join("..","..","vendor",path) ) - path2 = File.expand_path( File.join(File.dirname(__FILE__),"..","..","vendor",path) ) - filename = if (File.exists?(path1)) - path1 - elsif (File.exists?(path2)) - path2 - elsif File.exists?(CEEDLING_VENDOR) - path3 = File.expand_path( File.join(CEEDLING_VENDOR,path) ) - if (File.exists?(path3)) - path3 - else - basepath = File.join( CEEDLING_VENDOR, path.split(/\\\//)[0], 'release') - begin - [ @ceedling[:file_wrapper].read( File.join(base_path, 'release', 'version.info') ).strip, - @ceedling[:file_wrapper].read( File.join(base_path, 'release', 'build.info') ).strip ].join('.') - rescue - "#{name}" - end - end - else - module_eval("#{name} = 'unknown'") - continue - end - - # Actually look up the versions - a = [0,0,0] - begin - File.readlines(filename).each do |line| - ["VERSION_MAJOR", "VERSION_MINOR", "VERSION_BUILD"].each_with_index do |field, i| - m = line.match(/#{name}_#{field}\s+(\d+)/) - a[i] = m[1] unless (m.nil?) - end - end - rescue - abort("Can't collect data for vendor component: \"#{filename}\" . \nPlease check your setup.") - end - - # splat it to return the final value - eval("#{name} = '#{a.join(".")}'") - end - - GEM = "0.31.1" - CEEDLING = GEM - end -end diff --git a/vendor/ceedling/lib/ceedling/yaml_wrapper.rb b/vendor/ceedling/lib/ceedling/yaml_wrapper.rb deleted file mode 100644 index 00ece51..0000000 --- a/vendor/ceedling/lib/ceedling/yaml_wrapper.rb +++ /dev/null @@ -1,17 +0,0 @@ -require 'yaml' -require 'erb' - - -class YamlWrapper - - def load(filepath) - return YAML.load(ERB.new(File.read(filepath)).result) - end - - def dump(filepath, structure) - File.open(filepath, 'w') do |output| - YAML.dump(structure, output) - end - end - -end diff --git a/vendor/ceedling/plugins/beep/README.md b/vendor/ceedling/plugins/beep/README.md deleted file mode 100644 index e59d881..0000000 --- a/vendor/ceedling/plugins/beep/README.md +++ /dev/null @@ -1,22 +0,0 @@ -ceedling-beep -============= - -This is a simple plugin that just beeps at the end of a build and/or test sequence. Are you getting too distracted surfing -the internet, chatting with coworkers, or swordfighting while it's building or testing? The friendly beep will let you know -it's time to pay attention again. - -This plugin has very few configuration options. At this time it can beep on completion of a task and/or on an error condition. -For each of these, you can configure the method that it should beep. - -``` -:tools: - :beep_on_done: :bell - :beep_on_error: :bell -``` - -Each of these have the following options: - - - :bell - this option uses the ASCII bell character out stdout - - :speaker_test - this uses the linux speaker-test command if installed - -Very likely, we'll be adding to this list if people find this to be useful. diff --git a/vendor/ceedling/plugins/beep/lib/beep.rb b/vendor/ceedling/plugins/beep/lib/beep.rb deleted file mode 100644 index 6a6d01a..0000000 --- a/vendor/ceedling/plugins/beep/lib/beep.rb +++ /dev/null @@ -1,40 +0,0 @@ -require 'ceedling/plugin' -require 'ceedling/constants' - -class Beep < Plugin - - attr_reader :config - - def setup - @config = { - :on_done => ((defined? TOOLS_BEEP_ON_DONE) ? TOOLS_BEEP_ON_DONE : :bell ), - :on_error => ((defined? TOOLS_BEEP_ON_ERROR) ? TOOLS_BEEP_ON_ERROR : :bell ), - } - end - - def post_build - beep @config[:on_done] - end - - def post_error - beep @config[:on_error] - end - - private - - def beep(method = :none) - case method - when :bell - if (SystemWrapper.windows?) - puts "echo '\007'" - else - puts "echo -ne '\007'" - end - when :speaker_test - `speaker-test -t sine -f 1000 -l 1` - else - #do nothing with illegal or :none - end - end -end - diff --git a/vendor/ceedling/plugins/bullseye/README.md b/vendor/ceedling/plugins/bullseye/README.md deleted file mode 100644 index ab0b53b..0000000 --- a/vendor/ceedling/plugins/bullseye/README.md +++ /dev/null @@ -1,76 +0,0 @@ -ceedling-bullseye -================= - -# Plugin Overview - -Plugin for integrating Bullseye code coverage tool into Ceedling projects. -This plugin requires a working license to Bullseye code coverage tools. The tools -must be within the path or the path should be added to the environment in the -`project.yml file`. - -## Configuration - -The bullseye plugin supports configuration options via your `project.yml` provided -by Ceedling. The following is a typical configuration example: - -``` -:bullseye: - :auto_license: TRUE -:plugins: - :bullseye_lib_path: [] -:paths: - :bullseye_toolchain_include: [] - -:tools: - :bullseye_instrumentation: - :executable: covc - :arguments: - - '--file $': ENVIRONMENT_COVFILE - - -q - - ${1} - :bullseye_compiler: - :executable: gcc - :arguments: - - -g - - -I"$": COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR - - -I"$": COLLECTION_PATHS_BULLSEYE_TOOLCHAIN_INCLUDE - - -D$: COLLECTION_DEFINES_TEST_AND_VENDOR - - -DBULLSEYE_COMPILER - - -c "${1}" - - -o "${2}" - :bullseye_linker: - :executable: gcc - :arguments: - - ${1} - - -o ${2} - - -L$: PLUGINS_BULLSEYE_LIB_PATH - - -lcov - :bullseye_fixture: - :executable: ${1} - :bullseye_report_covsrc: - :executable: covsrc - :arguments: - - '--file $': ENVIRONMENT_COVFILE - - -q - - -w140 - :bullseye_report_covfn: - :executable: covfn - :stderr_redirect: :auto - :arguments: - - '--file $': ENVIRONMENT_COVFILE - - --width 120 - - --no-source - - '"${1}"' - :bullseye_browser: - :executable: CoverageBrowser - :background_exec: :auto - :optional: TRUE - :arguments: - - '"$"': ENVIRONMENT_COVFILE -``` - -## Example Usage - -```sh -ceedling bullseye:all utils:bullseye -``` diff --git a/vendor/ceedling/plugins/bullseye/assets/template.erb b/vendor/ceedling/plugins/bullseye/assets/template.erb deleted file mode 100644 index 504f855..0000000 --- a/vendor/ceedling/plugins/bullseye/assets/template.erb +++ /dev/null @@ -1,15 +0,0 @@ -% function_string = hash[:coverage][:functions].to_s -% branch_string = hash[:coverage][:branches].to_s -% format_string = "%#{[function_string.length, branch_string.length].max}i" -<%=@ceedling[:plugin_reportinator].generate_banner("#{hash[:header]}: CODE COVERAGE SUMMARY")%> -% if (!hash[:coverage][:functions].nil?) -FUNCTIONS: <%=sprintf(format_string, hash[:coverage][:functions])%>% -% else -FUNCTIONS: none -% end -% if (!hash[:coverage][:branches].nil?) -BRANCHES: <%=sprintf(format_string, hash[:coverage][:branches])%>% -% else -BRANCHES: none -% end - diff --git a/vendor/ceedling/plugins/bullseye/bullseye.rake b/vendor/ceedling/plugins/bullseye/bullseye.rake deleted file mode 100644 index 11073e7..0000000 --- a/vendor/ceedling/plugins/bullseye/bullseye.rake +++ /dev/null @@ -1,173 +0,0 @@ -directory(BULLSEYE_BUILD_OUTPUT_PATH) -directory(BULLSEYE_RESULTS_PATH) -directory(BULLSEYE_ARTIFACTS_PATH) -directory(BULLSEYE_DEPENDENCIES_PATH) - -CLEAN.include(File.join(BULLSEYE_BUILD_OUTPUT_PATH, '*')) -CLEAN.include(File.join(BULLSEYE_RESULTS_PATH, '*')) -CLEAN.include(File.join(BULLSEYE_DEPENDENCIES_PATH, '*')) - -CLOBBER.include(File.join(BULLSEYE_BUILD_PATH, '**/*')) -PLUGINS_BULLSEYE_LIB_PATH = 'C:\\tools\\BullseyeCoverage\\lib' if not defined?(PLUGINS_BULLSEYE_LIB_PATH) - -rule(/#{BULLSEYE_BUILD_OUTPUT_PATH}\/#{'.+\\'+EXTENSION_OBJECT}$/ => [ - proc do |task_name| - @ceedling[:file_finder].find_compilation_input_file(task_name) - end - ]) do |object| - - if File.basename(object.source) =~ /^(#{PROJECT_TEST_FILE_PREFIX}|#{CMOCK_MOCK_PREFIX}|#{BULLSEYE_IGNORE_SOURCES.join('|')})/i - @ceedling[:generator].generate_object_file( - TOOLS_BULLSEYE_COMPILER, - OPERATION_COMPILE_SYM, - BULLSEYE_SYM, - object.source, - object.name, - @ceedling[:file_path_utils].form_test_build_list_filepath(object.name) - ) - else - @ceedling[BULLSEYE_SYM].generate_coverage_object_file(object.source, object.name) - end - -end - -rule(/#{BULLSEYE_BUILD_OUTPUT_PATH}\/#{'.+\\'+EXTENSION_EXECUTABLE}$/) do |bin_file| - lib_args = @ceedling[:test_invoker].convert_libraries_to_arguments() - lib_paths = @ceedling[:test_invoker].get_library_paths_to_arguments() - @ceedling[:generator].generate_executable_file( - TOOLS_BULLSEYE_LINKER, - BULLSEYE_SYM, - bin_file.prerequisites, - bin_file.name, - @ceedling[:file_path_utils].form_test_build_map_filepath(bin_file.name), - lib_args, - lib_paths - ) -end - -rule(/#{BULLSEYE_RESULTS_PATH}\/#{'.+\\'+EXTENSION_TESTPASS}$/ => [ - proc do |task_name| - @ceedling[:file_path_utils].form_test_executable_filepath(task_name) - end - ]) do |test_result| - @ceedling[:generator].generate_test_results(TOOLS_BULLSEYE_FIXTURE, BULLSEYE_SYM, test_result.source, test_result.name) -end - -rule(/#{BULLSEYE_DEPENDENCIES_PATH}\/#{'.+\\'+EXTENSION_DEPENDENCIES}$/ => [ - proc do |task_name| - @ceedling[:file_finder].find_compilation_input_file(task_name) - end - ]) do |dep| - @ceedling[:generator].generate_dependencies_file( - TOOLS_TEST_DEPENDENCIES_GENERATOR, - BULLSEYE_SYM, - dep.source, - File.join(BULLSEYE_BUILD_OUTPUT_PATH, File.basename(dep.source).ext(EXTENSION_OBJECT) ), - dep.name - ) -end - -task :directories => [BULLSEYE_BUILD_OUTPUT_PATH, BULLSEYE_RESULTS_PATH, BULLSEYE_DEPENDENCIES_PATH, BULLSEYE_ARTIFACTS_PATH] - -namespace BULLSEYE_SYM do - task source_coverage: COLLECTION_ALL_SOURCE.pathmap("#{BULLSEYE_BUILD_OUTPUT_PATH}/%n#{@ceedling[:configurator].extension_object}") - - desc 'Run code coverage for all tests' - task all: [:test_deps] do - @ceedling[:configurator].replace_flattened_config(@ceedling[BULLSEYE_SYM].config) - @ceedling[BULLSEYE_SYM].enableBullseye(true) - @ceedling[:test_invoker].setup_and_invoke(COLLECTION_ALL_TESTS, BULLSEYE_SYM) - @ceedling[:configurator].restore_config - end - - desc "Run single test w/ coverage ([*] real test or source file name, no path)." - task :* do - message = "\nOops! '#{BULLSEYE_ROOT_NAME}:*' isn't a real task. " + - "Use a real test or source file name (no path) in place of the wildcard.\n" + - "Example: rake #{BULLSEYE_ROOT_NAME}:foo.c\n\n" - - @ceedling[:streaminator].stdout_puts( message ) - end - - desc 'Run tests by matching regular expression pattern.' - task :pattern, [:regex] => [:test_deps] do |_t, args| - matches = [] - - COLLECTION_ALL_TESTS.each do |test| - matches << test if test =~ /#{args.regex}/ - end - - if !matches.empty? - @ceedling[:configurator].replace_flattened_config(@ceedling[BULLSEYE_SYM].config) - @ceedling[BULLSEYE_SYM].enableBullseye(true) - @ceedling[:test_invoker].setup_and_invoke(matches, BULLSEYE_SYM, force_run: false) - @ceedling[:configurator].restore_config - else - @ceedling[:streaminator].stdout_puts("\nFound no tests matching pattern /#{args.regex}/.") - end - end - - desc 'Run tests whose test path contains [dir] or [dir] substring.' - task :path, [:dir] => [:test_deps] do |_t, args| - matches = [] - - COLLECTION_ALL_TESTS.each do |test| - matches << test if File.dirname(test).include?(args.dir.tr('\\', '/')) - end - - if !matches.empty? - @ceedling[:configurator].replace_flattened_config(@ceedling[BULLSEYE_SYM].config) - @ceedling[BULLSEYE_SYM].enableBullseye(true) - @ceedling[:test_invoker].setup_and_invoke(matches, BULLSEYE_SYM, force_run: false) - @ceedling[:configurator].restore_config - else - @ceedling[:streaminator].stdout_puts("\nFound no tests including the given path or path component.") - end - end - - desc 'Run code coverage for changed files' - task delta: [:test_deps] do - @ceedling[:configurator].replace_flattened_config(@ceedling[BULLSEYE_SYM].config) - @ceedling[BULLSEYE_SYM].enableBullseye(true) - @ceedling[:test_invoker].setup_and_invoke(COLLECTION_ALL_TESTS, BULLSEYE_SYM, {:force_run => false}) - @ceedling[:configurator].restore_config - end - - # use a rule to increase efficiency for large projects - # bullseye test tasks by regex - rule(/^#{BULLSEYE_TASK_ROOT}\S+$/ => [ - proc do |task_name| - test = task_name.sub(/#{BULLSEYE_TASK_ROOT}/, '') - test = "#{PROJECT_TEST_FILE_PREFIX}#{test}" unless test.start_with?(PROJECT_TEST_FILE_PREFIX) - @ceedling[:file_finder].find_test_from_file_path(test) - end - ]) do |test| - @ceedling[:rake_wrapper][:test_deps].invoke - @ceedling[:configurator].replace_flattened_config(@ceedling[BULLSEYE_SYM].config) - @ceedling[BULLSEYE_SYM].enableBullseye(true) - @ceedling[:test_invoker].setup_and_invoke([test.source], BULLSEYE_SYM) - @ceedling[:configurator].restore_config - end - -end - -if PROJECT_USE_DEEP_DEPENDENCIES -namespace REFRESH_SYM do - task BULLSEYE_SYM do - @ceedling[:configurator].replace_flattened_config(@ceedling[BULLSEYE_SYM].config) - @ceedling[BULLSEYE_SYM].enableBullseye(true) - @ceedling[:test_invoker].refresh_deep_dependencies - @ceedling[:configurator].restore_config - end -end -end - -namespace UTILS_SYM do - - desc "Open Bullseye code coverage browser" - task BULLSEYE_SYM do - command = @ceedling[:tool_executor].build_command_line(TOOLS_BULLSEYE_BROWSER, []) - @ceedling[:tool_executor].exec(command[:line], command[:options]) - end - -end diff --git a/vendor/ceedling/plugins/bullseye/config/defaults.yml b/vendor/ceedling/plugins/bullseye/config/defaults.yml deleted file mode 100644 index ed261d8..0000000 --- a/vendor/ceedling/plugins/bullseye/config/defaults.yml +++ /dev/null @@ -1,57 +0,0 @@ ---- - -:bullseye: - :auto_license: TRUE -:plugins: - :bullseye_lib_path: [] -:paths: - :bullseye_toolchain_include: [] - -:tools: - :bullseye_instrumentation: - :executable: covc - :arguments: - - '--file $': ENVIRONMENT_COVFILE - - -q - - ${1} - :bullseye_compiler: - :executable: gcc - :arguments: - - -g - - -I"$": COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR - - -I"$": COLLECTION_PATHS_BULLSEYE_TOOLCHAIN_INCLUDE - - -D$: COLLECTION_DEFINES_TEST_AND_VENDOR - - -DBULLSEYE_COMPILER - - -c "${1}" - - -o "${2}" - :bullseye_linker: - :executable: gcc - :arguments: - - ${1} - - -o ${2} - - -L$: PLUGINS_BULLSEYE_LIB_PATH - - -lcov - :bullseye_fixture: - :executable: ${1} - :bullseye_report_covsrc: - :executable: covsrc - :arguments: - - '--file $': ENVIRONMENT_COVFILE - - -q - - -w140 - :bullseye_report_covfn: - :executable: covfn - :stderr_redirect: :auto - :arguments: - - '--file $': ENVIRONMENT_COVFILE - - --width 120 - - --no-source - - '"${1}"' - :bullseye_browser: - :executable: CoverageBrowser - :background_exec: :auto - :optional: TRUE - :arguments: - - '"$"': ENVIRONMENT_COVFILE - -... diff --git a/vendor/ceedling/plugins/bullseye/lib/bullseye.rb b/vendor/ceedling/plugins/bullseye/lib/bullseye.rb deleted file mode 100644 index ffa444a..0000000 --- a/vendor/ceedling/plugins/bullseye/lib/bullseye.rb +++ /dev/null @@ -1,194 +0,0 @@ -require 'ceedling/plugin' -require 'ceedling/constants' - -BULLSEYE_ROOT_NAME = 'bullseye' -BULLSEYE_TASK_ROOT = BULLSEYE_ROOT_NAME + ':' -BULLSEYE_SYM = BULLSEYE_ROOT_NAME.to_sym - -BULLSEYE_BUILD_PATH = "#{PROJECT_BUILD_ROOT}/#{BULLSEYE_ROOT_NAME}" -BULLSEYE_BUILD_OUTPUT_PATH = "#{BULLSEYE_BUILD_PATH}/out" -BULLSEYE_RESULTS_PATH = "#{BULLSEYE_BUILD_PATH}/results" -BULLSEYE_DEPENDENCIES_PATH = "#{BULLSEYE_BUILD_PATH}/dependencies" -BULLSEYE_ARTIFACTS_PATH = "#{PROJECT_BUILD_ARTIFACTS_ROOT}/#{BULLSEYE_ROOT_NAME}" - -BULLSEYE_IGNORE_SOURCES = ['unity', 'cmock', 'cexception'] - - -class Bullseye < Plugin - - def setup - @result_list = [] - @environment = [ {:covfile => File.join( BULLSEYE_ARTIFACTS_PATH, 'test.cov' )} ] - @plugin_root = File.expand_path(File.join(File.dirname(__FILE__), '..')) - @coverage_template_all = @ceedling[:file_wrapper].read(File.join(@plugin_root, 'assets/template.erb')) - end - - def config - { - :project_test_build_output_path => BULLSEYE_BUILD_OUTPUT_PATH, - :project_test_results_path => BULLSEYE_RESULTS_PATH, - :project_test_dependencies_path => BULLSEYE_DEPENDENCIES_PATH, - :defines_test => DEFINES_TEST + ['CODE_COVERAGE'], - :collection_defines_test_and_vendor => COLLECTION_DEFINES_TEST_AND_VENDOR + ['CODE_COVERAGE'] - } - end - - def generate_coverage_object_file(source, object) - arg_hash = {:tool => TOOLS_BULLSEYE_INSTRUMENTATION, :context => BULLSEYE_SYM, :source => source, :object => object} - @ceedling[:plugin_manager].pre_compile_execute(arg_hash) - - @ceedling[:streaminator].stdout_puts("Compiling #{File.basename(source)} with coverage...") - compile_command = - @ceedling[:tool_executor].build_command_line( - TOOLS_BULLSEYE_COMPILER, - @ceedling[:flaginator].flag_down( OPERATION_COMPILE_SYM, BULLSEYE_SYM, source ), - source, - object, - @ceedling[:file_path_utils].form_test_build_list_filepath( object ) ) - coverage_command = @ceedling[:tool_executor].build_command_line(TOOLS_BULLSEYE_INSTRUMENTATION, [], compile_command[:line] ) - - shell_result = @ceedling[:tool_executor].exec( coverage_command[:line], coverage_command[:options] ) - - arg_hash[:shell_result] = shell_result - @ceedling[:plugin_manager].post_compile_execute(arg_hash) - end - - def post_test_fixture_execute(arg_hash) - result_file = arg_hash[:result_file] - - if ((result_file =~ /#{BULLSEYE_RESULTS_PATH}/) and (not @result_list.include?(result_file))) - @result_list << arg_hash[:result_file] - end - end - - def post_build - return if (not @ceedling[:task_invoker].invoked?(/^#{BULLSEYE_TASK_ROOT}/)) - - # test results - results = @ceedling[:plugin_reportinator].assemble_test_results(@result_list) - hash = { - :header => BULLSEYE_ROOT_NAME.upcase, - :results => results - } - - @ceedling[:plugin_reportinator].run_test_results_report(hash) do - message = '' - message = 'Unit test failures.' if (results[:counts][:failed] > 0) - message - end - - # coverage results - return if (verify_coverage_file() == false) - if (@ceedling[:task_invoker].invoked?(/^#{BULLSEYE_TASK_ROOT}(all|delta)/)) - command = @ceedling[:tool_executor].build_command_line(TOOLS_BULLSEYE_REPORT_COVSRC, []) - shell_result = @ceedling[:tool_executor].exec(command[:line], command[:options]) - report_coverage_results_all(shell_result[:output]) - else - report_per_function_coverage_results(@ceedling[:test_invoker].sources) - end - end - - def summary - return if (verify_coverage_file() == false) - result_list = @ceedling[:file_path_utils].form_pass_results_filelist( BULLSEYE_RESULTS_PATH, COLLECTION_ALL_TESTS ) - - # test results - # get test results for only those tests in our configuration and of those only tests with results on disk - hash = { - :header => BULLSEYE_ROOT_NAME.upcase, - :results => @ceedling[:plugin_reportinator].assemble_test_results(result_list, {:boom => false}) - } - - @ceedling[:plugin_reportinator].run_test_results_report(hash) - - # coverage results - command = @ceedling[:tool_executor].build_command_line(TOOLS_BULLSEYE_REPORT_COVSRC) - shell_result = @ceedling[:tool_executor].exec(command[:line], command[:options]) - report_coverage_results_all(shell_result[:output]) - end - - def enableBullseye(enable) - if BULLSEYE_AUTO_LICENSE - if (enable) - args = ['push', 'on'] - @ceedling[:streaminator].stdout_puts("Enabling Bullseye") - else - args = ['pop'] - @ceedling[:streaminator].stdout_puts("Reverting Bullseye to previous state") - end - - args.each do |arg| - command = @ceedling[:tool_executor].build_command_line(TOOLS_BULLSEYE_BUILD_ENABLE_DISABLE, [], arg) - shell_result = @ceedling[:tool_executor].exec(command[:line], command[:options]) - end - - end - end - - private ################################### - - def report_coverage_results_all(coverage) - results = { - :header => BULLSEYE_ROOT_NAME.upcase, - :coverage => { - :functions => nil, - :branches => nil - } - } - - if (coverage =~ /^Total.*?=\s+([0-9]+)\%/) - results[:coverage][:functions] = $1.to_i - end - - if (coverage =~ /^Total.*=\s+([0-9]+)\%\s*$/) - results[:coverage][:branches] = $1.to_i - end - - @ceedling[:plugin_reportinator].run_report($stdout, @coverage_template_all, results) - end - - def report_per_function_coverage_results(sources) - banner = @ceedling[:plugin_reportinator].generate_banner( "#{BULLSEYE_ROOT_NAME.upcase}: CODE COVERAGE SUMMARY" ) - @ceedling[:streaminator].stdout_puts "\n" + banner - - coverage_sources = sources.clone - coverage_sources.delete_if {|item| item =~ /#{CMOCK_MOCK_PREFIX}.+#{EXTENSION_SOURCE}$/} - coverage_sources.delete_if {|item| item =~ /#{BULLSEYE_IGNORE_SOURCES.join('|')}#{EXTENSION_SOURCE}$/} - - coverage_sources.each do |source| - command = @ceedling[:tool_executor].build_command_line(TOOLS_BULLSEYE_REPORT_COVFN, [], source) - shell_results = @ceedling[:tool_executor].exec(command[:line], command[:options]) - coverage_results = shell_results[:output].deep_clone - coverage_results.sub!(/.*\n.*\n/,'') # Remove the Bullseye tool banner - if (coverage_results =~ /warning cov814: report is empty/) - coverage_results = "WARNING: #{source} contains no coverage data!\n\n" - @ceedling[:streaminator].stdout_puts(coverage_results, Verbosity::COMPLAIN) - else - coverage_results += "\n" - @ceedling[:streaminator].stdout_puts(coverage_results) - end - end - end - - def verify_coverage_file - exist = @ceedling[:file_wrapper].exist?( ENVIRONMENT_COVFILE ) - - if (!exist) - banner = @ceedling[:plugin_reportinator].generate_banner( "#{BULLSEYE_ROOT_NAME.upcase}: CODE COVERAGE SUMMARY" ) - @ceedling[:streaminator].stdout_puts "\n" + banner + "\nNo coverage file.\n\n" - end - - return exist - end - -end - - -# end blocks always executed following rake run -END { - # cache our input configurations to use in comparison upon next execution - if (@ceedling[:task_invoker].invoked?(/^#{BULLSEYE_TASK_ROOT}/)) - @ceedling[:cacheinator].cache_test_config( @ceedling[:setupinator].config_hash ) - @ceedling[BULLSEYE_SYM].enableBullseye(false) - end -} diff --git a/vendor/ceedling/plugins/colour_report/README.md b/vendor/ceedling/plugins/colour_report/README.md deleted file mode 100644 index 4e0fcd4..0000000 --- a/vendor/ceedling/plugins/colour_report/README.md +++ /dev/null @@ -1,20 +0,0 @@ -ceedling-colour-report -====================== - -## Overview - -The colour_report replaces the normal ceedling "pretty" output with -a colorized variant, in order to make the results easier to read from -a standard command line. This is very useful on developer machines, but -can occasionally cause problems with parsing on CI servers. - -## Setup - -Enable the plugin in your project.yml by adding `colour_report` -to the list of enabled plugins. - -``` YAML -:plugins: - :enabled: - - colour_report -``` diff --git a/vendor/ceedling/plugins/colour_report/lib/colour_report.rb b/vendor/ceedling/plugins/colour_report/lib/colour_report.rb deleted file mode 100644 index 1211eab..0000000 --- a/vendor/ceedling/plugins/colour_report/lib/colour_report.rb +++ /dev/null @@ -1,16 +0,0 @@ -require 'ceedling/plugin' -require 'ceedling/streaminator' -require 'ceedling/constants' - -class ColourReport < Plugin - - def setup - @ceedling[:stream_wrapper].stdout_override(&ColourReport.method(:colour_stdout)) - end - - def self.colour_stdout(string) - require 'colour_reporter.rb' - report string - end - -end diff --git a/vendor/ceedling/plugins/command_hooks/README.md b/vendor/ceedling/plugins/command_hooks/README.md deleted file mode 100644 index 8ac64af..0000000 --- a/vendor/ceedling/plugins/command_hooks/README.md +++ /dev/null @@ -1,53 +0,0 @@ -ceedling-command-hooks -====================== - -Plugin for easily calling command line tools at various points in the build process - -Define any of these sections in :tools: to provide additional hooks to be called on demand: - -``` - :pre_mock_generate - :post_mock_generate - :pre_runner_generate - :post_runner_generate - :pre_compile_execute - :post_compile_execute - :pre_link_execute - :post_link_execute - :pre_test_fixture_execute - :pre_test - :post_test - :pre_release - :post_release - :pre_build - :post_build -``` - -Each of these tools can support an :executable string and an :arguments list, like so: - -``` -:tools: - :post_link_execute: - :executable: objcopy.exe - :arguments: - - ${1} #This is replaced with the executable name - - output.srec - - --strip-all -``` - -You may also specify an array of executables to be called in a particular place, like so: - -``` -:tools: - :post_test: - - :executable: echo - :arguments: "${1} was glorious!" - - :executable: echo - :arguments: - - it kinda made me cry a little. - - you? -``` - -Please note that it varies which arguments are being parsed down to the -hooks. For now see `command_hooks.rb` to figure out which suits you best. -Happy Tweaking! diff --git a/vendor/ceedling/plugins/command_hooks/lib/command_hooks.rb b/vendor/ceedling/plugins/command_hooks/lib/command_hooks.rb deleted file mode 100644 index 4bf8b53..0000000 --- a/vendor/ceedling/plugins/command_hooks/lib/command_hooks.rb +++ /dev/null @@ -1,92 +0,0 @@ -require 'ceedling/plugin' -require 'ceedling/constants' -class CommandHooks < Plugin - - attr_reader :config - - def setup - @config = { - :pre_mock_generate => ((defined? TOOLS_PRE_MOCK_GENERATE) ? TOOLS_PRE_MOCK_GENERATE : nil ), - :post_mock_generate => ((defined? TOOLS_POST_MOCK_GENERATE) ? TOOLS_POST_MOCK_GENERATE : nil ), - :pre_runner_generate => ((defined? TOOLS_PRE_RUNNER_GENERATE) ? TOOLS_PRE_RUNNER_GENERATE : nil ), - :post_runner_generate => ((defined? TOOLS_POST_RUNNER_GENERATE) ? TOOLS_POST_RUNNER_GENERATE : nil ), - :pre_compile_execute => ((defined? TOOLS_PRE_COMPILE_EXECUTE) ? TOOLS_PRE_COMPILE_EXECUTE : nil ), - :post_compile_execute => ((defined? TOOLS_POST_COMPILE_EXECUTE) ? TOOLS_POST_COMPILE_EXECUTE : nil ), - :pre_link_execute => ((defined? TOOLS_PRE_LINK_EXECUTE) ? TOOLS_PRE_LINK_EXECUTE : nil ), - :post_link_execute => ((defined? TOOLS_POST_LINK_EXECUTE) ? TOOLS_POST_LINK_EXECUTE : nil ), - :pre_test_fixture_execute => ((defined? TOOLS_PRE_TEST_FIXTURE_EXECUTE) ? TOOLS_PRE_TEST_FIXTURE_EXECUTE : nil ), - :post_test_fixture_execute => ((defined? TOOLS_POST_TEST_FIXTURE_EXECUTE) ? TOOLS_POST_TEST_FIXTURE_EXECUTE : nil ), - :pre_test => ((defined? TOOLS_PRE_TEST) ? TOOLS_PRE_TEST : nil ), - :post_test => ((defined? TOOLS_POST_TEST) ? TOOLS_POST_TEST : nil ), - :pre_release => ((defined? TOOLS_PRE_RELEASE) ? TOOLS_PRE_RELEASE : nil ), - :post_release => ((defined? TOOLS_POST_RELEASE) ? TOOLS_POST_RELEASE : nil ), - :pre_build => ((defined? TOOLS_PRE_BUILD) ? TOOLS_PRE_BUILD : nil ), - :post_build => ((defined? TOOLS_POST_BUILD) ? TOOLS_POST_BUILD : nil ), - :post_error => ((defined? TOOLS_POST_ERROR) ? TOOLS_POST_ERROR : nil ), - } - @plugin_root = File.expand_path(File.join(File.dirname(__FILE__), '..')) - end - - def pre_mock_generate(arg_hash); run_hook(:pre_mock_generate, arg_hash[:header_file] ); end - def post_mock_generate(arg_hash); run_hook(:post_mock_generate, arg_hash[:header_file] ); end - def pre_runner_generate(arg_hash); run_hook(:pre_runner_generate, arg_hash[:source ] ); end - def post_runner_generate(arg_hash); run_hook(:post_runner_generate, arg_hash[:runner_file] ); end - def pre_compile_execute(arg_hash); run_hook(:pre_compile_execute, arg_hash[:source_file] ); end - def post_compile_execute(arg_hash); run_hook(:post_compile_execute, arg_hash[:object_file] ); end - def pre_link_execute(arg_hash); run_hook(:pre_link_execute, arg_hash[:executable] ); end - def post_link_execute(arg_hash); run_hook(:post_link_execute, arg_hash[:executable] ); end - def pre_test_fixture_execute(arg_hash); run_hook(:pre_test_fixture_execute, arg_hash[:executable] ); end - def post_test_fixture_execute(arg_hash); run_hook(:post_test_fixture_execute, arg_hash[:executable] ); end - def pre_test(test); run_hook(:pre_test, test ); end - def post_test(test); run_hook(:post_test, test ); end - def pre_release; run_hook(:pre_release ); end - def post_release; run_hook(:post_release ); end - def pre_build; run_hook(:pre_build ); end - def post_build; run_hook(:post_build ); end - def post_error; run_hook(:post_error ); end - - private - - ## - # Run a hook if its available. - # - # :args: - # - hook: Name of the hook to run - # - name: Name of file (default: "") - # - # :return: - # shell_result. - # - def run_hook_step(hook, name="") - if (hook[:executable]) - # Handle argument replacemant ({$1}), and get commandline - cmd = @ceedling[:tool_executor].build_command_line( hook, [], name ) - shell_result = @ceedling[:tool_executor].exec(cmd[:line], cmd[:options]) - end - end - - ## - # Run a hook if its available. - # - # If __which_hook__ is an array, run each of them sequentially. - # - # :args: - # - which_hook: Name of the hook to run - # - name: Name of file - # - def run_hook(which_hook, name="") - if (@config[which_hook]) - @ceedling[:streaminator].stdout_puts("Running Hook #{which_hook}...", Verbosity::NORMAL) - if (@config[which_hook].is_a? Array) - @config[which_hook].each do |hook| - run_hook_step(hook, name) - end - elsif (@config[which_hook].is_a? Hash) - run_hook_step( @config[which_hook], name ) - else - @ceedling[:streaminator].stdout_puts("Hook #{which_hook} was poorly formed", Verbosity::COMPLAINT) - end - end - end -end - diff --git a/vendor/ceedling/plugins/compile_commands_json/README.md b/vendor/ceedling/plugins/compile_commands_json/README.md deleted file mode 100644 index ea80b73..0000000 --- a/vendor/ceedling/plugins/compile_commands_json/README.md +++ /dev/null @@ -1,29 +0,0 @@ -compile_commands_json -===================== - -## Overview - -Syntax highlighting and code completion are hard. Historically each editor or IDE has implemented their own and then competed amongst themselves to offer the best experience for developers. Often developers would still to an IDE that felt cumbersome and slow just because it had the best syntax highlighting on the market. If doing it for one language is hard (and it is) imagine doing it for dozens of them. Imagine a full stack developer who has to work with CSS, HTML, JavaScript and some Ruby - they need excellent support in all those languages which just made things even harder. - -In June of 2016, Microsoft with Red Hat and Codenvy got together to create a standard called the Language Server Protocol (LSP). The idea was simple, by standardising on one protocol, all the IDEs and editors out there would only have to support LSP, and not have custom plugins for each language. In turn, the backend code that actually does the highlighting can be written once and used by any IDE that supports LSP. Many editors already support it such as Sublime Text, vim and emacs. This means that if you're using a crufty old IDE or worse, you're using a shiny new editor without code completion, then this could be just the upgrade you're looking for! - -For C and C++ projects, many people use the `clangd` backend. So that it can do things like "go to definition", `clangd` needs to know how to build the project so that it can figure out all the pieces to the puzzle. There are manual tools such as `bear` which can be run with `gcc` or `clang` to extract this information it has a big limitation in that if run with `ceedling release` you won't get any auto completion for Unity and you'll also get error messages reported by your IDE because of what it perceives as missing headers. If you do the same with `ceedling test` now you get Unity but you might miss things that are only seen in the release build. - -This plugin resolves that issue. As it is run by Ceedling, it has access to all the build information it needs to create the perfect `compile_commands.json`. Once enabled, this plugin will generate that file and place it in `./build/artifacts/compile_commands.json`. `clangd` will search your project for this file, but it is easier to symlink it into the root directory (for example `ln -s ./build/artifacts/compile_commands.json`. - -For more information on LSP and to find out if your editor supports it, check out https://langserver.org/ - -## Setup - -Enable the plugin in your project.yml by adding `compile_commands_json` to the list -of enabled plugins. - -``` YAML -:plugins: - :enabled: - - compile_commands_json -``` - -## Configuration - -There is no additional configuration necessary to run this plugin. diff --git a/vendor/ceedling/plugins/compile_commands_json/lib/compile_commands_json.rb b/vendor/ceedling/plugins/compile_commands_json/lib/compile_commands_json.rb deleted file mode 100644 index 269cea4..0000000 --- a/vendor/ceedling/plugins/compile_commands_json/lib/compile_commands_json.rb +++ /dev/null @@ -1,35 +0,0 @@ -require 'ceedling/plugin' -require 'ceedling/constants' -require 'json' - -class CompileCommandsJson < Plugin - def setup - @fullpath = File.join(PROJECT_BUILD_ARTIFACTS_ROOT, "compile_commands.json") - @database = if (File.exists?(@fullpath)) - JSON.parse( File.read(@fullpath) ) - else - [] - end - end - - def post_compile_execute(arg_hash) - - # Create the new Entry - value = { - "directory" => Dir.pwd, - "command" => arg_hash[:shell_command], - "file" => arg_hash[:source] - } - - # Determine if we're updating an existing file description or adding a new one - index = @database.index {|h| h["file"] == arg_hash[:source]} - if index - @database[index] = value - else - @database << value - end - - # Update the Actual compile_commands.json file - File.open(@fullpath,'w') {|f| f << JSON.pretty_generate(@database)} - end -end diff --git a/vendor/ceedling/plugins/dependencies/README.md b/vendor/ceedling/plugins/dependencies/README.md deleted file mode 100644 index 256467d..0000000 --- a/vendor/ceedling/plugins/dependencies/README.md +++ /dev/null @@ -1,254 +0,0 @@ -ceedling-dependencies -===================== - -Plugin for supporting release dependencies. It's rare for an embedded project to -be built completely free of other libraries and modules. Some of these may be -standard internal libraries. Some of these may be 3rd party libraries. In either -case, they become part of the project's ecosystem. - -This plugin is intended to make that relationship easier. It allows you to specify -a source for dependencies. If required, it will automatically grab the appropriate -version of that dependency. - -Most 3rd party libraries have a method of building already in place. While we'd -love to convert the world to a place where everything downloads with a test suite -in Ceedling, that's not likely to happen anytime soon. Until then, this plugin -will allow the developer to specify what calls Ceedling should make to oversee -the build process of those third party utilities. Are they using Make? CMake? A -custom series of scripts that only a mad scientist could possibly understand? No -matter. Ceedling has you covered. Just specify what should be called, and Ceedling -will make it happen whenever it notices that the output artifacts are missing. - -Output artifacts? Sure! Things like static and dynamic libraries, or folders -containing header files that might want to be included by your release project. - -So how does all this magic work? - -First, you need to add the `:dependencies` plugin to your list. Then, we'll add a new -section called :dependencies. There, you can list as many dependencies as you desire. Each -has a series of fields which help Ceedling to understand your needs. Many of them are -optional. If you don't need that feature, just don't include it! In the end, it'll look -something like this: - -``` -:dependencies: - :libraries: - - :name: WolfSSL - :source_path: third_party/wolfssl/source - :build_path: third_party/wolfssl/build - :artifact_path: third_party/wolfssl/install - :fetch: - :method: :zip - :source: \\shared_drive\third_party_libs\wolfssl\wolfssl-4.2.0.zip - :environment: - - CFLAGS+=-DWOLFSSL_DTLS_ALLOW_FUTURE - :build: - - "autoreconf -i" - - "./configure --enable-tls13 --enable-singlethreaded" - - make - - make install - :artifacts: - :static_libraries: - - lib/wolfssl.a - :dynamic_libraries: - - lib/wolfssl.so - :includes: - - include/** -``` - -Let's take a deeper look at each of these features. - -The Starting Dash & Name ------------------------- - -Yes, that opening dash tells the dependencies plugin that the rest of these fields -belong to our first dependency. If we had a second dependency, we'd have another -dash, lined up with the first, and followed by all the fields indented again. - -By convention, we use the `:name` field as the first field for each tool. Ceedling -honestly doesn't care which order the fields are given... but as humans, it makes -it easier for us to see the name of each dependency with starting dash. - -The name field is only used to print progress while we're running Ceedling. You may -call the name of the field whatever you wish. - -Working Folders ---------------- - -The `:source_path` field allows us to specify where the source code for each of our -dependencies is stored. If fetching the dependency from elsewhere, it will be fetched -to this location. All commands to build this dependency will be executed from -this location (override this by specifying a `:build_path`). Finally, the output -artifacts will be referenced to this location (override this by specifying a `:artifact_path`) - -If unspecified, the `:source_path` will be `dependencies\dep_name` where `dep_name` -is the name specified in `:name` above (with special characters removed). It's best, -though, if you specify exactly where you want your dependencies to live. - -If the dependency is directly included in your project (you've specified `:none` as the -`:method` for fetching), then `:source_path` should be where your Ceedling can find the -source for your dependency in you repo. - -All artifacts are relative to the `:artifact_path` (which defaults to be the same as -`:source_path`) - -Fetching Dependencies ---------------------- - -The `:dependencies` plugin supports the ability to automatically fetch your dependencies -for you... using some common methods of fetching source. This section contains only a -couple of fields: - -- `:method` -- This is the method that this dependency is fetched. - - `:none` -- This tells Ceedling that the code is already included in the project. - - `:zip` -- This tells Ceedling that we want to unpack a zip file to our source path. - - `:git` -- This tells Ceedling that we want to clone a git repo to our source path. - - `:svn` -- This tells Ceedling that we want to checkout a subversion repo to our source path. - - `:custom` -- This tells Ceedling that we want to use a custom command or commands to fetch the code. -- `:source` -- This is the path or url to fetch code when using the zip or git method. -- `:tag`/`:branch` -- This is the specific tag or branch that you wish to retrieve (git only. optional). -- `:hash` -- This is the specific SHA1 hash you want to fetch (git only. optional, requires a deep clone). -- `:revision` -- This is the specific revision you want to fetch (svn only. optional). -- `:executable` -- This is a list of commands to execute when using the `:custom` method - - -Environment Variables ---------------------- - -Many build systems support customization through environment variables. By specifying -an array of environment variables, Ceedling will customize the shell environment before -calling the build process. - -Environment variables may be specified in three ways. Let's look at one of each: - -``` - :environment: - - ARCHITECTURE=ARM9 - - CFLAGS+=-DADD_AWESOMENESS - - CFLAGS-=-DWASTE -``` - -In the first example, you see the most straightforward method. The environment variable -`ARCHITECTURE` is set to the value `ARM9`. That's it. Simple. - -The next two options modify an existing symbol. In the first one, we use `+=`, which tells -Ceedling to add the define `ADD_AWESOMENESS` to the environment variable `CFLAGS`. The second -tells Ceedling to remove the define `WASTE` from the same environment variable. - -There are a couple of things to note here. - -First, when adding to a variable, Ceedling has no way of knowing -what delimiter you are expecting. In this example you can see we manually added some whitespace. -If we had been modifying `PATH` instead, we might have had to use a `:` on a unux or `;` on -Windows. - -Second, removing an argument will have no effect on the argument if that argument isn't found -precisely. It's case sensitive and the entire string must match. If symbol doesn't already exist, -it WILL after executing this command... however it will be assigned to nothing. - -Building Dependencies ---------------------- - -The heart of the `:dependencies` plugin is the ability for you, the developer, to specify the -build process for each of your dependencies. You will need to have any required tools installed -before using this feature. - -The steps are specified as an array of strings. Ceedling will execute those steps in the order -specified, moving from step to step unless an error is encountered. By the end of the process, -the artifacts should have been created by your process... otherwise an error will be produced. - -Artifacts ---------- - -These are the outputs of the build process. There are there types of artifacts. Any dependency -may have none or some of these. Calling out these files tells Ceedling that they are important. -Your dependency's build process may produce many other files... but these are the files that -Ceedling understands it needs to act on. - -### `static_libraries` - -Specifying one or more static libraries will tell Ceedling where it should find static libraries -output by your build process. These libraries are automatically added to the list of dependencies -and will be linked with the rest of your code to produce the final release. - -If any of these libraries don't exist, Ceedling will trigger your build process in order for it -to produce them. - -### `dynamic_libraries` - -Specifying one or more dynamic libraries will tell Ceedling where it should find dynamic libraries -output by your build process. These libraries are automatically copied to the same folder as your -final release binary. - -If any of these libraries don't exist, Ceedling will trigger your build process in order for it -to produce them. - -### `includes` - -Often when libraries are built, the same process will output a collection of includes so that -your release code knows how to interact with that library. It's the public API for that library. -By specifying the directories that will contain these includes (don't specify the files themselves, -Ceedling only needs the directories), Ceedling is able to automatically add these to its internal -include list. This allows these files to be used while building your release code, as well we making -them mockable during unit testing. - -### `source` - -It's possible that your external dependency will just produce additional C files as its output. -In this case, Ceedling is able to automatically add these to its internal source list. This allows -these files to be used while building your release code. - -Tasks ------ - -Once configured correctly, the `:dependencies` plugin should integrate seamlessly into your -workflow and you shouldn't have to think about it. In the real world, that doesn't always happen. -Here are a number of tasks that are added or modified by this plugin. - -### `ceedling dependencies:clean` - -This can be issued in order to completely remove the dependency from its source path. On the -next build, it will be refetched and rebuilt from scratch. This can also apply to a particular -dependency. For example, by specifying `dependencies:clean:DepName`. - -### `ceedling dependencies:fetch` - -This can be issued in order to fetch each dependency from its origin. This will have no effect on -dependencies that don't have fetch instructions specified. This can also apply to a particular -dependency. For example, by specifying `dependencies:fetch:DepName`. - -### `ceedling dependencies:make` - -This will force the dependencies to all build. This should happen automatically when a release -has been triggered... but if you're just getting your dependency configured at this moment, you -may want to just use this feature instead. A single dependency can also be built by specifying its -name, like `dependencies:make:MyTunaBoat`. - -### `ceedling dependencies:deploy` - -This will force any dynamic libraries produced by your dependencies to be copied to your release -build directory... just in case you clobbered them. - -### `paths:include` - -Maybe you want to verify that all the include paths are correct. If you query Ceedling with this -request, it will list all the header file paths that it's found, including those produced by -dependencies. - -### `files:include` - -Maybe you want to take that query further and actually get a list of ALL the header files -Ceedling has found, including those belonging to your dependencies. - -Testing -======= - -Hopefully all your dependencies are fully tested... but we can't always depend on that. -In the event that they are tested with Ceedling, you'll probably want to consider using -the `:subprojects` plugin instead of this one. The purpose of this plugin is to pull in -third party code for release... and to provide a mockable interface for Ceedling to use -during its tests of other modules. - -If that's what you're after... you've found the right plugin! - -Happy Testing! diff --git a/vendor/ceedling/plugins/dependencies/config/defaults.yml b/vendor/ceedling/plugins/dependencies/config/defaults.yml deleted file mode 100644 index 0415f8e..0000000 --- a/vendor/ceedling/plugins/dependencies/config/defaults.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -:dependencies: - :libraries: [] - -... diff --git a/vendor/ceedling/plugins/dependencies/dependencies.rake b/vendor/ceedling/plugins/dependencies/dependencies.rake deleted file mode 100644 index 08a1a48..0000000 --- a/vendor/ceedling/plugins/dependencies/dependencies.rake +++ /dev/null @@ -1,147 +0,0 @@ - -DEPENDENCIES_LIBRARIES.each do |deplib| - - # Look up the name of this dependency library - deplib_name = @ceedling[DEPENDENCIES_SYM].get_name(deplib) - - # Make sure the required working directories exists - # (don't worry about the subdirectories. That's the job of the dep's build tool) - paths = @ceedling[DEPENDENCIES_SYM].get_working_paths(deplib) - paths.each {|path| directory(path) } - task :directories => paths - - all_deps = @ceedling[DEPENDENCIES_SYM].get_static_libraries_for_dependency(deplib) + - @ceedling[DEPENDENCIES_SYM].get_dynamic_libraries_for_dependency(deplib) + - @ceedling[DEPENDENCIES_SYM].get_include_directories_for_dependency(deplib) + - @ceedling[DEPENDENCIES_SYM].get_source_files_for_dependency(deplib) - - # Add a rule for building the actual libraries from dependency list - (@ceedling[DEPENDENCIES_SYM].get_static_libraries_for_dependency(deplib) + - @ceedling[DEPENDENCIES_SYM].get_dynamic_libraries_for_dependency(deplib) - ).each do |libpath| - file libpath do |filetask| - path = filetask.name - - # We double-check that it doesn't already exist, because this process sometimes - # produces multiple files, but they may have already been flagged as invoked - unless (File.exists?(path)) - - # Set Environment Variables, Fetch, and Build - @ceedling[DEPENDENCIES_SYM].set_env_if_required(path) - @ceedling[DEPENDENCIES_SYM].fetch_if_required(path) - @ceedling[DEPENDENCIES_SYM].build_if_required(path) - end - end - end - - # Add a rule for building the source and includes from dependency list - (@ceedling[DEPENDENCIES_SYM].get_include_directories_for_dependency(deplib) + - @ceedling[DEPENDENCIES_SYM].get_source_files_for_dependency(deplib) - ).each do |libpath| - task libpath do |filetask| - path = filetask.name - - unless (File.file?(path) || File.directory?(path)) - - # Set Environment Variables, Fetch, and Build - @ceedling[DEPENDENCIES_SYM].set_env_if_required(path) - @ceedling[DEPENDENCIES_SYM].fetch_if_required(path) - @ceedling[DEPENDENCIES_SYM].build_if_required(path) - end - end - end - - # Give ourselves a way to trigger individual dependencies - namespace DEPENDENCIES_SYM do - namespace :deploy do - # Add task to directly just build this dependency - task(deplib_name => @ceedling[DEPENDENCIES_SYM].get_dynamic_libraries_for_dependency(deplib)) do |t,args| - @ceedling[DEPENDENCIES_SYM].deploy_if_required(deplib_name) - end - end - - namespace :make do - # Add task to directly just build this dependency - task(deplib_name => all_deps) - end - - namespace :clean do - # Add task to directly clobber this dependency - task(deplib_name) do - @ceedling[DEPENDENCIES_SYM].clean_if_required(deplib_name) - end - end - - namespace :fetch do - # Add task to directly clobber this dependency - task(deplib_name) do - @ceedling[DEPENDENCIES_SYM].fetch_if_required(deplib_name) - end - end - end - - # Add source files to our list of things to build during release - source_files = @ceedling[DEPENDENCIES_SYM].get_source_files_for_dependency(deplib) - task PROJECT_RELEASE_BUILD_TARGET => source_files - - # Finally, add the static libraries to our RELEASE build dependency list - static_libs = @ceedling[DEPENDENCIES_SYM].get_static_libraries_for_dependency(deplib) - task RELEASE_SYM => static_libs - - # Add the dynamic libraries to our RELEASE task dependency list so that they will be copied automatically - dynamic_libs = @ceedling[DEPENDENCIES_SYM].get_dynamic_libraries_for_dependency(deplib) - task RELEASE_SYM => dynamic_libs - - # Add the include dirs / files to our list of dependencies for release - headers = @ceedling[DEPENDENCIES_SYM].get_include_directories_for_dependency(deplib) - task RELEASE_SYM => headers - - # Paths to Libraries need to be Added to the Lib Path List - all_libs = static_libs + dynamic_libs - PATHS_LIBRARIES ||= [] - all_libs.each {|lib| PATHS_LIBRARIES << File.dirname(lib) } - PATHS_LIBRARIES.uniq! - PATHS_LIBRARIES.reject!{|s| s.empty?} - - # Libraries Need to be Added to the Library List - LIBRARIES_SYSTEM ||= [] - all_libs.each {|lib| LIBRARIES_SYSTEM << File.basename(lib,'.*').sub(/^lib/,'') } - LIBRARIES_SYSTEM.uniq! - LIBRARIES_SYSTEM.reject!{|s| s.empty?} -end - -# Add any artifact:include or :source folders to our release & test includes paths so linking and mocking work. -@ceedling[DEPENDENCIES_SYM].add_headers_and_sources() - -# Add tasks for building or cleaning ALL depencies -namespace DEPENDENCIES_SYM do - desc "Deploy missing dependencies." - task :deploy => DEPENDENCIES_LIBRARIES.map{|deplib| "#{DEPENDENCIES_SYM}:deploy:#{@ceedling[DEPENDENCIES_SYM].get_name(deplib)}"} - - desc "Build any missing dependencies." - task :make => DEPENDENCIES_LIBRARIES.map{|deplib| "#{DEPENDENCIES_SYM}:make:#{@ceedling[DEPENDENCIES_SYM].get_name(deplib)}"} - - desc "Clean all dependencies." - task :clean => DEPENDENCIES_LIBRARIES.map{|deplib| "#{DEPENDENCIES_SYM}:clean:#{@ceedling[DEPENDENCIES_SYM].get_name(deplib)}"} - - desc "Fetch all dependencies." - task :fetch => DEPENDENCIES_LIBRARIES.map{|deplib| "#{DEPENDENCIES_SYM}:fetch:#{@ceedling[DEPENDENCIES_SYM].get_name(deplib)}"} -end - -namespace :files do - desc "List all collected dependency libraries." - task :dependencies do - puts "dependency files:" - deps = [] - DEPENDENCIES_LIBRARIES.each do |deplib| - deps << @ceedling[DEPENDENCIES_SYM].get_static_libraries_for_dependency(deplib) - deps << @ceedling[DEPENDENCIES_SYM].get_dynamic_libraries_for_dependency(deplib) - end - deps.flatten! - deps.sort.each {|dep| puts " - #{dep}"} - puts "file count: #{deps.size}" - end -end - -# Make sure that we build dependencies before attempting to tackle any of the unit tests -Rake::Task[:test_deps].enhance ['dependencies:make'] diff --git a/vendor/ceedling/plugins/dependencies/lib/dependencies.rb b/vendor/ceedling/plugins/dependencies/lib/dependencies.rb deleted file mode 100644 index fc8ae99..0000000 --- a/vendor/ceedling/plugins/dependencies/lib/dependencies.rb +++ /dev/null @@ -1,237 +0,0 @@ -require 'ceedling/plugin' -require 'ceedling/constants' - -DEPENDENCIES_ROOT_NAME = 'dependencies' -DEPENDENCIES_TASK_ROOT = DEPENDENCIES_ROOT_NAME + ':' -DEPENDENCIES_SYM = DEPENDENCIES_ROOT_NAME.to_sym - -class Dependencies < Plugin - - def setup - @plugin_root = File.expand_path(File.join(File.dirname(__FILE__), '..')) - - # Set up a fast way to look up dependencies by name or static lib path - @dependencies = {} - @dynamic_libraries = [] - DEPENDENCIES_LIBRARIES.each do |deplib| - - @dependencies[ deplib[:name] ] = deplib.clone - all_deps = get_static_libraries_for_dependency(deplib) + - get_dynamic_libraries_for_dependency(deplib) + - get_include_directories_for_dependency(deplib) + - get_source_files_for_dependency(deplib) - all_deps.each do |key| - @dependencies[key] = @dependencies[ deplib[:name] ] - end - - @dynamic_libraries += get_dynamic_libraries_for_dependency(deplib) - end - end - - def config - updates = { - :collection_paths_include => COLLECTION_PATHS_INCLUDE, - :collection_all_headers => COLLECTION_ALL_HEADERS, - } - - @ceedling[DEPENDENCIES_SYM].get_include_directories_for_dependency(deplib).each do |incpath| - updates[:collection_paths_include] << incpath - Dir[ File.join(incpath, "*#{EXTENSION_HEADER}") ].each do |f| - updates[:collection_all_headers] << f - end - end - - return updates - end - - def get_name(deplib) - raise "Each dependency must have a name!" if deplib[:name].nil? - return deplib[:name].gsub(/\W*/,'') - end - - def get_source_path(deplib) - return deplib[:source_path] || File.join('dependencies', get_name(deplib)) - end - - def get_build_path(deplib) - return deplib[:build_path] || deplib[:source_path] || File.join('dependencies', get_name(deplib)) - end - - def get_artifact_path(deplib) - return deplib[:artifact_path] || deplib[:source_path] || File.join('dependencies', get_name(deplib)) - end - - def get_working_paths(deplib) - paths = [deplib[:source_path], deplib[:build_path], deplib[:artifact_paths]].compact.uniq - paths = [ File.join('dependencies', get_name(deplib)) ] if (paths.empty?) - return paths - end - - def get_static_libraries_for_dependency(deplib) - (deplib[:artifacts][:static_libraries] || []).map {|path| File.join(get_artifact_path(deplib), path)} - end - - def get_dynamic_libraries_for_dependency(deplib) - (deplib[:artifacts][:dynamic_libraries] || []).map {|path| File.join(get_artifact_path(deplib), path)} - end - - def get_source_files_for_dependency(deplib) - (deplib[:artifacts][:source] || []).map {|path| File.join(get_artifact_path(deplib), path)} - end - - def get_include_directories_for_dependency(deplib) - paths = (deplib[:artifacts][:includes] || []).map {|path| File.join(get_artifact_path(deplib), path)} - @ceedling[:file_system_utils].collect_paths(paths) - end - - def set_env_if_required(lib_path) - blob = @dependencies[lib_path] - raise "Could not find dependency '#{lib_path}'" if blob.nil? - return if (blob[:environment].nil?) - return if (blob[:environment].empty?) - - blob[:environment].each do |e| - m = e.match(/^(\w+)\s*(\+?\-?=)\s*(.*)$/) - unless m.nil? - case m[2] - when "+=" - ENV[m[1]] = (ENV[m[1]] || "") + m[3] - when "-=" - ENV[m[1]] = (ENV[m[1]] || "").gsub(m[3],'') - else - ENV[m[1]] = m[3] - end - end - end - end - - def fetch_if_required(lib_path) - blob = @dependencies[lib_path] - raise "Could not find dependency '#{lib_path}'" if blob.nil? - return if (blob[:fetch].nil?) - return if (blob[:fetch][:method].nil?) - return if (directory(blob[:source_path]) && !Dir.empty?(blob[:source_path])) - - steps = case blob[:fetch][:method] - when :none - return - when :zip - [ "gzip -d #{blob[:fetch][:source]}" ] - when :git - branch = blob[:fetch][:tag] || blob[:fetch][:branch] || '' - branch = ("-b " + branch) unless branch.empty? - unless blob[:fetch][:hash].nil? - # Do a deep clone to ensure the commit we want is available - retval = [ "git clone #{branch} #{blob[:fetch][:source]} ." ] - # Checkout the specified commit - retval << "git checkout #{blob[:fetch][:hash]}" - else - # Do a thin clone - retval = [ "git clone #{branch} --depth 1 #{blob[:fetch][:source]} ." ] - end - when :svn - revision = blob[:fetch][:revision] || '' - revision = ("--revision " + branch) unless branch.empty? - retval = [ "svn checkout #{revision} #{blob[:fetch][:source]} ." ] - retval - when :custom - blob[:fetch][:executable] - else - raise "Unknown fetch method '#{blob[:fetch][:method].to_s}' for dependency '#{blob[:name]}'" - end - - # Perform the actual fetching - @ceedling[:streaminator].stdout_puts("Fetching dependency #{blob[:name]}...", Verbosity::NORMAL) - Dir.chdir(get_source_path(blob)) do - steps.each do |step| - @ceedling[:tool_executor].exec( step ) - end - end - end - - def build_if_required(lib_path) - blob = @dependencies[lib_path] - raise "Could not find dependency '#{lib_path}'" if blob.nil? - - # We don't clean anything unless we know how to fetch a new copy - if (blob[:build].nil? || blob[:build].empty?) - @ceedling[:streaminator].stdout_puts("Nothing to build for dependency #{blob[:name]}", Verbosity::NORMAL) - return - end - - # Perform the build - @ceedling[:streaminator].stdout_puts("Building dependency #{blob[:name]}...", Verbosity::NORMAL) - Dir.chdir(get_build_path(blob)) do - blob[:build].each do |step| - @ceedling[:tool_executor].exec( step ) - end - end - end - - def clean_if_required(lib_path) - blob = @dependencies[lib_path] - raise "Could not find dependency '#{lib_path}'" if blob.nil? - - # We don't clean anything unless we know how to fetch a new copy - if (blob[:fetch].nil? || blob[:fetch][:method].nil? || (blob[:fetch][:method] == :none)) - @ceedling[:streaminator].stdout_puts("Nothing to clean for dependency #{blob[:name]}", Verbosity::NORMAL) - return - end - - # Perform the actual Cleaning - @ceedling[:streaminator].stdout_puts("Cleaning dependency #{blob[:name]}...", Verbosity::NORMAL) - get_working_paths(blob).each do |path| - FileUtils.rm_rf(path) if File.directory?(path) - end - end - - def deploy_if_required(lib_path) - blob = @dependencies[lib_path] - raise "Could not find dependency '#{lib_path}'" if blob.nil? - - # We don't need to deploy anything if there isn't anything to deploy - if (blob[:artifacts].nil? || blob[:artifacts][:dynamic_libraries].nil? || blob[:artifacts][:dynamic_libraries].empty?) - @ceedling[:streaminator].stdout_puts("Nothing to deploy for dependency #{blob[:name]}", Verbosity::NORMAL) - return - end - - # Perform the actual Deploying - @ceedling[:streaminator].stdout_puts("Deploying dependency #{blob[:name]}...", Verbosity::NORMAL) - FileUtils.cp( lib_path, File.dirname(PROJECT_RELEASE_BUILD_TARGET) ) - end - - def add_headers_and_sources() - # Search for header file paths and files to add to our collections - DEPENDENCIES_LIBRARIES.each do |deplib| - get_include_directories_for_dependency(deplib).each do |header| - cfg = @ceedling[:configurator].project_config_hash - cfg[:collection_paths_include] << header - cfg[:collection_paths_source_and_include] << header - cfg[:collection_paths_test_support_source_include] << header - cfg[:collection_paths_test_support_source_include_vendor] << header - cfg[:collection_paths_release_toolchain_include] << header - Dir[ File.join(header, "*#{EXTENSION_HEADER}") ].each do |f| - cfg[:collection_all_headers] << f - end - end - - get_source_files_for_dependency(deplib).each do |source| - cfg = @ceedling[:configurator].project_config_hash - cfg[:collection_paths_source_and_include] << source - cfg[:collection_paths_test_support_source_include] << source - cfg[:collection_paths_test_support_source_include_vendor] << source - cfg[:collection_paths_release_toolchain_include] << source - Dir[ File.join(source, "*#{EXTENSION_SOURCE}") ].each do |f| - cfg[:collection_all_source] << f - end - end - end - - # Make all these updated files findable by Ceedling - @ceedling[:file_finder].prepare_search_sources() - end -end - -# end blocks always executed following rake run -END { -} diff --git a/vendor/ceedling/plugins/fake_function_framework/README.md b/vendor/ceedling/plugins/fake_function_framework/README.md deleted file mode 100644 index 8042775..0000000 --- a/vendor/ceedling/plugins/fake_function_framework/README.md +++ /dev/null @@ -1,250 +0,0 @@ -# A Fake Function Framework Plug-in for Ceedling - -This is a plug-in for [Ceedling](https://github.com/ThrowTheSwitch/Ceedling) to use the [Fake Function Framework](https://github.com/meekrosoft/fff) for mocking instead of CMock. - -Using fff provides less strict mocking than CMock, and allows for more loosely-coupled tests. -And, when tests fail -- since you get the actual line number of the failure -- it's a lot easier to figure out what went wrong. - -## Installing the plug-in - -To use the plugin you need to 1) get the contents of this repo and 2) configure your project to use it. - -### Get the source - -The easiest way to get the source is to just clone this repo into the Ceedling plugin folder for your existing Ceedling project. -(Don't have a Ceedling project already? [Here are instructions to create one.](http://www.electronvector.com/blog/try-embedded-test-driven-development-right-now-with-ceedling)) -From within `<your-project>/vendor/ceedling/plugins`, run: - -`git clone https://github.com/ElectronVector/fake_function_framework.git` - -This will create a new folder named `fake_function_framework` in the plugins folder. - -### Enable the plug-in. - -The plug-in is enabled from within your project.yml file. - -In the `:plugins` configuration, add `fake_function_framework` to the list of enabled plugins: - -```yaml -:plugins: - :load_paths: - - vendor/ceedling/plugins - :enabled: - - stdout_pretty_tests_report - - module_generator - - fake_function_framework -``` -*Note that you could put the plugin source in some other loaction. -In that case you'd need to add a new path the `:load_paths`.* - -## How to use it - -You use fff with Ceedling the same way you used to use CMock. -Modules can still be generated with the default module generator: `rake module:create[my_module]`. -If you want to "mock" `some_module.h` in your tests, just `#include "mock_some_module.h"`. -This creates a fake function for each of the functions defined in `some_module.h`. - -The name of each fake is the original function name with an appended `_fake`. -For example, if we're generating fakes for a stack module with `push` and `pop` functions, we would have the fakes `push_fake` and `pop_fake`. -These fakes are linked into our test executable so that any time our unit under test calls `push` or `pop` our fakes are called instead. - -Each of these fakes is actually a structure containing information about how the function was called, and what it might return. -We can use Unity to inspect these fakes in our tests, and verify the interactions of our units. -There is also a global structure named `fff` which we can use to check the sequence of calls. - -The fakes can also be configured to return particular values, so you can exercise the unit under test however you want. - -The examples below explain how to use fff to test a variety of module interactions. -Each example uses fakes for a "display" module, created from a display.h file with `#include "mock_display.h"`. The `display.h` file must exist and must contain the prototypes for the functions to be faked. - -### Test that a function was called once - -```c -void -test_whenTheDeviceIsReset_thenTheStatusLedIsTurnedOff() -{ - // When - event_deviceReset(); - - // Then - TEST_ASSERT_EQUAL(1, display_turnOffStatusLed_fake.call_count); -} -``` - -### Test that a function was NOT called - -```c -void -test_whenThePowerReadingIsLessThan5_thenTheStatusLedIsNotTurnedOn(void) -{ - // When - event_powerReadingUpdate(4); - - // Then - TEST_ASSERT_EQUAL(0, display_turnOnStatusLed_fake.call_count); -} -``` - -## Test that a single function was called with the correct argument - -```c -void -test_whenTheVolumeKnobIsMaxed_thenVolumeDisplayIsSetTo11(void) -{ - // When - event_volumeKnobMaxed(); - - // Then - TEST_ASSERT_EQUAL(1, display_setVolume_fake.call_count); - TEST_ASSERT_EQUAL(11, display_setVolume_fake.arg0_val); -} -``` - -## Test that calls are made in a particular sequence - -```c -void -test_whenTheModeSelectButtonIsPressed_thenTheDisplayModeIsCycled(void) -{ - // When - event_modeSelectButtonPressed(); - event_modeSelectButtonPressed(); - event_modeSelectButtonPressed(); - - // Then - TEST_ASSERT_EQUAL_PTR((void*)display_setModeToMinimum, fff.call_history[0]); - TEST_ASSERT_EQUAL_PTR((void*)display_setModeToMaximum, fff.call_history[1]); - TEST_ASSERT_EQUAL_PTR((void*)display_setModeToAverage, fff.call_history[2]); -} -``` - -## Fake a return value from a function - -```c -void -test_givenTheDisplayHasAnError_whenTheDeviceIsPoweredOn_thenTheDisplayIsPoweredDown(void) -{ - // Given - display_isError_fake.return_val = true; - - // When - event_devicePoweredOn(); - - // Then - TEST_ASSERT_EQUAL(1, display_powerDown_fake.call_count); -} -``` - -## Fake a function with a value returned by reference - -```c -void -test_givenTheUserHasTypedSleep_whenItIsTimeToCheckTheKeyboard_theDisplayIsPoweredDown(void) -{ - // Given - char mockedEntry[] = "sleep"; - void return_mock_value(char * entry, int length) - { - if (length > strlen(mockedEntry)) - { - strncpy(entry, mockedEntry, length); - } - } - display_getKeyboardEntry_fake.custom_fake = return_mock_value; - - // When - event_keyboardCheckTimerExpired(); - - // Then - TEST_ASSERT_EQUAL(1, display_powerDown_fake.call_count); -} -``` - -## Fake a function with a function pointer parameter - -``` -void -test_givenNewDataIsAvailable_whenTheDisplayHasUpdated_thenTheEventIsComplete(void) -{ - // A mock function for capturing the callback handler function pointer. - void(*registeredCallback)(void) = 0; - void mock_display_updateData(int data, void(*callback)(void)) - { - //Save the callback function. - registeredCallback = callback; - } - display_updateData_fake.custom_fake = mock_display_updateData; - - // Given - event_newDataAvailable(10); - - // When - if (registeredCallback != 0) - { - registeredCallback(); - } - - // Then - TEST_ASSERT_EQUAL(true, eventProcessor_isLastEventComplete()); -} -``` - -## Helper macros - -For convenience, there are also some helper macros that create new Unity-style asserts: - -- `TEST_ASSERT_CALLED(function)`: Asserts that a function was called once. -- `TEST_ASSERT_NOT_CALLED(function)`: Asserts that a function was never called. -- `TEST_ASSERT_CALLED_TIMES(times, function)`: Asserts that a function was called a particular number of times. -- `TEST_ASSERT_CALLED_IN_ORDER(order, function)`: Asserts that a function was called in a particular order. - -Here's how you might use one of these instead of simply checking the call_count value: - -```c -void -test_whenTheDeviceIsReset_thenTheStatusLedIsTurnedOff() -{ - // When - event_deviceReset(); - - // Then - // This how to directly use fff... - TEST_ASSERT_EQUAL(1, display_turnOffStatusLed_fake.call_count); - // ...and this is how to use the helper macro. - TEST_ASSERT_CALLED(display_turnOffStatusLed); -} -``` - -## Test setup - -All of the fake functions, and any fff global state are all reset automatically between each test. - -## CMock configuration - -Use still use some of the CMock configuration options for setting things like the mock prefix, and for including additional header files in the mock files. - -```yaml -:cmock: - :mock_prefix: mock_ - :includes: - - - :includes_h_pre_orig_header: - - - :includes_h_post_orig_header: - - - :includes_c_pre_header: - - - :includes_c_post_header: -``` - -## Running the tests - -There are unit and integration tests for the plug-in itself. -These are run with the default `rake` task. -The integration test runs the tests for the example project in examples/fff_example. -For the integration tests to succeed, this repository must be placed in a Ceedling tree in the plugins folder. - -## More examples - -There is an example project in examples/fff_example. -It shows how to use the plug-in with some full-size examples. diff --git a/vendor/ceedling/plugins/fake_function_framework/Rakefile b/vendor/ceedling/plugins/fake_function_framework/Rakefile deleted file mode 100644 index bc55941..0000000 --- a/vendor/ceedling/plugins/fake_function_framework/Rakefile +++ /dev/null @@ -1,19 +0,0 @@ -require 'rake' -require 'rspec/core/rake_task' - -desc "Run all rspecs" -RSpec::Core::RakeTask.new(:spec) do |t| - t.pattern = Dir.glob('spec/**/*_spec.rb') - t.rspec_opts = '--format documentation' - # t.rspec_opts << ' more options' -end - -desc "Run integration test on example" -task :integration_test do - chdir("./examples/fff_example") do - sh "rake clobber" - sh "rake test:all" - end -end - -task :default => [:spec, :integration_test] \ No newline at end of file diff --git a/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/project.yml b/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/project.yml deleted file mode 100644 index 6bda222..0000000 --- a/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/project.yml +++ /dev/null @@ -1,71 +0,0 @@ ---- - -# Notes: -# Sample project C code is not presently written to produce a release artifact. -# As such, release build options are disabled. -# This sample, therefore, only demonstrates running a collection of unit tests. - -:project: - :use_exceptions: FALSE - :use_test_preprocessor: TRUE - :use_auxiliary_dependencies: TRUE - :build_root: build -# :release_build: TRUE - :test_file_prefix: test_ - -#:release_build: -# :output: MyApp.out -# :use_assembly: FALSE - -:environment: - -:extension: - :executable: .out - -:paths: - :test: - - +:test/** - :source: - - src/** - :support: - -:defines: - # in order to add common defines: - # 1) remove the trailing [] from the :common: section - # 2) add entries to the :common: section (e.g. :test: has TEST defined) - :commmon: &common_defines [] - :test: - - *common_defines - - TEST - :test_preprocess: - - *common_defines - - TEST - -:cmock: - :mock_prefix: mock_ - :when_no_prototypes: :warn - :enforce_strict_ordering: TRUE - :plugins: - - :ignore - - :callback - :treat_as: - uint8: HEX8 - uint16: HEX16 - uint32: UINT32 - int8: INT8 - bool: UINT8 - -#:tools: -# Ceedling defaults to using gcc for compiling, linking, etc. -# As [:tools] is blank, gcc will be used (so long as it's in your system path) -# See documentation to configure a given toolchain for use - -:plugins: - :load_paths: - # This change from the default is for running Ceedling out of another folder. - - ../../../../plugins - :enabled: - - stdout_pretty_tests_report - - module_generator - - fake_function_framework -... diff --git a/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/rakefile.rb b/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/rakefile.rb deleted file mode 100644 index e484d5f..0000000 --- a/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/rakefile.rb +++ /dev/null @@ -1,7 +0,0 @@ -# This change from the default is for running Ceedling out of another folder. -PROJECT_CEEDLING_ROOT = "../../../.." -load "#{PROJECT_CEEDLING_ROOT}/lib/ceedling.rb" - -Ceedling.load_project - -task :default => %w[ test:all release ] diff --git a/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/bar.c b/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/bar.c deleted file mode 100644 index 6a40323..0000000 --- a/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/bar.c +++ /dev/null @@ -1 +0,0 @@ -#include "bar.h" diff --git a/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/bar.h b/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/bar.h deleted file mode 100644 index febc586..0000000 --- a/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/bar.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef bar_H -#define bar_H - -#include "custom_types.h" - -void bar_turn_on(void); -void bar_print_message(const char * message); -void bar_print_message_formatted(const char * format, ...); -void bar_numbers(int one, int two, char three); -void bar_const_test(const char * a, char * const b, const int c); -custom_t bar_needs_custom_type(void); -const char * bar_return_const_ptr(int one); - -#endif // bar_H diff --git a/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/custom_types.h b/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/custom_types.h deleted file mode 100644 index b426b32..0000000 --- a/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/custom_types.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef custom_types_H -#define custom_types_H - -typedef int custom_t; - -#endif diff --git a/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/display.c b/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/display.c deleted file mode 100644 index 2f03449..0000000 --- a/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/display.c +++ /dev/null @@ -1,7 +0,0 @@ -#include <stdio.h> -#include "display.h" - -void display_turnOffStatusLed(void) -{ - printf("Display: Status LED off"); -} \ No newline at end of file diff --git a/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/display.h b/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/display.h deleted file mode 100644 index def2996..0000000 --- a/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/display.h +++ /dev/null @@ -1,16 +0,0 @@ -#include <stdbool.h> - -void display_turnOffStatusLed(void); -void display_turnOnStatusLed(void); -void display_setVolume(int level); -void display_setModeToMinimum(void); -void display_setModeToMaximum(void); -void display_setModeToAverage(void); -bool display_isError(void); -void display_powerDown(void); -void display_updateData(int data, void(*updateCompleteCallback)(void)); - -/* - The entry is returned (up to `length` bytes) in the provided `entry` buffer. -*/ -void display_getKeyboardEntry(char * entry, int length); diff --git a/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/event_processor.c b/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/event_processor.c deleted file mode 100644 index 916a923..0000000 --- a/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/event_processor.c +++ /dev/null @@ -1,93 +0,0 @@ -/* - This module implements some business logic to test. - - Signal events by calling the functions on the module. -*/ - -#include <stdio.h> -#include <string.h> -#include "event_processor.h" -#include "display.h" - -void event_deviceReset(void) -{ - //printf ("Device reset\n"); - display_turnOffStatusLed(); -} - -void event_volumeKnobMaxed(void) -{ - display_setVolume(11); -} - -void event_powerReadingUpdate(int powerReading) -{ - if (powerReading >= 5) - { - display_turnOnStatusLed(); - } -} - -void event_modeSelectButtonPressed(void) -{ - static int mode = 0; - - if (mode == 0) - { - display_setModeToMinimum(); - mode++; - } - else if (mode == 1) - { - display_setModeToMaximum(); - mode++; - } - else if (mode == 2) - { - display_setModeToAverage(); - mode++; - } - else - { - mode = 0; - } -} - -void event_devicePoweredOn(void) -{ - if (display_isError()) - { - display_powerDown(); - } -} - -void event_keyboardCheckTimerExpired(void) -{ - char userEntry[100]; - - display_getKeyboardEntry(userEntry, 100); - - if (strcmp(userEntry, "sleep") == 0) - { - display_powerDown(); - } -} - -static bool event_lastComplete = false; - -/* Function called when the display update is complete. */ -static void displayUpdateComplete(void) -{ - event_lastComplete = true; -} - -void event_newDataAvailable(int data) -{ - event_lastComplete = false; - display_updateData(data, displayUpdateComplete); -} - -bool eventProcessor_isLastEventComplete(void) -{ - return event_lastComplete; -} diff --git a/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/event_processor.h b/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/event_processor.h deleted file mode 100644 index a79e68c..0000000 --- a/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/event_processor.h +++ /dev/null @@ -1,11 +0,0 @@ -#include <stdbool.h> - -void event_deviceReset(void); -void event_volumeKnobMaxed(void); -void event_powerReadingUpdate(int powerReading); -void event_modeSelectButtonPressed(void); -void event_devicePoweredOn(void); -void event_keyboardCheckTimerExpired(void); -void event_newDataAvailable(int data); - -bool eventProcessor_isLastEventComplete(void); diff --git a/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/foo.c b/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/foo.c deleted file mode 100644 index c05b115..0000000 --- a/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/foo.c +++ /dev/null @@ -1,16 +0,0 @@ -#include "foo.h" -#include "bar.h" -#include "subfolder/zzz.h" - -void foo_turn_on(void) { - bar_turn_on(); - zzz_sleep(1, "sleepy"); -} - -void foo_print_message(const char * message) { - bar_print_message(message); -} - -void foo_print_special_message(void) { - bar_print_message_formatted("The numbers are %d, %d and %d", 1, 2, 3); -} diff --git a/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/foo.h b/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/foo.h deleted file mode 100644 index 3fea699..0000000 --- a/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/foo.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef foo_H -#define foo_H - -void foo_turn_on(void); -void foo_print_message(const char * message); -void foo_print_special_message(void); - -#endif // foo_H diff --git a/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/subfolder/zzz.c b/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/subfolder/zzz.c deleted file mode 100644 index 85f370e..0000000 --- a/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/subfolder/zzz.c +++ /dev/null @@ -1 +0,0 @@ -#include "zzz.h" diff --git a/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/subfolder/zzz.h b/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/subfolder/zzz.h deleted file mode 100644 index 32c5294..0000000 --- a/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/subfolder/zzz.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef zzz_H -#define zzz_H - -int zzz_sleep(int time, char * name); - -#endif // zzz_H diff --git a/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/test/test_event_processor.c b/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/test/test_event_processor.c deleted file mode 100644 index 9f99944..0000000 --- a/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/test/test_event_processor.c +++ /dev/null @@ -1,155 +0,0 @@ -#include "unity.h" -#include "event_processor.h" -#include "mock_display.h" -#include <string.h> - -void setUp (void) -{ -} - -void tearDown (void) -{ -} -/* - Test that a single function was called. -*/ -void -test_whenTheDeviceIsReset_thenTheStatusLedIsTurnedOff() -{ - // When - event_deviceReset(); - - // Then - TEST_ASSERT_EQUAL(1, display_turnOffStatusLed_fake.call_count); - // or use the helper macro... - TEST_ASSERT_CALLED(display_turnOffStatusLed); -} - -/* - Test that a single function is NOT called. -*/ -void -test_whenThePowerReadingIsLessThan5_thenTheStatusLedIsNotTurnedOn(void) -{ - // When - event_powerReadingUpdate(4); - - // Then - TEST_ASSERT_EQUAL(0, display_turnOnStatusLed_fake.call_count); - // or use the helper macro... - TEST_ASSERT_NOT_CALLED(display_turnOffStatusLed); -} - -/* - Test that a single function was called with the correct arugment. -*/ -void -test_whenTheVolumeKnobIsMaxed_thenVolumeDisplayIsSetTo11(void) -{ - // When - event_volumeKnobMaxed(); - - // Then - TEST_ASSERT_EQUAL(1, display_setVolume_fake.call_count); - // or use the helper macro... - TEST_ASSERT_CALLED(display_setVolume); - TEST_ASSERT_EQUAL(11, display_setVolume_fake.arg0_val); -} - -/* - Test a sequence of calls. -*/ - -void -test_whenTheModeSelectButtonIsPressed_thenTheDisplayModeIsCycled(void) -{ - // When - event_modeSelectButtonPressed(); - event_modeSelectButtonPressed(); - event_modeSelectButtonPressed(); - - // Then - TEST_ASSERT_EQUAL_PTR((void *)display_setModeToMinimum, fff.call_history[0]); - TEST_ASSERT_EQUAL_PTR((void *)display_setModeToMaximum, fff.call_history[1]); - TEST_ASSERT_EQUAL_PTR((void *)display_setModeToAverage, fff.call_history[2]); - // or use the helper macros... - TEST_ASSERT_CALLED_IN_ORDER(0, display_setModeToMinimum); - TEST_ASSERT_CALLED_IN_ORDER(1, display_setModeToMaximum); - TEST_ASSERT_CALLED_IN_ORDER(2, display_setModeToAverage); -} - -/* - Mock a return value from a function. -*/ -void -test_givenTheDisplayHasAnError_whenTheDeviceIsPoweredOn_thenTheDisplayIsPoweredDown(void) -{ - // Given - display_isError_fake.return_val = true; - - // When - event_devicePoweredOn(); - - // Then - TEST_ASSERT_EQUAL(1, display_powerDown_fake.call_count); - // or use the helper macro... - TEST_ASSERT_CALLED(display_powerDown); -} - -/* - Mock a sequence of calls with return values. -*/ - -/* - Mocking a function with a value returned by reference. -*/ -void -test_givenTheUserHasTypedSleep_whenItIsTimeToCheckTheKeyboard_theDisplayIsPoweredDown(void) -{ - // Given - char mockedEntry[] = "sleep"; - void return_mock_value(char * entry, int length) - { - if (length > strlen(mockedEntry)) - { - strncpy(entry, mockedEntry, length); - } - } - display_getKeyboardEntry_fake.custom_fake = return_mock_value; - - // When - event_keyboardCheckTimerExpired(); - - // Then - TEST_ASSERT_EQUAL(1, display_powerDown_fake.call_count); - // or use the helper macro... - TEST_ASSERT_CALLED(display_powerDown); -} - -/* - Mock a function with a function pointer parameter. -*/ -void -test_givenNewDataIsAvailable_whenTheDisplayHasUpdated_thenTheEventIsComplete(void) -{ - // A mock function for capturing the callback handler function pointer. - void(*registeredCallback)(void) = 0; - void mock_display_updateData(int data, void(*callback)(void)) - { - //Save the callback function. - registeredCallback = callback; - } - display_updateData_fake.custom_fake = mock_display_updateData; - - // Given - event_newDataAvailable(10); - - // When - if (registeredCallback != 0) - { - registeredCallback(); - } - - // Then - TEST_ASSERT_EQUAL(true, eventProcessor_isLastEventComplete()); -} diff --git a/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/test/test_foo.c b/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/test/test_foo.c deleted file mode 100644 index 12dd61a..0000000 --- a/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/test/test_foo.c +++ /dev/null @@ -1,47 +0,0 @@ -#include "unity.h" -#include "foo.h" -#include "mock_bar.h" -#include "mock_zzz.h" - -void setUp(void) -{ -} - -void tearDown(void) -{ -} - -void test_foo(void) -{ - //When - foo_turn_on(); - - //Then - TEST_ASSERT_EQUAL(1, bar_turn_on_fake.call_count); - TEST_ASSERT_EQUAL(1, zzz_sleep_fake.call_count); - TEST_ASSERT_EQUAL_STRING("sleepy", zzz_sleep_fake.arg1_val); -} - -void test_foo_again(void) -{ - //When - foo_turn_on(); - - //Then - TEST_ASSERT_EQUAL(1, bar_turn_on_fake.call_count); -} - -void test_foo_mock_with_const(void) -{ - foo_print_message("123"); - - TEST_ASSERT_EQUAL(1, bar_print_message_fake.call_count); - TEST_ASSERT_EQUAL_STRING("123", bar_print_message_fake.arg0_val); -} - -void test_foo_mock_with_variable_args(void) -{ - foo_print_special_message(); - TEST_ASSERT_EQUAL(1, bar_print_message_formatted_fake.call_count); - TEST_ASSERT_EQUAL_STRING("The numbers are %d, %d and %d", bar_print_message_formatted_fake.arg0_val); -} diff --git a/vendor/ceedling/plugins/fake_function_framework/lib/fake_function_framework.rb b/vendor/ceedling/plugins/fake_function_framework/lib/fake_function_framework.rb deleted file mode 100644 index 51a90b3..0000000 --- a/vendor/ceedling/plugins/fake_function_framework/lib/fake_function_framework.rb +++ /dev/null @@ -1,87 +0,0 @@ -require 'ceedling/plugin' -require 'fff_mock_generator' - -class FakeFunctionFramework < Plugin - - # Set up Ceedling to use this plugin. - def setup - # Get the location of this plugin. - @plugin_root = File.expand_path(File.join(File.dirname(__FILE__), '..')) - puts "Using fake function framework (fff)..." - - # Switch out the cmock_builder with our own. - @ceedling[:cmock_builder].cmock = FffMockGeneratorForCMock.new(@ceedling[:setupinator].config_hash[:cmock]) - - # Add the path to fff.h to the include paths. - COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR << "#{@plugin_root}/vendor/fff" - COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR << "#{@plugin_root}/src" - end - - def post_runner_generate(arg_hash) - # After the test runner file has been created, append the FFF globals - # definition to the end of the test runner. These globals will be shared by - # all mocks linked into the test. - File.open(arg_hash[:runner_file], 'a') do |f| - f.puts - f.puts "//=======Defintions of FFF variables=====" - f.puts %{#include "fff.h"} - f.puts "DEFINE_FFF_GLOBALS;" - end - end - -end # class FakeFunctionFramework - -class FffMockGeneratorForCMock - - def initialize(options=nil) - @cm_config = CMockConfig.new(options) - @cm_parser = CMockHeaderParser.new(@cm_config) - @silent = (@cm_config.verbosity < 2) - - # These are the additional files to include in the mock files. - @includes_h_pre_orig_header = (@cm_config.includes || @cm_config.includes_h_pre_orig_header || []).map{|h| h =~ /</ ? h : "\"#{h}\""} - @includes_h_post_orig_header = (@cm_config.includes_h_post_orig_header || []).map{|h| h =~ /</ ? h : "\"#{h}\""} - @includes_c_pre_header = (@cm_config.includes_c_pre_header || []).map{|h| h =~ /</ ? h : "\"#{h}\""} - @includes_c_post_header = (@cm_config.includes_c_post_header || []).map{|h| h =~ /</ ? h : "\"#{h}\""} - end - - def setup_mocks(files) - [files].flatten.each do |src| - generate_mock (src) - end - end - - def generate_mock (header_file_to_mock) - module_name = File.basename(header_file_to_mock, '.h') - puts "Creating mock for #{module_name}..." unless @silent - mock_name = @cm_config.mock_prefix + module_name + @cm_config.mock_suffix - mock_path = @cm_config.mock_path - if @cm_config.subdir - # If a subdirectory has been configured, append it to the mock path. - mock_path = "#{mock_path}/#{@cm_config.subdir}" - end - full_path_for_mock = "#{mock_path}/#{mock_name}" - - # Parse the header file so we know what to mock. - parsed_header = @cm_parser.parse(module_name, File.read(header_file_to_mock)) - - # Create the directory if it doesn't exist. - mkdir_p full_path_for_mock.pathmap("%d") - - # Generate the mock header file. - puts "Creating mock: #{full_path_for_mock}.h" - - # Create the mock header. - File.open("#{full_path_for_mock}.h", 'w') do |f| - f.write(FffMockGenerator.create_mock_header(module_name, mock_name, parsed_header, - @includes_h_pre_orig_header, @includes_h_post_orig_header)) - end - - # Create the mock source file. - File.open("#{full_path_for_mock}.c", 'w') do |f| - f.write(FffMockGenerator.create_mock_source(mock_name, parsed_header, - @includes_c_pre_orig_header, @includes_c_post_orig_header)) - end - end - -end diff --git a/vendor/ceedling/plugins/fake_function_framework/lib/fff_mock_generator.rb b/vendor/ceedling/plugins/fake_function_framework/lib/fff_mock_generator.rb deleted file mode 100644 index 9dc03a6..0000000 --- a/vendor/ceedling/plugins/fake_function_framework/lib/fff_mock_generator.rb +++ /dev/null @@ -1,163 +0,0 @@ -# Creates mock files from parsed header files that can be linked into applications. -# The mocks created are compatible with CMock for use with Ceedling. - -class FffMockGenerator - - def self.create_mock_header(module_name, mock_name, parsed_header, pre_includes=nil, - post_includes=nil) - output = StringIO.new - write_opening_include_guard(mock_name, output) - output.puts - write_extra_includes(pre_includes, output) - write_header_includes(module_name, output) - write_extra_includes(post_includes, output) - output.puts - write_typedefs(parsed_header, output) - output.puts - write_function_declarations(parsed_header, output) - output.puts - write_control_function_prototypes(mock_name, output) - output.puts - write_closing_include_guard(mock_name, output) - output.string - end - - def self.create_mock_source (mock_name, parsed_header, pre_includes=nil, - post_includes=nil) - output = StringIO.new - write_extra_includes(pre_includes, output) - write_source_includes(mock_name, output) - write_extra_includes(post_includes, output) - output.puts - write_function_definitions(parsed_header, output) - output.puts - write_control_function_definitions(mock_name, parsed_header, output) - output.string - end - - private - -# Header file generation functions. - - def self.write_opening_include_guard(mock_name, output) - output.puts "#ifndef #{mock_name}_H" - output.puts "#define #{mock_name}_H" - end - - def self.write_header_includes(module_name, output) - output.puts %{#include "fff.h"} - output.puts %{#include "fff_unity_helper.h"} - output.puts %{#include "#{module_name}.h"} - end - - def self.write_typedefs(parsed_header, output) - return unless parsed_header.key?(:typedefs) - parsed_header[:typedefs].each do |typedef| - output.puts typedef - end - end - - def self.write_function_declarations(parsed_header, output) - write_function_macros("DECLARE", parsed_header, output) - end - - - def self.write_control_function_prototypes(mock_name, output) - output.puts "void #{mock_name}_Init(void);" - output.puts "void #{mock_name}_Verify(void);" - output.puts "void #{mock_name}_Destroy(void);" - end - - def self.write_closing_include_guard(mock_name, output) - output.puts "#endif // #{mock_name}_H" - end - -# Source file generation functions. - - def self.write_source_includes (mock_name, output) - output.puts "#include <string.h>" - output.puts %{#include "fff.h"} - output.puts %{#include "#{mock_name}.h"} - end - - def self.write_function_definitions(parsed_header, output) - write_function_macros("DEFINE", parsed_header, output) - end - - def self.write_control_function_definitions(mock_name, parsed_header, output) - output.puts "void #{mock_name}_Init(void)" - output.puts "{" - # In the init function, reset the FFF globals. These are used for things - # like the call history. - output.puts " FFF_RESET_HISTORY();" - - # Also, reset all of the fakes. - if parsed_header[:functions] - parsed_header[:functions].each do |function| - output.puts " RESET_FAKE(#{function[:name]})" - end - end - output.puts "}" - output.puts "void #{mock_name}_Verify(void)" - output.puts "{" - output.puts "}" - output.puts "void #{mock_name}_Destroy(void)" - output.puts "{" - output.puts "}" - end - -# Shared functions. - - def self.write_extra_includes(includes, output) - if includes - includes.each {|inc| output.puts "#include #{inc}\n"} - end - end - - def self.write_function_macros(macro_type, parsed_header, output) - return unless parsed_header.key?(:functions) - parsed_header[:functions].each do |function| - name = function[:name] - return_type = function[:return][:type] - if function.has_key? :modifier - # Prepend any modifier. If there isn't one, trim any leading whitespace. - return_type = "#{function[:modifier]} #{return_type}".lstrip - end - arg_count = function[:args].size - - # Check for variable arguments. - var_arg_suffix = "" - if function[:var_arg] - # If there are are variable arguments, then we need to add this argument - # to the count, update the suffix that will get added to the macro. - arg_count += 1 - var_arg_suffix = "_VARARG" - end - - # Generate the correct macro. - if return_type == 'void' - output.print "#{macro_type}_FAKE_VOID_FUNC#{arg_count}#{var_arg_suffix}(#{name}" - else - output.print "#{macro_type}_FAKE_VALUE_FUNC#{arg_count}#{var_arg_suffix}(#{return_type}, #{name}" - end - - # Append each argument type. - function[:args].each do |arg| - output.print ", " - if arg[:const?] - output.print "const " - end - output.print "#{arg[:type]}" - end - - # If this argument list ends with a variable argument, add it here at the end. - if function[:var_arg] - output.print ", ..." - end - - # Close the declaration. - output.puts ");" - end - end - -end diff --git a/vendor/ceedling/plugins/fake_function_framework/spec/fff_mock_header_generator_spec.rb b/vendor/ceedling/plugins/fake_function_framework/spec/fff_mock_header_generator_spec.rb deleted file mode 100644 index e6ac11d..0000000 --- a/vendor/ceedling/plugins/fake_function_framework/spec/fff_mock_header_generator_spec.rb +++ /dev/null @@ -1,304 +0,0 @@ -require 'stringio' -require 'fff_mock_generator.rb' -require 'header_generator.rb' - -# Test the contents of the .h file created for the mock. -describe "FffMockGenerator.create_mock_header" do - - context "when there is nothing to mock," do - let(:mock_header) { - parsed_header = {} - FffMockGenerator.create_mock_header("display", "mock_display", parsed_header) - } - it "then the generated header file starts with an opening include guard" do - expect(mock_header).to start_with( - "#ifndef mock_display_H\n" + - "#define mock_display_H") - end - it "then the generated file ends with a closing include guard" do - expect(mock_header).to end_with( - "#endif // mock_display_H\n") - end - it "then the generated file includes the fff header" do - expect(mock_header).to include( - %{#include "fff.h"\n}) - end - it "then the generated file has a prototype for the init function" do - expect(mock_header).to include( - "void mock_display_Init(void);") - end - it "then the generated file has a prototype for the verify function" do - expect(mock_header).to include( - "void mock_display_Verify(void);") - end - it "then the generated file has a prototype for the destroy function" do - expect(mock_header).to include( - "void mock_display_Destroy(void);") - end - end - - context "when there is a function with no args and a void return," do - let(:mock_header) { - parsed_header = create_cmock_style_parsed_header( - [{:name => 'display_turnOffStatusLed', :return_type => 'void'}]) - FffMockGenerator.create_mock_header("display", "mock_display", parsed_header) - } - it "then the generated header file starts with an opening include guard" do - expect(mock_header).to start_with( - "#ifndef mock_display_H\n" + - "#define mock_display_H") - end - it "then the generated header file contains a fake function declaration" do - expect(mock_header).to include( - "DECLARE_FAKE_VOID_FUNC0(display_turnOffStatusLed);" - ) - end - it "then the generated file ends with a closing include guard" do - expect(mock_header).to end_with( - "#endif // mock_display_H\n") - end - end - - context "when there is a function with no args and a bool return," do - let(:mock_header) { - parsed_header = create_cmock_style_parsed_header( - [{:name => 'display_isError', :return_type => 'bool'}]) - FffMockGenerator.create_mock_header("display", "mock_display", parsed_header) - } - it "then the generated file contains the fake function declaration" do - expect(mock_header).to include( - "DECLARE_FAKE_VALUE_FUNC0(bool, display_isError);" - ) - end - end - - context "when there is a function with no args and an int return," do - let(:mock_header) { - parsed_header = create_cmock_style_parsed_header( - [{:name => 'display_isError', :return_type => 'int'}]) - FffMockGenerator.create_mock_header("display", "mock_display", parsed_header) - } - it "then the generated file contains the fake function declaration" do - expect(mock_header).to include( - "DECLARE_FAKE_VALUE_FUNC0(int, display_isError);" - ) - end - end - - context "when there is a function with args and a void return," do - let(:mock_header) { - parsed_header = create_cmock_style_parsed_header( - [{:name => 'display_setVolume', :return_type => 'void', :args => ['int']}]) - FffMockGenerator.create_mock_header("display", "mock_display", parsed_header) - } - it "then the generated file contains the fake function declaration" do - expect(mock_header).to include( - "DECLARE_FAKE_VOID_FUNC1(display_setVolume, int);" - ) - end - end - - context "when there is a function with args and a value return," do - let(:mock_header) { - parsed_header = create_cmock_style_parsed_header( - [{:name => 'a_function', :return_type => 'int', :args => ['char *']}]) - FffMockGenerator.create_mock_header("display", "mock_display", parsed_header) - } - it "then the generated file contains the fake function declaration" do - expect(mock_header).to include( - "FAKE_VALUE_FUNC1(int, a_function, char *);" - ) - end - end - - context "when there is a function with many args and a void return," do - let(:mock_header) { - parsed_header = create_cmock_style_parsed_header( - [{:name => 'a_function', :return_type => 'void', - :args => ['int', 'char *', 'int', 'int', 'bool', 'applesauce']}]) - FffMockGenerator.create_mock_header("display", "mock_display", parsed_header) - } - it "then the generated file contains the fake function declaration" do - expect(mock_header).to include( - "DECLARE_FAKE_VOID_FUNC6(a_function, int, char *, int, int, bool, applesauce);" - ) - end - end - - context "when there are multiple functions," do - let(:mock_header) { - parsed_header = create_cmock_style_parsed_header( - [ {:name => 'a_function', :return_type => 'int', :args => ['char *']}, - {:name => 'another_function', :return_type => 'void'}, - {:name => 'three', :return_type => 'bool', :args => ['float', 'int']} - ]) - FffMockGenerator.create_mock_header("display", "mock_display", parsed_header) - } - it "then the generated file contains the first fake function declaration" do - expect(mock_header).to include( - "DECLARE_FAKE_VALUE_FUNC1(int, a_function, char *);" - ) - end - it "then the generated file contains the second fake function declaration" do - expect(mock_header).to include( - "DECLARE_FAKE_VOID_FUNC0(another_function);" - ) - end - it "then the generated file contains the third fake function declaration" do - expect(mock_header).to include( - "DECLARE_FAKE_VALUE_FUNC2(bool, three, float, int);" - ) - end - end - - context "when there is a typedef," do - let(:mock_header) { - parsed_header = create_cmock_style_parsed_header( - nil, ["typedef void (*displayCompleteCallback) (void);"]) - FffMockGenerator.create_mock_header("display", "mock_display", parsed_header) - } - it "then the generated file contains the typedef" do - expect(mock_header).to include( - "typedef void (*displayCompleteCallback) (void);" - ) - end - end - - context "when there is a void function with variable arguments" do - let(:mock_header){ - parsed_header = {} - parsed_header[:functions] = [{ - :name => "function_with_var_args", - :return => {:type => "void"}, - :var_arg => "...", - :args => [{:type => 'char *'}] - }] - FffMockGenerator.create_mock_header("display", "mock_display", parsed_header) - } - it "then the generated file contains the vararg declaration" do - expect(mock_header).to include( - "DECLARE_FAKE_VOID_FUNC2_VARARG(function_with_var_args, char *, ...)" - ) - end - end - - context "when there is a function with a return value and variable arguments" do - let(:mock_header){ - parsed_header = {} - parsed_header[:functions] = [{ - :name => "function_with_var_args", - :return => {:type => "int"}, - :var_arg => "...", - :args => [{:type => 'char *'}] - }] - FffMockGenerator.create_mock_header("display", "mock_display", parsed_header) - } - it "then the generated file contains the vararg declaration" do - expect(mock_header).to include( - "DECLARE_FAKE_VALUE_FUNC2_VARARG(int, function_with_var_args, char *, ...)" - ) - end - end - - context "when there is a void function with variable arguments and " + - "additional arguments" do - let(:mock_header){ - parsed_header = {} - parsed_header[:functions] = [{ - :name => "function_with_var_args", - :return => {:type => "void"}, - :var_arg => "...", - :args => [{:type => 'char *'}, {:type => 'int'}] - }] - FffMockGenerator.create_mock_header("display", "mock_display", parsed_header) - } - it "then the generated file contains the vararg declaration" do - expect(mock_header).to include( - "DECLARE_FAKE_VOID_FUNC3_VARARG(function_with_var_args, char *, int, ...)" - ) - end - end - - context "when there is a function with a pointer to a const value" do - let(:mock_header){ - parsed_header = {} - parsed_header[:functions] = [{ - :name => "const_test_function", - :return => {:type => "void"}, - :args => [{:type => "char *", :name => "a", :ptr? => false, :const? => true}, - {:type => "char *", :name => "b", :ptr? => false, :const? => false}] - }] - FffMockGenerator.create_mock_header("display", "mock_display", parsed_header) - } - it "then the generated file contains the correct const argument in the declaration" do - expect(mock_header).to include( - "DECLARE_FAKE_VOID_FUNC2(const_test_function, const char *, char *)" - ) - end - end - - context "when there is a function that returns a const pointer" do - let(:mock_header){ - parsed_header = {} - parsed_header[:functions] = [{ - :name => "return_const_pointer_test_function", - :modifier => "const", - :return => {:type => "char *" }, - :args => [{:type => "int", :name => "a"}] - }] - FffMockGenerator.create_mock_header("display", "mock_display", parsed_header) - } - it "then the generated file contains the correct const return value in the declaration" do - expect(mock_header).to include( - "DECLARE_FAKE_VALUE_FUNC1(const char *, return_const_pointer_test_function, int)" - ) - end - end - - context "when there is a function that returns a const int" do - let(:mock_header){ - parsed_header = {} - parsed_header[:functions] = [{ - :name => "return_const_int_test_function", - :modifier => "const", - :return => {:type => "int" }, - :args => [] - }] - FffMockGenerator.create_mock_header("display", "mock_display", parsed_header) - } - it "then the generated file contains the correct const return value in the declaration" do - expect(mock_header).to include( - "DECLARE_FAKE_VALUE_FUNC0(const int, return_const_int_test_function)" - ) - end - end - - context "when there are pre-includes" do - let(:mock_header) { - parsed_header = {} - FffMockGenerator.create_mock_header("display", "mock_display", parsed_header, - [%{"another_header.h"}]) - } - it "then they are included before the other files" do - expect(mock_header).to include( - %{#include "another_header.h"\n} + - %{#include "fff.h"} - ) - end - end - - context "when there are post-includes" do - let(:mock_header) { - parsed_header = {} - FffMockGenerator.create_mock_header("display", "mock_display", parsed_header, - nil, [%{"another_header.h"}]) - } - it "then they are included after the other files" do - expect(mock_header).to include( - %{#include "display.h"\n} + - %{#include "another_header.h"\n} - ) - end - end - -end diff --git a/vendor/ceedling/plugins/fake_function_framework/spec/fff_mock_source_generator_spec.rb b/vendor/ceedling/plugins/fake_function_framework/spec/fff_mock_source_generator_spec.rb deleted file mode 100644 index 364f852..0000000 --- a/vendor/ceedling/plugins/fake_function_framework/spec/fff_mock_source_generator_spec.rb +++ /dev/null @@ -1,149 +0,0 @@ -require 'stringio' -require 'fff_mock_generator.rb' - -# Test the contents of the .c file created for the mock. -describe "FffMockGenerator.create_mock_source" do - - context "when there is nothing to mock," do - let(:mock_source) { - parsed_header = {} - FffMockGenerator.create_mock_source("mock_my_module", parsed_header) - } - it "then the generated file includes the fff header" do - expect(mock_source).to include( - # fff.h also requires including string.h - %{#include <string.h>\n} + - %{#include "fff.h"} - ) - end - it "then the generated file includes the mock header" do - expect(mock_source).to include( - %{#include "mock_my_module.h"\n} - ) - end - it "then the generated file defines the init function" do - expect(mock_source).to include( - "void mock_my_module_Init(void)\n" + - "{\n" + - " FFF_RESET_HISTORY();\n" + - "}" - ) - end - it "then the generated file defines the verify function" do - expect(mock_source).to include( - "void mock_my_module_Verify(void)\n" + - "{\n" + - "}" - ) - end - it "then the generated file defines the destroy function" do - expect(mock_source).to include( - "void mock_my_module_Destroy(void)\n" + - "{\n" + - "}" - ) - end - end - - context "when there are multiple functions," do - let(:mock_source) { - parsed_header = create_cmock_style_parsed_header( - [ {:name => 'a_function', :return_type => 'int', :args => ['char *']}, - {:name => 'another_function', :return_type => 'void'}, - {:name => 'three', :return_type => 'bool', :args => ['float', 'int']} - ]) - FffMockGenerator.create_mock_source("mock_display", parsed_header) - } - it "then the generated file contains the first fake function definition" do - expect(mock_source).to include( - "DEFINE_FAKE_VALUE_FUNC1(int, a_function, char *);" - ) - end - it "then the generated file contains the second fake function definition" do - expect(mock_source).to include( - "DEFINE_FAKE_VOID_FUNC0(another_function);" - ) - end - it "then the generated file contains the third fake function definition" do - expect(mock_source).to include( - "DEFINE_FAKE_VALUE_FUNC2(bool, three, float, int);" - ) - end - it "then the init function resets all of the fakes" do - expect(mock_source).to include( - "void mock_display_Init(void)\n" + - "{\n" + - " FFF_RESET_HISTORY();\n" + - " RESET_FAKE(a_function)\n" + - " RESET_FAKE(another_function)\n" + - " RESET_FAKE(three)\n" + - "}" - ) - end - end - - context "when there is a void function with variable arguments and " + - "additional arguments" do - let(:mock_source){ - parsed_header = {} - parsed_header[:functions] = [{ - :name => "function_with_var_args", - :return => {:type => "void"}, - :var_arg => "...", - :args => [{:type => 'char *'}, {:type => 'int'}] - }] - FffMockGenerator.create_mock_source("mock_display", parsed_header) - } - it "then the generated file contains the vararg definition" do - expect(mock_source).to include( - "DEFINE_FAKE_VOID_FUNC3_VARARG(function_with_var_args, char *, int, ...)" - ) - end - end - - context "when there is a function with a pointer to a const value" do - let(:mock_source){ - parsed_header = {} - parsed_header[:functions] = [{ - :name => "const_test_function", - :return => {:type => "void"}, - :args => [{:type => "char *", :name => "a", :ptr? => false, :const? => true}, - {:type => "char *", :name => "b", :ptr? => false, :const? => false}] - }] - FffMockGenerator.create_mock_source("mock_display", parsed_header) - } - it "then the generated file contains the correct const argument in the declaration" do - expect(mock_source).to include( - "DEFINE_FAKE_VOID_FUNC2(const_test_function, const char *, char *)" - ) - end - end - - context "when there are pre-includes" do - let(:mock_source) { - parsed_source = {} - FffMockGenerator.create_mock_source("mock_display", parsed_source, - [%{"another_header.h"}]) - } - it "then they are included before the other files" do - expect(mock_source).to include( - %{#include "another_header.h"\n} + - %{#include <string.h>} - ) - end - end - - context "when there are post-includes" do - let(:mock_source) { - parsed_source = {} - FffMockGenerator.create_mock_source("mock_display", parsed_source, - nil, [%{"another_header.h"}]) - } - it "then they are included before the other files" do - expect(mock_source).to include( - %{#include "mock_display.h"\n} + - %{#include "another_header.h"\n} - ) - end - end -end \ No newline at end of file diff --git a/vendor/ceedling/plugins/fake_function_framework/spec/header_generator.rb b/vendor/ceedling/plugins/fake_function_framework/spec/header_generator.rb deleted file mode 100644 index cda2784..0000000 --- a/vendor/ceedling/plugins/fake_function_framework/spec/header_generator.rb +++ /dev/null @@ -1,51 +0,0 @@ -# Create a CMock-style parsed header hash. This the type of hash created by -# CMock when parsing header files for automock generation. It contains all of -# includes, typedefs and functions (with return types and arguments) parsed from -# the header file. -def create_cmock_style_parsed_header(functions, typedefs = nil) - parsed_header = { - :includes => nil, - :functions => [], - :typedefs => [] - } - - # Add the typedefs. - if typedefs - typedefs.each do |typedef| - parsed_header[:typedefs] << typedef - end - end - - # Add the functions. - if functions - functions.each do |function| - # Build the array of arguments. - args = [] - if function.key?(:args) - function[:args].each do |arg| - args << { - :type => arg - } - end - end - parsed_header[:functions] << { - :name => function[:name], - :modifier => "", - :return => { - :type => function[:return_type], - :name => "cmock_to_return", - :ptr? => false, - :const? => false, - :str => "void cmock_to_return", - :void? => true - }, - :var_arg => nil, - :args_string => "void", - :args => args, - :args_call => "", - :contains_ptr? => false - } - end - end - parsed_header -end \ No newline at end of file diff --git a/vendor/ceedling/plugins/fake_function_framework/spec/spec_helper.rb b/vendor/ceedling/plugins/fake_function_framework/spec/spec_helper.rb deleted file mode 100644 index 25dc80a..0000000 --- a/vendor/ceedling/plugins/fake_function_framework/spec/spec_helper.rb +++ /dev/null @@ -1,96 +0,0 @@ -# This file was generated by the `rspec --init` command. Conventionally, all -# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. -# The generated `.rspec` file contains `--require spec_helper` which will cause -# this file to always be loaded, without a need to explicitly require it in any -# files. -# -# Given that it is always loaded, you are encouraged to keep this file as -# light-weight as possible. Requiring heavyweight dependencies from this file -# will add to the boot time of your test suite on EVERY test run, even for an -# individual file that may not need all of that loaded. Instead, consider making -# a separate helper file that requires the additional dependencies and performs -# the additional setup, and require it from the spec files that actually need -# it. -# -# The `.rspec` file also contains a few flags that are not defaults but that -# users commonly want. -# -# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration -RSpec.configure do |config| - # rspec-expectations config goes here. You can use an alternate - # assertion/expectation library such as wrong or the stdlib/minitest - # assertions if you prefer. - config.expect_with :rspec do |expectations| - # This option will default to `true` in RSpec 4. It makes the `description` - # and `failure_message` of custom matchers include text for helper methods - # defined using `chain`, e.g.: - # be_bigger_than(2).and_smaller_than(4).description - # # => "be bigger than 2 and smaller than 4" - # ...rather than: - # # => "be bigger than 2" - expectations.include_chain_clauses_in_custom_matcher_descriptions = true - end - - # rspec-mocks config goes here. You can use an alternate test double - # library (such as bogus or mocha) by changing the `mock_with` option here. - config.mock_with :rspec do |mocks| - # Prevents you from mocking or stubbing a method that does not exist on - # a real object. This is generally recommended, and will default to - # `true` in RSpec 4. - mocks.verify_partial_doubles = true - end - -# The settings below are suggested to provide a good initial experience -# with RSpec, but feel free to customize to your heart's content. -=begin - # These two settings work together to allow you to limit a spec run - # to individual examples or groups you care about by tagging them with - # `:focus` metadata. When nothing is tagged with `:focus`, all examples - # get run. - config.filter_run :focus - config.run_all_when_everything_filtered = true - - # Allows RSpec to persist some state between runs in order to support - # the `--only-failures` and `--next-failure` CLI options. We recommend - # you configure your source control system to ignore this file. - config.example_status_persistence_file_path = "spec/examples.txt" - - # Limits the available syntax to the non-monkey patched syntax that is - # recommended. For more details, see: - # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/ - # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ - # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode - config.disable_monkey_patching! - - # This setting enables warnings. It's recommended, but in some cases may - # be too noisy due to issues in dependencies. - config.warnings = true - - # Many RSpec users commonly either run the entire suite or an individual - # file, and it's useful to allow more verbose output when running an - # individual spec file. - if config.files_to_run.one? - # Use the documentation formatter for detailed output, - # unless a formatter has already been configured - # (e.g. via a command-line flag). - config.default_formatter = 'doc' - end - - # Print the 10 slowest examples and example groups at the - # end of the spec run, to help surface which specs are running - # particularly slow. - config.profile_examples = 10 - - # Run specs in random order to surface order dependencies. If you find an - # order dependency and want to debug it, you can fix the order by providing - # the seed, which is printed after each run. - # --seed 1234 - config.order = :random - - # Seed global randomization in this process using the `--seed` CLI option. - # Setting this allows you to use `--seed` to deterministically reproduce - # test failures related to randomization by passing the same `--seed` value - # as the one that triggered the failure. - Kernel.srand config.seed -=end -end diff --git a/vendor/ceedling/plugins/fake_function_framework/src/fff_unity_helper.h b/vendor/ceedling/plugins/fake_function_framework/src/fff_unity_helper.h deleted file mode 100644 index de3db44..0000000 --- a/vendor/ceedling/plugins/fake_function_framework/src/fff_unity_helper.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef fff_unity_helper_H -#define fff_unity_helper_H - -/* - FFF helper macros for Unity. -*/ - -/* - Fail if the function was not called the expected number of times. -*/ -#define TEST_ASSERT_CALLED_TIMES(times_, function_) \ - TEST_ASSERT_EQUAL_MESSAGE(times_, \ - function_ ## _fake.call_count, \ - "Function " #function_ " called the incorrect number of times.") -/* - Fail if the function was not called exactly once. -*/ -#define TEST_ASSERT_CALLED(function_) TEST_ASSERT_CALLED_TIMES(1, function_) - -/* - Fail if the function was called 1 or more times. -*/ -#define TEST_ASSERT_NOT_CALLED(function_) TEST_ASSERT_CALLED_TIMES(0, function_) - -/* - Fail if the function was not called in this particular order. -*/ -#define TEST_ASSERT_CALLED_IN_ORDER(order_, function_) \ - TEST_ASSERT_EQUAL_PTR_MESSAGE((void *) function_, \ - fff.call_history[order_], \ - "Function " #function_ " not called in order " #order_ ) - -#endif \ No newline at end of file diff --git a/vendor/ceedling/plugins/gcov/README.md b/vendor/ceedling/plugins/gcov/README.md deleted file mode 100644 index b144e3b..0000000 --- a/vendor/ceedling/plugins/gcov/README.md +++ /dev/null @@ -1,433 +0,0 @@ -ceedling-gcov -============= - -# Plugin Overview - -Plugin for integrating GNU GCov code coverage tool into Ceedling projects. -Currently only designed for the gcov command (like LCOV for example). In the -future we could configure this to work with other code coverage tools. - -This plugin currently uses [gcovr](https://www.gcovr.com/) and / or -[ReportGenerator](https://danielpalme.github.io/ReportGenerator/) -as utilities to generate HTML, XML, JSON, or Text reports. The normal gcov -plugin _must_ be run first for these reports to generate. - -## Installation - -gcovr can be installed via pip like so: - -```sh -pip install gcovr -``` - -ReportGenerator can be installed via .NET Core like so: - -```sh -dotnet tool install -g dotnet-reportgenerator-globaltool -``` - -It is not required to install both `gcovr` and `ReportGenerator`. Either utility -may be installed to create reports. - -## Configuration - -The gcov plugin supports configuration options via your `project.yml` provided -by Ceedling. - -### Utilities - -Gcovr and / or ReportGenerator may be enabled to create coverage reports. - -```yaml -:gcov: - :utilities: - - gcovr # Use gcovr to create the specified reports (default). - - ReportGenerator # Use ReportGenerator to create the specified reports. -``` - -### Reports - -Various reports are available and may be enabled with the following -configuration item. See the specific report sections in this README -for additional options and information. All generated reports will be found in `build/artifacts/gcov`. - -```yaml -:gcov: - # Specify one or more reports to generate. - # Defaults to HtmlBasic. - :reports: - # Make an HTML summary report. - # Supported utilities: gcovr, ReportGenerator - - HtmlBasic - - # Make an HTML report with line by line coverage of each source file. - # Supported utilities: gcovr, ReportGenerator - - HtmlDetailed - - # Make a Text report, which may be output to the console with gcovr or a file in both gcovr and ReportGenerator. - # Supported utilities: gcovr, ReportGenerator - - Text - - # Make a Cobertura XML report. - # Supported utilities: gcovr, ReportGenerator - - Cobertura - - # Make a SonarQube XML report. - # Supported utilities: gcovr, ReportGenerator - - SonarQube - - # Make a JSON report. - # Supported utilities: gcovr - - JSON - - # Make a detailed HTML report with CSS and JavaScript included in every HTML page. Useful for build servers. - # Supported utilities: ReportGenerator - - HtmlInline - - # Make a detailed HTML report with a light theme and CSS and JavaScript included in every HTML page for Azure DevOps. - # Supported utilities: ReportGenerator - - HtmlInlineAzure - - # Make a detailed HTML report with a dark theme and CSS and JavaScript included in every HTML page for Azure DevOps. - # Supported utilities: ReportGenerator - - HtmlInlineAzureDark - - # Make a single HTML file containing a chart with historic coverage information. - # Supported utilities: ReportGenerator - - HtmlChart - - # Make a detailed HTML report in a single file. - # Supported utilities: ReportGenerator - - MHtml - - # Make SVG and PNG files that show line and / or branch coverage information. - # Supported utilities: ReportGenerator - - Badges - - # Make a single CSV file containing coverage information per file. - # Supported utilities: ReportGenerator - - CsvSummary - - # Make a single TEX file containing a summary for all files and detailed reports for each files. - # Supported utilities: ReportGenerator - - Latex - - # Make a single TEX file containing a summary for all files. - # Supported utilities: ReportGenerator - - LatexSummary - - # Make a single PNG file containing a chart with historic coverage information. - # Supported utilities: ReportGenerator - - PngChart - - # Command line output interpreted by TeamCity. - # Supported utilities: ReportGenerator - - TeamCitySummary - - # Make a text file in lcov format. - # Supported utilities: ReportGenerator - - lcov - - # Make a XML file containing a summary for all classes and detailed reports for each class. - # Supported utilities: ReportGenerator - - Xml - - # Make a single XML file containing a summary for all files. - # Supported utilities: ReportGenerator - - XmlSummary -``` - -### Gcovr HTML Reports - -Generation of Gcovr HTML reports may be modified with the following configuration items. - -```yaml -:gcov: - # Set to 'true' to enable HTML reports or set to 'false' to disable. - # Defaults to enabled. (gcovr --html) - # Deprecated - See the :reports: configuration option. - :html_report: [true|false] - - # Gcovr supports generating two types of HTML reports. Use 'basic' to create - # an HTML report with only the overall file information. Use 'detailed' to create - # an HTML report with line by line coverage of each source file. - # Defaults to 'basic'. Set to 'detailed' for (gcovr --html-details). - # Deprecated - See the :reports: configuration option. - :html_report_type: [basic|detailed] - - - :gcovr: - # HTML report filename. - :html_artifact_filename: <output> - - # Use 'title' as title for the HTML report. - # Default is 'Head'. (gcovr --html-title) - :html_title: <title> - - # If the coverage is below MEDIUM, the value is marked as low coverage in the HTML report. - # MEDIUM has to be lower than or equal to value of html_high_threshold. - # If MEDIUM is equal to value of html_high_threshold the report has only high and low coverage. - # Default is 75.0. (gcovr --html-medium-threshold) - :html_medium_threshold: 75 - - # If the coverage is below HIGH, the value is marked as medium coverage in the HTML report. - # HIGH has to be greater than or equal to value of html_medium_threshold. - # If HIGH is equal to value of html_medium_threshold the report has only high and low coverage. - # Default is 90.0. (gcovr -html-high-threshold) - :html_high_threshold: 90 - - # Set to 'true' to use absolute paths to link the 'detailed' reports. - # Defaults to relative links. (gcovr --html-absolute-paths) - :html_absolute_paths: [true|false] - - # Override the declared HTML report encoding. Defaults to UTF-8. (gcovr --html-encoding) - :html_encoding: <html_encoding> -``` - -### Cobertura XML Reports - -Generation of Cobertura XML reports may be modified with the following configuration items. - -```yaml -:gcov: - # Set to 'true' to enable Cobertura XML reports or set to 'false' to disable. - # Defaults to disabled. (gcovr --xml) - # Deprecated - See the :reports: configuration option. - :xml_report: [true|false] - - - :gcovr: - # Set to 'true' to pretty-print the Cobertura XML report, otherwise set to 'false'. - # Defaults to disabled. (gcovr --xml-pretty) - :xml_pretty: [true|false] - :cobertura_pretty: [true|false] - - # Cobertura XML report filename. - :xml_artifact_filename: <output> - :cobertura_artifact_filename: <output> -``` - -### SonarQube XML Reports - -Generation of SonarQube XML reports may be modified with the following configuration items. - -```yaml -:gcov: - :gcovr: - # SonarQube XML report filename. - :sonarqube_artifact_filename: <output> -``` - -### JSON Reports - -Generation of JSON reports may be modified with the following configuration items. - -```yaml -:gcov: - :gcovr: - # Set to 'true' to pretty-print the JSON report, otherwise set 'false'. - # Defaults to disabled. (gcovr --json-pretty) - :json_pretty: [true|false] - - # JSON report filename. - :json_artifact_filename: <output> -``` - -### Text Reports - -Generation of text reports may be modified with the following configuration items. -Text reports may be printed to the console or output to a file. - -```yaml -:gcov: - :gcovr: - # Text report filename. - # The text report is printed to the console when no filename is provided. - :text_artifact_filename: <output> -``` - -### Common Report Options - -There are a number of options to control which files are considered part of -the coverage report. Most often, we only care about coverage on our source code, and not -on tests or automatically generated mocks, runners, etc. However, there are times -where this isn't true... or there are times where we've moved ceedling's directory -structure so that the project file isn't at the root of the project anymore. In these -cases, you may need to tweak `report_include`, `report_exclude`, and `exclude_directories`. - -One important note about `report_root`: gcovr will take only a single root folder, unlike -Ceedling's ability to take as many as you like. So you will need to choose a folder which is -a superset of ALL the folders you want, and then use the include or exclude options to set up -patterns of files to pay attention to or ignore. It's not ideal, but it works. - -Finally, there are a number of settings which can be specified to adjust the -default behaviors of gcovr: - -```yaml -:gcov: - :gcovr: - # The root directory of your source files. Defaults to ".", the current directory. - # File names are reported relative to this root. The report_root is the default report_include. - :report_root: "." - - # Load the specified configuration file. - # Defaults to gcovr.cfg in the report_root directory. (gcovr --config) - :config_file: <config_file> - - # Exit with a status of 2 if the total line coverage is less than MIN. - # Can be ORed with exit status of 'fail_under_branch' option. (gcovr --fail-under-line) - :fail_under_line: 30 - - # Exit with a status of 4 if the total branch coverage is less than MIN. - # Can be ORed with exit status of 'fail_under_line' option. (gcovr --fail-under-branch) - :fail_under_branch: 30 - - # Select the source file encoding. - # Defaults to the system default encoding (UTF-8). (gcovr --source-encoding) - :source_encoding: <source_encoding> - - # Report the branch coverage instead of the line coverage. For text report only. (gcovr --branches). - :branches: [true|false] - - # Sort entries by increasing number of uncovered lines. - # For text and HTML report. (gcovr --sort-uncovered) - :sort_uncovered: [true|false] - - # Sort entries by increasing percentage of uncovered lines. - # For text and HTML report. (gcovr --sort-percentage) - :sort_percentage: [true|false] - - # Print a small report to stdout with line & branch percentage coverage. - # This is in addition to other reports. (gcovr --print-summary). - :print_summary: [true|false] - - # Keep only source files that match this filter. (gcovr --filter). - :report_include: "^src" - - # Exclude source files that match this filter. (gcovr --exclude). - :report_exclude: "^vendor.*|^build.*|^test.*|^lib.*" - - # Keep only gcov data files that match this filter. (gcovr --gcov-filter). - :gcov_filter: <gcov_filter> - - # Exclude gcov data files that match this filter. (gcovr --gcov-exclude). - :gcov_exclude: <gcov_exclude> - - # Exclude directories that match this regex while searching - # raw coverage files. (gcovr --exclude-directories). - :exclude_directories: <exclude_dirs> - - # Use a particular gcov executable. (gcovr --gcov-executable). - :gcov_executable: <gcov_cmd> - - # Exclude branch coverage from lines without useful - # source code. (gcovr --exclude-unreachable-branches). - :exclude_unreachable_branches: [true|false] - - # For branch coverage, exclude branches that the compiler - # generates for exception handling. (gcovr --exclude-throw-branches). - :exclude_throw_branches: [true|false] - - # Use existing gcov files for analysis. Default: False. (gcovr --use-gcov-files) - :use_gcov_files: [true|false] - - # Skip lines with parse errors in GCOV files instead of - # exiting with an error. (gcovr --gcov-ignore-parse-errors). - :gcov_ignore_parse_errors: [true|false] - - # Override normal working directory detection. (gcovr --object-directory) - :object_directory: <objdir> - - # Keep gcov files after processing. (gcovr --keep). - :keep: [true|false] - - # Delete gcda files after processing. (gcovr --delete). - :delete: [true|false] - - # Set the number of threads to use in parallel. (gcovr -j). - :num_parallel_threads: <num_threads> - - # When scanning the code coverage, if any files are found that do not have - # associated coverage data, the command will abort with an error message. - :abort_on_uncovered: true - - # When using the ``abort_on_uncovered`` option, the files in this list will not - # trigger a failure. - # Ceedling globs described in the Ceedling packet ``Path`` section can be used - # when directories are placed on the list. Globs are limited to matching directories - # and not files. - :uncovered_ignore_list: [] -``` - -### ReportGenerator Configuration - -The ReportGenerator utility may be configured with the following configuration items. -All generated reports may be found in `build/artifacts/gcov/ReportGenerator`. - -```yaml -:gcov: - :report_generator: - # Optional directory for storing persistent coverage information. - # Can be used in future reports to show coverage evolution. - :history_directory: <history_directory> - - # Optional plugin files for custom reports or custom history storage (separated by semicolon). - :plugins: CustomReports.dll - - # Optional list of assemblies that should be included or excluded in the report (separated by semicolon).. - # Exclusion filters take precedence over inclusion filters. - # Wildcards are allowed, but not regular expressions. - :assembly_filters: "+Included;-Excluded" - - # Optional list of classes that should be included or excluded in the report (separated by semicolon).. - # Exclusion filters take precedence over inclusion filters. - # Wildcards are allowed, but not regular expressions. - :class_filters: "+Included;-Excluded" - - # Optional list of files that should be included or excluded in the report (separated by semicolon).. - # Exclusion filters take precedence over inclusion filters. - # Wildcards are allowed, but not regular expressions. - :file_filters: "-./vendor/*;-./build/*;-./test/*;-./lib/*;+./src/*" - - # The verbosity level of the log messages. - # Values: Verbose, Info, Warning, Error, Off - :verbosity: Warning - - # Optional tag or build version. - :tag: <tag> - - # Optional list of one or more regular expressions to exclude gcov notes files that match these filters. - :gcov_exclude: - - <exclude_regex1> - - <exclude_regex2> - - # Optionally use a particular gcov executable. Defaults to gcov. - :gcov_executable: <gcov_cmd> - - # Optionally set the number of threads to use in parallel. Defaults to 1. - :num_parallel_threads: <num_threads> - - # Optional list of one or more command line arguments to pass to Report Generator. - # Useful for configuring Risk Hotspots and Other Settings. - # https://github.com/danielpalme/ReportGenerator/wiki/Settings - :custom_args: - - <custom_arg1> - - <custom_arg2> -``` - -## Example Usage - -```sh -ceedling gcov:all utils:gcov -``` - -## To-Do list - -- Generate overall report (combined statistics from all files with coverage) - -## Citations - -Most of the comment text which describes the options was taken from the -[Gcovr User Guide](https://www.gcovr.com/en/stable/guide.html) and the -[ReportGenerator Wiki](https://github.com/danielpalme/ReportGenerator/wiki). -The text is repeated here to provide the most accurate option functionality. diff --git a/vendor/ceedling/plugins/gcov/assets/template.erb b/vendor/ceedling/plugins/gcov/assets/template.erb deleted file mode 100644 index 5e5a174..0000000 --- a/vendor/ceedling/plugins/gcov/assets/template.erb +++ /dev/null @@ -1,15 +0,0 @@ -% function_string = hash[:coverage][:functions].to_s -% branch_string = hash[:coverage][:branches].to_s -% format_string = "%#{[function_string.length, branch_string.length].max}i" -<%=@ceedling[:plugin_reportinator].generate_banner("#{GCOV_ROOT_NAME.upcase}: CODE COVERAGE SUMMARY")%> -% if (!hash[:coverage][:functions].nil?) -FUNCTIONS: <%=sprintf(format_string, hash[:coverage][:functions])%>% -% else -FUNCTIONS: none -% end -% if (!hash[:coverage][:branches].nil?) -BRANCHES: <%=sprintf(format_string, hash[:coverage][:branches])%>% -% else -BRANCHES: none -% end - diff --git a/vendor/ceedling/plugins/gcov/config/defaults_gcov.rb b/vendor/ceedling/plugins/gcov/config/defaults_gcov.rb deleted file mode 100644 index e3ce340..0000000 --- a/vendor/ceedling/plugins/gcov/config/defaults_gcov.rb +++ /dev/null @@ -1,118 +0,0 @@ - -DEFAULT_GCOV_COMPILER_TOOL = { - :executable => ENV['CC'].nil? ? FilePathUtils.os_executable_ext('gcc').freeze : ENV['CC'].split[0], - :name => 'default_gcov_compiler'.freeze, - :stderr_redirect => StdErrRedirect::NONE.freeze, - :background_exec => BackgroundExec::NONE.freeze, - :optional => false.freeze, - :arguments => [ - "-g".freeze, - "-fprofile-arcs".freeze, - "-ftest-coverage".freeze, - ENV['CC'].nil? ? "" : ENV['CC'].split[1..-1], - ENV['CPPFLAGS'].nil? ? "" : ENV['CPPFLAGS'].split, - {"-I\"$\"" => 'COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR'}.freeze, - {"-I\"$\"" => 'COLLECTION_PATHS_TEST_TOOLCHAIN_INCLUDE'}.freeze, - {"-D$" => 'COLLECTION_DEFINES_TEST_AND_VENDOR'}.freeze, - "-DGCOV_COMPILER".freeze, - "-DCODE_COVERAGE".freeze, - ENV['CFLAGS'].nil? ? "" : ENV['CFLAGS'].split, - "-c \"${1}\"".freeze, - "-o \"${2}\"".freeze - ].freeze - } - - -DEFAULT_GCOV_LINKER_TOOL = { - :executable => ENV['CCLD'].nil? ? FilePathUtils.os_executable_ext('gcc').freeze : ENV['CCLD'].split[0], - :name => 'default_gcov_linker'.freeze, - :stderr_redirect => StdErrRedirect::NONE.freeze, - :background_exec => BackgroundExec::NONE.freeze, - :optional => false.freeze, - :arguments => [ - "-g".freeze, - "-fprofile-arcs".freeze, - "-ftest-coverage".freeze, - ENV['CCLD'].nil? ? "" : ENV['CCLD'].split[1..-1], - ENV['CFLAGS'].nil? ? "" : ENV['CFLAGS'].split, - ENV['LDFLAGS'].nil? ? "" : ENV['LDFLAGS'].split, - "\"${1}\"".freeze, - "-o \"${2}\"".freeze, - "${4}".freeze, - "${5}".freeze, - ENV['LDLIBS'].nil? ? "" : ENV['LDLIBS'].split - ].freeze - } - -DEFAULT_GCOV_FIXTURE_TOOL = { - :executable => '${1}'.freeze, - :name => 'default_gcov_fixture'.freeze, - :stderr_redirect => StdErrRedirect::NONE.freeze, - :background_exec => BackgroundExec::NONE.freeze, - :optional => false.freeze, - :arguments => [].freeze - } - -DEFAULT_GCOV_REPORT_TOOL = { - :executable => ENV['GCOV'].nil? ? FilePathUtils.os_executable_ext('gcov').freeze : ENV['GCOV'].split[0], - :name => 'default_gcov_report'.freeze, - :stderr_redirect => StdErrRedirect::NONE.freeze, - :background_exec => BackgroundExec::NONE.freeze, - :optional => false.freeze, - :arguments => [ - "-n".freeze, - "-p".freeze, - "-b".freeze, - {"-o \"$\"" => 'GCOV_BUILD_OUTPUT_PATH'}.freeze, - "\"${1}\"".freeze - ].freeze - } - -DEFAULT_GCOV_GCOV_POST_REPORT_TOOL = { - :executable => ENV['GCOV'].nil? ? FilePathUtils.os_executable_ext('gcov').freeze : ENV['GCOV'].split[0], - :name => 'default_gcov_gcov_post_report'.freeze, - :stderr_redirect => StdErrRedirect::NONE.freeze, - :background_exec => BackgroundExec::NONE.freeze, - :optional => true.freeze, - :arguments => [ - "-b".freeze, - "-c".freeze, - "-r".freeze, - "-x".freeze, - "${1}".freeze - ].freeze - } - -DEFAULT_GCOV_GCOVR_POST_REPORT_TOOL = { - :executable => 'gcovr'.freeze, - :name => 'default_gcov_gcovr_post_report'.freeze, - :stderr_redirect => StdErrRedirect::NONE.freeze, - :background_exec => BackgroundExec::NONE.freeze, - :optional => true.freeze, - :arguments => [ - "${1}".freeze - ].freeze - } - -DEFAULT_GCOV_REPORTGENERATOR_POST_REPORT = { - :executable => 'reportgenerator'.freeze, - :name => 'default_gcov_reportgenerator_post_report'.freeze, - :stderr_redirect => StdErrRedirect::NONE.freeze, - :background_exec => BackgroundExec::NONE.freeze, - :optional => true.freeze, - :arguments => [ - "${1}".freeze - ].freeze - } - -def get_default_config - return :tools => { - :gcov_compiler => DEFAULT_GCOV_COMPILER_TOOL, - :gcov_linker => DEFAULT_GCOV_LINKER_TOOL, - :gcov_fixture => DEFAULT_GCOV_FIXTURE_TOOL, - :gcov_report => DEFAULT_GCOV_REPORT_TOOL, - :gcov_gcov_post_report => DEFAULT_GCOV_GCOV_POST_REPORT_TOOL, - :gcov_gcovr_post_report => DEFAULT_GCOV_GCOVR_POST_REPORT_TOOL, - :gcov_reportgenerator_post_report => DEFAULT_GCOV_REPORTGENERATOR_POST_REPORT - } -end diff --git a/vendor/ceedling/plugins/gcov/gcov.rake b/vendor/ceedling/plugins/gcov/gcov.rake deleted file mode 100644 index 1467564..0000000 --- a/vendor/ceedling/plugins/gcov/gcov.rake +++ /dev/null @@ -1,209 +0,0 @@ -require 'reportgenerator_reportinator' -require 'gcovr_reportinator' - -directory(GCOV_BUILD_OUTPUT_PATH) -directory(GCOV_RESULTS_PATH) -directory(GCOV_ARTIFACTS_PATH) -directory(GCOV_DEPENDENCIES_PATH) - -CLEAN.include(File.join(GCOV_BUILD_OUTPUT_PATH, '*')) -CLEAN.include(File.join(GCOV_RESULTS_PATH, '*')) -CLEAN.include(File.join(GCOV_ARTIFACTS_PATH, '*')) -CLEAN.include(File.join(GCOV_DEPENDENCIES_PATH, '*')) - -CLOBBER.include(File.join(GCOV_BUILD_PATH, '**/*')) - -rule(/#{GCOV_BUILD_OUTPUT_PATH}\/#{'.+\\' + EXTENSION_OBJECT}$/ => [ - proc do |task_name| - @ceedling[:file_finder].find_compilation_input_file(task_name) - end - ]) do |object| - - if File.basename(object.source) =~ /^(#{PROJECT_TEST_FILE_PREFIX}|#{CMOCK_MOCK_PREFIX})|(#{VENDORS_FILES.map{|source| '\b' + source + '\b'}.join('|')})/ - @ceedling[:generator].generate_object_file( - TOOLS_GCOV_COMPILER, - OPERATION_COMPILE_SYM, - GCOV_SYM, - object.source, - object.name, - @ceedling[:file_path_utils].form_test_build_list_filepath(object.name) - ) - else - @ceedling[GCOV_SYM].generate_coverage_object_file(object.source, object.name) - end -end - -rule(/#{GCOV_BUILD_OUTPUT_PATH}\/#{'.+\\' + EXTENSION_EXECUTABLE}$/) do |bin_file| - lib_args = @ceedling[:test_invoker].convert_libraries_to_arguments() - lib_paths = @ceedling[:test_invoker].get_library_paths_to_arguments() - @ceedling[:generator].generate_executable_file( - TOOLS_GCOV_LINKER, - GCOV_SYM, - bin_file.prerequisites, - bin_file.name, - @ceedling[:file_path_utils].form_test_build_map_filepath(bin_file.name), - lib_args, - lib_paths - ) -end - -rule(/#{GCOV_RESULTS_PATH}\/#{'.+\\' + EXTENSION_TESTPASS}$/ => [ - proc do |task_name| - @ceedling[:file_path_utils].form_test_executable_filepath(task_name) - end - ]) do |test_result| - @ceedling[:generator].generate_test_results(TOOLS_GCOV_FIXTURE, GCOV_SYM, test_result.source, test_result.name) -end - -rule(/#{GCOV_DEPENDENCIES_PATH}\/#{'.+\\' + EXTENSION_DEPENDENCIES}$/ => [ - proc do |task_name| - @ceedling[:file_finder].find_compilation_input_file(task_name) - end - ]) do |dep| - @ceedling[:generator].generate_dependencies_file( - TOOLS_TEST_DEPENDENCIES_GENERATOR, - GCOV_SYM, - dep.source, - File.join(GCOV_BUILD_OUTPUT_PATH, File.basename(dep.source).ext(EXTENSION_OBJECT)), - dep.name - ) -end - -task directories: [GCOV_BUILD_OUTPUT_PATH, GCOV_RESULTS_PATH, GCOV_DEPENDENCIES_PATH, GCOV_ARTIFACTS_PATH] - -namespace GCOV_SYM do - task source_coverage: COLLECTION_ALL_SOURCE.pathmap("#{GCOV_BUILD_OUTPUT_PATH}/%n#{@ceedling[:configurator].extension_object}") - - desc 'Run code coverage for all tests' - task all: [:test_deps] do - @ceedling[:configurator].replace_flattened_config(@ceedling[GCOV_SYM].config) - @ceedling[:test_invoker].setup_and_invoke(COLLECTION_ALL_TESTS, GCOV_SYM) - @ceedling[:configurator].restore_config - end - - desc 'Run single test w/ coverage ([*] real test or source file name, no path).' - task :* do - message = "\nOops! '#{GCOV_ROOT_NAME}:*' isn't a real task. " \ - "Use a real test or source file name (no path) in place of the wildcard.\n" \ - "Example: rake #{GCOV_ROOT_NAME}:foo.c\n\n" - - @ceedling[:streaminator].stdout_puts(message) - end - - desc 'Run tests by matching regular expression pattern.' - task :pattern, [:regex] => [:test_deps] do |_t, args| - matches = [] - - COLLECTION_ALL_TESTS.each do |test| - matches << test if test =~ /#{args.regex}/ - end - - if !matches.empty? - @ceedling[:configurator].replace_flattened_config(@ceedling[GCOV_SYM].config) - @ceedling[:test_invoker].setup_and_invoke(matches, GCOV_SYM, force_run: false) - @ceedling[:configurator].restore_config - else - @ceedling[:streaminator].stdout_puts("\nFound no tests matching pattern /#{args.regex}/.") - end - end - - desc 'Run tests whose test path contains [dir] or [dir] substring.' - task :path, [:dir] => [:test_deps] do |_t, args| - matches = [] - - COLLECTION_ALL_TESTS.each do |test| - matches << test if File.dirname(test).include?(args.dir.tr('\\', '/')) - end - - if !matches.empty? - @ceedling[:configurator].replace_flattened_config(@ceedling[GCOV_SYM].config) - @ceedling[:test_invoker].setup_and_invoke(matches, GCOV_SYM, force_run: false) - @ceedling[:configurator].restore_config - else - @ceedling[:streaminator].stdout_puts("\nFound no tests including the given path or path component.") - end - end - - desc 'Run code coverage for changed files' - task delta: [:test_deps] do - @ceedling[:configurator].replace_flattened_config(@ceedling[GCOV_SYM].config) - @ceedling[:test_invoker].setup_and_invoke(COLLECTION_ALL_TESTS, GCOV_SYM, force_run: false) - @ceedling[:configurator].restore_config - end - - # use a rule to increase efficiency for large projects - # gcov test tasks by regex - rule(/^#{GCOV_TASK_ROOT}\S+$/ => [ - proc do |task_name| - test = task_name.sub(/#{GCOV_TASK_ROOT}/, '') - test = "#{PROJECT_TEST_FILE_PREFIX}#{test}" unless test.start_with?(PROJECT_TEST_FILE_PREFIX) - @ceedling[:file_finder].find_test_from_file_path(test) - end - ]) do |test| - @ceedling[:rake_wrapper][:test_deps].invoke - @ceedling[:configurator].replace_flattened_config(@ceedling[GCOV_SYM].config) - @ceedling[:test_invoker].setup_and_invoke([test.source], GCOV_SYM) - @ceedling[:configurator].restore_config - end -end - -if PROJECT_USE_DEEP_DEPENDENCIES - namespace REFRESH_SYM do - task GCOV_SYM do - @ceedling[:configurator].replace_flattened_config(@ceedling[GCOV_SYM].config) - @ceedling[:test_invoker].refresh_deep_dependencies - @ceedling[:configurator].restore_config - end - end -end - -namespace UTILS_SYM do - # Report Creation Utilities - UTILITY_NAME_GCOVR = "gcovr" - UTILITY_NAME_REPORT_GENERATOR = "ReportGenerator" - UTILITY_NAMES = [UTILITY_NAME_GCOVR, UTILITY_NAME_REPORT_GENERATOR] - - # Returns true is the given utility is enabled, otherwise returns false. - def is_utility_enabled(opts, utility_name) - return !(opts.nil?) && !(opts[:gcov_utilities].nil?) && (opts[:gcov_utilities].map(&:upcase).include? utility_name.upcase) - end - - - desc "Create gcov code coverage html/xml/json/text report(s). (Note: Must run 'ceedling gcov' first)." - task GCOV_SYM do - # Get the gcov options from project.yml. - opts = @ceedling[:configurator].project_config_hash - - # Create the artifacts output directory. - if !File.directory? GCOV_ARTIFACTS_PATH - FileUtils.mkdir_p GCOV_ARTIFACTS_PATH - end - - # Remove unsupported reporting utilities. - if !(opts[:gcov_utilities].nil?) - opts[:gcov_utilities].reject! { |item| !(UTILITY_NAMES.map(&:upcase).include? item.upcase) } - end - - # Default to gcovr when no reporting utilities are specified. - if opts[:gcov_utilities].nil? || opts[:gcov_utilities].empty? - opts[:gcov_utilities] = [UTILITY_NAME_GCOVR] - end - - if opts[:gcov_reports].nil? - opts[:gcov_reports] = [] - end - - gcovr_reportinator = GcovrReportinator.new(@ceedling) - gcovr_reportinator.support_deprecated_options(opts) - - if is_utility_enabled(opts, UTILITY_NAME_GCOVR) - gcovr_reportinator.make_reports(opts) - end - - if is_utility_enabled(opts, UTILITY_NAME_REPORT_GENERATOR) - reportgenerator_reportinator = ReportGeneratorReportinator.new(@ceedling) - reportgenerator_reportinator.make_reports(opts) - end - - end -end diff --git a/vendor/ceedling/plugins/gcov/lib/gcov.rb b/vendor/ceedling/plugins/gcov/lib/gcov.rb deleted file mode 100644 index 30c6326..0000000 --- a/vendor/ceedling/plugins/gcov/lib/gcov.rb +++ /dev/null @@ -1,136 +0,0 @@ -require 'ceedling/plugin' -require 'ceedling/constants' -require 'gcov_constants' - -class Gcov < Plugin - attr_reader :config - - def setup - @result_list = [] - - @config = { - project_test_build_output_path: GCOV_BUILD_OUTPUT_PATH, - project_test_build_output_c_path: GCOV_BUILD_OUTPUT_PATH, - project_test_results_path: GCOV_RESULTS_PATH, - project_test_dependencies_path: GCOV_DEPENDENCIES_PATH, - defines_test: DEFINES_TEST + ['CODE_COVERAGE'], - gcov_html_report_filter: GCOV_FILTER_EXCLUDE - } - - @plugin_root = File.expand_path(File.join(File.dirname(__FILE__), '..')) - @coverage_template_all = @ceedling[:file_wrapper].read(File.join(@plugin_root, 'assets/template.erb')) - end - - def generate_coverage_object_file(source, object) - lib_args = @ceedling[:test_invoker].convert_libraries_to_arguments() - compile_command = - @ceedling[:tool_executor].build_command_line( - TOOLS_GCOV_COMPILER, - @ceedling[:flaginator].flag_down(OPERATION_COMPILE_SYM, GCOV_SYM, source), - source, - object, - @ceedling[:file_path_utils].form_test_build_list_filepath(object), - lib_args - ) - @ceedling[:streaminator].stdout_puts("Compiling #{File.basename(source)} with coverage...") - @ceedling[:tool_executor].exec(compile_command[:line], compile_command[:options]) - end - - def post_test_fixture_execute(arg_hash) - result_file = arg_hash[:result_file] - - if (result_file =~ /#{GCOV_RESULTS_PATH}/) && !@result_list.include?(result_file) - @result_list << arg_hash[:result_file] - end - end - - def post_build - return unless @ceedling[:task_invoker].invoked?(/^#{GCOV_TASK_ROOT}/) - - # test results - results = @ceedling[:plugin_reportinator].assemble_test_results(@result_list) - hash = { - header: GCOV_ROOT_NAME.upcase, - results: results - } - - @ceedling[:plugin_reportinator].run_test_results_report(hash) do - message = '' - message = 'Unit test failures.' if results[:counts][:failed] > 0 - message - end - - report_per_file_coverage_results(@ceedling[:test_invoker].sources) - end - - def summary - result_list = @ceedling[:file_path_utils].form_pass_results_filelist(GCOV_RESULTS_PATH, COLLECTION_ALL_TESTS) - - # test results - # get test results for only those tests in our configuration and of those only tests with results on disk - hash = { - header: GCOV_ROOT_NAME.upcase, - results: @ceedling[:plugin_reportinator].assemble_test_results(result_list, boom: false) - } - - @ceedling[:plugin_reportinator].run_test_results_report(hash) - end - - private ################################### - - def report_per_file_coverage_results(sources) - banner = @ceedling[:plugin_reportinator].generate_banner "#{GCOV_ROOT_NAME.upcase}: CODE COVERAGE SUMMARY" - @ceedling[:streaminator].stdout_puts "\n" + banner - - coverage_sources = @ceedling[:project_config_manager].filter_internal_sources(sources) - coverage_sources.each do |source| - basename = File.basename(source) - command = @ceedling[:tool_executor].build_command_line(TOOLS_GCOV_REPORT, [], [basename]) - shell_results = @ceedling[:tool_executor].exec(command[:line], command[:options]) - coverage_results = shell_results[:output] - - if coverage_results.strip =~ /(File\s+'#{Regexp.escape(source)}'.+$)/m - report = Regexp.last_match(1).lines.to_a[1..-1].map { |line| basename + ' ' + line }.join('') - @ceedling[:streaminator].stdout_puts(report + "\n\n") - end - end - - ignore_path_list = @ceedling[:file_system_utils].collect_paths(@ceedling[:configurator].project_config_hash[:gcov_uncovered_ignore_list] || []) - ignore_uncovered_list = @ceedling[:file_wrapper].instantiate_file_list - ignore_path_list.each do |path| - if File.exists?(path) and not File.directory?(path) - ignore_uncovered_list.include(path) - else - ignore_uncovered_list.include(File.join(path, "*#{EXTENSION_SOURCE}")) - end - end - - found_uncovered = false - COLLECTION_ALL_SOURCE.each do |source| - unless coverage_sources.include?(source) - v = Verbosity::DEBUG - msg = "Could not find coverage results for " + source - if ignore_uncovered_list.include?(source) - msg += " [IGNORED]" - else - found_uncovered = true - v = Verbosity::NORMAL - end - msg += "\n" - @ceedling[:streaminator].stdout_puts(msg, v) - end - end - if found_uncovered - if @ceedling[:configurator].project_config_hash[:gcov_abort_on_uncovered] - @ceedling[:streaminator].stderr_puts("There were files with no coverage results: aborting.\n") - exit(-1) - end - end - end -end - -# end blocks always executed following rake run -END { - # cache our input configurations to use in comparison upon next execution - @ceedling[:cacheinator].cache_test_config(@ceedling[:setupinator].config_hash) if @ceedling[:task_invoker].invoked?(/^#{GCOV_TASK_ROOT}/) -} diff --git a/vendor/ceedling/plugins/gcov/lib/gcov_constants.rb b/vendor/ceedling/plugins/gcov/lib/gcov_constants.rb deleted file mode 100644 index 74c9bbd..0000000 --- a/vendor/ceedling/plugins/gcov/lib/gcov_constants.rb +++ /dev/null @@ -1,48 +0,0 @@ - -GCOV_ROOT_NAME = 'gcov'.freeze -GCOV_TASK_ROOT = GCOV_ROOT_NAME + ':' -GCOV_SYM = GCOV_ROOT_NAME.to_sym - -GCOV_BUILD_PATH = File.join(PROJECT_BUILD_ROOT, GCOV_ROOT_NAME) -GCOV_BUILD_OUTPUT_PATH = File.join(GCOV_BUILD_PATH, "out") -GCOV_RESULTS_PATH = File.join(GCOV_BUILD_PATH, "results") -GCOV_DEPENDENCIES_PATH = File.join(GCOV_BUILD_PATH, "dependencies") -GCOV_ARTIFACTS_PATH = File.join(PROJECT_BUILD_ARTIFACTS_ROOT, GCOV_ROOT_NAME) -GCOV_REPORT_GENERATOR_PATH = File.join(GCOV_ARTIFACTS_PATH, "ReportGenerator") - -GCOV_ARTIFACTS_FILE_HTML = File.join(GCOV_ARTIFACTS_PATH, "GcovCoverageResults.html") -GCOV_ARTIFACTS_FILE_COBERTURA = File.join(GCOV_ARTIFACTS_PATH, "GcovCoverageCobertura.xml") -GCOV_ARTIFACTS_FILE_SONARQUBE = File.join(GCOV_ARTIFACTS_PATH, "GcovCoverageSonarQube.xml") -GCOV_ARTIFACTS_FILE_JSON = File.join(GCOV_ARTIFACTS_PATH, "GcovCoverage.json") - -GCOV_FILTER_EXCLUDE_PATHS = ['vendor', 'build', 'test', 'lib'] - -# gcovr supports regular expressions. -GCOV_FILTER_EXCLUDE = GCOV_FILTER_EXCLUDE_PATHS.map{|path| '^'.concat(*path).concat('.*')}.join('|') - -# ReportGenerator supports text with wildcard characters. -GCOV_REPORT_GENERATOR_FILE_FILTERS = GCOV_FILTER_EXCLUDE_PATHS.map{|path| File.join('-.', *path, '*')}.join(';') - -# Report Types -class ReportTypes - HTML_BASIC = "HtmlBasic" - HTML_DETAILED = "HtmlDetailed" - HTML_CHART = "HtmlChart" - HTML_INLINE = "HtmlInline" - HTML_INLINE_AZURE = "HtmlInlineAzure" - HTML_INLINE_AZURE_DARK = "HtmlInlineAzureDark" - MHTML = "MHtml" - TEXT = "Text" - COBERTURA = "Cobertura" - SONARQUBE = "SonarQube" - JSON = "JSON" - BADGES = "Badges" - CSV_SUMMARY = "CsvSummary" - LATEX = "Latex" - LATEX_SUMMARY = "LatexSummary" - PNG_CHART = "PngChart" - TEAM_CITY_SUMMARY = "TeamCitySummary" - LCOV = "lcov" - XML = "Xml" - XML_SUMMARY = "XmlSummary" -end diff --git a/vendor/ceedling/plugins/gcov/lib/gcovr_reportinator.rb b/vendor/ceedling/plugins/gcov/lib/gcovr_reportinator.rb deleted file mode 100644 index 5317c5d..0000000 --- a/vendor/ceedling/plugins/gcov/lib/gcovr_reportinator.rb +++ /dev/null @@ -1,331 +0,0 @@ -require 'reportinator_helper' - -class GcovrReportinator - - def initialize(system_objects) - @ceedling = system_objects - @reportinator_helper = ReportinatorHelper.new - end - - - # Generate the gcovr report(s) specified in the options. - def make_reports(opts) - # Get the gcovr version number. - gcovr_version_info = get_gcovr_version() - - # Build the common gcovr arguments. - args_common = args_builder_common(opts) - - if ((gcovr_version_info[0] == 4) && (gcovr_version_info[1] >= 2)) || (gcovr_version_info[0] > 4) - # gcovr version 4.2 and later supports generating multiple reports with a single call. - args = args_common - args += args_builder_cobertura(opts, false) - args += args_builder_sonarqube(opts, false) - args += args_builder_json(opts, true) - # As of gcovr version 4.2, the --html argument must appear last. - args += args_builder_html(opts, false) - - print "Creating gcov results report(s) in '#{GCOV_ARTIFACTS_PATH}'... " - STDOUT.flush - - # Generate the report(s). - run(args) - else - # gcovr version 4.1 and earlier supports HTML and Cobertura XML reports. - # It does not support SonarQube and JSON reports. - # Reports must also be generated separately. - args_cobertura = args_builder_cobertura(opts, true) - args_html = args_builder_html(opts, true) - - if args_html.length > 0 - print "Creating a gcov HTML report in '#{GCOV_ARTIFACTS_PATH}'... " - STDOUT.flush - - # Generate the HTML report. - run(args_common + args_html) - end - - if args_cobertura.length > 0 - print "Creating a gcov XML report in '#{GCOV_ARTIFACTS_PATH}'... " - STDOUT.flush - - # Generate the Cobertura XML report. - run(args_common + args_cobertura) - end - end - - # Determine if the gcovr text report is enabled. Defaults to disabled. - if is_report_enabled(opts, ReportTypes::TEXT) - make_text_report(opts, args_common) - end - end - - - def support_deprecated_options(opts) - # Support deprecated :html_report: and ":html_report_type: basic" options. - if !is_report_enabled(opts, ReportTypes::HTML_BASIC) && (opts[:gcov_html_report] || (opts[:gcov_html_report_type].is_a? String) && (opts[:gcov_html_report_type].casecmp("basic") == 0)) - opts[:gcov_reports].push(ReportTypes::HTML_BASIC) - end - - # Support deprecated ":html_report_type: detailed" option. - if !is_report_enabled(opts, ReportTypes::HTML_DETAILED) && (opts[:gcov_html_report_type].is_a? String) && (opts[:gcov_html_report_type].casecmp("detailed") == 0) - opts[:gcov_reports].push(ReportTypes::HTML_DETAILED) - end - - # Support deprecated :xml_report: option. - if opts[:gcov_xml_report] - opts[:gcov_reports].push(ReportTypes::COBERTURA) - end - - # Default to HTML basic report when no report types are defined. - if opts[:gcov_reports].empty? && opts[:gcov_html_report_type].nil? && opts[:gcov_xml_report].nil? - opts[:gcov_reports] = [ReportTypes::HTML_BASIC] - - puts "In your project.yml, define one or more of the" - puts "following to specify which reports to generate." - puts "For now, creating only an #{ReportTypes::HTML_BASIC} report." - puts "" - puts ":gcov:" - puts " :reports:" - puts " - #{ReportTypes::HTML_BASIC}" - puts " - #{ReportTypes::HTML_DETAILED}" - puts " - #{ReportTypes::TEXT}" - puts " - #{ReportTypes::COBERTURA}" - puts " - #{ReportTypes::SONARQUBE}" - puts " - #{ReportTypes::JSON}" - puts "" - end - end - - - private - - GCOVR_SETTING_PREFIX = "gcov_gcovr" - - # Build the gcovr report generation common arguments. - def args_builder_common(opts) - gcovr_opts = get_opts(opts) - - args = "" - args += "--root \"#{gcovr_opts[:report_root] || '.'}\" " - args += "--config \"#{gcovr_opts[:config_file]}\" " unless gcovr_opts[:config_file].nil? - args += "--filter \"#{gcovr_opts[:report_include]}\" " unless gcovr_opts[:report_include].nil? - args += "--exclude \"#{gcovr_opts[:report_exclude] || GCOV_FILTER_EXCLUDE}\" " - args += "--gcov-filter \"#{gcovr_opts[:gcov_filter]}\" " unless gcovr_opts[:gcov_filter].nil? - args += "--gcov-exclude \"#{gcovr_opts[:gcov_exclude]}\" " unless gcovr_opts[:gcov_exclude].nil? - args += "--exclude-directories \"#{gcovr_opts[:exclude_directories]}\" " unless gcovr_opts[:exclude_directories].nil? - args += "--branches " if gcovr_opts[:branches].nil? || gcovr_opts[:branches] # Defaults to enabled. - args += "--sort-uncovered " if gcovr_opts[:sort_uncovered] - args += "--sort-percentage " if gcovr_opts[:sort_percentage].nil? || gcovr_opts[:sort_percentage] # Defaults to enabled. - args += "--print-summary " if gcovr_opts[:print_summary] - args += "--gcov-executable \"#{gcovr_opts[:gcov_executable]}\" " unless gcovr_opts[:gcov_executable].nil? - args += "--exclude-unreachable-branches " if gcovr_opts[:exclude_unreachable_branches] - args += "--exclude-throw-branches " if gcovr_opts[:exclude_throw_branches] - args += "--use-gcov-files " if gcovr_opts[:use_gcov_files] - args += "--gcov-ignore-parse-errors " if gcovr_opts[:gcov_ignore_parse_errors] - args += "--keep " if gcovr_opts[:keep] - args += "--delete " if gcovr_opts[:delete] - args += "-j #{gcovr_opts[:num_parallel_threads]} " if !(gcovr_opts[:num_parallel_threads].nil?) && (gcovr_opts[:num_parallel_threads].is_a? Integer) - - [:fail_under_line, :fail_under_branch, :source_encoding, :object_directory].each do |opt| - unless gcovr_opts[opt].nil? - - value = gcovr_opts[opt] - if (opt == :fail_under_line) || (opt == :fail_under_branch) - if not value.is_a? Integer - puts "Option value #{opt} has to be an integer" - value = nil - elsif (value < 0) || (value > 100) - puts "Option value #{opt} has to be a percentage from 0 to 100" - value = nil - end - end - args += "--#{opt.to_s.gsub('_','-')} #{value} " unless value.nil? - end - end - - return args - end - - - # Build the gcovr Cobertura XML report generation arguments. - def args_builder_cobertura(opts, use_output_option=false) - gcovr_opts = get_opts(opts) - args = "" - - # Determine if the Cobertura XML report is enabled. Defaults to disabled. - if is_report_enabled(opts, ReportTypes::COBERTURA) - # Determine the Cobertura XML report file name. - artifacts_file_cobertura = GCOV_ARTIFACTS_FILE_COBERTURA - if !(gcovr_opts[:cobertura_artifact_filename].nil?) - artifacts_file_cobertura = File.join(GCOV_ARTIFACTS_PATH, gcovr_opts[:cobertura_artifact_filename]) - elsif !(gcovr_opts[:xml_artifact_filename].nil?) - artifacts_file_cobertura = File.join(GCOV_ARTIFACTS_PATH, gcovr_opts[:xml_artifact_filename]) - end - - args += "--xml-pretty " if gcovr_opts[:xml_pretty] || gcovr_opts[:cobertura_pretty] - args += "--xml #{use_output_option ? "--output " : ""} \"#{artifacts_file_cobertura}\" " - end - - return args - end - - - # Build the gcovr SonarQube report generation arguments. - def args_builder_sonarqube(opts, use_output_option=false) - gcovr_opts = get_opts(opts) - args = "" - - # Determine if the gcovr SonarQube XML report is enabled. Defaults to disabled. - if is_report_enabled(opts, ReportTypes::SONARQUBE) - # Determine the SonarQube XML report file name. - artifacts_file_sonarqube = GCOV_ARTIFACTS_FILE_SONARQUBE - if !(gcovr_opts[:sonarqube_artifact_filename].nil?) - artifacts_file_sonarqube = File.join(GCOV_ARTIFACTS_PATH, gcovr_opts[:sonarqube_artifact_filename]) - end - - args += "--sonarqube #{use_output_option ? "--output " : ""} \"#{artifacts_file_sonarqube}\" " - end - - return args - end - - - # Build the gcovr JSON report generation arguments. - def args_builder_json(opts, use_output_option=false) - gcovr_opts = get_opts(opts) - args = "" - - # Determine if the gcovr JSON report is enabled. Defaults to disabled. - if is_report_enabled(opts, ReportTypes::JSON) - # Determine the JSON report file name. - artifacts_file_json = GCOV_ARTIFACTS_FILE_JSON - if !(gcovr_opts[:json_artifact_filename].nil?) - artifacts_file_json = File.join(GCOV_ARTIFACTS_PATH, gcovr_opts[:json_artifact_filename]) - end - - args += "--json-pretty " if gcovr_opts[:json_pretty] - # Note: In gcovr 4.2, the JSON report is output only when the --output option is specified. - # Hopefully we can remove --output after a future gcovr release. - args += "--json #{use_output_option ? "--output " : ""} \"#{artifacts_file_json}\" " - end - - return args - end - - - # Build the gcovr HTML report generation arguments. - def args_builder_html(opts, use_output_option=false) - gcovr_opts = get_opts(opts) - args = "" - - # Determine if the gcovr HTML report is enabled. Defaults to enabled. - html_enabled = (opts[:gcov_html_report].nil? && opts[:gcov_reports].empty?) || - is_report_enabled(opts, ReportTypes::HTML_BASIC) || - is_report_enabled(opts, ReportTypes::HTML_DETAILED) - - if html_enabled - # Determine the HTML report file name. - artifacts_file_html = GCOV_ARTIFACTS_FILE_HTML - if !(gcovr_opts[:html_artifact_filename].nil?) - artifacts_file_html = File.join(GCOV_ARTIFACTS_PATH, gcovr_opts[:html_artifact_filename]) - end - - is_html_report_type_detailed = (opts[:gcov_html_report_type].is_a? String) && (opts[:gcov_html_report_type].casecmp("detailed") == 0) - - args += "--html-details " if is_html_report_type_detailed || is_report_enabled(opts, ReportTypes::HTML_DETAILED) - args += "--html-title \"#{gcovr_opts[:html_title]}\" " unless gcovr_opts[:html_title].nil? - args += "--html-absolute-paths " if !(gcovr_opts[:html_absolute_paths].nil?) && gcovr_opts[:html_absolute_paths] - args += "--html-encoding \"#{gcovr_opts[:html_encoding]}\" " unless gcovr_opts[:html_encoding].nil? - - [:html_medium_threshold, :html_high_threshold].each do |opt| - args += "--#{opt.to_s.gsub('_','-')} #{gcovr_opts[opt]} " unless gcovr_opts[opt].nil? - end - - # The following option must be appended last for gcovr version <= 4.2 to properly work. - args += "--html #{use_output_option ? "--output " : ""} \"#{artifacts_file_html}\" " - end - - return args - end - - - # Generate a gcovr text report. - def make_text_report(opts, args_common) - gcovr_opts = get_opts(opts) - args_text = "" - message_text = "Creating a gcov text report" - - if !(gcovr_opts[:text_artifact_filename].nil?) - artifacts_file_txt = File.join(GCOV_ARTIFACTS_PATH, gcovr_opts[:text_artifact_filename]) - args_text += "--output \"#{artifacts_file_txt}\" " - message_text += " in '#{GCOV_ARTIFACTS_PATH}'... " - else - message_text += "... " - end - - print message_text - STDOUT.flush - - # Generate the text report. - run(args_common + args_text) - end - - - # Get the gcovr options from the project options. - def get_opts(opts) - return opts[GCOVR_SETTING_PREFIX.to_sym] || {} - end - - - # Run gcovr with the given arguments. - def run(args) - begin - command = @ceedling[:tool_executor].build_command_line(TOOLS_GCOV_GCOVR_POST_REPORT, [], args) - shell_result = @ceedling[:tool_executor].exec(command[:line], command[:options]) - @reportinator_helper.print_shell_result(shell_result) - rescue - # handle any unforeseen issues with called tool - exitcode = $?.exitstatus - show_gcovr_message(exitcode) - exit(exitcode) - end - end - - - # Get the gcovr version number as components. - # Returns [major, minor]. - def get_gcovr_version() - version_number_major = 0 - version_number_minor = 0 - - command = @ceedling[:tool_executor].build_command_line(TOOLS_GCOV_GCOVR_POST_REPORT, [], "--version") - shell_result = @ceedling[:tool_executor].exec(command[:line], command[:options]) - version_number_match_data = shell_result[:output].match(/gcovr ([0-9]+)\.([0-9]+)/) - - if !(version_number_match_data.nil?) && !(version_number_match_data[1].nil?) && !(version_number_match_data[2].nil?) - version_number_major = version_number_match_data[1].to_i - version_number_minor = version_number_match_data[2].to_i - end - - return version_number_major, version_number_minor - end - - - # Show a more human-friendly message on gcovr return code - def show_gcovr_message(exitcode) - if ((exitcode & 2) == 2) - puts "The line coverage is less than the minimum" - end - if ((exitcode & 4) == 4) - puts "The branch coverage is less than the minimum" - end - end - - - # Returns true if the given report type is enabled, otherwise returns false. - def is_report_enabled(opts, report_type) - return !(opts.nil?) && !(opts[:gcov_reports].nil?) && (opts[:gcov_reports].map(&:upcase).include? report_type.upcase) - end - -end diff --git a/vendor/ceedling/plugins/gcov/lib/reportgenerator_reportinator.rb b/vendor/ceedling/plugins/gcov/lib/reportgenerator_reportinator.rb deleted file mode 100644 index d4a885c..0000000 --- a/vendor/ceedling/plugins/gcov/lib/reportgenerator_reportinator.rb +++ /dev/null @@ -1,195 +0,0 @@ -require 'benchmark' -require 'reportinator_helper' - -class ReportGeneratorReportinator - - def initialize(system_objects) - @ceedling = system_objects - @reportinator_helper = ReportinatorHelper.new - end - - - # Generate the ReportGenerator report(s) specified in the options. - def make_reports(opts) - shell_result = nil - total_time = Benchmark.realtime do - rg_opts = get_opts(opts) - - print "Creating gcov results report(s) with ReportGenerator in '#{GCOV_REPORT_GENERATOR_PATH}'... " - STDOUT.flush - - # Cleanup any existing .gcov files to avoid reporting old coverage results. - for gcov_file in Dir.glob("*.gcov") - File.delete(gcov_file) - end - - # Use a custom gcov executable, if specified. - GCOV_TOOL_CONFIG[:executable] = rg_opts[:gcov_executable] unless rg_opts[:gcov_executable].nil? - - # Avoid running gcov on the mock, test, unity, and cexception gcov notes files to save time. - gcno_exclude_str = "#{opts[:cmock_mock_prefix]}.*" - gcno_exclude_str += "|#{opts[:project_test_file_prefix]}.*" - gcno_exclude_str += "|#{VENDORS_FILES.join('|')}" - - # Avoid running gcov on custom specified .gcno files. - if !(rg_opts.nil?) && !(rg_opts[:gcov_exclude].nil?) && !(rg_opts[:gcov_exclude].empty?) - for gcno_exclude_expression in rg_opts[:gcov_exclude] - if !(gcno_exclude_expression.nil?) && !(gcno_exclude_expression.empty?) - # We want to filter .gcno files, not .gcov files. - # We will generate .gcov files from .gcno files. - gcno_exclude_expression = gcno_exclude_expression.chomp("\\.gcov") - gcno_exclude_expression = gcno_exclude_expression.chomp(".gcov") - # The .gcno extension will be added later as we create the regex. - gcno_exclude_expression = gcno_exclude_expression.chomp("\\.gcno") - gcno_exclude_expression = gcno_exclude_expression.chomp(".gcno") - # Append the custom expression. - gcno_exclude_str += "|#{gcno_exclude_expression}" - end - end - end - - gcno_exclude_regex = /(\/|\\)(#{gcno_exclude_str})\.gcno/ - - # Generate .gcov files by running gcov on gcov notes files (*.gcno). - for gcno_filepath in Dir.glob(File.join(GCOV_BUILD_PATH, "**", "*.gcno")) - match_data = gcno_filepath.match(gcno_exclude_regex) - if match_data.nil? || (match_data[1].nil? && match_data[1].nil?) - # Ensure there is a matching gcov data file. - if File.file?(gcno_filepath.gsub(".gcno", ".gcda")) - run_gcov("\"#{gcno_filepath}\"") - end - end - end - - if Dir.glob("*.gcov").length > 0 - # Build the command line arguments. - args = args_builder(opts) - - # Generate the report(s). - shell_result = run(args) - else - puts "\nWarning: No matching .gcno coverage files found." - end - - # Cleanup .gcov files. - for gcov_file in Dir.glob("*.gcov") - File.delete(gcov_file) - end - end - - if shell_result - shell_result[:time] = total_time - @reportinator_helper.print_shell_result(shell_result) - end - end - - - private - - # A dictionary of report types defined in this plugin to ReportGenerator report types. - REPORT_TYPE_TO_REPORT_GENERATOR_REPORT_NAME = { - ReportTypes::HTML_BASIC.upcase => "HtmlSummary", - ReportTypes::HTML_DETAILED.upcase => "Html", - ReportTypes::HTML_CHART.upcase => "HtmlChart", - ReportTypes::HTML_INLINE.upcase => "HtmlInline", - ReportTypes::HTML_INLINE_AZURE.upcase => "HtmlInline_AzurePipelines", - ReportTypes::HTML_INLINE_AZURE_DARK.upcase => "HtmlInline_AzurePipelines_Dark", - ReportTypes::MHTML.upcase => "MHtml", - ReportTypes::TEXT.upcase => "TextSummary", - ReportTypes::COBERTURA.upcase => "Cobertura", - ReportTypes::SONARQUBE.upcase => "SonarQube", - ReportTypes::BADGES.upcase => "Badges", - ReportTypes::CSV_SUMMARY.upcase => "CsvSummary", - ReportTypes::LATEX.upcase => "Latex", - ReportTypes::LATEX_SUMMARY.upcase => "LatexSummary", - ReportTypes::PNG_CHART.upcase => "PngChart", - ReportTypes::TEAM_CITY_SUMMARY.upcase => "TeamCitySummary", - ReportTypes::LCOV.upcase => "lcov", - ReportTypes::XML.upcase => "Xml", - ReportTypes::XML_SUMMARY.upcase => "XmlSummary", - } - - REPORT_GENERATOR_SETTING_PREFIX = "gcov_report_generator" - - # Deep clone the gcov tool config, so we can modify it locally if specified via options. - GCOV_TOOL_CONFIG = Marshal.load(Marshal.dump(TOOLS_GCOV_GCOV_POST_REPORT)) - - # Build the ReportGenerator arguments. - def args_builder(opts) - rg_opts = get_opts(opts) - report_type_count = 0 - - args = "" - args += "\"-reports:*.gcov\" " - args += "\"-targetdir:\"#{GCOV_REPORT_GENERATOR_PATH}\"\" " - - # Build the report types argument. - if !(opts.nil?) && !(opts[:gcov_reports].nil?) && !(opts[:gcov_reports].empty?) - args += "\"-reporttypes:" - - for report_type in opts[:gcov_reports] - rg_report_type = REPORT_TYPE_TO_REPORT_GENERATOR_REPORT_NAME[report_type.upcase] - if !(rg_report_type.nil?) - args += rg_report_type + ";" - report_type_count = report_type_count + 1 - end - end - - # Removing trailing ';' after the last report type. - args = args.chomp(";") - - # Append a space seperator after the report type. - args += "\" " - end - - # Build the source directories argument. - args += "\"-sourcedirs:.;" - if !(opts[:collection_paths_source].nil?) - args += opts[:collection_paths_source].join(';') - end - args = args.chomp(";") - args += "\" " - - args += "\"-historydir:#{rg_opts[:history_directory]}\" " unless rg_opts[:history_directory].nil? - args += "\"-plugins:#{rg_opts[:plugins]}\" " unless rg_opts[:plugins].nil? - args += "\"-assemblyfilters:#{rg_opts[:assembly_filters]}\" " unless rg_opts[:assembly_filters].nil? - args += "\"-classfilters:#{rg_opts[:class_filters]}\" " unless rg_opts[:class_filters].nil? - file_filters = rg_opts[:file_filters] || @ceedling[:tool_executor_helper].osify_path_separators(GCOV_REPORT_GENERATOR_FILE_FILTERS) - args += "\"-filefilters:#{file_filters}\" " - args += "\"-verbosity:#{rg_opts[:verbosity] || "Warning"}\" " - args += "\"-tag:#{rg_opts[:tag]}\" " unless rg_opts[:tag].nil? - args += "\"settings:createSubdirectoryForAllReportTypes=true\" " unless report_type_count <= 1 - args += "\"settings:numberOfReportsParsedInParallel=#{rg_opts[:num_parallel_threads]}\" " unless rg_opts[:num_parallel_threads].nil? - args += "\"settings:numberOfReportsMergedInParallel=#{rg_opts[:num_parallel_threads]}\" " unless rg_opts[:num_parallel_threads].nil? - - # Append custom arguments. - if !(rg_opts[:custom_args].nil?) && !(rg_opts[:custom_args].empty?) - for custom_arg in rg_opts[:custom_args] - args += "\"#{custom_arg}\" " unless custom_arg.nil? || custom_arg.empty? - end - end - - return args - end - - - # Get the ReportGenerator options from the project options. - def get_opts(opts) - return opts[REPORT_GENERATOR_SETTING_PREFIX.to_sym] || {} - end - - - # Run ReportGenerator with the given arguments. - def run(args) - command = @ceedling[:tool_executor].build_command_line(TOOLS_GCOV_REPORTGENERATOR_POST_REPORT, [], args) - return @ceedling[:tool_executor].exec(command[:line], command[:options]) - end - - - # Run gcov with the given arguments. - def run_gcov(args) - command = @ceedling[:tool_executor].build_command_line(GCOV_TOOL_CONFIG, [], args) - return @ceedling[:tool_executor].exec(command[:line], command[:options]) - end - -end diff --git a/vendor/ceedling/plugins/gcov/lib/reportinator_helper.rb b/vendor/ceedling/plugins/gcov/lib/reportinator_helper.rb deleted file mode 100644 index 92617fb..0000000 --- a/vendor/ceedling/plugins/gcov/lib/reportinator_helper.rb +++ /dev/null @@ -1,15 +0,0 @@ - -class ReportinatorHelper - - # Output the shell result to the console. - def print_shell_result(shell_result) - if !(shell_result.nil?) - puts "Done in %.3f seconds." % shell_result[:time] - - if !(shell_result[:output].nil?) && (shell_result[:output].length > 0) - puts shell_result[:output] - end - end - end - -end diff --git a/vendor/ceedling/plugins/json_tests_report/README.md b/vendor/ceedling/plugins/json_tests_report/README.md deleted file mode 100644 index 8e5a1e5..0000000 --- a/vendor/ceedling/plugins/json_tests_report/README.md +++ /dev/null @@ -1,36 +0,0 @@ -json_tests_report -================= - -## Overview - -The json_tests_report plugin creates a JSON file of test results, which is -handy for Continuous Integration build servers or as input into other -reporting tools. The JSON file is output to the appropriate -`<build_root>/artifacts/` directory (e.g. `artifacts/test/` for test tasks, -`artifacts/gcov/` for gcov, or `artifacts/bullseye/` for bullseye runs). - -## Setup - -Enable the plugin in your project.yml by adding `json_tests_report` to the list -of enabled plugins. - -``` YAML -:plugins: - :enabled: - - json_tests_report -``` - -## Configuration - -Optionally configure the output / artifact filename in your project.yml with -the `artifact_filename` configuration option. The default filename is -`report.json`. - -You can also configure the path that this artifact is stored. This can be done -by setting `path`. The default is that it will be placed in a subfolder under -the `build` directory. - -``` YAML -:json_tests_report: - :artifact_filename: report_spectuluarly.json -``` diff --git a/vendor/ceedling/plugins/json_tests_report/lib/json_tests_report.rb b/vendor/ceedling/plugins/json_tests_report/lib/json_tests_report.rb deleted file mode 100644 index e7023db..0000000 --- a/vendor/ceedling/plugins/json_tests_report/lib/json_tests_report.rb +++ /dev/null @@ -1,83 +0,0 @@ -require 'ceedling/plugin' -require 'ceedling/constants' -require 'json' - -class JsonTestsReport < Plugin - def setup - @results_list = {} - @test_counter = 0 - end - - def post_test_fixture_execute(arg_hash) - context = arg_hash[:context] - - @results_list[context] = [] if @results_list[context].nil? - - @results_list[context] << arg_hash[:result_file] - end - - def post_build - @results_list.each_key do |context| - results = @ceedling[:plugin_reportinator].assemble_test_results(@results_list[context]) - - artifact_filename = @ceedling[:configurator].project_config_hash[:json_tests_report_artifact_filename] || 'report.json' - artifact_fullpath = @ceedling[:configurator].project_config_hash[:json_tests_report_path] || File.join(PROJECT_BUILD_ARTIFACTS_ROOT, context.to_s) - file_path = File.join(artifact_fullpath, artifact_filename) - - @ceedling[:file_wrapper].open(file_path, 'w') do |f| - @test_counter = 1 - - json = { - "FailedTests" => write_failures(results[:failures]), - "PassedTests" => write_tests(results[:successes]), - "IgnoredTests" => write_tests(results[:ignores]), - "Summary" => write_statistics(results[:counts]) - } - - f << JSON.pretty_generate(json) - end - end - end - - private - - def write_failures(results) - retval = [] - results.each do |result| - result[:collection].each do |item| - @test_counter += 1 - retval << { - "file" => File.join(result[:source][:path], result[:source][:file]), - "test" => item[:test], - "line" => item[:line], - "message" => item[:message] - } - end - end - return retval.uniq - end - - def write_tests(results) - retval = [] - results.each do |result| - result[:collection].each do |item| - @test_counter += 1 - retval << { - "file" => File.join(result[:source][:path], result[:source][:file]), - "test" => item[:test] - } - end - end - return retval - end - - def write_statistics(counts) - return { - "total_tests" => counts[:total], - "passed" => (counts[:total] - counts[:ignored] - counts[:failed]), - "ignored" => counts[:ignored], - "failures" => counts[:failed] - } - end - -end diff --git a/vendor/ceedling/plugins/junit_tests_report/README.md b/vendor/ceedling/plugins/junit_tests_report/README.md deleted file mode 100644 index 1259fd6..0000000 --- a/vendor/ceedling/plugins/junit_tests_report/README.md +++ /dev/null @@ -1,36 +0,0 @@ -junit_tests_report -==================== - -## Overview - -The junit_tests_report plugin creates an XML file of test results in JUnit -format, which is handy for Continuous Integration build servers or as input -into other reporting tools. The XML file is output to the appropriate -`<build_root>/artifacts/` directory (e.g. `artifacts/test/` for test tasks, -`artifacts/gcov/` for gcov, or `artifacts/bullseye/` for bullseye runs). - -## Setup - -Enable the plugin in your project.yml by adding `junit_tests_report` -to the list of enabled plugins. - -``` YAML -:plugins: - :enabled: - - junit_tests_report -``` - -## Configuration - -Optionally configure the output / artifact filename in your project.yml with -the `artifact_filename` configuration option. The default filename is -`report.xml`. - -You can also configure the path that this artifact is stored. This can be done -by setting `path`. The default is that it will be placed in a subfolder under -the `build` directory. - -``` YAML -:junit_tests_report: - :artifact_filename: report_junit.xml -``` diff --git a/vendor/ceedling/plugins/junit_tests_report/lib/junit_tests_report.rb b/vendor/ceedling/plugins/junit_tests_report/lib/junit_tests_report.rb deleted file mode 100644 index 3104393..0000000 --- a/vendor/ceedling/plugins/junit_tests_report/lib/junit_tests_report.rb +++ /dev/null @@ -1,134 +0,0 @@ -require 'ceedling/plugin' -require 'ceedling/constants' - -class JunitTestsReport < Plugin - - def setup - @results_list = {} - @test_counter = 0 - @time_result = [] - end - - def post_test_fixture_execute(arg_hash) - context = arg_hash[:context] - - @results_list[context] = [] if (@results_list[context].nil?) - - @results_list[context] << arg_hash[:result_file] - @time_result << arg_hash[:shell_result][:time] - - end - - def post_build - @results_list.each_key do |context| - results = @ceedling[:plugin_reportinator].assemble_test_results(@results_list[context]) - - artifact_filename = @ceedling[:configurator].project_config_hash[:junit_tests_report_artifact_filename] || 'report.xml' - artifact_fullpath = @ceedling[:configurator].project_config_hash[:junit_tests_report_path] || File.join(PROJECT_BUILD_ARTIFACTS_ROOT, context.to_s) - file_path = File.join(artifact_fullpath, artifact_filename) - - @ceedling[:file_wrapper].open( file_path, 'w' ) do |f| - @testsuite_counter = 0 - @testcase_counter = 0 - suites = reorganise_results( results ) - - write_header( results, f ) - suites.each{|suite| write_suite( suite, f ) } - write_footer( f ) - end - end - end - - private - - def write_header( results, stream ) - results[:counts][:time] = @time_result.reduce(0, :+) - stream.puts '<?xml version="1.0" encoding="utf-8" ?>' - stream.puts('<testsuites tests="%<total>d" failures="%<failed>d" time="%<time>.3f">' % results[:counts]) - end - - def write_footer( stream ) - stream.puts '</testsuites>' - end - - def reorganise_results( results ) - # Reorganise the output by test suite instead of by result - suites = Hash.new{ |h,k| h[k] = {collection: [], total: 0, success: 0, failed: 0, ignored: 0, errors: 0, stdout: []} } - results[:successes].each do |result| - source = result[:source] - name = source[:file].sub(/\..{1,4}$/, "") - suites[name][:collection] += result[:collection].map{|test| test.merge(result: :success)} - suites[name][:total] += result[:collection].length - suites[name][:success] += result[:collection].length - end - results[:failures].each do |result| - source = result[:source] - name = source[:file].sub(/\..{1,4}$/, "") - suites[name][:collection] += result[:collection].map{|test| test.merge(result: :failed)} - suites[name][:total] += result[:collection].length - suites[name][:failed] += result[:collection].length - end - results[:ignores].each do |result| - source = result[:source] - name = source[:file].sub(/\..{1,4}$/, "") - suites[name][:collection] += result[:collection].map{|test| test.merge(result: :ignored)} - suites[name][:total] += result[:collection].length - suites[name][:ignored] += result[:collection].length - end - results[:stdout].each do |result| - source = result[:source] - name = source[:file].sub(/\..{1,4}$/, "") - suites[name][:stdout] += result[:collection] - end - suites.map{|name, data| data.merge(name: name) } - end - - def write_suite( suite, stream ) - suite[:time] = @time_result.shift - stream.puts(' <testsuite name="%<name>s" tests="%<total>d" failures="%<failed>d" skipped="%<ignored>d" errors="%<errors>d" time="%<time>.3f">' % suite) - - suite[:collection].each do |test| - write_test( test, stream ) - end - - unless suite[:stdout].empty? - stream.puts(' <system-out>') - suite[:stdout].each do |line| - line.gsub!(/&/, '&') - line.gsub!(/</, '<') - line.gsub!(/>/, '>') - line.gsub!(/"/, '"') - line.gsub!(/'/, ''') - stream.puts(line) - end - stream.puts(' </system-out>') - end - - stream.puts(' </testsuite>') - end - - def write_test( test, stream ) - test[:test].gsub!(/&/, '&') - test[:test].gsub!(/</, '<') - test[:test].gsub!(/>/, '>') - test[:test].gsub!(/"/, '"') - test[:test].gsub!(/'/, ''') - - case test[:result] - when :success - stream.puts(' <testcase name="%<test>s" time="%<unity_test_time>.3f"/>' % test) - when :failed - stream.puts(' <testcase name="%<test>s" time="%<unity_test_time>.3f">' % test) - if test[:message].empty? - stream.puts(' <failure />') - else - stream.puts(' <failure message="%s" />' % test[:message]) - end - stream.puts(' </testcase>') - when :ignored - stream.puts(' <testcase name="%<test>s" time="%<unity_test_time>.3f">' % test) - stream.puts(' <skipped />') - stream.puts(' </testcase>') - end - end -end diff --git a/vendor/ceedling/plugins/module_generator/README.md b/vendor/ceedling/plugins/module_generator/README.md deleted file mode 100644 index a3c2c7a..0000000 --- a/vendor/ceedling/plugins/module_generator/README.md +++ /dev/null @@ -1,119 +0,0 @@ -ceedling-module-generator -========================= - -## Overview - -The module_generator plugin adds a pair of new commands to Ceedling, allowing -you to make or remove modules according to predefined templates. WIth a single call, -Ceedling can generate a source, header, and test file for a new module. If given a -pattern, it can even create a series of submodules to support specific design patterns. -Finally, it can just as easily remove related modules, avoiding the need to delete -each individually. - -Let's say, for example, that you want to create a single module named `MadScience`. - -``` -ceedling module:create[MadScience] -``` - -It says we're speaking to the module plugin, and we want to create a new module. The -name of that module is between the brackets. It will keep this case, unless you have -specified a different default (see configuration). It will create three files: -`MadScience.c`, `MadScience.h`, and `TestMadScience.c`. *NOTE* that it is important that -there are no spaces between the brackets. We know, it's annoying... but it's the rules. - -You can also create an entire pattern of files. To do that, just add a second argument -to the pattern ID. Something like this: - -``` -ceedling module:create[SecretLair,mch] -``` - -In this example, we'd create 9 files total: 3 headers, 3 source files, and 3 test files. These -files would be named `SecretLairModel`, `SecretLairConductor`, and `SecretLairHardware`. Isn't -that nice? - -Similarly, you can create stubs for all functions in a header file just by making a single call -to your handy `stub` feature, like this: - -``` -ceedling module:stub[SecretLair] -``` - -This call will look in SecretLair.h and will generate a file SecretLair.c that contains a stub -for each function declared in the header! Even better, if SecretLair.c already exists, it will -add only new functions, leaving your existing calls alone so that it doesn't cause any problems. - -## Configuration - -Enable the plugin in your project.yml by adding `module_generator` -to the list of enabled plugins. - -Then, like much of Ceedling, you can just run as-is with the defaults, or you can override those -defaults for your own needs. For example, new source and header files will be automatically -placed in the `src/` folder while tests will go in the `test/` folder. That's great if your project -follows the default ceedling structure... but what if you have a different structure? - -``` -:module_generator: - :project_root: ./ - :source_root: source/ - :inc_root: includes/ - :test_root: tests/ -``` - -Now I've redirected the location where modules are going to be generated. - -### Includes - -You can make it so that all of your files are generated with a standard include list. This is done -by adding to the `:includes` array. For example: - -``` -:module_generator: - :includes: - :tst: - - defs.h - - board.h - :src: - - board.h -``` - -### Boilerplates - -You can specify the actual boilerplate used for each of your files. This is the handy place to -put that corporate copyright notice (or maybe a copyleft notice, if that's your perference?) - -``` -:module_generator: - :boilerplates: | - /*************************** - * This file is Awesome. * - * That is All. * - ***************************/ -``` - -### Test Defines - -You can specify the "#ifdef TEST" at the top of the test files with a custom define. -This example will put a "#ifdef CEEDLING_TEST" at the top of the test files. - -``` -:module_generator: - :test_define: CEEDLING_TEST -``` - -### Naming Convention - -Finally, you can force a particular naming convention. Even if someone calls the generator -with something like `MyNewModule`, if they have the naming convention set to `:caps`, it will -generate files like `MY_NEW_MODULE.c`. This keeps everyone on your team behaving the same way. - -Your options are as follows: - - - `:bumpy` - BumpyFilesLooksLikeSo - - `:camel` - camelFilesAreSimilarButStartLow - - `:snake` - snake_case_is_all_lower_and_uses_underscores - - `:caps` - CAPS_FEELS_LIKE_YOU_ARE_SCREAMING - - diff --git a/vendor/ceedling/plugins/module_generator/config/module_generator.yml b/vendor/ceedling/plugins/module_generator/config/module_generator.yml deleted file mode 100644 index cdb2da2..0000000 --- a/vendor/ceedling/plugins/module_generator/config/module_generator.yml +++ /dev/null @@ -1,4 +0,0 @@ -:module_generator: - :project_root: ./ - :source_root: src/ - :test_root: test/ \ No newline at end of file diff --git a/vendor/ceedling/plugins/module_generator/lib/module_generator.rb b/vendor/ceedling/plugins/module_generator/lib/module_generator.rb deleted file mode 100644 index d14288c..0000000 --- a/vendor/ceedling/plugins/module_generator/lib/module_generator.rb +++ /dev/null @@ -1,80 +0,0 @@ -require 'ceedling/plugin' -require 'ceedling/constants' -require 'erb' -require 'fileutils' - -class ModuleGenerator < Plugin - - attr_reader :config - - def create(module_name, optz={}) - - require "generate_module.rb" #From Unity Scripts - - if ((!optz.nil?) && (optz[:destroy])) - UnityModuleGenerator.new( divine_options(optz) ).destroy(module_name) - else - UnityModuleGenerator.new( divine_options(optz) ).generate(module_name) - end - end - - def stub_from_header(module_name, optz={}) - require "cmock.rb" #From CMock - stuboptz = divine_options(optz) - pathname = optz[:path_inc] || optz[:path_src] || "src" - filename = File.expand_path(optz[:module_root_path], File.join(pathname, module_name + ".h")) - CMock.new(stuboptz).setup_skeletons(filename) - end - - private - - def divine_options(optz={}) - unity_generator_options = - { - :path_src => ((defined? MODULE_GENERATOR_SOURCE_ROOT ) ? MODULE_GENERATOR_SOURCE_ROOT.gsub('\\', '/').sub(/^\//, '').sub(/\/$/, '') : "src" ), - :path_inc => ((defined? MODULE_GENERATOR_INC_ROOT ) ? - MODULE_GENERATOR_INC_ROOT.gsub('\\', '/').sub(/^\//, '').sub(/\/$/, '') - : (defined? MODULE_GENERATOR_SOURCE_ROOT ) ? - MODULE_GENERATOR_SOURCE_ROOT.gsub('\\', '/').sub(/^\//, '').sub(/\/$/, '') - : "src" ), - :path_tst => ((defined? MODULE_GENERATOR_TEST_ROOT ) ? MODULE_GENERATOR_TEST_ROOT.gsub( '\\', '/').sub(/^\//, '').sub(/\/$/, '') : "test" ), - :pattern => optz[:pattern], - :test_prefix => ((defined? PROJECT_TEST_FILE_PREFIX ) ? PROJECT_TEST_FILE_PREFIX : "Test" ), - :mock_prefix => ((defined? CMOCK_MOCK_PREFIX ) ? CMOCK_MOCK_PREFIX : "Mock" ), - :includes => ((defined? MODULE_GENERATOR_INCLUDES ) ? MODULE_GENERATOR_INCLUDES : {} ), - :boilerplates => ((defined? MODULE_GENERATOR_BOILERPLATES) ? MODULE_GENERATOR_BOILERPLATES : {} ), - :naming => ((defined? MODULE_GENERATOR_NAMING ) ? MODULE_GENERATOR_NAMING : nil ), - :update_svn => ((defined? MODULE_GENERATOR_UPDATE_SVN ) ? MODULE_GENERATOR_UPDATE_SVN : false ), - :skeleton_path=> ((defined? MODULE_GENERATOR_SOURCE_ROOT ) ? MODULE_GENERATOR_SOURCE_ROOT.gsub('\\', '/').sub(/^\//, '').sub(/\/$/, '') : "src" ), - :test_define => ((defined? MODULE_GENERATOR_TEST_DEFINE ) ? MODULE_GENERATOR_TEST_DEFINE : "TEST" ), - } - - # Read Boilerplate template file. - if (defined? MODULE_GENERATOR_BOILERPLATE_FILES) - - bf = MODULE_GENERATOR_BOILERPLATE_FILES - - if !bf[:src].nil? && File.exists?(bf[:src]) - unity_generator_options[:boilerplates][:src] = File.read(bf[:src]) - end - - if !bf[:inc].nil? && File.exists?(bf[:inc]) - unity_generator_options[:boilerplates][:inc] = File.read(bf[:inc]) - end - - if !bf[:tst].nil? && File.exists?(bf[:tst]) - unity_generator_options[:boilerplates][:tst] = File.read(bf[:tst]) - end - end - - # If using "create[<module_root>:<module_name>]" option from command line. - unless optz[:module_root_path].to_s.empty? - unity_generator_options[:path_src] = File.join(optz[:module_root_path], unity_generator_options[:path_src]) - unity_generator_options[:path_inc] = File.join(optz[:module_root_path], unity_generator_options[:path_inc]) - unity_generator_options[:path_tst] = File.join(optz[:module_root_path], unity_generator_options[:path_tst]) - end - - return unity_generator_options - end - -end diff --git a/vendor/ceedling/plugins/module_generator/module_generator.rake b/vendor/ceedling/plugins/module_generator/module_generator.rake deleted file mode 100644 index f4ed9f1..0000000 --- a/vendor/ceedling/plugins/module_generator/module_generator.rake +++ /dev/null @@ -1,62 +0,0 @@ - -namespace :module do - module_root_separator = ":" - - desc "Generate module (source, header and test files)" - task :create, :module_path do |t, args| - files = [args[:module_path]] + (args.extras || []) - optz = { :module_root_path => "" } - ["dh", "dih", "mch", "mvp", "src", "test"].each do |pat| - p = files.delete(pat) - optz[:pattern] = p unless p.nil? - end - files.each do |v| - module_root_path, module_name = v.split(module_root_separator, 2) - if module_name - optz[:module_root_path] = module_root_path - v = module_name - end - if (v =~ /^test_?/i) - # If the name of the file starts with test, automatically treat it as one - @ceedling[:module_generator].create(v.sub(/^test_?/i,''), optz.merge({:pattern => 'test'})) - else - # Otherwise, go through the normal procedure - @ceedling[:module_generator].create(v, optz) - end - end - end - - desc "Generate module stubs from header" - task :stub, :module_path do |t, args| - files = [args[:module_path]] + (args.extras || []) - optz = { :module_root_path => "" } - files.each do |v| - module_root_path, module_name = v.split(module_root_separator, 2) - if module_name - optz[:module_root_path] = module_root_path - v = module_name - end - # Otherwise, go through the normal procedure - @ceedling[:module_generator].stub_from_header(v, optz) - end - end - - desc "Destroy module (source, header and test files)" - task :destroy, :module_path do |t, args| - files = [args[:module_path]] + (args.extras || []) - optz = { :destroy => true, :module_root_path => "" } - ["dh", "dih", "mch", "mvp", "src", "test"].each do |pat| - p = files.delete(pat) - optz[:pattern] = p unless p.nil? - end - files.each do |v| - module_root_path, module_name = v.split(module_root_separator, 2) - if module_name - optz[:module_root_path] = module_root_path - v = module_name - end - @ceedling[:module_generator].create(v, optz) - end - end - -end diff --git a/vendor/ceedling/plugins/raw_output_report/README.md b/vendor/ceedling/plugins/raw_output_report/README.md deleted file mode 100644 index 330e87d..0000000 --- a/vendor/ceedling/plugins/raw_output_report/README.md +++ /dev/null @@ -1,19 +0,0 @@ -ceedling-raw-output-report -========================== - -## Overview - -The raw-output-report allows you to capture all the output from the called -tools in a single document, so you can trace back through it later. This is -useful for debugging... but can eat through memory quickly if left running. - -## Setup - -Enable the plugin in your project.yml by adding `raw_output_report` -to the list of enabled plugins. - -``` YAML -:plugins: - :enabled: - - raw_output_report -``` diff --git a/vendor/ceedling/plugins/raw_output_report/lib/raw_output_report.rb b/vendor/ceedling/plugins/raw_output_report/lib/raw_output_report.rb deleted file mode 100644 index 014e677..0000000 --- a/vendor/ceedling/plugins/raw_output_report/lib/raw_output_report.rb +++ /dev/null @@ -1,41 +0,0 @@ -require 'ceedling/plugin' -require 'ceedling/constants' - -class RawOutputReport < Plugin - def setup - @log_paths = {} - end - - def post_test_fixture_execute(arg_hash) - output = strip_output(arg_hash[:shell_result][:output]) - write_raw_output_log(arg_hash, output) - end - - private - - def strip_output(raw_output) - output = "" - raw_output.each_line do |line| - next if line =~ /^\n$/ - next if line =~ /^.*:\d+:.*:(IGNORE|PASS|FAIL)/ - return output if line =~/^-----------------------\n$/ - output << line - end - end - def write_raw_output_log(arg_hash, output) - logging = generate_log_path(arg_hash) - @ceedling[:file_wrapper].write(logging[:path], output , logging[:flags]) unless logging.nil? - end - - def generate_log_path(arg_hash) - f_name = File.basename(arg_hash[:result_file], '.pass') - base_path = File.join(PROJECT_BUILD_ARTIFACTS_ROOT, arg_hash[:context].to_s) - file_path = File.join(base_path, f_name + '.log') - - if @ceedling[:file_wrapper].exist?(base_path) - return { path: file_path, flags: 'w' } - end - - nil - end -end diff --git a/vendor/ceedling/plugins/stdout_gtestlike_tests_report/README.md b/vendor/ceedling/plugins/stdout_gtestlike_tests_report/README.md deleted file mode 100644 index 9ab6084..0000000 --- a/vendor/ceedling/plugins/stdout_gtestlike_tests_report/README.md +++ /dev/null @@ -1,19 +0,0 @@ -ceedling-stdout-gtestlike-tests-report -====================== - -## Overview - -The stdout_gtestlike_tests_report replaces the normal ceedling "pretty" output with -a variant that resembles the output of gtest. This is most helpful when trying to -integrate into an IDE or CI that is meant to work with google test. - -## Setup - -Enable the plugin in your project.yml by adding `stdout_gtestlike_tests_report` -to the list of enabled plugins. - -``` YAML -:plugins: - :enabled: - - stdout_gtestlike_tests_report -``` diff --git a/vendor/ceedling/plugins/stdout_gtestlike_tests_report/assets/template.erb b/vendor/ceedling/plugins/stdout_gtestlike_tests_report/assets/template.erb deleted file mode 100644 index fb8e3b1..0000000 --- a/vendor/ceedling/plugins/stdout_gtestlike_tests_report/assets/template.erb +++ /dev/null @@ -1,84 +0,0 @@ -% ignored = hash[:results][:counts][:ignored] -% failed = hash[:results][:counts][:failed] -% stdout_count = hash[:results][:counts][:stdout] -% header_prepend = ((hash[:header].length > 0) ? "#{hash[:header]}: " : '') -% banner_width = 25 + header_prepend.length # widest message -% results = {} -% hash[:results][:successes].each do |testresult| -% results[ testresult[:source][:file] ] = testresult[:collection] -% results[ testresult[:source][:file] ].length.times do |i| -% results[ testresult[:source][:file] ][i][:pass] = true -% end -% end -% hash[:results][:ignores].each do |testresult| -% if (results[ testresult[:source][:file] ].nil?) -% results[ testresult[:source][:file] ] = testresult[:collection] -% else -% results[ testresult[:source][:file] ] += testresult[:collection] -% end -% results[ testresult[:source][:file] ].length.times do |i| -% results[ testresult[:source][:file] ][i][:pass] = true -% end -% end -% hash[:results][:failures].each do |testresult| -% if (results[ testresult[:source][:file] ].nil?) -% results[ testresult[:source][:file] ] = testresult[:collection] -% else -% results[ testresult[:source][:file] ] += testresult[:collection] -% end -% end - - -[==========] Running <%=hash[:results][:counts][:total].to_s%> tests from <%=results.length.to_s%> test cases. -[----------] Global test environment set-up. -% results.each_pair do |modulename, moduledetails| -[----------] <%=moduledetails.length.to_s%> tests from <%=modulename%> -% moduledetails.each do |item| -[ RUN ] <%=modulename%>.<%=item[:test]%> -% if (not item[:pass]) -% if (not item[:message].empty?) -<%=modulename%>(<%=item[:line]%>): error: <%=item[:message]%> - -% m = item[:message].match(/Expected\s+(.*)\s+Was\s+([^\.]*)\./) -% if m.nil? - Actual: FALSE - Expected: TRUE -% else - Actual: <%=m[2]%> - Expected: <%=m[1]%> -% end -% else -<%=modulename%>(<%=item[:line]%>): fail: <%=item[:message]%> - Actual: FALSE - Expected: TRUE -% end -[ FAILED ] <%=modulename%>.<%=item[:test]%> (0 ms) -% else -[ OK ] <%=modulename%>.<%=item[:test]%> (0 ms) -% end -% end -[----------] <%=moduledetails.length.to_s%> tests from <%=modulename%> (0 ms total) -% end - -% if (hash[:results][:counts][:total] > 0) -[----------] Global test environment tear-down. -[==========] <%=hash[:results][:counts][:total].to_s%> tests from <%=hash[:results][:stdout].length.to_s%> test cases ran. -[ PASSED ] <%=hash[:results][:counts][:passed].to_s%> tests. -% if (failed == 0) -[ FAILED ] 0 tests. - - 0 FAILED TESTS -% else -[ FAILED ] <%=failed.to_s%> tests, listed below: -% hash[:results][:failures].each do |failure| -% failure[:collection].each do |item| -[ FAILED ] <%=failure[:source][:file]%>.<%=item[:test]%> -% end -% end -% end - - <%=failed.to_s%> FAILED TESTS -% else - -No tests executed. -% end diff --git a/vendor/ceedling/plugins/stdout_gtestlike_tests_report/assets/template.erb copy b/vendor/ceedling/plugins/stdout_gtestlike_tests_report/assets/template.erb copy deleted file mode 100644 index a90f495..0000000 --- a/vendor/ceedling/plugins/stdout_gtestlike_tests_report/assets/template.erb copy +++ /dev/null @@ -1,59 +0,0 @@ -% ignored = hash[:results][:counts][:ignored] -% failed = hash[:results][:counts][:failed] -% stdout_count = hash[:results][:counts][:stdout] -% header_prepend = ((hash[:header].length > 0) ? "#{hash[:header]}: " : '') -% banner_width = 25 + header_prepend.length # widest message - - -% if (stdout_count > 0) -[==========] Running <%=hash[:results][:counts][:total].to_s%> tests from <%=hash[:results][:stdout].length.to_s%> test cases. -[----------] Global test environment set-up. -% end -% if (failed > 0) -% hash[:results][:failures].each do |failure| -[----------] <%=failure[:collection].length.to_s%> tests from <%=failure[:source][:file]%> -% failure[:collection].each do |item| -[ RUN ] <%=failure[:source][:file]%>.<%=item[:test]%> -% if (not item[:message].empty?) -<%=failure[:source][:file]%>(<%=item[:line]%>): error: <%=item[:message]%> - -% m = item[:message].match(/Expected\s+(.*)\s+Was\s+([^\.]*)\./) -% if m.nil? - Actual: FALSE - Expected: TRUE -% else - Actual: <%=m[2]%> - Expected: <%=m[1]%> -% end -% else -<%=failure[:source][:file]%>(<%=item[:line]%>): fail: <%=item[:message]%> - Actual: FALSE - Expected: TRUE -% end -[ FAILED ] <%=failure[:source][:file]%>.<%=item[:test]%> (0 ms) -% end -[----------] <%=failure[:collection].length.to_s%> tests from <%=failure[:source][:file]%> (0 ms total) -% end -% end -% if (hash[:results][:counts][:total] > 0) -[----------] Global test environment tear-down. -[==========] <%=hash[:results][:counts][:total].to_s%> tests from <%=hash[:results][:stdout].length.to_s%> test cases ran. -[ PASSED ] <%=hash[:results][:counts][:passed].to_s%> tests. -% if (failed == 0) -[ FAILED ] 0 tests. - - 0 FAILED TESTS -% else -[ FAILED ] <%=failed.to_s%> tests, listed below: -% hash[:results][:failures].each do |failure| -% failure[:collection].each do |item| -[ FAILED ] <%=failure[:source][:file]%>.<%=item[:test]%> -% end -% end - - <%=failed.to_s%> FAILED TESTS -% end -% else - -No tests executed. -% end diff --git a/vendor/ceedling/plugins/stdout_gtestlike_tests_report/config/stdout_gtestlike_tests_report.yml b/vendor/ceedling/plugins/stdout_gtestlike_tests_report/config/stdout_gtestlike_tests_report.yml deleted file mode 100644 index c25acf5..0000000 --- a/vendor/ceedling/plugins/stdout_gtestlike_tests_report/config/stdout_gtestlike_tests_report.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -:plugins: - # tell Ceedling we got results display taken care of - :display_raw_test_results: FALSE diff --git a/vendor/ceedling/plugins/stdout_gtestlike_tests_report/lib/stdout_gtestlike_tests_report.rb b/vendor/ceedling/plugins/stdout_gtestlike_tests_report/lib/stdout_gtestlike_tests_report.rb deleted file mode 100644 index a51438a..0000000 --- a/vendor/ceedling/plugins/stdout_gtestlike_tests_report/lib/stdout_gtestlike_tests_report.rb +++ /dev/null @@ -1,43 +0,0 @@ -require 'ceedling/plugin' -require 'ceedling/defaults' - -class StdoutGtestlikeTestsReport < Plugin - - def setup - @result_list = [] - @plugin_root = File.expand_path(File.join(File.dirname(__FILE__), '..')) - template = @ceedling[:file_wrapper].read(File.join(@plugin_root, 'assets/template.erb')) - @ceedling[:plugin_reportinator].register_test_results_template( template ) - end - - def post_test_fixture_execute(arg_hash) - return if not (arg_hash[:context] == TEST_SYM) - - @result_list << arg_hash[:result_file] - end - - def post_build - return if not (@ceedling[:task_invoker].test_invoked?) - - results = @ceedling[:plugin_reportinator].assemble_test_results(@result_list) - hash = { - :header => '', - :results => results - } - - @ceedling[:plugin_reportinator].run_test_results_report(hash) - end - - def summary - result_list = @ceedling[:file_path_utils].form_pass_results_filelist( PROJECT_TEST_RESULTS_PATH, COLLECTION_ALL_TESTS ) - - # get test results for only those tests in our configuration and of those only tests with results on disk - hash = { - :header => '', - :results => @ceedling[:plugin_reportinator].assemble_test_results(result_list, {:boom => false}) - } - - @ceedling[:plugin_reportinator].run_test_results_report(hash) - end - -end diff --git a/vendor/ceedling/plugins/stdout_ide_tests_report/README.md b/vendor/ceedling/plugins/stdout_ide_tests_report/README.md deleted file mode 100644 index ed6c655..0000000 --- a/vendor/ceedling/plugins/stdout_ide_tests_report/README.md +++ /dev/null @@ -1,18 +0,0 @@ -ceedling-stdout-ide-tests-report -================================ - -## Overview - -The stdout_ide_tests_report replaces the normal ceedling "pretty" output with -a simplified variant intended to be easily parseable. - -## Setup - -Enable the plugin in your project.yml by adding `stdout_ide_tests_report` -to the list of enabled plugins. - -``` YAML -:plugins: - :enabled: - - stdout_ide_tests_report -``` diff --git a/vendor/ceedling/plugins/stdout_ide_tests_report/config/stdout_ide_tests_report.yml b/vendor/ceedling/plugins/stdout_ide_tests_report/config/stdout_ide_tests_report.yml deleted file mode 100644 index c25acf5..0000000 --- a/vendor/ceedling/plugins/stdout_ide_tests_report/config/stdout_ide_tests_report.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -:plugins: - # tell Ceedling we got results display taken care of - :display_raw_test_results: FALSE diff --git a/vendor/ceedling/plugins/stdout_ide_tests_report/lib/stdout_ide_tests_report.rb b/vendor/ceedling/plugins/stdout_ide_tests_report/lib/stdout_ide_tests_report.rb deleted file mode 100644 index 48b3e81..0000000 --- a/vendor/ceedling/plugins/stdout_ide_tests_report/lib/stdout_ide_tests_report.rb +++ /dev/null @@ -1,44 +0,0 @@ -require 'ceedling/plugin' -require 'ceedling/defaults' - -class StdoutIdeTestsReport < Plugin - - def setup - @result_list = [] - end - - def post_test_fixture_execute(arg_hash) - return if not (arg_hash[:context] == TEST_SYM) - - @result_list << arg_hash[:result_file] - end - - def post_build - return if (not @ceedling[:task_invoker].test_invoked?) - - results = @ceedling[:plugin_reportinator].assemble_test_results(@result_list) - hash = { - :header => '', - :results => results - } - - @ceedling[:plugin_reportinator].run_test_results_report(hash) do - message = '' - message = 'Unit test failures.' if (hash[:results][:counts][:failed] > 0) - message - end - end - - def summary - result_list = @ceedling[:file_path_utils].form_pass_results_filelist( PROJECT_TEST_RESULTS_PATH, COLLECTION_ALL_TESTS ) - - # get test results for only those tests in our configuration and of those only tests with results on disk - hash = { - :header => '', - :results => @ceedling[:plugin_reportinator].assemble_test_results(result_list, {:boom => false}) - } - - @ceedling[:plugin_reportinator].run_test_results_report(hash) - end - -end diff --git a/vendor/ceedling/plugins/stdout_pretty_tests_report/README.md b/vendor/ceedling/plugins/stdout_pretty_tests_report/README.md deleted file mode 100644 index 7e1be23..0000000 --- a/vendor/ceedling/plugins/stdout_pretty_tests_report/README.md +++ /dev/null @@ -1,20 +0,0 @@ -ceedling-pretty-tests-report -============================ - -## Overview - -The stdout_pretty_tests_report is the default output of ceedling. Instead of -showing most of the raw output of CMock, Ceedling, etc., it shows a simplified -view. It also creates a nice summary at the end of execution which groups the -results into ignored and failed tests. - -## Setup - -Enable the plugin in your project.yml by adding `stdout_pretty_tests_report` -to the list of enabled plugins. - -``` YAML -:plugins: - :enabled: - - stdout_pretty_tests_report -``` diff --git a/vendor/ceedling/plugins/stdout_pretty_tests_report/assets/template.erb b/vendor/ceedling/plugins/stdout_pretty_tests_report/assets/template.erb deleted file mode 100644 index 52b29f7..0000000 --- a/vendor/ceedling/plugins/stdout_pretty_tests_report/assets/template.erb +++ /dev/null @@ -1,59 +0,0 @@ -% ignored = hash[:results][:counts][:ignored] -% failed = hash[:results][:counts][:failed] -% stdout_count = hash[:results][:counts][:stdout] -% header_prepend = ((hash[:header].length > 0) ? "#{hash[:header]}: " : '') -% banner_width = 25 + header_prepend.length # widest message - -% if (stdout_count > 0) -<%=@ceedling[:plugin_reportinator].generate_banner(header_prepend + 'TEST OUTPUT')%> -% hash[:results][:stdout].each do |string| -[<%=string[:source][:file]%>] -% string[:collection].each do |item| - - "<%=item%>" -% end - -% end -% end -% if (ignored > 0) -<%=@ceedling[:plugin_reportinator].generate_banner(header_prepend + 'IGNORED TEST SUMMARY')%> -% hash[:results][:ignores].each do |ignore| -[<%=ignore[:source][:file]%>] -% ignore[:collection].each do |item| - Test: <%=item[:test]%> -% if (not item[:message].empty?) - At line (<%=item[:line]%>): "<%=item[:message]%>" -% else - At line (<%=item[:line]%>) -% end - -% end -% end -% end -% if (failed > 0) -<%=@ceedling[:plugin_reportinator].generate_banner(header_prepend + 'FAILED TEST SUMMARY')%> -% hash[:results][:failures].each do |failure| -[<%=failure[:source][:file]%>] -% failure[:collection].each do |item| - Test: <%=item[:test]%> -% if (not item[:message].empty?) - At line (<%=item[:line]%>): "<%=item[:message]%>" -% else - At line (<%=item[:line]%>) -% end - -% end -% end -% end -% total_string = hash[:results][:counts][:total].to_s -% format_string = "%#{total_string.length}i" -<%=@ceedling[:plugin_reportinator].generate_banner(header_prepend + 'OVERALL TEST SUMMARY')%> -% if (hash[:results][:counts][:total] > 0) -TESTED: <%=hash[:results][:counts][:total].to_s%> -PASSED: <%=sprintf(format_string, hash[:results][:counts][:passed])%> -FAILED: <%=sprintf(format_string, failed)%> -IGNORED: <%=sprintf(format_string, ignored)%> -% else - -No tests executed. -% end - diff --git a/vendor/ceedling/plugins/stdout_pretty_tests_report/config/stdout_pretty_tests_report.yml b/vendor/ceedling/plugins/stdout_pretty_tests_report/config/stdout_pretty_tests_report.yml deleted file mode 100644 index c25acf5..0000000 --- a/vendor/ceedling/plugins/stdout_pretty_tests_report/config/stdout_pretty_tests_report.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -:plugins: - # tell Ceedling we got results display taken care of - :display_raw_test_results: FALSE diff --git a/vendor/ceedling/plugins/stdout_pretty_tests_report/lib/stdout_pretty_tests_report.rb b/vendor/ceedling/plugins/stdout_pretty_tests_report/lib/stdout_pretty_tests_report.rb deleted file mode 100644 index 018388f..0000000 --- a/vendor/ceedling/plugins/stdout_pretty_tests_report/lib/stdout_pretty_tests_report.rb +++ /dev/null @@ -1,47 +0,0 @@ -require 'ceedling/plugin' -require 'ceedling/defaults' - -class StdoutPrettyTestsReport < Plugin - - def setup - @result_list = [] - @plugin_root = File.expand_path(File.join(File.dirname(__FILE__), '..')) - template = @ceedling[:file_wrapper].read(File.join(@plugin_root, 'assets/template.erb')) - @ceedling[:plugin_reportinator].register_test_results_template( template ) - end - - def post_test_fixture_execute(arg_hash) - return if not (arg_hash[:context] == TEST_SYM) - - @result_list << arg_hash[:result_file] - end - - def post_build - return if not (@ceedling[:task_invoker].test_invoked?) - - results = @ceedling[:plugin_reportinator].assemble_test_results(@result_list) - hash = { - :header => '', - :results => results - } - - @ceedling[:plugin_reportinator].run_test_results_report(hash) do - message = '' - message = 'Unit test failures.' if (results[:counts][:failed] > 0) - message - end - end - - def summary - result_list = @ceedling[:file_path_utils].form_pass_results_filelist( PROJECT_TEST_RESULTS_PATH, COLLECTION_ALL_TESTS ) - - # get test results for only those tests in our configuration and of those only tests with results on disk - hash = { - :header => '', - :results => @ceedling[:plugin_reportinator].assemble_test_results(result_list, {:boom => false}) - } - - @ceedling[:plugin_reportinator].run_test_results_report(hash) - end - -end diff --git a/vendor/ceedling/plugins/subprojects/README.md b/vendor/ceedling/plugins/subprojects/README.md deleted file mode 100644 index e51a4e6..0000000 --- a/vendor/ceedling/plugins/subprojects/README.md +++ /dev/null @@ -1,63 +0,0 @@ -ceedling-subprojects -==================== - -Plugin for supporting subprojects that are built as static libraries. It continues to support -dependency tracking, without getting confused between your main project files and your -subproject files. It accepts different compiler flags and linker flags, allowing you to -optimize for your situation. - -First, you're going to want to add the extension to your list of known extensions: - -``` -:extension: - :subprojects: '.a' -``` - -Define a new section called :subprojects. There, you can list as many subprojects -as you may need under the :paths key. For each, you specify a unique place to build -and a unique name. - -``` -:subprojects: - :paths: - - :name: libprojectA - :source: - - ./subprojectA/first/dir - - ./subprojectA/second/dir - :include: - - ./subprojectA/include/dir - :build_root: ./subprojectA/build/dir - :defines: - - DEFINE_JUST_FOR_THIS_FILE - - AND_ANOTHER - - :name: libprojectB - :source: - - ./subprojectB/only/dir - :include: - - ./subprojectB/first/include/dir - - ./subprojectB/second/include/dir - :build_root: ./subprojectB/build/dir - :defines: [] #none for this one -``` - -You can specify the compiler and linker, just as you would a release build: - -``` -:tools: - :subprojects_compiler: - :executable: gcc - :arguments: - - -g - - -I"$": COLLECTION_PATHS_SUBPROJECTS - - -D$: COLLECTION_DEFINES_SUBPROJECTS - - -c "${1}" - - -o "${2}" - :subprojects_linker: - :executable: ar - :arguments: - - rcs - - ${2} - - ${1} -``` - -That's all there is to it! Happy Hacking! diff --git a/vendor/ceedling/plugins/subprojects/config/defaults.yml b/vendor/ceedling/plugins/subprojects/config/defaults.yml deleted file mode 100644 index 1045a59..0000000 --- a/vendor/ceedling/plugins/subprojects/config/defaults.yml +++ /dev/null @@ -1,33 +0,0 @@ ---- -#:extension: -# :subprojects: '.a' - -:subprojects: - :paths: [] -# - :name: subprojectA -# :source: -# - ./first/subproject/dir -# - ./second/subproject/dir -# :include: -# - ./first/include/dir -# :build_root: ./subproject/build/dir -# :defines: -# - FIRST_DEFINE - -:tools: - :subprojects_compiler: - :executable: gcc - :arguments: - - -g - - -I"$": COLLECTION_PATHS_SUBPROJECTS - - -D$: COLLECTION_DEFINES_SUBPROJECTS - - -c "${1}" - - -o "${2}" - :subprojects_linker: - :executable: ar - :arguments: - - rcs - - ${2} - - ${1} - -... diff --git a/vendor/ceedling/plugins/subprojects/lib/subprojects.rb b/vendor/ceedling/plugins/subprojects/lib/subprojects.rb deleted file mode 100644 index 559251e..0000000 --- a/vendor/ceedling/plugins/subprojects/lib/subprojects.rb +++ /dev/null @@ -1,92 +0,0 @@ -require 'ceedling/plugin' -require 'ceedling/constants' - -SUBPROJECTS_ROOT_NAME = 'subprojects' -SUBPROJECTS_TASK_ROOT = SUBPROJECTS_ROOT_NAME + ':' -SUBPROJECTS_SYM = SUBPROJECTS_ROOT_NAME.to_sym - -class Subprojects < Plugin - - def setup - @plugin_root = File.expand_path(File.join(File.dirname(__FILE__), '..')) - - # Add to the test paths - SUBPROJECTS_PATHS.each do |subproj| - subproj[:source].each do |path| - COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR << path - end - subproj[:include].each do |path| - COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR << path - end - end - - # Gather information about the subprojects - @subprojects = {} - @subproject_lookup_by_path = {} - SUBPROJECTS_PATHS.each do |subproj| - @subprojects[ subproj[:name] ] = subproj.clone - @subprojects[ subproj[:name] ][:c] = [] - @subprojects[ subproj[:name] ][:asm] = [] - subproj[:source].each do |path| - search_path = "#{path[-1].match(/\\|\//) ? path : "#{path}/"}*#{EXTENSION_SOURCE}" - @subprojects[ subproj[:name] ][:c] += Dir[search_path] - if (EXTENSION_ASSEMBLY && !EXTENSION_ASSEMBLY.empty?) - search_path = "#{path[-1].match(/\\|\//) ? path : "#{path}/"}*#{EXTENSION_ASSEMBLY}" - @subprojects[ subproj[:name] ][:asm] += Dir[search_path] - end - end - @subproject_lookup_by_path[ subproj[:build_root] ] = subproj[:name] - end - end - - def find_my_project( c_file, file_type = :c ) - @subprojects.each_pair do |subprojname, subproj| - return subprojname if (subproj[file_type].include?(c_file)) - end - end - - def find_my_paths( c_file, file_type = :c ) - @subprojects.each_pair do |subprojname, subproj| - return (subproj[:source] + (subproj[:include] || [])) if (subproj[file_type].include?(c_file)) - end - return [] - end - - def find_my_defines( c_file, file_type = :c ) - @subprojects.each_pair do |subprojname, subproj| - return (subproj[:defines] || []) if (subproj[file_type].include?(c_file)) - end - return [] - end - - def list_all_object_files_for_subproject( lib_name ) - subproj = File.basename(lib_name, EXTENSION_SUBPROJECTS) - objpath = "#{@subprojects[subproj][:build_root]}/out/c" - bbb = @subprojects[subproj][:c].map{|f| "#{objpath}/#{File.basename(f,EXTENSION_SOURCE)}#{EXTENSION_OBJECT}" } - bbb - end - - def find_library_source_file_for_object( obj_name ) - cname = "#{File.basename(obj_name, EXTENSION_OBJECT)}#{EXTENSION_SOURCE}" - dname = File.dirname(obj_name)[0..-7] - pname = @subproject_lookup_by_path[dname] - return @ceedling[:file_finder].find_file_from_list(cname, @subprojects[pname][:c], :error) - end - - def find_library_assembly_file_for_object( obj_name ) - cname = "#{File.basename(obj_name, EXTENSION_OBJECT)}#{EXTENSION_ASEMBLY}" - dname = File.dirname(obj_name)[0..-7] - pname = @subproject_lookup_by_path[dname] - return @ceedling[:file_finder].find_file_from_list(cname, @subprojects[pname][:asm], :error) - end - - def replace_constant(constant, new_value) - Object.send(:remove_const, constant.to_sym) if (Object.const_defined? constant) - Object.const_set(constant, new_value) - end - -end - -# end blocks always executed following rake run -END { -} diff --git a/vendor/ceedling/plugins/subprojects/subprojects.rake b/vendor/ceedling/plugins/subprojects/subprojects.rake deleted file mode 100644 index 0025c3e..0000000 --- a/vendor/ceedling/plugins/subprojects/subprojects.rake +++ /dev/null @@ -1,78 +0,0 @@ - - -SUBPROJECTS_PATHS.each do |subproj| - - subproj_source = subproj[:source] - subproj_include = subproj[:include] - subproj_name = subproj[:name] - subproj_build_root = subproj[:build_root] - subproj_build_out = "#{subproj[:build_root]}/out" - subproj_build_c = "#{subproj[:build_root]}/out/c" - subproj_build_asm = "#{subproj[:build_root]}/out/asm" - subproj_directories = [ subproj_build_root, subproj_build_out, subproj_build_c, subproj_build_asm ] - - subproj_directories.each do |subdir| - directory(subdir) - end - - CLEAN.include(File.join(subproj_build_root, '*')) - CLEAN.include(File.join(subproj_build_out, '*')) - - CLOBBER.include(File.join(subproj_build_root, '**/*')) - - # Add a rule for building the actual static library from our object files - rule(/#{subproj_build_root}#{'.+\\'+EXTENSION_SUBPROJECTS}$/ => [ - proc do |task_name| - @ceedling[SUBPROJECTS_SYM].list_all_object_files_for_subproject(task_name) - end - ]) do |bin_file| - @ceedling[:generator].generate_executable_file( - TOOLS_SUBPROJECTS_LINKER, - SUBPROJECTS_SYM, - bin_file.prerequisites, - bin_file.name, - @ceedling[:file_path_utils].form_test_build_map_filepath(bin_file.name)) - end - - # Add a rule for building object files from assembly files to link into a library - if (RELEASE_BUILD_USE_ASSEMBLY) - rule(/#{subproj_build_asm}#{'.+\\'+EXTENSION_OBJECT}$/ => [ - proc do |task_name| - @ceedling[SUBPROJECTS_SYM].find_library_assembly_file_for_object(task_name) - end - ]) do |object| - @ceedling[SUBPROJECTS_SYM].replace_constant(:COLLECTION_PATHS_SUBPROJECTS, @ceedling[SUBPROJECTS_SYM].find_my_paths(object.source, :asm)) - @ceedling[SUBPROJECTS_SYM].replace_constant(:COLLECTION_DEFINES_SUBPROJECTS, @ceedling[SUBPROJECTS_SYM].find_my_defines(object.source, :asm)) - @ceedling[:generator].generate_object_file( - TOOLS_SUBPROJECTS_ASSEMBLER, - OPERATION_ASSEMBLE_SYM, - SUBPROJECTS_SYM, - object.source, - object.name ) - end - end - - # Add a rule for building object files from C files to link into a library - rule(/#{subproj_build_c}#{'.+\\'+EXTENSION_OBJECT}$/ => [ - proc do |task_name| - @ceedling[SUBPROJECTS_SYM].find_library_source_file_for_object(task_name) - end - ]) do |object| - @ceedling[SUBPROJECTS_SYM].replace_constant(:COLLECTION_PATHS_SUBPROJECTS, @ceedling[SUBPROJECTS_SYM].find_my_paths(object.source, :c)) - @ceedling[SUBPROJECTS_SYM].replace_constant(:COLLECTION_DEFINES_SUBPROJECTS, @ceedling[SUBPROJECTS_SYM].find_my_defines(object.source, :c)) - @ceedling[:generator].generate_object_file( - TOOLS_SUBPROJECTS_COMPILER, - OPERATION_COMPILE_SYM, - SUBPROJECTS_SYM, - object.source, - object.name, - @ceedling[:file_path_utils].form_release_build_c_list_filepath( object.name ) ) - end - - # Add the subdirectories involved to our list of those that should be autogenerated - task :directories => subproj_directories.clone - - # Finally, add the static library to our RELEASE build dependency list - task RELEASE_SYM => ["#{subproj_build_root}/#{subproj_name}#{EXTENSION_SUBPROJECTS}"] -end - diff --git a/vendor/ceedling/plugins/teamcity_tests_report/README.md b/vendor/ceedling/plugins/teamcity_tests_report/README.md deleted file mode 100644 index 9fcda7d..0000000 --- a/vendor/ceedling/plugins/teamcity_tests_report/README.md +++ /dev/null @@ -1,18 +0,0 @@ -ceedling-teamcity-tests-report -============================== - -## Overview - -The teamcity_tests_report replaces the normal ceedling "pretty" output with -a version that has results tagged to be consumed with the teamcity CI server. - -## Setup - -Enable the plugin in your project.yml by adding `teamcity_tests_report` -to the list of enabled plugins. - -``` YAML -:plugins: - :enabled: - - teamcity_tests_report -``` diff --git a/vendor/ceedling/plugins/teamcity_tests_report/config/teamcity_tests_report.yml b/vendor/ceedling/plugins/teamcity_tests_report/config/teamcity_tests_report.yml deleted file mode 100644 index c25acf5..0000000 --- a/vendor/ceedling/plugins/teamcity_tests_report/config/teamcity_tests_report.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -:plugins: - # tell Ceedling we got results display taken care of - :display_raw_test_results: FALSE diff --git a/vendor/ceedling/plugins/teamcity_tests_report/lib/teamcity_tests_report.rb b/vendor/ceedling/plugins/teamcity_tests_report/lib/teamcity_tests_report.rb deleted file mode 100644 index 33d8548..0000000 --- a/vendor/ceedling/plugins/teamcity_tests_report/lib/teamcity_tests_report.rb +++ /dev/null @@ -1,57 +0,0 @@ -require 'ceedling/plugin' -require 'ceedling/defaults' - -class TeamcityTestsReport < Plugin - - def setup - @suite_started = nil - @output_enabled = !defined?(TEAMCITY_BUILD) || TEAMCITY_BUILD - end - - def escape(string) - string.gsub(/['|\[\]]/, '|\0').gsub('\r', '|r').gsub('\n', '|n') - end - - def pre_test(test) - teamcity_message "testSuiteStarted name='#{File.basename(test, '.c')}'" - @suite_started = Time.now - end - - def post_test(test) - teamcity_message "testSuiteFinished name='#{File.basename(test, '.c')}'" - end - - def post_test_fixture_execute(arg_hash) - duration = (Time.now - @suite_started) * 1000 - results = @ceedling[:plugin_reportinator].assemble_test_results([arg_hash[:result_file]]) - avg_duration = (duration / [1, results[:counts][:passed] + results[:counts][:failed]].max).round - - results[:successes].each do |success| - success[:collection].each do |test| - teamcity_message "testStarted name='#{test[:test]}'" - teamcity_message "testFinished name='#{test[:test]}' duration='#{avg_duration}'" - end - end - - results[:failures].each do |failure| - failure[:collection].each do |test| - teamcity_message "testStarted name='#{test[:test]}'" - teamcity_message "testFailed name='#{test[:test]}' message='#{escape(test[:message])}' details='File: #{failure[:source][:path]}/#{failure[:source][:file]} Line: #{test[:line]}'" - teamcity_message "testFinished name='#{test[:test]}' duration='#{avg_duration}'" - end - end - - results[:ignores].each do |failure| - failure[:collection].each do |test| - teamcity_message "testIgnored name='#{test[:test]}' message='#{escape(test[:message])}'" - end - end - - # We ignore stdout - end - - def teamcity_message(content) - puts "##teamcity[#{content}]" unless !@output_enabled - end - -end diff --git a/vendor/ceedling/plugins/warnings_report/README.md b/vendor/ceedling/plugins/warnings_report/README.md deleted file mode 100644 index fd7fae5..0000000 --- a/vendor/ceedling/plugins/warnings_report/README.md +++ /dev/null @@ -1,19 +0,0 @@ -warnings-report -=============== - -## Overview - -The warnings_report captures all warnings throughout the build process -and collects them into a single report at the end of execution. It places all -of this into a warnings file in the output artifact directory. - -## Setup - -Enable the plugin in your project.yml by adding `warnings_report` -to the list of enabled plugins. - -``` YAML -:plugins: - :enabled: - - warnings_report -``` diff --git a/vendor/ceedling/plugins/warnings_report/lib/warnings_report.rb b/vendor/ceedling/plugins/warnings_report/lib/warnings_report.rb deleted file mode 100644 index d4f43fb..0000000 --- a/vendor/ceedling/plugins/warnings_report/lib/warnings_report.rb +++ /dev/null @@ -1,69 +0,0 @@ -require 'ceedling/plugin' -require 'ceedling/constants' - -class WarningsReport < Plugin - def setup - @stderr_redirect = nil - @log_paths = {} - end - - def pre_compile_execute(arg_hash) - # at beginning of compile, override tool's stderr_redirect so we can parse $stderr + $stdout - set_stderr_redirect(arg_hash) - end - - def post_compile_execute(arg_hash) - # after compilation, grab output for parsing/logging, restore stderr_redirect, log warning if it exists - output = arg_hash[:shell_result][:output] - restore_stderr_redirect(arg_hash) - write_warning_log(arg_hash[:context], output) - end - - def pre_link_execute(arg_hash) - # at beginning of link, override tool's stderr_redirect so we can parse $stderr + $stdout - set_stderr_redirect(arg_hash) - end - - def post_link_execute(arg_hash) - # after linking, grab output for parsing/logging, restore stderr_redirect, log warning if it exists - output = arg_hash[:shell_result][:output] - restore_stderr_redirect(arg_hash) - write_warning_log(arg_hash[:context], output) - end - - private - - def set_stderr_redirect(hash) - @stderr_redirect = hash[:tool][:stderr_redirect] - hash[:tool][:stderr_redirect] = StdErrRedirect::AUTO - end - - def restore_stderr_redirect(hash) - hash[:tool][:stderr_redirect] = @stderr_redirect - end - - def write_warning_log(context, output) - # if $stderr/$stdout contain "warning", log it - if output =~ /warning/i - # generate a log path & file io write flags - logging = generate_log_path(context) - @ceedling[:file_wrapper].write(logging[:path], output + "\n", logging[:flags]) unless logging.nil? - end - end - - def generate_log_path(context) - # if path has already been generated, return it & 'append' file io flags (append to log) - return { path: @log_paths[context], flags: 'a' } unless @log_paths[context].nil? - - # first time through, generate path & 'write' file io flags (create new log) - base_path = File.join(PROJECT_BUILD_ARTIFACTS_ROOT, context.to_s) - file_path = File.join(base_path, 'warnings.log') - - if @ceedling[:file_wrapper].exist?(base_path) - @log_paths[context] = file_path - return { path: file_path, flags: 'w' } - end - - nil - end -end diff --git a/vendor/ceedling/plugins/xml_tests_report/README.md b/vendor/ceedling/plugins/xml_tests_report/README.md deleted file mode 100644 index 6200c7d..0000000 --- a/vendor/ceedling/plugins/xml_tests_report/README.md +++ /dev/null @@ -1,36 +0,0 @@ -xml_tests_report -================ - -## Overview - -The xml_tests_report plugin creates an XML file of test results in xUnit -format, which is handy for Continuous Integration build servers or as input -into other reporting tools. The XML file is output to the appropriate -`<build_root>/artifacts/` directory (e.g. `artifacts/test/` for test tasks, -`artifacts/gcov/` for gcov, or `artifacts/bullseye/` for bullseye runs). - -## Setup - -Enable the plugin in your project.yml by adding `xml_tests_report` to the list -of enabled plugins. - -``` YAML -:plugins: - :enabled: - - xml_tests_report -``` - -## Configuration - -Optionally configure the output / artifact filename in your project.yml with -the `artifact_filename` configuration option. The default filename is -`report.xml`. - -You can also configure the path that this artifact is stored. This can be done -by setting `path`. The default is that it will be placed in a subfolder under -the `build` directory. - -``` YAML -:xml_tests_report: - :artifact_filename: report_xunit.xml -``` diff --git a/vendor/ceedling/plugins/xml_tests_report/lib/xml_tests_report.rb b/vendor/ceedling/plugins/xml_tests_report/lib/xml_tests_report.rb deleted file mode 100644 index ed4e996..0000000 --- a/vendor/ceedling/plugins/xml_tests_report/lib/xml_tests_report.rb +++ /dev/null @@ -1,110 +0,0 @@ -require 'ceedling/plugin' -require 'ceedling/constants' - -class XmlTestsReport < Plugin - def setup - @results_list = {} - @test_counter = 0 - end - - def post_test_fixture_execute(arg_hash) - context = arg_hash[:context] - - @results_list[context] = [] if @results_list[context].nil? - - @results_list[context] << arg_hash[:result_file] - end - - def post_build - @results_list.each_key do |context| - results = @ceedling[:plugin_reportinator].assemble_test_results(@results_list[context]) - - artifact_filename = @ceedling[:configurator].project_config_hash[:xml_tests_report_artifact_filename] || 'report.xml' - artifact_fullpath = @ceedling[:configurator].project_config_hash[:xml_tests_report_path] || File.join(PROJECT_BUILD_ARTIFACTS_ROOT, context.to_s) - file_path = File.join(artifact_fullpath, artifact_filename) - - @ceedling[:file_wrapper].open(file_path, 'w') do |f| - @test_counter = 1 - write_results(results, f) - end - end - end - - private - - def write_results(results, stream) - write_header(stream) - write_failures(results[:failures], stream) - write_tests(results[:successes], stream, 'SuccessfulTests') - write_tests(results[:ignores], stream, 'IgnoredTests') - write_statistics(results[:counts], stream) - write_footer(stream) - end - - def write_header(stream) - stream.puts "<?xml version='1.0' encoding='utf-8' ?>" - stream.puts '<TestRun>' - end - - def write_failures(results, stream) - if results.size.zero? - stream.puts "\t<FailedTests/>" - return - end - - stream.puts "\t<FailedTests>" - - results.each do |result| - result[:collection].each do |item| - filename = File.join(result[:source][:path], result[:source][:file]) - - stream.puts "\t\t<Test id=\"#{@test_counter}\">" - stream.puts "\t\t\t<Name>#{filename}::#{item[:test]}</Name>" - stream.puts "\t\t\t<FailureType>Assertion</FailureType>" - stream.puts "\t\t\t<Location>" - stream.puts "\t\t\t\t<File>#{filename}</File>" - stream.puts "\t\t\t\t<Line>#{item[:line]}</Line>" - stream.puts "\t\t\t</Location>" - stream.puts "\t\t\t<Message>#{item[:message]}</Message>" - stream.puts "\t\t</Test>" - @test_counter += 1 - end - end - - stream.puts "\t</FailedTests>" - end - - def write_tests(results, stream, tag) - if results.size.zero? - stream.puts "\t<#{tag}/>" - return - end - - stream.puts "\t<#{tag}>" - - results.each do |result| - result[:collection].each do |item| - stream.puts "\t\t<Test id=\"#{@test_counter}\">" - stream.puts "\t\t\t<Name>#{File.join(result[:source][:path], result[:source][:file])}::#{item[:test]}</Name>" - stream.puts "\t\t</Test>" - @test_counter += 1 - end - end - - stream.puts "\t</#{tag}>" - end - - def write_statistics(counts, stream) - stream.puts "\t<Statistics>" - stream.puts "\t\t<Tests>#{counts[:total]}</Tests>" - stream.puts "\t\t<Ignores>#{counts[:ignored]}</Ignores>" - stream.puts "\t\t<FailuresTotal>#{counts[:failed]}</FailuresTotal>" - stream.puts "\t\t<Errors>0</Errors>" - stream.puts "\t\t<Failures>#{counts[:failed]}</Failures>" - stream.puts "\t</Statistics>" - end - - def write_footer(stream) - stream.puts '</TestRun>' - end -end diff --git a/vendor/ceedling/vendor/c_exception/lib/CException.c b/vendor/ceedling/vendor/c_exception/lib/CException.c deleted file mode 100644 index fdff8f4..0000000 --- a/vendor/ceedling/vendor/c_exception/lib/CException.c +++ /dev/null @@ -1,46 +0,0 @@ -#include "CException.h" - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wmissing-field-initializers" -volatile CEXCEPTION_FRAME_T CExceptionFrames[CEXCEPTION_NUM_ID] = {{ 0 }}; -#pragma GCC diagnostic pop - -//------------------------------------------------------------------------------------------ -// Throw -//------------------------------------------------------------------------------------------ -void Throw(CEXCEPTION_T ExceptionID) -{ - unsigned int MY_ID = CEXCEPTION_GET_ID; - CExceptionFrames[MY_ID].Exception = ExceptionID; - if (CExceptionFrames[MY_ID].pFrame) - { - longjmp(*CExceptionFrames[MY_ID].pFrame, 1); - } - CEXCEPTION_NO_CATCH_HANDLER(ExceptionID); -} - -//------------------------------------------------------------------------------------------ -// Explanation of what it's all for: -//------------------------------------------------------------------------------------------ -/* -#define Try - { <- give us some local scope. most compilers are happy with this - jmp_buf *PrevFrame, NewFrame; <- prev frame points to the last try block's frame. new frame gets created on stack for this Try block - unsigned int MY_ID = CEXCEPTION_GET_ID; <- look up this task's id for use in frame array. always 0 if single-tasking - PrevFrame = CExceptionFrames[CEXCEPTION_GET_ID].pFrame; <- set pointer to point at old frame (which array is currently pointing at) - CExceptionFrames[MY_ID].pFrame = &NewFrame; <- set array to point at my new frame instead, now - CExceptionFrames[MY_ID].Exception = CEXCEPTION_NONE; <- initialize my exception id to be NONE - if (setjmp(NewFrame) == 0) { <- do setjmp. it returns 1 if longjump called, otherwise 0 - if (&PrevFrame) <- this is here to force proper scoping. it requires braces or a single line to be but after Try, otherwise won't compile. This is always true at this point. - -#define Catch(e) - else { } <- this also forces proper scoping. Without this they could stick their own 'else' in and it would get ugly - CExceptionFrames[MY_ID].Exception = CEXCEPTION_NONE; <- no errors happened, so just set the exception id to NONE (in case it was corrupted) - } - else <- an exception occurred - { e = CExceptionFrames[MY_ID].Exception; e=e;} <- assign the caught exception id to the variable passed in. - CExceptionFrames[MY_ID].pFrame = PrevFrame; <- make the pointer in the array point at the previous frame again, as if NewFrame never existed. - } <- finish off that local scope we created to have our own variables - if (CExceptionFrames[CEXCEPTION_GET_ID].Exception != CEXCEPTION_NONE) <- start the actual 'catch' processing if we have an exception id saved away - */ - diff --git a/vendor/ceedling/vendor/c_exception/lib/CException.h b/vendor/ceedling/vendor/c_exception/lib/CException.h deleted file mode 100644 index be9e186..0000000 --- a/vendor/ceedling/vendor/c_exception/lib/CException.h +++ /dev/null @@ -1,115 +0,0 @@ -#ifndef _CEXCEPTION_H -#define _CEXCEPTION_H - -#include <setjmp.h> - -#ifdef __cplusplus -extern "C" -{ -#endif - - -#define CEXCEPTION_VERSION_MAJOR 1 -#define CEXCEPTION_VERSION_MINOR 3 -#define CEXCEPTION_VERSION_BUILD 3 -#define CEXCEPTION_VERSION ((CEXCEPTION_VERSION_MAJOR << 16) | (CEXCEPTION_VERSION_MINOR << 8) | CEXCEPTION_VERSION_BUILD) - -//To Use CException, you have a number of options: -//1. Just include it and run with the defaults -//2. Define any of the following symbols at the command line to override them -//3. Include a header file before CException.h everywhere which defines any of these -//4. Create an Exception.h in your path, and just define EXCEPTION_USE_CONFIG_FILE first - -#ifdef CEXCEPTION_USE_CONFIG_FILE -#include "CExceptionConfig.h" -#endif - -//This is the value to assign when there isn't an exception -#ifndef CEXCEPTION_NONE -#define CEXCEPTION_NONE (0x5A5A5A5A) -#endif - -//This is number of exception stacks to keep track of (one per task) -#ifndef CEXCEPTION_NUM_ID -#define CEXCEPTION_NUM_ID (1) //there is only the one stack by default -#endif - -//This is the method of getting the current exception stack index (0 if only one stack) -#ifndef CEXCEPTION_GET_ID -#define CEXCEPTION_GET_ID (0) //use the first index always because there is only one anyway -#endif - -//The type to use to store the exception values. -#ifndef CEXCEPTION_T -#define CEXCEPTION_T unsigned int -#endif - -//This is an optional special handler for when there is no global Catch -#ifndef CEXCEPTION_NO_CATCH_HANDLER -#define CEXCEPTION_NO_CATCH_HANDLER(id) -#endif - -//These hooks allow you to inject custom code into places, particularly useful for saving and restoring additional state -#ifndef CEXCEPTION_HOOK_START_TRY -#define CEXCEPTION_HOOK_START_TRY -#endif -#ifndef CEXCEPTION_HOOK_HAPPY_TRY -#define CEXCEPTION_HOOK_HAPPY_TRY -#endif -#ifndef CEXCEPTION_HOOK_AFTER_TRY -#define CEXCEPTION_HOOK_AFTER_TRY -#endif -#ifndef CEXCEPTION_HOOK_START_CATCH -#define CEXCEPTION_HOOK_START_CATCH -#endif - -//exception frame structures -typedef struct { - jmp_buf* pFrame; - CEXCEPTION_T volatile Exception; -} CEXCEPTION_FRAME_T; - -//actual root frame storage (only one if single-tasking) -extern volatile CEXCEPTION_FRAME_T CExceptionFrames[]; - -//Try (see C file for explanation) -#define Try \ - { \ - jmp_buf *PrevFrame, NewFrame; \ - unsigned int MY_ID = CEXCEPTION_GET_ID; \ - PrevFrame = CExceptionFrames[MY_ID].pFrame; \ - CExceptionFrames[MY_ID].pFrame = (jmp_buf*)(&NewFrame); \ - CExceptionFrames[MY_ID].Exception = CEXCEPTION_NONE; \ - CEXCEPTION_HOOK_START_TRY; \ - if (setjmp(NewFrame) == 0) { \ - if (1) - -//Catch (see C file for explanation) -#define Catch(e) \ - else { } \ - CExceptionFrames[MY_ID].Exception = CEXCEPTION_NONE; \ - CEXCEPTION_HOOK_HAPPY_TRY; \ - } \ - else \ - { \ - e = CExceptionFrames[MY_ID].Exception; \ - (void)e; \ - CEXCEPTION_HOOK_START_CATCH; \ - } \ - CExceptionFrames[MY_ID].pFrame = PrevFrame; \ - CEXCEPTION_HOOK_AFTER_TRY; \ - } \ - if (CExceptionFrames[CEXCEPTION_GET_ID].Exception != CEXCEPTION_NONE) - -//Throw an Error -void Throw(CEXCEPTION_T ExceptionID); - -//Just exit the Try block and skip the Catch. -#define ExitTry() Throw(CEXCEPTION_NONE) - -#ifdef __cplusplus -} // extern "C" -#endif - - -#endif // _CEXCEPTION_H diff --git a/vendor/ceedling/vendor/c_exception/lib/meson.build b/vendor/ceedling/vendor/c_exception/lib/meson.build deleted file mode 100644 index 2770122..0000000 --- a/vendor/ceedling/vendor/c_exception/lib/meson.build +++ /dev/null @@ -1,11 +0,0 @@ -# -# build script written by : Michael Brockus. -# github repo author: Mark VanderVoord. -# -# license: MIT -# -cexception_dir = include_directories('.') - -cexception_lib = static_library(meson.project_name(), - files('CException.c'), - include_directories : cexception_dir) diff --git a/vendor/ceedling/vendor/cmock/config/production_environment.rb b/vendor/ceedling/vendor/cmock/config/production_environment.rb deleted file mode 100644 index 082b63f..0000000 --- a/vendor/ceedling/vendor/cmock/config/production_environment.rb +++ /dev/null @@ -1,12 +0,0 @@ -# ========================================== -# CMock Project - Automatic Mock Generation for C -# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams -# [Released under MIT License. Please refer to license.txt for details] -# ========================================== - -# Setup our load path: -[ - 'lib' -].each do |dir| - $:.unshift(File.join(__dir__ + '/../', dir)) -end diff --git a/vendor/ceedling/vendor/cmock/config/test_environment.rb b/vendor/ceedling/vendor/cmock/config/test_environment.rb deleted file mode 100644 index aeae3a3..0000000 --- a/vendor/ceedling/vendor/cmock/config/test_environment.rb +++ /dev/null @@ -1,16 +0,0 @@ -# ========================================== -# CMock Project - Automatic Mock Generation for C -# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams -# [Released under MIT License. Please refer to license.txt for details] -# ========================================== - -# Setup our load path: -[ - './lib', - './vendor/behaviors/lib', - './vendor/hardmock/lib', - './vendor/unity/auto/', - './test/system/' -].each do |dir| - $:.unshift(File.join(File.expand_path(File.dirname(__FILE__) + '/../'), dir)) -end diff --git a/vendor/ceedling/vendor/cmock/lib/cmock.rb b/vendor/ceedling/vendor/cmock/lib/cmock.rb deleted file mode 100644 index 72f8641..0000000 --- a/vendor/ceedling/vendor/cmock/lib/cmock.rb +++ /dev/null @@ -1,111 +0,0 @@ -# ========================================== -# CMock Project - Automatic Mock Generation for C -# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams -# [Released under MIT License. Please refer to license.txt for details] -# ========================================== - -['../config/production_environment', - 'cmock_header_parser', - 'cmock_generator', - 'cmock_file_writer', - 'cmock_config', - 'cmock_plugin_manager', - 'cmock_generator_utils', - 'cmock_unityhelper_parser'].each { |req| require "#{__dir__}/#{req}" } - -class CMock - def initialize(options = nil) - cm_config = CMockConfig.new(options) - cm_unityhelper = CMockUnityHelperParser.new(cm_config) - cm_writer = CMockFileWriter.new(cm_config) - cm_gen_utils = CMockGeneratorUtils.new(cm_config, - :unity_helper => cm_unityhelper) - cm_gen_plugins = CMockPluginManager.new(cm_config, cm_gen_utils) - @cm_parser = CMockHeaderParser.new(cm_config) - @cm_generator = CMockGenerator.new(cm_config, cm_writer, cm_gen_utils, - cm_gen_plugins) - @silent = (cm_config.verbosity < 2) - end - - def setup_mocks(files, folder = nil) - [files].flatten.each do |src| - generate_mock(src, folder) - end - end - - def setup_skeletons(files) - [files].flatten.each do |src| - generate_skeleton src - end - end - - private ############################### - - def generate_mock(src, folder) - name = File.basename(src, '.*') - ext = File.extname(src) - puts "Creating mock for #{name}..." unless @silent - @cm_generator.create_mock(name, @cm_parser.parse(name, File.read(src)), ext, folder) - end - - def generate_skeleton(src) - name = File.basename(src, '.*') - puts "Creating skeleton for #{name}..." unless @silent - @cm_generator.create_skeleton(name, @cm_parser.parse(name, File.read(src))) - end -end - -def option_maker(options, key, val) - options ||= {} - options[key.to_sym] = - if val.chr == ':' - val[1..-1].to_sym - elsif val.include? ';' - val.split(';') - elsif val == 'true' - true - elsif val == 'false' - false - elsif val =~ /^\d+$/ - val.to_i - else - val - end - options -end - -# Command Line Support ############################### - -if $0 == __FILE__ - usage = "usage: ruby #{__FILE__} (-oOptionsFile) File(s)ToMock" - - unless ARGV[0] - puts usage - exit 1 - end - - options = {} - filelist = [] - ARGV.each do |arg| - if arg =~ /^-o\"?([a-zA-Z0-9@._\\\/:\s]+)\"?/ - options.merge! CMockConfig.load_config_file_from_yaml(arg.gsub(/^-o/, '')) - elsif arg == '--skeleton' - options[:skeleton] = true - elsif arg =~ /^--strippables=\"?(.*)\"?/ - # --strippables are dealt with separately since the user is allowed to - # enter any valid regular expression as argument - options = option_maker(options, 'strippables', Regexp.last_match(1)) - elsif arg =~ /^--([a-zA-Z0-9._\\\/:\s]+)=\"?([a-zA-Z0-9._\-\\\/:\s\;]*)\"?/x - options = option_maker(options, Regexp.last_match(1), - Regexp.last_match(2)) - else - filelist << arg - end - end - - if options[:skeleton] - CMock.new(options).setup_skeletons(filelist) - else - CMock.new(options).setup_mocks(filelist) - end -end diff --git a/vendor/ceedling/vendor/cmock/lib/cmock_config.rb b/vendor/ceedling/vendor/cmock/lib/cmock_config.rb deleted file mode 100644 index 716a0c5..0000000 --- a/vendor/ceedling/vendor/cmock/lib/cmock_config.rb +++ /dev/null @@ -1,174 +0,0 @@ -# ========================================== -# CMock Project - Automatic Mock Generation for C -# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams -# [Released under MIT License. Please refer to license.txt for details] -# ========================================== - -class CMockConfig - CMOCK_DEFAULT_OPTIONS = - { - :framework => :unity, - :mock_path => 'mocks', - :mock_prefix => 'Mock', - :mock_suffix => '', - :skeleton_path => '', - :weak => '', - :subdir => nil, - :plugins => [], - :strippables => ['(?:__attribute__\s*\(+.*?\)+)'], - :attributes => %w[__ramfunc __irq __fiq register extern], - :c_calling_conventions => %w[__stdcall __cdecl __fastcall], - :enforce_strict_ordering => false, - :fail_on_unexpected_calls => true, - :unity_helper_path => false, - :treat_as => {}, - :treat_as_array => {}, - :treat_as_void => [], - :memcmp_if_unknown => true, - :when_no_prototypes => :warn, # the options being :ignore, :warn, or :error - :when_ptr => :compare_data, # the options being :compare_ptr, :compare_data, or :smart - :verbosity => 2, # the options being 0 errors only, 1 warnings and errors, 2 normal info, 3 verbose - :treat_externs => :exclude, # the options being :include or :exclude - :treat_inlines => :exclude, # the options being :include or :exclude - :callback_include_count => true, - :callback_after_arg_check => false, - :includes => nil, - :includes_h_pre_orig_header => nil, - :includes_h_post_orig_header => nil, - :includes_c_pre_header => nil, - :includes_c_post_header => nil, - :orig_header_include_fmt => '#include "%s"', - :array_size_type => [], - :array_size_name => 'size|len', - :skeleton => false, - :exclude_setjmp_h => false, - - # Format to look for inline functions. - # This is a combination of "static" and "inline" keywords ("static inline", "inline static", "inline", "static") - # There are several possibilities: - # - sometimes they appear together, sometimes individually, - # - The keywords can appear before or after the return type (this is a compiler warning but people do weird stuff), - # so we check for word boundaries when searching for them - # - We first remove "static inline" combinations and boil down to single inline or static statements - :inline_function_patterns => ['(static\s+inline|inline\s+static)\s*', '(\bstatic\b|\binline\b)\s*'] # Last part (\s*) is just to remove whitespaces (only to prettify the output) - }.freeze - - def initialize(options = nil) - case options - when NilClass then options = CMOCK_DEFAULT_OPTIONS.dup - when String then options = CMOCK_DEFAULT_OPTIONS.dup.merge(load_config_file_from_yaml(options)) - when Hash then options = CMOCK_DEFAULT_OPTIONS.dup.merge(options) - else raise 'If you specify arguments, it should be a filename or a hash of options' - end - - # do some quick type verification - %i[plugins attributes treat_as_void].each do |opt| - unless options[opt].class == Array - options[opt] = [] - puts "WARNING: :#{opt} should be an array." unless options[:verbosity] < 1 - end - end - %i[includes includes_h_pre_orig_header includes_h_post_orig_header includes_c_pre_header includes_c_post_header].each do |opt| - unless options[opt].nil? || (options[opt].class == Array) - options[opt] = [] - puts "WARNING: :#{opt} should be an array." unless options[:verbosity] < 1 - end - end - options[:unity_helper_path] ||= options[:unity_helper] - options[:unity_helper_path] = [options[:unity_helper_path]] if options[:unity_helper_path].is_a? String - - if options[:unity_helper_path] - require 'pathname' - includes1 = options[:includes_c_post_header] || [] - includes2 = options[:unity_helper_path].map do |path| - Pathname(path).relative_path_from(Pathname(options[:mock_path])).to_s - end - options[:includes_c_post_header] = (includes1 + includes2).uniq - end - - options[:plugins].compact! - options[:plugins].map!(&:to_sym) - @options = options - - treat_as_map = standard_treat_as_map # .clone - treat_as_map.merge!(@options[:treat_as]) - @options[:treat_as] = treat_as_map - - @options.each_key do |key| - unless methods.include?(key) - eval("def #{key}() return @options[:#{key}] end") - end - end - end - - def load_config_file_from_yaml(yaml_filename) - self.class.load_config_file_from_yaml yaml_filename - end - - def self.load_config_file_from_yaml(yaml_filename) - require 'yaml' - require 'fileutils' - YAML.load_file(yaml_filename)[:cmock] - end - - def path(new_path) - @src_path = new_path - end - - def load_unity_helper - return nil unless @options[:unity_helper_path] - - @options[:unity_helper_path].inject('') do |unity_helper, filename| - unity_helper + "\n" + File.new(filename).read - end - end - - def standard_treat_as_map - { - 'int' => 'INT', - 'char' => 'INT8', - 'short' => 'INT16', - 'long' => 'INT', - 'int8' => 'INT8', - 'int16' => 'INT16', - 'int32' => 'INT', - 'int8_t' => 'INT8', - 'int16_t' => 'INT16', - 'int32_t' => 'INT', - 'INT8_T' => 'INT8', - 'INT16_T' => 'INT16', - 'INT32_T' => 'INT', - 'bool' => 'INT', - 'bool_t' => 'INT', - 'BOOL' => 'INT', - 'BOOL_T' => 'INT', - 'unsigned int' => 'HEX32', - 'unsigned long' => 'HEX32', - 'uint32' => 'HEX32', - 'uint32_t' => 'HEX32', - 'UINT32' => 'HEX32', - 'UINT32_T' => 'HEX32', - 'void*' => 'HEX8_ARRAY', - 'void const*' => 'HEX8_ARRAY', - 'const void*' => 'HEX8_ARRAY', - 'unsigned short' => 'HEX16', - 'uint16' => 'HEX16', - 'uint16_t' => 'HEX16', - 'UINT16' => 'HEX16', - 'UINT16_T' => 'HEX16', - 'unsigned char' => 'HEX8', - 'uint8' => 'HEX8', - 'uint8_t' => 'HEX8', - 'UINT8' => 'HEX8', - 'UINT8_T' => 'HEX8', - 'char*' => 'STRING', - 'char const*' => 'STRING', - 'const char*' => 'STRING', - 'pCHAR' => 'STRING', - 'cstring' => 'STRING', - 'CSTRING' => 'STRING', - 'float' => 'FLOAT', - 'double' => 'FLOAT' - } - end -end diff --git a/vendor/ceedling/vendor/cmock/lib/cmock_file_writer.rb b/vendor/ceedling/vendor/cmock/lib/cmock_file_writer.rb deleted file mode 100644 index f30c44b..0000000 --- a/vendor/ceedling/vendor/cmock/lib/cmock_file_writer.rb +++ /dev/null @@ -1,47 +0,0 @@ -# ========================================== -# CMock Project - Automatic Mock Generation for C -# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams -# [Released under MIT License. Please refer to license.txt for details] -# ========================================== - -class CMockFileWriter - attr_reader :config - - def initialize(config) - @config = config - end - - def create_subdir(subdir) - require 'fileutils' - FileUtils.mkdir_p "#{@config.mock_path}/" unless Dir.exist?("#{@config.mock_path}/") - FileUtils.mkdir_p "#{@config.mock_path}/#{subdir + '/' if subdir}" if subdir && !Dir.exist?("#{@config.mock_path}/#{subdir + '/' if subdir}") - end - - def create_file(filename, subdir) - raise "Where's the block of data to create?" unless block_given? - - full_file_name_temp = "#{@config.mock_path}/#{subdir + '/' if subdir}#{filename}.new" - full_file_name_done = "#{@config.mock_path}/#{subdir + '/' if subdir}#{filename}" - File.open(full_file_name_temp, 'w') do |file| - yield(file, filename) - end - update_file(full_file_name_done, full_file_name_temp) - end - - def append_file(filename, subdir) - raise "Where's the block of data to create?" unless block_given? - - full_file_name = "#{@config.skeleton_path}/#{subdir + '/' if subdir}#{filename}" - File.open(full_file_name, 'a') do |file| - yield(file, filename) - end - end - - private ################################### - - def update_file(dest, src) - require 'fileutils' - FileUtils.rm(dest, :force => true) - FileUtils.mv(src, dest) - end -end diff --git a/vendor/ceedling/vendor/cmock/lib/cmock_generator.rb b/vendor/ceedling/vendor/cmock/lib/cmock_generator.rb deleted file mode 100644 index 6ed5110..0000000 --- a/vendor/ceedling/vendor/cmock/lib/cmock_generator.rb +++ /dev/null @@ -1,368 +0,0 @@ -# ========================================== -# CMock Project - Automatic Mock Generation for C -# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams -# [Released under MIT License. Please refer to license.txt for details] -# ========================================== - -class CMockGenerator - attr_accessor :config, :file_writer, :module_name, :module_ext, :clean_mock_name, :mock_name, :utils, :plugins, :weak, :ordered - - def initialize(config, file_writer, utils, plugins) - @file_writer = file_writer - @utils = utils - @plugins = plugins - @config = config - @prefix = @config.mock_prefix - @suffix = @config.mock_suffix - @weak = @config.weak - @include_inline = @config.treat_inlines - @ordered = @config.enforce_strict_ordering - @framework = @config.framework.to_s - @fail_on_unexpected_calls = @config.fail_on_unexpected_calls - @exclude_setjmp_h = @config.exclude_setjmp_h - @subdir = @config.subdir - - @includes_h_pre_orig_header = (@config.includes || @config.includes_h_pre_orig_header || []).map { |h| h =~ /</ ? h : "\"#{h}\"" } - @includes_h_post_orig_header = (@config.includes_h_post_orig_header || []).map { |h| h =~ /</ ? h : "\"#{h}\"" } - @includes_c_pre_header = (@config.includes_c_pre_header || []).map { |h| h =~ /</ ? h : "\"#{h}\"" } - @includes_c_post_header = (@config.includes_c_post_header || []).map { |h| h =~ /</ ? h : "\"#{h}\"" } - - here = File.dirname __FILE__ - unity_path_in_ceedling = "#{here}/../../unity" # path to Unity from within Ceedling - unity_path_in_cmock = "#{here}/../vendor/unity" # path to Unity from within CMock - # path to Unity as specified by env var - unity_path_in_env = ENV.key?('UNITY_DIR') ? File.expand_path(ENV.fetch('UNITY_DIR')) : nil - - if unity_path_in_env && File.exist?(unity_path_in_env) - require "#{unity_path_in_env}/auto/type_sanitizer" - elsif File.exist? unity_path_in_ceedling - require "#{unity_path_in_ceedling}/auto/type_sanitizer" - elsif File.exist? unity_path_in_cmock - require "#{unity_path_in_cmock}/auto/type_sanitizer" - else - raise 'Failed to find an instance of Unity to pull in type_sanitizer module!' - end - end - - def create_mock(module_name, parsed_stuff, module_ext = nil, folder = nil) - # determine the name for our new mock - mock_name = @prefix + module_name + @suffix - - # determine the folder our mock will reside - mock_folder = if folder && @subdir - File.join(@subdir, folder) - elsif @subdir - @subdir - else - folder - end - - # adds a trailing slash to the folder output - mock_folder = File.join(mock_folder, '') if mock_folder - - # create out mock project from incoming data - mock_project = { - :module_name => module_name, - :module_ext => (module_ext || '.h'), - :mock_name => mock_name, - :clean_name => TypeSanitizer.sanitize_c_identifier(mock_name), - :folder => mock_folder, - :parsed_stuff => parsed_stuff, - :skeleton => false - } - - create_mock_subdir(mock_project) - create_mock_header_file(mock_project) - create_mock_source_file(mock_project) - end - - def create_skeleton(module_name, parsed_stuff) - mock_project = { - :module_name => module_name, - :module_ext => '.h', - :parsed_stuff => parsed_stuff, - :skeleton => true - } - - create_skeleton_source_file(mock_project) - end - - private if $ThisIsOnlyATest.nil? ############################## - - def create_mock_subdir(mock_project) - @file_writer.create_subdir(mock_project[:folder]) - end - - def create_using_statement(file, function) - file << "using namespace #{function[:namespace].join('::')};\n" unless function[:namespace].empty? - end - - def create_mock_header_file(mock_project) - if @include_inline == :include - @file_writer.create_file(mock_project[:module_name] + (mock_project[:module_ext]), mock_project[:folder]) do |file, _filename| - file << mock_project[:parsed_stuff][:normalized_source] - end - end - - @file_writer.create_file(mock_project[:mock_name] + mock_project[:module_ext], mock_project[:folder]) do |file, filename| - create_mock_header_header(file, filename, mock_project) - create_mock_header_service_call_declarations(file, mock_project) - create_typedefs(file, mock_project) - mock_project[:parsed_stuff][:functions].each do |function| - create_using_statement(file, function) - file << @plugins.run(:mock_function_declarations, function) - end - create_mock_header_footer(file) - end - end - - def create_mock_source_file(mock_project) - @file_writer.create_file(mock_project[:mock_name] + '.c', mock_project[:folder]) do |file, filename| - create_source_header_section(file, filename, mock_project) - create_instance_structure(file, mock_project) - create_extern_declarations(file) - create_mock_verify_function(file, mock_project) - create_mock_init_function(file, mock_project) - create_mock_destroy_function(file, mock_project) - mock_project[:parsed_stuff][:functions].each do |function| - create_mock_implementation(file, function) - create_mock_interfaces(file, function) - end - end - end - - def create_skeleton_source_file(mock_project) - filename = "#{@config.mock_path}/#{@subdir + '/' if @subdir}#{mock_project[:module_name]}.c" - existing = File.exist?(filename) ? File.read(filename) : '' - @file_writer.append_file(mock_project[:module_name] + '.c', @subdir) do |file, fullname| - blank_project = mock_project.clone - blank_project[:parsed_stuff] = { :functions => [] } - create_source_header_section(file, fullname, blank_project) if existing.empty? - mock_project[:parsed_stuff][:functions].each do |function| - create_function_skeleton(file, function, existing) - end - end - end - - def create_mock_header_header(file, _filename, mock_project) - define_name = mock_project[:clean_name].upcase - orig_filename = (mock_project[:folder] || '') + mock_project[:module_name] + mock_project[:module_ext] - file << "/* AUTOGENERATED FILE. DO NOT EDIT. */\n" - file << "#ifndef _#{define_name}_H\n" - file << "#define _#{define_name}_H\n\n" - file << "#include \"#{@framework}.h\"\n" - @includes_h_pre_orig_header.each { |inc| file << "#include #{inc}\n" } - file << @config.orig_header_include_fmt.gsub(/%s/, orig_filename.to_s) + "\n" - @includes_h_post_orig_header.each { |inc| file << "#include #{inc}\n" } - plugin_includes = @plugins.run(:include_files) - file << plugin_includes unless plugin_includes.empty? - file << "\n" - file << "/* Ignore the following warnings, since we are copying code */\n" - file << "#if defined(__GNUC__) && !defined(__ICC) && !defined(__TMS470__)\n" - file << "#if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ > 6 || (__GNUC_MINOR__ == 6 && __GNUC_PATCHLEVEL__ > 0)))\n" - file << "#pragma GCC diagnostic push\n" - file << "#endif\n" - file << "#if !defined(__clang__)\n" - file << "#pragma GCC diagnostic ignored \"-Wpragmas\"\n" - file << "#endif\n" - file << "#pragma GCC diagnostic ignored \"-Wunknown-pragmas\"\n" - file << "#pragma GCC diagnostic ignored \"-Wduplicate-decl-specifier\"\n" - file << "#endif\n" - file << "\n" - end - - def create_typedefs(file, mock_project) - file << "\n" - mock_project[:parsed_stuff][:typedefs].each { |typedef| file << "#{typedef}\n" } - file << "\n\n" - end - - def create_mock_header_service_call_declarations(file, mock_project) - file << "void #{mock_project[:clean_name]}_Init(void);\n" - file << "void #{mock_project[:clean_name]}_Destroy(void);\n" - file << "void #{mock_project[:clean_name]}_Verify(void);\n\n" - end - - def create_mock_header_footer(header) - header << "\n" - header << "#if defined(__GNUC__) && !defined(__ICC) && !defined(__TMS470__)\n" - header << "#if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ > 6 || (__GNUC_MINOR__ == 6 && __GNUC_PATCHLEVEL__ > 0)))\n" - header << "#pragma GCC diagnostic pop\n" - header << "#endif\n" - header << "#endif\n" - header << "\n" - header << "#endif\n" - end - - def create_source_header_section(file, filename, mock_project) - header_file = (mock_project[:folder] || '') + filename.gsub('.c', mock_project[:module_ext]) - file << "/* AUTOGENERATED FILE. DO NOT EDIT. */\n" unless mock_project[:parsed_stuff][:functions].empty? - file << "#include <string.h>\n" - file << "#include <stdlib.h>\n" - unless @exclude_setjmp_h - file << "#include <setjmp.h>\n" - end - file << "#include \"cmock.h\"\n" - @includes_c_pre_header.each { |inc| file << "#include #{inc}\n" } - file << "#include \"#{header_file}\"\n" - @includes_c_post_header.each { |inc| file << "#include #{inc}\n" } - file << "\n" - strs = [] - mock_project[:parsed_stuff][:functions].each do |func| - strs << func[:name] - func[:args].each { |arg| strs << arg[:name] } - end - strs.uniq.sort.each do |str| - file << "static const char* CMockString_#{str} = \"#{str}\";\n" - end - file << "\n" - end - - def create_instance_structure(file, mock_project) - functions = mock_project[:parsed_stuff][:functions] - functions.each do |function| - file << "typedef struct _CMOCK_#{function[:name]}_CALL_INSTANCE\n{\n" - file << " UNITY_LINE_TYPE LineNumber;\n" - file << @plugins.run(:instance_typedefs, function) - file << "\n} CMOCK_#{function[:name]}_CALL_INSTANCE;\n\n" - end - file << "static struct #{mock_project[:clean_name]}Instance\n{\n" - if functions.empty? - file << " unsigned char placeHolder;\n" - end - functions.each do |function| - file << @plugins.run(:instance_structure, function) - file << " CMOCK_MEM_INDEX_TYPE #{function[:name]}_CallInstance;\n" - end - file << "} Mock;\n\n" - end - - def create_extern_declarations(file) - unless @exclude_setjmp_h - file << "extern jmp_buf AbortFrame;\n" - end - if @ordered - file << "extern int GlobalExpectCount;\n" - file << "extern int GlobalVerifyOrder;\n" - end - file << "\n" - end - - def create_mock_verify_function(file, mock_project) - file << "void #{mock_project[:clean_name]}_Verify(void)\n{\n" - verifications = mock_project[:parsed_stuff][:functions].collect do |function| - v = @plugins.run(:mock_verify, function) - v.empty? ? v : [" call_instance = Mock.#{function[:name]}_CallInstance;\n", v] - end.join - unless verifications.empty? - file << " UNITY_LINE_TYPE cmock_line = TEST_LINE_NUM;\n" - file << " CMOCK_MEM_INDEX_TYPE call_instance;\n" - file << verifications - end - file << "}\n\n" - end - - def create_mock_init_function(file, mock_project) - file << "void #{mock_project[:clean_name]}_Init(void)\n{\n" - file << " #{mock_project[:clean_name]}_Destroy();\n" - file << "}\n\n" - end - - def create_mock_destroy_function(file, mock_project) - file << "void #{mock_project[:clean_name]}_Destroy(void)\n{\n" - file << " CMock_Guts_MemFreeAll();\n" - file << " memset(&Mock, 0, sizeof(Mock));\n" - file << mock_project[:parsed_stuff][:functions].collect { |function| @plugins.run(:mock_destroy, function) }.join - - unless @fail_on_unexpected_calls - file << mock_project[:parsed_stuff][:functions].collect { |function| @plugins.run(:mock_ignore, function) }.join - end - - if @ordered - file << " GlobalExpectCount = 0;\n" - file << " GlobalVerifyOrder = 0;\n" - end - file << "}\n\n" - end - - def create_mock_implementation(file, function) - # prepare return value and arguments - function_mod_and_rettype = (function[:modifier].empty? ? '' : "#{function[:modifier]} ") + - (function[:return][:type]) + - (function[:c_calling_convention] ? " #{function[:c_calling_convention]}" : '') - args_string = function[:args_string] - args_string += (', ' + function[:var_arg]) unless function[:var_arg].nil? - - # Encapsulate in namespace(s) if applicable - function[:namespace].each do |ns| - file << "namespace #{ns} {\n" - end - - # Determine class prefix (if any) - cls_pre = '' - unless function[:class].nil? - cls_pre = "#{function[:class]}::" - end - - # Create mock function - unless @weak.empty? - file << "#if defined (__IAR_SYSTEMS_ICC__)\n" - file << "#pragma weak #{function[:unscoped_name]}\n" - file << "#else\n" - file << "#{function_mod_and_rettype} #{function[:unscoped_name]}(#{args_string}) #{weak};\n" - file << "#endif\n\n" - end - file << "#{function_mod_and_rettype} #{cls_pre}#{function[:unscoped_name]}(#{args_string})\n" - file << "{\n" - file << " UNITY_LINE_TYPE cmock_line = TEST_LINE_NUM;\n" - file << " CMOCK_#{function[:name]}_CALL_INSTANCE* cmock_call_instance;\n" - file << " UNITY_SET_DETAIL(CMockString_#{function[:name]});\n" - file << " cmock_call_instance = (CMOCK_#{function[:name]}_CALL_INSTANCE*)CMock_Guts_GetAddressFor(Mock.#{function[:name]}_CallInstance);\n" - file << " Mock.#{function[:name]}_CallInstance = CMock_Guts_MemNext(Mock.#{function[:name]}_CallInstance);\n" - file << @plugins.run(:mock_implementation_precheck, function) - file << " UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringCalledMore);\n" - file << " cmock_line = cmock_call_instance->LineNumber;\n" - if @ordered - file << " if (cmock_call_instance->CallOrder > ++GlobalVerifyOrder)\n" - file << " UNITY_TEST_FAIL(cmock_line, CMockStringCalledEarly);\n" - file << " if (cmock_call_instance->CallOrder < GlobalVerifyOrder)\n" - file << " UNITY_TEST_FAIL(cmock_line, CMockStringCalledLate);\n" - end - file << @plugins.run(:mock_implementation, function) - file << " UNITY_CLR_DETAILS();\n" - file << " return cmock_call_instance->ReturnVal;\n" unless function[:return][:void?] - file << "}\n" - - # Close any namespace(s) opened above - function[:namespace].each do - file << "}\n" - end - - file << "\n" - end - - def create_mock_interfaces(file, function) - file << @utils.code_add_argument_loader(function) - file << @plugins.run(:mock_interfaces, function) - end - - def create_function_skeleton(file, function, existing) - # prepare return value and arguments - function_mod_and_rettype = (function[:modifier].empty? ? '' : "#{function[:modifier]} ") + - (function[:return][:type]) + - (function[:c_calling_convention] ? " #{function[:c_calling_convention]}" : '') - args_string = function[:args_string] - args_string += (', ' + function[:var_arg]) unless function[:var_arg].nil? - - decl = "#{function_mod_and_rettype} #{function[:name]}(#{args_string})" - - return if existing.include?(decl) - - file << "#{decl}\n" - file << "{\n" - file << " /*TODO: Implement Me!*/\n" - function[:args].each { |arg| file << " (void)#{arg[:name]};\n" } - file << " return (#{(function[:return][:type])})0;\n" unless function[:return][:void?] - file << "}\n\n" - end -end diff --git a/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_array.rb b/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_array.rb deleted file mode 100644 index a9864ab..0000000 --- a/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_array.rb +++ /dev/null @@ -1,63 +0,0 @@ -# ========================================== -# CMock Project - Automatic Mock Generation for C -# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams -# [Released under MIT License. Please refer to license.txt for details] -# ========================================== - -class CMockGeneratorPluginArray - attr_reader :priority - attr_accessor :config, :utils, :unity_helper, :ordered - def initialize(config, utils) - @config = config - @ptr_handling = @config.when_ptr - @ordered = @config.enforce_strict_ordering - @utils = utils - @unity_helper = @utils.helpers[:unity_helper] - @priority = 8 - end - - def instance_typedefs(function) - function[:args].inject('') do |all, arg| - arg[:ptr?] ? all + " int Expected_#{arg[:name]}_Depth;\n" : all - end - end - - def mock_function_declarations(function) - return nil unless function[:contains_ptr?] - - args_call = function[:args].map { |m| m[:ptr?] ? "#{m[:name]}, #{m[:name]}_Depth" : (m[:name]).to_s }.join(', ') - args_string = function[:args].map do |m| - type = @utils.arg_type_with_const(m) - m[:ptr?] ? "#{type} #{m[:name]}, int #{m[:name]}_Depth" : "#{type} #{m[:name]}" - end.join(', ') - if function[:return][:void?] - return "#define #{function[:name]}_ExpectWithArray(#{args_call}) #{function[:name]}_CMockExpectWithArray(__LINE__, #{args_call})\n" \ - "void #{function[:name]}_CMockExpectWithArray(UNITY_LINE_TYPE cmock_line, #{args_string});\n" - else - return "#define #{function[:name]}_ExpectWithArrayAndReturn(#{args_call}, cmock_retval) #{function[:name]}_CMockExpectWithArrayAndReturn(__LINE__, #{args_call}, cmock_retval)\n" \ - "void #{function[:name]}_CMockExpectWithArrayAndReturn(UNITY_LINE_TYPE cmock_line, #{args_string}, #{function[:return][:str]});\n" - end - end - - def mock_interfaces(function) - return nil unless function[:contains_ptr?] - - lines = [] - func_name = function[:name] - args_string = function[:args].map do |m| - type = @utils.arg_type_with_const(m) - m[:ptr?] ? "#{type} #{m[:name]}, int #{m[:name]}_Depth" : "#{type} #{m[:name]}" - end.join(', ') - call_string = function[:args].map { |m| m[:ptr?] ? "#{m[:name]}, #{m[:name]}_Depth" : m[:name] }.join(', ') - lines << if function[:return][:void?] - "void #{func_name}_CMockExpectWithArray(UNITY_LINE_TYPE cmock_line, #{args_string})\n" - else - "void #{func_name}_CMockExpectWithArrayAndReturn(UNITY_LINE_TYPE cmock_line, #{args_string}, #{function[:return][:str]})\n" - end - lines << "{\n" - lines << @utils.code_add_base_expectation(func_name) - lines << " CMockExpectParameters_#{func_name}(cmock_call_instance, #{call_string});\n" - lines << " cmock_call_instance->ReturnVal = cmock_to_return;\n" unless function[:return][:void?] - lines << "}\n\n" - end -end diff --git a/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_callback.rb b/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_callback.rb deleted file mode 100644 index 6ba8e9b..0000000 --- a/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_callback.rb +++ /dev/null @@ -1,88 +0,0 @@ -# ========================================== -# CMock Project - Automatic Mock Generation for C -# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams -# [Released under MIT License. Please refer to license.txt for details] -# ========================================== - -class CMockGeneratorPluginCallback - attr_accessor :include_count - attr_reader :priority - attr_reader :config, :utils - - def initialize(config, utils) - @config = config - @utils = utils - @priority = 6 - - @include_count = @config.callback_include_count - end - - def instance_structure(function) - func_name = function[:name] - " char #{func_name}_CallbackBool;\n" \ - " CMOCK_#{func_name}_CALLBACK #{func_name}_CallbackFunctionPointer;\n" \ - " int #{func_name}_CallbackCalls;\n" - end - - def mock_function_declarations(function) - func_name = function[:name] - return_type = function[:return][:type] - action = @config.callback_after_arg_check ? 'AddCallback' : 'Stub' - style = (@include_count ? 1 : 0) | (function[:args].empty? ? 0 : 2) - styles = ['void', 'int cmock_num_calls', function[:args_string], "#{function[:args_string]}, int cmock_num_calls"] - "typedef #{return_type} (* CMOCK_#{func_name}_CALLBACK)(#{styles[style]});\n" \ - "void #{func_name}_AddCallback(CMOCK_#{func_name}_CALLBACK Callback);\n" \ - "void #{func_name}_Stub(CMOCK_#{func_name}_CALLBACK Callback);\n" \ - "#define #{func_name}_StubWithCallback #{func_name}_#{action}\n" - end - - def generate_call(function) - args = function[:args].map { |m| m[:name] } - args << "Mock.#{function[:name]}_CallbackCalls++" if @include_count - "Mock.#{function[:name]}_CallbackFunctionPointer(#{args.join(', ')})" - end - - def mock_implementation(function) - " if (Mock.#{function[:name]}_CallbackFunctionPointer != NULL)\n {\n" + - if function[:return][:void?] - " #{generate_call(function)};\n }\n" - else - " cmock_call_instance->ReturnVal = #{generate_call(function)};\n }\n" - end - end - - def mock_implementation_precheck(function) - " if (!Mock.#{function[:name]}_CallbackBool &&\n" \ - " Mock.#{function[:name]}_CallbackFunctionPointer != NULL)\n {\n" + - if function[:return][:void?] - " #{generate_call(function)};\n" \ - " UNITY_CLR_DETAILS();\n" \ - " return;\n }\n" - else - " #{function[:return][:type]} cmock_cb_ret = #{generate_call(function)};\n" \ - " UNITY_CLR_DETAILS();\n" \ - " return cmock_cb_ret;\n }\n" - end - end - - def mock_interfaces(function) - func_name = function[:name] - has_ignore = @config.plugins.include? :ignore - lines = '' - lines << "void #{func_name}_AddCallback(CMOCK_#{func_name}_CALLBACK Callback)\n{\n" - lines << " Mock.#{func_name}_IgnoreBool = (char)0;\n" if has_ignore - lines << " Mock.#{func_name}_CallbackBool = (char)1;\n" - lines << " Mock.#{func_name}_CallbackFunctionPointer = Callback;\n}\n\n" - lines << "void #{func_name}_Stub(CMOCK_#{func_name}_CALLBACK Callback)\n{\n" - lines << " Mock.#{func_name}_IgnoreBool = (char)0;\n" if has_ignore - lines << " Mock.#{func_name}_CallbackBool = (char)0;\n" - lines << " Mock.#{func_name}_CallbackFunctionPointer = Callback;\n}\n\n" - end - - def mock_verify(function) - func_name = function[:name] - " if (Mock.#{func_name}_CallbackFunctionPointer != NULL)\n {\n" \ - " call_instance = CMOCK_GUTS_NONE;\n" \ - " (void)call_instance;\n }\n" - end -end diff --git a/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_cexception.rb b/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_cexception.rb deleted file mode 100644 index 7e2d7b6..0000000 --- a/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_cexception.rb +++ /dev/null @@ -1,50 +0,0 @@ -# ========================================== -# CMock Project - Automatic Mock Generation for C -# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams -# [Released under MIT License. Please refer to license.txt for details] -# ========================================== - -class CMockGeneratorPluginCexception - attr_reader :priority - attr_reader :config, :utils - - def initialize(config, utils) - @config = config - @utils = utils - @priority = 7 - raise 'Error: cexception is not supported without setjmp support' if @config.exclude_setjmp_h - end - - def include_files - "#include \"CException.h\"\n" - end - - def instance_typedefs(_function) - " CEXCEPTION_T ExceptionToThrow;\n" - end - - def mock_function_declarations(function) - if function[:args_string] == 'void' - "#define #{function[:name]}_ExpectAndThrow(cmock_to_throw) #{function[:name]}_CMockExpectAndThrow(__LINE__, cmock_to_throw)\n" \ - "void #{function[:name]}_CMockExpectAndThrow(UNITY_LINE_TYPE cmock_line, CEXCEPTION_T cmock_to_throw);\n" - else - "#define #{function[:name]}_ExpectAndThrow(#{function[:args_call]}, cmock_to_throw) #{function[:name]}_CMockExpectAndThrow(__LINE__, #{function[:args_call]}, cmock_to_throw)\n" \ - "void #{function[:name]}_CMockExpectAndThrow(UNITY_LINE_TYPE cmock_line, #{function[:args_string]}, CEXCEPTION_T cmock_to_throw);\n" - end - end - - def mock_implementation(_function) - " if (cmock_call_instance->ExceptionToThrow != CEXCEPTION_NONE)\n {\n" \ - " UNITY_CLR_DETAILS();\n" \ - " Throw(cmock_call_instance->ExceptionToThrow);\n }\n" - end - - def mock_interfaces(function) - arg_insert = function[:args_string] == 'void' ? '' : "#{function[:args_string]}, " - ["void #{function[:name]}_CMockExpectAndThrow(UNITY_LINE_TYPE cmock_line, #{arg_insert}CEXCEPTION_T cmock_to_throw)\n{\n", - @utils.code_add_base_expectation(function[:name]), - @utils.code_call_argument_loader(function), - " cmock_call_instance->ExceptionToThrow = cmock_to_throw;\n", - "}\n\n"].join - end -end diff --git a/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_expect.rb b/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_expect.rb deleted file mode 100644 index 3a79c1a..0000000 --- a/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_expect.rb +++ /dev/null @@ -1,100 +0,0 @@ -# ========================================== -# CMock Project - Automatic Mock Generation for C -# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams -# [Released under MIT License. Please refer to license.txt for details] -# ========================================== - -class CMockGeneratorPluginExpect - attr_reader :priority - attr_accessor :config, :utils, :unity_helper, :ordered - - def initialize(config, utils) - @config = config - @ptr_handling = @config.when_ptr - @ordered = @config.enforce_strict_ordering - @utils = utils - @unity_helper = @utils.helpers[:unity_helper] - @priority = 5 - - if @config.plugins.include? :expect_any_args - alias :mock_implementation :mock_implementation_might_check_args - else - alias :mock_implementation :mock_implementation_always_check_args - end - end - - def instance_typedefs(function) - lines = '' - lines << " #{function[:return][:type]} ReturnVal;\n" unless function[:return][:void?] - lines << " int CallOrder;\n" if @ordered - function[:args].each do |arg| - lines << " #{arg[:type]} Expected_#{arg[:name]};\n" - end - lines - end - - def mock_function_declarations(function) - if function[:args].empty? - if function[:return][:void?] - "#define #{function[:name]}_Expect() #{function[:name]}_CMockExpect(__LINE__)\n" \ - "void #{function[:name]}_CMockExpect(UNITY_LINE_TYPE cmock_line);\n" - else - "#define #{function[:name]}_ExpectAndReturn(cmock_retval) #{function[:name]}_CMockExpectAndReturn(__LINE__, cmock_retval)\n" \ - "void #{function[:name]}_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]});\n" - end - elsif function[:return][:void?] - "#define #{function[:name]}_Expect(#{function[:args_call]}) #{function[:name]}_CMockExpect(__LINE__, #{function[:args_call]})\n" \ - "void #{function[:name]}_CMockExpect(UNITY_LINE_TYPE cmock_line, #{function[:args_string]});\n" - else - "#define #{function[:name]}_ExpectAndReturn(#{function[:args_call]}, cmock_retval) #{function[:name]}_CMockExpectAndReturn(__LINE__, #{function[:args_call]}, cmock_retval)\n" \ - "void #{function[:name]}_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:args_string]}, #{function[:return][:str]});\n" - end - end - - def mock_implementation_always_check_args(function) - lines = '' - function[:args].each do |arg| - lines << @utils.code_verify_an_arg_expectation(function, arg) - end - lines - end - - def mock_implementation_might_check_args(function) - return '' if function[:args].empty? - - lines = " if (!cmock_call_instance->ExpectAnyArgsBool)\n {\n" - function[:args].each do |arg| - lines << @utils.code_verify_an_arg_expectation(function, arg) - end - lines << " }\n" - lines - end - - def mock_interfaces(function) - lines = '' - func_name = function[:name] - lines << if function[:return][:void?] - if function[:args_string] == 'void' - "void #{func_name}_CMockExpect(UNITY_LINE_TYPE cmock_line)\n{\n" - else - "void #{func_name}_CMockExpect(UNITY_LINE_TYPE cmock_line, #{function[:args_string]})\n{\n" - end - elsif function[:args_string] == 'void' - "void #{func_name}_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]})\n{\n" - else - "void #{func_name}_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:args_string]}, #{function[:return][:str]})\n{\n" - end - lines << @utils.code_add_base_expectation(func_name) - lines << @utils.code_call_argument_loader(function) - lines << @utils.code_assign_argument_quickly('cmock_call_instance->ReturnVal', function[:return]) unless function[:return][:void?] - lines << "}\n\n" - end - - def mock_verify(function) - " if (CMOCK_GUTS_NONE != call_instance)\n" \ - " {\n" \ - " UNITY_SET_DETAIL(CMockString_#{function[:name]});\n" \ - " UNITY_TEST_FAIL(cmock_line, CMockStringCalledLess);\n" \ - " }\n" - end -end diff --git a/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_expect_any_args.rb b/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_expect_any_args.rb deleted file mode 100644 index 0fc88e1..0000000 --- a/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_expect_any_args.rb +++ /dev/null @@ -1,50 +0,0 @@ -# ========================================== -# CMock Project - Automatic Mock Generation for C -# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams -# [Released under MIT License. Please refer to license.txt for details] -# ========================================== - -class CMockGeneratorPluginExpectAnyArgs - attr_reader :priority - attr_reader :config, :utils - - def initialize(config, utils) - @config = config - @utils = utils - @priority = 3 - end - - def instance_typedefs(_function) - " char ExpectAnyArgsBool;\n" - end - - def mock_function_declarations(function) - if function[:args].empty? - '' - elsif function[:return][:void?] - "#define #{function[:name]}_ExpectAnyArgs() #{function[:name]}_CMockExpectAnyArgs(__LINE__)\n" \ - "void #{function[:name]}_CMockExpectAnyArgs(UNITY_LINE_TYPE cmock_line);\n" - else - "#define #{function[:name]}_ExpectAnyArgsAndReturn(cmock_retval) #{function[:name]}_CMockExpectAnyArgsAndReturn(__LINE__, cmock_retval)\n" \ - "void #{function[:name]}_CMockExpectAnyArgsAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]});\n" - end - end - - def mock_interfaces(function) - lines = '' - unless function[:args].empty? - lines << if function[:return][:void?] - "void #{function[:name]}_CMockExpectAnyArgs(UNITY_LINE_TYPE cmock_line)\n{\n" - else - "void #{function[:name]}_CMockExpectAnyArgsAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]})\n{\n" - end - lines << @utils.code_add_base_expectation(function[:name], true) - unless function[:return][:void?] - lines << " cmock_call_instance->ReturnVal = cmock_to_return;\n" - end - lines << " cmock_call_instance->ExpectAnyArgsBool = (char)1;\n" - lines << "}\n\n" - end - lines - end -end diff --git a/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_ignore.rb b/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_ignore.rb deleted file mode 100644 index b292f3d..0000000 --- a/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_ignore.rb +++ /dev/null @@ -1,88 +0,0 @@ -# ========================================== -# CMock Project - Automatic Mock Generation for C -# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams -# [Released under MIT License. Please refer to license.txt for details] -# ========================================== - -class CMockGeneratorPluginIgnore - attr_reader :priority - attr_reader :config, :utils - - def initialize(config, utils) - @config = config - @utils = utils - @priority = 2 - end - - def instance_structure(function) - if function[:return][:void?] - " char #{function[:name]}_IgnoreBool;\n" - else - " char #{function[:name]}_IgnoreBool;\n #{function[:return][:type]} #{function[:name]}_FinalReturn;\n" - end - end - - def mock_function_declarations(function) - lines = if function[:return][:void?] - "#define #{function[:name]}_Ignore() #{function[:name]}_CMockIgnore()\n" \ - "void #{function[:name]}_CMockIgnore(void);\n" - else - "#define #{function[:name]}_IgnoreAndReturn(cmock_retval) #{function[:name]}_CMockIgnoreAndReturn(__LINE__, cmock_retval)\n" \ - "void #{function[:name]}_CMockIgnoreAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]});\n" - end - - # Add stop ignore function. it does not matter if there are any args - lines << "#define #{function[:name]}_StopIgnore() #{function[:name]}_CMockStopIgnore()\n" \ - "void #{function[:name]}_CMockStopIgnore(void);\n" - lines - end - - def mock_implementation_precheck(function) - lines = " if (Mock.#{function[:name]}_IgnoreBool)\n {\n" - lines << " UNITY_CLR_DETAILS();\n" - if function[:return][:void?] - lines << " return;\n }\n" - else - retval = function[:return].merge(:name => 'cmock_call_instance->ReturnVal') - lines << " if (cmock_call_instance == NULL)\n return Mock.#{function[:name]}_FinalReturn;\n" - lines << ' ' + @utils.code_assign_argument_quickly("Mock.#{function[:name]}_FinalReturn", retval) unless retval[:void?] - lines << " return cmock_call_instance->ReturnVal;\n }\n" - end - lines - end - - def mock_interfaces(function) - lines = '' - lines << if function[:return][:void?] - "void #{function[:name]}_CMockIgnore(void)\n{\n" - else - "void #{function[:name]}_CMockIgnoreAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]})\n{\n" - end - unless function[:return][:void?] - lines << @utils.code_add_base_expectation(function[:name], false) - end - unless function[:return][:void?] - lines << " cmock_call_instance->ReturnVal = cmock_to_return;\n" - end - lines << " Mock.#{function[:name]}_IgnoreBool = (char)1;\n" - lines << "}\n\n" - - # Add stop ignore function. it does not matter if there are any args - lines << "void #{function[:name]}_CMockStopIgnore(void)\n{\n" - unless function[:return][:void?] - lines << " if(Mock.#{function[:name]}_IgnoreBool)\n" - lines << " Mock.#{function[:name]}_CallInstance = CMock_Guts_MemNext(Mock.#{function[:name]}_CallInstance);\n" - end - lines << " Mock.#{function[:name]}_IgnoreBool = (char)0;\n" - lines << "}\n\n" - end - - def mock_ignore(function) - " Mock.#{function[:name]}_IgnoreBool = (char) 1;\n" - end - - def mock_verify(function) - func_name = function[:name] - " if (Mock.#{func_name}_IgnoreBool)\n call_instance = CMOCK_GUTS_NONE;\n" - end -end diff --git a/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_ignore_arg.rb b/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_ignore_arg.rb deleted file mode 100644 index d55e84c..0000000 --- a/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_ignore_arg.rb +++ /dev/null @@ -1,42 +0,0 @@ -class CMockGeneratorPluginIgnoreArg - attr_reader :priority - attr_accessor :utils - - def initialize(_config, utils) - @utils = utils - @priority = 10 - end - - def instance_typedefs(function) - lines = '' - function[:args].each do |arg| - lines << " char IgnoreArg_#{arg[:name]};\n" - end - lines - end - - def mock_function_declarations(function) - lines = '' - function[:args].each do |arg| - lines << "#define #{function[:name]}_IgnoreArg_#{arg[:name]}()" - lines << " #{function[:name]}_CMockIgnoreArg_#{arg[:name]}(__LINE__)\n" - lines << "void #{function[:name]}_CMockIgnoreArg_#{arg[:name]}(UNITY_LINE_TYPE cmock_line);\n" - end - lines - end - - def mock_interfaces(function) - lines = [] - func_name = function[:name] - function[:args].each do |arg| - lines << "void #{func_name}_CMockIgnoreArg_#{arg[:name]}(UNITY_LINE_TYPE cmock_line)\n" - lines << "{\n" - lines << " CMOCK_#{func_name}_CALL_INSTANCE* cmock_call_instance = " \ - "(CMOCK_#{func_name}_CALL_INSTANCE*)CMock_Guts_GetAddressFor(CMock_Guts_MemEndOfChain(Mock.#{func_name}_CallInstance));\n" - lines << " UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringIgnPreExp);\n" - lines << " cmock_call_instance->IgnoreArg_#{arg[:name]} = 1;\n" - lines << "}\n\n" - end - lines - end -end diff --git a/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_ignore_stateless.rb b/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_ignore_stateless.rb deleted file mode 100644 index 9196ede..0000000 --- a/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_ignore_stateless.rb +++ /dev/null @@ -1,85 +0,0 @@ -# ========================================== -# CMock Project - Automatic Mock Generation for C -# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams -# [Released under MIT License. Please refer to license.txt for details] -# ========================================== - -class CMockGeneratorPluginIgnoreStateless - attr_reader :priority - attr_reader :config, :utils - - def initialize(config, utils) - @config = config - @utils = utils - @priority = 2 - end - - def instance_structure(function) - if function[:return][:void?] - " char #{function[:name]}_IgnoreBool;\n" - else - " char #{function[:name]}_IgnoreBool;\n #{function[:return][:type]} #{function[:name]}_FinalReturn;\n" - end - end - - def mock_function_declarations(function) - lines = if function[:return][:void?] - "#define #{function[:name]}_Ignore() #{function[:name]}_CMockIgnore()\n" \ - "void #{function[:name]}_CMockIgnore(void);\n" - else - "#define #{function[:name]}_IgnoreAndReturn(cmock_retval) #{function[:name]}_CMockIgnoreAndReturn(cmock_retval)\n" \ - "void #{function[:name]}_CMockIgnoreAndReturn(#{function[:return][:str]});\n" - end - - # Add stop ignore function. it does not matter if there are any args - lines << "#define #{function[:name]}_StopIgnore() #{function[:name]}_CMockStopIgnore()\n" \ - "void #{function[:name]}_CMockStopIgnore(void);\n" - lines - end - - def mock_implementation_precheck(function) - lines = " if (Mock.#{function[:name]}_IgnoreBool)\n {\n" - lines << " UNITY_CLR_DETAILS();\n" - if function[:return][:void?] - lines << " return;\n }\n" - else - retval = function[:return].merge(:name => 'cmock_call_instance->ReturnVal') - lines << " if (cmock_call_instance == NULL)\n return Mock.#{function[:name]}_FinalReturn;\n" - lines << ' ' + @utils.code_assign_argument_quickly("Mock.#{function[:name]}_FinalReturn", retval) unless retval[:void?] - lines << " return cmock_call_instance->ReturnVal;\n }\n" - end - lines - end - - # this function is adjusted - def mock_interfaces(function) - lines = '' - lines << if function[:return][:void?] - "void #{function[:name]}_CMockIgnore(void)\n{\n" - else - "void #{function[:name]}_CMockIgnoreAndReturn(#{function[:return][:str]})\n{\n" - end - unless function[:return][:void?] - lines << " Mock.#{function[:name]}_CallInstance = CMOCK_GUTS_NONE;\n" - lines << " Mock.#{function[:name]}_FinalReturn = cmock_to_return;\n" - end - lines << " Mock.#{function[:name]}_IgnoreBool = (char)1;\n" - lines << "}\n\n" - - # Add stop ignore function. it does not matter if there are any args - lines << "void #{function[:name]}_CMockStopIgnore(void)\n{\n" - lines << " Mock.#{function[:name]}_IgnoreBool = (char)0;\n" - lines << "}\n\n" - - lines - end - - def mock_ignore(function) - " Mock.#{function[:name]}_IgnoreBool = (char)1;\n" - end - - def mock_verify(function) - func_name = function[:name] - " if (Mock.#{func_name}_IgnoreBool)\n call_instance = CMOCK_GUTS_NONE;\n" - end -end diff --git a/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_return_thru_ptr.rb b/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_return_thru_ptr.rb deleted file mode 100644 index 96b2003..0000000 --- a/vendor/ceedling/vendor/cmock/lib/cmock_generator_plugin_return_thru_ptr.rb +++ /dev/null @@ -1,79 +0,0 @@ -class CMockGeneratorPluginReturnThruPtr - attr_reader :priority - attr_accessor :utils - - def initialize(_config, utils) - @utils = utils - @priority = 9 - end - - def instance_typedefs(function) - lines = '' - function[:args].each do |arg| - next unless @utils.ptr_or_str?(arg[:type]) && !(arg[:const?]) - - lines << " char ReturnThruPtr_#{arg[:name]}_Used;\n" - lines << " #{arg[:type]} ReturnThruPtr_#{arg[:name]}_Val;\n" - lines << " size_t ReturnThruPtr_#{arg[:name]}_Size;\n" - end - lines - end - - def mock_function_declarations(function) - lines = '' - function[:args].each do |arg| - next unless @utils.ptr_or_str?(arg[:type]) && !(arg[:const?]) - - lines << "#define #{function[:name]}_ReturnThruPtr_#{arg[:name]}(#{arg[:name]})" - # If the pointer type actually contains an asterisk, we can do sizeof the type (super safe), otherwise - # we need to do a sizeof the dereferenced pointer (which could be a problem if give the wrong size - lines << if arg[:type][-1] == '*' - " #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(__LINE__, #{arg[:name]}, sizeof(#{arg[:type][0..-2]}))\n" - else - " #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(__LINE__, #{arg[:name]}, sizeof(*#{arg[:name]}))\n" - end - lines << "#define #{function[:name]}_ReturnArrayThruPtr_#{arg[:name]}(#{arg[:name]}, cmock_len)" - lines << " #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(__LINE__, #{arg[:name]}, cmock_len * sizeof(*#{arg[:name]}))\n" - lines << "#define #{function[:name]}_ReturnMemThruPtr_#{arg[:name]}(#{arg[:name]}, cmock_size)" - lines << " #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(__LINE__, #{arg[:name]}, cmock_size)\n" - lines << "void #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(UNITY_LINE_TYPE cmock_line, #{arg[:type]} #{arg[:name]}, size_t cmock_size);\n" - end - lines - end - - def mock_interfaces(function) - lines = [] - func_name = function[:name] - function[:args].each do |arg| - arg_name = arg[:name] - next unless @utils.ptr_or_str?(arg[:type]) && !(arg[:const?]) - - lines << "void #{func_name}_CMockReturnMemThruPtr_#{arg_name}(UNITY_LINE_TYPE cmock_line, #{arg[:type]} #{arg_name}, size_t cmock_size)\n" - lines << "{\n" - lines << " CMOCK_#{func_name}_CALL_INSTANCE* cmock_call_instance = " \ - "(CMOCK_#{func_name}_CALL_INSTANCE*)CMock_Guts_GetAddressFor(CMock_Guts_MemEndOfChain(Mock.#{func_name}_CallInstance));\n" - lines << " UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringPtrPreExp);\n" - lines << " cmock_call_instance->ReturnThruPtr_#{arg_name}_Used = 1;\n" - lines << " cmock_call_instance->ReturnThruPtr_#{arg_name}_Val = #{arg_name};\n" - lines << " cmock_call_instance->ReturnThruPtr_#{arg_name}_Size = cmock_size;\n" - lines << "}\n\n" - end - lines - end - - def mock_implementation(function) - lines = [] - function[:args].each do |arg| - arg_name = arg[:name] - next unless @utils.ptr_or_str?(arg[:type]) && !(arg[:const?]) - - lines << " if (cmock_call_instance->ReturnThruPtr_#{arg_name}_Used)\n" - lines << " {\n" - lines << " UNITY_TEST_ASSERT_NOT_NULL(#{arg_name}, cmock_line, CMockStringPtrIsNULL);\n" - lines << " memcpy((void*)#{arg_name}, (void*)cmock_call_instance->ReturnThruPtr_#{arg_name}_Val,\n" - lines << " cmock_call_instance->ReturnThruPtr_#{arg_name}_Size);\n" - lines << " }\n" - end - lines - end -end diff --git a/vendor/ceedling/vendor/cmock/lib/cmock_generator_utils.rb b/vendor/ceedling/vendor/cmock/lib/cmock_generator_utils.rb deleted file mode 100644 index ecbc37e..0000000 --- a/vendor/ceedling/vendor/cmock/lib/cmock_generator_utils.rb +++ /dev/null @@ -1,250 +0,0 @@ -# ========================================== -# CMock Project - Automatic Mock Generation for C -# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams -# [Released under MIT License. Please refer to license.txt for details] -# ========================================== - -class CMockGeneratorUtils - attr_accessor :config, :helpers, :ordered, :ptr_handling, :arrays, :cexception - - def initialize(config, helpers = {}) - @config = config - @ptr_handling = @config.when_ptr - @ordered = @config.enforce_strict_ordering - @arrays = @config.plugins.include? :array - @cexception = @config.plugins.include? :cexception - @expect_any = @config.plugins.include? :expect_any_args - @return_thru_ptr = @config.plugins.include? :return_thru_ptr - @ignore_arg = @config.plugins.include? :ignore_arg - @ignore = @config.plugins.include? :ignore - @ignore_stateless = @config.plugins.include? :ignore_stateless - @treat_as = @config.treat_as - @helpers = helpers - end - - def self.arg_type_with_const(arg) - # Restore any "const" that was removed in header parsing - if arg[:type].include?('*') - arg[:const_ptr?] ? "#{arg[:type]} const" : arg[:type] - else - arg[:const?] ? "const #{arg[:type]}" : arg[:type] - end - end - - def arg_type_with_const(arg) - self.class.arg_type_with_const(arg) - end - - def code_verify_an_arg_expectation(function, arg) - if @arrays - case @ptr_handling - when :smart then code_verify_an_arg_expectation_with_smart_arrays(function, arg) - when :compare_data then code_verify_an_arg_expectation_with_normal_arrays(function, arg) - when :compare_ptr then raise "ERROR: the array plugin doesn't enjoy working with :compare_ptr only. Disable one option." - end - else - code_verify_an_arg_expectation_with_no_arrays(function, arg) - end - end - - def code_add_base_expectation(func_name, global_ordering_supported = true) - lines = " CMOCK_MEM_INDEX_TYPE cmock_guts_index = CMock_Guts_MemNew(sizeof(CMOCK_#{func_name}_CALL_INSTANCE));\n" - lines << " CMOCK_#{func_name}_CALL_INSTANCE* cmock_call_instance = (CMOCK_#{func_name}_CALL_INSTANCE*)CMock_Guts_GetAddressFor(cmock_guts_index);\n" - lines << " UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringOutOfMemory);\n" - lines << " memset(cmock_call_instance, 0, sizeof(*cmock_call_instance));\n" - lines << " Mock.#{func_name}_CallInstance = CMock_Guts_MemChain(Mock.#{func_name}_CallInstance, cmock_guts_index);\n" - lines << " Mock.#{func_name}_IgnoreBool = (char)0;\n" if @ignore || @ignore_stateless - lines << " cmock_call_instance->LineNumber = cmock_line;\n" - lines << " cmock_call_instance->CallOrder = ++GlobalExpectCount;\n" if @ordered && global_ordering_supported - lines << " cmock_call_instance->ExceptionToThrow = CEXCEPTION_NONE;\n" if @cexception - lines << " cmock_call_instance->ExpectAnyArgsBool = (char)0;\n" if @expect_any - lines - end - - def code_add_an_arg_expectation(arg, depth = 1) - lines = code_assign_argument_quickly("cmock_call_instance->Expected_#{arg[:name]}", arg) - lines << " cmock_call_instance->Expected_#{arg[:name]}_Depth = #{arg[:name]}_Depth;\n" if @arrays && (depth.class == String) - lines << " cmock_call_instance->IgnoreArg_#{arg[:name]} = 0;\n" if @ignore_arg - lines << " cmock_call_instance->ReturnThruPtr_#{arg[:name]}_Used = 0;\n" if @return_thru_ptr && ptr_or_str?(arg[:type]) && !(arg[:const?]) - lines - end - - def code_assign_argument_quickly(dest, arg) - if arg[:ptr?] || @treat_as.include?(arg[:type]) - " #{dest} = #{arg[:name]};\n" - else - assert_expr = "sizeof(#{arg[:name]}) == sizeof(#{arg[:type]}) ? 1 : -1" - comment = "/* add #{arg[:type]} to :treat_as_array if this causes an error */" - " memcpy((void*)(&#{dest}), (void*)(&#{arg[:name]}),\n" \ - " sizeof(#{arg[:type]}[#{assert_expr}])); #{comment}\n" - end - end - - def code_add_argument_loader(function) - if function[:args_string] != 'void' - if @arrays - args_string = function[:args].map do |m| - type = arg_type_with_const(m) - m[:ptr?] ? "#{type} #{m[:name]}, int #{m[:name]}_Depth" : "#{type} #{m[:name]}" - end.join(', ') - "void CMockExpectParameters_#{function[:name]}(CMOCK_#{function[:name]}_CALL_INSTANCE* cmock_call_instance, #{args_string});\n" \ - "void CMockExpectParameters_#{function[:name]}(CMOCK_#{function[:name]}_CALL_INSTANCE* cmock_call_instance, #{args_string})\n{\n" + - function[:args].inject('') { |all, arg| all + code_add_an_arg_expectation(arg, (arg[:ptr?] ? "#{arg[:name]}_Depth" : 1)) } + - "}\n\n" - else - "void CMockExpectParameters_#{function[:name]}(CMOCK_#{function[:name]}_CALL_INSTANCE* cmock_call_instance, #{function[:args_string]});\n" \ - "void CMockExpectParameters_#{function[:name]}(CMOCK_#{function[:name]}_CALL_INSTANCE* cmock_call_instance, #{function[:args_string]})\n{\n" + - function[:args].inject('') { |all, arg| all + code_add_an_arg_expectation(arg) } + - "}\n\n" - end - else - '' - end - end - - def code_call_argument_loader(function) - if function[:args_string] != 'void' - args = function[:args].map do |m| - if @arrays && m[:ptr?] && !(m[:array_data?]) - "#{m[:name]}, 1" - elsif @arrays && m[:array_size?] - "#{m[:name]}, #{m[:name]}" - else - m[:name] - end - end - " CMockExpectParameters_#{function[:name]}(cmock_call_instance, #{args.join(', ')});\n" - else - '' - end - end - - def ptr_or_str?(arg_type) - (arg_type.include?('*') || - @treat_as.fetch(arg_type, '').include?('*')) - end - - # private ###################### - - def lookup_expect_type(_function, arg) - c_type = arg[:type] - arg_name = arg[:name] - expected = "cmock_call_instance->Expected_#{arg_name}" - ignore = "cmock_call_instance->IgnoreArg_#{arg_name}" - unity_func = if (arg[:ptr?]) && ((c_type =~ /\*\*/) || (@ptr_handling == :compare_ptr)) - ['UNITY_TEST_ASSERT_EQUAL_PTR', ''] - else - @helpers.nil? || @helpers[:unity_helper].nil? ? ['UNITY_TEST_ASSERT_EQUAL', ''] : @helpers[:unity_helper].get_helper(c_type) - end - [c_type, arg_name, expected, ignore, unity_func[0], unity_func[1]] - end - - def code_verify_an_arg_expectation_with_no_arrays(function, arg) - c_type, arg_name, expected, ignore, unity_func, pre = lookup_expect_type(function, arg) - lines = '' - lines << " if (!#{ignore})\n" if @ignore_arg - lines << " {\n" - lines << " UNITY_SET_DETAILS(CMockString_#{function[:name]},CMockString_#{arg_name});\n" - case unity_func - when 'UNITY_TEST_ASSERT_EQUAL_MEMORY' - c_type_local = c_type.gsub(/\*$/, '') - lines << " UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type_local}), cmock_line, CMockStringMismatch);\n" - when 'UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY' - if pre == '&' - lines << " UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type.sub('*', '')}), cmock_line, CMockStringMismatch);\n" - else - lines << " if (#{pre}#{expected} == NULL)\n" - lines << " { UNITY_TEST_ASSERT_NULL(#{pre}#{arg_name}, cmock_line, CMockStringExpNULL); }\n" - lines << " else\n" - lines << " { UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type.sub('*', '')}), cmock_line, CMockStringMismatch); }\n" - end - when /_ARRAY/ - if pre == '&' - lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, 1, cmock_line, CMockStringMismatch);\n" - else - lines << " if (#{pre}#{expected} == NULL)\n" - lines << " { UNITY_TEST_ASSERT_NULL(#{pre}#{arg_name}, cmock_line, CMockStringExpNULL); }\n" - lines << " else\n" - lines << " { #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, 1, cmock_line, CMockStringMismatch); }\n" - end - else - lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, CMockStringMismatch);\n" - end - lines << " }\n" - lines - end - - def code_verify_an_arg_expectation_with_normal_arrays(function, arg) - c_type, arg_name, expected, ignore, unity_func, pre = lookup_expect_type(function, arg) - depth_name = arg[:ptr?] ? "cmock_call_instance->Expected_#{arg_name}_Depth" : 1 - lines = '' - lines << " if (!#{ignore})\n" if @ignore_arg - lines << " {\n" - lines << " UNITY_SET_DETAILS(CMockString_#{function[:name]},CMockString_#{arg_name});\n" - case unity_func - when 'UNITY_TEST_ASSERT_EQUAL_MEMORY' - c_type_local = c_type.gsub(/\*$/, '') - lines << " UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type_local}), cmock_line, CMockStringMismatch);\n" - when 'UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY' - if pre == '&' - lines << " UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type.sub('*', '')}), cmock_line, CMockStringMismatch);\n" - else - lines << " if (#{pre}#{expected} == NULL)\n" - lines << " { UNITY_TEST_ASSERT_NULL(#{pre}#{arg_name}, cmock_line, CMockStringExpNULL); }\n" - lines << " else\n" - lines << " { UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type.sub('*', '')}), #{depth_name}, cmock_line, CMockStringMismatch); }\n" - end - when /_ARRAY/ - if pre == '&' - lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, #{depth_name}, cmock_line, CMockStringMismatch);\n" - else - lines << " if (#{pre}#{expected} == NULL)\n" - lines << " { UNITY_TEST_ASSERT_NULL(#{pre}#{arg_name}, cmock_line, CMockStringExpNULL); }\n" - lines << " else\n" - lines << " { #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, #{depth_name}, cmock_line, CMockStringMismatch); }\n" - end - else - lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, CMockStringMismatch);\n" - end - lines << " }\n" - lines - end - - def code_verify_an_arg_expectation_with_smart_arrays(function, arg) - c_type, arg_name, expected, ignore, unity_func, pre = lookup_expect_type(function, arg) - depth_name = arg[:ptr?] ? "cmock_call_instance->Expected_#{arg_name}_Depth" : 1 - lines = '' - lines << " if (!#{ignore})\n" if @ignore_arg - lines << " {\n" - lines << " UNITY_SET_DETAILS(CMockString_#{function[:name]},CMockString_#{arg_name});\n" - case unity_func - when 'UNITY_TEST_ASSERT_EQUAL_MEMORY' - c_type_local = c_type.gsub(/\*$/, '') - lines << " UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type_local}), cmock_line, CMockStringMismatch);\n" - when 'UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY' - if pre == '&' - lines << " UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type.sub('*', '')}), #{depth_name}, cmock_line, CMockStringMismatch);\n" - else - lines << " if (#{pre}#{expected} == NULL)\n" - lines << " { UNITY_TEST_ASSERT_NULL(#{arg_name}, cmock_line, CMockStringExpNULL); }\n" - lines << (depth_name != 1 ? " else if (#{depth_name} == 0)\n { UNITY_TEST_ASSERT_EQUAL_PTR(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, CMockStringMismatch); }\n" : '') - lines << " else\n" - lines << " { UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type.sub('*', '')}), #{depth_name}, cmock_line, CMockStringMismatch); }\n" - end - when /_ARRAY/ - if pre == '&' - lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, #{depth_name}, cmock_line, CMockStringMismatch);\n" - else - lines << " if (#{pre}#{expected} == NULL)\n" - lines << " { UNITY_TEST_ASSERT_NULL(#{pre}#{arg_name}, cmock_line, CMockStringExpNULL); }\n" - lines << (depth_name != 1 ? " else if (#{depth_name} == 0)\n { UNITY_TEST_ASSERT_EQUAL_PTR(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, CMockStringMismatch); }\n" : '') - lines << " else\n" - lines << " { #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, #{depth_name}, cmock_line, CMockStringMismatch); }\n" - end - else - lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, CMockStringMismatch);\n" - end - lines << " }\n" - lines - end -end diff --git a/vendor/ceedling/vendor/cmock/lib/cmock_header_parser.rb b/vendor/ceedling/vendor/cmock/lib/cmock_header_parser.rb deleted file mode 100644 index 9730bf4..0000000 --- a/vendor/ceedling/vendor/cmock/lib/cmock_header_parser.rb +++ /dev/null @@ -1,623 +0,0 @@ -# ========================================== -# CMock Project - Automatic Mock Generation for C -# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams -# [Released under MIT License. Please refer to license.txt for details] -# ========================================== - -class CMockHeaderParser - attr_accessor :funcs, :c_attr_noconst, :c_attributes, :treat_as_void, :treat_externs, :treat_inlines, :inline_function_patterns - - def initialize(cfg) - @c_strippables = cfg.strippables - @c_attr_noconst = cfg.attributes.uniq - ['const'] - @c_attributes = ['const'] + c_attr_noconst - @c_calling_conventions = cfg.c_calling_conventions.uniq - @treat_as_array = cfg.treat_as_array - @treat_as_void = (['void'] + cfg.treat_as_void).uniq - @function_declaration_parse_base_match = '([\w\s\*\(\),\[\]]+??)\(([\w\s\*\(\),\.\[\]+\-\/]*)\)' - @declaration_parse_matcher = /#{@function_declaration_parse_base_match}$/m - @standards = (%w[int short char long unsigned signed] + cfg.treat_as.keys).uniq - @array_size_name = cfg.array_size_name - @array_size_type = (%w[int size_t] + cfg.array_size_type).uniq - @when_no_prototypes = cfg.when_no_prototypes - @local_as_void = @treat_as_void - @verbosity = cfg.verbosity - @treat_externs = cfg.treat_externs - @treat_inlines = cfg.treat_inlines - @inline_function_patterns = cfg.inline_function_patterns - @c_strippables += ['extern'] if @treat_externs == :include # we'll need to remove the attribute if we're allowing externs - @c_strippables += ['inline'] if @treat_inlines == :include # we'll need to remove the attribute if we're allowing inlines - end - - def parse(name, source) - parse_project = { - :module_name => name.gsub(/\W/, ''), - :typedefs => [], - :functions => [], - :normalized_source => nil - } - - function_names = [] - - all_funcs = parse_functions(import_source(source, parse_project)).map { |item| [item] } - all_funcs += parse_cpp_functions(import_source(source, parse_project, true)) - all_funcs.map do |decl| - func = parse_declaration(parse_project, *decl) - unless function_names.include? func[:name] - parse_project[:functions] << func - function_names << func[:name] - end - end - - parse_project[:normalized_source] = if @treat_inlines == :include - transform_inline_functions(source) - else - '' - end - - { :includes => nil, - :functions => parse_project[:functions], - :typedefs => parse_project[:typedefs], - :normalized_source => parse_project[:normalized_source] } - end - - private if $ThisIsOnlyATest.nil? ################ - - # Remove C/C++ comments from a string - # +source+:: String which will have the comments removed - def remove_comments_from_source(source) - # 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) - end - - def remove_nested_pairs_of_braces(source) - # remove nested pairs of braces because no function declarations will be inside of them (leave outer pair for function definition detection) - if RUBY_VERSION.split('.')[0].to_i > 1 - # we assign a string first because (no joke) if Ruby 1.9.3 sees this line as a regex, it will crash. - r = '\\{([^\\{\\}]*|\\g<0>)*\\}' - source.gsub!(/#{r}/m, '{ }') - else - while source.gsub!(/\{[^\{\}]*\{[^\{\}]*\}[^\{\}]*\}/m, '{ }') - end - end - - source - end - - # Return the number of pairs of braces/square brackets in the function provided by the user - # +source+:: String containing the function to be processed - def count_number_of_pairs_of_braces_in_function(source) - is_function_start_found = false - curr_level = 0 - total_pairs = 0 - - source.each_char do |c| - if c == '{' - curr_level += 1 - total_pairs += 1 - is_function_start_found = true - elsif c == '}' - curr_level -= 1 - end - - break if is_function_start_found && curr_level == 0 # We reached the end of the inline function body - end - - if curr_level != 0 - total_pairs = 0 # Something is fishy about this source, not enough closing braces? - end - - total_pairs - end - - # Transform inline functions to regular functions in the source by the user - # +source+:: String containing the source to be processed - def transform_inline_functions(source) - inline_function_regex_formats = [] - square_bracket_pair_regex_format = /\{[^\{\}]*\}/ # Regex to match one whole block enclosed by two square brackets - - # Convert user provided string patterns to regex - # Use word bounderies before and after the user regex to limit matching to actual word iso part of a word - @inline_function_patterns.each do |user_format_string| - user_regex = Regexp.new(user_format_string) - word_boundary_before_user_regex = /\b/ - cleanup_spaces_after_user_regex = /[ ]*\b/ - inline_function_regex_formats << Regexp.new(word_boundary_before_user_regex.source + user_regex.source + cleanup_spaces_after_user_regex.source) - end - - # let's clean up the encoding in case they've done anything weird with the characters we might find - source = source.force_encoding('ISO-8859-1').encode('utf-8', :replace => nil) - - # Comments can contain words that will trigger the parser (static|inline|<user_defined_static_keyword>) - remove_comments_from_source(source) - - # smush multiline macros into single line (checking for continuation character at end of line '\') - # If the user uses a macro to declare an inline function, - # smushing the macros makes it easier to recognize them as a macro and if required, - # remove them later on in this function - source.gsub!(/\s*\\\s*/m, ' ') - - # Just looking for static|inline in the gsub is a bit too aggressive (functions that are named like this, ...), so we try to be a bit smarter - # Instead, look for an inline pattern (f.e. "static inline") and parse it. - # Below is a small explanation on how the general mechanism works: - # - Everything before the match should just be copied, we don't want - # to touch anything but the inline functions. - # - Remove the implementation of the inline function (this is enclosed - # in square brackets) and replace it with ";" to complete the - # transformation to normal/non-inline function. - # To ensure proper removal of the function body, we count the number of square-bracket pairs - # and remove the pairs one-by-one. - # - Copy everything after the inline function implementation and start the parsing of the next inline function - # There are ofcourse some special cases (inline macro declarations, inline function declarations, ...) which are handled and explained below - inline_function_regex_formats.each do |format| - inspected_source = '' - regex_matched = false - loop do - inline_function_match = source.match(/#{format}/) # Search for inline function declaration - - if inline_function_match.nil? # No inline functions so nothing to do - # Join pre and post match stripped parts for the next inline function detection regex - source = inspected_source + source if regex_matched == true - break - end - - regex_matched = true - # 1. Determine if we are dealing with a user defined macro to declare inline functions - # If the end of the pre-match string is a macro-declaration-like string, - # we are dealing with a user defined macro to declare inline functions - if /(#define\s*)\z/ =~ inline_function_match.pre_match - # Remove the macro from the source - stripped_pre_match = inline_function_match.pre_match.sub(/(#define\s*)\z/, '') - stripped_post_match = inline_function_match.post_match.sub(/\A(.*[\n]?)/, '') - inspected_source += stripped_pre_match - source = stripped_post_match - next - end - - # 2. Determine if we are dealing with an inline function declaration iso function definition - # If the start of the post-match string is a function-declaration-like string (something ending with semicolon after the function arguments), - # we are dealing with a inline function declaration - if /\A#{@function_declaration_parse_base_match}\s*;/m =~ inline_function_match.post_match - # Only remove the inline part from the function declaration, leaving the function declaration won't do any harm - inspected_source += inline_function_match.pre_match - source = inline_function_match.post_match - next - end - - # 3. If we get here, we found an inline function declaration AND inline function body. - # Remove the function body to transform it into a 'normal' function declaration. - if /\A#{@function_declaration_parse_base_match}\s*\{/m =~ inline_function_match.post_match - total_pairs_to_remove = count_number_of_pairs_of_braces_in_function(inline_function_match.post_match) - - break if total_pairs_to_remove == 0 # Bad source? - - inline_function_stripped = inline_function_match.post_match - - total_pairs_to_remove.times do - inline_function_stripped.sub!(/\s*#{square_bracket_pair_regex_format}/, ';') # Remove inline implementation (+ some whitespace because it's prettier) - end - inspected_source += inline_function_match.pre_match - source = inline_function_stripped - next - end - - # 4. If we get here, it means the regex match, but it is not related to the function (ex. static variable in header) - # Leave this code as it is. - inspected_source += inline_function_match.pre_match + inline_function_match[0] - source = inline_function_match.post_match - end - end - - source - end - - def import_source(source, parse_project, cpp = false) - # let's clean up the encoding in case they've done anything weird with the characters we might find - source = source.force_encoding('ISO-8859-1').encode('utf-8', :replace => nil) - - # void must be void for cmock _ExpectAndReturn calls to process properly, not some weird typedef which equates to void - # to a certain extent, this action assumes we're chewing on pre-processed header files, otherwise we'll most likely just get stuff from @treat_as_void - @local_as_void = @treat_as_void - void_types = source.scan(/typedef\s+(?:\(\s*)?void(?:\s*\))?\s+([\w]+)\s*;/) - if void_types - @local_as_void += void_types.flatten.uniq.compact - end - - # If user wants to mock inline functions, - # remove the (user specific) inline keywords before removing anything else to avoid missing an inline function - if @treat_inlines == :include - @inline_function_patterns.each do |user_format_string| - source.gsub!(/#{user_format_string}/, '') # remove user defined inline function patterns - end - end - - # smush multiline macros into single line (checking for continuation character at end of line '\') - source.gsub!(/\s*\\\s*/m, ' ') - - remove_comments_from_source(source) - - # remove assembler pragma sections - source.gsub!(/^\s*#\s*pragma\s+asm\s+.*?#\s*pragma\s+endasm/m, '') - - # remove gcc's __attribute__ tags - source.gsub!(/__attribute(?:__)?\s*\(\(+.*\)\)+/, '') - - # remove preprocessor statements and extern "C" - source.gsub!(/^\s*#.*/, '') - source.gsub!(/extern\s+\"C\"\s*\{/, '') - - # enums, unions, structs, and typedefs can all contain things (e.g. function pointers) that parse like function prototypes, so yank them - # forward declared structs are removed before struct definitions so they don't mess up real thing later. we leave structs keywords in function prototypes - source.gsub!(/^[\w\s]*struct[^;\{\}\(\)]+;/m, '') # remove forward declared structs - source.gsub!(/^[\w\s]*(enum|union|struct|typedef)[\w\s]*\{[^\}]+\}[\w\s\*\,]*;/m, '') # remove struct, union, and enum definitions and typedefs with braces - # remove problem keywords - source.gsub!(/(\W)(?:register|auto|restrict)(\W)/, '\1\2') - source.gsub!(/(\W)(?:static)(\W)/, '\1\2') unless cpp - - source.gsub!(/\s*=\s*['"a-zA-Z0-9_\.]+\s*/, '') # remove default value statements from argument lists - source.gsub!(/^(?:[\w\s]*\W)?typedef\W[^;]*/m, '') # remove typedef statements - source.gsub!(/\)(\w)/, ') \1') # add space between parenthese and alphanumeric - source.gsub!(/(^|\W+)(?:#{@c_strippables.join('|')})(?=$|\W+)/, '\1') unless @c_strippables.empty? # remove known attributes slated to be stripped - - # scan standalone function pointers and remove them, because they can just be ignored - source.gsub!(/\w+\s*\(\s*\*\s*\w+\s*\)\s*\([^)]*\)\s*;/, ';') - - # scan for functions which return function pointers, because they are a pain - source.gsub!(/([\w\s\*]+)\(*\(\s*\*([\w\s\*]+)\s*\(([\w\s\*,]*)\)\)\s*\(([\w\s\*,]*)\)\)*/) do |_m| - functype = "cmock_#{parse_project[:module_name]}_func_ptr#{parse_project[:typedefs].size + 1}" - unless cpp # only collect once - parse_project[:typedefs] << "typedef #{Regexp.last_match(1).strip}(*#{functype})(#{Regexp.last_match(4)});" - "#{functype} #{Regexp.last_match(2).strip}(#{Regexp.last_match(3)});" - end - end - - source = remove_nested_pairs_of_braces(source) unless cpp - - if @treat_inlines == :include - # Functions having "{ }" at this point are/were inline functions, - # User wants them in so 'disguise' them as normal functions with the ";" - source.gsub!('{ }', ';') - end - - # remove function definitions by stripping off the arguments right now - source.gsub!(/\([^\)]*\)\s*\{[^\}]*\}/m, ';') - - # drop extra white space to make the rest go faster - source.gsub!(/^\s+/, '') # remove extra white space from beginning of line - source.gsub!(/\s+$/, '') # remove extra white space from end of line - source.gsub!(/\s*\(\s*/, '(') # remove extra white space from before left parens - source.gsub!(/\s*\)\s*/, ')') # remove extra white space from before right parens - source.gsub!(/\s+/, ' ') # remove remaining extra white space - - # split lines on semicolons and remove things that are obviously not what we are looking for - src_lines = source.split(/\s*;\s*/) - src_lines = src_lines.uniq unless cpp # must retain closing braces for class/namespace - src_lines.delete_if { |line| line.strip.empty? } # remove blank lines - src_lines.delete_if { |line| !(line =~ /[\w\s\*]+\(+\s*\*[\*\s]*[\w\s]+(?:\[[\w\s]*\]\s*)+\)+\s*\((?:[\w\s\*]*,?)*\s*\)/).nil? } # remove function pointer arrays - - unless @treat_externs == :include - src_lines.delete_if { |line| !(line =~ /(?:^|\s+)(?:extern)\s+/).nil? } # remove extern functions - end - - unless @treat_inlines == :include - src_lines.delete_if { |line| !(line =~ /(?:^|\s+)(?:inline)\s+/).nil? } # remove inline functions - end - - src_lines.delete_if(&:empty?) # drop empty lines - end - - # Rudimentary C++ parser - does not handle all situations - e.g.: - # * A namespace function appears after a class with private members (should be parsed) - # * Anonymous namespace (shouldn't parse anything - no matter how nested - within it) - # * A class nested within another class - def parse_cpp_functions(source) - funcs = [] - - ns = [] - pub = false - source.each do |line| - # Search for namespace, class, opening and closing braces - line.scan(/(?:(?:\b(?:namespace|class)\s+(?:\S+)\s*)?{)|}/).each do |item| - if item == '}' - ns.pop - else - token = item.strip.sub(/\s+/, ' ') - ns << token - - pub = false if token.start_with? 'class' - pub = true if token.start_with? 'namespace' - end - end - - pub = true if line =~ /public:/ - pub = false if line =~ /private:/ || line =~ /protected:/ - - # ignore non-public and non-static - next unless pub - next unless line =~ /\bstatic\b/ - - line.sub!(/^.*static/, '') - next unless line =~ @declaration_parse_matcher - - tmp = ns.reject { |item| item == '{' } - - # Identify class name, if any - cls = nil - if tmp[-1].start_with? 'class ' - cls = tmp.pop.sub(/class (\S+) {/, '\1') - end - - # Assemble list of namespaces - tmp.each { |item| item.sub!(/(?:namespace|class) (\S+) {/, '\1') } - - funcs << [line.strip.gsub(/\s+/, ' '), tmp, cls] - end - funcs - end - - def parse_functions(source) - funcs = [] - source.each { |line| funcs << line.strip.gsub(/\s+/, ' ') if line =~ @declaration_parse_matcher } - if funcs.empty? - case @when_no_prototypes - when :error - raise 'ERROR: No function prototypes found!' - when :warn - puts 'WARNING: No function prototypes found!' unless @verbosity < 1 - end - end - funcs - end - - def parse_type_and_name(arg) - # Split up words and remove known attributes. For pointer types, make sure - # to remove 'const' only when it applies to the pointer itself, not when it - # applies to the type pointed to. For non-pointer types, remove any - # occurrence of 'const'. - arg.gsub!(/(\w)\*/, '\1 *') # pull asterisks away from preceding word - arg.gsub!(/\*(\w)/, '* \1') # pull asterisks away from following word - arg_array = arg.split - arg_info = divine_ptr_and_const(arg) - arg_info[:name] = arg_array[-1] - - attributes = arg.include?('*') ? @c_attr_noconst : @c_attributes - attr_array = [] - type_array = [] - - arg_array[0..-2].each do |word| - if attributes.include?(word) - attr_array << word - elsif @c_calling_conventions.include?(word) - arg_info[:c_calling_convention] = word - else - type_array << word - end - end - - if arg_info[:const_ptr?] - attr_array << 'const' - type_array.delete_at(type_array.rindex('const')) - end - - arg_info[:modifier] = attr_array.join(' ') - arg_info[:type] = type_array.join(' ').gsub(/\s+\*/, '*') # remove space before asterisks - arg_info - end - - def parse_args(arg_list) - args = [] - arg_list.split(',').each do |arg| - arg.strip! - return args if arg =~ /^\s*((\.\.\.)|(void))\s*$/ # we're done if we reach void by itself or ... - - arg_info = parse_type_and_name(arg) - arg_info.delete(:modifier) # don't care about this - arg_info.delete(:c_calling_convention) # don't care about this - - # in C, array arguments implicitly degrade to pointers - # make the translation explicit here to simplify later logic - if @treat_as_array[arg_info[:type]] && !(arg_info[:ptr?]) - arg_info[:type] = "#{@treat_as_array[arg_info[:type]]}*" - arg_info[:type] = "const #{arg_info[:type]}" if arg_info[:const?] - arg_info[:ptr?] = true - end - - args << arg_info - end - - # Try to find array pair in parameters following this pattern : <type> * <name>, <@array_size_type> <@array_size_name> - args.each_with_index do |val, index| - next_index = index + 1 - next unless args.length > next_index - - if (val[:ptr?] == true) && args[next_index][:name].match(@array_size_name) && @array_size_type.include?(args[next_index][:type]) - val[:array_data?] = true - args[next_index][:array_size?] = true - end - end - - args - end - - def divine_ptr(arg) - return false unless arg.include? '*' - # treat "const char *" and similar as a string, not a pointer - return false if /(^|\s)(const\s+)?char(\s+const)?\s*\*(?!.*\*)/ =~ arg - - true - end - - def divine_const(arg) - # a non-pointer arg containing "const" is a constant - # an arg containing "const" before the last * is a pointer to a constant - if arg.include?('*') ? (/(^|\s|\*)const(\s(\w|\s)*)?\*(?!.*\*)/ =~ arg) : (/(^|\s)const(\s|$)/ =~ arg) - true - else - false - end - end - - def divine_ptr_and_const(arg) - divination = {} - - divination[:ptr?] = divine_ptr(arg) - divination[:const?] = divine_const(arg) - - # an arg containing "const" after the last * is a constant pointer - divination[:const_ptr?] = /\*(?!.*\*)\s*const(\s|$)/ =~ arg ? true : false - - divination - end - - def clean_args(arg_list, parse_project) - if @local_as_void.include?(arg_list.strip) || arg_list.empty? - 'void' - else - c = 0 - # magically turn brackets into asterisks, also match for parentheses that come from macros - arg_list.gsub!(/(\w+)(?:\s*\[[^\[\]]*\])+/, '*\1') - # remove space to place asterisks with type (where they belong) - arg_list.gsub!(/\s+\*/, '*') - # pull asterisks away from arg to place asterisks with type (where they belong) - arg_list.gsub!(/\*(\w)/, '* \1') - - # scan argument list for function pointers and replace them with custom types - arg_list.gsub!(/([\w\s\*]+)\(+\s*\*[\*\s]*([\w\s]*)\s*\)+\s*\(((?:[\w\s\*]*,?)*)\s*\)*/) do |_m| - functype = "cmock_#{parse_project[:module_name]}_func_ptr#{parse_project[:typedefs].size + 1}" - funcret = Regexp.last_match(1).strip - funcname = Regexp.last_match(2).strip - funcargs = Regexp.last_match(3).strip - funconst = '' - if funcname.include? 'const' - funcname.gsub!('const', '').strip! - funconst = 'const ' - end - parse_project[:typedefs] << "typedef #{funcret}(*#{functype})(#{funcargs});" - funcname = "cmock_arg#{c += 1}" if funcname.empty? - "#{functype} #{funconst}#{funcname}" - end - - # scan argument list for function pointers with shorthand notation and replace them with custom types - arg_list.gsub!(/([\w\s\*]+)+\s+(\w+)\s*\(((?:[\w\s\*]*,?)*)\s*\)*/) do |_m| - functype = "cmock_#{parse_project[:module_name]}_func_ptr#{parse_project[:typedefs].size + 1}" - funcret = Regexp.last_match(1).strip - funcname = Regexp.last_match(2).strip - funcargs = Regexp.last_match(3).strip - funconst = '' - if funcname.include? 'const' - funcname.gsub!('const', '').strip! - funconst = 'const ' - end - parse_project[:typedefs] << "typedef #{funcret}(*#{functype})(#{funcargs});" - funcname = "cmock_arg#{c += 1}" if funcname.empty? - "#{functype} #{funconst}#{funcname}" - end - - # automatically name unnamed arguments (those that only had a type) - arg_list.split(/\s*,\s*/).map do |arg| - parts = (arg.split - ['struct', 'union', 'enum', 'const', 'const*']) - if (parts.size < 2) || (parts[-1][-1].chr == '*') || @standards.include?(parts[-1]) - "#{arg} cmock_arg#{c += 1}" - else - arg - end - end.join(', ') - end - end - - def parse_declaration(parse_project, declaration, namespace = [], classname = nil) - decl = {} - decl[:namespace] = namespace - decl[:class] = classname - - regex_match = @declaration_parse_matcher.match(declaration) - raise "Failed parsing function declaration: '#{declaration}'" if regex_match.nil? - - # grab argument list - args = regex_match[2].strip - - # process function attributes, return type, and name - parsed = parse_type_and_name(regex_match[1]) - - # Record original name without scope prefix - decl[:unscoped_name] = parsed[:name] - - # Prefix name with namespace scope (if any) and then class - decl[:name] = namespace.join('_') - unless classname.nil? - decl[:name] << '_' unless decl[:name].empty? - decl[:name] << classname - end - # Add original name to complete fully scoped name - decl[:name] << '_' unless decl[:name].empty? - decl[:name] << decl[:unscoped_name] - - decl[:modifier] = parsed[:modifier] - unless parsed[:c_calling_convention].nil? - decl[:c_calling_convention] = parsed[:c_calling_convention] - end - - rettype = parsed[:type] - rettype = 'void' if @local_as_void.include?(rettype.strip) - decl[:return] = { :type => rettype, - :name => 'cmock_to_return', - :str => "#{rettype} cmock_to_return", - :void? => (rettype == 'void'), - :ptr? => parsed[:ptr?] || false, - :const? => parsed[:const?] || false, - :const_ptr? => parsed[:const_ptr?] || false } - - # remove default argument statements from mock definitions - args.gsub!(/=\s*[a-zA-Z0-9_\.]+\s*/, ' ') - - # check for var args - if args =~ /\.\.\./ - decl[:var_arg] = args.match(/[\w\s]*\.\.\./).to_s.strip - args = if args =~ /\,[\w\s]*\.\.\./ - args.gsub!(/\,[\w\s]*\.\.\./, '') - else - 'void' - end - else - decl[:var_arg] = nil - end - args = clean_args(args, parse_project) - decl[:args_string] = args - decl[:args] = parse_args(args) - decl[:args_call] = decl[:args].map { |a| a[:name] }.join(', ') - decl[:contains_ptr?] = decl[:args].inject(false) { |ptr, arg| arg[:ptr?] ? true : ptr } - - if decl[:return][:type].nil? || decl[:name].nil? || decl[:args].nil? || - decl[:return][:type].empty? || decl[:name].empty? - raise "Failed Parsing Declaration Prototype!\n" \ - " declaration: '#{declaration}'\n" \ - " modifier: '#{decl[:modifier]}'\n" \ - " return: #{prototype_inspect_hash(decl[:return])}\n" \ - " function: '#{decl[:name]}'\n" \ - " args: #{prototype_inspect_array_of_hashes(decl[:args])}\n" - end - - decl - end - - def prototype_inspect_hash(hash) - pairs = [] - hash.each_pair { |name, value| pairs << ":#{name} => #{"'" if value.class == String}#{value}#{"'" if value.class == String}" } - "{#{pairs.join(', ')}}" - end - - def prototype_inspect_array_of_hashes(array) - hashes = [] - array.each { |hash| hashes << prototype_inspect_hash(hash) } - case array.size - when 0 - return '[]' - when 1 - return "[#{hashes[0]}]" - else - return "[\n #{hashes.join("\n ")}\n ]\n" - end - end -end diff --git a/vendor/ceedling/vendor/cmock/lib/cmock_plugin_manager.rb b/vendor/ceedling/vendor/cmock/lib/cmock_plugin_manager.rb deleted file mode 100644 index 342014e..0000000 --- a/vendor/ceedling/vendor/cmock/lib/cmock_plugin_manager.rb +++ /dev/null @@ -1,50 +0,0 @@ -# ========================================== -# CMock Project - Automatic Mock Generation for C -# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams -# [Released under MIT License. Please refer to license.txt for details] -# ========================================== - -class CMockPluginManager - attr_accessor :plugins - - def initialize(config, utils) - @plugins = [] - plugins_to_load = [:expect, config.plugins].flatten.uniq.compact - plugins_to_load.each do |plugin| - plugin_name = plugin.to_s - object_name = 'CMockGeneratorPlugin' + camelize(plugin_name) - self.class.mutex.synchronize { load_plugin(plugin_name, object_name, config, utils) } - end - @plugins.sort! { |a, b| a.priority <=> b.priority } - end - - def run(method, args = nil) - if args.nil? - @plugins.collect { |plugin| plugin.send(method) if plugin.respond_to?(method) }.flatten.join - else - @plugins.collect { |plugin| plugin.send(method, args) if plugin.respond_to?(method) }.flatten.join - end - end - - def camelize(lower_case_and_underscored_word) - lower_case_and_underscored_word.gsub(/\/(.?)/) { '::' + Regexp.last_match(1).upcase }.gsub(/(^|_)(.)/) { Regexp.last_match(2).upcase } - end - - def self.mutex - @mutex ||= Mutex.new - end - - private - - def load_plugin(plugin_name, object_name, config, utils) - unless Object.const_defined? object_name - file_name = "#{__dir__}/cmock_generator_plugin_#{plugin_name.downcase}.rb" - require file_name - end - class_name = Object.const_get(object_name) - @plugins << class_name.new(config, utils) - rescue StandardError - file_name = "#{__dir__}/cmock_generator_plugin_#{plugin_name.downcase}.rb" - raise "ERROR: CMock unable to load plugin '#{plugin_name}' '#{object_name}' #{file_name}" - end -end diff --git a/vendor/ceedling/vendor/cmock/lib/cmock_unityhelper_parser.rb b/vendor/ceedling/vendor/cmock/lib/cmock_unityhelper_parser.rb deleted file mode 100644 index 9f4beb7..0000000 --- a/vendor/ceedling/vendor/cmock/lib/cmock_unityhelper_parser.rb +++ /dev/null @@ -1,77 +0,0 @@ -# ========================================== -# CMock Project - Automatic Mock Generation for C -# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams -# [Released under MIT License. Please refer to license.txt for details] -# ========================================== - -class CMockUnityHelperParser - attr_accessor :c_types - - def initialize(config) - @config = config - @fallback = @config.plugins.include?(:array) ? 'UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY' : 'UNITY_TEST_ASSERT_EQUAL_MEMORY' - @c_types = map_c_types.merge(import_source) - end - - def get_helper(ctype) - lookup = ctype.gsub(/(?:^|(\S?)(\s*)|(\W))const(?:$|(\s*)(\S)|(\W))/, '\1\3\5\6').strip.gsub(/\s+/, '_') - return [@c_types[lookup], ''] if @c_types[lookup] - - if lookup =~ /\*$/ - lookup = lookup.gsub(/\*$/, '') - return [@c_types[lookup], '*'] if @c_types[lookup] - else - lookup += '*' - return [@c_types[lookup], '&'] if @c_types[lookup] - end - return ['UNITY_TEST_ASSERT_EQUAL_PTR', ''] if ctype =~ /cmock_\w+_ptr\d+/ - raise("Don't know how to test #{ctype} and memory tests are disabled!") unless @config.memcmp_if_unknown - - lookup =~ /\*$/ ? [@fallback, '&'] : [@fallback, ''] - end - - private ########################### - - def map_c_types - c_types = {} - @config.treat_as.each_pair do |ctype, expecttype| - c_type = ctype.gsub(/\s+/, '_') - if expecttype =~ /\*/ - c_types[c_type] = "UNITY_TEST_ASSERT_EQUAL_#{expecttype.delete('*')}_ARRAY" - else - c_types[c_type] = "UNITY_TEST_ASSERT_EQUAL_#{expecttype}" - c_types[c_type + '*'] ||= "UNITY_TEST_ASSERT_EQUAL_#{expecttype}_ARRAY" - end - end - c_types - end - - def import_source - source = @config.load_unity_helper - return {} if source.nil? - - c_types = {} - source = source.gsub(/\/\/.*$/, '') # remove line comments - source = source.gsub(/\/\*.*?\*\//m, '') # remove block comments - - # scan for comparison helpers - match_regex = Regexp.new('^\s*#define\s+(UNITY_TEST_ASSERT_EQUAL_(\w+))\s*\(' + Array.new(4, '\s*\w+\s*').join(',') + '\)') - pairs = source.scan(match_regex).flatten.compact - (pairs.size / 2).times do |i| - expect = pairs[i * 2] - ctype = pairs[(i * 2) + 1] - c_types[ctype] = expect unless expect.include?('_ARRAY') - end - - # scan for array variants of those helpers - match_regex = Regexp.new('^\s*#define\s+(UNITY_TEST_ASSERT_EQUAL_(\w+_ARRAY))\s*\(' + Array.new(5, '\s*\w+\s*').join(',') + '\)') - pairs = source.scan(match_regex).flatten.compact - (pairs.size / 2).times do |i| - expect = pairs[i * 2] - ctype = pairs[(i * 2) + 1] - c_types[ctype.gsub('_ARRAY', '*')] = expect - end - - c_types - end -end diff --git a/vendor/ceedling/vendor/cmock/src/cmock.c b/vendor/ceedling/vendor/cmock/src/cmock.c deleted file mode 100644 index 88f2c2b..0000000 --- a/vendor/ceedling/vendor/cmock/src/cmock.c +++ /dev/null @@ -1,216 +0,0 @@ -/* ========================================== - CMock Project - Automatic Mock Generation for C - Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams - [Released under MIT License. Please refer to license.txt for details] -========================================== */ - -#include "cmock.h" - -/* public constants to be used by mocks */ -const char* CMockStringOutOfMemory = "CMock has run out of memory. Please allocate more."; -const char* CMockStringCalledMore = "Called more times than expected."; -const char* CMockStringCalledLess = "Called fewer times than expected."; -const char* CMockStringCalledEarly = "Called earlier than expected."; -const char* CMockStringCalledLate = "Called later than expected."; -const char* CMockStringCallOrder = "Called out of order."; -const char* CMockStringIgnPreExp = "IgnoreArg called before Expect."; -const char* CMockStringPtrPreExp = "ReturnThruPtr called before Expect."; -const char* CMockStringPtrIsNULL = "Pointer is NULL."; -const char* CMockStringExpNULL = "Expected NULL."; -const char* CMockStringMismatch = "Function called with unexpected argument value."; - -/* private variables */ -#ifdef CMOCK_MEM_DYNAMIC -static unsigned char* CMock_Guts_Buffer = NULL; -static CMOCK_MEM_INDEX_TYPE CMock_Guts_BufferSize = CMOCK_MEM_ALIGN_SIZE; -static CMOCK_MEM_INDEX_TYPE CMock_Guts_FreePtr = CMOCK_MEM_ALIGN_SIZE; -#else -static unsigned char CMock_Guts_Buffer[CMOCK_MEM_SIZE + CMOCK_MEM_ALIGN_SIZE]; -static CMOCK_MEM_INDEX_TYPE CMock_Guts_BufferSize = CMOCK_MEM_SIZE + CMOCK_MEM_ALIGN_SIZE; -static CMOCK_MEM_INDEX_TYPE CMock_Guts_FreePtr = CMOCK_MEM_ALIGN_SIZE; -#endif - -/*------------------------------------------------------- - * CMock_Guts_MemNew - *-------------------------------------------------------*/ -CMOCK_MEM_INDEX_TYPE CMock_Guts_MemNew(CMOCK_MEM_INDEX_TYPE size) -{ - CMOCK_MEM_INDEX_TYPE index; - - /* verify arguments valid (we must be allocating space for at least 1 byte, and the existing chain must be in memory somewhere) */ - if (size < 1) - return CMOCK_GUTS_NONE; - - /* verify we have enough room */ - size = size + CMOCK_MEM_INDEX_SIZE; - if (size & CMOCK_MEM_ALIGN_MASK) - size = (size + CMOCK_MEM_ALIGN_MASK) & ~CMOCK_MEM_ALIGN_MASK; - if ((CMock_Guts_BufferSize - CMock_Guts_FreePtr) < size) - { -#ifndef CMOCK_MEM_DYNAMIC - return CMOCK_GUTS_NONE; /* nothing we can do; our static buffer is out of memory */ -#else - /* our dynamic buffer does not have enough room; request more via realloc() */ - CMOCK_MEM_INDEX_TYPE new_buffersize = CMock_Guts_BufferSize + CMOCK_MEM_SIZE + size; - unsigned char* new_buffer = realloc(CMock_Guts_Buffer, (size_t)new_buffersize); - if (new_buffer == NULL) - return CMOCK_GUTS_NONE; /* realloc() failed; out of memory */ - CMock_Guts_Buffer = new_buffer; - CMock_Guts_BufferSize = new_buffersize; -#endif - } - - /* determine where we're putting this new block, and init its pointer to be the end of the line */ - index = CMock_Guts_FreePtr + CMOCK_MEM_INDEX_SIZE; - *(CMOCK_MEM_INDEX_TYPE*)(&CMock_Guts_Buffer[CMock_Guts_FreePtr]) = CMOCK_GUTS_NONE; - CMock_Guts_FreePtr += size; - - return index; -} - -/*------------------------------------------------------- - * CMock_Guts_MemChain - *-------------------------------------------------------*/ -CMOCK_MEM_INDEX_TYPE CMock_Guts_MemChain(CMOCK_MEM_INDEX_TYPE root_index, CMOCK_MEM_INDEX_TYPE obj_index) -{ - CMOCK_MEM_INDEX_TYPE index; - void* root; - void* obj; - void* next; - - if (root_index == CMOCK_GUTS_NONE) - { - /* if there is no root currently, we return this object as the root of the chain */ - return obj_index; - } - else - { - /* reject illegal nodes */ - if ((root_index < CMOCK_MEM_ALIGN_SIZE) || (root_index >= CMock_Guts_FreePtr)) - { - return CMOCK_GUTS_NONE; - } - if ((obj_index < CMOCK_MEM_ALIGN_SIZE) || (obj_index >= CMock_Guts_FreePtr)) - { - return CMOCK_GUTS_NONE; - } - - root = (void*)(&CMock_Guts_Buffer[root_index]); - obj = (void*)(&CMock_Guts_Buffer[obj_index]); - - /* find the end of the existing chain and add us */ - next = root; - do { - index = *(CMOCK_MEM_INDEX_TYPE*)((CMOCK_MEM_PTR_AS_INT)next - CMOCK_MEM_INDEX_SIZE); - if (index >= CMock_Guts_FreePtr) - return CMOCK_GUTS_NONE; - if (index > 0) - next = (void*)(&CMock_Guts_Buffer[index]); - } while (index > 0); - *(CMOCK_MEM_INDEX_TYPE*)((CMOCK_MEM_PTR_AS_INT)next - CMOCK_MEM_INDEX_SIZE) = (CMOCK_MEM_INDEX_TYPE)((CMOCK_MEM_PTR_AS_INT)obj - (CMOCK_MEM_PTR_AS_INT)CMock_Guts_Buffer); - return root_index; - } -} - -/*------------------------------------------------------- - * CMock_Guts_MemNext - *-------------------------------------------------------*/ -CMOCK_MEM_INDEX_TYPE CMock_Guts_MemNext(CMOCK_MEM_INDEX_TYPE previous_item_index) -{ - CMOCK_MEM_INDEX_TYPE index; - void* previous_item; - - /* There is nothing "next" if the pointer isn't from our buffer */ - if ((previous_item_index < CMOCK_MEM_ALIGN_SIZE) || (previous_item_index >= CMock_Guts_FreePtr)) - return CMOCK_GUTS_NONE; - previous_item = (void*)(&CMock_Guts_Buffer[previous_item_index]); - - /* if the pointer is good, then use it to look up the next index - * (we know the first element always goes in zero, so NEXT must always be > 1) */ - index = *(CMOCK_MEM_INDEX_TYPE*)((CMOCK_MEM_PTR_AS_INT)previous_item - CMOCK_MEM_INDEX_SIZE); - if ((index > 1) && (index < CMock_Guts_FreePtr)) - return index; - else - return CMOCK_GUTS_NONE; -} - -/*------------------------------------------------------- - * CMock_Guts_MemEndOfChain - *-------------------------------------------------------*/ -CMOCK_MEM_INDEX_TYPE CMock_Guts_MemEndOfChain(CMOCK_MEM_INDEX_TYPE root_index) -{ - CMOCK_MEM_INDEX_TYPE index = root_index; - CMOCK_MEM_INDEX_TYPE next_index; - - for (next_index = root_index; - next_index != CMOCK_GUTS_NONE; - next_index = CMock_Guts_MemNext(index)) - { - index = next_index; - } - - return index; -} - -/*------------------------------------------------------- - * CMock_GetAddressFor - *-------------------------------------------------------*/ -void* CMock_Guts_GetAddressFor(CMOCK_MEM_INDEX_TYPE index) -{ - if ((index >= CMOCK_MEM_ALIGN_SIZE) && (index < CMock_Guts_FreePtr)) - { - return (void*)(&CMock_Guts_Buffer[index]); - } - else - { - return NULL; - } -} - -/*------------------------------------------------------- - * CMock_Guts_MemBytesCapacity - *-------------------------------------------------------*/ -CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesCapacity(void) -{ - return (sizeof(CMock_Guts_Buffer) - CMOCK_MEM_ALIGN_SIZE); -} - -/*------------------------------------------------------- - * CMock_Guts_MemBytesFree - *-------------------------------------------------------*/ -CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesFree(void) -{ - return CMock_Guts_BufferSize - CMock_Guts_FreePtr; -} - -/*------------------------------------------------------- - * CMock_Guts_MemBytesUsed - *-------------------------------------------------------*/ -CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesUsed(void) -{ - return CMock_Guts_FreePtr - CMOCK_MEM_ALIGN_SIZE; -} - -/*------------------------------------------------------- - * CMock_Guts_MemFreeAll - *-------------------------------------------------------*/ -void CMock_Guts_MemFreeAll(void) -{ - CMock_Guts_FreePtr = CMOCK_MEM_ALIGN_SIZE; /* skip the very beginning */ -} - -/*------------------------------------------------------- - * CMock_Guts_MemFreeFinal - *-------------------------------------------------------*/ -void CMock_Guts_MemFreeFinal(void) -{ - CMock_Guts_FreePtr = CMOCK_MEM_ALIGN_SIZE; -#ifdef CMOCK_MEM_DYNAMIC - if (CMock_Guts_Buffer) - { - free(CMock_Guts_Buffer); - CMock_Guts_Buffer = NULL; - } -#endif -} - diff --git a/vendor/ceedling/vendor/cmock/src/cmock.h b/vendor/ceedling/vendor/cmock/src/cmock.h deleted file mode 100644 index 45bab18..0000000 --- a/vendor/ceedling/vendor/cmock/src/cmock.h +++ /dev/null @@ -1,47 +0,0 @@ -/* ========================================== - CMock Project - Automatic Mock Generation for C - Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams - [Released under MIT License. Please refer to license.txt for details] -========================================== */ - -#ifndef CMOCK_FRAMEWORK_H -#define CMOCK_FRAMEWORK_H - -#include "cmock_internals.h" - -#define CMOCK_VERSION_MAJOR 2 -#define CMOCK_VERSION_MINOR 5 -#define CMOCK_VERSION_BUILD 4 -#define CMOCK_VERSION ((CMOCK_VERSION_MAJOR << 16) | (CMOCK_VERSION_MINOR << 8) | CMOCK_VERSION_BUILD) - -/* should be big enough to index full range of CMOCK_MEM_MAX */ -#ifndef CMOCK_MEM_INDEX_TYPE -#include <stddef.h> -#define CMOCK_MEM_INDEX_TYPE size_t -#endif - -#define CMOCK_GUTS_NONE (0) - -#if defined __GNUC__ -# define CMOCK_FUNCTION_ATTR(a) __attribute__((a)) -#else -# define CMOCK_FUNCTION_ATTR(a) /* ignore */ -#endif - -/*------------------------------------------------------- - * Memory API - *-------------------------------------------------------*/ -CMOCK_MEM_INDEX_TYPE CMock_Guts_MemNew(CMOCK_MEM_INDEX_TYPE size); -CMOCK_MEM_INDEX_TYPE CMock_Guts_MemChain(CMOCK_MEM_INDEX_TYPE root_index, CMOCK_MEM_INDEX_TYPE obj_index); -CMOCK_MEM_INDEX_TYPE CMock_Guts_MemNext(CMOCK_MEM_INDEX_TYPE previous_item_index) CMOCK_FUNCTION_ATTR(pure); -CMOCK_MEM_INDEX_TYPE CMock_Guts_MemEndOfChain(CMOCK_MEM_INDEX_TYPE root_index) CMOCK_FUNCTION_ATTR(pure); - -void* CMock_Guts_GetAddressFor(CMOCK_MEM_INDEX_TYPE index) CMOCK_FUNCTION_ATTR(pure); - -CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesCapacity(void) CMOCK_FUNCTION_ATTR(const); -CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesFree(void) CMOCK_FUNCTION_ATTR(pure); -CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesUsed(void) CMOCK_FUNCTION_ATTR(pure); -void CMock_Guts_MemFreeAll(void); -void CMock_Guts_MemFreeFinal(void); - -#endif /* end of CMOCK_FRAMEWORK_H */ diff --git a/vendor/ceedling/vendor/cmock/src/cmock_internals.h b/vendor/ceedling/vendor/cmock/src/cmock_internals.h deleted file mode 100644 index 56fb33b..0000000 --- a/vendor/ceedling/vendor/cmock/src/cmock_internals.h +++ /dev/null @@ -1,91 +0,0 @@ -/* ========================================== - CMock Project - Automatic Mock Generation for C - Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams - [Released under MIT License. Please refer to license.txt for details] -========================================== */ - -#ifndef CMOCK_FRAMEWORK_INTERNALS_H -#define CMOCK_FRAMEWORK_INTERNALS_H - -#include "unity.h" - -/* These are constants that the generated mocks have access to */ -extern const char* CMockStringOutOfMemory; -extern const char* CMockStringCalledMore; -extern const char* CMockStringCalledLess; -extern const char* CMockStringCalledEarly; -extern const char* CMockStringCalledLate; -extern const char* CMockStringCallOrder; -extern const char* CMockStringIgnPreExp; -extern const char* CMockStringPtrPreExp; -extern const char* CMockStringPtrIsNULL; -extern const char* CMockStringExpNULL; -extern const char* CMockStringMismatch; - -/* define CMOCK_MEM_DYNAMIC to grab memory as needed with malloc - * when you do that, CMOCK_MEM_SIZE is used for incremental size instead of total */ -#ifdef CMOCK_MEM_STATIC -#undef CMOCK_MEM_DYNAMIC -#endif - -#ifdef CMOCK_MEM_DYNAMIC -#include <stdlib.h> -#endif - -/* this is used internally during pointer arithmetic. make sure this type is the same size as the target's pointer type */ -#ifndef CMOCK_MEM_PTR_AS_INT -#ifdef UNITY_POINTER_WIDTH -#ifdef UNITY_INT_WIDTH -#if UNITY_POINTER_WIDTH == UNITY_INT_WIDTH -#define CMOCK_MEM_PTR_AS_INT unsigned int -#endif -#endif -#endif -#endif - -#ifndef CMOCK_MEM_PTR_AS_INT -#ifdef UNITY_POINTER_WIDTH -#ifdef UNITY_LONG_WIDTH -#if UNITY_POINTER_WIDTH == UNITY_LONG_WIDTH -#define CMOCK_MEM_PTR_AS_INT unsigned long -#endif -#if UNITY_POINTER_WIDTH > UNITY_LONG_WIDTH -#define CMOCK_MEM_PTR_AS_INT unsigned long long -#endif -#endif -#endif -#endif - -#ifndef CMOCK_MEM_PTR_AS_INT -#define CMOCK_MEM_PTR_AS_INT unsigned long -#endif - -/* 0 for no alignment, 1 for 16-bit, 2 for 32-bit, 3 for 64-bit */ -#ifndef CMOCK_MEM_ALIGN - #ifdef UNITY_LONG_WIDTH - #if (UNITY_LONG_WIDTH == 16) - #define CMOCK_MEM_ALIGN (1) - #elif (UNITY_LONG_WIDTH == 32) - #define CMOCK_MEM_ALIGN (2) - #elif (UNITY_LONG_WIDTH == 64) - #define CMOCK_MEM_ALIGN (3) - #else - #define CMOCK_MEM_ALIGN (2) - #endif - #else - #define CMOCK_MEM_ALIGN (2) - #endif -#endif - -/* amount of memory to allow cmock to use in its internal heap */ -#ifndef CMOCK_MEM_SIZE -#define CMOCK_MEM_SIZE (32768) -#endif - -/* automatically calculated defs for easier reading */ -#define CMOCK_MEM_ALIGN_SIZE (CMOCK_MEM_INDEX_TYPE)(1u << CMOCK_MEM_ALIGN) -#define CMOCK_MEM_ALIGN_MASK (CMOCK_MEM_INDEX_TYPE)(CMOCK_MEM_ALIGN_SIZE - 1) -#define CMOCK_MEM_INDEX_SIZE (CMOCK_MEM_INDEX_TYPE)(CMOCK_MEM_PTR_AS_INT)((sizeof(CMOCK_MEM_INDEX_TYPE) > CMOCK_MEM_ALIGN_SIZE) ? sizeof(CMOCK_MEM_INDEX_TYPE) : CMOCK_MEM_ALIGN_SIZE) - - -#endif /* end of CMOCK_FRAMEWORK_INTERNALS_H */ diff --git a/vendor/ceedling/vendor/cmock/src/meson.build b/vendor/ceedling/vendor/cmock/src/meson.build deleted file mode 100644 index c03c4e5..0000000 --- a/vendor/ceedling/vendor/cmock/src/meson.build +++ /dev/null @@ -1,12 +0,0 @@ -# -# build script written by : Michael Brockus. -# github repo author: Mike Karlesky, Mark VanderVoord, Greg Williams. -# -# license: MIT -# -cmock_dir = include_directories('.') - -cmock_lib = static_library(meson.project_name(), - files('cmock.c'), - dependencies: [unity_dep], - include_directories: cmock_dir) diff --git a/vendor/ceedling/vendor/diy/lib/diy.rb b/vendor/ceedling/vendor/diy/lib/diy.rb deleted file mode 100644 index 581afc7..0000000 --- a/vendor/ceedling/vendor/diy/lib/diy.rb +++ /dev/null @@ -1,403 +0,0 @@ -require 'diy/factory.rb' -require 'yaml' -require 'set' - -module DIY #:nodoc:# - VERSION = '1.1.2' - class Context - - class << self - # Enable / disable automatic requiring of libraries. Default: true - attr_accessor :auto_require - end - @auto_require = true - - # Accepts a Hash defining the object context (usually loaded from objects.yml), and an additional - # Hash containing objects to inject into the context. - def initialize(context_hash, extra_inputs={}) - raise "Nil context hash" unless context_hash - raise "Need a hash" unless context_hash.kind_of?(Hash) - [ "[]", "keys" ].each do |mname| - unless extra_inputs.respond_to?(mname) - raise "Extra inputs must respond to hash-like [] operator and methods #keys and #each" - end - end - - # store extra inputs - if extra_inputs.kind_of?(Hash) - @extra_inputs= {} - extra_inputs.each { |k,v| @extra_inputs[k.to_s] = v } # smooth out the names - else - @extra_inputs = extra_inputs - end - - collect_object_and_subcontext_defs context_hash - - # init the cache - @cache = {} - @cache['this_context'] = self - end - - - # Convenience: create a new DIY::Context by loading from a String (or open file handle.) - def self.from_yaml(io_or_string, extra_inputs={}) - raise "nil input to YAML" unless io_or_string - Context.new(YAML.load(io_or_string), extra_inputs) - end - - # Convenience: create a new DIY::Context by loading from the named file. - def self.from_file(fname, extra_inputs={}) - raise "nil file name" unless fname - self.from_yaml(File.read(fname), extra_inputs) - end - - # Return a reference to the object named. If necessary, the object will - # be instantiated on first use. If the object is non-singleton, a new - # object will be produced each time. - def get_object(obj_name) - key = obj_name.to_s - obj = @cache[key] - unless obj - if extra_inputs_has(key) - obj = @extra_inputs[key] - else - case @defs[key] - when MethodDef - obj = construct_method(key) - when FactoryDef - obj = construct_factory(key) - @cache[key] = obj - else - obj = construct_object(key) - @cache[key] = obj if @defs[key].singleton? - end - end - end - obj - end - alias :[] :get_object - - # Inject a named object into the Context. This must be done before the Context has instantiated the - # object in question. - def set_object(obj_name,obj) - key = obj_name.to_s - raise "object '#{key}' already exists in context" if @cache.keys.include?(key) - @cache[key] = obj - end - alias :[]= :set_object - - # Provide a listing of object names - def keys - (@defs.keys.to_set + @extra_inputs.keys.to_set).to_a - end - - # Instantiate and yield the named subcontext - def within(sub_context_name) - # Find the subcontext definitaion: - context_def = @sub_context_defs[sub_context_name.to_s] - raise "No sub-context named #{sub_context_name}" unless context_def - # Instantiate a new context using self as parent: - context = Context.new( context_def, self ) - - yield context - end - - # Returns true if the context contains an object with the given name - def contains_object(obj_name) - key = obj_name.to_s - @defs.keys.member?(key) or extra_inputs_has(key) - end - - # Every top level object in the Context is instantiated. This is especially useful for - # systems that have "floating observers"... objects that are never directly accessed, who - # would thus never be instantiated by coincedence. This does not build any subcontexts - # that may exist. - def build_everything - @defs.keys.each { |k| self[k] } - end - alias :build_all :build_everything - alias :preinstantiate_singletons :build_everything - - private - - def collect_object_and_subcontext_defs(context_hash) - @defs = {} - @sub_context_defs = {} - get_defs_from context_hash - end - - def get_defs_from(hash, namespace=nil) - hash.each do |name,info| - # we modify the info hash below so it's important to have a new - # instance to play with - info = info.dup if info - - # see if we are building a factory - if info and info.has_key?('builds') - unless info.has_key?('auto_require') - info['auto_require'] = self.class.auto_require - end - - if namespace - info['builds'] = namespace.build_classname(info['builds']) - end - @defs[name] = FactoryDef.new({:name => name, - :target => info['builds'], - :library => info['library'], - :auto_require => info['auto_require']}) - next - end - - name = name.to_s - case name - when /^\+/ - # subcontext - @sub_context_defs[name.gsub(/^\+/,'')] = info - - when /^using_namespace/ - # namespace: use a module(s) prefix for the classname of contained object defs - # NOTE: namespacing is NOT scope... it's just a convenient way to setup class names for a group of objects. - get_defs_from info, parse_namespace(name) - when /^method\s/ - key_name = name.gsub(/^method\s/, "") - @defs[key_name] = MethodDef.new(:name => key_name, - :object => info['object'], - :method => info['method'], - :attach => info['attach']) - else - # Normal object def - info ||= {} - if extra_inputs_has(name) - raise ConstructionError.new(name, "Object definition conflicts with parent context") - end - unless info.has_key?('auto_require') - info['auto_require'] = self.class.auto_require - end - if namespace - if info['class'] - info['class'] = namespace.build_classname(info['class']) - else - info['class'] = namespace.build_classname(name) - end - end - - @defs[name] = ObjectDef.new(:name => name, :info => info) - - end - end - end - - def construct_method(key) - method_definition = @defs[key] - object = get_object(method_definition.object) - method = object.method(method_definition.method) - - unless method_definition.attach.nil? - instance_var_name = "@__diy_#{method_definition.object}" - - method_definition.attach.each do |object_key| - get_object(object_key).instance_eval do - instance_variable_set(instance_var_name, object) - eval %|def #{key}(*args) - #{instance_var_name}.#{method_definition.method}(*args) - end| - end - end - end - - return method - rescue Exception => oops - build_and_raise_construction_error(key, oops) - end - - def construct_object(key) - # Find the object definition - obj_def = @defs[key] - raise "No object definition for '#{key}'" unless obj_def - # If object def mentions a library, load it - require obj_def.library if obj_def.library - - # Resolve all components for the object - arg_hash = {} - obj_def.components.each do |name,value| - case value - when Lookup - arg_hash[name.to_sym] = get_object(value.name) - when StringValue - arg_hash[name.to_sym] = value.literal_value - else - raise "Cannot cope with component definition '#{value.inspect}'" - end - end - # Get a reference to the class for the object - big_c = get_class_for_name_with_module_delimeters(obj_def.class_name) - # Make and return the instance - if obj_def.use_class_directly? - return big_c - elsif arg_hash.keys.size > 0 - return big_c.new(arg_hash) - else - return big_c.new - end - rescue Exception => oops - build_and_raise_construction_error(key, oops) - end - - def build_and_raise_construction_error(key, oops) - cerr = ConstructionError.new(key,oops) - cerr.set_backtrace(oops.backtrace) - raise cerr - end - - def get_class_for_name_with_module_delimeters(class_name) - class_name.split(/::/).inject(Object) do |mod,const_name| mod.const_get(const_name) end - end - - def extra_inputs_has(key) - if key.nil? or key.strip == '' - raise ArgumentError.new("Cannot lookup objects with nil keys") - end - @extra_inputs.keys.member?(key) or @extra_inputs.keys.member?(key.to_sym) - end - - def parse_namespace(str) - Namespace.new(str) - end - end - - class Namespace #:nodoc:# - def initialize(str) - # 'using_namespace Animal Reptile' - parts = str.split(/\s+/) - raise "Namespace definitions must begin with 'using_namespace'" unless parts[0] == 'using_namespace' - parts.shift - - if parts.length > 0 and parts[0] =~ /::/ - parts = parts[0].split(/::/) - end - - raise NamespaceError, "Namespace needs to indicate a module" if parts.empty? - - @module_nest = parts - end - - def build_classname(name) - [ @module_nest, Infl.camelize(name) ].flatten.join("::") - end - end - - class Lookup #:nodoc: - attr_reader :name - def initialize(obj_name) - @name = obj_name - end - end - - class MethodDef #:nodoc: - attr_accessor :name, :object, :method, :attach - - def initialize(opts) - @name, @object, @method, @attach = opts[:name], opts[:object], opts[:method], opts[:attach] - end - end - - class ObjectDef #:nodoc: - attr_accessor :name, :class_name, :library, :components - def initialize(opts) - name = opts[:name] - raise "Can't make an ObjectDef without a name" if name.nil? - - info = opts[:info] || {} - info = info.clone - - @components = {} - - # Object name - @name = name - - # Class name - @class_name = info.delete 'class' - @class_name ||= info.delete 'type' - @class_name ||= Infl.camelize(@name) - - # Auto Require - @auto_require = info.delete 'auto_require' - - # Library - @library = info.delete 'library' - @library ||= info.delete 'lib' - @library ||= Infl.underscore(@class_name) if @auto_require - - # Use Class Directly - @use_class_directly = info.delete 'use_class_directly' - - # Auto-compose - compose = info.delete 'compose' - if compose - case compose - when Array - auto_names = compose.map { |x| x.to_s } - when String - auto_names = compose.split(',').map { |x| x.to_s.strip } - when Symbol - auto_names = [ compose.to_s ] - else - raise "Cannot auto compose object #{@name}, bad 'compose' format: #{compose.inspect}" - end - end - auto_names ||= [] - auto_names.each do |cname| - @components[cname] = Lookup.new(cname) - end - - # Singleton status - if info['singleton'].nil? - @singleton = true - else - @singleton = info['singleton'] - end - info.delete 'singleton' - - # Remaining keys - info.each do |key,val| - @components[key.to_s] = Lookup.new(val.to_s) - end - - end - - def singleton? - @singleton - end - - def use_class_directly? - @use_class_directly == true - end - - end - - class ConstructionError < RuntimeError #:nodoc:# - def initialize(object_name, cause=nil) - object_name = object_name - cause = cause - m = "Failed to construct '#{object_name}'" - if cause - m << "\n ...caused by:\n >>> #{cause}" - end - super m - end - end - - class NamespaceError < RuntimeError #:nodoc:# - end - - module Infl #:nodoc:# - # Ganked this from Inflector: - def self.camelize(lower_case_and_underscored_word) - lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase } - end - # Ganked this from Inflector: - def self.underscore(camel_cased_word) - camel_cased_word.to_s.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z])/,'\1_\2').gsub(/([a-z\d])([A-Z])/,'\1_\2').downcase - end - end -end diff --git a/vendor/ceedling/vendor/diy/lib/diy/factory.rb b/vendor/ceedling/vendor/diy/lib/diy/factory.rb deleted file mode 100644 index d2566c5..0000000 --- a/vendor/ceedling/vendor/diy/lib/diy/factory.rb +++ /dev/null @@ -1,36 +0,0 @@ -module DIY #:nodoc:# - class FactoryDef #:nodoc: - attr_accessor :name, :target, :class_name, :library - - def initialize(opts) - @name, @target, @library, @auto_require = - opts[:name], opts[:target], opts[:library], opts[:auto_require] - - @class_name = Infl.camelize(@target) - @library ||= Infl.underscore(@class_name) if @auto_require - end - end - - class Context - def construct_factory(key) - factory_def = @defs[key] -# puts "requiring #{factory_def.library}" - require factory_def.library if factory_def.library - - big_c = get_class_for_name_with_module_delimeters(factory_def.class_name) - - FactoryFactory.new(big_c) - end - end - - class FactoryFactory - def initialize(clazz) - @class_to_create = clazz - end - - def create(*args) - @class_to_create.new(*args) - end - end -end - diff --git a/vendor/ceedling/vendor/unity/auto/colour_prompt.rb b/vendor/ceedling/vendor/unity/auto/colour_prompt.rb deleted file mode 100644 index 85cbfd8..0000000 --- a/vendor/ceedling/vendor/unity/auto/colour_prompt.rb +++ /dev/null @@ -1,119 +0,0 @@ -# ========================================== -# 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] -# ========================================== - -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 -end - -class ColourCommandLine - def initialize - 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, win32_colour(new_colour)) - else - "\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 - end - end - - def posix_colour(colour) - # ANSI Escape Codes - Foreground colors - # | Code | Color | - # | 39 | Default foreground color | - # | 30 | Black | - # | 31 | Red | - # | 32 | Green | - # | 33 | Yellow | - # | 34 | Blue | - # | 35 | Magenta | - # | 36 | Cyan | - # | 37 | Light gray | - # | 90 | Dark gray | - # | 91 | Light red | - # | 92 | Light green | - # | 93 | Light yellow | - # | 94 | Light blue | - # | 95 | Light magenta | - # | 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 - 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 - end -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 diff --git a/vendor/ceedling/vendor/unity/auto/colour_reporter.rb b/vendor/ceedling/vendor/unity/auto/colour_reporter.rb deleted file mode 100644 index 1c3bc21..0000000 --- a/vendor/ceedling/vendor/unity/auto/colour_reporter.rb +++ /dev/null @@ -1,39 +0,0 @@ -# ========================================== -# 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_relative 'colour_prompt' - -$colour_output = true - -def report(message) - if !$colour_output - $stdout.puts(message) - else - 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 - 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 diff --git a/vendor/ceedling/vendor/unity/auto/generate_config.yml b/vendor/ceedling/vendor/unity/auto/generate_config.yml deleted file mode 100644 index 4a5e474..0000000 --- a/vendor/ceedling/vendor/unity/auto/generate_config.yml +++ /dev/null @@ -1,36 +0,0 @@ -#this is a sample configuration file for generate_module -#you would use it by calling generate_module with the -ygenerate_config.yml option -#files like this are useful for customizing generate_module to your environment -:generate_module: - :defaults: - #these defaults are used in place of any missing options at the command line - :path_src: ../src/ - :path_inc: ../src/ - :path_tst: ../test/ - :update_svn: true - :includes: - #use [] for no additional includes, otherwise list the includes on separate lines - :src: - - Defs.h - - Board.h - :inc: [] - :tst: - - Defs.h - - Board.h - - Exception.h - :boilerplates: - #these are inserted at the top of generated files. - #just comment out or remove if not desired. - #use %1$s where you would like the file name to appear (path/extension not included) - :src: | - //------------------------------------------- - // %1$s.c - //------------------------------------------- - :inc: | - //------------------------------------------- - // %1$s.h - //------------------------------------------- - :tst: | - //------------------------------------------- - // Test%1$s.c : Units tests for %1$s.c - //------------------------------------------- diff --git a/vendor/ceedling/vendor/unity/auto/generate_module.rb b/vendor/ceedling/vendor/unity/auto/generate_module.rb deleted file mode 100644 index 0a88bec..0000000 --- a/vendor/ceedling/vendor/unity/auto/generate_module.rb +++ /dev/null @@ -1,313 +0,0 @@ -# ========================================== -# 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] -# ========================================== - -# This script creates all the files with start code necessary for a new module. -# A simple module only requires a source file, header file, and test file. -# Triad modules require a source, header, and test file for each triad type (like model, conductor, and hardware). - -require 'rubygems' -require 'fileutils' -require 'pathname' - -# TEMPLATE_TST -TEMPLATE_TST ||= '#ifdef TEST - -#include "unity.h" - -%2$s#include "%1$s.h" - -void setUp(void) -{ -} - -void tearDown(void) -{ -} - -void test_%4$s_NeedToImplement(void) -{ - TEST_IGNORE_MESSAGE("Need to Implement %1$s"); -} - -#endif // TEST -'.freeze - -# TEMPLATE_SRC -TEMPLATE_SRC ||= '%2$s#include "%1$s.h" -'.freeze - -# 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) - @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' - end - - # Create default file paths if none were provided - @options[:path_src] = "#{__dir__}/../src/" if @options[:path_src].nil? - @options[:path_inc] = @options[:path_src] if @options[:path_inc].nil? - @options[:path_tst] = "#{__dir__}/../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: [] - }, - update_svn: false, - boilerplates: {}, - test_prefix: 'Test', - mock_prefix: 'Mock' - } - end - - ############################ - def self.grab_config(config_file) - 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 - options - end - - ############################ - 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 - 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] }] - - # 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 - triad.select! { |v| v[:inc] == :tst } if pattern == 'test' - - # Assemble the path/names of the files we need to work with. - files = [] - triad.each do |cfg| - patterns.each_pair do |pattern_file, pattern_traits| - 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| 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 - - files - end - - ############################ - def neutralize_filename(name, start_cap = true) - return name if name.empty? - name = name.split(/(?:\s+|_|(?=[A-Z][a-z]))|(?<=[a-z])(?=[A-Z])/).map { |v| v.capitalize }.join('_') - name = name[0].downcase + name[1..-1] unless start_cap - return name - end - - ############################ - def create_filename(part1, part2 = '') - name = part2.empty? ? part1 : part1 + '_' + part2 - case (@options[:naming]) - when 'bumpy' then neutralize_filename(name,false).delete('_') - when 'camel' then neutralize_filename(name).delete('_') - when 'snake' then neutralize_filename(name).downcase - when 'caps' then neutralize_filename(name).upcase - else name - end - end - - ############################ - def generate(module_name, pattern = nil) - files = files_to_operate_on(module_name, pattern) - - # Abort if all of the module files already exist - all_files_exist = true - files.each do |file| - 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| - # 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) - 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 { |ff| "#include \"#{ff}\"\n" }.join, - file[:name].upcase.gsub(/-/, '_'), - file[:name].gsub(/-/, '_')]) - end - if @options[:update_svn] - `svn add \"#{file[:path]}\"` - 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!" - end - else - puts "File #{file[:path]} created" - end - end - puts 'Generate Complete' - end - - ############################ - def destroy(module_name, pattern = nil) - files_to_operate_on(module_name, pattern).each do |filespec| - file = filespec[:path] - if File.exist?(file) - if @options[:update_svn] - `svn delete \"#{file}\" --force` - puts "File #{file} deleted and removed from source control" - else - FileUtils.remove(file) - puts "File #{file} deleted" - end - else - puts "File #{file} does not exist so cannot be removed." - end - end - puts 'Destroy Complete' - end -end - -############################ -# Handle As Command Line If Called That Way -if $0 == __FILE__ - destroy = false - 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] = 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 - - 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.', - ' 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 - UnityModuleGenerator.new(options).destroy(module_name) - else - UnityModuleGenerator.new(options).generate(module_name) - end - -end diff --git a/vendor/ceedling/vendor/unity/auto/generate_test_runner.rb b/vendor/ceedling/vendor/unity/auto/generate_test_runner.rb deleted file mode 100644 index d1d8f91..0000000 --- a/vendor/ceedling/vendor/unity/auto/generate_test_runner.rb +++ /dev/null @@ -1,511 +0,0 @@ -# ========================================== -# 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] -# ========================================== - -class UnityTestRunnerGenerator - def initialize(options = nil) - @options = UnityTestRunnerGenerator.default_options - case options - when NilClass - @options - when String - @options.merge!(UnityTestRunnerGenerator.grab_config(options)) - when Hash - # Check if some of these have been specified - @options[:has_setup] = !options[:setup_name].nil? - @options[:has_teardown] = !options[:teardown_name].nil? - @options[:has_suite_setup] = !options[:suite_setup].nil? - @options[:has_suite_teardown] = !options[:suite_teardown].nil? - @options.merge!(options) - else - raise 'If you specify arguments, it should be a filename or a hash of options' - end - require_relative 'type_sanitizer' - end - - def self.default_options - { - includes: [], - defines: [], - plugins: [], - framework: :unity, - test_prefix: 'test|spec|should', - mock_prefix: 'Mock', - mock_suffix: '', - setup_name: 'setUp', - teardown_name: 'tearDown', - test_reset_name: 'resetTest', - test_verify_name: 'verifyTest', - main_name: 'main', # set to :auto to automatically generate each time - main_export_decl: '', - cmdline_args: false, - omit_begin_end: false, - use_param_tests: false, - include_extensions: '(?:hpp|hh|H|h)', - source_extensions: '(?:cpp|cc|ino|C|c)' - } - end - - def self.grab_config(config_file) - 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 - options - end - - def run(input_file, output_file, options = nil) - @options.merge!(options) unless options.nil? - - # pull required data from source file - source = File.read(input_file) - 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)/ } - find_setup_and_teardown(source) - - # build runner file - generate(input_file, output_file, tests, used_mocks, testfile_includes) - - # 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 += @options[:includes] unless @options[:includes].empty? - 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) - File.open(output_file, 'w') do |output| - create_header(output, used_mocks, testfile_includes) - create_externs(output, tests, used_mocks) - create_mock_management(output, used_mocks) - create_setup(output) - create_teardown(output) - create_suite_setup(output) - create_suite_teardown(output) - create_reset(output) - create_run_test(output) unless tests.empty? - create_args_wrappers(output, tests) - create_main(output, input_file, tests, 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 - - def find_tests(source) - tests_and_line_numbers = [] - - # contains characters which will be substituted from within strings, doing - # this prevents these characters from interfering with scrubbers - # @ is not a valid C character, so there should be no clashes with files genuinely containing these markers - substring_subs = { '{' => '@co@', '}' => '@cc@', ';' => '@ss@', '/' => '@fs@' } - substring_re = Regexp.union(substring_subs.keys) - substring_unsubs = substring_subs.invert # the inverse map will be used to fix the strings afterwords - substring_unsubs['@quote@'] = '\\"' - substring_unsubs['@apos@'] = '\\\'' - substring_unre = Regexp.union(substring_unsubs.keys) - source_scrubbed = source.clone - source_scrubbed = source_scrubbed.gsub(/\\"/, '@quote@') # hide escaped quotes to allow capture of the full string/char - source_scrubbed = source_scrubbed.gsub(/\\'/, '@apos@') # hide escaped apostrophes to allow capture of the full string/char - source_scrubbed = source_scrubbed.gsub(/("[^"\n]*")|('[^'\n]*')/) { |s| s.gsub(substring_re, substring_subs) } # temporarily hide problematic characters within strings - source_scrubbed = source_scrubbed.gsub(/\/\/(?:.+\/\*|\*(?:$|[^\/])).*$/, '') # remove line comments that comment out the start of blocks - source_scrubbed = source_scrubbed.gsub(/\/\*.*?\*\//m, '') # remove block comments - source_scrubbed = source_scrubbed.gsub(/\/\/.*$/, '') # remove line comments (all that remain) - lines = source_scrubbed.split(/(^\s*\#.*$) | (;|\{|\}) /x) # Treat preprocessor directives as a logical line. Match ;, {, and } as end of lines - .map { |line| line.gsub(substring_unre, substring_unsubs) } # unhide the problematic characters previously removed - - lines.each_with_index do |line, _index| - # find tests - next unless line =~ /^((?:\s*(?:TEST_CASE|TEST_RANGE)\s*\(.*?\)\s*)*)\s*void\s+((?:#{@options[:test_prefix]}).*)\s*\(\s*(.*)\s*\)/m - - 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] } - - arguments.scan(/\s*TEST_RANGE\s*\((.*)\)\s*$/).flatten.each do |range_str| - args += range_str.scan(/\[\s*(-?\d+.?\d*),\s*(-?\d+.?\d*),\s*(-?\d+.?\d*)\s*\]/).map do |arg_values_str| - arg_values_str.map do |arg_value_str| - arg_value_str.include?('.') ? arg_value_str.to_f : arg_value_str.to_i - end - end.map do |arg_values| - (arg_values[0]..arg_values[1]).step(arg_values[2]).to_a - end.reduce do |result, arg_range_expanded| - result.product(arg_range_expanded) - end.map do |arg_combinations| - arg_combinations.flatten.join(', ') - end - end - 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] } - - # determine line numbers and create tests to run - source_lines = source.split("\n") - source_index = 0 - tests_and_line_numbers.size.times do |i| - source_lines[source_index..-1].each_with_index do |line, index| - next unless line =~ /\s+#{tests_and_line_numbers[i][:test]}(?:\s|\()/ - - source_index += index - tests_and_line_numbers[i][:line_number] = source_index + 1 - break - end - end - - tests_and_line_numbers - end - - def find_includes(source) - # 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 - includes = { - local: source.scan(/^\s*#include\s+\"\s*(.+\.#{@options[:include_extensions]})\s*\"/).flatten, - system: source.scan(/^\s*#include\s+<\s*(.+)\s*>/).flatten.map { |inc| "<#{inc}>" }, - linkonly: source.scan(/^TEST_FILE\(\s*\"\s*(.+\.#{@options[:source_extensions]})\s*\"/).flatten - } - 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 =~ /^#{@options[:mock_prefix]}.*#{@options[:mock_suffix]}\.h$/i - end - mock_headers - end - - def find_setup_and_teardown(source) - @options[:has_setup] = source =~ /void\s+#{@options[:setup_name]}\s*\(/ - @options[:has_teardown] = source =~ /void\s+#{@options[:teardown_name]}\s*\(/ - @options[:has_suite_setup] ||= (source =~ /void\s+suiteSetUp\s*\(/) - @options[:has_suite_teardown] ||= (source =~ /int\s+suiteTearDown\s*\(int\s+([a-zA-Z0-9_])+\s*\)/) - end - - def create_header(output, mocks, testfile_includes = []) - output.puts('/* AUTOGENERATED FILE. DO NOT EDIT. */') - output.puts("\n/*=======Automagically Detected Files To Include=====*/") - output.puts("#include \"#{@options[:framework]}.h\"") - output.puts('#include "cmock.h"') unless mocks.empty? - if @options[:defines] && !@options[:defines].empty? - @options[:defines].each { |d| output.puts("#ifndef #{d}\n#define #{d}\n#endif /* #{d} */") } - end - 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}\""}") - end - testfile_includes.each do |inc| - output.puts("#include #{inc.include?('<') ? inc : "\"#{inc}\""}") - end - end - mocks.each do |mock| - output.puts("#include \"#{mock}\"") - 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) - output.puts("\n/*=======External Functions This Runner Calls=====*/") - output.puts("extern void #{@options[:setup_name]}(void);") - output.puts("extern void #{@options[:teardown_name]}(void);") - output.puts("\n#ifdef __cplusplus\nextern \"C\"\n{\n#endif") if @options[:externc] - tests.each do |test| - output.puts("extern void #{test[:test]}(#{test[:call] || 'void'});") - end - output.puts("#ifdef __cplusplus\n}\n#endif") if @options[:externc] - output.puts('') - end - - def create_mock_management(output, mock_headers) - 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") - - 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_setup(output) - return if @options[:has_setup] - - output.puts("\n/*=======Setup (stub)=====*/") - output.puts("void #{@options[:setup_name]}(void) {}") - end - - def create_teardown(output) - return if @options[:has_teardown] - - output.puts("\n/*=======Teardown (stub)=====*/") - output.puts("void #{@options[:teardown_name]}(void) {}") - end - - def create_suite_setup(output) - return if @options[:suite_setup].nil? - - output.puts("\n/*=======Suite Setup=====*/") - output.puts('void suiteSetUp(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('int suiteTearDown(int num_failures)') - output.puts('{') - output.puts(@options[:suite_teardown]) - output.puts('}') - end - - def create_reset(output) - output.puts("\n/*=======Test Reset Options=====*/") - output.puts("void #{@options[:test_reset_name]}(void);") - output.puts("void #{@options[:test_reset_name]}(void)") - output.puts('{') - output.puts(" #{@options[:teardown_name]}();") - output.puts(' CMock_Verify();') - output.puts(' CMock_Destroy();') - output.puts(' CMock_Init();') - output.puts(" #{@options[:setup_name]}();") - output.puts('}') - output.puts("void #{@options[:test_verify_name]}(void);") - output.puts("void #{@options[:test_verify_name]}(void)") - output.puts('{') - output.puts(' CMock_Verify();') - output.puts('}') - end - - def create_run_test(output) - require 'erb' - template = ERB.new(File.read(File.join(__dir__, 'run_test.erb')), nil, '<>') - output.puts("\n" + template.result(binding)) - end - - def create_args_wrappers(output, tests) - return unless @options[:use_param_tests] - - output.puts("\n/*=======Parameterized Test Wrappers=====*/") - tests.each do |test| - next if test[:args].nil? || test[:args].empty? - - test[:args].each.with_index(1) do |args, idx| - output.puts("static void runner_args#{idx}_#{test[:test]}(void)") - output.puts('{') - output.puts(" #{test[:test]}(#{args});") - output.puts("}\n") - end - end - end - - def create_main(output, filename, tests, used_mocks) - output.puts("\n/*=======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();') - tests.each do |test| - if (!@options[:use_param_tests]) || test[:args].nil? || test[:args].empty? - output.puts(" UnityPrint(\" #{test[:test]}\");") - output.puts(' UNITY_PRINT_EOL();') - else - test[:args].each do |args| - output.puts(" UnityPrint(\" #{test[:test]}(#{args})\");") - output.puts(' UNITY_PRINT_EOL();') - end - end - end - output.puts(' return 0;') - output.puts(' }') - output.puts(' return parse_status;') - output.puts(' }') - else - main_return = @options[:omit_begin_end] ? 'void' : 'int' - if main_name != 'main' - output.puts("#{@options[:main_export_decl]} #{main_return} #{main_name}(void);") - end - output.puts("#{main_return} #{main_name}(void)") - output.puts('{') - end - output.puts(' suiteSetUp();') if @options[:has_suite_setup] - if @options[:omit_begin_end] - output.puts(" UnitySetTestFile(\"#{filename.gsub(/\\/, '\\\\\\')}\");") - else - output.puts(" UnityBegin(\"#{filename.gsub(/\\/, '\\\\\\')}\");") - end - tests.each do |test| - if (!@options[:use_param_tests]) || test[:args].nil? || test[:args].empty? - output.puts(" run_test(#{test[:test]}, \"#{test[:test]}\", #{test[:line_number]});") - else - test[:args].each.with_index(1) do |args, idx| - wrapper = "runner_args#{idx}_#{test[:test]}" - testname = "#{test[:test]}(#{args})".dump - output.puts(" run_test(#{wrapper}, #{testname}, #{test[:line_number]});") - end - end - end - output.puts - output.puts(' CMock_Guts_MemFreeFinal();') unless used_mocks.empty? - if @options[:has_suite_teardown] - if @options[:omit_begin_end] - output.puts(' (void) suite_teardown(0);') - else - output.puts(' return suiteTearDown(UnityEnd());') - end - else - output.puts(' return UnityEnd();') unless @options[:omit_begin_end] - end - 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. */') - output.puts("#ifndef _#{filename}") - output.puts("#define _#{filename}\n\n") - 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}\""}") - end - testfile_includes.each do |inc| - output.puts("#include #{inc.include?('<') ? inc : "\"#{inc}\""}") - end - output.puts "\n" - tests.each do |test| - if test[:params].nil? || test[:params].empty? - output.puts("void #{test[:test]}(void);") - else - output.puts("void #{test[:test]}(#{test[:params]});") - end - end - output.puts("#endif\n\n") - end -end - -if $0 == __FILE__ - options = { includes: [] } - - # 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[Regexp.last_match(1).to_sym] = Regexp.last_match(2) - true - when /\.*\.(?:hpp|hh|H|h)$/ - options[:includes] << arg - true - else false - end - end - - # 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', - ' -externc - add extern "C" for cpp 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', - ' --test_reset_name="" - redefine resetTest func name to something else', - ' --test_verify_name="" - redefine verifyTest func name to something else', - ' --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)', - ' --omit_begin_end=1 - omit calls to UnityBegin and UnityEnd (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') unless ARGV[1] - - UnityTestRunnerGenerator.new(options).run(ARGV[0], ARGV[1]) -end diff --git a/vendor/ceedling/vendor/unity/auto/parse_output.rb b/vendor/ceedling/vendor/unity/auto/parse_output.rb deleted file mode 100644 index d72c6e8..0000000 --- a/vendor/ceedling/vendor/unity/auto/parse_output.rb +++ /dev/null @@ -1,322 +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 Linux builds use the following: -# make | tee Output.txt -# -# This script can handle the following output formats: -# - normal output (raw unity) -# - fixture output (unity_fixture.h/.c) -# - fixture output with verbose flag set ("-v") -# -# 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 -#============================================================ - -# Parser class for handling the input file -class ParseOutput - def initialize - # internal data - @class_name_idx = 0 - @path_delim = nil - - # xml output related - @xml_out = false - @array_list = false - - # current suite name and statistics - @test_suite = nil - @total_tests = 0 - @test_passed = 0 - @test_failed = 0 - @test_ignored = 0 - 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 - end - - # Pushes the suite info as xml to the array list, which will be written later - def push_xml_output_suite_info - # Insert opening tag at front - heading = '<testsuite name="Unity" tests="' + @total_tests.to_s + '" failures="' + @test_failed.to_s + '"' + ' skips="' + @test_ignored.to_s + '">' - @array_list.insert(0, heading) - # Push back the closing tag - @array_list.push '</testsuite>' - end - - # Pushes xml output data to the array list, which will be written later - def push_xml_output_passed(test_name) - @array_list.push ' <testcase classname="' + @test_suite + '" name="' + test_name + '"/>' - end - - # Pushes xml output data to the array list, which will be written later - def push_xml_output_failed(test_name, reason) - @array_list.push ' <testcase classname="' + @test_suite + '" name="' + test_name + '">' - @array_list.push ' <failure type="ASSERT FAILED">' + reason + '</failure>' - @array_list.push ' </testcase>' - end - - # Pushes xml output data to the array list, which will be written later - def push_xml_output_ignored(test_name, reason) - @array_list.push ' <testcase classname="' + @test_suite + '" name="' + test_name + '">' - @array_list.push ' <skipped type="TEST IGNORED">' + reason + '</skipped>' - @array_list.push ' </testcase>' - 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) - # Split the path name - test_name = test_suite_name.split(@path_delim) - - # Remove the extension and extract the base_name - base_name = test_name[test_name.size - 1].split('.')[0] - - # Return if the test suite hasn't changed - return unless base_name.to_s != @test_suite.to_s - - @test_suite = base_name - printf "New Test: %s\n", @test_suite - end - - # Prepares the line for verbose fixture output ("-v") - def prepare_fixture_line(line) - line = line.sub('IGNORE_TEST(', '') - line = line.sub('TEST(', '') - line = line.sub(')', ',') - line = line.chomp - array = line.split(',') - array.map { |x| x.to_s.lstrip.chomp } - 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) - class_name = array[0] - test_name = array[1] - test_suite_verify(class_name) - printf "%-40s PASS\n", test_name - - push_xml_output_passed(test_name) if @xml_out - end - - # Test was flagged as having failed so format the output. - # This is using the Unity fixture output and not the original Unity output. - def test_failed_unity_fixture(array) - class_name = array[0] - test_name = array[1] - test_suite_verify(class_name) - reason_array = array[2].split(':') - reason = reason_array[-1].lstrip.chomp + ' at line: ' + reason_array[-4] - - printf "%-40s FAILED\n", test_name - - push_xml_output_failed(test_name, reason) if @xml_out - end - - # Test was flagged as being ignored so format the output. - # This is using the Unity fixture output and not the original Unity output. - def test_ignored_unity_fixture(array) - class_name = array[0] - test_name = array[1] - reason = 'No reason given' - if array.size > 2 - reason_array = array[2].split(':') - tmp_reason = reason_array[-1].lstrip.chomp - reason = tmp_reason == 'IGNORE' ? 'No reason given' : tmp_reason - end - test_suite_verify(class_name) - printf "%-40s IGNORED\n", test_name - - push_xml_output_ignored(test_name, reason) if @xml_out - 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_idx]) - printf "%-40s PASS\n", test_name - - return unless @xml_out - - push_xml_output_passed(test_name) if @xml_out - 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.lstrip + ' at line: ' + array[last_item - 3] - class_name = array[@class_name_idx] - - if test_name.start_with? 'TEST(' - array2 = test_name.split(' ') - - test_suite = array2[0].sub('TEST(', '') - test_suite = test_suite.sub(',', '') - class_name = test_suite - - test_name = array2[1].sub(')', '') - end - - test_suite_verify(class_name) - printf "%-40s FAILED\n", test_name - - push_xml_output_failed(test_name, reason) if @xml_out - end - - # Test was flagged as being ignored so format the output - def test_ignored(array) - last_item = array.length - 1 - test_name = array[last_item - 2] - reason = array[last_item].chomp.lstrip - class_name = array[@class_name_idx] - - if test_name.start_with? 'TEST(' - array2 = test_name.split(' ') - - test_suite = array2[0].sub('TEST(', '') - test_suite = test_suite.sub(',', '') - class_name = test_suite - - test_name = array2[1].sub(')', '') - end - - test_suite_verify(class_name) - printf "%-40s IGNORED\n", test_name - - push_xml_output_ignored(test_name, reason) if @xml_out - end - - # Adjusts the os specific members according to the current path style - # (Windows or Unix based) - def detect_os_specifics(line) - if line.include? '\\' - # Windows X:\Y\Z - @class_name_idx = 1 - @path_delim = '\\' - else - # Unix Based /X/Y/Z - @class_name_idx = 0 - @path_delim = '/' - end - end - - # Main function used to parse the file that was captured. - def process(file_name) - @array_list = [] - - puts 'Parsing file: ' + file_name - - @test_passed = 0 - @test_failed = 0 - @test_ignored = 0 - puts '' - puts '=================== RESULTS =====================' - puts '' - File.open(file_name).each do |line| - # Typical test lines look like these: - # ---------------------------------------------------- - # 1. normal output: - # <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 - # - # 2. fixture output - # <path>/<test_file>.c:63:TEST(<test_group>, <test_function>):FAIL: Expected 0x00001234 Was 0x00005A5A - # <path>/<test_file>.c:36:TEST(<test_group>, <test_function>):IGNORE - # Note: "PASS" information won't be generated in this mode - # - # 3. fixture output with verbose information ("-v") - # TEST(<test_group, <test_file>)<path>/<test_file>:168::FAIL: Expected 0x8D Was 0x8C - # TEST(<test_group>, <test_file>)<path>/<test_file>:22::IGNORE: This Test Was Ignored On Purpose - # IGNORE_TEST(<test_group, <test_file>) - # TEST(<test_group, <test_file>) PASS - # - # Note: Where path is different on Unix vs Windows devices (Windows leads with a drive letter)! - detect_os_specifics(line) - 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. - next unless (line_array.size >= 4) || (line.start_with? 'TEST(') || (line.start_with? 'IGNORE_TEST(') - - # check if the output is fixture output (with verbose flag "-v") - if (line.start_with? 'TEST(') || (line.start_with? 'IGNORE_TEST(') - line_array = prepare_fixture_line(line) - if line.include? ' PASS' - test_passed_unity_fixture(line_array) - @test_passed += 1 - elsif line.include? 'FAIL' - test_failed_unity_fixture(line_array) - @test_failed += 1 - elsif line.include? 'IGNORE' - test_ignored_unity_fixture(line_array) - @test_ignored += 1 - end - # normal output / fixture output (without verbose "-v") - elsif line.include? ':PASS' - test_passed(line_array) - @test_passed += 1 - elsif line.include? ':FAIL' - test_failed(line_array) - @test_failed += 1 - elsif line.include? ':IGNORE:' - test_ignored(line_array) - @test_ignored += 1 - elsif line.include? ':IGNORE' - line_array.push('No reason given') - test_ignored(line_array) - @test_ignored += 1 - end - @total_tests = @test_passed + @test_failed + @test_ignored - end - puts '' - puts '=================== SUMMARY =====================' - puts '' - puts 'Tests Passed : ' + @test_passed.to_s - puts 'Tests Failed : ' + @test_failed.to_s - puts 'Tests Ignored : ' + @test_ignored.to_s - - return unless @xml_out - - # push information about the suite - push_xml_output_suite_info - # write xml output file - 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 |arg| - if arg == '-xml' - parse_my_file.set_xml_output - else - parse_my_file.process(arg) - break - end - end -end diff --git a/vendor/ceedling/vendor/unity/auto/run_test.erb b/vendor/ceedling/vendor/unity/auto/run_test.erb deleted file mode 100644 index f91b566..0000000 --- a/vendor/ceedling/vendor/unity/auto/run_test.erb +++ /dev/null @@ -1,37 +0,0 @@ -/*=======Test Runner Used To Run Each Test=====*/ -static void run_test(UnityTestFunction func, const char* name, UNITY_LINE_TYPE line_num) -{ - Unity.CurrentTestName = name; - Unity.CurrentTestLineNumber = line_num; -#ifdef UNITY_USE_COMMAND_LINE_ARGS - if (!UnityTestMatches()) - return; -#endif - Unity.NumberOfTests++; - UNITY_CLR_DETAILS(); - UNITY_EXEC_TIME_START(); - CMock_Init(); - if (TEST_PROTECT()) - { -<% if @options[:plugins].include?(:cexception) %> - CEXCEPTION_T e; - Try { - <%= @options[:setup_name] %>(); - func(); - } Catch(e) { - TEST_ASSERT_EQUAL_HEX32_MESSAGE(CEXCEPTION_NONE, e, "Unhandled Exception!"); - } -<% else %> - <%= @options[:setup_name] %>(); - func(); -<% end %> - } - if (TEST_PROTECT()) - { - <%= @options[:teardown_name] %>(); - CMock_Verify(); - } - CMock_Destroy(); - UNITY_EXEC_TIME_STOP(); - UnityConcludeTest(); -} diff --git a/vendor/ceedling/vendor/unity/auto/stylize_as_junit.rb b/vendor/ceedling/vendor/unity/auto/stylize_as_junit.rb deleted file mode 100644 index e01f791..0000000 --- a/vendor/ceedling/vendor/unity/auto/stylize_as_junit.rb +++ /dev/null @@ -1,251 +0,0 @@ -#!/usr/bin/ruby -# -# unity_to_junit.rb -# -require 'fileutils' -require 'optparse' -require 'ostruct' -require 'set' - -require 'pp' - -VERSION = 1.0 - -class ArgvParser - # - # Return a structure describing the options. - # - def self.parse(args) - # 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' - - opts = OptionParser.new do |o| - o.banner = 'Usage: unity_to_junit.rb [options]' - - o.separator '' - o.separator 'Specific options:' - - o.on('-r', '--results <dir>', 'Look for Unity Results files here.') do |results| - # puts "results #{results}" - options.results_dir = results - end - - o.on('-p', '--root_path <path>', 'Prepend this path to files in results.') do |root_path| - options.root_path = root_path - end - - o.on('-o', '--output <filename>', 'XML file to generate.') do |out_file| - # puts "out_file: #{out_file}" - options.out_file = out_file - end - - o.separator '' - o.separator 'Common options:' - - # No argument, shows at tail. This will print an options summary. - o.on_tail('-h', '--help', 'Show this message') do - puts o - exit - end - - # Another typical switch to print the version. - o.on_tail('--version', 'Show version') do - puts "unity_to_junit.rb version #{VERSION}" - exit - end - end - - opts.parse!(args) - options - end -end - -class UnityToJUnit - include FileUtils::Verbose - attr_reader :report, :total_tests, :failures, :ignored - attr_writer :targets, :root, :out_file - - def initialize - @report = '' - @unit_name = '' - end - - def run - # Clean up result file names - 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) - results.each do |result_file| - 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, '.*') - - 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) - f.close - end - - 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' - - exit 1 - end - - protected - - def get_details(_result_file, lines) - results = results_structure - lines.each do |line| - 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 - results - end - - def parse_test_summary(summary) - 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 - - private - - 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) - stream.puts "<?xml version='1.0' encoding='utf-8' ?>" - end - - def write_suites_header(stream) - stream.puts '<testsuites>' - end - - 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) - result = results[:failures] - 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\">" - stream.puts "\t\t\t<failure message=\"#{item[:message]}\" type=\"Assertion\"/>" - stream.puts "\t\t\t<system-err> [File] #{filename} [Line] #{item[:line]} </system-err>" - stream.puts "\t\t</testcase>" - end - end - - def write_tests(results, stream) - result = results[:successes] - result.each do |item| - stream.puts "\t\t<testcase classname=\"#{@unit_name}\" name=\"#{item[:test]}\" time=\"0\" />" - end - end - - def write_ignored(results, stream) - result = results[:ignores] - result.each do |item| - filename = File.join(results[:source][:path], File.basename(results[:source][:file], '.*')) - puts "Writing ignored tests for test harness: #{filename}" - stream.puts "\t\t<testcase classname=\"#{@unit_name}\" name=\"#{item[:test]}\" time=\"0\">" - stream.puts "\t\t\t<skipped message=\"#{item[:message]}\" type=\"Assertion\"/>" - stream.puts "\t\t\t<system-err> [File] #{filename} [Line] #{item[:line]} </system-err>" - stream.puts "\t\t</testcase>" - end - end - - def write_suite_footer(stream) - stream.puts "\t</testsuite>" - end - - def write_suites_footer(stream) - stream.puts '</testsuites>' - end -end - -if $0 == __FILE__ - # parse out the command options - options = ArgvParser.parse(ARGV) - - # create an instance to work with - utj = UnityToJUnit.new - begin - # 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.targets = results - - # set the root path - utj.root = options.root_path - - # set the output XML file name - # puts "Output File from options: #{options.out_file}" - utj.out_file = options.out_file - - # run the summarizer - puts utj.run - rescue StandardError => e - utj.usage e.message - end -end diff --git a/vendor/ceedling/vendor/unity/auto/test_file_filter.rb b/vendor/ceedling/vendor/unity/auto/test_file_filter.rb deleted file mode 100644 index 5c3a79f..0000000 --- a/vendor/ceedling/vendor/unity/auto/test_file_filter.rb +++ /dev/null @@ -1,25 +0,0 @@ -# ========================================== -# 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' - -module RakefileHelpers - class TestFileFilter - def initialize(all_files = false) - @all_files = all_files - - return unless @all_files - return 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 diff --git a/vendor/ceedling/vendor/unity/auto/type_sanitizer.rb b/vendor/ceedling/vendor/unity/auto/type_sanitizer.rb deleted file mode 100644 index dafb882..0000000 --- a/vendor/ceedling/vendor/unity/auto/type_sanitizer.rb +++ /dev/null @@ -1,6 +0,0 @@ -module TypeSanitizer - def self.sanitize_c_identifier(unsanitized) - # convert filename to valid C identifier by replacing invalid chars with '_' - unsanitized.gsub(/[-\/\\\.\,\s]/, '_') - end -end diff --git a/vendor/ceedling/vendor/unity/auto/unity_test_summary.py b/vendor/ceedling/vendor/unity/auto/unity_test_summary.py deleted file mode 100644 index 00c0da8..0000000 --- a/vendor/ceedling/vendor/unity/auto/unity_test_summary.py +++ /dev/null @@ -1,139 +0,0 @@ -#! python3 -# ========================================== -# Unity Project - A Test Framework for C -# Copyright (c) 2015 Alexander Mueller / XelaRellum@web.de -# [Released under MIT License. Please refer to license.txt for details] -# Based on the ruby script by Mike Karlesky, Mark VanderVoord, Greg Williams -# ========================================== -import sys -import os -import re -from glob import glob - -class UnityTestSummary: - def __init__(self): - self.report = '' - self.total_tests = 0 - self.failures = 0 - self.ignored = 0 - - def run(self): - # Clean up result file names - results = [] - for target in self.targets: - results.append(target.replace('\\', '/')) - - # Dig through each result file, looking for details on pass/fail: - failure_output = [] - ignore_output = [] - - for result_file in results: - lines = list(map(lambda line: line.rstrip(), open(result_file, "r").read().split('\n'))) - if len(lines) == 0: - raise Exception("Empty test result file: %s" % result_file) - - details = self.get_details(result_file, lines) - failures = details['failures'] - ignores = details['ignores'] - if len(failures) > 0: failure_output.append('\n'.join(failures)) - if len(ignores) > 0: ignore_output.append('n'.join(ignores)) - tests,failures,ignored = self.parse_test_summary('\n'.join(lines)) - self.total_tests += tests - self.failures += failures - self.ignored += ignored - - if self.ignored > 0: - self.report += "\n" - self.report += "--------------------------\n" - self.report += "UNITY IGNORED TEST SUMMARY\n" - self.report += "--------------------------\n" - self.report += "\n".join(ignore_output) - - if self.failures > 0: - self.report += "\n" - self.report += "--------------------------\n" - self.report += "UNITY FAILED TEST SUMMARY\n" - self.report += "--------------------------\n" - self.report += '\n'.join(failure_output) - - self.report += "\n" - self.report += "--------------------------\n" - self.report += "OVERALL UNITY TEST SUMMARY\n" - self.report += "--------------------------\n" - self.report += "{total_tests} TOTAL TESTS {failures} TOTAL FAILURES {ignored} IGNORED\n".format(total_tests = self.total_tests, failures=self.failures, ignored=self.ignored) - self.report += "\n" - - return self.report - - def set_targets(self, target_array): - self.targets = target_array - - def set_root_path(self, path): - self.root = path - - def usage(self, err_msg=None): - print("\nERROR: ") - if err_msg: - print(err_msg) - print("\nUsage: unity_test_summary.py result_file_directory/ root_path/") - print(" result_file_directory - The location of your results files.") - print(" Defaults to current directory if not specified.") - print(" Should end in / if specified.") - print(" root_path - Helpful for producing more verbose output if using relative paths.") - sys.exit(1) - - def get_details(self, result_file, lines): - results = { 'failures': [], 'ignores': [], 'successes': [] } - for line in lines: - parts = line.split(':') - if len(parts) == 5: - src_file,src_line,test_name,status,msg = parts - elif len(parts) == 4: - src_file,src_line,test_name,status = parts - msg = '' - else: - continue - if len(self.root) > 0: - line_out = "%s%s" % (self.root, line) - else: - line_out = line - if status == 'IGNORE': - results['ignores'].append(line_out) - elif status == 'FAIL': - results['failures'].append(line_out) - elif status == 'PASS': - results['successes'].append(line_out) - return results - - def parse_test_summary(self, summary): - m = re.search(r"([0-9]+) Tests ([0-9]+) Failures ([0-9]+) Ignored", summary) - if not m: - raise Exception("Couldn't parse test results: %s" % summary) - - return int(m.group(1)), int(m.group(2)), int(m.group(3)) - - -if __name__ == '__main__': - uts = UnityTestSummary() - try: - #look in the specified or current directory for result files - if len(sys.argv) > 1: - targets_dir = sys.argv[1] - else: - targets_dir = './' - targets = list(map(lambda x: x.replace('\\', '/'), glob(targets_dir + '**/*.test*', recursive=True))) - if len(targets) == 0: - raise Exception("No *.testpass or *.testfail files found in '%s'" % targets_dir) - uts.set_targets(targets) - - #set the root path - if len(sys.argv) > 2: - root_path = sys.argv[2] - else: - root_path = os.path.split(__file__)[0] - uts.set_root_path(root_path) - - #run the summarizer - print(uts.run()) - except Exception as e: - uts.usage(e) diff --git a/vendor/ceedling/vendor/unity/auto/unity_test_summary.rb b/vendor/ceedling/vendor/unity/auto/unity_test_summary.rb deleted file mode 100644 index b3fe8a6..0000000 --- a/vendor/ceedling/vendor/unity/auto/unity_test_summary.rb +++ /dev/null @@ -1,135 +0,0 @@ -# ========================================== -# 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] -# ========================================== - -# !/usr/bin/ruby -# -# unity_test_summary.rb -# -require 'fileutils' -require 'set' - -class UnityTestSummary - include FileUtils::Verbose - - attr_reader :report, :total_tests, :failures, :ignored - attr_writer :targets, :root - - def initialize(_opts = {}) - @report = '' - @total_tests = 0 - @failures = 0 - @ignored = 0 - end - - def run - # Clean up result file names - 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(&: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 - @report += "\n" - @report += "--------------------------\n" - @report += "UNITY IGNORED TEST SUMMARY\n" - @report += "--------------------------\n" - @report += ignore_output.flatten.join("\n") - end - - if @failures > 0 - @report += "\n" - @report += "--------------------------\n" - @report += "UNITY FAILED TEST SUMMARY\n" - @report += "--------------------------\n" - @report += failure_output.flatten.join("\n") - end - - @report += "\n" - @report += "--------------------------\n" - @report += "OVERALL UNITY TEST SUMMARY\n" - @report += "--------------------------\n" - @report += "#{@total_tests} TOTAL TESTS #{@failures} TOTAL FAILURES #{@ignored} IGNORED\n" - @report += "\n" - end - - 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.' - exit 1 - end - - protected - - 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 - end - end - results - end - - def parse_test_summary(summary) - 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 -end - -if $0 == __FILE__ - - # 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 - uts = UnityTestSummary.new(opts) - - begin - # look in the specified or current directory for result files - args[0] ||= './' - targets = "#{ARGV[0].tr('\\', '/')}**/*.test*" - results = Dir[targets] - - raise "No *.testpass, *.testfail, or *.testresults files found in '#{targets}'" if results.empty? - - uts.targets = results - - # set the root path - args[1] ||= Dir.pwd + '/' - uts.root = ARGV[1] - - # run the summarizer - puts uts.run - rescue StandardError => e - uts.usage e.message - end -end diff --git a/vendor/ceedling/vendor/unity/auto/unity_to_junit.py b/vendor/ceedling/vendor/unity/auto/unity_to_junit.py deleted file mode 100644 index 71dd568..0000000 --- a/vendor/ceedling/vendor/unity/auto/unity_to_junit.py +++ /dev/null @@ -1,146 +0,0 @@ -import sys -import os -from glob import glob - -from pyparsing import * -from junit_xml import TestSuite, TestCase - - -class UnityTestSummary: - def __init__(self): - self.report = '' - self.total_tests = 0 - self.failures = 0 - self.ignored = 0 - self.targets = 0 - self.root = None - self.test_suites = dict() - - def run(self): - # Clean up result file names - results = [] - for target in self.targets: - results.append(target.replace('\\', '/')) - - # Dig through each result file, looking for details on pass/fail: - for result_file in results: - lines = list(map(lambda line: line.rstrip(), open(result_file, "r").read().split('\n'))) - if len(lines) == 0: - raise Exception("Empty test result file: %s" % result_file) - - # define an expression for your file reference - entry_one = Combine( - oneOf(list(alphas)) + ':/' + - Word(alphanums + '_-./')) - - entry_two = Word(printables + ' ', excludeChars=':') - entry = entry_one | entry_two - - delimiter = Literal(':').suppress() - tc_result_line = Group(entry.setResultsName('tc_file_name') + delimiter + entry.setResultsName( - 'tc_line_nr') + delimiter + entry.setResultsName('tc_name') + delimiter + entry.setResultsName( - 'tc_status') + Optional( - delimiter + entry.setResultsName('tc_msg'))).setResultsName("tc_line") - - eol = LineEnd().suppress() - sol = LineStart().suppress() - blank_line = sol + eol - - tc_summary_line = Group(Word(nums).setResultsName("num_of_tests") + "Tests" + Word(nums).setResultsName( - "num_of_fail") + "Failures" + Word(nums).setResultsName("num_of_ignore") + "Ignored").setResultsName( - "tc_summary") - tc_end_line = Or(Literal("FAIL"), Literal('Ok')).setResultsName("tc_result") - - # run it and see... - pp1 = tc_result_line | Optional(tc_summary_line | tc_end_line) - pp1.ignore(blank_line | OneOrMore("-")) - - result = list() - for l in lines: - result.append((pp1.parseString(l)).asDict()) - # delete empty results - result = filter(None, result) - - tc_list = list() - for r in result: - if 'tc_line' in r: - tmp_tc_line = r['tc_line'] - - # get only the file name which will be used as the classname - file_name = tmp_tc_line['tc_file_name'].split('\\').pop().split('/').pop().rsplit('.', 1)[0] - tmp_tc = TestCase(name=tmp_tc_line['tc_name'], classname=file_name) - if 'tc_status' in tmp_tc_line: - if str(tmp_tc_line['tc_status']) == 'IGNORE': - if 'tc_msg' in tmp_tc_line: - tmp_tc.add_skipped_info(message=tmp_tc_line['tc_msg'], - output=r'[File]={0}, [Line]={1}'.format( - tmp_tc_line['tc_file_name'], tmp_tc_line['tc_line_nr'])) - else: - tmp_tc.add_skipped_info(message=" ") - elif str(tmp_tc_line['tc_status']) == 'FAIL': - if 'tc_msg' in tmp_tc_line: - tmp_tc.add_failure_info(message=tmp_tc_line['tc_msg'], - output=r'[File]={0}, [Line]={1}'.format( - tmp_tc_line['tc_file_name'], tmp_tc_line['tc_line_nr'])) - else: - tmp_tc.add_failure_info(message=" ") - - tc_list.append((str(result_file), tmp_tc)) - - for k, v in tc_list: - try: - self.test_suites[k].append(v) - except KeyError: - self.test_suites[k] = [v] - ts = [] - for suite_name in self.test_suites: - ts.append(TestSuite(suite_name, self.test_suites[suite_name])) - - with open('result.xml', 'w') as f: - TestSuite.to_file(f, ts, prettyprint='True', encoding='utf-8') - - return self.report - - def set_targets(self, target_array): - self.targets = target_array - - def set_root_path(self, path): - self.root = path - - @staticmethod - def usage(err_msg=None): - print("\nERROR: ") - if err_msg: - print(err_msg) - print("\nUsage: unity_test_summary.py result_file_directory/ root_path/") - print(" result_file_directory - The location of your results files.") - print(" Defaults to current directory if not specified.") - print(" Should end in / if specified.") - print(" root_path - Helpful for producing more verbose output if using relative paths.") - sys.exit(1) - - -if __name__ == '__main__': - uts = UnityTestSummary() - try: - # look in the specified or current directory for result files - if len(sys.argv) > 1: - targets_dir = sys.argv[1] - else: - targets_dir = './' - targets = list(map(lambda x: x.replace('\\', '/'), glob(targets_dir + '*.test*'))) - if len(targets) == 0: - raise Exception("No *.testpass or *.testfail files found in '%s'" % targets_dir) - uts.set_targets(targets) - - # set the root path - if len(sys.argv) > 2: - root_path = sys.argv[2] - else: - root_path = os.path.split(__file__)[0] - uts.set_root_path(root_path) - - # run the summarizer - print(uts.run()) - except Exception as e: - UnityTestSummary.usage(e) diff --git a/vendor/ceedling/vendor/unity/src/meson.build b/vendor/ceedling/vendor/unity/src/meson.build deleted file mode 100644 index 1c7b426..0000000 --- a/vendor/ceedling/vendor/unity/src/meson.build +++ /dev/null @@ -1,11 +0,0 @@ -# -# build script written by : Michael Brockus. -# github repo author: Mike Karlesky, Mark VanderVoord, Greg Williams. -# -# license: MIT -# -unity_dir = include_directories('.') - -unity_lib = static_library(meson.project_name(), - files('unity.c'), - include_directories: unity_dir) diff --git a/vendor/ceedling/vendor/unity/src/unity.c b/vendor/ceedling/vendor/unity/src/unity.c deleted file mode 100644 index 764a42b..0000000 --- a/vendor/ceedling/vendor/unity/src/unity.c +++ /dev/null @@ -1,2110 +0,0 @@ -/* ========================================================================= - Unity Project - A Test Framework for C - Copyright (c) 2007-21 Mike Karlesky, Mark VanderVoord, Greg Williams - [Released under MIT License. Please refer to license.txt for details] -============================================================================ */ - -#include "unity.h" -#include <stddef.h> - -#ifdef AVR -#include <avr/pgmspace.h> -#else -#define PROGMEM -#endif - -/* If omitted from header, declare overrideable prototypes here so they're ready for use */ -#ifdef UNITY_OMIT_OUTPUT_CHAR_HEADER_DECLARATION -void UNITY_OUTPUT_CHAR(int); -#endif - -/* Helpful macros for us to use here in Assert functions */ -#define UNITY_FAIL_AND_BAIL { Unity.CurrentTestFailed = 1; UNITY_OUTPUT_FLUSH(); TEST_ABORT(); } -#define UNITY_IGNORE_AND_BAIL { Unity.CurrentTestIgnored = 1; UNITY_OUTPUT_FLUSH(); TEST_ABORT(); } -#define RETURN_IF_FAIL_OR_IGNORE if (Unity.CurrentTestFailed || Unity.CurrentTestIgnored) TEST_ABORT() - -struct UNITY_STORAGE_T Unity; - -#ifdef UNITY_OUTPUT_COLOR -const char PROGMEM UnityStrOk[] = "\033[42mOK\033[00m"; -const char PROGMEM UnityStrPass[] = "\033[42mPASS\033[00m"; -const char PROGMEM UnityStrFail[] = "\033[41mFAIL\033[00m"; -const char PROGMEM UnityStrIgnore[] = "\033[43mIGNORE\033[00m"; -#else -const char PROGMEM UnityStrOk[] = "OK"; -const char PROGMEM UnityStrPass[] = "PASS"; -const char PROGMEM UnityStrFail[] = "FAIL"; -const char PROGMEM UnityStrIgnore[] = "IGNORE"; -#endif -static const char PROGMEM UnityStrNull[] = "NULL"; -static const char PROGMEM UnityStrSpacer[] = ". "; -static const char PROGMEM UnityStrExpected[] = " Expected "; -static const char PROGMEM UnityStrWas[] = " Was "; -static const char PROGMEM UnityStrGt[] = " to be greater than "; -static const char PROGMEM UnityStrLt[] = " to be less than "; -static const char PROGMEM UnityStrOrEqual[] = "or equal to "; -static const char PROGMEM UnityStrNotEqual[] = " to be not equal to "; -static const char PROGMEM UnityStrElement[] = " Element "; -static const char PROGMEM UnityStrByte[] = " Byte "; -static const char PROGMEM UnityStrMemory[] = " Memory Mismatch."; -static const char PROGMEM UnityStrDelta[] = " Values Not Within Delta "; -static const char PROGMEM UnityStrPointless[] = " You Asked Me To Compare Nothing, Which Was Pointless."; -static const char PROGMEM UnityStrNullPointerForExpected[] = " Expected pointer to be NULL"; -static const char PROGMEM UnityStrNullPointerForActual[] = " Actual pointer was NULL"; -#ifndef UNITY_EXCLUDE_FLOAT -static const char PROGMEM UnityStrNot[] = "Not "; -static const char PROGMEM UnityStrInf[] = "Infinity"; -static const char PROGMEM UnityStrNegInf[] = "Negative Infinity"; -static const char PROGMEM UnityStrNaN[] = "NaN"; -static const char PROGMEM UnityStrDet[] = "Determinate"; -static const char PROGMEM UnityStrInvalidFloatTrait[] = "Invalid Float Trait"; -#endif -const char PROGMEM UnityStrErrShorthand[] = "Unity Shorthand Support Disabled"; -const char PROGMEM UnityStrErrFloat[] = "Unity Floating Point Disabled"; -const char PROGMEM UnityStrErrDouble[] = "Unity Double Precision Disabled"; -const char PROGMEM UnityStrErr64[] = "Unity 64-bit Support Disabled"; -static const char PROGMEM UnityStrBreaker[] = "-----------------------"; -static const char PROGMEM UnityStrResultsTests[] = " Tests "; -static const char PROGMEM UnityStrResultsFailures[] = " Failures "; -static const char PROGMEM UnityStrResultsIgnored[] = " Ignored "; -#ifndef UNITY_EXCLUDE_DETAILS -static const char PROGMEM UnityStrDetail1Name[] = UNITY_DETAIL1_NAME " "; -static const char PROGMEM UnityStrDetail2Name[] = " " UNITY_DETAIL2_NAME " "; -#endif -/*----------------------------------------------- - * Pretty Printers & Test Result Output Handlers - *-----------------------------------------------*/ - -/*-----------------------------------------------*/ -/* Local helper function to print characters. */ -static void UnityPrintChar(const char* pch) -{ - /* printable characters plus CR & LF are printed */ - if ((*pch <= 126) && (*pch >= 32)) - { - UNITY_OUTPUT_CHAR(*pch); - } - /* write escaped carriage returns */ - else if (*pch == 13) - { - UNITY_OUTPUT_CHAR('\\'); - UNITY_OUTPUT_CHAR('r'); - } - /* write escaped line feeds */ - else if (*pch == 10) - { - UNITY_OUTPUT_CHAR('\\'); - UNITY_OUTPUT_CHAR('n'); - } - /* unprintable characters are shown as codes */ - else - { - UNITY_OUTPUT_CHAR('\\'); - UNITY_OUTPUT_CHAR('x'); - UnityPrintNumberHex((UNITY_UINT)*pch, 2); - } -} - -/*-----------------------------------------------*/ -/* Local helper function to print ANSI escape strings e.g. "\033[42m". */ -#ifdef UNITY_OUTPUT_COLOR -static UNITY_UINT UnityPrintAnsiEscapeString(const char* string) -{ - const char* pch = string; - UNITY_UINT count = 0; - - while (*pch && (*pch != 'm')) - { - UNITY_OUTPUT_CHAR(*pch); - pch++; - count++; - } - UNITY_OUTPUT_CHAR('m'); - count++; - - return count; -} -#endif - -/*-----------------------------------------------*/ -void UnityPrint(const char* string) -{ - const char* pch = string; - - if (pch != NULL) - { - while (*pch) - { -#ifdef UNITY_OUTPUT_COLOR - /* print ANSI escape code */ - if ((*pch == 27) && (*(pch + 1) == '[')) - { - pch += UnityPrintAnsiEscapeString(pch); - continue; - } -#endif - UnityPrintChar(pch); - pch++; - } - } -} -/*-----------------------------------------------*/ -void UnityPrintLen(const char* string, const UNITY_UINT32 length) -{ - const char* pch = string; - - if (pch != NULL) - { - while (*pch && ((UNITY_UINT32)(pch - string) < length)) - { - /* printable characters plus CR & LF are printed */ - if ((*pch <= 126) && (*pch >= 32)) - { - UNITY_OUTPUT_CHAR(*pch); - } - /* write escaped carriage returns */ - else if (*pch == 13) - { - UNITY_OUTPUT_CHAR('\\'); - UNITY_OUTPUT_CHAR('r'); - } - /* write escaped line feeds */ - else if (*pch == 10) - { - UNITY_OUTPUT_CHAR('\\'); - UNITY_OUTPUT_CHAR('n'); - } - /* unprintable characters are shown as codes */ - else - { - UNITY_OUTPUT_CHAR('\\'); - UNITY_OUTPUT_CHAR('x'); - UnityPrintNumberHex((UNITY_UINT)*pch, 2); - } - pch++; - } - } -} - -/*-----------------------------------------------*/ -void UnityPrintNumberByStyle(const UNITY_INT number, const UNITY_DISPLAY_STYLE_T style) -{ - if ((style & UNITY_DISPLAY_RANGE_INT) == UNITY_DISPLAY_RANGE_INT) - { - if (style == UNITY_DISPLAY_STYLE_CHAR) - { - /* printable characters plus CR & LF are printed */ - UNITY_OUTPUT_CHAR('\''); - if ((number <= 126) && (number >= 32)) - { - UNITY_OUTPUT_CHAR((int)number); - } - /* write escaped carriage returns */ - else if (number == 13) - { - UNITY_OUTPUT_CHAR('\\'); - UNITY_OUTPUT_CHAR('r'); - } - /* write escaped line feeds */ - else if (number == 10) - { - UNITY_OUTPUT_CHAR('\\'); - UNITY_OUTPUT_CHAR('n'); - } - /* unprintable characters are shown as codes */ - else - { - UNITY_OUTPUT_CHAR('\\'); - UNITY_OUTPUT_CHAR('x'); - UnityPrintNumberHex((UNITY_UINT)number, 2); - } - UNITY_OUTPUT_CHAR('\''); - } - else - { - UnityPrintNumber(number); - } - } - else if ((style & UNITY_DISPLAY_RANGE_UINT) == UNITY_DISPLAY_RANGE_UINT) - { - UnityPrintNumberUnsigned((UNITY_UINT)number); - } - else - { - UNITY_OUTPUT_CHAR('0'); - UNITY_OUTPUT_CHAR('x'); - UnityPrintNumberHex((UNITY_UINT)number, (char)((style & 0xF) * 2)); - } -} - -/*-----------------------------------------------*/ -void UnityPrintNumber(const UNITY_INT number_to_print) -{ - UNITY_UINT number = (UNITY_UINT)number_to_print; - - if (number_to_print < 0) - { - /* A negative number, including MIN negative */ - UNITY_OUTPUT_CHAR('-'); - number = (~number) + 1; - } - UnityPrintNumberUnsigned(number); -} - -/*----------------------------------------------- - * basically do an itoa using as little ram as possible */ -void UnityPrintNumberUnsigned(const UNITY_UINT number) -{ - UNITY_UINT divisor = 1; - - /* figure out initial divisor */ - while (number / divisor > 9) - { - divisor *= 10; - } - - /* now mod and print, then divide divisor */ - do - { - UNITY_OUTPUT_CHAR((char)('0' + (number / divisor % 10))); - divisor /= 10; - } while (divisor > 0); -} - -/*-----------------------------------------------*/ -void UnityPrintNumberHex(const UNITY_UINT number, const char nibbles_to_print) -{ - int nibble; - char nibbles = nibbles_to_print; - - if ((unsigned)nibbles > UNITY_MAX_NIBBLES) - { - nibbles = UNITY_MAX_NIBBLES; - } - - while (nibbles > 0) - { - nibbles--; - nibble = (int)(number >> (nibbles * 4)) & 0x0F; - if (nibble <= 9) - { - UNITY_OUTPUT_CHAR((char)('0' + nibble)); - } - else - { - UNITY_OUTPUT_CHAR((char)('A' - 10 + nibble)); - } - } -} - -/*-----------------------------------------------*/ -void UnityPrintMask(const UNITY_UINT mask, const UNITY_UINT number) -{ - UNITY_UINT current_bit = (UNITY_UINT)1 << (UNITY_INT_WIDTH - 1); - UNITY_INT32 i; - - for (i = 0; i < UNITY_INT_WIDTH; i++) - { - if (current_bit & mask) - { - if (current_bit & number) - { - UNITY_OUTPUT_CHAR('1'); - } - else - { - UNITY_OUTPUT_CHAR('0'); - } - } - else - { - UNITY_OUTPUT_CHAR('X'); - } - current_bit = current_bit >> 1; - } -} - -/*-----------------------------------------------*/ -#ifndef UNITY_EXCLUDE_FLOAT_PRINT -/* - * This function prints a floating-point value in a format similar to - * printf("%.7g") on a single-precision machine or printf("%.9g") on a - * double-precision machine. The 7th digit won't always be totally correct - * in single-precision operation (for that level of accuracy, a more - * complicated algorithm would be needed). - */ -void UnityPrintFloat(const UNITY_DOUBLE input_number) -{ -#ifdef UNITY_INCLUDE_DOUBLE - static const int sig_digits = 9; - static const UNITY_INT32 min_scaled = 100000000; - static const UNITY_INT32 max_scaled = 1000000000; -#else - static const int sig_digits = 7; - static const UNITY_INT32 min_scaled = 1000000; - static const UNITY_INT32 max_scaled = 10000000; -#endif - - UNITY_DOUBLE number = input_number; - - /* print minus sign (does not handle negative zero) */ - if (number < 0.0f) - { - UNITY_OUTPUT_CHAR('-'); - number = -number; - } - - /* handle zero, NaN, and +/- infinity */ - if (number == 0.0f) - { - UnityPrint("0"); - } - else if (isnan(number)) - { - UnityPrint("nan"); - } - else if (isinf(number)) - { - UnityPrint("inf"); - } - else - { - UNITY_INT32 n_int = 0, n; - int exponent = 0; - int decimals, digits; - char buf[16] = {0}; - - /* - * Scale up or down by powers of 10. To minimize rounding error, - * start with a factor/divisor of 10^10, which is the largest - * power of 10 that can be represented exactly. Finally, compute - * (exactly) the remaining power of 10 and perform one more - * multiplication or division. - */ - if (number < 1.0f) - { - UNITY_DOUBLE factor = 1.0f; - - while (number < (UNITY_DOUBLE)max_scaled / 1e10f) { number *= 1e10f; exponent -= 10; } - while (number * factor < (UNITY_DOUBLE)min_scaled) { factor *= 10.0f; exponent--; } - - number *= factor; - } - else if (number > (UNITY_DOUBLE)max_scaled) - { - UNITY_DOUBLE divisor = 1.0f; - - while (number > (UNITY_DOUBLE)min_scaled * 1e10f) { number /= 1e10f; exponent += 10; } - while (number / divisor > (UNITY_DOUBLE)max_scaled) { divisor *= 10.0f; exponent++; } - - number /= divisor; - } - else - { - /* - * In this range, we can split off the integer part before - * doing any multiplications. This reduces rounding error by - * freeing up significant bits in the fractional part. - */ - UNITY_DOUBLE factor = 1.0f; - n_int = (UNITY_INT32)number; - number -= (UNITY_DOUBLE)n_int; - - while (n_int < min_scaled) { n_int *= 10; factor *= 10.0f; exponent--; } - - number *= factor; - } - - /* round to nearest integer */ - n = ((UNITY_INT32)(number + number) + 1) / 2; - -#ifndef UNITY_ROUND_TIES_AWAY_FROM_ZERO - /* round to even if exactly between two integers */ - if ((n & 1) && (((UNITY_DOUBLE)n - number) == 0.5f)) - n--; -#endif - - n += n_int; - - if (n >= max_scaled) - { - n = min_scaled; - exponent++; - } - - /* determine where to place decimal point */ - decimals = ((exponent <= 0) && (exponent >= -(sig_digits + 3))) ? (-exponent) : (sig_digits - 1); - exponent += decimals; - - /* truncate trailing zeroes after decimal point */ - while ((decimals > 0) && ((n % 10) == 0)) - { - n /= 10; - decimals--; - } - - /* build up buffer in reverse order */ - digits = 0; - while ((n != 0) || (digits <= decimals)) - { - buf[digits++] = (char)('0' + n % 10); - n /= 10; - } - while (digits > 0) - { - if (digits == decimals) { UNITY_OUTPUT_CHAR('.'); } - UNITY_OUTPUT_CHAR(buf[--digits]); - } - - /* print exponent if needed */ - if (exponent != 0) - { - UNITY_OUTPUT_CHAR('e'); - - if (exponent < 0) - { - UNITY_OUTPUT_CHAR('-'); - exponent = -exponent; - } - else - { - UNITY_OUTPUT_CHAR('+'); - } - - digits = 0; - while ((exponent != 0) || (digits < 2)) - { - buf[digits++] = (char)('0' + exponent % 10); - exponent /= 10; - } - while (digits > 0) - { - UNITY_OUTPUT_CHAR(buf[--digits]); - } - } - } -} -#endif /* ! UNITY_EXCLUDE_FLOAT_PRINT */ - -/*-----------------------------------------------*/ -static void UnityTestResultsBegin(const char* file, const UNITY_LINE_TYPE line) -{ -#ifdef UNITY_OUTPUT_FOR_ECLIPSE - UNITY_OUTPUT_CHAR('('); - UnityPrint(file); - UNITY_OUTPUT_CHAR(':'); - UnityPrintNumber((UNITY_INT)line); - UNITY_OUTPUT_CHAR(')'); - UNITY_OUTPUT_CHAR(' '); - UnityPrint(Unity.CurrentTestName); - UNITY_OUTPUT_CHAR(':'); -#else -#ifdef UNITY_OUTPUT_FOR_IAR_WORKBENCH - UnityPrint("<SRCREF line="); - UnityPrintNumber((UNITY_INT)line); - UnityPrint(" file=\""); - UnityPrint(file); - UNITY_OUTPUT_CHAR('"'); - UNITY_OUTPUT_CHAR('>'); - UnityPrint(Unity.CurrentTestName); - UnityPrint("</SRCREF> "); -#else -#ifdef UNITY_OUTPUT_FOR_QT_CREATOR - UnityPrint("file://"); - UnityPrint(file); - UNITY_OUTPUT_CHAR(':'); - UnityPrintNumber((UNITY_INT)line); - UNITY_OUTPUT_CHAR(' '); - UnityPrint(Unity.CurrentTestName); - UNITY_OUTPUT_CHAR(':'); -#else - UnityPrint(file); - UNITY_OUTPUT_CHAR(':'); - UnityPrintNumber((UNITY_INT)line); - UNITY_OUTPUT_CHAR(':'); - UnityPrint(Unity.CurrentTestName); - UNITY_OUTPUT_CHAR(':'); -#endif -#endif -#endif -} - -/*-----------------------------------------------*/ -static void UnityTestResultsFailBegin(const UNITY_LINE_TYPE line) -{ - UnityTestResultsBegin(Unity.TestFile, line); - UnityPrint(UnityStrFail); - UNITY_OUTPUT_CHAR(':'); -} - -/*-----------------------------------------------*/ -void UnityConcludeTest(void) -{ - if (Unity.CurrentTestIgnored) - { - Unity.TestIgnores++; - } - else if (!Unity.CurrentTestFailed) - { - UnityTestResultsBegin(Unity.TestFile, Unity.CurrentTestLineNumber); - UnityPrint(UnityStrPass); - } - else - { - Unity.TestFailures++; - } - - Unity.CurrentTestFailed = 0; - Unity.CurrentTestIgnored = 0; - UNITY_PRINT_EXEC_TIME(); - UNITY_PRINT_EOL(); - UNITY_FLUSH_CALL(); -} - -/*-----------------------------------------------*/ -static void UnityAddMsgIfSpecified(const char* msg) -{ - if (msg) - { - UnityPrint(UnityStrSpacer); - -#ifdef UNITY_PRINT_TEST_CONTEXT - UNITY_PRINT_TEST_CONTEXT(); -#endif -#ifndef UNITY_EXCLUDE_DETAILS - if (Unity.CurrentDetail1) - { - UnityPrint(UnityStrDetail1Name); - UnityPrint(Unity.CurrentDetail1); - if (Unity.CurrentDetail2) - { - UnityPrint(UnityStrDetail2Name); - UnityPrint(Unity.CurrentDetail2); - } - UnityPrint(UnityStrSpacer); - } -#endif - UnityPrint(msg); - } -} - -/*-----------------------------------------------*/ -static void UnityPrintExpectedAndActualStrings(const char* expected, const char* actual) -{ - UnityPrint(UnityStrExpected); - if (expected != NULL) - { - UNITY_OUTPUT_CHAR('\''); - UnityPrint(expected); - UNITY_OUTPUT_CHAR('\''); - } - else - { - UnityPrint(UnityStrNull); - } - UnityPrint(UnityStrWas); - if (actual != NULL) - { - UNITY_OUTPUT_CHAR('\''); - UnityPrint(actual); - UNITY_OUTPUT_CHAR('\''); - } - else - { - UnityPrint(UnityStrNull); - } -} - -/*-----------------------------------------------*/ -static void UnityPrintExpectedAndActualStringsLen(const char* expected, - const char* actual, - const UNITY_UINT32 length) -{ - UnityPrint(UnityStrExpected); - if (expected != NULL) - { - UNITY_OUTPUT_CHAR('\''); - UnityPrintLen(expected, length); - UNITY_OUTPUT_CHAR('\''); - } - else - { - UnityPrint(UnityStrNull); - } - UnityPrint(UnityStrWas); - if (actual != NULL) - { - UNITY_OUTPUT_CHAR('\''); - UnityPrintLen(actual, length); - UNITY_OUTPUT_CHAR('\''); - } - else - { - UnityPrint(UnityStrNull); - } -} - -/*----------------------------------------------- - * Assertion & Control Helpers - *-----------------------------------------------*/ - -/*-----------------------------------------------*/ -static int UnityIsOneArrayNull(UNITY_INTERNAL_PTR expected, - UNITY_INTERNAL_PTR actual, - const UNITY_LINE_TYPE lineNumber, - const char* msg) -{ - /* Both are NULL or same pointer */ - if (expected == actual) { return 0; } - - /* print and return true if just expected is NULL */ - if (expected == NULL) - { - UnityTestResultsFailBegin(lineNumber); - UnityPrint(UnityStrNullPointerForExpected); - UnityAddMsgIfSpecified(msg); - return 1; - } - - /* print and return true if just actual is NULL */ - if (actual == NULL) - { - UnityTestResultsFailBegin(lineNumber); - UnityPrint(UnityStrNullPointerForActual); - UnityAddMsgIfSpecified(msg); - return 1; - } - - return 0; /* return false if neither is NULL */ -} - -/*----------------------------------------------- - * Assertion Functions - *-----------------------------------------------*/ - -/*-----------------------------------------------*/ -void UnityAssertBits(const UNITY_INT mask, - const UNITY_INT expected, - const UNITY_INT actual, - const char* msg, - const UNITY_LINE_TYPE lineNumber) -{ - RETURN_IF_FAIL_OR_IGNORE; - - if ((mask & expected) != (mask & actual)) - { - UnityTestResultsFailBegin(lineNumber); - UnityPrint(UnityStrExpected); - UnityPrintMask((UNITY_UINT)mask, (UNITY_UINT)expected); - UnityPrint(UnityStrWas); - UnityPrintMask((UNITY_UINT)mask, (UNITY_UINT)actual); - UnityAddMsgIfSpecified(msg); - UNITY_FAIL_AND_BAIL; - } -} - -/*-----------------------------------------------*/ -void UnityAssertEqualNumber(const UNITY_INT expected, - const UNITY_INT actual, - const char* msg, - const UNITY_LINE_TYPE lineNumber, - const UNITY_DISPLAY_STYLE_T style) -{ - RETURN_IF_FAIL_OR_IGNORE; - - if (expected != actual) - { - UnityTestResultsFailBegin(lineNumber); - UnityPrint(UnityStrExpected); - UnityPrintNumberByStyle(expected, style); - UnityPrint(UnityStrWas); - UnityPrintNumberByStyle(actual, style); - UnityAddMsgIfSpecified(msg); - UNITY_FAIL_AND_BAIL; - } -} - -/*-----------------------------------------------*/ -void UnityAssertGreaterOrLessOrEqualNumber(const UNITY_INT threshold, - const UNITY_INT actual, - const UNITY_COMPARISON_T compare, - const char *msg, - const UNITY_LINE_TYPE lineNumber, - const UNITY_DISPLAY_STYLE_T style) -{ - int failed = 0; - RETURN_IF_FAIL_OR_IGNORE; - - if ((threshold == actual) && (compare & UNITY_EQUAL_TO)) { return; } - if ((threshold == actual)) { failed = 1; } - - if ((style & UNITY_DISPLAY_RANGE_INT) == UNITY_DISPLAY_RANGE_INT) - { - if ((actual > threshold) && (compare & UNITY_SMALLER_THAN)) { failed = 1; } - if ((actual < threshold) && (compare & UNITY_GREATER_THAN)) { failed = 1; } - } - else /* UINT or HEX */ - { - if (((UNITY_UINT)actual > (UNITY_UINT)threshold) && (compare & UNITY_SMALLER_THAN)) { failed = 1; } - if (((UNITY_UINT)actual < (UNITY_UINT)threshold) && (compare & UNITY_GREATER_THAN)) { failed = 1; } - } - - if (failed) - { - UnityTestResultsFailBegin(lineNumber); - UnityPrint(UnityStrExpected); - UnityPrintNumberByStyle(actual, style); - if (compare & UNITY_GREATER_THAN) { UnityPrint(UnityStrGt); } - if (compare & UNITY_SMALLER_THAN) { UnityPrint(UnityStrLt); } - if (compare & UNITY_EQUAL_TO) { UnityPrint(UnityStrOrEqual); } - if (compare == UNITY_NOT_EQUAL) { UnityPrint(UnityStrNotEqual); } - UnityPrintNumberByStyle(threshold, style); - UnityAddMsgIfSpecified(msg); - UNITY_FAIL_AND_BAIL; - } -} - -#define UnityPrintPointlessAndBail() \ -{ \ - UnityTestResultsFailBegin(lineNumber); \ - UnityPrint(UnityStrPointless); \ - UnityAddMsgIfSpecified(msg); \ - UNITY_FAIL_AND_BAIL; } - -/*-----------------------------------------------*/ -void UnityAssertEqualIntArray(UNITY_INTERNAL_PTR expected, - UNITY_INTERNAL_PTR actual, - const UNITY_UINT32 num_elements, - const char* msg, - const UNITY_LINE_TYPE lineNumber, - const UNITY_DISPLAY_STYLE_T style, - const UNITY_FLAGS_T flags) -{ - UNITY_UINT32 elements = num_elements; - unsigned int length = style & 0xF; - unsigned int increment = 0; - - RETURN_IF_FAIL_OR_IGNORE; - - if (num_elements == 0) - { - UnityPrintPointlessAndBail(); - } - - if (expected == actual) - { - return; /* Both are NULL or same pointer */ - } - - if (UnityIsOneArrayNull(expected, actual, lineNumber, msg)) - { - UNITY_FAIL_AND_BAIL; - } - - while ((elements > 0) && (elements--)) - { - UNITY_INT expect_val; - UNITY_INT actual_val; - - switch (length) - { - case 1: - expect_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT8*)expected; - actual_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT8*)actual; - increment = sizeof(UNITY_INT8); - break; - - case 2: - expect_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT16*)expected; - actual_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT16*)actual; - increment = sizeof(UNITY_INT16); - 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; - increment = sizeof(UNITY_INT64); - break; -#endif - - default: /* default is length 4 bytes */ - case 4: - expect_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT32*)expected; - actual_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT32*)actual; - increment = sizeof(UNITY_INT32); - length = 4; - break; - } - - if (expect_val != actual_val) - { - if ((style & UNITY_DISPLAY_RANGE_UINT) && (length < (UNITY_INT_WIDTH / 8))) - { /* For UINT, remove sign extension (padding 1's) from signed type casts above */ - UNITY_INT mask = 1; - mask = (mask << 8 * length) - 1; - expect_val &= mask; - actual_val &= mask; - } - UnityTestResultsFailBegin(lineNumber); - UnityPrint(UnityStrElement); - UnityPrintNumberUnsigned(num_elements - elements - 1); - UnityPrint(UnityStrExpected); - UnityPrintNumberByStyle(expect_val, style); - UnityPrint(UnityStrWas); - UnityPrintNumberByStyle(actual_val, style); - UnityAddMsgIfSpecified(msg); - UNITY_FAIL_AND_BAIL; - } - /* Walk through array by incrementing the pointers */ - if (flags == UNITY_ARRAY_TO_ARRAY) - { - expected = (UNITY_INTERNAL_PTR)((const char*)expected + increment); - } - actual = (UNITY_INTERNAL_PTR)((const char*)actual + increment); - } -} - -/*-----------------------------------------------*/ -#ifndef UNITY_EXCLUDE_FLOAT -/* Wrap this define in a function with variable types as float or double */ -#define UNITY_FLOAT_OR_DOUBLE_WITHIN(delta, expected, actual, diff) \ - if (isinf(expected) && isinf(actual) && (((expected) < 0) == ((actual) < 0))) return 1; \ - if (UNITY_NAN_CHECK) return 1; \ - (diff) = (actual) - (expected); \ - if ((diff) < 0) (diff) = -(diff); \ - if ((delta) < 0) (delta) = -(delta); \ - return !(isnan(diff) || isinf(diff) || ((diff) > (delta))) - /* This first part of this condition will catch any NaN or Infinite values */ -#ifndef UNITY_NAN_NOT_EQUAL_NAN - #define UNITY_NAN_CHECK isnan(expected) && isnan(actual) -#else - #define UNITY_NAN_CHECK 0 -#endif - -#ifndef UNITY_EXCLUDE_FLOAT_PRINT - #define UNITY_PRINT_EXPECTED_AND_ACTUAL_FLOAT(expected, actual) \ - { \ - UnityPrint(UnityStrExpected); \ - UnityPrintFloat(expected); \ - UnityPrint(UnityStrWas); \ - UnityPrintFloat(actual); } -#else - #define UNITY_PRINT_EXPECTED_AND_ACTUAL_FLOAT(expected, actual) \ - UnityPrint(UnityStrDelta) -#endif /* UNITY_EXCLUDE_FLOAT_PRINT */ - -/*-----------------------------------------------*/ -static int UnityFloatsWithin(UNITY_FLOAT delta, UNITY_FLOAT expected, UNITY_FLOAT actual) -{ - UNITY_FLOAT diff; - UNITY_FLOAT_OR_DOUBLE_WITHIN(delta, expected, actual, diff); -} - -/*-----------------------------------------------*/ -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_FLAGS_T flags) -{ - UNITY_UINT32 elements = num_elements; - UNITY_PTR_ATTRIBUTE const UNITY_FLOAT* ptr_expected = expected; - UNITY_PTR_ATTRIBUTE const UNITY_FLOAT* ptr_actual = actual; - - RETURN_IF_FAIL_OR_IGNORE; - - if (elements == 0) - { - UnityPrintPointlessAndBail(); - } - - if (expected == actual) - { - return; /* Both are NULL or same pointer */ - } - - if (UnityIsOneArrayNull((UNITY_INTERNAL_PTR)expected, (UNITY_INTERNAL_PTR)actual, lineNumber, msg)) - { - UNITY_FAIL_AND_BAIL; - } - - while (elements--) - { - if (!UnityFloatsWithin(*ptr_expected * UNITY_FLOAT_PRECISION, *ptr_expected, *ptr_actual)) - { - UnityTestResultsFailBegin(lineNumber); - UnityPrint(UnityStrElement); - UnityPrintNumberUnsigned(num_elements - elements - 1); - UNITY_PRINT_EXPECTED_AND_ACTUAL_FLOAT((UNITY_DOUBLE)*ptr_expected, (UNITY_DOUBLE)*ptr_actual); - UnityAddMsgIfSpecified(msg); - UNITY_FAIL_AND_BAIL; - } - if (flags == UNITY_ARRAY_TO_ARRAY) - { - ptr_expected++; - } - ptr_actual++; - } -} - -/*-----------------------------------------------*/ -void UnityAssertFloatsWithin(const UNITY_FLOAT delta, - const UNITY_FLOAT expected, - const UNITY_FLOAT actual, - const char* msg, - const UNITY_LINE_TYPE lineNumber) -{ - RETURN_IF_FAIL_OR_IGNORE; - - - if (!UnityFloatsWithin(delta, expected, actual)) - { - UnityTestResultsFailBegin(lineNumber); - UNITY_PRINT_EXPECTED_AND_ACTUAL_FLOAT((UNITY_DOUBLE)expected, (UNITY_DOUBLE)actual); - UnityAddMsgIfSpecified(msg); - UNITY_FAIL_AND_BAIL; - } -} - -/*-----------------------------------------------*/ -void UnityAssertFloatSpecial(const UNITY_FLOAT actual, - const char* msg, - const UNITY_LINE_TYPE lineNumber, - const UNITY_FLOAT_TRAIT_T style) -{ - const char* trait_names[] = {UnityStrInf, UnityStrNegInf, UnityStrNaN, UnityStrDet}; - UNITY_INT should_be_trait = ((UNITY_INT)style & 1); - UNITY_INT is_trait = !should_be_trait; - UNITY_INT trait_index = (UNITY_INT)(style >> 1); - - RETURN_IF_FAIL_OR_IGNORE; - - switch (style) - { - case UNITY_FLOAT_IS_INF: - case UNITY_FLOAT_IS_NOT_INF: - is_trait = isinf(actual) && (actual > 0); - break; - case UNITY_FLOAT_IS_NEG_INF: - case UNITY_FLOAT_IS_NOT_NEG_INF: - is_trait = isinf(actual) && (actual < 0); - break; - - case UNITY_FLOAT_IS_NAN: - case UNITY_FLOAT_IS_NOT_NAN: - is_trait = isnan(actual) ? 1 : 0; - break; - - case UNITY_FLOAT_IS_DET: /* A determinate number is non infinite and not NaN. */ - case UNITY_FLOAT_IS_NOT_DET: - is_trait = !isinf(actual) && !isnan(actual); - break; - - default: /* including UNITY_FLOAT_INVALID_TRAIT */ - trait_index = 0; - trait_names[0] = UnityStrInvalidFloatTrait; - break; - } - - if (is_trait != should_be_trait) - { - UnityTestResultsFailBegin(lineNumber); - UnityPrint(UnityStrExpected); - if (!should_be_trait) - { - UnityPrint(UnityStrNot); - } - UnityPrint(trait_names[trait_index]); - UnityPrint(UnityStrWas); -#ifndef UNITY_EXCLUDE_FLOAT_PRINT - UnityPrintFloat((UNITY_DOUBLE)actual); -#else - if (should_be_trait) - { - UnityPrint(UnityStrNot); - } - UnityPrint(trait_names[trait_index]); -#endif - UnityAddMsgIfSpecified(msg); - UNITY_FAIL_AND_BAIL; - } -} - -#endif /* not UNITY_EXCLUDE_FLOAT */ - -/*-----------------------------------------------*/ -#ifndef UNITY_EXCLUDE_DOUBLE -static int UnityDoublesWithin(UNITY_DOUBLE delta, UNITY_DOUBLE expected, UNITY_DOUBLE actual) -{ - UNITY_DOUBLE diff; - UNITY_FLOAT_OR_DOUBLE_WITHIN(delta, expected, actual, diff); -} - -/*-----------------------------------------------*/ -void UnityAssertEqualDoubleArray(UNITY_PTR_ATTRIBUTE const UNITY_DOUBLE* expected, - UNITY_PTR_ATTRIBUTE const UNITY_DOUBLE* actual, - const UNITY_UINT32 num_elements, - const char* msg, - const UNITY_LINE_TYPE lineNumber, - const UNITY_FLAGS_T flags) -{ - UNITY_UINT32 elements = num_elements; - UNITY_PTR_ATTRIBUTE const UNITY_DOUBLE* ptr_expected = expected; - UNITY_PTR_ATTRIBUTE const UNITY_DOUBLE* ptr_actual = actual; - - RETURN_IF_FAIL_OR_IGNORE; - - if (elements == 0) - { - UnityPrintPointlessAndBail(); - } - - if (expected == actual) - { - return; /* Both are NULL or same pointer */ - } - - if (UnityIsOneArrayNull((UNITY_INTERNAL_PTR)expected, (UNITY_INTERNAL_PTR)actual, lineNumber, msg)) - { - UNITY_FAIL_AND_BAIL; - } - - while (elements--) - { - if (!UnityDoublesWithin(*ptr_expected * UNITY_DOUBLE_PRECISION, *ptr_expected, *ptr_actual)) - { - UnityTestResultsFailBegin(lineNumber); - UnityPrint(UnityStrElement); - UnityPrintNumberUnsigned(num_elements - elements - 1); - UNITY_PRINT_EXPECTED_AND_ACTUAL_FLOAT(*ptr_expected, *ptr_actual); - UnityAddMsgIfSpecified(msg); - UNITY_FAIL_AND_BAIL; - } - if (flags == UNITY_ARRAY_TO_ARRAY) - { - ptr_expected++; - } - ptr_actual++; - } -} - -/*-----------------------------------------------*/ -void UnityAssertDoublesWithin(const UNITY_DOUBLE delta, - const UNITY_DOUBLE expected, - const UNITY_DOUBLE actual, - const char* msg, - const UNITY_LINE_TYPE lineNumber) -{ - RETURN_IF_FAIL_OR_IGNORE; - - if (!UnityDoublesWithin(delta, expected, actual)) - { - UnityTestResultsFailBegin(lineNumber); - UNITY_PRINT_EXPECTED_AND_ACTUAL_FLOAT(expected, actual); - UnityAddMsgIfSpecified(msg); - UNITY_FAIL_AND_BAIL; - } -} - -/*-----------------------------------------------*/ -void UnityAssertDoubleSpecial(const UNITY_DOUBLE actual, - const char* msg, - const UNITY_LINE_TYPE lineNumber, - const UNITY_FLOAT_TRAIT_T style) -{ - const char* trait_names[] = {UnityStrInf, UnityStrNegInf, UnityStrNaN, UnityStrDet}; - UNITY_INT should_be_trait = ((UNITY_INT)style & 1); - UNITY_INT is_trait = !should_be_trait; - UNITY_INT trait_index = (UNITY_INT)(style >> 1); - - RETURN_IF_FAIL_OR_IGNORE; - - switch (style) - { - case UNITY_FLOAT_IS_INF: - case UNITY_FLOAT_IS_NOT_INF: - is_trait = isinf(actual) && (actual > 0); - break; - case UNITY_FLOAT_IS_NEG_INF: - case UNITY_FLOAT_IS_NOT_NEG_INF: - is_trait = isinf(actual) && (actual < 0); - break; - - case UNITY_FLOAT_IS_NAN: - case UNITY_FLOAT_IS_NOT_NAN: - is_trait = isnan(actual) ? 1 : 0; - break; - - case UNITY_FLOAT_IS_DET: /* A determinate number is non infinite and not NaN. */ - case UNITY_FLOAT_IS_NOT_DET: - is_trait = !isinf(actual) && !isnan(actual); - break; - - default: /* including UNITY_FLOAT_INVALID_TRAIT */ - trait_index = 0; - trait_names[0] = UnityStrInvalidFloatTrait; - break; - } - - if (is_trait != should_be_trait) - { - UnityTestResultsFailBegin(lineNumber); - UnityPrint(UnityStrExpected); - if (!should_be_trait) - { - UnityPrint(UnityStrNot); - } - UnityPrint(trait_names[trait_index]); - UnityPrint(UnityStrWas); -#ifndef UNITY_EXCLUDE_FLOAT_PRINT - UnityPrintFloat(actual); -#else - if (should_be_trait) - { - UnityPrint(UnityStrNot); - } - UnityPrint(trait_names[trait_index]); -#endif - UnityAddMsgIfSpecified(msg); - UNITY_FAIL_AND_BAIL; - } -} - -#endif /* not UNITY_EXCLUDE_DOUBLE */ - -/*-----------------------------------------------*/ -void UnityAssertNumbersWithin(const UNITY_UINT delta, - const UNITY_INT expected, - const UNITY_INT actual, - const char* msg, - const UNITY_LINE_TYPE lineNumber, - const UNITY_DISPLAY_STYLE_T style) -{ - RETURN_IF_FAIL_OR_IGNORE; - - if ((style & UNITY_DISPLAY_RANGE_INT) == UNITY_DISPLAY_RANGE_INT) - { - if (actual > expected) - { - Unity.CurrentTestFailed = (((UNITY_UINT)actual - (UNITY_UINT)expected) > delta); - } - else - { - Unity.CurrentTestFailed = (((UNITY_UINT)expected - (UNITY_UINT)actual) > delta); - } - } - else - { - if ((UNITY_UINT)actual > (UNITY_UINT)expected) - { - Unity.CurrentTestFailed = (((UNITY_UINT)actual - (UNITY_UINT)expected) > delta); - } - else - { - Unity.CurrentTestFailed = (((UNITY_UINT)expected - (UNITY_UINT)actual) > delta); - } - } - - if (Unity.CurrentTestFailed) - { - UnityTestResultsFailBegin(lineNumber); - UnityPrint(UnityStrDelta); - UnityPrintNumberByStyle((UNITY_INT)delta, style); - UnityPrint(UnityStrExpected); - UnityPrintNumberByStyle(expected, style); - UnityPrint(UnityStrWas); - UnityPrintNumberByStyle(actual, style); - UnityAddMsgIfSpecified(msg); - UNITY_FAIL_AND_BAIL; - } -} - -/*-----------------------------------------------*/ -void UnityAssertNumbersArrayWithin(const UNITY_UINT delta, - UNITY_INTERNAL_PTR expected, - UNITY_INTERNAL_PTR actual, - const UNITY_UINT32 num_elements, - const char* msg, - const UNITY_LINE_TYPE lineNumber, - const UNITY_DISPLAY_STYLE_T style, - const UNITY_FLAGS_T flags) -{ - UNITY_UINT32 elements = num_elements; - unsigned int length = style & 0xF; - unsigned int increment = 0; - - RETURN_IF_FAIL_OR_IGNORE; - - if (num_elements == 0) - { - UnityPrintPointlessAndBail(); - } - - if (expected == actual) - { - return; /* Both are NULL or same pointer */ - } - - if (UnityIsOneArrayNull(expected, actual, lineNumber, msg)) - { - UNITY_FAIL_AND_BAIL; - } - - while ((elements > 0) && (elements--)) - { - UNITY_INT expect_val; - UNITY_INT actual_val; - - switch (length) - { - case 1: - expect_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT8*)expected; - actual_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT8*)actual; - increment = sizeof(UNITY_INT8); - break; - - case 2: - expect_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT16*)expected; - actual_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT16*)actual; - increment = sizeof(UNITY_INT16); - 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; - increment = sizeof(UNITY_INT64); - break; -#endif - - default: /* default is length 4 bytes */ - case 4: - expect_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT32*)expected; - actual_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT32*)actual; - increment = sizeof(UNITY_INT32); - length = 4; - break; - } - - if ((style & UNITY_DISPLAY_RANGE_INT) == UNITY_DISPLAY_RANGE_INT) - { - if (actual_val > expect_val) - { - Unity.CurrentTestFailed = (((UNITY_UINT)actual_val - (UNITY_UINT)expect_val) > delta); - } - else - { - Unity.CurrentTestFailed = (((UNITY_UINT)expect_val - (UNITY_UINT)actual_val) > delta); - } - } - else - { - if ((UNITY_UINT)actual_val > (UNITY_UINT)expect_val) - { - Unity.CurrentTestFailed = (((UNITY_UINT)actual_val - (UNITY_UINT)expect_val) > delta); - } - else - { - Unity.CurrentTestFailed = (((UNITY_UINT)expect_val - (UNITY_UINT)actual_val) > delta); - } - } - - if (Unity.CurrentTestFailed) - { - if ((style & UNITY_DISPLAY_RANGE_UINT) && (length < (UNITY_INT_WIDTH / 8))) - { /* For UINT, remove sign extension (padding 1's) from signed type casts above */ - UNITY_INT mask = 1; - mask = (mask << 8 * length) - 1; - expect_val &= mask; - actual_val &= mask; - } - UnityTestResultsFailBegin(lineNumber); - UnityPrint(UnityStrDelta); - UnityPrintNumberByStyle((UNITY_INT)delta, style); - UnityPrint(UnityStrElement); - UnityPrintNumberUnsigned(num_elements - elements - 1); - UnityPrint(UnityStrExpected); - UnityPrintNumberByStyle(expect_val, style); - UnityPrint(UnityStrWas); - UnityPrintNumberByStyle(actual_val, style); - UnityAddMsgIfSpecified(msg); - UNITY_FAIL_AND_BAIL; - } - /* Walk through array by incrementing the pointers */ - if (flags == UNITY_ARRAY_TO_ARRAY) - { - expected = (UNITY_INTERNAL_PTR)((const char*)expected + increment); - } - actual = (UNITY_INTERNAL_PTR)((const char*)actual + increment); - } -} - -/*-----------------------------------------------*/ -void UnityAssertEqualString(const char* expected, - const char* actual, - const char* msg, - const UNITY_LINE_TYPE lineNumber) -{ - UNITY_UINT32 i; - - RETURN_IF_FAIL_OR_IGNORE; - - /* if both pointers not null compare the strings */ - if (expected && actual) - { - for (i = 0; expected[i] || actual[i]; i++) - { - if (expected[i] != actual[i]) - { - Unity.CurrentTestFailed = 1; - break; - } - } - } - else - { /* handle case of one pointers being null (if both null, test should pass) */ - if (expected != actual) - { - Unity.CurrentTestFailed = 1; - } - } - - if (Unity.CurrentTestFailed) - { - UnityTestResultsFailBegin(lineNumber); - UnityPrintExpectedAndActualStrings(expected, actual); - UnityAddMsgIfSpecified(msg); - UNITY_FAIL_AND_BAIL; - } -} - -/*-----------------------------------------------*/ -void UnityAssertEqualStringLen(const char* expected, - const char* actual, - const UNITY_UINT32 length, - const char* msg, - const UNITY_LINE_TYPE lineNumber) -{ - UNITY_UINT32 i; - - RETURN_IF_FAIL_OR_IGNORE; - - /* if both pointers not null compare the strings */ - if (expected && actual) - { - for (i = 0; (i < length) && (expected[i] || actual[i]); i++) - { - if (expected[i] != actual[i]) - { - Unity.CurrentTestFailed = 1; - break; - } - } - } - else - { /* handle case of one pointers being null (if both null, test should pass) */ - if (expected != actual) - { - Unity.CurrentTestFailed = 1; - } - } - - if (Unity.CurrentTestFailed) - { - UnityTestResultsFailBegin(lineNumber); - UnityPrintExpectedAndActualStringsLen(expected, actual, length); - UnityAddMsgIfSpecified(msg); - UNITY_FAIL_AND_BAIL; - } -} - -/*-----------------------------------------------*/ -void UnityAssertEqualStringArray(UNITY_INTERNAL_PTR expected, - const char** actual, - const UNITY_UINT32 num_elements, - const char* msg, - const UNITY_LINE_TYPE lineNumber, - const UNITY_FLAGS_T flags) -{ - UNITY_UINT32 i = 0; - UNITY_UINT32 j = 0; - const char* expd = NULL; - const char* act = NULL; - - RETURN_IF_FAIL_OR_IGNORE; - - /* if no elements, it's an error */ - if (num_elements == 0) - { - UnityPrintPointlessAndBail(); - } - - 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) - { - expd = (const char*)expected; - } - - do - { - act = actual[j]; - if (flags == UNITY_ARRAY_TO_ARRAY) - { - expd = ((const char* const*)expected)[j]; - } - - /* if both pointers not null compare the strings */ - if (expd && act) - { - for (i = 0; expd[i] || act[i]; i++) - { - if (expd[i] != act[i]) - { - Unity.CurrentTestFailed = 1; - break; - } - } - } - else - { /* handle case of one pointers being null (if both null, test should pass) */ - if (expd != act) - { - Unity.CurrentTestFailed = 1; - } - } - - if (Unity.CurrentTestFailed) - { - UnityTestResultsFailBegin(lineNumber); - if (num_elements > 1) - { - UnityPrint(UnityStrElement); - UnityPrintNumberUnsigned(j); - } - UnityPrintExpectedAndActualStrings(expd, act); - UnityAddMsgIfSpecified(msg); - UNITY_FAIL_AND_BAIL; - } - } while (++j < num_elements); -} - -/*-----------------------------------------------*/ -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_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; - UNITY_UINT32 elements = num_elements; - UNITY_UINT32 bytes; - - RETURN_IF_FAIL_OR_IGNORE; - - if ((elements == 0) || (length == 0)) - { - UnityPrintPointlessAndBail(); - } - - if (expected == actual) - { - return; /* Both are NULL or same pointer */ - } - - if (UnityIsOneArrayNull(expected, actual, lineNumber, msg)) - { - UNITY_FAIL_AND_BAIL; - } - - while (elements--) - { - bytes = length; - while (bytes--) - { - if (*ptr_exp != *ptr_act) - { - UnityTestResultsFailBegin(lineNumber); - UnityPrint(UnityStrMemory); - if (num_elements > 1) - { - UnityPrint(UnityStrElement); - UnityPrintNumberUnsigned(num_elements - elements - 1); - } - UnityPrint(UnityStrByte); - UnityPrintNumberUnsigned(length - bytes - 1); - UnityPrint(UnityStrExpected); - UnityPrintNumberByStyle(*ptr_exp, UNITY_DISPLAY_STYLE_HEX8); - UnityPrint(UnityStrWas); - UnityPrintNumberByStyle(*ptr_act, UNITY_DISPLAY_STYLE_HEX8); - UnityAddMsgIfSpecified(msg); - UNITY_FAIL_AND_BAIL; - } - 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 - -/*----------------------------------------------- - * printf helper function - *-----------------------------------------------*/ -#ifdef UNITY_INCLUDE_PRINT_FORMATTED -static void UnityPrintFVA(const char* format, va_list va) -{ - const char* pch = format; - if (pch != NULL) - { - while (*pch) - { - /* format identification character */ - if (*pch == '%') - { - pch++; - - if (pch != NULL) - { - switch (*pch) - { - case 'd': - case 'i': - { - const int number = va_arg(va, int); - UnityPrintNumber((UNITY_INT)number); - break; - } -#ifndef UNITY_EXCLUDE_FLOAT_PRINT - case 'f': - case 'g': - { - const double number = va_arg(va, double); - UnityPrintFloat((UNITY_DOUBLE)number); - break; - } -#endif - case 'u': - { - const unsigned int number = va_arg(va, unsigned int); - UnityPrintNumberUnsigned((UNITY_UINT)number); - break; - } - case 'b': - { - const unsigned int number = va_arg(va, unsigned int); - const UNITY_UINT mask = (UNITY_UINT)0 - (UNITY_UINT)1; - UNITY_OUTPUT_CHAR('0'); - UNITY_OUTPUT_CHAR('b'); - UnityPrintMask(mask, (UNITY_UINT)number); - break; - } - case 'x': - case 'X': - case 'p': - { - const unsigned int number = va_arg(va, unsigned int); - UNITY_OUTPUT_CHAR('0'); - UNITY_OUTPUT_CHAR('x'); - UnityPrintNumberHex((UNITY_UINT)number, 8); - break; - } - case 'c': - { - const int ch = va_arg(va, int); - UnityPrintChar((const char *)&ch); - break; - } - case 's': - { - const char * string = va_arg(va, const char *); - UnityPrint(string); - break; - } - case '%': - { - UnityPrintChar(pch); - break; - } - default: - { - /* print the unknown format character */ - UNITY_OUTPUT_CHAR('%'); - UnityPrintChar(pch); - break; - } - } - } - } -#ifdef UNITY_OUTPUT_COLOR - /* print ANSI escape code */ - else if ((*pch == 27) && (*(pch + 1) == '[')) - { - pch += UnityPrintAnsiEscapeString(pch); - continue; - } -#endif - else if (*pch == '\n') - { - UNITY_PRINT_EOL(); - } - else - { - UnityPrintChar(pch); - } - - pch++; - } - } -} - -void UnityPrintF(const UNITY_LINE_TYPE line, const char* format, ...) -{ - UnityTestResultsBegin(Unity.TestFile, line); - UnityPrint("INFO"); - if(format != NULL) - { - UnityPrint(": "); - va_list va; - va_start(va, format); - UnityPrintFVA(format, va); - va_end(va); - } - UNITY_PRINT_EOL(); -} -#endif /* ! UNITY_INCLUDE_PRINT_FORMATTED */ - - -/*----------------------------------------------- - * Control Functions - *-----------------------------------------------*/ - -/*-----------------------------------------------*/ -void UnityFail(const char* msg, const UNITY_LINE_TYPE line) -{ - RETURN_IF_FAIL_OR_IGNORE; - - UnityTestResultsBegin(Unity.TestFile, line); - UnityPrint(UnityStrFail); - if (msg != NULL) - { - UNITY_OUTPUT_CHAR(':'); - -#ifdef UNITY_PRINT_TEST_CONTEXT - UNITY_PRINT_TEST_CONTEXT(); -#endif -#ifndef UNITY_EXCLUDE_DETAILS - if (Unity.CurrentDetail1) - { - UnityPrint(UnityStrDetail1Name); - UnityPrint(Unity.CurrentDetail1); - if (Unity.CurrentDetail2) - { - UnityPrint(UnityStrDetail2Name); - UnityPrint(Unity.CurrentDetail2); - } - UnityPrint(UnityStrSpacer); - } -#endif - if (msg[0] != ' ') - { - UNITY_OUTPUT_CHAR(' '); - } - UnityPrint(msg); - } - - UNITY_FAIL_AND_BAIL; -} - -/*-----------------------------------------------*/ -void UnityIgnore(const char* msg, const UNITY_LINE_TYPE line) -{ - RETURN_IF_FAIL_OR_IGNORE; - - UnityTestResultsBegin(Unity.TestFile, line); - UnityPrint(UnityStrIgnore); - if (msg != NULL) - { - UNITY_OUTPUT_CHAR(':'); - UNITY_OUTPUT_CHAR(' '); - UnityPrint(msg); - } - UNITY_IGNORE_AND_BAIL; -} - -/*-----------------------------------------------*/ -void UnityMessage(const char* msg, const UNITY_LINE_TYPE line) -{ - UnityTestResultsBegin(Unity.TestFile, line); - UnityPrint("INFO"); - if (msg != NULL) - { - UNITY_OUTPUT_CHAR(':'); - UNITY_OUTPUT_CHAR(' '); - UnityPrint(msg); - } - UNITY_PRINT_EOL(); -} - -/*-----------------------------------------------*/ -/* If we have not defined our own test runner, then include our default test runner to make life easier */ -#ifndef UNITY_SKIP_DEFAULT_RUNNER -void UnityDefaultTestRun(UnityTestFunction Func, const char* FuncName, const int FuncLineNum) -{ - Unity.CurrentTestName = FuncName; - Unity.CurrentTestLineNumber = (UNITY_LINE_TYPE)FuncLineNum; - Unity.NumberOfTests++; - UNITY_CLR_DETAILS(); - UNITY_EXEC_TIME_START(); - if (TEST_PROTECT()) - { - setUp(); - Func(); - } - if (TEST_PROTECT()) - { - tearDown(); - } - UNITY_EXEC_TIME_STOP(); - UnityConcludeTest(); -} -#endif - -/*-----------------------------------------------*/ -void UnitySetTestFile(const char* filename) -{ - Unity.TestFile = filename; -} - -/*-----------------------------------------------*/ -void UnityBegin(const char* filename) -{ - Unity.TestFile = filename; - Unity.CurrentTestName = NULL; - Unity.CurrentTestLineNumber = 0; - Unity.NumberOfTests = 0; - Unity.TestFailures = 0; - Unity.TestIgnores = 0; - Unity.CurrentTestFailed = 0; - Unity.CurrentTestIgnored = 0; - - UNITY_CLR_DETAILS(); - UNITY_OUTPUT_START(); -} - -/*-----------------------------------------------*/ -int UnityEnd(void) -{ - UNITY_PRINT_EOL(); - UnityPrint(UnityStrBreaker); - UNITY_PRINT_EOL(); - UnityPrintNumber((UNITY_INT)(Unity.NumberOfTests)); - UnityPrint(UnityStrResultsTests); - UnityPrintNumber((UNITY_INT)(Unity.TestFailures)); - UnityPrint(UnityStrResultsFailures); - UnityPrintNumber((UNITY_INT)(Unity.TestIgnores)); - UnityPrint(UnityStrResultsIgnored); - UNITY_PRINT_EOL(); - if (Unity.TestFailures == 0U) - { - UnityPrint(UnityStrOk); - } - else - { - UnityPrint(UnityStrFail); -#ifdef UNITY_DIFFERENTIATE_FINAL_FAIL - UNITY_OUTPUT_CHAR('E'); UNITY_OUTPUT_CHAR('D'); -#endif - } - UNITY_PRINT_EOL(); - UNITY_FLUSH_CALL(); - UNITY_OUTPUT_COMPLETE(); - return (int)(Unity.TestFailures); -} - -/*----------------------------------------------- - * Command Line Argument Support - *-----------------------------------------------*/ -#ifdef UNITY_USE_COMMAND_LINE_ARGS - -char* UnityOptionIncludeNamed = NULL; -char* UnityOptionExcludeNamed = NULL; -int UnityVerbosity = 1; - -/*-----------------------------------------------*/ -int UnityParseOptions(int argc, char** argv) -{ - int i; - UnityOptionIncludeNamed = NULL; - UnityOptionExcludeNamed = NULL; - - for (i = 1; i < argc; i++) - { - if (argv[i][0] == '-') - { - switch (argv[i][1]) - { - case 'l': /* list tests */ - return -1; - case 'n': /* include tests with name including this string */ - case 'f': /* an alias for -n */ - if (argv[i][2] == '=') - { - UnityOptionIncludeNamed = &argv[i][3]; - } - else if (++i < argc) - { - UnityOptionIncludeNamed = argv[i]; - } - else - { - UnityPrint("ERROR: No Test String to Include Matches For"); - UNITY_PRINT_EOL(); - return 1; - } - break; - case 'q': /* quiet */ - UnityVerbosity = 0; - break; - case 'v': /* verbose */ - UnityVerbosity = 2; - break; - case 'x': /* exclude tests with name including this string */ - if (argv[i][2] == '=') - { - UnityOptionExcludeNamed = &argv[i][3]; - } - else if (++i < argc) - { - UnityOptionExcludeNamed = argv[i]; - } - else - { - UnityPrint("ERROR: No Test String to Exclude Matches For"); - UNITY_PRINT_EOL(); - return 1; - } - break; - default: - UnityPrint("ERROR: Unknown Option "); - UNITY_OUTPUT_CHAR(argv[i][1]); - UNITY_PRINT_EOL(); - return 1; - } - } - } - - return 0; -} - -/*-----------------------------------------------*/ -int IsStringInBiggerString(const char* longstring, const char* shortstring) -{ - const char* lptr = longstring; - const char* sptr = shortstring; - const char* lnext = lptr; - - if (*sptr == '*') - { - return 1; - } - - while (*lptr) - { - lnext = lptr + 1; - - /* If they current bytes match, go on to the next bytes */ - while (*lptr && *sptr && (*lptr == *sptr)) - { - lptr++; - sptr++; - - /* We're done if we match the entire string or up to a wildcard */ - if (*sptr == '*') - return 1; - if (*sptr == ',') - return 1; - if (*sptr == '"') - return 1; - if (*sptr == '\'') - return 1; - if (*sptr == ':') - return 2; - if (*sptr == 0) - return 1; - } - - /* Otherwise we start in the long pointer 1 character further and try again */ - lptr = lnext; - sptr = shortstring; - } - - return 0; -} - -/*-----------------------------------------------*/ -int UnityStringArgumentMatches(const char* str) -{ - int retval; - const char* ptr1; - const char* ptr2; - const char* ptrf; - - /* Go through the options and get the substrings for matching one at a time */ - ptr1 = str; - while (ptr1[0] != 0) - { - if ((ptr1[0] == '"') || (ptr1[0] == '\'')) - { - ptr1++; - } - - /* look for the start of the next partial */ - ptr2 = ptr1; - ptrf = 0; - do - { - ptr2++; - if ((ptr2[0] == ':') && (ptr2[1] != 0) && (ptr2[0] != '\'') && (ptr2[0] != '"') && (ptr2[0] != ',')) - { - ptrf = &ptr2[1]; - } - } while ((ptr2[0] != 0) && (ptr2[0] != '\'') && (ptr2[0] != '"') && (ptr2[0] != ',')); - - while ((ptr2[0] != 0) && ((ptr2[0] == ':') || (ptr2[0] == '\'') || (ptr2[0] == '"') || (ptr2[0] == ','))) - { - ptr2++; - } - - /* done if complete filename match */ - retval = IsStringInBiggerString(Unity.TestFile, ptr1); - if (retval == 1) - { - return retval; - } - - /* done if testname match after filename partial match */ - if ((retval == 2) && (ptrf != 0)) - { - if (IsStringInBiggerString(Unity.CurrentTestName, ptrf)) - { - return 1; - } - } - - /* done if complete testname match */ - if (IsStringInBiggerString(Unity.CurrentTestName, ptr1) == 1) - { - return 1; - } - - ptr1 = ptr2; - } - - /* we couldn't find a match for any substrings */ - return 0; -} - -/*-----------------------------------------------*/ -int UnityTestMatches(void) -{ - /* Check if this test name matches the included test pattern */ - int retval; - if (UnityOptionIncludeNamed) - { - retval = UnityStringArgumentMatches(UnityOptionIncludeNamed); - } - else - { - retval = 1; - } - - /* Check if this test name matches the excluded test pattern */ - if (UnityOptionExcludeNamed) - { - if (UnityStringArgumentMatches(UnityOptionExcludeNamed)) - { - retval = 0; - } - } - - return retval; -} - -#endif /* UNITY_USE_COMMAND_LINE_ARGS */ -/*-----------------------------------------------*/ diff --git a/vendor/ceedling/vendor/unity/src/unity.h b/vendor/ceedling/vendor/unity/src/unity.h deleted file mode 100644 index 338df0b..0000000 --- a/vendor/ceedling/vendor/unity/src/unity.h +++ /dev/null @@ -1,661 +0,0 @@ -/* ========================================== - Unity Project - A Test Framework for C - Copyright (c) 2007-21 Mike Karlesky, Mark VanderVoord, Greg Williams - [Released under MIT License. Please refer to license.txt for details] -========================================== */ - -#ifndef UNITY_FRAMEWORK_H -#define UNITY_FRAMEWORK_H -#define UNITY - -#define UNITY_VERSION_MAJOR 2 -#define UNITY_VERSION_MINOR 5 -#define UNITY_VERSION_BUILD 4 -#define UNITY_VERSION ((UNITY_VERSION_MAJOR << 16) | (UNITY_VERSION_MINOR << 8) | UNITY_VERSION_BUILD) - -#ifdef __cplusplus -extern "C" -{ -#endif - -#include "unity_internals.h" - -/*------------------------------------------------------- - * Test Setup / Teardown - *-------------------------------------------------------*/ - -/* These functions are intended to be called before and after each test. - * If using unity directly, these will need to be provided for each test - * executable built. If you are using the test runner generator and/or - * Ceedling, these are optional. */ -void setUp(void); -void tearDown(void); - -/* These functions are intended to be called at the beginning and end of an - * entire test suite. suiteTearDown() is passed the number of tests that - * failed, and its return value becomes the exit code of main(). If using - * Unity directly, you're in charge of calling these if they are desired. - * If using Ceedling or the test runner generator, these will be called - * automatically if they exist. */ -void suiteSetUp(void); -int suiteTearDown(int num_failures); - -/*------------------------------------------------------- - * Test Reset and Verify - *-------------------------------------------------------*/ - -/* These functions are intended to be called before during tests in order - * to support complex test loops, etc. Both are NOT built into Unity. Instead - * the test runner generator will create them. resetTest will run teardown and - * setup again, verifying any end-of-test needs between. verifyTest will only - * run the verification. */ -void resetTest(void); -void verifyTest(void); - -/*------------------------------------------------------- - * Configuration Options - *------------------------------------------------------- - * All options described below should be passed as a compiler flag to all files using Unity. If you must add #defines, place them BEFORE the #include above. - - * Integers/longs/pointers - * - Unity attempts to automatically discover your integer sizes - * - define UNITY_EXCLUDE_STDINT_H to stop attempting to look in <stdint.h> - * - define UNITY_EXCLUDE_LIMITS_H to stop attempting to look in <limits.h> - * - If you cannot use the automatic methods above, you can force Unity by using these options: - * - define UNITY_SUPPORT_64 - * - set UNITY_INT_WIDTH - * - set UNITY_LONG_WIDTH - * - set UNITY_POINTER_WIDTH - - * Floats - * - define UNITY_EXCLUDE_FLOAT to disallow floating point comparisons - * - define UNITY_FLOAT_PRECISION to specify the precision to use when doing TEST_ASSERT_EQUAL_FLOAT - * - define UNITY_FLOAT_TYPE to specify doubles instead of single precision floats - * - define UNITY_INCLUDE_DOUBLE to allow double floating point comparisons - * - define UNITY_EXCLUDE_DOUBLE to disallow double floating point comparisons (default) - * - define UNITY_DOUBLE_PRECISION to specify the precision to use when doing TEST_ASSERT_EQUAL_DOUBLE - * - define UNITY_DOUBLE_TYPE to specify something other than double - * - define UNITY_EXCLUDE_FLOAT_PRINT to trim binary size, won't print floating point values in errors - - * Output - * - by default, Unity prints to standard out with putchar. define UNITY_OUTPUT_CHAR(a) with a different function if desired - * - define UNITY_DIFFERENTIATE_FINAL_FAIL to print FAILED (vs. FAIL) at test end summary - for automated search for failure - - * Optimization - * - by default, line numbers are stored in unsigned shorts. Define UNITY_LINE_TYPE with a different type if your files are huge - * - by default, test and failure counters are unsigned shorts. Define UNITY_COUNTER_TYPE with a different type if you want to save space or have more than 65535 Tests. - - * Test Cases - * - define UNITY_SUPPORT_TEST_CASES to include the TEST_CASE macro, though really it's mostly about the runner generator script - - * Parameterized Tests - * - you'll want to create a define of TEST_CASE(...) which basically evaluates to nothing - - * Tests with Arguments - * - you'll want to define UNITY_USE_COMMAND_LINE_ARGS if you have the test runner passing arguments to Unity - - *------------------------------------------------------- - * Basic Fail and Ignore - *-------------------------------------------------------*/ - -#define TEST_FAIL_MESSAGE(message) UNITY_TEST_FAIL(__LINE__, (message)) -#define TEST_FAIL() UNITY_TEST_FAIL(__LINE__, NULL) -#define TEST_IGNORE_MESSAGE(message) UNITY_TEST_IGNORE(__LINE__, (message)) -#define TEST_IGNORE() UNITY_TEST_IGNORE(__LINE__, NULL) -#define TEST_MESSAGE(message) UnityMessage((message), __LINE__) -#define TEST_ONLY() -#ifdef UNITY_INCLUDE_PRINT_FORMATTED -#define TEST_PRINTF(message, ...) UnityPrintF(__LINE__, (message), __VA_ARGS__) -#endif - -/* It is not necessary for you to call PASS. A PASS condition is assumed if nothing fails. - * This method allows you to abort a test immediately with a PASS state, ignoring the remainder of the test. */ -#define TEST_PASS() TEST_ABORT() -#define TEST_PASS_MESSAGE(message) do { UnityMessage((message), __LINE__); TEST_ABORT(); } while(0) - -/* 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) - *-------------------------------------------------------*/ - -/* Boolean */ -#define TEST_ASSERT(condition) UNITY_TEST_ASSERT( (condition), __LINE__, " Expression Evaluated To FALSE") -#define TEST_ASSERT_TRUE(condition) UNITY_TEST_ASSERT( (condition), __LINE__, " Expected TRUE Was FALSE") -#define TEST_ASSERT_UNLESS(condition) UNITY_TEST_ASSERT( !(condition), __LINE__, " Expression Evaluated To TRUE") -#define TEST_ASSERT_FALSE(condition) UNITY_TEST_ASSERT( !(condition), __LINE__, " Expected FALSE Was TRUE") -#define TEST_ASSERT_NULL(pointer) UNITY_TEST_ASSERT_NULL( (pointer), __LINE__, " Expected NULL") -#define TEST_ASSERT_NOT_NULL(pointer) UNITY_TEST_ASSERT_NOT_NULL((pointer), __LINE__, " Expected Non-NULL") -#define TEST_ASSERT_EMPTY(pointer) UNITY_TEST_ASSERT_EMPTY( (pointer), __LINE__, " Expected Empty") -#define TEST_ASSERT_NOT_EMPTY(pointer) UNITY_TEST_ASSERT_NOT_EMPTY((pointer), __LINE__, " Expected Non-Empty") - -/* Integers (of all sizes) */ -#define TEST_ASSERT_EQUAL_INT(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_INT8(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT8((expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_INT16(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT16((expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_INT32(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT32((expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_INT64(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT64((expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_UINT(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT( (expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_UINT8(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT8( (expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_UINT16(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT16( (expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_UINT32(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT32( (expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_UINT64(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT64( (expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_size_t(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT((expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_HEX(expected, actual) UNITY_TEST_ASSERT_EQUAL_HEX32((expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_HEX8(expected, actual) UNITY_TEST_ASSERT_EQUAL_HEX8( (expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_HEX16(expected, actual) UNITY_TEST_ASSERT_EQUAL_HEX16((expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_HEX32(expected, actual) UNITY_TEST_ASSERT_EQUAL_HEX32((expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_HEX64(expected, actual) UNITY_TEST_ASSERT_EQUAL_HEX64((expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_CHAR(expected, actual) UNITY_TEST_ASSERT_EQUAL_CHAR((expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_BITS(mask, expected, actual) UNITY_TEST_ASSERT_BITS((mask), (expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_BITS_HIGH(mask, actual) UNITY_TEST_ASSERT_BITS((mask), (UNITY_UINT)(-1), (actual), __LINE__, NULL) -#define TEST_ASSERT_BITS_LOW(mask, actual) UNITY_TEST_ASSERT_BITS((mask), (UNITY_UINT)(0), (actual), __LINE__, NULL) -#define TEST_ASSERT_BIT_HIGH(bit, actual) UNITY_TEST_ASSERT_BITS(((UNITY_UINT)1 << (bit)), (UNITY_UINT)(-1), (actual), __LINE__, NULL) -#define TEST_ASSERT_BIT_LOW(bit, actual) UNITY_TEST_ASSERT_BITS(((UNITY_UINT)1 << (bit)), (UNITY_UINT)(0), (actual), __LINE__, NULL) - -/* Integer Not Equal To (of all sizes) */ -#define TEST_ASSERT_NOT_EQUAL_INT(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_INT((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_NOT_EQUAL_INT8(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_INT8((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_NOT_EQUAL_INT16(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_INT16((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_NOT_EQUAL_INT32(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_INT32((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_NOT_EQUAL_INT64(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_INT64((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_NOT_EQUAL_UINT(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_UINT((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_NOT_EQUAL_UINT8(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_UINT8((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_NOT_EQUAL_UINT16(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_UINT16((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_NOT_EQUAL_UINT32(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_UINT32((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_NOT_EQUAL_UINT64(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_UINT64((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_NOT_EQUAL_size_t(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_UINT((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_NOT_EQUAL_HEX8(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_HEX8((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_NOT_EQUAL_HEX16(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_HEX16((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_NOT_EQUAL_HEX32(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_HEX32((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_NOT_EQUAL_HEX64(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_HEX64((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_NOT_EQUAL_CHAR(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_CHAR((threshold), (actual), __LINE__, NULL) - -/* Integer Greater Than/ Less Than (of all sizes) */ -#define TEST_ASSERT_GREATER_THAN(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_GREATER_THAN_INT(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_GREATER_THAN_INT8(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT8((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_GREATER_THAN_INT16(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT16((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_GREATER_THAN_INT32(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT32((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_GREATER_THAN_INT64(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT64((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_GREATER_THAN_UINT(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_GREATER_THAN_UINT8(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT8((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_GREATER_THAN_UINT16(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT16((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_GREATER_THAN_UINT32(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT32((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_GREATER_THAN_UINT64(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT64((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_GREATER_THAN_size_t(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_GREATER_THAN_HEX8(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_HEX8((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_GREATER_THAN_HEX16(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_HEX16((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_GREATER_THAN_HEX32(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_HEX32((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_GREATER_THAN_HEX64(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_HEX64((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_GREATER_THAN_CHAR(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_CHAR((threshold), (actual), __LINE__, NULL) - -#define TEST_ASSERT_LESS_THAN(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_LESS_THAN_INT(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_LESS_THAN_INT8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT8((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_LESS_THAN_INT16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT16((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_LESS_THAN_INT32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT32((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_LESS_THAN_INT64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT64((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_LESS_THAN_UINT(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_LESS_THAN_UINT8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT8((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_LESS_THAN_UINT16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT16((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_LESS_THAN_UINT32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT32((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_LESS_THAN_UINT64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT64((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_LESS_THAN_size_t(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_LESS_THAN_HEX8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_HEX8((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_LESS_THAN_HEX16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_HEX16((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_LESS_THAN_HEX32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_HEX32((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_LESS_THAN_HEX64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_HEX64((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_LESS_THAN_CHAR(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_CHAR((threshold), (actual), __LINE__, NULL) - -#define TEST_ASSERT_GREATER_OR_EQUAL(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_GREATER_OR_EQUAL_INT(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_GREATER_OR_EQUAL_INT8(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT8((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_GREATER_OR_EQUAL_INT16(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT16((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_GREATER_OR_EQUAL_INT32(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT32((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_GREATER_OR_EQUAL_INT64(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT64((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_GREATER_OR_EQUAL_UINT(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_GREATER_OR_EQUAL_UINT8(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT8((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_GREATER_OR_EQUAL_UINT16(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT16((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_GREATER_OR_EQUAL_UINT32(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT32((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_GREATER_OR_EQUAL_UINT64(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT64((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_GREATER_OR_EQUAL_size_t(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_GREATER_OR_EQUAL_HEX8(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX8((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_GREATER_OR_EQUAL_HEX16(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX16((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_GREATER_OR_EQUAL_HEX32(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX32((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_GREATER_OR_EQUAL_HEX64(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX64((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_GREATER_OR_EQUAL_CHAR(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_CHAR((threshold), (actual), __LINE__, NULL) - -#define TEST_ASSERT_LESS_OR_EQUAL(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_LESS_OR_EQUAL_INT(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_LESS_OR_EQUAL_INT8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT8((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_LESS_OR_EQUAL_INT16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT16((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_LESS_OR_EQUAL_INT32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT32((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_LESS_OR_EQUAL_INT64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT64((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_LESS_OR_EQUAL_UINT(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_LESS_OR_EQUAL_UINT8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT8((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_LESS_OR_EQUAL_UINT16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT16((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_LESS_OR_EQUAL_UINT32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT32((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_LESS_OR_EQUAL_UINT64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT64((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_LESS_OR_EQUAL_size_t(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_LESS_OR_EQUAL_HEX8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX8((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_LESS_OR_EQUAL_HEX16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX16((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_LESS_OR_EQUAL_HEX32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX32((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_LESS_OR_EQUAL_HEX64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX64((threshold), (actual), __LINE__, NULL) -#define TEST_ASSERT_LESS_OR_EQUAL_CHAR(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_CHAR((threshold), (actual), __LINE__, NULL) - -/* Integer Ranges (of all sizes) */ -#define TEST_ASSERT_INT_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_INT_WITHIN((delta), (expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_INT8_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_INT8_WITHIN((delta), (expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_INT16_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_INT16_WITHIN((delta), (expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_INT32_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_INT32_WITHIN((delta), (expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_INT64_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_INT64_WITHIN((delta), (expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_UINT_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT_WITHIN((delta), (expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_UINT8_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT8_WITHIN((delta), (expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_UINT16_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT16_WITHIN((delta), (expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_UINT32_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT32_WITHIN((delta), (expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_UINT64_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT64_WITHIN((delta), (expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_size_t_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT_WITHIN((delta), (expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_HEX_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX32_WITHIN((delta), (expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_HEX8_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX8_WITHIN((delta), (expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_HEX16_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX16_WITHIN((delta), (expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_HEX32_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX32_WITHIN((delta), (expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_HEX64_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX64_WITHIN((delta), (expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_CHAR_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_CHAR_WITHIN((delta), (expected), (actual), __LINE__, NULL) - -/* Integer Array Ranges (of all sizes) */ -#define TEST_ASSERT_INT_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_INT_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) -#define TEST_ASSERT_INT8_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_INT8_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) -#define TEST_ASSERT_INT16_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_INT16_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) -#define TEST_ASSERT_INT32_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_INT32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) -#define TEST_ASSERT_INT64_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_INT64_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) -#define TEST_ASSERT_UINT_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_UINT_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) -#define TEST_ASSERT_UINT8_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_UINT8_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) -#define TEST_ASSERT_UINT16_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_UINT16_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) -#define TEST_ASSERT_UINT32_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_UINT32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) -#define TEST_ASSERT_UINT64_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_UINT64_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) -#define TEST_ASSERT_size_t_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_UINT_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) -#define TEST_ASSERT_HEX_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_HEX32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) -#define TEST_ASSERT_HEX8_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_HEX8_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) -#define TEST_ASSERT_HEX16_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_HEX16_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) -#define TEST_ASSERT_HEX32_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_HEX32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) -#define TEST_ASSERT_HEX64_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_HEX64_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) -#define TEST_ASSERT_CHAR_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_CHAR_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) - - -/* Structs and Strings */ -#define TEST_ASSERT_EQUAL_PTR(expected, actual) UNITY_TEST_ASSERT_EQUAL_PTR((expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_STRING(expected, actual) UNITY_TEST_ASSERT_EQUAL_STRING((expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_STRING_LEN(expected, actual, len) UNITY_TEST_ASSERT_EQUAL_STRING_LEN((expected), (actual), (len), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_MEMORY(expected, actual, len) UNITY_TEST_ASSERT_EQUAL_MEMORY((expected), (actual), (len), __LINE__, NULL) - -/* Arrays */ -#define TEST_ASSERT_EQUAL_INT_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_INT_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_INT8_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_INT8_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_INT16_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_INT16_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_INT32_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_INT32_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_INT64_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_INT64_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_UINT_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT8_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_UINT16_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT16_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_UINT32_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT32_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_UINT64_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT64_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_size_t_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_HEX_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_HEX8_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX8_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_HEX16_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX16_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_HEX32_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_HEX64_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX64_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) -#define TEST_ASSERT_EQUAL_PTR_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_PTR_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) -#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) -#define TEST_ASSERT_EQUAL_CHAR_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_CHAR_ARRAY((expected), (actual), (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_size_t(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_UINT((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) -#define TEST_ASSERT_EACH_EQUAL_CHAR(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_CHAR((expected), (actual), (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) -#define TEST_ASSERT_FLOAT_IS_DETERMINATE(actual) UNITY_TEST_ASSERT_FLOAT_IS_DETERMINATE((actual), __LINE__, NULL) -#define TEST_ASSERT_FLOAT_IS_NOT_INF(actual) UNITY_TEST_ASSERT_FLOAT_IS_NOT_INF((actual), __LINE__, NULL) -#define TEST_ASSERT_FLOAT_IS_NOT_NEG_INF(actual) UNITY_TEST_ASSERT_FLOAT_IS_NOT_NEG_INF((actual), __LINE__, NULL) -#define TEST_ASSERT_FLOAT_IS_NOT_NAN(actual) UNITY_TEST_ASSERT_FLOAT_IS_NOT_NAN((actual), __LINE__, NULL) -#define TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE(actual) UNITY_TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE((actual), __LINE__, NULL) - -/* Double (If Enabled) */ -#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) -#define TEST_ASSERT_DOUBLE_IS_DETERMINATE(actual) UNITY_TEST_ASSERT_DOUBLE_IS_DETERMINATE((actual), __LINE__, NULL) -#define TEST_ASSERT_DOUBLE_IS_NOT_INF(actual) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_INF((actual), __LINE__, NULL) -#define TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF(actual) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF((actual), __LINE__, NULL) -#define TEST_ASSERT_DOUBLE_IS_NOT_NAN(actual) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NAN((actual), __LINE__, NULL) -#define TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE(actual) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE((actual), __LINE__, NULL) - -/* Shorthand */ -#ifdef UNITY_SHORTHAND_AS_OLD -#define TEST_ASSERT_EQUAL(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_NOT_EQUAL(expected, actual) UNITY_TEST_ASSERT(((expected) != (actual)), __LINE__, " Expected Not-Equal") -#endif -#ifdef UNITY_SHORTHAND_AS_INT -#define TEST_ASSERT_EQUAL(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, NULL) -#define TEST_ASSERT_NOT_EQUAL(expected, actual) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand) -#endif -#ifdef UNITY_SHORTHAND_AS_MEM -#define TEST_ASSERT_EQUAL(expected, actual) UNITY_TEST_ASSERT_EQUAL_MEMORY((&expected), (&actual), sizeof(expected), __LINE__, NULL) -#define TEST_ASSERT_NOT_EQUAL(expected, actual) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand) -#endif -#ifdef UNITY_SHORTHAND_AS_RAW -#define TEST_ASSERT_EQUAL(expected, actual) UNITY_TEST_ASSERT(((expected) == (actual)), __LINE__, " Expected Equal") -#define TEST_ASSERT_NOT_EQUAL(expected, actual) UNITY_TEST_ASSERT(((expected) != (actual)), __LINE__, " Expected Not-Equal") -#endif -#ifdef UNITY_SHORTHAND_AS_NONE -#define TEST_ASSERT_EQUAL(expected, actual) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand) -#define TEST_ASSERT_NOT_EQUAL(expected, actual) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand) -#endif - -/*------------------------------------------------------- - * Test Asserts (with additional messages) - *-------------------------------------------------------*/ - -/* Boolean */ -#define TEST_ASSERT_MESSAGE(condition, message) UNITY_TEST_ASSERT( (condition), __LINE__, (message)) -#define TEST_ASSERT_TRUE_MESSAGE(condition, message) UNITY_TEST_ASSERT( (condition), __LINE__, (message)) -#define TEST_ASSERT_UNLESS_MESSAGE(condition, message) UNITY_TEST_ASSERT( !(condition), __LINE__, (message)) -#define TEST_ASSERT_FALSE_MESSAGE(condition, message) UNITY_TEST_ASSERT( !(condition), __LINE__, (message)) -#define TEST_ASSERT_NULL_MESSAGE(pointer, message) UNITY_TEST_ASSERT_NULL( (pointer), __LINE__, (message)) -#define TEST_ASSERT_NOT_NULL_MESSAGE(pointer, message) UNITY_TEST_ASSERT_NOT_NULL((pointer), __LINE__, (message)) -#define TEST_ASSERT_EMPTY_MESSAGE(pointer, message) UNITY_TEST_ASSERT_EMPTY( (pointer), __LINE__, (message)) -#define TEST_ASSERT_NOT_EMPTY_MESSAGE(pointer, message) UNITY_TEST_ASSERT_NOT_EMPTY((pointer), __LINE__, (message)) - -/* Integers (of all sizes) */ -#define TEST_ASSERT_EQUAL_INT_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_INT8_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT8((expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_INT16_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT16((expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_INT32_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT32((expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_INT64_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT64((expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_UINT_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT( (expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT8( (expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_UINT16_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT16( (expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_UINT32_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT32( (expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_UINT64_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT64( (expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_size_t_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT( (expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_HEX_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX32((expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_HEX8_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX8( (expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_HEX16_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX16((expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_HEX32_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX32((expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_HEX64_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX64((expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_BITS_MESSAGE(mask, expected, actual, message) UNITY_TEST_ASSERT_BITS((mask), (expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_BITS_HIGH_MESSAGE(mask, actual, message) UNITY_TEST_ASSERT_BITS((mask), (UNITY_UINT32)(-1), (actual), __LINE__, (message)) -#define TEST_ASSERT_BITS_LOW_MESSAGE(mask, actual, message) UNITY_TEST_ASSERT_BITS((mask), (UNITY_UINT32)(0), (actual), __LINE__, (message)) -#define TEST_ASSERT_BIT_HIGH_MESSAGE(bit, actual, message) UNITY_TEST_ASSERT_BITS(((UNITY_UINT32)1 << (bit)), (UNITY_UINT32)(-1), (actual), __LINE__, (message)) -#define TEST_ASSERT_BIT_LOW_MESSAGE(bit, actual, message) UNITY_TEST_ASSERT_BITS(((UNITY_UINT32)1 << (bit)), (UNITY_UINT32)(0), (actual), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_CHAR_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_CHAR((expected), (actual), __LINE__, (message)) - -/* Integer Not Equal To (of all sizes) */ -#define TEST_ASSERT_NOT_EQUAL_INT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_INT((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_NOT_EQUAL_INT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_INT8((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_NOT_EQUAL_INT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_INT16((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_NOT_EQUAL_INT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_INT32((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_NOT_EQUAL_INT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_INT64((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_NOT_EQUAL_UINT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_UINT((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_NOT_EQUAL_UINT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_UINT8((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_NOT_EQUAL_UINT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_UINT16((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_NOT_EQUAL_UINT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_UINT32((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_NOT_EQUAL_UINT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_UINT64((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_NOT_EQUAL_size_t_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_UINT((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_NOT_EQUAL_HEX8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_HEX8((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_NOT_EQUAL_HEX16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_HEX16((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_NOT_EQUAL_HEX32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_HEX32((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_NOT_EQUAL_HEX64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_HEX64((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_NOT_EQUAL_CHAR_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_CHAR((threshold), (actual), __LINE__, (message)) - - -/* Integer Greater Than/ Less Than (of all sizes) */ -#define TEST_ASSERT_GREATER_THAN_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_GREATER_THAN_INT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_GREATER_THAN_INT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT8((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_GREATER_THAN_INT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT16((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_GREATER_THAN_INT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT32((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_GREATER_THAN_INT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT64((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_GREATER_THAN_UINT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_GREATER_THAN_UINT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT8((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_GREATER_THAN_UINT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT16((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_GREATER_THAN_UINT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT32((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_GREATER_THAN_UINT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT64((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_GREATER_THAN_size_t_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_GREATER_THAN_HEX8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_HEX8((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_GREATER_THAN_HEX16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_HEX16((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_GREATER_THAN_HEX32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_HEX32((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_GREATER_THAN_HEX64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_HEX64((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_GREATER_THAN_CHAR_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_CHAR((threshold), (actual), __LINE__, (message)) - -#define TEST_ASSERT_LESS_THAN_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_LESS_THAN_INT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_LESS_THAN_INT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT8((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_LESS_THAN_INT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT16((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_LESS_THAN_INT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT32((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_LESS_THAN_INT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT64((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_LESS_THAN_UINT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_LESS_THAN_UINT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT8((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_LESS_THAN_UINT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT16((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_LESS_THAN_UINT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT32((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_LESS_THAN_UINT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT64((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_LESS_THAN_size_t_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_LESS_THAN_HEX8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_HEX8((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_LESS_THAN_HEX16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_HEX16((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_LESS_THAN_HEX32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_HEX32((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_LESS_THAN_HEX64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_HEX64((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_LESS_THAN_CHAR_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_CHAR((threshold), (actual), __LINE__, (message)) - -#define TEST_ASSERT_GREATER_OR_EQUAL_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_GREATER_OR_EQUAL_INT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_GREATER_OR_EQUAL_INT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT8((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_GREATER_OR_EQUAL_INT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT16((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_GREATER_OR_EQUAL_INT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT32((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_GREATER_OR_EQUAL_INT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT64((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_GREATER_OR_EQUAL_UINT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_GREATER_OR_EQUAL_UINT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT8((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_GREATER_OR_EQUAL_UINT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT16((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_GREATER_OR_EQUAL_UINT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT32((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_GREATER_OR_EQUAL_UINT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT64((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_GREATER_OR_EQUAL_size_t_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_GREATER_OR_EQUAL_HEX8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX8((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_GREATER_OR_EQUAL_HEX16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX16((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_GREATER_OR_EQUAL_HEX32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX32((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_GREATER_OR_EQUAL_HEX64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX64((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_GREATER_OR_EQUAL_CHAR_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_CHAR((threshold), (actual), __LINE__, (message)) - -#define TEST_ASSERT_LESS_OR_EQUAL_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_LESS_OR_EQUAL_INT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_LESS_OR_EQUAL_INT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT8((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_LESS_OR_EQUAL_INT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT16((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_LESS_OR_EQUAL_INT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT32((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_LESS_OR_EQUAL_INT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT64((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_LESS_OR_EQUAL_UINT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_LESS_OR_EQUAL_UINT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT8((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_LESS_OR_EQUAL_UINT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT16((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_LESS_OR_EQUAL_UINT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT32((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_LESS_OR_EQUAL_UINT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT64((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_LESS_OR_EQUAL_size_t_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_LESS_OR_EQUAL_HEX8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX8((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_LESS_OR_EQUAL_HEX16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX16((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_LESS_OR_EQUAL_HEX32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX32((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_LESS_OR_EQUAL_HEX64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX64((threshold), (actual), __LINE__, (message)) -#define TEST_ASSERT_LESS_OR_EQUAL_CHAR_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_CHAR((threshold), (actual), __LINE__, (message)) - -/* Integer Ranges (of all sizes) */ -#define TEST_ASSERT_INT_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_INT_WITHIN((delta), (expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_INT8_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_INT8_WITHIN((delta), (expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_INT16_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_INT16_WITHIN((delta), (expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_INT32_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_INT32_WITHIN((delta), (expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_INT64_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_INT64_WITHIN((delta), (expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_UINT_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT_WITHIN((delta), (expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_UINT8_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT8_WITHIN((delta), (expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_UINT16_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT16_WITHIN((delta), (expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_UINT32_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT32_WITHIN((delta), (expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_UINT64_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT64_WITHIN((delta), (expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_size_t_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT_WITHIN((delta), (expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_HEX_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX32_WITHIN((delta), (expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_HEX8_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX8_WITHIN((delta), (expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_HEX16_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX16_WITHIN((delta), (expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_HEX32_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX32_WITHIN((delta), (expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_HEX64_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX64_WITHIN((delta), (expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_CHAR_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_CHAR_WITHIN((delta), (expected), (actual), __LINE__, (message)) - -/* Integer Array Ranges (of all sizes) */ -#define TEST_ASSERT_INT_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_INT_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) -#define TEST_ASSERT_INT8_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_INT8_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) -#define TEST_ASSERT_INT16_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_INT16_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) -#define TEST_ASSERT_INT32_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_INT32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) -#define TEST_ASSERT_INT64_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_INT64_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) -#define TEST_ASSERT_UINT_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_UINT_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) -#define TEST_ASSERT_UINT8_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_UINT8_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) -#define TEST_ASSERT_UINT16_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_UINT16_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) -#define TEST_ASSERT_UINT32_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_UINT32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) -#define TEST_ASSERT_UINT64_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_UINT64_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) -#define TEST_ASSERT_size_t_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_UINT_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) -#define TEST_ASSERT_HEX_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_HEX32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) -#define TEST_ASSERT_HEX8_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_HEX8_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) -#define TEST_ASSERT_HEX16_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_HEX16_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) -#define TEST_ASSERT_HEX32_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_HEX32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) -#define TEST_ASSERT_HEX64_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_HEX64_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) -#define TEST_ASSERT_CHAR_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_CHAR_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) - - -/* Structs and Strings */ -#define TEST_ASSERT_EQUAL_PTR_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_PTR((expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_STRING((expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_STRING_LEN_MESSAGE(expected, actual, len, message) UNITY_TEST_ASSERT_EQUAL_STRING_LEN((expected), (actual), (len), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_MEMORY_MESSAGE(expected, actual, len, message) UNITY_TEST_ASSERT_EQUAL_MEMORY((expected), (actual), (len), __LINE__, (message)) - -/* Arrays */ -#define TEST_ASSERT_EQUAL_INT_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_INT_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_INT8_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_INT8_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_INT16_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_INT16_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_INT32_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_INT32_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_INT64_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_INT64_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_UINT_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_UINT8_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT8_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_UINT16_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT16_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_UINT32_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT32_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_UINT64_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT64_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_size_t_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_HEX_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_HEX8_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX8_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_HEX16_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX16_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_HEX32_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_HEX64_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX64_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) -#define TEST_ASSERT_EQUAL_PTR_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_PTR_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) -#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)) -#define TEST_ASSERT_EQUAL_CHAR_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_CHAR_ARRAY((expected), (actual), (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_size_t_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_UINT((expected), (actual), (num_elements), __LINE__, (message)) -#define TEST_ASSERT_EACH_EQUAL_HEX_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_HEX32((expected), (actual), (num_elements), __LINE__, (message)) -#define TEST_ASSERT_EACH_EQUAL_HEX8_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_HEX8((expected), (actual), (num_elements), __LINE__, (message)) -#define TEST_ASSERT_EACH_EQUAL_HEX16_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_HEX16((expected), (actual), (num_elements), __LINE__, (message)) -#define TEST_ASSERT_EACH_EQUAL_HEX32_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_HEX32((expected), (actual), (num_elements), __LINE__, (message)) -#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)) -#define TEST_ASSERT_EACH_EQUAL_CHAR_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_CHAR((expected), (actual), (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)) -#define TEST_ASSERT_FLOAT_IS_DETERMINATE_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_DETERMINATE((actual), __LINE__, (message)) -#define TEST_ASSERT_FLOAT_IS_NOT_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_NOT_INF((actual), __LINE__, (message)) -#define TEST_ASSERT_FLOAT_IS_NOT_NEG_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_NOT_NEG_INF((actual), __LINE__, (message)) -#define TEST_ASSERT_FLOAT_IS_NOT_NAN_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_NOT_NAN((actual), __LINE__, (message)) -#define TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE((actual), __LINE__, (message)) - -/* Double (If Enabled) */ -#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)) -#define TEST_ASSERT_DOUBLE_IS_DETERMINATE_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_DETERMINATE((actual), __LINE__, (message)) -#define TEST_ASSERT_DOUBLE_IS_NOT_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_INF((actual), __LINE__, (message)) -#define TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF((actual), __LINE__, (message)) -#define TEST_ASSERT_DOUBLE_IS_NOT_NAN_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NAN((actual), __LINE__, (message)) -#define TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE((actual), __LINE__, (message)) - -/* Shorthand */ -#ifdef UNITY_SHORTHAND_AS_OLD -#define TEST_ASSERT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, (message)) -#define TEST_ASSERT_NOT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT(((expected) != (actual)), __LINE__, (message)) -#endif -#ifdef UNITY_SHORTHAND_AS_INT -#define TEST_ASSERT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, message) -#define TEST_ASSERT_NOT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand) -#endif -#ifdef UNITY_SHORTHAND_AS_MEM -#define TEST_ASSERT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_MEMORY((&expected), (&actual), sizeof(expected), __LINE__, message) -#define TEST_ASSERT_NOT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand) -#endif -#ifdef UNITY_SHORTHAND_AS_RAW -#define TEST_ASSERT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT(((expected) == (actual)), __LINE__, message) -#define TEST_ASSERT_NOT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT(((expected) != (actual)), __LINE__, message) -#endif -#ifdef UNITY_SHORTHAND_AS_NONE -#define TEST_ASSERT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand) -#define TEST_ASSERT_NOT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand) -#endif - -/* end of UNITY_FRAMEWORK_H */ -#ifdef __cplusplus -} -#endif -#endif diff --git a/vendor/ceedling/vendor/unity/src/unity_internals.h b/vendor/ceedling/vendor/unity/src/unity_internals.h deleted file mode 100644 index 2c91b6d..0000000 --- a/vendor/ceedling/vendor/unity/src/unity_internals.h +++ /dev/null @@ -1,1053 +0,0 @@ -/* ========================================== - Unity Project - A Test Framework for C - Copyright (c) 2007-21 Mike Karlesky, Mark VanderVoord, Greg Williams - [Released under MIT License. Please refer to license.txt for details] -========================================== */ - -#ifndef UNITY_INTERNALS_H -#define UNITY_INTERNALS_H - -#ifdef UNITY_INCLUDE_CONFIG_H -#include "unity_config.h" -#endif - -#ifndef UNITY_EXCLUDE_SETJMP_H -#include <setjmp.h> -#endif - -#ifndef UNITY_EXCLUDE_MATH_H -#include <math.h> -#endif - -#ifndef UNITY_EXCLUDE_STDDEF_H -#include <stddef.h> -#endif - -#ifdef UNITY_INCLUDE_PRINT_FORMATTED -#include <stdarg.h> -#endif - -/* Unity Attempts to Auto-Detect Integer Types - * Attempt 1: UINT_MAX, ULONG_MAX in <limits.h>, or default to 32 bits - * Attempt 2: UINTPTR_MAX in <stdint.h>, or default to same size as long - * The user may override any of these derived constants: - * UNITY_INT_WIDTH, UNITY_LONG_WIDTH, UNITY_POINTER_WIDTH */ -#ifndef UNITY_EXCLUDE_STDINT_H -#include <stdint.h> -#endif - -#ifndef UNITY_EXCLUDE_LIMITS_H -#include <limits.h> -#endif - -#if defined(__GNUC__) || defined(__clang__) - #define UNITY_FUNCTION_ATTR(a) __attribute__((a)) -#else - #define UNITY_FUNCTION_ATTR(a) /* ignore */ -#endif - -#ifndef UNITY_NORETURN - #if defined(__cplusplus) - #if __cplusplus >= 201103L - #define UNITY_NORETURN [[ noreturn ]] - #endif - #elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L - #include <stdnoreturn.h> - #define UNITY_NORETURN noreturn - #endif -#endif -#ifndef UNITY_NORETURN - #define UNITY_NORETURN UNITY_FUNCTION_ATTR(noreturn) -#endif - -/*------------------------------------------------------- - * Guess Widths If Not Specified - *-------------------------------------------------------*/ - -/* Determine the size of an int, if not already specified. - * We cannot use sizeof(int), because it is not yet defined - * at this stage in the translation of the C program. - * Also sizeof(int) does return the size in addressable units on all platforms, - * which may not necessarily be the size in bytes. - * Therefore, infer it from UINT_MAX if possible. */ -#ifndef UNITY_INT_WIDTH - #ifdef UINT_MAX - #if (UINT_MAX == 0xFFFF) - #define UNITY_INT_WIDTH (16) - #elif (UINT_MAX == 0xFFFFFFFF) - #define UNITY_INT_WIDTH (32) - #elif (UINT_MAX == 0xFFFFFFFFFFFFFFFF) - #define UNITY_INT_WIDTH (64) - #endif - #else /* Set to default */ - #define UNITY_INT_WIDTH (32) - #endif /* UINT_MAX */ -#endif - -/* Determine the size of a long, if not already specified. */ -#ifndef UNITY_LONG_WIDTH - #ifdef ULONG_MAX - #if (ULONG_MAX == 0xFFFF) - #define UNITY_LONG_WIDTH (16) - #elif (ULONG_MAX == 0xFFFFFFFF) - #define UNITY_LONG_WIDTH (32) - #elif (ULONG_MAX == 0xFFFFFFFFFFFFFFFF) - #define UNITY_LONG_WIDTH (64) - #endif - #else /* Set to default */ - #define UNITY_LONG_WIDTH (32) - #endif /* ULONG_MAX */ -#endif - -/* Determine the size of a pointer, if not already specified. */ -#ifndef UNITY_POINTER_WIDTH - #ifdef UINTPTR_MAX - #if (UINTPTR_MAX <= 0xFFFF) - #define UNITY_POINTER_WIDTH (16) - #elif (UINTPTR_MAX <= 0xFFFFFFFF) - #define UNITY_POINTER_WIDTH (32) - #elif (UINTPTR_MAX <= 0xFFFFFFFFFFFFFFFF) - #define UNITY_POINTER_WIDTH (64) - #endif - #else /* Set to default */ - #define UNITY_POINTER_WIDTH UNITY_LONG_WIDTH - #endif /* UINTPTR_MAX */ -#endif - -/*------------------------------------------------------- - * Int Support (Define types based on detected sizes) - *-------------------------------------------------------*/ - -#if (UNITY_INT_WIDTH == 32) - typedef unsigned char UNITY_UINT8; - typedef unsigned short UNITY_UINT16; - typedef unsigned int UNITY_UINT32; - typedef signed char UNITY_INT8; - typedef signed short UNITY_INT16; - typedef signed int UNITY_INT32; -#elif (UNITY_INT_WIDTH == 16) - typedef unsigned char UNITY_UINT8; - typedef unsigned int UNITY_UINT16; - typedef unsigned long UNITY_UINT32; - typedef signed char UNITY_INT8; - typedef signed int UNITY_INT16; - typedef signed long UNITY_INT32; -#else - #error Invalid UNITY_INT_WIDTH specified! (16 or 32 are supported) -#endif - -/*------------------------------------------------------- - * 64-bit Support - *-------------------------------------------------------*/ - -/* Auto-detect 64 Bit Support */ -#ifndef UNITY_SUPPORT_64 - #if UNITY_LONG_WIDTH == 64 || UNITY_POINTER_WIDTH == 64 - #define UNITY_SUPPORT_64 - #endif -#endif - -/* 64-Bit Support Dependent Configuration */ -#ifndef UNITY_SUPPORT_64 - /* No 64-bit Support */ - typedef UNITY_UINT32 UNITY_UINT; - typedef UNITY_INT32 UNITY_INT; - #define UNITY_MAX_NIBBLES (8) /* Maximum number of nibbles in a UNITY_(U)INT */ -#else - /* 64-bit Support */ - #if (UNITY_LONG_WIDTH == 32) - typedef unsigned long long UNITY_UINT64; - typedef signed long long UNITY_INT64; - #elif (UNITY_LONG_WIDTH == 64) - typedef unsigned long UNITY_UINT64; - typedef signed long UNITY_INT64; - #else - #error Invalid UNITY_LONG_WIDTH specified! (32 or 64 are supported) - #endif - typedef UNITY_UINT64 UNITY_UINT; - typedef UNITY_INT64 UNITY_INT; - #define UNITY_MAX_NIBBLES (16) /* Maximum number of nibbles in a UNITY_(U)INT */ -#endif - -/*------------------------------------------------------- - * Pointer Support - *-------------------------------------------------------*/ - -#if (UNITY_POINTER_WIDTH == 32) - #define UNITY_PTR_TO_INT UNITY_INT32 - #define UNITY_DISPLAY_STYLE_POINTER UNITY_DISPLAY_STYLE_HEX32 -#elif (UNITY_POINTER_WIDTH == 64) - #define UNITY_PTR_TO_INT UNITY_INT64 - #define UNITY_DISPLAY_STYLE_POINTER UNITY_DISPLAY_STYLE_HEX64 -#elif (UNITY_POINTER_WIDTH == 16) - #define UNITY_PTR_TO_INT UNITY_INT16 - #define UNITY_DISPLAY_STYLE_POINTER UNITY_DISPLAY_STYLE_HEX16 -#else - #error Invalid UNITY_POINTER_WIDTH specified! (16, 32 or 64 are supported) -#endif - -#ifndef UNITY_PTR_ATTRIBUTE - #define UNITY_PTR_ATTRIBUTE -#endif - -#ifndef UNITY_INTERNAL_PTR - #define UNITY_INTERNAL_PTR UNITY_PTR_ATTRIBUTE const void* -#endif - -/*------------------------------------------------------- - * Float Support - *-------------------------------------------------------*/ - -#ifdef UNITY_EXCLUDE_FLOAT - -/* No Floating Point Support */ -#ifndef UNITY_EXCLUDE_DOUBLE -#define UNITY_EXCLUDE_DOUBLE /* Remove double when excluding float support */ -#endif -#ifndef UNITY_EXCLUDE_FLOAT_PRINT -#define UNITY_EXCLUDE_FLOAT_PRINT -#endif - -#else - -/* Floating Point Support */ -#ifndef UNITY_FLOAT_PRECISION -#define UNITY_FLOAT_PRECISION (0.00001f) -#endif -#ifndef UNITY_FLOAT_TYPE -#define UNITY_FLOAT_TYPE float -#endif -typedef UNITY_FLOAT_TYPE UNITY_FLOAT; - -/* isinf & isnan macros should be provided by math.h */ -#ifndef isinf -/* The value of Inf - Inf is NaN */ -#define isinf(n) (isnan((n) - (n)) && !isnan(n)) -#endif - -#ifndef isnan -/* NaN is the only floating point value that does NOT equal itself. - * Therefore if n != n, then it is NaN. */ -#define isnan(n) ((n != n) ? 1 : 0) -#endif - -#endif - -/*------------------------------------------------------- - * Double Float Support - *-------------------------------------------------------*/ - -/* unlike float, we DON'T include by default */ -#if defined(UNITY_EXCLUDE_DOUBLE) || !defined(UNITY_INCLUDE_DOUBLE) - - /* No Floating Point Support */ - #ifndef UNITY_EXCLUDE_DOUBLE - #define UNITY_EXCLUDE_DOUBLE - #else - #undef UNITY_INCLUDE_DOUBLE - #endif - - #ifndef UNITY_EXCLUDE_FLOAT - #ifndef UNITY_DOUBLE_TYPE - #define UNITY_DOUBLE_TYPE double - #endif - typedef UNITY_FLOAT UNITY_DOUBLE; - /* For parameter in UnityPrintFloat(UNITY_DOUBLE), which aliases to double or float */ - #endif - -#else - - /* Double Floating Point Support */ - #ifndef UNITY_DOUBLE_PRECISION - #define UNITY_DOUBLE_PRECISION (1e-12) - #endif - - #ifndef UNITY_DOUBLE_TYPE - #define UNITY_DOUBLE_TYPE double - #endif - typedef UNITY_DOUBLE_TYPE UNITY_DOUBLE; - -#endif - -/*------------------------------------------------------- - * Output Method: stdout (DEFAULT) - *-------------------------------------------------------*/ -#ifndef UNITY_OUTPUT_CHAR - /* Default to using putchar, which is defined in stdio.h */ - #include <stdio.h> - #define UNITY_OUTPUT_CHAR(a) (void)putchar(a) -#else - /* If defined as something else, make sure we declare it here so it's ready for use */ - #ifdef UNITY_OUTPUT_CHAR_HEADER_DECLARATION - extern void UNITY_OUTPUT_CHAR_HEADER_DECLARATION; - #endif -#endif - -#ifndef UNITY_OUTPUT_FLUSH - #ifdef UNITY_USE_FLUSH_STDOUT - /* We want to use the stdout flush utility */ - #include <stdio.h> - #define UNITY_OUTPUT_FLUSH() (void)fflush(stdout) - #else - /* We've specified nothing, therefore flush should just be ignored */ - #define UNITY_OUTPUT_FLUSH() - #endif -#else - /* If defined as something else, make sure we declare it here so it's ready for use */ - #ifdef UNITY_OUTPUT_FLUSH_HEADER_DECLARATION - extern void UNITY_OUTPUT_FLUSH_HEADER_DECLARATION; - #endif -#endif - -#ifndef UNITY_OUTPUT_FLUSH -#define UNITY_FLUSH_CALL() -#else -#define UNITY_FLUSH_CALL() UNITY_OUTPUT_FLUSH() -#endif - -#ifndef UNITY_PRINT_EOL -#define UNITY_PRINT_EOL() UNITY_OUTPUT_CHAR('\n') -#endif - -#ifndef UNITY_OUTPUT_START -#define UNITY_OUTPUT_START() -#endif - -#ifndef UNITY_OUTPUT_COMPLETE -#define UNITY_OUTPUT_COMPLETE() -#endif - -#ifdef UNITY_INCLUDE_EXEC_TIME - #if !defined(UNITY_EXEC_TIME_START) && \ - !defined(UNITY_EXEC_TIME_STOP) && \ - !defined(UNITY_PRINT_EXEC_TIME) && \ - !defined(UNITY_TIME_TYPE) - /* If none any of these macros are defined then try to provide a default implementation */ - - #if defined(UNITY_CLOCK_MS) - /* This is a simple way to get a default implementation on platforms that support getting a millisecond counter */ - #define UNITY_TIME_TYPE UNITY_UINT - #define UNITY_EXEC_TIME_START() Unity.CurrentTestStartTime = UNITY_CLOCK_MS() - #define UNITY_EXEC_TIME_STOP() Unity.CurrentTestStopTime = UNITY_CLOCK_MS() - #define UNITY_PRINT_EXEC_TIME() { \ - UNITY_UINT execTimeMs = (Unity.CurrentTestStopTime - Unity.CurrentTestStartTime); \ - UnityPrint(" ("); \ - UnityPrintNumberUnsigned(execTimeMs); \ - UnityPrint(" ms)"); \ - } - #elif defined(_WIN32) - #include <time.h> - #define UNITY_TIME_TYPE clock_t - #define UNITY_GET_TIME(t) t = (clock_t)((clock() * 1000) / CLOCKS_PER_SEC) - #define UNITY_EXEC_TIME_START() UNITY_GET_TIME(Unity.CurrentTestStartTime) - #define UNITY_EXEC_TIME_STOP() UNITY_GET_TIME(Unity.CurrentTestStopTime) - #define UNITY_PRINT_EXEC_TIME() { \ - UNITY_UINT execTimeMs = (Unity.CurrentTestStopTime - Unity.CurrentTestStartTime); \ - UnityPrint(" ("); \ - UnityPrintNumberUnsigned(execTimeMs); \ - UnityPrint(" ms)"); \ - } - #elif defined(__unix__) || defined(__APPLE__) - #include <time.h> - #define UNITY_TIME_TYPE struct timespec - #define UNITY_GET_TIME(t) clock_gettime(CLOCK_MONOTONIC, &t) - #define UNITY_EXEC_TIME_START() UNITY_GET_TIME(Unity.CurrentTestStartTime) - #define UNITY_EXEC_TIME_STOP() UNITY_GET_TIME(Unity.CurrentTestStopTime) - #define UNITY_PRINT_EXEC_TIME() { \ - UNITY_UINT execTimeMs = ((Unity.CurrentTestStopTime.tv_sec - Unity.CurrentTestStartTime.tv_sec) * 1000L); \ - execTimeMs += ((Unity.CurrentTestStopTime.tv_nsec - Unity.CurrentTestStartTime.tv_nsec) / 1000000L); \ - UnityPrint(" ("); \ - UnityPrintNumberUnsigned(execTimeMs); \ - UnityPrint(" ms)"); \ - } - #endif - #endif -#endif - -#ifndef UNITY_EXEC_TIME_START -#define UNITY_EXEC_TIME_START() do{}while(0) -#endif - -#ifndef UNITY_EXEC_TIME_STOP -#define UNITY_EXEC_TIME_STOP() do{}while(0) -#endif - -#ifndef UNITY_TIME_TYPE -#define UNITY_TIME_TYPE UNITY_UINT -#endif - -#ifndef UNITY_PRINT_EXEC_TIME -#define UNITY_PRINT_EXEC_TIME() do{}while(0) -#endif - -/*------------------------------------------------------- - * Footprint - *-------------------------------------------------------*/ - -#ifndef UNITY_LINE_TYPE -#define UNITY_LINE_TYPE UNITY_UINT -#endif - -#ifndef UNITY_COUNTER_TYPE -#define UNITY_COUNTER_TYPE UNITY_UINT -#endif - -/*------------------------------------------------------- - * Internal Structs Needed - *-------------------------------------------------------*/ - -typedef void (*UnityTestFunction)(void); - -#define UNITY_DISPLAY_RANGE_INT (0x10) -#define UNITY_DISPLAY_RANGE_UINT (0x20) -#define UNITY_DISPLAY_RANGE_HEX (0x40) -#define UNITY_DISPLAY_RANGE_CHAR (0x80) - -typedef enum -{ - UNITY_DISPLAY_STYLE_INT = (UNITY_INT_WIDTH / 8) + UNITY_DISPLAY_RANGE_INT, - UNITY_DISPLAY_STYLE_INT8 = 1 + UNITY_DISPLAY_RANGE_INT, - UNITY_DISPLAY_STYLE_INT16 = 2 + UNITY_DISPLAY_RANGE_INT, - UNITY_DISPLAY_STYLE_INT32 = 4 + UNITY_DISPLAY_RANGE_INT, -#ifdef UNITY_SUPPORT_64 - UNITY_DISPLAY_STYLE_INT64 = 8 + UNITY_DISPLAY_RANGE_INT, -#endif - - UNITY_DISPLAY_STYLE_UINT = (UNITY_INT_WIDTH / 8) + UNITY_DISPLAY_RANGE_UINT, - UNITY_DISPLAY_STYLE_UINT8 = 1 + UNITY_DISPLAY_RANGE_UINT, - UNITY_DISPLAY_STYLE_UINT16 = 2 + UNITY_DISPLAY_RANGE_UINT, - UNITY_DISPLAY_STYLE_UINT32 = 4 + UNITY_DISPLAY_RANGE_UINT, -#ifdef UNITY_SUPPORT_64 - UNITY_DISPLAY_STYLE_UINT64 = 8 + UNITY_DISPLAY_RANGE_UINT, -#endif - - UNITY_DISPLAY_STYLE_HEX8 = 1 + UNITY_DISPLAY_RANGE_HEX, - UNITY_DISPLAY_STYLE_HEX16 = 2 + UNITY_DISPLAY_RANGE_HEX, - UNITY_DISPLAY_STYLE_HEX32 = 4 + UNITY_DISPLAY_RANGE_HEX, -#ifdef UNITY_SUPPORT_64 - UNITY_DISPLAY_STYLE_HEX64 = 8 + UNITY_DISPLAY_RANGE_HEX, -#endif - - UNITY_DISPLAY_STYLE_CHAR = 1 + UNITY_DISPLAY_RANGE_CHAR + UNITY_DISPLAY_RANGE_INT, - - UNITY_DISPLAY_STYLE_UNKNOWN -} UNITY_DISPLAY_STYLE_T; - -typedef enum -{ - UNITY_WITHIN = 0x0, - UNITY_EQUAL_TO = 0x1, - UNITY_GREATER_THAN = 0x2, - UNITY_GREATER_OR_EQUAL = 0x2 + UNITY_EQUAL_TO, - UNITY_SMALLER_THAN = 0x4, - UNITY_SMALLER_OR_EQUAL = 0x4 + UNITY_EQUAL_TO, - UNITY_NOT_EQUAL = 0x0, - UNITY_UNKNOWN -} UNITY_COMPARISON_T; - -#ifndef UNITY_EXCLUDE_FLOAT -typedef enum UNITY_FLOAT_TRAIT -{ - UNITY_FLOAT_IS_NOT_INF = 0, - UNITY_FLOAT_IS_INF, - UNITY_FLOAT_IS_NOT_NEG_INF, - UNITY_FLOAT_IS_NEG_INF, - UNITY_FLOAT_IS_NOT_NAN, - UNITY_FLOAT_IS_NAN, - UNITY_FLOAT_IS_NOT_DET, - UNITY_FLOAT_IS_DET, - UNITY_FLOAT_INVALID_TRAIT -} UNITY_FLOAT_TRAIT_T; -#endif - -typedef enum -{ - UNITY_ARRAY_TO_VAL = 0, - UNITY_ARRAY_TO_ARRAY, - UNITY_ARRAY_UNKNOWN -} UNITY_FLAGS_T; - -struct UNITY_STORAGE_T -{ - const char* TestFile; - const char* CurrentTestName; -#ifndef UNITY_EXCLUDE_DETAILS - const char* CurrentDetail1; - const char* CurrentDetail2; -#endif - UNITY_LINE_TYPE CurrentTestLineNumber; - UNITY_COUNTER_TYPE NumberOfTests; - UNITY_COUNTER_TYPE TestFailures; - UNITY_COUNTER_TYPE TestIgnores; - UNITY_COUNTER_TYPE CurrentTestFailed; - UNITY_COUNTER_TYPE CurrentTestIgnored; -#ifdef UNITY_INCLUDE_EXEC_TIME - UNITY_TIME_TYPE CurrentTestStartTime; - UNITY_TIME_TYPE CurrentTestStopTime; -#endif -#ifndef UNITY_EXCLUDE_SETJMP_H - jmp_buf AbortFrame; -#endif -}; - -extern struct UNITY_STORAGE_T Unity; - -/*------------------------------------------------------- - * Test Suite Management - *-------------------------------------------------------*/ - -void UnityBegin(const char* filename); -int UnityEnd(void); -void UnitySetTestFile(const char* filename); -void UnityConcludeTest(void); - -#ifndef RUN_TEST -void UnityDefaultTestRun(UnityTestFunction Func, const char* FuncName, const int FuncLineNum); -#else -#define UNITY_SKIP_DEFAULT_RUNNER -#endif - -/*------------------------------------------------------- - * Details Support - *-------------------------------------------------------*/ - -#ifdef UNITY_EXCLUDE_DETAILS -#define UNITY_CLR_DETAILS() -#define UNITY_SET_DETAIL(d1) -#define UNITY_SET_DETAILS(d1,d2) -#else -#define UNITY_CLR_DETAILS() { Unity.CurrentDetail1 = 0; Unity.CurrentDetail2 = 0; } -#define UNITY_SET_DETAIL(d1) { Unity.CurrentDetail1 = (d1); Unity.CurrentDetail2 = 0; } -#define UNITY_SET_DETAILS(d1,d2) { Unity.CurrentDetail1 = (d1); Unity.CurrentDetail2 = (d2); } - -#ifndef UNITY_DETAIL1_NAME -#define UNITY_DETAIL1_NAME "Function" -#endif - -#ifndef UNITY_DETAIL2_NAME -#define UNITY_DETAIL2_NAME "Argument" -#endif -#endif - -#ifdef UNITY_PRINT_TEST_CONTEXT -void UNITY_PRINT_TEST_CONTEXT(void); -#endif - -/*------------------------------------------------------- - * Test Output - *-------------------------------------------------------*/ - -void UnityPrint(const char* string); - -#ifdef UNITY_INCLUDE_PRINT_FORMATTED -void UnityPrintF(const UNITY_LINE_TYPE line, const char* format, ...); -#endif - -void UnityPrintLen(const char* string, const UNITY_UINT32 length); -void UnityPrintMask(const UNITY_UINT mask, const UNITY_UINT number); -void UnityPrintNumberByStyle(const UNITY_INT number, const UNITY_DISPLAY_STYLE_T style); -void UnityPrintNumber(const UNITY_INT number_to_print); -void UnityPrintNumberUnsigned(const UNITY_UINT number); -void UnityPrintNumberHex(const UNITY_UINT number, const char nibbles_to_print); - -#ifndef UNITY_EXCLUDE_FLOAT_PRINT -void UnityPrintFloat(const UNITY_DOUBLE input_number); -#endif - -/*------------------------------------------------------- - * Test Assertion Functions - *------------------------------------------------------- - * Use the macros below this section instead of calling - * these directly. The macros have a consistent naming - * convention and will pull in file and line information - * for you. */ - -void UnityAssertEqualNumber(const UNITY_INT expected, - const UNITY_INT actual, - const char* msg, - const UNITY_LINE_TYPE lineNumber, - const UNITY_DISPLAY_STYLE_T style); - -void UnityAssertGreaterOrLessOrEqualNumber(const UNITY_INT threshold, - const UNITY_INT actual, - const UNITY_COMPARISON_T compare, - const char *msg, - const UNITY_LINE_TYPE lineNumber, - const UNITY_DISPLAY_STYLE_T style); - -void UnityAssertEqualIntArray(UNITY_INTERNAL_PTR expected, - UNITY_INTERNAL_PTR actual, - const UNITY_UINT32 num_elements, - const char* msg, - const UNITY_LINE_TYPE lineNumber, - const UNITY_DISPLAY_STYLE_T style, - const UNITY_FLAGS_T flags); - -void UnityAssertBits(const UNITY_INT mask, - const UNITY_INT expected, - const UNITY_INT actual, - const char* msg, - const UNITY_LINE_TYPE lineNumber); - -void UnityAssertEqualString(const char* expected, - const char* actual, - const char* msg, - const UNITY_LINE_TYPE lineNumber); - -void UnityAssertEqualStringLen(const char* expected, - const char* actual, - const UNITY_UINT32 length, - const char* msg, - const UNITY_LINE_TYPE lineNumber); - -void UnityAssertEqualStringArray( UNITY_INTERNAL_PTR expected, - const char** actual, - const UNITY_UINT32 num_elements, - const char* msg, - 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_FLAGS_T flags); - -void UnityAssertNumbersWithin(const UNITY_UINT delta, - const UNITY_INT expected, - const UNITY_INT actual, - const char* msg, - const UNITY_LINE_TYPE lineNumber, - const UNITY_DISPLAY_STYLE_T style); - -void UnityAssertNumbersArrayWithin(const UNITY_UINT delta, - UNITY_INTERNAL_PTR expected, - UNITY_INTERNAL_PTR actual, - const UNITY_UINT32 num_elements, - const char* msg, - const UNITY_LINE_TYPE lineNumber, - const UNITY_DISPLAY_STYLE_T style, - const UNITY_FLAGS_T flags); - -#ifndef UNITY_EXCLUDE_SETJMP_H -UNITY_NORETURN void UnityFail(const char* message, const UNITY_LINE_TYPE line); -UNITY_NORETURN void UnityIgnore(const char* message, const UNITY_LINE_TYPE line); -#else -void UnityFail(const char* message, const UNITY_LINE_TYPE line); -void UnityIgnore(const char* message, const UNITY_LINE_TYPE line); -#endif - -void UnityMessage(const char* message, const UNITY_LINE_TYPE line); - -#ifndef UNITY_EXCLUDE_FLOAT -void UnityAssertFloatsWithin(const UNITY_FLOAT delta, - const UNITY_FLOAT expected, - const UNITY_FLOAT actual, - const char* msg, - const UNITY_LINE_TYPE lineNumber); - -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_FLAGS_T flags); - -void UnityAssertFloatSpecial(const UNITY_FLOAT actual, - const char* msg, - const UNITY_LINE_TYPE lineNumber, - const UNITY_FLOAT_TRAIT_T style); -#endif - -#ifndef UNITY_EXCLUDE_DOUBLE -void UnityAssertDoublesWithin(const UNITY_DOUBLE delta, - const UNITY_DOUBLE expected, - const UNITY_DOUBLE actual, - const char* msg, - const UNITY_LINE_TYPE lineNumber); - -void UnityAssertEqualDoubleArray(UNITY_PTR_ATTRIBUTE const UNITY_DOUBLE* expected, - UNITY_PTR_ATTRIBUTE const UNITY_DOUBLE* actual, - const UNITY_UINT32 num_elements, - const char* msg, - const UNITY_LINE_TYPE lineNumber, - const UNITY_FLAGS_T flags); - -void UnityAssertDoubleSpecial(const UNITY_DOUBLE actual, - const char* msg, - const UNITY_LINE_TYPE lineNumber, - const UNITY_FLOAT_TRAIT_T style); -#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 - *-------------------------------------------------------*/ - -extern const char UnityStrOk[]; -extern const char UnityStrPass[]; -extern const char UnityStrFail[]; -extern const char UnityStrIgnore[]; - -extern const char UnityStrErrFloat[]; -extern const char UnityStrErrDouble[]; -extern const char UnityStrErr64[]; -extern const char UnityStrErrShorthand[]; - -/*------------------------------------------------------- - * Test Running Macros - *-------------------------------------------------------*/ - -#ifndef UNITY_EXCLUDE_SETJMP_H -#define TEST_PROTECT() (setjmp(Unity.AbortFrame) == 0) -#define TEST_ABORT() longjmp(Unity.AbortFrame, 1) -#else -#define TEST_PROTECT() 1 -#define TEST_ABORT() return -#endif - -/* This tricky series of macros gives us an optional line argument to treat it as RUN_TEST(func, num=__LINE__) */ -#ifndef RUN_TEST -#ifdef __STDC_VERSION__ -#if __STDC_VERSION__ >= 199901L -#define UNITY_SUPPORT_VARIADIC_MACROS -#endif -#endif -#ifdef UNITY_SUPPORT_VARIADIC_MACROS -#define RUN_TEST(...) RUN_TEST_AT_LINE(__VA_ARGS__, __LINE__, throwaway) -#define RUN_TEST_AT_LINE(func, line, ...) UnityDefaultTestRun(func, #func, line) -#endif -#endif - -/* If we can't do the tricky version, we'll just have to require them to always include the line number */ -#ifndef RUN_TEST -#ifdef CMOCK -#define RUN_TEST(func, num) UnityDefaultTestRun(func, #func, num) -#else -#define RUN_TEST(func) UnityDefaultTestRun(func, #func, __LINE__) -#endif -#endif - -#define TEST_LINE_NUM (Unity.CurrentTestLineNumber) -#define TEST_IS_IGNORED (Unity.CurrentTestIgnored) -#define UNITY_NEW_TEST(a) \ - Unity.CurrentTestName = (a); \ - Unity.CurrentTestLineNumber = (UNITY_LINE_TYPE)(__LINE__); \ - Unity.NumberOfTests++; - -#ifndef UNITY_BEGIN -#define UNITY_BEGIN() UnityBegin(__FILE__) -#endif - -#ifndef UNITY_END -#define UNITY_END() UnityEnd() -#endif - -#ifndef UNITY_SHORTHAND_AS_INT -#ifndef UNITY_SHORTHAND_AS_MEM -#ifndef UNITY_SHORTHAND_AS_NONE -#ifndef UNITY_SHORTHAND_AS_RAW -#define UNITY_SHORTHAND_AS_OLD -#endif -#endif -#endif -#endif - -/*----------------------------------------------- - * Command Line Argument Support - *-----------------------------------------------*/ - -#ifdef UNITY_USE_COMMAND_LINE_ARGS -int UnityParseOptions(int argc, char** argv); -int UnityTestMatches(void); -#endif - -/*------------------------------------------------------- - * Basic Fail and Ignore - *-------------------------------------------------------*/ - -#define UNITY_TEST_FAIL(line, message) UnityFail( (message), (UNITY_LINE_TYPE)(line)) -#define UNITY_TEST_IGNORE(line, message) UnityIgnore( (message), (UNITY_LINE_TYPE)(line)) - -/*------------------------------------------------------- - * Test Asserts - *-------------------------------------------------------*/ - -#define UNITY_TEST_ASSERT(condition, line, message) do {if (condition) {} else {UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), (message));}} while(0) -#define UNITY_TEST_ASSERT_NULL(pointer, line, message) UNITY_TEST_ASSERT(((pointer) == NULL), (UNITY_LINE_TYPE)(line), (message)) -#define UNITY_TEST_ASSERT_NOT_NULL(pointer, line, message) UNITY_TEST_ASSERT(((pointer) != NULL), (UNITY_LINE_TYPE)(line), (message)) -#define UNITY_TEST_ASSERT_EMPTY(pointer, line, message) UNITY_TEST_ASSERT(((pointer[0]) == 0), (UNITY_LINE_TYPE)(line), (message)) -#define UNITY_TEST_ASSERT_NOT_EMPTY(pointer, line, message) UNITY_TEST_ASSERT(((pointer[0]) != 0), (UNITY_LINE_TYPE)(line), (message)) - -#define UNITY_TEST_ASSERT_EQUAL_INT(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) -#define UNITY_TEST_ASSERT_EQUAL_INT8(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_INT8 )(expected), (UNITY_INT)(UNITY_INT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) -#define UNITY_TEST_ASSERT_EQUAL_INT16(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_INT16)(expected), (UNITY_INT)(UNITY_INT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) -#define UNITY_TEST_ASSERT_EQUAL_INT32(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_INT32)(expected), (UNITY_INT)(UNITY_INT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) -#define UNITY_TEST_ASSERT_EQUAL_UINT(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) -#define UNITY_TEST_ASSERT_EQUAL_UINT8(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_UINT8 )(expected), (UNITY_INT)(UNITY_UINT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) -#define UNITY_TEST_ASSERT_EQUAL_UINT16(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_UINT16)(expected), (UNITY_INT)(UNITY_UINT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) -#define UNITY_TEST_ASSERT_EQUAL_UINT32(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_UINT32)(expected), (UNITY_INT)(UNITY_UINT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) -#define UNITY_TEST_ASSERT_EQUAL_HEX8(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_INT8 )(expected), (UNITY_INT)(UNITY_INT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) -#define UNITY_TEST_ASSERT_EQUAL_HEX16(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_INT16)(expected), (UNITY_INT)(UNITY_INT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) -#define UNITY_TEST_ASSERT_EQUAL_HEX32(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_INT32)(expected), (UNITY_INT)(UNITY_INT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) -#define UNITY_TEST_ASSERT_EQUAL_CHAR(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_INT8 )(expected), (UNITY_INT)(UNITY_INT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR) -#define UNITY_TEST_ASSERT_BITS(mask, expected, actual, line, message) UnityAssertBits((UNITY_INT)(mask), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line)) - -#define UNITY_TEST_ASSERT_NOT_EQUAL_INT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) -#define UNITY_TEST_ASSERT_NOT_EQUAL_INT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) -#define UNITY_TEST_ASSERT_NOT_EQUAL_INT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT16)(threshold), (UNITY_INT)(UNITY_INT16)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) -#define UNITY_TEST_ASSERT_NOT_EQUAL_INT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT32)(threshold), (UNITY_INT)(UNITY_INT32)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) -#define UNITY_TEST_ASSERT_NOT_EQUAL_UINT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) -#define UNITY_TEST_ASSERT_NOT_EQUAL_UINT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) -#define UNITY_TEST_ASSERT_NOT_EQUAL_UINT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) -#define UNITY_TEST_ASSERT_NOT_EQUAL_UINT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) -#define UNITY_TEST_ASSERT_NOT_EQUAL_HEX8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) -#define UNITY_TEST_ASSERT_NOT_EQUAL_HEX16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) -#define UNITY_TEST_ASSERT_NOT_EQUAL_HEX32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) -#define UNITY_TEST_ASSERT_NOT_EQUAL_CHAR(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR) - -#define UNITY_TEST_ASSERT_GREATER_THAN_INT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) -#define UNITY_TEST_ASSERT_GREATER_THAN_INT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) -#define UNITY_TEST_ASSERT_GREATER_THAN_INT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT16)(threshold), (UNITY_INT)(UNITY_INT16)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) -#define UNITY_TEST_ASSERT_GREATER_THAN_INT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT32)(threshold), (UNITY_INT)(UNITY_INT32)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) -#define UNITY_TEST_ASSERT_GREATER_THAN_UINT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) -#define UNITY_TEST_ASSERT_GREATER_THAN_UINT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) -#define UNITY_TEST_ASSERT_GREATER_THAN_UINT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) -#define UNITY_TEST_ASSERT_GREATER_THAN_UINT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) -#define UNITY_TEST_ASSERT_GREATER_THAN_HEX8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) -#define UNITY_TEST_ASSERT_GREATER_THAN_HEX16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) -#define UNITY_TEST_ASSERT_GREATER_THAN_HEX32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) -#define UNITY_TEST_ASSERT_GREATER_THAN_CHAR(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR) - -#define UNITY_TEST_ASSERT_SMALLER_THAN_INT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) -#define UNITY_TEST_ASSERT_SMALLER_THAN_INT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) -#define UNITY_TEST_ASSERT_SMALLER_THAN_INT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT16)(threshold), (UNITY_INT)(UNITY_INT16)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) -#define UNITY_TEST_ASSERT_SMALLER_THAN_INT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT32)(threshold), (UNITY_INT)(UNITY_INT32)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) -#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) -#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) -#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) -#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) -#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) -#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) -#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) -#define UNITY_TEST_ASSERT_SMALLER_THAN_CHAR(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR) - -#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT) (threshold), (UNITY_INT) (actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) -#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 ) (threshold), (UNITY_INT)(UNITY_INT8 ) (actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) -#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT16) (threshold), (UNITY_INT)(UNITY_INT16) (actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) -#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT32) (threshold), (UNITY_INT)(UNITY_INT32) (actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) -#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT) (threshold), (UNITY_INT) (actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) -#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) -#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) -#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) -#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) -#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) -#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) -#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_CHAR(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 ) (threshold), (UNITY_INT)(UNITY_INT8 ) (actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR) - -#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT) (threshold), (UNITY_INT) (actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) -#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 ) (actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) -#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT16)(threshold), (UNITY_INT)(UNITY_INT16) (actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) -#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT32)(threshold), (UNITY_INT)(UNITY_INT32) (actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) -#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT) (threshold), (UNITY_INT) (actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) -#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) -#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) -#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) -#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) -#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) -#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) -#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_CHAR(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 ) (actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR) - -#define UNITY_TEST_ASSERT_INT_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin( (delta), (UNITY_INT) (expected), (UNITY_INT) (actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) -#define UNITY_TEST_ASSERT_INT8_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT8 )(delta), (UNITY_INT)(UNITY_INT8 ) (expected), (UNITY_INT)(UNITY_INT8 ) (actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) -#define UNITY_TEST_ASSERT_INT16_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT16)(delta), (UNITY_INT)(UNITY_INT16) (expected), (UNITY_INT)(UNITY_INT16) (actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) -#define UNITY_TEST_ASSERT_INT32_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT32)(delta), (UNITY_INT)(UNITY_INT32) (expected), (UNITY_INT)(UNITY_INT32) (actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) -#define UNITY_TEST_ASSERT_UINT_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin( (delta), (UNITY_INT) (expected), (UNITY_INT) (actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) -#define UNITY_TEST_ASSERT_UINT8_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT8 )(delta), (UNITY_INT)(UNITY_UINT)(UNITY_UINT8 )(expected), (UNITY_INT)(UNITY_UINT)(UNITY_UINT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) -#define UNITY_TEST_ASSERT_UINT16_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT16)(delta), (UNITY_INT)(UNITY_UINT)(UNITY_UINT16)(expected), (UNITY_INT)(UNITY_UINT)(UNITY_UINT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) -#define UNITY_TEST_ASSERT_UINT32_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT32)(delta), (UNITY_INT)(UNITY_UINT)(UNITY_UINT32)(expected), (UNITY_INT)(UNITY_UINT)(UNITY_UINT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) -#define UNITY_TEST_ASSERT_HEX8_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT8 )(delta), (UNITY_INT)(UNITY_UINT)(UNITY_UINT8 )(expected), (UNITY_INT)(UNITY_UINT)(UNITY_UINT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) -#define UNITY_TEST_ASSERT_HEX16_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT16)(delta), (UNITY_INT)(UNITY_UINT)(UNITY_UINT16)(expected), (UNITY_INT)(UNITY_UINT)(UNITY_UINT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) -#define UNITY_TEST_ASSERT_HEX32_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT32)(delta), (UNITY_INT)(UNITY_UINT)(UNITY_UINT32)(expected), (UNITY_INT)(UNITY_UINT)(UNITY_UINT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) -#define UNITY_TEST_ASSERT_CHAR_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT8 )(delta), (UNITY_INT)(UNITY_INT8 ) (expected), (UNITY_INT)(UNITY_INT8 ) (actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR) - -#define UNITY_TEST_ASSERT_INT_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin( (delta), (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_INT8_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT8 )(delta), (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_INT16_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT16)(delta), (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_INT32_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT32)(delta), (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_UINT_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin( (delta), (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_UINT8_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT16)(delta), (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_UINT16_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT16)(delta), (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_UINT32_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT32)(delta), (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_HEX8_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT8 )(delta), (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_HEX16_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT16)(delta), (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_HEX32_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT32)(delta), (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_CHAR_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT8 )(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR, UNITY_ARRAY_TO_ARRAY) - - -#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), 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_EQUAL_CHAR_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_CHAR, UNITY_ARRAY_TO_ARRAY) - -#define UNITY_TEST_ASSERT_EACH_EQUAL_INT(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT) (expected), (UNITY_INT_WIDTH / 8)), (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), (UNITY_INT_WIDTH / 8)), (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), (UNITY_POINTER_WIDTH / 8)), (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) -#define UNITY_TEST_ASSERT_EACH_EQUAL_CHAR(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_CHAR, 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, 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_VAL) -#define UNITY_TEST_ASSERT_EACH_EQUAL_UINT64(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_UINT64)(expected), 8), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64, UNITY_ARRAY_TO_VAL) -#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_VAL) -#define UNITY_TEST_ASSERT_INT64_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((delta), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) -#define UNITY_TEST_ASSERT_UINT64_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((delta), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) -#define UNITY_TEST_ASSERT_HEX64_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((delta), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) -#define UNITY_TEST_ASSERT_NOT_EQUAL_INT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) -#define UNITY_TEST_ASSERT_NOT_EQUAL_UINT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) -#define UNITY_TEST_ASSERT_NOT_EQUAL_HEX64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) -#define UNITY_TEST_ASSERT_GREATER_THAN_INT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) -#define UNITY_TEST_ASSERT_GREATER_THAN_UINT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) -#define UNITY_TEST_ASSERT_GREATER_THAN_HEX64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) -#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) -#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) -#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) -#define UNITY_TEST_ASSERT_SMALLER_THAN_INT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) -#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) -#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) -#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) -#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) -#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) -#define UNITY_TEST_ASSERT_INT64_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT64)(delta), (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_UINT64_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT64)(delta), (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_HEX64_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT64)(delta), (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) -#else -#define UNITY_TEST_ASSERT_EQUAL_INT64(expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) -#define UNITY_TEST_ASSERT_EQUAL_UINT64(expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) -#define UNITY_TEST_ASSERT_EQUAL_HEX64(expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) -#define UNITY_TEST_ASSERT_EQUAL_INT64_ARRAY(expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) -#define UNITY_TEST_ASSERT_EQUAL_UINT64_ARRAY(expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) -#define UNITY_TEST_ASSERT_EQUAL_HEX64_ARRAY(expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) -#define UNITY_TEST_ASSERT_INT64_WITHIN(delta, expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) -#define UNITY_TEST_ASSERT_UINT64_WITHIN(delta, expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) -#define UNITY_TEST_ASSERT_HEX64_WITHIN(delta, expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) -#define UNITY_TEST_ASSERT_GREATER_THAN_INT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) -#define UNITY_TEST_ASSERT_GREATER_THAN_UINT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) -#define UNITY_TEST_ASSERT_GREATER_THAN_HEX64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) -#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) -#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) -#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) -#define UNITY_TEST_ASSERT_SMALLER_THAN_INT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) -#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) -#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) -#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) -#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) -#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) -#define UNITY_TEST_ASSERT_INT64_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) -#define UNITY_TEST_ASSERT_UINT64_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) -#define UNITY_TEST_ASSERT_HEX64_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) -#endif - -#ifdef UNITY_EXCLUDE_FLOAT -#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) -#define UNITY_TEST_ASSERT_FLOAT_IS_DETERMINATE(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) -#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) -#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_NEG_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) -#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_NAN(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) -#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) -#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), 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) -#define UNITY_TEST_ASSERT_FLOAT_IS_DETERMINATE(actual, line, message) UnityAssertFloatSpecial((UNITY_FLOAT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_DET) -#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_INF(actual, line, message) UnityAssertFloatSpecial((UNITY_FLOAT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_INF) -#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_NEG_INF(actual, line, message) UnityAssertFloatSpecial((UNITY_FLOAT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_NEG_INF) -#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_NAN(actual, line, message) UnityAssertFloatSpecial((UNITY_FLOAT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_NAN) -#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE(actual, line, message) UnityAssertFloatSpecial((UNITY_FLOAT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_DET) -#endif - -#ifdef UNITY_EXCLUDE_DOUBLE -#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) -#define UNITY_TEST_ASSERT_DOUBLE_IS_DETERMINATE(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) -#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) -#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) -#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NAN(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) -#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) -#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), 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) -#define UNITY_TEST_ASSERT_DOUBLE_IS_DETERMINATE(actual, line, message) UnityAssertDoubleSpecial((UNITY_DOUBLE)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_DET) -#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_INF(actual, line, message) UnityAssertDoubleSpecial((UNITY_DOUBLE)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_INF) -#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF(actual, line, message) UnityAssertDoubleSpecial((UNITY_DOUBLE)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_NEG_INF) -#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NAN(actual, line, message) UnityAssertDoubleSpecial((UNITY_DOUBLE)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_NAN) -#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE(actual, line, message) UnityAssertDoubleSpecial((UNITY_DOUBLE)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_DET) -#endif - -/* End of UNITY_INTERNALS_H */ -#endif From 5f1a419c41d8e5672f257be18f606211461f15c7 Mon Sep 17 00:00:00 2001 From: Paul Jacobson <20469645+pajacobson@users.noreply.github.com> Date: Sun, 11 Dec 2022 07:44:58 +1100 Subject: [PATCH 11/22] Change output extension to .elf - Allows import into MPLABX IDE --- project.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project.yml b/project.yml index bb1a968..2527d2d 100644 --- a/project.yml +++ b/project.yml @@ -31,7 +31,7 @@ # - :xc_version: "v2.00" :extension: - :executable: .out + :executable: .elf :paths: :test: From 236d3bbf360b7ee96786d127cbb4e20e9478a0ef Mon Sep 17 00:00:00 2001 From: Paul Jacobson <20469645+pajacobson@users.noreply.github.com> Date: Sun, 11 Dec 2022 07:46:40 +1100 Subject: [PATCH 12/22] Move INCLUDE_UNITY_CONFIG_H under test defines --- project.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/project.yml b/project.yml index 2527d2d..e4f74e7 100644 --- a/project.yml +++ b/project.yml @@ -60,15 +60,11 @@ :test: - *common_defines - TEST - + - UNITY_INCLUDE_CONFIG_H :test_preprocess: - *common_defines - TEST -:unity: - :defines: - - UNITY_INCLUDE_CONFIG_H - :cmock: :mock_prefix: mock_ :when_no_prototypes: :warn From 65c21670cecb2bd566bffbf2aaeb9d0632ea6af4 Mon Sep 17 00:00:00 2001 From: Paul Jacobson <20469645+pajacobson@users.noreply.github.com> Date: Sun, 11 Dec 2022 07:47:11 +1100 Subject: [PATCH 13/22] Update comments --- test/simulation/sim_test_fixture.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/simulation/sim_test_fixture.rb b/test/simulation/sim_test_fixture.rb index 3590b49..75c3767 100644 --- a/test/simulation/sim_test_fixture.rb +++ b/test/simulation/sim_test_fixture.rb @@ -16,7 +16,7 @@ stdin.puts("Wait 30000") stdin.puts("Quit") -# Filter out tedious MDB Java logr and NetBeans errors +# Filter out MDB Java logr and NetBeans errors errors = stderr.readlines.reject { | line | line.match(/(logr|dumb|Preferences)/)} result = stdout.readlines @@ -25,8 +25,9 @@ # Remove stray command prompts result = result.map {|s| s.gsub(/^>/, "")} -# find the test results block +# First line of results test_start = result.find_index { |line| line.match(/^.*\:(?:FAIL|PASS|IGNORE)/) } +# Last line of results test_status = result.find_index { |line| line.match(/^(?:OK|FAIL)\n/) } # start and last will be missing if code causes an Exception From d461aea492e326d2153b1d5bf9813e497228393d Mon Sep 17 00:00:00 2001 From: Paul Jacobson <20469645+pajacobson@users.noreply.github.com> Date: Sun, 11 Dec 2022 07:48:12 +1100 Subject: [PATCH 14/22] Revert to loop behavior --- test/support/UnityHelper.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/support/UnityHelper.c b/test/support/UnityHelper.c index 10bf07f..4218ce0 100644 --- a/test/support/UnityHelper.c +++ b/test/support/UnityHelper.c @@ -1,6 +1,4 @@ -#include "UnityHelper.h" - void UnityHelperDeadLoop(void){ - while(0){}; + while(1){}; } From 09a48348853b2592e6b043da46c6a35db3d1ce45 Mon Sep 17 00:00:00 2001 From: Paul Jacobson <20469645+pajacobson@users.noreply.github.com> Date: Sun, 11 Dec 2022 07:49:01 +1100 Subject: [PATCH 15/22] Output cleaned errors to STDERR --- test/simulation/sim_test_fixture.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/simulation/sim_test_fixture.rb b/test/simulation/sim_test_fixture.rb index 75c3767..9bb05e9 100644 --- a/test/simulation/sim_test_fixture.rb +++ b/test/simulation/sim_test_fixture.rb @@ -41,5 +41,5 @@ end errors.each do | line | - STDOUT.print line + STDERR.print line end From 81193770c2e7c6f41c7791f8d9c6bf537f5bd3e4 Mon Sep 17 00:00:00 2001 From: Paul Jacobson <20469645+pajacobson@users.noreply.github.com> Date: Sun, 11 Dec 2022 07:50:01 +1100 Subject: [PATCH 16/22] Remove testing TEST_FAIL --- test/test_gpio_access.c | 1 - 1 file changed, 1 deletion(-) diff --git a/test/test_gpio_access.c b/test/test_gpio_access.c index 385695d..c8b3a1c 100644 --- a/test/test_gpio_access.c +++ b/test/test_gpio_access.c @@ -178,7 +178,6 @@ void test_GPIO_ClearBit_should_clear_the_corresponding_SFR_bit_for_B3(void) void test_GPIO_ClearBit_should_clear_the_corresponding_SFR_bit_for_B4(void) { - TEST_FAIL(); // Create initial condition LATBbits.LATB4 = 1; // Call function under test From cdb22b7237fb76ecff3b7f637207eb74e5d6d86b Mon Sep 17 00:00:00 2001 From: Paul Jacobson <20469645+pajacobson@users.noreply.github.com> Date: Sun, 11 Dec 2022 07:50:35 +1100 Subject: [PATCH 17/22] White space changes --- .gitignore | 1 + test/support/unity_config.h | 1 + 2 files changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index e43b0f9..5ca0973 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ .DS_Store + diff --git a/test/support/unity_config.h b/test/support/unity_config.h index eebfca0..4244062 100644 --- a/test/support/unity_config.h +++ b/test/support/unity_config.h @@ -1,5 +1,6 @@ #ifndef UNITY_CONFIG_H #define UNITY_CONFIG_H + #include "UnityHelper.h" #define UNITY_OUTPUT_COMPLETE() UnityHelperDeadLoop() From 9752b22e659312645917a75cf7fdad9cd85177a1 Mon Sep 17 00:00:00 2001 From: Paul Jacobson <20469645+pajacobson@users.noreply.github.com> Date: Sun, 11 Dec 2022 07:51:41 +1100 Subject: [PATCH 18/22] Adding missing debug defines --- project.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/project.yml b/project.yml index e4f74e7..a4ed399 100644 --- a/project.yml +++ b/project.yml @@ -101,9 +101,10 @@ - -mcpu=24HJ128GP202 - -x c - -c + - -g - "${1}" - -o "${2}" - - -D_DEBUG + - -D__DEBUG=__DEBUG - -D__MPLAB_DEBUGGER_SIMULATOR=1 - -D$: COLLECTION_DEFINES_TEST_AND_VENDOR - -I"$": COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR @@ -118,9 +119,7 @@ - -mcpu=24HJ128GP202 - ${1} - -o ${2} - - -Wl,-Tp24HJ128GP202.gld,--heap=0, - --defsym=__MPLAB_BUILD=1,--defsym=__MPLAB_DEBUG=1, - --defsym=__DEBUG=1,-D__DEBUG=__DEBUG,--defsym=__MPLAB_DEBUGGER_SIMULATOR=1 + - "-Wl,-Tp24HJ128GP202.gld,--heap=0,--defsym=__MPLAB_BUILD=1,--defsym=__MPLAB_DEBUG=1,--defsym=__DEBUG=1,-D__DEBUG=__DEBUG,--defsym=__MPLAB_DEBUGGER_SIMULATOR=1" :test_fixture: :executable: ruby From 0c4692a15d478bd43f920e65f9db4f600a1679af Mon Sep 17 00:00:00 2001 From: Paul Jacobson <20469645+pajacobson@users.noreply.github.com> Date: Wed, 4 Jan 2023 15:31:32 +1100 Subject: [PATCH 19/22] Move fixture config to project.yml --- README.md | 23 +++++++++++---- project.yml | 12 ++++++++ test/simulation/sim_test_fixture.rb | 44 ++++++++++++++--------------- 3 files changed, 50 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 7db76f4..e6a3d88 100644 --- a/README.md +++ b/README.md @@ -23,23 +23,34 @@ Edit: 2022-12-07 * Ceedling updated to 0.31.1 * Update Simulation configuration located in test/simulation +Edit: 2023-01-04 - sim_test_fixture.rd sim_test_fixture.rd now programs and runs the test binary. Changes eliminate the need for "sleep" and "wait" timeouts and breakpoints. -- sim_instructions.txt -This file should only include configuration for the device - Device, HWTool and "set". -Running commands - Program, Reset, Run, Wait, Sleep, Quit - should not be used. - -- project.yml +MDB is configured using the `:text_fixture:` section of the `project.yml` file. +The first 6 arguments are required, and must be supplied in the given order. +Set options must be supplied as `option value` pairs. ```yaml :test_fixture: :executable: ruby :name: "Microchip simulator test fixture" - :stderr_redirect: :win #inform Ceedling what model of $stderr capture to use + :stderr_redirect: :auto #inform Ceedling what model of $stderr capture to use :arguments: - test/simulation/sim_test_fixture.rb - ${1} + # MDB command + - "mdb.sh" + # MDB timeout - fail safe + - "30000" + # Device + - PIC24HJ128GP202 + # HWTOOL + - SIM + # Set options + - "warningmessagebreakoptions.W0011_CORE_SIM32_UNIMPLEMENTED_RAMACCESS break" + - "uart1io.output window" + - "uart1io.uartioenabled true" ``` diff --git a/project.yml b/project.yml index a4ed399..ead4ca1 100644 --- a/project.yml +++ b/project.yml @@ -128,6 +128,18 @@ :arguments: - test/simulation/sim_test_fixture.rb - ${1} + # MDB command + - "mdb.sh" + # MDB timeout - fail safe + - "30000" + # Device + - PIC24HJ128GP202 + # HWTOOL + - SIM + # Set options + - "warningmessagebreakoptions.W0011_CORE_SIM32_UNIMPLEMENTED_RAMACCESS break" + - "uart1io.output window" + - "uart1io.uartioenabled true" :release_compiler: :executable: xc16-gcc diff --git a/test/simulation/sim_test_fixture.rb b/test/simulation/sim_test_fixture.rb index 9bb05e9..8e02598 100644 --- a/test/simulation/sim_test_fixture.rb +++ b/test/simulation/sim_test_fixture.rb @@ -1,20 +1,25 @@ require 'open3' -MDB = "mdb.sh" # or "mdb" +test_file = ARGV.shift +mdb_command = ARGV.shift +timeout = ARGV.shift -CONFIG_FILE = "./test/simulation/sim_configuration.txt" +stdin, stdout, stderr, wait_thr = Open3.popen3(mdb_command) -test_file = ARGV[0] +stdin.puts "Device #{ARGV.shift}" +stdin.puts "Hwtool #{ARGV.shift}" -stdin, stdout, stderr, wait_thr = Open3.popen3(MDB, CONFIG_FILE) +ARGV.each_slice(2) do | opt, val | + stdin.puts "set #{opt} #{val}" +end + +stdin.puts "Program #{test_file}" -stdin.puts("Program " + test_file) -stdin.puts("Break UnityHelperDeadLoop") -stdin.puts("Run") +stdin.puts "Break UnityHelperDeadLoop" +stdin.puts "Run" +stdin.puts "Wait #{timeout}" +stdin.puts "Quit" -# Failsafe: exit after 30 seconds if SIM does not halt -stdin.puts("Wait 30000") -stdin.puts("Quit") # Filter out MDB Java logr and NetBeans errors errors = stderr.readlines.reject { | line | line.match(/(logr|dumb|Preferences)/)} @@ -22,24 +27,17 @@ Process.waitall -# Remove stray command prompts +# Remove command prompts result = result.map {|s| s.gsub(/^>/, "")} -# First line of results -test_start = result.find_index { |line| line.match(/^.*\:(?:FAIL|PASS|IGNORE)/) } -# Last line of results +# Results start 2 lines after Running, and end with OK or FAIL +test_start = result.find_index { |line| line.match(/^Running/) } test_status = result.find_index { |line| line.match(/^(?:OK|FAIL)\n/) } -# start and last will be missing if code causes an Exception if (test_start != nil) & (test_status != nil) - result = result[test_start , (test_status - test_start) + 1] + result = result[test_start + 2 , (test_status - test_start - 1)] end -# Play back cleaned results and errors -result.each do | line | - STDOUT.print line -end +STDOUT.print result.join() +STDERR.print errors.join() -errors.each do | line | - STDERR.print line -end From 98bf4fb23758652bfcda80ccbd63003f7f6a5e46 Mon Sep 17 00:00:00 2001 From: Paul Jacobson <20469645+pajacobson@users.noreply.github.com> Date: Wed, 4 Jan 2023 15:32:03 +1100 Subject: [PATCH 20/22] Remove config file --- test/simulation/sim_configuration.txt | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 test/simulation/sim_configuration.txt diff --git a/test/simulation/sim_configuration.txt b/test/simulation/sim_configuration.txt deleted file mode 100644 index 5fa7931..0000000 --- a/test/simulation/sim_configuration.txt +++ /dev/null @@ -1,8 +0,0 @@ -Device PIC24HJ128GP202 -Hwtool SIM - -set uart1io.output window -set uart1io.uartioenabled true - -# Only Device and HWTool and "set" options should be added to this file. -# sim_test_fixture.rb handles loading, programming and running test code. From 008bcaea5c21a068d049987a031985cccbb5affb Mon Sep 17 00:00:00 2001 From: Paul Jacobson <20469645+pajacobson@users.noreply.github.com> Date: Wed, 4 Jan 2023 15:37:41 +1100 Subject: [PATCH 21/22] Formatting --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e6a3d88..8fb3d1e 100644 --- a/README.md +++ b/README.md @@ -29,8 +29,9 @@ sim_test_fixture.rd now programs and runs the test binary. Changes eliminate the need for "sleep" and "wait" timeouts and breakpoints. MDB is configured using the `:text_fixture:` section of the `project.yml` file. -The first 6 arguments are required, and must be supplied in the given order. -Set options must be supplied as `option value` pairs. + + - The first 6 arguments are required, and must be supplied in the given order. + - Set options must be supplied as `option value` pairs. ```yaml :test_fixture: From 97bc56de2d83f70664d941e1ddf80adf0e4092de Mon Sep 17 00:00:00 2001 From: Paul Jacobson <20469645+pajacobson@users.noreply.github.com> Date: Wed, 4 Jan 2023 15:49:46 +1100 Subject: [PATCH 22/22] Formatting fixup --- README.md | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 8fb3d1e..0a1cced 100644 --- a/README.md +++ b/README.md @@ -24,14 +24,12 @@ Edit: 2022-12-07 * Update Simulation configuration located in test/simulation Edit: 2023-01-04 -- sim_test_fixture.rd -sim_test_fixture.rd now programs and runs the test binary. -Changes eliminate the need for "sleep" and "wait" timeouts and breakpoints. - -MDB is configured using the `:text_fixture:` section of the `project.yml` file. - - - The first 6 arguments are required, and must be supplied in the given order. - - Set options must be supplied as `option value` pairs. +* Vendor directories removed +* sim_test_fixture.rd now programs and runs the test binary +* [UnityDeadLoop](http://www.throwtheswitch.org/build/cross) configuation added +* Fixture configuration moved to `:text_fixture:` section of the `project.yml` file. + - The first 6 arguments are required, and must be supplied in the given order. + - Set options must be supplied as `option value` pairs. ```yaml :test_fixture: