The ReturnThrPtr plugin now works even when using Ignore (Fix #61, #225)

This commit is contained in:
Mark VanderVoord
2026-06-26 10:15:07 -04:00
parent d482f56066
commit 5f74197056
5 changed files with 186 additions and 0 deletions
+1
View File
@@ -346,6 +346,7 @@ class CMockGenerator
file << " UNITY_SET_DETAIL(CMockString_#{function[:name]});\n"
file << " cmock_call_instance = (CMOCK_#{function[:name]}_CALL_INSTANCE*)CMock_Guts_GetAddressFor(Mock.#{function[:name]}_CallInstance);\n"
file << " Mock.#{function[:name]}_CallInstance = CMock_Guts_MemNext(Mock.#{function[:name]}_CallInstance);\n"
file << @plugins.run(:mock_precheck_return_thru_ptr, function)
file << @plugins.run(:mock_implementation_precheck, function)
file << " UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringCalledMore);\n"
file << " cmock_line = cmock_call_instance->LineNumber;\n"
@@ -13,6 +13,8 @@ class CMockGeneratorPluginReturnThruPtr
@utils = utils
@priority = 9
@config = config
plugins = @config.plugins
@ignore_used = plugins.include?(:ignore) || plugins.include?(:ignore_stateless)
end
def ptr_to_const(arg_type)
@@ -69,6 +71,25 @@ class CMockGeneratorPluginReturnThruPtr
lines
end
def mock_precheck_return_thru_ptr(function)
return '' unless @ignore_used
lines = []
function[:args].each do |arg|
arg_name = arg[:name]
next unless @utils.ptr_or_str?(arg[:type]) && !(arg[:const?])
lines << " if (Mock.#{function[:name]}_IgnoreBool && cmock_call_instance != NULL &&\n"
lines << " cmock_call_instance->ReturnThruPtr_#{arg_name}_Used)\n"
lines << " {\n"
lines << " UNITY_TEST_ASSERT_NOT_NULL(#{arg_name}, cmock_line, CMockStringPtrIsNULL);\n"
lines << " memcpy((void*)#{arg_name}, (const void*)cmock_call_instance->ReturnThruPtr_#{arg_name}_Val,\n"
lines << " cmock_call_instance->ReturnThruPtr_#{arg_name}_Size);\n"
lines << " }\n"
end
lines
end
def mock_interfaces(function)
lines = []
func_name = function[:name]
@@ -80,6 +101,23 @@ class CMockGeneratorPluginReturnThruPtr
lines << "{\n"
lines << " CMOCK_#{func_name}_CALL_INSTANCE* cmock_call_instance = " \
"(CMOCK_#{func_name}_CALL_INSTANCE*)CMock_Guts_GetAddressFor(CMock_Guts_MemEndOfChain(Mock.#{func_name}_CallInstance));\n"
if @ignore_used
lines << " if (Mock.#{func_name}_IgnoreBool &&\n"
lines << " (cmock_call_instance == NULL || cmock_call_instance->ReturnThruPtr_#{arg_name}_Used))\n"
lines << " {\n"
lines << " CMOCK_MEM_INDEX_TYPE cmock_guts_index = CMock_Guts_MemNew(sizeof(CMOCK_#{func_name}_CALL_INSTANCE));\n"
lines << " CMOCK_#{func_name}_CALL_INSTANCE* new_instance = (CMOCK_#{func_name}_CALL_INSTANCE*)CMock_Guts_GetAddressFor(cmock_guts_index);\n"
lines << " UNITY_TEST_ASSERT_NOT_NULL(new_instance, cmock_line, CMockStringOutOfMemory);\n"
lines << " memset(new_instance, 0, sizeof(*new_instance));\n"
lines << " new_instance->LineNumber = cmock_line;\n"
unless function[:return][:void?]
lines << " if (cmock_call_instance != NULL)\n"
lines << " new_instance->ReturnVal = cmock_call_instance->ReturnVal;\n"
end
lines << " Mock.#{func_name}_CallInstance = CMock_Guts_MemChain(Mock.#{func_name}_CallInstance, cmock_guts_index);\n"
lines << " cmock_call_instance = new_instance;\n"
lines << " }\n"
end
lines << " UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringPtrPreExp);\n"
lines << " cmock_call_instance->ReturnThruPtr_#{arg_name}_Used = 1;\n"
lines << " cmock_call_instance->ReturnThruPtr_#{arg_name}_Val = #{arg_name};\n"
@@ -0,0 +1,142 @@
# =========================================================================
# CMock - Automatic Mock Generation for C
# ThrowTheSwitch.org
# Copyright (c) 2007-26 Mike Karlesky, Mark VanderVoord, & Greg Williams
# SPDX-License-Identifier: MIT
# =========================================================================
---
:cmock:
:mock_path: test/mocks
:mock_prefix: mock_
:when_ptr: :smart
:plugins:
- :ignore
- :return_thru_ptr
:systest:
:types: ""
:mockable: |
void ptr_ret_int(int *r);
int ptr_ret_int_rtn(int *r);
:source:
:header: |
#include <string.h>
#define lengthof(x) (sizeof(x)/sizeof((x)[0]))
:code: |
:tests:
:common: |
void setUp(void) {}
void tearDown(void) {}
:units:
- :pass: TRUE
:should: "handle a single int* argument"
:code: |
test()
{
int r = 1;
int res = 4;
ptr_ret_int_Expect(&r);
ptr_ret_int_ReturnThruPtr_r(&res);
ptr_ret_int(&r);
TEST_ASSERT_EQUAL(4, r);
}
- :pass: TRUE
:should: "ignore a call but still return arguments"
:code: |
test()
{
int r = 1;
int res = 4;
ptr_ret_int_Ignore();
ptr_ret_int_ReturnThruPtr_r(&res);
ptr_ret_int(&r);
TEST_ASSERT_EQUAL(4, r);
}
- :pass: TRUE
:should: "queue multiple return values in ignored calls"
:code: |
test()
{
int r = 1;
int res1 = 4;
int res2 = 8;
int res3 = 16;
ptr_ret_int_Ignore();
ptr_ret_int_ReturnThruPtr_r(&res1);
ptr_ret_int_ReturnThruPtr_r(&res2);
ptr_ret_int_ReturnThruPtr_r(&res3);
ptr_ret_int(&r);
TEST_ASSERT_EQUAL(4, r);
ptr_ret_int(&r);
TEST_ASSERT_EQUAL(8, r);
ptr_ret_int(&r);
TEST_ASSERT_EQUAL(16, r);
}
- :pass: TRUE
:should: "return func and handle a single int* argument"
:code: |
test()
{
int r = 1;
int res = 4;
ptr_ret_int_rtn_ExpectAndReturn(&r,1);
ptr_ret_int_rtn_ReturnThruPtr_r(&res);
TEST_ASSERT_EQUAL_INT(1,ptr_ret_int_rtn(&r));
TEST_ASSERT_EQUAL(4, r);
}
- :pass: TRUE
:should: "ignore and return a call but still return arguments"
:code: |
test()
{
int r = 1;
int res = 4;
ptr_ret_int_rtn_IgnoreAndReturn(1);
ptr_ret_int_rtn_ReturnThruPtr_r(&res);
TEST_ASSERT_EQUAL_INT(1,ptr_ret_int_rtn(&r));
TEST_ASSERT_EQUAL(4, r);
}
- :pass: TRUE
:should: "queue multiple return values in ignore and return calls"
:code: |
test()
{
int r = 1;
int res1 = 4;
int res2 = 8;
int res3 = 16;
ptr_ret_int_rtn_IgnoreAndReturn(1);
ptr_ret_int_rtn_ReturnThruPtr_r(&res1);
ptr_ret_int_rtn_ReturnThruPtr_r(&res2);
ptr_ret_int_rtn_ReturnThruPtr_r(&res3);
TEST_ASSERT_EQUAL_INT(1,ptr_ret_int_rtn(&r));
TEST_ASSERT_EQUAL(4, r);
TEST_ASSERT_EQUAL_INT(1,ptr_ret_int_rtn(&r));
TEST_ASSERT_EQUAL(8, r);
TEST_ASSERT_EQUAL_INT(1,ptr_ret_int_rtn(&r));
TEST_ASSERT_EQUAL(16, r);
}
+4
View File
@@ -539,6 +539,7 @@ describe CMockGenerator, "Verify CMockGenerator Module" do
" return cmock_call_instance->ReturnVal;\n",
"}\n\n"
]
@plugins.expect :run, "", [:mock_precheck_return_thru_ptr, function]
@plugins.expect :run, [" uno"], [:mock_implementation_precheck, function]
@plugins.expect :run, [" dos"," tres"], [:mock_implementation, function]
@@ -577,6 +578,7 @@ describe CMockGenerator, "Verify CMockGenerator Module" do
" return cmock_call_instance->ReturnVal;\n",
"}\n\n"
]
@plugins.expect :run, "", [:mock_precheck_return_thru_ptr, function]
@plugins.expect :run, [" uno"], [:mock_implementation_precheck, function]
@plugins.expect :run, [" dos"," tres"], [:mock_implementation, function]
@@ -618,6 +620,7 @@ describe CMockGenerator, "Verify CMockGenerator Module" do
"}\n",
"}\n\n",
]
@plugins.expect :run, "", [:mock_precheck_return_thru_ptr, function]
@plugins.expect :run, [" uno"], [:mock_implementation_precheck, function]
@plugins.expect :run, [" dos"," tres"], [:mock_implementation, function]
@@ -656,6 +659,7 @@ describe CMockGenerator, "Verify CMockGenerator Module" do
" return cmock_call_instance->ReturnVal;\n",
"}\n\n"
]
@plugins.expect :run, "", [:mock_precheck_return_thru_ptr, function]
@plugins.expect :run, [" uno"], [:mock_implementation_precheck, function]
@plugins.expect :run, [" dos"," tres"], [:mock_implementation, function]
@@ -57,6 +57,7 @@ describe CMockGeneratorPluginReturnThruPtr, "Verify CMockGeneratorPluginReturnTh
:contains_ptr? => true }
#no strict ordering
@config.expect :plugins, []
@cmock_generator_plugin_return_thru_ptr = CMockGeneratorPluginReturnThruPtr.new(@config, @utils)
end