45 Commits

Author SHA1 Message Date
Mark VanderVoord 3eccb8e3d4 Revert "CMock can now compile without setjmp.h present on the platform" 2021-01-28 08:15:10 -05:00
Mark VanderVoord 1f939c9005 Merge pull request #329 from jmrubillon/master
CMock can now compile without setjmp.h present on the platform
2021-01-28 08:04:40 -05:00
Jean Rubillon 9e1c6c068d Fix missed has_setjmp_h convert to exclude_setjmp_h 2021-01-28 12:57:02 +00:00
Jean Rubillon 4ae268dbbe Changed has_setjmp_h option to exclude_setjmp_h 2021-01-27 18:56:02 +00:00
Mark VanderVoord d847e6777c Merge pull request #344 from ThrowTheSwitch/test/switch_to_actions
Switch to github actions
2021-01-16 22:22:34 -05:00
Mark VanderVoord dcde998087 cleanup style 2021-01-16 22:20:16 -05:00
Mark VanderVoord 38d6dccc8e Show the correct badge for this project.
Fix a bug in a test.
2021-01-16 22:15:36 -05:00
Mark VanderVoord 03acc531bf when we checkout the project, do it recursively so we get unity for our tests. :) 2021-01-16 21:33:19 -05:00
Mark VanderVoord 45920ed724 Need project present before running bundler. 2021-01-16 21:21:51 -05:00
Mark VanderVoord c4842fad0c Don't run bundler as root. 2021-01-16 21:17:55 -05:00
Mark VanderVoord 9f3cee70cd Switch to github actions 2021-01-16 21:13:55 -05:00
Mark VanderVoord 4dd557f2df Merge pull request #311 from andred/master
allow compilation with stricter warnings
2021-01-07 18:02:24 -05:00
Mark VanderVoord af1818a652 Merge pull request #327 from Hannes103/feature/sub-folder-supprt
add optional folder argument to create_mock()
2021-01-07 17:59:10 -05:00
Mark VanderVoord e352bb8c3b Merge pull request #340 from CezaryGapinski/fix-static-variables-for-enabled-inline-funcs-mocks
Fix static variables detection in headers for enabled inline function mocks
2021-01-07 17:57:36 -05:00
Mark VanderVoord 63f5e2f962 Merge pull request #341 from laurensmiers/master
Remove comments before start of inline-function-parsing
2021-01-07 17:57:17 -05:00
Cezary Gapinski 5eec2510b1 Change inline function detection to leave code not related to functions
static keyword can be used for variable in headers, like in issue #313 or ThrowTheSwitch/Ceedling#541
2020-12-15 21:10:45 +01:00
Cezary Gapinski f5984f44e8 Add test to leaves static variables for enabled inline functions mocks 2020-12-14 21:12:11 +01:00
Mark VanderVoord 9c1c6a05dc Merge pull request #337 from ollehu/master
Improve the regexps for parsing parameters to cmock.rb
2020-11-12 11:54:15 -05:00
ollehu 70d5750659 Merge branch 'master' into master 2020-11-12 16:01:43 +01:00
Mark VanderVoord 72f1c9e2b8 Merge pull request #339 from naggety/master
Allow parsing empty values for options in CLI arguments
2020-11-04 07:06:33 -05:00
Iñigo Huguet 334f46781a Allow parsing empty values for options in CLI arguments
If an option is passed via CLI, it cannot be passed with an
empty value because the Regex makes it to match 1 or more
characters.

For example, arguments `--mock_prefix=""` and `--mock_prefix=`
are invalid, because they don't match the regex and are not
recognized as options, so they're treated as files to mock.

Changing the regex to match 0 or more characters for the option
value, instead of 1 or more, solves the problem.
2020-11-04 09:42:36 +01:00
Olle Hynén Ulfsjöö ea061bbb50 Improve the regexps for parsing parameters to cmock.rb
Also, conform to the standard 80 character limit

Change-Id: I7830ddd5d65ccc06c96884c1c3d4575241f99e6d
2020-10-23 16:26:36 +02:00
Jean Rubillon 21d181380f Signal that cexception needs setjmp to be supported. 2020-09-08 21:11:54 +01:00
Jean Rubillon 72b356b97d Added option to remove setjmp.h from generated mock files as not supported on all embedded systems 2020-09-08 20:50:48 +01:00
Hannes Bachl 22a7228bbc add optional folder argument to create_mock() 2020-09-01 10:17:54 +02:00
Mark VanderVoord afa294982e Merge pull request #326 from cloudsftp/ignore_stateless
Resolve Ruby Offenses found by CI
2020-08-19 07:51:00 -04:00
cloudsftp 44f126878b remove trailing whitespace 2020-08-19 13:15:21 +02:00
cloudsftp 1987138e81 resolve ruby offenses found by CI 2020-08-19 12:40:35 +02:00
Mark VanderVoord baa946a05f Merge pull request #325 from cloudsftp/ignore_stateless
Plugin: IgnoreStateless
2020-08-19 06:38:03 -04:00
cloudsftp d304ff273a add StopIgnore to new plugin 2020-08-19 11:25:27 +02:00
cloudsftp 56faeb935f add documentation 2020-08-19 10:38:26 +02:00
cloudsftp 61ed5cc7f8 add more tests for the new plugin 2020-08-19 10:17:05 +02:00
cloudsftp 496cabff10 add more test cases for the new plugin 2020-08-18 16:56:36 +02:00
cloudsftp 94ca645061 add first simple test and remove warning "unused parameter" 2020-08-18 16:31:45 +02:00
cloudsftp d36662da2a repair failing unit tests for plugins 2020-08-18 15:33:51 +02:00
cloudsftp b735d09603 add plugin :ignore_stateless that solves ThrowTheSwitch/CMock#307 2020-08-18 15:25:55 +02:00
Mark VanderVoord 5f8ec6da7f Merge pull request #321 from michaelbrockus/let_meson_handle_flags
Letting Meson handle flags
2020-08-06 16:29:30 -04:00
Michael Brockus 3e28a5412d use files method 2020-08-06 13:26:00 -07:00
Michael Brockus 5f8e90b82a Update meson.build 2020-08-06 12:39:56 -07:00
laurens 541e7034ad Remove comments before start of inline-function-parsing 2020-06-13 12:49:33 +02:00
Mark VanderVoord eeecc49ce8 Merge pull request #312 from Skinner927/patch-1
Stop strippables default value from being parsed (Thanks @Skinner927 )
2020-06-04 13:15:31 -04:00
Dennis Skinner 175a834574 Stop strippables default value from being parsed
Default value for `:strippables` was rendering incorrectly because of markdown parsing.
2020-06-04 13:02:30 -04:00
André Draszik ec6fa2c516 Revert "drop unnecessary prototype (immediately before definition)"
This reverts commit 7fbeb40965.

This causes compilation warnings / errors when a project uses
-Wmissing-prototypes compilation flags for safety reasons:

.../test/mocks/mock_logMessages.c:685:6: warning: no previous prototype for ‘CMockExpectParameters_log_message’ [-Wmissing-prototypes]
  685 | void CMockExpectParameters_log_message(CMOCK_log_message_CALL_INSTANCE* cmock_call_instance, const char* logMessage, int messageID, severity_t severityIn)
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

etc.

Signed-off-by: André Draszik <git@andred.net>
2020-05-25 16:35:54 +01:00
André Draszik 7ee27d6891 cmock: annotate pure & const APIs (fix Wsuggest-attribute= warnings)
GCC (& Clang) have the notion of pure and const functions [1],
where those attributes are intended to help the optimiser.

Annotate a few APIs here with the appropriate key words, which
also fixes Wsuggest-attribute=pure and Wsuggest-attribute=const
warnings, which a source base might have enabled:

.../src/cmock.c: In function ‘CMock_Guts_MemNext’:
.../src/cmock.c:118:22: warning: function might be candidate for attribute ‘pure’ [-Wsuggest-attribute=pure]
  118 | CMOCK_MEM_INDEX_TYPE CMock_Guts_MemNext(CMOCK_MEM_INDEX_TYPE previous_item_index)
      |                      ^~~~~~~~~~~~~~~~~~
.../src/cmock.c: In function ‘CMock_Guts_MemEndOfChain’:
.../src/cmock.c:140:22: warning: function might be candidate for attribute ‘pure’ if it is known to return normally [-Wsuggest-attribute=pure]
  140 | CMOCK_MEM_INDEX_TYPE CMock_Guts_MemEndOfChain(CMOCK_MEM_INDEX_TYPE root_index)
      |                      ^~~~~~~~~~~~~~~~~~~~~~~~
