mirror of
https://github.com/ThrowTheSwitch/CMock.git
synced 2026-07-02 10:20:32 +00:00
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 85ed528e68 | |||
| 6560abf792 | |||
| a737db33eb | |||
| 922ebfa699 | |||
| 847e87e71e | |||
| af43eb87b1 | |||
| 9a412dfccc | |||
| bf10a5bc8a | |||
| 895d066157 | |||
| 61f6f2991b | |||
| ff87d4c08a | |||
| 3d745ce8f5 | |||
| aedb21638f | |||
| 8c3a33617f | |||
| 4b523b568e | |||
| 125fcdef3c | |||
| 1724a4d0a2 | |||
| a25354f659 | |||
| ebdc8ee128 | |||
| dd922f17b0 | |||
| b01cfdc531 | |||
| 38dc454826 | |||
| 2e76508412 | |||
| a2ac5c2c63 | |||
| 3541b31c56 |
+144
-25
@@ -11,42 +11,161 @@ on:
|
|||||||
branches: [ master ]
|
branches: [ master ]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
# Job: Unit test suite
|
# Job: Ruby unit tests across all supported Ruby versions and OSes.
|
||||||
unit-tests:
|
# These are fast (no C compilation) and verify the generator logic is Ruby-version-portable.
|
||||||
name: "Unit Tests"
|
ruby-tests:
|
||||||
runs-on: ubuntu-latest
|
name: "Ruby Tests (${{ matrix.os }}, Ruby ${{ matrix.ruby }})"
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
ruby: ['3.0', '3.1', '3.2', '3.3']
|
ruby: ['3.0', '3.1', '3.2', '3.3']
|
||||||
|
exclude:
|
||||||
|
# create sparse matrix to avoid pointless duplication
|
||||||
|
- os: macos-latest
|
||||||
|
ruby: '3.0'
|
||||||
|
- os: macos-latest
|
||||||
|
ruby: '3.1'
|
||||||
|
- os: macos-latest
|
||||||
|
ruby: '3.2'
|
||||||
|
- os: windows-latest
|
||||||
|
ruby: '3.0'
|
||||||
|
- os: windows-latest
|
||||||
|
ruby: '3.1'
|
||||||
|
- os: windows-latest
|
||||||
|
ruby: '3.2'
|
||||||
steps:
|
steps:
|
||||||
# Install Multilib
|
|
||||||
- name: Install Multilib
|
|
||||||
run: |
|
|
||||||
sudo apt-get update -qq
|
|
||||||
sudo apt-get install --assume-yes --quiet gcc-multilib
|
|
||||||
|
|
||||||
# Checks out repository under $GITHUB_WORKSPACE
|
|
||||||
- name: Checkout Latest Repo
|
- name: Checkout Latest Repo
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
|
|
||||||
# Setup Ruby Testing Tools to do tests on multiple ruby version
|
- name: Setup Ruby
|
||||||
- name: Setup Ruby Testing Tools
|
|
||||||
uses: ruby/setup-ruby@v1
|
uses: ruby/setup-ruby@v1
|
||||||
with:
|
with:
|
||||||
ruby-version: ${{ matrix.ruby }}
|
ruby-version: ${{ matrix.ruby }}
|
||||||
|
|
||||||
# Install Ruby Testing Tools
|
- name: Install Ruby Dependencies
|
||||||
- name: Setup Ruby Testing Tools
|
|
||||||
run: |
|
run: |
|
||||||
sudo gem install rspec
|
gem install bundler
|
||||||
sudo gem install rubocop -v 1.57.2
|
bundle install
|
||||||
sudo gem install bundler
|
|
||||||
bundle update
|
|
||||||
bundle install
|
|
||||||
|
|
||||||
# Run Tests
|
- name: Run Ruby Unit Tests
|
||||||
- name: Run All Unit Tests
|
env:
|
||||||
|
NO_COLOR: ${{ matrix.os == 'windows-latest' && '1' || '' }}
|
||||||
run: |
|
run: |
|
||||||
cd test && rake ci
|
cd test && rake test:unit
|
||||||
|
|
||||||
|
- name: Run Style Check
|
||||||
|
env:
|
||||||
|
NO_COLOR: ${{ matrix.os == 'windows-latest' && '1' || '' }}
|
||||||
|
run: |
|
||||||
|
cd test && rake style:check
|
||||||
|
|
||||||
|
# Job: C compilation and system tests — only needs to run on one Ruby version per OS,
|
||||||
|
# since the generated C code and runtime behavior don't vary with the Ruby version.
|
||||||
|
c-tests:
|
||||||
|
name: "C Tests (${{ matrix.os }})"
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
|
steps:
|
||||||
|
# Install Multilib (Linux only)
|
||||||
|
- name: Install Multilib
|
||||||
|
if: matrix.os == 'ubuntu-latest'
|
||||||
|
run: |
|
||||||
|
sudo apt-get update -qq
|
||||||
|
sudo apt-get install --assume-yes --quiet gcc-multilib
|
||||||
|
|
||||||
|
# Add MinGW GCC to PATH (Windows only — MSYS2 is pre-installed on the runner)
|
||||||
|
- name: Add GCC to PATH
|
||||||
|
if: matrix.os == 'windows-latest'
|
||||||
|
run: echo "C:\msys64\mingw64\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
|
||||||
|
|
||||||
|
- name: Checkout Latest Repo
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Setup Ruby
|
||||||
|
uses: ruby/setup-ruby@v1
|
||||||
|
with:
|
||||||
|
ruby-version: '3.3'
|
||||||
|
|
||||||
|
- name: Install Ruby Dependencies
|
||||||
|
run: |
|
||||||
|
gem install bundler
|
||||||
|
bundle install
|
||||||
|
|
||||||
|
- name: Run C Unit Tests
|
||||||
|
env:
|
||||||
|
NO_COLOR: ${{ matrix.os == 'windows-latest' && '1' || '' }}
|
||||||
|
run: cd test && rake test:c
|
||||||
|
|
||||||
|
- name: Run System Tests
|
||||||
|
env:
|
||||||
|
NO_COLOR: ${{ matrix.os == 'windows-latest' && '1' || '' }}
|
||||||
|
run: cd test && rake test:system
|
||||||
|
|
||||||
|
- name: Run Examples
|
||||||
|
env:
|
||||||
|
NO_COLOR: ${{ matrix.os == 'windows-latest' && '1' || '' }}
|
||||||
|
run: cd test && rake test:examples
|
||||||
|
|
||||||
|
# Job: Valgrind memory-leak check (Linux/gcc_64 only, latest Ruby)
|
||||||
|
valgrind:
|
||||||
|
name: "Valgrind Memory Check"
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Install Dependencies
|
||||||
|
run: |
|
||||||
|
sudo apt-get update -qq
|
||||||
|
sudo apt-get install --assume-yes --quiet gcc-multilib valgrind
|
||||||
|
|
||||||
|
- name: Checkout Latest Repo
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Setup Ruby
|
||||||
|
uses: ruby/setup-ruby@v1
|
||||||
|
with:
|
||||||
|
ruby-version: '3.3'
|
||||||
|
|
||||||
|
- name: Install Ruby Dependencies
|
||||||
|
run: |
|
||||||
|
gem install bundler
|
||||||
|
bundle install
|
||||||
|
|
||||||
|
# Build and run C unit tests, then re-run the executable under valgrind.
|
||||||
|
# test:system clobbers the build directory, so check TestCMockC before that happens.
|
||||||
|
- name: Build and Run C Unit Tests
|
||||||
|
run: cd test && rake config[gcc_64_valgrind] test:c
|
||||||
|
|
||||||
|
- name: Valgrind Check - C Unit Tests
|
||||||
|
run: |
|
||||||
|
valgrind --leak-check=full --track-origins=yes --error-exitcode=1 \
|
||||||
|
test/system/build/TestCMockC.exe
|
||||||
|
|
||||||
|
# Build and run system tests, then re-run each executable under valgrind.
|
||||||
|
- name: Build and Run System Tests
|
||||||
|
run: cd test && rake config[gcc_64_valgrind] test:system
|
||||||
|
|
||||||
|
- name: Valgrind Check - System Tests
|
||||||
|
run: |
|
||||||
|
failed=0
|
||||||
|
for exe in test/system/build/test_*.exe; do
|
||||||
|
echo "Checking: $exe"
|
||||||
|
# Use exit code 42 to distinguish valgrind errors from Unity test failures.
|
||||||
|
# Some executables intentionally contain tests expected to fail (testing CMock's
|
||||||
|
# error-handling), so Unity exits non-zero. The `|| exit_code=$?` prevents bash's
|
||||||
|
# set -e from aborting the script on Unity's non-zero exit, while still capturing
|
||||||
|
# valgrind's own error exit code (42) separately.
|
||||||
|
exit_code=0
|
||||||
|
valgrind --leak-check=full --track-origins=yes --error-exitcode=42 "$exe" || exit_code=$?
|
||||||
|
[ $exit_code -eq 42 ] && failed=1
|
||||||
|
done
|
||||||
|
exit $failed
|
||||||
|
|||||||
@@ -1 +1,4 @@
|
|||||||
source "http://rubygems.org/"
|
source "https://rubygems.org/"
|
||||||
|
|
||||||
|
gem 'rspec'
|
||||||
|
gem 'rubocop', '1.57.2'
|
||||||
|
|||||||
@@ -13,6 +13,41 @@ Prior to 2008, the project was an internal project and not released to the publi
|
|||||||
|
|
||||||
## Log
|
## Log
|
||||||
|
|
||||||
|
### CMock 2.7.0 (July 2026)
|
||||||
|
|
||||||
|
New Features:
|
||||||
|
|
||||||
|
- Significant improvements to array and pointer handling:
|
||||||
|
- Arrays are now passed as arrays. Yes, even multidimensional ones. (Fixes #69, #119, #213, #422)
|
||||||
|
- Array plugin now supports comparing `char*` (string) arguments as byte arrays via `_ExpectWithArray`, while still treating them as strings via `_Expect` (Fixes #262 and #177)
|
||||||
|
- Improved automatic detection of pointer/length argument pairs (Fixes #520)
|
||||||
|
- When a pointer is auto-paired with a size argument, `_ExpectWithArrayExtended` is also generated as a fallback to allow explicit depth override (Fixes #476)
|
||||||
|
- `void*` arguments now default to pointer comparison without the array plugin, and to byte-by-byte comparison when the array plugin is active (Fixes #400)
|
||||||
|
- Handles *simple* preprocessor features like #if 1 and #if 0 (Fixes #163)
|
||||||
|
- Ignores static assertions of various types (Fixes #128)
|
||||||
|
- Added option to trace all mock setup and mocked calls (Implements #403)
|
||||||
|
- Significant improvements to header parsing speed
|
||||||
|
|
||||||
|
Significant Bugfixes:
|
||||||
|
|
||||||
|
- Fixed matching of pointer/len argument pairs in reverse order (Fixes #479)
|
||||||
|
- Fixed handling of array of pointers or a pointer to an array (Fixes #450)
|
||||||
|
- Fixed const and pointer order handling issues (Fixes #484 and #485)
|
||||||
|
- Fixed handling of skeleton paths (Fixes #488)
|
||||||
|
- Fixed handling of memory alignment issues (Fixes #178)
|
||||||
|
- Fixed handling of failures in teardown (#67)
|
||||||
|
- Improved handling of function-looking structs (Fixes #513 and #334)
|
||||||
|
- Improved handling of function-looking macros (Fixes #502)
|
||||||
|
- Improved handling of volatiles (Fixes #110 and #135)
|
||||||
|
- Improved handling of stub and callback counters (Fixes #132)
|
||||||
|
- Improved handling and testing of Windows (Fixes #435)
|
||||||
|
|
||||||
|
Other:
|
||||||
|
|
||||||
|
- Added verification that memory errors are reported and stop tests (Verifies #463)
|
||||||
|
- Added verification that CMock features pass Valgrind (Verifies #506)
|
||||||
|
- Documented custom type support (#124)
|
||||||
|
|
||||||
### CMock 2.6.0 (January 2025)
|
### CMock 2.6.0 (January 2025)
|
||||||
|
|
||||||
New Features:
|
New Features:
|
||||||
|
|||||||
@@ -9,5 +9,4 @@ be found on our Github repository.
|
|||||||
## Issues
|
## Issues
|
||||||
|
|
||||||
- Able to parse most C header files without preprocessor needs, but when handling headers with significant preprocessor usage (#ifdefs, etc), it can get confused
|
- Able to parse most C header files without preprocessor needs, but when handling headers with significant preprocessor usage (#ifdefs, etc), it can get confused
|
||||||
- Multi-dimensional arrays currently simplified to single dimensional arrays of the full size
|
|
||||||
- Incomplete support for VarArgs
|
- Incomplete support for VarArgs
|
||||||
|
|||||||
@@ -1,16 +1,32 @@
|
|||||||
CMock: Argument Validation
|
CMock: Argument Validation
|
||||||
==========================
|
==========================
|
||||||
|
|
||||||
Much of the power of CMock comes from its ability to automatically
|
Much of the power of CMock comes from its ability to automatically
|
||||||
validate that the arguments passed to mocked functions are the
|
validate that the arguments passed to mocked functions are the
|
||||||
values that were expected to be passed. CMock puts a lot of effort
|
values that were expected to be passed. CMock puts a lot of effort
|
||||||
into guessing how the user would most like to see those values
|
into guessing how the user would most like to see those values
|
||||||
compared, and then represented when failures are encountered.
|
compared, and then represented when failures are encountered.
|
||||||
|
|
||||||
Like Unity, CMock follows a philosophy of making its best guesses,
|
Like Unity, CMock follows a philosophy of making its best guesses,
|
||||||
and then allowing the user to explicity specify any features that
|
and then allowing the user to explicitly specify any features that
|
||||||
they would like to change or customize.
|
they would like to change or customize.
|
||||||
|
|
||||||
|
Quick Reference: Which Option Should I Use?
|
||||||
|
-------------------------------------------
|
||||||
|
|
||||||
|
| Situation | Recommended Option |
|
||||||
|
|-----------|-------------------|
|
||||||
|
| Built-in C types (`int`, `uint8_t`, `float`, …) | Nothing — Option 1 handles these automatically |
|
||||||
|
| Simple typedef or `#define` alias of a known type | Option 2: add a `:treat_as` entry |
|
||||||
|
| Small `enum` type | Option 2: map to `INT8`, `INT16`, or `INT` |
|
||||||
|
| Opaque handle / function pointer where only identity matters | Option 2: map to `PTR` |
|
||||||
|
| `typedef`'d fixed-size array | Option 2: `:treat_as_array` |
|
||||||
|
| Legacy `typedef void MY_VOID` | Option 2: `:treat_as_void` |
|
||||||
|
| `struct` or `union` needing field-level comparison | Option 3: custom assertion + `:unity_helper_path` |
|
||||||
|
| Pointer to a `struct` with a custom assertion | Option 2 + 3: custom assertion, then `:treat_as` the pointer |
|
||||||
|
| Type that changes meaning per test, or one-off complex logic | Option 4: Callback |
|
||||||
|
| Last resort — type is unknown and rough equality is enough | Option 1b: memcmp fallback (automatic) |
|
||||||
|
|
||||||
Option 1: Common Types
|
Option 1: Common Types
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
@@ -72,22 +88,129 @@ a custom type?
|
|||||||
Option 2: Treat-As
|
Option 2: Treat-As
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
CMock maintains a list of non-standard types which are basically
|
CMock maintains a list of non-standard types which are basically
|
||||||
aliases of standard types. For example, a common shorthand for
|
aliases of standard types. For example, a common shorthand for
|
||||||
a single-byte unsigned integer might be `u8` or `U8` or `UNIT8`.
|
a single-byte unsigned integer might be `u8` or `U8` or `UINT8`.
|
||||||
Any of these can simply be mapped to the standard
|
Any of these can simply be mapped to the standard
|
||||||
`TEST_ASSERT_EQUAL_HEX8`.
|
`TEST_ASSERT_EQUAL_HEX8`.
|
||||||
|
|
||||||
While CMock has its own list of `:treat_as` mappings, you can
|
### Default Handlers
|
||||||
|
|
||||||
|
CMock ships with a built-in `:treat_as` list that already covers the
|
||||||
|
most common type aliases found in embedded C codebases. You get all
|
||||||
|
of these for free without any configuration:
|
||||||
|
|
||||||
|
| C Type | Unity Assertion Used |
|
||||||
|
|---------------------|---------------------------|
|
||||||
|
| `int` | `INT` |
|
||||||
|
| `char` | `INT8` |
|
||||||
|
| `short` | `INT16` |
|
||||||
|
| `long` | `INT` |
|
||||||
|
| `unsigned int` | `HEX32` |
|
||||||
|
| `unsigned long` | `HEX32` |
|
||||||
|
| `unsigned short` | `HEX16` |
|
||||||
|
| `unsigned char` | `HEX8` |
|
||||||
|
| `int8_t` / `INT8_T` / `int8` | `INT8` |
|
||||||
|
| `int16_t` / `INT16_T` / `int16` | `INT16` |
|
||||||
|
| `int32_t` / `INT32_T` / `int32` | `INT` |
|
||||||
|
| `uint8_t` / `UINT8_T` / `uint8` / `UINT8` | `HEX8` |
|
||||||
|
| `uint16_t` / `UINT16_T` / `uint16` / `UINT16` | `HEX16` |
|
||||||
|
| `uint32_t` / `UINT32_T` / `uint32` / `UINT32` | `HEX32` |
|
||||||
|
| `bool` / `bool_t` / `BOOL` / `BOOL_T` | `INT` |
|
||||||
|
| `char*` | `STRING` |
|
||||||
|
| `pCHAR` / `cstring` / `CSTRING` | `STRING` |
|
||||||
|
| `void*` | `HEX8_ARRAY` |
|
||||||
|
| `float` / `double` | `FLOAT` |
|
||||||
|
|
||||||
|
The right-hand side of each mapping is the suffix of the Unity assertion
|
||||||
|
that will be used. `HEX8` means CMock will call `TEST_ASSERT_EQUAL_HEX8`,
|
||||||
|
for instance. Pointer variants (ending in `*`) map to the corresponding
|
||||||
|
array assertion (e.g. `HEX8*` → `TEST_ASSERT_EQUAL_HEX8_ARRAY`).
|
||||||
|
|
||||||
|
### Adding Your Own Mappings
|
||||||
|
|
||||||
|
While CMock has its own list of `:treat_as` mappings, you can
|
||||||
add your own pairings to this list. This works especially well for
|
add your own pairings to this list. This works especially well for
|
||||||
the following types:
|
the following types:
|
||||||
|
|
||||||
- aliases of standard types using `#define` or `typedef`
|
- aliases of standard types using `#define` or `typedef`
|
||||||
- `enum` types (works well as `INT8` or whatever size your enums are)
|
- `enum` types (works well as `INT8` or whatever size your enums are)
|
||||||
- function pointers often work well as `PTR` comparisons
|
- function pointers often work well as `PTR` comparisons
|
||||||
- `union` types sometimes make sense to treat as the largest type...
|
- `union` types sometimes make sense to treat as the largest type...
|
||||||
but this is a judgement call
|
but this is a judgement call
|
||||||
|
|
||||||
|
Your entries **merge** with the defaults — you are only adding or
|
||||||
|
overriding specific types, not replacing the entire list. To remove
|
||||||
|
a default mapping, set its value to `nil`.
|
||||||
|
|
||||||
|
Here is a YAML configuration example:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
:cmock:
|
||||||
|
:treat_as:
|
||||||
|
MY_BOOL: INT # typedef bool MY_BOOL → compare as int
|
||||||
|
MY_U8: HEX8 # typedef uint8_t MY_U8 → compare as hex byte
|
||||||
|
MY_U16: HEX16
|
||||||
|
MY_U32: HEX32
|
||||||
|
STATUS_T: INT8 # small enum → compare as signed byte
|
||||||
|
HANDLE_T: PTR # opaque pointer → compare pointer addresses
|
||||||
|
float: nil # remove the default float mapping (unusual)
|
||||||
|
```
|
||||||
|
|
||||||
|
Or from Ruby:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
CMock.new(
|
||||||
|
treat_as: {
|
||||||
|
'MY_BOOL' => 'INT',
|
||||||
|
'STATUS_T' => 'INT8',
|
||||||
|
'HANDLE_T' => 'PTR',
|
||||||
|
}
|
||||||
|
).setup_mocks('my_module.h')
|
||||||
|
```
|
||||||
|
|
||||||
|
### Pointer Types in :treat_as
|
||||||
|
|
||||||
|
You can map pointer-to-custom-type the same way. Use a `*` suffix on
|
||||||
|
the right-hand side to indicate the comparison should use the array
|
||||||
|
variant of the assertion:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
:treat_as:
|
||||||
|
MY_DATA_PTR: HEX8* # compares the bytes pointed to, not the address
|
||||||
|
```
|
||||||
|
|
||||||
|
### Related Options: :treat_as_array and :treat_as_void
|
||||||
|
|
||||||
|
Two narrower variants of `:treat_as` handle specific edge cases:
|
||||||
|
|
||||||
|
**`:treat_as_array`** — for types that are themselves `typedef`'d arrays,
|
||||||
|
such as `typedef int TenIntegers[10];`. This is a hash of typedef name
|
||||||
|
to element type:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
:cmock:
|
||||||
|
:treat_as_array:
|
||||||
|
TenIntegers: int
|
||||||
|
MyBuffer: uint8_t
|
||||||
|
```
|
||||||
|
|
||||||
|
This lets CMock treat parameters of these types the same way it would
|
||||||
|
treat a pointer-plus-count, enabling features like `ExpectWithArray`
|
||||||
|
and `ReturnArrayThruPtr`.
|
||||||
|
|
||||||
|
**`:treat_as_void`** — for legacy codebases that typedef `void` to a
|
||||||
|
custom name (e.g. `typedef void MY_VOID;`). Add such names here so
|
||||||
|
CMock knows functions returning or accepting that type are effectively
|
||||||
|
`void`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
:cmock:
|
||||||
|
:treat_as_void:
|
||||||
|
- MY_VOID
|
||||||
|
- NORETURN_T
|
||||||
|
```
|
||||||
|
|
||||||
Option 3: Custom Assertions for Custom Types
|
Option 3: Custom Assertions for Custom Types
|
||||||
--------------------------------------------
|
--------------------------------------------
|
||||||
|
|
||||||
@@ -206,31 +329,63 @@ void AssertEqualMyType(const MyType expected, const MyType actual, UNITY_LINE_TY
|
|||||||
|
|
||||||
### Wrapping our Assertion in Macros
|
### Wrapping our Assertion in Macros
|
||||||
|
|
||||||
Once you have a function which does the main work, we *need* to create
|
Once you have a function which does the main work, we need to create
|
||||||
one macro, and there are a number of other macros which are useful to
|
macros around it so that the assertion can be used conveniently both
|
||||||
create, in order to treat our assertion just like any other Unity
|
by CMock and directly in test code.
|
||||||
assertion.
|
|
||||||
|
|
||||||
`#define UNITY_TEST_ASSERT_EQUAL_MyType(e,a,l,m) AssertEqualMyType(e,a,l,m)`
|
The macro that CMock **requires** is the `UNITY_TEST_ASSERT_EQUAL_` form.
|
||||||
|
It starts with exactly that prefix, followed by the type name exactly as
|
||||||
|
declared, and takes four arguments:
|
||||||
|
|
||||||
The macro above is the one that CMock is looking for. Notice that it
|
```c
|
||||||
starts with `UNITY_TEST_ASSERT_EQUAL_` followed by the name of our type,
|
#define UNITY_TEST_ASSERT_EQUAL_MyType(e,a,l,m) AssertEqualMyType(e,a,l,m)
|
||||||
*exactly* the way our type is named. The arguments are, in order:
|
```
|
||||||
|
|
||||||
- `e` - expected value
|
- `e` - expected value
|
||||||
- `a` - actual value
|
- `a` - actual value
|
||||||
- `l` - line number to report
|
- `l` - line number to report (filled in automatically by CMock)
|
||||||
- `m` - message to append at the end
|
- `m` - message to append at the end
|
||||||
|
|
||||||
If CMock finds a macro that matches this argument list and naming convention,
|
CMock scans the helper header for macros matching this pattern and
|
||||||
then it can automatically use this assertion where needed... all we need to
|
automatically uses them when it encounters the corresponding type.
|
||||||
do now is tell CMock where to find our custom assertion.
|
|
||||||
|
It is also useful (though optional) to add the simpler `TEST_ASSERT_EQUAL_`
|
||||||
|
form so the assertion is easy to call directly inside your own test
|
||||||
|
functions:
|
||||||
|
|
||||||
|
```c
|
||||||
|
#define TEST_ASSERT_EQUAL_MyType(e,a) \
|
||||||
|
UNITY_TEST_ASSERT_EQUAL_MyType(e,a,__LINE__,NULL)
|
||||||
|
|
||||||
|
#define TEST_ASSERT_EQUAL_MyType_MESSAGE(e,a,m) \
|
||||||
|
UNITY_TEST_ASSERT_EQUAL_MyType(e,a,__LINE__,m)
|
||||||
|
```
|
||||||
|
|
||||||
|
With these in place, you can write `TEST_ASSERT_EQUAL_MyType(expected, actual)`
|
||||||
|
in your tests just like any built-in Unity assertion.
|
||||||
|
|
||||||
### Informing CMock about our Assertion
|
### Informing CMock about our Assertion
|
||||||
|
|
||||||
In the CMock configuration file, in the `:cmock` or `:unity` sections,
|
CMock needs to know which header file(s) contain your custom assertions.
|
||||||
there can be an option for `unity_helper_path`. Add the location of your
|
Set the `:unity_helper_path` option in your CMock configuration to point
|
||||||
new Unity helper file (file with this assertion) to this list.
|
at the helper header:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
:cmock:
|
||||||
|
:unity_helper_path:
|
||||||
|
- test/support/my_types_helper.h
|
||||||
|
```
|
||||||
|
|
||||||
|
Or from Ruby:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
CMock.new(unity_helper_path: ['test/support/my_types_helper.h'])
|
||||||
|
.setup_mocks('my_module.h')
|
||||||
|
```
|
||||||
|
|
||||||
|
CMock parses each listed file, finds every `UNITY_TEST_ASSERT_EQUAL_*`
|
||||||
|
macro definition, and uses those macros automatically when it generates
|
||||||
|
mocks for parameters or return values of the matching types.
|
||||||
|
|
||||||
Done!
|
Done!
|
||||||
|
|
||||||
|
|||||||
+45
-3
@@ -189,7 +189,7 @@ care how many times it was called, right?
|
|||||||
StopIgnore:
|
StopIgnore:
|
||||||
-------
|
-------
|
||||||
|
|
||||||
Maybe you want to ignore a particular function for part of a test but dont want to
|
Maybe you want to ignore a particular function for part of a test but don't want to
|
||||||
ignore it later on. In that case, you want to use StopIgnore which will cancel the
|
ignore it later on. In that case, you want to use StopIgnore which will cancel the
|
||||||
previously called Ignore or IgnoreAndReturn requiring you to Expect or otherwise
|
previously called Ignore or IgnoreAndReturn requiring you to Expect or otherwise
|
||||||
handle the call to a function.
|
handle the call to a function.
|
||||||
@@ -199,6 +199,25 @@ handle the call to a function.
|
|||||||
* `retval func(void)` => `void func_StopIgnore(void)`
|
* `retval func(void)` => `void func_StopIgnore(void)`
|
||||||
* `retval func(params)` => `void func_StopIgnore(void)`
|
* `retval func(params)` => `void func_StopIgnore(void)`
|
||||||
|
|
||||||
|
It's important to note that the effect of this function is immediate and applies to
|
||||||
|
this function's stack of expectations. So the following will work as intended:
|
||||||
|
|
||||||
|
```
|
||||||
|
Blah_Ignore();
|
||||||
|
funcThatMightCallBlahButWeDoNotCare();
|
||||||
|
Blah_StopIgnore();
|
||||||
|
funcThatWeWantToMakeSureDoesNotCallBlah();
|
||||||
|
```
|
||||||
|
|
||||||
|
But this is NOT going to work, because StopIgnore immediately cancels ignore:
|
||||||
|
|
||||||
|
```
|
||||||
|
Blah_Ignore();
|
||||||
|
Blah_StopIgnore();
|
||||||
|
funcThatMightCallBlahButWeDoNotCare();
|
||||||
|
funcThatWeWantToMakeSureDoesNotCallBlah();
|
||||||
|
```
|
||||||
|
|
||||||
IgnoreStateless:
|
IgnoreStateless:
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
@@ -294,6 +313,14 @@ order (based on any Expects you've set up) before calling the callback.
|
|||||||
to the callback instead. In this case, you are replacing the normal mock calls
|
to the callback instead. In this case, you are replacing the normal mock calls
|
||||||
with your own custom stub function.
|
with your own custom stub function.
|
||||||
|
|
||||||
|
Calling either `func_AddCallback` or `func_Stub` resets the call count for
|
||||||
|
that function to zero, so `NumCalls` always reflects calls made since the
|
||||||
|
current stub or callback was installed.
|
||||||
|
|
||||||
|
You can read the current call count at any time using `func_CallCount()`.
|
||||||
|
This is useful when you need to verify how many times a stub was invoked
|
||||||
|
without setting up formal Expects.
|
||||||
|
|
||||||
There is also an older name, `func_StubWithCallback`, which is just an alias
|
There is also an older name, `func_StubWithCallback`, which is just an alias
|
||||||
for either `func_AddCallback` or `func_Stub` depending on setting of the
|
for either `func_AddCallback` or `func_Stub` depending on setting of the
|
||||||
`:callback_after_arg_check` toggle. This is deprecated and we recommend using
|
`:callback_after_arg_check` toggle. This is deprecated and we recommend using
|
||||||
@@ -720,6 +747,20 @@ from the defaults. We've tried to specify what the defaults are below.
|
|||||||
* 2 for normal (default)
|
* 2 for normal (default)
|
||||||
* 3 for verbose
|
* 3 for verbose
|
||||||
|
|
||||||
|
* `:debug_output`:
|
||||||
|
When enabled, the generated mock will emit a `TEST_MESSAGE` for each
|
||||||
|
mock setup call (e.g. `_Expect`, `_Ignore`, `_AddCallback`) and each
|
||||||
|
actual mock invocation. This can help diagnose the order in which mock
|
||||||
|
calls are being set up and executed during a test.
|
||||||
|
|
||||||
|
For example, with `:debug_output: true` and a mocked function `int foo(int a)`,
|
||||||
|
the generated mock will print messages such as:
|
||||||
|
|
||||||
|
CMock: foo_ExpectAndReturn called
|
||||||
|
CMock: mock foo called
|
||||||
|
|
||||||
|
* default: false
|
||||||
|
|
||||||
* `:weak`:
|
* `:weak`:
|
||||||
When set this to some value, the generated mocks are defined as weak
|
When set this to some value, the generated mocks are defined as weak
|
||||||
symbols using the configured format. This allows them to be overridden
|
symbols using the configured format. This allows them to be overridden
|
||||||
@@ -929,8 +970,9 @@ that exposes them as virtual methods and modify your code to inject mocks at
|
|||||||
run-time... but there is another way!
|
run-time... but there is another way!
|
||||||
|
|
||||||
Simply use CMock to mock the static member methods and a C++ mocking framework
|
Simply use CMock to mock the static member methods and a C++ mocking framework
|
||||||
to handle the virtual methods. (Yes, you can mix mocks from CMock and a C++
|
to handle the virtual methods. CMock does NOT mock non-static members. For those,
|
||||||
mocking framework together in the same test!)
|
you'll need an actual C++ mocking framework. (Yes, you can mix mocks from CMock
|
||||||
|
and a C++ mocking framework together in the same test!)
|
||||||
|
|
||||||
Keep in mind that since C++ mocking frameworks often link the real object to the
|
Keep in mind that since C++ mocking frameworks often link the real object to the
|
||||||
unit test too, we need to resolve multiple definition errors with something like
|
unit test too, we need to resolve multiple definition errors with something like
|
||||||
|
|||||||
+6
-1
@@ -52,7 +52,12 @@ class CMockConfig
|
|||||||
# - The keywords can appear before or after the return type (this is a compiler warning but people do weird stuff),
|
# - The keywords can appear before or after the return type (this is a compiler warning but people do weird stuff),
|
||||||
# so we check for word boundaries when searching for them
|
# so we check for word boundaries when searching for them
|
||||||
# - We first remove "static inline" combinations and boil down to single inline or static statements
|
# - We first remove "static inline" combinations and boil down to single inline or static statements
|
||||||
:inline_function_patterns => ['(static\s+inline|inline\s+static)\s*', '(\binline\b)\s*', '(?:static\s*)?(?:__inline__)?__attribute__\s*\([ (]*always_inline[ )]*\)', 'static __inline__'] # Last part (\s*) is just to remove whitespaces (only to prettify the output)
|
:inline_function_patterns => ['(static\s+inline|inline\s+static)\s*', '(\binline\b)\s*', '(?:static\s*)?(?:__inline__)?__attribute__\s*\([ (]*always_inline[ )]*\)', 'static __inline__'], # Last part (\s*) is just to remove whitespaces (only to prettify the output)
|
||||||
|
|
||||||
|
# Compile-time assertion macro names to strip entirely to avoid being confused with function prototypes
|
||||||
|
# Common C11, BSD, and embedded RTOS variants are included by default. Add custom names as needed.
|
||||||
|
:ct_assert_patterns => ['ct_assert', '_?[Ss]tatic_[Aa]ssert', 'STATIC_ASSERT', 'BUILD_ASSERT', 'CTASSERT'],
|
||||||
|
:debug_output => false
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
def initialize(options = nil)
|
def initialize(options = nil)
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ class CMockGenerator
|
|||||||
@fail_on_unexpected_calls = @config.fail_on_unexpected_calls
|
@fail_on_unexpected_calls = @config.fail_on_unexpected_calls
|
||||||
@exclude_setjmp_h = @config.exclude_setjmp_h
|
@exclude_setjmp_h = @config.exclude_setjmp_h
|
||||||
@subdir = @config.subdir
|
@subdir = @config.subdir
|
||||||
|
@debug_output = @config.debug_output
|
||||||
|
|
||||||
@includes_h_pre_orig_header = ((@config.includes || []) + (@config.includes_h_pre_orig_header || [])).uniq.map { |h| h =~ /</ ? h : "\"#{h}\"" }
|
@includes_h_pre_orig_header = ((@config.includes || []) + (@config.includes_h_pre_orig_header || [])).uniq.map { |h| h =~ /</ ? h : "\"#{h}\"" }
|
||||||
@includes_h_post_orig_header = (@config.includes_h_post_orig_header || []).map { |h| h =~ /</ ? h : "\"#{h}\"" }
|
@includes_h_post_orig_header = (@config.includes_h_post_orig_header || []).map { |h| h =~ /</ ? h : "\"#{h}\"" }
|
||||||
@@ -344,6 +345,7 @@ class CMockGenerator
|
|||||||
file << " UNITY_LINE_TYPE cmock_line = TEST_LINE_NUM;\n"
|
file << " UNITY_LINE_TYPE cmock_line = TEST_LINE_NUM;\n"
|
||||||
file << " CMOCK_#{function[:name]}_CALL_INSTANCE* cmock_call_instance;\n"
|
file << " CMOCK_#{function[:name]}_CALL_INSTANCE* cmock_call_instance;\n"
|
||||||
file << " UNITY_SET_DETAIL(CMockString_#{function[:name]});\n"
|
file << " UNITY_SET_DETAIL(CMockString_#{function[:name]});\n"
|
||||||
|
file << " TEST_MESSAGE(\"CMock: mock #{function[:name]} called\");\n" if @debug_output
|
||||||
file << " cmock_call_instance = (CMOCK_#{function[:name]}_CALL_INSTANCE*)CMock_Guts_GetAddressFor(Mock.#{function[:name]}_CallInstance);\n"
|
file << " cmock_call_instance = (CMOCK_#{function[:name]}_CALL_INSTANCE*)CMock_Guts_GetAddressFor(Mock.#{function[:name]}_CallInstance);\n"
|
||||||
file << " Mock.#{function[:name]}_CallInstance = CMock_Guts_MemNext(Mock.#{function[:name]}_CallInstance);\n"
|
file << " Mock.#{function[:name]}_CallInstance = CMock_Guts_MemNext(Mock.#{function[:name]}_CallInstance);\n"
|
||||||
file << @plugins.run(:mock_precheck_return_thru_ptr, function)
|
file << @plugins.run(:mock_precheck_return_thru_ptr, function)
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ class CMockGeneratorPluginCallback
|
|||||||
@priority = 6
|
@priority = 6
|
||||||
|
|
||||||
@include_count = @config.callback_include_count
|
@include_count = @config.callback_include_count
|
||||||
|
@debug_output = @config.debug_output
|
||||||
end
|
end
|
||||||
|
|
||||||
def instance_structure(function)
|
def instance_structure(function)
|
||||||
@@ -33,7 +34,8 @@ class CMockGeneratorPluginCallback
|
|||||||
"typedef #{return_type} (* CMOCK_#{func_name}_CALLBACK)(#{styles[style]});\n" \
|
"typedef #{return_type} (* CMOCK_#{func_name}_CALLBACK)(#{styles[style]});\n" \
|
||||||
"void #{func_name}_AddCallback(CMOCK_#{func_name}_CALLBACK Callback);\n" \
|
"void #{func_name}_AddCallback(CMOCK_#{func_name}_CALLBACK Callback);\n" \
|
||||||
"void #{func_name}_Stub(CMOCK_#{func_name}_CALLBACK Callback);\n" \
|
"void #{func_name}_Stub(CMOCK_#{func_name}_CALLBACK Callback);\n" \
|
||||||
"#define #{func_name}_StubWithCallback #{func_name}_#{action}\n"
|
"#define #{func_name}_StubWithCallback #{func_name}_#{action}\n" \
|
||||||
|
"int #{func_name}_CallCount(void);\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
def generate_call(function)
|
def generate_call(function)
|
||||||
@@ -71,12 +73,19 @@ class CMockGeneratorPluginCallback
|
|||||||
has_ignore = @config.plugins.include? :ignore
|
has_ignore = @config.plugins.include? :ignore
|
||||||
lines = ''
|
lines = ''
|
||||||
lines << "void #{func_name}_AddCallback(CMOCK_#{func_name}_CALLBACK Callback)\n{\n"
|
lines << "void #{func_name}_AddCallback(CMOCK_#{func_name}_CALLBACK Callback)\n{\n"
|
||||||
|
lines << " TEST_MESSAGE(\"CMock: #{func_name}_AddCallback called\");\n" if @debug_output
|
||||||
lines << " Mock.#{func_name}_IgnoreBool = (char)0;\n" if has_ignore
|
lines << " Mock.#{func_name}_IgnoreBool = (char)0;\n" if has_ignore
|
||||||
lines << " Mock.#{func_name}_CallbackBool = (char)1;\n"
|
lines << " Mock.#{func_name}_CallbackBool = (char)1;\n"
|
||||||
|
lines << " Mock.#{func_name}_CallbackCalls = 0;\n"
|
||||||
lines << " Mock.#{func_name}_CallbackFunctionPointer = Callback;\n}\n\n"
|
lines << " Mock.#{func_name}_CallbackFunctionPointer = Callback;\n}\n\n"
|
||||||
|
lines << "int #{func_name}_CallCount(void)\n{\n"
|
||||||
|
lines << " TEST_MESSAGE(\"CMock: #{func_name}_CallCount called\");\n" if @debug_output
|
||||||
|
lines << " return Mock.#{func_name}_CallbackCalls;\n}\n\n"
|
||||||
lines << "void #{func_name}_Stub(CMOCK_#{func_name}_CALLBACK Callback)\n{\n"
|
lines << "void #{func_name}_Stub(CMOCK_#{func_name}_CALLBACK Callback)\n{\n"
|
||||||
|
lines << " TEST_MESSAGE(\"CMock: #{func_name}_Stub called\");\n" if @debug_output
|
||||||
lines << " Mock.#{func_name}_IgnoreBool = (char)0;\n" if has_ignore
|
lines << " Mock.#{func_name}_IgnoreBool = (char)0;\n" if has_ignore
|
||||||
lines << " Mock.#{func_name}_CallbackBool = (char)0;\n"
|
lines << " Mock.#{func_name}_CallbackBool = (char)0;\n"
|
||||||
|
lines << " Mock.#{func_name}_CallbackCalls = 0;\n"
|
||||||
lines << " Mock.#{func_name}_CallbackFunctionPointer = Callback;\n}\n\n"
|
lines << " Mock.#{func_name}_CallbackFunctionPointer = Callback;\n}\n\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ class CMockGeneratorPluginExpect
|
|||||||
@utils = utils
|
@utils = utils
|
||||||
@unity_helper = @utils.helpers[:unity_helper]
|
@unity_helper = @utils.helpers[:unity_helper]
|
||||||
@priority = 5
|
@priority = 5
|
||||||
|
@debug_output = @config.debug_output
|
||||||
|
|
||||||
if @config.plugins.include? :expect_any_args
|
if @config.plugins.include? :expect_any_args
|
||||||
alias :mock_implementation :mock_implementation_might_check_args
|
alias :mock_implementation :mock_implementation_might_check_args
|
||||||
@@ -30,7 +31,7 @@ class CMockGeneratorPluginExpect
|
|||||||
lines << " #{function[:return][:type]} ReturnVal;\n" unless function[:return][:void?]
|
lines << " #{function[:return][:type]} ReturnVal;\n" unless function[:return][:void?]
|
||||||
lines << " int CallOrder;\n" if @ordered
|
lines << " int CallOrder;\n" if @ordered
|
||||||
function[:args].each do |arg|
|
function[:args].each do |arg|
|
||||||
lines << " #{arg[:type]} Expected_#{arg[:name]};\n"
|
lines << " #{arg[:volatile?] ? "volatile #{arg[:type]}" : arg[:type]} Expected_#{arg[:name]};\n"
|
||||||
end
|
end
|
||||||
lines
|
lines
|
||||||
end
|
end
|
||||||
@@ -92,6 +93,7 @@ class CMockGeneratorPluginExpect
|
|||||||
else
|
else
|
||||||
"void #{func_name}_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:args_string]}, #{function[:return][:str]})\n{\n"
|
"void #{func_name}_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:args_string]}, #{function[:return][:str]})\n{\n"
|
||||||
end
|
end
|
||||||
|
lines << " TEST_MESSAGE(\"CMock: #{func_name}_#{function[:return][:void?] ? 'Expect' : 'ExpectAndReturn'} called\");\n" if @debug_output
|
||||||
lines << @utils.code_add_base_expectation(func_name)
|
lines << @utils.code_add_base_expectation(func_name)
|
||||||
lines << @utils.code_call_argument_loader(function)
|
lines << @utils.code_call_argument_loader(function)
|
||||||
lines << @utils.code_assign_argument_quickly('cmock_call_instance->ReturnVal', function[:return]) unless function[:return][:void?]
|
lines << @utils.code_assign_argument_quickly('cmock_call_instance->ReturnVal', function[:return]) unless function[:return][:void?]
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ class CMockGeneratorPluginExpectAnyArgs
|
|||||||
@error_stubs = @config.create_error_stubs
|
@error_stubs = @config.create_error_stubs
|
||||||
@utils = utils
|
@utils = utils
|
||||||
@priority = 3
|
@priority = 3
|
||||||
|
@debug_output = @config.debug_output
|
||||||
end
|
end
|
||||||
|
|
||||||
def instance_typedefs(_function)
|
def instance_typedefs(_function)
|
||||||
@@ -43,6 +44,7 @@ class CMockGeneratorPluginExpectAnyArgs
|
|||||||
else
|
else
|
||||||
"void #{function[:name]}_CMockExpectAnyArgsAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]})\n{\n"
|
"void #{function[:name]}_CMockExpectAnyArgsAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]})\n{\n"
|
||||||
end
|
end
|
||||||
|
lines << " TEST_MESSAGE(\"CMock: #{function[:name]}_#{function[:return][:void?] ? 'ExpectAnyArgs' : 'ExpectAnyArgsAndReturn'} called\");\n" if @debug_output
|
||||||
lines << @utils.code_add_base_expectation(function[:name], true)
|
lines << @utils.code_add_base_expectation(function[:name], true)
|
||||||
unless function[:return][:void?]
|
unless function[:return][:void?]
|
||||||
lines << " cmock_call_instance->ReturnVal = cmock_to_return;\n"
|
lines << " cmock_call_instance->ReturnVal = cmock_to_return;\n"
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ class CMockGeneratorPluginIgnore
|
|||||||
@error_stubs = @config.create_error_stubs
|
@error_stubs = @config.create_error_stubs
|
||||||
@utils = utils
|
@utils = utils
|
||||||
@priority = 2
|
@priority = 2
|
||||||
|
@debug_output = @config.debug_output
|
||||||
end
|
end
|
||||||
|
|
||||||
def instance_structure(function)
|
def instance_structure(function)
|
||||||
@@ -62,6 +63,7 @@ class CMockGeneratorPluginIgnore
|
|||||||
else
|
else
|
||||||
"void #{function[:name]}_CMockIgnoreAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]})\n{\n"
|
"void #{function[:name]}_CMockIgnoreAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]})\n{\n"
|
||||||
end
|
end
|
||||||
|
lines << " TEST_MESSAGE(\"CMock: #{function[:name]}_#{function[:return][:void?] ? 'Ignore' : 'IgnoreAndReturn'} called\");\n" if @debug_output
|
||||||
unless function[:return][:void?]
|
unless function[:return][:void?]
|
||||||
lines << @utils.code_add_base_expectation(function[:name], false)
|
lines << @utils.code_add_base_expectation(function[:name], false)
|
||||||
end
|
end
|
||||||
@@ -73,6 +75,7 @@ class CMockGeneratorPluginIgnore
|
|||||||
|
|
||||||
# Add stop ignore function. it does not matter if there are any args
|
# Add stop ignore function. it does not matter if there are any args
|
||||||
lines << "void #{function[:name]}_CMockStopIgnore(void)\n{\n"
|
lines << "void #{function[:name]}_CMockStopIgnore(void)\n{\n"
|
||||||
|
lines << " TEST_MESSAGE(\"CMock: #{function[:name]}_StopIgnore called\");\n" if @debug_output
|
||||||
unless function[:return][:void?]
|
unless function[:return][:void?]
|
||||||
lines << " if(Mock.#{function[:name]}_IgnoreBool)\n"
|
lines << " if(Mock.#{function[:name]}_IgnoreBool)\n"
|
||||||
lines << " Mock.#{function[:name]}_CallInstance = CMock_Guts_MemNext(Mock.#{function[:name]}_CallInstance);\n"
|
lines << " Mock.#{function[:name]}_CallInstance = CMock_Guts_MemNext(Mock.#{function[:name]}_CallInstance);\n"
|
||||||
|
|||||||
@@ -9,9 +9,10 @@ class CMockGeneratorPluginIgnoreArg
|
|||||||
attr_reader :priority
|
attr_reader :priority
|
||||||
attr_accessor :utils
|
attr_accessor :utils
|
||||||
|
|
||||||
def initialize(_config, utils)
|
def initialize(config, utils)
|
||||||
@utils = utils
|
@utils = utils
|
||||||
@priority = 10
|
@priority = 10
|
||||||
|
@debug_output = config.debug_output
|
||||||
end
|
end
|
||||||
|
|
||||||
def instance_typedefs(function)
|
def instance_typedefs(function)
|
||||||
@@ -38,6 +39,7 @@ class CMockGeneratorPluginIgnoreArg
|
|||||||
function[:args].each do |arg|
|
function[:args].each do |arg|
|
||||||
lines << "void #{func_name}_CMockIgnoreArg_#{arg[:name]}(UNITY_LINE_TYPE cmock_line)\n"
|
lines << "void #{func_name}_CMockIgnoreArg_#{arg[:name]}(UNITY_LINE_TYPE cmock_line)\n"
|
||||||
lines << "{\n"
|
lines << "{\n"
|
||||||
|
lines << " TEST_MESSAGE(\"CMock: #{func_name}_IgnoreArg_#{arg[:name]} called\");\n" if @debug_output
|
||||||
lines << " CMOCK_#{func_name}_CALL_INSTANCE* cmock_call_instance = " \
|
lines << " CMOCK_#{func_name}_CALL_INSTANCE* cmock_call_instance = " \
|
||||||
"(CMOCK_#{func_name}_CALL_INSTANCE*)CMock_Guts_GetAddressFor(CMock_Guts_MemEndOfChain(Mock.#{func_name}_CallInstance));\n"
|
"(CMOCK_#{func_name}_CALL_INSTANCE*)CMock_Guts_GetAddressFor(CMock_Guts_MemEndOfChain(Mock.#{func_name}_CallInstance));\n"
|
||||||
lines << " UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringIgnPreExp);\n"
|
lines << " UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringIgnPreExp);\n"
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ class CMockGeneratorPluginIgnoreStateless
|
|||||||
@error_stubs = @config.create_error_stubs
|
@error_stubs = @config.create_error_stubs
|
||||||
@utils = utils
|
@utils = utils
|
||||||
@priority = 2
|
@priority = 2
|
||||||
|
@debug_output = @config.debug_output
|
||||||
end
|
end
|
||||||
|
|
||||||
def instance_structure(function)
|
def instance_structure(function)
|
||||||
@@ -63,6 +64,7 @@ class CMockGeneratorPluginIgnoreStateless
|
|||||||
else
|
else
|
||||||
"void #{function[:name]}_CMockIgnoreAndReturn(#{function[:return][:str]})\n{\n"
|
"void #{function[:name]}_CMockIgnoreAndReturn(#{function[:return][:str]})\n{\n"
|
||||||
end
|
end
|
||||||
|
lines << " TEST_MESSAGE(\"CMock: #{function[:name]}_#{function[:return][:void?] ? 'Ignore' : 'IgnoreAndReturn'} called\");\n" if @debug_output
|
||||||
unless function[:return][:void?]
|
unless function[:return][:void?]
|
||||||
lines << " Mock.#{function[:name]}_CallInstance = CMOCK_GUTS_NONE;\n"
|
lines << " Mock.#{function[:name]}_CallInstance = CMOCK_GUTS_NONE;\n"
|
||||||
lines << " Mock.#{function[:name]}_FinalReturn = cmock_to_return;\n"
|
lines << " Mock.#{function[:name]}_FinalReturn = cmock_to_return;\n"
|
||||||
@@ -72,6 +74,7 @@ class CMockGeneratorPluginIgnoreStateless
|
|||||||
|
|
||||||
# Add stop ignore function. it does not matter if there are any args
|
# Add stop ignore function. it does not matter if there are any args
|
||||||
lines << "void #{function[:name]}_CMockStopIgnore(void)\n{\n"
|
lines << "void #{function[:name]}_CMockStopIgnore(void)\n{\n"
|
||||||
|
lines << " TEST_MESSAGE(\"CMock: #{function[:name]}_StopIgnore called\");\n" if @debug_output
|
||||||
lines << " Mock.#{function[:name]}_IgnoreBool = (char)0;\n"
|
lines << " Mock.#{function[:name]}_IgnoreBool = (char)0;\n"
|
||||||
lines << "}\n\n"
|
lines << "}\n\n"
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ class CMockGeneratorPluginReturnThruPtr
|
|||||||
@utils = utils
|
@utils = utils
|
||||||
@priority = 9
|
@priority = 9
|
||||||
@config = config
|
@config = config
|
||||||
|
@debug_output = @config.debug_output
|
||||||
plugins = @config.plugins
|
plugins = @config.plugins
|
||||||
@ignore_used = plugins.include?(:ignore) || plugins.include?(:ignore_stateless)
|
@ignore_used = plugins.include?(:ignore) || plugins.include?(:ignore_stateless)
|
||||||
end
|
end
|
||||||
@@ -99,6 +100,7 @@ class CMockGeneratorPluginReturnThruPtr
|
|||||||
|
|
||||||
lines << "void #{func_name}_CMockReturnMemThruPtr_#{arg_name}(UNITY_LINE_TYPE cmock_line, #{ptr_to_const(arg[:type])} #{arg_name}, size_t cmock_size)\n"
|
lines << "void #{func_name}_CMockReturnMemThruPtr_#{arg_name}(UNITY_LINE_TYPE cmock_line, #{ptr_to_const(arg[:type])} #{arg_name}, size_t cmock_size)\n"
|
||||||
lines << "{\n"
|
lines << "{\n"
|
||||||
|
lines << " TEST_MESSAGE(\"CMock: #{func_name}_ReturnThruPtr_#{arg_name} called\");\n" if @debug_output
|
||||||
lines << " CMOCK_#{func_name}_CALL_INSTANCE* cmock_call_instance = " \
|
lines << " CMOCK_#{func_name}_CALL_INSTANCE* cmock_call_instance = " \
|
||||||
"(CMOCK_#{func_name}_CALL_INSTANCE*)CMock_Guts_GetAddressFor(CMock_Guts_MemEndOfChain(Mock.#{func_name}_CallInstance));\n"
|
"(CMOCK_#{func_name}_CALL_INSTANCE*)CMock_Guts_GetAddressFor(CMock_Guts_MemEndOfChain(Mock.#{func_name}_CallInstance));\n"
|
||||||
if @ignore_used
|
if @ignore_used
|
||||||
|
|||||||
@@ -25,12 +25,13 @@ class CMockGeneratorUtils
|
|||||||
end
|
end
|
||||||
|
|
||||||
def self.arg_type_with_const(arg)
|
def self.arg_type_with_const(arg)
|
||||||
# Restore any "const" that was removed in header parsing
|
# Restore any "const" or "volatile" that was removed in header parsing
|
||||||
if arg[:type].include?('*')
|
type = if arg[:type].include?('*')
|
||||||
arg[:const_ptr?] ? "#{arg[:type]} const" : arg[:type]
|
arg[:const_ptr?] ? "#{arg[:type]} const" : arg[:type]
|
||||||
else
|
else
|
||||||
arg[:const?] ? "const #{arg[:type]}" : arg[:type]
|
arg[:const?] ? "const #{arg[:type]}" : arg[:type]
|
||||||
end
|
end
|
||||||
|
arg[:volatile?] ? "volatile #{type}" : type
|
||||||
end
|
end
|
||||||
|
|
||||||
def arg_type_with_const(arg)
|
def arg_type_with_const(arg)
|
||||||
|
|||||||
+72
-10
@@ -15,7 +15,7 @@ class CMockHeaderParser
|
|||||||
@c_calling_conventions = cfg.c_calling_conventions.uniq
|
@c_calling_conventions = cfg.c_calling_conventions.uniq
|
||||||
@treat_as_array = cfg.treat_as_array
|
@treat_as_array = cfg.treat_as_array
|
||||||
@treat_as_void = (['void'] + cfg.treat_as_void).uniq
|
@treat_as_void = (['void'] + cfg.treat_as_void).uniq
|
||||||
@function_declaration_parse_base_match = '([\w\s\*\(\),\[\]]*?\w[\w\s\*\(\),\[\]]*?)\(([\w\s\*\(\),\.\[\]+\-\/]*)\)'
|
@function_declaration_parse_base_match = '([^(]*\w)\s*\(([\w\s\*\(\),\.\[\]+\-\/]*)\)'
|
||||||
@declaration_parse_matcher = /#{@function_declaration_parse_base_match}$/m
|
@declaration_parse_matcher = /#{@function_declaration_parse_base_match}$/m
|
||||||
@standards = (%w[int short char long unsigned signed] + cfg.treat_as.keys).uniq
|
@standards = (%w[int short char long unsigned signed] + cfg.treat_as.keys).uniq
|
||||||
@array_size_name = cfg.array_size_name
|
@array_size_name = cfg.array_size_name
|
||||||
@@ -26,6 +26,7 @@ class CMockHeaderParser
|
|||||||
@treat_externs = cfg.treat_externs
|
@treat_externs = cfg.treat_externs
|
||||||
@treat_inlines = cfg.treat_inlines
|
@treat_inlines = cfg.treat_inlines
|
||||||
@inline_function_patterns = cfg.inline_function_patterns
|
@inline_function_patterns = cfg.inline_function_patterns
|
||||||
|
@ct_assert_patterns = cfg.ct_assert_patterns
|
||||||
@c_strippables += ['extern'] if @treat_externs == :include # we'll need to remove the attribute if we're allowing externs
|
@c_strippables += ['extern'] if @treat_externs == :include # we'll need to remove the attribute if we're allowing externs
|
||||||
@c_strippables += ['inline'] if @treat_inlines == :include # we'll need to remove the attribute if we're allowing inlines
|
@c_strippables += ['inline'] if @treat_inlines == :include # we'll need to remove the attribute if we're allowing inlines
|
||||||
end
|
end
|
||||||
@@ -64,6 +65,48 @@ class CMockHeaderParser
|
|||||||
|
|
||||||
private if $ThisIsOnlyATest.nil? ################
|
private if $ThisIsOnlyATest.nil? ################
|
||||||
|
|
||||||
|
# Remove code disabled by basic preprocesser tags like #if 0, #if 1, etc.
|
||||||
|
def remove_disabled_code_from_source(source)
|
||||||
|
result = []
|
||||||
|
emit = true
|
||||||
|
# Stack entries: [restore_emit, else_emit, seen_else]
|
||||||
|
# restore_emit: value to restore `emit` to after matching #endif
|
||||||
|
# else_emit: value to set `emit` to after #else
|
||||||
|
# seen_else: whether #else at this level has already been seen
|
||||||
|
stack = []
|
||||||
|
|
||||||
|
source.each_line do |line|
|
||||||
|
stripped = line.strip
|
||||||
|
if stripped =~ /^#\s*if\s+0\s*$/
|
||||||
|
stack.push([emit, emit, false])
|
||||||
|
emit = false
|
||||||
|
elsif stripped =~ /^#\s*if\s+1\s*$/
|
||||||
|
stack.push([emit, false, false])
|
||||||
|
# emit unchanged: keep the if-branch
|
||||||
|
elsif stripped =~ /^#\s*if/
|
||||||
|
stack.push([emit, emit, false])
|
||||||
|
# emit unchanged: unknown condition, keep both branches
|
||||||
|
elsif stripped =~ /^#\s*else\b/
|
||||||
|
unless stack.empty?
|
||||||
|
entry = stack.last
|
||||||
|
unless entry[2]
|
||||||
|
stack[-1] = [entry[0], entry[1], true]
|
||||||
|
emit = entry[1]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elsif stripped =~ /^#\s*endif\b/
|
||||||
|
unless stack.empty?
|
||||||
|
entry = stack.pop
|
||||||
|
emit = entry[0]
|
||||||
|
end
|
||||||
|
elsif emit
|
||||||
|
result << line
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
result.join
|
||||||
|
end
|
||||||
|
|
||||||
# Remove C/C++ comments from a string
|
# Remove C/C++ comments from a string
|
||||||
# +source+:: String which will have the comments removed
|
# +source+:: String which will have the comments removed
|
||||||
def remove_comments_from_source(source)
|
def remove_comments_from_source(source)
|
||||||
@@ -75,15 +118,13 @@ class CMockHeaderParser
|
|||||||
|
|
||||||
def remove_nested_pairs_of_braces(source)
|
def remove_nested_pairs_of_braces(source)
|
||||||
# remove nested pairs of braces because no function declarations will be inside of them (leave outer pair for function definition detection)
|
# remove nested pairs of braces because no function declarations will be inside of them (leave outer pair for function definition detection)
|
||||||
if RUBY_VERSION.split('.')[0].to_i > 1
|
# Collapse innermost brace pairs first using a brace-free sentinel (\x00), working
|
||||||
# we assign a string first because (no joke) if Ruby 1.9.3 sees this line as a regex, it will crash.
|
# outward until no balanced pairs remain. This avoids the catastrophic backtracking
|
||||||
r = '\\{([^\\{\\}]*|\\g<0>)*\\}'
|
# of the recursive regex \{([^\{\}]*|\g<0>)*\} on Ruby < 3.2 while preserving
|
||||||
source.gsub!(/#{r}/m, '{ }')
|
# identical semantics: every balanced brace structure is collapsed to '{ }'.
|
||||||
else
|
while source.gsub!(/\{[^{}]*\}/m, "\x00")
|
||||||
while source.gsub!(/\{[^{}]*\{[^{}]*\}[^{}]*\}/m, '{ }')
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
source.gsub!("\x00", '{ }')
|
||||||
source
|
source
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -248,6 +289,10 @@ class CMockHeaderParser
|
|||||||
|
|
||||||
# remove preprocessor statements and extern "C"
|
# remove preprocessor statements and extern "C"
|
||||||
source.gsub!(/extern\s+"C"\s*\{/, '')
|
source.gsub!(/extern\s+"C"\s*\{/, '')
|
||||||
|
|
||||||
|
# handle basic literal preprocessor conditionals before stripping all directives
|
||||||
|
source = remove_disabled_code_from_source(source)
|
||||||
|
|
||||||
source.gsub!(/^\s*#.*/, '')
|
source.gsub!(/^\s*#.*/, '')
|
||||||
|
|
||||||
# enums, unions, structs, and typedefs can all contain things (e.g. function pointers) that parse like function prototypes, so yank them
|
# enums, unions, structs, and typedefs can all contain things (e.g. function pointers) that parse like function prototypes, so yank them
|
||||||
@@ -260,6 +305,12 @@ class CMockHeaderParser
|
|||||||
source.gsub!(/(\W)(?:register|auto|restrict)(\W)/, '\1\2')
|
source.gsub!(/(\W)(?:register|auto|restrict)(\W)/, '\1\2')
|
||||||
source.gsub!(/(\W)(?:static)(\W)/, '\1\2') unless cpp
|
source.gsub!(/(\W)(?:static)(\W)/, '\1\2') unless cpp
|
||||||
|
|
||||||
|
# strip calls to known compile-time assertion macros by name -- never function prototypes regardless of argument form
|
||||||
|
source.gsub!(/\b(?:#{@ct_assert_patterns.join('|')})\s*\([^;]*\)/, '') unless @ct_assert_patterns.empty?
|
||||||
|
# strip any remaining WORD(...==...) etc. -- calls containing comparison operators cannot be C function prototypes
|
||||||
|
# must run before default-value removal, which would corrupt "!= 0" into "!" by removing "= 0"
|
||||||
|
source.gsub!(/\b\w+\s*\((?:[^()!=<>]|\([^()]*\))*(?:==|!=|<=|>=)[^;]*\)/, '')
|
||||||
|
|
||||||
source.gsub!(/\s*=\s*['"a-zA-Z0-9_.]+\s*/, '') # remove default value statements from argument lists
|
source.gsub!(/\s*=\s*['"a-zA-Z0-9_.]+\s*/, '') # remove default value statements from argument lists
|
||||||
|
|
||||||
# strip macro decorator patterns that cannot be C function prototypes.
|
# strip macro decorator patterns that cannot be C function prototypes.
|
||||||
@@ -277,7 +328,7 @@ class CMockHeaderParser
|
|||||||
source.gsub!(/(^|\W+)(?:#{@c_strippables.join('|')})(?=$|\W+)/, '\1') unless @c_strippables.empty? # remove known attributes slated to be stripped
|
source.gsub!(/(^|\W+)(?:#{@c_strippables.join('|')})(?=$|\W+)/, '\1') unless @c_strippables.empty? # remove known attributes slated to be stripped
|
||||||
|
|
||||||
# scan standalone function pointers and remove them, because they can just be ignored
|
# scan standalone function pointers and remove them, because they can just be ignored
|
||||||
source.gsub!(/\w+\s*\(\s*\*\s*\w+\s*\)\s*\([^)]*\)\s*;/, ';')
|
source.gsub!(/\w[\w\s*]*\(\s*\*\s*\w+\s*\)\s*\([^)]*\)\s*;/, ';')
|
||||||
|
|
||||||
# scan for functions which return function pointers, because they are a pain
|
# scan for functions which return function pointers, because they are a pain
|
||||||
source.gsub!(/([\w\s*]+)\(*\(\s*\*([\w\s*]+)\s*\(([\w\s*,]*)\)\)\s*\(([\w\s*,]*)\)\)*/) do |_m|
|
source.gsub!(/([\w\s*]+)\(*\(\s*\*([\w\s*]+)\s*\(([\w\s*,]*)\)\)\s*\(([\w\s*,]*)\)\)*/) do |_m|
|
||||||
@@ -449,6 +500,11 @@ class CMockHeaderParser
|
|||||||
arg_info.delete(:modifier) # don't care about this
|
arg_info.delete(:modifier) # don't care about this
|
||||||
arg_info.delete(:c_calling_convention) # don't care about this
|
arg_info.delete(:c_calling_convention) # don't care about this
|
||||||
|
|
||||||
|
# Strip volatile from pointer-to-volatile arg types so internal storage and
|
||||||
|
# comparisons use the clean type; volatile? flag lets generators reconstruct
|
||||||
|
# it where needed (e.g. function signatures via arg_type_with_const).
|
||||||
|
arg_info[:type] = arg_info[:type].gsub(/\bvolatile\s*/, '').gsub(/\s+\*/, '*').strip if arg_info[:volatile?]
|
||||||
|
|
||||||
arg_info[:array_dims] = array_dims_by_name[arg_info[:name]] if array_dims_by_name.key?(arg_info[:name])
|
arg_info[:array_dims] = array_dims_by_name[arg_info[:name]] if array_dims_by_name.key?(arg_info[:name])
|
||||||
|
|
||||||
# Handle pointer-to-array args: (*name)[dims] was rewritten to * name before clean_args
|
# Handle pointer-to-array args: (*name)[dims] was rewritten to * name before clean_args
|
||||||
@@ -542,12 +598,18 @@ class CMockHeaderParser
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def divine_volatile(arg)
|
||||||
|
# only flag pointer types where volatile applies to the pointed-to type (before the last *)
|
||||||
|
arg.include?('*') && (/(^|\s|\*)volatile(\s(\w|\s)*)?\*(?!.*\*)/ =~ arg ? true : false)
|
||||||
|
end
|
||||||
|
|
||||||
def divine_ptr_and_const(arg)
|
def divine_ptr_and_const(arg)
|
||||||
divination = {}
|
divination = {}
|
||||||
|
|
||||||
divination[:ptr?] = divine_ptr(arg)
|
divination[:ptr?] = divine_ptr(arg)
|
||||||
divination[:string?] = !divination[:ptr?] && (/(^|\s)(const\s+)?char(\s+const)?\s*\*(?!.*\*)/ =~ arg ? true : false)
|
divination[:string?] = !divination[:ptr?] && (/(^|\s)(const\s+)?char(\s+const)?\s*\*(?!.*\*)/ =~ arg ? true : false)
|
||||||
divination[:const?] = divine_const(arg)
|
divination[:const?] = divine_const(arg)
|
||||||
|
divination[:volatile?] = true if divine_volatile(arg)
|
||||||
|
|
||||||
# an arg containing "const" after the last * is a constant pointer
|
# an arg containing "const" after the last * is a constant pointer
|
||||||
divination[:const_ptr?] = /\*(?!.*\*)\s*const(\s|$)/ =~ arg ? true : false
|
divination[:const_ptr?] = /\*(?!.*\*)\s*const(\s|$)/ =~ arg ? true : false
|
||||||
|
|||||||
@@ -25,8 +25,12 @@ const char* CMockStringMismatch = "Function called with unexpected argument v
|
|||||||
static unsigned char* CMock_Guts_Buffer = NULL;
|
static unsigned char* CMock_Guts_Buffer = NULL;
|
||||||
static CMOCK_MEM_INDEX_TYPE CMock_Guts_BufferSize = CMOCK_MEM_ALIGN_SIZE;
|
static CMOCK_MEM_INDEX_TYPE CMock_Guts_BufferSize = CMOCK_MEM_ALIGN_SIZE;
|
||||||
static CMOCK_MEM_INDEX_TYPE CMock_Guts_FreePtr = CMOCK_MEM_ALIGN_SIZE;
|
static CMOCK_MEM_INDEX_TYPE CMock_Guts_FreePtr = CMOCK_MEM_ALIGN_SIZE;
|
||||||
|
#else
|
||||||
|
#if !defined(UNITY_EXCLUDE_STDDEF_H) && defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
|
||||||
|
static _Alignas(max_align_t) long long CMock_Guts_Space[(CMOCK_MEM_SIZE + CMOCK_MEM_ALIGN_SIZE + sizeof(long long) - 1) / sizeof(long long)];
|
||||||
#else
|
#else
|
||||||
static long long CMock_Guts_Space[(CMOCK_MEM_SIZE + CMOCK_MEM_ALIGN_SIZE + sizeof(long long) - 1) / sizeof(long long)];
|
static long long CMock_Guts_Space[(CMOCK_MEM_SIZE + CMOCK_MEM_ALIGN_SIZE + sizeof(long long) - 1) / sizeof(long long)];
|
||||||
|
#endif
|
||||||
static unsigned char* CMock_Guts_Buffer = (unsigned char*)CMock_Guts_Space;
|
static unsigned char* CMock_Guts_Buffer = (unsigned char*)CMock_Guts_Space;
|
||||||
static CMOCK_MEM_INDEX_TYPE CMock_Guts_BufferSize = CMOCK_MEM_SIZE + CMOCK_MEM_ALIGN_SIZE;//sizeof(CMock_Guts_Space);
|
static CMOCK_MEM_INDEX_TYPE CMock_Guts_BufferSize = CMOCK_MEM_SIZE + CMOCK_MEM_ALIGN_SIZE;//sizeof(CMock_Guts_Space);
|
||||||
static CMOCK_MEM_INDEX_TYPE CMock_Guts_FreePtr = CMOCK_MEM_ALIGN_SIZE;
|
static CMOCK_MEM_INDEX_TYPE CMock_Guts_FreePtr = CMOCK_MEM_ALIGN_SIZE;
|
||||||
|
|||||||
+2
-2
@@ -11,8 +11,8 @@
|
|||||||
#include "cmock_internals.h"
|
#include "cmock_internals.h"
|
||||||
|
|
||||||
#define CMOCK_VERSION_MAJOR 2
|
#define CMOCK_VERSION_MAJOR 2
|
||||||
#define CMOCK_VERSION_MINOR 6
|
#define CMOCK_VERSION_MINOR 7
|
||||||
#define CMOCK_VERSION_BUILD 4
|
#define CMOCK_VERSION_BUILD 0
|
||||||
#define CMOCK_VERSION ((CMOCK_VERSION_MAJOR << 16) | (CMOCK_VERSION_MINOR << 8) | CMOCK_VERSION_BUILD)
|
#define CMOCK_VERSION ((CMOCK_VERSION_MAJOR << 16) | (CMOCK_VERSION_MINOR << 8) | CMOCK_VERSION_BUILD)
|
||||||
|
|
||||||
/* should be big enough to index full range of CMOCK_MEM_MAX */
|
/* should be big enough to index full range of CMOCK_MEM_MAX */
|
||||||
|
|||||||
@@ -76,6 +76,18 @@ extern const char* CMockStringMismatch;
|
|||||||
#else
|
#else
|
||||||
#define CMOCK_MEM_ALIGN (2)
|
#define CMOCK_MEM_ALIGN (2)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Boost to 8-byte alignment when 64-bit integers or doubles are enabled,
|
||||||
|
* since those types require 8-byte alignment even on 32-bit platforms */
|
||||||
|
#if CMOCK_MEM_ALIGN < 3
|
||||||
|
#if defined(UNITY_SUPPORT_64) || defined(UNITY_INCLUDE_DOUBLE)
|
||||||
|
#undef CMOCK_MEM_ALIGN
|
||||||
|
#define CMOCK_MEM_ALIGN (3)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* sentinel: CMOCK_MEM_ALIGN was auto-detected (not user-supplied) */
|
||||||
|
#define CMOCK_MEM_ALIGN_AUTO
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* amount of memory to allow cmock to use in its internal heap */
|
/* amount of memory to allow cmock to use in its internal heap */
|
||||||
@@ -98,6 +110,17 @@ extern const char* CMockStringMismatch;
|
|||||||
/* automatically calculated defs for easier reading */
|
/* automatically calculated defs for easier reading */
|
||||||
#define CMOCK_MEM_ALIGN_SIZE (CMOCK_MEM_INDEX_TYPE)(1u << CMOCK_MEM_ALIGN)
|
#define CMOCK_MEM_ALIGN_SIZE (CMOCK_MEM_INDEX_TYPE)(1u << CMOCK_MEM_ALIGN)
|
||||||
#define CMOCK_MEM_ALIGN_MASK (CMOCK_MEM_INDEX_TYPE)(CMOCK_MEM_ALIGN_SIZE - 1)
|
#define CMOCK_MEM_ALIGN_MASK (CMOCK_MEM_INDEX_TYPE)(CMOCK_MEM_ALIGN_SIZE - 1)
|
||||||
|
|
||||||
|
/* When CMOCK_MEM_ALIGN was auto-detected and stddef.h is available (C11+),
|
||||||
|
* use sizeof(max_align_t) to guarantee alignment is sufficient for all
|
||||||
|
* fundamental types on this platform, taking the larger of the two values */
|
||||||
|
#if defined(CMOCK_MEM_ALIGN_AUTO) && !defined(UNITY_EXCLUDE_STDDEF_H) && defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
|
||||||
|
#undef CMOCK_MEM_ALIGN_SIZE
|
||||||
|
#undef CMOCK_MEM_ALIGN_MASK
|
||||||
|
#define CMOCK_MEM_ALIGN_SIZE (CMOCK_MEM_INDEX_TYPE)(sizeof(max_align_t) > (1u << CMOCK_MEM_ALIGN) ? sizeof(max_align_t) : (1u << CMOCK_MEM_ALIGN))
|
||||||
|
#define CMOCK_MEM_ALIGN_MASK (CMOCK_MEM_INDEX_TYPE)(CMOCK_MEM_ALIGN_SIZE - 1)
|
||||||
|
#endif
|
||||||
|
|
||||||
#define CMOCK_MEM_INDEX_SIZE (CMOCK_MEM_INDEX_TYPE)(CMOCK_MEM_PTR_AS_INT)((sizeof(CMOCK_MEM_INDEX_TYPE) > CMOCK_MEM_ALIGN_SIZE) ? sizeof(CMOCK_MEM_INDEX_TYPE) : CMOCK_MEM_ALIGN_SIZE)
|
#define CMOCK_MEM_INDEX_SIZE (CMOCK_MEM_INDEX_TYPE)(CMOCK_MEM_PTR_AS_INT)((sizeof(CMOCK_MEM_INDEX_TYPE) > CMOCK_MEM_ALIGN_SIZE) ? sizeof(CMOCK_MEM_INDEX_TYPE) : CMOCK_MEM_ALIGN_SIZE)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
# =========================================================================
|
||||||
|
# CMock - Automatic Mock Generation for C
|
||||||
|
# ThrowTheSwitch.org
|
||||||
|
# Copyright (c) 2007-26 Mike Karlesky, Mark VanderVoord, & Greg Williams
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
# =========================================================================
|
||||||
|
|
||||||
|
# gcc_64 with debug symbols enabled for meaningful valgrind output.
|
||||||
|
# Used by the CI valgrind job to check for memory leaks and errors.
|
||||||
|
|
||||||
|
---
|
||||||
|
:tools:
|
||||||
|
:test_compiler:
|
||||||
|
:name: compiler
|
||||||
|
:executable: gcc
|
||||||
|
:arguments:
|
||||||
|
- "-c"
|
||||||
|
- "-m64"
|
||||||
|
- "-g"
|
||||||
|
- "-Wall"
|
||||||
|
- "-Wno-address"
|
||||||
|
- "-std=c99"
|
||||||
|
- "-pedantic"
|
||||||
|
- '-I"${5}"'
|
||||||
|
- "-D${6}"
|
||||||
|
- "${1}"
|
||||||
|
- "-o ${2}"
|
||||||
|
:test_linker:
|
||||||
|
:name: linker
|
||||||
|
:executable: gcc
|
||||||
|
:arguments:
|
||||||
|
- "${1}"
|
||||||
|
- "-lm"
|
||||||
|
- "-m64"
|
||||||
|
- "-o ${2}"
|
||||||
|
:extension:
|
||||||
|
:object: ".o"
|
||||||
|
:executable: ".exe"
|
||||||
|
:defines:
|
||||||
|
:test:
|
||||||
|
- UNITY_EXCLUDE_STDINT_H
|
||||||
|
- UNITY_EXCLUDE_LIMITS_H
|
||||||
|
- UNITY_INCLUDE_DOUBLE
|
||||||
|
- UNITY_SUPPORT_TEST_CASES
|
||||||
|
- UNITY_SUPPORT_64
|
||||||
|
- UNITY_INT_WIDTH=32
|
||||||
|
- UNITY_LONG_WIDTH=64
|
||||||
|
- UNITY_POINTER_WIDTH=64
|
||||||
@@ -80,7 +80,7 @@ module RakefileHelpers
|
|||||||
raise "Cannot find Config File #{config_target}"
|
raise "Cannot find Config File #{config_target}"
|
||||||
end
|
end
|
||||||
|
|
||||||
$colour_output = $proj[:project][:colour]
|
$colour_output = $proj[:project][:colour] && !ENV['NO_COLOR']
|
||||||
end
|
end
|
||||||
|
|
||||||
def configure_clean
|
def configure_clean
|
||||||
@@ -411,7 +411,9 @@ module RakefileHelpers
|
|||||||
|
|
||||||
test_file = 'test_' + File.basename(test_case).ext(C_EXTENSION)
|
test_file = 'test_' + File.basename(test_case).ext(C_EXTENSION)
|
||||||
result_file = test_file.ext(RESULT_EXTENSION)
|
result_file = test_file.ext(RESULT_EXTENSION)
|
||||||
test_results = File.readlines(SYSTEST_BUILD_FILES_PATH + result_file).reject {|line| line.size < 10 }
|
all_results = File.readlines(SYSTEST_BUILD_FILES_PATH + result_file).reject {|line| line.size < 10 }
|
||||||
|
info_results = all_results.select {|line| line =~ /:INFO:/}
|
||||||
|
test_results = all_results.reject {|line| line =~ /:INFO:/}
|
||||||
tests.each_with_index do |test, index|
|
tests.each_with_index do |test, index|
|
||||||
this_failed = case(test[:pass])
|
this_failed = case(test[:pass])
|
||||||
when :ignore
|
when :ignore
|
||||||
@@ -432,6 +434,11 @@ module RakefileHelpers
|
|||||||
new_msg = "#{test_file}:test#{index+1}:should #{test[:should]}:should have output matching '#{test[:verify_error]}' but was '#{test_results[index]}'"
|
new_msg = "#{test_file}:test#{index+1}:should #{test[:should]}:should have output matching '#{test[:verify_error]}' but was '#{test_results[index]}'"
|
||||||
failure_messages << new_msg
|
failure_messages << new_msg
|
||||||
report new_msg
|
report new_msg
|
||||||
|
elsif (test[:verify_message]) and not info_results.any? {|line| line =~ /test#{index+1}:INFO:.*#{test[:verify_message]}/}
|
||||||
|
total_failures += 1
|
||||||
|
new_msg = "#{test_file}:test#{index+1}:should #{test[:should]}:should have message matching '#{test[:verify_message]}' but none found in: #{info_results.select{|l| l =~ /test#{index+1}:/}.inspect}"
|
||||||
|
failure_messages << new_msg
|
||||||
|
report new_msg
|
||||||
else
|
else
|
||||||
report "#{test_file}:test#{index+1}:should #{test[:should]}:PASS"
|
report "#{test_file}:test#{index+1}:should #{test[:should]}:PASS"
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -0,0 +1,235 @@
|
|||||||
|
# =========================================================================
|
||||||
|
# CMock - Automatic Mock Generation for C
|
||||||
|
# ThrowTheSwitch.org
|
||||||
|
# Copyright (c) 2007-26 Mike Karlesky, Mark VanderVoord, & Greg Williams
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
# =========================================================================
|
||||||
|
|
||||||
|
---
|
||||||
|
:cmock:
|
||||||
|
:debug_output: true
|
||||||
|
:plugins:
|
||||||
|
- :ignore
|
||||||
|
- :callback
|
||||||
|
- :expect_any_args
|
||||||
|
- :return_thru_ptr
|
||||||
|
- :ignore_arg
|
||||||
|
|
||||||
|
:systest:
|
||||||
|
:types: |
|
||||||
|
|
||||||
|
:mockable: |
|
||||||
|
void foo(int a);
|
||||||
|
int bar(void);
|
||||||
|
int qux(int a);
|
||||||
|
void baz(int* p);
|
||||||
|
|
||||||
|
:source:
|
||||||
|
:header: |
|
||||||
|
void function(int a);
|
||||||
|
:code: |
|
||||||
|
void function(int a)
|
||||||
|
{
|
||||||
|
int temp = 0;
|
||||||
|
foo(a);
|
||||||
|
foo(bar());
|
||||||
|
qux(a);
|
||||||
|
baz(&temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
:tests:
|
||||||
|
:common: |
|
||||||
|
void setUp(void) {}
|
||||||
|
void tearDown(void) {}
|
||||||
|
void my_foo_callback(int a, int cmock_num_calls) { (void)a; (void)cmock_num_calls; }
|
||||||
|
|
||||||
|
:units:
|
||||||
|
- :pass: TRUE
|
||||||
|
:should: 'output a debug message when foo_Expect is called'
|
||||||
|
:verify_message: 'CMock: foo_Expect called'
|
||||||
|
:code: |
|
||||||
|
test()
|
||||||
|
{
|
||||||
|
foo_Expect(1);
|
||||||
|
foo_Expect(42);
|
||||||
|
bar_ExpectAndReturn(42);
|
||||||
|
qux_IgnoreAndReturn(0);
|
||||||
|
baz_Ignore();
|
||||||
|
function(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
- :pass: TRUE
|
||||||
|
:should: 'output a debug message when mock foo is called'
|
||||||
|
:verify_message: 'CMock: mock foo called'
|
||||||
|
:code: |
|
||||||
|
test()
|
||||||
|
{
|
||||||
|
foo_Expect(1);
|
||||||
|
foo_Expect(42);
|
||||||
|
bar_ExpectAndReturn(42);
|
||||||
|
qux_IgnoreAndReturn(0);
|
||||||
|
baz_Ignore();
|
||||||
|
function(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
- :pass: TRUE
|
||||||
|
:should: 'output a debug message when bar_ExpectAndReturn is called'
|
||||||
|
:verify_message: 'CMock: bar_ExpectAndReturn called'
|
||||||
|
:code: |
|
||||||
|
test()
|
||||||
|
{
|
||||||
|
foo_Expect(1);
|
||||||
|
foo_Expect(42);
|
||||||
|
bar_ExpectAndReturn(42);
|
||||||
|
qux_IgnoreAndReturn(0);
|
||||||
|
baz_Ignore();
|
||||||
|
function(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
- :pass: TRUE
|
||||||
|
:should: 'output a debug message when mock bar is called'
|
||||||
|
:verify_message: 'CMock: mock bar called'
|
||||||
|
:code: |
|
||||||
|
test()
|
||||||
|
{
|
||||||
|
foo_Expect(1);
|
||||||
|
foo_Expect(42);
|
||||||
|
bar_ExpectAndReturn(42);
|
||||||
|
qux_IgnoreAndReturn(0);
|
||||||
|
baz_Ignore();
|
||||||
|
function(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
- :pass: TRUE
|
||||||
|
:should: 'output a debug message when foo_Ignore is called'
|
||||||
|
:verify_message: 'CMock: foo_Ignore called'
|
||||||
|
:code: |
|
||||||
|
test()
|
||||||
|
{
|
||||||
|
foo_Ignore();
|
||||||
|
bar_ExpectAndReturn(42);
|
||||||
|
qux_IgnoreAndReturn(0);
|
||||||
|
baz_Ignore();
|
||||||
|
function(99);
|
||||||
|
}
|
||||||
|
|
||||||
|
- :pass: TRUE
|
||||||
|
:should: 'output a debug message when bar_IgnoreAndReturn is called'
|
||||||
|
:verify_message: 'CMock: bar_IgnoreAndReturn called'
|
||||||
|
:code: |
|
||||||
|
test()
|
||||||
|
{
|
||||||
|
foo_Expect(1);
|
||||||
|
foo_Expect(42);
|
||||||
|
bar_IgnoreAndReturn(42);
|
||||||
|
qux_IgnoreAndReturn(0);
|
||||||
|
baz_Ignore();
|
||||||
|
function(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
- :pass: TRUE
|
||||||
|
:should: 'output a debug message when foo_StopIgnore is called'
|
||||||
|
:verify_message: 'CMock: foo_StopIgnore called'
|
||||||
|
:code: |
|
||||||
|
test()
|
||||||
|
{
|
||||||
|
foo_Ignore();
|
||||||
|
foo_StopIgnore();
|
||||||
|
foo_Expect(1);
|
||||||
|
foo_Expect(42);
|
||||||
|
bar_ExpectAndReturn(42);
|
||||||
|
qux_IgnoreAndReturn(0);
|
||||||
|
baz_Ignore();
|
||||||
|
function(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
- :pass: TRUE
|
||||||
|
:should: 'output a debug message when foo_ExpectAnyArgs is called'
|
||||||
|
:verify_message: 'CMock: foo_ExpectAnyArgs called'
|
||||||
|
:code: |
|
||||||
|
test()
|
||||||
|
{
|
||||||
|
foo_ExpectAnyArgs();
|
||||||
|
foo_ExpectAnyArgs();
|
||||||
|
bar_ExpectAndReturn(42);
|
||||||
|
qux_IgnoreAndReturn(0);
|
||||||
|
baz_Ignore();
|
||||||
|
function(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
- :pass: TRUE
|
||||||
|
:should: 'output a debug message when qux_ExpectAnyArgsAndReturn is called'
|
||||||
|
:verify_message: 'CMock: qux_ExpectAnyArgsAndReturn called'
|
||||||
|
:code: |
|
||||||
|
test()
|
||||||
|
{
|
||||||
|
foo_Expect(1);
|
||||||
|
foo_Expect(42);
|
||||||
|
bar_ExpectAndReturn(42);
|
||||||
|
qux_ExpectAnyArgsAndReturn(0);
|
||||||
|
baz_Ignore();
|
||||||
|
function(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
- :pass: TRUE
|
||||||
|
:should: 'output a debug message when foo_AddCallback is called'
|
||||||
|
:verify_message: 'CMock: foo_AddCallback called'
|
||||||
|
:code: |
|
||||||
|
test()
|
||||||
|
{
|
||||||
|
foo_AddCallback(my_foo_callback);
|
||||||
|
foo_Expect(1);
|
||||||
|
foo_Expect(42);
|
||||||
|
bar_ExpectAndReturn(42);
|
||||||
|
qux_IgnoreAndReturn(0);
|
||||||
|
baz_Ignore();
|
||||||
|
function(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
- :pass: TRUE
|
||||||
|
:should: 'output a debug message when foo_Stub is called'
|
||||||
|
:verify_message: 'CMock: foo_Stub called'
|
||||||
|
:code: |
|
||||||
|
test()
|
||||||
|
{
|
||||||
|
foo_Stub(my_foo_callback);
|
||||||
|
bar_ExpectAndReturn(42);
|
||||||
|
qux_IgnoreAndReturn(0);
|
||||||
|
baz_Ignore();
|
||||||
|
function(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
- :pass: TRUE
|
||||||
|
:should: 'output a debug message when baz_ReturnThruPtr_p is called'
|
||||||
|
:verify_message: 'CMock: baz_ReturnThruPtr_p called'
|
||||||
|
:code: |
|
||||||
|
test()
|
||||||
|
{
|
||||||
|
int val = 99;
|
||||||
|
foo_Expect(1);
|
||||||
|
foo_Expect(42);
|
||||||
|
bar_ExpectAndReturn(42);
|
||||||
|
qux_IgnoreAndReturn(0);
|
||||||
|
baz_Expect(NULL);
|
||||||
|
baz_IgnoreArg_p();
|
||||||
|
baz_ReturnThruPtr_p(&val);
|
||||||
|
function(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
- :pass: TRUE
|
||||||
|
:should: 'output a debug message when foo_IgnoreArg_a is called'
|
||||||
|
:verify_message: 'CMock: foo_IgnoreArg_a called'
|
||||||
|
:code: |
|
||||||
|
test()
|
||||||
|
{
|
||||||
|
foo_Expect(999);
|
||||||
|
foo_IgnoreArg_a();
|
||||||
|
foo_Expect(999);
|
||||||
|
foo_IgnoreArg_a();
|
||||||
|
bar_ExpectAndReturn(42);
|
||||||
|
qux_IgnoreAndReturn(0);
|
||||||
|
baz_Ignore();
|
||||||
|
function(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
...
|
||||||
@@ -0,0 +1,291 @@
|
|||||||
|
# =========================================================================
|
||||||
|
# CMock - Automatic Mock Generation for C
|
||||||
|
# ThrowTheSwitch.org
|
||||||
|
# Copyright (c) 2007-26 Mike Karlesky, Mark VanderVoord, & Greg Williams
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
# =========================================================================
|
||||||
|
|
||||||
|
---
|
||||||
|
:cmock:
|
||||||
|
:mock_path: test/mocks
|
||||||
|
:mock_prefix: mock_
|
||||||
|
:plugins:
|
||||||
|
- :array
|
||||||
|
- :cexception
|
||||||
|
- :ignore
|
||||||
|
- :callback
|
||||||
|
- :return_thru_ptr
|
||||||
|
- :ignore_arg
|
||||||
|
- :expect_any_args
|
||||||
|
:callback_after_arg_check: true
|
||||||
|
:callback_include_count: false
|
||||||
|
|
||||||
|
:systest:
|
||||||
|
:types: |
|
||||||
|
typedef struct {
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
} point_t;
|
||||||
|
|
||||||
|
:mockable: |
|
||||||
|
#include "CException.h"
|
||||||
|
void update_point(volatile point_t *p);
|
||||||
|
void update_points(volatile point_t *p, int n);
|
||||||
|
void update_int(volatile int *v);
|
||||||
|
int get_value(volatile point_t *p);
|
||||||
|
void mixed_volatile(int a, volatile int *v);
|
||||||
|
|
||||||
|
:source:
|
||||||
|
:header: |
|
||||||
|
#include "CException.h"
|
||||||
|
|
||||||
|
:code: |
|
||||||
|
|
||||||
|
:tests:
|
||||||
|
:common: |
|
||||||
|
#include "CException.h"
|
||||||
|
void setUp(void) {}
|
||||||
|
void tearDown(void) {}
|
||||||
|
void my_update_point_callback(volatile point_t *p) { p->x += 1; }
|
||||||
|
void my_update_int_callback(volatile int *v) { *v = 99; }
|
||||||
|
void my_update_points_callback(volatile point_t *p, int n)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < n; i++) { p[i].x = 100 + i; }
|
||||||
|
}
|
||||||
|
|
||||||
|
:units:
|
||||||
|
|
||||||
|
# --- expect plugin (base) ---
|
||||||
|
|
||||||
|
- :pass: TRUE
|
||||||
|
:should: "Expect passes when volatile struct pointer arg matches"
|
||||||
|
:code: |
|
||||||
|
test()
|
||||||
|
{
|
||||||
|
volatile point_t p = { 1, 2 };
|
||||||
|
update_point_Expect(&p);
|
||||||
|
update_point(&p);
|
||||||
|
}
|
||||||
|
|
||||||
|
- :pass: FALSE
|
||||||
|
:should: "Expect fails when volatile struct pointer arg does not match"
|
||||||
|
:code: |
|
||||||
|
test()
|
||||||
|
{
|
||||||
|
volatile point_t p = { 1, 2 };
|
||||||
|
volatile point_t wrong = { 9, 9 };
|
||||||
|
update_point_Expect(&wrong);
|
||||||
|
update_point(&p);
|
||||||
|
}
|
||||||
|
|
||||||
|
- :pass: TRUE
|
||||||
|
:should: "ExpectAndReturn works with a volatile struct pointer arg"
|
||||||
|
:code: |
|
||||||
|
test()
|
||||||
|
{
|
||||||
|
volatile point_t p = { 5, 7 };
|
||||||
|
get_value_ExpectAndReturn(&p, 42);
|
||||||
|
TEST_ASSERT_EQUAL(42, get_value(&p));
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- return_thru_ptr plugin ---
|
||||||
|
|
||||||
|
- :pass: TRUE
|
||||||
|
:should: "ReturnThruPtr writes through a volatile struct pointer arg"
|
||||||
|
:code: |
|
||||||
|
test()
|
||||||
|
{
|
||||||
|
volatile point_t p = { 0, 0 };
|
||||||
|
point_t result = { 10, 20 };
|
||||||
|
update_point_Expect(&p);
|
||||||
|
update_point_ReturnThruPtr_p(&result);
|
||||||
|
update_point(&p);
|
||||||
|
TEST_ASSERT_EQUAL(10, p.x);
|
||||||
|
TEST_ASSERT_EQUAL(20, p.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
- :pass: TRUE
|
||||||
|
:should: "ReturnThruPtr writes through a volatile int pointer arg"
|
||||||
|
:code: |
|
||||||
|
test()
|
||||||
|
{
|
||||||
|
volatile int v = 0;
|
||||||
|
int result = 42;
|
||||||
|
update_int_Expect(&v);
|
||||||
|
update_int_ReturnThruPtr_v(&result);
|
||||||
|
update_int(&v);
|
||||||
|
TEST_ASSERT_EQUAL(42, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
- :pass: TRUE
|
||||||
|
:should: "ReturnThruPtr macros are defined for volatile pointer args"
|
||||||
|
:code: |
|
||||||
|
test()
|
||||||
|
{
|
||||||
|
#if !defined(update_point_ReturnThruPtr_p)
|
||||||
|
TEST_FAIL_MESSAGE("ReturnThruPtr not defined for volatile struct pointer arg.");
|
||||||
|
#endif
|
||||||
|
#if !defined(update_int_ReturnThruPtr_v)
|
||||||
|
TEST_FAIL_MESSAGE("ReturnThruPtr not defined for volatile int pointer arg.");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- array plugin ---
|
||||||
|
|
||||||
|
- :pass: TRUE
|
||||||
|
:should: "ExpectWithArray passes when all elements of a volatile array match"
|
||||||
|
:code: |
|
||||||
|
test()
|
||||||
|
{
|
||||||
|
volatile point_t p[3] = { {1,2}, {3,4}, {5,6} };
|
||||||
|
point_t expected[3] = { {1,2}, {3,4}, {5,6} };
|
||||||
|
update_points_ExpectWithArray(expected, 3, 3);
|
||||||
|
update_points(p, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
- :pass: FALSE
|
||||||
|
:should: "ExpectWithArray fails when one element of a volatile array does not match"
|
||||||
|
:code: |
|
||||||
|
test()
|
||||||
|
{
|
||||||
|
volatile point_t p[3] = { {1,2}, {3,4}, {5,6} };
|
||||||
|
point_t expected[3] = { {1,2}, {3,4}, {5,9} };
|
||||||
|
update_points_ExpectWithArray(expected, 3, 3);
|
||||||
|
update_points(p, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- ignore plugin ---
|
||||||
|
|
||||||
|
- :pass: TRUE
|
||||||
|
:should: "Ignore suppresses calls to a volatile-arg function"
|
||||||
|
:code: |
|
||||||
|
test()
|
||||||
|
{
|
||||||
|
volatile point_t p = { 1, 2 };
|
||||||
|
update_point_Ignore();
|
||||||
|
update_point(&p);
|
||||||
|
update_point(&p);
|
||||||
|
}
|
||||||
|
|
||||||
|
- :pass: TRUE
|
||||||
|
:should: "IgnoreAndReturn suppresses calls and returns value for volatile-arg function"
|
||||||
|
:code: |
|
||||||
|
test()
|
||||||
|
{
|
||||||
|
volatile point_t p = { 1, 2 };
|
||||||
|
get_value_IgnoreAndReturn(77);
|
||||||
|
TEST_ASSERT_EQUAL(77, get_value(&p));
|
||||||
|
TEST_ASSERT_EQUAL(77, get_value(&p));
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- ignore_arg plugin ---
|
||||||
|
|
||||||
|
- :pass: TRUE
|
||||||
|
:should: "IgnoreArg allows any value for the volatile pointer arg"
|
||||||
|
:code: |
|
||||||
|
test()
|
||||||
|
{
|
||||||
|
volatile int v1 = 10;
|
||||||
|
volatile int v2 = 20;
|
||||||
|
mixed_volatile_Expect(5, &v1);
|
||||||
|
mixed_volatile_IgnoreArg_v();
|
||||||
|
mixed_volatile(5, &v2);
|
||||||
|
}
|
||||||
|
|
||||||
|
- :pass: FALSE
|
||||||
|
:should: "IgnoreArg ignores volatile arg but still checks other args"
|
||||||
|
:code: |
|
||||||
|
test()
|
||||||
|
{
|
||||||
|
volatile int v = 10;
|
||||||
|
mixed_volatile_Expect(5, &v);
|
||||||
|
mixed_volatile_IgnoreArg_v();
|
||||||
|
mixed_volatile(99, &v);
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- expect_any_args plugin ---
|
||||||
|
|
||||||
|
- :pass: TRUE
|
||||||
|
:should: "ExpectAnyArgs accepts any volatile array regardless of contents"
|
||||||
|
:code: |
|
||||||
|
test()
|
||||||
|
{
|
||||||
|
volatile point_t p1[2] = { {1,2}, {3,4} };
|
||||||
|
volatile point_t p2[2] = { {9,9}, {8,8} };
|
||||||
|
update_points_ExpectAnyArgs();
|
||||||
|
update_points_ExpectAnyArgs();
|
||||||
|
update_points(p1, 2);
|
||||||
|
update_points(p2, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
- :pass: TRUE
|
||||||
|
:should: "ExpectAnyArgsAndReturn works with a volatile array arg"
|
||||||
|
:code: |
|
||||||
|
test()
|
||||||
|
{
|
||||||
|
volatile point_t p[2] = { {1,2}, {3,4} };
|
||||||
|
get_value_ExpectAnyArgsAndReturn(55);
|
||||||
|
TEST_ASSERT_EQUAL(55, get_value(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
- :pass: TRUE
|
||||||
|
:should: "ExpectAnyArgs and ReturnThruPtr can be combined on a volatile pointer arg"
|
||||||
|
:code: |
|
||||||
|
test()
|
||||||
|
{
|
||||||
|
volatile point_t p = { 0, 0 };
|
||||||
|
point_t result = { 7, 8 };
|
||||||
|
update_point_ExpectAnyArgs();
|
||||||
|
update_point_ReturnThruPtr_p(&result);
|
||||||
|
update_point(&p);
|
||||||
|
TEST_ASSERT_EQUAL(7, p.x);
|
||||||
|
TEST_ASSERT_EQUAL(8, p.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- callback plugin ---
|
||||||
|
|
||||||
|
- :pass: TRUE
|
||||||
|
:should: "StubWithCallback can read and write all elements of a volatile array"
|
||||||
|
:code: |
|
||||||
|
test()
|
||||||
|
{
|
||||||
|
volatile point_t p[3] = { {0,0}, {0,0}, {0,0} };
|
||||||
|
point_t expected[3] = { {0,0}, {0,0}, {0,0} };
|
||||||
|
update_points_Expect(expected, 3);
|
||||||
|
update_points_StubWithCallback(my_update_points_callback);
|
||||||
|
update_points(p, 3);
|
||||||
|
TEST_ASSERT_EQUAL(100, p[0].x);
|
||||||
|
TEST_ASSERT_EQUAL(101, p[1].x);
|
||||||
|
TEST_ASSERT_EQUAL(102, p[2].x);
|
||||||
|
}
|
||||||
|
|
||||||
|
- :pass: TRUE
|
||||||
|
:should: "StubWithCallback receives a volatile int pointer and can modify it"
|
||||||
|
:code: |
|
||||||
|
test()
|
||||||
|
{
|
||||||
|
volatile int v = 0;
|
||||||
|
update_int_Expect(&v);
|
||||||
|
update_int_StubWithCallback(my_update_int_callback);
|
||||||
|
update_int(&v);
|
||||||
|
TEST_ASSERT_EQUAL(99, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- cexception plugin ---
|
||||||
|
|
||||||
|
- :pass: TRUE
|
||||||
|
:should: "ExpectAndThrow throws when a volatile-arg function is called"
|
||||||
|
:code: |
|
||||||
|
test()
|
||||||
|
{
|
||||||
|
CEXCEPTION_T e = 0;
|
||||||
|
volatile point_t p = { 1, 2 };
|
||||||
|
update_point_ExpectAndThrow(&p, 42);
|
||||||
|
Try {
|
||||||
|
update_point(&p);
|
||||||
|
TEST_FAIL_MESSAGE("Expected exception was not thrown.");
|
||||||
|
} Catch(e) {
|
||||||
|
TEST_ASSERT_EQUAL(42, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -50,6 +50,7 @@ describe CMockGenerator, "Verify CMockGenerator Module" do
|
|||||||
@config.expect :fail_on_unexpected_calls, true
|
@config.expect :fail_on_unexpected_calls, true
|
||||||
@config.expect :treat_inlines, :exclude
|
@config.expect :treat_inlines, :exclude
|
||||||
@config.expect :exclude_setjmp_h, false
|
@config.expect :exclude_setjmp_h, false
|
||||||
|
@config.expect :debug_output, false
|
||||||
@cmock_generator = CMockGenerator.new(@config, @file_writer, @utils, @plugins)
|
@cmock_generator = CMockGenerator.new(@config, @file_writer, @utils, @plugins)
|
||||||
@cmock_generator.module_name = @module_name
|
@cmock_generator.module_name = @module_name
|
||||||
@cmock_generator.module_ext = '.h'
|
@cmock_generator.module_ext = '.h'
|
||||||
@@ -71,6 +72,7 @@ describe CMockGenerator, "Verify CMockGenerator Module" do
|
|||||||
@config.expect :fail_on_unexpected_calls, true
|
@config.expect :fail_on_unexpected_calls, true
|
||||||
@config.expect :treat_inlines, :exclude
|
@config.expect :treat_inlines, :exclude
|
||||||
@config.expect :exclude_setjmp_h, false
|
@config.expect :exclude_setjmp_h, false
|
||||||
|
@config.expect :debug_output, false
|
||||||
@cmock_generator_strict = CMockGenerator.new(@config, @file_writer, @utils, @plugins)
|
@cmock_generator_strict = CMockGenerator.new(@config, @file_writer, @utils, @plugins)
|
||||||
|
|
||||||
@test_project = {
|
@test_project = {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ describe CMockGeneratorPluginExpectAnyArgs, "Verify Generation Of Mock Function
|
|||||||
|
|
||||||
before do
|
before do
|
||||||
create_mocks :config, :utils
|
create_mocks :config, :utils
|
||||||
@config = create_stub(:respond_to? => true, :create_error_stubs => false)
|
@config = create_stub(:respond_to? => true, :create_error_stubs => false, :debug_output => false)
|
||||||
@cmock_generator_plugin_expect_any_args = CMockGeneratorPluginExpectAnyArgs.new(@config, @utils)
|
@cmock_generator_plugin_expect_any_args = CMockGeneratorPluginExpectAnyArgs.new(@config, @utils)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,8 @@ describe CMockGeneratorPluginExpect, "Verify Generation Of Mock Function Declara
|
|||||||
:enforce_strict_ordering => false,
|
:enforce_strict_ordering => false,
|
||||||
:respond_to? => true,
|
:respond_to? => true,
|
||||||
:create_error_stubs => false,
|
:create_error_stubs => false,
|
||||||
:plugins => [ :expect ] )
|
:plugins => [ :expect ],
|
||||||
|
:debug_output => false )
|
||||||
|
|
||||||
@utils.expect :helpers, {}
|
@utils.expect :helpers, {}
|
||||||
@cmock_generator_plugin_expect = CMockGeneratorPluginExpect.new(@config, @utils)
|
@cmock_generator_plugin_expect = CMockGeneratorPluginExpect.new(@config, @utils)
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ describe CMockGeneratorPluginIgnoreStateless, "Verify Generation Of Mock Functio
|
|||||||
|
|
||||||
before do
|
before do
|
||||||
create_mocks :config, :utils
|
create_mocks :config, :utils
|
||||||
@config = create_stub(:respond_to? => true, :create_error_stubs => false)
|
@config = create_stub(:respond_to? => true, :create_error_stubs => false, :debug_output => false)
|
||||||
@cmock_generator_plugin_ignore_stateless = CMockGeneratorPluginIgnoreStateless.new(@config, @utils)
|
@cmock_generator_plugin_ignore_stateless = CMockGeneratorPluginIgnoreStateless.new(@config, @utils)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ describe CMockGeneratorPluginIgnore, "Verify Generation Of Mock Function Declara
|
|||||||
|
|
||||||
before do
|
before do
|
||||||
create_mocks :config, :utils
|
create_mocks :config, :utils
|
||||||
@config = create_stub(:respond_to? => true, :create_error_stubs => false)
|
@config = create_stub(:respond_to? => true, :create_error_stubs => false, :debug_output => false)
|
||||||
@cmock_generator_plugin_ignore = CMockGeneratorPluginIgnore.new(@config, @utils)
|
@cmock_generator_plugin_ignore = CMockGeneratorPluginIgnore.new(@config, @utils)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ describe CMockGeneratorPluginCallback, "Verify CMockGeneratorPluginCallback Modu
|
|||||||
@config.expect :callback_include_count, true
|
@config.expect :callback_include_count, true
|
||||||
@config.expect :callback_after_arg_check, false
|
@config.expect :callback_after_arg_check, false
|
||||||
@config.expect :plugins, [:ignore]
|
@config.expect :plugins, [:ignore]
|
||||||
|
@config.expect :debug_output, false
|
||||||
|
|
||||||
@cmock_generator_plugin_callback = CMockGeneratorPluginCallback.new(@config, @utils)
|
@cmock_generator_plugin_callback = CMockGeneratorPluginCallback.new(@config, @utils)
|
||||||
end
|
end
|
||||||
@@ -45,7 +46,8 @@ describe CMockGeneratorPluginCallback, "Verify CMockGeneratorPluginCallback Modu
|
|||||||
expected = [ "typedef void (* CMOCK_Maple_CALLBACK)(int cmock_num_calls);\n",
|
expected = [ "typedef void (* CMOCK_Maple_CALLBACK)(int cmock_num_calls);\n",
|
||||||
"void Maple_AddCallback(CMOCK_Maple_CALLBACK Callback);\n",
|
"void Maple_AddCallback(CMOCK_Maple_CALLBACK Callback);\n",
|
||||||
"void Maple_Stub(CMOCK_Maple_CALLBACK Callback);\n",
|
"void Maple_Stub(CMOCK_Maple_CALLBACK Callback);\n",
|
||||||
"#define Maple_StubWithCallback Maple_Stub\n" ].join
|
"#define Maple_StubWithCallback Maple_Stub\n",
|
||||||
|
"int Maple_CallCount(void);\n" ].join
|
||||||
returned = @cmock_generator_plugin_callback.mock_function_declarations(function)
|
returned = @cmock_generator_plugin_callback.mock_function_declarations(function)
|
||||||
assert_equal(expected, returned)
|
assert_equal(expected, returned)
|
||||||
end
|
end
|
||||||
@@ -55,7 +57,8 @@ describe CMockGeneratorPluginCallback, "Verify CMockGeneratorPluginCallback Modu
|
|||||||
expected = [ "typedef void (* CMOCK_Maple_CALLBACK)(void);\n",
|
expected = [ "typedef void (* CMOCK_Maple_CALLBACK)(void);\n",
|
||||||
"void Maple_AddCallback(CMOCK_Maple_CALLBACK Callback);\n",
|
"void Maple_AddCallback(CMOCK_Maple_CALLBACK Callback);\n",
|
||||||
"void Maple_Stub(CMOCK_Maple_CALLBACK Callback);\n",
|
"void Maple_Stub(CMOCK_Maple_CALLBACK Callback);\n",
|
||||||
"#define Maple_StubWithCallback Maple_Stub\n" ].join
|
"#define Maple_StubWithCallback Maple_Stub\n",
|
||||||
|
"int Maple_CallCount(void);\n" ].join
|
||||||
@cmock_generator_plugin_callback.include_count = false
|
@cmock_generator_plugin_callback.include_count = false
|
||||||
returned = @cmock_generator_plugin_callback.mock_function_declarations(function)
|
returned = @cmock_generator_plugin_callback.mock_function_declarations(function)
|
||||||
assert_equal(expected, returned)
|
assert_equal(expected, returned)
|
||||||
@@ -66,7 +69,8 @@ describe CMockGeneratorPluginCallback, "Verify CMockGeneratorPluginCallback Modu
|
|||||||
expected = [ "typedef void (* CMOCK_Maple_CALLBACK)(int* tofu, int cmock_num_calls);\n",
|
expected = [ "typedef void (* CMOCK_Maple_CALLBACK)(int* tofu, int cmock_num_calls);\n",
|
||||||
"void Maple_AddCallback(CMOCK_Maple_CALLBACK Callback);\n",
|
"void Maple_AddCallback(CMOCK_Maple_CALLBACK Callback);\n",
|
||||||
"void Maple_Stub(CMOCK_Maple_CALLBACK Callback);\n",
|
"void Maple_Stub(CMOCK_Maple_CALLBACK Callback);\n",
|
||||||
"#define Maple_StubWithCallback Maple_Stub\n" ].join
|
"#define Maple_StubWithCallback Maple_Stub\n",
|
||||||
|
"int Maple_CallCount(void);\n" ].join
|
||||||
returned = @cmock_generator_plugin_callback.mock_function_declarations(function)
|
returned = @cmock_generator_plugin_callback.mock_function_declarations(function)
|
||||||
assert_equal(expected, returned)
|
assert_equal(expected, returned)
|
||||||
end
|
end
|
||||||
@@ -76,7 +80,8 @@ describe CMockGeneratorPluginCallback, "Verify CMockGeneratorPluginCallback Modu
|
|||||||
expected = [ "typedef const char* (* CMOCK_Maple_CALLBACK)(int* tofu, int cmock_num_calls);\n",
|
expected = [ "typedef const char* (* CMOCK_Maple_CALLBACK)(int* tofu, int cmock_num_calls);\n",
|
||||||
"void Maple_AddCallback(CMOCK_Maple_CALLBACK Callback);\n",
|
"void Maple_AddCallback(CMOCK_Maple_CALLBACK Callback);\n",
|
||||||
"void Maple_Stub(CMOCK_Maple_CALLBACK Callback);\n",
|
"void Maple_Stub(CMOCK_Maple_CALLBACK Callback);\n",
|
||||||
"#define Maple_StubWithCallback Maple_Stub\n" ].join
|
"#define Maple_StubWithCallback Maple_Stub\n",
|
||||||
|
"int Maple_CallCount(void);\n" ].join
|
||||||
returned = @cmock_generator_plugin_callback.mock_function_declarations(function)
|
returned = @cmock_generator_plugin_callback.mock_function_declarations(function)
|
||||||
assert_equal(expected, returned)
|
assert_equal(expected, returned)
|
||||||
end
|
end
|
||||||
@@ -86,7 +91,8 @@ describe CMockGeneratorPluginCallback, "Verify CMockGeneratorPluginCallback Modu
|
|||||||
expected = [ "typedef const char* (* CMOCK_Maple_CALLBACK)(int* tofu);\n",
|
expected = [ "typedef const char* (* CMOCK_Maple_CALLBACK)(int* tofu);\n",
|
||||||
"void Maple_AddCallback(CMOCK_Maple_CALLBACK Callback);\n",
|
"void Maple_AddCallback(CMOCK_Maple_CALLBACK Callback);\n",
|
||||||
"void Maple_Stub(CMOCK_Maple_CALLBACK Callback);\n",
|
"void Maple_Stub(CMOCK_Maple_CALLBACK Callback);\n",
|
||||||
"#define Maple_StubWithCallback Maple_Stub\n" ].join
|
"#define Maple_StubWithCallback Maple_Stub\n",
|
||||||
|
"int Maple_CallCount(void);\n" ].join
|
||||||
@cmock_generator_plugin_callback.include_count = false
|
@cmock_generator_plugin_callback.include_count = false
|
||||||
returned = @cmock_generator_plugin_callback.mock_function_declarations(function)
|
returned = @cmock_generator_plugin_callback.mock_function_declarations(function)
|
||||||
assert_equal(expected, returned)
|
assert_equal(expected, returned)
|
||||||
@@ -273,12 +279,18 @@ describe CMockGeneratorPluginCallback, "Verify CMockGeneratorPluginCallback Modu
|
|||||||
"{\n",
|
"{\n",
|
||||||
" Mock.Lemon_IgnoreBool = (char)0;\n",
|
" Mock.Lemon_IgnoreBool = (char)0;\n",
|
||||||
" Mock.Lemon_CallbackBool = (char)1;\n",
|
" Mock.Lemon_CallbackBool = (char)1;\n",
|
||||||
|
" Mock.Lemon_CallbackCalls = 0;\n",
|
||||||
" Mock.Lemon_CallbackFunctionPointer = Callback;\n",
|
" Mock.Lemon_CallbackFunctionPointer = Callback;\n",
|
||||||
"}\n\n",
|
"}\n\n",
|
||||||
|
"int Lemon_CallCount(void)\n",
|
||||||
|
"{\n",
|
||||||
|
" return Mock.Lemon_CallbackCalls;\n",
|
||||||
|
"}\n\n",
|
||||||
"void Lemon_Stub(CMOCK_Lemon_CALLBACK Callback)\n",
|
"void Lemon_Stub(CMOCK_Lemon_CALLBACK Callback)\n",
|
||||||
"{\n",
|
"{\n",
|
||||||
" Mock.Lemon_IgnoreBool = (char)0;\n",
|
" Mock.Lemon_IgnoreBool = (char)0;\n",
|
||||||
" Mock.Lemon_CallbackBool = (char)0;\n",
|
" Mock.Lemon_CallbackBool = (char)0;\n",
|
||||||
|
" Mock.Lemon_CallbackCalls = 0;\n",
|
||||||
" Mock.Lemon_CallbackFunctionPointer = Callback;\n",
|
" Mock.Lemon_CallbackFunctionPointer = Callback;\n",
|
||||||
"}\n\n"
|
"}\n\n"
|
||||||
].join
|
].join
|
||||||
|
|||||||
@@ -18,7 +18,8 @@ describe CMockGeneratorPluginExpect, "Verify CMockGeneratorPluginExpect Module W
|
|||||||
:enforce_strict_ordering => false,
|
:enforce_strict_ordering => false,
|
||||||
:respond_to? => true,
|
:respond_to? => true,
|
||||||
:create_error_stubs => true,
|
:create_error_stubs => true,
|
||||||
:plugins => [ :expect ] )
|
:plugins => [ :expect ],
|
||||||
|
:debug_output => false )
|
||||||
|
|
||||||
@utils.expect :helpers, {}
|
@utils.expect :helpers, {}
|
||||||
@cmock_generator_plugin_expect = CMockGeneratorPluginExpect.new(@config, @utils)
|
@cmock_generator_plugin_expect = CMockGeneratorPluginExpect.new(@config, @utils)
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ describe CMockGeneratorPluginExpectAnyArgs, "Verify CMockGeneratorPluginExpectAn
|
|||||||
|
|
||||||
before do
|
before do
|
||||||
create_mocks :config, :utils
|
create_mocks :config, :utils
|
||||||
@config = create_stub(:respond_to? => true, :create_error_stubs => true)
|
@config = create_stub(:respond_to? => true, :create_error_stubs => true, :debug_output => false)
|
||||||
@cmock_generator_plugin_expect_any_args = CMockGeneratorPluginExpectAnyArgs.new(@config, @utils)
|
@cmock_generator_plugin_expect_any_args = CMockGeneratorPluginExpectAnyArgs.new(@config, @utils)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,8 @@ describe CMockGeneratorPluginExpect, "Verify CMockGeneratorPluginExpect Module w
|
|||||||
:enforce_strict_ordering => true,
|
:enforce_strict_ordering => true,
|
||||||
:respond_to? => true,
|
:respond_to? => true,
|
||||||
:create_error_stubs => true,
|
:create_error_stubs => true,
|
||||||
:plugins => [ :expect, :expect_any_args ] )
|
:plugins => [ :expect, :expect_any_args ],
|
||||||
|
:debug_output => false )
|
||||||
|
|
||||||
@utils.expect :helpers, {}
|
@utils.expect :helpers, {}
|
||||||
@cmock_generator_plugin_expect = CMockGeneratorPluginExpect.new(@config, @utils)
|
@cmock_generator_plugin_expect = CMockGeneratorPluginExpect.new(@config, @utils)
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ describe CMockGeneratorPluginIgnoreArg, "Verify CMockGeneratorPluginIgnoreArg Mo
|
|||||||
:contains_ptr? => true }
|
:contains_ptr? => true }
|
||||||
|
|
||||||
#no strict ordering
|
#no strict ordering
|
||||||
|
@config.expect :debug_output, false
|
||||||
@cmock_generator_plugin_ignore_arg = CMockGeneratorPluginIgnoreArg.new(@config, @utils)
|
@cmock_generator_plugin_ignore_arg = CMockGeneratorPluginIgnoreArg.new(@config, @utils)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ describe CMockGeneratorPluginIgnoreStateless, "Verify CMockGeneratorPluginIgnore
|
|||||||
|
|
||||||
before do
|
before do
|
||||||
create_mocks :config, :utils
|
create_mocks :config, :utils
|
||||||
@config = create_stub(:respond_to? => true, :create_error_stubs => true)
|
@config = create_stub(:respond_to? => true, :create_error_stubs => true, :debug_output => false)
|
||||||
@cmock_generator_plugin_ignore_stateless = CMockGeneratorPluginIgnoreStateless.new(@config, @utils)
|
@cmock_generator_plugin_ignore_stateless = CMockGeneratorPluginIgnoreStateless.new(@config, @utils)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ describe CMockGeneratorPluginIgnore, "Verify CMockGeneratorPluginIgnore Module"
|
|||||||
|
|
||||||
before do
|
before do
|
||||||
create_mocks :config, :utils
|
create_mocks :config, :utils
|
||||||
@config = create_stub(:respond_to? => true, :create_error_stubs => true)
|
@config = create_stub(:respond_to? => true, :create_error_stubs => true, :debug_output => false)
|
||||||
@cmock_generator_plugin_ignore = CMockGeneratorPluginIgnore.new(@config, @utils)
|
@cmock_generator_plugin_ignore = CMockGeneratorPluginIgnore.new(@config, @utils)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -56,8 +56,20 @@ describe CMockGeneratorPluginReturnThruPtr, "Verify CMockGeneratorPluginReturnTh
|
|||||||
:return => test_return[:void],
|
:return => test_return[:void],
|
||||||
:contains_ptr? => true }
|
:contains_ptr? => true }
|
||||||
|
|
||||||
|
# void Cedar(volatile struct foo_obj *foo_handle)
|
||||||
|
# arg[:type] has volatile stripped at parse time; volatile? flag carries the information
|
||||||
|
@volatile_ptr_func = {:name => "Cedar",
|
||||||
|
:args => [{ :type => "struct foo_obj*",
|
||||||
|
:name => "foo_handle",
|
||||||
|
:ptr? => true,
|
||||||
|
:volatile? => true,
|
||||||
|
}],
|
||||||
|
:return => test_return[:void],
|
||||||
|
:contains_ptr? => true }
|
||||||
|
|
||||||
#no strict ordering
|
#no strict ordering
|
||||||
@config.expect :plugins, []
|
@config.expect :plugins, []
|
||||||
|
@config.expect :debug_output, false
|
||||||
@cmock_generator_plugin_return_thru_ptr = CMockGeneratorPluginReturnThruPtr.new(@config, @utils)
|
@cmock_generator_plugin_return_thru_ptr = CMockGeneratorPluginReturnThruPtr.new(@config, @utils)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -82,6 +94,10 @@ describe CMockGeneratorPluginReturnThruPtr, "Verify CMockGeneratorPluginReturnTh
|
|||||||
@config.expect :treat_as_void, ['MY_FANCY_VOID']
|
@config.expect :treat_as_void, ['MY_FANCY_VOID']
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def volatile_ptr_func_expect
|
||||||
|
@utils.expect :ptr_or_str?, true, ['struct foo_obj*']
|
||||||
|
end
|
||||||
|
|
||||||
it "have set up internal priority correctly on init" do
|
it "have set up internal priority correctly on init" do
|
||||||
assert_equal(9, @cmock_generator_plugin_return_thru_ptr.priority)
|
assert_equal(9, @cmock_generator_plugin_return_thru_ptr.priority)
|
||||||
end
|
end
|
||||||
@@ -207,6 +223,51 @@ describe CMockGeneratorPluginReturnThruPtr, "Verify CMockGeneratorPluginReturnTh
|
|||||||
assert_equal(expected, returned)
|
assert_equal(expected, returned)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "has no volatile in the Val typedef member for a volatile pointer arg (type is pre-stripped)" do
|
||||||
|
volatile_ptr_func_expect()
|
||||||
|
|
||||||
|
# arg[:type] = "struct foo_obj*" (volatile stripped at parse time)
|
||||||
|
# ptr_to_const("struct foo_obj*") => "struct foo_obj const*"
|
||||||
|
expected = " char ReturnThruPtr_foo_handle_Used;\n" +
|
||||||
|
" struct foo_obj const* ReturnThruPtr_foo_handle_Val;\n" +
|
||||||
|
" size_t ReturnThruPtr_foo_handle_Size;\n"
|
||||||
|
|
||||||
|
returned = @cmock_generator_plugin_return_thru_ptr.instance_typedefs(@volatile_ptr_func)
|
||||||
|
assert_equal(expected, returned)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "has no volatile in the _CMockReturnMemThruPtr_ declaration for a volatile pointer arg" do
|
||||||
|
volatile_ptr_func_expect()
|
||||||
|
|
||||||
|
# arg[:type] = "struct foo_obj*" (volatile stripped), so sizeof and param type are clean.
|
||||||
|
expected =
|
||||||
|
"#define Cedar_ReturnThruPtr_foo_handle(foo_handle)" +
|
||||||
|
" Cedar_CMockReturnMemThruPtr_foo_handle(__LINE__, foo_handle, sizeof(struct foo_obj))\n" +
|
||||||
|
"#define Cedar_ReturnArrayThruPtr_foo_handle(foo_handle, cmock_len)" +
|
||||||
|
" Cedar_CMockReturnMemThruPtr_foo_handle(__LINE__, foo_handle, (cmock_len * sizeof(*foo_handle)))\n" +
|
||||||
|
"#define Cedar_ReturnMemThruPtr_foo_handle(foo_handle, cmock_size)" +
|
||||||
|
" Cedar_CMockReturnMemThruPtr_foo_handle(__LINE__, foo_handle, (cmock_size))\n" +
|
||||||
|
"void Cedar_CMockReturnMemThruPtr_foo_handle(UNITY_LINE_TYPE cmock_line, struct foo_obj const* foo_handle, size_t cmock_size);\n"
|
||||||
|
|
||||||
|
returned = @cmock_generator_plugin_return_thru_ptr.mock_function_declarations(@volatile_ptr_func)
|
||||||
|
assert_equal(expected, returned)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "uses (void*) cast in mock_implementation for volatile pointer arg" do
|
||||||
|
volatile_ptr_func_expect()
|
||||||
|
|
||||||
|
expected =
|
||||||
|
" if (cmock_call_instance->ReturnThruPtr_foo_handle_Used)\n" +
|
||||||
|
" {\n" +
|
||||||
|
" UNITY_TEST_ASSERT_NOT_NULL(foo_handle, cmock_line, CMockStringPtrIsNULL);\n" +
|
||||||
|
" CMOCK_MEMCPY((void*)foo_handle, (const void*)cmock_call_instance->ReturnThruPtr_foo_handle_Val,\n" +
|
||||||
|
" cmock_call_instance->ReturnThruPtr_foo_handle_Size);\n" +
|
||||||
|
" }\n"
|
||||||
|
|
||||||
|
returned = @cmock_generator_plugin_return_thru_ptr.mock_implementation(@volatile_ptr_func).join("")
|
||||||
|
assert_equal(expected, returned)
|
||||||
|
end
|
||||||
|
|
||||||
it "converts single pointer type to pointer-to-const via ptr_to_const" do
|
it "converts single pointer type to pointer-to-const via ptr_to_const" do
|
||||||
plugin = @cmock_generator_plugin_return_thru_ptr
|
plugin = @cmock_generator_plugin_return_thru_ptr
|
||||||
assert_equal("int const*", plugin.ptr_to_const("int*"))
|
assert_equal("int const*", plugin.ptr_to_const("int*"))
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
|||||||
@config.expect :inline_function_patterns, ['(static\s+inline|inline\s+static)\s*', '(\bstatic\b|\binline\b)\s*']
|
@config.expect :inline_function_patterns, ['(static\s+inline|inline\s+static)\s*', '(\bstatic\b|\binline\b)\s*']
|
||||||
@config.expect :array_size_type, ['int', 'size_t']
|
@config.expect :array_size_type, ['int', 'size_t']
|
||||||
@config.expect :array_size_name, 'size|len'
|
@config.expect :array_size_name, 'size|len'
|
||||||
|
@config.expect :ct_assert_patterns, ['ct_assert', '_?[Ss]tatic_[Aa]ssert', '_Static_assert', 'STATIC_ASSERT', 'BUILD_ASSERT', 'CTASSERT']
|
||||||
|
|
||||||
@parser = CMockHeaderParser.new(@config)
|
@parser = CMockHeaderParser.new(@config)
|
||||||
|
|
||||||
@@ -146,6 +147,118 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
|||||||
assert_equal(expected, @parser.import_source(source, @test_project))
|
assert_equal(expected, @parser.import_source(source, @test_project))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "remove code inside #if 0 blocks" do
|
||||||
|
source =
|
||||||
|
"void before(void);\n" +
|
||||||
|
"#if 0\n" +
|
||||||
|
"void hidden(void);\n" +
|
||||||
|
"#endif\n" +
|
||||||
|
"void after(void);\n"
|
||||||
|
|
||||||
|
expected = ["void before(void)", "void after(void)"]
|
||||||
|
|
||||||
|
assert_equal(expected, @parser.import_source(source, @test_project).map! { |s| s.strip })
|
||||||
|
end
|
||||||
|
|
||||||
|
it "keep code inside #if 1 blocks" do
|
||||||
|
source =
|
||||||
|
"void before(void);\n" +
|
||||||
|
"#if 1\n" +
|
||||||
|
"void visible(void);\n" +
|
||||||
|
"#endif\n" +
|
||||||
|
"void after(void);\n"
|
||||||
|
|
||||||
|
expected = ["void before(void)", "void visible(void)", "void after(void)"]
|
||||||
|
|
||||||
|
assert_equal(expected, @parser.import_source(source, @test_project).map! { |s| s.strip })
|
||||||
|
end
|
||||||
|
|
||||||
|
it "keep else branch of #if 0 blocks" do
|
||||||
|
source =
|
||||||
|
"void before(void);\n" +
|
||||||
|
"#if 0\n" +
|
||||||
|
"void hidden(void);\n" +
|
||||||
|
"#else\n" +
|
||||||
|
"void visible(void);\n" +
|
||||||
|
"#endif\n" +
|
||||||
|
"void after(void);\n"
|
||||||
|
|
||||||
|
expected = ["void before(void)", "void visible(void)", "void after(void)"]
|
||||||
|
|
||||||
|
assert_equal(expected, @parser.import_source(source, @test_project).map! { |s| s.strip })
|
||||||
|
end
|
||||||
|
|
||||||
|
it "remove else branch of #if 1 blocks" do
|
||||||
|
source =
|
||||||
|
"void before(void);\n" +
|
||||||
|
"#if 1\n" +
|
||||||
|
"void visible(void);\n" +
|
||||||
|
"#else\n" +
|
||||||
|
"void hidden(void);\n" +
|
||||||
|
"#endif\n" +
|
||||||
|
"void after(void);\n"
|
||||||
|
|
||||||
|
expected = ["void before(void)", "void visible(void)", "void after(void)"]
|
||||||
|
|
||||||
|
assert_equal(expected, @parser.import_source(source, @test_project).map! { |s| s.strip })
|
||||||
|
end
|
||||||
|
|
||||||
|
it "handle nested #if 1 blocks inside #if 0" do
|
||||||
|
source =
|
||||||
|
"void before(void);\n" +
|
||||||
|
"#if 0\n" +
|
||||||
|
"void hidden1(void);\n" +
|
||||||
|
"#if 1\n" +
|
||||||
|
"void hidden2(void);\n" +
|
||||||
|
"#endif\n" +
|
||||||
|
"void hidden3(void);\n" +
|
||||||
|
"#endif\n" +
|
||||||
|
"void after(void);\n"
|
||||||
|
|
||||||
|
expected = ["void before(void)", "void after(void)"]
|
||||||
|
|
||||||
|
assert_equal(expected, @parser.import_source(source, @test_project).map! { |s| s.strip })
|
||||||
|
end
|
||||||
|
|
||||||
|
it "handle nested #if 0 blocks inside #if 1" do
|
||||||
|
source =
|
||||||
|
"void before(void);\n" +
|
||||||
|
"#if 1\n" +
|
||||||
|
"void visible1(void);\n" +
|
||||||
|
"#if 0\n" +
|
||||||
|
"void hidden1(void);\n" +
|
||||||
|
"#endif\n" +
|
||||||
|
"void visible2(void);\n" +
|
||||||
|
"#endif\n" +
|
||||||
|
"void after(void);\n"
|
||||||
|
|
||||||
|
expected = ["void before(void)", "void visible1(void)", "void visible2(void)", "void after(void)"]
|
||||||
|
|
||||||
|
assert_equal(expected, @parser.import_source(source, @test_project).map! { |s| s.strip })
|
||||||
|
end
|
||||||
|
|
||||||
|
it "handle back to back #if 1 blocks and #if 0 blocks" do
|
||||||
|
source =
|
||||||
|
"void before(void);\n" +
|
||||||
|
"#if 0\n" +
|
||||||
|
"void hidden1(void);\n" +
|
||||||
|
"#endif\n" +
|
||||||
|
"#if 1\n" +
|
||||||
|
"void visible1(void);\n" +
|
||||||
|
"#endif\n" +
|
||||||
|
"#if 0\n" +
|
||||||
|
"void hidden2(void);\n" +
|
||||||
|
"#endif\n" +
|
||||||
|
"#if 1\n" +
|
||||||
|
"void visible2(void);\n" +
|
||||||
|
"#endif\n" +
|
||||||
|
"void after(void);\n"
|
||||||
|
|
||||||
|
expected = ["void before(void)", "void visible1(void)", "void visible2(void)", "void after(void)"]
|
||||||
|
|
||||||
|
assert_equal(expected, @parser.import_source(source, @test_project).map! { |s| s.strip })
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
it "remove assembler pragma sections" do
|
it "remove assembler pragma sections" do
|
||||||
source =
|
source =
|
||||||
@@ -259,6 +372,32 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
it "ignore compile-time assertions and not treat them as function prototypes" do
|
||||||
|
source =
|
||||||
|
"static_assert(BLAH_BOOLEAN_TRAIT);\n" +
|
||||||
|
"void real_func(int a);\n" +
|
||||||
|
"ct_assert(COMMIT_ID_H, ID_SIZE == (sizeof(ID)) - 1);\n" +
|
||||||
|
"CTASSERT(OTHER_HEADER_H, BUF_SIZE != 0);\n" +
|
||||||
|
"BUILD_ASSERT(MAX_LEN <= 256);\n" +
|
||||||
|
"STATIC_ASSERT(sizeof(MyStruct) >= 4);\n"
|
||||||
|
|
||||||
|
expected = ["void real_func(int a)"]
|
||||||
|
|
||||||
|
assert_equal(expected, @parser.import_source(source, @test_project).map! { |s| s.strip })
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
it "ignore function pointer variables with pointer return types and not treat them as function prototypes" do
|
||||||
|
source =
|
||||||
|
"struct_t * (*func)(some_argument);\n" +
|
||||||
|
"void real_func(int a);\n"
|
||||||
|
|
||||||
|
expected = ["void real_func(int a)"]
|
||||||
|
|
||||||
|
assert_equal(expected, @parser.import_source(source, @test_project).map! { |s| s.strip })
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
it "remove struct statements" do
|
it "remove struct statements" do
|
||||||
source =
|
source =
|
||||||
"struct _NamedStruct1 {\n" +
|
"struct _NamedStruct1 {\n" +
|
||||||
@@ -1119,6 +1258,98 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
|
|||||||
assert_equal(expected, @parser.parse("module", source)[:functions])
|
assert_equal(expected, @parser.parse("module", source)[:functions])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "properly parses volatile pointer argument types" do
|
||||||
|
|
||||||
|
source = "int16_t foo(volatile struct foo_obj *foo_handle, int plain, volatile int not_a_ptr);\n"
|
||||||
|
|
||||||
|
expected = [{ :name => "foo",
|
||||||
|
:unscoped_name => "foo",
|
||||||
|
:namespace=>[],
|
||||||
|
:class=>nil,
|
||||||
|
:modifier => "",
|
||||||
|
:return => { :type => "int16_t",
|
||||||
|
:name => "cmock_to_return",
|
||||||
|
:str => "int16_t cmock_to_return",
|
||||||
|
:void? => false,
|
||||||
|
:ptr? => false,
|
||||||
|
:const? => false,
|
||||||
|
:const_ptr? => false
|
||||||
|
},
|
||||||
|
:var_arg => nil,
|
||||||
|
:args_string => "volatile struct foo_obj* foo_handle, int plain, volatile int not_a_ptr",
|
||||||
|
:args => [{ :type => "struct foo_obj*", :name => "foo_handle",
|
||||||
|
:ptr? => true, :string? => false, :const? => false, :const_ptr? => false, :volatile? => true },
|
||||||
|
{ :type => "int", :name => "plain",
|
||||||
|
:ptr? => false, :string? => false, :const? => false, :const_ptr? => false },
|
||||||
|
{ :type => "volatile int", :name => "not_a_ptr",
|
||||||
|
:ptr? => false, :string? => false, :const? => false, :const_ptr? => false }],
|
||||||
|
:args_call => "foo_handle, plain, not_a_ptr",
|
||||||
|
:contains_ptr? => true
|
||||||
|
}]
|
||||||
|
assert_equal(expected, @parser.parse("module", source)[:functions])
|
||||||
|
end
|
||||||
|
|
||||||
|
it "properly parses T volatile* style volatile pointer argument types" do
|
||||||
|
# volatile can appear before OR after the base type; both mean "pointer to volatile T"
|
||||||
|
# e.g. "int volatile*" is identical to "volatile int*" in C
|
||||||
|
|
||||||
|
source = "void bar(int volatile* a, struct foo_obj volatile* b);\n"
|
||||||
|
|
||||||
|
expected = [{ :name => "bar",
|
||||||
|
:unscoped_name => "bar",
|
||||||
|
:namespace=>[],
|
||||||
|
:class=>nil,
|
||||||
|
:modifier => "",
|
||||||
|
:return => { :type => "void",
|
||||||
|
:name => "cmock_to_return",
|
||||||
|
:str => "void cmock_to_return",
|
||||||
|
:void? => true,
|
||||||
|
:ptr? => false,
|
||||||
|
:const? => false,
|
||||||
|
:const_ptr? => false
|
||||||
|
},
|
||||||
|
:var_arg => nil,
|
||||||
|
:args_string => "int volatile* a, struct foo_obj volatile* b",
|
||||||
|
:args => [{ :type => "int*", :name => "a",
|
||||||
|
:ptr? => true, :string? => false, :const? => false, :const_ptr? => false, :volatile? => true },
|
||||||
|
{ :type => "struct foo_obj*", :name => "b",
|
||||||
|
:ptr? => true, :string? => false, :const? => false, :const_ptr? => false, :volatile? => true }],
|
||||||
|
:args_call => "a, b",
|
||||||
|
:contains_ptr? => true
|
||||||
|
}]
|
||||||
|
assert_equal(expected, @parser.parse("module", source)[:functions])
|
||||||
|
end
|
||||||
|
|
||||||
|
it "treats int*volatile (volatile pointer to non-volatile type) as a plain pointer without volatile? flag" do
|
||||||
|
# "int * volatile p" = volatile pointer to int (the pointer itself is volatile, not the pointed-to value)
|
||||||
|
# This is distinct from "volatile int *p" (pointer to volatile int).
|
||||||
|
# CMock must NOT set volatile? here: the pointed-to type is not volatile, so no cast-qual issue.
|
||||||
|
|
||||||
|
source = "void baz(int * volatile p);\n"
|
||||||
|
|
||||||
|
expected = [{ :name => "baz",
|
||||||
|
:unscoped_name => "baz",
|
||||||
|
:namespace=>[],
|
||||||
|
:class=>nil,
|
||||||
|
:modifier => "",
|
||||||
|
:return => { :type => "void",
|
||||||
|
:name => "cmock_to_return",
|
||||||
|
:str => "void cmock_to_return",
|
||||||
|
:void? => true,
|
||||||
|
:ptr? => false,
|
||||||
|
:const? => false,
|
||||||
|
:const_ptr? => false
|
||||||
|
},
|
||||||
|
:var_arg => nil,
|
||||||
|
:args_string => "int* volatile p",
|
||||||
|
:args => [{ :type => "int* volatile", :name => "p",
|
||||||
|
:ptr? => true, :string? => false, :const? => false, :const_ptr? => false }],
|
||||||
|
:args_call => "p",
|
||||||
|
:contains_ptr? => true
|
||||||
|
}]
|
||||||
|
assert_equal(expected, @parser.parse("module", source)[:functions])
|
||||||
|
end
|
||||||
|
|
||||||
it "converts typedef'd array arguments to pointers" do
|
it "converts typedef'd array arguments to pointers" do
|
||||||
|
|
||||||
source = "Book AddToBook(Book book, const IntArray values);\n"
|
source = "Book AddToBook(Book book, const IntArray values);\n"
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ describe CMockPluginManager, "Verify CMockPluginManager Module" do
|
|||||||
:enforce_strict_ordering => false,
|
:enforce_strict_ordering => false,
|
||||||
:ignore => :args_and_calls,
|
:ignore => :args_and_calls,
|
||||||
:exclude_setjmp_h => false,
|
:exclude_setjmp_h => false,
|
||||||
:create_error_stubs => true
|
:create_error_stubs => true,
|
||||||
|
:debug_output => false
|
||||||
)
|
)
|
||||||
|
|
||||||
def @config.plugins
|
def @config.plugins
|
||||||
|
|||||||
Reference in New Issue
Block a user