From b735d096031a15da58f456410446e09da652b707 Mon Sep 17 00:00:00 2001 From: cloudsftp Date: Tue, 18 Aug 2020 15:25:55 +0200 Subject: [PATCH 1/7] add plugin :ignore_stateless that solves ThrowTheSwitch/CMock#307 --- ...cmock_generator_plugin_ignore_stateless.rb | 85 +++++++++++++++++++ lib/cmock_generator_utils.rb | 3 +- 2 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 lib/cmock_generator_plugin_ignore_stateless.rb diff --git a/lib/cmock_generator_plugin_ignore_stateless.rb b/lib/cmock_generator_plugin_ignore_stateless.rb new file mode 100644 index 0000000..64f797e --- /dev/null +++ b/lib/cmock_generator_plugin_ignore_stateless.rb @@ -0,0 +1,85 @@ +# ========================================== +# CMock Project - Automatic Mock Generation for C +# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams +# [Released under MIT License. Please refer to license.txt for details] +# +# !!! This file is not included in the original Cmock framework !!! +# Adjusted copy of cmock_generator_plugin_ignore.rb +# ========================================== + +class CMockGeneratorPluginIgnoreStateless + attr_reader :priority + attr_reader :config, :utils + + def initialize(config, utils) + @config = config + @utils = utils + @priority = 2 + end + + def instance_structure(function) + if function[:return][:void?] + " char #{function[:name]}_IgnoreBool;\n" + else + " char #{function[:name]}_IgnoreBool;\n #{function[:return][:type]} #{function[:name]}_FinalReturn;\n" + end + end + + def mock_function_declarations(function) + lines = if (function[:return][:void?]) + "#define #{function[:name]}_Ignore() #{function[:name]}_CMockIgnore()\n" + + "void #{function[:name]}_CMockIgnore(void);\n" + else + "#define #{function[:name]}_IgnoreAndReturn(cmock_retval) #{function[:name]}_CMockIgnoreAndReturn(__LINE__, cmock_retval)\n" + + "void #{function[:name]}_CMockIgnoreAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]});\n"; + end + + # Add stop ignore function. it does not matter if there are any args + lines << "#define #{function[:name]}_StopIgnore() #{function[:name]}_CMockStopIgnore()\n" \ + "void #{function[:name]}_CMockStopIgnore(void);\n" + lines + end + + def mock_implementation_precheck(function) + lines = " if (Mock.#{function[:name]}_IgnoreBool)\n {\n" + lines << " UNITY_CLR_DETAILS();\n" + if function[:return][:void?] + lines << " return;\n }\n" + else + retval = function[:return].merge(:name => 'cmock_call_instance->ReturnVal') + lines << " if (cmock_call_instance == NULL)\n return Mock.#{function[:name]}_FinalReturn;\n" + lines << ' ' + @utils.code_assign_argument_quickly("Mock.#{function[:name]}_FinalReturn", retval) unless retval[:void?] + lines << " return cmock_call_instance->ReturnVal;\n }\n" + end + lines + end + + # this function is adjusted + def mock_interfaces(function) + lines = '' + lines << if function[:return][:void?] + "void #{function[:name]}_CMockIgnore(void)\n{\n" + else + "void #{function[:name]}_CMockIgnoreAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]})\n{\n" + end + unless function[:return][:void?] + lines << " Mock.#{function[:name]}_CallInstance = CMOCK_GUTS_NONE;\n" + end + unless function[:return][:void?] + lines << " Mock.#{function[:name]}_FinalReturn = cmock_to_return;\n" + end + lines << " Mock.#{function[:name]}_IgnoreBool = (char) 1;\n" + lines << "}\n\n" + + lines + end + + def mock_ignore(function) + " Mock.#{function[:name]}_IgnoreBool = (char) 1;\n" + end + + def mock_verify(function) + func_name = function[:name] + " if (Mock.#{func_name}_IgnoreBool)\n call_instance = CMOCK_GUTS_NONE;\n" + end +end diff --git a/lib/cmock_generator_utils.rb b/lib/cmock_generator_utils.rb index 11225d6..0dc4aa9 100644 --- a/lib/cmock_generator_utils.rb +++ b/lib/cmock_generator_utils.rb @@ -17,6 +17,7 @@ class CMockGeneratorUtils @return_thru_ptr = @config.plugins.include? :return_thru_ptr @ignore_arg = @config.plugins.include? :ignore_arg @ignore = @config.plugins.include? :ignore + @ignore_stateless = @config.plugins.include? :ignore_stateless # added line @treat_as = @config.treat_as @helpers = helpers end @@ -52,7 +53,7 @@ class CMockGeneratorUtils lines << " UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringOutOfMemory);\n" lines << " memset(cmock_call_instance, 0, sizeof(*cmock_call_instance));\n" lines << " Mock.#{func_name}_CallInstance = CMock_Guts_MemChain(Mock.#{func_name}_CallInstance, cmock_guts_index);\n" - lines << " Mock.#{func_name}_IgnoreBool = (char)0;\n" if @ignore + lines << " Mock.#{func_name}_IgnoreBool = (char)0;\n" if @ignore || @ignore_stateless # altered line lines << " cmock_call_instance->LineNumber = cmock_line;\n" lines << " cmock_call_instance->CallOrder = ++GlobalExpectCount;\n" if @ordered && global_ordering_supported lines << " cmock_call_instance->ExceptionToThrow = CEXCEPTION_NONE;\n" if @cexception From d36662da2a01ef4429eddc59d0cd4cc930e44ce5 Mon Sep 17 00:00:00 2001 From: cloudsftp Date: Tue, 18 Aug 2020 15:33:51 +0200 Subject: [PATCH 2/7] repair failing unit tests for plugins --- test/unit/cmock_generator_utils_test.rb | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/test/unit/cmock_generator_utils_test.rb b/test/unit/cmock_generator_utils_test.rb index ab9df2a..b1f3268 100644 --- a/test/unit/cmock_generator_utils_test.rb +++ b/test/unit/cmock_generator_utils_test.rb @@ -20,17 +20,19 @@ describe CMockGeneratorUtils, "Verify CMockGeneratorUtils Module" do @config.expect :plugins, [] @config.expect :plugins, [] @config.expect :plugins, [] + @config.expect :plugins, [] @config.expect :treat_as, {'int' => 'INT','short' => 'INT16','long' => 'INT','char' => 'INT8','const char*' => 'STRING'} @cmock_generator_utils_simple = CMockGeneratorUtils.new(@config, {:unity_helper => @unity_helper}) @config.expect :when_ptr, :smart @config.expect :enforce_strict_ordering, true - @config.expect :plugins, [:array, :cexception, :return_thru_ptr, :ignore_arg, :ignore] - @config.expect :plugins, [:array, :cexception, :return_thru_ptr, :ignore_arg, :ignore] - @config.expect :plugins, [:array, :cexception, :return_thru_ptr, :ignore_arg, :ignore] - @config.expect :plugins, [:array, :cexception, :return_thru_ptr, :ignore_arg, :ignore] - @config.expect :plugins, [:array, :cexception, :return_thru_ptr, :ignore_arg, :ignore] - @config.expect :plugins, [:array, :cexception, :return_thru_ptr, :ignore_arg, :ignore] + @config.expect :plugins, [:array, :cexception, :return_thru_ptr, :ignore_arg, :ignore, :ignore_stateless] + @config.expect :plugins, [:array, :cexception, :return_thru_ptr, :ignore_arg, :ignore, :ignore_stateless] + @config.expect :plugins, [:array, :cexception, :return_thru_ptr, :ignore_arg, :ignore, :ignore_stateless] + @config.expect :plugins, [:array, :cexception, :return_thru_ptr, :ignore_arg, :ignore, :ignore_stateless] + @config.expect :plugins, [:array, :cexception, :return_thru_ptr, :ignore_arg, :ignore, :ignore_stateless] + @config.expect :plugins, [:array, :cexception, :return_thru_ptr, :ignore_arg, :ignore, :ignore_stateless] + @config.expect :plugins, [:array, :cexception, :return_thru_ptr, :ignore_arg, :ignore, :ignore_stateless] @config.expect :treat_as, {'int' => 'INT','short' => 'INT16','long' => 'INT','char' => 'INT8','uint32_t' => 'HEX32','const char*' => 'STRING'} @cmock_generator_utils_complex = CMockGeneratorUtils.new(@config, {:unity_helper => @unity_helper, :A=>1, :B=>2}) end From 94ca64506104023053f22d9c39d71b03862341f5 Mon Sep 17 00:00:00 2001 From: cloudsftp Date: Tue, 18 Aug 2020 16:31:45 +0200 Subject: [PATCH 3/7] add first simple test and remove warning "unused parameter" --- ...cmock_generator_plugin_ignore_stateless.rb | 11 ++---- lib/cmock_generator_utils.rb | 4 +- .../ignore_and_return_stateless.yml | 39 +++++++++++++++++++ 3 files changed, 44 insertions(+), 10 deletions(-) create mode 100644 test/system/test_interactions/ignore_and_return_stateless.yml diff --git a/lib/cmock_generator_plugin_ignore_stateless.rb b/lib/cmock_generator_plugin_ignore_stateless.rb index 64f797e..fa39334 100644 --- a/lib/cmock_generator_plugin_ignore_stateless.rb +++ b/lib/cmock_generator_plugin_ignore_stateless.rb @@ -2,9 +2,6 @@ # CMock Project - Automatic Mock Generation for C # Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams # [Released under MIT License. Please refer to license.txt for details] -# -# !!! This file is not included in the original Cmock framework !!! -# Adjusted copy of cmock_generator_plugin_ignore.rb # ========================================== class CMockGeneratorPluginIgnoreStateless @@ -30,8 +27,8 @@ class CMockGeneratorPluginIgnoreStateless "#define #{function[:name]}_Ignore() #{function[:name]}_CMockIgnore()\n" + "void #{function[:name]}_CMockIgnore(void);\n" else - "#define #{function[:name]}_IgnoreAndReturn(cmock_retval) #{function[:name]}_CMockIgnoreAndReturn(__LINE__, cmock_retval)\n" + - "void #{function[:name]}_CMockIgnoreAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]});\n"; + "#define #{function[:name]}_IgnoreAndReturn(cmock_retval) #{function[:name]}_CMockIgnoreAndReturn(cmock_retval)\n" + + "void #{function[:name]}_CMockIgnoreAndReturn(#{function[:return][:str]});\n"; end # Add stop ignore function. it does not matter if there are any args @@ -60,12 +57,10 @@ class CMockGeneratorPluginIgnoreStateless lines << if function[:return][:void?] "void #{function[:name]}_CMockIgnore(void)\n{\n" else - "void #{function[:name]}_CMockIgnoreAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]})\n{\n" + "void #{function[:name]}_CMockIgnoreAndReturn(#{function[:return][:str]})\n{\n" end unless function[:return][:void?] lines << " Mock.#{function[:name]}_CallInstance = CMOCK_GUTS_NONE;\n" - end - unless function[:return][:void?] lines << " Mock.#{function[:name]}_FinalReturn = cmock_to_return;\n" end lines << " Mock.#{function[:name]}_IgnoreBool = (char) 1;\n" diff --git a/lib/cmock_generator_utils.rb b/lib/cmock_generator_utils.rb index 0dc4aa9..7e1ce51 100644 --- a/lib/cmock_generator_utils.rb +++ b/lib/cmock_generator_utils.rb @@ -17,7 +17,7 @@ class CMockGeneratorUtils @return_thru_ptr = @config.plugins.include? :return_thru_ptr @ignore_arg = @config.plugins.include? :ignore_arg @ignore = @config.plugins.include? :ignore - @ignore_stateless = @config.plugins.include? :ignore_stateless # added line + @ignore_stateless = @config.plugins.include? :ignore_stateless @treat_as = @config.treat_as @helpers = helpers end @@ -53,7 +53,7 @@ class CMockGeneratorUtils lines << " UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringOutOfMemory);\n" lines << " memset(cmock_call_instance, 0, sizeof(*cmock_call_instance));\n" lines << " Mock.#{func_name}_CallInstance = CMock_Guts_MemChain(Mock.#{func_name}_CallInstance, cmock_guts_index);\n" - lines << " Mock.#{func_name}_IgnoreBool = (char)0;\n" if @ignore || @ignore_stateless # altered line + lines << " Mock.#{func_name}_IgnoreBool = (char)0;\n" if @ignore || @ignore_stateless lines << " cmock_call_instance->LineNumber = cmock_line;\n" lines << " cmock_call_instance->CallOrder = ++GlobalExpectCount;\n" if @ordered && global_ordering_supported lines << " cmock_call_instance->ExceptionToThrow = CEXCEPTION_NONE;\n" if @cexception diff --git a/test/system/test_interactions/ignore_and_return_stateless.yml b/test/system/test_interactions/ignore_and_return_stateless.yml new file mode 100644 index 0000000..cdb3fae --- /dev/null +++ b/test/system/test_interactions/ignore_and_return_stateless.yml @@ -0,0 +1,39 @@ +--- +:cmock: + :plugins: + - 'ignore_stateless' + +:systest: + :types: | + + :mockable: | + int foo(int a); + void bar(int b); + + :source: + :header: | + int function(int a, int b, int c); + :code: | + int function(int a, int b, int c) + { + bar(b); + return foo(a) + foo(b) + foo(c); + } + + :tests: + :common: | + void setUp(void) {} + void tearDown(void) {} + + :units: + - :pass: TRUE + :should: 'successfully exercise simple ExpectAndReturn mock calls' + :code: | + test() + { + bar_Expect(2); + foo_ExpectAndReturn(1, 10); + foo_ExpectAndReturn(2, 20); + foo_ExpectAndReturn(3, 30); + TEST_ASSERT_EQUAL(60, function(1, 2, 3)); + } From 496cabff10666e3c10d3a05f1f3ea99b243bb706 Mon Sep 17 00:00:00 2001 From: cloudsftp Date: Tue, 18 Aug 2020 16:56:36 +0200 Subject: [PATCH 4/7] add more test cases for the new plugin --- .../ignore_and_return_stateless.yml | 237 ++++++++++++++++++ 1 file changed, 237 insertions(+) diff --git a/test/system/test_interactions/ignore_and_return_stateless.yml b/test/system/test_interactions/ignore_and_return_stateless.yml index cdb3fae..8fcfc48 100644 --- a/test/system/test_interactions/ignore_and_return_stateless.yml +++ b/test/system/test_interactions/ignore_and_return_stateless.yml @@ -37,3 +37,240 @@ foo_ExpectAndReturn(3, 30); TEST_ASSERT_EQUAL(60, function(1, 2, 3)); } + + - :pass: TRUE + :should: 'ignore foo() calls' + :code: | + test() + { + bar_Expect(4); + foo_IgnoreAndReturn(40); + TEST_ASSERT_EQUAL(120, function(3, 4, 3)); + } + + - :pass: TRUE + :should: 'ignore the situation where foo() is not called even though we explicitly ignored it' + :code: | + test() + { + foo_IgnoreAndReturn(20); + //notice we do not call foo + } + + - :pass: TRUE + :should: 'ignore foo() calls and always return last item' + :code: | + test() + { + bar_Expect(4); + foo_IgnoreAndReturn(20); + foo_IgnoreAndReturn(30); + TEST_ASSERT_EQUAL(90, function(3, 4, 9)); + } + + - :pass: TRUE + :should: 'ignore bar() and foo() calls' + :code: | + test() + { + bar_Ignore(); + foo_IgnoreAndReturn(50); + TEST_ASSERT_EQUAL(150, function(0, 0, 0)); + } + + - :pass: TRUE + :should: 'multiple cycles of expects still pass when ignores enabled' + :code: | + test() + { + bar_Expect(2); + foo_ExpectAndReturn(1, 50); + foo_ExpectAndReturn(2, 60); + foo_ExpectAndReturn(3, 70); + TEST_ASSERT_EQUAL(180, function(1, 2, 3)); + + bar_Expect(5); + foo_ExpectAndReturn(4, 30); + foo_ExpectAndReturn(5, 80); + foo_ExpectAndReturn(6, 10); + TEST_ASSERT_EQUAL(120, function(4, 5, 6)); + + bar_Expect(8); + foo_ExpectAndReturn(7, 70); + foo_ExpectAndReturn(8, 20); + foo_ExpectAndReturn(9, 20); + TEST_ASSERT_EQUAL(110, function(7, 8, 9)); + } + + - :pass: FALSE + :should: 'multiple cycles of expects still fail when ignores enabled' + :code: | + test() + { + bar_Expect(2); + foo_ExpectAndReturn(1, 50); + foo_ExpectAndReturn(2, 60); + foo_ExpectAndReturn(3, 70); + TEST_ASSERT_EQUAL(180, function(1, 2, 3)); + + bar_Expect(5); + foo_ExpectAndReturn(4, 30); + foo_ExpectAndReturn(5, 80); + foo_ExpectAndReturn(6, 10); + TEST_ASSERT_EQUAL(120, function(4, 5, 6)); + + bar_Expect(8); + foo_ExpectAndReturn(7, 70); + foo_ExpectAndReturn(8, 20); + foo_ExpectAndReturn(9, 20); + TEST_ASSERT_EQUAL(110, function(0, 8, 9)); + } + + - :pass: FALSE + :should: 'With "fail_on_unexpected_calls" enabled, Expect/Ignore/... of bar is required and test fails.' + :code: | + test() + { + function(1, 2, 3); + } + + - :pass: TRUE + :should: 'we can override an ignore with an expect and pass' + :code: | + test() + { + bar_Ignore(); + + bar_Expect(2); + foo_ExpectAndReturn(1, 50); + foo_ExpectAndReturn(2, 60); + foo_ExpectAndReturn(3, 70); + TEST_ASSERT_EQUAL(180, function(1, 2, 3)); + + bar_Expect(5); + foo_ExpectAndReturn(4, 30); + foo_ExpectAndReturn(5, 80); + foo_ExpectAndReturn(6, 10); + TEST_ASSERT_EQUAL(120, function(4, 5, 6)); + + bar_Expect(8); + foo_ExpectAndReturn(7, 70); + foo_ExpectAndReturn(8, 20); + foo_ExpectAndReturn(9, 20); + TEST_ASSERT_EQUAL(110, function(7, 8, 9)); + } + + - :pass: FALSE + :should: 'we can override an ignore with an expect and fail' + :code: | + test() + { + bar_Ignore(); + + bar_Expect(2); + foo_ExpectAndReturn(1, 50); + foo_ExpectAndReturn(2, 60); + foo_ExpectAndReturn(3, 70); + TEST_ASSERT_EQUAL(180, function(1, 2, 3)); + + bar_Expect(5); + foo_ExpectAndReturn(4, 30); + foo_ExpectAndReturn(5, 80); + foo_ExpectAndReturn(6, 10); + TEST_ASSERT_EQUAL(120, function(4, 5, 6)); + + bar_Expect(9); + foo_ExpectAndReturn(7, 70); + foo_ExpectAndReturn(8, 20); + foo_ExpectAndReturn(9, 20); + TEST_ASSERT_EQUAL(110, function(7, 8, 9)); + } + + - :pass: TRUE + :should: 'we can override an ignore and return with an expect and pass' + :code: | + test() + { + bar_Ignore(); + foo_IgnoreAndReturn(30); + TEST_ASSERT_EQUAL(90, function(1, 2, 3)); + + bar_Expect(5); + foo_ExpectAndReturn(4, 30); + foo_ExpectAndReturn(5, 80); + foo_ExpectAndReturn(6, 10); + TEST_ASSERT_EQUAL(120, function(4, 5, 6)); + + bar_Expect(8); + foo_ExpectAndReturn(7, 70); + foo_ExpectAndReturn(8, 20); + foo_ExpectAndReturn(9, 20); + TEST_ASSERT_EQUAL(110, function(7, 8, 9)); + } + + - :pass: FALSE + :should: 'we can override an ignore and return with an expect and fail' + :code: | + test() + { + bar_Ignore(); + foo_IgnoreAndReturn(0); + TEST_ASSERT_EQUAL(0, function(1, 2, 3)); + + bar_Expect(5); + foo_ExpectAndReturn(4, 30); + foo_ExpectAndReturn(5, 80); + foo_ExpectAndReturn(6, 10); + TEST_ASSERT_EQUAL(120, function(4, 5, 6)); + + bar_Expect(9); + foo_ExpectAndReturn(7, 70); + foo_ExpectAndReturn(8, 20); + foo_ExpectAndReturn(9, 20); + TEST_ASSERT_EQUAL(110, function(7, 8, 9)); + } + + - :pass: TRUE + :should: 'we can override an expect with an ignore' + :code: | + test() + { + bar_Expect(5); + bar_Ignore(); + foo_ExpectAndReturn(1, 50); + foo_ExpectAndReturn(2, 60); + foo_ExpectAndReturn(3, 70); + TEST_ASSERT_EQUAL(180, function(1, 2, 3)); + } + + - :pass: FALSE + :should: 'we can override an expect with an ignore and return and fail after' + :code: | + test() + { + bar_Expect(5); + foo_ExpectAndReturn(4, 30); + foo_ExpectAndReturn(5, 50); + foo_IgnoreAndReturn(20); + TEST_ASSERT_EQUAL(100, function(4, 5, 6)); + + bar_Expect(5); + foo_ExpectAndReturn(9, 30); //THIS ONE WILL FAIL + foo_ExpectAndReturn(2, 80); + foo_ExpectAndReturn(3, 60); + TEST_ASSERT_EQUAL(170, function(1, 2, 3)); + } + + - :pass: TRUE + :should: 'we can override an expect with an ignore and return and only the ignore and return is acknowledged' + :code: | + test() + { + bar_Expect(5); + foo_ExpectAndReturn(2, 30); //NOTE THIS WOULD NORMALLY FAIL + foo_ExpectAndReturn(5, 50); + foo_IgnoreAndReturn(20); //BUT WE SAID WE NO LONGER CARE + TEST_ASSERT_EQUAL(60, function(4, 5, 6)); + } + +... From 61ed5cc7f80ba339b4e5fb96b8c5a4c3b1638b56 Mon Sep 17 00:00:00 2001 From: cloudsftp Date: Wed, 19 Aug 2020 10:17:05 +0200 Subject: [PATCH 5/7] add more tests for the new plugin --- ...cmock_generator_plugin_ignore_stateless.rb | 9 +- ..._generator_plugin_ignore_stateless_test.rb | 105 ++++++++++++++++++ 2 files changed, 107 insertions(+), 7 deletions(-) create mode 100644 test/unit/cmock_generator_plugin_ignore_stateless_test.rb diff --git a/lib/cmock_generator_plugin_ignore_stateless.rb b/lib/cmock_generator_plugin_ignore_stateless.rb index fa39334..0f215da 100644 --- a/lib/cmock_generator_plugin_ignore_stateless.rb +++ b/lib/cmock_generator_plugin_ignore_stateless.rb @@ -30,11 +30,6 @@ class CMockGeneratorPluginIgnoreStateless "#define #{function[:name]}_IgnoreAndReturn(cmock_retval) #{function[:name]}_CMockIgnoreAndReturn(cmock_retval)\n" + "void #{function[:name]}_CMockIgnoreAndReturn(#{function[:return][:str]});\n"; end - - # Add stop ignore function. it does not matter if there are any args - lines << "#define #{function[:name]}_StopIgnore() #{function[:name]}_CMockStopIgnore()\n" \ - "void #{function[:name]}_CMockStopIgnore(void);\n" - lines end def mock_implementation_precheck(function) @@ -63,14 +58,14 @@ class CMockGeneratorPluginIgnoreStateless lines << " Mock.#{function[:name]}_CallInstance = CMOCK_GUTS_NONE;\n" lines << " Mock.#{function[:name]}_FinalReturn = cmock_to_return;\n" end - lines << " Mock.#{function[:name]}_IgnoreBool = (char) 1;\n" + lines << " Mock.#{function[:name]}_IgnoreBool = (char)1;\n" lines << "}\n\n" lines end def mock_ignore(function) - " Mock.#{function[:name]}_IgnoreBool = (char) 1;\n" + " Mock.#{function[:name]}_IgnoreBool = (char)1;\n" end def mock_verify(function) diff --git a/test/unit/cmock_generator_plugin_ignore_stateless_test.rb b/test/unit/cmock_generator_plugin_ignore_stateless_test.rb new file mode 100644 index 0000000..5367e1a --- /dev/null +++ b/test/unit/cmock_generator_plugin_ignore_stateless_test.rb @@ -0,0 +1,105 @@ +# ========================================== +# CMock Project - Automatic Mock Generation for C +# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams +# [Released under MIT License. Please refer to license.txt for details] +# ========================================== + +require File.expand_path(File.dirname(__FILE__)) + "/../test_helper" +require File.expand_path(File.dirname(__FILE__)) + '/../../lib/cmock_generator_plugin_ignore_stateless' + +describe CMockGeneratorPluginIgnoreStateless, "Verify CMockGeneratorPluginIgnoreStateless Module" do + + before do + create_mocks :config, :utils + @config = create_stub(:respond_to? => true) + @cmock_generator_plugin_ignore_stateless = CMockGeneratorPluginIgnoreStateless.new(@config, @utils) + end + + after do + end + + it "have set up internal priority" do + assert_equal(2, @cmock_generator_plugin_ignore_stateless.priority) + end + + it "not have any additional include file requirements" do + assert(!@cmock_generator_plugin_ignore_stateless.respond_to?(:include_files)) + end + + it "add a required variable to the instance structure" do + function = {:name => "Grass", :args => [], :return => test_return[:void]} + expected = " char Grass_IgnoreBool;\n" + returned = @cmock_generator_plugin_ignore_stateless.instance_structure(function) + assert_equal(expected, returned) + end + + 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" + 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"+ + "void Fungus_CMockIgnoreAndReturn(const char* cmock_to_return);\n" + returned = @cmock_generator_plugin_ignore_stateless.mock_function_declarations(function) + assert_equal(expected, returned) + end + + it "add required code to implementation precheck with void function" do + function = {:name => "Mold", :args_string => "void", :return => test_return[:void]} + expected = [" if (Mock.Mold_IgnoreBool)\n", + " {\n", + " UNITY_CLR_DETAILS();\n", + " return;\n", + " }\n" + ].join + returned = @cmock_generator_plugin_ignore_stateless.mock_implementation_precheck(function) + assert_equal(expected, returned) + end + + it "add required code to implementation precheck with return functions" do + function = {:name => "Fungus", :args_string => "void", :return => test_return[:int]} + retval = test_return[:int].merge({ :name => "cmock_call_instance->ReturnVal"}) + @utils.expect :code_assign_argument_quickly, ' mock_retval_0', ["Mock.Fungus_FinalReturn", retval] + expected = [" if (Mock.Fungus_IgnoreBool)\n", + " {\n", + " UNITY_CLR_DETAILS();\n", + " if (cmock_call_instance == NULL)\n", + " return Mock.Fungus_FinalReturn;\n", + " mock_retval_0", + " return cmock_call_instance->ReturnVal;\n", + " }\n" + ].join + returned = @cmock_generator_plugin_ignore_stateless.mock_implementation_precheck(function) + assert_equal(expected, returned) + end + + it "add a new mock interface for ignoring when function had no return value" do + function = {:name => "Slime", :args => [], :args_string => "void", :return => test_return[:void]} + expected = ["void Slime_CMockIgnore(void)\n", + "{\n", + " Mock.Slime_IgnoreBool = (char)1;\n", + "}\n\n" + ].join + returned = @cmock_generator_plugin_ignore_stateless.mock_interfaces(function) + assert_equal(expected, returned) + end + + it "add a new mock interface for ignoring when function has return value" do + function = {:name => "Slime", :args => [], :args_string => "void", :return => test_return[:int]} + @utils.expect :code_add_base_expectation, "mock_return_1", ["Slime", false] + expected = ["void Slime_CMockIgnoreAndReturn(int cmock_to_return)\n", + "{\n", + " Mock.Slime_CallInstance = CMOCK_GUTS_NONE;\n", + " Mock.Slime_FinalReturn = cmock_to_return;\n", + " Mock.Slime_IgnoreBool = (char)1;\n", + "}\n\n" + ].join + returned = @cmock_generator_plugin_ignore_stateless.mock_interfaces(function) + assert_equal(expected, returned) + end + +end From 56faeb935f40065c2f6208a5af510692a2240dac Mon Sep 17 00:00:00 2001 From: cloudsftp Date: Wed, 19 Aug 2020 10:38:26 +0200 Subject: [PATCH 6/7] add documentation --- docs/CMock_Summary.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/docs/CMock_Summary.md b/docs/CMock_Summary.md index f72a2f5..04a9885 100644 --- a/docs/CMock_Summary.md +++ b/docs/CMock_Summary.md @@ -174,6 +174,20 @@ handle the call to a function. * `retval func(void)` => `void func_StopIgnore(void)` * `retval func(params)` => `void func_StopIgnore(void)` +IgnoreStateless: +---------------- + +This plugin is similar to the Ignore plugin, but the IgnoreAndReturn functions are +stateless. So the Ignored function will always return the last specified return value +and does not queue the return values as the IgnoreAndReturn of the default plugin will. +To stop ignoring a function you can call StopIgnore or simply overwrite the Ignore +(resp. IgnoreAndReturn) with an Expect (resp. ExpectAndReturn). + +You can use this plugin by using `:ignore_stateless` instead of `:ignore` in your +CMock configuration file. + +The generated functions are the same as **Ignore** and **StopIgnore** above. + Ignore Arg: ------------ @@ -440,6 +454,7 @@ from the defaults. We've tried to specify what the defaults are below. available currently: * `:ignore` + * `:ignore_stateless` * `:ignore_arg` * `:expect_any_args` * `:array` From d304ff273a8934c870a1f3cf25bfaf2c44251f4a Mon Sep 17 00:00:00 2001 From: cloudsftp Date: Wed, 19 Aug 2020 11:25:27 +0200 Subject: [PATCH 7/7] add StopIgnore to new plugin --- docs/CMock_Summary.md | 5 +- ...cmock_generator_plugin_ignore_stateless.rb | 10 ++++ .../ignore_and_return_stateless.yml | 49 +++++++++++++++++++ ..._generator_plugin_ignore_stateless_test.rb | 15 +++++- 4 files changed, 76 insertions(+), 3 deletions(-) diff --git a/docs/CMock_Summary.md b/docs/CMock_Summary.md index 04a9885..efd50a3 100644 --- a/docs/CMock_Summary.md +++ b/docs/CMock_Summary.md @@ -180,8 +180,11 @@ IgnoreStateless: This plugin is similar to the Ignore plugin, but the IgnoreAndReturn functions are stateless. So the Ignored function will always return the last specified return value and does not queue the return values as the IgnoreAndReturn of the default plugin will. + To stop ignoring a function you can call StopIgnore or simply overwrite the Ignore -(resp. IgnoreAndReturn) with an Expect (resp. ExpectAndReturn). +(resp. IgnoreAndReturn) with an Expect (resp. ExpectAndReturn). Note that calling +Ignore (resp IgnoreAndReturn) will clear your previous called Expect +(resp. ExpectAndReturn), so they are not restored after StopIgnore is called. You can use this plugin by using `:ignore_stateless` instead of `:ignore` in your CMock configuration file. diff --git a/lib/cmock_generator_plugin_ignore_stateless.rb b/lib/cmock_generator_plugin_ignore_stateless.rb index 0f215da..0551067 100644 --- a/lib/cmock_generator_plugin_ignore_stateless.rb +++ b/lib/cmock_generator_plugin_ignore_stateless.rb @@ -30,6 +30,11 @@ class CMockGeneratorPluginIgnoreStateless "#define #{function[:name]}_IgnoreAndReturn(cmock_retval) #{function[:name]}_CMockIgnoreAndReturn(cmock_retval)\n" + "void #{function[:name]}_CMockIgnoreAndReturn(#{function[:return][:str]});\n"; end + + # Add stop ignore function. it does not matter if there are any args + lines << "#define #{function[:name]}_StopIgnore() #{function[:name]}_CMockStopIgnore()\n" \ + "void #{function[:name]}_CMockStopIgnore(void);\n" + lines end def mock_implementation_precheck(function) @@ -61,6 +66,11 @@ class CMockGeneratorPluginIgnoreStateless lines << " Mock.#{function[:name]}_IgnoreBool = (char)1;\n" lines << "}\n\n" + # Add stop ignore function. it does not matter if there are any args + lines << "void #{function[:name]}_CMockStopIgnore(void)\n{\n" + lines << " Mock.#{function[:name]}_IgnoreBool = (char)0;\n" + lines << "}\n\n" + lines end diff --git a/test/system/test_interactions/ignore_and_return_stateless.yml b/test/system/test_interactions/ignore_and_return_stateless.yml index 8fcfc48..aefe4dd 100644 --- a/test/system/test_interactions/ignore_and_return_stateless.yml +++ b/test/system/test_interactions/ignore_and_return_stateless.yml @@ -273,4 +273,53 @@ TEST_ASSERT_EQUAL(60, function(4, 5, 6)); } +# StopIgnore + + - :pass: FALSE + :should: 'fail when function is called after ignore is stopped' + :code: | + test() + { + bar_Ignore(); + foo_IgnoreAndReturn(10); + function(0, 0, 0); + bar_StopIgnore(); + function(0, 0, 0); + } + + - :pass: FALSE + :should: 'delete expect after ignore is stopped' + :code: | + test() + { + bar_Ignore(); + foo_ExpectAndReturn(0, 40); + foo_ExpectAndReturn(0, 30); + foo_ExpectAndReturn(0, 40); + + foo_IgnoreAndReturn(20); + foo_StopIgnore(); + + TEST_ASSERT_EQUAL(110, function(0, 0, 0)); // THIS SHOULD FAIL + } + + - :pass: TRUE + :should: 'delete expected return values after ignore is stopped' + :code: | + test() + { + bar_Ignore(); + foo_ExpectAndReturn(0, 40); + foo_ExpectAndReturn(0, 30); + foo_ExpectAndReturn(0, 40); + + foo_IgnoreAndReturn(20); + foo_StopIgnore(); + + foo_ExpectAndReturn(0, 50); + foo_ExpectAndReturn(0, 30); + foo_ExpectAndReturn(0, 40); + TEST_ASSERT_EQUAL(120, function(0, 0, 0)); + } + ... diff --git a/test/unit/cmock_generator_plugin_ignore_stateless_test.rb b/test/unit/cmock_generator_plugin_ignore_stateless_test.rb index 5367e1a..b40d978 100644 --- a/test/unit/cmock_generator_plugin_ignore_stateless_test.rb +++ b/test/unit/cmock_generator_plugin_ignore_stateless_test.rb @@ -35,7 +35,8 @@ describe CMockGeneratorPluginIgnoreStateless, "Verify CMockGeneratorPluginIgnore 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" + expected = "#define Mold_Ignore() Mold_CMockIgnore()\nvoid Mold_CMockIgnore(void);\n" + + "#define Mold_StopIgnore() Mold_CMockStopIgnore()\nvoid Mold_CMockStopIgnore(void);\n" returned = @cmock_generator_plugin_ignore_stateless.mock_function_declarations(function) assert_equal(expected, returned) end @@ -43,7 +44,9 @@ describe CMockGeneratorPluginIgnoreStateless, "Verify CMockGeneratorPluginIgnore 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"+ - "void Fungus_CMockIgnoreAndReturn(const char* cmock_to_return);\n" + "void Fungus_CMockIgnoreAndReturn(const char* cmock_to_return);\n" + + "#define Fungus_StopIgnore() Fungus_CMockStopIgnore()\n"+ + "void Fungus_CMockStopIgnore(void);\n" returned = @cmock_generator_plugin_ignore_stateless.mock_function_declarations(function) assert_equal(expected, returned) end @@ -82,6 +85,10 @@ describe CMockGeneratorPluginIgnoreStateless, "Verify CMockGeneratorPluginIgnore expected = ["void Slime_CMockIgnore(void)\n", "{\n", " Mock.Slime_IgnoreBool = (char)1;\n", + "}\n\n", + "void Slime_CMockStopIgnore(void)\n", + "{\n", + " Mock.Slime_IgnoreBool = (char)0;\n", "}\n\n" ].join returned = @cmock_generator_plugin_ignore_stateless.mock_interfaces(function) @@ -96,6 +103,10 @@ describe CMockGeneratorPluginIgnoreStateless, "Verify CMockGeneratorPluginIgnore " Mock.Slime_CallInstance = CMOCK_GUTS_NONE;\n", " Mock.Slime_FinalReturn = cmock_to_return;\n", " Mock.Slime_IgnoreBool = (char)1;\n", + "}\n\n", + "void Slime_CMockStopIgnore(void)\n", + "{\n", + " Mock.Slime_IgnoreBool = (char)0;\n", "}\n\n" ].join returned = @cmock_generator_plugin_ignore_stateless.mock_interfaces(function)