.../src/cmock.c: In function ‘CMock_Guts_GetAddressFor’:
.../src/cmock.c:158:7: warning: function might be candidate for attribute ‘pure’ [-Wsuggest-attribute=pure]
  158 | void* CMock_Guts_GetAddressFor(CMOCK_MEM_INDEX_TYPE index)
      |       ^~~~~~~~~~~~~~~~~~~~~~~~
.../src/cmock.c: In function ‘CMock_Guts_MemBytesCapacity’:
.../src/cmock.c:173:22: warning: function might be candidate for attribute ‘const’ [-Wsuggest-attribute=const]
  173 | CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesCapacity(void)
      |                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~
.../src/cmock.c: In function ‘CMock_Guts_MemBytesFree’:
.../src/cmock.c:181:22: warning: function might be candidate for attribute ‘pure’ [-Wsuggest-attribute=pure]
  181 | CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesFree(void)
      |                      ^~~~~~~~~~~~~~~~~~~~~~~
.../src/cmock.c: In function ‘CMock_Guts_MemBytesUsed’:
.../src/cmock.c:189:22: warning: function might be candidate for attribute ‘pure’ [-Wsuggest-attribute=pure]
  189 | CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesUsed(void)
      |                      ^~~~~~~~~~~~~~~~~~~~~~~

[1] https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html

Signed-off-by: André Draszik <git@andred.net>
2020-05-25 15:39:21 +01:00
André Draszik 2568a3657f return_thru_ptr: fix Wsign-conversion warning
Compiling a source base / test with Wsign-conversion enabled, gives
the following warning:

build/test/mocks/mock_logMessages.c: In function ‘countLogMessages’:
build/test/mocks/mock_logMessages.c:749:26: warning: conversion to ‘size_t’ {aka ‘long unsigned int’} from ‘int’ may change the sign of the result [-Wsign-conversion]
  749 |       cmock_call_instance->ReturnThruPtr_fileIn_Size);
      |       ~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~

The ReturnThruPtr_XXX_Size is used as argument to a call to memcpy(),
which expects size_t (unsigned) for a good reason. The size leading
to this call is being determined using sizeof(), so there appears
no reason to ever convert this to (signed) int.

Stop converting size_t to int, and thereby fix the compiler
warning.

