1
0
mirror of https://github.com/meekrosoft/fff synced 2026-01-23 16:35:59 +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-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://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
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.
## Running all tests
### Linux / MacOS
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!
## Hello fake world!
Say you are testing an embedded user interface and you have a function that
you want to create a fake for:
@@ -94,7 +62,11 @@ typedef struct 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?
@@ -132,7 +104,9 @@ type (a char pointer in this example).
A variable is created for every argument in the form
`"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
`FAKE_VALUE_FUNC` macro. For instance:
@@ -179,7 +153,10 @@ you would use a syntax like this:
```c
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
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
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.
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);
```
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
## User Defined Argument History
@@ -300,6 +277,7 @@ override the default by defining it before include the `fff.h` like this:
#include "../fff.h"
```
## Function Return Value Sequences
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
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
#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
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
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
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
fake in the sequence. This macro works much like the `SET_RETURN_SEQ` macro.
## Return Value History
fake in the sequence. This macro works much like the SET_RETURN_SEQ macro.
## Return value history
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
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
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]);
}
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
You can fake variadic functions using the macros `FAKE_VALUE_FUNC_VARARG`
and `FAKE_VOID_FUNC_VARARG`. For instance:
You can fake variadic functions using the macros <tt>FAKE_VALUE_FUNC_VARARG</tt>
and <tt>FAKE_VOID_FUNC_VARARG</tt>. For instance:
FAKE_VALUE_FUNC_VARARG(int, fprintf, FILE *, const char*, ...);
In order to access the variadic parameters from a custom fake function, declare a
`va_list` parameter. For instance, a custom fake for `fprintf()`
could call the real `fprintf()` like this:
<tt>va_list</tt> parameter. For instance, a custom fake for <tt>fprintf()</tt>
could call the real <tt>fprintf()</tt> like this:
int fprintf_custom(FILE *stream, const char *format, va_list ap) {
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);
}
Just like [return value delegates](#custom-return-value-delegate-sequences), you can also specify sequences for variadic functions using `SET_CUSTOM_FAKE_SEQ`.
See the test files for examples.
## 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.
## 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.
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
#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 */
typedef struct {
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)
{
Time t;
Time getTime_custom_now = {
.hour = 13,
.min = 05,
};
getTime_fake.custom_fake = [getTime_custom_now](Time *now) {
*now = getTime_custom_now;
};
Time getTime_custom_now;
void getTime_custom_fake(Time *now) {
*now = getTime_custom_now;
}
getTime_fake.custom_fake = getTime_custom_fake;
/* given a specific time */
getTime_custom_now.hour = 13;
getTime_custom_now.min = 05;
/* when getTime is called */
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?
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.
## 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.
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);
```
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
/* 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.
```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);
/* The fake, attempt two */
@@ -583,10 +530,8 @@ TEST_F(FFFTestSuite, test_fake_with_function_pointer)
ASSERT_EQ(cb_timeout_called, 1);
}
```
### 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.
## 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.
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
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
## Find out more...
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.
@@ -648,11 +572,10 @@ So whats the point?
* 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
* There are tests under _./test_
* There is an example for testing an embedded UI and a hardware driver under _./examples_
* There is an example of weak_linking under _./examples_
* There are tests under src/test
* There is an example for testing an embedded UI and a hardware driver under src/examples
## 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_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); |

View File

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

View File

@@ -1,9 +1,8 @@
extern "C"{
#include "driver.h"
#include "registers.h"
#include "hardware_abstraction.h"
}
#include "fff.h"
#include "../../fff.h"
#include <gtest/gtest.h>
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 "fff.h"
#include "../../fff.h"
#include "SYSTEM.h"
#include "DISPLAY.h"

View File

@@ -6,7 +6,7 @@ extern "C"{
#include <gtest/gtest.h>
#include "fff.h"
#include "../../fff.h"
DEFINE_FFF_GLOBALS;
/* 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
$MAX_CALL_HISTORY = 50
def license
File.foreach("#{__dir__}/LICENSE") { |line| putd line }
end
def include_dependencies
putd "#include <stdarg.h>"
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 "#endif"
putd "#ifndef FFF_GCC_FUNCTION_ATTRIBUTES"
indent {
putd "#define FFF_GCC_FUNCTION_ATTRIBUTES"
}
putd "#endif"
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
@@ -180,9 +159,9 @@ def define_value_function_variables_helper
puts
putd_backslash "#define DECLARE_VALUE_FUNCTION_VARIABLES(RETURN_TYPE)"
indent {
putd_backslash "RETURN_TYPE return_val;"
putd_backslash "int return_val_seq_len;"
putd_backslash "int return_val_seq_idx;"
putd_backslash "RETURN_TYPE return_val;"
putd_backslash "int return_val_seq_len;"
putd_backslash "int return_val_seq_idx;"
putd_backslash "RETURN_TYPE * return_val_seq;"
}
end
@@ -229,8 +208,8 @@ def define_extern_c_helper
puts
putd "#ifdef __cplusplus"
indent {
putd "#define FFF_EXTERN_C extern \"C\"{"
putd "#define FFF_END_EXTERN_C } "
putd "#define FFF_EXTERN_C extern \"C\"{"
putd "#define FFF_END_EXTERN_C } "
}
putd "#else /* ansi c */"
indent {
@@ -246,9 +225,7 @@ def define_reset_fake_helper
indent {
putd_backslash "void FUNCNAME##_reset(void){"
indent {
putd_backslash "memset((void*)&FUNCNAME##_fake, 0, sizeof(FUNCNAME##_fake) - sizeof(FUNCNAME##_fake.custom_fake) - sizeof(FUNCNAME##_fake.custom_fake_seq));"
putd_backslash "FUNCNAME##_fake.custom_fake = NULL;"
putd_backslash "FUNCNAME##_fake.custom_fake_seq = NULL;"
putd_backslash "memset(&FUNCNAME##_fake, 0, sizeof(FUNCNAME##_fake));"
putd_backslash "FUNCNAME##_fake.arg_history_len = FFF_ARG_HISTORY_LEN;"
}
putd "}"
@@ -277,12 +254,12 @@ def popd
end
def indent
pushd
pushd
yield
popd
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" : ""
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" : ""
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 {
output_variables(saved_arg_count, has_varargs, has_calling_conventions, is_value_function)
}
puts
output_macro_header(define_macro_name, saved_arg_count, has_varargs, has_calling_conventions, return_type)
indent {
putd_backslash "FUNCNAME##_Fake FUNCNAME##_fake;"
putd_backslash function_signature(saved_arg_count, has_varargs, has_calling_conventions, is_value_function) + "{"
indent {
output_function_body(saved_arg_count, has_varargs, is_value_function)
extern_c { # define argument capture variables
output_variables(saved_arg_count, has_varargs, is_value_function)
}
putd_backslash "}"
putd_backslash "DEFINE_RESET_FUNCTION(FUNCNAME)"
}
puts
output_macro_header(fake_macro_name, saved_arg_count, has_varargs, has_calling_conventions, return_type)
output_macro_header(define_macro_name, saved_arg_count, has_varargs, return_type)
indent {
putd macro_signature_for(declare_macro_name, saved_arg_count, has_varargs, has_calling_conventions, return_type)
putd macro_signature_for(define_macro_name, saved_arg_count, has_varargs, has_calling_conventions, return_type)
extern_c {
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)"
}
}
puts
output_macro_header(fake_macro_name, saved_arg_count, has_varargs, return_type)
indent {
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, return_type)
puts
}
end
def output_macro_header(macro_name, arg_count, has_varargs, has_calling_conventions, return_type)
output_macro_name(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, return_type)
end
# #define #macro_name(RETURN_TYPE, FUNCNAME, ARG0,...)
def output_macro_name(macro_name, arg_count, has_varargs, has_calling_conventions, return_type)
putd "#define " + macro_signature_for(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, return_type)
end
# #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}("
if return_type != ""
parameter_list += return_type
parameter_list += ", "
end
parameter_list += "CALLING_CONVENTION, " if (has_calling_conventions)
parameter_list += "FUNCNAME"
arg_count.times { |i| parameter_list += ", ARG#{i}_TYPE" }
@@ -347,21 +327,21 @@ def macro_signature_for(macro_name, arg_count, has_varargs, has_calling_conventi
parameter_list
end
def output_variables(arg_count, has_varargs, has_calling_conventions, is_value_function)
def output_variables(arg_count, has_varargs, is_value_function)
in_struct{
arg_count.times { |argN|
arg_count.times { |argN|
putd_backslash "DECLARE_ARG(ARG#{argN}_TYPE, #{argN}, FUNCNAME)"
}
putd_backslash "DECLARE_ALL_FUNC_COMMON"
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_CUSTOM_FAKE_SEQ_VARIABLES"
output_custom_function_signature(arg_count, has_varargs, has_calling_conventions, is_value_function)
output_custom_function_array(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, is_value_function)
}
putd_backslash "extern FUNCNAME##_Fake FUNCNAME##_fake;"
putd_backslash "void FUNCNAME##_reset(void);"
putd_backslash function_signature(arg_count, has_varargs, has_calling_conventions, is_value_function) + ";"
putd_backslash function_signature(arg_count, has_varargs, is_value_function) + ";"
end
#example: ARG0_TYPE arg0, ARG1_TYPE arg1
@@ -372,14 +352,6 @@ def arg_val_list(args_count)
arguments.join(", ")
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
def arg_list(args_count)
arguments = []
@@ -388,33 +360,26 @@ def arg_list(args_count)
end
# 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);\
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"
ap_list = has_varargs ? ", va_list ap" : ""
calling_conv = has_calling_conventions ? ", CALLING_CONVENTION" : ""
putd_backslash "CUSTOM_FFF_FUNCTION_TEMPLATE(#{return_type}#{calling_conv}, custom_fake, #{arg_type_list(arg_count)}#{ap_list});"
signature = "(*custom_fake)(#{arg_val_list(arg_count)}#{ap_list});"
putd_backslash return_type + signature
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"
ap_list = has_varargs ? ", va_list ap" : ""
calling_conv = has_calling_conventions ? ", CALLING_CONVENTION" : ""
putd_backslash "CUSTOM_FFF_FUNCTION_TEMPLATE(#{return_type}#{calling_conv}, *custom_fake_seq, #{arg_type_list(arg_count)}#{ap_list});"
custom_array = "(**custom_fake_seq)(#{arg_val_list(arg_count)}#{ap_list});"
putd_backslash return_type + custom_array
end
# example: RETURN_TYPE FUNCNAME(ARG0_TYPE arg0, ARG1_TYPE arg1)
# OR
# RETURN_TYPE CALLING_CONVENTION FUNCNAME(ARG0_TYPE arg0, ARG1_TYPE arg1)
def function_signature(arg_count, has_varargs, has_calling_conventions, is_value_function)
def function_signature(arg_count, has_varargs, is_value_function)
return_type = is_value_function ? "RETURN_TYPE" : "void"
varargs = has_varargs ? ", ..." : ""
calling_conventions = has_calling_conventions ?
"#{return_type} FFF_GCC_FUNCTION_ATTRIBUTES CALLING_CONVENTION FUNCNAME(#{arg_val_list(arg_count)}#{varargs})" :
"#{return_type} FFF_GCC_FUNCTION_ATTRIBUTES FUNCNAME(#{arg_val_list(arg_count)}#{varargs})"
"#{return_type} FUNCNAME(#{arg_val_list(arg_count)}#{varargs})"
end
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);"
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){"
indent {
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 "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_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 "if (FUNCNAME##_fake.custom_fake != NULL){ "
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 "}"
putd_backslash "if (FUNCNAME##_fake.custom_fake) #{return_type}FUNCNAME##_fake.custom_fake(#{arg_list(arg_count)});"
end
putd_backslash "RETURN_FAKE_RESULT(FUNCNAME)" if is_value_function
@@ -524,9 +453,9 @@ def define_fff_globals
}
putd "} fff_globals_t;"
puts
putd "FFF_EXTERN_C"
putd_backslash "FFF_EXTERN_C"
putd "extern fff_globals_t fff;"
putd "FFF_END_EXTERN_C"
putd_backslash "FFF_END_EXTERN_C"
puts
putd_backslash "#define DEFINE_FFF_GLOBALS"
indent {
@@ -537,21 +466,25 @@ def define_fff_globals
putd "FFF_END_EXTERN_C"
}
puts
putd_backslash "#define FFF_RESET_HISTORY()"
indent {
putd_backslash "fff.call_history_idx = 0;"
putd "memset(fff.call_history, 0, sizeof(fff.call_history));"
}
putd "#define FFF_RESET_HISTORY() fff.call_history_idx = 0;"
puts
putd_backslash "#define REGISTER_CALL(function)"
indent {
putd_backslash "if(fff.call_history_idx < FFF_CALL_HISTORY_LEN)"
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
def extern_c
putd_backslash "FFF_EXTERN_C"
indent {
yield
}
putd_backslash "FFF_END_EXTERN_C"
end
def in_struct
putd_backslash "typedef struct FUNCNAME##_Fake {"
indent {
@@ -572,22 +505,18 @@ def include_guard
end
def msvc_expand_macro_fix
putd "/* MSVC expand macro fix */"
putd "#define EXPAND(x) x"
putd "/* MSVC expand macro fix */"
putd "#define EXPAND(x) x"
end
def generate_arg_sequence(args, prefix, do_reverse, joinstr)
fmap = (0..args).flat_map {|i| [prefix + i.to_s]}
if do_reverse then fmap.reverse.join(joinstr) else fmap.join(", ") end
fmap = (0..args).flat_map {|i| [prefix + i.to_s]}
if do_reverse then fmap.reverse.join(joinstr) else fmap.join(", ") 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" : ""
if has_calling_conventions
minus_count = (type == :VOID) ? 2 : 3
else
minus_count = (type == :VOID) ? 1 : 2
end
minus_count = (type == :VOID) ? 1 : 2
<<-MACRO_COUNTING_INSTANCE
#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
end
def output_macro_counting_shortcuts(has_calling_conventions)
has_calling_conventions ?
(arg_depth = ["3", "2"]; calling_conv = "callingConv, ") :
(arg_depth = ["2", "1"]; calling_conv = "")
def output_macro_counting_shortcuts
msvc_expand_macro_fix
putd <<-MACRO_COUNTING
#define PP_NARG_MINUS#{arg_depth[0]}(...) \
EXPAND(PP_NARG_MINUS#{arg_depth[0]}_(__VA_ARGS__, PP_RSEQ_N_MINUS#{arg_depth[0]}()))
#define PP_NARG_MINUS2(...) \
EXPAND(PP_NARG_MINUS2_(__VA_ARGS__, PP_RSEQ_N_MINUS2()))
#define PP_NARG_MINUS#{arg_depth[0]}_(...) \
EXPAND(PP_ARG_MINUS#{arg_depth[0]}_N(__VA_ARGS__))
#define PP_NARG_MINUS2_(...) \
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]}() \
#{generate_arg_sequence($MAX_ARGS, '', true, ',')}
#define PP_RSEQ_N_MINUS2() \
#{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]}_(...) \
EXPAND(PP_ARG_MINUS#{arg_depth[1]}_N(__VA_ARGS__))
#define PP_NARG_MINUS1(...) \
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]}() \
#{generate_arg_sequence($MAX_ARGS, '', true, ',')}
#define PP_ARG_MINUS1_N(#{generate_arg_sequence($MAX_ARGS, '_', false, ", ")}, N, ...) N
#define PP_RSEQ_N_MINUS1() \
#{generate_arg_sequence($MAX_ARGS, '', true, ',')}
/* DECLARE AND DEFINE FAKE FUNCTIONS - PLACE IN TEST FILES */
#{counting_macro_instance(:VALUE, has_calling_conventions)}
#{counting_macro_instance(:VOID, has_calling_conventions)}
#{counting_macro_instance(:VALUE, has_calling_conventions, :vararg)}
#{counting_macro_instance(:VOID, has_calling_conventions, :vararg)}
#{counting_macro_instance(:VALUE)}
#{counting_macro_instance(:VOID)}
#{counting_macro_instance(:VALUE, :vararg)}
#{counting_macro_instance(:VOID, :vararg)}
/* DECLARE FAKE FUNCTIONS - PLACE IN HEADER FILES */
#{counting_macro_instance(:VALUE, has_calling_conventions, :non_vararg, "DECLARE_")}
#{counting_macro_instance(:VOID, has_calling_conventions, :non_vararg, "DECLARE_")}
#{counting_macro_instance(:VALUE, has_calling_conventions, :vararg, "DECLARE_")}
#{counting_macro_instance(:VOID, has_calling_conventions, :vararg, "DECLARE_")}
#{counting_macro_instance(:VALUE, :non_vararg, "DECLARE_")}
#{counting_macro_instance(:VOID, :non_vararg, "DECLARE_")}
#{counting_macro_instance(:VALUE, :vararg, "DECLARE_")}
#{counting_macro_instance(:VOID, :vararg, "DECLARE_")}
/* DEFINE FAKE FUNCTIONS - PLACE IN SOURCE FILES */
#{counting_macro_instance(:VALUE, has_calling_conventions, :non_vararg, "DEFINE_")}
#{counting_macro_instance(:VOID, has_calling_conventions, :non_vararg, "DEFINE_")}
#{counting_macro_instance(:VALUE, has_calling_conventions, :vararg, "DEFINE_")}
#{counting_macro_instance(:VOID, has_calling_conventions, :vararg, "DEFINE_")}
#{counting_macro_instance(:VALUE, :non_vararg, "DEFINE_")}
#{counting_macro_instance(:VOID, :non_vararg, "DEFINE_")}
#{counting_macro_instance(:VALUE, :vararg, "DEFINE_")}
#{counting_macro_instance(:VOID, :vararg, "DEFINE_")}
MACRO_COUNTING
end
def output_c_and_cpp(has_calling_conventions)
license
def output_c_and_cpp
include_guard {
include_dependencies
output_constants
output_default_function_pointer_macro(has_calling_conventions)
output_internal_helper_macros
yield
output_macro_counting_shortcuts(has_calling_conventions)
output_macro_counting_shortcuts
}
end
def help
# Check if we should generate _with_ support for specifying calling conventions
if (ARGV[0] == "--help" or ARGV[0] == "-h")
puts "Usage: fakegen.rb [options]
-h, --help Show this help message
-wcc, --with-calling-conventions Support specifying calling conventions"
exit
end
yield
end
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)}
}
}
# lets generate!!
output_c_and_cpp{
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, false)}
num_fake_generators.times {|arg_count| output_macro(arg_count, false, true)}
# generate the varargs variants
(2..$MAX_ARGS).each {|arg_count| output_macro(arg_count, true, false)}
(2..$MAX_ARGS).each {|arg_count| output_macro(arg_count, true, true)}
}

10104
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 FFF_CALL_HISTORY_LEN OVERRIDE_CALL_HIST_LEN
#include "fff.h"
#include "../fff.h"
#include "c_test_framework.h"
#include <assert.h>
@@ -21,31 +21,18 @@ struct MyStruct {
int y;
};
#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_VALUE_FUNC(enum MYBOOL, enumfunc0);
FAKE_VALUE_FUNC(struct MyStruct, structfunc0);
FAKE_VOID_FUNC_VARARG(voidfunc3var, const char *, int, ...);
FAKE_VALUE_FUNC_VARARG(int, valuefunc3var, const char *, int, ...);
FAKE_VOID_FUNC_VARARG(voidfunc3var, char *, int, ...);
FAKE_VALUE_FUNC_VARARG(int, valuefunc3var, char *, int, ...);
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_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()
{
@@ -116,10 +103,6 @@ int main()
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, 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, 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_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, value_func_can_capture_upto_20_arguments_correctly);

View File

@@ -2,7 +2,7 @@
extern "C"{
#include "global_fakes.h"
}
#include "gtest/gtest.h"
#include <gtest/gtest.h>
DEFINE_FFF_GLOBALS;
@@ -15,8 +15,6 @@ public:
RESET_FAKE(voidfunc2);
RESET_FAKE(longfunc0);
RESET_FAKE(voidfunc1outparam);
RESET_FAKE(voidfunc3var);
RESET_FAKE(valuefunc3var);
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_
#define GLOBAL_FAKES_H_
#include <fff.h>
#include <string.h>
#include "../fff.h"
#include "string.h"
//// Imaginary production code header file ///
@@ -15,7 +16,6 @@ enum MYBOOL enumfunc();
struct MyStruct structfunc();
//// End Imaginary production code header file ///
#ifndef TEST_WITH_CALLING_CONVENTIONS
DECLARE_FAKE_VOID_FUNC(voidfunc1, int);
DECLARE_FAKE_VOID_FUNC(voidfunc2, char, 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_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);
#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 TEST_WITH_CALLING_CONVENTIONS
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 /* 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)
{
REGISTER_CALL(longfunc0);
REGISTER_CALL(voidfunc1);
FFF_RESET_HISTORY();
REGISTER_CALL(voidfunc2);
ASSERT_EQ(1u, fff.call_history_idx);
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)
@@ -244,11 +242,9 @@ void voidfunc1outparam_custom_fake3(char *a)
TEST_F(FFFTestSuite, custom_fake_sequence_not_exausthed)
{
CUSTOM_FFF_FUNCTION_TEMPLATE(void, custom_fakes[], char *) = {
voidfunc1outparam_custom_fake1,
voidfunc1outparam_custom_fake2,
voidfunc1outparam_custom_fake3
};
void (*custom_fakes[])(char *) = {voidfunc1outparam_custom_fake1,
voidfunc1outparam_custom_fake2,
voidfunc1outparam_custom_fake3};
char a = 'a';
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);
}
}
long custom_longfunc1(void)
long custom_longfunc1()
{
return 42;
}
long custom_longfunc2(void)
long custom_longfunc2()
{
return 15;
}
long custom_longfunc3(void)
long custom_longfunc3()
{
return 7;
}
TEST_F(FFFTestSuite, custom_fake_seq_return_values_saved_in_history)
{
CUSTOM_FFF_FUNCTION_TEMPLATE(long, custom_fakes[], void) = {
custom_longfunc1,
custom_longfunc2,
custom_longfunc3};
long (*custom_fakes[])(void) = {custom_longfunc1,
custom_longfunc2,
custom_longfunc3};
SET_CUSTOM_FAKE_SEQ(longfunc0, custom_fakes, 3);
longfunc0();
@@ -324,10 +317,9 @@ TEST_F(FFFTestSuite, custom_fake_seq_return_values_saved_in_history)
TEST_F(FFFTestSuite, custom_fake_sequence_exhausted)
{
CUSTOM_FFF_FUNCTION_TEMPLATE(void, custom_fakes[], char *) = {
voidfunc1outparam_custom_fake1,
voidfunc1outparam_custom_fake2,
voidfunc1outparam_custom_fake3};
void (*custom_fakes[])(char *) = {voidfunc1outparam_custom_fake1,
voidfunc1outparam_custom_fake2,
voidfunc1outparam_custom_fake3};
char a = 'a';
SET_CUSTOM_FAKE_SEQ(voidfunc1outparam, custom_fakes, 3);
@@ -351,13 +343,6 @@ long my_custom_value_fake(void)
{
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)
{
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);
}
TEST_F(FFFTestSuite, return_values_from_custom_fake_saved_in_history)
{
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));
}
#ifndef __cplusplus
TEST_F(FFFTestSuite, use_void_vararg_fake_with_different_number_of_arguments)
{
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("3 parameters", 3, 10, 20, 30);
ASSERT_EQ(voidfunc3var_fake.call_count, 4u);
ASSERT_EQ(voidfunc3var_fake.call_count, 4);
char msg[] = "3 parameters";
ASSERT_EQ(strcmp(voidfunc3var_fake.arg0_val, msg), 0);
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("3 parameters", 3, 10, 20, 30);
ASSERT_EQ(valuefunc3var_fake.call_count, 4u);
ASSERT_EQ(valuefunc3var_fake.call_count, 4);
char msg[] = "3 parameters";
ASSERT_EQ(strcmp(valuefunc3var_fake.arg0_val, msg), 0);
ASSERT_EQ(3, valuefunc3var_fake.arg1_val);
}
#endif /* __cplusplus */
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(19, valuefunc20_fake.arg19_val);
}