1
0
mirror of https://github.com/meekrosoft/fff synced 2026-01-29 03:04:27 +01:00

2 Commits

73 changed files with 34067 additions and 6657 deletions

View File

@@ -1,28 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Compiler, toolset, platform (please complete the following information):**
- OS: [e.g. Ubuntu 16.04 LTS]
- Compiler: [e.g. gcc (Ubuntu 5.4.0-6ubuntu1~16.04.10) 5.4.0 20160609]
**Additional context**
Add any other context about the problem here.

View File

@@ -1,17 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@@ -1,8 +0,0 @@
Thank you for your contribution.
Before submitting this PR, please make sure:
- [ ] Your code builds clean without any errors or warnings
- [ ] You are not breaking consistency
- [ ] You have added unit tests
- [ ] All tests and other checks pass

View File

@@ -1,25 +0,0 @@
name: Check PR
on:
pull_request:
branches:
- master
push:
jobs:
check-pr:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
steps:
- uses: actions/checkout@v3
- uses: seanmiddleditch/gha-setup-ninja@master
- name: Build
run: |
mkdir build
cmake -GNinja -B build
cmake --build build
ctest --test-dir build --output-on-failure

36
.gitignore vendored
View File

@@ -2,39 +2,3 @@ build/
*~ *~
*.sublime-project *.sublime-project
*.sublime-workspace *.sublime-workspace
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015/2017 cache/options directory
.vs/
# IntelliJ IDE project directory
.idea/
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb

View File

@@ -1,46 +0,0 @@
# Copyright 2022 Google LLC
# SPDX-License-Identifier: Apache-2.0
cmake_minimum_required(VERSION 3.20.0)
project(fff)
set(CMAKE_CXX_STANDARD 11)
# Enable ctest
enable_testing()
add_library(fff INTERFACE)
option(FFF_GENERATE "If enabled, fff.h will be regenerated using ruby" OFF)
# Generate fff.h if fakegen.rb changed
if(FFF_GENERATE)
add_custom_command(
OUTPUT
${CMAKE_CURRENT_LIST_DIR}/fff.h
COMMAND
ruby ${CMAKE_CURRENT_LIST_DIR}/fakegen.rb >> ${CMAKE_CURRENT_LIST_DIR}/fff.h
DEPENDS
${CMAKE_CURRENT_LIST_DIR}/fakegen.rb
${CMAKE_CURRENT_LIST_DIR}/LICENSE
)
add_custom_target(fff_h DEPENDS ${CMAKE_CURRENT_LIST_DIR}/fff.h)
else()
add_library(fff_h INTERFACE)
set_target_properties(fff_h
PROPERTIES PUBLIC_HEADER "fff.h"
)
endif()
add_dependencies(fff fff_h)
# Add an interface library for fff.h
target_include_directories(fff INTERFACE ${CMAKE_CURRENT_LIST_DIR})
option(FFF_UNIT_TESTING "If enabled, fff tests will be compiled and run" OFF)
if(FFF_UNIT_TESTING)
# Add tests and samples
add_subdirectory(test)
add_subdirectory(examples)
endif()

10
Makefile Normal file
View File

@@ -0,0 +1,10 @@
all:
mkdir -p build
cd gtest; $(MAKE) all
cd test; $(MAKE) all
cd examples; $(MAKE) all
clean:
cd gtest; $(MAKE) clean
cd test; $(MAKE) clean
cd examples; $(MAKE) clean

181
README.md
View File

