Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding a preamble to mocked function name #116

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,21 @@ You can mark all fakes with the weak attribute like so:

See the example project that demonstrates the above approach: _./examples/weak_linking_.

## Specifying a preamble in the mock funtion name

You can make fff add a preamble to the mock function name by generating fff.h as below
```
ruby fakegen.rb --preamble bar_
```
This will cause the mock of function foo() to be named as bar_foo() for every mocked function foo().

This is useful if one needs to build with the real function included. Note that references to the real function will need to change to refer to the new mock function name, this can be done with the help of linkers.

One example is below,
- Use method described here to name function foo() as __wrap_foo()
- use the GNU linker option -Wl,--wrap foo to re-route all references to foo() to __wrap_foo()
- Set 'foo_fake.custom_fake' field to point to the real version of foo(), this will now be named as __real_foo()

## Find Out More

Look under the examples directory for full length examples in both C and C++.
Expand Down
46 changes: 29 additions & 17 deletions fakegen.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def output_constants
putd "#define FFF_GCC_FUNCTION_ATTRIBUTES"
}
putd "#endif"

end


Expand Down Expand Up @@ -269,7 +269,7 @@ def indent
popd
end

def output_macro(arg_count, has_varargs, has_calling_conventions, is_value_function)
def output_macro(arg_count, has_varargs, has_calling_conventions, is_value_function, preamble)