Signed-off-by: André Draszik <git@andred.net>
2020-05-25 07:45:34 +01:00
19 changed files with 842 additions and 129 deletions
+41
View File
@@ -0,0 +1,41 @@
---
# Continuous Integration Workflow: Test case suite run + validation build check
name: CI
# Controls when the action will run.
# Triggers the workflow on push or pull request events but only for the master branch
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
# Job: Unit test suite
unit-tests:
name: "Unit Tests"
runs-on: ubuntu-latest
steps:
# Install Multilib
- name: Install Multilib
run: |
sudo apt-get install --assume-yes --quiet gcc-multilib
# Checks out repository under $GITHUB_WORKSPACE
- name: Checkout Latest Repo
uses: actions/checkout@v2
with:
submodules: recursive
# Install Ruby Testing Tools
- name: Setup Ruby Testing Tools
run: |
sudo gem install bundler
sudo gem install rspec
sudo gem install rubocop -v 0.57.2
bundle install
# Run Tests
- name: Run All Unit Tests
run: |
cd test && rake ci
+1
View File
@@ -1,6 +1,7 @@
test/system/build
test/system/generated
*.sublime-project
*.sublime-workspace
Gemfile.lock
.rake_t_cache
.DS_Store
-28
View File
@@ -1,28 +0,0 @@
sudo: required
language: ruby c
matrix:
include:
#- os: osx
# compiler: clang
# osx_image: xcode7.3
- os: linux
dist: trusty
rvm: "2.4"
compiler: gcc
- os: linux
dist: xenial
rvm: "2.7"
compiler: clang
before_install:
- sudo apt-get install --assume-yes --quiet gcc-multilib
install:
- gem install bundler
- bundle install
- gem install rspec
- gem install rubocop -v 0.57.2
script:
- cd test && rake ci
+8 -3
View File
@@ -1,7 +1,12 @@
CMock - Mock/stub generator for C
=================================
CMock ![CI](https://github.com/ThrowTheSwitch/CMock/workflows/CI/badge.svg)
=====
CMock is a mock and stub generator and runtime for unit testing C. It's been designed
to work smoothly with Unity Test, another of the embedded-software testing tools
developed by ThrowTheSwitch.org. CMock automagically parses your C headers and creates
useful and usable mock interfaces for unit testing. Give it a try!
[![CMock Build Status](https://api.travis-ci.org/ThrowTheSwitch/CMock.png?branch=master)](https://travis-ci.org/ThrowTheSwitch/CMock)
If you don't care to manage unit testing builds yourself, consider checking out Ceedling,
a test-centered build manager for unit testing C code.
Getting Started
================
+19 -1
View File
@@ -174,6 +174,23 @@ handle the call to a function.
* `retval func(void)` => `void func_StopIgnore(void)`
* `retval func(params)` => `void func_StopIgnore(void)`
IgnoreStateless:
----------------
This plugin is similar to the Ignore plugin, but the IgnoreAndReturn functions are
stateless. So the Ignored function will always return the last specified return value
and does not queue the return values as the IgnoreAndReturn of the default plugin will.
To stop ignoring a function you can call StopIgnore or simply overwrite the Ignore
(resp. IgnoreAndReturn) with an Expect (resp. ExpectAndReturn). Note that calling
Ignore (resp IgnoreAndReturn) will clear your previous called Expect
(resp. ExpectAndReturn), so they are not restored after StopIgnore is called.
You can use this plugin by using `:ignore_stateless` instead of `:ignore` in your
CMock configuration file.
The generated functions are the same as **Ignore** and **StopIgnore** above.
Ignore Arg:
------------
@@ -440,6 +457,7 @@ from the defaults. We've tried to specify what the defaults are below.
available currently:
* `:ignore`
* `:ignore_stateless`
* `:ignore_arg`
* `:expect_any_args`
* `:array`
@@ -457,7 +475,7 @@ from the defaults. We've tried to specify what the defaults are below.
to prevent a function `functionName` from being mocked. By default, it
is ignoring all gcc attribute extensions.
* default: ['(?:__attribute__\s*\(+.*?\)+)']
* default: `['(?:__attribute__\s*\(+.*?\)+)']`
* `:subdir`:
This is a relative subdirectory for your mocks. Set this to e.g. "sys" in
+16 -9
View File
@@ -18,16 +18,18 @@ class CMock
cm_config = CMockConfig.new(options)
cm_unityhelper = CMockUnityHelperParser.new(cm_config)
cm_writer = CMockFileWriter.new(cm_config)
cm_gen_utils = CMockGeneratorUtils.new(cm_config, :unity_helper => cm_unityhelper)
cm_gen_utils = CMockGeneratorUtils.new(cm_config,
:unity_helper => cm_unityhelper)
cm_gen_plugins = CMockPluginManager.new(cm_config, cm_gen_utils)
@cm_parser = CMockHeaderParser.new(cm_config)
@cm_generator = CMockGenerator.new(cm_config, cm_writer, cm_gen_utils, cm_gen_plugins)
@cm_generator = CMockGenerator.new(cm_config, cm_writer, cm_gen_utils,
cm_gen_plugins)
@silent = (cm_config.verbosity < 2)
end
def setup_mocks(files)
def setup_mocks(files, folder = nil)
[files].flatten.each do |src|
generate_mock src
generate_mock(src, folder)
end
end
@@ -39,11 +41,11 @@ class CMock
private ###############################
def generate_mock(src)
def generate_mock(src, folder)
name = File.basename(src, '.*')
ext = File.extname(src)
puts "Creating mock for #{name}..." unless @silent
@cm_generator.create_mock(name, @cm_parser.parse(name, File.read(src)), ext)
@cm_generator.create_mock(name, @cm_parser.parse(name, File.read(src)), ext, folder)
end
def generate_skeleton(src)
@@ -85,12 +87,17 @@ if $0 == __FILE__
options = {}
filelist = []
ARGV.each do |arg|
if arg =~ /^-o\"?([a-zA-Z0-9._\\\/:\s]+)\"?/
if arg =~ /^-o\"?([a-zA-Z0-9@._\\\/:\s]+)\"?/
options.merge! CMockConfig.load_config_file_from_yaml(arg.gsub(/^-o/, ''))
elsif arg == '--skeleton'
options[:skeleton] = true
elsif arg =~ /^--([a-zA-Z0-9._\\\/:\s]+)=\"?([a-zA-Z0-9._\-\\\/:\s\;]+)\"?/
options = option_maker(options, Regexp.last_match(1), Regexp.last_match(2))
elsif arg =~ /^--strippables=\"?(.*)\"?/
# --strippables are dealt with separately since the user is allowed to
# enter any valid regular expression as argument
options = option_maker(options, 'strippables', Regexp.last_match(1))
elsif arg =~ /^--([a-zA-Z0-9._\\\/:\s]+)=\"?([a-zA-Z0-9._\-\\\/:\s\;]*)\"?/x
options = option_maker(options, Regexp.last_match(1),
Regexp.last_match(2))
else
filelist << arg
end
+20 -7
View File
@@ -21,6 +21,7 @@ class CMockGenerator
@fail_on_unexpected_calls = @config.fail_on_unexpected_calls
@subdir = @config.subdir
@folder = nil
@includes_h_pre_orig_header = (@config.includes || @config.includes_h_pre_orig_header || []).map { |h| h =~ /</ ? h : "\"#{h}\"" }
@includes_h_post_orig_header = (@config.includes_h_post_orig_header || []).map { |h| h =~ /</ ? h : "\"#{h}\"" }
@@ -44,12 +45,24 @@ class CMockGenerator
end
end
def create_mock(module_name, parsed_stuff, module_ext = nil)
def create_mock(module_name, parsed_stuff, module_ext = nil, folder = nil)
@module_name = module_name
@module_ext = module_ext || '.h'
@mock_name = @prefix + @module_name + @suffix
@clean_mock_name = TypeSanitizer.sanitize_c_identifier(@mock_name)
@folder = if folder && @subdir
File.join(@subdir, folder)
elsif @subdir
@subdir
else
folder
end
# adds a trailing slash to the folder output
@folder = File.join(@folder, '') if @folder
create_mock_subdir
create_mock_header_file(parsed_stuff)
create_mock_source_file(parsed_stuff)
end
@@ -62,7 +75,7 @@ class CMockGenerator
private if $ThisIsOnlyATest.nil? ##############################
def create_mock_subdir
@file_writer.create_subdir(@subdir)
@file_writer.create_subdir(@folder)
end
def create_using_statement(file, function)
@@ -71,12 +84,12 @@ class CMockGenerator
def create_mock_header_file(parsed_stuff)
if @include_inline == :include
@file_writer.create_file(@module_name + (@module_ext || '.h'), @subdir) do |file, _filename|
@file_writer.create_file(@module_name + (@module_ext || '.h'), @folder) do |file, _filename|
file << parsed_stuff[:normalized_source]
end
end
@file_writer.create_file(@mock_name + (@module_ext || '.h'), @subdir) do |file, filename|
@file_writer.create_file(@mock_name + (@module_ext || '.h'), @folder) do |file, filename|
create_mock_header_header(file, filename)
create_mock_header_service_call_declarations(file)
create_typedefs(file, parsed_stuff[:typedefs])
@@ -89,7 +102,7 @@ class CMockGenerator
end
def create_mock_source_file(parsed_stuff)
@file_writer.create_file(@mock_name + '.c', @subdir) do |file, filename|
@file_writer.create_file(@mock_name + '.c', @folder) do |file, filename|
create_source_header_section(file, filename, parsed_stuff[:functions])
create_instance_structure(file, parsed_stuff[:functions])
create_extern_declarations(file)
@@ -116,7 +129,7 @@ class CMockGenerator
def create_mock_header_header(file, _filename)
define_name = @clean_mock_name.upcase
orig_filename = (@subdir ? @subdir + '/' : '') + @module_name + (@module_ext || '.h')
orig_filename = (@folder || '') + @module_name + (@module_ext || '.h')
file << "/* AUTOGENERATED FILE. DO NOT EDIT. */\n"
file << "#ifndef _#{define_name}_H\n"
file << "#define _#{define_name}_H\n\n"
@@ -165,7 +178,7 @@ class CMockGenerator
end
def create_source_header_section(file, filename, functions)
header_file = (@subdir ? @subdir + '/' : '') + filename.gsub('.c', (@module_ext || '.h'))
header_file = (@folder || '') + filename.gsub('.c', (@module_ext || '.h'))
file << "/* AUTOGENERATED FILE. DO NOT EDIT. */\n" unless functions.empty?
file << "#include <string.h>\n"
file << "#include <stdlib.h>\n"
@@ -0,0 +1,85 @@
# ==========================================
# CMock Project - Automatic Mock Generation for C
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
# [Released under MIT License. Please refer to license.txt for details]
# ==========================================
class CMockGeneratorPluginIgnoreStateless
attr_reader :priority
attr_reader :config, :utils
def initialize(config, utils)
@config = config
@utils = utils
@priority = 2
end
def instance_structure(function)
if function[:return][:void?]
" char #{function[:name]}_IgnoreBool;\n"
else
" char #{function[:name]}_IgnoreBool;\n #{function[:return][:type]} #{function[:name]}_FinalReturn;\n"
end
end
def mock_function_declarations(function)
lines = if function[:return][:void?]
"#define #{function[:name]}_Ignore() #{function[:name]}_CMockIgnore()\n" \
"void #{function[:name]}_CMockIgnore(void);\n"
else
"#define #{function[:name]}_IgnoreAndReturn(cmock_retval) #{function[:name]}_CMockIgnoreAndReturn(cmock_retval)\n" \
"void #{function[:name]}_CMockIgnoreAndReturn(#{function[:return][:str]});\n"
end
# Add stop ignore function. it does not matter if there are any args
lines << "#define #{function[:name]}_StopIgnore() #{function[:name]}_CMockStopIgnore()\n" \
"void #{function[:name]}_CMockStopIgnore(void);\n"
lines
end
def mock_implementation_precheck(function)
lines = " if (Mock.#{function[:name]}_IgnoreBool)\n {\n"
lines << " UNITY_CLR_DETAILS();\n"
if function[:return][:void?]
lines << " return;\n }\n"
else
retval = function[:return].merge(:name => 'cmock_call_instance->ReturnVal')
lines << " if (cmock_call_instance == NULL)\n return Mock.#{function[:name]}_FinalReturn;\n"
lines << ' ' + @utils.code_assign_argument_quickly("Mock.#{function[:name]}_FinalReturn", retval) unless retval[:void?]
lines << " return cmock_call_instance->ReturnVal;\n }\n"
end
lines
end
# this function is adjusted
def mock_interfaces(function)
lines = ''
lines << if function[:return][:void?]
"void #{function[:name]}_CMockIgnore(void)\n{\n"
else
"void #{function[:name]}_CMockIgnoreAndReturn(#{function[:return][:str]})\n{\n"
end
unless function[:return][:void?]
lines << " Mock.#{function[:name]}_CallInstance = CMOCK_GUTS_NONE;\n"
lines << " Mock.#{function[:name]}_FinalReturn = cmock_to_return;\n"
end
lines << " Mock.#{function[:name]}_IgnoreBool = (char)1;\n"
lines << "}\n\n"
# Add stop ignore function. it does not matter if there are any args
lines << "void #{function[:name]}_CMockStopIgnore(void)\n{\n"
lines << " Mock.#{function[:name]}_IgnoreBool = (char)0;\n"
lines << "}\n\n"
lines
end
def mock_ignore(function)
" Mock.#{function[:name]}_IgnoreBool = (char)1;\n"
end
def mock_verify(function)
func_name = function[:name]
" if (Mock.#{func_name}_IgnoreBool)\n call_instance = CMOCK_GUTS_NONE;\n"
end
end
@@ -14,7 +14,7 @@ class CMockGeneratorPluginReturnThruPtr
lines << " char ReturnThruPtr_#{arg[:name]}_Used;\n"
lines << " #{arg[:type]} ReturnThruPtr_#{arg[:name]}_Val;\n"
lines << " int ReturnThruPtr_#{arg[:name]}_Size;\n"
lines << " size_t ReturnThruPtr_#{arg[:name]}_Size;\n"
end
lines
end
@@ -33,10 +33,10 @@ class CMockGeneratorPluginReturnThruPtr
" #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(__LINE__, #{arg[:name]}, sizeof(*#{arg[:name]}))\n"
end
lines << "#define #{function[:name]}_ReturnArrayThruPtr_#{arg[:name]}(#{arg[:name]}, cmock_len)"
lines << " #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(__LINE__, #{arg[:name]}, (int)(cmock_len * (int)sizeof(*#{arg[:name]})))\n"
lines << " #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(__LINE__, #{arg[:name]}, cmock_len * sizeof(*#{arg[:name]}))\n"
lines << "#define #{function[:name]}_ReturnMemThruPtr_#{arg[:name]}(#{arg[:name]}, cmock_size)"
lines << " #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(__LINE__, #{arg[:name]}, cmock_size)\n"
lines << "void #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(UNITY_LINE_TYPE cmock_line, #{arg[:type]} #{arg[:name]}, int cmock_size);\n"
lines << "void #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(UNITY_LINE_TYPE cmock_line, #{arg[:type]} #{arg[:name]}, size_t cmock_size);\n"
end
lines
end
@@ -48,7 +48,7 @@ class CMockGeneratorPluginReturnThruPtr
arg_name = arg[:name]
next unless @utils.ptr_or_str?(arg[:type]) && !(arg[:const?])
lines << "void #{func_name}_CMockReturnMemThruPtr_#{arg_name}(UNITY_LINE_TYPE cmock_line, #{arg[:type]} #{arg_name}, int cmock_size)\n"
lines << "void #{func_name}_CMockReturnMemThruPtr_#{arg_name}(UNITY_LINE_TYPE cmock_line, #{arg[:type]} #{arg_name}, size_t cmock_size)\n"
lines << "{\n"
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"
+6 -3
View File
@@ -17,6 +17,7 @@ class CMockGeneratorUtils
@return_thru_ptr = @config.plugins.include? :return_thru_ptr
@ignore_arg = @config.plugins.include? :ignore_arg
@ignore = @config.plugins.include? :ignore
@ignore_stateless = @config.plugins.include? :ignore_stateless
@treat_as = @config.treat_as
@helpers = helpers
end
@@ -52,7 +53,7 @@ class CMockGeneratorUtils
lines << " UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringOutOfMemory);\n"
lines << " memset(cmock_call_instance, 0, sizeof(*cmock_call_instance));\n"
lines << " Mock.#{func_name}_CallInstance = CMock_Guts_MemChain(Mock.#{func_name}_CallInstance, cmock_guts_index);\n"
lines << " Mock.#{func_name}_IgnoreBool = (char)0;\n" if @ignore
lines << " Mock.#{func_name}_IgnoreBool = (char)0;\n" if @ignore || @ignore_stateless
lines << " cmock_call_instance->LineNumber = cmock_line;\n"
lines << " cmock_call_instance->CallOrder = ++GlobalExpectCount;\n" if @ordered && global_ordering_supported
lines << " cmock_call_instance->ExceptionToThrow = CEXCEPTION_NONE;\n" if @cexception
@@ -86,11 +87,13 @@ class CMockGeneratorUtils
type = arg_type_with_const(m)
m[:ptr?] ? "#{type} #{m[:name]}, int #{m[:name]}_Depth" : "#{type} #{m[:name]}"
end.join(', ')
"void CMockExpectParameters_#{function[:name]}(CMOCK_#{function[:name]}_CALL_INSTANCE* cmock_call_instance, #{args_string})\n{\n" +
"void CMockExpectParameters_#{function[:name]}(CMOCK_#{function[:name]}_CALL_INSTANCE* cmock_call_instance, #{args_string});\n" \
"void CMockExpectParameters_#{function[:name]}(CMOCK_#{function[:name]}_CALL_INSTANCE* cmock_call_instance, #{args_string})\n{\n" +
function[:args].inject('') { |all, arg| all + code_add_an_arg_expectation(arg, (arg[:ptr?] ? "#{arg[:name]}_Depth" : 1)) } +
"}\n\n"
else
"void CMockExpectParameters_#{function[:name]}(CMOCK_#{function[:name]}_CALL_INSTANCE* cmock_call_instance, #{function[:args_string]})\n{\n" +
"void CMockExpectParameters_#{function[:name]}(CMOCK_#{function[:name]}_CALL_INSTANCE* cmock_call_instance, #{function[:args_string]});\n" \
"void CMockExpectParameters_#{function[:name]}(CMOCK_#{function[:name]}_CALL_INSTANCE* cmock_call_instance, #{function[:args_string]})\n{\n" +
function[:args].inject('') { |all, arg| all + code_add_an_arg_expectation(arg) } +
"}\n\n"
end
+40 -14
View File
@@ -61,6 +61,15 @@ class CMockHeaderParser
private if $ThisIsOnlyATest.nil? ################
# Remove C/C++ comments from a string
# +source+:: String which will have the comments removed
def remove_comments_from_source(source)
# remove comments (block and line, in three steps to ensure correct precedence)
source.gsub!(/(?<!\*)\/\/(?:.+\/\*|\*(?:$|[^\/])).*$/, '') # remove line comments that comment out the start of blocks
source.gsub!(/\/\*.*?\*\//m, '') # remove block comments
source.gsub!(/\/\/.*$/, '') # remove line comments (all that remain)
end
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)
if RUBY_VERSION.split('.')[0].to_i > 1
@@ -119,6 +128,9 @@ class CMockHeaderParser
# let's clean up the encoding in case they've done anything weird with the characters we might find
source = source.force_encoding('ISO-8859-1').encode('utf-8', :replace => nil)
# Comments can contain words that will trigger the parser (static|inline|<user_defined_static_keyword>)
remove_comments_from_source(source)
# smush multiline macros into single line (checking for continuation character at end of line '\')
# If the user uses a macro to declare an inline function,
# smushing the macros makes it easier to recognize them as a macro and if required,
@@ -138,11 +150,18 @@ class CMockHeaderParser
# - Copy everything after the inline function implementation and start the parsing of the next inline function
# There are ofcourse some special cases (inline macro declarations, inline function declarations, ...) which are handled and explained below
inline_function_regex_formats.each do |format|
inspected_source = ''
regex_matched = false
loop do
inline_function_match = source.match(/#{format}/) # Search for inline function declaration
break if inline_function_match.nil? # No inline functions so nothing to do
if inline_function_match.nil? # No inline functions so nothing to do
# Join pre and post match stripped parts for the next inline function detection regex
source = inspected_source + source if regex_matched == true
break
end
regex_matched = true
# 1. Determine if we are dealing with a user defined macro to declare inline functions
# If the end of the pre-match string is a macro-declaration-like string,
# we are dealing with a user defined macro to declare inline functions
@@ -150,7 +169,8 @@ class CMockHeaderParser
# Remove the macro from the source
stripped_pre_match = inline_function_match.pre_match.sub(/(#define\s*)\z/, '')
stripped_post_match = inline_function_match.post_match.sub(/\A(.*[\n]?)/, '')
source = stripped_pre_match + stripped_post_match
inspected_source += stripped_pre_match
source = stripped_post_match
next
end
@@ -159,23 +179,32 @@ class CMockHeaderParser
# we are dealing with a inline function declaration
if /\A#{@function_declaration_parse_base_match}\s*;/m =~ inline_function_match.post_match
# Only remove the inline part from the function declaration, leaving the function declaration won't do any harm
source = inline_function_match.pre_match + inline_function_match.post_match
inspected_source += inline_function_match.pre_match
source = inline_function_match.post_match
next
end
# 3. If we get here, we found an inline function declaration AND inline function body.
# Remove the function body to transform it into a 'normal' function.
total_pairs_to_remove = count_number_of_pairs_of_braces_in_function(inline_function_match.post_match)
# Remove the function body to transform it into a 'normal' function declaration.
if /\A#{@function_declaration_parse_base_match}\s*\{/m =~ inline_function_match.post_match
total_pairs_to_remove = count_number_of_pairs_of_braces_in_function(inline_function_match.post_match)
break if total_pairs_to_remove == 0 # Bad source?
break if total_pairs_to_remove == 0 # Bad source?
inline_function_stripped = inline_function_match.post_match
inline_function_stripped = inline_function_match.post_match
total_pairs_to_remove.times do
inline_function_stripped.sub!(/\s*#{square_bracket_pair_regex_format}/, ';') # Remove inline implementation (+ some whitespace because it's prettier)
total_pairs_to_remove.times do
inline_function_stripped.sub!(/\s*#{square_bracket_pair_regex_format}/, ';') # Remove inline implementation (+ some whitespace because it's prettier)
end
inspected_source += inline_function_match.pre_match
source = inline_function_stripped
next
end
source = inline_function_match.pre_match + inline_function_stripped # Make new source with the inline function removed and move on to the next
# 4. If we get here, it means the regex match, but it is not related to the function (ex. static variable in header)
# Leave this code as it is.
inspected_source += inline_function_match.pre_match + inline_function_match[0]
source = inline_function_match.post_match
end
end
@@ -205,10 +234,7 @@ class CMockHeaderParser
# smush multiline macros into single line (checking for continuation character at end of line '\')
source.gsub!(/\s*\\\s*/m, ' ')
# remove comments (block and line, in three steps to ensure correct precedence)
source.gsub!(/(?<!\*)\/\/(?:.+\/\*|\*(?:$|[^\/])).*$/, '') # remove line comments that comment out the start of blocks
source.gsub!(/\/\*.*?\*\//m, '') # remove block comments
source.gsub!(/\/\/.*$/, '') # remove line comments (all that remain)
remove_comments_from_source(source)
# remove assembler pragma sections
source.gsub!(/^\s*#\s*pragma\s+asm\s+.*?#\s*pragma\s+endasm/m, '')
+1 -37
View File
@@ -8,46 +8,10 @@ project('cmock', 'c',
license: 'MIT',
meson_version: '>=0.53.0',
subproject_dir : 'vendor',
default_options: ['layout=flat', 'warning_level=3', 'werror=true', 'c_std=c11']
default_options: ['werror=true', 'c_std=c11']
)
lang = 'c'
cc = meson.get_compiler(lang)
#
# Meson: Add compiler flags
#
if cc.get_id() == 'clang'
add_project_arguments(cc.get_supported_arguments(
[
'-Wexit-time-destructors',
'-Wglobal-constructors',
'-Wmissing-prototypes',
'-Wmissing-noreturn',
'-Wno-missing-braces',
'-Wold-style-cast', '-Wpointer-arith', '-Wweak-vtables',
'-Wcast-align', '-Wconversion', '-Wcast-qual', '-Wshadow'
]
), language: lang)
endif
if cc.get_argument_syntax() == 'gcc'
add_project_arguments(cc.get_supported_arguments(
[
'-Wformat', '-Waddress', '-Winit-self', '-Wno-multichar',
'-Wpointer-arith' , '-Wwrite-strings' ,
'-Wno-parentheses' , '-Wno-type-limits' ,
'-Wformat-security' , '-Wunreachable-code' ,
'-Waggregate-return' , '-Wformat-nonliteral' ,
'-Wmissing-declarations', '-Wmissing-include-dirs' ,
'-Wno-unused-parameter'
]
), language: lang)
endif
unity_dep = dependency('unity', fallback: ['unity', 'unity_dep'])
#
# Sub directory to project source code
subdir('src')
cmock_dep = declare_dependency(link_with: cmock_lib, include_directories: cmock_dir)
+12 -6
View File
@@ -22,19 +22,25 @@
#define CMOCK_GUTS_NONE (0)
#if defined __GNUC__
# define CMOCK_FUNCTION_ATTR(a) __attribute__((a))
#else
# define CMOCK_FUNCTION_ATTR(a) /* ignore */
#endif
/*-------------------------------------------------------
* Memory API
*-------------------------------------------------------*/
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemNew(CMOCK_MEM_INDEX_TYPE size);
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemChain(CMOCK_MEM_INDEX_TYPE root_index, CMOCK_MEM_INDEX_TYPE obj_index);
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemNext(CMOCK_MEM_INDEX_TYPE previous_item_index);
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemEndOfChain(CMOCK_MEM_INDEX_TYPE root_index);
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemNext(CMOCK_MEM_INDEX_TYPE previous_item_index) CMOCK_FUNCTION_ATTR(pure);
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemEndOfChain(CMOCK_MEM_INDEX_TYPE root_index) CMOCK_FUNCTION_ATTR(pure);
void* CMock_Guts_GetAddressFor(CMOCK_MEM_INDEX_TYPE index);
void* CMock_Guts_GetAddressFor(CMOCK_MEM_INDEX_TYPE index) CMOCK_FUNCTION_ATTR(pure);
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesCapacity(void);
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesFree(void);
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesUsed(void);
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesCapacity(void) CMOCK_FUNCTION_ATTR(const);
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesFree(void) CMOCK_FUNCTION_ATTR(pure);
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesUsed(void) CMOCK_FUNCTION_ATTR(pure);
void CMock_Guts_MemFreeAll(void);
void CMock_Guts_MemFreeFinal(void);
+1 -1
View File
@@ -7,6 +7,6 @@
cmock_dir = include_directories('.')
cmock_lib = static_library(meson.project_name(),
sources: ['cmock.c'],
files('cmock.c'),
dependencies: [unity_dep],
include_directories: cmock_dir)
@@ -0,0 +1,325 @@
---
:cmock:
:plugins:
- 'ignore_stateless'
:systest:
:types: |
:mockable: |
int foo(int a);
void bar(int b);
:source:
:header: |
int function(int a, int b, int c);
:code: |
int function(int a, int b, int c)
{
bar(b);
return foo(a) + foo(b) + foo(c);
}
:tests:
:common: |
void setUp(void) {}
void tearDown(void) {}
:units:
- :pass: TRUE
:should: 'successfully exercise simple ExpectAndReturn mock calls'
:code: |
test()
{
bar_Expect(2);
foo_ExpectAndReturn(1, 10);
foo_ExpectAndReturn(2, 20);
foo_ExpectAndReturn(3, 30);
TEST_ASSERT_EQUAL(60, function(1, 2, 3));
}
- :pass: TRUE
:should: 'ignore foo() calls'
:code: |
test()
{
bar_Expect(4);
foo_IgnoreAndReturn(40);
TEST_ASSERT_EQUAL(120, function(3, 4, 3));
}
- :pass: TRUE
:should: 'ignore the situation where foo() is not called even though we explicitly ignored it'
:code: |
test()
{
foo_IgnoreAndReturn(20);
//notice we do not call foo
}
- :pass: TRUE
:should: 'ignore foo() calls and always return last item'
:code: |
test()
{
bar_Expect(4);
foo_IgnoreAndReturn(20);
foo_IgnoreAndReturn(30);
TEST_ASSERT_EQUAL(90, function(3, 4, 9));
}
- :pass: TRUE
:should: 'ignore bar() and foo() calls'
:code: |
test()
{
bar_Ignore();
foo_IgnoreAndReturn(50);
TEST_ASSERT_EQUAL(150, function(0, 0, 0));
}
- :pass: TRUE
:should: 'multiple cycles of expects still pass when ignores enabled'
:code: |
test()
{
bar_Expect(2);
foo_ExpectAndReturn(1, 50);
foo_ExpectAndReturn(2, 60);
foo_ExpectAndReturn(3, 70);
TEST_ASSERT_EQUAL(180, function(1, 2, 3));
bar_Expect(5);
foo_ExpectAndReturn(4, 30);
foo_ExpectAndReturn(5, 80);
foo_ExpectAndReturn(6, 10);
TEST_ASSERT_EQUAL(120, function(4, 5, 6));
bar_Expect(8);
foo_ExpectAndReturn(7, 70);
foo_ExpectAndReturn(8, 20);
foo_ExpectAndReturn(9, 20);
TEST_ASSERT_EQUAL(110, function(7, 8, 9));
}
- :pass: FALSE
:should: 'multiple cycles of expects still fail when ignores enabled'
:code: |
test()
{
bar_Expect(2);
foo_ExpectAndReturn(1, 50);
foo_ExpectAndReturn(2, 60);
foo_ExpectAndReturn(3, 70);
TEST_ASSERT_EQUAL(180, function(1, 2, 3));
bar_Expect(5);
foo_ExpectAndReturn(4, 30);
foo_ExpectAndReturn(5, 80);
foo_ExpectAndReturn(6, 10);
TEST_ASSERT_EQUAL(120, function(4, 5, 6));
bar_Expect(8);
foo_ExpectAndReturn(7, 70);
foo_ExpectAndReturn(8, 20);
foo_ExpectAndReturn(9, 20);
TEST_ASSERT_EQUAL(110, function(0, 8, 9));
}
- :pass: FALSE
:should: 'With "fail_on_unexpected_calls" enabled, Expect/Ignore/... of bar is required and test fails.'
:code: |
test()
{
function(1, 2, 3);
}
- :pass: TRUE
:should: 'we can override an ignore with an expect and pass'
:code: |
test()
{
bar_Ignore();
bar_Expect(2);
foo_ExpectAndReturn(1, 50);
foo_ExpectAndReturn(2, 60);
foo_ExpectAndReturn(3, 70);
TEST_ASSERT_EQUAL(180, function(1, 2, 3));
bar_Expect(5);
foo_ExpectAndReturn(4, 30);
foo_ExpectAndReturn(5, 80);
foo_ExpectAndReturn(6, 10);
TEST_ASSERT_EQUAL(120, function(4, 5, 6));
bar_Expect(8);
foo_ExpectAndReturn(7, 70);
foo_ExpectAndReturn(8, 20);
foo_ExpectAndReturn(9, 20);
TEST_ASSERT_EQUAL(110, function(7, 8, 9));
}
- :pass: FALSE
:should: 'we can override an ignore with an expect and fail'
:code: |
test()
{
bar_Ignore();
bar_Expect(2);
foo_ExpectAndReturn(1, 50);
foo_ExpectAndReturn(2, 60);
foo_ExpectAndReturn(3, 70);
TEST_ASSERT_EQUAL(180, function(1, 2, 3));
bar_Expect(5);
foo_ExpectAndReturn(4, 30);
foo_ExpectAndReturn(5, 80);
foo_ExpectAndReturn(6, 10);
TEST_ASSERT_EQUAL(120, function(4, 5, 6));
bar_Expect(9);
foo_ExpectAndReturn(7, 70);
foo_ExpectAndReturn(8, 20);
foo_ExpectAndReturn(9, 20);
TEST_ASSERT_EQUAL(110, function(7, 8, 9));
}
- :pass: TRUE
:should: 'we can override an ignore and return with an expect and pass'
:code: |
test()
{
bar_Ignore();
foo_IgnoreAndReturn(30);
TEST_ASSERT_EQUAL(90, function(1, 2, 3));
bar_Expect(5);
foo_ExpectAndReturn(4, 30);
foo_ExpectAndReturn(5, 80);
foo_ExpectAndReturn(6, 10);
TEST_ASSERT_EQUAL(120, function(4, 5, 6));
bar_Expect(8);
foo_ExpectAndReturn(7, 70);
foo_ExpectAndReturn(8, 20);
foo_ExpectAndReturn(9, 20);
TEST_ASSERT_EQUAL(110, function(7, 8, 9));
}
- :pass: FALSE
:should: 'we can override an ignore and return with an expect and fail'
:code: |
test()
{
bar_Ignore();
foo_IgnoreAndReturn(0);
TEST_ASSERT_EQUAL(0, function(1, 2, 3));
bar_Expect(5);
foo_ExpectAndReturn(4, 30);
foo_ExpectAndReturn(5, 80);
foo_ExpectAndReturn(6, 10);
TEST_ASSERT_EQUAL(120, function(4, 5, 6));
bar_Expect(9);
foo_ExpectAndReturn(7, 70);
foo_ExpectAndReturn(8, 20);
foo_ExpectAndReturn(9, 20);
TEST_ASSERT_EQUAL(110, function(7, 8, 9));
}
- :pass: TRUE
:should: 'we can override an expect with an ignore'
:code: |
test()
{
bar_Expect(5);
bar_Ignore();
foo_ExpectAndReturn(1, 50);
foo_ExpectAndReturn(2, 60);
foo_ExpectAndReturn(3, 70);
TEST_ASSERT_EQUAL(180, function(1, 2, 3));
}
- :pass: FALSE
:should: 'we can override an expect with an ignore and return and fail after'
:code: |
test()
{
bar_Expect(5);
foo_ExpectAndReturn(4, 30);
foo_ExpectAndReturn(5, 50);
foo_IgnoreAndReturn(20);
TEST_ASSERT_EQUAL(100, function(4, 5, 6));
bar_Expect(5);
foo_ExpectAndReturn(9, 30); //THIS ONE WILL FAIL
foo_ExpectAndReturn(2, 80);
foo_ExpectAndReturn(3, 60);
TEST_ASSERT_EQUAL(170, function(1, 2, 3));
}
- :pass: TRUE
:should: 'we can override an expect with an ignore and return and only the ignore and return is acknowledged'
:code: |
test()
{
bar_Expect(5);
foo_ExpectAndReturn(2, 30); //NOTE THIS WOULD NORMALLY FAIL
foo_ExpectAndReturn(5, 50);
foo_IgnoreAndReturn(20); //BUT WE SAID WE NO LONGER CARE
TEST_ASSERT_EQUAL(60, function(4, 5, 6));
}
# StopIgnore
- :pass: FALSE
:should: 'fail when function is called after ignore is stopped'
:code: |
test()
{
bar_Ignore();
foo_IgnoreAndReturn(10);
function(0, 0, 0);
bar_StopIgnore();
function(0, 0, 0);
}
- :pass: FALSE
:should: 'delete expect after ignore is stopped'
:code: |
test()
{
bar_Ignore();
foo_ExpectAndReturn(0, 40);
foo_ExpectAndReturn(0, 30);
foo_ExpectAndReturn(0, 40);
foo_IgnoreAndReturn(20);
foo_StopIgnore();
TEST_ASSERT_EQUAL(110, function(0, 0, 0)); // THIS SHOULD FAIL
}
- :pass: TRUE
:should: 'delete expected return values after ignore is stopped'
:code: |
test()
{
bar_Ignore();
foo_ExpectAndReturn(0, 40);
foo_ExpectAndReturn(0, 30);
foo_ExpectAndReturn(0, 40);
foo_IgnoreAndReturn(20);
foo_StopIgnore();
foo_ExpectAndReturn(0, 50);
foo_ExpectAndReturn(0, 30);
foo_ExpectAndReturn(0, 40);
TEST_ASSERT_EQUAL(120, function(0, 0, 0));
}
...
@@ -0,0 +1,116 @@
# ==========================================
# CMock Project - Automatic Mock Generation for C
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
# [Released under MIT License. Please refer to license.txt for details]
# ==========================================
require File.expand_path(File.dirname(__FILE__)) + "/../test_helper"
require File.expand_path(File.dirname(__FILE__)) + '/../../lib/cmock_generator_plugin_ignore_stateless'
describe CMockGeneratorPluginIgnoreStateless, "Verify CMockGeneratorPluginIgnoreStateless Module" do
before do
create_mocks :config, :utils
@config = create_stub(:respond_to? => true)
@cmock_generator_plugin_ignore_stateless = CMockGeneratorPluginIgnoreStateless.new(@config, @utils)
end
after do
end
it "have set up internal priority" do
assert_equal(2, @cmock_generator_plugin_ignore_stateless.priority)
end
it "not have any additional include file requirements" do
assert(!@cmock_generator_plugin_ignore_stateless.respond_to?(:include_files))
end
it "add a required variable to the instance structure" do
function = {:name => "Grass", :args => [], :return => test_return[:void]}
expected = " char Grass_IgnoreBool;\n"
returned = @cmock_generator_plugin_ignore_stateless.instance_structure(function)
assert_equal(expected, returned)
end
it "handle function declarations for functions without return values" do
function = {:name => "Mold", :args_string => "void", :return => test_return[:void]}
expected = "#define Mold_Ignore() Mold_CMockIgnore()\nvoid Mold_CMockIgnore(void);\n" +
"#define Mold_StopIgnore() Mold_CMockStopIgnore()\nvoid Mold_CMockStopIgnore(void);\n"
returned = @cmock_generator_plugin_ignore_stateless.mock_function_declarations(function)
assert_equal(expected, returned)
end
it "handle function declarations for functions that returns something" do
function = {:name => "Fungus", :args_string => "void", :return => test_return[:string]}
expected = "#define Fungus_IgnoreAndReturn(cmock_retval) Fungus_CMockIgnoreAndReturn(cmock_retval)\n"+
"void Fungus_CMockIgnoreAndReturn(const char* cmock_to_return);\n" +
"#define Fungus_StopIgnore() Fungus_CMockStopIgnore()\n"+
"void Fungus_CMockStopIgnore(void);\n"
returned = @cmock_generator_plugin_ignore_stateless.mock_function_declarations(function)
assert_equal(expected, returned)
end
it "add required code to implementation precheck with void function" do
function = {:name => "Mold", :args_string => "void", :return => test_return[:void]}
expected = [" if (Mock.Mold_IgnoreBool)\n",
" {\n",
" UNITY_CLR_DETAILS();\n",
" return;\n",
" }\n"
].join
returned = @cmock_generator_plugin_ignore_stateless.mock_implementation_precheck(function)
assert_equal(expected, returned)
end
it "add required code to implementation precheck with return functions" do
function = {:name => "Fungus", :args_string => "void", :return => test_return[:int]}
retval = test_return[:int].merge({ :name => "cmock_call_instance->ReturnVal"})
@utils.expect :code_assign_argument_quickly, ' mock_retval_0', ["Mock.Fungus_FinalReturn", retval]
expected = [" if (Mock.Fungus_IgnoreBool)\n",
" {\n",
" UNITY_CLR_DETAILS();\n",
" if (cmock_call_instance == NULL)\n",
" return Mock.Fungus_FinalReturn;\n",
" mock_retval_0",
" return cmock_call_instance->ReturnVal;\n",
" }\n"
].join
returned = @cmock_generator_plugin_ignore_stateless.mock_implementation_precheck(function)
assert_equal(expected, returned)
end
it "add a new mock interface for ignoring when function had no return value" do
function = {:name => "Slime", :args => [], :args_string => "void", :return => test_return[:void]}
expected = ["void Slime_CMockIgnore(void)\n",
"{\n",
" Mock.Slime_IgnoreBool = (char)1;\n",
"}\n\n",
"void Slime_CMockStopIgnore(void)\n",
"{\n",
" Mock.Slime_IgnoreBool = (char)0;\n",
"}\n\n"
].join
returned = @cmock_generator_plugin_ignore_stateless.mock_interfaces(function)
assert_equal(expected, returned)
end
it "add a new mock interface for ignoring when function has return value" do
function = {:name => "Slime", :args => [], :args_string => "void", :return => test_return[:int]}
@utils.expect :code_add_base_expectation, "mock_return_1", ["Slime", false]
expected = ["void Slime_CMockIgnoreAndReturn(int cmock_to_return)\n",
"{\n",
" Mock.Slime_CallInstance = CMOCK_GUTS_NONE;\n",
" Mock.Slime_FinalReturn = cmock_to_return;\n",
" Mock.Slime_IgnoreBool = (char)1;\n",
"}\n\n",
"void Slime_CMockStopIgnore(void)\n",
"{\n",
" Mock.Slime_IgnoreBool = (char)0;\n",
"}\n\n"
].join
returned = @cmock_generator_plugin_ignore_stateless.mock_interfaces(function)
assert_equal(expected, returned)
end
end
@@ -73,7 +73,7 @@ describe CMockGeneratorPluginReturnThruPtr, "Verify CMockGeneratorPluginReturnTh
complex_func_expect()
expected = " char ReturnThruPtr_tofu_Used;\n" +
" int* ReturnThruPtr_tofu_Val;\n" +
" int ReturnThruPtr_tofu_Size;\n"
" size_t ReturnThruPtr_tofu_Size;\n"
returned = @cmock_generator_plugin_return_thru_ptr.instance_typedefs(@complex_func)
assert_equal(expected, returned)
end
@@ -91,10 +91,10 @@ describe CMockGeneratorPluginReturnThruPtr, "Verify CMockGeneratorPluginReturnTh
"#define Pine_ReturnThruPtr_tofu(tofu)" +
" Pine_CMockReturnMemThruPtr_tofu(__LINE__, tofu, sizeof(int))\n" +
"#define Pine_ReturnArrayThruPtr_tofu(tofu, cmock_len)" +
" Pine_CMockReturnMemThruPtr_tofu(__LINE__, tofu, (int)(cmock_len * (int)sizeof(*tofu)))\n" +
" Pine_CMockReturnMemThruPtr_tofu(__LINE__, tofu, cmock_len * sizeof(*tofu))\n" +
"#define Pine_ReturnMemThruPtr_tofu(tofu, cmock_size)" +
" Pine_CMockReturnMemThruPtr_tofu(__LINE__, tofu, cmock_size)\n" +
"void Pine_CMockReturnMemThruPtr_tofu(UNITY_LINE_TYPE cmock_line, int* tofu, int cmock_size);\n"
"void Pine_CMockReturnMemThruPtr_tofu(UNITY_LINE_TYPE cmock_line, int* tofu, size_t cmock_size);\n"
returned = @cmock_generator_plugin_return_thru_ptr.mock_function_declarations(@complex_func)
assert_equal(expected, returned)
@@ -104,7 +104,7 @@ describe CMockGeneratorPluginReturnThruPtr, "Verify CMockGeneratorPluginReturnTh
complex_func_expect();
expected =
"void Pine_CMockReturnMemThruPtr_tofu(UNITY_LINE_TYPE cmock_line, int* tofu, int cmock_size)\n" +
"void Pine_CMockReturnMemThruPtr_tofu(UNITY_LINE_TYPE cmock_line, int* tofu, size_t cmock_size)\n" +
"{\n" +
" CMOCK_Pine_CALL_INSTANCE* cmock_call_instance = " +
"(CMOCK_Pine_CALL_INSTANCE*)CMock_Guts_GetAddressFor(CMock_Guts_MemEndOfChain(Mock.Pine_CallInstance));\n" +
+14 -9
View File
@@ -20,17 +20,19 @@ describe CMockGeneratorUtils, "Verify CMockGeneratorUtils Module" do
@config.expect :plugins, []
@config.expect :plugins, []
@config.expect :plugins, []
@config.expect :plugins, []
@config.expect :treat_as, {'int' => 'INT','short' => 'INT16','long' => 'INT','char' => 'INT8','const char*' => 'STRING'}
@cmock_generator_utils_simple = CMockGeneratorUtils.new(@config, {:unity_helper => @unity_helper})
@config.expect :when_ptr, :smart
@config.expect :enforce_strict_ordering, true
@config.expect :plugins, [:array, :cexception, :return_thru_ptr, :ignore_arg, :ignore]
@config.expect :plugins, [:array, :cexception, :return_thru_ptr, :ignore_arg, :ignore]
@config.expect :plugins, [:array, :cexception, :return_thru_ptr, :ignore_arg, :ignore]
@config.expect :plugins, [:array, :cexception, :return_thru_ptr, :ignore_arg, :ignore]
@config.expect :plugins, [:array, :cexception, :return_thru_ptr, :ignore_arg, :ignore]
@config.expect :plugins, [:array, :cexception, :return_thru_ptr, :ignore_arg, :ignore]
@config.expect :plugins, [:array, :cexception, :return_thru_ptr, :ignore_arg, :ignore, :ignore_stateless]
@config.expect :plugins, [:array, :cexception, :return_thru_ptr, :ignore_arg, :ignore, :ignore_stateless]
@config.expect :plugins, [:array, :cexception, :return_thru_ptr, :ignore_arg, :ignore, :ignore_stateless]
@config.expect :plugins, [:array, :cexception, :return_thru_ptr, :ignore_arg, :ignore, :ignore_stateless]
@config.expect :plugins, [:array, :cexception, :return_thru_ptr, :ignore_arg, :ignore, :ignore_stateless]
@config.expect :plugins, [:array, :cexception, :return_thru_ptr, :ignore_arg, :ignore, :ignore_stateless]
@config.expect :plugins, [:array, :cexception, :return_thru_ptr, :ignore_arg, :ignore, :ignore_stateless]
@config.expect :treat_as, {'int' => 'INT','short' => 'INT16','long' => 'INT','char' => 'INT8','uint32_t' => 'HEX32','const char*' => 'STRING'}
@cmock_generator_utils_complex = CMockGeneratorUtils.new(@config, {:unity_helper => @unity_helper, :A=>1, :B=>2})
end
@@ -153,7 +155,8 @@ describe CMockGeneratorUtils, "Verify CMockGeneratorUtils Module" do
:args_string => "stuff",
:args => [test_arg[:int_ptr], test_arg[:mytype], test_arg[:string]]
}
expected = "void CMockExpectParameters_Melon(CMOCK_Melon_CALL_INSTANCE* cmock_call_instance, stuff)\n{\n" +
expected = "void CMockExpectParameters_Melon(CMOCK_Melon_CALL_INSTANCE* cmock_call_instance, stuff);\n" +
"void CMockExpectParameters_Melon(CMOCK_Melon_CALL_INSTANCE* cmock_call_instance, stuff)\n{\n" +
" cmock_call_instance->Expected_MyIntPtr = MyIntPtr;\n" +
" memcpy((void*)(&cmock_call_instance->Expected_MyMyType), (void*)(&MyMyType),\n" +
" sizeof(MY_TYPE[sizeof(MyMyType) == sizeof(MY_TYPE) ? 1 : -1])); /* add MY_TYPE to :treat_as_array if this causes an error */\n" +
@@ -167,7 +170,8 @@ describe CMockGeneratorUtils, "Verify CMockGeneratorUtils Module" do
:args_string => "stuff",
:args => [test_arg[:int_ptr], test_arg[:mytype], test_arg[:string]]
}
expected = "void CMockExpectParameters_Melon(CMOCK_Melon_CALL_INSTANCE* cmock_call_instance, int* MyIntPtr, int MyIntPtr_Depth, const MY_TYPE MyMyType, const char* MyStr)\n{\n" +
expected = "void CMockExpectParameters_Melon(CMOCK_Melon_CALL_INSTANCE* cmock_call_instance, int* MyIntPtr, int MyIntPtr_Depth, const MY_TYPE MyMyType, const char* MyStr);\n" +
"void CMockExpectParameters_Melon(CMOCK_Melon_CALL_INSTANCE* cmock_call_instance, int* MyIntPtr, int MyIntPtr_Depth, const MY_TYPE MyMyType, const char* MyStr)\n{\n" +
" cmock_call_instance->Expected_MyIntPtr = MyIntPtr;\n" +
" cmock_call_instance->Expected_MyIntPtr_Depth = MyIntPtr_Depth;\n" +
" cmock_call_instance->IgnoreArg_MyIntPtr = 0;\n" +
@@ -186,7 +190,8 @@ describe CMockGeneratorUtils, "Verify CMockGeneratorUtils Module" do
:args_string => "stuff",
:args => [test_arg[:const_ptr], test_arg[:double_ptr]]
}
expected = "void CMockExpectParameters_Melon(CMOCK_Melon_CALL_INSTANCE* cmock_call_instance, int* const MyConstPtr, int MyConstPtr_Depth, int const** MyDoublePtr, int MyDoublePtr_Depth)\n{\n" +
expected = "void CMockExpectParameters_Melon(CMOCK_Melon_CALL_INSTANCE* cmock_call_instance, int* const MyConstPtr, int MyConstPtr_Depth, int const** MyDoublePtr, int MyDoublePtr_Depth);\n" +
"void CMockExpectParameters_Melon(CMOCK_Melon_CALL_INSTANCE* cmock_call_instance, int* const MyConstPtr, int MyConstPtr_Depth, int const** MyDoublePtr, int MyDoublePtr_Depth)\n{\n" +
" cmock_call_instance->Expected_MyConstPtr = MyConstPtr;\n" +
" cmock_call_instance->Expected_MyConstPtr_Depth = MyConstPtr_Depth;\n" +
" cmock_call_instance->IgnoreArg_MyConstPtr = 0;\n" +
+129 -3
View File
@@ -2009,7 +2009,8 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
end
end
it "Transform inline functions doesn't change a header with no inlines" do
it "Transform inline functions only removes comments from a header with no inlines" do
# We remove the comments from the header, this is to protect the parser from wrongfully recognizing inline functions
source =
"#ifndef _NOINCLUDES\n" +
"#define _NOINCLUDES\n" +
@@ -2040,7 +2041,37 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
"\n" +
"#endif _NOINCLUDES\n"
assert_equal(source, @parser.transform_inline_functions(source))
expected =
"#ifndef _NOINCLUDES\n" +
"#define _NOINCLUDES\n" +
"#include \"unity.h\"\n" +
"#include \"cmock.h\"\n" +
"#include \"YetAnotherHeader.h\"\n" +
"\n" +
"\n" + # Removed comment
"#if defined(__GNUC__) && !defined(__ICC) && !defined(__TMS470__)\n" +
"#if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ > 6 || (__GNUC_MINOR__ == 6 && __GNUC_PATCHLEVEL__ > 0)))\n" +
"#pragma GCC diagnostic push\n" +
"#endif\n" +
"#if !defined(__clang__)\n" +
"#pragma GCC diagnostic ignored \"-Wpragmas\"\n" +
"#endif\n" +
"#pragma GCC diagnostic ignored \"-Wunknown-pragmas\"\n" +
"#pragma GCC diagnostic ignored \"-Wduplicate-decl-specifier\"\n" +
"#endif\n" +
"\n" +
"struct my_struct {\n" +
"int a;\n" +
"int b;\n" +
"int b;\n" +
"char c;\n" +
"};\n" +
"int my_function(int a);\n" +
"int my_better_function(struct my_struct *s);\n" +
"\n" +
"#endif _NOINCLUDES\n"
assert_equal(expected, @parser.transform_inline_functions(source))
end
it "Transform inline functions changes inline functions to function declarations" do
@@ -2133,7 +2164,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
"#include \"cmock.h\"\n" +
"#include \"YetAnotherHeader.h\"\n" +
"\n" +
"/* Ignore the following warnings since we are copying code */\n" +
"\n" + # Removed comment
"#if defined(__GNUC__) && !defined(__ICC) && !defined(__TMS470__)\n" +
"#if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ > 6 || (__GNUC_MINOR__ == 6 && __GNUC_PATCHLEVEL__ > 0)))\n" +
"#pragma GCC diagnostic push\n" +
@@ -2173,6 +2204,73 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
assert_equal(expected, @parser.transform_inline_functions(source))
end
it "Transform inline functions leaves static variables" do
source =
"#ifndef _NOINCLUDES\n" +
"#define _NOINCLUDES\n" +
"#include \"unity.h\"\n" +
"#include \"cmock.h\"\n" +
"#include \"YetAnotherHeader.h\"\n" +
"\n" +
"/* Ignore the following warnings since we are copying code */\n" +
"#if defined(__GNUC__) && !defined(__ICC) && !defined(__TMS470__)\n" +
"#if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ > 6 || (__GNUC_MINOR__ == 6 && __GNUC_PATCHLEVEL__ > 0)))\n" +
"#pragma GCC diagnostic push\n" +
"#endif\n" +
"#if !defined(__clang__)\n" +
"#pragma GCC diagnostic ignored \"-Wpragmas\"\n" +
"#endif\n" +
"#pragma GCC diagnostic ignored \"-Wunknown-pragmas\"\n" +
"#pragma GCC diagnostic ignored \"-Wduplicate-decl-specifier\"\n" +
"#endif\n" +
"\n" +
"int my_function(int a);\n" +
"static inline int staticinlinefunc(struct my_struct *s)\n" +
"{\n" +
" return s->a;\n" +
"}\n" +
"static const int my_variable = 5;\n" +
"struct my_struct {\n" +
"int a;\n" +
"int b;\n" +
"int b;\n" +
"char c;\n" +
"};\n" +
"#endif _NOINCLUDES\n"
expected =
"#ifndef _NOINCLUDES\n" +
"#define _NOINCLUDES\n" +
"#include \"unity.h\"\n" +
"#include \"cmock.h\"\n" +
"#include \"YetAnotherHeader.h\"\n" +
"\n" +
"\n" + #The comments are now removed
"#if defined(__GNUC__) && !defined(__ICC) && !defined(__TMS470__)\n" +
"#if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ > 6 || (__GNUC_MINOR__ == 6 && __GNUC_PATCHLEVEL__ > 0)))\n" +
"#pragma GCC diagnostic push\n" +
"#endif\n" +
"#if !defined(__clang__)\n" +
"#pragma GCC diagnostic ignored \"-Wpragmas\"\n" +
"#endif\n" +
"#pragma GCC diagnostic ignored \"-Wunknown-pragmas\"\n" +
"#pragma GCC diagnostic ignored \"-Wduplicate-decl-specifier\"\n" +
"#endif\n" +
"\n" +
"int my_function(int a);\n" +
"int staticinlinefunc(struct my_struct *s);\n" +
"static const int my_variable = 5;\n" +
"struct my_struct {\n" +
"int a;\n" +
"int b;\n" +
"int b;\n" +
"char c;\n" +
"};\n" +
"#endif _NOINCLUDES\n"
assert_equal(expected, @parser.transform_inline_functions(source))
end
it "Count number of pairs of braces in function succesfully" do
source =
"int foo(struct my_struct *s)\n" +
@@ -2714,4 +2812,32 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
assert_equal(expected, @parser.transform_inline_functions(source))
end
it "Transform inline functions will ignore comments containing static" do
source =
"typedef struct {\n" +
"const uint32_t var1;\n" +
"const uint16_t var2; // comment with the word static in it\n" +
"} struct1;\n" +
"\n" +
"typedef struct {\n" +
"const uint32_t var1;\n" +
"const uint16_t var2;\n" +
"} struct2;\n"
expected =
"typedef struct {\n" +
"const uint32_t var1;\n" +
"const uint16_t var2; \n" +
"} struct1;\n" +
"\n" +
"typedef struct {\n" +
"const uint32_t var1;\n" +
"const uint16_t var2;\n" +
"} struct2;\n"
@parser.treat_inlines = :include
assert_equal(expected, @parser.transform_inline_functions(source))
end
end