52 Commits

Author SHA1 Message Date
Mark VanderVoord 27bca0c3c4 style cleanup 2021-02-05 15:53:43 -05:00
Mark VanderVoord 9bb250ea4a Update so only config is shared. Everything else about the current job is passed. 2021-02-05 15:15:14 -05:00
Mark VanderVoord 9d092898ef Merge pull request #346 from ThrowTheSwitch/reapply_329
Revert "Revert "CMock can now compile without setjmp.h present on the…
2021-01-29 10:54:18 -05:00
Mark VanderVoord dd00b96f0d Fix broken tests for supporting exclude_setjmp. Verify cexception won't be run when this is enabled. 2021-01-29 10:47:52 -05:00
Mark VanderVoord aa5113e012 Update apt-get in the hopes that this makes multilib happy. 2021-01-29 10:12:40 -05:00
Mark VanderVoord 325b6b333a Revert "Revert "CMock can now compile without setjmp.h present on the platform""
This reverts commit 3eccb8e3d4.
2021-01-29 10:06:08 -05:00
Mark VanderVoord 73fd65928c Merge pull request #345 from ThrowTheSwitch/revert-329-master
Revert "CMock can now compile without setjmp.h present on the platform"
2021-01-28 08:15:45 -05:00
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
25 changed files with 1068 additions and 295 deletions
+42
View File
@@ -0,0 +1,42 @@
---
# 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 update --assume-yes
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
================
+26 -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,14 @@ 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*\(+.*?\)+)']`
* `:exclude_setjmp_h`:
Some embedded systems don't have <setjmp.h> available. Setting this to true
removes references to this header file and the ability to use cexception.
* default: false
* `: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
+1
View File
@@ -41,6 +41,7 @@ class CMockConfig
:array_size_type => [],
:array_size_name => 'size|len',
:skeleton => false,
:exclude_setjmp_h => false,
# Format to look for inline functions.
# This is a combination of "static" and "inline" keywords ("static inline", "inline static", "inline", "static")
+2 -3
View File
@@ -41,8 +41,7 @@ class CMockFileWriter
def update_file(dest, src)
require 'fileutils'
FileUtils.rm(dest) if File.exist?(dest)
FileUtils.cp(src, dest)
FileUtils.rm(src)
FileUtils.rm(dest, :force => true)
FileUtils.mv(src, dest)
end
end
+96 -61
View File
@@ -19,7 +19,7 @@ class CMockGenerator
@ordered = @config.enforce_strict_ordering
@framework = @config.framework.to_s
@fail_on_unexpected_calls = @config.fail_on_unexpected_calls
@exclude_setjmp_h = @config.exclude_setjmp_h
@subdir = @config.subdir
@includes_h_pre_orig_header = (@config.includes || @config.includes_h_pre_orig_header || []).map { |h| h =~ /</ ? h : "\"#{h}\"" }
@@ -44,43 +44,71 @@ class CMockGenerator
end
end
def create_mock(module_name, parsed_stuff, module_ext = 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)
create_mock_subdir
create_mock_header_file(parsed_stuff)
create_mock_source_file(parsed_stuff)
def create_mock(module_name, parsed_stuff, module_ext = nil, folder = nil)
# determine the name for our new mock
mock_name = @prefix + module_name + @suffix
# determine the folder our mock will reside
mock_folder = if folder && @subdir
File.join(@subdir, folder)
elsif @subdir
@subdir
else
folder
end
# adds a trailing slash to the folder output
mock_folder = File.join(mock_folder, '') if mock_folder
# create out mock project from incoming data
mock_project = {
:module_name => module_name,
:module_ext => (module_ext || '.h'),
:mock_name => mock_name,
:clean_name => TypeSanitizer.sanitize_c_identifier(mock_name),
:folder => mock_folder,
:parsed_stuff => parsed_stuff,
:skeleton => false
}
create_mock_subdir(mock_project)
create_mock_header_file(mock_project)
create_mock_source_file(mock_project)
end
def create_skeleton(module_name, parsed_stuff)
@module_name = module_name
create_skeleton_source_file(parsed_stuff)
mock_project = {
:module_name => module_name,
:module_ext => '.h',
:parsed_stuff => parsed_stuff,
:skeleton => true
}
create_skeleton_source_file(mock_project)
end
private if $ThisIsOnlyATest.nil? ##############################
def create_mock_subdir
@file_writer.create_subdir(@subdir)
def create_mock_subdir(mock_project)
@file_writer.create_subdir(mock_project[:folder])
end
def create_using_statement(file, function)
file << "using namespace #{function[:namespace].join('::')};\n" unless function[:namespace].empty?
end
def create_mock_header_file(parsed_stuff)
def create_mock_header_file(mock_project)
if @include_inline == :include
@file_writer.create_file(@module_name + (@module_ext || '.h'), @subdir) do |file, _filename|
file << parsed_stuff[:normalized_source]
@file_writer.create_file(mock_project[:module_name] + (mock_project[:module_ext]), mock_project[:folder]) do |file, _filename|
file << mock_project[:parsed_stuff][:normalized_source]
end
end
@file_writer.create_file(@mock_name + (@module_ext || '.h'), @subdir) do |file, filename|
create_mock_header_header(file, filename)
create_mock_header_service_call_declarations(file)
create_typedefs(file, parsed_stuff[:typedefs])
parsed_stuff[:functions].each do |function|
@file_writer.create_file(mock_project[:mock_name] + mock_project[:module_ext], mock_project[:folder]) do |file, filename|
create_mock_header_header(file, filename, mock_project)
create_mock_header_service_call_declarations(file, mock_project)
create_typedefs(file, mock_project)
mock_project[:parsed_stuff][:functions].each do |function|
create_using_statement(file, function)
file << @plugins.run(:mock_function_declarations, function)
end
@@ -88,35 +116,37 @@ class CMockGenerator
end
end
def create_mock_source_file(parsed_stuff)
@file_writer.create_file(@mock_name + '.c', @subdir) do |file, filename|
create_source_header_section(file, filename, parsed_stuff[:functions])
create_instance_structure(file, parsed_stuff[:functions])
def create_mock_source_file(mock_project)
@file_writer.create_file(mock_project[:mock_name] + '.c', mock_project[:folder]) do |file, filename|
create_source_header_section(file, filename, mock_project)
create_instance_structure(file, mock_project)
create_extern_declarations(file)
create_mock_verify_function(file, parsed_stuff[:functions])
create_mock_init_function(file)
create_mock_destroy_function(file, parsed_stuff[:functions])
parsed_stuff[:functions].each do |function|
create_mock_verify_function(file, mock_project)
create_mock_init_function(file, mock_project)
create_mock_destroy_function(file, mock_project)
mock_project[:parsed_stuff][:functions].each do |function|
create_mock_implementation(file, function)
create_mock_interfaces(file, function)
end
end
end
def create_skeleton_source_file(parsed_stuff)
filename = "#{@config.mock_path}/#{@subdir + '/' if @subdir}#{module_name}.c"
def create_skeleton_source_file(mock_project)
filename = "#{@config.mock_path}/#{@subdir + '/' if @subdir}#{mock_project[:module_name]}.c"
existing = File.exist?(filename) ? File.read(filename) : ''
@file_writer.append_file(@module_name + '.c', @subdir) do |file, fullname|
create_source_header_section(file, fullname, []) if existing.empty?
parsed_stuff[:functions].each do |function|
@file_writer.append_file(mock_project[:module_name] + '.c', @subdir) do |file, fullname|
blank_project = mock_project.clone
blank_project[:parsed_stuff] = { :functions => [] }
create_source_header_section(file, fullname, blank_project) if existing.empty?
mock_project[:parsed_stuff][:functions].each do |function|
create_function_skeleton(file, function, existing)
end
end
end
def create_mock_header_header(file, _filename)
define_name = @clean_mock_name.upcase
orig_filename = (@subdir ? @subdir + '/' : '') + @module_name + (@module_ext || '.h')
def create_mock_header_header(file, _filename, mock_project)
define_name = mock_project[:clean_name].upcase
orig_filename = (mock_project[:folder] || '') + mock_project[:module_name] + mock_project[:module_ext]
file << "/* AUTOGENERATED FILE. DO NOT EDIT. */\n"
file << "#ifndef _#{define_name}_H\n"
file << "#define _#{define_name}_H\n\n"
@@ -141,16 +171,16 @@ class CMockGenerator
file << "\n"
end
def create_typedefs(file, typedefs)
def create_typedefs(file, mock_project)
file << "\n"
typedefs.each { |typedef| file << "#{typedef}\n" }
mock_project[:parsed_stuff][:typedefs].each { |typedef| file << "#{typedef}\n" }
file << "\n\n"
end
def create_mock_header_service_call_declarations(file)
file << "void #{@clean_mock_name}_Init(void);\n"
file << "void #{@clean_mock_name}_Destroy(void);\n"
file << "void #{@clean_mock_name}_Verify(void);\n\n"
def create_mock_header_service_call_declarations(file, mock_project)
file << "void #{mock_project[:clean_name]}_Init(void);\n"
file << "void #{mock_project[:clean_name]}_Destroy(void);\n"
file << "void #{mock_project[:clean_name]}_Verify(void);\n\n"
end
def create_mock_header_footer(header)
@@ -164,19 +194,21 @@ class CMockGenerator
header << "#endif\n"
end
def create_source_header_section(file, filename, functions)
header_file = (@subdir ? @subdir + '/' : '') + filename.gsub('.c', (@module_ext || '.h'))
file << "/* AUTOGENERATED FILE. DO NOT EDIT. */\n" unless functions.empty?
def create_source_header_section(file, filename, mock_project)
header_file = (mock_project[:folder] || '') + filename.gsub('.c', mock_project[:module_ext])
file << "/* AUTOGENERATED FILE. DO NOT EDIT. */\n" unless mock_project[:parsed_stuff][:functions].empty?
file << "#include <string.h>\n"
file << "#include <stdlib.h>\n"
file << "#include <setjmp.h>\n"
unless @exclude_setjmp_h
file << "#include <setjmp.h>\n"
end
file << "#include \"cmock.h\"\n"
@includes_c_pre_header.each { |inc| file << "#include #{inc}\n" }
file << "#include \"#{header_file}\"\n"
@includes_c_post_header.each { |inc| file << "#include #{inc}\n" }
file << "\n"
strs = []
functions.each do |func|
mock_project[:parsed_stuff][:functions].each do |func|
strs << func[:name]
func[:args].each { |arg| strs << arg[:name] }
end
@@ -186,14 +218,15 @@ class CMockGenerator
file << "\n"
end
def create_instance_structure(file, functions)
def create_instance_structure(file, mock_project)
functions = mock_project[:parsed_stuff][:functions]
functions.each do |function|
file << "typedef struct _CMOCK_#{function[:name]}_CALL_INSTANCE\n{\n"
file << " UNITY_LINE_TYPE LineNumber;\n"
file << @plugins.run(:instance_typedefs, function)
file << "\n} CMOCK_#{function[:name]}_CALL_INSTANCE;\n\n"
end
file << "static struct #{@clean_mock_name}Instance\n{\n"
file << "static struct #{mock_project[:clean_name]}Instance\n{\n"
if functions.empty?
file << " unsigned char placeHolder;\n"
end
@@ -205,7 +238,9 @@ class CMockGenerator
end
def create_extern_declarations(file)
file << "extern jmp_buf AbortFrame;\n"
unless @exclude_setjmp_h
file << "extern jmp_buf AbortFrame;\n"
end
if @ordered
file << "extern int GlobalExpectCount;\n"
file << "extern int GlobalVerifyOrder;\n"
@@ -213,9 +248,9 @@ class CMockGenerator
file << "\n"
end
def create_mock_verify_function(file, functions)
file << "void #{@clean_mock_name}_Verify(void)\n{\n"
verifications = functions.collect do |function|
def create_mock_verify_function(file, mock_project)
file << "void #{mock_project[:clean_name]}_Verify(void)\n{\n"
verifications = mock_project[:parsed_stuff][:functions].collect do |function|
v = @plugins.run(:mock_verify, function)
v.empty? ? v : [" call_instance = Mock.#{function[:name]}_CallInstance;\n", v]
end.join
@@ -227,20 +262,20 @@ class CMockGenerator
file << "}\n\n"
end
def create_mock_init_function(file)
file << "void #{@clean_mock_name}_Init(void)\n{\n"
file << " #{@clean_mock_name}_Destroy();\n"
def create_mock_init_function(file, mock_project)
file << "void #{mock_project[:clean_name]}_Init(void)\n{\n"
file << " #{mock_project[:clean_name]}_Destroy();\n"
file << "}\n\n"
end
def create_mock_destroy_function(file, functions)
file << "void #{@clean_mock_name}_Destroy(void)\n{\n"
def create_mock_destroy_function(file, mock_project)
file << "void #{mock_project[:clean_name]}_Destroy(void)\n{\n"
file << " CMock_Guts_MemFreeAll();\n"
file << " memset(&Mock, 0, sizeof(Mock));\n"
file << functions.collect { |function| @plugins.run(:mock_destroy, function) }.join
file << mock_project[:parsed_stuff][:functions].collect { |function| @plugins.run(:mock_destroy, function) }.join
unless @fail_on_unexpected_calls
file << functions.collect { |function| @plugins.run(:mock_ignore, function) }.join
file << mock_project[:parsed_stuff][:functions].collect { |function| @plugins.run(:mock_ignore, function) }.join
end
if @ordered
+1
View File
@@ -12,6 +12,7 @@ class CMockGeneratorPluginCexception
@config = config
@utils = utils
@priority = 7
raise 'Error: cexception is not supported without setjmp support' if @config.exclude_setjmp_h
end
def include_files
@@ -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
+69 -41
View File
@@ -8,7 +8,6 @@ class CMockHeaderParser
attr_accessor :funcs, :c_attr_noconst, :c_attributes, :treat_as_void, :treat_externs, :treat_inlines, :inline_function_patterns
def initialize(cfg)
@funcs = []
@c_strippables = cfg.strippables
@c_attr_noconst = cfg.attributes.uniq - ['const']
@c_attributes = ['const'] + c_attr_noconst
@@ -31,36 +30,48 @@ class CMockHeaderParser
end
def parse(name, source)
@module_name = name.gsub(/\W/, '')
@typedefs = []
@funcs = []
@normalized_source = nil
parse_project = {
:module_name => name.gsub(/\W/, ''),
:typedefs => [],
:functions => [],
:normalized_source => nil
}
function_names = []
all_funcs = parse_functions(import_source(source)).map { |item| [item] }
all_funcs += parse_cpp_functions(import_source(source, true))
all_funcs = parse_functions(import_source(source, parse_project)).map { |item| [item] }
all_funcs += parse_cpp_functions(import_source(source, parse_project, true))
all_funcs.map do |decl|
func = parse_declaration(*decl)
func = parse_declaration(parse_project, *decl)
unless function_names.include? func[:name]
@funcs << func
parse_project[:functions] << func
function_names << func[:name]
end
end
@normalized_source = if @treat_inlines == :include
transform_inline_functions(source)
else
''
end
parse_project[:normalized_source] = if @treat_inlines == :include
transform_inline_functions(source)
else
''
end
{ :includes => nil,
:functions => @funcs,
:typedefs => @typedefs,
:normalized_source => @normalized_source }
:functions => parse_project[:functions],
:typedefs => parse_project[:typedefs],
:normalized_source => parse_project[:normalized_source] }
end
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 +130,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 +152,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 +171,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,30 +181,39 @@ 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
source
end
def import_source(source, cpp = false)
def import_source(source, parse_project, cpp = false)
# 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)
@@ -205,10 +236,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, '')
@@ -238,9 +266,9 @@ class CMockHeaderParser
# 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|
functype = "cmock_#{@module_name}_func_ptr#{@typedefs.size + 1}"
functype = "cmock_#{parse_project[:module_name]}_func_ptr#{parse_project[:typedefs].size + 1}"
unless cpp # only collect once
@typedefs << "typedef #{Regexp.last_match(1).strip}(*#{functype})(#{Regexp.last_match(4)});"
parse_project[:typedefs] << "typedef #{Regexp.last_match(1).strip}(*#{functype})(#{Regexp.last_match(4)});"
"#{functype} #{Regexp.last_match(2).strip}(#{Regexp.last_match(3)});"
end
end
@@ -443,7 +471,7 @@ class CMockHeaderParser
divination
end
def clean_args(arg_list)
def clean_args(arg_list, parse_project)
if @local_as_void.include?(arg_list.strip) || arg_list.empty?
'void'
else
@@ -457,7 +485,7 @@ class CMockHeaderParser
# scan argument list for function pointers and replace them with custom types
arg_list.gsub!(/([\w\s\*]+)\(+\s*\*[\*\s]*([\w\s]*)\s*\)+\s*\(((?:[\w\s\*]*,?)*)\s*\)*/) do |_m|
functype = "cmock_#{@module_name}_func_ptr#{@typedefs.size + 1}"
functype = "cmock_#{parse_project[:module_name]}_func_ptr#{parse_project[:typedefs].size + 1}"
funcret = Regexp.last_match(1).strip
funcname = Regexp.last_match(2).strip
funcargs = Regexp.last_match(3).strip
@@ -466,14 +494,14 @@ class CMockHeaderParser
funcname.gsub!('const', '').strip!
funconst = 'const '
end
@typedefs << "typedef #{funcret}(*#{functype})(#{funcargs});"
parse_project[:typedefs] << "typedef #{funcret}(*#{functype})(#{funcargs});"
funcname = "cmock_arg#{c += 1}" if funcname.empty?
"#{functype} #{funconst}#{funcname}"
end
# scan argument list for function pointers with shorthand notation and replace them with custom types
arg_list.gsub!(/([\w\s\*]+)+\s+(\w+)\s*\(((?:[\w\s\*]*,?)*)\s*\)*/) do |_m|
functype = "cmock_#{@module_name}_func_ptr#{@typedefs.size + 1}"
functype = "cmock_#{parse_project[:module_name]}_func_ptr#{parse_project[:typedefs].size + 1}"
funcret = Regexp.last_match(1).strip
funcname = Regexp.last_match(2).strip
funcargs = Regexp.last_match(3).strip
@@ -482,7 +510,7 @@ class CMockHeaderParser
funcname.gsub!('const', '').strip!
funconst = 'const '
end
@typedefs << "typedef #{funcret}(*#{functype})(#{funcargs});"
parse_project[:typedefs] << "typedef #{funcret}(*#{functype})(#{funcargs});"
funcname = "cmock_arg#{c += 1}" if funcname.empty?
"#{functype} #{funconst}#{funcname}"
end
@@ -499,7 +527,7 @@ class CMockHeaderParser
end
end
def parse_declaration(declaration, namespace = [], classname = nil)
def parse_declaration(parse_project, declaration, namespace = [], classname = nil)
decl = {}
decl[:namespace] = namespace
decl[:class] = classname
@@ -555,7 +583,7 @@ class CMockHeaderParser
else
decl[:var_arg] = nil
end
args = clean_args(args)
args = clean_args(args, parse_project)
decl[:args_string] = args
decl[:args] = parse_args(args)
decl[:args_call] = decl[:args].map { |a| a[:name] }.join(', ')
+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)
+13 -7
View File
@@ -11,7 +11,7 @@
#define CMOCK_VERSION_MAJOR 2
#define CMOCK_VERSION_MINOR 5
#define CMOCK_VERSION_BUILD 2
#define CMOCK_VERSION_BUILD 3
#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 */
@@ -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));
}
...
+48 -40
View File
@@ -55,6 +55,7 @@ describe CMockGenerator, "Verify CMockGenerator Module" do
@config.expect :subdir, nil
@config.expect :fail_on_unexpected_calls, true
@config.expect :treat_inlines, :exclude
@config.expect :exclude_setjmp_h, false
@cmock_generator = CMockGenerator.new(@config, @file_writer, @utils, @plugins)
@cmock_generator.module_name = @module_name
@cmock_generator.module_ext = '.h'
@@ -75,21 +76,28 @@ describe CMockGenerator, "Verify CMockGenerator Module" do
@config.expect :subdir, nil
@config.expect :fail_on_unexpected_calls, true
@config.expect :treat_inlines, :exclude
@config.expect :exclude_setjmp_h, false
@cmock_generator_strict = CMockGenerator.new(@config, @file_writer, @utils, @plugins)
@cmock_generator_strict.module_name = @module_name
@cmock_generator_strict.module_ext = '.h'
@cmock_generator_strict.mock_name = "Mock#{@module_name}"
@cmock_generator_strict.clean_mock_name = "Mock#{@module_name}"
@test_project = {
:module_name => @module_name,
:module_ext => '.h',
:mock_name => "Mock#{@module_name}",
:clean_name => "Mock#{@module_name}",
:folder => nil,
:parsed_stuff => {},
:skeleton => false
}
end
after do
end
def helper_create_header_top_with_opt_incldues_form_config_and_plugin(ext)
def helper_create_header_top_with_opt_includes_form_config_and_plugin(ext)
@config.expect :mock_prefix, "Mock"
@config.expect :mock_suffix, ""
@config.expect :weak, ""
@cmock_generator.module_ext = ext
orig_filename = "PoutPoutFish#{ext}"
define_name = "MOCKPOUTPOUTFISH_H"
output = []
@@ -120,40 +128,26 @@ describe CMockGenerator, "Verify CMockGenerator Module" do
@config.expect :orig_header_include_fmt, "#include \"%s\""
@plugins.expect :run, "#include \"PluginRequiredHeader.h\"\n", [:include_files]
@cmock_generator.create_mock_header_header(output, "Mock#{orig_filename}")
# Update the extention for this test
test_project = @test_project.clone
test_project[:module_ext] = ext
@cmock_generator.create_mock_header_header(output, "Mock#{orig_filename}", test_project)
assert_equal(expected, output)
end
it "create the top of a header file with optional include files from config and include file from plugin" do
['.h','.hh','.hpp'].each do |ext|
helper_create_header_top_with_opt_incldues_form_config_and_plugin(ext)
helper_create_header_top_with_opt_includes_form_config_and_plugin(ext)
end
end
it "handle dashes and spaces in the module name" do
#no strict handling
@config.expect :mock_prefix, "Mock"
@config.expect :mock_suffix, ""
@config.expect :weak, ""
@config.expect :enforce_strict_ordering, nil
@config.expect :framework, :unity
@config.expect :includes, ["ConfigRequiredHeader1.h","ConfigRequiredHeader2.h"]
@config.expect :includes_h_post_orig_header, nil
@config.expect :includes_c_pre_header, nil
@config.expect :includes_c_post_header, nil
@config.expect :subdir, nil
@config.expect :fail_on_unexpected_calls, true
@config.expect :treat_inlines, :exclude
@cmock_generator2 = CMockGenerator.new(@config, @file_writer, @utils, @plugins)
@cmock_generator2.module_name = "Pout-Pout Fish"
@cmock_generator2.module_ext = '.h'
@cmock_generator2.mock_name = "MockPout-Pout Fish"
@cmock_generator2.clean_mock_name = "MockPout_Pout_Fish"
@config.expect :mock_prefix, "Mock"
@config.expect :mock_suffix, ""
@config.expect :weak, ""
orig_filename = "Pout-Pout Fish.h"
define_name = "MOCKPOUT_POUT_FISH_H"
output = []
@@ -184,7 +178,13 @@ describe CMockGenerator, "Verify CMockGenerator Module" do
@config.expect :orig_header_include_fmt, "#include \"%s\""
@plugins.expect :run, "#include \"PluginRequiredHeader.h\"\n", [:include_files]
@cmock_generator2.create_mock_header_header(output, "MockPout-Pout Fish.h")
# Create a project with some added challenges
test_project = @test_project.clone
test_project[:module_name] = "Pout-Pout Fish"
test_project[:mock_name] = "MockPout-Pout Fish"
test_project[:clean_name] = "MockPout_Pout_Fish"
@cmock_generator.create_mock_header_header(output, "MockPout-Pout Fish.h", test_project)
assert_equal(expected, output)
end
@@ -222,7 +222,7 @@ describe CMockGenerator, "Verify CMockGenerator Module" do
@config.expect :orig_header_include_fmt, "#include \"%s\""
@plugins.expect :run, '', [:include_files]
@cmock_generator.create_mock_header_header(output, "MockPoutPoutFish.h")
@cmock_generator.create_mock_header_header(output, "MockPoutPoutFish.h", @test_project)
assert_equal(expected, output)
end
@@ -261,7 +261,7 @@ describe CMockGenerator, "Verify CMockGenerator Module" do
@config.expect :orig_header_include_fmt, "#include \"%s\""
@plugins.expect :run, "#include \"PluginRequiredHeader.h\"\n", [:include_files]
@cmock_generator.create_mock_header_header(output, "MockPoutPoutFish.h")
@cmock_generator.create_mock_header_header(output, "MockPoutPoutFish.h", @test_project)
assert_equal(expected, output)
end
@@ -279,7 +279,8 @@ describe CMockGenerator, "Verify CMockGenerator Module" do
"\n\n"
]
@cmock_generator.create_typedefs(output, typedefs)
@test_project[:parsed_stuff][:typedefs] = typedefs
@cmock_generator.create_typedefs(output, @test_project)
assert_equal(expected, output.flatten)
end
@@ -293,7 +294,7 @@ describe CMockGenerator, "Verify CMockGenerator Module" do
"void #{mock_name}_Verify(void);\n\n"
]
@cmock_generator.create_mock_header_service_call_declarations(output)
@cmock_generator.create_mock_header_service_call_declarations(output, @test_project)
assert_equal(expected, output)
end
@@ -337,7 +338,8 @@ describe CMockGenerator, "Verify CMockGenerator Module" do
"\n"
]
@cmock_generator.create_source_header_section(output, "MockPoutPoutFish.c", functions)
@test_project[:parsed_stuff][:functions] = functions
@cmock_generator.create_source_header_section(output, "MockPoutPoutFish.c", @test_project)
assert_equal(expected, output)
end
@@ -351,7 +353,8 @@ describe CMockGenerator, "Verify CMockGenerator Module" do
"} Mock;\n\n"
].join
@cmock_generator.create_instance_structure(output, functions)
@test_project[:parsed_stuff][:functions] = functions
@cmock_generator.create_instance_structure(output, @test_project)
assert_equal(expected, output.join)
end
@@ -381,7 +384,8 @@ describe CMockGenerator, "Verify CMockGenerator Module" do
@plugins.expect :run, [" d1"], [:instance_structure, functions[0]]
@plugins.expect :run, [" e1"," e2"," e3"], [:instance_structure, functions[1]]
@cmock_generator.create_instance_structure(output, functions)
@test_project[:parsed_stuff][:functions] = functions
@cmock_generator.create_instance_structure(output, @test_project)
assert_equal(expected, output.join)
end
@@ -413,7 +417,8 @@ describe CMockGenerator, "Verify CMockGenerator Module" do
output = []
expected = "void MockPoutPoutFish_Verify(void)\n{\n}\n\n"
@cmock_generator.create_mock_verify_function(output, functions)
@test_project[:parsed_stuff][:functions] = functions
@cmock_generator.create_mock_verify_function(output, @test_project)
assert_equal(expected, output.join)
end
@@ -438,7 +443,8 @@ describe CMockGenerator, "Verify CMockGenerator Module" do
@plugins.expect :run, [" Uno_Second"," Dos_Second"], [:mock_verify, functions[1]]
@cmock_generator.ordered = true
@cmock_generator.create_mock_verify_function(output, functions)
@test_project[:parsed_stuff][:functions] = functions
@cmock_generator.create_mock_verify_function(output, @test_project)
assert_equal(expected, output.flatten)
end
@@ -450,7 +456,7 @@ describe CMockGenerator, "Verify CMockGenerator Module" do
"}\n\n"
]
@cmock_generator.create_mock_init_function(output)
@cmock_generator.create_mock_init_function(output, @test_project)
assert_equal(expected.join, output.join)
end
@@ -464,7 +470,8 @@ describe CMockGenerator, "Verify CMockGenerator Module" do
"}\n\n"
]
@cmock_generator.create_mock_destroy_function(output, functions)
@test_project[:parsed_stuff][:functions] = functions
@cmock_generator.create_mock_destroy_function(output, @test_project)
assert_equal(expected.join, output.join)
end
@@ -485,7 +492,8 @@ describe CMockGenerator, "Verify CMockGenerator Module" do
@plugins.expect :run, [], [:mock_destroy, functions[0]]
@plugins.expect :run, [" uno"], [:mock_destroy, functions[1]]
@cmock_generator_strict.create_mock_destroy_function(output, functions)
@test_project[:parsed_stuff][:functions] = functions
@cmock_generator_strict.create_mock_destroy_function(output, @test_project)
assert_equal(expected.join, output.join)
end
@@ -11,6 +11,9 @@ describe CMockGeneratorPluginCexception, "Verify CMockGeneratorPluginCexception
before do
create_mocks :config, :utils
@config.expect :exclude_setjmp_h, false
@cmock_generator_plugin_cexception = CMockGeneratorPluginCexception.new(@config, @utils)
end
@@ -93,4 +96,13 @@ describe CMockGeneratorPluginCexception, "Verify CMockGeneratorPluginCexception
assert_equal(expected, returned)
end
it "should throw an exception if we try to use this plugin when setjmp disabled" do
@config.expect :exclude_setjmp_h, true
assert_raises RuntimeError do
@cmock_generator_plugin_cexception = CMockGeneratorPluginCexception.new(@config, @utils)
end
end
end
@@ -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" +
+175 -43
View File
@@ -13,7 +13,6 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
before do
create_mocks :config
@test_name = 'test_file.h'
@config.expect :strippables, ["STRIPPABLE"]
@config.expect :attributes, ['__ramfunc', 'funky_attrib', 'SQLITE_API']
@config.expect :c_calling_conventions, ['__stdcall']
@@ -29,13 +28,20 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
@config.expect :array_size_name, 'size|len'
@parser = CMockHeaderParser.new(@config)
@test_project = {
:module_name => 'test_file.h',
:typedefs => [],
:functions => [],
:normalized_source => nil
}
end
after do
end
it "create and initialize variables to defaults appropriately" do
assert_equal([], @parser.funcs)
assert_equal(nil, @parser.funcs)
assert_equal(['const', '__ramfunc', 'funky_attrib', 'SQLITE_API'], @parser.c_attributes)
assert_equal(['void','MY_FUNKY_VOID'], @parser.treat_as_void)
end
@@ -52,7 +58,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
"who"
]
assert_equal(expected, @parser.import_source(source).map!{|s|s.strip})
assert_equal(expected, @parser.import_source(source, @test_project).map!{|s|s.strip})
end
it "remove block comments" do
@@ -85,7 +91,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
"shown_because_line_above_ended_comment_this_time"
]
assert_equal(expected, @parser.import_source(source).map!{|s|s.strip})
assert_equal(expected, @parser.import_source(source, @test_project).map!{|s|s.strip})
end
it "remove strippables from the beginning or end of function declarations" do
@@ -105,7 +111,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
"void universal_handler()"
]
assert_equal(expected, @parser.import_source(source))
assert_equal(expected, @parser.import_source(source, @test_project))
end
it "remove gcc's function __attribute__'s" do
@@ -125,7 +131,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
"void universal_handler()"
]
assert_equal(expected, @parser.import_source(source))
assert_equal(expected, @parser.import_source(source, @test_project))
end
it "remove preprocessor directives" do
@@ -136,7 +142,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
expected = []
assert_equal(expected, @parser.import_source(source))
assert_equal(expected, @parser.import_source(source, @test_project))
end
@@ -151,7 +157,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
expected = ["foo"]
assert_equal(expected, @parser.import_source(source))
assert_equal(expected, @parser.import_source(source, @test_project))
end
@@ -165,7 +171,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
"hoo hah when"
]
assert_equal(expected, @parser.import_source(source).map!{|s|s.strip})
assert_equal(expected, @parser.import_source(source, @test_project).map!{|s|s.strip})
end
@@ -178,7 +184,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
expected = ["but I'm here"]
assert_equal(expected, @parser.import_source(source))
assert_equal(expected, @parser.import_source(source, @test_project))
end
@@ -212,7 +218,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
"this should remain!"
]
assert_equal(expected, @parser.import_source(source).map!{|s|s.strip})
assert_equal(expected, @parser.import_source(source, @test_project).map!{|s|s.strip})
end
@@ -230,7 +236,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
"} Thinger;\n" +
"or me!!\n"
assert_equal(["don't delete me!! or me!!"], @parser.import_source(source).map!{|s|s.strip})
assert_equal(["don't delete me!! or me!!"], @parser.import_source(source, @test_project).map!{|s|s.strip})
end
@@ -248,7 +254,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
"} Whatever;\n" +
"me too!!\n"
assert_equal(["I want to live!! me too!!"], @parser.import_source(source).map!{|s|s.strip})
assert_equal(["I want to live!! me too!!"], @parser.import_source(source, @test_project).map!{|s|s.strip})
end
@@ -271,7 +277,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
"I want to live!!\n"
assert_equal(["void foo(void)", "struct THINGER foo(void)", "I want to live!!"],
@parser.import_source(source).map!{|s|s.strip})
@parser.import_source(source, @test_project).map!{|s|s.strip})
end
it "remove externed and inline functions" do
@@ -290,7 +296,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
"uint32 funcinline(unsigned int)"
]
assert_equal(expected, @parser.import_source(source).map!{|s|s.strip})
assert_equal(expected, @parser.import_source(source, @test_project).map!{|s|s.strip})
end
it "remove function definitions but keep function declarations" do
@@ -312,7 +318,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
"uint32 func_with_decl_b", #okay. it's not going to be interpretted as another function
]
assert_equal(expected, @parser.import_source(source).map!{|s|s.strip})
assert_equal(expected, @parser.import_source(source, @test_project).map!{|s|s.strip})
end
it "remove function definitions with nested braces but keep function declarations" do
@@ -354,7 +360,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
"uint32 func_with_decl_c", #okay. it's not going to be interpretted as another function
]
assert_equal(expected, @parser.import_source(source).map!{|s|s.strip})
assert_equal(expected, @parser.import_source(source, @test_project).map!{|s|s.strip})
end
it "remove a fully defined inline function" do
@@ -371,7 +377,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
@parser.parse("module", source)
end
assert_equal([], @parser.funcs)
assert_equal(nil, @parser.funcs)
# verify exception message
begin
@@ -395,7 +401,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
@parser.parse("module", source)
end
assert_equal([], @parser.funcs)
assert_equal(nil, @parser.funcs)
# verify exception message
begin
@@ -423,7 +429,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
@parser.parse("module", source)
end
assert_equal([], @parser.funcs)
assert_equal(nil, @parser.funcs)
# verify exception message
begin
@@ -452,7 +458,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
]
@parser.treat_externs = :include
assert_equal(expected, @parser.import_source(source).map!{|s|s.strip})
assert_equal(expected, @parser.import_source(source, @test_project).map!{|s|s.strip})
end
it "leave inline functions if inline to be included" do
@@ -478,7 +484,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
]
@parser.treat_inlines = :include
assert_equal(expected, @parser.import_source(source).map!{|s|s.strip})
assert_equal(expected, @parser.import_source(source, @test_project).map!{|s|s.strip})
end
it "leave inline and extern functions if inline and extern to be included" do
@@ -507,7 +513,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
@parser.treat_externs = :include
@parser.treat_inlines = :include
assert_equal(expected, @parser.import_source(source).map!{|s|s.strip})
assert_equal(expected, @parser.import_source(source, @test_project).map!{|s|s.strip})
end
it "Include inline functions that contain user defined inline function formats" do
@@ -538,7 +544,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
@parser.treat_inlines = :include
@parser.inline_function_patterns = ['static __inline__ __attribute__ \(\(always_inline\)\)', 'static __inline__', '\binline\b']
assert_equal(expected, @parser.import_source(source).map!{|s|s.strip})
assert_equal(expected, @parser.import_source(source, @test_project).map!{|s|s.strip})
end
it "remove defines" do
@@ -554,7 +560,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
"void hello(void)",
]
assert_equal(expected, @parser.import_source(source).map!{|s|s.strip})
assert_equal(expected, @parser.import_source(source, @test_project).map!{|s|s.strip})
end
@@ -567,7 +573,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
"const int TheMatrix(int Trinity, unsigned int * Neo)",
]
assert_equal(expected, @parser.import_source(source).map!{|s|s.strip})
assert_equal(expected, @parser.import_source(source, @test_project).map!{|s|s.strip})
end
@@ -593,7 +599,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
:args=>[{:type=>"int", :name=>"a", :ptr? => false, :const? => false, :const_ptr? => false}],
:args_string=>"int a",
:args_call=>"a"}
assert_equal(expected, @parser.parse_declaration(source))
assert_equal(expected, @parser.parse_declaration(@test_project, source))
end
it "handle odd case of typedef'd void as arg" do
@@ -616,7 +622,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
:args=>[],
:args_string=>"void",
:args_call=>"" }
assert_equal(expected, @parser.parse_declaration(source))
assert_equal(expected, @parser.parse_declaration(@test_project, source))
end
it "handle odd case of typedef'd void as arg pointer" do
@@ -639,7 +645,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
:args=>[{:type=>"MY_FUNKY_VOID*", :name=>"bluh", :ptr? => true, :const? => false, :const_ptr? => false}],
:args_string=>"MY_FUNKY_VOID* bluh",
:args_call=>"bluh" }
assert_equal(expected, @parser.parse_declaration(source))
assert_equal(expected, @parser.parse_declaration(@test_project, source))
end
@@ -652,7 +658,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
"void Foo(int a, float b, char c, char* e)"
]
assert_equal(expected, @parser.import_source(source).map!{|s|s.strip})
assert_equal(expected, @parser.import_source(source, @test_project).map!{|s|s.strip})
end
@@ -664,7 +670,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
@parser.parse("module", source)
end
assert_equal([], @parser.funcs)
assert_equal(nil, @parser.funcs)
# verify exception message
begin
@@ -693,7 +699,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
@parser.parse("module", source)
end
assert_equal([], @parser.funcs)
assert_equal(nil, @parser.funcs)
# verify exception message
begin
@@ -743,7 +749,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
],
:args_string=>"int a, unsigned int b",
:args_call=>"a, b" }
assert_equal(expected, @parser.parse_declaration(source))
assert_equal(expected, @parser.parse_declaration(@test_project, source))
end
it "extract and return function declarations with no retval" do
@@ -770,7 +776,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
],
:args_string=>"uint la, int de, bool da",
:args_call=>"la, de, da" }
assert_equal(expected, @parser.parse_declaration(source))
assert_equal(expected, @parser.parse_declaration(@test_project, source))
end
it "extract and return function declarations with implied voids" do
@@ -794,7 +800,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
:args=>[ ],
:args_string=>"void",
:args_call=>"" }
assert_equal(expected, @parser.parse_declaration(source))
assert_equal(expected, @parser.parse_declaration(@test_project, source))
end
it "extract modifiers properly" do
@@ -820,7 +826,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
],
:args_string=>"int Trinity, unsigned int* Neo",
:args_call=>"Trinity, Neo" }
assert_equal(expected, @parser.parse_declaration(source))
assert_equal(expected, @parser.parse_declaration(@test_project, source))
end
it "extract c calling conventions properly" do
@@ -847,7 +853,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
],
:args_string=>"int Trinity, unsigned int* Neo",
:args_call=>"Trinity, Neo" }
assert_equal(expected, @parser.parse_declaration(source))
assert_equal(expected, @parser.parse_declaration(@test_project, source))
end
it "extract and return function declarations inside namespace and class" do
@@ -872,7 +878,7 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
],
:args_string=>"int a, unsigned int b",
:args_call=>"a, b" }
assert_equal(expected, @parser.parse_declaration(source, ["ns1", "ns2"], "Bar"))
assert_equal(expected, @parser.parse_declaration(@test_project, source, ["ns1", "ns2"], "Bar"))
end
it "fully parse multiple prototypes" do
@@ -2009,7 +2015,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 +2047,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 +2170,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 +2210,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" +
@@ -2289,8 +2393,8 @@ describe CMockHeaderParser, "Verify CMockHeaderParser Module" do
"} }"
]
assert_equal(expected, @parser.import_source(source, cpp=true))
refute_equal(expected, @parser.import_source(source))
assert_equal(expected, @parser.import_source(source, @test_project, cpp=true))
refute_equal(expected, @parser.import_source(source, @test_project))
end
# only so parse_functions does not raise an error
@@ -2714,4 +2818,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
+2 -1
View File
@@ -18,7 +18,8 @@ describe CMockPluginManager, "Verify CMockPluginManager Module" do
:respond_to => true,
:when_ptr => :compare_data,
:enforce_strict_ordering => false,
:ignore => :args_and_calls
:ignore => :args_and_calls,
:exclude_setjmp_h => false
)
def @config.plugins