adding new ceedling test project
This commit is contained in:
250
test/vendor/ceedling/plugins/fake_function_framework/README.md
vendored
Normal file
250
test/vendor/ceedling/plugins/fake_function_framework/README.md
vendored
Normal file
@@ -0,0 +1,250 @@
|
||||
# A Fake Function Framework Plug-in for Ceedling
|
||||
|
||||
This is a plug-in for [Ceedling](https://github.com/ThrowTheSwitch/Ceedling) to use the [Fake Function Framework](https://github.com/meekrosoft/fff) for mocking instead of CMock.
|
||||
|
||||
Using fff provides less strict mocking than CMock, and allows for more loosely-coupled tests.
|
||||
And, when tests fail -- since you get the actual line number of the failure -- it's a lot easier to figure out what went wrong.
|
||||
|
||||
## Installing the plug-in
|
||||
|
||||
To use the plugin you need to 1) get the contents of this repo and 2) configure your project to use it.
|
||||
|
||||
### Get the source
|
||||
|
||||
The easiest way to get the source is to just clone this repo into the Ceedling plugin folder for your existing Ceedling project.
|
||||
(Don't have a Ceedling project already? [Here are instructions to create one.](http://www.electronvector.com/blog/try-embedded-test-driven-development-right-now-with-ceedling))
|
||||
From within `<your-project>/vendor/ceedling/plugins`, run:
|
||||
|
||||
`git clone https://github.com/ElectronVector/fake_function_framework.git`
|
||||
|
||||
This will create a new folder named `fake_function_framework` in the plugins folder.
|
||||
|
||||
### Enable the plug-in.
|
||||
|
||||
The plug-in is enabled from within your project.yml file.
|
||||
|
||||
In the `:plugins` configuration, add `fake_function_framework` to the list of enabled plugins:
|
||||
|
||||
```yaml
|
||||
:plugins:
|
||||
:load_paths:
|
||||
- vendor/ceedling/plugins
|
||||
:enabled:
|
||||
- stdout_pretty_tests_report
|
||||
- module_generator
|
||||
- fake_function_framework
|
||||
```
|
||||
*Note that you could put the plugin source in some other loaction.
|
||||
In that case you'd need to add a new path the `:load_paths`.*
|
||||
|
||||
## How to use it
|
||||
|
||||
You use fff with Ceedling the same way you used to use CMock.
|
||||
Modules can still be generated with the default module generator: `rake module:create[my_module]`.
|
||||
If you want to "mock" `some_module.h` in your tests, just `#include "mock_some_module.h"`.
|
||||
This creates a fake function for each of the functions defined in `some_module.h`.
|
||||
|
||||
The name of each fake is the original function name with an appended `_fake`.
|
||||
For example, if we're generating fakes for a stack module with `push` and `pop` functions, we would have the fakes `push_fake` and `pop_fake`.
|
||||
These fakes are linked into our test executable so that any time our unit under test calls `push` or `pop` our fakes are called instead.
|
||||
|
||||
Each of these fakes is actually a structure containing information about how the function was called, and what it might return.
|
||||
We can use Unity to inspect these fakes in our tests, and verify the interactions of our units.
|
||||
There is also a global structure named `fff` which we can use to check the sequence of calls.
|
||||
|
||||
The fakes can also be configured to return particular values, so you can exercise the unit under test however you want.
|
||||
|
||||
The examples below explain how to use fff to test a variety of module interactions.
|
||||
Each example uses fakes for a "display" module, created from a display.h file with `#include "mock_display.h"`. The `display.h` file must exist and must contain the prototypes for the functions to be faked.
|
||||
|
||||
### Test that a function was called once
|
||||
|
||||
```c
|
||||
void
|
||||
test_whenTheDeviceIsReset_thenTheStatusLedIsTurnedOff()
|
||||
{
|
||||
// When
|
||||
event_deviceReset();
|
||||
|
||||
// Then
|
||||
TEST_ASSERT_EQUAL(1, display_turnOffStatusLed_fake.call_count);
|
||||
}
|
||||
```
|
||||
|
||||
### Test that a function was NOT called
|
||||
|
||||
```c
|
||||
void
|
||||
test_whenThePowerReadingIsLessThan5_thenTheStatusLedIsNotTurnedOn(void)
|
||||
{
|
||||
// When
|
||||
event_powerReadingUpdate(4);
|
||||
|
||||
// Then
|
||||
TEST_ASSERT_EQUAL(0, display_turnOnStatusLed_fake.call_count);
|
||||
}
|
||||
```
|
||||
|
||||
## Test that a single function was called with the correct argument
|
||||
|
||||
```c
|
||||
void
|
||||
test_whenTheVolumeKnobIsMaxed_thenVolumeDisplayIsSetTo11(void)
|
||||
{
|
||||
// When
|
||||
event_volumeKnobMaxed();
|
||||
|
||||
// Then
|
||||
TEST_ASSERT_EQUAL(1, display_setVolume_fake.call_count);
|
||||
TEST_ASSERT_EQUAL(11, display_setVolume_fake.arg0_val);
|
||||
}
|
||||
```
|
||||
|
||||
## Test that calls are made in a particular sequence
|
||||
|
||||
```c
|
||||
void
|
||||
test_whenTheModeSelectButtonIsPressed_thenTheDisplayModeIsCycled(void)
|
||||
{
|
||||
// When
|
||||
event_modeSelectButtonPressed();
|
||||
event_modeSelectButtonPressed();
|
||||
event_modeSelectButtonPressed();
|
||||
|
||||
// Then
|
||||
TEST_ASSERT_EQUAL_PTR((void*)display_setModeToMinimum, fff.call_history[0]);
|
||||
TEST_ASSERT_EQUAL_PTR((void*)display_setModeToMaximum, fff.call_history[1]);
|
||||
TEST_ASSERT_EQUAL_PTR((void*)display_setModeToAverage, fff.call_history[2]);
|
||||
}
|
||||
```
|
||||
|
||||
## Fake a return value from a function
|
||||
|
||||
```c
|
||||
void
|
||||
test_givenTheDisplayHasAnError_whenTheDeviceIsPoweredOn_thenTheDisplayIsPoweredDown(void)
|
||||
{
|
||||
// Given
|
||||
display_isError_fake.return_val = true;
|
||||
|
||||
// When
|
||||
event_devicePoweredOn();
|
||||
|
||||
// Then
|
||||
TEST_ASSERT_EQUAL(1, display_powerDown_fake.call_count);
|
||||
}
|
||||
```
|
||||
|
||||
## Fake a function with a value returned by reference
|
||||
|
||||
```c
|
||||
void
|
||||
test_givenTheUserHasTypedSleep_whenItIsTimeToCheckTheKeyboard_theDisplayIsPoweredDown(void)
|
||||
{
|
||||
// Given
|
||||
char mockedEntry[] = "sleep";
|
||||
void return_mock_value(char * entry, int length)
|
||||
{
|
||||
if (length > strlen(mockedEntry))
|
||||
{
|
||||
strncpy(entry, mockedEntry, length);
|
||||
}
|
||||
}
|
||||
display_getKeyboardEntry_fake.custom_fake = return_mock_value;
|
||||
|
||||
// When
|
||||
event_keyboardCheckTimerExpired();
|
||||
|
||||
// Then
|
||||
TEST_ASSERT_EQUAL(1, display_powerDown_fake.call_count);
|
||||
}
|
||||
```
|
||||
|
||||
## Fake a function with a function pointer parameter
|
||||
|
||||
```
|
||||
void
|
||||
test_givenNewDataIsAvailable_whenTheDisplayHasUpdated_thenTheEventIsComplete(void)
|
||||
{
|
||||
// A mock function for capturing the callback handler function pointer.
|
||||
void(*registeredCallback)(void) = 0;
|
||||
void mock_display_updateData(int data, void(*callback)(void))
|
||||
{
|
||||
//Save the callback function.
|
||||
registeredCallback = callback;
|
||||
}
|
||||
display_updateData_fake.custom_fake = mock_display_updateData;
|
||||
|
||||
// Given
|
||||
event_newDataAvailable(10);
|
||||
|
||||
// When
|
||||
if (registeredCallback != 0)
|
||||
{
|
||||
registeredCallback();
|
||||
}
|
||||
|
||||
// Then
|
||||
TEST_ASSERT_EQUAL(true, eventProcessor_isLastEventComplete());
|
||||
}
|
||||
```
|
||||
|
||||
## Helper macros
|
||||
|
||||
For convenience, there are also some helper macros that create new Unity-style asserts:
|
||||
|
||||
- `TEST_ASSERT_CALLED(function)`: Asserts that a function was called once.
|
||||
- `TEST_ASSERT_NOT_CALLED(function)`: Asserts that a function was never called.
|
||||
- `TEST_ASSERT_CALLED_TIMES(times, function)`: Asserts that a function was called a particular number of times.
|
||||
- `TEST_ASSERT_CALLED_IN_ORDER(order, function)`: Asserts that a function was called in a particular order.
|
||||
|
||||
Here's how you might use one of these instead of simply checking the call_count value:
|
||||
|
||||
```c
|
||||
void
|
||||
test_whenTheDeviceIsReset_thenTheStatusLedIsTurnedOff()
|
||||
{
|
||||
// When
|
||||
event_deviceReset();
|
||||
|
||||
// Then
|
||||
// This how to directly use fff...
|
||||
TEST_ASSERT_EQUAL(1, display_turnOffStatusLed_fake.call_count);
|
||||
// ...and this is how to use the helper macro.
|
||||
TEST_ASSERT_CALLED(display_turnOffStatusLed);
|
||||
}
|
||||
```
|
||||
|
||||
## Test setup
|
||||
|
||||
All of the fake functions, and any fff global state are all reset automatically between each test.
|
||||
|
||||
## CMock configuration
|
||||
|
||||
Use still use some of the CMock configuration options for setting things like the mock prefix, and for including additional header files in the mock files.
|
||||
|
||||
```yaml
|
||||
:cmock:
|
||||
:mock_prefix: mock_
|
||||
:includes:
|
||||
-
|
||||
:includes_h_pre_orig_header:
|
||||
-
|
||||
:includes_h_post_orig_header:
|
||||
-
|
||||
:includes_c_pre_header:
|
||||
-
|
||||
:includes_c_post_header:
|
||||
```
|
||||
|
||||
## Running the tests
|
||||
|
||||
There are unit and integration tests for the plug-in itself.
|
||||
These are run with the default `rake` task.
|
||||
The integration test runs the tests for the example project in examples/fff_example.
|
||||
For the integration tests to succeed, this repository must be placed in a Ceedling tree in the plugins folder.
|
||||
|
||||
## More examples
|
||||
|
||||
There is an example project in examples/fff_example.
|
||||
It shows how to use the plug-in with some full-size examples.
|
||||
19
test/vendor/ceedling/plugins/fake_function_framework/Rakefile
vendored
Normal file
19
test/vendor/ceedling/plugins/fake_function_framework/Rakefile
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
require 'rake'
|
||||
require 'rspec/core/rake_task'
|
||||
|
||||
desc "Run all rspecs"
|
||||
RSpec::Core::RakeTask.new(:spec) do |t|
|
||||
t.pattern = Dir.glob('spec/**/*_spec.rb')
|
||||
t.rspec_opts = '--format documentation'
|
||||
# t.rspec_opts << ' more options'
|
||||
end
|
||||
|
||||
desc "Run integration test on example"
|
||||
task :integration_test do
|
||||
chdir("./examples/fff_example") do
|
||||
sh "rake clobber"
|
||||
sh "rake test:all"
|
||||
end
|
||||
end
|
||||
|
||||
task :default => [:spec, :integration_test]
|
||||
71
test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/project.yml
vendored
Normal file
71
test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/project.yml
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
---
|
||||
|
||||
# Notes:
|
||||
# Sample project C code is not presently written to produce a release artifact.
|
||||
# As such, release build options are disabled.
|
||||
# This sample, therefore, only demonstrates running a collection of unit tests.
|
||||
|
||||
:project:
|
||||
:use_exceptions: FALSE
|
||||
:use_test_preprocessor: TRUE
|
||||
:use_auxiliary_dependencies: TRUE
|
||||
:build_root: build
|
||||
# :release_build: TRUE
|
||||
:test_file_prefix: test_
|
||||
|
||||
#:release_build:
|
||||
# :output: MyApp.out
|
||||
# :use_assembly: FALSE
|
||||
|
||||
:environment:
|
||||
|
||||
:extension:
|
||||
:executable: .out
|
||||
|
||||
:paths:
|
||||
:test:
|
||||
- +:test/**
|
||||
:source:
|
||||
- src/**
|
||||
:support:
|
||||
|
||||
:defines:
|
||||
# in order to add common defines:
|
||||
# 1) remove the trailing [] from the :common: section
|
||||
# 2) add entries to the :common: section (e.g. :test: has TEST defined)
|
||||
:commmon: &common_defines []
|
||||
:test:
|
||||
- *common_defines
|
||||
- TEST
|
||||
:test_preprocess:
|
||||
- *common_defines
|
||||
- TEST
|
||||
|
||||
:cmock:
|
||||
:mock_prefix: mock_
|
||||
:when_no_prototypes: :warn
|
||||
:enforce_strict_ordering: TRUE
|
||||
:plugins:
|
||||
- :ignore
|
||||
- :callback
|
||||
:treat_as:
|
||||
uint8: HEX8
|
||||
uint16: HEX16
|
||||
uint32: UINT32
|
||||
int8: INT8
|
||||
bool: UINT8
|
||||
|
||||
#:tools:
|
||||
# Ceedling defaults to using gcc for compiling, linking, etc.
|
||||
# As [:tools] is blank, gcc will be used (so long as it's in your system path)
|
||||
# See documentation to configure a given toolchain for use
|
||||
|
||||
:plugins:
|
||||
:load_paths:
|
||||
# This change from the default is for running Ceedling out of another folder.
|
||||
- ../../../../plugins
|
||||
:enabled:
|
||||
- stdout_pretty_tests_report
|
||||
- module_generator
|
||||
- fake_function_framework
|
||||
...
|
||||
7
test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/rakefile.rb
vendored
Normal file
7
test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/rakefile.rb
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
# This change from the default is for running Ceedling out of another folder.
|
||||
PROJECT_CEEDLING_ROOT = "../../../.."
|
||||
load "#{PROJECT_CEEDLING_ROOT}/lib/ceedling.rb"
|
||||
|
||||
Ceedling.load_project
|
||||
|
||||
task :default => %w[ test:all release ]
|
||||
1
test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/bar.c
vendored
Normal file
1
test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/bar.c
vendored
Normal file
@@ -0,0 +1 @@
|
||||
#include "bar.h"
|
||||
14
test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/bar.h
vendored
Normal file
14
test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/bar.h
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
#ifndef bar_H
|
||||
#define bar_H
|
||||
|
||||
#include "custom_types.h"
|
||||
|
||||
void bar_turn_on(void);
|
||||
void bar_print_message(const char * message);
|
||||
void bar_print_message_formatted(const char * format, ...);
|
||||
void bar_numbers(int one, int two, char three);
|
||||
void bar_const_test(const char * a, char * const b, const int c);
|
||||
custom_t bar_needs_custom_type(void);
|
||||
const char * bar_return_const_ptr(int one);
|
||||
|
||||
#endif // bar_H
|
||||
6
test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/custom_types.h
vendored
Normal file
6
test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/custom_types.h
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef custom_types_H
|
||||
#define custom_types_H
|
||||
|
||||
typedef int custom_t;
|
||||
|
||||
#endif
|
||||
7
test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/display.c
vendored
Normal file
7
test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/display.c
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
#include <stdio.h>
|
||||
#include "display.h"
|
||||
|
||||
void display_turnOffStatusLed(void)
|
||||
{
|
||||
printf("Display: Status LED off");
|
||||
}
|
||||
16
test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/display.h
vendored
Normal file
16
test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/display.h
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
#include <stdbool.h>
|
||||
|
||||
void display_turnOffStatusLed(void);
|
||||
void display_turnOnStatusLed(void);
|
||||
void display_setVolume(int level);
|
||||
void display_setModeToMinimum(void);
|
||||
void display_setModeToMaximum(void);
|
||||
void display_setModeToAverage(void);
|
||||
bool display_isError(void);
|
||||
void display_powerDown(void);
|
||||
void display_updateData(int data, void(*updateCompleteCallback)(void));
|
||||
|
||||
/*
|
||||
The entry is returned (up to `length` bytes) in the provided `entry` buffer.
|
||||
*/
|
||||
void display_getKeyboardEntry(char * entry, int length);
|
||||
93
test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/event_processor.c
vendored
Normal file
93
test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/event_processor.c
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
This module implements some business logic to test.
|
||||
|
||||
Signal events by calling the functions on the module.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "event_processor.h"
|
||||
#include "display.h"
|
||||
|
||||
void event_deviceReset(void)
|
||||
{
|
||||
//printf ("Device reset\n");
|
||||
display_turnOffStatusLed();
|
||||
}
|
||||
|
||||
void event_volumeKnobMaxed(void)
|
||||
{
|
||||
display_setVolume(11);
|
||||
}
|
||||
|
||||
void event_powerReadingUpdate(int powerReading)
|
||||
{
|
||||
if (powerReading >= 5)
|
||||
{
|
||||
display_turnOnStatusLed();
|
||||
}
|
||||
}
|
||||
|
||||
void event_modeSelectButtonPressed(void)
|
||||
{
|
||||
static int mode = 0;
|
||||
|
||||
if (mode == 0)
|
||||
{
|
||||
display_setModeToMinimum();
|
||||
mode++;
|
||||
}
|
||||
else if (mode == 1)
|
||||
{
|
||||
display_setModeToMaximum();
|
||||
mode++;
|
||||
}
|
||||
else if (mode == 2)
|
||||
{
|
||||
display_setModeToAverage();
|
||||
mode++;
|
||||
}
|
||||
else
|
||||
{
|
||||
mode = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void event_devicePoweredOn(void)
|
||||
{
|
||||
if (display_isError())
|
||||
{
|
||||
display_powerDown();
|
||||
}
|
||||
}
|
||||
|
||||
void event_keyboardCheckTimerExpired(void)
|
||||
{
|
||||
char userEntry[100];
|
||||
|
||||
display_getKeyboardEntry(userEntry, 100);
|
||||
|
||||
if (strcmp(userEntry, "sleep") == 0)
|
||||
{
|
||||
display_powerDown();
|
||||
}
|
||||
}
|
||||
|
||||
static bool event_lastComplete = false;
|
||||
|
||||
/* Function called when the display update is complete. */
|
||||
static void displayUpdateComplete(void)
|
||||
{
|
||||
event_lastComplete = true;
|
||||
}
|
||||
|
||||
void event_newDataAvailable(int data)
|
||||
{
|
||||
event_lastComplete = false;
|
||||
display_updateData(data, displayUpdateComplete);
|
||||
}
|
||||
|
||||
bool eventProcessor_isLastEventComplete(void)
|
||||
{
|
||||
return event_lastComplete;
|
||||
}
|
||||
11
test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/event_processor.h
vendored
Normal file
11
test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/event_processor.h
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
#include <stdbool.h>
|
||||
|
||||
void event_deviceReset(void);
|
||||
void event_volumeKnobMaxed(void);
|
||||
void event_powerReadingUpdate(int powerReading);
|
||||
void event_modeSelectButtonPressed(void);
|
||||
void event_devicePoweredOn(void);
|
||||
void event_keyboardCheckTimerExpired(void);
|
||||
void event_newDataAvailable(int data);
|
||||
|
||||
bool eventProcessor_isLastEventComplete(void);
|
||||
16
test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/foo.c
vendored
Normal file
16
test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/foo.c
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
#include "foo.h"
|
||||
#include "bar.h"
|
||||
#include "subfolder/zzz.h"
|
||||
|
||||
void foo_turn_on(void) {
|
||||
bar_turn_on();
|
||||
zzz_sleep(1, "sleepy");
|
||||
}
|
||||
|
||||
void foo_print_message(const char * message) {
|
||||
bar_print_message(message);
|
||||
}
|
||||
|
||||
void foo_print_special_message(void) {
|
||||
bar_print_message_formatted("The numbers are %d, %d and %d", 1, 2, 3);
|
||||
}
|
||||
8
test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/foo.h
vendored
Normal file
8
test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/foo.h
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef foo_H
|
||||
#define foo_H
|
||||
|
||||
void foo_turn_on(void);
|
||||
void foo_print_message(const char * message);
|
||||
void foo_print_special_message(void);
|
||||
|
||||
#endif // foo_H
|
||||
@@ -0,0 +1 @@
|
||||
#include "zzz.h"
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef zzz_H
|
||||
#define zzz_H
|
||||
|
||||
int zzz_sleep(int time, char * name);
|
||||
|
||||
#endif // zzz_H
|
||||
@@ -0,0 +1,155 @@
|
||||
#include "unity.h"
|
||||
#include "event_processor.h"
|
||||
#include "mock_display.h"
|
||||
#include <string.h>
|
||||
|
||||
void setUp (void)
|
||||
{
|
||||
}
|
||||
|
||||
void tearDown (void)
|
||||
{
|
||||
}
|
||||
/*
|
||||
Test that a single function was called.
|
||||
*/
|
||||
void
|
||||
test_whenTheDeviceIsReset_thenTheStatusLedIsTurnedOff()
|
||||
{
|
||||
// When
|
||||
event_deviceReset();
|
||||
|
||||
// Then
|
||||
TEST_ASSERT_EQUAL(1, display_turnOffStatusLed_fake.call_count);
|
||||
// or use the helper macro...
|
||||
TEST_ASSERT_CALLED(display_turnOffStatusLed);
|
||||
}
|
||||
|
||||
/*
|
||||
Test that a single function is NOT called.
|
||||
*/
|
||||
void
|
||||
test_whenThePowerReadingIsLessThan5_thenTheStatusLedIsNotTurnedOn(void)
|
||||
{
|
||||
// When
|
||||
event_powerReadingUpdate(4);
|
||||
|
||||
// Then
|
||||
TEST_ASSERT_EQUAL(0, display_turnOnStatusLed_fake.call_count);
|
||||
// or use the helper macro...
|
||||
TEST_ASSERT_NOT_CALLED(display_turnOffStatusLed);
|
||||
}
|
||||
|
||||
/*
|
||||
Test that a single function was called with the correct arugment.
|
||||
*/
|
||||
void
|
||||
test_whenTheVolumeKnobIsMaxed_thenVolumeDisplayIsSetTo11(void)
|
||||
{
|
||||
// When
|
||||
event_volumeKnobMaxed();
|
||||
|
||||
// Then
|
||||
TEST_ASSERT_EQUAL(1, display_setVolume_fake.call_count);
|
||||
// or use the helper macro...
|
||||
TEST_ASSERT_CALLED(display_setVolume);
|
||||
TEST_ASSERT_EQUAL(11, display_setVolume_fake.arg0_val);
|
||||
}
|
||||
|
||||
/*
|
||||
Test a sequence of calls.
|
||||
*/
|
||||
|
||||
void
|
||||
test_whenTheModeSelectButtonIsPressed_thenTheDisplayModeIsCycled(void)
|
||||
{
|
||||
// When
|
||||
event_modeSelectButtonPressed();
|
||||
event_modeSelectButtonPressed();
|
||||
event_modeSelectButtonPressed();
|
||||
|
||||
// Then
|
||||
TEST_ASSERT_EQUAL_PTR((void *)display_setModeToMinimum, fff.call_history[0]);
|
||||
TEST_ASSERT_EQUAL_PTR((void *)display_setModeToMaximum, fff.call_history[1]);
|
||||
TEST_ASSERT_EQUAL_PTR((void *)display_setModeToAverage, fff.call_history[2]);
|
||||
// or use the helper macros...
|
||||
TEST_ASSERT_CALLED_IN_ORDER(0, display_setModeToMinimum);
|
||||
TEST_ASSERT_CALLED_IN_ORDER(1, display_setModeToMaximum);
|
||||
TEST_ASSERT_CALLED_IN_ORDER(2, display_setModeToAverage);
|
||||
}
|
||||
|
||||
/*
|
||||
Mock a return value from a function.
|
||||
*/
|
||||
void
|
||||
test_givenTheDisplayHasAnError_whenTheDeviceIsPoweredOn_thenTheDisplayIsPoweredDown(void)
|
||||
{
|
||||
// Given
|
||||
display_isError_fake.return_val = true;
|
||||
|
||||
// When
|
||||
event_devicePoweredOn();
|
||||
|
||||
// Then
|
||||
TEST_ASSERT_EQUAL(1, display_powerDown_fake.call_count);
|
||||
// or use the helper macro...
|
||||
TEST_ASSERT_CALLED(display_powerDown);
|
||||
}
|
||||
|
||||
/*
|
||||
Mock a sequence of calls with return values.
|
||||
*/
|
||||
|
||||
/*
|
||||
Mocking a function with a value returned by reference.
|
||||
*/
|
||||
void
|
||||
test_givenTheUserHasTypedSleep_whenItIsTimeToCheckTheKeyboard_theDisplayIsPoweredDown(void)
|
||||
{
|
||||
// Given
|
||||
char mockedEntry[] = "sleep";
|
||||
void return_mock_value(char * entry, int length)
|
||||
{
|
||||
if (length > strlen(mockedEntry))
|
||||
{
|
||||
strncpy(entry, mockedEntry, length);
|
||||
}
|
||||
}
|
||||
display_getKeyboardEntry_fake.custom_fake = return_mock_value;
|
||||
|
||||
// When
|
||||
event_keyboardCheckTimerExpired();
|
||||
|
||||
// Then
|
||||
TEST_ASSERT_EQUAL(1, display_powerDown_fake.call_count);
|
||||
// or use the helper macro...
|
||||
TEST_ASSERT_CALLED(display_powerDown);
|
||||
}
|
||||
|
||||
/*
|
||||
Mock a function with a function pointer parameter.
|
||||
*/
|
||||
void
|
||||
test_givenNewDataIsAvailable_whenTheDisplayHasUpdated_thenTheEventIsComplete(void)
|
||||
{
|
||||
// A mock function for capturing the callback handler function pointer.
|
||||
void(*registeredCallback)(void) = 0;
|
||||
void mock_display_updateData(int data, void(*callback)(void))
|
||||
{
|
||||
//Save the callback function.
|
||||
registeredCallback = callback;
|
||||
}
|
||||
display_updateData_fake.custom_fake = mock_display_updateData;
|
||||
|
||||
// Given
|
||||
event_newDataAvailable(10);
|
||||
|
||||
// When
|
||||
if (registeredCallback != 0)
|
||||
{
|
||||
registeredCallback();
|
||||
}
|
||||
|
||||
// Then
|
||||
TEST_ASSERT_EQUAL(true, eventProcessor_isLastEventComplete());
|
||||
}
|
||||
47
test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/test/test_foo.c
vendored
Normal file
47
test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/test/test_foo.c
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
#include "unity.h"
|
||||
#include "foo.h"
|
||||
#include "mock_bar.h"
|
||||
#include "mock_zzz.h"
|
||||
|
||||
void setUp(void)
|
||||
{
|
||||
}
|
||||
|
||||
void tearDown(void)
|
||||
{
|
||||
}
|
||||
|
||||
void test_foo(void)
|
||||
{
|
||||
//When
|
||||
foo_turn_on();
|
||||
|
||||
//Then
|
||||
TEST_ASSERT_EQUAL(1, bar_turn_on_fake.call_count);
|
||||
TEST_ASSERT_EQUAL(1, zzz_sleep_fake.call_count);
|
||||
TEST_ASSERT_EQUAL_STRING("sleepy", zzz_sleep_fake.arg1_val);
|
||||
}
|
||||
|
||||
void test_foo_again(void)
|
||||
{
|
||||
//When
|
||||
foo_turn_on();
|
||||
|
||||
//Then
|
||||
TEST_ASSERT_EQUAL(1, bar_turn_on_fake.call_count);
|
||||
}
|
||||
|
||||
void test_foo_mock_with_const(void)
|
||||
{
|
||||
foo_print_message("123");
|
||||
|
||||
TEST_ASSERT_EQUAL(1, bar_print_message_fake.call_count);
|
||||
TEST_ASSERT_EQUAL_STRING("123", bar_print_message_fake.arg0_val);
|
||||
}
|
||||
|
||||
void test_foo_mock_with_variable_args(void)
|
||||
{
|
||||
foo_print_special_message();
|
||||
TEST_ASSERT_EQUAL(1, bar_print_message_formatted_fake.call_count);
|
||||
TEST_ASSERT_EQUAL_STRING("The numbers are %d, %d and %d", bar_print_message_formatted_fake.arg0_val);
|
||||
}
|
||||
87
test/vendor/ceedling/plugins/fake_function_framework/lib/fake_function_framework.rb
vendored
Normal file
87
test/vendor/ceedling/plugins/fake_function_framework/lib/fake_function_framework.rb
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
require 'ceedling/plugin'
|
||||
require 'fff_mock_generator'
|
||||
|
||||
class FakeFunctionFramework < Plugin
|
||||
|
||||
# Set up Ceedling to use this plugin.
|
||||
def setup
|
||||
# Get the location of this plugin.
|
||||
@plugin_root = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
||||
puts "Using fake function framework (fff)..."
|
||||
|
||||
# Switch out the cmock_builder with our own.
|
||||
@ceedling[:cmock_builder].cmock = FffMockGeneratorForCMock.new(@ceedling[:setupinator].config_hash[:cmock])
|
||||
|
||||
# Add the path to fff.h to the include paths.
|
||||
COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR << "#{@plugin_root}/vendor/fff"
|
||||
COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR << "#{@plugin_root}/src"
|
||||
end
|
||||
|
||||
def post_runner_generate(arg_hash)
|
||||
# After the test runner file has been created, append the FFF globals
|
||||
# definition to the end of the test runner. These globals will be shared by
|
||||
# all mocks linked into the test.
|
||||
File.open(arg_hash[:runner_file], 'a') do |f|
|
||||
f.puts
|
||||
f.puts "//=======Defintions of FFF variables====="
|
||||
f.puts %{#include "fff.h"}
|
||||
f.puts "DEFINE_FFF_GLOBALS;"
|
||||
end
|
||||
end
|
||||
|
||||
end # class FakeFunctionFramework
|
||||
|
||||
class FffMockGeneratorForCMock
|
||||
|
||||
def initialize(options=nil)
|
||||
@cm_config = CMockConfig.new(options)
|
||||
@cm_parser = CMockHeaderParser.new(@cm_config)
|
||||
@silent = (@cm_config.verbosity < 2)
|
||||
|
||||
# These are the additional files to include in the mock files.
|
||||
@includes_h_pre_orig_header = (@cm_config.includes || @cm_config.includes_h_pre_orig_header || []).map{|h| h =~ /</ ? h : "\"#{h}\""}
|
||||
@includes_h_post_orig_header = (@cm_config.includes_h_post_orig_header || []).map{|h| h =~ /</ ? h : "\"#{h}\""}
|
||||
@includes_c_pre_header = (@cm_config.includes_c_pre_header || []).map{|h| h =~ /</ ? h : "\"#{h}\""}
|
||||
@includes_c_post_header = (@cm_config.includes_c_post_header || []).map{|h| h =~ /</ ? h : "\"#{h}\""}
|
||||
end
|
||||
|
||||
def setup_mocks(files)
|
||||
[files].flatten.each do |src|
|
||||
generate_mock (src)
|
||||
end
|
||||
end
|
||||
|
||||
def generate_mock (header_file_to_mock)
|
||||
module_name = File.basename(header_file_to_mock, '.h')
|
||||
puts "Creating mock for #{module_name}..." unless @silent
|
||||
mock_name = @cm_config.mock_prefix + module_name + @cm_config.mock_suffix
|
||||
mock_path = @cm_config.mock_path
|
||||
if @cm_config.subdir
|
||||
# If a subdirectory has been configured, append it to the mock path.
|
||||
mock_path = "#{mock_path}/#{@cm_config.subdir}"
|
||||
end
|
||||
full_path_for_mock = "#{mock_path}/#{mock_name}"
|
||||
|
||||
# Parse the header file so we know what to mock.
|
||||
parsed_header = @cm_parser.parse(module_name, File.read(header_file_to_mock))
|
||||
|
||||
# Create the directory if it doesn't exist.
|
||||
mkdir_p full_path_for_mock.pathmap("%d")
|
||||
|
||||
# Generate the mock header file.
|
||||
puts "Creating mock: #{full_path_for_mock}.h"
|
||||
|
||||
# Create the mock header.
|
||||
File.open("#{full_path_for_mock}.h", 'w') do |f|
|
||||
f.write(FffMockGenerator.create_mock_header(module_name, mock_name, parsed_header,
|
||||
@includes_h_pre_orig_header, @includes_h_post_orig_header))
|
||||
end
|
||||
|
||||
# Create the mock source file.
|
||||
File.open("#{full_path_for_mock}.c", 'w') do |f|
|
||||
f.write(FffMockGenerator.create_mock_source(mock_name, parsed_header,
|
||||
@includes_c_pre_orig_header, @includes_c_post_orig_header))
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
163
test/vendor/ceedling/plugins/fake_function_framework/lib/fff_mock_generator.rb
vendored
Normal file
163
test/vendor/ceedling/plugins/fake_function_framework/lib/fff_mock_generator.rb
vendored
Normal file
@@ -0,0 +1,163 @@
|
||||
# Creates mock files from parsed header files that can be linked into applications.
|
||||
# The mocks created are compatible with CMock for use with Ceedling.
|
||||
|
||||
class FffMockGenerator
|
||||
|
||||
def self.create_mock_header(module_name, mock_name, parsed_header, pre_includes=nil,
|
||||
post_includes=nil)
|
||||
output = StringIO.new
|
||||
write_opening_include_guard(mock_name, output)
|
||||
output.puts
|
||||
write_extra_includes(pre_includes, output)
|
||||
write_header_includes(module_name, output)
|
||||
write_extra_includes(post_includes, output)
|
||||
output.puts
|
||||
write_typedefs(parsed_header, output)
|
||||
output.puts
|
||||
write_function_declarations(parsed_header, output)
|
||||
output.puts
|
||||
write_control_function_prototypes(mock_name, output)
|
||||
output.puts
|
||||
write_closing_include_guard(mock_name, output)
|
||||
output.string
|
||||
end
|
||||
|
||||
def self.create_mock_source (mock_name, parsed_header, pre_includes=nil,
|
||||
post_includes=nil)
|
||||
output = StringIO.new
|
||||
write_extra_includes(pre_includes, output)
|
||||
write_source_includes(mock_name, output)
|
||||
write_extra_includes(post_includes, output)
|
||||
output.puts
|
||||
write_function_definitions(parsed_header, output)
|
||||
output.puts
|
||||
write_control_function_definitions(mock_name, parsed_header, output)
|
||||
output.string
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Header file generation functions.
|
||||
|
||||
def self.write_opening_include_guard(mock_name, output)
|
||||
output.puts "#ifndef #{mock_name}_H"
|
||||
output.puts "#define #{mock_name}_H"
|
||||
end
|
||||
|
||||
def self.write_header_includes(module_name, output)
|
||||
output.puts %{#include "fff.h"}
|
||||
output.puts %{#include "fff_unity_helper.h"}
|
||||
output.puts %{#include "#{module_name}.h"}
|
||||
end
|
||||
|
||||
def self.write_typedefs(parsed_header, output)
|
||||
return unless parsed_header.key?(:typedefs)
|
||||
parsed_header[:typedefs].each do |typedef|
|
||||
output.puts typedef
|
||||
end
|
||||
end
|
||||
|
||||
def self.write_function_declarations(parsed_header, output)
|
||||
write_function_macros("DECLARE", parsed_header, output)
|
||||
end
|
||||
|
||||
|
||||
def self.write_control_function_prototypes(mock_name, output)
|
||||
output.puts "void #{mock_name}_Init(void);"
|
||||
output.puts "void #{mock_name}_Verify(void);"
|
||||
output.puts "void #{mock_name}_Destroy(void);"
|
||||
end
|
||||
|
||||
def self.write_closing_include_guard(mock_name, output)
|
||||
output.puts "#endif // #{mock_name}_H"
|
||||
end
|
||||
|
||||
# Source file generation functions.
|
||||
|
||||
def self.write_source_includes (mock_name, output)
|
||||
output.puts "#include <string.h>"
|
||||
output.puts %{#include "fff.h"}
|
||||
output.puts %{#include "#{mock_name}.h"}
|
||||
end
|
||||
|
||||
def self.write_function_definitions(parsed_header, output)
|
||||
write_function_macros("DEFINE", parsed_header, output)
|
||||
end
|
||||
|
||||
def self.write_control_function_definitions(mock_name, parsed_header, output)
|
||||
output.puts "void #{mock_name}_Init(void)"
|
||||
output.puts "{"
|
||||
# In the init function, reset the FFF globals. These are used for things
|
||||
# like the call history.
|
||||
output.puts " FFF_RESET_HISTORY();"
|
||||
|
||||
# Also, reset all of the fakes.
|
||||
if parsed_header[:functions]
|
||||
parsed_header[:functions].each do |function|
|
||||
output.puts " RESET_FAKE(#{function[:name]})"
|
||||
end
|
||||
end
|
||||
output.puts "}"
|
||||
output.puts "void #{mock_name}_Verify(void)"
|
||||
output.puts "{"
|
||||
output.puts "}"
|
||||
output.puts "void #{mock_name}_Destroy(void)"
|
||||
output.puts "{"
|
||||
output.puts "}"
|
||||
end
|
||||
|
||||
# Shared functions.
|
||||
|
||||
def self.write_extra_includes(includes, output)
|
||||
if includes
|
||||
includes.each {|inc| output.puts "#include #{inc}\n"}
|
||||
end
|
||||
end
|
||||
|
||||
def self.write_function_macros(macro_type, parsed_header, output)
|
||||
return unless parsed_header.key?(:functions)
|
||||
parsed_header[:functions].each do |function|
|
||||
name = function[:name]
|
||||
return_type = function[:return][:type]
|
||||
if function.has_key? :modifier
|
||||
# Prepend any modifier. If there isn't one, trim any leading whitespace.
|
||||
return_type = "#{function[:modifier]} #{return_type}".lstrip
|
||||
end
|
||||
arg_count = function[:args].size
|
||||
|
||||
# Check for variable arguments.
|
||||
var_arg_suffix = ""
|
||||
if function[:var_arg]
|
||||
# If there are are variable arguments, then we need to add this argument
|
||||
# to the count, update the suffix that will get added to the macro.
|
||||
arg_count += 1
|
||||
var_arg_suffix = "_VARARG"
|
||||
end
|
||||
|
||||
# Generate the correct macro.
|
||||
if return_type == 'void'
|
||||
output.print "#{macro_type}_FAKE_VOID_FUNC#{arg_count}#{var_arg_suffix}(#{name}"
|
||||
else
|
||||
output.print "#{macro_type}_FAKE_VALUE_FUNC#{arg_count}#{var_arg_suffix}(#{return_type}, #{name}"
|
||||
end
|
||||
|
||||
# Append each argument type.
|
||||
function[:args].each do |arg|
|
||||
output.print ", "
|
||||
if arg[:const?]
|
||||
output.print "const "
|
||||
end
|
||||
output.print "#{arg[:type]}"
|
||||
end
|
||||
|
||||
# If this argument list ends with a variable argument, add it here at the end.
|
||||
if function[:var_arg]
|
||||
output.print ", ..."
|
||||
end
|
||||
|
||||
# Close the declaration.
|
||||
output.puts ");"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
304
test/vendor/ceedling/plugins/fake_function_framework/spec/fff_mock_header_generator_spec.rb
vendored
Normal file
304
test/vendor/ceedling/plugins/fake_function_framework/spec/fff_mock_header_generator_spec.rb
vendored
Normal file
@@ -0,0 +1,304 @@
|
||||
require 'stringio'
|
||||
require 'fff_mock_generator.rb'
|
||||
require 'header_generator.rb'
|
||||
|
||||
# Test the contents of the .h file created for the mock.
|
||||
describe "FffMockGenerator.create_mock_header" do
|
||||
|
||||
context "when there is nothing to mock," do
|
||||
let(:mock_header) {
|
||||
parsed_header = {}
|
||||
FffMockGenerator.create_mock_header("display", "mock_display", parsed_header)
|
||||
}
|
||||
it "then the generated header file starts with an opening include guard" do
|
||||
expect(mock_header).to start_with(
|
||||
"#ifndef mock_display_H\n" +
|
||||
"#define mock_display_H")
|
||||
end
|
||||
it "then the generated file ends with a closing include guard" do
|
||||
expect(mock_header).to end_with(
|
||||
"#endif // mock_display_H\n")
|
||||
end
|
||||
it "then the generated file includes the fff header" do
|
||||
expect(mock_header).to include(
|
||||
%{#include "fff.h"\n})
|
||||
end
|
||||
it "then the generated file has a prototype for the init function" do
|
||||
expect(mock_header).to include(
|
||||
"void mock_display_Init(void);")
|
||||
end
|
||||
it "then the generated file has a prototype for the verify function" do
|
||||
expect(mock_header).to include(
|
||||
"void mock_display_Verify(void);")
|
||||
end
|
||||
it "then the generated file has a prototype for the destroy function" do
|
||||
expect(mock_header).to include(
|
||||
"void mock_display_Destroy(void);")
|
||||
end
|
||||
end
|
||||
|
||||
context "when there is a function with no args and a void return," do
|
||||
let(:mock_header) {
|
||||
parsed_header = create_cmock_style_parsed_header(
|
||||
[{:name => 'display_turnOffStatusLed', :return_type => 'void'}])
|
||||
FffMockGenerator.create_mock_header("display", "mock_display", parsed_header)
|
||||
}
|
||||
it "then the generated header file starts with an opening include guard" do
|
||||
expect(mock_header).to start_with(
|
||||
"#ifndef mock_display_H\n" +
|
||||
"#define mock_display_H")
|
||||
end
|
||||
it "then the generated header file contains a fake function declaration" do
|
||||
expect(mock_header).to include(
|
||||
"DECLARE_FAKE_VOID_FUNC0(display_turnOffStatusLed);"
|
||||
)
|
||||
end
|
||||
it "then the generated file ends with a closing include guard" do
|
||||
expect(mock_header).to end_with(
|
||||
"#endif // mock_display_H\n")
|
||||
end
|
||||
end
|
||||
|
||||
context "when there is a function with no args and a bool return," do
|
||||
let(:mock_header) {
|
||||
parsed_header = create_cmock_style_parsed_header(
|
||||
[{:name => 'display_isError', :return_type => 'bool'}])
|
||||
FffMockGenerator.create_mock_header("display", "mock_display", parsed_header)
|
||||
}
|
||||
it "then the generated file contains the fake function declaration" do
|
||||
expect(mock_header).to include(
|
||||
"DECLARE_FAKE_VALUE_FUNC0(bool, display_isError);"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context "when there is a function with no args and an int return," do
|
||||
let(:mock_header) {
|
||||
parsed_header = create_cmock_style_parsed_header(
|
||||
[{:name => 'display_isError', :return_type => 'int'}])
|
||||
FffMockGenerator.create_mock_header("display", "mock_display", parsed_header)
|
||||
}
|
||||
it "then the generated file contains the fake function declaration" do
|
||||
expect(mock_header).to include(
|
||||
"DECLARE_FAKE_VALUE_FUNC0(int, display_isError);"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context "when there is a function with args and a void return," do
|
||||
let(:mock_header) {
|
||||
parsed_header = create_cmock_style_parsed_header(
|
||||
[{:name => 'display_setVolume', :return_type => 'void', :args => ['int']}])
|
||||
FffMockGenerator.create_mock_header("display", "mock_display", parsed_header)
|
||||
}
|
||||
it "then the generated file contains the fake function declaration" do
|
||||
expect(mock_header).to include(
|
||||
"DECLARE_FAKE_VOID_FUNC1(display_setVolume, int);"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context "when there is a function with args and a value return," do
|
||||
let(:mock_header) {
|
||||
parsed_header = create_cmock_style_parsed_header(
|
||||
[{:name => 'a_function', :return_type => 'int', :args => ['char *']}])
|
||||
FffMockGenerator.create_mock_header("display", "mock_display", parsed_header)
|
||||
}
|
||||
it "then the generated file contains the fake function declaration" do
|
||||
expect(mock_header).to include(
|
||||
"FAKE_VALUE_FUNC1(int, a_function, char *);"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context "when there is a function with many args and a void return," do
|
||||
let(:mock_header) {
|
||||
parsed_header = create_cmock_style_parsed_header(
|
||||
[{:name => 'a_function', :return_type => 'void',
|
||||
:args => ['int', 'char *', 'int', 'int', 'bool', 'applesauce']}])
|
||||
FffMockGenerator.create_mock_header("display", "mock_display", parsed_header)
|
||||
}
|
||||
it "then the generated file contains the fake function declaration" do
|
||||
expect(mock_header).to include(
|
||||
"DECLARE_FAKE_VOID_FUNC6(a_function, int, char *, int, int, bool, applesauce);"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context "when there are multiple functions," do
|
||||
let(:mock_header) {
|
||||
parsed_header = create_cmock_style_parsed_header(
|
||||
[ {:name => 'a_function', :return_type => 'int', :args => ['char *']},
|
||||
{:name => 'another_function', :return_type => 'void'},
|
||||
{:name => 'three', :return_type => 'bool', :args => ['float', 'int']}
|
||||
])
|
||||
FffMockGenerator.create_mock_header("display", "mock_display", parsed_header)
|
||||
}
|
||||
it "then the generated file contains the first fake function declaration" do
|
||||
expect(mock_header).to include(
|
||||
"DECLARE_FAKE_VALUE_FUNC1(int, a_function, char *);"
|
||||
)
|
||||
end
|
||||
it "then the generated file contains the second fake function declaration" do
|
||||
expect(mock_header).to include(
|
||||
"DECLARE_FAKE_VOID_FUNC0(another_function);"
|
||||
)
|
||||
end
|
||||
it "then the generated file contains the third fake function declaration" do
|
||||
expect(mock_header).to include(
|
||||
"DECLARE_FAKE_VALUE_FUNC2(bool, three, float, int);"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context "when there is a typedef," do
|
||||
let(:mock_header) {
|
||||
parsed_header = create_cmock_style_parsed_header(
|
||||
nil, ["typedef void (*displayCompleteCallback) (void);"])
|
||||
FffMockGenerator.create_mock_header("display", "mock_display", parsed_header)
|
||||
}
|
||||
it "then the generated file contains the typedef" do
|
||||
expect(mock_header).to include(
|
||||
"typedef void (*displayCompleteCallback) (void);"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context "when there is a void function with variable arguments" do
|
||||
let(:mock_header){
|
||||
parsed_header = {}
|
||||
parsed_header[:functions] = [{
|
||||
:name => "function_with_var_args",
|
||||
:return => {:type => "void"},
|
||||
:var_arg => "...",
|
||||
:args => [{:type => 'char *'}]
|
||||
}]
|
||||
FffMockGenerator.create_mock_header("display", "mock_display", parsed_header)
|
||||
}
|
||||
it "then the generated file contains the vararg declaration" do
|
||||
expect(mock_header).to include(
|
||||
"DECLARE_FAKE_VOID_FUNC2_VARARG(function_with_var_args, char *, ...)"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context "when there is a function with a return value and variable arguments" do
|
||||
let(:mock_header){
|
||||
parsed_header = {}
|
||||
parsed_header[:functions] = [{
|
||||
:name => "function_with_var_args",
|
||||
:return => {:type => "int"},
|
||||
:var_arg => "...",
|
||||
:args => [{:type => 'char *'}]
|
||||
}]
|
||||
FffMockGenerator.create_mock_header("display", "mock_display", parsed_header)
|
||||
}
|
||||
it "then the generated file contains the vararg declaration" do
|
||||
expect(mock_header).to include(
|
||||
"DECLARE_FAKE_VALUE_FUNC2_VARARG(int, function_with_var_args, char *, ...)"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context "when there is a void function with variable arguments and " +
|
||||
"additional arguments" do
|
||||
let(:mock_header){
|
||||
parsed_header = {}
|
||||
parsed_header[:functions] = [{
|
||||
:name => "function_with_var_args",
|
||||
:return => {:type => "void"},
|
||||
:var_arg => "...",
|
||||
:args => [{:type => 'char *'}, {:type => 'int'}]
|
||||
}]
|
||||
FffMockGenerator.create_mock_header("display", "mock_display", parsed_header)
|
||||
}
|
||||
it "then the generated file contains the vararg declaration" do
|
||||
expect(mock_header).to include(
|
||||
"DECLARE_FAKE_VOID_FUNC3_VARARG(function_with_var_args, char *, int, ...)"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context "when there is a function with a pointer to a const value" do
|
||||
let(:mock_header){
|
||||
parsed_header = {}
|
||||
parsed_header[:functions] = [{
|
||||
:name => "const_test_function",
|
||||
:return => {:type => "void"},
|
||||
:args => [{:type => "char *", :name => "a", :ptr? => false, :const? => true},
|
||||
{:type => "char *", :name => "b", :ptr? => false, :const? => false}]
|
||||
}]
|
||||
FffMockGenerator.create_mock_header("display", "mock_display", parsed_header)
|
||||
}
|
||||
it "then the generated file contains the correct const argument in the declaration" do
|
||||
expect(mock_header).to include(
|
||||
"DECLARE_FAKE_VOID_FUNC2(const_test_function, const char *, char *)"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context "when there is a function that returns a const pointer" do
|
||||
let(:mock_header){
|
||||
parsed_header = {}
|
||||
parsed_header[:functions] = [{
|
||||
:name => "return_const_pointer_test_function",
|
||||
:modifier => "const",
|
||||
:return => {:type => "char *" },
|
||||
:args => [{:type => "int", :name => "a"}]
|
||||
}]
|
||||
FffMockGenerator.create_mock_header("display", "mock_display", parsed_header)
|
||||
}
|
||||
it "then the generated file contains the correct const return value in the declaration" do
|
||||
expect(mock_header).to include(
|
||||
"DECLARE_FAKE_VALUE_FUNC1(const char *, return_const_pointer_test_function, int)"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context "when there is a function that returns a const int" do
|
||||
let(:mock_header){
|
||||
parsed_header = {}
|
||||
parsed_header[:functions] = [{
|
||||
:name => "return_const_int_test_function",
|
||||
:modifier => "const",
|
||||
:return => {:type => "int" },
|
||||
:args => []
|
||||
}]
|
||||
FffMockGenerator.create_mock_header("display", "mock_display", parsed_header)
|
||||
}
|
||||
it "then the generated file contains the correct const return value in the declaration" do
|
||||
expect(mock_header).to include(
|
||||
"DECLARE_FAKE_VALUE_FUNC0(const int, return_const_int_test_function)"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context "when there are pre-includes" do
|
||||
let(:mock_header) {
|
||||
parsed_header = {}
|
||||
FffMockGenerator.create_mock_header("display", "mock_display", parsed_header,
|
||||
[%{"another_header.h"}])
|
||||
}
|
||||
it "then they are included before the other files" do
|
||||
expect(mock_header).to include(
|
||||
%{#include "another_header.h"\n} +
|
||||
%{#include "fff.h"}
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context "when there are post-includes" do
|
||||
let(:mock_header) {
|
||||
parsed_header = {}
|
||||
FffMockGenerator.create_mock_header("display", "mock_display", parsed_header,
|
||||
nil, [%{"another_header.h"}])
|
||||
}
|
||||
it "then they are included after the other files" do
|
||||
expect(mock_header).to include(
|
||||
%{#include "display.h"\n} +
|
||||
%{#include "another_header.h"\n}
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
149
test/vendor/ceedling/plugins/fake_function_framework/spec/fff_mock_source_generator_spec.rb
vendored
Normal file
149
test/vendor/ceedling/plugins/fake_function_framework/spec/fff_mock_source_generator_spec.rb
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
require 'stringio'
|
||||
require 'fff_mock_generator.rb'
|
||||
|
||||
# Test the contents of the .c file created for the mock.
|
||||
describe "FffMockGenerator.create_mock_source" do
|
||||
|
||||
context "when there is nothing to mock," do
|
||||
let(:mock_source) {
|
||||
parsed_header = {}
|
||||
FffMockGenerator.create_mock_source("mock_my_module", parsed_header)
|
||||
}
|
||||
it "then the generated file includes the fff header" do
|
||||
expect(mock_source).to include(
|
||||
# fff.h also requires including string.h
|
||||
%{#include <string.h>\n} +
|
||||
%{#include "fff.h"}
|
||||
)
|
||||
end
|
||||
it "then the generated file includes the mock header" do
|
||||
expect(mock_source).to include(
|
||||
%{#include "mock_my_module.h"\n}
|
||||
)
|
||||
end
|
||||
it "then the generated file defines the init function" do
|
||||
expect(mock_source).to include(
|
||||
"void mock_my_module_Init(void)\n" +
|
||||
"{\n" +
|
||||
" FFF_RESET_HISTORY();\n" +
|
||||
"}"
|
||||
)
|
||||
end
|
||||
it "then the generated file defines the verify function" do
|
||||
expect(mock_source).to include(
|
||||
"void mock_my_module_Verify(void)\n" +
|
||||
"{\n" +
|
||||
"}"
|
||||
)
|
||||
end
|
||||
it "then the generated file defines the destroy function" do
|
||||
expect(mock_source).to include(
|
||||
"void mock_my_module_Destroy(void)\n" +
|
||||
"{\n" +
|
||||
"}"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context "when there are multiple functions," do
|
||||
let(:mock_source) {
|
||||
parsed_header = create_cmock_style_parsed_header(
|
||||
[ {:name => 'a_function', :return_type => 'int', :args => ['char *']},
|
||||
{:name => 'another_function', :return_type => 'void'},
|
||||
{:name => 'three', :return_type => 'bool', :args => ['float', 'int']}
|
||||
])
|
||||
FffMockGenerator.create_mock_source("mock_display", parsed_header)
|
||||
}
|
||||
it "then the generated file contains the first fake function definition" do
|
||||
expect(mock_source).to include(
|
||||
"DEFINE_FAKE_VALUE_FUNC1(int, a_function, char *);"
|
||||
)
|
||||
end
|
||||
it "then the generated file contains the second fake function definition" do
|
||||
expect(mock_source).to include(
|
||||
"DEFINE_FAKE_VOID_FUNC0(another_function);"
|
||||
)
|
||||
end
|
||||
it "then the generated file contains the third fake function definition" do
|
||||
expect(mock_source).to include(
|
||||
"DEFINE_FAKE_VALUE_FUNC2(bool, three, float, int);"
|
||||
)
|
||||
end
|
||||
it "then the init function resets all of the fakes" do
|
||||
expect(mock_source).to include(
|
||||
"void mock_display_Init(void)\n" +
|
||||
"{\n" +
|
||||
" FFF_RESET_HISTORY();\n" +
|
||||
" RESET_FAKE(a_function)\n" +
|
||||
" RESET_FAKE(another_function)\n" +
|
||||
" RESET_FAKE(three)\n" +
|
||||
"}"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context "when there is a void function with variable arguments and " +
|
||||
"additional arguments" do
|
||||
let(:mock_source){
|
||||
parsed_header = {}
|
||||
parsed_header[:functions] = [{
|
||||
:name => "function_with_var_args",
|
||||
:return => {:type => "void"},
|
||||
:var_arg => "...",
|
||||
:args => [{:type => 'char *'}, {:type => 'int'}]
|
||||
}]
|
||||
FffMockGenerator.create_mock_source("mock_display", parsed_header)
|
||||
}
|
||||
it "then the generated file contains the vararg definition" do
|
||||
expect(mock_source).to include(
|
||||
"DEFINE_FAKE_VOID_FUNC3_VARARG(function_with_var_args, char *, int, ...)"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context "when there is a function with a pointer to a const value" do
|
||||
let(:mock_source){
|
||||
parsed_header = {}
|
||||
parsed_header[:functions] = [{
|
||||
:name => "const_test_function",
|
||||
:return => {:type => "void"},
|
||||
:args => [{:type => "char *", :name => "a", :ptr? => false, :const? => true},
|
||||
{:type => "char *", :name => "b", :ptr? => false, :const? => false}]
|
||||
}]
|
||||
FffMockGenerator.create_mock_source("mock_display", parsed_header)
|
||||
}
|
||||
it "then the generated file contains the correct const argument in the declaration" do
|
||||
expect(mock_source).to include(
|
||||
"DEFINE_FAKE_VOID_FUNC2(const_test_function, const char *, char *)"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context "when there are pre-includes" do
|
||||
let(:mock_source) {
|
||||
parsed_source = {}
|
||||
FffMockGenerator.create_mock_source("mock_display", parsed_source,
|
||||
[%{"another_header.h"}])
|
||||
}
|
||||
it "then they are included before the other files" do
|
||||
expect(mock_source).to include(
|
||||
%{#include "another_header.h"\n} +
|
||||
%{#include <string.h>}
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context "when there are post-includes" do
|
||||
let(:mock_source) {
|
||||
parsed_source = {}
|
||||
FffMockGenerator.create_mock_source("mock_display", parsed_source,
|
||||
nil, [%{"another_header.h"}])
|
||||
}
|
||||
it "then they are included before the other files" do
|
||||
expect(mock_source).to include(
|
||||
%{#include "mock_display.h"\n} +
|
||||
%{#include "another_header.h"\n}
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
51
test/vendor/ceedling/plugins/fake_function_framework/spec/header_generator.rb
vendored
Normal file
51
test/vendor/ceedling/plugins/fake_function_framework/spec/header_generator.rb
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
# Create a CMock-style parsed header hash. This the type of hash created by
|
||||
# CMock when parsing header files for automock generation. It contains all of
|
||||
# includes, typedefs and functions (with return types and arguments) parsed from
|
||||
# the header file.
|
||||
def create_cmock_style_parsed_header(functions, typedefs = nil)
|
||||
parsed_header = {
|
||||
:includes => nil,
|
||||
:functions => [],
|
||||
:typedefs => []
|
||||
}
|
||||
|
||||
# Add the typedefs.
|
||||
if typedefs
|
||||
typedefs.each do |typedef|
|
||||
parsed_header[:typedefs] << typedef
|
||||
end
|
||||
end
|
||||
|
||||
# Add the functions.
|
||||
if functions
|
||||
functions.each do |function|
|
||||
# Build the array of arguments.
|
||||
args = []
|
||||
if function.key?(:args)
|
||||
function[:args].each do |arg|
|
||||
args << {
|
||||
:type => arg
|
||||
}
|
||||
end
|
||||
end
|
||||
parsed_header[:functions] << {
|
||||
:name => function[:name],
|
||||
:modifier => "",
|
||||
:return => {
|
||||
:type => function[:return_type],
|
||||
:name => "cmock_to_return",
|
||||
:ptr? => false,
|
||||
:const? => false,
|
||||
:str => "void cmock_to_return",
|
||||
:void? => true
|
||||
},
|
||||
:var_arg => nil,
|
||||
:args_string => "void",
|
||||
:args => args,
|
||||
:args_call => "",
|
||||
:contains_ptr? => false
|
||||
}
|
||||
end
|
||||
end
|
||||
parsed_header
|
||||
end
|
||||
96
test/vendor/ceedling/plugins/fake_function_framework/spec/spec_helper.rb
vendored
Normal file
96
test/vendor/ceedling/plugins/fake_function_framework/spec/spec_helper.rb
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
# This file was generated by the `rspec --init` command. Conventionally, all
|
||||
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
||||
# The generated `.rspec` file contains `--require spec_helper` which will cause
|
||||
# this file to always be loaded, without a need to explicitly require it in any
|
||||
# files.
|
||||
#
|
||||
# Given that it is always loaded, you are encouraged to keep this file as
|
||||
# light-weight as possible. Requiring heavyweight dependencies from this file
|
||||
# will add to the boot time of your test suite on EVERY test run, even for an
|
||||
# individual file that may not need all of that loaded. Instead, consider making
|
||||
# a separate helper file that requires the additional dependencies and performs
|
||||
# the additional setup, and require it from the spec files that actually need
|
||||
# it.
|
||||
#
|
||||
# The `.rspec` file also contains a few flags that are not defaults but that
|
||||
# users commonly want.
|
||||
#
|
||||
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
||||
RSpec.configure do |config|
|
||||
# rspec-expectations config goes here. You can use an alternate
|
||||
# assertion/expectation library such as wrong or the stdlib/minitest
|
||||
# assertions if you prefer.
|
||||
config.expect_with :rspec do |expectations|
|
||||
# This option will default to `true` in RSpec 4. It makes the `description`
|
||||
# and `failure_message` of custom matchers include text for helper methods
|
||||
# defined using `chain`, e.g.:
|
||||
# be_bigger_than(2).and_smaller_than(4).description
|
||||
# # => "be bigger than 2 and smaller than 4"
|
||||
# ...rather than:
|
||||
# # => "be bigger than 2"
|
||||
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
||||
end
|
||||
|
||||
# rspec-mocks config goes here. You can use an alternate test double
|
||||
# library (such as bogus or mocha) by changing the `mock_with` option here.
|
||||
config.mock_with :rspec do |mocks|
|
||||
# Prevents you from mocking or stubbing a method that does not exist on
|
||||
# a real object. This is generally recommended, and will default to
|
||||
# `true` in RSpec 4.
|
||||
mocks.verify_partial_doubles = true
|
||||
end
|
||||
|
||||
# The settings below are suggested to provide a good initial experience
|
||||
# with RSpec, but feel free to customize to your heart's content.
|
||||
=begin
|
||||
# These two settings work together to allow you to limit a spec run
|
||||
# to individual examples or groups you care about by tagging them with
|
||||
# `:focus` metadata. When nothing is tagged with `:focus`, all examples
|
||||
# get run.
|
||||
config.filter_run :focus
|
||||
config.run_all_when_everything_filtered = true
|
||||
|
||||
# Allows RSpec to persist some state between runs in order to support
|
||||
# the `--only-failures` and `--next-failure` CLI options. We recommend
|
||||
# you configure your source control system to ignore this file.
|
||||
config.example_status_persistence_file_path = "spec/examples.txt"
|
||||
|
||||
# Limits the available syntax to the non-monkey patched syntax that is
|
||||
# recommended. For more details, see:
|
||||
# - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
|
||||
# - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
|
||||
# - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
|
||||
config.disable_monkey_patching!
|
||||
|
||||
# This setting enables warnings. It's recommended, but in some cases may
|
||||
# be too noisy due to issues in dependencies.
|
||||
config.warnings = true
|
||||
|
||||
# Many RSpec users commonly either run the entire suite or an individual
|
||||
# file, and it's useful to allow more verbose output when running an
|
||||
# individual spec file.
|
||||
if config.files_to_run.one?
|
||||
# Use the documentation formatter for detailed output,
|
||||
# unless a formatter has already been configured
|
||||
# (e.g. via a command-line flag).
|
||||
config.default_formatter = 'doc'
|
||||
end
|
||||
|
||||
# Print the 10 slowest examples and example groups at the
|
||||
# end of the spec run, to help surface which specs are running
|
||||
# particularly slow.
|
||||
config.profile_examples = 10
|
||||
|
||||
# Run specs in random order to surface order dependencies. If you find an
|
||||
# order dependency and want to debug it, you can fix the order by providing
|
||||
# the seed, which is printed after each run.
|
||||
# --seed 1234
|
||||
config.order = :random
|
||||
|
||||
# Seed global randomization in this process using the `--seed` CLI option.
|
||||
# Setting this allows you to use `--seed` to deterministically reproduce
|
||||
# test failures related to randomization by passing the same `--seed` value
|
||||
# as the one that triggered the failure.
|
||||
Kernel.srand config.seed
|
||||
=end
|
||||
end
|
||||
33
test/vendor/ceedling/plugins/fake_function_framework/src/fff_unity_helper.h
vendored
Normal file
33
test/vendor/ceedling/plugins/fake_function_framework/src/fff_unity_helper.h
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
#ifndef fff_unity_helper_H
|
||||
#define fff_unity_helper_H
|
||||
|
||||
/*
|
||||
FFF helper macros for Unity.
|
||||
*/
|
||||
|
||||
/*
|
||||
Fail if the function was not called the expected number of times.
|
||||
*/
|
||||
#define TEST_ASSERT_CALLED_TIMES(times_, function_) \
|
||||
TEST_ASSERT_EQUAL_MESSAGE(times_, \
|
||||
function_ ## _fake.call_count, \
|
||||
"Function " #function_ " called the incorrect number of times.")
|
||||
/*
|
||||
Fail if the function was not called exactly once.
|
||||
*/
|
||||
#define TEST_ASSERT_CALLED(function_) TEST_ASSERT_CALLED_TIMES(1, function_)
|
||||
|
||||
/*
|
||||
Fail if the function was called 1 or more times.
|
||||
*/
|
||||
#define TEST_ASSERT_NOT_CALLED(function_) TEST_ASSERT_CALLED_TIMES(0, function_)
|
||||
|
||||
/*
|
||||
Fail if the function was not called in this particular order.
|
||||
*/
|
||||
#define TEST_ASSERT_CALLED_IN_ORDER(order_, function_) \
|
||||
TEST_ASSERT_EQUAL_PTR_MESSAGE((void *) function_, \
|
||||
fff.call_history[order_], \
|
||||
"Function " #function_ " not called in order " #order_ )
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user