summaryrefslogtreecommitdiffstats
path: root/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/README.md
diff options
context:
space:
mode:
Diffstat (limited to 'tinyusb/test/vendor/ceedling/plugins/fake_function_framework/README.md')
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/fake_function_framework/README.md250
1 files changed, 250 insertions, 0 deletions
diff --git a/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/README.md b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/README.md
new file mode 100755
index 00000000..8042775e
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/README.md
@@ -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.