vararg_name = has_varargs ? "_VARARG" : ""
fake_macro_name = is_value_function ? "FAKE_VALUE_FUNC#{arg_count}#{vararg_name}" : "FAKE_VOID_FUNC#{arg_count}#{vararg_name}"
Expand All @@ -281,16 +281,16 @@ def output_macro(arg_count, has_varargs, has_calling_conventions, is_value_funct
puts
output_macro_header(declare_macro_name, saved_arg_count, has_varargs, has_calling_conventions, return_type)
indent {
output_variables(saved_arg_count, has_varargs, has_calling_conventions, is_value_function)
output_variables(saved_arg_count, has_varargs, has_calling_conventions, is_value_function, preamble)
}

puts
output_macro_header(define_macro_name, saved_arg_count, has_varargs, has_calling_conventions, return_type)
indent {
putd_backslash "FUNCNAME##_Fake FUNCNAME##_fake;"
putd_backslash function_signature(saved_arg_count, has_varargs, has_calling_conventions, is_value_function) + "{"
putd_backslash function_signature(saved_arg_count, has_varargs, has_calling_conventions, is_value_function, preamble) + "{"
indent {
output_function_body(saved_arg_count, has_varargs, is_value_function)
output_function_body(saved_arg_count, has_varargs, is_value_function, preamble)
}
putd_backslash "}"
putd_backslash "DEFINE_RESET_FUNCTION(FUNCNAME)"
Expand Down Expand Up @@ -334,7 +334,7 @@ def macro_signature_for(macro_name, arg_count, has_varargs, has_calling_conventi
parameter_list
end

def output_variables(arg_count, has_varargs, has_calling_conventions, is_value_function)
def output_variables(arg_count, has_varargs, has_calling_conventions, is_value_function, preamble)
in_struct{
arg_count.times { |argN|
putd_backslash "DECLARE_ARG(ARG#{argN}_TYPE, #{argN}, FUNCNAME)"
Expand All @@ -348,7 +348,7 @@ def output_variables(arg_count, has_varargs, has_calling_conventions, is_value_f
}
putd_backslash "extern FUNCNAME##_Fake FUNCNAME##_fake;"
putd_backslash "void FUNCNAME##_reset(void);"
putd_backslash function_signature(arg_count, has_varargs, has_calling_conventions, is_value_function) + ";"
putd_backslash function_signature(arg_count, has_varargs, has_calling_conventions, is_value_function, preamble) + ";"
end

#example: ARG0_TYPE arg0, ARG1_TYPE arg1
Expand Down Expand Up @@ -390,15 +390,15 @@ def output_custom_function_array(arg_count, has_varargs, has_calling_conventions
# example: RETURN_TYPE FUNCNAME(ARG0_TYPE arg0, ARG1_TYPE arg1)
# OR
# RETURN_TYPE CALLING_CONVENTION FUNCNAME(ARG0_TYPE arg0, ARG1_TYPE arg1)
def function_signature(arg_count, has_varargs, has_calling_conventions, is_value_function)
def function_signature(arg_count, has_varargs, has_calling_conventions, is_value_function, preamble)
return_type = is_value_function ? "RETURN_TYPE" : "void"
varargs = has_varargs ? ", ..." : ""
calling_conventions = has_calling_conventions ?
"#{return_type} FFF_GCC_FUNCTION_ATTRIBUTES CALLING_CONVENTION FUNCNAME(#{arg_val_list(arg_count)}#{varargs})" :
"#{return_type} FFF_GCC_FUNCTION_ATTRIBUTES FUNCNAME(#{arg_val_list(arg_count)}#{varargs})"
"#{return_type} FFF_GCC_FUNCTION_ATTRIBUTES CALLING_CONVENTION #{preamble}FUNCNAME(#{arg_val_list(arg_count)}#{varargs})" :
"#{return_type} FFF_GCC_FUNCTION_ATTRIBUTES #{preamble}FUNCNAME(#{arg_val_list(arg_count)}#{varargs})"
end

def output_function_body(arg_count, has_varargs, is_value_function)
def output_function_body(arg_count, has_varargs, is_value_function, preamble)
arg_count.times { |i| putd_backslash "SAVE_ARG(FUNCNAME, #{i});" }
putd_backslash "if(ROOM_FOR_MORE_HISTORY(FUNCNAME)){"
indent {
Expand All @@ -411,7 +411,7 @@ def output_function_body(arg_count, has_varargs, is_value_function)
}
putd_backslash "}"
putd_backslash "INCREMENT_CALL_COUNT(FUNCNAME);"
putd_backslash "REGISTER_CALL(FUNCNAME);"
putd_backslash "REGISTER_CALL(#{preamble}FUNCNAME);"

if has_varargs
return_type = is_value_function ? "return " : ""
Expand Down Expand Up @@ -662,17 +662,29 @@ def help
end

help {
args = ARGV
preamble = ""
while !args.empty?
current_arg, *args = args
if current_arg == "--with-calling-conventions" or current_arg == "-wcc"
has_calling_conventions = true
elsif current_arg == "--preamble" or current_arg == "-p"
preamble, *args = args
preamble = "#{preamble}##"
end
end

# Determine if we should generate with support for calling conventions
has_calling_conventions = true if (ARGV[0] == "--with-calling-conventions" or ARGV[0] == "-wcc")
#has_calling_conventions = true if (ARGV[0] == "--with-calling-conventions" or ARGV[0] == "-wcc")
# lets generate!!
output_c_and_cpp(has_calling_conventions) {
define_fff_globals
# Create fake generators for 0..MAX_ARGS
num_fake_generators = $MAX_ARGS + 1
num_fake_generators.times {|arg_count| output_macro(arg_count, false, has_calling_conventions, false)}
num_fake_generators.times {|arg_count| output_macro(arg_count, false, has_calling_conventions, true)}
num_fake_generators.times {|arg_count| output_macro(arg_count, false, has_calling_conventions, false, preamble)}
num_fake_generators.times {|arg_count| output_macro(arg_count, false, has_calling_conventions, true, preamble)}
# generate the varargs variants
(2..$MAX_ARGS).each {|arg_count| output_macro(arg_count, true, has_calling_conventions, false)}
(2..$MAX_ARGS).each {|arg_count| output_macro(arg_count, true, has_calling_conventions, true)}
(2..$MAX_ARGS).each {|arg_count| output_macro(arg_count, true, has_calling_conventions, false, preamble)}
(2..$MAX_ARGS).each {|arg_count| output_macro(arg_count, true, has_calling_conventions, true, preamble)}
}
}
26 changes: 25 additions & 1 deletion test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,25 @@ add_executable(cpp_global_test
)
target_link_libraries(cpp_global_test PRIVATE gtest fff)

# genertae fff_preamble.h so we can test --preamble command
add_custom_command(
OUTPUT
${CMAKE_CURRENT_LIST_DIR}/fff_preamble.h
COMMAND
ruby ${CMAKE_CURRENT_LIST_DIR}/../fakegen.rb --preamble __wrap_ >> ${CMAKE_CURRENT_LIST_DIR}/fff_preamble.h
DEPENDS
${CMAKE_CURRENT_LIST_DIR}/../fakegen.rb
${CMAKE_CURRENT_LIST_DIR}/../LICENSE
)
add_custom_target(fff_preamble_h DEPENDS ${CMAKE_CURRENT_LIST_DIR}/fff_preamble.h)

# Create the test executable to test fff_preamble.h
add_executable(c_preamble_test
fff_preamble.h
fff_test_preamble.c
${COMMON_FILE_LIST}
)

# Add the tests for ctest
add_test(
NAME c_test
Expand All @@ -53,4 +72,9 @@ add_test(
add_test(
NAME cpp_global_test
COMMAND $<TARGET_FILE:cpp_global_test>
)
)

add_test(
NAME c_preamble_test
COMMAND $<TARGET_FILE:c_global_test>
)
36 changes: 36 additions & 0 deletions test/fff_test_preamble.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#include "fff_preamble.h"
#include "c_test_framework.h"

FAKE_VOID_FUNC(voidfunc1, int);

void setup()
{
RESET_FAKE(voidfunc1);
FFF_RESET_HISTORY();
}

TEST_F(FFFTestSuite, fake_function_with_preamble_is_callable)
{
// note the test case assumes the preamble is "__wrap_"
__wrap_voidfunc1(10);
ASSERT_EQ(voidfunc1_fake.call_count, 1);
}

DEFINE_FFF_GLOBALS;
int main()
{
setbuf(stdout, NULL);
fprintf(stdout, "-------------\n");
fprintf(stdout, "Running Tests\n");
fprintf(stdout, "-------------\n\n");
fflush(0);

/* Run tests */
RUN_TEST(FFFTestSuite, fake_function_with_preamble_is_callable);

printf("\n-------------\n");
printf("Complete\n");
printf("-------------\n\n");

return 0;
}