From cde38e47520f44e40120b858e691b4c4405129bc Mon Sep 17 00:00:00 2001 From: Mark VanderVoord Date: Mon, 6 Feb 2023 16:13:08 -0500 Subject: [PATCH 01/35] test against all valid rubies --- .github/workflows/main.yml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a0471ecc..33b1e86f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -15,12 +15,10 @@ jobs: unit-tests: name: "Unit Tests" runs-on: ubuntu-latest + strategy: + matrix: + ruby: ['2.7', '3.0', '3.1', '3.2'] steps: - - uses: ruby/setup-ruby@v1 - with: - ruby-version: '3.0' # Not needed with a .ruby-version file - bundler-cache: true # runs 'bundle install' and caches - # Install Multilib - name: Install Multilib run: | From 0b28344d2384bdd91b28372fe971a09ed1392863 Mon Sep 17 00:00:00 2001 From: Mark VanderVoord Date: Mon, 6 Feb 2023 16:13:29 -0500 Subject: [PATCH 02/35] bump version --- src/cmock.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cmock.h b/src/cmock.h index 45bab182..44792f62 100644 --- a/src/cmock.h +++ b/src/cmock.h @@ -10,8 +10,8 @@ #include "cmock_internals.h" #define CMOCK_VERSION_MAJOR 2 -#define CMOCK_VERSION_MINOR 5 -#define CMOCK_VERSION_BUILD 4 +#define CMOCK_VERSION_MINOR 6 +#define CMOCK_VERSION_BUILD 0 #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 */ From 69258f70347997babcdefaaafc4ab5845faea5f2 Mon Sep 17 00:00:00 2001 From: Mark VanderVoord Date: Mon, 6 Feb 2023 16:24:23 -0500 Subject: [PATCH 03/35] Tweaks to self-test action script and bump version info --- .github/workflows/main.yml | 11 +++++++++-- LICENSE.txt | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 33b1e86f..70a13681 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -22,7 +22,7 @@ jobs: # Install Multilib - name: Install Multilib run: | - sudo apt-get update --assume-yes + sudo apt-get update -qq sudo apt-get install --assume-yes --quiet gcc-multilib # Checks out repository under $GITHUB_WORKSPACE @@ -31,12 +31,19 @@ jobs: with: submodules: recursive + # Setup Ruby Testing Tools to do tests on multiple ruby version + - name: Setup Ruby Testing Tools + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + # Install Ruby Testing Tools - name: Setup Ruby Testing Tools run: | - sudo gem install bundler sudo gem install rspec sudo gem install rubocop -v 0.57.2 + sudo gem install bundler + bundle update bundle install # Run Tests diff --git a/LICENSE.txt b/LICENSE.txt index 98167e40..06f2b75f 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright (c) 2007-14 Mike Karlesky, Mark VanderVoord, Greg Williams +Copyright (c) 2007-23 Mike Karlesky, Mark VanderVoord, Greg Williams Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From bbfaf0425f358f58505710036ed2e0f1bc5cf911 Mon Sep 17 00:00:00 2001 From: Mark VanderVoord Date: Mon, 6 Feb 2023 16:46:48 -0500 Subject: [PATCH 04/35] Handle yaml.load in a way that is ruby version agnostic. --- examples/temp_sensor/rakefile_helper.rb | 10 +++++++++- lib/cmock_config.rb | 6 +++++- test/rakefile_helper.rb | 15 ++++++++++++--- vendor/unity | 2 +- 4 files changed, 27 insertions(+), 6 deletions(-) diff --git a/examples/temp_sensor/rakefile_helper.rb b/examples/temp_sensor/rakefile_helper.rb index ce401d37..fb4a2622 100644 --- a/examples/temp_sensor/rakefile_helper.rb +++ b/examples/temp_sensor/rakefile_helper.rb @@ -9,9 +9,17 @@ module RakefileHelpers C_EXTENSION = '.c'.freeze + def load_yaml(yaml_string) + begin + return YAML.load(yaml_string, aliases: true) + rescue ArgumentError + return YAML.load(yaml_string) + end + end + def load_configuration(config_file) $cfg_file = config_file - $cfg = YAML.load(File.read($cfg_file)) + $cfg = load_yaml(File.read('./targets/' + $cfg_file)) $colour_output = false unless $cfg['colour'] end diff --git a/lib/cmock_config.rb b/lib/cmock_config.rb index c7db9451..16d917bc 100644 --- a/lib/cmock_config.rb +++ b/lib/cmock_config.rb @@ -108,7 +108,11 @@ 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] + begin + return YAML.load_file(yaml_filename, aliases: true)[:cmock] + rescue ArgumentError + return YAML.load_file(yaml_filename)[:cmock] + end end def path(new_path) diff --git a/test/rakefile_helper.rb b/test/rakefile_helper.rb index 3d898905..1ce08655 100644 --- a/test/rakefile_helper.rb +++ b/test/rakefile_helper.rb @@ -19,9 +19,18 @@ module RakefileHelpers C_EXTENSION = '.c' RESULT_EXTENSION = '.result' + def load_yaml(yaml_filename) + yaml_string = File.read(yaml_filename) + begin + return YAML.load(yaml_string, aliases: true) + rescue ArgumentError + return YAML.load(yaml_string) + end + end + def load_configuration(config_file) $cfg_file = config_file - $cfg = YAML.load(File.read('./targets/' + $cfg_file)) + $cfg = load_yaml('./targets/' + $cfg_file) $colour_output = false unless $cfg['colour'] end @@ -252,7 +261,7 @@ def run_system_test_interactions(test_case_files) failure_messages = [] test_case_files.each do |test_case| - tests = (YAML.load_file(test_case))[:systest][:tests][:units] + tests = (load_yaml(test_case))[:systest][:tests][:units] total_tests += tests.size test_file = 'test_' + File.basename(test_case).ext(C_EXTENSION) @@ -367,7 +376,7 @@ def build_and_test_c_files report "----------------\n" errors = false FileList.new("c/*.yml").each do |yaml_file| - test = YAML.load(File.read(yaml_file)) + test = load_yaml(yaml_file) report "\nTesting #{yaml_file.sub('.yml','')}" report "(#{test[:options].join(', ')})" test[:files].each { |f| compile(f, test[:options]) } diff --git a/vendor/unity b/vendor/unity index 4389bab8..5204c1ba 160000 --- a/vendor/unity +++ b/vendor/unity @@ -1 +1 @@ -Subproject commit 4389bab82ee8a4b4631a03be2e07dd5c67dab2d4 +Subproject commit 5204c1bacf37e0c38211d2fbb6d9796e410223f8 From e4ba3be48b7fc071b60c32cd4d8e5dc93b0f072b Mon Sep 17 00:00:00 2001 From: Mark VanderVoord Date: Tue, 7 Feb 2023 08:00:51 -0500 Subject: [PATCH 05/35] newer rubies are confused about the first array argument to some functions when the array is empty... so we name the parameters when we pass them to clear things up. --- test/unit/cmock_generator_main_test.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/unit/cmock_generator_main_test.rb b/test/unit/cmock_generator_main_test.rb index 1a66c0a5..f8b5daed 100644 --- a/test/unit/cmock_generator_main_test.rb +++ b/test/unit/cmock_generator_main_test.rb @@ -550,7 +550,7 @@ def helper_create_header_top_with_opt_includes_form_config_and_plugin(ext) @plugins.expect :run, [" uno"], [:mock_implementation_precheck, function] @plugins.expect :run, [" dos"," tres"], [:mock_implementation, function] - @cmock_generator.create_mock_implementation(output, function) + @cmock_generator.create_mock_implementation(file = output, function = function) assert_equal(expected.join, output.join) end @@ -588,7 +588,7 @@ def helper_create_header_top_with_opt_includes_form_config_and_plugin(ext) @plugins.expect :run, [" uno"], [:mock_implementation_precheck, function] @plugins.expect :run, [" dos"," tres"], [:mock_implementation, function] - @cmock_generator.create_mock_implementation(output, function) + @cmock_generator.create_mock_implementation(file = output, function = function) assert_equal(expected.join, output.join) end @@ -629,7 +629,7 @@ def helper_create_header_top_with_opt_includes_form_config_and_plugin(ext) @plugins.expect :run, [" uno"], [:mock_implementation_precheck, function] @plugins.expect :run, [" dos"," tres"], [:mock_implementation, function] - @cmock_generator.create_mock_implementation(output, function) + @cmock_generator.create_mock_implementation(file = output, function = function) assert_equal(expected.join, output.join) end @@ -667,7 +667,7 @@ def helper_create_header_top_with_opt_includes_form_config_and_plugin(ext) @plugins.expect :run, [" uno"], [:mock_implementation_precheck, function] @plugins.expect :run, [" dos"," tres"], [:mock_implementation, function] - @cmock_generator.create_mock_implementation(output, function) + @cmock_generator.create_mock_implementation(file = output, function = function) assert_equal(expected.join, output.join) end @@ -687,7 +687,7 @@ def helper_create_header_top_with_opt_includes_form_config_and_plugin(ext) output = [] expected = "using namespace ns1;\n" - @cmock_generator.create_using_statement(output, function) + @cmock_generator.create_using_statement(file = output, function = function) assert_equal(expected, output.join) end @@ -707,7 +707,7 @@ def helper_create_header_top_with_opt_includes_form_config_and_plugin(ext) output = [] expected = "using namespace ns1::ns2;\n" - @cmock_generator.create_using_statement(output, function) + @cmock_generator.create_using_statement(file = output, function = function) assert_equal(expected, output.join) end From 6cf8fb9b71b97b6b628c933b666b80a641ccb567 Mon Sep 17 00:00:00 2001 From: Mark VanderVoord Date: Mon, 13 Nov 2023 22:33:16 -0500 Subject: [PATCH 06/35] Fix to incorrect handling of static inlines. Fix to Ruby deprecated interfaces. Fix to keep up with new C standards. --- docs/CMock_Summary.md | 6 +++++- lib/cmock_config.rb | 2 +- test/.ruby-version | 1 + test/rakefile | 2 +- test/rakefile_helper.rb | 2 +- test/system/test_compilation/osek.h | 2 +- test/system/test_interactions/skeleton_update.yml | 2 +- 7 files changed, 11 insertions(+), 6 deletions(-) create mode 100644 test/.ruby-version diff --git a/docs/CMock_Summary.md b/docs/CMock_Summary.md index e63a065c..7c517e72 100644 --- a/docs/CMock_Summary.md +++ b/docs/CMock_Summary.md @@ -608,17 +608,19 @@ from the defaults. We've tried to specify what the defaults are below. - "static inline" - "inline static" - "inline" - - "static" + You can override these patterns, check out :inline_function_patterns. Enabling this feature does require a change in the build system that is using CMock. To understand why, we need to give some more info on how we are handling inline functions internally. + Let's say we want to mock a header called example.h. example.h contains inline functions, we cannot include this header in the mocks or test code if we want to mock the inline functions simply because the inline functions contain an implementation that we want to override in our mocks! + So, to circumvent this, we generate a new header, also named example.h, in the same directory as mock_example.h/c . This newly generated header should/is exactly the same as the original header, @@ -626,11 +628,13 @@ from the defaults. We've tried to specify what the defaults are below. functions declarations. Placing the new header in the same directory as mock_example.h/c ensures that they will include the new header and not the old one. + However, CMock has no control in how the build system is configured and which include paths the test code is compiled with. In order for the test code to also see the newly generated header ,and not the old header with inline functions, the build system has to add the mock folder to the include paths. + Furthermore, we need to keep the order of include paths in mind. We have to set the mock folder before the other includes to avoid the test code including the original header instead of the newly diff --git a/lib/cmock_config.rb b/lib/cmock_config.rb index 16d917bc..b2df4cd4 100644 --- a/lib/cmock_config.rb +++ b/lib/cmock_config.rb @@ -50,7 +50,7 @@ class CMockConfig # - 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*', '(?:static\s*)?(?:__inline__)?__attribute__\s*\([ (]*always_inline[ )]*\)', 'static __inline__'] # Last part (\s*) is just to remove whitespaces (only to prettify the output) + :inline_function_patterns => ['(static\s+inline|inline\s+static)\s*', '(\binline\b)\s*', '(?:static\s*)?(?:__inline__)?__attribute__\s*\([ (]*always_inline[ )]*\)', 'static __inline__'] # Last part (\s*) is just to remove whitespaces (only to prettify the output) }.freeze def initialize(options = nil) diff --git a/test/.ruby-version b/test/.ruby-version new file mode 100644 index 00000000..944880fa --- /dev/null +++ b/test/.ruby-version @@ -0,0 +1 @@ +3.2.0 diff --git a/test/rakefile b/test/rakefile index c57c7153..0169eaae 100644 --- a/test/rakefile +++ b/test/rakefile @@ -140,7 +140,7 @@ namespace :style do end task :clean do - File.delete(".rubocop_todo.yml") if File.exists?(".rubocop_todo.yml") + File.delete(".rubocop_todo.yml") if File.exist?(".rubocop_todo.yml") end end diff --git a/test/rakefile_helper.rb b/test/rakefile_helper.rb index 1ce08655..bffb3add 100644 --- a/test/rakefile_helper.rb +++ b/test/rakefile_helper.rb @@ -66,7 +66,7 @@ def extract_headers(filename) def find_source_file(header, paths) paths.each do |dir| src_file = dir + header.ext(C_EXTENSION) - if (File.exists?(src_file)) + if (File.exist?(src_file)) return src_file end end diff --git a/test/system/test_compilation/osek.h b/test/system/test_compilation/osek.h index f3abe7b5..8db9cb8f 100644 --- a/test/system/test_compilation/osek.h +++ b/test/system/test_compilation/osek.h @@ -242,7 +242,7 @@ void OSEKOSStartupEnable(void); void OSEKOSNop(void); unsigned int OSEKOSV850CheckIsrSwitch(void); void OSEKOSV850InitInterrupts(void); -void OSEKOSV850SetupInterrupts(); +void OSEKOSV850SetupInterrupts(void); void OSEKOSV850SyncContextLoad(OSEKOSSaveType); void OSEKOSV850SyncContextLoadFromIRQ(OSEKOSSaveType); void OSEKOSV850ASyncContextLoad(OSEKOSSaveType); diff --git a/test/system/test_interactions/skeleton_update.yml b/test/system/test_interactions/skeleton_update.yml index 757e8b13..e4031e82 100644 --- a/test/system/test_interactions/skeleton_update.yml +++ b/test/system/test_interactions/skeleton_update.yml @@ -37,7 +37,7 @@ :common: | void setUp(void) {} void tearDown(void) {} - extern int function_d(); + extern int function_d(void); :units: - :pass: TRUE From 097b3ec42a00b264967012ee6186d057a69d84ca Mon Sep 17 00:00:00 2001 From: Mark VanderVoord Date: Wed, 22 Nov 2023 15:02:17 -0500 Subject: [PATCH 07/35] Let's see how we're doing if we only run on Ruby 3.x --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 70a13681..d5c1550d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - ruby: ['2.7', '3.0', '3.1', '3.2'] + ruby: ['3.0', '3.1', '3.2'] steps: # Install Multilib - name: Install Multilib From 32049399b30a18abddcb4eadd4449b1e27a6a348 Mon Sep 17 00:00:00 2001 From: Mark VanderVoord Date: Wed, 22 Nov 2023 15:52:54 -0500 Subject: [PATCH 08/35] Fixes to the temp_sensor example. --- examples/temp_sensor/rakefile_helper.rb | 6 +++--- examples/temp_sensor/src/TemperatureFilter.c | 13 ++++++++----- examples/temp_sensor/{ => targets}/gcc.yml | 0 examples/temp_sensor/{ => targets}/iar_v4.yml | 0 examples/temp_sensor/{ => targets}/iar_v5.yml | 0 .../test/TestTimerInterruptConfigurator.c | 2 +- 6 files changed, 12 insertions(+), 9 deletions(-) rename examples/temp_sensor/{ => targets}/gcc.yml (100%) rename examples/temp_sensor/{ => targets}/iar_v4.yml (100%) rename examples/temp_sensor/{ => targets}/iar_v5.yml (100%) diff --git a/examples/temp_sensor/rakefile_helper.rb b/examples/temp_sensor/rakefile_helper.rb index fb4a2622..99208cdb 100644 --- a/examples/temp_sensor/rakefile_helper.rb +++ b/examples/temp_sensor/rakefile_helper.rb @@ -199,7 +199,7 @@ def run_tests(test_files) next unless header =~ /Mock/ require '../../lib/cmock.rb' - @cmock ||= CMock.new($cfg_file) + @cmock ||= CMock.new('./targets/' + $cfg_file) @cmock.setup_mocks([$cfg['compiler']['source_path'] + header.gsub('Mock', '')]) end @@ -217,7 +217,7 @@ def run_tests(test_files) runner_name = test_base + '_Runner.c' if $cfg['compiler']['runner_path'].nil? runner_path = $cfg['compiler']['build_path'] + runner_name - test_gen = UnityTestRunnerGenerator.new($cfg_file) + test_gen = UnityTestRunnerGenerator.new('./targets/' + $cfg_file) test_gen.run(test, runner_path) else runner_path = $cfg['compiler']['runner_path'] + runner_name @@ -254,7 +254,7 @@ def build_application(main) report 'Building application...' obj_list = [] - load_configuration($cfg_file) + load_configuration('./targets/' + $cfg_file) main_path = $cfg['compiler']['source_path'] + main + C_EXTENSION # Detect dependencies and build required required modules diff --git a/examples/temp_sensor/src/TemperatureFilter.c b/examples/temp_sensor/src/TemperatureFilter.c index 02fc0450..cd2b4a2d 100644 --- a/examples/temp_sensor/src/TemperatureFilter.c +++ b/examples/temp_sensor/src/TemperatureFilter.c @@ -27,13 +27,16 @@ void TemperatureFilter_ProcessInput(float temperature) { if (temperature == +INFINITY || temperature == -INFINITY || - temperature == +NAN || - temperature == -NAN) + temperature != temperature) { + /* Check if +/- Infinity or NaN... reset to -Inf in this instance. */ initialized = FALSE; - temperature = -INFINITY; + temperatureInCelcius = -INFINITY; + } + else + { + /* Otherwise apply our low-pass filter to smooth the values */ + temperatureInCelcius = (temperatureInCelcius * 0.75f) + (temperature * 0.25); } - - temperatureInCelcius = (temperatureInCelcius * 0.75f) + (temperature * 0.25); } } diff --git a/examples/temp_sensor/gcc.yml b/examples/temp_sensor/targets/gcc.yml similarity index 100% rename from examples/temp_sensor/gcc.yml rename to examples/temp_sensor/targets/gcc.yml diff --git a/examples/temp_sensor/iar_v4.yml b/examples/temp_sensor/targets/iar_v4.yml similarity index 100% rename from examples/temp_sensor/iar_v4.yml rename to examples/temp_sensor/targets/iar_v4.yml diff --git a/examples/temp_sensor/iar_v5.yml b/examples/temp_sensor/targets/iar_v5.yml similarity index 100% rename from examples/temp_sensor/iar_v5.yml rename to examples/temp_sensor/targets/iar_v5.yml diff --git a/examples/temp_sensor/test/TestTimerInterruptConfigurator.c b/examples/temp_sensor/test/TestTimerInterruptConfigurator.c index 13c35f44..95265252 100644 --- a/examples/temp_sensor/test/TestTimerInterruptConfigurator.c +++ b/examples/temp_sensor/test/TestTimerInterruptConfigurator.c @@ -35,7 +35,7 @@ void testResetSystemTimeDelegatesTo_Timer_SetSystemTime_Appropriately(void) void testConfigureInterruptShouldSetInterruptHandlerAppropriately(void) { - AT91C_BASE_AIC->AIC_SVR[AT91C_ID_TC0] = (uint32)NULL; + AT91C_BASE_AIC->AIC_SVR[AT91C_ID_TC0] = (uint32)0; Timer_ConfigureInterrupt(); TEST_ASSERT_EQUAL((uint32)Timer_InterruptHandler, AT91C_BASE_AIC->AIC_SVR[AT91C_ID_TC0]); } From a642b1fe4907aa3d9921a45c74e83d4a97484eba Mon Sep 17 00:00:00 2001 From: Mark VanderVoord Date: Wed, 22 Nov 2023 17:40:07 -0500 Subject: [PATCH 09/35] Update to latest Unity and therefore newer Rubocop standards. Tweaked scripts to match latest standards. --- config/production_environment.rb | 2 +- config/test_environment.rb | 2 +- examples/temp_sensor/rakefile.rb | 2 +- examples/temp_sensor/rakefile_helper.rb | 47 +++++++++---------- lib/cmock.rb | 11 +++-- lib/cmock_config.rb | 10 ++-- lib/cmock_file_writer.rb | 8 ++-- lib/cmock_generator.rb | 14 +++--- lib/cmock_generator_plugin_array.rb | 5 +- lib/cmock_generator_plugin_callback.rb | 3 +- lib/cmock_generator_plugin_cexception.rb | 3 +- lib/cmock_generator_plugin_expect_any_args.rb | 3 +- lib/cmock_generator_plugin_ignore.rb | 5 +- ...cmock_generator_plugin_ignore_stateless.rb | 5 +- lib/cmock_generator_utils.rb | 10 ++-- lib/cmock_header_parser.rb | 47 ++++++++++--------- lib/cmock_plugin_manager.rb | 4 +- lib/cmock_unityhelper_parser.rb | 7 +-- scripts/create_makefile.rb | 12 ++--- test/rakefile | 5 +- test/rakefile_helper.rb | 4 ++ vendor/unity | 2 +- 22 files changed, 107 insertions(+), 104 deletions(-) diff --git a/config/production_environment.rb b/config/production_environment.rb index 082b63fd..96d9e304 100644 --- a/config/production_environment.rb +++ b/config/production_environment.rb @@ -8,5 +8,5 @@ [ 'lib' ].each do |dir| - $:.unshift(File.join(__dir__ + '/../', dir)) + $:.unshift(File.join("#{__dir__}//..//", dir)) end diff --git a/config/test_environment.rb b/config/test_environment.rb index aeae3a34..d82f026b 100644 --- a/config/test_environment.rb +++ b/config/test_environment.rb @@ -12,5 +12,5 @@ './vendor/unity/auto/', './test/system/' ].each do |dir| - $:.unshift(File.join(File.expand_path(File.dirname(__FILE__) + '/../'), dir)) + $:.unshift(File.join(File.expand_path("#{File.dirname(__FILE__)}//..//"), dir)) end diff --git a/examples/temp_sensor/rakefile.rb b/examples/temp_sensor/rakefile.rb index 06ab1d51..00d817e4 100644 --- a/examples/temp_sensor/rakefile.rb +++ b/examples/temp_sensor/rakefile.rb @@ -1,4 +1,4 @@ -HERE = __dir__ + '/' +HERE = "#{__dir__}//".freeze require 'rake' require 'rake/clean' diff --git a/examples/temp_sensor/rakefile_helper.rb b/examples/temp_sensor/rakefile_helper.rb index 99208cdb..5a9735bc 100644 --- a/examples/temp_sensor/rakefile_helper.rb +++ b/examples/temp_sensor/rakefile_helper.rb @@ -10,21 +10,19 @@ module RakefileHelpers C_EXTENSION = '.c'.freeze def load_yaml(yaml_string) - begin - return YAML.load(yaml_string, aliases: true) - rescue ArgumentError - return YAML.load(yaml_string) - end + YAML.load(yaml_string, aliases: true) + rescue ArgumentError + YAML.load(yaml_string) end def load_configuration(config_file) $cfg_file = config_file - $cfg = load_yaml(File.read('./targets/' + $cfg_file)) + $cfg = load_yaml(File.read("./targets/#{$cfg_file}")) $colour_output = false unless $cfg['colour'] end def configure_clean - CLEAN.include($cfg['compiler']['build_path'] + '*.*') unless $cfg['compiler']['build_path'].nil? + CLEAN.include("#{$cfg['compiler']['build_path']}*.*") unless $cfg['compiler']['build_path'].nil? end def configure_toolchain(config_file = DEFAULT_CONFIG_FILE) @@ -34,7 +32,7 @@ def configure_toolchain(config_file = DEFAULT_CONFIG_FILE) end def unit_test_files - path = $cfg['compiler']['unit_tests_path'] + 'Test*' + C_EXTENSION + path = $cfg['compiler']['unit_tests_path'] + "Test*#{C_EXTENSION}" path.tr!('\\', '/') FileList.new(path) end @@ -49,7 +47,7 @@ def extract_headers(filename) includes = [] lines = File.readlines(filename) lines.each do |line| - m = line.match(/^\s*#include\s+\"\s*(.+\.[hH])\s*\"/) + m = line.match(/^\s*#include\s+"\s*(.+\.[hH])\s*"/) unless m.nil? includes << m[1] end @@ -95,7 +93,7 @@ def build_compiler_fields end options = squash('', $cfg['compiler']['options']) includes = squash($cfg['compiler']['includes']['prefix'], $cfg['compiler']['includes']['items']) - includes = includes.gsub(/\\ /, ' ').gsub(/\\\"/, '"').gsub(/\\$/, '') # Remove trailing slashes (for IAR) + includes = includes.gsub(/\\ /, ' ').gsub(/\\"/, '"').gsub(/\\$/, '') # Remove trailing slashes (for IAR) { :command => command, :defines => defines, :options => options, :includes => includes } end @@ -120,17 +118,17 @@ def build_linker_fields else squash($cfg['linker']['includes']['prefix'], $cfg['linker']['includes']['items']) end - includes = includes.gsub(/\\ /, ' ').gsub(/\\\"/, '"').gsub(/\\$/, '') # Remove trailing slashes (for IAR) + includes = includes.gsub(/\\ /, ' ').gsub(/\\"/, '"').gsub(/\\$/, '') # Remove trailing slashes (for IAR) { :command => command, :options => options, :includes => includes } end def link_it(exe_name, obj_list) linker = build_linker_fields - cmd_str = "#{linker[:command]}#{linker[:includes]} " + - (obj_list.map { |obj| "#{$cfg['linker']['object_files']['path']}#{obj} " }).join + - $cfg['linker']['bin_files']['prefix'] + ' ' + - $cfg['linker']['bin_files']['destination'] + - exe_name + $cfg['linker']['bin_files']['extension'] + " #{linker[:options]}" + cmd_str = "#{linker[:command]}#{linker[:includes]} " \ + "#{(obj_list.map { |obj| "#{$cfg['linker']['object_files']['path']}#{obj} " }).join}" \ + "#{$cfg['linker']['bin_files']['prefix']} " \ + "#{$cfg['linker']['bin_files']['destination']}" \ + "#{exe_name}#{$cfg['linker']['bin_files']['extension']} #{linker[:options]}" execute(cmd_str) end @@ -140,7 +138,7 @@ def build_simulator_fields command = if $cfg['simulator']['path'].nil? '' else - (tackit($cfg['simulator']['path']) + ' ') + "#{tackit($cfg['simulator']['path'])} " end pre_support = if $cfg['simulator']['pre_support'].nil? '' @@ -190,20 +188,19 @@ def run_tests(test_files) # Build and execute each unit test test_files.each do |test| - obj_list = [] - # Detect dependencies and build required required modules header_list = (extract_headers(test) + ['cmock.h'] + [$cfg[:cmock][:unity_helper_path]]).compact.uniq header_list.each do |header| # create mocks if needed next unless header =~ /Mock/ - require '../../lib/cmock.rb' - @cmock ||= CMock.new('./targets/' + $cfg_file) + require '../../lib/cmock' + @cmock ||= CMock.new(".//targets//#{$cfg_file}") @cmock.setup_mocks([$cfg['compiler']['source_path'] + header.gsub('Mock', '')]) end # compile all mocks + obj_list = [] header_list.each do |header| # compile source file header if it exists src_file = find_source_file(header, include_dirs) @@ -214,10 +211,10 @@ def run_tests(test_files) # Build the test runner (generate if configured to do so) test_base = File.basename(test, C_EXTENSION) - runner_name = test_base + '_Runner.c' + runner_name = "#{test_base}_Runner.c" if $cfg['compiler']['runner_path'].nil? - runner_path = $cfg['compiler']['build_path'] + runner_name - test_gen = UnityTestRunnerGenerator.new('./targets/' + $cfg_file) + runner_path = "#{$cfg['compiler']['build_path']}#{runner_name}" + test_gen = UnityTestRunnerGenerator.new(".//targets//#{$cfg_file}") test_gen.run(test, runner_path) else runner_path = $cfg['compiler']['runner_path'] + runner_name @@ -254,7 +251,7 @@ def build_application(main) report 'Building application...' obj_list = [] - load_configuration('./targets/' + $cfg_file) + load_configuration(".//targets//#{$cfg_file}") main_path = $cfg['compiler']['source_path'] + main + C_EXTENSION # Detect dependencies and build required required modules diff --git a/lib/cmock.rb b/lib/cmock.rb index 72f86418..b889f5e1 100644 --- a/lib/cmock.rb +++ b/lib/cmock.rb @@ -59,7 +59,7 @@ def option_maker(options, key, val) options ||= {} options[key.to_sym] = if val.chr == ':' - val[1..-1].to_sym + val[1..].to_sym elsif val.include? ';' val.split(';') elsif val == 'true' @@ -87,15 +87,16 @@ def option_maker(options, key, val) options = {} filelist = [] ARGV.each do |arg| - if arg =~ /^-o\"?([a-zA-Z0-9@._\\\/:\s]+)\"?/ + case arg + when /^-o"?([a-zA-Z0-9@._\\\/:\s]+)"?/ options.merge! CMockConfig.load_config_file_from_yaml(arg.gsub(/^-o/, '')) - elsif arg == '--skeleton' + when '--skeleton' options[:skeleton] = true - elsif arg =~ /^--strippables=\"?(.*)\"?/ + when /^--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 + when /^--([a-zA-Z0-9._\\\/:\s]+)="?([a-zA-Z0-9._\-\\\/:\s;]*)"?/x options = option_maker(options, Regexp.last_match(1), Regexp.last_match(2)) else diff --git a/lib/cmock_config.rb b/lib/cmock_config.rb index b2df4cd4..c811090d 100644 --- a/lib/cmock_config.rb +++ b/lib/cmock_config.rb @@ -63,13 +63,13 @@ def initialize(options = nil) # do some quick type verification %i[plugins attributes treat_as_void].each do |opt| - unless options[opt].class == Array + unless options[opt].instance_of?(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) + unless options[opt].nil? || options[opt].instance_of?(Array) options[opt] = [] puts "WARNING: :#{opt} should be an array." unless options[:verbosity] < 1 end @@ -109,9 +109,9 @@ def self.load_config_file_from_yaml(yaml_filename) require 'yaml' require 'fileutils' begin - return YAML.load_file(yaml_filename, aliases: true)[:cmock] + YAML.load_file(yaml_filename, aliases: true)[:cmock] rescue ArgumentError - return YAML.load_file(yaml_filename)[:cmock] + YAML.load_file(yaml_filename)[:cmock] end end @@ -123,7 +123,7 @@ 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 + unity_helper + "\n#{File.new(filename).read}" end end diff --git a/lib/cmock_file_writer.rb b/lib/cmock_file_writer.rb index f30c44b2..5793f298 100644 --- a/lib/cmock_file_writer.rb +++ b/lib/cmock_file_writer.rb @@ -14,14 +14,14 @@ def initialize(config) 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}") + 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}" + 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 @@ -31,7 +31,7 @@ def create_file(filename, subdir) 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}" + full_file_name = "#{@config.skeleton_path}/#{"#{subdir}/" if subdir}#{filename}" File.open(full_file_name, 'a') do |file| yield(file, filename) end diff --git a/lib/cmock_generator.rb b/lib/cmock_generator.rb index c3896dfb..cc05631e 100644 --- a/lib/cmock_generator.rb +++ b/lib/cmock_generator.rb @@ -117,7 +117,7 @@ def create_mock_header_file(mock_project) end def create_mock_source_file(mock_project) - @file_writer.create_file(mock_project[:mock_name] + '.c', mock_project[:folder]) do |file, filename| + @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) @@ -132,9 +132,9 @@ def create_mock_source_file(mock_project) end def create_skeleton_source_file(mock_project) - filename = "#{@config.mock_path}/#{@subdir + '/' if @subdir}#{mock_project[:module_name]}.c" + filename = "#{@config.mock_path}/#{"#{@subdir}/" if @subdir}#{mock_project[:module_name]}.c" existing = File.exist?(filename) ? File.read(filename) : '' - @file_writer.create_file(mock_project[:module_name] + '.c', @subdir) do |file, fullname| + @file_writer.create_file("#{mock_project[:module_name]}.c", @subdir) do |file, fullname| blank_project = mock_project.clone blank_project[:parsed_stuff] = { :functions => [] } if existing.empty? @@ -156,7 +156,7 @@ def create_mock_header_header(file, _filename, mock_project) 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" + 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? @@ -303,7 +303,7 @@ def create_mock_implementation(file, function) (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| @@ -364,7 +364,7 @@ def create_function_skeleton(file, function, existing) (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? decl = "#{function_mod_and_rettype} #{function[:name]}(#{args_string})" @@ -374,7 +374,7 @@ def create_function_skeleton(file, function, existing) 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 << " return (#{function[:return][:type]})0;\n" unless function[:return][:void?] file << "}\n\n" end end diff --git a/lib/cmock_generator_plugin_array.rb b/lib/cmock_generator_plugin_array.rb index a9864ab7..249a622f 100644 --- a/lib/cmock_generator_plugin_array.rb +++ b/lib/cmock_generator_plugin_array.rb @@ -7,6 +7,7 @@ class CMockGeneratorPluginArray attr_reader :priority attr_accessor :config, :utils, :unity_helper, :ordered + def initialize(config, utils) @config = config @ptr_handling = @config.when_ptr @@ -31,10 +32,10 @@ def mock_function_declarations(function) 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" \ + "#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" \ + "#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 diff --git a/lib/cmock_generator_plugin_callback.rb b/lib/cmock_generator_plugin_callback.rb index 6ba8e9bd..db717220 100644 --- a/lib/cmock_generator_plugin_callback.rb +++ b/lib/cmock_generator_plugin_callback.rb @@ -6,8 +6,7 @@ class CMockGeneratorPluginCallback attr_accessor :include_count - attr_reader :priority - attr_reader :config, :utils + attr_reader :priority, :config, :utils def initialize(config, utils) @config = config diff --git a/lib/cmock_generator_plugin_cexception.rb b/lib/cmock_generator_plugin_cexception.rb index 7e2d7b62..28f9eb5a 100644 --- a/lib/cmock_generator_plugin_cexception.rb +++ b/lib/cmock_generator_plugin_cexception.rb @@ -5,8 +5,7 @@ # ========================================== class CMockGeneratorPluginCexception - attr_reader :priority - attr_reader :config, :utils + attr_reader :priority, :config, :utils def initialize(config, utils) @config = config diff --git a/lib/cmock_generator_plugin_expect_any_args.rb b/lib/cmock_generator_plugin_expect_any_args.rb index 0fc88e12..3451fbaa 100644 --- a/lib/cmock_generator_plugin_expect_any_args.rb +++ b/lib/cmock_generator_plugin_expect_any_args.rb @@ -5,8 +5,7 @@ # ========================================== class CMockGeneratorPluginExpectAnyArgs - attr_reader :priority - attr_reader :config, :utils + attr_reader :priority, :config, :utils def initialize(config, utils) @config = config diff --git a/lib/cmock_generator_plugin_ignore.rb b/lib/cmock_generator_plugin_ignore.rb index b292f3d4..bbb7c145 100644 --- a/lib/cmock_generator_plugin_ignore.rb +++ b/lib/cmock_generator_plugin_ignore.rb @@ -5,8 +5,7 @@ # ========================================== class CMockGeneratorPluginIgnore - attr_reader :priority - attr_reader :config, :utils + attr_reader :priority, :config, :utils def initialize(config, utils) @config = config @@ -45,7 +44,7 @@ def mock_implementation_precheck(function) 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 << " #{@utils.code_assign_argument_quickly("Mock.#{function[:name]}_FinalReturn", retval)}" unless retval[:void?] lines << " return cmock_call_instance->ReturnVal;\n }\n" end lines diff --git a/lib/cmock_generator_plugin_ignore_stateless.rb b/lib/cmock_generator_plugin_ignore_stateless.rb index 9196edea..bdf9594b 100644 --- a/lib/cmock_generator_plugin_ignore_stateless.rb +++ b/lib/cmock_generator_plugin_ignore_stateless.rb @@ -5,8 +5,7 @@ # ========================================== class CMockGeneratorPluginIgnoreStateless - attr_reader :priority - attr_reader :config, :utils + attr_reader :priority, :config, :utils def initialize(config, utils) @config = config @@ -45,7 +44,7 @@ def mock_implementation_precheck(function) 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 << " #{@utils.code_assign_argument_quickly("Mock.#{function[:name]}_FinalReturn", retval)}" unless retval[:void?] lines << " return cmock_call_instance->ReturnVal;\n }\n" end lines diff --git a/lib/cmock_generator_utils.rb b/lib/cmock_generator_utils.rb index ecbc37e5..77da6d0c 100644 --- a/lib/cmock_generator_utils.rb +++ b/lib/cmock_generator_utils.rb @@ -63,7 +63,7 @@ def code_add_base_expectation(func_name, global_ordering_supported = true) 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->Expected_#{arg[:name]}_Depth = #{arg[:name]}_Depth;\n" if @arrays && depth.instance_of?(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 @@ -88,13 +88,13 @@ def code_add_argument_loader(function) 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)) } + + "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) } + + "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 diff --git a/lib/cmock_header_parser.rb b/lib/cmock_header_parser.rb index 15224349..d41deefd 100644 --- a/lib/cmock_header_parser.rb +++ b/lib/cmock_header_parser.rb @@ -79,7 +79,7 @@ def remove_nested_pairs_of_braces(source) r = '\\{([^\\{\\}]*|\\g<0>)*\\}' source.gsub!(/#{r}/m, '{ }') else - while source.gsub!(/\{[^\{\}]*\{[^\{\}]*\}[^\{\}]*\}/m, '{ }') + while source.gsub!(/\{[^{}]*\{[^{}]*\}[^{}]*\}/m, '{ }') end end @@ -94,11 +94,12 @@ def count_number_of_pairs_of_braces_in_function(source) total_pairs = 0 source.each_char do |c| - if c == '{' + case c + when '{' curr_level += 1 total_pairs += 1 is_function_start_found = true - elsif c == '}' + when '}' curr_level -= 1 end @@ -116,14 +117,14 @@ def count_number_of_pairs_of_braces_in_function(source) # +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 + 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/ + 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 @@ -170,7 +171,7 @@ def transform_inline_functions(source) 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]?)/, '') + stripped_post_match = inline_function_match.post_match.sub(/\A(.*\n?)/, '') inspected_source += stripped_pre_match source = stripped_post_match next @@ -220,7 +221,7 @@ def import_source(source, parse_project, cpp = false) # 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*;/) + void_types = source.scan(/typedef\s+(?:\(\s*)?void(?:\s*\))?\s+(\w+)\s*;/) if void_types @local_as_void += void_types.flatten.uniq.compact end @@ -245,18 +246,18 @@ def import_source(source, parse_project, cpp = false) source.gsub!(/__attribute(?:__)?\s*\(\(+.*\)\)+/, '') # remove preprocessor statements and extern "C" - source.gsub!(/extern\s+\"C\"\s*\{/, '') + source.gsub!(/extern\s+"C"\s*\{/, '') source.gsub!(/^\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 + 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!(/\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 @@ -265,7 +266,7 @@ def import_source(source, parse_project, cpp = false) 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| + 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)});" @@ -282,7 +283,7 @@ def import_source(source, parse_project, cpp = false) end # remove function definitions by stripping off the arguments right now - source.gsub!(/\([^\)]*\)\s*\{[^\}]*\}/m, ';') + 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 @@ -295,7 +296,7 @@ def import_source(source, parse_project, cpp = false) 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 + 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 @@ -484,7 +485,7 @@ def clean_args(arg_list, parse_project) arg_list.gsub!(/\*(\w)/, '* \1') # scan argument list for function pointers and replace them with custom types - arg_list.gsub!(/([\w\s\*]+)\(+([\w\s]*)\*[\*\s]*([\w\s]*)\s*\)+\s*\(((?:[\w\s\*]*,?)*)\s*\)*/) do |_m| + arg_list.gsub!(/([\w\s*]+)\(+([\w\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 funcdecl = Regexp.last_match(2).strip @@ -504,7 +505,7 @@ def clean_args(arg_list, parse_project) 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| + 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 @@ -574,13 +575,13 @@ def parse_declaration(parse_project, declaration, namespace = [], classname = ni :const_ptr? => parsed[:const_ptr?] || false } # remove default argument statements from mock definitions - args.gsub!(/=\s*[a-zA-Z0-9_\.]+\s*/, ' ') + 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]*\.\.\./, '') + args = if args =~ /,[\w\s]*\.\.\./ + args.gsub!(/,[\w\s]*\.\.\./, '') else 'void' end @@ -608,7 +609,7 @@ def parse_declaration(parse_project, declaration, namespace = [], classname = ni def prototype_inspect_hash(hash) pairs = [] - hash.each_pair { |name, value| pairs << ":#{name} => #{"'" if value.class == String}#{value}#{"'" if value.class == String}" } + hash.each_pair { |name, value| pairs << ":#{name} => #{"'" if value.instance_of?(String)}#{value}#{"'" if value.instance_of?(String)}" } "{#{pairs.join(', ')}}" end @@ -617,11 +618,11 @@ def prototype_inspect_array_of_hashes(array) array.each { |hash| hashes << prototype_inspect_hash(hash) } case array.size when 0 - return '[]' + '[]' when 1 - return "[#{hashes[0]}]" + "[#{hashes[0]}]" else - return "[\n #{hashes.join("\n ")}\n ]\n" + "[\n #{hashes.join("\n ")}\n ]\n" end end end diff --git a/lib/cmock_plugin_manager.rb b/lib/cmock_plugin_manager.rb index 342014e2..c92f7c40 100644 --- a/lib/cmock_plugin_manager.rb +++ b/lib/cmock_plugin_manager.rb @@ -12,7 +12,7 @@ def initialize(config, utils) 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) + 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 } @@ -27,7 +27,7 @@ def run(method, args = nil) 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 } + lower_case_and_underscored_word.gsub(/\/(.?)/) { "::#{Regexp.last_match(1).upcase}" }.gsub(/(^|_)(.)/) { Regexp.last_match(2).upcase } end def self.mutex diff --git a/lib/cmock_unityhelper_parser.rb b/lib/cmock_unityhelper_parser.rb index 57f2aeb1..64fc0814 100644 --- a/lib/cmock_unityhelper_parser.rb +++ b/lib/cmock_unityhelper_parser.rb @@ -38,12 +38,13 @@ def map_c_types if ctype.is_a?(Symbol) raise ":treat_as expects a list of identifier: identifier mappings, but got a symbol: #{ctype}. Check the indentation in your project.yml" end + 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 @@ -58,7 +59,7 @@ def import_source 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(',') + '\)') + 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] @@ -67,7 +68,7 @@ def import_source 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(',') + '\)') + 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] diff --git a/scripts/create_makefile.rb b/scripts/create_makefile.rb index 56cb78e9..80ffad15 100644 --- a/scripts/create_makefile.rb +++ b/scripts/create_makefile.rb @@ -20,7 +20,7 @@ MOCK_PREFIX = ENV.fetch('TEST_MOCK_PREFIX', 'mock_') MOCK_SUFFIX = ENV.fetch('TEST_MOCK_SUFFIX', '') TEST_MAKEFILE = ENV.fetch('TEST_MAKEFILE', File.join(TEST_BUILD_DIR, 'MakefileTestSupport')) -MOCK_MATCHER = /#{MOCK_PREFIX}[A-Za-z_][A-Za-z0-9_\-\.]+#{MOCK_SUFFIX}/ +MOCK_MATCHER = /#{MOCK_PREFIX}[A-Za-z_][A-Za-z0-9_\-.]+#{MOCK_SUFFIX}/ [TEST_BUILD_DIR, OBJ_DIR, RUNNERS_DIR, MOCKS_DIR, TEST_BIN_DIR].each do |dir| FileUtils.mkdir_p dir @@ -83,7 +83,7 @@ def reject_mock_files(file) runner_source = File.join(RUNNERS_DIR, "runner_#{module_name}.c") runner_obj = File.join(OBJ_DIR, "runner_#{module_name}.o") test_bin = File.join(TEST_BIN_DIR, module_name) - test_results = File.join(TEST_BIN_DIR, module_name + '.testresult') + test_results = File.join(TEST_BIN_DIR, "#{module_name}.testresult") cfg = { src: test, @@ -151,7 +151,7 @@ def reject_mock_files(file) all_headers_to_mock += headers_to_mock mock_objs = headers_to_mock.map do |hdr| mock_name = MOCK_PREFIX + File.basename(hdr, '.*') - File.join(MOCKS_DIR, mock_name + '.o') + File.join(MOCKS_DIR, "#{mock_name}.o") end all_headers_to_mock.uniq! @@ -178,8 +178,8 @@ def reject_mock_files(file) all_headers_to_mock.each do |hdr| mock_name = MOCK_PREFIX + File.basename(hdr, '.*') mock_header = File.join(MOCKS_DIR, mock_name + File.extname(hdr)) - mock_src = File.join(MOCKS_DIR, mock_name + '.c') - mock_obj = File.join(MOCKS_DIR, mock_name + '.o') + mock_src = File.join(MOCKS_DIR, "#{mock_name}.c") + mock_obj = File.join(MOCKS_DIR, "#{mock_name}.o") mkfile.puts "#{mock_src}: #{hdr}" mkfile.puts "\t@CMOCK_DIR=${CMOCK_DIR} ruby ${CMOCK_DIR}/scripts/create_mock.rb #{hdr}" @@ -198,6 +198,6 @@ def reject_mock_files(file) mkfile.puts '' # Create target to run all tests - mkfile.puts "test: #{test_targets.map { |t| t + '.testresult' }.join(' ')} test_summary" + mkfile.puts "test: #{test_targets.map { |t| "#{t}.testresult" }.join(' ')} test_summary" mkfile.puts '' end diff --git a/test/rakefile b/test/rakefile index 0169eaae..fe64f5df 100644 --- a/test/rakefile +++ b/test/rakefile @@ -117,7 +117,10 @@ end namespace :style do desc "Check style" task :check do - report "\nVERIFYING RUBY STYLE" + report "\n" + report "--------------------\n" + report "VERIFYING RUBY STYLE\n" + report "--------------------\n" report execute("rubocop ../lib ../examples ../config ../scripts --config ../vendor/unity/test/.rubocop.yml", true) report "Styling Ruby:PASS" end diff --git a/test/rakefile_helper.rb b/test/rakefile_helper.rb index bffb3add..bbe3eb96 100644 --- a/test/rakefile_helper.rb +++ b/test/rakefile_helper.rb @@ -396,6 +396,10 @@ def build_and_test_c_files end def run_examples() + report "\n" + report "-----------------\n" + report "VALIDATE EXAMPLES\n" + report "-----------------\n" [ "cd #{File.join("..","examples","make_example")} && make clean && make setup && make test", "cd #{File.join("..","examples","temp_sensor")} && rake ci" ].each do |cmd| diff --git a/vendor/unity b/vendor/unity index 5204c1ba..bf560290 160000 --- a/vendor/unity +++ b/vendor/unity @@ -1 +1 @@ -Subproject commit 5204c1bacf37e0c38211d2fbb6d9796e410223f8 +Subproject commit bf560290f6020737eafaa8b5cbd2177c3956c03f From 4f73b406984c53a264ec5db573ab0d62d23e9998 Mon Sep 17 00:00:00 2001 From: Mark VanderVoord Date: Wed, 22 Nov 2023 19:47:19 -0500 Subject: [PATCH 10/35] Bump to the latest rubocop --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d5c1550d..a9bf8b7e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -41,7 +41,7 @@ jobs: - name: Setup Ruby Testing Tools run: | sudo gem install rspec - sudo gem install rubocop -v 0.57.2 + sudo gem install rubocop -v 1.57.2 sudo gem install bundler bundle update bundle install From c2e3c742baf8eefef2cbdcb82a4717532ee5fff5 Mon Sep 17 00:00:00 2001 From: Mark VanderVoord Date: Wed, 22 Nov 2023 20:05:20 -0500 Subject: [PATCH 11/35] Fix test for const feature of return-thru-pointer --- test/unit/cmock_generator_plugin_return_thru_ptr_test.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/unit/cmock_generator_plugin_return_thru_ptr_test.rb b/test/unit/cmock_generator_plugin_return_thru_ptr_test.rb index 05ecdeec..374caa1f 100644 --- a/test/unit/cmock_generator_plugin_return_thru_ptr_test.rb +++ b/test/unit/cmock_generator_plugin_return_thru_ptr_test.rb @@ -144,14 +144,14 @@ def void_ptr_func_expect " Spruce_CMockReturnMemThruPtr_pork(__LINE__, pork, cmock_len * sizeof(*pork))\n" + "#define Spruce_ReturnMemThruPtr_pork(pork, cmock_size)" + " Spruce_CMockReturnMemThruPtr_pork(__LINE__, pork, cmock_size)\n" + - "void Spruce_CMockReturnMemThruPtr_pork(UNITY_LINE_TYPE cmock_line, void* pork, size_t cmock_size);\n" + + "void Spruce_CMockReturnMemThruPtr_pork(UNITY_LINE_TYPE cmock_line, void const* pork, size_t cmock_size);\n" + "#define Spruce_ReturnThruPtr_salad(salad)" + " Spruce_CMockReturnMemThruPtr_salad(__LINE__, salad, sizeof(*salad))\n" + "#define Spruce_ReturnArrayThruPtr_salad(salad, cmock_len)" + " Spruce_CMockReturnMemThruPtr_salad(__LINE__, salad, cmock_len * sizeof(*salad))\n" + "#define Spruce_ReturnMemThruPtr_salad(salad, cmock_size)" + " Spruce_CMockReturnMemThruPtr_salad(__LINE__, salad, cmock_size)\n" + - "void Spruce_CMockReturnMemThruPtr_salad(UNITY_LINE_TYPE cmock_line, MY_FANCY_VOID* salad, size_t cmock_size);\n" + "void Spruce_CMockReturnMemThruPtr_salad(UNITY_LINE_TYPE cmock_line, MY_FANCY_VOID const* salad, size_t cmock_size);\n" returned = @cmock_generator_plugin_return_thru_ptr.mock_function_declarations(@void_ptr_func) assert_equal(expected, returned) From 95d29ee087692d1077ef0e93e267bb78cd38e3f2 Mon Sep 17 00:00:00 2001 From: Mark VanderVoord Date: Wed, 22 Nov 2023 23:59:19 -0500 Subject: [PATCH 12/35] Add part of our new "standard" documentation for status! woo! --- README.md | 3 + docs/CMockChangeLog.md | 166 +++++++++++++++++++++++++++++++++++++++ docs/CMockKnownIssues.md | 13 +++ docs/CMock_Summary.md | 8 +- 4 files changed, 187 insertions(+), 3 deletions(-) create mode 100644 docs/CMockChangeLog.md create mode 100644 docs/CMockKnownIssues.md diff --git a/README.md b/README.md index c9180122..16d10adf 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,9 @@ useful and usable mock interfaces for unit testing. Give it a try! If you don't care to manage unit testing builds yourself, consider checking out Ceedling, a test-centered build manager for unit testing C code. + - [Known Issues](docs/CMockKnownIssues.md) + - [Change Log](docs/CMockChangeLog.md) + Getting Started ================ diff --git a/docs/CMockChangeLog.md b/docs/CMockChangeLog.md new file mode 100644 index 00000000..104208a2 --- /dev/null +++ b/docs/CMockChangeLog.md @@ -0,0 +1,166 @@ +# CMock - Change Log + +## A Note + +This document captures significant features and fixes to the CMock project core source files +and scripts. More detail can be found in the history on Github. + +This project is now tracking changes in more detail. Previous releases get less detailed as +we move back in histroy. + +Prior to 2012, the project was hosted on SourceForge.net +Prior to 2008, the project was an internal project and not released to the public. + +## Log + +### CMock 2.6.0 () + +New Features: + + - Reintroduced option to run CMock without setjmp (slightly limited) + - Significant speed improvements to parsing + +Significant Bugfixes: + + - Make return-thru-pointer calls const + - Fix handling of static inlines + - Fix some situations where parenthetical statements were misinterpreted as functions + - Fix error in skeleton creation + - Improvements towards making generated code fully C-compliant and warning free + +Other: + + - Improve error message wording where possible + - Improve documentation + - Updated to Ruby 3.0 - 3.3 + - Reintroduce matrix testing across multiple Ruby versions + +### CMock 2.5.3 (January 2021) + +New Features: + + - Support mocks in sub-folders + - Improved handling of static and inline functions + - Stateless Ignore plugin added + +Significant Bugfixes: + + - Allow setting values to empty at command prompt + - Improvements towards making generated code fully C-compliant and warning free + +Other: + + - Really basic mocking of cpp files (like C files with extern C) + +### CMock 2.5.2 (May 2020) + +Significant Bugfixes: + + - Fix whitespace errors + - Fix Stop Ignore + +### CMock 2.5.1 (April 2020) + +New Features: + + - Add StopIgnore function to Ignore Plugin + - Add ability to generate skeleton from a header. + - Inline functions now have option to remove and mock (with Ceedling's help) + +Significant Bugfixes: + + - Convert internal handling of bools to chars from ints for memory savings + - Convert CMOCK_MEM_INDEX_TYPE default type to size_t + - Switch to old-school comments for supporting old C compilers + - Significant improvements to handling array length expressions + - Significant improvements to our "C parser" + - Added brace-pair counting to improve parsing + - Fixed error when `:unity_helper_path` is relative + +Other: + + - Improve documentation + - Optimize speed for pass case, particularly in `_verify()` functions + - Increased depth of unit and system tests + +### CMock 2.5.0 (October 2019) + +New Features: + + - New memory bounds checking. + - New memory alignment algorithm. + - Add `ExpectAnyArgs` plugin + - Divided `CVallback` from `Stub` functionality so we can do both. + - Improved wording of failure messages. + - Added `:treat_as_array` configuration option + +Significant Bugfixes: + + - Fixed bug where `CMock_Guts_MemBytesUsed()` didn't always return `0` before usage + - Fixed bug which sometimes got `CMOCK_MEM_ALIGN` wrong + - Fixed bug where `ExpectAnyArgs` was generated for functions without args. + - Better handling of function pointers + +Other: + + - `void*` now tested as bytewise array comparison. + - Documentation fixes, particularly to examples. + - Added `resetTest` to documentation + - New handling of messaging to greatly reduce memory footprint + +### CMock 2.4.6 (November 2017) + +Significant Bugfixes: + + - Fixed critical bug when running dynamic memory. + +### CMock 2.4.5 (September 2017) + +New Features: + + - Simple threading of mocks introduced. + +Significant Bugfixes: + + - Improvements to handling pointer const arguments. + - Treat `char*` separately from an array of bytes. + - Fixed handling of string arguments. + - Preserve `const` in all arguments. + - Fixed race condition when `require`ing plugins + +Other: + + - Expand docs on `strict_mock_calling` + +### CMock 2.4.4 (April 2017) + +New Features: + + - Add `INCLUDE_PATH` option for specifying source + +Significant Bugfixes: + + - Parsing improvements related to braces, brackets, and parenthesis + - `ReturnThruPtr` checks destination not null before copying data. + - Stub overrides Ignore + - Improvements to guessing memory alignment based on datatypes + +Other: + + - Reorganize testing into subdirectory to not clutter for new users + - Docs switching to markdown from pdf + +### CMock 2.4.3 (October 2016) + +New Features: + + - Support multiple helper header files. + - Add ability to use `weak` symbols if compiler supports it + - Add mock suffix option in addition to mock prefix. + +Significant Bugfixes: + + - Improved UNICODE support + + + diff --git a/docs/CMockKnownIssues.md b/docs/CMockKnownIssues.md new file mode 100644 index 00000000..8a9dea77 --- /dev/null +++ b/docs/CMockKnownIssues.md @@ -0,0 +1,13 @@ +# CMock - Known Issues + +## A Note + +This project will do its best to keep track of significant bugs that might effect your usage of this +project and its supporting scripts. A more detailed and up-to-date list for cutting edge CMock can +be found on our Github repository. + +## Issues + + - Able to parse most C header files without preprocessor needs, but when handling headers with significant preprocessor usage (#ifdefs, etc), it can get confused + - Multi-dimensional arrays currently simplified to single dimensional arrays of the full size + - Incomplete support for VarArgs diff --git a/docs/CMock_Summary.md b/docs/CMock_Summary.md index 7c517e72..75259381 100644 --- a/docs/CMock_Summary.md +++ b/docs/CMock_Summary.md @@ -1,10 +1,12 @@ CMock: A Summary ================ -*[ThrowTheSwitch.org](http://throwtheswitch.org)* +*[ThrowTheSwitch.org](http://throwtheswitch.org)* *This documentation is released under a Creative Commons 3.0 Attribution Share-Alike License* + - [Known Issues](docs/CMockKnownIssues.md) + - [Change Log](docs/CMockChangeLog.md) What Exactly Are We Talking About Here? --------------------------------------- @@ -61,7 +63,7 @@ call DoesSomething enough, or too much, or with the wrong arguments, or in the wrong order. CMock is based on Unity, which it uses for all internal testing. -It uses Ruby to do all the main work (versions 2.0.0 and above). +It uses Ruby to do all the main work (versions 3.0.0 and above). Installing @@ -77,7 +79,7 @@ have it. You can prove it by typing the following: If it replied in a way that implies ignorance, then you're going to need to install it. You can go to [ruby-lang](https://ruby-lang.org) to get the latest version. You're also going to need to do that if it -replied with a version that is older than 2.0.0. Go ahead. We'll wait. +replied with a version that is older than 3.0.0. Go ahead. We'll wait. Once you have Ruby, you have three options: From cac4907c27adc074a25e3f277dd25c06c5e8a766 Mon Sep 17 00:00:00 2001 From: Mark VanderVoord Date: Wed, 29 Nov 2023 11:44:06 -0500 Subject: [PATCH 13/35] Add Argument Validation documentation, because it's a common question. --- docs/CMock_ArgumentValidation.md | 274 +++++++++++++++++++++++++++++++ docs/CMock_Summary.md | 5 +- 2 files changed, 278 insertions(+), 1 deletion(-) create mode 100644 docs/CMock_ArgumentValidation.md diff --git a/docs/CMock_ArgumentValidation.md b/docs/CMock_ArgumentValidation.md new file mode 100644 index 00000000..8fd945e8 --- /dev/null +++ b/docs/CMock_ArgumentValidation.md @@ -0,0 +1,274 @@ +CMock: Argument Validation +========================== + +Much of the power of CMock comes from its ability to automatically +validate that the arguments passed to mocked functions are the +values that were expected to be passed. CMock puts a lot of effort +into guessing how the user would most like to see those values +compared, and then represented when failures are encountered. + +Like Unity, CMock follows a philosophy of making its best guesses, +and then allowing the user to explicity specify any features that +they would like to change or customize. + +Option 1: Common Types +---------------------- + +First, if you're dealing with C's standard types, there is nothing +further you need to do. CMock will choose an appropriate assertion +from Unity's list of assertions and will perform the comparison and +display using that. For example, if you specify a `short`, then it's +very likely CMock will compare using `TEST_ASSERT_EQUAL_INT16`. For +unsigned values, it assumes you'd like them displayed in hex. Are you +interested in comparing a `const char*`? That would be Unity's +string comparison. + +What if you have some other type of pointer? If you've instructed +CMock to compare pointers, it'll use `TEST_ASSERT_EQUAL_PTR`. +Otherwise it'll use dereference the value being pointed at and +compare that for you. (Read more about the Array plugin for more +details on how this all works). The TYPE being pointed to follows the +same rules as the those above... so if they're common types, for example +`unsigned char*`, then CMock will choose to compare using the +logical assertion (in this case `TEST_ASSERT_EQUAL_HEX8`). + +A quick note about floating point types: we're calling the assertions +`TEST_ASSERT_EQUAL_FLOAT` (for example), but don't worry... these +assertions are actually checking to make sure that the values are +"incredibly close" to the desired value instead of identical. This +is because many numbers can be represented in multiple ways when +using floating point. These differences are out of the control of +the user, for the most part. You can ready more about this in the +Unity documentation if you're interested in the details. + +Option 1b: The Fallback Plan +---------------------------- + +So what happens when CMock doesn't recognize the type being used? +This will happen for any custom types being used. What constitutes +a custom type? + + - You've used `#define` to create an alias for a standard type + - You've used `typedef` to create an alias for a standard type + - You've created an `enum` type + - You've created a `union` type + - You've created a `struct` type + - You're working with a function pointer + + When CMock doesn't recognize the type as a standard type, (and + assuming you don't have a better option specified, as any of the + options below), it will fall back to performing a memory + comparison using `TEST_ASSERT_EQUAL_MEMORY`. For the most part, + this is effective, but the reported failures are not terribly + descriptive. + + **WARNING:** There is one important instance where this fallback method + doesn't work at all. If the custom type is a `struct` and that + struct isn't packed, then it's possible you can get false failures + when the unused bytes between fields differ. For an unpacked struct, + it's important that you either use option 3 or 4 below, or ignore that + particular argument (and possibly test it manually yourself). + +Option 2: Treat-As +------------------ + +CMock maintains a list of non-standard types which are basically +aliases of standard types. For example, a common shorthand for +a single-byte unsigned integer might be `u8` or `U8` or `UNIT8`. +Any of these can simply be mapped to the standard +`TEST_ASSERT_EQUAL_HEX8`. + +While CMock has its own list of `:treat_as` mappings, you can +add your own pairings to this list. This works especially well for +the following types: + + - aliases of standard types using `#define` or `typedef` + - `enum` types (works well as `INT8` or whatever size your enums are) + - function pointers often work well as `PTR` comparisons + - `union` types sometimes make sense to treat as the largest type... + but this is a judgement call + +Option 3: Custom Assertions for Custom Types +-------------------------------------------- + +CMock has the ability to use custom assertions, if you form them +according to certain specifications. Creating a custom assertion +can be a bit of work, But the reward is that, once you've done so, +you can use those assertions within your own tests AND CMock will +magically use them within its own mocks. + +To accomplish this, we're going tackle multiple steps: + + 1. Write a custom assertion function + 2. Wrap it in a `UNITY_TEST_` macro + 3. Wrap it in a `TEST_` macro + 4. Inform CMock that it exists + +Let's look at each of those steps in detail: + +### Creating a Custom Assertion + +A custom assertion is a function which accepts a standard set of +inputs, and then uses Unity's assertion macros to verify any details +required for the types involved. + +The inputs: + + - the `expected` value (as a `const` version of type being verified) + - the `actual` value (also as a `const` version of the desired type) + - the `line` this function was called from (as type `UNITY_LINE_TYPE`) + - an optional `message` to be appended (as type `const char*`) + +Inside the function, we use the *internal* versions of Unity's assertions +to validate any details that need validating. + +Let's look at an example! Let's say we have the following type: + +``` +typedef struct MyType_t +{ + int a; + const char* b; +} MyType; +``` + +In our application, the length of `b` is supposed to be specified by `a`, +and `b` is therefore allowed to have any value (including `0x00`). + +Our custom assertion might look something like this: + +``` +void AssertEqualMyType(const MyType expected, const MyType actual, UNITY_LINE_TYPE line, const char* message) +{ + //It's common to override the default message with our own + (void)message; + + // Verify the lengths are the same, or they're clearly not matched + UNITY_TEST_ASSERT_EQUAL_INT(expected.a, actual.a, line, "Data length mismatch"); + + // Verify we're dealing with actual pointers + UNITY_TEST_ASSERT_NOT_NULL(expected.b, line, "Expected value should not be NULL"); + UNITY_TEST_ASSERT_NOT_NULL(actual.b, line, "Actual value should not be NULL"); + + // Verify the string contents + UNITY_TEST_ASSERT_EQUAL_MEMORY(expected.b, actual.b, expected.a, line, "Data not equal"); +} +``` + +There are a few things to note about this. First, notice we're using the +`UNITY_TEST_ASSERT_` assertions? That's because these allow us to pass +on the specific line number. Second, notice we override the message with our +own more helpful messages? You don't need to do this, but anything you can do +to help a developer find a bug is a good thing. + +What if there isn't an assertion that is right for your needs? You can +always do whatever operations are necessary yourself, and use `UNITY_TEST_FAIL()` +directly. + +One final note: It's best to only test the things that are hard rules about +how a type is supposed to work in your system. Anything else should be left to +the test code. + +For example, let's say that in our example above, there are situations where +it IS valid for the pointers to be `NULL`. Perhaps the pointers are ignored +completely when the `a` field is `0`. In that case, we could drop those +assertions completely, or add logic to only check when necessary. + +Similarly, should our assertion check that the length is positive? In this +case, it's dangerous if it's negative, because the memory check wouldn't like it. + +Updating for these concerns: + + +``` +void AssertEqualMyType(const MyType expected, const MyType actual, UNITY_LINE_TYPE line, const char* message) +{ + //It's common to override the default message with our own + (void)message; + + // Verify the lengths are the same, or they're clearly not matched + UNITY_TEST_ASSERT_EQUAL_INT(expected.a, actual.a, line, "Data length mismatch"); + + // Verify the lengths are non-negative + UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT(0, expected.a, line, "Data length must be positive"); + + if (expected.a > 0) + { + // Verify we're dealing with actual pointers + UNITY_TEST_ASSERT_NOT_NULL(expected.b, line, "Expected value should not be NULL"); + UNITY_TEST_ASSERT_NOT_NULL(actual.b, line, "Actual value should not be NULL"); + + // Verify the string contents + UNITY_TEST_ASSERT_EQUAL_MEMORY(expected.b, actual.b, expected.a, line, "Data not equal"); + } +} +``` + +### Wrapping our Assertion in Macros + +Once you have a function which does the main work, we *need* to create +one macro, and there are a number of other macros which are useful to +create, in order to treat our assertion just like any other Unity +assertion. + +`#define UNITY_TEST_ASSERT_EQUAL_MyType(e,a,l,m) AssertEqualMyType(e,a,l,m)` + +The macro above is the one that CMock is looking for. Notice that it +starts with `UNITY_TEST_ASSERT_EQUAL_` followed by the name of our type, +*exactly* the way our type is named. The arguments are, in order: + + - `e` - expected value + - `a` - actual value + - `l` - line number to report + - `m` - message to append at the end + +If CMock finds a macro that matches this argument list and naming convention, +then it can automatically use this assertion where needed... all we need to +do now is tell CMock where to find our custom assertion. + +### Informing CMock about our Assertion + +In the CMock configuration file, in the `:cmock` or `:unity` sections, +there can be an option for `unity_helper_path`. Add the location of your +new Unity helper file (file with this assertion) to this list. + +Done! + +**Bonus:** Once you've created a custom assertion, you can use it +with `:treat_as`, just like any other standard type! This is +particularly useful when there is a custom type which is a pointer +to a custom type. + +For example, let's say you have these types: + +``` +typedef struct MY_STRUCT_T_ +{ + int a; + const char* b; +} MY_STRUCT_T; + +typedef MY_STRUCT_T* MY_STRUCT_POINTER_T; +``` + +Also, let's assume you've created the following assertion: + +``` +UNITY_TEST_ASSERT_EQUAL_MY_STRUCT_T(e,a,l,m) +``` + +You can use `:treat_as` like so: + +``` +:treat_as: + MY_STRUCT_POINTER_T: MY_STRUCT_T* +``` + +Option 4: Callback +------------------ + +Finally, You can choose to avoid the use of `_Expect` calls altogether +for challenging types, and use a `Callback` instead. The advantage is that +you can fill in whichever assertions make sense for that particular test, +instead of needing to rely on reusable assertions as used elsewhere. +Typically, this option is also less work than option 3. diff --git a/docs/CMock_Summary.md b/docs/CMock_Summary.md index 75259381..31836657 100644 --- a/docs/CMock_Summary.md +++ b/docs/CMock_Summary.md @@ -7,6 +7,7 @@ CMock: A Summary - [Known Issues](docs/CMockKnownIssues.md) - [Change Log](docs/CMockChangeLog.md) + - [How Does CMock Validate Arguments](docs/CMock_ArgumentValidation.md) What Exactly Are We Talking About Here? --------------------------------------- @@ -818,7 +819,8 @@ and start over clean. This is really useful when wanting to test a function in an iterative manner with different arguments. C++ Support ---------- +----------- + C++ unit test/mocking frameworks often use a completely different approach (vs. CMock) that relies on overloading virtual class members and does not support directly mocking static class member methods or free functions (i.e., functions @@ -853,6 +855,7 @@ Will generate functions like void MyNamespace_MyClass_DoesSomething_ExpectAndReturn(int a, int b, int toReturn); + Examples ======== From 083bbd6a3882f6de7c0632cd4f2845539da1bf1f Mon Sep 17 00:00:00 2001 From: Mark VanderVoord Date: Wed, 21 Feb 2024 13:52:07 -0500 Subject: [PATCH 14/35] Add to verbosity of failures to find prototypes in headers. --- lib/cmock_header_parser.rb | 8 ++++---- test/unit/cmock_header_parser_test.rb | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/cmock_header_parser.rb b/lib/cmock_header_parser.rb index d41deefd..d248a8bb 100644 --- a/lib/cmock_header_parser.rb +++ b/lib/cmock_header_parser.rb @@ -39,7 +39,7 @@ def parse(name, source) function_names = [] - all_funcs = parse_functions(import_source(source, parse_project)).map { |item| [item] } + all_funcs = parse_functions(name, 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) @@ -358,15 +358,15 @@ def parse_cpp_functions(source) funcs end - def parse_functions(source) + def parse_functions(filename, 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!' + raise 'ERROR: No function prototypes found by CMock in #{filename}' when :warn - puts 'WARNING: No function prototypes found!' unless @verbosity < 1 + puts 'WARNING: No function prototypes found by CMock in #{filename}' unless @verbosity < 1 end end funcs diff --git a/test/unit/cmock_header_parser_test.rb b/test/unit/cmock_header_parser_test.rb index 43832ff8..a04adaf8 100644 --- a/test/unit/cmock_header_parser_test.rb +++ b/test/unit/cmock_header_parser_test.rb @@ -383,7 +383,7 @@ begin @parser.parse("module", source) rescue RuntimeError => e - assert_equal("ERROR: No function prototypes found!", e.message) + assert_match("ERROR: No function prototypes found", e.message) end end @@ -407,7 +407,7 @@ begin @parser.parse("module", source) rescue RuntimeError => e - assert_equal("ERROR: No function prototypes found!", e.message) + assert_match("ERROR: No function prototypes found", e.message) end end @@ -435,7 +435,7 @@ begin @parser.parse("module", source) rescue RuntimeError => e - assert_equal("ERROR: No function prototypes found!", e.message) + assert_match("ERROR: No function prototypes found", e.message) end end @@ -676,7 +676,7 @@ begin @parser.parse("module", source) rescue RuntimeError => e - assert_equal("ERROR: No function prototypes found!", e.message) + assert_match("ERROR: No function prototypes found", e.message) end end @@ -705,7 +705,7 @@ begin @parser.parse("module", source) rescue RuntimeError => e - assert_equal("ERROR: No function prototypes found!", e.message) + assert_match("ERROR: No function prototypes found", e.message) end end From 3232b72205b8a56e07719cb234baf1fc64767cc1 Mon Sep 17 00:00:00 2001 From: Mark VanderVoord Date: Wed, 21 Feb 2024 14:58:23 -0500 Subject: [PATCH 15/35] fixed wrong quote usage. --- lib/cmock_header_parser.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cmock_header_parser.rb b/lib/cmock_header_parser.rb index d248a8bb..bf99cba3 100644 --- a/lib/cmock_header_parser.rb +++ b/lib/cmock_header_parser.rb @@ -364,9 +364,9 @@ def parse_functions(filename, source) if funcs.empty? case @when_no_prototypes when :error - raise 'ERROR: No function prototypes found by CMock in #{filename}' + raise "ERROR: No function prototypes found by CMock in #{filename}" when :warn - puts 'WARNING: No function prototypes found by CMock in #{filename}' unless @verbosity < 1 + puts "WARNING: No function prototypes found by CMock in #{filename}" unless @verbosity < 1 end end funcs From dddd01dfa706828574555838a894450429848495 Mon Sep 17 00:00:00 2001 From: Mark VanderVoord Date: Sat, 9 Mar 2024 19:08:11 -0500 Subject: [PATCH 16/35] copied change from pr 468 --- LICENSE.txt | 2 +- lib/cmock_generator.rb | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/LICENSE.txt b/LICENSE.txt index 06f2b75f..04fd3e8e 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright (c) 2007-23 Mike Karlesky, Mark VanderVoord, Greg Williams +Copyright (c) 2007-24 Mike Karlesky, Mark VanderVoord, Greg Williams Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/lib/cmock_generator.rb b/lib/cmock_generator.rb index cc05631e..1e710555 100644 --- a/lib/cmock_generator.rb +++ b/lib/cmock_generator.rb @@ -140,7 +140,8 @@ def create_skeleton_source_file(mock_project) if existing.empty? create_source_header_section(file, fullname, blank_project) else - file << existing << "\n" + file << existing + file << "\n" if existing[-1] != "\n" end mock_project[:parsed_stuff][:functions].each do |function| create_function_skeleton(file, function, existing) From 4fb4fba206175cf49a10a02b3492763e9288a7bc Mon Sep 17 00:00:00 2001 From: Mark VanderVoord Date: Sat, 9 Mar 2024 20:09:05 -0500 Subject: [PATCH 17/35] Jump to next release of unity and cexception. --- vendor/c_exception | 2 +- vendor/unity | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/vendor/c_exception b/vendor/c_exception index 71b47be7..372f60a0 160000 --- a/vendor/c_exception +++ b/vendor/c_exception @@ -1 +1 @@ -Subproject commit 71b47be7c950f1bf5f7e5303779fa99a16224bb6 +Subproject commit 372f60a021aafafe8082d4dcc8da7ce41b44a732 diff --git a/vendor/unity b/vendor/unity index bf560290..860062d5 160000 --- a/vendor/unity +++ b/vendor/unity @@ -1 +1 @@ -Subproject commit bf560290f6020737eafaa8b5cbd2177c3956c03f +Subproject commit 860062d51b2e8a75d150337b63ca2a472840d13c From 7925641d7d8b854c95eab8a634fa6469d47364ed Mon Sep 17 00:00:00 2001 From: Mark VanderVoord Date: Wed, 13 Mar 2024 15:07:47 -0400 Subject: [PATCH 18/35] :memo: Add Code of Conduct and Contributing docs --- docs/CODE_OF_CONDUCT.md | 138 +++++++++++++++++++++++ docs/CONTRIBUTING.md | 238 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 376 insertions(+) create mode 100644 docs/CODE_OF_CONDUCT.md create mode 100644 docs/CONTRIBUTING.md diff --git a/docs/CODE_OF_CONDUCT.md b/docs/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..84e34806 --- /dev/null +++ b/docs/CODE_OF_CONDUCT.md @@ -0,0 +1,138 @@ + +# ThrowTheSwitch.org Code of Conduct + +Thank you for participating in a ThrowTheSwitch.org community project! We want +this to continue to be a warm and inviting place for everyone to share ideas +and get help. To accomplish this goal, we've developed this Code of Conduct. + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall + community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or advances of + any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email address, + without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official email address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +hello@thingamabyte.com. + +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of +actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent +ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the +community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. + +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at +[https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md new file mode 100644 index 00000000..e64a285a --- /dev/null +++ b/docs/CONTRIBUTING.md @@ -0,0 +1,238 @@ +# Contributing to a ThrowTheSwitch.org Project + +👍🎉 _First off, thanks for taking the time to contribute!_ 🎉👍 + +The following is a set of guidelines for contributing to any of ThrowTheSwitch.org's projects or the website itself, hosted at throwtheswitch.org or ThrowTheSwitch's organization on GitHub. These are mostly guidelines, not rules. Use your best judgment, and feel free to propose changes to this document in a pull request. + +### Table Of Contents + +- [Code of Conduct](#book-code-of-conduct) +- [Asking Questions](#bulb-asking-questions) +- [Opening an Issue](#inbox_tray-opening-an-issue) +- [Feature Requests](#love_letter-feature-requests) +- [Triaging Issues](#mag-triaging-issues) +- [Submitting Pull Requests](#repeat-submitting-pull-requests) +- [Writing Commit Messages](#memo-writing-commit-messages) +- [Code Review](#white_check_mark-code-review) +- [Coding Style](#nail_care-coding-style) +- [Certificate of Origin](#medal_sports-certificate-of-origin) +- [Credits](#pray-credits) + +## :book: Code of Conduct + +Please review our [Code of Conduct](CODE_OF_CONDUCT.md). It is in effect at all times. We expect it to be honored by everyone who contributes to this project. Be a Good Human! + +## :bulb: Asking Questions + +> **Note:** Please don't file an issue to ask a question. We have an official forum where the community chimes in with helpful advice if you have questions. + +* [ThrowTheSwitch Forums](https://throwtheswitch.org/forums) + +### What should I know before I get started? + +ThrowTheSwitch hosts a number of open source projects — Ceedling is the entrypoint for many users. Ceedling is actually built upon the foundation of Unity Test (a flexible C testing framework) and CMock (a mocking tool for C) and it coordinates many other open source and proprietary tools. Please do your best to focus your ideas and questions at the correct tool. We'll do our best to help you find your way, but there will be times where we'll have to direct your attention to another subtool. + +Here are some of the main projects hosted by ThrowTheSwitch.org: + + - [Ceedling](https://www.github.com/throwtheswitch/ceedling) -- Build coordinator for testing C applications, especially embedded C (and optionally your release build too!) + - [CMock](https://www.github.com/throwtheswitch/cmock) -- Mocking tool for automatically creating stubs, mocks, and skeletons in C + - [Unity](https://www.github.com/throwtheswitch/unity) -- Unit Testing framework for C, specially embedded C. + - [MadScienceLabDocker](https://www.github.com/throwtheswitch/madsciencelabdocker) -- Docker image giving you a shortcut to getting running with Ceedling + - [CException](https://www.github.com/throwtheswitch/cexception) -- An exception framework for using simple exceptions in C. + +There are many more, but this list should be a good starting point. + +## :inbox_tray: Opening an Issue + +Before [creating an issue](https://help.github.com/en/github/managing-your-work-on-github/creating-an-issue), check if you are using the latest version of the project. If you are not up-to-date, see if updating fixes your issue first. + +### :beetle: Bug Reports and Other Issues + +A great way to contribute to the project is to send a detailed issue when you encounter a problem. We always appreciate a well-written, thorough bug report. :v: + +In short, since you are most likely a developer, **provide a ticket that you would like to receive**. + +- **Review the documentation** before opening a new issue. + +- **Do not open a duplicate issue!** Search through existing issues to see if your issue has previously been reported. If your issue exists, comment with any additional information you have. You may simply note "I have this problem too", which helps prioritize the most common problems and requests. + +- **Prefer using [reactions](https://github.blog/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/)**, not comments, if you simply want to "+1" an existing issue. + +- **Fully complete the provided issue template.** The bug report template requests all the information we need to quickly and efficiently address your issue. Be clear, concise, and descriptive. Provide as much information as you can, including steps to reproduce, stack traces, compiler errors, library versions, OS versions, and screenshots (if applicable). + +- **Use [GitHub-flavored Markdown](https://help.github.com/en/github/writing-on-github/basic-writing-and-formatting-syntax).** Especially put code blocks and console outputs in backticks (```). This improves readability. + +## :seedling: Feature Requests + +Feature requests are welcome! We don't have all the answers and we truly love the collaborative experience of building software together! That being said, we cannot guarantee your request will be accepted. We want to avoid [feature creep](https://en.wikipedia.org/wiki/Feature_creep). Your idea may be great, but also out-of-scope for the project. If accepted, we'll do our best to tackle it in a timely manner, but cannot make any commitments regarding the timeline for implementation and release. However, you are welcome to submit a pull request to help! + +- **Please don't open a duplicate feature request.** Search for existing feature requests first. If you find your feature (or one very similar) previously requested, comment on that issue. + +- **Fully complete the provided issue template.** The feature request template asks for all necessary information for us to begin a productive conversation. + +- Be precise about the proposed outcome of the feature and how it relates to existing features. Include implementation details if possible. + +## :mag: Triaging Issues + +You can triage issues which may include reproducing bug reports or asking for additional information, such as version numbers or reproduction instructions. Any help you can provide to quickly resolve an issue is very much appreciated! + +## :repeat: Submitting Pull Requests + +We **love** pull requests! Before [forking the repo](https://help.github.com/en/github/getting-started-with-github/fork-a-repo) and [creating a pull request](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/proposing-changes-to-your-work-with-pull-requests) for non-trivial changes, it is usually best to first open an issue to discuss the changes, or discuss your intended approach for solving the problem in the comments for an existing issue. + +For most contributions, after your first pull request is accepted and merged, you will be [invited to the project](https://help.github.com/en/github/setting-up-and-managing-your-github-user-account/inviting-collaborators-to-a-personal-repository) and given **push access**. :tada: + +*Note: All contributions will be licensed under the project's license.* + +- **Smaller is better.** Submit **one** pull request per bug fix or feature. A pull request should contain isolated changes pertaining to a single bug fix or feature implementation. **Do not** refactor or reformat code that is unrelated to your change. It is better to **submit many small pull requests** rather than a single large one. Enormous pull requests will take enormous amounts of time to review, or may be rejected altogether. + +- **Coordinate bigger changes.** For large and non-trivial changes, open an issue to discuss a strategy with the maintainers. Otherwise, you risk doing a lot of work for nothing! + +- **Prioritize understanding over cleverness.** Write code clearly and concisely. Remember that source code usually gets written once and read often. Ensure the code is clear to the reader. The purpose and logic should be obvious to a reasonably skilled developer, otherwise you should add a comment that explains it. + +- **Follow existing coding style and conventions.** Keep your code consistent with the style, formatting, and conventions in the rest of the code base. When possible, these will be enforced with a linter. Consistency makes it easier to review and modify in the future. + +- **Include test coverage.** Add unit tests when possible. Follow existing patterns for implementing tests. + +- **Update the example project** if one exists to exercise any new functionality you have added. + +- **Add documentation.** Document your changes with code doc comments or in existing guides. + +- **Update the CHANGELOG** for all enhancements and bug fixes. Include the corresponding issue number if one exists, and your GitHub username. (example: "- Fixed crash in profile view. #123 @jessesquires") + +- **Use the repo's default branch.** Branch from and [submit your pull request](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request-from-a-fork) to the repo's default branch. Usually this is `main`, but it could be `dev`, `develop`, or `master`. + +- **[Resolve any merge conflicts](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/resolving-a-merge-conflict-on-github)** that occur. + +- **Promptly address any CI failures**. If your pull request fails to build or pass tests, please push another commit to fix it. + +- When writing comments, use properly constructed sentences, including punctuation. + +- Use spaces, not tabs. + +## :memo: Writing Commit Messages + +Please [write a great commit message](https://chris.beams.io/posts/git-commit/). + +1. Separate subject from body with a blank line +1. Limit the subject line to 50 characters +1. Capitalize the subject line +1. Do not end the subject line with a period +1. Wrap the body at _about_ 72 characters +1. Use the body to explain **why**, *not what and how* (the code shows that!) +1. If applicable, prefix the title with the relevant component name or emoji (see below. examples: "[Docs] Fix typo", "[Profile] Fix missing avatar") + +``` +:palm_tree: Summary of Amazing Feature Here + +Add a more detailed explanation here, if necessary. Possibly give +some background about the issue being fixed, etc. The body of the +commit message can be several paragraphs. Further paragraphs come +after blank lines and please do proper word-wrap. + +Wrap it to about 72 characters or so. In some contexts, +the first line is treated as the subject of the commit and the +rest of the text as the body. The blank line separating the summary +from the body is critical (unless you omit the body entirely); +various tools like `log`, `shortlog` and `rebase` can get confused +if you run the two together. + +Explain the problem that this commit is solving. Focus on why you +are making this change as opposed to how or what. The code explains +how or what. Reviewers and your future self can read the patch, +but might not understand why a particular solution was implemented. +Are there side effects or other unintuitive consequences of this +change? Here's the place to explain them. + + - Bullet points are awesome, too + + - A hyphen should be used for the bullet, preceded + by a single space, with blank lines in between + +Note the fixed or relevant GitHub issues at the end: + +Resolves: #123 +See also: #456, #789 +``` + +## :heart: Who Loves Emoji? + +Commit comments, Issues, Feature Requests... they can all use a little sprucing up, right? Consider using the following emoji for a mix of function and :sparkles: dazzle! + + - actions + - :seedling: `:seedling:` (or other plants) when growing new features. Choose your fav! :cactus: :herb: :evergreen_tree: :palm_tree: :deciduous_tree: :blossom: + - :art: `:art:` when improving the format/structure of the code + - :racehorse: `:racehorse:` when improving performance + - :non-potable_water: `:non-potable_water:` when plugging memory leaks + - :memo: `:memo:` when writing docs + - :bug: `:bug:` (or other insects) when fixing a bug. Maybe :beetle: :ant: or :honeybee: ? + - :fire: `:fire:` when removing code or files + - :green_heart: `:green_heart:` when fixing the CI build + - :white_check_mark: `:white_check_mark:` when adding tests + - :lock: `:lock:` when dealing with security + - :arrow_up: `:arrow_up:` when upgrading dependencies + - :arrow_down: `:arrow_down:` when downgrading dependencies + - :shirt: `:shirt:` when removing linter warnings + + - platforms + - :penguin: `:penguin:` when fixing something on Linux + - :apple: `:apple:` when fixing something on macOS + - :checkered_flag: `:checkered_flag:` when fixing something on Windows + +## :white_check_mark: Code Review + +- **Review the code, not the author.** Look for and suggest improvements without disparaging or insulting the author. Provide actionable feedback and explain your reasoning. + +- **You are not your code.** When your code is critiqued, questioned, or constructively criticized, remember that you are not your code. Do not take code review personally. + +- **Always do your best.** No one writes bugs on purpose. Do your best, and learn from your mistakes. + +- Kindly note any violations to the guidelines specified in this document. + +## :violin: Coding Style + +Consistency is the most important. Following the existing style, formatting, and naming conventions of the file you are modifying and of the overall project. Failure to do so will result in a prolonged review process that has to focus on updating the superficial aspects of your code, rather than improving its functionality and performance. + +For example, if all private properties are prefixed with an underscore `_`, then new ones you add should be prefixed in the same way. Or, if methods are named using camelcase, like `thisIsMyNewMethod`, then do not diverge from that by writing `this_is_my_new_method`. You get the idea. If in doubt, please ask or search the codebase for something similar. + +When possible, style and format will be enforced with a linter. + +### C Styleguide + +C code is linted with [AStyle](https://astyle.sourceforge.net/). + +### Ruby Styleguide + +Ruby code is linted with [Rubocop](https://github.com/rubocop/rubocop) + +## :medal_sports: Certificate of Origin + +*Developer's Certificate of Origin 1.1* + +By making a contribution to this project, I certify that: + +> 1. The contribution was created in whole or in part by me and I have the right to submit it under the open source license indicated in the file; or +> 1. The contribution is based upon previous work that, to the best of my knowledge, is covered under an appropriate open source license and I have the right under that license to submit that work with modifications, whether created in whole or in part by me, under the same open source license (unless I am permitted to submit under a different license), as indicated in the file; or +> 1. The contribution was provided directly to me by some other person who certified (1), (2) or (3) and I have not modified it. +> 1. I understand and agree that this project and the contribution are public and that a record of the contribution (including all personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with this project or the open source license(s) involved. + +## [No Brown M&M's](https://en.wikipedia.org/wiki/Van_Halen#Contract_riders) + +If you are reading this, bravo dear user and (hopefully) contributor for making it this far! You are awesome. :100: + +To confirm that you have read this guide and are following it as best as possible, **include this emoji at the top** of your issue or pull request: :pineapple: `:pineapple:` + +## :pray: Credits + +Written by [@jessesquires](https://github.com/jessesquires). Lovingly adapted to ThrowTheSwitch.org by [@mvandervoord](https://github.com/mvandervoord). + +**Please feel free to adopt this guide in your own projects. Fork it wholesale or remix it for your needs.** + +*Many of the ideas and prose for the statements in this document were based on or inspired by work from the following communities:* + +- [Alamofire](https://github.com/Alamofire/Alamofire/blob/master/CONTRIBUTING.md) +- [CocoaPods](https://github.com/CocoaPods/CocoaPods/blob/master/CONTRIBUTING.md) +- [Docker](https://github.com/moby/moby/blob/master/CONTRIBUTING.md) +- [Linux](https://elinux.org/Developer_Certificate_Of_Origin) + +*We commend them for their efforts to facilitate collaboration in their projects.* From 07a0e257b56c8cb2196e4a6a9d172da5059d343b Mon Sep 17 00:00:00 2001 From: Mark VanderVoord Date: Thu, 14 Mar 2024 08:59:31 -0400 Subject: [PATCH 19/35] :beetle: Added fail messages when using Expect for ExpectAndReturn or vice versa. (see issue #462) --- lib/cmock_generator_plugin_expect.rb | 4 + .../wrong_expect_and_return.yml | 101 ++++++++++++++++++ .../cmock_generator_plugin_expect_a_test.rb | 9 +- .../cmock_generator_plugin_expect_b_test.rb | 9 +- 4 files changed, 117 insertions(+), 6 deletions(-) create mode 100644 test/system/test_interactions/wrong_expect_and_return.yml diff --git a/lib/cmock_generator_plugin_expect.rb b/lib/cmock_generator_plugin_expect.rb index 3a79c1a4..ed44dab2 100644 --- a/lib/cmock_generator_plugin_expect.rb +++ b/lib/cmock_generator_plugin_expect.rb @@ -36,16 +36,20 @@ def instance_typedefs(function) def mock_function_declarations(function) if function[:args].empty? if function[:return][:void?] + "#define #{function[:name]}_ExpectAndReturn(cmock_retval) TEST_FAIL_MESSAGE(\"#{function[:name]} requires _Expect (not AndReturn)\");\n" \ "#define #{function[:name]}_Expect() #{function[:name]}_CMockExpect(__LINE__)\n" \ "void #{function[:name]}_CMockExpect(UNITY_LINE_TYPE cmock_line);\n" else + "#define #{function[:name]}_Expect() TEST_FAIL_MESSAGE(\"#{function[:name]} requires _ExpectAndReturn\");\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 elsif function[:return][:void?] + "#define #{function[:name]}_ExpectAndReturn(#{function[:args_call]}, cmock_retval) TEST_FAIL_MESSAGE(\"#{function[:name]} requires _Expect (not AndReturn)\");\n" \ "#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]}_Expect(#{function[:args_call]}) TEST_FAIL_MESSAGE(\"#{function[:name]} requires _ExpectAndReturn\");\n" \ "#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 diff --git a/test/system/test_interactions/wrong_expect_and_return.yml b/test/system/test_interactions/wrong_expect_and_return.yml new file mode 100644 index 00000000..8b26385e --- /dev/null +++ b/test/system/test_interactions/wrong_expect_and_return.yml @@ -0,0 +1,101 @@ +--- +:cmock: + :plugins: + - # none + +:systest: + :types: | + #define UINT32 unsigned int + + typedef signed int custom_type; + + :mockable: | + UINT32 foo(custom_type a); + UINT32 bar(void); + UINT32 foo_varargs(custom_type a, ...); + void do_it(void); + void do_another(int i); + + :source: + :header: | + UINT32 function_a(int a); + void function_b(void); + UINT32 function_c(int a); + void function_d(void); + + :code: | + UINT32 function_a(int a) + { + return foo((custom_type)a) + bar(); + } + + void function_b(void) { } + + UINT32 function_c(int a) + { + return foo_varargs((custom_type)a, "ignored", 5); + } + + void function_d(void) + { + do_it(); + do_another(2); + } + + :tests: + :common: | + void setUp(void) {} + void tearDown(void) {} + + :units: + - :pass: FALSE + :should: 'successfully report using Expect instead of ExpectAndReturn with args' + :code: | + test() + { + foo_Expect((custom_type)1); + bar_ExpectAndReturn(2); + function_a(1); + } + + - :pass: FALSE + :should: 'successfully report using Expect instead of ExpectAndReturn without args' + :code: | + test() + { + foo_ExpectAndReturn((custom_type)1, 4); + bar_Expect(); + function_a(1); + } + + - :pass: FALSE + :should: 'successfully report using Expect instead of ExpectAndReturn with varargs' + :code: | + test() + { + foo_varargs_Expect((custom_type)3); + function_c(3); + } + + - :pass: FALSE + :should: 'successfully report using ExpectAndReturn instead of Expect with args' + :code: | + test() + { + do_it_Expect(); + do_another_ExpectAndReturn(2, 2); + function_d(); + } + + - :pass: FALSE + :should: 'successfully report using ExpectAndReturn instead of Expect without args' + :code: | + test() + { + do_it_ExpectAndReturn(6); + do_another_Expect(2); + function_d(); + } + + +... diff --git a/test/unit/cmock_generator_plugin_expect_a_test.rb b/test/unit/cmock_generator_plugin_expect_a_test.rb index dd86689a..db57996e 100644 --- a/test/unit/cmock_generator_plugin_expect_a_test.rb +++ b/test/unit/cmock_generator_plugin_expect_a_test.rb @@ -64,7 +64,8 @@ it "add mock function declaration for functions of style 'void func(void)'" do function = {:name => "Maple", :args => [], :return => test_return[:void]} - expected = "#define Maple_Expect() Maple_CMockExpect(__LINE__)\n" + + expected = "#define Maple_ExpectAndReturn(cmock_retval) TEST_FAIL_MESSAGE(\"Maple requires _Expect (not AndReturn)\");\n" + + "#define Maple_Expect() Maple_CMockExpect(__LINE__)\n" + "void Maple_CMockExpect(UNITY_LINE_TYPE cmock_line);\n" returned = @cmock_generator_plugin_expect.mock_function_declarations(function) assert_equal(expected, returned) @@ -72,7 +73,8 @@ it "add mock function declaration for functions of style 'int func(void)'" do function = {:name => "Spruce", :args => [], :return => test_return[:int]} - expected = "#define Spruce_ExpectAndReturn(cmock_retval) Spruce_CMockExpectAndReturn(__LINE__, cmock_retval)\n" + + expected = "#define Spruce_Expect() TEST_FAIL_MESSAGE(\"Spruce requires _ExpectAndReturn\");\n" + + "#define Spruce_ExpectAndReturn(cmock_retval) Spruce_CMockExpectAndReturn(__LINE__, cmock_retval)\n" + "void Spruce_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, int cmock_to_return);\n" returned = @cmock_generator_plugin_expect.mock_function_declarations(function) assert_equal(expected, returned) @@ -80,7 +82,8 @@ it "add mock function declaration for functions of style 'const char* func(int tofu)'" do function = {:name => "Pine", :args => ["int tofu"], :args_string => "int tofu", :args_call => 'tofu', :return => test_return[:string]} - expected = "#define Pine_ExpectAndReturn(tofu, cmock_retval) Pine_CMockExpectAndReturn(__LINE__, tofu, cmock_retval)\n" + + expected = "#define Pine_Expect(tofu) TEST_FAIL_MESSAGE(\"Pine requires _ExpectAndReturn\");\n" + + "#define Pine_ExpectAndReturn(tofu, cmock_retval) Pine_CMockExpectAndReturn(__LINE__, tofu, cmock_retval)\n" + "void Pine_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, int tofu, const char* cmock_to_return);\n" returned = @cmock_generator_plugin_expect.mock_function_declarations(function) assert_equal(expected, returned) diff --git a/test/unit/cmock_generator_plugin_expect_b_test.rb b/test/unit/cmock_generator_plugin_expect_b_test.rb index 35d48715..2ba2622d 100644 --- a/test/unit/cmock_generator_plugin_expect_b_test.rb +++ b/test/unit/cmock_generator_plugin_expect_b_test.rb @@ -64,7 +64,8 @@ it "add mock function declaration for functions of style 'void func(void)'" do function = {:name => "Maple", :args => [], :return => test_return[:void]} - expected = "#define Maple_Expect() Maple_CMockExpect(__LINE__)\n" + + expected = "#define Maple_ExpectAndReturn(cmock_retval) TEST_FAIL_MESSAGE(\"Maple requires _Expect (not AndReturn)\");\n" + + "#define Maple_Expect() Maple_CMockExpect(__LINE__)\n" + "void Maple_CMockExpect(UNITY_LINE_TYPE cmock_line);\n" returned = @cmock_generator_plugin_expect.mock_function_declarations(function) assert_equal(expected, returned) @@ -72,7 +73,8 @@ it "add mock function declaration for functions of style 'int func(void)'" do function = {:name => "Spruce", :args => [], :return => test_return[:int]} - expected = "#define Spruce_ExpectAndReturn(cmock_retval) Spruce_CMockExpectAndReturn(__LINE__, cmock_retval)\n" + + expected = "#define Spruce_Expect() TEST_FAIL_MESSAGE(\"Spruce requires _ExpectAndReturn\");\n" + + "#define Spruce_ExpectAndReturn(cmock_retval) Spruce_CMockExpectAndReturn(__LINE__, cmock_retval)\n" + "void Spruce_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, int cmock_to_return);\n" returned = @cmock_generator_plugin_expect.mock_function_declarations(function) assert_equal(expected, returned) @@ -80,7 +82,8 @@ it "add mock function declaration for functions of style 'const char* func(int tofu)'" do function = {:name => "Pine", :args => ["int tofu"], :args_string => "int tofu", :args_call => 'tofu', :return => test_return[:string]} - expected = "#define Pine_ExpectAndReturn(tofu, cmock_retval) Pine_CMockExpectAndReturn(__LINE__, tofu, cmock_retval)\n" + + expected = "#define Pine_Expect(tofu) TEST_FAIL_MESSAGE(\"Pine requires _ExpectAndReturn\");\n" + + "#define Pine_ExpectAndReturn(tofu, cmock_retval) Pine_CMockExpectAndReturn(__LINE__, tofu, cmock_retval)\n" + "void Pine_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, int tofu, const char* cmock_to_return);\n" returned = @cmock_generator_plugin_expect.mock_function_declarations(function) assert_equal(expected, returned) From 0240b4ae19b31d1c089a817ed11a77b9c762d41b Mon Sep 17 00:00:00 2001 From: Mark VanderVoord Date: Thu, 14 Mar 2024 09:00:56 -0400 Subject: [PATCH 20/35] :arrow_up: Updated Unity and CException to latest versions. --- vendor/c_exception | 2 +- vendor/unity | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/vendor/c_exception b/vendor/c_exception index 372f60a0..12dd9808 160000 --- a/vendor/c_exception +++ b/vendor/c_exception @@ -1 +1 @@ -Subproject commit 372f60a021aafafe8082d4dcc8da7ce41b44a732 +Subproject commit 12dd980876cb351db29ce41fadcc9fdb4f255f75 diff --git a/vendor/unity b/vendor/unity index 860062d5..85452ad1 160000 --- a/vendor/unity +++ b/vendor/unity @@ -1 +1 @@ -Subproject commit 860062d51b2e8a75d150337b63ca2a472840d13c +Subproject commit 85452ad1544f77d752a2444eb8859f73346bfb97 From 3a6f1f29a35ee990172d14a86caac4cc74890791 Mon Sep 17 00:00:00 2001 From: Mark VanderVoord Date: Wed, 20 Mar 2024 15:55:59 -0400 Subject: [PATCH 21/35] :beetle: Fixed issue where `-oblah.yml` isn't parsed by powershell. :fern: `-o blah.yml` also accepted as valid input now. --- README.md | 19 +++++++++++++------ lib/cmock.rb | 10 +++++++++- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 16d10adf..f8808550 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ CMock ![CI](https://github.com/ThrowTheSwitch/CMock/workflows/CI/badge.svg) ===== + CMock is a mock and stub generator and runtime for unit testing C. It's been designed to work smoothly with Unity Test, another of the embedded-software testing tools developed by ThrowTheSwitch.org. CMock automagically parses your C headers and creates @@ -12,22 +13,28 @@ a test-centered build manager for unit testing C code. - [Change Log](docs/CMockChangeLog.md) Getting Started -================ +=============== If you're using Ceedling, there is no need to install CMock. It will handle it for you. For everyone else, the simplest way is to grab it off github. You can also download it as a zip if you prefer. The Github method looks something like this: > git clone --recursive https://github.com/throwtheswitch/cmock.git - > cd cmock - > bundle install # Ensures you have all RubyGems needed + +Contributing to this Project +============================ If you plan to help with the development of CMock (or just want to verify that it can -perform its self tests on your system) then you can enter the test directory and then -ask it to test: +perform its self tests on your system) then you can grab its self-testing dependencies, +then run its self-tests: + > cd cmock + > bundle install # Ensures you have all RubyGems needed > cd test - > rake # Run all CMock self tests + > rake # Run all CMock self tests + +Before working on this project, you're going to want to read our guidelines on +[contributing](docs/CONTRIBUTING.md). API Documentation ================= diff --git a/lib/cmock.rb b/lib/cmock.rb index b889f5e1..36b9e053 100644 --- a/lib/cmock.rb +++ b/lib/cmock.rb @@ -86,10 +86,13 @@ def option_maker(options, key, val) options = {} filelist = [] + opt_flag = false ARGV.each do |arg| case arg when /^-o"?([a-zA-Z0-9@._\\\/:\s]+)"?/ options.merge! CMockConfig.load_config_file_from_yaml(arg.gsub(/^-o/, '')) + when /^-o$/ + opt_flag = true when '--skeleton' options[:skeleton] = true when /^--strippables="?(.*)"?/ @@ -100,7 +103,12 @@ def option_maker(options, key, val) options = option_maker(options, Regexp.last_match(1), Regexp.last_match(2)) else - filelist << arg + if opt_flag + options.merge! CMockConfig.load_config_file_from_yaml(arg) + opt_flag = false + else + filelist << arg + end end end From 597a6d86eb5142003aad729eb8927786f822ef80 Mon Sep 17 00:00:00 2001 From: Mark VanderVoord Date: Thu, 21 Mar 2024 11:35:21 -0400 Subject: [PATCH 22/35] Finish giving clues when you've chosen the wrong AndReturn version. ReturnArrayThruPtr (and others) now protect sizes in parenthesis #415 --- lib/cmock_generator_plugin_array.rb | 13 +++--- lib/cmock_generator_plugin_expect.rb | 8 ++-- lib/cmock_generator_plugin_expect_any_args.rb | 6 ++- lib/cmock_generator_plugin_ignore.rb | 2 + ...cmock_generator_plugin_ignore_stateless.rb | 2 + lib/cmock_generator_plugin_return_thru_ptr.rb | 4 +- .../wrong_expect_and_return.yml | 43 ++++++++++++++++++- .../unit/cmock_generator_plugin_array_test.rb | 9 ++-- ...k_generator_plugin_expect_any_args_test.rb | 7 ++- ..._generator_plugin_ignore_stateless_test.rb | 10 +++-- .../cmock_generator_plugin_ignore_test.rb | 10 +++-- ...k_generator_plugin_return_thru_ptr_test.rb | 16 +++---- 12 files changed, 97 insertions(+), 33 deletions(-) diff --git a/lib/cmock_generator_plugin_array.rb b/lib/cmock_generator_plugin_array.rb index 249a622f..b36a8161 100644 --- a/lib/cmock_generator_plugin_array.rb +++ b/lib/cmock_generator_plugin_array.rb @@ -26,17 +26,20 @@ def instance_typedefs(function) 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_call_i = function[:args].map { |m| m[:ptr?] ? "#{m[:name]}, #{m[:name]}_Depth" : (m[:name]).to_s }.join(', ') + args_call_o = 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?] - "#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" + "#define #{function[:name]}_ExpectWithArrayAndReturn(#{args_call_i}, cmock_retval) TEST_FAIL_MESSAGE(\"#{function[:name]} requires _ExpectWithArray (not AndReturn)\");\n" \ + "#define #{function[:name]}_ExpectWithArray(#{args_call_i}) #{function[:name]}_CMockExpectWithArray(__LINE__, #{args_call_o})\n" \ + "void #{function[:name]}_CMockExpectWithArray(UNITY_LINE_TYPE cmock_line, #{args_string});\n" else - "#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" + "#define #{function[:name]}_ExpectWithArray(#{args_call_i}) TEST_FAIL_MESSAGE(\"#{function[:name]} requires _ExpectWithArrayAndReturn\");\n" \ + "#define #{function[:name]}_ExpectWithArrayAndReturn(#{args_call_i}, cmock_retval) #{function[:name]}_CMockExpectWithArrayAndReturn(__LINE__, #{args_call_o}, cmock_retval)\n" \ + "void #{function[:name]}_CMockExpectWithArrayAndReturn(UNITY_LINE_TYPE cmock_line, #{args_string}, #{function[:return][:str]});\n" end end diff --git a/lib/cmock_generator_plugin_expect.rb b/lib/cmock_generator_plugin_expect.rb index ed44dab2..d034c959 100644 --- a/lib/cmock_generator_plugin_expect.rb +++ b/lib/cmock_generator_plugin_expect.rb @@ -38,20 +38,20 @@ def mock_function_declarations(function) if function[:return][:void?] "#define #{function[:name]}_ExpectAndReturn(cmock_retval) TEST_FAIL_MESSAGE(\"#{function[:name]} requires _Expect (not AndReturn)\");\n" \ "#define #{function[:name]}_Expect() #{function[:name]}_CMockExpect(__LINE__)\n" \ - "void #{function[:name]}_CMockExpect(UNITY_LINE_TYPE cmock_line);\n" + "void #{function[:name]}_CMockExpect(UNITY_LINE_TYPE cmock_line);\n" else "#define #{function[:name]}_Expect() TEST_FAIL_MESSAGE(\"#{function[:name]} requires _ExpectAndReturn\");\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" + "void #{function[:name]}_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]});\n" end elsif function[:return][:void?] "#define #{function[:name]}_ExpectAndReturn(#{function[:args_call]}, cmock_retval) TEST_FAIL_MESSAGE(\"#{function[:name]} requires _Expect (not AndReturn)\");\n" \ "#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" + "void #{function[:name]}_CMockExpect(UNITY_LINE_TYPE cmock_line, #{function[:args_string]});\n" else "#define #{function[:name]}_Expect(#{function[:args_call]}) TEST_FAIL_MESSAGE(\"#{function[:name]} requires _ExpectAndReturn\");\n" \ "#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" + "void #{function[:name]}_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:args_string]}, #{function[:return][:str]});\n" end end diff --git a/lib/cmock_generator_plugin_expect_any_args.rb b/lib/cmock_generator_plugin_expect_any_args.rb index 3451fbaa..e7de7ef3 100644 --- a/lib/cmock_generator_plugin_expect_any_args.rb +++ b/lib/cmock_generator_plugin_expect_any_args.rb @@ -21,11 +21,13 @@ def mock_function_declarations(function) if function[:args].empty? '' elsif function[:return][:void?] + "#define #{function[:name]}_ExpectAnyArgsAndReturn(cmock_retval) TEST_FAIL_MESSAGE(\"#{function[:name]} requires _ExpectAnyArgs (not AndReturn)\");\n" \ "#define #{function[:name]}_ExpectAnyArgs() #{function[:name]}_CMockExpectAnyArgs(__LINE__)\n" \ - "void #{function[:name]}_CMockExpectAnyArgs(UNITY_LINE_TYPE cmock_line);\n" + "void #{function[:name]}_CMockExpectAnyArgs(UNITY_LINE_TYPE cmock_line);\n" else + "#define #{function[:name]}_ExpectAnyArgs() TEST_FAIL_MESSAGE(\"#{function[:name]} requires _ExpectAnyArgsAndReturn\");\n" \ "#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" + "void #{function[:name]}_CMockExpectAnyArgsAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]});\n" end end diff --git a/lib/cmock_generator_plugin_ignore.rb b/lib/cmock_generator_plugin_ignore.rb index bbb7c145..d3ab46b9 100644 --- a/lib/cmock_generator_plugin_ignore.rb +++ b/lib/cmock_generator_plugin_ignore.rb @@ -23,9 +23,11 @@ def instance_structure(function) def mock_function_declarations(function) lines = if function[:return][:void?] + "#define #{function[:name]}_IgnoreAndReturn(cmock_retval) TEST_FAIL_MESSAGE(\"#{function[:name]} requires _Ignore (not AndReturn)\");\n" \ "#define #{function[:name]}_Ignore() #{function[:name]}_CMockIgnore()\n" \ "void #{function[:name]}_CMockIgnore(void);\n" else + "#define #{function[:name]}_Ignore() TEST_FAIL_MESSAGE(\"#{function[:name]} requires _IgnoreAndReturn\");\n" \ "#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 diff --git a/lib/cmock_generator_plugin_ignore_stateless.rb b/lib/cmock_generator_plugin_ignore_stateless.rb index bdf9594b..bce8b897 100644 --- a/lib/cmock_generator_plugin_ignore_stateless.rb +++ b/lib/cmock_generator_plugin_ignore_stateless.rb @@ -23,9 +23,11 @@ def instance_structure(function) def mock_function_declarations(function) lines = if function[:return][:void?] + "#define #{function[:name]}_IgnoreAndReturn(cmock_retval) TEST_FAIL_MESSAGE(\"#{function[:name]} requires _Ignore (not AndReturn)\");\n" \ "#define #{function[:name]}_Ignore() #{function[:name]}_CMockIgnore()\n" \ "void #{function[:name]}_CMockIgnore(void);\n" else + "#define #{function[:name]}_Ignore() TEST_FAIL_MESSAGE(\"#{function[:name]} requires _IgnoreAndReturn\");\n" \ "#define #{function[:name]}_IgnoreAndReturn(cmock_retval) #{function[:name]}_CMockIgnoreAndReturn(cmock_retval)\n" \ "void #{function[:name]}_CMockIgnoreAndReturn(#{function[:return][:str]});\n" end diff --git a/lib/cmock_generator_plugin_return_thru_ptr.rb b/lib/cmock_generator_plugin_return_thru_ptr.rb index 8d0b2d56..7fd19c74 100644 --- a/lib/cmock_generator_plugin_return_thru_ptr.rb +++ b/lib/cmock_generator_plugin_return_thru_ptr.rb @@ -49,9 +49,9 @@ def mock_function_declarations(function) " #{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 << " #{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 << " #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(__LINE__, #{arg[:name]}, (cmock_size))\n" lines << "void #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(UNITY_LINE_TYPE cmock_line, #{ptr_to_const(arg[:type])} #{arg[:name]}, size_t cmock_size);\n" end lines diff --git a/test/system/test_interactions/wrong_expect_and_return.yml b/test/system/test_interactions/wrong_expect_and_return.yml index 8b26385e..74fc4c3c 100644 --- a/test/system/test_interactions/wrong_expect_and_return.yml +++ b/test/system/test_interactions/wrong_expect_and_return.yml @@ -1,7 +1,8 @@ --- :cmock: :plugins: - - # none + - :ignore + - :expect_any_args :systest: :types: | @@ -97,5 +98,45 @@ function_d(); } + - :pass: FALSE + :should: 'successfully report using ExpectAnyArgs instead of ExpectAnyArgsAndReturn' + :code: | + test() + { + foo_ExpectAnyArgs(); + bar_ExpectAndReturn(2); + function_a(1); + } + + - :pass: FALSE + :should: 'successfully report using ExpectAnyArgsAndReturn instead of ExpectAnyArgs' + :code: | + test() + { + do_it_Expect(); + do_another_ExpectAnyArgsAndReturn(2); + function_d(); + } + + - :pass: FALSE + :should: 'successfully report using Ignore instead of IgnoreAndReturn' + :code: | + test() + { + foo_Ignore(); + bar_IgnoreAndReturn(2); + function_a(1); + } + + - :pass: FALSE + :should: 'successfully report using IgnoreAndReturn instead of Ignore' + :code: | + test() + { + do_it_Ignore(); + do_another_IgnoreAndReturn(2); + function_d(); + } + ... diff --git a/test/unit/cmock_generator_plugin_array_test.rb b/test/unit/cmock_generator_plugin_array_test.rb index 64c0b283..2c42c0a3 100644 --- a/test/unit/cmock_generator_plugin_array_test.rb +++ b/test/unit/cmock_generator_plugin_array_test.rb @@ -73,7 +73,8 @@ def code_add_base_expectation(func) :return => test_return[:void], :contains_ptr? => true } - expected = "#define #{function[:name]}_ExpectWithArray(tofu, tofu_Depth) #{function[:name]}_CMockExpectWithArray(__LINE__, tofu, tofu_Depth)\n" + + expected = "#define #{function[:name]}_ExpectWithArrayAndReturn(tofu, tofu_Depth, cmock_retval) TEST_FAIL_MESSAGE(\"#{function[:name]} requires _ExpectWithArray (not AndReturn)\");\n" + + "#define #{function[:name]}_ExpectWithArray(tofu, tofu_Depth) #{function[:name]}_CMockExpectWithArray(__LINE__, tofu, (tofu_Depth))\n" + "void #{function[:name]}_CMockExpectWithArray(UNITY_LINE_TYPE cmock_line, int* tofu, int tofu_Depth);\n" returned = @cmock_generator_plugin_array.mock_function_declarations(function) assert_equal(expected, returned) @@ -88,7 +89,8 @@ def code_add_base_expectation(func) :return => test_return[:string], :contains_ptr? => true } - expected = "#define #{function[:name]}_ExpectWithArrayAndReturn(tofu, tofu_Depth, cmock_retval) #{function[:name]}_CMockExpectWithArrayAndReturn(__LINE__, tofu, tofu_Depth, cmock_retval)\n" + + expected = "#define #{function[:name]}_ExpectWithArray(tofu, tofu_Depth) TEST_FAIL_MESSAGE(\"#{function[:name]} requires _ExpectWithArrayAndReturn\");\n" + + "#define #{function[:name]}_ExpectWithArrayAndReturn(tofu, tofu_Depth, cmock_retval) #{function[:name]}_CMockExpectWithArrayAndReturn(__LINE__, tofu, (tofu_Depth), cmock_retval)\n" + "void #{function[:name]}_CMockExpectWithArrayAndReturn(UNITY_LINE_TYPE cmock_line, int* tofu, int tofu_Depth, const char* cmock_to_return);\n" returned = @cmock_generator_plugin_array.mock_function_declarations(function) assert_equal(expected, returned) @@ -104,7 +106,8 @@ def code_add_base_expectation(func) :return => test_return[:string], :contains_ptr? => true } - expected = "#define #{function[:name]}_ExpectWithArrayAndReturn(tofu, tofu_Depth, cmock_retval) #{function[:name]}_CMockExpectWithArrayAndReturn(__LINE__, tofu, tofu_Depth, cmock_retval)\n" + + expected = "#define #{function[:name]}_ExpectWithArray(tofu, tofu_Depth) TEST_FAIL_MESSAGE(\"#{function[:name]} requires _ExpectWithArrayAndReturn\");\n" + + "#define #{function[:name]}_ExpectWithArrayAndReturn(tofu, tofu_Depth, cmock_retval) #{function[:name]}_CMockExpectWithArrayAndReturn(__LINE__, tofu, (tofu_Depth), cmock_retval)\n" + "void #{function[:name]}_CMockExpectWithArrayAndReturn(UNITY_LINE_TYPE cmock_line, const int* tofu, int tofu_Depth, const char* cmock_to_return);\n" returned = @cmock_generator_plugin_array.mock_function_declarations(function) assert_equal(expected, returned) diff --git a/test/unit/cmock_generator_plugin_expect_any_args_test.rb b/test/unit/cmock_generator_plugin_expect_any_args_test.rb index 5a014d6e..9d1c9bd1 100644 --- a/test/unit/cmock_generator_plugin_expect_any_args_test.rb +++ b/test/unit/cmock_generator_plugin_expect_any_args_test.rb @@ -35,14 +35,17 @@ it "handle function declarations for functions without return values" do function = {:name => "Mold", :args_string => "int meh", :args => [ :stuff ], :return => test_return[:void]} - expected = "#define Mold_ExpectAnyArgs() Mold_CMockExpectAnyArgs(__LINE__)\nvoid Mold_CMockExpectAnyArgs(UNITY_LINE_TYPE cmock_line);\n" + expected = "#define Mold_ExpectAnyArgsAndReturn(cmock_retval) TEST_FAIL_MESSAGE(\"Mold requires _ExpectAnyArgs (not AndReturn)\");\n"+ + "#define Mold_ExpectAnyArgs() Mold_CMockExpectAnyArgs(__LINE__)\n"+ + "void Mold_CMockExpectAnyArgs(UNITY_LINE_TYPE cmock_line);\n" returned = @cmock_generator_plugin_expect_any_args.mock_function_declarations(function) assert_equal(expected, returned) end it "handle function declarations for functions that returns something" do function = {:name => "Fungus", :args_string => "int meh", :args => [ :stuff ], :return => test_return[:string]} - expected = "#define Fungus_ExpectAnyArgsAndReturn(cmock_retval) Fungus_CMockExpectAnyArgsAndReturn(__LINE__, cmock_retval)\n"+ + expected = "#define Fungus_ExpectAnyArgs() TEST_FAIL_MESSAGE(\"Fungus requires _ExpectAnyArgsAndReturn\");\n"+ + "#define Fungus_ExpectAnyArgsAndReturn(cmock_retval) Fungus_CMockExpectAnyArgsAndReturn(__LINE__, cmock_retval)\n"+ "void Fungus_CMockExpectAnyArgsAndReturn(UNITY_LINE_TYPE cmock_line, const char* cmock_to_return);\n" returned = @cmock_generator_plugin_expect_any_args.mock_function_declarations(function) assert_equal(expected, returned) diff --git a/test/unit/cmock_generator_plugin_ignore_stateless_test.rb b/test/unit/cmock_generator_plugin_ignore_stateless_test.rb index b40d9785..4962d0a3 100644 --- a/test/unit/cmock_generator_plugin_ignore_stateless_test.rb +++ b/test/unit/cmock_generator_plugin_ignore_stateless_test.rb @@ -35,15 +35,19 @@ it "handle function declarations for functions without return values" do function = {:name => "Mold", :args_string => "void", :return => test_return[:void]} - expected = "#define Mold_Ignore() Mold_CMockIgnore()\nvoid Mold_CMockIgnore(void);\n" + - "#define Mold_StopIgnore() Mold_CMockStopIgnore()\nvoid Mold_CMockStopIgnore(void);\n" + expected = "#define Mold_IgnoreAndReturn(cmock_retval) TEST_FAIL_MESSAGE(\"Mold requires _Ignore (not AndReturn)\");\n" + + "#define Mold_Ignore() Mold_CMockIgnore()\n" + + "void Mold_CMockIgnore(void);\n" + + "#define Mold_StopIgnore() Mold_CMockStopIgnore()\n" + + "void Mold_CMockStopIgnore(void);\n" returned = @cmock_generator_plugin_ignore_stateless.mock_function_declarations(function) assert_equal(expected, returned) end it "handle function declarations for functions that returns something" do function = {:name => "Fungus", :args_string => "void", :return => test_return[:string]} - expected = "#define Fungus_IgnoreAndReturn(cmock_retval) Fungus_CMockIgnoreAndReturn(cmock_retval)\n"+ + expected = "#define Fungus_Ignore() TEST_FAIL_MESSAGE(\"Fungus requires _IgnoreAndReturn\");\n"+ + "#define Fungus_IgnoreAndReturn(cmock_retval) Fungus_CMockIgnoreAndReturn(cmock_retval)\n"+ "void Fungus_CMockIgnoreAndReturn(const char* cmock_to_return);\n" + "#define Fungus_StopIgnore() Fungus_CMockStopIgnore()\n"+ "void Fungus_CMockStopIgnore(void);\n" diff --git a/test/unit/cmock_generator_plugin_ignore_test.rb b/test/unit/cmock_generator_plugin_ignore_test.rb index c0c28b84..d213efba 100644 --- a/test/unit/cmock_generator_plugin_ignore_test.rb +++ b/test/unit/cmock_generator_plugin_ignore_test.rb @@ -35,15 +35,19 @@ it "handle function declarations for functions without return values" do function = {:name => "Mold", :args_string => "void", :return => test_return[:void]} - expected = "#define Mold_Ignore() Mold_CMockIgnore()\nvoid Mold_CMockIgnore(void);\n" + - "#define Mold_StopIgnore() Mold_CMockStopIgnore()\nvoid Mold_CMockStopIgnore(void);\n" + expected = "#define Mold_IgnoreAndReturn(cmock_retval) TEST_FAIL_MESSAGE(\"Mold requires _Ignore (not AndReturn)\");\n" + + "#define Mold_Ignore() Mold_CMockIgnore()\n" + + "void Mold_CMockIgnore(void);\n" + + "#define Mold_StopIgnore() Mold_CMockStopIgnore()\n" + + "void Mold_CMockStopIgnore(void);\n" returned = @cmock_generator_plugin_ignore.mock_function_declarations(function) assert_equal(expected, returned) end it "handle function declarations for functions that returns something" do function = {:name => "Fungus", :args_string => "void", :return => test_return[:string]} - expected = "#define Fungus_IgnoreAndReturn(cmock_retval) Fungus_CMockIgnoreAndReturn(__LINE__, cmock_retval)\n"+ + expected = "#define Fungus_Ignore() TEST_FAIL_MESSAGE(\"Fungus requires _IgnoreAndReturn\");\n"+ + "#define Fungus_IgnoreAndReturn(cmock_retval) Fungus_CMockIgnoreAndReturn(__LINE__, cmock_retval)\n"+ "void Fungus_CMockIgnoreAndReturn(UNITY_LINE_TYPE cmock_line, const char* cmock_to_return);\n" + "#define Fungus_StopIgnore() Fungus_CMockStopIgnore()\n"+ "void Fungus_CMockStopIgnore(void);\n" diff --git a/test/unit/cmock_generator_plugin_return_thru_ptr_test.rb b/test/unit/cmock_generator_plugin_return_thru_ptr_test.rb index 374caa1f..9ed5a12d 100644 --- a/test/unit/cmock_generator_plugin_return_thru_ptr_test.rb +++ b/test/unit/cmock_generator_plugin_return_thru_ptr_test.rb @@ -118,16 +118,16 @@ def void_ptr_func_expect "#define Pine_ReturnThruPtr_tofu(tofu)" + " Pine_CMockReturnMemThruPtr_tofu(__LINE__, tofu, sizeof(int))\n" + "#define Pine_ReturnArrayThruPtr_tofu(tofu, cmock_len)" + - " Pine_CMockReturnMemThruPtr_tofu(__LINE__, tofu, cmock_len * sizeof(*tofu))\n" + + " Pine_CMockReturnMemThruPtr_tofu(__LINE__, tofu, (cmock_len * sizeof(*tofu)))\n" + "#define Pine_ReturnMemThruPtr_tofu(tofu, cmock_size)" + - " Pine_CMockReturnMemThruPtr_tofu(__LINE__, tofu, cmock_size)\n" + + " Pine_CMockReturnMemThruPtr_tofu(__LINE__, tofu, (cmock_size))\n" + "void Pine_CMockReturnMemThruPtr_tofu(UNITY_LINE_TYPE cmock_line, int const* tofu, size_t cmock_size);\n"+ "#define Pine_ReturnThruPtr_bean_buffer(bean_buffer)" + " Pine_CMockReturnMemThruPtr_bean_buffer(__LINE__, bean_buffer, sizeof(char*))\n" + "#define Pine_ReturnArrayThruPtr_bean_buffer(bean_buffer, cmock_len)" + - " Pine_CMockReturnMemThruPtr_bean_buffer(__LINE__, bean_buffer, cmock_len * sizeof(*bean_buffer))\n" + + " Pine_CMockReturnMemThruPtr_bean_buffer(__LINE__, bean_buffer, (cmock_len * sizeof(*bean_buffer)))\n" + "#define Pine_ReturnMemThruPtr_bean_buffer(bean_buffer, cmock_size)" + - " Pine_CMockReturnMemThruPtr_bean_buffer(__LINE__, bean_buffer, cmock_size)\n" + + " Pine_CMockReturnMemThruPtr_bean_buffer(__LINE__, bean_buffer, (cmock_size))\n" + "void Pine_CMockReturnMemThruPtr_bean_buffer(UNITY_LINE_TYPE cmock_line, char* const* bean_buffer, size_t cmock_size);\n" returned = @cmock_generator_plugin_return_thru_ptr.mock_function_declarations(@complex_func) @@ -141,16 +141,16 @@ def void_ptr_func_expect "#define Spruce_ReturnThruPtr_pork(pork)" + " Spruce_CMockReturnMemThruPtr_pork(__LINE__, pork, sizeof(*pork))\n" + "#define Spruce_ReturnArrayThruPtr_pork(pork, cmock_len)" + - " Spruce_CMockReturnMemThruPtr_pork(__LINE__, pork, cmock_len * sizeof(*pork))\n" + + " Spruce_CMockReturnMemThruPtr_pork(__LINE__, pork, (cmock_len * sizeof(*pork)))\n" + "#define Spruce_ReturnMemThruPtr_pork(pork, cmock_size)" + - " Spruce_CMockReturnMemThruPtr_pork(__LINE__, pork, cmock_size)\n" + + " Spruce_CMockReturnMemThruPtr_pork(__LINE__, pork, (cmock_size))\n" + "void Spruce_CMockReturnMemThruPtr_pork(UNITY_LINE_TYPE cmock_line, void const* pork, size_t cmock_size);\n" + "#define Spruce_ReturnThruPtr_salad(salad)" + " Spruce_CMockReturnMemThruPtr_salad(__LINE__, salad, sizeof(*salad))\n" + "#define Spruce_ReturnArrayThruPtr_salad(salad, cmock_len)" + - " Spruce_CMockReturnMemThruPtr_salad(__LINE__, salad, cmock_len * sizeof(*salad))\n" + + " Spruce_CMockReturnMemThruPtr_salad(__LINE__, salad, (cmock_len * sizeof(*salad)))\n" + "#define Spruce_ReturnMemThruPtr_salad(salad, cmock_size)" + - " Spruce_CMockReturnMemThruPtr_salad(__LINE__, salad, cmock_size)\n" + + " Spruce_CMockReturnMemThruPtr_salad(__LINE__, salad, (cmock_size))\n" + "void Spruce_CMockReturnMemThruPtr_salad(UNITY_LINE_TYPE cmock_line, MY_FANCY_VOID const* salad, size_t cmock_size);\n" returned = @cmock_generator_plugin_return_thru_ptr.mock_function_declarations(@void_ptr_func) From 001bbeca51c7b9ab1f34e0b8ce23ef24f19f222c Mon Sep 17 00:00:00 2001 From: Mark VanderVoord Date: Fri, 22 Mar 2024 21:41:45 -0400 Subject: [PATCH 23/35] :beetle: `:fail_on_unexpected_calls` options now insists on required `:ignore plugin` (#376) --- README.md | 14 ++++++++++---- lib/cmock_config.rb | 3 +++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index f8808550..631d0168 100644 --- a/README.md +++ b/README.md @@ -15,12 +15,18 @@ a test-centered build manager for unit testing C code. Getting Started =============== -If you're using Ceedling, there is no need to install CMock. It will handle it for you. -For everyone else, the simplest way is to grab it off github. You can also download it -as a zip if you prefer. The Github method looks something like this: +Your first step is to get yourself a copy of CMock. There are a number of ways to do this: + +1. If you're using Ceedling, there is no need to install CMock. It will handle it for you. + +2. The simplest way is to grab it off github. The Github method looks something like this: > git clone --recursive https://github.com/throwtheswitch/cmock.git +3. You can also grab the `zip` file from github. If you do this, you'll also need to grab yourself a +copy of Unity and CException, because github unfortunately doesn't bake dependencies into the zip +files. + Contributing to this Project ============================ @@ -41,7 +47,7 @@ API Documentation * Not sure what you're doing? * [View docs/CMock_Summary.md](docs/CMock_Summary.md) -* Interested in our MIT-style license? +* Interested in our MIT license? * [View docs/license.txt](LICENSE.txt) * Are there examples? * They are all in [/examples](examples/) diff --git a/lib/cmock_config.rb b/lib/cmock_config.rb index c811090d..f8c88f90 100644 --- a/lib/cmock_config.rb +++ b/lib/cmock_config.rb @@ -88,6 +88,9 @@ def initialize(options = nil) options[:plugins].compact! options[:plugins].map!(&:to_sym) + + raise 'The :ignore plugin is required to disable :fail_on_unexpected_calls' if (!options[:plugins].include? :ignore) && (!options[:fail_on_unexpected_calls]) + @options = options treat_as_map = standard_treat_as_map # .clone From 714619eefb61c5a0c86ba78c01f5c1b41a1e23b7 Mon Sep 17 00:00:00 2001 From: Mark VanderVoord Date: Fri, 22 Mar 2024 22:04:30 -0400 Subject: [PATCH 24/35] :beetle: protect against bad filenames with multiple `.c` instances in them (#348) --- lib/cmock_generator.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cmock_generator.rb b/lib/cmock_generator.rb index 1e710555..dfbe3e26 100644 --- a/lib/cmock_generator.rb +++ b/lib/cmock_generator.rb @@ -208,7 +208,7 @@ def create_mock_header_footer(header) end def create_source_header_section(file, filename, mock_project) - header_file = (mock_project[:folder] || '') + filename.gsub('.c', mock_project[:module_ext]) + header_file = (mock_project[:folder] || '') + filename.sub(/.*\K\.c/, mock_project[:module_ext]) file << "/* AUTOGENERATED FILE. DO NOT EDIT. */\n" unless mock_project[:parsed_stuff][:functions].empty? file << "#include \n" file << "#include \n" From ecaccb428bedcc4ea012e792eadeafbd961c256b Mon Sep 17 00:00:00 2001 From: Mark VanderVoord Date: Tue, 26 Mar 2024 22:29:06 -0400 Subject: [PATCH 25/35] :beetle: remove unused AbortFrame (#316) --- lib/cmock_generator.rb | 3 --- test/unit/cmock_generator_main_test.rb | 6 ++---- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/lib/cmock_generator.rb b/lib/cmock_generator.rb index dfbe3e26..2713e50a 100644 --- a/lib/cmock_generator.rb +++ b/lib/cmock_generator.rb @@ -251,9 +251,6 @@ def create_instance_structure(file, mock_project) 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" diff --git a/test/unit/cmock_generator_main_test.rb b/test/unit/cmock_generator_main_test.rb index f8b5daed..57d147fc 100644 --- a/test/unit/cmock_generator_main_test.rb +++ b/test/unit/cmock_generator_main_test.rb @@ -412,8 +412,7 @@ def helper_create_header_top_with_opt_includes_form_config_and_plugin(ext) it "create extern declarations for source file" do output = [] - expected = [ "extern jmp_buf AbortFrame;\n", - "\n" ] + expected = [ "\n" ] @cmock_generator.create_extern_declarations(output) @@ -422,8 +421,7 @@ def helper_create_header_top_with_opt_includes_form_config_and_plugin(ext) it "create extern declarations for source file when using strict ordering" do output = [] - expected = [ "extern jmp_buf AbortFrame;\n", - "extern int GlobalExpectCount;\n", + expected = [ "extern int GlobalExpectCount;\n", "extern int GlobalVerifyOrder;\n", "\n" ] From 93e2f528cc35ee0775a4d0b504b20ae04192f731 Mon Sep 17 00:00:00 2001 From: Mark VanderVoord Date: Tue, 2 Apr 2024 17:40:40 -0400 Subject: [PATCH 26/35] Update example project to handle pointers of different sizes and not complain on modern platforms. --- examples/temp_sensor/src/AT91SAM7X256.h | 25 ++++----- .../src/TimerInterruptConfigurator.c | 2 +- examples/temp_sensor/targets/gcc.yml | 54 +++++++++++++++++-- examples/temp_sensor/targets/iar_v4.yml | 54 +++++++++++++++++-- examples/temp_sensor/targets/iar_v5.yml | 54 +++++++++++++++++-- .../test/TestTimerInterruptConfigurator.c | 4 +- 6 files changed, 167 insertions(+), 26 deletions(-) diff --git a/examples/temp_sensor/src/AT91SAM7X256.h b/examples/temp_sensor/src/AT91SAM7X256.h index baa03139..990c97f5 100644 --- a/examples/temp_sensor/src/AT91SAM7X256.h +++ b/examples/temp_sensor/src/AT91SAM7X256.h @@ -45,15 +45,16 @@ #define AT91SAM7X256_H typedef volatile unsigned int AT91_REG;// Hardware register definition +typedef volatile void* AT91_PTR;// Hardware register pointer // ***************************************************************************** // SOFTWARE API DEFINITION FOR System Peripherals // ***************************************************************************** typedef struct _AT91S_SYS { AT91_REG AIC_SMR[32]; // Source Mode Register - AT91_REG AIC_SVR[32]; // Source Vector Register - AT91_REG AIC_IVR; // IRQ Vector Register - AT91_REG AIC_FVR; // FIQ Vector Register + AT91_PTR AIC_SVR[32]; // Source Vector Register + AT91_PTR AIC_IVR; // IRQ Vector Register + AT91_PTR AIC_FVR; // FIQ Vector Register AT91_REG AIC_ISR; // Interrupt Status Register AT91_REG AIC_IPR; // Interrupt Pending Register AT91_REG AIC_IMR; // Interrupt Mask Register @@ -64,7 +65,7 @@ typedef struct _AT91S_SYS { AT91_REG AIC_ICCR; // Interrupt Clear Command Register AT91_REG AIC_ISCR; // Interrupt Set Command Register AT91_REG AIC_EOICR; // End of Interrupt Command Register - AT91_REG AIC_SPU; // Spurious Vector Register + AT91_PTR AIC_SPU; // Spurious Vector Register AT91_REG AIC_DCR; // Debug Control Register (Protect) AT91_REG Reserved1[1]; // AT91_REG AIC_FFER; // Fast Forcing Enable Register @@ -214,9 +215,9 @@ typedef struct _AT91S_SYS { // ***************************************************************************** typedef struct _AT91S_AIC { AT91_REG AIC_SMR[32]; // Source Mode Register - AT91_REG AIC_SVR[32]; // Source Vector Register - AT91_REG AIC_IVR; // IRQ Vector Register - AT91_REG AIC_FVR; // FIQ Vector Register + AT91_PTR AIC_SVR[32]; // Source Vector Register + AT91_PTR AIC_IVR; // IRQ Vector Register + AT91_PTR AIC_FVR; // FIQ Vector Register AT91_REG AIC_ISR; // Interrupt Status Register AT91_REG AIC_IPR; // Interrupt Pending Register AT91_REG AIC_IMR; // Interrupt Mask Register @@ -227,7 +228,7 @@ typedef struct _AT91S_AIC { AT91_REG AIC_ICCR; // Interrupt Clear Command Register AT91_REG AIC_ISCR; // Interrupt Set Command Register AT91_REG AIC_EOICR; // End of Interrupt Command Register - AT91_REG AIC_SPU; // Spurious Vector Register + AT91_PTR AIC_SPU; // Spurious Vector Register AT91_REG AIC_DCR; // Debug Control Register (Protect) AT91_REG Reserved1[1]; // AT91_REG AIC_FFER; // Fast Forcing Enable Register @@ -1727,14 +1728,14 @@ typedef struct _AT91S_ADC { #define AT91C_AIC_EOICR ((AT91_REG *) 0xFFFFF130) // (AIC) End of Interrupt Command Register #define AT91C_AIC_DCR ((AT91_REG *) 0xFFFFF138) // (AIC) Debug Control Register (Protect) #define AT91C_AIC_FFER ((AT91_REG *) 0xFFFFF140) // (AIC) Fast Forcing Enable Register -#define AT91C_AIC_SVR ((AT91_REG *) 0xFFFFF080) // (AIC) Source Vector Register -#define AT91C_AIC_SPU ((AT91_REG *) 0xFFFFF134) // (AIC) Spurious Vector Register +#define AT91C_AIC_SVR ((AT91_PTR *) 0xFFFFF080) // (AIC) Source Vector Register +#define AT91C_AIC_SPU ((AT91_PTR *) 0xFFFFF134) // (AIC) Spurious Vector Register #define AT91C_AIC_FFDR ((AT91_REG *) 0xFFFFF144) // (AIC) Fast Forcing Disable Register -#define AT91C_AIC_FVR ((AT91_REG *) 0xFFFFF104) // (AIC) FIQ Vector Register +#define AT91C_AIC_FVR ((AT91_PTR *) 0xFFFFF104) // (AIC) FIQ Vector Register #define AT91C_AIC_FFSR ((AT91_REG *) 0xFFFFF148) // (AIC) Fast Forcing Status Register #define AT91C_AIC_IMR ((AT91_REG *) 0xFFFFF110) // (AIC) Interrupt Mask Register #define AT91C_AIC_ISR ((AT91_REG *) 0xFFFFF108) // (AIC) Interrupt Status Register -#define AT91C_AIC_IVR ((AT91_REG *) 0xFFFFF100) // (AIC) IRQ Vector Register +#define AT91C_AIC_IVR ((AT91_PTR *) 0xFFFFF100) // (AIC) IRQ Vector Register #define AT91C_AIC_IDCR ((AT91_REG *) 0xFFFFF124) // (AIC) Interrupt Disable Command Register #define AT91C_AIC_CISR ((AT91_REG *) 0xFFFFF114) // (AIC) Core Interrupt Status Register #define AT91C_AIC_IPR ((AT91_REG *) 0xFFFFF10C) // (AIC) Interrupt Pending Register diff --git a/examples/temp_sensor/src/TimerInterruptConfigurator.c b/examples/temp_sensor/src/TimerInterruptConfigurator.c index fe603ef3..ab1283dc 100644 --- a/examples/temp_sensor/src/TimerInterruptConfigurator.c +++ b/examples/temp_sensor/src/TimerInterruptConfigurator.c @@ -36,7 +36,7 @@ void Timer_EnableInterrupt(void) static inline void SetInterruptHandler(void) { - AT91C_BASE_AIC->AIC_SVR[AT91C_ID_TC0] = (uint32)Timer_InterruptHandler; + AT91C_BASE_AIC->AIC_SVR[AT91C_ID_TC0] = Timer_InterruptHandler; } static inline void ConfigureInterruptSourceModeRegister(void) diff --git a/examples/temp_sensor/targets/gcc.yml b/examples/temp_sensor/targets/gcc.yml index f41bf07d..ac823e03 100644 --- a/examples/temp_sensor/targets/gcc.yml +++ b/examples/temp_sensor/targets/gcc.yml @@ -18,6 +18,7 @@ compiler: prefix: '-D' items: - __monitor + - UNITY_SUPPORT_64 object_files: prefix: '-o' extension: '.o' @@ -36,9 +37,56 @@ linker: extension: '.exe' destination: *build_path :cmock: - :plugins: [] - :includes: + # Core conffiguration + :plugins: [] # What plugins should be used by CMock? + :verbosity: 2 # the options being 0 errors only, 1 warnings and errors, 2 normal info, 3 verbose + :when_no_prototypes: :warn # the options being :ignore, :warn, or :erro + + # File configuration + :mock_path: './build/mocks' # Subdirectory to store mocks when generated (default: mocks) + :skeleton_path: '' # Subdirectory to store stubs when generated (default: '') + :subdir: nil # Subdirectory under mock_path to store when generated (default: nil) + :mock_prefix: 'Mock' # Prefix to append to filenames for mocks + :mock_suffix: '' # Suffix to append to filenames for mocks + + # Parser configuration + :strippables: ['(?:__attribute__\s*\([ (]*.*?[ )]*\)+)'] + :attributes: + - __ramfunc + - __irq + - __fiq + - register + - extern + :c_calling_conventions: + - __stdcall + - __cdecl + - __fastcall + :treat_externs: :exclude # the options being :include or :exclud + :treat_inlines: :exclude # the options being :include or :exclud + + # Type handling configuration + #:unity_helper_path: '' # specify a string of where to find a unity_helper.h file to discover custom type assertions + #:treat_as: {} # optionally add additional types to map custom types + #:treat_as_array: {} # hint to cmock that these types are pointers to something + #:treat_as_void: [] # hint to cmock that these types are actually aliases of void + :memcmp_if_unknown: true # allow cmock to use the memory comparison assertions for unknown types + :when_ptr: :compare_data # hint to cmock how to handle pointers in general, the options being :compare_ptr, :compare_data, or :smart + + # Mock generation configuration + :weak: '' # Symbol to use to declare weak functions + :enforce_strict_ordering: false # Do we want cmock to enforce ordering of all function calls? + :fail_on_unexpected_calls: true # Do we want cmock to fail when it encounters a function call that wasn't expected? + :callback_include_count: true # Do we want cmock to include the number of calls to this callback, when using callbacks? + :callback_after_arg_check: false # Do we want cmock to enforce an argument check first when using a callback? + :includes: # You can add additional includes here, or specify the location with the options below - Types.h - :mock_path: ./build/mocks + :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: [] # Specify a type or types that should be used for array lengths + :array_size_name: 'size|len' # Specify a name or names that CMock might automatically recognize as the length of an array + :exclude_setjmp_h: false # Don't use setjmp when running CMock. Note that this might result in late reporting or out-of-order failures. colour: true diff --git a/examples/temp_sensor/targets/iar_v4.yml b/examples/temp_sensor/targets/iar_v4.yml index 76217521..d90d8f6f 100644 --- a/examples/temp_sensor/targets/iar_v4.yml +++ b/examples/temp_sensor/targets/iar_v4.yml @@ -85,8 +85,54 @@ simulator: - -d - sim :cmock: - :plugins: [] - :includes: - - Types.h - :mock_path: ./build/mocks + # Core conffiguration + :plugins: [] # What plugins should be used by CMock? + :verbosity: 2 # the options being 0 errors only, 1 warnings and errors, 2 normal info, 3 verbose + :when_no_prototypes: :warn # the options being :ignore, :warn, or :erro + + # File configuration + :mock_path: './build/mocks' # Subdirectory to store mocks when generated (default: mocks) + :skeleton_path: './' # Subdirectory to store stubs when generated (default: '') + :subdir: nil # Subdirectory under mock_path to store when generated (default: nil) + :mock_prefix: 'Mock' # Prefix to append to filenames for mocks + :mock_suffix: '' # Suffix to append to filenames for mocks + + # Parser configuration + :strippables: ['(?:__attribute__\s*\([ (]*.*?[ )]*\)+)'] + :attributes: + - __ramfunc + - __irq + - __fiq + - register + - extern + :c_calling_conventions: + - __stdcall + - __cdecl + - __fastcall + :treat_externs: :exclude # the options being :include or :exclud + :treat_inlines: :exclude # the options being :include or :exclud + # Type handling configuration + #:unity_helper_path: '' # specify a string of where to find a unity_helper.h file to discover custom type assertions + #:treat_as: {} # optionally add additional types to map custom types + #:treat_as_array: {} # hint to cmock that these types are pointers to something + #:treat_as_void: [] # hint to cmock that these types are actually aliases of void + :memcmp_if_unknown: true # allow cmock to use the memory comparison assertions for unknown types + :when_ptr: :compare_data # hint to cmock how to handle pointers in general, the options being :compare_ptr, :compare_data, or :smart + + # Mock generation configuration + :weak: '' # Symbol to use to declare weak functions + :enforce_strict_ordering: false # Do we want cmock to enforce ordering of all function calls? + :fail_on_unexpected_calls: true # Do we want cmock to fail when it encounters a function call that wasn't expected? + :callback_include_count: true # Do we want cmock to include the number of calls to this callback, when using callbacks? + :callback_after_arg_check: false # Do we want cmock to enforce an argument check first when using a callback? + :includes: # You can add additional includes here, or specify the location with the options below + - Types.h + :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: [] # Specify a type or types that should be used for array lengths + :array_size_name: 'size|len' # Specify a name or names that CMock might automatically recognize as the length of an array + :exclude_setjmp_h: false # Don't use setjmp when running CMock. Note that this might result in late reporting or out-of-order failures. diff --git a/examples/temp_sensor/targets/iar_v5.yml b/examples/temp_sensor/targets/iar_v5.yml index 01786496..dbad401f 100644 --- a/examples/temp_sensor/targets/iar_v5.yml +++ b/examples/temp_sensor/targets/iar_v5.yml @@ -74,8 +74,54 @@ simulator: - -d - sim :cmock: - :plugins: [] - :includes: - - Types.h - :mock_path: ./build/mocks + # Core conffiguration + :plugins: [] # What plugins should be used by CMock? + :verbosity: 2 # the options being 0 errors only, 1 warnings and errors, 2 normal info, 3 verbose + :when_no_prototypes: :warn # the options being :ignore, :warn, or :erro + + # File configuration + :mock_path: './build/mocks' # Subdirectory to store mocks when generated (default: mocks) + :skeleton_path: '' # Subdirectory to store stubs when generated (default: '') + :subdir: nil # Subdirectory under mock_path to store when generated (default: nil) + :mock_prefix: 'Mock' # Prefix to append to filenames for mocks + :mock_suffix: '' # Suffix to append to filenames for mocks + + # Parser configuration + :strippables: ['(?:__attribute__\s*\([ (]*.*?[ )]*\)+)'] + :attributes: + - __ramfunc + - __irq + - __fiq + - register + - extern + :c_calling_conventions: + - __stdcall + - __cdecl + - __fastcall + :treat_externs: :exclude # the options being :include or :exclud + :treat_inlines: :exclude # the options being :include or :exclud + # Type handling configuration + #:unity_helper_path: '' # specify a string of where to find a unity_helper.h file to discover custom type assertions + #:treat_as: {} # optionally add additional types to map custom types + #:treat_as_array: {} # hint to cmock that these types are pointers to something + #:treat_as_void: [] # hint to cmock that these types are actually aliases of void + :memcmp_if_unknown: true # allow cmock to use the memory comparison assertions for unknown types + :when_ptr: :compare_data # hint to cmock how to handle pointers in general, the options being :compare_ptr, :compare_data, or :smart + + # Mock generation configuration + :weak: '' # Symbol to use to declare weak functions + :enforce_strict_ordering: false # Do we want cmock to enforce ordering of all function calls? + :fail_on_unexpected_calls: true # Do we want cmock to fail when it encounters a function call that wasn't expected? + :callback_include_count: true # Do we want cmock to include the number of calls to this callback, when using callbacks? + :callback_after_arg_check: false # Do we want cmock to enforce an argument check first when using a callback? + :includes: # You can add additional includes here, or specify the location with the options below + - Types.h + :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: [] # Specify a type or types that should be used for array lengths + :array_size_name: 'size|len' # Specify a name or names that CMock might automatically recognize as the length of an array + :exclude_setjmp_h: false # Don't use setjmp when running CMock. Note that this might result in late reporting or out-of-order failures. diff --git a/examples/temp_sensor/test/TestTimerInterruptConfigurator.c b/examples/temp_sensor/test/TestTimerInterruptConfigurator.c index 95265252..a32ff26d 100644 --- a/examples/temp_sensor/test/TestTimerInterruptConfigurator.c +++ b/examples/temp_sensor/test/TestTimerInterruptConfigurator.c @@ -35,9 +35,9 @@ void testResetSystemTimeDelegatesTo_Timer_SetSystemTime_Appropriately(void) void testConfigureInterruptShouldSetInterruptHandlerAppropriately(void) { - AT91C_BASE_AIC->AIC_SVR[AT91C_ID_TC0] = (uint32)0; + AT91C_BASE_AIC->AIC_SVR[AT91C_ID_TC0] = 0; Timer_ConfigureInterrupt(); - TEST_ASSERT_EQUAL((uint32)Timer_InterruptHandler, AT91C_BASE_AIC->AIC_SVR[AT91C_ID_TC0]); + TEST_ASSERT_EQUAL_PTR(Timer_InterruptHandler, AT91C_BASE_AIC->AIC_SVR[AT91C_ID_TC0]); } void testConfigureInterruptShouldSetInterruptLevelInSourceModeRegisterAppropriately(void) From 9cc8fb5302cbedd8bdf8d6c2ff37fdda082ea7f6 Mon Sep 17 00:00:00 2001 From: Mark VanderVoord Date: Tue, 2 Apr 2024 18:44:35 -0400 Subject: [PATCH 27/35] Let's enable validation of examples. failures should trip errors. Also make them verbose so we can see what is going on. --- examples/make_example/Makefile | 2 +- examples/make_example/test/test_foo.c | 2 +- examples/temp_sensor/rakefile_helper.rb | 2 +- lib/cmock.rb | 2 +- test/rakefile | 2 +- test/rakefile_helper.rb | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/make_example/Makefile b/examples/make_example/Makefile index a0fe5322..329f7901 100644 --- a/examples/make_example/Makefile +++ b/examples/make_example/Makefile @@ -23,7 +23,7 @@ ${BUILD_DIR}/main: ${SRC_DIR}/main.c ${SRC_DIR}/foo.c ${CC} $< -o $@ run: - ./build/main || true + ./build/main test: setup diff --git a/examples/make_example/test/test_foo.c b/examples/make_example/test/test_foo.c index 80f17f33..3531e681 100644 --- a/examples/make_example/test/test_foo.c +++ b/examples/make_example/test/test_foo.c @@ -13,5 +13,5 @@ void test_foo_init_should_initialize_multiplier() { foo_init(); - TEST_ASSERT_FALSE(1); + TEST_ASSERT_FALSE(0); } diff --git a/examples/temp_sensor/rakefile_helper.rb b/examples/temp_sensor/rakefile_helper.rb index 5a9735bc..4d9bd50d 100644 --- a/examples/temp_sensor/rakefile_helper.rb +++ b/examples/temp_sensor/rakefile_helper.rb @@ -236,7 +236,7 @@ def run_tests(test_files) else "#{simulator[:command]} #{simulator[:pre_support]} #{executable} #{simulator[:post_support]}" end - output = execute(cmd_str, true, true) + output = execute(cmd_str, true) test_results = $cfg['compiler']['build_path'] + test_base test_results += if output.match(/OK$/m).nil? '.testfail' diff --git a/lib/cmock.rb b/lib/cmock.rb index 36b9e053..0f6a950e 100644 --- a/lib/cmock.rb +++ b/lib/cmock.rb @@ -99,7 +99,7 @@ def option_maker(options, key, val) # --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)) - when /^--([a-zA-Z0-9._\\\/:\s]+)="?([a-zA-Z0-9._\-\\\/:\s;]*)"?/x + when /^--([a-zA-Z0-9._\\\/:\s]+)="?([a-zA-Z0-9._\-\\\/:\s;@#%!$&\(\)\*]*)"?/x options = option_maker(options, Regexp.last_match(1), Regexp.last_match(2)) else diff --git a/test/rakefile b/test/rakefile index fe64f5df..a03daf58 100644 --- a/test/rakefile +++ b/test/rakefile @@ -91,7 +91,7 @@ namespace :test do desc "Test cmock examples" task :examples => [:prep_system_tests] do - run_examples() + run_examples(true) end #individual system tests diff --git a/test/rakefile_helper.rb b/test/rakefile_helper.rb index bbe3eb96..01c92520 100644 --- a/test/rakefile_helper.rb +++ b/test/rakefile_helper.rb @@ -395,7 +395,7 @@ def build_and_test_c_files end end - def run_examples() + def run_examples(verbose=false, raise_on_failure=true) report "\n" report "-----------------\n" report "VALIDATE EXAMPLES\n" @@ -404,7 +404,7 @@ def run_examples() "cd #{File.join("..","examples","temp_sensor")} && rake ci" ].each do |cmd| report "Testing '#{cmd}'" - execute(cmd, false) + execute(cmd, verbose, raise_on_failure) end end From df73448935290296252a0b87899a639728fa7f14 Mon Sep 17 00:00:00 2001 From: Mark VanderVoord Date: Tue, 2 Apr 2024 19:13:31 -0400 Subject: [PATCH 28/35] Remove some stuff that shouldn't really be in config file. --- examples/temp_sensor/targets/gcc.yml | 14 ++++++-------- examples/temp_sensor/targets/iar_v4.yml | 14 ++++++-------- examples/temp_sensor/targets/iar_v5.yml | 14 ++++++-------- 3 files changed, 18 insertions(+), 24 deletions(-) diff --git a/examples/temp_sensor/targets/gcc.yml b/examples/temp_sensor/targets/gcc.yml index ac823e03..76f724ef 100644 --- a/examples/temp_sensor/targets/gcc.yml +++ b/examples/temp_sensor/targets/gcc.yml @@ -45,7 +45,6 @@ linker: # File configuration :mock_path: './build/mocks' # Subdirectory to store mocks when generated (default: mocks) :skeleton_path: '' # Subdirectory to store stubs when generated (default: '') - :subdir: nil # Subdirectory under mock_path to store when generated (default: nil) :mock_prefix: 'Mock' # Prefix to append to filenames for mocks :mock_suffix: '' # Suffix to append to filenames for mocks @@ -80,13 +79,12 @@ linker: :callback_after_arg_check: false # Do we want cmock to enforce an argument check first when using a callback? :includes: # You can add additional includes here, or specify the location with the options below - Types.h - :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: [] # Specify a type or types that should be used for array lengths - :array_size_name: 'size|len' # Specify a name or names that CMock might automatically recognize as the length of an array + #:includes_h_pre_orig_header: [] + #:includes_h_post_orig_header: [] + #:includes_c_pre_header: [] + #:includes_c_post_header: [] + #:array_size_type: [] # Specify a type or types that should be used for array lengths + #:array_size_name: 'size|len' # Specify a name or names that CMock might automatically recognize as the length of an array :exclude_setjmp_h: false # Don't use setjmp when running CMock. Note that this might result in late reporting or out-of-order failures. colour: true diff --git a/examples/temp_sensor/targets/iar_v4.yml b/examples/temp_sensor/targets/iar_v4.yml index d90d8f6f..24febbaf 100644 --- a/examples/temp_sensor/targets/iar_v4.yml +++ b/examples/temp_sensor/targets/iar_v4.yml @@ -93,7 +93,6 @@ simulator: # File configuration :mock_path: './build/mocks' # Subdirectory to store mocks when generated (default: mocks) :skeleton_path: './' # Subdirectory to store stubs when generated (default: '') - :subdir: nil # Subdirectory under mock_path to store when generated (default: nil) :mock_prefix: 'Mock' # Prefix to append to filenames for mocks :mock_suffix: '' # Suffix to append to filenames for mocks @@ -128,11 +127,10 @@ simulator: :callback_after_arg_check: false # Do we want cmock to enforce an argument check first when using a callback? :includes: # You can add additional includes here, or specify the location with the options below - Types.h - :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: [] # Specify a type or types that should be used for array lengths - :array_size_name: 'size|len' # Specify a name or names that CMock might automatically recognize as the length of an array + #:includes_h_pre_orig_header: [] + #:includes_h_post_orig_header: [] + #:includes_c_pre_header: [] + #:includes_c_post_header: [] + #:array_size_type: [] # Specify a type or types that should be used for array lengths + #:array_size_name: 'size|len' # Specify a name or names that CMock might automatically recognize as the length of an array :exclude_setjmp_h: false # Don't use setjmp when running CMock. Note that this might result in late reporting or out-of-order failures. diff --git a/examples/temp_sensor/targets/iar_v5.yml b/examples/temp_sensor/targets/iar_v5.yml index dbad401f..69a39ee8 100644 --- a/examples/temp_sensor/targets/iar_v5.yml +++ b/examples/temp_sensor/targets/iar_v5.yml @@ -82,7 +82,6 @@ simulator: # File configuration :mock_path: './build/mocks' # Subdirectory to store mocks when generated (default: mocks) :skeleton_path: '' # Subdirectory to store stubs when generated (default: '') - :subdir: nil # Subdirectory under mock_path to store when generated (default: nil) :mock_prefix: 'Mock' # Prefix to append to filenames for mocks :mock_suffix: '' # Suffix to append to filenames for mocks @@ -117,11 +116,10 @@ simulator: :callback_after_arg_check: false # Do we want cmock to enforce an argument check first when using a callback? :includes: # You can add additional includes here, or specify the location with the options below - Types.h - :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: [] # Specify a type or types that should be used for array lengths - :array_size_name: 'size|len' # Specify a name or names that CMock might automatically recognize as the length of an array + #:includes_h_pre_orig_header: [] + #:includes_h_post_orig_header: [] + #:includes_c_pre_header: [] + #:includes_c_post_header: [] + #:array_size_type: [] # Specify a type or types that should be used for array lengths + #:array_size_name: 'size|len' # Specify a name or names that CMock might automatically recognize as the length of an array :exclude_setjmp_h: false # Don't use setjmp when running CMock. Note that this might result in late reporting or out-of-order failures. From 119f6607d90f57a85ab6e8ddea8a6d6d25fd7c40 Mon Sep 17 00:00:00 2001 From: Mark VanderVoord Date: Tue, 2 Apr 2024 19:28:29 -0400 Subject: [PATCH 29/35] Don't need to escape symbols in brackets --- lib/cmock.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cmock.rb b/lib/cmock.rb index 0f6a950e..0e5cc7ad 100644 --- a/lib/cmock.rb +++ b/lib/cmock.rb @@ -99,7 +99,7 @@ def option_maker(options, key, val) # --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)) - when /^--([a-zA-Z0-9._\\\/:\s]+)="?([a-zA-Z0-9._\-\\\/:\s;@#%!$&\(\)\*]*)"?/x + when /^--([a-zA-Z0-9._\\\/:\s]+)="?([a-zA-Z0-9._\-\\\/:\s;@#%!$&()*]*)"?/x options = option_maker(options, Regexp.last_match(1), Regexp.last_match(2)) else From c83f8bddf28d23e8bb2e5287fb5eef66d1fe452e Mon Sep 17 00:00:00 2001 From: Mark VanderVoord Date: Thu, 1 Aug 2024 11:47:58 -0400 Subject: [PATCH 30/35] Working towards gemifying and automatically reporting version. --- Gemfile | 7 ------- cmock.gemspec | 34 ++++++++++++++++++++++++++++++++++ lib/cmock.rb | 6 ++++++ lib/cmock_version.rb | 23 +++++++++++++++++++++++ 4 files changed, 63 insertions(+), 7 deletions(-) create mode 100644 cmock.gemspec create mode 100644 lib/cmock_version.rb diff --git a/Gemfile b/Gemfile index 96ac06ec..c6d4f853 100644 --- a/Gemfile +++ b/Gemfile @@ -1,8 +1 @@ source "http://rubygems.org/" - -gem "bundler" -gem "rake" -gem "minitest" -gem "require_all" -gem "constructor" -gem "diy" diff --git a/cmock.gemspec b/cmock.gemspec new file mode 100644 index 00000000..9253126d --- /dev/null +++ b/cmock.gemspec @@ -0,0 +1,34 @@ +# -*- encoding: utf-8 -*- +$LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__), 'lib')) +require "lib/cmock_version" +require 'date' + +Gem::Specification.new do |s| + s.name = "cmock" + s.version = CMockVersion::GEM + s.platform = Gem::Platform::RUBY + s.authors = ["Mark VanderVoord", "Michael Karlesky", "Greg Williams"] + s.email = ["mark@vandervoord.net", "michael@karlesky.net", "barney.williams@gmail.com"] + s.homepage = "http://throwtheswitch.org/cmock" + s.summary = "CMock is a mocking framework for C unit testing. It's a member of the ThrowTheSwitch.org family of tools." + s.description = <<-DESC +CMock is a mocking framework for C unit testing. It accepts header files and generates mocks automagically for you. + DESC + s.licenses = ['MIT'] + + s.metadata = { + "homepage_uri" => s.homepage, + "bug_tracker_uri" => "https://github.com/ThrowTheSwitch/CMock/issues", + "documentation_uri" => "https://github.com/ThrowTheSwitch/CMock/blob/master/docs/CMock_Summary.md", + "mailing_list_uri" => "https://groups.google.com/forum/#!categories/throwtheswitch/cmock", + "source_code_uri" => "https://github.com/ThrowTheSwitch/CMock" + } + + s.required_ruby_version = ">= 3.0.0" + + s.files += Dir['**/*'] + s.test_files = Dir['test/**/*'] + s.executables = ['lib/cmock.rb'] + + s.require_paths = ["lib"] +end diff --git a/lib/cmock.rb b/lib/cmock.rb index 0e5cc7ad..daa34048 100644 --- a/lib/cmock.rb +++ b/lib/cmock.rb @@ -1,3 +1,4 @@ +#!/bin/ruby # ========================================== # CMock Project - Automatic Mock Generation for C # Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams @@ -95,6 +96,11 @@ def option_maker(options, key, val) opt_flag = true when '--skeleton' options[:skeleton] = true + when '--version' + require 'cmock_version' + include CMockVersion + puts CMOCK_VERSION + exit(0) when /^--strippables="?(.*)"?/ # --strippables are dealt with separately since the user is allowed to # enter any valid regular expression as argument diff --git a/lib/cmock_version.rb b/lib/cmock_version.rb new file mode 100644 index 00000000..dc77c23e --- /dev/null +++ b/lib/cmock_version.rb @@ -0,0 +1,23 @@ + +module CMockVersion + # Where is the header file from here? + path = File.expand_path( File.join(File.dirname(__FILE__),"..","src","cmock.h") ) + + # Actually look up the version in the header file + a = [0,0,0] + begin + File.readlines(path).each do |line| + ["VERSION_MAJOR", "VERSION_MINOR", "VERSION_BUILD"].each_with_index do |field, i| + m = line.match(/CMOCK_#{field}\s+(\d+)/) + a[i] = m[1] unless (m.nil?) + end + end + rescue + abort("Can't find my header file.") + end + + # splat it to return the final value + CMOCK_VERSION = "#{a.join(".")}" + + GEM = "0.32.0" +end From 6b0587fce562733999348ff68940b2d7ac01715c Mon Sep 17 00:00:00 2001 From: Mark VanderVoord Date: Thu, 1 Aug 2024 12:12:08 -0400 Subject: [PATCH 31/35] Fixes to latest stylistic warnings. --- lib/cmock.rb | 0 lib/cmock_version.rb | 17 ++++++++--------- 2 files changed, 8 insertions(+), 9 deletions(-) mode change 100644 => 100755 lib/cmock.rb diff --git a/lib/cmock.rb b/lib/cmock.rb old mode 100644 new mode 100755 diff --git a/lib/cmock_version.rb b/lib/cmock_version.rb index dc77c23e..d4fa78f0 100644 --- a/lib/cmock_version.rb +++ b/lib/cmock_version.rb @@ -1,23 +1,22 @@ - module CMockVersion # Where is the header file from here? - path = File.expand_path( File.join(File.dirname(__FILE__),"..","src","cmock.h") ) + path = File.expand_path(File.join(File.dirname(__FILE__), '..', 'src', 'cmock.h')) # Actually look up the version in the header file - a = [0,0,0] + a = [0, 0, 0] begin File.readlines(path).each do |line| - ["VERSION_MAJOR", "VERSION_MINOR", "VERSION_BUILD"].each_with_index do |field, i| + %w[VERSION_MAJOR VERSION_MINOR VERSION_BUILD].each_with_index do |field, i| m = line.match(/CMOCK_#{field}\s+(\d+)/) - a[i] = m[1] unless (m.nil?) + a[i] = m[1] unless m.nil? end end - rescue - abort("Can't find my header file.") + rescue StandardError + abort('Can\'t find my header file.') end # splat it to return the final value - CMOCK_VERSION = "#{a.join(".")}" + CMOCK_VERSION = a.join('.') - GEM = "0.32.0" + GEM = CMOCK_VERSION end From 74b8ed295ab6ce1212502ab5ab2de9bf9b2decde Mon Sep 17 00:00:00 2001 From: Mark VanderVoord Date: Thu, 1 Aug 2024 13:55:45 -0400 Subject: [PATCH 32/35] Bump dependencies --- vendor/c_exception | 2 +- vendor/unity | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/vendor/c_exception b/vendor/c_exception index 12dd9808..be54d744 160000 --- a/vendor/c_exception +++ b/vendor/c_exception @@ -1 +1 @@ -Subproject commit 12dd980876cb351db29ce41fadcc9fdb4f255f75 +Subproject commit be54d7440e0d9c78515070665892af4e15f8b14c diff --git a/vendor/unity b/vendor/unity index 85452ad1..18fb3392 160000 --- a/vendor/unity +++ b/vendor/unity @@ -1 +1 @@ -Subproject commit 85452ad1544f77d752a2444eb8859f73346bfb97 +Subproject commit 18fb33921f1bb973c81a9ce740c52b92a152333d From 43618c8c78b1383841f5b8c7bd934484ba4a72b4 Mon Sep 17 00:00:00 2001 From: Mark VanderVoord Date: Thu, 3 Oct 2024 10:03:33 -0400 Subject: [PATCH 33/35] :bug: Fix problem if unity helper path is specified as relative path starting with .. --- lib/cmock_config.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cmock_config.rb b/lib/cmock_config.rb index f8c88f90..c1b495f8 100644 --- a/lib/cmock_config.rb +++ b/lib/cmock_config.rb @@ -81,7 +81,7 @@ def initialize(options = nil) 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 + Pathname(File.expand_path(path)).relative_path_from(Pathname(File.expand_path(options[:mock_path]))).to_s end options[:includes_c_post_header] = (includes1 + includes2).uniq end From 7d6ec0354a4087605ac865d5876f90f6fb9781ac Mon Sep 17 00:00:00 2001 From: Mark VanderVoord Date: Wed, 23 Oct 2024 15:35:37 -0400 Subject: [PATCH 34/35] If a short-path cannot be created, fallback to absolute path, even though it's more verbose. --- lib/cmock_config.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/cmock_config.rb b/lib/cmock_config.rb index c1b495f8..1b3acfd8 100644 --- a/lib/cmock_config.rb +++ b/lib/cmock_config.rb @@ -81,7 +81,11 @@ def initialize(options = nil) require 'pathname' includes1 = options[:includes_c_post_header] || [] includes2 = options[:unity_helper_path].map do |path| - Pathname(File.expand_path(path)).relative_path_from(Pathname(File.expand_path(options[:mock_path]))).to_s + begin + Pathname(File.expand_path(path)).relative_path_from(Pathname(File.expand_path(options[:mock_path]))).to_s + rescue + path + end end options[:includes_c_post_header] = (includes1 + includes2).uniq end From d5e938e4b1ffc64acc70c7cf9b7ac6591f806c0b Mon Sep 17 00:00:00 2001 From: Mark VanderVoord Date: Wed, 23 Oct 2024 16:01:48 -0400 Subject: [PATCH 35/35] - refactor to match coding standards. - test against Ruby 3.3 also. --- .github/workflows/main.yml | 2 +- lib/cmock_config.rb | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a9bf8b7e..9c89b144 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - ruby: ['3.0', '3.1', '3.2'] + ruby: ['3.0', '3.1', '3.2', '3.3'] steps: # Install Multilib - name: Install Multilib diff --git a/lib/cmock_config.rb b/lib/cmock_config.rb index 1b3acfd8..8bb6b5a1 100644 --- a/lib/cmock_config.rb +++ b/lib/cmock_config.rb @@ -81,11 +81,9 @@ def initialize(options = nil) require 'pathname' includes1 = options[:includes_c_post_header] || [] includes2 = options[:unity_helper_path].map do |path| - begin - Pathname(File.expand_path(path)).relative_path_from(Pathname(File.expand_path(options[:mock_path]))).to_s - rescue - path - end + Pathname(File.expand_path(path)).relative_path_from(Pathname(File.expand_path(options[:mock_path]))).to_s + rescue StandardError + path end options[:includes_c_post_header] = (includes1 + includes2).uniq end