diff --git a/README.md b/README.md index 3255e6a..ecc717a 100644 --- a/README.md +++ b/README.md @@ -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++. diff --git a/fakegen.rb b/fakegen.rb index d937bd3..1bfd8b3 100644 --- a/fakegen.rb +++ b/fakegen.rb @@ -35,7 +35,7 @@ def output_constants putd "#define FFF_GCC_FUNCTION_ATTRIBUTES" } putd "#endif" - + end @@ -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}" @@ -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)" @@ -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)" @@ -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 @@ -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 { @@ -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 " : "" @@ -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)} } } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 0aa6679..4259b86 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -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 @@ -53,4 +72,9 @@ add_test( add_test( NAME cpp_global_test COMMAND $ -) \ No newline at end of file +) + +add_test( + NAME c_preamble_test + COMMAND $ +) diff --git a/test/fff_test_preamble.c b/test/fff_test_preamble.c new file mode 100644 index 0000000..3a27972 --- /dev/null +++ b/test/fff_test_preamble.c @@ -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; +}