@@ -2,45 +2,13 @@
----------------------------- -----------------------------
[![Build Status](https://travis-ci.org/meekrosoft/fff.svg?branch=master)](https://travis-ci.org/meekrosoft/fff) [![Build Status](https://travis-ci.org/meekrosoft/fff.svg?branch=master)](https://travis-ci.org/meekrosoft/fff)
[![Build status](https://ci.appveyor.com/api/projects/status/md1gn8cxnjkrkq3b/branch/master?svg=true)](https://ci.appveyor.com/project/wulfgarpro/fff/branch/master)
[![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/wulfgarpro/fff?utm_source=share-link&utm_medium=link&utm_campaign=share-link)
- [A Fake Function Framework for C](#a-fake-function-framework-for-c)
- [Hello Fake World!](#hello-fake-world)
- [Capturing Arguments](#capturing-arguments)
- [Return Values](#return-values)
- [Resetting a Fake](#resetting-a-fake)
- [Call History](#call-history)
- [Default Argument History](#default-argument-history)
- [User Defined Argument History](#user-defined-argument-history)
- [Function Return Value Sequences](#function-return-value-sequences)
- [Custom Return Value Delegate](#custom-return-value-delegate)
- [Return Value History](#return-value-history)
- [Variadic Functions](#variadic-functions)
- [Common Questions](#common-questions)
- [Specifying GCC Function Attributes](#specifying-gcc-function-attributes)
- [Find Out More](#find-out-more)
- [Benefits](#benefits)
- [Under the Hood](#under-the-hood)
- [Cheat Sheet](#cheat-sheet)
## A Fake Function Framework for C ## A Fake Function Framework for C
fff is a micro-framework for creating fake C functions for tests. Because life fff is a micro-framework for creating fake C functions for tests. Because life
is too short to spend time hand-writing fake functions for testing. is too short to spend time hand-writing fake functions for testing.
## Running all tests
### Linux / MacOS ## Hello fake world!
To run all the tests and sample apps, simply call `$ buildandtest`. This script
will call down into CMake with the following:
```shell
cmake -B build -DFFF_GENERATE=ON -DFFF_UNIT_TESTING=ON
cmake --build build
ctest --test-dir build --output-on-failure
```
## Hello Fake World!
Say you are testing an embedded user interface and you have a function that Say you are testing an embedded user interface and you have a function that
you want to create a fake for: you want to create a fake for:
@@ -94,7 +62,11 @@ typedef struct DISPLAY_init_Fake {
DISPLAY_init_Fake DISPLAY_init_fake; DISPLAY_init_Fake DISPLAY_init_fake;
``` ```
## Capturing Arguments
## Capturing arguments
Ok, enough with the toy examples. What about faking functions with arguments? Ok, enough with the toy examples. What about faking functions with arguments?
@@ -132,7 +104,9 @@ type (a char pointer in this example).
A variable is created for every argument in the form A variable is created for every argument in the form
`"function_name"fake.argN_val` `"function_name"fake.argN_val`
## Return Values
## Return values
When you want to define a fake function that returns a value, you should use the When you want to define a fake function that returns a value, you should use the
`FAKE_VALUE_FUNC` macro. For instance: `FAKE_VALUE_FUNC` macro. For instance:
@@ -179,7 +153,10 @@ you would use a syntax like this:
```c ```c
FAKE_VALUE_FUNC(double, pow, double, double); FAKE_VALUE_FUNC(double, pow, double, double);
``` ```
## Resetting a Fake
## Resetting a fake
Good tests are isolated tests, so it is important to reset the fakes for each Good tests are isolated tests, so it is important to reset the fakes for each
unit test. All the fakes have a reset function to reset their arguments and unit test. All the fakes have a reset function to reset their arguments and
@@ -219,9 +196,9 @@ void setup()
} }
``` ```
## Call History ## Call history
Say you want to test that a function calls functionA, then functionB, then Say you want to test that a function calls functionA, then functionB, then
functionA again, how would you do that? Well fff maintains a call functionA again, how would you do that? Well `fff` maintains a call
history so that it is easy to assert these expectations. history so that it is easy to assert these expectations.
Here's how it works: Here's how it works:
@@ -283,7 +260,7 @@ The other is to check if the call count is greater than the history size:
ASSERT(voidfunc2_fake.arg_history_len < voidfunc2_fake.call_count); ASSERT(voidfunc2_fake.arg_history_len < voidfunc2_fake.call_count);
``` ```
The argument histories for a fake function are reset when the `RESET_FAKE` The argument histories for a fake function are reset when the RESET_FAKE
function is called function is called
## User Defined Argument History ## User Defined Argument History
@@ -300,6 +277,7 @@ override the default by defining it before include the `fff.h` like this:
#include "../fff.h" #include "../fff.h"
``` ```
## Function Return Value Sequences ## Function Return Value Sequences
Often in testing we would like to test the behaviour of sequence of function call Often in testing we would like to test the behaviour of sequence of function call
@@ -330,7 +308,7 @@ value in the sequence indefinitely.
## Custom Return Value Delegate ## Custom Return Value Delegate
You can specify your own function to provide the return value for the fake. This You can specify your own function to provide the return value for the fake. This
is done by setting the `custom_fake` member of the fake. Here's an example: is done by setting the custom_fake member of the fake. Here's an example:
```c ```c
#define MEANING_OF_LIFE 42 #define MEANING_OF_LIFE 42
@@ -346,13 +324,13 @@ TEST_F(FFFTestSuite, when_value_custom_fake_called_THEN_it_returns_custom_return
} }
``` ```
### Custom Return Value Delegate Sequences ## Custom Return Value Delegate Sequences
Say you have a function with an out parameter, and you want it to have a different behaviour Say you have a function with an out parameter, and you want it to have a different behaviour
on the first three calls, for example: set the value 'x' to the out parameter on the first call, on the first three calls, for example: set the value 'x' to the out parameter on the first call,
the value 'y' to the out parameter on the second call, and the value 'z' to the out parameter the value 'y' to the out parameter on the second call, and the value 'z' to the out parameter
on the third call. You can specify a sequence of custom functions to a non-variadic function on the third call. You can specify a sequence of custom functions to a non-variadic function
using the `SET_CUSTOM_FAKE_SEQ` macro. Here's an example: using the SET_CUSTOM_FAKE_SEQ macro. Here's an example:
```c ```c
void voidfunc1outparam_custom_fake1(char *a) void voidfunc1outparam_custom_fake1(char *a)
@@ -388,15 +366,14 @@ TEST_F(FFFTestSuite, custom_fake_sequence_not_exausthed)
} }
``` ```
The fake will call your custom functions in the order specified by the `SET_CUSTOM_FAKE_SEQ` The fake will call your custom functions in the order specified by the SET_CUSTOM_FAKE_SEQ
macro. When the last custom fake is reached the fake will keep calling the last custom macro. When the last custom fake is reached the fake will keep calling the last custom
fake in the sequence. This macro works much like the `SET_RETURN_SEQ` macro. fake in the sequence. This macro works much like the SET_RETURN_SEQ macro.
## Return Value History
## Return value history
Say you have two functions f1 and f2. f2 must be called to release some resource Say you have two functions f1 and f2. f2 must be called to release some resource
allocated by f1, but only in the cases where f1 returns zero. f1 could be allocated by f1, but only in the cases where f1 returns zero. f1 could be
pthread_mutex_trylock and f2 could be pthread_mutex_unlock. fff will pthread_mutex_trylock and f2 could be pthread_mutex_unlock. <tt>fff</tt> will
save the history of returned values so this can be easily checked, even when save the history of returned values so this can be easily checked, even when
you use a sequence of custom fakes. Here's a simple example: you use a sequence of custom fakes. Here's a simple example:
@@ -412,18 +389,18 @@ you use a sequence of custom fakes. Here's a simple example:
ASSERT_EQ(myReturnVals[2], longfunc0_fake.return_val_history[2]); ASSERT_EQ(myReturnVals[2], longfunc0_fake.return_val_history[2]);
} }
You access the returned values in the `return_val_history` field. You access the returned values in the <tt>return_val_history</tt> field.
## Variadic Functions ## Variadic Functions
You can fake variadic functions using the macros `FAKE_VALUE_FUNC_VARARG` You can fake variadic functions using the macros <tt>FAKE_VALUE_FUNC_VARARG</tt>
and `FAKE_VOID_FUNC_VARARG`. For instance: and <tt>FAKE_VOID_FUNC_VARARG</tt>. For instance:
FAKE_VALUE_FUNC_VARARG(int, fprintf, FILE *, const char*, ...); FAKE_VALUE_FUNC_VARARG(int, fprintf, FILE *, const char*, ...);
In order to access the variadic parameters from a custom fake function, declare a In order to access the variadic parameters from a custom fake function, declare a
`va_list` parameter. For instance, a custom fake for `fprintf()` <tt>va_list</tt> parameter. For instance, a custom fake for <tt>fprintf()</tt>
could call the real `fprintf()` like this: could call the real <tt>fprintf()</tt> like this:
int fprintf_custom(FILE *stream, const char *format, va_list ap) { int fprintf_custom(FILE *stream, const char *format, va_list ap) {
if (fprintf0_fake.return_val < 0) // should we fail? if (fprintf0_fake.return_val < 0) // should we fail?
@@ -431,45 +408,14 @@ could call the real `fprintf()` like this:
return vfprintf(stream, format, ap); return vfprintf(stream, format, ap);
} }
Just like [return value delegates](#custom-return-value-delegate-sequences), you can also specify sequences for variadic functions using `SET_CUSTOM_FAKE_SEQ`. ## How do I fake a function that returns a value by reference?
See the test files for examples. The basic mechanism that FFF provides you in this case is the custom_fake field described in the *Custom Return Value Delegate* example above.
## Common Questions
### How do I specify calling conventions for my fake functions?
fff has a limited capability for enabling specification of Microsoft's Visual C/C++ calling conventions, but this support must be enabled when generating fff's header file `fff.h`.
```bash
ruby fakegen.rb --with-calling-conventions > fff.h
```
By enabling this support, all of fff's fake function scaffolding will necessitate the specification of a calling convention, e.g. `__cdecl` for each VALUE or VOID fake.
Here are some basic examples: take note that the placement of the calling convention being specified is different depending on whether the fake is a VOID or VALUE function.
```c
FAKE_VOID_FUNC(__cdecl, voidfunc1, int);
FAKE_VALUE_FUNC(long, __cdecl, longfunc0);
```
### How do I fake a function that returns a value by reference?
The basic mechanism that fff provides you in this case is the custom_fake field described in the *Custom Return Value Delegate* example above.
You need to create a custom function (e.g. getTime_custom_fake) to produce the output optionally by use of a helper variable (e.g. getTime_custom_now) to retrieve that output from. Then some creativity to tie it all together. The most important part (IMHO) is to keep your test case readable and maintainable. You need to create a custom function (e.g. getTime_custom_fake) to produce the output optionally by use of a helper variable (e.g. getTime_custom_now) to retrieve that output from. Then some creativity to tie it all together. The most important part (IMHO) is to keep your test case readable and maintainable.
In case your project uses a C compiler that supports nested functions (e.g. GCC), or when using C++ lambdas, you can even combine all this in a single unit test function so you can easily oversee all details of the test. In case your project uses a C compiler that supports nested functions (e.g. GCC) you can even combine all this in a single unit test function so you can easily oversee all details of the test.
```c ```c
#include <functional>
/* Configure FFF to use std::function, which enables capturing lambdas */
#define CUSTOM_FFF_FUNCTION_TEMPLATE(RETURN, FUNCNAME, ...) \
std::function<RETURN (__VA_ARGS__)> FUNCNAME
#include "fff.h"
/* The time structure */ /* The time structure */
typedef struct { typedef struct {
int hour, min; int hour, min;
@@ -482,13 +428,15 @@ FAKE_VOID_FUNC(getTime, Time*);
TEST_F(FFFTestSuite, when_value_custom_fake_called_THEN_it_returns_custom_output) TEST_F(FFFTestSuite, when_value_custom_fake_called_THEN_it_returns_custom_output)
{ {
Time t; Time t;
Time getTime_custom_now = { Time getTime_custom_now;
.hour = 13, void getTime_custom_fake(Time *now) {
.min = 05, *now = getTime_custom_now;
}; }
getTime_fake.custom_fake = [getTime_custom_now](Time *now) { getTime_fake.custom_fake = getTime_custom_fake;
*now = getTime_custom_now;
}; /* given a specific time */
getTime_custom_now.hour = 13;
getTime_custom_now.min = 05;
/* when getTime is called */ /* when getTime is called */
getTime(&t); getTime(&t);
@@ -499,9 +447,8 @@ TEST_F(FFFTestSuite, when_value_custom_fake_called_THEN_it_returns_custom_output
} }
``` ```
### How do I fake a function with a function pointer parameter? ## How do I fake a function with a function pointer parameter?
Using FFF to stub functions that have function pointer parameter can cause problems when trying to stub them. Presented here is an example how to deal with this situation.
Using fff to stub functions that have function pointer parameter can cause problems when trying to stub them. Presented here is an example how to deal with this situation.
If you need to stub a function that has a function pointer parameter, e.g. something like: If you need to stub a function that has a function pointer parameter, e.g. something like:
@@ -511,7 +458,7 @@ typedef int timer_handle;
extern int timer_start(timer_handle handle, long delay, void (*cb_function) (int arg), int arg); extern int timer_start(timer_handle handle, long delay, void (*cb_function) (int arg), int arg);
``` ```
Then creating a fake like below will horribly fail when trying to compile because the fff macro will internally expand into an illegal variable ```int (*)(int) arg2_val```. Then creating a fake like below will horribly fail when trying to compile because the FFF macro will internally expand into an illegal variable ```int (*)(int) arg2_val```.
```c ```c
/* The fake, attempt one */ /* The fake, attempt one */
@@ -526,7 +473,7 @@ FAKE_VALUE_FUNC(int,
The solution to this problem is to create a bridging type that needs only to be visible in the unit tester. The fake will use that intermediate type. This way the compiler will not complain because the types match. The solution to this problem is to create a bridging type that needs only to be visible in the unit tester. The fake will use that intermediate type. This way the compiler will not complain because the types match.
```c ```c
/* Additional type needed to be able to use callback in fff */ /* Additional type needed to be able to use callback in FFF */
typedef void (*timer_cb) (int argument); typedef void (*timer_cb) (int argument);
/* The fake, attempt two */ /* The fake, attempt two */
@@ -583,10 +530,8 @@ TEST_F(FFFTestSuite, test_fake_with_function_pointer)
ASSERT_EQ(cb_timeout_called, 1); ASSERT_EQ(cb_timeout_called, 1);
} }
``` ```
## How do I reuse a fake across multiple test-suites?
### How do I reuse a fake across multiple test-suites? FFF functions like FAKE_VALUE_FUNC will perform both the declaration AND the definition of the fake function and the corresponding data structs. This cannot be placed in a header, since it will lead to multiple definitions of the fake functions.
fff functions like `FAKE_VALUE_FUNC` will perform both the declaration AND the definition of the fake function and the corresponding data structs. This cannot be placed in a header, since it will lead to multiple definitions of the fake functions.
The solution is to separate declaration and definition of the fakes, and place the declaration into a public header file, and the definition into a private source file. The solution is to separate declaration and definition of the fakes, and place the declaration into a public header file, and the definition into a private source file.
@@ -612,28 +557,7 @@ DEFINE_FAKE_VOID_FUNC_VARARG(void_function_vargs, const char *, int, ...);
``` ```
## Specifying GCC Function Attributes ## Find out more...
You can specify GCC function attributes for your fakes using the `FFF_GCC_FUNCTION_ATTRIBUTES` directive.
### Weak Functions
One usful attribute is the _weak_ attribute that marks a function such that it can be overridden by a non-weak variant at link time. Using weak functions in combination with fff can help simplify your testing approach.
For example:
* Define a library of fake functions, e.g. libfake.a.
* Link a binary (you might have many) that defines a subset of real variants of the fake functions to the aforementioned fake library.
* This has the benefit of allowing a binary to selectively use a subset of the required fake functions while testing the real variants without the need for many different make targets.
You can mark all fakes with the weak attribute like so:
```
#define FFF_GCC_FUNCTION_ATTRIBUTES __attribute__((weak))
#include "fff.h"
```
See the example project that demonstrates the above approach: _./examples/weak_linking_.
## Find Out More
Look under the examples directory for full length examples in both C and C++. Look under the examples directory for full length examples in both C and C++.
There is also a test suite for the framework under the test directory. There is also a test suite for the framework under the test directory.
@@ -648,11 +572,10 @@ So whats the point?
* To work in both C and C++ test environments * To work in both C and C++ test environments
## Under the Hood ## Under the hood:
* The fff.h header file is generated by a ruby script * The fff.h header file is generated by a ruby script
* There are tests under _./test_ * There are tests under src/test
* There is an example for testing an embedded UI and a hardware driver under _./examples_ * There is an example for testing an embedded UI and a hardware driver under src/examples
* There is an example of weak_linking under _./examples_
## Cheat Sheet ## Cheat Sheet
@@ -660,6 +583,4 @@ So whats the point?
|-------|-------------|---------| |-------|-------------|---------|
| FAKE_VOID_FUNC(fn [,arg_types*]); | Define a fake function named fn returning void with n arguments | FAKE_VOID_FUNC(DISPLAY_output_message, const char*); | | FAKE_VOID_FUNC(fn [,arg_types*]); | Define a fake function named fn returning void with n arguments | FAKE_VOID_FUNC(DISPLAY_output_message, const char*); |
| FAKE_VALUE_FUNC(return_type, fn [,arg_types*]); | Define a fake function returning a value with type return_type taking n arguments | FAKE_VALUE_FUNC(int, DISPLAY_get_line_insert_index); | | FAKE_VALUE_FUNC(return_type, fn [,arg_types*]); | Define a fake function returning a value with type return_type taking n arguments | FAKE_VALUE_FUNC(int, DISPLAY_get_line_insert_index); |
| FAKE_VOID_FUNC_VARARG(fn [,arg_types*], ...); | Define a fake variadic function returning void with type return_type taking n arguments and n variadic arguments | FAKE_VOID_FUNC_VARARG(fn, const char*, ...) |
| FAKE_VALUE_FUNC_VARARG(return_type, fn [,arg_types*], ...); | Define a fake variadic function returning a value with type return_type taking n arguments and n variadic arguments | FAKE_VALUE_FUNC_VARARG(int, fprintf, FILE*, const char*, ...) |
| RESET_FAKE(fn); | Reset the state of fake function called fn | RESET_FAKE(DISPLAY_init); | | RESET_FAKE(fn); | Reset the state of fake function called fn | RESET_FAKE(DISPLAY_init); |

View File

@@ -1,15 +1,16 @@
#!/bin/bash #!/bin/bash
set -e set -e
# Clear the environment cat LICENSE > fff.h
rm -fr build fff.h echo >> fff.h
mkdir build ruby fakegen.rb >> fff.h
make clean
# Configure the build make all
cmake -B build -DFFF_GENERATE=ON -DFFF_UNIT_TESTING=ON || exit -1 build/fff_test_c
build/fff_test_cpp --gtest_output=xml:build/test_results.xml
# Build all targets build/ui_test_ansic
cmake --build build || exit -1 build/ui_test_cpp --gtest_output=xml:build/example_results.xml
build/fff_test_glob_c
# Run all tests build/fff_test_glob_cpp --gtest_output=xml:build/test_global_results.xml
ctest --test-dir build --output-on-failure build/driver_testing --gtest_output=xml:build/driver_testing.xml
build/driver_testing_fff --gtest_output=xml:build/driver_testing_fff.xml

View File

@@ -1,6 +0,0 @@
# Copyright 2022 Google LLC
# SPDX-License-Identifier: Apache-2.0
add_subdirectory(driver_testing)
add_subdirectory(embedded_ui)
add_subdirectory(weak_linking)

7
examples/Makefile Normal file
View File

@@ -0,0 +1,7 @@
all:
cd embedded_ui; $(MAKE) all
cd driver_testing; $(MAKE) all
clean:
cd embedded_ui; $(MAKE) clean
cd driver_testing; $(MAKE) clean

View File

@@ -1,31 +0,0 @@
# Copyright 2022 Google LLC
# SPDX-License-Identifier: Apache-2.0
# Create the driver test binary
add_executable(driver_test
src/driver.c
src/driver.test.cpp
)
target_include_directories(driver_test PRIVATE include)
target_link_libraries(driver_test PRIVATE GTest::gtest_main fff)
target_compile_definitions(driver_test PUBLIC TEST_USER_OWN_TR1_TUPLE=1 TESTING)
# Create the driver fff test binary
add_executable(driver_fff_test
src/driver.c
src/driver.test.fff.cpp
)
target_include_directories(driver_fff_test PRIVATE include)
target_link_libraries(driver_fff_test PRIVATE GTest::gtest_main fff)
target_compile_definitions(driver_fff_test PUBLIC TEST_USER_OWN_TR1_TUPLE=1 TESTING)
# Add tests to ctest
add_test(
NAME driver_test
COMMAND $<TARGET_FILE:driver_test>
)
add_test(
NAME driver_fff_test
COMMAND $<TARGET_FILE:driver_fff_test>
)

View File

@@ -0,0 +1,64 @@
$(VERBOSE).SILENT:
BUILD_DIR = ../../build
TEMPLATE_PROGNAME = $(BUILD_DIR)/template
CPP_PROGNAME_NOFFF = $(BUILD_DIR)/driver_testing
CPP_PROGNAME_FFF = $(BUILD_DIR)/driver_testing_fff
CC = gcc
CC += -c
CPP = g++
CPP += -c
LD = g++
GTEST_OBJS = $(BUILD_DIR)/gtest-all.o $(BUILD_DIR)/gtest-main.o
C_OBJFILES = $(BUILD_DIR)/driver.o
TEMPLATE_OBJFILES = $(BUILD_DIR)/test_suite_template.o
FFF_OBJFILES = $(BUILD_DIR)/driver.test.fff.o $(GTEST_OBJS)
NOFFF_OBJFILES = $(BUILD_DIR)/driver.test.o $(GTEST_OBJS)
CPP_LIBS = -lpthread
all: $(CPP_PROGNAME_NOFFF) $(CPP_PROGNAME_FFF) $(TEMPLATE_PROGNAME)
.PHONY: clean
clean:
@echo "Cleaning object files"
@echo " rm -f $(BUILD_DIR)/*.o"
rm -f $(BUILD_DIR)/*.o
@echo "Cleaning backups"
@echo " rm -f *~"
rm -f *~
@echo "Removing programs"
@echo " rm -f $(CPP_PROGNAME_NOFFF) $(CPP_PROGNAME_FFF) $(TEMPLATE_PROGNAME)"
rm -f $(CPP_PROGNAME_NOFFF) $(CPP_PROGNAME_FFF) $(TEMPLATE_PROGNAME)
$(BUILD_DIR)/%.o: %.c
@echo "Compiling "$@
@echo " CC "$<
$(CC) -o $@ $< -DTESTING
$(BUILD_DIR)/%.o: %.cpp
@echo "Compiling "$@
@echo " CPP "$<
$(CPP) -DGTEST_USE_OWN_TR1_TUPLE=1 -I../.. -o $@ $< -DTESTING
$(TEMPLATE_PROGNAME): $(TEMPLATE_OBJFILES)
@echo "Linking "$@
@echo " LD -o "ctemplate" "$(TEMPLATE_OBJFILES)
$(LD) -o $(TEMPLATE_PROGNAME) $(TEMPLATE_OBJFILES)
$(CPP_PROGNAME_FFF): $(FFF_OBJFILES) $(C_OBJFILES)
@echo "Linking "$@
@echo " LD -o "$(CPP_PROGNAME_FFF)" "$(FFF_OBJFILES)
$(LD) -o $(CPP_PROGNAME_FFF) $(FFF_OBJFILES) $(C_OBJFILES) $(CPP_LIBS)
$(CPP_PROGNAME_NOFFF): $(NOFFF_OBJFILES) $(C_OBJFILES)
@echo "Linking "$@
@echo " LD -o "$(CPP_PROGNAME_NOFFF)" "$(NOFFF_OBJFILES)
$(LD) -o $(CPP_PROGNAME_NOFFF) $(NOFFF_OBJFILES) $(C_OBJFILES) $(CPP_LIBS)
nothing:
@echo "Nothing to do; quitting :("
@echo "HINT: Try make all"

View File

@@ -3,7 +3,7 @@ extern "C"
#include "driver.h" #include "driver.h"
#include "registers.h" #include "registers.h"
} }
#include "../../../fff.h" #include "../../fff.h"
#include <gtest/gtest.h> #include <gtest/gtest.h>

View File

@@ -1,9 +1,8 @@
extern "C"{ extern "C"{
#include "driver.h" #include "driver.h"
#include "registers.h" #include "registers.h"
#include "hardware_abstraction.h"
} }
#include "fff.h" #include "../../fff.h"
#include <gtest/gtest.h> #include <gtest/gtest.h>
DEFINE_FFF_GLOBALS; DEFINE_FFF_GLOBALS;

View File

@@ -1,23 +0,0 @@
# Copyright 2022 Google LLC
# SPDX-License-Identifier: Apache-2.0
# Create the ui_test_ansic test binary
add_executable(ui_test_ansic src/UI_test_ansic.c src/UI.c)
target_include_directories(ui_test_ansic PRIVATE include)
target_link_libraries(ui_test_ansic PRIVATE fff)
# Create the ui_test_cpp test binary
add_executable(ui_test_cpp src/UI_test_cpp.cpp src/UI.c)
target_include_directories(ui_test_cpp PRIVATE include)
target_link_libraries(ui_test_cpp PRIVATE GTest::gtest_main fff)
# Add tests to ctest
add_test(
NAME ui_test_ansic
COMMAND $<TARGET_FILE:ui_test_ansic>
)
add_test(
NAME ui_test_cpp
COMMAND $<TARGET_FILE:ui_test_cpp>
)

View File

@@ -0,0 +1,67 @@
$(VERBOSE).SILENT:
BUILD_DIR = ../../build
TEMPLATE_PROGNAME = $(BUILD_DIR)/template
C_PROGNAME = $(BUILD_DIR)/ui_test_ansic
CPP_PROGNAME = $(BUILD_DIR)/ui_test_cpp
CC = gcc
CC += -c
CPP = g++
CPP += -c
LD = g++
GTEST_OBJS = $(BUILD_DIR)/gtest-all.o $(BUILD_DIR)/gtest-main.o
C_OBJFILES = $(BUILD_DIR)/UI_test_ansic.o $(BUILD_DIR)/UI.o
TEMPLATE_OBJFILES = $(BUILD_DIR)/test_suite_template.o
CPP_OBJFILES = $(BUILD_DIR)/UI_test_cpp.o $(BUILD_DIR)/UI.o $(GTEST_OBJS)
CPP_LIBS = -lpthread
all: $(C_PROGNAME) $(CPP_PROGNAME) $(TEMPLATE_PROGNAME)
.PHONY: clean
clean:
@echo "Cleaning object files"
@echo " rm -f $(BUILD_DIR)/*.o"
rm -f $(BUILD_DIR)/*.o
@echo "Cleaning backups"
@echo " rm -f *~"
rm -f *~
@echo "Removing programs"
@echo " rm -f "$(C_PROGNAME)
rm -f $(C_PROGNAME)
@echo " rm -f "$(CPP_PROGNAME) $(TEMPLATE_PROGNAME)
rm -f $(CPP_PROGNAME) $(TEMPLATE_PROGNAME)
$(BUILD_DIR)/%.o: %.c
@echo "Compiling "$@
@echo " CC "$<
$(CC) -o $@ $<
$(BUILD_DIR)/%.o: %.cpp
@echo "Compiling "$@
@echo " CPP "$<
$(CPP) -DGTEST_USE_OWN_TR1_TUPLE=1 -I../.. -o $@ $<
$(TEMPLATE_PROGNAME): $(TEMPLATE_OBJFILES)
@echo "Linking "$@
@echo " LD -o "ctemplate" "$(TEMPLATE_OBJFILES)
$(LD) -o $(TEMPLATE_PROGNAME) $(TEMPLATE_OBJFILES)
$(C_PROGNAME): $(C_OBJFILES)
@echo "Linking "$@
@echo " LD -o "$(C_PROGNAME)" "$(C_OBJFILES)
$(LD) -o $(C_PROGNAME) $(C_OBJFILES)
$(CPP_PROGNAME): $(CPP_OBJFILES) $(C_OBJFILES)
@echo "Linking "$@
@echo " LD -o "$(CPP_PROGNAME)" "$(CPP_OBJFILES)
$(LD) -o $(CPP_PROGNAME) $(CPP_OBJFILES) $(CPP_LIBS)
nothing:
@echo "Nothing to do; quitting :("
@echo "HINT: Try make all"

View File

@@ -1,5 +1,5 @@
#include "UI.h" #include "UI.h"
#include "fff.h" #include "../../fff.h"
#include "SYSTEM.h" #include "SYSTEM.h"
#include "DISPLAY.h" #include "DISPLAY.h"

View File

@@ -6,7 +6,7 @@ extern "C"{
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include "fff.h" #include "../../fff.h"
DEFINE_FFF_GLOBALS; DEFINE_FFF_GLOBALS;
/* SYSTEM.h */ /* SYSTEM.h */

View File

@@ -0,0 +1,34 @@
#include "../../test/c_test_framework.h"
/* Initialializers called for every test */
void setup()
{
}
/* Tests go here */
TEST_F(GreeterTests, hello_world)
{
assert(1 == 0);
}
int main()
{
setbuf(stderr, NULL);
fprintf(stdout, "-------------\n");
fprintf(stdout, "Running Tests\n");
fprintf(stdout, "-------------\n\n");
fflush(0);
/* Run tests */
RUN_TEST(GreeterTests, hello_world);
printf("\n-------------\n");
printf("Complete\n");
printf("-------------\n\n");
return 0;
}

View File

@@ -1,54 +0,0 @@
# Copyright 2022 Google LLC
# SPDX-License-Identifier: Apache-2.0
# Skip these tests for Windows
if(WIN32)
message(STATUS "Weak linking requires __attribute__((weak)) which isn't supported on MS VS, skipping tests")
return()
endif()
# Set the global FFF_GCC_FUNCTION_ATTRIBUTES for config.h
set(FFF_GCC_FUNCTION_ATTRIBUTES "__attribute__((weak))")
configure_file(config/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
# Create a libfakes static library that will be used in the executables below.
# This library will depend on the above generated config.h which will add the
# FFF 'weak' function attributes.
add_library(libfakes STATIC
test/src/bus.fake.c
test/src/display.fake.c
test/src/error.fake.c
test/src/sensor.fake.c
test/src/test_common.c
)
target_precompile_headers(libfakes PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/config.h)
target_include_directories(libfakes PUBLIC include test/include)
target_link_libraries(libfakes PUBLIC fff)
# Create the main test binary
add_executable(test_main src/main.c test/src/main.test.c)
target_link_libraries(test_main PRIVATE libfakes)
# Create the sensor test binary
add_executable(test_sensor src/sensor.c test/src/sensor.test.c)
target_link_libraries(test_sensor PRIVATE libfakes)
# Create the display test binary
add_executable(test_display src/display.c test/src/display.test.c ${LIBFAKES_SRCS})
target_link_libraries(test_display PRIVATE libfakes)
# Add tests to ctest
add_test(
NAME test_main
COMMAND $<TARGET_FILE:test_main>
)
add_test(
NAME test_sensor
COMMAND $<TARGET_FILE:test_sensor>
)
add_test(
NAME test_display
COMMAND $<TARGET_FILE:test_display>
)

View File

@@ -1,5 +0,0 @@
/* Copyright 2022 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
#cmakedefine FFF_GCC_FUNCTION_ATTRIBUTES @FFF_GCC_FUNCTION_ATTRIBUTES@

View File

@@ -1,6 +0,0 @@
#pragma once
#include "error.h"
bool bus_read_write( uint8_t dev, uint8_t registry, uint8_t* buffer, int len, bool assume_echo );
bool bus_write( uint8_t dev, uint8_t registry, const uint8_t* buffer, int len, bool assume_echo );

View File

@@ -1,5 +0,0 @@
#pragma once
#include "error.h"
bool display_init();
void display_update( const char* info );

View File

@@ -1,7 +0,0 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
void runtime_error( const char* msg );
char* runtime_error_nice_print( const char* msg );

View File

@@ -1,6 +0,0 @@
#pragma once
#include "error.h"
bool sensor_init();
float sensor_read();

View File

@@ -1,30 +0,0 @@
#pragma once
uint16_t* BUS_REGISTER_BASE = (uint16_t*)0xDEADBEEF;
typedef struct
{
uint16_t action;
uint16_t reg;
uint8_t input;
uint8_t output
} BusDevice;
BusDevice* BUS = (BusDevice*)BUS_REGISTER_BASE;
bool bus_read_write( uint8_t dev, uint8_t registry, uint8_t* buffer, int len, bool assume_echo )
{
// Something that we dont want to run, since the emulation would be hard.
BUS->action = 0x01;
BUS->reg = registry;
for ( int loop =0 ; loop < len; loop ++ )
{
char output = buffer[loop];
BUS->output = output;
buffer[loop] = BUS->input;
if ( ( assume_echo ) && ( buffer[loop] != output ) )
return false;
}
return true;
}

View File

@@ -1,29 +0,0 @@
#include <string.h>
#include "display.h"
#include "bus.h"
#define DISPLAY_ADDRESS 0xAF
#define DISPLAY_REG_INIT 0x10
#define DISPLAY_REG_UPDATE 0x20
bool display_init()
{
char init_config[] = { 0xDE, 0xFE, 0x00 };
bus_read_write( DISPLAY_ADDRESS, DISPLAY_REG_INIT, (uint8_t*)init_config, 3, false );
if (init_config[2] != 0x10)
return false;
return true;
}
void display_update( const char* info )
{
int len = strlen( info );
if ( bus_write( DISPLAY_ADDRESS, DISPLAY_REG_UPDATE, (const uint8_t*)info, len, true ) != true )
{
runtime_error("display update failed!");
}
}

View File

@@ -1,10 +0,0 @@
#include <assert.h>
#include "error.h"
char* runtime_error_nice_print( const char* msg )
{
char* buffer = malloc(512);
snprintf(buffer, 512, "Got error: %s", msg );
buffer[511] = 0;
return buffer;
}

View File

@@ -1,27 +0,0 @@
#include <stdlib.h>
#include <stdio.h>
#include "display.h"
#include "sensor.h"
void give_error( const char* msg )
{
char* buffer = runtime_error_nice_print( msg );
runtime_error( buffer );
free(buffer);
}
int update_main( void )
{
if ( !sensor_init() )
runtime_error("sensor init failed");
if ( !display_init() )
runtime_error("display init failed");
char buffer[32];
float reading = sensor_read();
snprintf( buffer, 32, "Sensor: %0.1f", reading );
display_update( buffer );
return 0;
}

View File

@@ -1,29 +0,0 @@
#include <string.h>
#include "sensor.h"
#include "bus.h"
#define SENSOR_ADDRESS 0xAA
#define SENSOR_REG_READ 0xF0
float LOCAL_buffer[4];
bool sensor_init()
{
memset( LOCAL_buffer, 0x00, sizeof(LOCAL_buffer));
return true;
}
float sensor_read()
{
char data[4] = { 0xFF, 0xFF, 0x00, 0x00 };
bus_read_write( SENSOR_ADDRESS, SENSOR_REG_READ, (uint8_t*)&data, 4, false );
if (data[0] != 0x10)
{
runtime_error("sensor read failed");
}
float ret_value = data[1] + data[2] / 256.0;
return ret_value;
}

View File

@@ -1,10 +0,0 @@
#ifndef _AUTOFAKE_BUS_H
#define _AUTOFAKE_BUS_H
#include "fff.h"
#include "bus.h"
DECLARE_FAKE_VALUE_FUNC( bool, bus_read_write, uint8_t, uint8_t, uint8_t*, int, bool );
DECLARE_FAKE_VALUE_FUNC( bool, bus_write, uint8_t, uint8_t, const uint8_t*, int, bool );
#endif // _AUTOFAKE_BUS_H

View File

@@ -1,10 +0,0 @@
#ifndef _AUTOFAKE_DISPLAY_H
#define _AUTOFAKE_DISPLAY_H
#include "fff.h"
#include "display.h"
DECLARE_FAKE_VALUE_FUNC( bool, display_init );
DECLARE_FAKE_VOID_FUNC( display_update, const char* );
#endif // _AUTOFAKE_DISPLAY_H

View File

@@ -1,10 +0,0 @@
#ifndef _AUTOFAKE_ERROR_H
#define _AUTOFAKE_ERROR_H
#include "fff.h"
#include "error.h"
DECLARE_FAKE_VOID_FUNC( runtime_error, const char* );
DECLARE_FAKE_VALUE_FUNC( char*, runtime_error_nice_print, const char* );
#endif // _AUTOFAKE_ERROR_H

View File

@@ -1,13 +0,0 @@
#ifndef _AUTOMOCK_SENSOR_H
#define _AUTOMOCK_SENSOR_H
#include "fff.h"
#include "sensor.h"
DECLARE_FAKE_VALUE_FUNC( bool, sensor_init );
DECLARE_FAKE_VALUE_FUNC( float, sensor_read );
void TEST_sensor_generate_data( char* buffer, float value );
#endif // _AUTOMOCK_SENSOR_H

View File

@@ -1,13 +0,0 @@
#pragma once
#include <assert.h>
#include <stdio.h>
#include "fff.h"
#include "bus.fake.h"
#include "error.fake.h"
void init_tests();
extern char GLOBAL_TEST_bus_read_ret[32];

View File

@@ -1,4 +0,0 @@
#include "bus.fake.h"
DEFINE_FAKE_VALUE_FUNC( bool, bus_read_write, uint8_t, uint8_t, uint8_t*, int, bool );
DEFINE_FAKE_VALUE_FUNC( bool, bus_write, uint8_t, uint8_t, const uint8_t*, int, bool );

View File

@@ -1,4 +0,0 @@
#include "display.fake.h"
DEFINE_FAKE_VALUE_FUNC( bool, display_init );
DEFINE_FAKE_VOID_FUNC( display_update, const char* );

View File

@@ -1,24 +0,0 @@
#include "test_common.h"
#include "display.h"
DEFINE_FFF_GLOBALS;
int main(void)
{
init_tests(); // Resets common and hook errors to asserts.
GLOBAL_TEST_bus_read_ret[2] = 0x10;
assert( display_init() == true );
assert( bus_read_write_fake.call_count == 1);
display_update( "TEST INFO" );
assert( bus_read_write_fake.call_count == 1 );
assert( bus_write_fake.call_count == 1 );
GLOBAL_TEST_bus_read_ret[2] = 0x00;
assert( display_init() == false );
printf("Test " __FILE__ " ok\n");
return 0;
}

View File

@@ -1,4 +0,0 @@
#include "error.fake.h"
DEFINE_FAKE_VOID_FUNC( runtime_error, const char* );
DEFINE_FAKE_VALUE_FUNC( char*, runtime_error_nice_print, const char* );

View File

@@ -1,26 +0,0 @@
#include "display.fake.h"
#include "sensor.fake.h"
#include "test_common.h"
DEFINE_FFF_GLOBALS;
int update_main( void );
int main(void)
{
init_tests(); // Resets common and hook errors to asserts.
sensor_init_fake.return_val = true;
display_init_fake.return_val = true;
update_main();
assert( sensor_init_fake.call_count == 1 );
assert( display_init_fake.call_count == 1 );
assert( display_update_fake.call_count == 1 );
printf("Test " __FILE__ " ok\n");
return 0;
}

View File

@@ -1,11 +0,0 @@
#include "sensor.fake.h"
DEFINE_FAKE_VALUE_FUNC( bool, sensor_init );
DEFINE_FAKE_VALUE_FUNC( float, sensor_read );
void TEST_sensor_generate_data( char* buffer, float value )
{
buffer[0] = 0x10;
buffer[1] = (int)(value);
buffer[2] = (value - buffer[1])*255;
}

View File

@@ -1,23 +0,0 @@
#include <stdio.h>
#include "test_common.h"
#include "sensor.h"
#include "sensor.fake.h"
DEFINE_FFF_GLOBALS;
int main(void)
{
init_tests();
assert( sensor_init() == true );
TEST_sensor_generate_data( GLOBAL_TEST_bus_read_ret, 1.5f );
float value = sensor_read();
float value_error = value - 1.5f;
assert( value_error < 0.1f && value_error > -0.1f );
printf("Test " __FILE__ " ok\n");
return 0;
}

View File

@@ -1,33 +0,0 @@
#include "test_common.h"
#include <assert.h>
#include <stdio.h>
char GLOBAL_TEST_bus_read_ret[32];
void spoof_runtime_error( const char* info )
{
fprintf(stderr, "Runtime error: %s\n", info );
assert(0);
}
bool spoof_bus_read_write( uint8_t dev, uint8_t registry, uint8_t* buffer, int len, bool assume_echo )
{
memcpy( buffer, GLOBAL_TEST_bus_read_ret, len );
fprintf(stderr, "bus spoof %d %d\n", (int)dev, (int)registry );
return true;
}
void init_tests()
{
memset( GLOBAL_TEST_bus_read_ret, 0x00, sizeof(GLOBAL_TEST_bus_read_ret));
FFF_RESET_HISTORY();
RESET_FAKE(bus_read_write);
RESET_FAKE(bus_write);
RESET_FAKE(runtime_error);
runtime_error_fake.custom_fake = spoof_runtime_error;
bus_read_write_fake.custom_fake = spoof_bus_read_write;
bus_write_fake.return_val = true;
}

View File

@@ -8,10 +8,6 @@ $MAX_ARGS = 20
$DEFAULT_ARG_HISTORY = 50 $DEFAULT_ARG_HISTORY = 50
$MAX_CALL_HISTORY = 50 $MAX_CALL_HISTORY = 50
def license
File.foreach("#{__dir__}/LICENSE") { |line| putd line }
end
def include_dependencies def include_dependencies
putd "#include <stdarg.h>" putd "#include <stdarg.h>"
putd "#include <string.h> /* For memset and memcpy */" putd "#include <string.h> /* For memset and memcpy */"
@@ -30,26 +26,9 @@ def output_constants
putd "#define FFF_CALL_HISTORY_LEN (#{$MAX_CALL_HISTORY}u)" putd "#define FFF_CALL_HISTORY_LEN (#{$MAX_CALL_HISTORY}u)"
} }
putd "#endif" putd "#endif"
putd "#ifndef FFF_GCC_FUNCTION_ATTRIBUTES"
indent {
putd "#define FFF_GCC_FUNCTION_ATTRIBUTES"
}
putd "#endif"
end end
def output_default_function_pointer_macro(has_calling_conventions)
name = has_calling_conventions ? "(CALLING_CONVENTION *FUNCNAME)" : "(*FUNCNAME)"
calling_conv = has_calling_conventions ? ", CALLING_CONVENTION" : ""
putd "#ifndef CUSTOM_FFF_FUNCTION_TEMPLATE"
putd_backslash "#define CUSTOM_FFF_FUNCTION_TEMPLATE(RETURN#{calling_conv}, FUNCNAME, ...)"
indent {
putd "RETURN#{name}(__VA_ARGS__)"
}
putd "#endif /* CUSTOM_FFF_FUNCTION_TEMPLATE */"
end
@@ -246,9 +225,7 @@ def define_reset_fake_helper
indent { indent {
putd_backslash "void FUNCNAME##_reset(void){" putd_backslash "void FUNCNAME##_reset(void){"
indent { indent {
putd_backslash "memset((void*)&FUNCNAME##_fake, 0, sizeof(FUNCNAME##_fake) - sizeof(FUNCNAME##_fake.custom_fake) - sizeof(FUNCNAME##_fake.custom_fake_seq));" putd_backslash "memset(&FUNCNAME##_fake, 0, sizeof(FUNCNAME##_fake));"
putd_backslash "FUNCNAME##_fake.custom_fake = NULL;"
putd_backslash "FUNCNAME##_fake.custom_fake_seq = NULL;"
putd_backslash "FUNCNAME##_fake.arg_history_len = FFF_ARG_HISTORY_LEN;" putd_backslash "FUNCNAME##_fake.arg_history_len = FFF_ARG_HISTORY_LEN;"
} }
putd "}" putd "}"
@@ -282,7 +259,7 @@ def indent
popd popd
end end
def output_macro(arg_count, has_varargs, has_calling_conventions, is_value_function) def output_macro(arg_count, has_varargs, is_value_function)
vararg_name = has_varargs ? "_VARARG" : "" 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}" fake_macro_name = is_value_function ? "FAKE_VALUE_FUNC#{arg_count}#{vararg_name}" : "FAKE_VOID_FUNC#{arg_count}#{vararg_name}"
@@ -292,50 +269,53 @@ def output_macro(arg_count, has_varargs, has_calling_conventions, is_value_funct
return_type = is_value_function ? "RETURN_TYPE" : "" return_type = is_value_function ? "RETURN_TYPE" : ""
puts puts
output_macro_header(declare_macro_name, saved_arg_count, has_varargs, has_calling_conventions, return_type) output_macro_header(declare_macro_name, saved_arg_count, has_varargs, return_type)
indent { indent {
output_variables(saved_arg_count, has_varargs, has_calling_conventions, is_value_function) extern_c { # define argument capture variables
} output_variables(saved_arg_count, has_varargs, is_value_function)
}
puts }
output_macro_header(define_macro_name, saved_arg_count, has_varargs, has_calling_conventions, return_type)
indent { puts
putd_backslash "FUNCNAME##_Fake FUNCNAME##_fake;" output_macro_header(define_macro_name, saved_arg_count, has_varargs, return_type)
putd_backslash function_signature(saved_arg_count, has_varargs, has_calling_conventions, is_value_function) + "{" indent {
indent { extern_c {
output_function_body(saved_arg_count, has_varargs, is_value_function) putd_backslash "FUNCNAME##_Fake FUNCNAME##_fake;"
putd_backslash function_signature(saved_arg_count, has_varargs, is_value_function) + "{"
indent {
output_function_body(saved_arg_count, has_varargs, is_value_function)
}
putd_backslash "}"
putd_backslash "DEFINE_RESET_FUNCTION(FUNCNAME)"
} }
putd_backslash "}"
putd_backslash "DEFINE_RESET_FUNCTION(FUNCNAME)"
} }
puts puts
output_macro_header(fake_macro_name, saved_arg_count, has_varargs, has_calling_conventions, return_type) output_macro_header(fake_macro_name, saved_arg_count, has_varargs, return_type)
indent { indent {
putd macro_signature_for(declare_macro_name, saved_arg_count, has_varargs, has_calling_conventions, return_type) putd macro_signature_for(declare_macro_name, saved_arg_count, has_varargs, return_type)
putd macro_signature_for(define_macro_name, saved_arg_count, has_varargs, has_calling_conventions, return_type) putd macro_signature_for(define_macro_name, saved_arg_count, has_varargs, return_type)
puts puts
} }
end end
def output_macro_header(macro_name, arg_count, has_varargs, has_calling_conventions, return_type) def output_macro_header(macro_name, arg_count, has_varargs, return_type)
output_macro_name(macro_name, arg_count, has_varargs, has_calling_conventions, return_type) output_macro_name(macro_name, arg_count, has_varargs, return_type)
end end
# #define #macro_name(RETURN_TYPE, FUNCNAME, ARG0,...) # #define #macro_name(RETURN_TYPE, FUNCNAME, ARG0,...)
def output_macro_name(macro_name, arg_count, has_varargs, has_calling_conventions, return_type) def output_macro_name(macro_name, arg_count, has_varargs, return_type)
putd "#define " + macro_signature_for(macro_name, arg_count, has_varargs, has_calling_conventions, return_type) putd "#define " + macro_signature_for(macro_name, arg_count, has_varargs, return_type)
end end
# #macro_name(RETURN_TYPE, FUNCNAME, ARG0,...) \ # #macro_name(RETURN_TYPE, FUNCNAME, ARG0,...) \
def macro_signature_for(macro_name, arg_count, has_varargs, has_calling_conventions, return_type) def macro_signature_for(macro_name, arg_count, has_varargs, return_type)
parameter_list = "#{macro_name}(" parameter_list = "#{macro_name}("
if return_type != "" if return_type != ""
parameter_list += return_type parameter_list += return_type
parameter_list += ", " parameter_list += ", "
end end
parameter_list += "CALLING_CONVENTION, " if (has_calling_conventions)
parameter_list += "FUNCNAME" parameter_list += "FUNCNAME"
arg_count.times { |i| parameter_list += ", ARG#{i}_TYPE" } arg_count.times { |i| parameter_list += ", ARG#{i}_TYPE" }
@@ -347,7 +327,7 @@ def macro_signature_for(macro_name, arg_count, has_varargs, has_calling_conventi
parameter_list parameter_list
end end
def output_variables(arg_count, has_varargs, has_calling_conventions, is_value_function) def output_variables(arg_count, has_varargs, is_value_function)
in_struct{ in_struct{
arg_count.times { |argN| arg_count.times { |argN|
putd_backslash "DECLARE_ARG(ARG#{argN}_TYPE, #{argN}, FUNCNAME)" putd_backslash "DECLARE_ARG(ARG#{argN}_TYPE, #{argN}, FUNCNAME)"
@@ -356,12 +336,12 @@ def output_variables(arg_count, has_varargs, has_calling_conventions, is_value_f
putd_backslash "DECLARE_VALUE_FUNCTION_VARIABLES(RETURN_TYPE)" unless not is_value_function putd_backslash "DECLARE_VALUE_FUNCTION_VARIABLES(RETURN_TYPE)" unless not is_value_function
putd_backslash "DECLARE_RETURN_VALUE_HISTORY(RETURN_TYPE)" unless not is_value_function putd_backslash "DECLARE_RETURN_VALUE_HISTORY(RETURN_TYPE)" unless not is_value_function
putd_backslash "DECLARE_CUSTOM_FAKE_SEQ_VARIABLES" putd_backslash "DECLARE_CUSTOM_FAKE_SEQ_VARIABLES"
output_custom_function_signature(arg_count, has_varargs, has_calling_conventions, is_value_function) output_custom_function_signature(arg_count, has_varargs, is_value_function)
output_custom_function_array(arg_count, has_varargs, has_calling_conventions, is_value_function) output_custom_function_array(arg_count, has_varargs, is_value_function)
} }
putd_backslash "extern FUNCNAME##_Fake FUNCNAME##_fake;" putd_backslash "extern FUNCNAME##_Fake FUNCNAME##_fake;"
putd_backslash "void FUNCNAME##_reset(void);" 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, is_value_function) + ";"
end end
#example: ARG0_TYPE arg0, ARG1_TYPE arg1 #example: ARG0_TYPE arg0, ARG1_TYPE arg1
@@ -372,14 +352,6 @@ def arg_val_list(args_count)
arguments.join(", ") arguments.join(", ")
end end
#example: ARG0_TYPE, ARG1_TYPE
def arg_type_list(args_count)
return "void" if (args_count == 0)
arguments = []
args_count.times { |i| arguments << "ARG#{i}_TYPE" }
arguments.join(", ")
end
#example: arg0, arg1 #example: arg0, arg1
def arg_list(args_count) def arg_list(args_count)
arguments = [] arguments = []
@@ -388,33 +360,26 @@ def arg_list(args_count)
end end
# RETURN_TYPE (*custom_fake)(ARG0_TYPE arg0);\ # RETURN_TYPE (*custom_fake)(ARG0_TYPE arg0);\
# OR
# RETURN_TYPE (CALLING_CONVENTION *custom_fake)(ARG0_TYPE arg0);\
#
# void (*custom_fake)(ARG0_TYPE arg0, ARG1_TYPE arg1, ARG2_TYPE arg2);\ # void (*custom_fake)(ARG0_TYPE arg0, ARG1_TYPE arg1, ARG2_TYPE arg2);\
def output_custom_function_signature(arg_count, has_varargs, has_calling_conventions, is_value_function) def output_custom_function_signature(arg_count, has_varargs, is_value_function)
return_type = is_value_function ? "RETURN_TYPE" : "void" return_type = is_value_function ? "RETURN_TYPE" : "void"
ap_list = has_varargs ? ", va_list ap" : "" ap_list = has_varargs ? ", va_list ap" : ""
calling_conv = has_calling_conventions ? ", CALLING_CONVENTION" : "" signature = "(*custom_fake)(#{arg_val_list(arg_count)}#{ap_list});"
putd_backslash "CUSTOM_FFF_FUNCTION_TEMPLATE(#{return_type}#{calling_conv}, custom_fake, #{arg_type_list(arg_count)}#{ap_list});" putd_backslash return_type + signature
end end
def output_custom_function_array(arg_count, has_varargs, has_calling_conventions, is_value_function) def output_custom_function_array(arg_count, has_varargs, is_value_function)
return_type = is_value_function ? "RETURN_TYPE" : "void" return_type = is_value_function ? "RETURN_TYPE" : "void"
ap_list = has_varargs ? ", va_list ap" : "" ap_list = has_varargs ? ", va_list ap" : ""
calling_conv = has_calling_conventions ? ", CALLING_CONVENTION" : "" custom_array = "(**custom_fake_seq)(#{arg_val_list(arg_count)}#{ap_list});"
putd_backslash "CUSTOM_FFF_FUNCTION_TEMPLATE(#{return_type}#{calling_conv}, *custom_fake_seq, #{arg_type_list(arg_count)}#{ap_list});" putd_backslash return_type + custom_array
end end
# example: RETURN_TYPE FUNCNAME(ARG0_TYPE arg0, ARG1_TYPE arg1) # example: RETURN_TYPE FUNCNAME(ARG0_TYPE arg0, ARG1_TYPE arg1)
# OR def function_signature(arg_count, has_varargs, is_value_function)
# RETURN_TYPE CALLING_CONVENTION FUNCNAME(ARG0_TYPE arg0, ARG1_TYPE arg1)
def function_signature(arg_count, has_varargs, has_calling_conventions, is_value_function)
return_type = is_value_function ? "RETURN_TYPE" : "void" return_type = is_value_function ? "RETURN_TYPE" : "void"
varargs = has_varargs ? ", ..." : "" varargs = has_varargs ? ", ..." : ""
calling_conventions = has_calling_conventions ? "#{return_type} FUNCNAME(#{arg_val_list(arg_count)}#{varargs})"
"#{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})"
end end
def output_function_body(arg_count, has_varargs, is_value_function) def output_function_body(arg_count, has_varargs, is_value_function)
@@ -433,35 +398,6 @@ def output_function_body(arg_count, has_varargs, is_value_function)
putd_backslash "REGISTER_CALL(FUNCNAME);" putd_backslash "REGISTER_CALL(FUNCNAME);"
if has_varargs if has_varargs
return_type = is_value_function ? "return " : ""
putd_backslash "if (FUNCNAME##_fake.custom_fake_seq_len){ /* a sequence of custom fakes */"
indent {
putd_backslash "if (FUNCNAME##_fake.custom_fake_seq_idx < FUNCNAME##_fake.custom_fake_seq_len){"
indent {
putd_backslash "va_list ap;"
putd_backslash "va_start(ap, arg#{arg_count-1});"
putd_backslash "RETURN_TYPE ret = FUNCNAME##_fake.custom_fake_seq[FUNCNAME##_fake.custom_fake_seq_idx++](#{arg_list(arg_count)}, ap);" unless not is_value_function
putd_backslash "SAVE_RET_HISTORY(FUNCNAME, ret);" unless not is_value_function
putd_backslash "va_end(ap);" unless not is_value_function
putd_backslash "return ret;" unless not is_value_function
putd_backslash "#{return_type}FUNCNAME##_fake.custom_fake_seq[FUNCNAME##_fake.custom_fake_seq_idx++](#{arg_list(arg_count)}, ap);" unless is_value_function
putd_backslash "va_end(ap);" unless is_value_function
}
putd_backslash "}"
putd_backslash "else{"
indent {
putd_backslash "va_list ap;"
putd_backslash "va_start(ap, arg#{arg_count-1});"
putd_backslash "RETURN_TYPE ret = FUNCNAME##_fake.custom_fake_seq[FUNCNAME##_fake.custom_fake_seq_len-1](#{arg_list(arg_count)}, ap);" unless not is_value_function
putd_backslash "SAVE_RET_HISTORY(FUNCNAME, ret);" unless not is_value_function
putd_backslash "va_end(ap);" unless not is_value_function
putd_backslash "return ret;" unless not is_value_function
putd_backslash "#{return_type}FUNCNAME##_fake.custom_fake_seq[FUNCNAME##_fake.custom_fake_seq_len-1](#{arg_list(arg_count)}, ap);" unless is_value_function
putd_backslash "va_end(ap);" unless is_value_function
}
putd_backslash "}"
}
putd_backslash "}"
putd_backslash "if(FUNCNAME##_fake.custom_fake){" putd_backslash "if(FUNCNAME##_fake.custom_fake){"
indent { indent {
putd_backslash "RETURN_TYPE ret;" if is_value_function putd_backslash "RETURN_TYPE ret;" if is_value_function
@@ -497,19 +433,12 @@ def output_function_body(arg_count, has_varargs, is_value_function)
putd_backslash "RETURN_TYPE ret = FUNCNAME##_fake.custom_fake_seq[FUNCNAME##_fake.custom_fake_seq_len-1](#{arg_list(arg_count)});" unless not is_value_function putd_backslash "RETURN_TYPE ret = FUNCNAME##_fake.custom_fake_seq[FUNCNAME##_fake.custom_fake_seq_len-1](#{arg_list(arg_count)});" unless not is_value_function
putd_backslash "SAVE_RET_HISTORY(FUNCNAME, ret);" unless not is_value_function putd_backslash "SAVE_RET_HISTORY(FUNCNAME, ret);" unless not is_value_function
putd_backslash "return ret;" unless not is_value_function putd_backslash "return ret;" unless not is_value_function
putd_backslash "#{return_type}FUNCNAME##_fake.custom_fake_seq[FUNCNAME##_fake.custom_fake_seq_len-1](#{arg_list(arg_count)});" unless is_value_function putd_backslash "#{return_type}FUNCNAME##_fake.custom_fake_seq[FUNCNAME##_fake.custom_fake_seq_len-1](#{arg_list(arg_count)});"
} }
putd_backslash "}" putd_backslash "}"
} }
putd_backslash "}" putd_backslash "}"
putd_backslash "if (FUNCNAME##_fake.custom_fake != NULL){ " putd_backslash "if (FUNCNAME##_fake.custom_fake) #{return_type}FUNCNAME##_fake.custom_fake(#{arg_list(arg_count)});"
indent {
putd_backslash "RETURN_TYPE ret = FUNCNAME##_fake.custom_fake(#{arg_list(arg_count)});" unless not is_value_function
putd_backslash "SAVE_RET_HISTORY(FUNCNAME, ret);" unless not is_value_function
putd_backslash "return ret;" unless not is_value_function
putd_backslash "#{return_type}FUNCNAME##_fake.custom_fake(#{arg_list(arg_count)});" unless is_value_function
}
putd_backslash "}"
end end
putd_backslash "RETURN_FAKE_RESULT(FUNCNAME)" if is_value_function putd_backslash "RETURN_FAKE_RESULT(FUNCNAME)" if is_value_function
@@ -524,9 +453,9 @@ def define_fff_globals
} }
putd "} fff_globals_t;" putd "} fff_globals_t;"
puts puts
putd "FFF_EXTERN_C" putd_backslash "FFF_EXTERN_C"
putd "extern fff_globals_t fff;" putd "extern fff_globals_t fff;"
putd "FFF_END_EXTERN_C" putd_backslash "FFF_END_EXTERN_C"
puts puts
putd_backslash "#define DEFINE_FFF_GLOBALS" putd_backslash "#define DEFINE_FFF_GLOBALS"
indent { indent {
@@ -537,21 +466,25 @@ def define_fff_globals
putd "FFF_END_EXTERN_C" putd "FFF_END_EXTERN_C"
} }
puts puts
putd_backslash "#define FFF_RESET_HISTORY()" putd "#define FFF_RESET_HISTORY() fff.call_history_idx = 0;"
indent {
putd_backslash "fff.call_history_idx = 0;"
putd "memset(fff.call_history, 0, sizeof(fff.call_history));"
}
puts puts
putd_backslash "#define REGISTER_CALL(function)" putd_backslash "#define REGISTER_CALL(function)"
indent { indent {
putd_backslash "if(fff.call_history_idx < FFF_CALL_HISTORY_LEN)" putd_backslash "if(fff.call_history_idx < FFF_CALL_HISTORY_LEN)"
indent { indent {
putd "fff.call_history[fff.call_history_idx++] = (fff_function_t)function;" putd "fff.call_history[fff.call_history_idx++] = (fff_function_t)function;"
} }
} }
end end
def extern_c
putd_backslash "FFF_EXTERN_C"
indent {
yield
}
putd_backslash "FFF_END_EXTERN_C"
end
def in_struct def in_struct
putd_backslash "typedef struct FUNCNAME##_Fake {" putd_backslash "typedef struct FUNCNAME##_Fake {"
indent { indent {
@@ -572,22 +505,18 @@ def include_guard
end end
def msvc_expand_macro_fix def msvc_expand_macro_fix
putd "/* MSVC expand macro fix */" putd "/* MSVC expand macro fix */"
putd "#define EXPAND(x) x" putd "#define EXPAND(x) x"
end end
def generate_arg_sequence(args, prefix, do_reverse, joinstr) def generate_arg_sequence(args, prefix, do_reverse, joinstr)
fmap = (0..args).flat_map {|i| [prefix + i.to_s]} fmap = (0..args).flat_map {|i| [prefix + i.to_s]}
if do_reverse then fmap.reverse.join(joinstr) else fmap.join(", ") end if do_reverse then fmap.reverse.join(joinstr) else fmap.join(", ") end
end end
def counting_macro_instance(type, has_calling_conventions, vararg = :non_vararg, prefix = "") def counting_macro_instance(type, vararg = :non_vararg, prefix = "")
appendix = (vararg == :vararg) ? "_VARARG" : "" appendix = (vararg == :vararg) ? "_VARARG" : ""
if has_calling_conventions minus_count = (type == :VOID) ? 1 : 2
minus_count = (type == :VOID) ? 2 : 3
else
minus_count = (type == :VOID) ? 1 : 2
end
<<-MACRO_COUNTING_INSTANCE <<-MACRO_COUNTING_INSTANCE
#define #{prefix}FAKE_#{type.to_s}_FUNC#{appendix}(...) \ #define #{prefix}FAKE_#{type.to_s}_FUNC#{appendix}(...) \
@@ -602,97 +531,78 @@ def counting_macro_instance(type, has_calling_conventions, vararg = :non_vararg,
MACRO_COUNTING_INSTANCE MACRO_COUNTING_INSTANCE
end end
def output_macro_counting_shortcuts(has_calling_conventions) def output_macro_counting_shortcuts
has_calling_conventions ?
(arg_depth = ["3", "2"]; calling_conv = "callingConv, ") :
(arg_depth = ["2", "1"]; calling_conv = "")
msvc_expand_macro_fix msvc_expand_macro_fix
putd <<-MACRO_COUNTING putd <<-MACRO_COUNTING
#define PP_NARG_MINUS#{arg_depth[0]}(...) \ #define PP_NARG_MINUS2(...) \
EXPAND(PP_NARG_MINUS#{arg_depth[0]}_(__VA_ARGS__, PP_RSEQ_N_MINUS#{arg_depth[0]}())) EXPAND(PP_NARG_MINUS2_(__VA_ARGS__, PP_RSEQ_N_MINUS2()))
#define PP_NARG_MINUS#{arg_depth[0]}_(...) \ #define PP_NARG_MINUS2_(...) \
EXPAND(PP_ARG_MINUS#{arg_depth[0]}_N(__VA_ARGS__)) EXPAND(PP_ARG_MINUS2_N(__VA_ARGS__))
#define PP_ARG_MINUS#{arg_depth[0]}_N(returnVal, #{calling_conv} #{generate_arg_sequence($MAX_ARGS, '_', false, ", ")}, N, ...) N #define PP_ARG_MINUS2_N(returnVal, #{generate_arg_sequence($MAX_ARGS, '_', false, ", ")}, N, ...) N
#define PP_RSEQ_N_MINUS#{arg_depth[0]}() \ #define PP_RSEQ_N_MINUS2() \
#{generate_arg_sequence($MAX_ARGS, '', true, ',')} #{generate_arg_sequence($MAX_ARGS, '', true, ',')}
#define PP_NARG_MINUS#{arg_depth[1]}(...) \
EXPAND(PP_NARG_MINUS#{arg_depth[1]}_(__VA_ARGS__, PP_RSEQ_N_MINUS#{arg_depth[1]}()))
#define PP_NARG_MINUS#{arg_depth[1]}_(...) \ #define PP_NARG_MINUS1(...) \
EXPAND(PP_ARG_MINUS#{arg_depth[1]}_N(__VA_ARGS__)) EXPAND(PP_NARG_MINUS1_(__VA_ARGS__, PP_RSEQ_N_MINUS1()))
#define PP_ARG_MINUS#{arg_depth[1]}_N(#{calling_conv} #{generate_arg_sequence($MAX_ARGS, '_', false, ", ")}, N, ...) N #define PP_NARG_MINUS1_(...) \
EXPAND(PP_ARG_MINUS1_N(__VA_ARGS__))
#define PP_RSEQ_N_MINUS#{arg_depth[1]}() \ #define PP_ARG_MINUS1_N(#{generate_arg_sequence($MAX_ARGS, '_', false, ", ")}, N, ...) N
#{generate_arg_sequence($MAX_ARGS, '', true, ',')}
#define PP_RSEQ_N_MINUS1() \
#{generate_arg_sequence($MAX_ARGS, '', true, ',')}
/* DECLARE AND DEFINE FAKE FUNCTIONS - PLACE IN TEST FILES */ /* DECLARE AND DEFINE FAKE FUNCTIONS - PLACE IN TEST FILES */
#{counting_macro_instance(:VALUE, has_calling_conventions)} #{counting_macro_instance(:VALUE)}
#{counting_macro_instance(:VOID, has_calling_conventions)} #{counting_macro_instance(:VOID)}
#{counting_macro_instance(:VALUE, has_calling_conventions, :vararg)} #{counting_macro_instance(:VALUE, :vararg)}
#{counting_macro_instance(:VOID, has_calling_conventions, :vararg)} #{counting_macro_instance(:VOID, :vararg)}
/* DECLARE FAKE FUNCTIONS - PLACE IN HEADER FILES */ /* DECLARE FAKE FUNCTIONS - PLACE IN HEADER FILES */
#{counting_macro_instance(:VALUE, has_calling_conventions, :non_vararg, "DECLARE_")} #{counting_macro_instance(:VALUE, :non_vararg, "DECLARE_")}
#{counting_macro_instance(:VOID, has_calling_conventions, :non_vararg, "DECLARE_")} #{counting_macro_instance(:VOID, :non_vararg, "DECLARE_")}
#{counting_macro_instance(:VALUE, has_calling_conventions, :vararg, "DECLARE_")} #{counting_macro_instance(:VALUE, :vararg, "DECLARE_")}
#{counting_macro_instance(:VOID, has_calling_conventions, :vararg, "DECLARE_")} #{counting_macro_instance(:VOID, :vararg, "DECLARE_")}
/* DEFINE FAKE FUNCTIONS - PLACE IN SOURCE FILES */ /* DEFINE FAKE FUNCTIONS - PLACE IN SOURCE FILES */
#{counting_macro_instance(:VALUE, has_calling_conventions, :non_vararg, "DEFINE_")} #{counting_macro_instance(:VALUE, :non_vararg, "DEFINE_")}
#{counting_macro_instance(:VOID, has_calling_conventions, :non_vararg, "DEFINE_")} #{counting_macro_instance(:VOID, :non_vararg, "DEFINE_")}
#{counting_macro_instance(:VALUE, has_calling_conventions, :vararg, "DEFINE_")} #{counting_macro_instance(:VALUE, :vararg, "DEFINE_")}
#{counting_macro_instance(:VOID, has_calling_conventions, :vararg, "DEFINE_")} #{counting_macro_instance(:VOID, :vararg, "DEFINE_")}
MACRO_COUNTING MACRO_COUNTING
end end
def output_c_and_cpp(has_calling_conventions) def output_c_and_cpp
license
include_guard { include_guard {
include_dependencies include_dependencies
output_constants output_constants
output_default_function_pointer_macro(has_calling_conventions)
output_internal_helper_macros output_internal_helper_macros
yield yield
output_macro_counting_shortcuts(has_calling_conventions) output_macro_counting_shortcuts
} }
end end
def help # lets generate!!
# Check if we should generate _with_ support for specifying calling conventions output_c_and_cpp{
if (ARGV[0] == "--help" or ARGV[0] == "-h") define_fff_globals
puts "Usage: fakegen.rb [options] # Create fake generators for 0..MAX_ARGS
-h, --help Show this help message num_fake_generators = $MAX_ARGS + 1
-wcc, --with-calling-conventions Support specifying calling conventions" num_fake_generators.times {|arg_count| output_macro(arg_count, false, false)}
exit num_fake_generators.times {|arg_count| output_macro(arg_count, false, true)}
end # generate the varargs variants
yield (2..$MAX_ARGS).each {|arg_count| output_macro(arg_count, true, false)}
end (2..$MAX_ARGS).each {|arg_count| output_macro(arg_count, true, true)}
help {
# Determine if we should generate with support for calling conventions
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)}
# 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)}
}
} }

9944
fff.h

File diff suppressed because it is too large Load Diff

22
gtest/Makefile Normal file
View File

@@ -0,0 +1,22 @@
BUILD_DIR = ../build
LIBS := -lpthread
CPP_OBJS=$(BUILD_DIR)/gtest-all.o $(BUILD_DIR)/gtest-main.o
SOURCES=gtest-all.cc gtest-main.cc
# Each subdirectory must supply rules for building sources it contributes
$(BUILD_DIR)/%.o: %.cc
@echo 'Building file: $<'
@echo 'Invoking: GCC C++ Compiler'
g++ -I../ -O0 -g3 -Wall -DGTEST_USE_OWN_TR1_TUPLE=1 -c -o "$@" "$<"
@echo 'Finished building: $<'
@echo ' '
all: $(CPP_OBJS)
clean:
-$(RM) $(CPP_OBJS)
-@echo ' '

9118
gtest/gtest-all.cc Normal file

File diff suppressed because it is too large Load Diff

6
gtest/gtest-main.cc Normal file
View File

@@ -0,0 +1,6 @@
#include "gtest.h"
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

19537
gtest/gtest.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,87 +0,0 @@
# Copyright 2022 Google LLC
# SPDX-License-Identifier: Apache-2.0
# Create a list of common files needed for tests
set(
COMMON_FILE_LIST
include/c_test_framework.h
src/test_cases.include
)
include(FetchContent)
FetchContent_Declare(
googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG v1.12.0
)
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)
# Create the C test executable
add_executable(c_test src/fff_test_c.c ${COMMON_FILE_LIST})
target_include_directories(c_test PRIVATE include)
target_link_libraries(c_test PRIVATE fff)
# Create the C++ test executable
add_executable(cpp_test src/fff_test_cpp.cpp ${COMMON_FILE_LIST})
target_include_directories(cpp_test PRIVATE include)
target_link_libraries(cpp_test PRIVATE GTest::gtest_main fff)
# Create the C global test executable
add_executable(c_global_test
src/fff_test_global_c.c
src/global_fakes.c
include/global_fakes.h
${COMMON_FILE_LIST}
)
target_include_directories(c_global_test PRIVATE include)
target_link_libraries(c_global_test PRIVATE fff)
# Create the C++ global test executable
add_executable(cpp_global_test
src/fff_test_global_cpp.cpp
src/global_fakes.c
include/global_fakes.h
${COMMON_FILE_LIST}
)
target_include_directories(cpp_global_test PRIVATE include)
target_link_libraries(cpp_global_test PRIVATE GTest::gtest_main fff)
# Create the C++ custom function signature executable
add_executable(cpp_custom_fn_signature_test
src/fff_test_custom_function_template.cpp
${COMMON_FILE_LIST}
)
target_include_directories(cpp_custom_fn_signature_test PRIVATE include)
target_link_libraries(cpp_custom_fn_signature_test PRIVATE GTest::gtest_main fff)
# Due to a bug in WinLibs for Windows it's not currently possible to use:
# target_precompile_headers(cpp_custom_fn_signature_test PUBLIC include/custom_function.hpp)
# See more info at target_precompile_headers(cpp_custom_fn_signature_test PUBLIC include/custom_function.hpp)
add_test(
NAME cpp_custom_fn_signature_test
COMMAND $<TARGET_FILE:cpp_custom_fn_signature_test>
)
# Add the tests for ctest
add_test(
NAME c_test
COMMAND $<TARGET_FILE:c_test>
)
add_test(
NAME cpp_test
COMMAND $<TARGET_FILE:cpp_test>
)
add_test(
NAME c_global_test
COMMAND $<TARGET_FILE:c_global_test>
)
add_test(
NAME cpp_global_test
COMMAND $<TARGET_FILE:cpp_global_test>
)

81
test/Makefile Normal file
View File

@@ -0,0 +1,81 @@
BUILD_DIR = ../build
FFF_TEST_CPP_OBJS += \
$(BUILD_DIR)/fff_test_cpp.o \
$(BUILD_DIR)/gtest-all.o \
$(BUILD_DIR)/gtest-main.o
FFF_TEST_GLOBAL_CPP_OBJS += \
$(BUILD_DIR)/fff_test_global_cpp.o \
$(BUILD_DIR)/global_fakes.o \
$(BUILD_DIR)/gtest-all.o \
$(BUILD_DIR)/gtest-main.o
FFF_TEST_C_OBJS = $(BUILD_DIR)/fff_test_c.o
FFF_TEST_GLOBAL_C_OBJS += \
$(BUILD_DIR)/global_fakes.o \
$(BUILD_DIR)/fff_test_global_c.o
FFF_TEST_CPP_TARGET = $(BUILD_DIR)/fff_test_cpp
FFF_TEST_C_TARGET = $(BUILD_DIR)/fff_test_c
FFF_TEST_GLOBAL_C_TARGET = $(BUILD_DIR)/fff_test_glob_c
FFF_TEST_GLOBAL_CPP_TARGET = $(BUILD_DIR)/fff_test_glob_cpp
LIBS := -lpthread
# All Target
all: $(FFF_TEST_CPP_TARGET) $(FFF_TEST_C_TARGET) $(FFF_TEST_GLOBAL_C_TARGET) $(FFF_TEST_GLOBAL_CPP_TARGET)
# Each subdirectory must supply rules for building sources it contributes
$(BUILD_DIR)/%.o: %.cpp
@echo 'Building file: $<'
@echo 'Invoking: GCC C++ Compiler'
g++ -I../ -O0 -g3 -Wall -DGTEST_USE_OWN_TR1_TUPLE=1 -c -o "$@" "$<"
@echo 'Finished building: $<'
@echo ' '
$(BUILD_DIR)/%.o: %.c
@echo 'Building file: $<'
@echo 'Invoking: GCC C Compiler'
gcc -I../ -O0 -g3 -Wall -std=c99 -c -o "$@" "$<"
@echo 'Finished building: $<'
@echo ' '
# Link targets
$(FFF_TEST_CPP_TARGET): $(FFF_TEST_CPP_OBJS)
@echo 'Building target: $@'
@echo 'Invoking: GCC C++ Linker'
g++ -o "$(FFF_TEST_CPP_TARGET)" $(FFF_TEST_CPP_OBJS) $(LIBS)
@echo 'Finished building target: $@'
@echo ' '
$(FFF_TEST_C_TARGET): $(FFF_TEST_C_OBJS)
@echo 'Building target: $@'
@echo 'Invoking: GCC C Linker'
gcc -o "$(FFF_TEST_C_TARGET)" $(FFF_TEST_C_OBJS) $(LIBS)
@echo 'Finished building target: $@'
@echo ' '
$(FFF_TEST_GLOBAL_C_TARGET): $(FFF_TEST_GLOBAL_C_OBJS)
@echo 'Building target: $@'
@echo 'Invoking: GCC C++ Linker'
gcc -o "$(FFF_TEST_GLOBAL_C_TARGET)" $(FFF_TEST_GLOBAL_C_OBJS) $(LIBS) $(WRAP_LDFLAGS)
@echo 'Finished building target: $@'
@echo ' '
$(FFF_TEST_GLOBAL_CPP_TARGET): $(FFF_TEST_GLOBAL_CPP_OBJS)
@echo 'Building target: $@'
@echo 'Invoking: GCC C++ Linker'
g++ -o "$(FFF_TEST_GLOBAL_CPP_TARGET)" $(FFF_TEST_GLOBAL_CPP_OBJS) $(LIBS)
@echo 'Finished building target: $@'
@echo ' '
# Other Targets
clean:
-$(RM) $(FFF_TEST_CPP_OBJS) $(FFF_TEST_GLOBAL_C_OBJS) $(FFF_TEST_C_OBJS) \
$(FFF_TEST_CPP_TARGET) $(FFF_TEST_C_TARGET) $(FFF_TEST_GLOBAL_CPP_TARGET) $(FFF_TEST_GLOBAL_C_TARGET)
-@echo ' '

View File

@@ -6,7 +6,7 @@
#define OVERRIDE_CALL_HIST_LEN 17u #define OVERRIDE_CALL_HIST_LEN 17u
#define FFF_CALL_HISTORY_LEN OVERRIDE_CALL_HIST_LEN #define FFF_CALL_HISTORY_LEN OVERRIDE_CALL_HIST_LEN
#include "fff.h" #include "../fff.h"
#include "c_test_framework.h" #include "c_test_framework.h"
#include <assert.h> #include <assert.h>
@@ -21,31 +21,18 @@ struct MyStruct {
int y; int y;
}; };
#ifndef TEST_WITH_CALLING_CONVENTIONS
FAKE_VOID_FUNC(voidfunc1, int); FAKE_VOID_FUNC(voidfunc1, int);
FAKE_VOID_FUNC(voidfunc2, char, char); FAKE_VOID_FUNC(voidfunc2, char, char);
FAKE_VOID_FUNC(voidfunc1outparam, char *); FAKE_VOID_FUNC(voidfunc1outparam, char *);
FAKE_VALUE_FUNC(long, longfunc0); FAKE_VALUE_FUNC(long, longfunc0);
FAKE_VALUE_FUNC(enum MYBOOL, enumfunc0); FAKE_VALUE_FUNC(enum MYBOOL, enumfunc0);
FAKE_VALUE_FUNC(struct MyStruct, structfunc0); FAKE_VALUE_FUNC(struct MyStruct, structfunc0);
FAKE_VOID_FUNC_VARARG(voidfunc3var, const char *, int, ...); FAKE_VOID_FUNC_VARARG(voidfunc3var, char *, int, ...);
FAKE_VALUE_FUNC_VARARG(int, valuefunc3var, const char *, int, ...); FAKE_VALUE_FUNC_VARARG(int, valuefunc3var, char *, int, ...);
FAKE_VALUE_FUNC(int, strlcpy3, char* const, const char* const, const size_t); FAKE_VALUE_FUNC(int, strlcpy3, char* const, const char* const, const size_t);
FAKE_VOID_FUNC(voidfunc20, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int); FAKE_VOID_FUNC(voidfunc20, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int);
FAKE_VALUE_FUNC(int, valuefunc20, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int); FAKE_VALUE_FUNC(int, valuefunc20, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int);
#else
FAKE_VOID_FUNC(__cdecl, voidfunc1, int);
FAKE_VOID_FUNC(__cdecl, voidfunc2, char, char);
FAKE_VOID_FUNC(__cdecl, voidfunc1outparam, char *);
FAKE_VALUE_FUNC(long, __cdecl, longfunc0);
FAKE_VALUE_FUNC(enum MYBOOL, __cdecl, enumfunc0);
FAKE_VALUE_FUNC(struct MyStruct, __cdecl, structfunc0);
FAKE_VOID_FUNC_VARARG(__cdecl, voidfunc3var, char *, int, ...);
FAKE_VALUE_FUNC_VARARG(int, __cdecl, valuefunc3var, char *, int, ...);
FAKE_VALUE_FUNC(int, __cdecl, strlcpy3, char* const, const char* const, const size_t);
FAKE_VOID_FUNC(__cdecl, voidfunc20, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int);
FAKE_VALUE_FUNC(int, __cdecl, valuefunc20, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int);
#endif
void setup() void setup()
{ {
@@ -116,10 +103,6 @@ int main()
RUN_TEST(FFFTestSuite, use_void_vararg_fake_with_different_number_of_arguments); RUN_TEST(FFFTestSuite, use_void_vararg_fake_with_different_number_of_arguments);
RUN_TEST(FFFTestSuite, use_value_vararg_fake_with_different_number_of_arguments); RUN_TEST(FFFTestSuite, use_value_vararg_fake_with_different_number_of_arguments);
RUN_TEST(FFFTestSuite, vararg_custom_fake_sequence_not_exhausted);
RUN_TEST(FFFTestSuite, vararg_custom_fake_seq_return_values_saved_in_history);
RUN_TEST(FFFTestSuite, vararg_custom_fake_sequence_exhausted);
RUN_TEST(FFFTestSuite, vararg_custom_fake_sequence_reset);
RUN_TEST(FFFTestSuite, can_capture_upto_20_arguments_correctly); RUN_TEST(FFFTestSuite, can_capture_upto_20_arguments_correctly);
RUN_TEST(FFFTestSuite, value_func_can_capture_upto_20_arguments_correctly); RUN_TEST(FFFTestSuite, value_func_can_capture_upto_20_arguments_correctly);

48
test/fff_test_cpp.cpp Normal file
View File

@@ -0,0 +1,48 @@
/*
* fff_test.cpp
*
* Created on: Dec 20, 2010
* Author: mlong
*/
// Want to keep the argument history for 13 calls
#define OVERRIDE_ARG_HIST_LEN 13u
#define FFF_ARG_HISTORY_LEN OVERRIDE_ARG_HIST_LEN
// Want to keep the call sequence history for 17 function calls
#define OVERRIDE_CALL_HIST_LEN 17u
#define FFF_CALL_HISTORY_LEN OVERRIDE_CALL_HIST_LEN
#include "../fff.h"
#include <gtest/gtest.h>
DEFINE_FFF_GLOBALS
FAKE_VOID_FUNC(voidfunc1, int);
FAKE_VOID_FUNC(voidfunc2, char, char);
FAKE_VOID_FUNC(voidfunc1outparam, char *);
FAKE_VALUE_FUNC(long, longfunc0);
FAKE_VOID_FUNC(voidfunc20, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int);
FAKE_VALUE_FUNC(int, valuefunc20, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int);
class FFFTestSuite: public testing::Test
{
public:
void SetUp()
{
RESET_FAKE(voidfunc1);
RESET_FAKE(voidfunc2);
RESET_FAKE(longfunc0);
RESET_FAKE(voidfunc1outparam);
FFF_RESET_HISTORY();
}
};
#include "test_cases.include"
TEST_F(FFFTestSuite, default_constants_can_be_overridden)
{
unsigned sizeCallHistory = (sizeof fff.call_history) / (sizeof fff.call_history[0]);
ASSERT_EQ(OVERRIDE_CALL_HIST_LEN, sizeCallHistory);
ASSERT_EQ(OVERRIDE_ARG_HIST_LEN, voidfunc2_fake.arg_history_len);
}

View File

@@ -68,10 +68,6 @@ int main()
RUN_TEST(FFFTestSuite, use_void_vararg_fake_with_different_number_of_arguments); RUN_TEST(FFFTestSuite, use_void_vararg_fake_with_different_number_of_arguments);
RUN_TEST(FFFTestSuite, use_value_vararg_fake_with_different_number_of_arguments); RUN_TEST(FFFTestSuite, use_value_vararg_fake_with_different_number_of_arguments);
RUN_TEST(FFFTestSuite, vararg_custom_fake_sequence_not_exhausted);
RUN_TEST(FFFTestSuite, vararg_custom_fake_seq_return_values_saved_in_history);
RUN_TEST(FFFTestSuite, vararg_custom_fake_sequence_exhausted);
RUN_TEST(FFFTestSuite, vararg_custom_fake_sequence_reset);
RUN_TEST(FFFTestSuite, can_capture_upto_20_arguments_correctly); RUN_TEST(FFFTestSuite, can_capture_upto_20_arguments_correctly);
RUN_TEST(FFFTestSuite, value_func_can_capture_upto_20_arguments_correctly); RUN_TEST(FFFTestSuite, value_func_can_capture_upto_20_arguments_correctly);

View File

@@ -2,7 +2,7 @@
extern "C"{ extern "C"{
#include "global_fakes.h" #include "global_fakes.h"
} }
#include "gtest/gtest.h" #include <gtest/gtest.h>
DEFINE_FFF_GLOBALS; DEFINE_FFF_GLOBALS;
@@ -15,8 +15,6 @@ public:
RESET_FAKE(voidfunc2); RESET_FAKE(voidfunc2);
RESET_FAKE(longfunc0); RESET_FAKE(longfunc0);
RESET_FAKE(voidfunc1outparam); RESET_FAKE(voidfunc1outparam);
RESET_FAKE(voidfunc3var);
RESET_FAKE(valuefunc3var);
FFF_RESET_HISTORY(); FFF_RESET_HISTORY();
} }
}; };

17
test/global_fakes.c Normal file
View File

@@ -0,0 +1,17 @@
#include "global_fakes.h"
#include <string.h> // for memcpy
DEFINE_FAKE_VOID_FUNC(voidfunc1, int);
DEFINE_FAKE_VOID_FUNC(voidfunc2, char, char);
DEFINE_FAKE_VOID_FUNC(voidfunc1outparam, char *);
DEFINE_FAKE_VALUE_FUNC(long, longfunc0);
DEFINE_FAKE_VALUE_FUNC(enum MYBOOL, enumfunc0);
DEFINE_FAKE_VALUE_FUNC(struct MyStruct, structfunc0);
DEFINE_FAKE_VOID_FUNC_VARARG(voidfunc3var, const char *, int, ...);
DEFINE_FAKE_VALUE_FUNC_VARARG(int, valuefunc3var, const char *, int, ...);
#ifndef __cplusplus
DEFINE_FAKE_VALUE_FUNC(int, strlcpy3, char* const, const char* const, const size_t);
#endif /* __cplusplus */
DEFINE_FAKE_VOID_FUNC(voidfunc20, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int);
DEFINE_FAKE_VALUE_FUNC(int, valuefunc20, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int);

View File

@@ -1,8 +1,9 @@
#ifndef GLOBAL_FAKES_H_ #ifndef GLOBAL_FAKES_H_
#define GLOBAL_FAKES_H_ #define GLOBAL_FAKES_H_
#include <fff.h> #include "../fff.h"
#include <string.h> #include "string.h"
//// Imaginary production code header file /// //// Imaginary production code header file ///
@@ -15,7 +16,6 @@ enum MYBOOL enumfunc();
struct MyStruct structfunc(); struct MyStruct structfunc();
//// End Imaginary production code header file /// //// End Imaginary production code header file ///
#ifndef TEST_WITH_CALLING_CONVENTIONS
DECLARE_FAKE_VOID_FUNC(voidfunc1, int); DECLARE_FAKE_VOID_FUNC(voidfunc1, int);
DECLARE_FAKE_VOID_FUNC(voidfunc2, char, char); DECLARE_FAKE_VOID_FUNC(voidfunc2, char, char);
DECLARE_FAKE_VOID_FUNC(voidfunc1outparam, char *); DECLARE_FAKE_VOID_FUNC(voidfunc1outparam, char *);
@@ -26,24 +26,8 @@ DECLARE_FAKE_VOID_FUNC_VARARG(voidfunc3var, const char *, int, ...);
DECLARE_FAKE_VALUE_FUNC_VARARG(int, valuefunc3var, const char *, int, ...); DECLARE_FAKE_VALUE_FUNC_VARARG(int, valuefunc3var, const char *, int, ...);
DECLARE_FAKE_VOID_FUNC(voidfunc20, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int); DECLARE_FAKE_VOID_FUNC(voidfunc20, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int);
DECLARE_FAKE_VALUE_FUNC(int, valuefunc20, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int); DECLARE_FAKE_VALUE_FUNC(int, valuefunc20, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int);
#else
DECLARE_FAKE_VOID_FUNC(__cdecl, voidfunc1, int);
DECLARE_FAKE_VOID_FUNC(__cdecl, voidfunc2, char, char);
DECLARE_FAKE_VOID_FUNC(__cdecl, voidfunc1outparam, char *);
DECLARE_FAKE_VALUE_FUNC(long, __cdecl, longfunc0);
DECLARE_FAKE_VALUE_FUNC(enum MYBOOL, __cdecl, enumfunc0);
DECLARE_FAKE_VALUE_FUNC(struct MyStruct, __cdecl, structfunc0);
DECLARE_FAKE_VOID_FUNC_VARARG(__cdecl, voidfunc3var, const char *, int, ...);
DECLARE_FAKE_VALUE_FUNC_VARARG(int, __cdecl, valuefunc3var, const char *, int, ...);
DECLARE_FAKE_VOID_FUNC(__cdecl, voidfunc20, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int);
DECLARE_FAKE_VALUE_FUNC(int, __cdecl, valuefunc20, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int);
#endif
#ifndef __cplusplus #ifndef __cplusplus
#ifndef TEST_WITH_CALLING_CONVENTIONS
DECLARE_FAKE_VALUE_FUNC(int, strlcpy3, char* const, const char* const, const size_t); DECLARE_FAKE_VALUE_FUNC(int, strlcpy3, char* const, const char* const, const size_t);
#else
DECLARE_FAKE_VALUE_FUNC(int, __cdecl, strlcpy3, char* const, const char* const, const size_t);
#endif
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif /* GLOBAL_FAKES_H_ */ #endif /* GLOBAL_FAKES_H_ */

View File

@@ -1,10 +0,0 @@
/* Copyright 2022 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <functional>
#define CUSTOM_FFF_FUNCTION_TEMPLATE(RETURN, FUNCNAME, ...) \
std::function<RETURN (__VA_ARGS__)> FUNCNAME

View File

@@ -1,11 +0,0 @@
/* Copyright 2022 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <functional>
#include "custom_function.hpp"
#include <fff.h>

View File

@@ -1,101 +0,0 @@
/*
* fff_test.cpp
*
* Created on: Dec 20, 2010
* Author: mlong
*/
// Want to keep the argument history for 13 calls
#define OVERRIDE_ARG_HIST_LEN 13u
#define FFF_ARG_HISTORY_LEN OVERRIDE_ARG_HIST_LEN
// Want to keep the call sequence history for 17 function calls
#define OVERRIDE_CALL_HIST_LEN 17u
#define FFF_CALL_HISTORY_LEN OVERRIDE_CALL_HIST_LEN
#include "fff.h"
#include "gtest/gtest.h"
DEFINE_FFF_GLOBALS
#ifndef TEST_WITH_CALLING_CONVENTIONS
FAKE_VOID_FUNC(voidfunc1, int);
FAKE_VOID_FUNC(voidfunc2, char, char);
FAKE_VOID_FUNC(voidfunc1outparam, char *);
FAKE_VALUE_FUNC(long, longfunc0);
FAKE_VOID_FUNC_VARARG(voidfunc3var, const char *, int, ...);
FAKE_VALUE_FUNC_VARARG(int, valuefunc3var, const char *, int, ...);
FAKE_VOID_FUNC(voidfunc20, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int);
FAKE_VALUE_FUNC(int, valuefunc20, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int);
#else
FAKE_VOID_FUNC(__cdecl, voidfunc1, int);
FAKE_VOID_FUNC(__cdecl, voidfunc2, char, char);
FAKE_VOID_FUNC(__cdecl, voidfunc1outparam, char *);
FAKE_VALUE_FUNC(long, __cdecl, longfunc0);
FAKE_VOID_FUNC_VARARG(__cdecl, voidfunc3var, const char *, int, ...);
FAKE_VALUE_FUNC_VARARG(int, __cdecl, valuefunc3var, const char *, int, ...);
FAKE_VOID_FUNC(__cdecl, voidfunc20, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int);
FAKE_VALUE_FUNC(int, __cdecl, valuefunc20, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int);
#endif
class FFFTestSuite: public testing::Test
{
public:
void SetUp()
{
RESET_FAKE(voidfunc1);
RESET_FAKE(voidfunc2);
RESET_FAKE(longfunc0);
RESET_FAKE(voidfunc1outparam);
RESET_FAKE(voidfunc3var);
RESET_FAKE(valuefunc3var);
FFF_RESET_HISTORY();
}
};
TEST_F(FFFTestSuite, default_constants_can_be_overridden)
{
unsigned sizeCallHistory = (sizeof fff.call_history) / (sizeof fff.call_history[0]);
ASSERT_EQ(OVERRIDE_CALL_HIST_LEN, sizeCallHistory);
ASSERT_EQ(OVERRIDE_ARG_HIST_LEN, voidfunc2_fake.arg_history_len);
}
// Fake declared in C++ context (not extern "C", using namespace)
// before the fake is declared
namespace cxx
{
typedef int int_t;
void voidfunc1(cxx::int_t);
}
// Now declare the fake. Must be in the same namespace as the
// original declaration.
namespace cxx
{
#ifndef TEST_WITH_CALLING_CONVENTIONS
FAKE_VOID_FUNC(voidfunc1, cxx::int_t);
#else
FAKE_VOID_FUNC(_cdecl, voidfunc1, cxx::int_t);
#endif
}
TEST_F(FFFTestSuite, cxx_fake_is_called)
{
cxx::voidfunc1(66);
ASSERT_EQ(cxx::voidfunc1_fake.call_count, 1u);
ASSERT_EQ(cxx::voidfunc1_fake.arg0_val, 66);
}
static int cxx_my_custom_fake_called = 0;
void cxx_my_custom_fake(cxx::int_t i)
{
cxx_my_custom_fake_called++;
}
TEST_F(FFFTestSuite, cxx_can_register_custom_fake)
{
cxx::voidfunc1_fake.custom_fake = cxx_my_custom_fake;
cxx::voidfunc1(66);
ASSERT_EQ(1, cxx_my_custom_fake_called);
}
#include "test_cases.include"

View File

@@ -1,29 +0,0 @@
/* Copyright 2022 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
#include <gtest/gtest.h>
#include "fff_wrapper.hpp"
DEFINE_FFF_GLOBALS
FAKE_VOID_FUNC(do_stuff, int);
class FFFCustomFakeSuite : public ::testing::Test {
public:
void SetUp() override {
RESET_FAKE(do_stuff);
FFF_RESET_HISTORY();
}
};
TEST_F(FFFCustomFakeSuite, custom_cpp_fake_function)
{
int x = 0;
do_stuff_fake.custom_fake = [&x](int i) {
x = i;
};
do_stuff(5);
ASSERT_EQ(5, x);
}

View File

@@ -1,34 +0,0 @@
#include "global_fakes.h"
#include <string.h> // for memcpy
#ifndef TEST_WITH_CALLING_CONVENTIONS
DEFINE_FAKE_VOID_FUNC(voidfunc1, int);
DEFINE_FAKE_VOID_FUNC(voidfunc2, char, char);
DEFINE_FAKE_VOID_FUNC(voidfunc1outparam, char *);
DEFINE_FAKE_VALUE_FUNC(long, longfunc0);
DEFINE_FAKE_VALUE_FUNC(enum MYBOOL, enumfunc0);
DEFINE_FAKE_VALUE_FUNC(struct MyStruct, structfunc0);
DEFINE_FAKE_VOID_FUNC_VARARG(voidfunc3var, const char *, int, ...);
DEFINE_FAKE_VALUE_FUNC_VARARG(int, valuefunc3var, const char *, int, ...);
#ifndef __cplusplus
DEFINE_FAKE_VALUE_FUNC(int, strlcpy3, char* const, const char* const, const size_t);
#endif /* __cplusplus */
DEFINE_FAKE_VOID_FUNC(voidfunc20, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int);
DEFINE_FAKE_VALUE_FUNC(int, valuefunc20, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int);
#else
DEFINE_FAKE_VOID_FUNC(__cdecl, voidfunc1, int);
DEFINE_FAKE_VOID_FUNC(__cdecl, voidfunc2, char, char);
DEFINE_FAKE_VOID_FUNC(__cdecl, voidfunc1outparam, char *);
DEFINE_FAKE_VALUE_FUNC(long, __cdecl, longfunc0);
DEFINE_FAKE_VALUE_FUNC(enum MYBOOL, __cdecl, enumfunc0);
DEFINE_FAKE_VALUE_FUNC(struct MyStruct, __cdecl, structfunc0);
DEFINE_FAKE_VOID_FUNC_VARARG(__cdecl, voidfunc3var, const char *, int, ...);
DEFINE_FAKE_VALUE_FUNC_VARARG(int, __cdecl, valuefunc3var, const char *, int, ...);
#ifndef __cplusplus
DEFINE_FAKE_VALUE_FUNC(int, __cdecl, strlcpy3, char* const, const char* const, const size_t);
#endif /* __cplusplus */
DEFINE_FAKE_VOID_FUNC(__cdecl, voidfunc20, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int);
DEFINE_FAKE_VALUE_FUNC(int, __cdecl,valuefunc20, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int);
#endif

View File

@@ -158,13 +158,11 @@ TEST_F(FFFTestSuite, register_call_macro_registers_two_calls)
TEST_F(FFFTestSuite, reset_call_history_resets_call_history) TEST_F(FFFTestSuite, reset_call_history_resets_call_history)
{ {
REGISTER_CALL(longfunc0); REGISTER_CALL(longfunc0);
REGISTER_CALL(voidfunc1);
FFF_RESET_HISTORY(); FFF_RESET_HISTORY();
REGISTER_CALL(voidfunc2); REGISTER_CALL(voidfunc2);
ASSERT_EQ(1u, fff.call_history_idx); ASSERT_EQ(1u, fff.call_history_idx);
ASSERT_EQ(fff.call_history[0], (void *)voidfunc2); ASSERT_EQ(fff.call_history[0], (void *)voidfunc2);
ASSERT_EQ(fff.call_history[1], (void *)0);
} }
TEST_F(FFFTestSuite, call_history_will_not_write_past_array_bounds) TEST_F(FFFTestSuite, call_history_will_not_write_past_array_bounds)
@@ -244,11 +242,9 @@ void voidfunc1outparam_custom_fake3(char *a)
TEST_F(FFFTestSuite, custom_fake_sequence_not_exausthed) TEST_F(FFFTestSuite, custom_fake_sequence_not_exausthed)
{ {
CUSTOM_FFF_FUNCTION_TEMPLATE(void, custom_fakes[], char *) = { void (*custom_fakes[])(char *) = {voidfunc1outparam_custom_fake1,
voidfunc1outparam_custom_fake1, voidfunc1outparam_custom_fake2,
voidfunc1outparam_custom_fake2, voidfunc1outparam_custom_fake3};
voidfunc1outparam_custom_fake3
};
char a = 'a'; char a = 'a';
SET_CUSTOM_FAKE_SEQ(voidfunc1outparam, custom_fakes, 3); SET_CUSTOM_FAKE_SEQ(voidfunc1outparam, custom_fakes, 3);
@@ -288,29 +284,26 @@ TEST_F(FFFTestSuite, return_value_saved_in_history)
ASSERT_EQ(longfunc0_fake.return_val_history[i], i + 1); ASSERT_EQ(longfunc0_fake.return_val_history[i], i + 1);
} }
} }
long custom_longfunc1()
long custom_longfunc1(void)
{ {
return 42; return 42;
} }
long custom_longfunc2(void) long custom_longfunc2()
{ {
return 15; return 15;
} }
long custom_longfunc3(void) long custom_longfunc3()
{ {
return 7; return 7;
} }
TEST_F(FFFTestSuite, custom_fake_seq_return_values_saved_in_history) TEST_F(FFFTestSuite, custom_fake_seq_return_values_saved_in_history)
{ {
CUSTOM_FFF_FUNCTION_TEMPLATE(long, custom_fakes[], void) = { long (*custom_fakes[])(void) = {custom_longfunc1,
custom_longfunc1, custom_longfunc2,
custom_longfunc2, custom_longfunc3};
custom_longfunc3};
SET_CUSTOM_FAKE_SEQ(longfunc0, custom_fakes, 3); SET_CUSTOM_FAKE_SEQ(longfunc0, custom_fakes, 3);
longfunc0(); longfunc0();
@@ -324,10 +317,9 @@ TEST_F(FFFTestSuite, custom_fake_seq_return_values_saved_in_history)
TEST_F(FFFTestSuite, custom_fake_sequence_exhausted) TEST_F(FFFTestSuite, custom_fake_sequence_exhausted)
{ {
CUSTOM_FFF_FUNCTION_TEMPLATE(void, custom_fakes[], char *) = { void (*custom_fakes[])(char *) = {voidfunc1outparam_custom_fake1,
voidfunc1outparam_custom_fake1, voidfunc1outparam_custom_fake2,
voidfunc1outparam_custom_fake2, voidfunc1outparam_custom_fake3};
voidfunc1outparam_custom_fake3};
char a = 'a'; char a = 'a';
SET_CUSTOM_FAKE_SEQ(voidfunc1outparam, custom_fakes, 3); SET_CUSTOM_FAKE_SEQ(voidfunc1outparam, custom_fakes, 3);
@@ -351,13 +343,6 @@ long my_custom_value_fake(void)
{ {
return MEANING_OF_LIFE; return MEANING_OF_LIFE;
} }
long my_custom_value_fake2(void)
{
static long val = 0;
return val++;
}
TEST_F(FFFTestSuite, when_value_custom_fake_called_THEN_it_returns_custom_return_value) TEST_F(FFFTestSuite, when_value_custom_fake_called_THEN_it_returns_custom_return_value)
{ {
longfunc0_fake.custom_fake = my_custom_value_fake; longfunc0_fake.custom_fake = my_custom_value_fake;
@@ -365,104 +350,7 @@ TEST_F(FFFTestSuite, when_value_custom_fake_called_THEN_it_returns_custom_return
ASSERT_EQ(MEANING_OF_LIFE, retval); ASSERT_EQ(MEANING_OF_LIFE, retval);
} }
TEST_F(FFFTestSuite, return_values_from_custom_fake_saved_in_history) #ifndef __cplusplus
{
longfunc0_fake.custom_fake = my_custom_value_fake2;
longfunc0();
longfunc0();
longfunc0();
ASSERT_EQ(0, longfunc0_fake.return_val_history[0]);
ASSERT_EQ(1, longfunc0_fake.return_val_history[1]);
ASSERT_EQ(2, longfunc0_fake.return_val_history[2]);
}
int valuefunc3var_custom_fake1(const char *str, int a, va_list vl)
{
int arg;
while ((arg = va_arg(vl, int)) != 0)
a += arg;
return a;
}
int valuefunc3var_custom_fake2(const char *str, int a, va_list vl)
{
int arg;
while ((arg = va_arg(vl, int)) != 0)
a -= arg;
return a;
}
int valuefunc3var_custom_fake3(const char *str, int a, va_list vl)
{
int arg;
while ((arg = va_arg(vl, int)) != 0)
a *= arg;
return a;
}
TEST_F(FFFTestSuite, vararg_custom_fake_sequence_not_exhausted)
{
CUSTOM_FFF_FUNCTION_TEMPLATE(int, custom_fakes[], const char *, int,
va_list) = {valuefunc3var_custom_fake1,
valuefunc3var_custom_fake2,
valuefunc3var_custom_fake3};
SET_CUSTOM_FAKE_SEQ(valuefunc3var, custom_fakes, 3);
int a = 1;
ASSERT_EQ(valuefunc3var("a", a, 2, 3, 4, 0), 10);
ASSERT_EQ(valuefunc3var("aa", a, 2, 3, 4, 2, 0), -10);
ASSERT_EQ(valuefunc3var("aaa", a, 2, 3, 0), 6);
}
TEST_F(FFFTestSuite, vararg_custom_fake_seq_return_values_saved_in_history)
{
CUSTOM_FFF_FUNCTION_TEMPLATE(int, custom_fakes[], const char *, int,
va_list) = {valuefunc3var_custom_fake1,
valuefunc3var_custom_fake2,
valuefunc3var_custom_fake3};
SET_CUSTOM_FAKE_SEQ(valuefunc3var, custom_fakes, 3);
int a = 1;
valuefunc3var("a", a, 2, 3, 4, 0);
valuefunc3var("aa", a, 2, 3, 4, 2, 0);
valuefunc3var("aaa", a, 2, 3, 0);
ASSERT_EQ(10, valuefunc3var_fake.return_val_history[0]);
ASSERT_EQ(-10, valuefunc3var_fake.return_val_history[1]);
ASSERT_EQ(6, valuefunc3var_fake.return_val_history[2]);
}
TEST_F(FFFTestSuite, vararg_custom_fake_sequence_exhausted)
{
CUSTOM_FFF_FUNCTION_TEMPLATE(int, custom_fakes[], const char *, int,
va_list) = {valuefunc3var_custom_fake1,
valuefunc3var_custom_fake2,
valuefunc3var_custom_fake3};
SET_CUSTOM_FAKE_SEQ(valuefunc3var, custom_fakes, 3);
int a = 1;
ASSERT_EQ(valuefunc3var("a", a, 2, 3, 4, 0), 10);
ASSERT_EQ(valuefunc3var("aa", a, 2, 3, 4, 2, 0), -10);
ASSERT_EQ(valuefunc3var("aaa", a, 2, 3, 0), 6);
ASSERT_EQ(valuefunc3var("aaa", a, 4, 5, 1, 0), 20);
ASSERT_EQ(valuefunc3var("aaa", a, 4, 0), 4);
}
TEST_F(FFFTestSuite, vararg_custom_fake_sequence_reset)
{
CUSTOM_FFF_FUNCTION_TEMPLATE(int, custom_fakes[], const char *, int,
va_list) = {valuefunc3var_custom_fake1,
valuefunc3var_custom_fake2,
valuefunc3var_custom_fake3};
SET_CUSTOM_FAKE_SEQ(valuefunc3var, custom_fakes, 3);
int a = 1;
ASSERT_EQ(valuefunc3var("a", a, 2, 3, 4, 0), 10);
ASSERT_EQ(valuefunc3var("aa", a, 2, 3, 4, 2, 0), -10);
RESET_FAKE(valuefunc3var);
ASSERT_EQ(0, valuefunc3var("b", 7, 4, 5));
valuefunc3var_fake.return_val = 1;
ASSERT_EQ(1, valuefunc3var("c", 5, 4, 4));
valuefunc3var_fake.return_val = 2;
ASSERT_EQ(2, valuefunc3var("d", 6, 3, 5));
}
TEST_F(FFFTestSuite, use_void_vararg_fake_with_different_number_of_arguments) TEST_F(FFFTestSuite, use_void_vararg_fake_with_different_number_of_arguments)
{ {
voidfunc3var("0 parameters", 0); voidfunc3var("0 parameters", 0);
@@ -470,7 +358,7 @@ TEST_F(FFFTestSuite, use_void_vararg_fake_with_different_number_of_arguments)
voidfunc3var("2 parameters", 2, 10, 20); voidfunc3var("2 parameters", 2, 10, 20);
voidfunc3var("3 parameters", 3, 10, 20, 30); voidfunc3var("3 parameters", 3, 10, 20, 30);
ASSERT_EQ(voidfunc3var_fake.call_count, 4u); ASSERT_EQ(voidfunc3var_fake.call_count, 4);
char msg[] = "3 parameters"; char msg[] = "3 parameters";
ASSERT_EQ(strcmp(voidfunc3var_fake.arg0_val, msg), 0); ASSERT_EQ(strcmp(voidfunc3var_fake.arg0_val, msg), 0);
ASSERT_EQ(3, voidfunc3var_fake.arg1_val); ASSERT_EQ(3, voidfunc3var_fake.arg1_val);
@@ -483,11 +371,12 @@ TEST_F(FFFTestSuite, use_value_vararg_fake_with_different_number_of_arguments)
valuefunc3var("2 parameters", 2, 10, 20); valuefunc3var("2 parameters", 2, 10, 20);
valuefunc3var("3 parameters", 3, 10, 20, 30); valuefunc3var("3 parameters", 3, 10, 20, 30);
ASSERT_EQ(valuefunc3var_fake.call_count, 4u); ASSERT_EQ(valuefunc3var_fake.call_count, 4);
char msg[] = "3 parameters"; char msg[] = "3 parameters";
ASSERT_EQ(strcmp(valuefunc3var_fake.arg0_val, msg), 0); ASSERT_EQ(strcmp(valuefunc3var_fake.arg0_val, msg), 0);
ASSERT_EQ(3, valuefunc3var_fake.arg1_val); ASSERT_EQ(3, valuefunc3var_fake.arg1_val);
} }
#endif /* __cplusplus */
TEST_F(FFFTestSuite, can_capture_upto_20_arguments_correctly) TEST_F(FFFTestSuite, can_capture_upto_20_arguments_correctly)
{ {
@@ -542,3 +431,4 @@ TEST_F(FFFTestSuite, value_func_can_capture_upto_20_arguments_correctly)
ASSERT_EQ(18, valuefunc20_fake.arg18_val); ASSERT_EQ(18, valuefunc20_fake.arg18_val);
ASSERT_EQ(19, valuefunc20_fake.arg19_val); ASSERT_EQ(19, valuefunc20_fake.arg19_val);
} }