diff --git a/docs/CMock_Summary.md b/docs/CMock_Summary.md index 6d8d051..a1bec86 100644 --- a/docs/CMock_Summary.md +++ b/docs/CMock_Summary.md @@ -196,19 +196,28 @@ Callback: If all those other options don't work, and you really need to do something custom, you still have a choice. As soon as you stub a callback in a test, it will call the callback -whenever the mock is encountered and return the retval returned from the callback (if any) -instead of performing the usual expect checks. It can be configured to check the arguments -first (like expects) or just jump directly to the callback. +whenever the mock is encountered and return the retval returned from the callback (if any). -* `void func(void)` => `void func_StubWithCallback(CMOCK_func_CALLBACK callback)` +* `void func(void)` => `void func_[Check,Ignore]WithCallback(CMOCK_func_CALLBACK callback)` where `CMOCK_func_CALLBACK` looks like: `void func(int NumCalls)` -* `void func(params)` => `void func_StubWithCallback(CMOCK_func_CALLBACK callback)` +* `void func(params)` => `void func_[Check,Ignore]WithCallback(CMOCK_func_CALLBACK callback)` where `CMOCK_func_CALLBACK` looks like: `void func(params, int NumCalls)` -* `retval func(void)` => `void func_StubWithCallback(CMOCK_func_CALLBACK callback)` +* `retval func(void)` => `void func_[Check,Ignore]WithCallback(CMOCK_func_CALLBACK callback)` where `CMOCK_func_CALLBACK` looks like: `retval func(int NumCalls)` -* `retval func(params)` => `void func_StubWithCallback(CMOCK_func_CALLBACK callback)` +* `retval func(params)` => `void func_[Check,Ignore]WithCallback(CMOCK_func_CALLBACK callback)` where `CMOCK_func_CALLBACK` looks like: `retval func(params, int NumCalls)` +You can choose from two options: + +* `func_CheckWithCallback` tells the mock to check its arguments and calling +order (based on any Expects you've set up) before calling the callback. +* `func_IgnoreWithCallback` tells the mock to skip all the normal checks (just +like Ignore) and jump directly to the callback instead. + +There is also an older name, `func_StubWithCallback`, which is just an alias for +either `func_CheckWithCallback` or `func_IgnoreWithCallback` depending on +setting of the `:callback_after_arg_check` toggle. + Cexception: ----------- diff --git a/lib/cmock_generator_plugin_callback.rb b/lib/cmock_generator_plugin_callback.rb index 4e27443..02ea990 100644 --- a/lib/cmock_generator_plugin_callback.rb +++ b/lib/cmock_generator_plugin_callback.rb @@ -16,78 +16,68 @@ class CMockGeneratorPluginCallback @priority = 6 @include_count = @config.callback_include_count - if (@config.callback_after_arg_check) - alias :mock_implementation :mock_implementation_for_callbacks_after_arg_check - alias :mock_implementation_precheck :nothing - else - alias :mock_implementation_precheck :mock_implementation_for_callbacks_without_arg_check - alias :mock_implementation :nothing - end end def instance_structure(function) func_name = function[:name] - " CMOCK_#{func_name}_CALLBACK #{func_name}_CallbackFunctionPointer;\n" + + " int #{func_name}_IgnoreWithCallbackBool;\n" \ + " CMOCK_#{func_name}_CALLBACK #{func_name}_CallbackFunctionPointer;\n" \ " int #{func_name}_CallbackCalls;\n" end def mock_function_declarations(function) func_name = function[:name] return_type = function[:return][:type] + action = @config.callback_after_arg_check ? 'Check' : 'Ignore' style = (@include_count ? 1 : 0) | (function[:args].empty? ? 0 : 2) styles = [ "void", "int cmock_num_calls", function[:args_string], "#{function[:args_string]}, int cmock_num_calls" ] - "typedef #{return_type} (* CMOCK_#{func_name}_CALLBACK)(#{styles[style]});\nvoid #{func_name}_StubWithCallback(CMOCK_#{func_name}_CALLBACK Callback);\n" + "typedef #{return_type} (* CMOCK_#{func_name}_CALLBACK)(#{styles[style]});\n" \ + "void #{func_name}_CheckWithCallback(CMOCK_#{func_name}_CALLBACK Callback);\n" \ + "void #{func_name}_IgnoreWithCallback(CMOCK_#{func_name}_CALLBACK Callback);\n" \ + "#define #{func_name}_StubWithCallback #{func_name}_#{action}WithCallback\n" end - def mock_implementation_for_callbacks_after_arg_check(function) - func_name = function[:name] - style = (@include_count ? 1 : 0) | (function[:args].empty? ? 0 : 2) | (function[:return][:void?] ? 0 : 4) - " if (Mock.#{func_name}_CallbackFunctionPointer != NULL)\n {\n" + - case(style) - when 0 then " Mock.#{func_name}_CallbackFunctionPointer();\n }\n" - when 1 then " Mock.#{func_name}_CallbackFunctionPointer(Mock.#{func_name}_CallbackCalls++);\n }\n" - when 2 then " Mock.#{func_name}_CallbackFunctionPointer(#{function[:args].map{|m| m[:name]}.join(', ')});\n }\n" - when 3 then " Mock.#{func_name}_CallbackFunctionPointer(#{function[:args].map{|m| m[:name]}.join(', ')}, Mock.#{func_name}_CallbackCalls++);\n }\n" - when 4 then " cmock_call_instance->ReturnVal = Mock.#{func_name}_CallbackFunctionPointer();\n }\n" - when 5 then " cmock_call_instance->ReturnVal = Mock.#{func_name}_CallbackFunctionPointer(Mock.#{func_name}_CallbackCalls++);\n }\n" - when 6 then " cmock_call_instance->ReturnVal = Mock.#{func_name}_CallbackFunctionPointer(#{function[:args].map{|m| m[:name]}.join(', ')});\n }\n" - when 7 then " cmock_call_instance->ReturnVal = Mock.#{func_name}_CallbackFunctionPointer(#{function[:args].map{|m| m[:name]}.join(', ')}, Mock.#{func_name}_CallbackCalls++);\n }\n" - end + def generate_call(function) + args = function[:args].map { |m| m[:name] } + args << "Mock.#{function[:name]}_CallbackCalls++" if @include_count + "Mock.#{function[:name]}_CallbackFunctionPointer(#{args.join(', ')})" end - def mock_implementation_for_callbacks_without_arg_check(function) - func_name = function[:name] - style = (@include_count ? 1 : 0) | (function[:args].empty? ? 0 : 2) | (function[:return][:void?] ? 0 : 4) - " if (Mock.#{func_name}_CallbackFunctionPointer != NULL)\n {\n" + - case(style) - when 0 then " Mock.#{func_name}_CallbackFunctionPointer();\n return;\n }\n" - when 1 then " Mock.#{func_name}_CallbackFunctionPointer(Mock.#{func_name}_CallbackCalls++);\n return;\n }\n" - when 2 then " Mock.#{func_name}_CallbackFunctionPointer(#{function[:args].map{|m| m[:name]}.join(', ')});\n return;\n }\n" - when 3 then " Mock.#{func_name}_CallbackFunctionPointer(#{function[:args].map{|m| m[:name]}.join(', ')}, Mock.#{func_name}_CallbackCalls++);\n return;\n }\n" - when 4 then " return Mock.#{func_name}_CallbackFunctionPointer();\n }\n" - when 5 then " return Mock.#{func_name}_CallbackFunctionPointer(Mock.#{func_name}_CallbackCalls++);\n }\n" - when 6 then " return Mock.#{func_name}_CallbackFunctionPointer(#{function[:args].map{|m| m[:name]}.join(', ')});\n }\n" - when 7 then " return Mock.#{func_name}_CallbackFunctionPointer(#{function[:args].map{|m| m[:name]}.join(', ')}, Mock.#{func_name}_CallbackCalls++);\n }\n" - end + def mock_implementation(function) + " if (Mock.#{function[:name]}_CallbackFunctionPointer != NULL)\n {\n" + + if function[:return][:void?] + " #{generate_call(function)};\n }\n" + else + " cmock_call_instance->ReturnVal = #{generate_call(function)};\n }\n" + end end - def nothing(function) - return "" + def mock_implementation_precheck(function) + " if (Mock.#{function[:name]}_IgnoreWithCallbackBool &&\n" \ + " Mock.#{function[:name]}_CallbackFunctionPointer != NULL)\n {\n" + + if function[:return][:void?] + " #{generate_call(function)};\n" \ + " UNITY_CLR_DETAILS();\n" \ + " return;\n }\n" + else + " #{function[:return][:type]} ret = #{generate_call(function)};\n" \ + " UNITY_CLR_DETAILS();\n" \ + " return ret;\n }\n" + end end def mock_interfaces(function) func_name = function[:name] + has_ignore = @config.plugins.include? :ignore lines = "" - lines << "void #{func_name}_StubWithCallback(CMOCK_#{func_name}_CALLBACK Callback)\n{\n" - if @config.plugins.include? :ignore - lines << " Mock.#{func_name}_IgnoreBool = (int)0;\n" - end + lines << "void #{func_name}_CheckWithCallback(CMOCK_#{func_name}_CALLBACK Callback)\n{\n" + lines << " Mock.#{func_name}_IgnoreBool = (int)0;\n" if has_ignore + lines << " Mock.#{func_name}_IgnoreWithCallbackBool = (int)0;\n" + lines << " Mock.#{func_name}_CallbackFunctionPointer = Callback;\n}\n\n" + lines << "void #{func_name}_IgnoreWithCallback(CMOCK_#{func_name}_CALLBACK Callback)\n{\n" + lines << " Mock.#{func_name}_IgnoreBool = (int)0;\n" if has_ignore + lines << " Mock.#{func_name}_IgnoreWithCallbackBool = (int)1;\n" lines << " Mock.#{func_name}_CallbackFunctionPointer = Callback;\n}\n\n" - end - - def mock_destroy(function) - " Mock.#{function[:name]}_CallbackFunctionPointer = NULL;\n" + - " Mock.#{function[:name]}_CallbackCalls = 0;\n" end def mock_verify(function) diff --git a/test/unit/cmock_generator_plugin_callback_test.rb b/test/unit/cmock_generator_plugin_callback_test.rb index fd6579e..6fc0a60 100644 --- a/test/unit/cmock_generator_plugin_callback_test.rb +++ b/test/unit/cmock_generator_plugin_callback_test.rb @@ -32,7 +32,8 @@ describe CMockGeneratorPluginCallback, "Verify CMockGeneratorPluginCallback Modu it "add to instance structure" do function = {:name => "Oak", :args => [:type => "int*", :name => "blah", :ptr? => true], :return => test_return[:int_ptr]} - expected = " CMOCK_Oak_CALLBACK Oak_CallbackFunctionPointer;\n" + + expected = " int Oak_IgnoreWithCallbackBool;\n" + + " CMOCK_Oak_CALLBACK Oak_CallbackFunctionPointer;\n" + " int Oak_CallbackCalls;\n" returned = @cmock_generator_plugin_callback.instance_structure(function) assert_equal(expected, returned) @@ -41,7 +42,9 @@ describe CMockGeneratorPluginCallback, "Verify CMockGeneratorPluginCallback Modu it "add mock function declaration for function without arguments" do function = {:name => "Maple", :args_string => "void", :args => [], :return => test_return[:void]} expected = [ "typedef void (* CMOCK_Maple_CALLBACK)(int cmock_num_calls);\n", - "void Maple_StubWithCallback(CMOCK_Maple_CALLBACK Callback);\n" ].join + "void Maple_CheckWithCallback(CMOCK_Maple_CALLBACK Callback);\n", + "void Maple_IgnoreWithCallback(CMOCK_Maple_CALLBACK Callback);\n", + "#define Maple_StubWithCallback Maple_IgnoreWithCallback\n" ].join returned = @cmock_generator_plugin_callback.mock_function_declarations(function) assert_equal(expected, returned) end @@ -49,7 +52,9 @@ describe CMockGeneratorPluginCallback, "Verify CMockGeneratorPluginCallback Modu it "add mock function declaration for function without arguments when count is also turned off" do function = {:name => "Maple", :args_string => "void", :args => [], :return => test_return[:void]} expected = [ "typedef void (* CMOCK_Maple_CALLBACK)(void);\n", - "void Maple_StubWithCallback(CMOCK_Maple_CALLBACK Callback);\n" ].join + "void Maple_CheckWithCallback(CMOCK_Maple_CALLBACK Callback);\n", + "void Maple_IgnoreWithCallback(CMOCK_Maple_CALLBACK Callback);\n", + "#define Maple_StubWithCallback Maple_IgnoreWithCallback\n" ].join @cmock_generator_plugin_callback.include_count = false returned = @cmock_generator_plugin_callback.mock_function_declarations(function) assert_equal(expected, returned) @@ -58,7 +63,9 @@ describe CMockGeneratorPluginCallback, "Verify CMockGeneratorPluginCallback Modu it "add mock function declaration for function with arguments" do function = {:name => "Maple", :args_string => "int* tofu", :args => [1], :return => test_return[:void]} expected = [ "typedef void (* CMOCK_Maple_CALLBACK)(int* tofu, int cmock_num_calls);\n", - "void Maple_StubWithCallback(CMOCK_Maple_CALLBACK Callback);\n" ].join + "void Maple_CheckWithCallback(CMOCK_Maple_CALLBACK Callback);\n", + "void Maple_IgnoreWithCallback(CMOCK_Maple_CALLBACK Callback);\n", + "#define Maple_StubWithCallback Maple_IgnoreWithCallback\n" ].join returned = @cmock_generator_plugin_callback.mock_function_declarations(function) assert_equal(expected, returned) end @@ -66,7 +73,9 @@ describe CMockGeneratorPluginCallback, "Verify CMockGeneratorPluginCallback Modu it "add mock function declaration for function with return values" do function = {:name => "Maple", :args_string => "int* tofu", :args => [1], :return => test_return[:string]} expected = [ "typedef const char* (* CMOCK_Maple_CALLBACK)(int* tofu, int cmock_num_calls);\n", - "void Maple_StubWithCallback(CMOCK_Maple_CALLBACK Callback);\n" ].join + "void Maple_CheckWithCallback(CMOCK_Maple_CALLBACK Callback);\n", + "void Maple_IgnoreWithCallback(CMOCK_Maple_CALLBACK Callback);\n", + "#define Maple_StubWithCallback Maple_IgnoreWithCallback\n" ].join returned = @cmock_generator_plugin_callback.mock_function_declarations(function) assert_equal(expected, returned) end @@ -74,7 +83,9 @@ describe CMockGeneratorPluginCallback, "Verify CMockGeneratorPluginCallback Modu it "add mock function declaration for function with return values and count is turned off" do function = {:name => "Maple", :args_string => "int* tofu", :args => [1], :return => test_return[:string]} expected = [ "typedef const char* (* CMOCK_Maple_CALLBACK)(int* tofu);\n", - "void Maple_StubWithCallback(CMOCK_Maple_CALLBACK Callback);\n" ].join + "void Maple_CheckWithCallback(CMOCK_Maple_CALLBACK Callback);\n", + "void Maple_IgnoreWithCallback(CMOCK_Maple_CALLBACK Callback);\n", + "#define Maple_StubWithCallback Maple_IgnoreWithCallback\n" ].join @cmock_generator_plugin_callback.include_count = false returned = @cmock_generator_plugin_callback.mock_function_declarations(function) assert_equal(expected, returned) @@ -87,7 +98,7 @@ describe CMockGeneratorPluginCallback, "Verify CMockGeneratorPluginCallback Modu " Mock.Apple_CallbackFunctionPointer(Mock.Apple_CallbackCalls++);\n", " }\n" ].join - returned = @cmock_generator_plugin_callback.mock_implementation_for_callbacks_after_arg_check(function) + returned = @cmock_generator_plugin_callback.mock_implementation(function) assert_equal(expected, returned) end @@ -99,7 +110,7 @@ describe CMockGeneratorPluginCallback, "Verify CMockGeneratorPluginCallback Modu " }\n" ].join @cmock_generator_plugin_callback.include_count = false - returned = @cmock_generator_plugin_callback.mock_implementation_for_callbacks_after_arg_check(function) + returned = @cmock_generator_plugin_callback.mock_implementation(function) assert_equal(expected, returned) end @@ -110,7 +121,7 @@ describe CMockGeneratorPluginCallback, "Verify CMockGeneratorPluginCallback Modu " cmock_call_instance->ReturnVal = Mock.Apple_CallbackFunctionPointer(Mock.Apple_CallbackCalls++);\n", " }\n" ].join - returned = @cmock_generator_plugin_callback.mock_implementation_for_callbacks_after_arg_check(function) + returned = @cmock_generator_plugin_callback.mock_implementation(function) assert_equal(expected, returned) end @@ -125,7 +136,7 @@ describe CMockGeneratorPluginCallback, "Verify CMockGeneratorPluginCallback Modu " Mock.Apple_CallbackFunctionPointer(steak, flag, Mock.Apple_CallbackCalls++);\n", " }\n" ].join - returned = @cmock_generator_plugin_callback.mock_implementation_for_callbacks_after_arg_check(function) + returned = @cmock_generator_plugin_callback.mock_implementation(function) assert_equal(expected, returned) end @@ -141,7 +152,7 @@ describe CMockGeneratorPluginCallback, "Verify CMockGeneratorPluginCallback Modu " }\n" ].join @cmock_generator_plugin_callback.include_count = false - returned = @cmock_generator_plugin_callback.mock_implementation_for_callbacks_after_arg_check(function) + returned = @cmock_generator_plugin_callback.mock_implementation(function) assert_equal(expected, returned) end @@ -156,31 +167,36 @@ describe CMockGeneratorPluginCallback, "Verify CMockGeneratorPluginCallback Modu " cmock_call_instance->ReturnVal = Mock.Apple_CallbackFunctionPointer(steak, flag, Mock.Apple_CallbackCalls++);\n", " }\n" ].join - returned = @cmock_generator_plugin_callback.mock_implementation_for_callbacks_after_arg_check(function) + returned = @cmock_generator_plugin_callback.mock_implementation(function) assert_equal(expected, returned) end it "add mock function implementation for functions without arg check and of style 'void func(void)' when count turned off" do function = {:name => "Apple", :args => [], :args_string => "void", :return => test_return[:void]} - expected = [" if (Mock.Apple_CallbackFunctionPointer != NULL)\n", + expected = [" if (Mock.Apple_IgnoreWithCallbackBool &&\n", + " Mock.Apple_CallbackFunctionPointer != NULL)\n", " {\n", " Mock.Apple_CallbackFunctionPointer();\n", + " UNITY_CLR_DETAILS();\n", " return;\n", " }\n" ].join @cmock_generator_plugin_callback.include_count = false - returned = @cmock_generator_plugin_callback.mock_implementation_for_callbacks_without_arg_check(function) + returned = @cmock_generator_plugin_callback.mock_implementation_precheck(function) assert_equal(expected, returned) end it "add mock function implementation for functions without arg check and of style 'int func(void)'" do function = {:name => "Apple", :args => [], :args_string => "void", :return => test_return[:int]} - expected = [" if (Mock.Apple_CallbackFunctionPointer != NULL)\n", + expected = [" if (Mock.Apple_IgnoreWithCallbackBool &&\n", + " Mock.Apple_CallbackFunctionPointer != NULL)\n", " {\n", - " return Mock.Apple_CallbackFunctionPointer(Mock.Apple_CallbackCalls++);\n", + " int ret = Mock.Apple_CallbackFunctionPointer(Mock.Apple_CallbackCalls++);\n", + " UNITY_CLR_DETAILS();\n", + " return ret;\n", " }\n" ].join - returned = @cmock_generator_plugin_callback.mock_implementation_for_callbacks_without_arg_check(function) + returned = @cmock_generator_plugin_callback.mock_implementation_precheck(function) assert_equal(expected, returned) end @@ -190,13 +206,15 @@ describe CMockGeneratorPluginCallback, "Verify CMockGeneratorPluginCallback Modu { :type => 'uint8_t', :name => 'flag', :ptr? => false} ], :args_string => "int* steak, uint8_t flag", :return=> test_return[:void]} - expected = [" if (Mock.Apple_CallbackFunctionPointer != NULL)\n", + expected = [" if (Mock.Apple_IgnoreWithCallbackBool &&\n", + " Mock.Apple_CallbackFunctionPointer != NULL)\n", " {\n", " Mock.Apple_CallbackFunctionPointer(steak, flag, Mock.Apple_CallbackCalls++);\n", + " UNITY_CLR_DETAILS();\n", " return;\n", " }\n" ].join - returned = @cmock_generator_plugin_callback.mock_implementation_for_callbacks_without_arg_check(function) + returned = @cmock_generator_plugin_callback.mock_implementation_precheck(function) assert_equal(expected, returned) end @@ -206,14 +224,16 @@ describe CMockGeneratorPluginCallback, "Verify CMockGeneratorPluginCallback Modu { :type => 'uint8_t', :name => 'flag', :ptr? => false} ], :args_string => "int* steak, uint8_t flag", :return=> test_return[:void]} - expected = [" if (Mock.Apple_CallbackFunctionPointer != NULL)\n", + expected = [" if (Mock.Apple_IgnoreWithCallbackBool &&\n", + " Mock.Apple_CallbackFunctionPointer != NULL)\n", " {\n", " Mock.Apple_CallbackFunctionPointer(steak, flag);\n", + " UNITY_CLR_DETAILS();\n", " return;\n", " }\n" ].join @cmock_generator_plugin_callback.include_count = false - returned = @cmock_generator_plugin_callback.mock_implementation_for_callbacks_without_arg_check(function) + returned = @cmock_generator_plugin_callback.mock_implementation_precheck(function) assert_equal(expected, returned) end @@ -223,12 +243,15 @@ describe CMockGeneratorPluginCallback, "Verify CMockGeneratorPluginCallback Modu { :type => 'uint8_t', :name => 'flag', :ptr? => false} ], :args_string => "int* steak, uint8_t flag", :return => test_return[:int]} - expected = [" if (Mock.Apple_CallbackFunctionPointer != NULL)\n", + expected = [" if (Mock.Apple_IgnoreWithCallbackBool &&\n", + " Mock.Apple_CallbackFunctionPointer != NULL)\n", " {\n", - " return Mock.Apple_CallbackFunctionPointer(steak, flag, Mock.Apple_CallbackCalls++);\n", + " int ret = Mock.Apple_CallbackFunctionPointer(steak, flag, Mock.Apple_CallbackCalls++);\n", + " UNITY_CLR_DETAILS();\n", + " return ret;\n", " }\n" ].join - returned = @cmock_generator_plugin_callback.mock_implementation_for_callbacks_without_arg_check(function) + returned = @cmock_generator_plugin_callback.mock_implementation_precheck(function) assert_equal(expected, returned) end @@ -239,21 +262,20 @@ describe CMockGeneratorPluginCallback, "Verify CMockGeneratorPluginCallback Modu :return => test_return[:int] } - expected = ["void Lemon_StubWithCallback(CMOCK_Lemon_CALLBACK Callback)\n", + expected = ["void Lemon_CheckWithCallback(CMOCK_Lemon_CALLBACK Callback)\n", "{\n", " Mock.Lemon_IgnoreBool = (int)0;\n", + " Mock.Lemon_IgnoreWithCallbackBool = (int)0;\n", + " Mock.Lemon_CallbackFunctionPointer = Callback;\n", + "}\n\n", + "void Lemon_IgnoreWithCallback(CMOCK_Lemon_CALLBACK Callback)\n", + "{\n", + " Mock.Lemon_IgnoreBool = (int)0;\n", + " Mock.Lemon_IgnoreWithCallbackBool = (int)1;\n", " Mock.Lemon_CallbackFunctionPointer = Callback;\n", "}\n\n" ].join returned = @cmock_generator_plugin_callback.mock_interfaces(function) assert_equal(expected, returned) end - - it "add mock destroy for functions" do - function = {:name => "Peach", :args => [], :return => test_return[:void] } - expected = " Mock.Peach_CallbackFunctionPointer = NULL;\n" + - " Mock.Peach_CallbackCalls = 0;\n" - returned = @cmock_generator_plugin_callback.mock_destroy(function) - assert_equal(expected, returned) - end end