mirror of
https://github.com/hathach/tinyusb.git
synced 2025-01-17 05:32:55 +08:00
update ceedling to 0.31.1
This commit is contained in:
parent
d9817ebe17
commit
a652212f27
@ -15,6 +15,7 @@
|
|||||||
# :release_build: TRUE
|
# :release_build: TRUE
|
||||||
:test_file_prefix: test_
|
:test_file_prefix: test_
|
||||||
:which_ceedling: vendor/ceedling
|
:which_ceedling: vendor/ceedling
|
||||||
|
:ceedling_version: 0.31.1
|
||||||
:default_tasks:
|
:default_tasks:
|
||||||
- test:all
|
- test:all
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@
|
|||||||
|
|
||||||
// CFG_TUSB_DEBUG is defined by compiler in DEBUG build
|
// CFG_TUSB_DEBUG is defined by compiler in DEBUG build
|
||||||
#ifndef CFG_TUSB_DEBUG
|
#ifndef CFG_TUSB_DEBUG
|
||||||
#define CFG_TUSB_DEBUG 0
|
#define CFG_TUSB_DEBUG 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
|
/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
|
||||||
|
79
test/vendor/ceedling/bin/ceedling
vendored
79
test/vendor/ceedling/bin/ceedling
vendored
@ -49,16 +49,16 @@ unless (project_found)
|
|||||||
end
|
end
|
||||||
|
|
||||||
desc "upgrade PROJECT_NAME", "upgrade ceedling for a project (not req'd if gem used)"
|
desc "upgrade PROJECT_NAME", "upgrade ceedling for a project (not req'd if gem used)"
|
||||||
method_option :docs, :type => :boolean, :default => false, :desc => "Add docs in project vendor directory"
|
|
||||||
method_option :local, :type => :boolean, :default => false, :desc => "Create a copy of Ceedling in the project vendor directory"
|
|
||||||
method_option :no_configs, :type => :boolean, :default => false, :desc => "Don't install starter configuration files"
|
|
||||||
method_option :noconfigs, :type => :boolean, :default => false
|
|
||||||
|
|
||||||
#deprecated:
|
|
||||||
method_option :no_docs, :type => :boolean, :default => false
|
|
||||||
method_option :nodocs, :type => :boolean, :default => false
|
|
||||||
def upgrade(name, silent = false)
|
def upgrade(name, silent = false)
|
||||||
copy_assets_and_create_structure(name, silent, true, options || {:upgrade => true})
|
as_local = true
|
||||||
|
begin
|
||||||
|
require "yaml"
|
||||||
|
as_local = (YAML.load_file(File.join(name, "project.yml"))[:project][:which_ceedling] != 'gem')
|
||||||
|
rescue
|
||||||
|
raise "ERROR: Could not find valid project file '#{yaml_path}'"
|
||||||
|
end
|
||||||
|
found_docs = File.exists?( File.join(name, "docs", "CeedlingPacket.md") )
|
||||||
|
copy_assets_and_create_structure(name, silent, true, {:upgrade => true, :no_configs => true, :local => as_local, :docs => found_docs})
|
||||||
end
|
end
|
||||||
|
|
||||||
no_commands do
|
no_commands do
|
||||||
@ -90,26 +90,30 @@ unless (project_found)
|
|||||||
FileUtils.touch(File.join(test_support_path, '.gitkeep'))
|
FileUtils.touch(File.join(test_support_path, '.gitkeep'))
|
||||||
|
|
||||||
# If documentation requested, create a place to dump them and do so
|
# If documentation requested, create a place to dump them and do so
|
||||||
|
doc_path = ""
|
||||||
if use_docs
|
if use_docs
|
||||||
doc_path = File.join(ceedling_path, 'docs')
|
doc_path = use_gem ? File.join(name, 'docs') : File.join(ceedling_path, 'docs')
|
||||||
FileUtils.mkdir_p doc_path
|
FileUtils.mkdir_p doc_path
|
||||||
|
|
||||||
in_doc_path = lambda {|f| File.join(doc_path, f)}
|
in_doc_path = lambda {|f| File.join(doc_path, f)}
|
||||||
|
|
||||||
doc_files = [
|
# Add documentation from main projects to list
|
||||||
'docs/CeedlingPacket.md',
|
doc_files = {}
|
||||||
'vendor/c_exception/docs/CException.md',
|
['docs','vendor/unity/docs','vendor/cmock/docs','vendor/cexception/docs'].each do |p|
|
||||||
'vendor/cmock/docs/CMock_Summary.md',
|
Dir[ File.expand_path(File.join(here, p, '*.md')) ].each do |f|
|
||||||
'vendor/unity/docs/UnityAssertionsCheatSheetSuitableforPrintingandPossiblyFraming.pdf',
|
doc_files[ File.basename(f) ] = f unless(doc_files.include? f)
|
||||||
'vendor/unity/docs/UnityAssertionsReference.md',
|
end
|
||||||
'vendor/unity/docs/UnityConfigurationGuide.md',
|
end
|
||||||
'vendor/unity/docs/UnityGettingStartedGuide.md',
|
|
||||||
'vendor/unity/docs/UnityHelperScriptsGuide.md',
|
|
||||||
'vendor/unity/docs/ThrowTheSwitchCodingStandard.md',
|
|
||||||
]
|
|
||||||
|
|
||||||
doc_files.each do |f|
|
# Add documentation from plugins to list
|
||||||
copy_file(f, in_doc_path.call(File.basename(f)), :force => force)
|
Dir[ File.join(here, 'plugins/**/README.md') ].each do |plugin_path|
|
||||||
|
k = "plugin_" + plugin_path.split(/\\|\//)[-2] + ".md"
|
||||||
|
doc_files[ k ] = File.expand_path(plugin_path)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Copy all documentation
|
||||||
|
doc_files.each_pair do |k, v|
|
||||||
|
copy_file(v, in_doc_path.call(k), :force => force)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -133,7 +137,6 @@ unless (project_found)
|
|||||||
{:src => 'vendor/cmock/config/', :dst => 'vendor/cmock/config'},
|
{:src => 'vendor/cmock/config/', :dst => 'vendor/cmock/config'},
|
||||||
{:src => 'vendor/cmock/lib/', :dst => 'vendor/cmock/lib'},
|
{:src => 'vendor/cmock/lib/', :dst => 'vendor/cmock/lib'},
|
||||||
{:src => 'vendor/cmock/src/', :dst => 'vendor/cmock/src'},
|
{:src => 'vendor/cmock/src/', :dst => 'vendor/cmock/src'},
|
||||||
{:src => 'vendor/deep_merge/lib/', :dst => 'vendor/deep_merge/lib'},
|
|
||||||
{:src => 'vendor/diy/lib', :dst => 'vendor/diy/lib'},
|
{:src => 'vendor/diy/lib', :dst => 'vendor/diy/lib'},
|
||||||
{:src => 'vendor/unity/auto/', :dst => 'vendor/unity/auto'},
|
{:src => 'vendor/unity/auto/', :dst => 'vendor/unity/auto'},
|
||||||
{:src => 'vendor/unity/src/', :dst => 'vendor/unity/src'},
|
{:src => 'vendor/unity/src/', :dst => 'vendor/unity/src'},
|
||||||
@ -146,16 +149,24 @@ unless (project_found)
|
|||||||
|
|
||||||
# We're copying in a configuration file if we haven't said not to
|
# We're copying in a configuration file if we haven't said not to
|
||||||
if (use_configs)
|
if (use_configs)
|
||||||
if use_gem
|
dst_yaml = File.join(name, 'project.yml')
|
||||||
copy_file(File.join('assets', 'project_as_gem.yml'), File.join(name, 'project.yml'), :force => force)
|
src_yaml = if use_gem
|
||||||
|
File.join(here, 'assets', 'project_as_gem.yml')
|
||||||
else
|
else
|
||||||
copy_file(File.join('assets', 'project_with_guts.yml'), File.join(name, 'project.yml'), :force => force)
|
|
||||||
if is_windows?
|
if is_windows?
|
||||||
copy_file(File.join('assets', 'ceedling.cmd'), File.join(name, 'ceedling.cmd'), :force => force)
|
copy_file(File.join('assets', 'ceedling.cmd'), File.join(name, 'ceedling.cmd'), :force => force)
|
||||||
else
|
else
|
||||||
copy_file(File.join('assets', 'ceedling'), File.join(name, 'ceedling'), :force => force)
|
copy_file(File.join('assets', 'ceedling'), File.join(name, 'ceedling'), :force => force)
|
||||||
File.chmod(0755, File.join(name, 'ceedling'))
|
File.chmod(0755, File.join(name, 'ceedling'))
|
||||||
end
|
end
|
||||||
|
File.join(here, 'assets', 'project_with_guts.yml')
|
||||||
|
end
|
||||||
|
|
||||||
|
# Perform the actual clone of the config file, while updating the version
|
||||||
|
File.open(dst_yaml,'w') do |dst|
|
||||||
|
require File.expand_path(File.join(File.dirname(__FILE__),"..","lib","ceedling","version.rb"))
|
||||||
|
dst << File.read(src_yaml).gsub(":ceedling_version: '?'",":ceedling_version: #{Ceedling::Version::CEEDLING}")
|
||||||
|
puts " create #{dst_yaml}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -167,8 +178,8 @@ unless (project_found)
|
|||||||
unless silent
|
unless silent
|
||||||
puts "\n"
|
puts "\n"
|
||||||
puts "Project '#{name}' #{force ? "upgraded" : "created"}!"
|
puts "Project '#{name}' #{force ? "upgraded" : "created"}!"
|
||||||
puts " - Tool documentation is located in vendor/ceedling/docs" if use_docs
|
puts " - Tool documentation is located in #{doc_path}" if use_docs
|
||||||
puts " - Execute 'ceedling help' to view available test & build tasks"
|
puts " - Execute 'ceedling help' from #{name} to view available test & build tasks"
|
||||||
puts ''
|
puts ''
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -206,10 +217,10 @@ unless (project_found)
|
|||||||
|
|
||||||
desc "version", "return the version of the tools installed"
|
desc "version", "return the version of the tools installed"
|
||||||
def version()
|
def version()
|
||||||
require 'ceedling/version.rb'
|
require File.expand_path(File.join(File.dirname(__FILE__),"..","lib","ceedling","version.rb"))
|
||||||
puts " Ceedling:: #{Ceedling::Version::CEEDLING}"
|
puts " Ceedling:: #{Ceedling::Version::CEEDLING}"
|
||||||
puts " CMock:: #{Ceedling::Version::CMOCK}"
|
puts " CMock:: #{Ceedling::Version::CMOCK}"
|
||||||
puts " Unity:: #{Ceedling::Version::UNITY}"
|
puts " Unity:: #{Ceedling::Version::UNITY}"
|
||||||
puts " CException:: #{Ceedling::Version::CEXCEPTION}"
|
puts " CException:: #{Ceedling::Version::CEXCEPTION}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -287,6 +298,8 @@ else
|
|||||||
options[:list_tasks] = true
|
options[:list_tasks] = true
|
||||||
when /^-T$/
|
when /^-T$/
|
||||||
options[:list_tasks] = true
|
options[:list_tasks] = true
|
||||||
|
when /^--tasks$/
|
||||||
|
options[:list_tasks] = true
|
||||||
when /^project:(\w+)/
|
when /^project:(\w+)/
|
||||||
ENV['CEEDLING_USER_PROJECT_FILE'] = "#{$1}.yml"
|
ENV['CEEDLING_USER_PROJECT_FILE'] = "#{$1}.yml"
|
||||||
else
|
else
|
||||||
|
292
test/vendor/ceedling/docs/CException.md
vendored
292
test/vendor/ceedling/docs/CException.md
vendored
@ -1,292 +0,0 @@
|
|||||||
|
|
||||||
CException
|
|
||||||
==========
|
|
||||||
|
|
||||||
CException is a basic exception framework for C, suitable for use in
|
|
||||||
embedded applications. It provides an exception framework similar in
|
|
||||||
use to C++, but with much less overhead.
|
|
||||||
|
|
||||||
|
|
||||||
CException uses C standard library functions `setjmp` and `longjmp` to
|
|
||||||
operate. As long as the target system has these two functions defined,
|
|
||||||
this library should be useable with very little configuration. It
|
|
||||||
even supports environments where multiple program flows are in use,
|
|
||||||
such as real-time operating systems.
|
|
||||||
|
|
||||||
|
|
||||||
There are about a gabillion exception frameworks using a similar
|
|
||||||
setjmp/longjmp method out there... and there will probably be more
|
|
||||||
in the future. Unfortunately, when we started our last embedded
|
|
||||||
project, all those that existed either (a) did not support multiple
|
|
||||||
tasks (therefore multiple stacks) or (b) were way more complex than
|
|
||||||
we really wanted. CException was born.
|
|
||||||
|
|
||||||
|
|
||||||
*Why use CException?*
|
|
||||||
|
|
||||||
|
|
||||||
0. It's ANSI C, and it beats passing error codes around.
|
|
||||||
1. You want something simple... CException throws a single id. You can
|
|
||||||
define those ID's to be whatever you like. You might even choose which
|
|
||||||
type that number is for your project. But that's as far as it goes.
|
|
||||||
We weren't interested in passing objects or structs or strings...
|
|
||||||
just simple error codes.
|
|
||||||
2. Performance... CException can be configured for single tasking or
|
|
||||||
multitasking. In single tasking, there is very little overhead past
|
|
||||||
the setjmp/longjmp calls (which are already fast). In multitasking,
|
|
||||||
your only additional overhead is the time it takes you to determine
|
|
||||||
a unique task id 0 - num_tasks.
|
|
||||||
|
|
||||||
|
|
||||||
For the latest version, go to [ThrowTheSwitch.org](http://throwtheswitch.org)
|
|
||||||
|
|
||||||
|
|
||||||
CONTENTS OF THIS DOCUMENT
|
|
||||||
=========================
|
|
||||||
|
|
||||||
* Usage
|
|
||||||
* Limitations
|
|
||||||
*API
|
|
||||||
* Configuration
|
|
||||||
* Testing
|
|
||||||
* License
|
|
||||||
|
|
||||||
|
|
||||||
Usage
|
|
||||||
-----
|
|
||||||
|
|
||||||
Code that is to be protected are wrapped in `Try { } Catch { }` blocks.
|
|
||||||
The code directly following the Try call is "protected", meaning that
|
|
||||||
if any Throws occur, program control is directly transferred to the
|
|
||||||
start of the Catch block.
|
|
||||||
|
|
||||||
|
|
||||||
A numerical exception ID is included with Throw, and is made accessible
|
|
||||||
from the Catch block.
|
|
||||||
|
|
||||||
|
|
||||||
Throws can occur from within function calls (nested as deeply as you
|
|
||||||
like) or directly from within the function itself.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Limitations
|
|
||||||
-----------
|
|
||||||
|
|
||||||
|
|
||||||
This library was made to be as fast as possible, and provide basic
|
|
||||||
exception handling. It is not a full-blown exception library. Because
|
|
||||||
of this, there are a few limitations that should be observed in order
|
|
||||||
to successfully utilize this library:
|
|
||||||
|
|
||||||
1. Do not directly "return" from within a `Try` block, nor `goto`
|
|
||||||
into or out of a `Try` block.
|
|
||||||
|
|
||||||
*Why?*
|
|
||||||
|
|
||||||
The `Try` macro allocates some local memory and alters a global
|
|
||||||
pointer. These are cleaned up at the top of the `Catch` macro.
|
|
||||||
Gotos and returns would bypass some of these steps, resulting in
|
|
||||||
memory leaks or unpredictable behavior.
|
|
||||||
|
|
||||||
|
|
||||||
2. If (a) you change local (stack) variables within your `Try` block,
|
|
||||||
AND (b) wish to make use of the updated values after an exception
|
|
||||||
is thrown, those variables should be made `volatile`. Note that this
|
|
||||||
is ONLY for locals and ONLY when you need access to them after a
|
|
||||||
`Throw`.
|
|
||||||
|
|
||||||
*Why?*
|
|
||||||
|
|
||||||
Compilers optimize. There is no way to guarantee that the actual
|
|
||||||
memory location was updated and not just a register unless the
|
|
||||||
variable is marked volatile.
|
|
||||||
|
|
||||||
|
|
||||||
3. Memory which is `malloc`'d or `new`'d is not automatically released
|
|
||||||
when an error is thrown. This will sometimes be desirable, and
|
|
||||||
othertimes may not. It will be the responsibility of the `Catch`
|
|
||||||
block to perform this kind of cleanup.
|
|
||||||
|
|
||||||
*Why?*
|
|
||||||
|
|
||||||
There's just no easy way to track `malloc`'d memory, etc., without
|
|
||||||
replacing or wrapping malloc calls or something like that. This
|
|
||||||
is a light framework, so these options were not desirable.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
API
|
|
||||||
---
|
|
||||||
|
|
||||||
###Try
|
|
||||||
|
|
||||||
`Try` is a macro which starts a protected block. It MUST be followed by
|
|
||||||
a pair of braces or a single protected line (similar to an 'if'),
|
|
||||||
enclosing the data that is to be protected. It **must** be followed by a
|
|
||||||
`Catch` block (don't worry, you'll get compiler errors to let you know if
|
|
||||||
you mess any of that up).
|
|
||||||
|
|
||||||
|
|
||||||
###Catch(e)
|
|
||||||
|
|
||||||
`Catch` is a macro which ends the `Try` block and starts the error handling
|
|
||||||
block. The `Catch` block is called if and only if an exception was thrown
|
|
||||||
while within the `Try` block. This error was thrown by a `Throw` call
|
|
||||||
somewhere within `Try` (or within a function called within `Try`, or a function
|
|
||||||
called by a function called within `Try`, etc).
|
|
||||||
|
|
||||||
The single parameter `e` is filled with the error code which was thrown.
|
|
||||||
This can be used for reporting, conditional cleanup, etc. (or you can just
|
|
||||||
ignore it if you really want... people ignore return codes all the time,
|
|
||||||
right?). `e` should be of type `EXCEPTION_T`
|
|
||||||
|
|
||||||
|
|
||||||
###Throw(e)
|
|
||||||
|
|
||||||
This is the method of throwing an error. A `Throw` should only occur from within a
|
|
||||||
protected (`Try` ... `Catch`) block, though it may easily be nested many function
|
|
||||||
calls deep without an impact on performance or functionality. `Throw` takes
|
|
||||||
a single argument, which is an exception id which will be passed to `Catch`
|
|
||||||
as the reason for the error.
|
|
||||||
|
|
||||||
If you wish to rethrow an error, this can be done by calling `Throw(e)` with
|
|
||||||
the error code you just caught. It **is** valid to throw from a catch block.
|
|
||||||
|
|
||||||
|
|
||||||
###ExitTry()
|
|
||||||
|
|
||||||
On rare occasion, you might want to immediately exit your current `Try` block
|
|
||||||
but **not** treat this as an error. Don't run the `Catch`. Just start executing
|
|
||||||
from after the `Catch` as if nothing had happened... That's what `ExitTry` is
|
|
||||||
for.
|
|
||||||
|
|
||||||
|
|
||||||
CONFIGURATION
|
|
||||||
-------------
|
|
||||||
|
|
||||||
CException is a mostly portable library. It has one universal
|
|
||||||
dependency, and some macros which are required if working in a
|
|
||||||
multi-tasking environment.
|
|
||||||
|
|
||||||
1. The standard C library setjmp must be available. Since this is part
|
|
||||||
of the standard library, chances are good that you'll be fine.
|
|
||||||
|
|
||||||
2. If working in a multitasking environment, methods for obtaining an
|
|
||||||
index into an array of frames and to get the overall number of
|
|
||||||
id's are required. If the OS supports a method to retrieve Task
|
|
||||||
ID's, and those Tasks are number 0, 1, 2... you are in an ideal
|
|
||||||
situation. Otherwise, a more creative mapping function may be
|
|
||||||
required. Note that this function is likely to be called twice
|
|
||||||
for each protected block and once during a throw. This is the
|
|
||||||
only overhead in the system.
|
|
||||||
|
|
||||||
|
|
||||||
Exception.h
|
|
||||||
-----------
|
|
||||||
|
|
||||||
By convention, most projects include `Exception.h` which defines any
|
|
||||||
further requirements, then calls `CException.h` to do the gruntwork. All
|
|
||||||
of these are optional. You could directly include `CException.h` if
|
|
||||||
you wanted and just use the defaults provided.
|
|
||||||
|
|
||||||
* `EXCEPTION_T`
|
|
||||||
* Set this to the type you want your exception id's to be. Defaults to 'unsigned int'.
|
|
||||||
|
|
||||||
* `EXCEPTION_NONE`
|
|
||||||
* Set this to a number which will never be an exception id in your system. Defaults to `0x5a5a5a5a`.
|
|
||||||
|
|
||||||
* `EXCEPTION_GET_ID`
|
|
||||||
* If in a multi-tasking environment, this should be
|
|
||||||
set to be a call to the function described in #2 above.
|
|
||||||
Defaults to just return `0` all the time (good for
|
|
||||||
single tasking environments)
|
|
||||||
|
|
||||||
* `EXCEPTION_NUM_ID`
|
|
||||||
* If in a multi-tasking environment, this should be set
|
|
||||||
to the number of ID's required (usually the number of
|
|
||||||
tasks in the system). Defaults to `1` (for single
|
|
||||||
tasking environments).
|
|
||||||
|
|
||||||
* `CEXCEPTION_NO_CATCH_HANDLER(id)`
|
|
||||||
* This macro can be optionally specified.
|
|
||||||
It allows you to specify code to be called when a Throw
|
|
||||||
is made outside of `Try` ... `Catch` protection. Consider
|
|
||||||
this the emergency fallback plan for when something has
|
|
||||||
gone terribly wrong.
|
|
||||||
|
|
||||||
|
|
||||||
You may also want to include any header files which will commonly be
|
|
||||||
needed by the rest of your application where it uses exception handling
|
|
||||||
here. For example, OS header files or exception codes would be useful.
|
|
||||||
|
|
||||||
|
|
||||||
Finally, there are some hook macros which you can implement to inject
|
|
||||||
your own target-specific code in particular places. It is a rare instance
|
|
||||||
where you will need these, but they are here if you need them:
|
|
||||||
|
|
||||||
|
|
||||||
* `CEXCEPTION_HOOK_START_TRY`
|
|
||||||
* called immediately before the Try block
|
|
||||||
|
|
||||||
* `CEXCEPTION_HOOK_HAPPY_TRY`
|
|
||||||
* called immediately after the Try block if no exception was thrown
|
|
||||||
|
|
||||||
* `CEXCEPTION_HOOK_AFTER_TRY`
|
|
||||||
* called immediately after the Try block OR before an exception is caught
|
|
||||||
|
|
||||||
* `CEXCEPTION_HOOK_START_CATCH`
|
|
||||||
* called immediately before the catch
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
TESTING
|
|
||||||
-------
|
|
||||||
|
|
||||||
|
|
||||||
If you want to validate that CException works with your tools or that
|
|
||||||
it works with your custom configuration, you may want to run the test
|
|
||||||
suite.
|
|
||||||
|
|
||||||
|
|
||||||
The test suite included makes use of the `Unity` Test Framework. It will
|
|
||||||
require a native C compiler. The example makefile uses MinGW's gcc.
|
|
||||||
Modify the makefile to include the proper paths to tools, then run `make`
|
|
||||||
to compile and run the test application.
|
|
||||||
|
|
||||||
* `C_COMPILER`
|
|
||||||
* The C compiler to use to perform the tests
|
|
||||||
|
|
||||||
* `C_LIBS`
|
|
||||||
* The path to the C libraries (including setjmp)
|
|
||||||
|
|
||||||
* `UNITY_DIR`
|
|
||||||
* The path to the Unity framework (required to run tests)
|
|
||||||
(get it at [ThrowTheSwitch.org](http://throwtheswitch.org))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
LICENSE
|
|
||||||
-------
|
|
||||||
|
|
||||||
This software is licensed under the MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2007-2017 Mark VanderVoord
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
603
test/vendor/ceedling/docs/CMock_Summary.md
vendored
603
test/vendor/ceedling/docs/CMock_Summary.md
vendored
@ -1,603 +0,0 @@
|
|||||||
CMock: A Summary
|
|
||||||
================
|
|
||||||
|
|
||||||
*[ThrowTheSwitch.org](http://throwtheswitch.org)*
|
|
||||||
|
|
||||||
*This documentation is released under a Creative Commons 3.0 Attribution Share-Alike License*
|
|
||||||
|
|
||||||
|
|
||||||
What Exactly Are We Talking About Here?
|
|
||||||
---------------------------------------
|
|
||||||
|
|
||||||
CMock is a nice little tool which takes your header files and creates
|
|
||||||
a Mock interface for it so that you can more easily unit test modules
|
|
||||||
that touch other modules. For each function prototype in your
|
|
||||||
header, like this one:
|
|
||||||
|
|
||||||
int DoesSomething(int a, int b);
|
|
||||||
|
|
||||||
|
|
||||||
...you get an automatically generated DoesSomething function
|
|
||||||
that you can link to instead of your real DoesSomething function.
|
|
||||||
By using this Mocked version, you can then verify that it receives
|
|
||||||
the data you want, and make it return whatever data you desire,
|
|
||||||
make it throw errors when you want, and more... Create these for
|
|
||||||
everything your latest real module touches, and you're suddenly
|
|
||||||
in a position of power: You can control and verify every detail
|
|
||||||
of your latest creation.
|
|
||||||
|
|
||||||
To make that easier, CMock also gives you a bunch of functions
|
|
||||||
like the ones below, so you can tell that generated DoesSomething
|
|
||||||
function how to behave for each test:
|
|
||||||
|
|
||||||
void DoesSomething_ExpectAndReturn(int a, int b, int toReturn);
|
|
||||||
void DoesSomething_ExpectAndThrow(int a, int b, EXCEPTION_T error);
|
|
||||||
void DoesSomething_StubWithCallback(CMOCK_DoesSomething_CALLBACK YourCallback);
|
|
||||||
void DoesSomething_IgnoreAndReturn(int toReturn);
|
|
||||||
|
|
||||||
|
|
||||||
You can pile a bunch of these back to back, and it remembers what
|
|
||||||
you wanted to pass when, like so:
|
|
||||||
|
|
||||||
test_CallsDoesSomething_ShouldDoJustThat(void)
|
|
||||||
{
|
|
||||||
DoesSomething_ExpectAndReturn(1,2,3);
|
|
||||||
DoesSomething_ExpectAndReturn(4,5,6);
|
|
||||||
DoesSomething_ExpectAndThrow(7,8, STATUS_ERROR_OOPS);
|
|
||||||
|
|
||||||
CallsDoesSomething( );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
This test will call CallsDoesSomething, which is the function
|
|
||||||
we are testing. We are expecting that function to call DoesSomething
|
|
||||||
three times. The first time, we check to make sure it's called
|
|
||||||
as DoesSomething(1, 2) and we'll magically return a 3. The second
|
|
||||||
time we check for DoesSomething(4, 5) and we'll return a 6. The
|
|
||||||
third time we verify DoesSomething(7, 8) and we'll throw an error
|
|
||||||
instead of returning anything. If CallsDoesSomething gets
|
|
||||||
any of this wrong, it fails the test. It will fail if you didn't
|
|
||||||
call DoesSomething enough, or too much, or with the wrong arguments,
|
|
||||||
or in the wrong order.
|
|
||||||
|
|
||||||
CMock is based on Unity, which it uses for all internal testing.
|
|
||||||
It uses Ruby to do all the main work (versions 2.0.0 and above).
|
|
||||||
|
|
||||||
|
|
||||||
Installing
|
|
||||||
==========
|
|
||||||
|
|
||||||
The first thing you need to do to install CMock is to get yourself
|
|
||||||
a copy of Ruby. If you're on linux or osx, you probably already
|
|
||||||
have it. You can prove it by typing the following:
|
|
||||||
|
|
||||||
ruby --version
|
|
||||||
|
|
||||||
|
|
||||||
If it replied in a way that implies ignorance, then you're going to
|
|
||||||
need to install it. You can go to [ruby-lang](https://ruby-lang.org)
|
|
||||||
to get the latest version. You're also going to need to do that if it
|
|
||||||
replied with a version that is older than 2.0.0. Go ahead. We'll wait.
|
|
||||||
|
|
||||||
Once you have Ruby, you have three options:
|
|
||||||
|
|
||||||
* Clone the latest [CMock repo on github](https://github.com/ThrowTheSwitch/CMock/)
|
|
||||||
* Download the latest [CMock zip from github](https://github.com/ThrowTheSwitch/CMock/)
|
|
||||||
* Install Ceedling (which has it built in!) through your commandline using `gem install ceedling`.
|
|
||||||
|
|
||||||
|
|
||||||
Generated Mock Module Summary
|
|
||||||
=============================
|
|
||||||
|
|
||||||
In addition to the mocks themselves, CMock will generate the
|
|
||||||
following functions for use in your tests. The expect functions
|
|
||||||
are always generated. The other functions are only generated
|
|
||||||
if those plugins are enabled:
|
|
||||||
|
|
||||||
|
|
||||||
Expect:
|
|
||||||
-------
|
|
||||||
|
|
||||||
Your basic staple Expects which will be used for most of your day
|
|
||||||
to day CMock work. By calling this, you are telling CMock that you
|
|
||||||
expect that function to be called during your test. It also specifies
|
|
||||||
which arguments you expect it to be called with, and what return
|
|
||||||
value you want returned when that happens. You can call this function
|
|
||||||
multiple times back to back in order to queue up multiple calls.
|
|
||||||
|
|
||||||
* `void func(void)` => `void func_Expect(void)`
|
|
||||||
* `void func(params)` => `void func_Expect(expected_params)`
|
|
||||||
* `retval func(void)` => `void func_ExpectAndReturn(retval_to_return)`
|
|
||||||
* `retval func(params)` => `void func_ExpectAndReturn(expected_params, retval_to_return)`
|
|
||||||
|
|
||||||
|
|
||||||
ExpectAnyArgs:
|
|
||||||
--------------
|
|
||||||
|
|
||||||
This behaves just like the Expects calls, except that it doesn't really
|
|
||||||
care what the arguments are that the mock gets called with. It still counts
|
|
||||||
the number of times the mock is called and it still handles return values
|
|
||||||
if there are some.
|
|
||||||
|
|
||||||
* `void func(void)` => `void func_ExpectAnyArgs(void)`
|
|
||||||
* `void func(params)` => `void func_ExpectAnyArgs(void)`
|
|
||||||
* `retval func(void)` => `void func_ExpectAnyArgsAndReturn(retval_to_return)`
|
|
||||||
* `retval func(params)` => `void func_ExpectAnyArgsAndReturn(retval_to_return)`
|
|
||||||
|
|
||||||
|
|
||||||
Array:
|
|
||||||
------
|
|
||||||
|
|
||||||
An ExpectWithArray is another variant of Expect. Like expect, it cares about
|
|
||||||
the number of times a mock is called, the arguments it is called with, and the
|
|
||||||
values it is to return. This variant has another feature, though. For anything
|
|
||||||
that resembles a pointer or array, it breaks the argument into TWO arguments.
|
|
||||||
The first is the original pointer. The second specify the number of elements
|
|
||||||
it is to verify of that array. If you specify 1, it'll check one object. If 2,
|
|
||||||
it'll assume your pointer is pointing at the first of two elements in an array.
|
|
||||||
If you specify zero elements, it will check just the pointer if
|
|
||||||
`:smart` mode is configured or fail if `:compare_data` is set.
|
|
||||||
|
|
||||||
* `void func(void)` => (nothing. In fact, an additional function is only generated if the params list contains pointers)
|
|
||||||
* `void func(ptr * param, other)` => `void func_ExpectWithArray(ptr* param, int param_depth, other)`
|
|
||||||
* `retval func(void)` => (nothing. In fact, an additional function is only generated if the params list contains pointers)
|
|
||||||
* `retval func(other, ptr* param)` => `void func_ExpectWithArrayAndReturn(other, ptr* param, int param_depth, retval_to_return)`
|
|
||||||
|
|
||||||
|
|
||||||
Ignore:
|
|
||||||
-------
|
|
||||||
|
|
||||||
Maybe you don't care about the number of times a particular function is called or
|
|
||||||
the actual arguments it is called with. In that case, you want to use Ignore. Ignore
|
|
||||||
only needs to be called once per test. It will then ignore any further calls to that
|
|
||||||
particular mock. The IgnoreAndReturn works similarly, except that it has the added
|
|
||||||
benefit of knowing what to return when that call happens. If the mock is called more
|
|
||||||
times than IgnoreAndReturn was called, it will keep returning the last value without
|
|
||||||
complaint. If it's called less times, it will also ignore that. You SAID you didn't
|
|
||||||
care how many times it was called, right?
|
|
||||||
|
|
||||||
* `void func(void)` => `void func_Ignore(void)`
|
|
||||||
* `void func(params)` => `void func_Ignore(void)`
|
|
||||||
* `retval func(void)` => `void func_IgnoreAndReturn(retval_to_return)`
|
|
||||||
* `retval func(params)` => `void func_IgnoreAndReturn(retval_to_return)`
|
|
||||||
|
|
||||||
|
|
||||||
Ignore Arg:
|
|
||||||
------------
|
|
||||||
|
|
||||||
Maybe you overall want to use Expect and its similar variations, but you don't care
|
|
||||||
what is passed to a particular argument. This is particularly useful when that argument
|
|
||||||
is a pointer to a value that is supposed to be filled in by the function. You don't want
|
|
||||||
to use ExpectAnyArgs, because you still care about the other arguments. Instead, before
|
|
||||||
any of your Expect calls are made, you can call this function. It tells CMock to ignore
|
|
||||||
a particular argument for the rest of this test, for this mock function.
|
|
||||||
|
|
||||||
* `void func(params)` => `void func_IgnoreArg_paramName(void)`
|
|
||||||
|
|
||||||
|
|
||||||
ReturnThruPtr:
|
|
||||||
--------------
|
|
||||||
|
|
||||||
Another option which operates on a particular argument of a function is the ReturnThruPtr
|
|
||||||
plugin. For every argument that resembles a pointer or reference, CMock generates an
|
|
||||||
instance of this function. Just as the AndReturn functions support injecting one or more
|
|
||||||
return values into a queue, this function lets you specify one or more return values which
|
|
||||||
are queued up and copied into the space being pointed at each time the mock is called.
|
|
||||||
|
|
||||||
* `void func(param1)` => `void func_ReturnThruPtr_paramName(val_to_return)`
|
|
||||||
* => `void func_ReturnArrayThruPtr_paramName(cal_to_return, len)`
|
|
||||||
* => `void func_ReturnMemThruPtr_paramName(val_to_return, size)`
|
|
||||||
|
|
||||||
|
|
||||||
Callback:
|
|
||||||
---------
|
|
||||||
|
|
||||||
If all those other options don't work, and you really need to do something custom, you
|
|
||||||
still have a choice. As soon as you stub a callback in a test, it will call the callback
|
|
||||||
whenever the mock is encountered and return the retval returned from the callback (if any)
|
|
||||||
instead of performing the usual expect checks. It can be configured to check the arguments
|
|
||||||
first (like expects) or just jump directly to the callback.
|
|
||||||
|
|
||||||
* `void func(void)` => `void func_StubWithCallback(CMOCK_func_CALLBACK callback)`
|
|
||||||
where `CMOCK_func_CALLBACK` looks like: `void func(int NumCalls)`
|
|
||||||
* `void func(params)` => `void func_StubWithCallback(CMOCK_func_CALLBACK callback)`
|
|
||||||
where `CMOCK_func_CALLBACK` looks like: `void func(params, int NumCalls)`
|
|
||||||
* `retval func(void)` => `void func_StubWithCallback(CMOCK_func_CALLBACK callback)`
|
|
||||||
where `CMOCK_func_CALLBACK` looks like: `retval func(int NumCalls)`
|
|
||||||
* `retval func(params)` => `void func_StubWithCallback(CMOCK_func_CALLBACK callback)`
|
|
||||||
where `CMOCK_func_CALLBACK` looks like: `retval func(params, int NumCalls)`
|
|
||||||
|
|
||||||
|
|
||||||
Cexception:
|
|
||||||
-----------
|
|
||||||
|
|
||||||
Finally, if you are using Cexception for error handling, you can use this to throw errors
|
|
||||||
from inside mocks. Like Expects, it remembers which call was supposed to throw the error,
|
|
||||||
and it still checks parameters first.
|
|
||||||
|
|
||||||
* `void func(void)` => `void func_ExpectAndThrow(value_to_throw)`
|
|
||||||
* `void func(params)` => `void func_ExpectAndThrow(expected_params, value_to_throw)`
|
|
||||||
* `retval func(void)` => `void func_ExpectAndThrow(value_to_throw)`
|
|
||||||
* `retval func(params)` => `void func_ExpectAndThrow(expected_params, value_to_throw)`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Running CMock
|
|
||||||
=============
|
|
||||||
|
|
||||||
CMock is a Ruby script and class. You can therefore use it directly
|
|
||||||
from the command line, or include it in your own scripts or rakefiles.
|
|
||||||
|
|
||||||
|
|
||||||
Mocking from the Command Line
|
|
||||||
-----------------------------
|
|
||||||
|
|
||||||
After unpacking CMock, you will find cmock.rb in the 'lib' directory.
|
|
||||||
This is the file that you want to run. It takes a list of header files
|
|
||||||
to be mocked, as well as an optional yaml file for a more detailed
|
|
||||||
configuration (see config options below).
|
|
||||||
|
|
||||||
For example, this will create three mocks using the configuration
|
|
||||||
specified in MyConfig.yml:
|
|
||||||
|
|
||||||
ruby cmock.rb -oMyConfig.yml super.h duper.h awesome.h
|
|
||||||
|
|
||||||
And this will create two mocks using the default configuration:
|
|
||||||
|
|
||||||
ruby cmock.rb ../mocking/stuff/is/fun.h ../try/it/yourself.h
|
|
||||||
|
|
||||||
|
|
||||||
Mocking From Scripts or Rake
|
|
||||||
----------------------------
|
|
||||||
|
|
||||||
CMock can be used directly from your own scripts or from a rakefile.
|
|
||||||
Start by including cmock.rb, then create an instance of CMock.
|
|
||||||
When you create your instance, you may initialize it in one of
|
|
||||||
three ways.
|
|
||||||
|
|
||||||
You may specify nothing, allowing it to run with default settings:
|
|
||||||
|
|
||||||
require 'cmock.rb'
|
|
||||||
cmock = CMock.new
|
|
||||||
|
|
||||||
You may specify a YAML file containing the configuration options
|
|
||||||
you desire:
|
|
||||||
|
|
||||||
cmock = CMock.new('../MyConfig.yml')
|
|
||||||
|
|
||||||
You may specify the options explicitly:
|
|
||||||
|
|
||||||
cmock = Cmock.new(:plugins => [:cexception, :ignore], :mock_path => 'my/mocks/')
|
|
||||||
|
|
||||||
|
|
||||||
Config Options:
|
|
||||||
---------------
|
|
||||||
|
|
||||||
The following configuration options can be specified in the
|
|
||||||
yaml file or directly when instantiating.
|
|
||||||
|
|
||||||
Passed as Ruby, they look like this:
|
|
||||||
|
|
||||||
{ :attributes => [“__funky”, “__intrinsic”], :when_ptr => :compare }
|
|
||||||
|
|
||||||
Defined in the yaml file, they look more like this:
|
|
||||||
|
|
||||||
:cmock:
|
|
||||||
:attributes:
|
|
||||||
- __funky
|
|
||||||
- __intrinsic
|
|
||||||
:when_ptr: :compare
|
|
||||||
|
|
||||||
In all cases, you can just include the things that you want to override
|
|
||||||
from the defaults. We've tried to specify what the defaults are below.
|
|
||||||
|
|
||||||
* `:attributes`:
|
|
||||||
These are attributes that CMock should ignore for you for testing
|
|
||||||
purposes. Custom compiler extensions and externs are handy things to
|
|
||||||
put here. If your compiler is choking on some extended syntax, this
|
|
||||||
is often a good place to look.
|
|
||||||
|
|
||||||
* defaults: ['__ramfunc', '__irq', '__fiq', 'register', 'extern']
|
|
||||||
* **note:** this option will reinsert these attributes onto the mock's calls.
|
|
||||||
If that isn't what you are looking for, check out :strippables.
|
|
||||||
|
|
||||||
* `:c_calling_conventions`:
|
|
||||||
Similarly, CMock may need to understand which C calling conventions
|
|
||||||
might show up in your codebase. If it encounters something it doesn't
|
|
||||||
recognize, it's not going to mock it. We have the most common covered,
|
|
||||||
but there are many compilers out there, and therefore many other options.
|
|
||||||
|
|
||||||
* defaults: ['__stdcall', '__cdecl', '__fastcall']
|
|
||||||
* **note:** this option will reinsert these attributes onto the mock's calls.
|
|
||||||
If that isn't what you are looking for, check out :strippables.
|
|
||||||
|
|
||||||
* `:callback_after_arg_check`:
|
|
||||||
Tell `:callback` plugin to do the normal argument checking **before** it
|
|
||||||
calls the callback function by setting this to true. When false, the
|
|
||||||
callback function is called **instead** of the argument verification.
|
|
||||||
|
|
||||||
* default: false
|
|
||||||
|
|
||||||
* `:callback_include_count`:
|
|
||||||
Tell `:callback` plugin to include an extra parameter to specify the
|
|
||||||
number of times the callback has been called. If set to false, the
|
|
||||||
callback has the same interface as the mocked function. This can be
|
|
||||||
handy when you're wanting to use callback as a stub.
|
|
||||||
|
|
||||||
* default: true
|
|
||||||
|
|
||||||
* `:cexception_include`:
|
|
||||||
Tell `:cexception` plugin where to find CException.h... You only need to
|
|
||||||
define this if it's not in your build path already... which it usually
|
|
||||||
will be for the purpose of your builds.
|
|
||||||
|
|
||||||
* default: *nil*
|
|
||||||
|
|
||||||
* `:enforce_strict_ordering`:
|
|
||||||
CMock always enforces the order that you call a particular function,
|
|
||||||
so if you expect GrabNabber(int size) to be called three times, it
|
|
||||||
will verify that the sizes are in the order you specified. You might
|
|
||||||
*also* want to make sure that all different functions are called in a
|
|
||||||
particular order. If so, set this to true.
|
|
||||||
|
|
||||||
* default: false
|
|
||||||
|
|
||||||
* `:framework`:
|
|
||||||
Currently the only option is `:unity.` Eventually if we support other
|
|
||||||
unity test frameworks (or if you write one for us), they'll get added
|
|
||||||
here.
|
|
||||||
|
|
||||||
: default: :unity
|
|
||||||
|
|
||||||
* `:includes`:
|
|
||||||
An array of additional include files which should be added to the
|
|
||||||
mocks. Useful for global types and definitions used in your project.
|
|
||||||
There are more specific versions if you care WHERE in the mock files
|
|
||||||
the includes get placed. You can define any or all of these options.
|
|
||||||
|
|
||||||
* `:includes`
|
|
||||||
* `:includes_h_pre_orig_header`
|
|
||||||
* `:includes_h_post_orig_header`
|
|
||||||
* `:includes_c_pre_header`
|
|
||||||
* `:includes_c_post_header`
|
|
||||||
* default: nil #for all 5 options
|
|
||||||
|
|
||||||
* `:memcmp_if_unknown`:
|
|
||||||
C developers create a lot of types, either through typedef or preprocessor
|
|
||||||
macros. CMock isn't going to automatically know what you were thinking all
|
|
||||||
the time (though it tries its best). If it comes across a type it doesn't
|
|
||||||
recognize, you have a choice on how you want it to handle it. It can either
|
|
||||||
perform a raw memory comparison and report any differences, or it can fail
|
|
||||||
with a meaningful message. Either way, this feature will only happen after
|
|
||||||
all other mechanisms have failed (The thing encountered isn't a standard
|
|
||||||
type. It isn't in the :treat_as list. It isn't in a custom unity_helper).
|
|
||||||
|
|
||||||
* default: true
|
|
||||||
|
|
||||||
* `:mock_path`:
|
|
||||||
The directory where you would like the mock files generated to be
|
|
||||||
placed.
|
|
||||||
|
|
||||||
* default: mocks
|
|
||||||
|
|
||||||
* `:mock_prefix`:
|
|
||||||
The prefix to prepend to your mock files. For example, if it's “Mock”, a file
|
|
||||||
“USART.h” will get a mock called “MockUSART.c”. This CAN be used with a suffix
|
|
||||||
at the same time.
|
|
||||||
|
|
||||||
* default: Mock
|
|
||||||
|
|
||||||
* `:mock_suffix`:
|
|
||||||
The suffix to append to your mock files. For example, it it's "_Mock", a file
|
|
||||||
"USART.h" will get a mock called "USART_Mock.h". This CAN be used with a prefix
|
|
||||||
at the same time.
|
|
||||||
|
|
||||||
* default: ""
|
|
||||||
|
|
||||||
* `:plugins`:
|
|
||||||
An array of which plugins to enable. ':expect' is always active. Also
|
|
||||||
available currently:
|
|
||||||
|
|
||||||
* `:ignore`
|
|
||||||
* `:ignore_arg`
|
|
||||||
* `:expect_any_args`
|
|
||||||
* `:array`
|
|
||||||
* `:cexception`
|
|
||||||
* `:callback`
|
|
||||||
* `:return_thru_ptr`
|
|
||||||
|
|
||||||
* `:strippables`:
|
|
||||||
An array containing a list of items to remove from the header
|
|
||||||
before deciding what should be mocked. This can be something simple
|
|
||||||
like a compiler extension CMock wouldn't recognize, or could be a
|
|
||||||
regex to reject certain function name patterns. This is a great way to
|
|
||||||
get rid of compiler extensions when your test compiler doesn't support
|
|
||||||
them. For example, use `:strippables: ['(?:functionName\s*\(+.*?\)+)']`
|
|
||||||
to prevent a function `functionName` from being mocked. By default, it
|
|
||||||
is ignoring all gcc attribute extensions.
|
|
||||||
|
|
||||||
* default: ['(?:__attribute__\s*\(+.*?\)+)']
|
|
||||||
|
|
||||||
* `:subdir`:
|
|
||||||
This is a relative subdirectory for your mocks. Set this to e.g. "sys" in
|
|
||||||
order to create a mock for `sys/types.h` in `(:mock_path)/sys/`.
|
|
||||||
|
|
||||||
* default: ""
|
|
||||||
|
|
||||||
* `:treat_as`:
|
|
||||||
The `:treat_as` list is a shortcut for when you have created typedefs
|
|
||||||
of standard types. Why create a custom unity helper for UINT16 when
|
|
||||||
the unity function TEST_ASSERT_EQUAL_HEX16 will work just perfectly?
|
|
||||||
Just add 'UINT16' => 'HEX16' to your list (actually, don't. We already
|
|
||||||
did that one for you). Maybe you have a type that is a pointer to an
|
|
||||||
array of unsigned characters? No problem, just add 'UINT8_T*' =>
|
|
||||||
'HEX8*'
|
|
||||||
|
|
||||||
* NOTE: unlike the other options, your specifications MERGE with the
|
|
||||||
default list. Therefore, if you want to override something, you must
|
|
||||||
reassign it to something else (or to *nil* if you don't want it)
|
|
||||||
|
|
||||||
* default:
|
|
||||||
* 'int': 'INT'
|
|
||||||
* 'char': 'INT8'
|
|
||||||
* 'short': 'INT16'
|
|
||||||
* 'long': 'INT'
|
|
||||||
* 'int8': 'INT8'
|
|
||||||
* 'int16': 'INT16'
|
|
||||||
* 'int32': 'INT'
|
|
||||||
* 'int8_t': 'INT8'
|
|
||||||
* 'int16_t': 'INT16'
|
|
||||||
* 'int32_t': 'INT'
|
|
||||||
* 'INT8_T': 'INT8'
|
|
||||||
* 'INT16_T': 'INT16'
|
|
||||||
* 'INT32_T': 'INT'
|
|
||||||
* 'bool': 'INT'
|
|
||||||
* 'bool_t': 'INT'
|
|
||||||
* 'BOOL': 'INT'
|
|
||||||
* 'BOOL_T': 'INT'
|
|
||||||
* 'unsigned int': 'HEX32'
|
|
||||||
* 'unsigned long': 'HEX32'
|
|
||||||
* 'uint32': 'HEX32'
|
|
||||||
* 'uint32_t': 'HEX32'
|
|
||||||
* 'UINT32': 'HEX32'
|
|
||||||
* 'UINT32_T': 'HEX32'
|
|
||||||
* 'void*': 'HEX8_ARRAY'
|
|
||||||
* 'unsigned short': 'HEX16'
|
|
||||||
* 'uint16': 'HEX16'
|
|
||||||
* 'uint16_t': 'HEX16'
|
|
||||||
* 'UINT16': 'HEX16'
|
|
||||||
* 'UINT16_T': 'HEX16'
|
|
||||||
* 'unsigned char': 'HEX8'
|
|
||||||
* 'uint8': 'HEX8'
|
|
||||||
* 'uint8_t': 'HEX8'
|
|
||||||
* 'UINT8': 'HEX8'
|
|
||||||
* 'UINT8_T': 'HEX8'
|
|
||||||
* 'char*': 'STRING'
|
|
||||||
* 'pCHAR': 'STRING'
|
|
||||||
* 'cstring': 'STRING'
|
|
||||||
* 'CSTRING': 'STRING'
|
|
||||||
* 'float': 'FLOAT'
|
|
||||||
* 'double': 'FLOAT'
|
|
||||||
|
|
||||||
* `:treat_as_void`:
|
|
||||||
We've seen "fun" legacy systems typedef 'void' with a custom type,
|
|
||||||
like MY_VOID. Add any instances of those to this list to help CMock
|
|
||||||
understand how to deal with your code.
|
|
||||||
|
|
||||||
* default: []
|
|
||||||
|
|
||||||
* `:treat_externs`:
|
|
||||||
This specifies how you want CMock to handle functions that have been
|
|
||||||
marked as extern in the header file. Should it mock them?
|
|
||||||
|
|
||||||
* `:include` will mock externed functions
|
|
||||||
* `:exclude` will ignore externed functions (default).
|
|
||||||
|
|
||||||
* `:unity_helper_path`:
|
|
||||||
If you have created a header with your own extensions to unity to
|
|
||||||
handle your own types, you can set this argument to that path. CMock
|
|
||||||
will then automagically pull in your helpers and use them. The only
|
|
||||||
trick is that you make sure you follow the naming convention:
|
|
||||||
`UNITY_TEST_ASSERT_EQUAL_YourType`. If it finds macros of the right
|
|
||||||
shape that match that pattern, it'll use them.
|
|
||||||
|
|
||||||
* default: []
|
|
||||||
|
|
||||||
* `:verbosity`:
|
|
||||||
How loud should CMock be?
|
|
||||||
|
|
||||||
* 0 for errors only
|
|
||||||
* 1 for errors and warnings
|
|
||||||
* 2 for normal (default)
|
|
||||||
* 3 for verbose
|
|
||||||
|
|
||||||
* `:weak`:
|
|
||||||
When set this to some value, the generated mocks are defined as weak
|
|
||||||
symbols using the configured format. This allows them to be overridden
|
|
||||||
in particular tests.
|
|
||||||
|
|
||||||
* Set to '__attribute ((weak))' for weak mocks when using GCC.
|
|
||||||
* Set to any non-empty string for weak mocks when using IAR.
|
|
||||||
* default: ""
|
|
||||||
|
|
||||||
* `:when_no_prototypes`:
|
|
||||||
When you give CMock a header file and ask it to create a mock out of
|
|
||||||
it, it usually contains function prototypes (otherwise what was the
|
|
||||||
point?). You can control what happens when this isn't true. You can
|
|
||||||
set this to `:warn,` `:ignore,` or `:error`
|
|
||||||
|
|
||||||
* default: :warn
|
|
||||||
|
|
||||||
* `:when_ptr`:
|
|
||||||
You can customize how CMock deals with pointers (c strings result in
|
|
||||||
string comparisons... we're talking about **other** pointers here). Your
|
|
||||||
options are `:compare_ptr` to just verify the pointers are the same,
|
|
||||||
`:compare_data` or `:smart` to verify that the data is the same.
|
|
||||||
`:compare_data` and `:smart` behaviors will change slightly based on
|
|
||||||
if you have the array plugin enabled. By default, they compare a
|
|
||||||
single element of what is being pointed to. So if you have a pointer
|
|
||||||
to a struct called ORGAN_T, it will compare one ORGAN_T (whatever that
|
|
||||||
is).
|
|
||||||
|
|
||||||
* default: :smart
|
|
||||||
|
|
||||||
* `:fail_on_unexpected_calls`:
|
|
||||||
By default, CMock will fail a test if a mock is called without _Expect and _Ignore
|
|
||||||
called first. While this forces test writers to be more explicit in their expectations,
|
|
||||||
it can clutter tests with _Expect or _Ignore calls for functions which are not the focus
|
|
||||||
of the test. While this is a good indicator that this module should be refactored, some
|
|
||||||
users are not fans of the additional noise.
|
|
||||||
|
|
||||||
Therefore, :fail_on_unexpected_calls can be set to false to force all mocks to start with
|
|
||||||
the assumption that they are operating as _Ignore unless otherwise specified.
|
|
||||||
|
|
||||||
* default: true
|
|
||||||
* **note:**
|
|
||||||
If this option is disabled, the mocked functions will return
|
|
||||||
a default value (0) when called (and only if they have to return something of course).
|
|
||||||
|
|
||||||
|
|
||||||
Compiled Options:
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
A number of #defines also exist for customizing the cmock experience.
|
|
||||||
Feel free to pass these into your compiler or whatever is most
|
|
||||||
convenient. CMock will otherwise do its best to guess what you want
|
|
||||||
based on other settings, particularly Unity's settings.
|
|
||||||
|
|
||||||
* `CMOCK_MEM_STATIC` or `CMOCK_MEM_DYNAMIC`
|
|
||||||
Define one of these to determine if you want to dynamically add
|
|
||||||
memory during tests as required from the heap. If static, you
|
|
||||||
can control the total footprint of Cmock. If dynamic, you will
|
|
||||||
need to make sure you make some heap space available for Cmock.
|
|
||||||
|
|
||||||
* `CMOCK_MEM_SIZE`
|
|
||||||
In static mode this is the total amount of memory you are allocating
|
|
||||||
to Cmock. In Dynamic mode this is the size of each chunk allocated
|
|
||||||
at once (larger numbers grab more memory but require less mallocs).
|
|
||||||
|
|
||||||
* `CMOCK_MEM_ALIGN`
|
|
||||||
The way to align your data to. Not everything is as flexible as
|
|
||||||
a PC, as most embedded designers know. This defaults to 2, meaning
|
|
||||||
align to the closest 2^2 -> 4 bytes (32 bits). You can turn off alignment
|
|
||||||
by setting 0, force alignment to the closest uint16 with 1 or even
|
|
||||||
to the closest uint64 with 3.
|
|
||||||
|
|
||||||
* `CMOCK_MEM_PTR_AS_INT`
|
|
||||||
This is used internally to hold pointers... it needs to be big
|
|
||||||
enough. On most processors a pointer is the same as an unsigned
|
|
||||||
long... but maybe that's not true for yours?
|
|
||||||
|
|
||||||
* `CMOCK_MEM_INDEX_TYPE`
|
|
||||||
This needs to be something big enough to point anywhere in Cmock's
|
|
||||||
memory space... usually it's an unsigned int.
|
|
||||||
|
|
||||||
Examples
|
|
||||||
========
|
|
||||||
|
|
||||||
You can look in the [examples directory](/examples/) for a couple of examples on how
|
|
||||||
you might tool CMock into your build process. You may also want to consider
|
|
||||||
using [Ceedling](https://throwtheswitch.org/ceedling). Please note that
|
|
||||||
these examples are meant to show how the build process works. They have
|
|
||||||
failing tests ON PURPOSE to show what that would look like. Don't be alarmed. ;)
|
|
||||||
|
|
2060
test/vendor/ceedling/docs/CeedlingPacket.md
vendored
2060
test/vendor/ceedling/docs/CeedlingPacket.md
vendored
File diff suppressed because it is too large
Load Diff
@ -1,206 +0,0 @@
|
|||||||
# ThrowTheSwitch.org Coding Standard
|
|
||||||
|
|
||||||
Hi. Welcome to the coding standard for ThrowTheSwitch.org. For the most part,
|
|
||||||
we try to follow these standards to unify our contributors' code into a cohesive
|
|
||||||
unit (puns intended). You might find places where these standards aren't
|
|
||||||
followed. We're not perfect. Please be polite where you notice these discrepancies
|
|
||||||
and we'll try to be polite when we notice yours.
|
|
||||||
|
|
||||||
;)
|
|
||||||
|
|
||||||
|
|
||||||
## Why Have A Coding Standard?
|
|
||||||
|
|
||||||
Being consistent makes code easier to understand. We've tried to keep
|
|
||||||
our standard simple because we also believe that we can only expect someone to
|
|
||||||
follow something that is understandable. Please do your best.
|
|
||||||
|
|
||||||
|
|
||||||
## Our Philosophy
|
|
||||||
|
|
||||||
Before we get into details on syntax, let's take a moment to talk about our
|
|
||||||
vision for these tools. We're C developers and embedded software developers.
|
|
||||||
These tools are great to test any C code, but catering to embedded software has
|
|
||||||
made us more tolerant of compiler quirks. There are a LOT of quirky compilers
|
|
||||||
out there. By quirky I mean "doesn't follow standards because they feel like
|
|
||||||
they have a license to do as they wish."
|
|
||||||
|
|
||||||
Our philosophy is "support every compiler we can". Most often, this means that
|
|
||||||
we aim for writing C code that is standards compliant (often C89... that seems
|
|
||||||
to be a sweet spot that is almost always compatible). But it also means these
|
|
||||||
tools are tolerant of things that aren't common. Some that aren't even
|
|
||||||
compliant. There are configuration options to override the size of standard
|
|
||||||
types. There are configuration options to force Unity to not use certain
|
|
||||||
standard library functions. A lot of Unity is configurable and we have worked
|
|
||||||
hard to make it not TOO ugly in the process.
|
|
||||||
|
|
||||||
Similarly, our tools that parse C do their best. They aren't full C parsers
|
|
||||||
(yet) and, even if they were, they would still have to accept non-standard
|
|
||||||
additions like gcc extensions or specifying `@0x1000` to force a variable to
|
|
||||||
compile to a particular location. It's just what we do, because we like
|
|
||||||
everything to Just Work™.
|
|
||||||
|
|
||||||
Speaking of having things Just Work™, that's our second philosophy. By that, we
|
|
||||||
mean that we do our best to have EVERY configuration option have a logical
|
|
||||||
default. We believe that if you're working with a simple compiler and target,
|
|
||||||
you shouldn't need to configure very much... we try to make the tools guess as
|
|
||||||
much as they can, but give the user the power to override it when it's wrong.
|
|
||||||
|
|
||||||
|
|
||||||
## Naming Things
|
|
||||||
|
|
||||||
Let's talk about naming things. Programming is all about naming things. We name
|
|
||||||
files, functions, variables, and so much more. While we're not always going to
|
|
||||||
find the best name for something, we actually put a bit of effort into
|
|
||||||
finding *What Something WANTS to be Called*™.
|
|
||||||
|
|
||||||
When naming things, we follow this hierarchy, the first being the
|
|
||||||
most important to us (but we do all four when possible):
|
|
||||||
1. Readable
|
|
||||||
2. Descriptive
|
|
||||||
3. Consistent
|
|
||||||
4. Memorable
|
|
||||||
|
|
||||||
|
|
||||||
#### Readable
|
|
||||||
|
|
||||||
We want to read our code. This means we like names and flow that are more
|
|
||||||
naturally read. We try to avoid double negatives. We try to avoid cryptic
|
|
||||||
abbreviations (sticking to ones we feel are common).
|
|
||||||
|
|
||||||
|
|
||||||
#### Descriptive
|
|
||||||
|
|
||||||
We like descriptive names for things, especially functions and variables.
|
|
||||||
Finding the right name for something is an important endeavor. You might notice
|
|
||||||
from poking around our code that this often results in names that are a little
|
|
||||||
longer than the average. Guilty. We're okay with a bit more typing if it
|
|
||||||
means our code is easier to understand.
|
|
||||||
|
|
||||||
There are two exceptions to this rule that we also stick to as religiously as
|
|
||||||
possible:
|
|
||||||
|
|
||||||
First, while we realize hungarian notation (and similar systems for encoding
|
|
||||||
type information into variable names) is providing a more descriptive name, we
|
|
||||||
feel that (for the average developer) it takes away from readability and is to be avoided.
|
|
||||||
|
|
||||||
Second, loop counters and other local throw-away variables often have a purpose
|
|
||||||
which is obvious. There's no need, therefore, to get carried away with complex
|
|
||||||
naming. We find i, j, and k are better loop counters than loopCounterVar or
|
|
||||||
whatnot. We only break this rule when we see that more description could improve
|
|
||||||
understanding of an algorithm.
|
|
||||||
|
|
||||||
|
|
||||||
#### Consistent
|
|
||||||
|
|
||||||
We like consistency, but we're not really obsessed with it. We try to name our
|
|
||||||
configuration macros in a consistent fashion... you'll notice a repeated use of
|
|
||||||
UNITY_EXCLUDE_BLAH or UNITY_USES_BLAH macros. This helps users avoid having to
|
|
||||||
remember each macro's details.
|
|
||||||
|
|
||||||
|
|
||||||
#### Memorable
|
|
||||||
|
|
||||||
Where ever it doesn't violate the above principles, we try to apply memorable
|
|
||||||
names. Sometimes this means using something that is simply descriptive, but
|
|
||||||
often we strive for descriptive AND unique... we like quirky names that stand
|
|
||||||
out in our memory and are easier to search for. Take a look through the file
|
|
||||||
names in Ceedling and you'll get a good idea of what we are talking about here.
|
|
||||||
Why use preprocess when you can use preprocessinator? Or what better describes a
|
|
||||||
module in charge of invoking tasks during releases than release_invoker? Don't
|
|
||||||
get carried away. The names are still descriptive and fulfill the above
|
|
||||||
requirements, but they don't feel stale.
|
|
||||||
|
|
||||||
|
|
||||||
## C and C++ Details
|
|
||||||
|
|
||||||
We don't really want to add to the style battles out there. Tabs or spaces?
|
|
||||||
How many spaces? Where do the braces go? These are age-old questions that will
|
|
||||||
never be answered... or at least not answered in a way that will make everyone
|
|
||||||
happy.
|
|
||||||
|
|
||||||
We've decided on our own style preferences. If you'd like to contribute to these
|
|
||||||
projects (and we hope that you do), then we ask if you do your best to follow
|
|
||||||
the same. It will only hurt a little. We promise.
|
|
||||||
|
|
||||||
|
|
||||||
#### Whitespace
|
|
||||||
|
|
||||||
Our C-style is to use spaces and to use 4 of them per indent level. It's a nice
|
|
||||||
power-of-2 number that looks decent on a wide-screen. We have no more reason
|
|
||||||
than that. We break that rule when we have lines that wrap (macros or function
|
|
||||||
arguments or whatnot). When that happens, we like to indent further to line
|
|
||||||
things up in nice tidy columns.
|
|
||||||
|
|
||||||
```C
|
|
||||||
if (stuff_happened)
|
|
||||||
{
|
|
||||||
do_something();
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
#### Case
|
|
||||||
|
|
||||||
- Files - all lower case with underscores.
|
|
||||||
- Variables - all lower case with underscores
|
|
||||||
- Macros - all caps with underscores.
|
|
||||||
- Typedefs - all caps with underscores. (also ends with _T).
|
|
||||||
- Functions - camel cased. Usually named ModuleName_FuncName
|
|
||||||
- Constants and Globals - camel cased.
|
|
||||||
|
|
||||||
|
|
||||||
#### Braces
|
|
||||||
|
|
||||||
The left brace is on the next line after the declaration. The right brace is
|
|
||||||
directly below that. Everything in between in indented one level. If you're
|
|
||||||
catching an error and you have a one-line, go ahead and to it on the same line.
|
|
||||||
|
|
||||||
```C
|
|
||||||
while (blah)
|
|
||||||
{
|
|
||||||
//Like so. Even if only one line, we use braces.
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
#### Comments
|
|
||||||
|
|
||||||
Do you know what we hate? Old-school C block comments. BUT, we're using them
|
|
||||||
anyway. As we mentioned, our goal is to support every compiler we can,
|
|
||||||
especially embedded compilers. There are STILL C compilers out there that only
|
|
||||||
support old-school block comments. So that is what we're using. We apologize. We
|
|
||||||
think they are ugly too.
|
|
||||||
|
|
||||||
|
|
||||||
## Ruby Details
|
|
||||||
|
|
||||||
Is there really such thing as a Ruby coding standard? Ruby is such a free form
|
|
||||||
language, it seems almost sacrilegious to suggest that people should comply to
|
|
||||||
one method! We'll keep it really brief!
|
|
||||||
|
|
||||||
|
|
||||||
#### Whitespace
|
|
||||||
|
|
||||||
Our Ruby style is to use spaces and to use 2 of them per indent level. It's a
|
|
||||||
nice power-of-2 number that really grooves with Ruby's compact style. We have no
|
|
||||||
more reason than that. We break that rule when we have lines that wrap. When
|
|
||||||
that happens, we like to indent further to line things up in nice tidy columns.
|
|
||||||
|
|
||||||
|
|
||||||
#### Case
|
|
||||||
|
|
||||||
- Files - all lower case with underscores.
|
|
||||||
- Variables - all lower case with underscores
|
|
||||||
- Classes, Modules, etc - Camel cased.
|
|
||||||
- Functions - all lower case with underscores
|
|
||||||
- Constants - all upper case with underscores
|
|
||||||
|
|
||||||
|
|
||||||
## Documentation
|
|
||||||
|
|
||||||
Egad. Really? We use mark down and we like pdf files because they can be made to
|
|
||||||
look nice while still being portable. Good enough?
|
|
||||||
|
|
||||||
|
|
||||||
*Find The Latest of This And More at [ThrowTheSwitch.org](https://throwtheswitch.org)*
|
|
Binary file not shown.
@ -1,779 +0,0 @@
|
|||||||
# Unity Assertions Reference
|
|
||||||
|
|
||||||
## Background and Overview
|
|
||||||
|
|
||||||
### Super Condensed Version
|
|
||||||
|
|
||||||
- An assertion establishes truth (i.e. boolean True) for a single condition.
|
|
||||||
Upon boolean False, an assertion stops execution and reports the failure.
|
|
||||||
- Unity is mainly a rich collection of assertions and the support to gather up
|
|
||||||
and easily execute those assertions.
|
|
||||||
- The structure of Unity allows you to easily separate test assertions from
|
|
||||||
source code in, well, test code.
|
|
||||||
- Unity's assertions:
|
|
||||||
- Come in many, many flavors to handle different C types and assertion cases.
|
|
||||||
- Use context to provide detailed and helpful failure messages.
|
|
||||||
- Document types, expected values, and basic behavior in your source code for
|
|
||||||
free.
|
|
||||||
|
|
||||||
|
|
||||||
### Unity Is Several Things But Mainly It's Assertions
|
|
||||||
|
|
||||||
One way to think of Unity is simply as a rich collection of assertions you can
|
|
||||||
use to establish whether your source code behaves the way you think it does.
|
|
||||||
Unity provides a framework to easily organize and execute those assertions in
|
|
||||||
test code separate from your source code.
|
|
||||||
|
|
||||||
|
|
||||||
### What's an Assertion?
|
|
||||||
|
|
||||||
At their core, assertions are an establishment of truth - boolean truth. Was this
|
|
||||||
thing equal to that thing? Does that code doohickey have such-and-such property
|
|
||||||
or not? You get the idea. Assertions are executable code (to appreciate the big
|
|
||||||
picture on this read up on the difference between
|
|
||||||
[link:Dynamic Verification and Static Analysis]). A failing assertion stops
|
|
||||||
execution and reports an error through some appropriate I/O channel (e.g.
|
|
||||||
stdout, GUI, file, blinky light).
|
|
||||||
|
|
||||||
Fundamentally, for dynamic verification all you need is a single assertion
|
|
||||||
mechanism. In fact, that's what the [assert() macro in C's standard library](http://en.wikipedia.org/en/wiki/Assert.h)
|
|
||||||
is for. So why not just use it? Well, we can do far better in the reporting
|
|
||||||
department. C's `assert()` is pretty dumb as-is and is particularly poor for
|
|
||||||
handling common data types like arrays, structs, etc. And, without some other
|
|
||||||
support, it's far too tempting to litter source code with C's `assert()`'s. It's
|
|
||||||
generally much cleaner, manageable, and more useful to separate test and source
|
|
||||||
code in the way Unity facilitates.
|
|
||||||
|
|
||||||
|
|
||||||
### Unity's Assertions: Helpful Messages _and_ Free Source Code Documentation
|
|
||||||
|
|
||||||
Asserting a simple truth condition is valuable, but using the context of the
|
|
||||||
assertion is even more valuable. For instance, if you know you're comparing bit
|
|
||||||
flags and not just integers, then why not use that context to give explicit,
|
|
||||||
readable, bit-level feedback when an assertion fails?
|
|
||||||
|
|
||||||
That's what Unity's collection of assertions do - capture context to give you
|
|
||||||
helpful, meaningful assertion failure messages. In fact, the assertions
|
|
||||||
themselves also serve as executable documentation about types and values in your
|
|
||||||
source code. So long as your tests remain current with your source and all those
|
|
||||||
tests pass, you have a detailed, up-to-date view of the intent and mechanisms in
|
|
||||||
your source code. And due to a wondrous mystery, well-tested code usually tends
|
|
||||||
to be well designed code.
|
|
||||||
|
|
||||||
|
|
||||||
## Assertion Conventions and Configurations
|
|
||||||
|
|
||||||
### Naming and Parameter Conventions
|
|
||||||
|
|
||||||
The convention of assertion parameters generally follows this order:
|
|
||||||
|
|
||||||
TEST_ASSERT_X( {modifiers}, {expected}, actual, {size/count} )
|
|
||||||
|
|
||||||
The very simplest assertion possible uses only a single "actual" parameter (e.g.
|
|
||||||
a simple null check).
|
|
||||||
|
|
||||||
"Actual" is the value being tested and unlike the other parameters in an
|
|
||||||
assertion construction is the only parameter present in all assertion variants.
|
|
||||||
"Modifiers" are masks, ranges, bit flag specifiers, floating point deltas.
|
|
||||||
"Expected" is your expected value (duh) to compare to an "actual" value; it's
|
|
||||||
marked as an optional parameter because some assertions only need a single
|
|
||||||
"actual" parameter (e.g. null check).
|
|
||||||
"Size/count" refers to string lengths, number of array elements, etc.
|
|
||||||
|
|
||||||
Many of Unity's assertions are clear duplications in that the same data type
|
|
||||||
is handled by several assertions. The differences among these are in how failure
|
|
||||||
messages are presented. For instance, a `_HEX` variant of an assertion prints
|
|
||||||
the expected and actual values of that assertion formatted as hexadecimal.
|
|
||||||
|
|
||||||
|
|
||||||
#### TEST_ASSERT_X_MESSAGE Variants
|
|
||||||
|
|
||||||
_All_ assertions are complemented with a variant that includes a simple string
|
|
||||||
message as a final parameter. The string you specify is appended to an assertion
|
|
||||||
failure message in Unity output.
|
|
||||||
|
|
||||||
For brevity, the assertion variants with a message parameter are not listed
|
|
||||||
below. Just tack on `_MESSAGE` as the final component to any assertion name in
|
|
||||||
the reference list below and add a string as the final parameter.
|
|
||||||
|
|
||||||
_Example:_
|
|
||||||
|
|
||||||
TEST_ASSERT_X( {modifiers}, {expected}, actual, {size/count} )
|
|
||||||
|
|
||||||
becomes messageified like thus...
|
|
||||||
|
|
||||||
TEST_ASSERT_X_MESSAGE( {modifiers}, {expected}, actual, {size/count}, message )
|
|
||||||
|
|
||||||
Notes:
|
|
||||||
- The `_MESSAGE` variants intentionally do not support `printf` style formatting
|
|
||||||
since many embedded projects don't support or avoid `printf` for various reasons.
|
|
||||||
It is possible to use `sprintf` before the assertion to assemble a complex fail
|
|
||||||
message, if necessary.
|
|
||||||
- If you want to output a counter value within an assertion fail message (e.g. from
|
|
||||||
a loop) , building up an array of results and then using one of the `_ARRAY`
|
|
||||||
assertions (see below) might be a handy alternative to `sprintf`.
|
|
||||||
|
|
||||||
|
|
||||||
#### TEST_ASSERT_X_ARRAY Variants
|
|
||||||
|
|
||||||
Unity provides a collection of assertions for arrays containing a variety of
|
|
||||||
types. These are documented in the Array section below. These are almost on par
|
|
||||||
with the `_MESSAGE`variants of Unity's Asserts in that for pretty much any Unity
|
|
||||||
type assertion you can tack on `_ARRAY` and run assertions on an entire block of
|
|
||||||
memory.
|
|
||||||
|
|
||||||
TEST_ASSERT_EQUAL_TYPEX_ARRAY( expected, actual, {size/count} )
|
|
||||||
|
|
||||||
"Expected" is an array itself.
|
|
||||||
"Size/count" is one or two parameters necessary to establish the number of array
|
|
||||||
elements and perhaps the length of elements within the array.
|
|
||||||
|
|
||||||
Notes:
|
|
||||||
- The `_MESSAGE` variant convention still applies here to array assertions. The
|
|
||||||
`_MESSAGE` variants of the `_ARRAY` assertions have names ending with
|
|
||||||
`_ARRAY_MESSAGE`.
|
|
||||||
- Assertions for handling arrays of floating point values are grouped with float
|
|
||||||
and double assertions (see immediately following section).
|
|
||||||
|
|
||||||
|
|
||||||
### TEST_ASSERT_EACH_EQUAL_X Variants
|
|
||||||
|
|
||||||
Unity provides a collection of assertions for arrays containing a variety of
|
|
||||||
types which can be compared to a single value as well. These are documented in
|
|
||||||
the Each Equal section below. these are almost on par with the `_MESSAGE`
|
|
||||||
variants of Unity's Asserts in that for pretty much any Unity type assertion you
|
|
||||||
can inject _EACH_EQUAL and run assertions on an entire block of memory.
|
|
||||||
|
|
||||||
TEST_ASSERT_EACH_EQUAL_TYPEX( expected, actual, {size/count} )
|
|
||||||
|
|
||||||
"Expected" is a single value to compare to.
|
|
||||||
"Actual" is an array where each element will be compared to the expected value.
|
|
||||||
"Size/count" is one of two parameters necessary to establish the number of array
|
|
||||||
elements and perhaps the length of elements within the array.
|
|
||||||
|
|
||||||
Notes:
|
|
||||||
- The `_MESSAGE` variant convention still applies here to Each Equal assertions.
|
|
||||||
- Assertions for handling Each Equal of floating point values are grouped with
|
|
||||||
float and double assertions (see immediately following section).
|
|
||||||
|
|
||||||
|
|
||||||
### Configuration
|
|
||||||
|
|
||||||
#### Floating Point Support Is Optional
|
|
||||||
|
|
||||||
Support for floating point types is configurable. That is, by defining the
|
|
||||||
appropriate preprocessor symbols, floats and doubles can be individually enabled
|
|
||||||
or disabled in Unity code. This is useful for embedded targets with no floating
|
|
||||||
point math support (i.e. Unity compiles free of errors for fixed point only
|
|
||||||
platforms). See Unity documentation for specifics.
|
|
||||||
|
|
||||||
|
|
||||||
#### Maximum Data Type Width Is Configurable
|
|
||||||
|
|
||||||
Not all targets support 64 bit wide types or even 32 bit wide types. Define the
|
|
||||||
appropriate preprocessor symbols and Unity will omit all operations from
|
|
||||||
compilation that exceed the maximum width of your target. See Unity
|
|
||||||
documentation for specifics.
|
|
||||||
|
|
||||||
|
|
||||||
## The Assertions in All Their Blessed Glory
|
|
||||||
|
|
||||||
### Basic Fail and Ignore
|
|
||||||
|
|
||||||
##### `TEST_FAIL()`
|
|
||||||
|
|
||||||
This fella is most often used in special conditions where your test code is
|
|
||||||
performing logic beyond a simple assertion. That is, in practice, `TEST_FAIL()`
|
|
||||||
will always be found inside a conditional code block.
|
|
||||||
|
|
||||||
_Examples:_
|
|
||||||
- Executing a state machine multiple times that increments a counter your test
|
|
||||||
code then verifies as a final step.
|
|
||||||
- Triggering an exception and verifying it (as in Try / Catch / Throw - see the
|
|
||||||
[CException](https://github.com/ThrowTheSwitch/CException) project).
|
|
||||||
|
|
||||||
##### `TEST_IGNORE()`
|
|
||||||
|
|
||||||
Marks a test case (i.e. function meant to contain test assertions) as ignored.
|
|
||||||
Usually this is employed as a breadcrumb to come back and implement a test case.
|
|
||||||
An ignored test case has effects if other assertions are in the enclosing test
|
|
||||||
case (see Unity documentation for more).
|
|
||||||
|
|
||||||
### Boolean
|
|
||||||
|
|
||||||
##### `TEST_ASSERT (condition)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_TRUE (condition)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_FALSE (condition)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_UNLESS (condition)`
|
|
||||||
|
|
||||||
A simple wording variation on `TEST_ASSERT_FALSE`.The semantics of
|
|
||||||
`TEST_ASSERT_UNLESS` aid readability in certain test constructions or
|
|
||||||
conditional statements.
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_NULL (pointer)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_NOT_NULL (pointer)`
|
|
||||||
|
|
||||||
|
|
||||||
### Signed and Unsigned Integers (of all sizes)
|
|
||||||
|
|
||||||
Large integer sizes can be disabled for build targets that do not support them.
|
|
||||||
For example, if your target only supports up to 16 bit types, by defining the
|
|
||||||
appropriate symbols Unity can be configured to omit 32 and 64 bit operations
|
|
||||||
that would break compilation (see Unity documentation for more). Refer to
|
|
||||||
Advanced Asserting later in this document for advice on dealing with other word
|
|
||||||
sizes.
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_EQUAL_INT (expected, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_EQUAL_INT8 (expected, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_EQUAL_INT16 (expected, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_EQUAL_INT32 (expected, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_EQUAL_INT64 (expected, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_EQUAL (expected, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_NOT_EQUAL (expected, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_EQUAL_UINT (expected, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_EQUAL_UINT8 (expected, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_EQUAL_UINT16 (expected, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_EQUAL_UINT32 (expected, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_EQUAL_UINT64 (expected, actual)`
|
|
||||||
|
|
||||||
|
|
||||||
### Unsigned Integers (of all sizes) in Hexadecimal
|
|
||||||
|
|
||||||
All `_HEX` assertions are identical in function to unsigned integer assertions
|
|
||||||
but produce failure messages with the `expected` and `actual` values formatted
|
|
||||||
in hexadecimal. Unity output is big endian.
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_EQUAL_HEX (expected, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_EQUAL_HEX8 (expected, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_EQUAL_HEX16 (expected, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_EQUAL_HEX32 (expected, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_EQUAL_HEX64 (expected, actual)`
|
|
||||||
|
|
||||||
|
|
||||||
### Masked and Bit-level Assertions
|
|
||||||
|
|
||||||
Masked and bit-level assertions produce output formatted in hexadecimal. Unity
|
|
||||||
output is big endian.
|
|
||||||
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_BITS (mask, expected, actual)`
|
|
||||||
|
|
||||||
Only compares the masked (i.e. high) bits of `expected` and `actual` parameters.
|
|
||||||
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_BITS_HIGH (mask, actual)`
|
|
||||||
|
|
||||||
Asserts the masked bits of the `actual` parameter are high.
|
|
||||||
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_BITS_LOW (mask, actual)`
|
|
||||||
|
|
||||||
Asserts the masked bits of the `actual` parameter are low.
|
|
||||||
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_BIT_HIGH (bit, actual)`
|
|
||||||
|
|
||||||
Asserts the specified bit of the `actual` parameter is high.
|
|
||||||
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_BIT_LOW (bit, actual)`
|
|
||||||
|
|
||||||
Asserts the specified bit of the `actual` parameter is low.
|
|
||||||
|
|
||||||
### Integer Less Than / Greater Than
|
|
||||||
|
|
||||||
These assertions verify that the `actual` parameter is less than or greater
|
|
||||||
than `threshold` (exclusive). For example, if the threshold value is 0 for the
|
|
||||||
greater than assertion will fail if it is 0 or less.
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_GREATER_THAN (threshold, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_GREATER_THAN_INT (threshold, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_GREATER_THAN_INT8 (threshold, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_GREATER_THAN_INT16 (threshold, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_GREATER_THAN_INT32 (threshold, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_GREATER_THAN_UINT (threshold, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_GREATER_THAN_UINT8 (threshold, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_GREATER_THAN_UINT16 (threshold, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_GREATER_THAN_UINT32 (threshold, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_GREATER_THAN_HEX8 (threshold, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_GREATER_THAN_HEX16 (threshold, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_GREATER_THAN_HEX32 (threshold, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_LESS_THAN (threshold, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_LESS_THAN_INT (threshold, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_LESS_THAN_INT8 (threshold, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_LESS_THAN_INT16 (threshold, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_LESS_THAN_INT32 (threshold, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_LESS_THAN_UINT (threshold, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_LESS_THAN_UINT8 (threshold, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_LESS_THAN_UINT16 (threshold, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_LESS_THAN_UINT32 (threshold, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_LESS_THAN_HEX8 (threshold, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_LESS_THAN_HEX16 (threshold, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_LESS_THAN_HEX32 (threshold, actual)`
|
|
||||||
|
|
||||||
|
|
||||||
### Integer Ranges (of all sizes)
|
|
||||||
|
|
||||||
These assertions verify that the `expected` parameter is within +/- `delta`
|
|
||||||
(inclusive) of the `actual` parameter. For example, if the expected value is 10
|
|
||||||
and the delta is 3 then the assertion will fail for any value outside the range
|
|
||||||
of 7 - 13.
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_INT_WITHIN (delta, expected, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_INT8_WITHIN (delta, expected, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_INT16_WITHIN (delta, expected, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_INT32_WITHIN (delta, expected, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_INT64_WITHIN (delta, expected, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_UINT_WITHIN (delta, expected, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_UINT8_WITHIN (delta, expected, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_UINT16_WITHIN (delta, expected, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_UINT32_WITHIN (delta, expected, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_UINT64_WITHIN (delta, expected, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_HEX_WITHIN (delta, expected, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_HEX8_WITHIN (delta, expected, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_HEX16_WITHIN (delta, expected, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_HEX32_WITHIN (delta, expected, actual)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_HEX64_WITHIN (delta, expected, actual)`
|
|
||||||
|
|
||||||
|
|
||||||
### Structs and Strings
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_EQUAL_PTR (expected, actual)`
|
|
||||||
|
|
||||||
Asserts that the pointers point to the same memory location.
|
|
||||||
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_EQUAL_STRING (expected, actual)`
|
|
||||||
|
|
||||||
Asserts that the null terminated (`'\0'`)strings are identical. If strings are
|
|
||||||
of different lengths or any portion of the strings before their terminators
|
|
||||||
differ, the assertion fails. Two NULL strings (i.e. zero length) are considered
|
|
||||||
equivalent.
|
|
||||||
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_EQUAL_MEMORY (expected, actual, len)`
|
|
||||||
|
|
||||||
Asserts that the contents of the memory specified by the `expected` and `actual`
|
|
||||||
pointers is identical. The size of the memory blocks in bytes is specified by
|
|
||||||
the `len` parameter.
|
|
||||||
|
|
||||||
|
|
||||||
### Arrays
|
|
||||||
|
|
||||||
`expected` and `actual` parameters are both arrays. `num_elements` specifies the
|
|
||||||
number of elements in the arrays to compare.
|
|
||||||
|
|
||||||
`_HEX` assertions produce failure messages with expected and actual array
|
|
||||||
contents formatted in hexadecimal.
|
|
||||||
|
|
||||||
For array of strings comparison behavior, see comments for
|
|
||||||
`TEST_ASSERT_EQUAL_STRING` in the preceding section.
|
|
||||||
|
|
||||||
Assertions fail upon the first element in the compared arrays found not to
|
|
||||||
match. Failure messages specify the array index of the failed comparison.
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_EQUAL_INT_ARRAY (expected, actual, num_elements)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_EQUAL_INT8_ARRAY (expected, actual, num_elements)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_EQUAL_INT16_ARRAY (expected, actual, num_elements)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_EQUAL_INT32_ARRAY (expected, actual, num_elements)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_EQUAL_INT64_ARRAY (expected, actual, num_elements)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_EQUAL_UINT_ARRAY (expected, actual, num_elements)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_EQUAL_UINT8_ARRAY (expected, actual, num_elements)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_EQUAL_UINT16_ARRAY (expected, actual, num_elements)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_EQUAL_UINT32_ARRAY (expected, actual, num_elements)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_EQUAL_UINT64_ARRAY (expected, actual, num_elements)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_EQUAL_HEX_ARRAY (expected, actual, num_elements)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_EQUAL_HEX8_ARRAY (expected, actual, num_elements)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_EQUAL_HEX16_ARRAY (expected, actual, num_elements)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_EQUAL_HEX32_ARRAY (expected, actual, num_elements)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_EQUAL_HEX64_ARRAY (expected, actual, num_elements)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_EQUAL_PTR_ARRAY (expected, actual, num_elements)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_EQUAL_STRING_ARRAY (expected, actual, num_elements)`
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_EQUAL_MEMORY_ARRAY (expected, actual, len, num_elements)`
|
|
||||||
|
|
||||||
`len` is the memory in bytes to be compared at each array element.
|
|
||||||
|
|
||||||
|
|
||||||
### Each Equal (Arrays to Single Value)
|
|
||||||
|
|
||||||
`expected` are single values and `actual` are arrays. `num_elements` specifies
|
|
||||||
the number of elements in the arrays to compare.
|
|
||||||
|
|
||||||
`_HEX` assertions produce failure messages with expected and actual array
|
|
||||||
contents formatted in hexadecimal.
|
|
||||||
|
|
||||||
Assertions fail upon the first element in the compared arrays found not to
|
|
||||||
match. Failure messages specify the array index of the failed comparison.
|
|
||||||
|
|
||||||
#### `TEST_ASSERT_EACH_EQUAL_INT (expected, actual, num_elements)`
|
|
||||||
|
|
||||||
#### `TEST_ASSERT_EACH_EQUAL_INT8 (expected, actual, num_elements)`
|
|
||||||
|
|
||||||
#### `TEST_ASSERT_EACH_EQUAL_INT16 (expected, actual, num_elements)`
|
|
||||||
|
|
||||||
#### `TEST_ASSERT_EACH_EQUAL_INT32 (expected, actual, num_elements)`
|
|
||||||
|
|
||||||
#### `TEST_ASSERT_EACH_EQUAL_INT64 (expected, actual, num_elements)`
|
|
||||||
|
|
||||||
#### `TEST_ASSERT_EACH_EQUAL_UINT (expected, actual, num_elements)`
|
|
||||||
|
|
||||||
#### `TEST_ASSERT_EACH_EQUAL_UINT8 (expected, actual, num_elements)`
|
|
||||||
|
|
||||||
#### `TEST_ASSERT_EACH_EQUAL_UINT16 (expected, actual, num_elements)`
|
|
||||||
|
|
||||||
#### `TEST_ASSERT_EACH_EQUAL_UINT32 (expected, actual, num_elements)`
|
|
||||||
|
|
||||||
#### `TEST_ASSERT_EACH_EQUAL_UINT64 (expected, actual, num_elements)`
|
|
||||||
|
|
||||||
#### `TEST_ASSERT_EACH_EQUAL_HEX (expected, actual, num_elements)`
|
|
||||||
|
|
||||||
#### `TEST_ASSERT_EACH_EQUAL_HEX8 (expected, actual, num_elements)`
|
|
||||||
|
|
||||||
#### `TEST_ASSERT_EACH_EQUAL_HEX16 (expected, actual, num_elements)`
|
|
||||||
|
|
||||||
#### `TEST_ASSERT_EACH_EQUAL_HEX32 (expected, actual, num_elements)`
|
|
||||||
|
|
||||||
#### `TEST_ASSERT_EACH_EQUAL_HEX64 (expected, actual, num_elements)`
|
|
||||||
|
|
||||||
#### `TEST_ASSERT_EACH_EQUAL_PTR (expected, actual, num_elements)`
|
|
||||||
|
|
||||||
#### `TEST_ASSERT_EACH_EQUAL_STRING (expected, actual, num_elements)`
|
|
||||||
|
|
||||||
#### `TEST_ASSERT_EACH_EQUAL_MEMORY (expected, actual, len, num_elements)`
|
|
||||||
|
|
||||||
`len` is the memory in bytes to be compared at each array element.
|
|
||||||
|
|
||||||
|
|
||||||
### Floating Point (If enabled)
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_FLOAT_WITHIN (delta, expected, actual)`
|
|
||||||
|
|
||||||
Asserts that the `actual` value is within +/- `delta` of the `expected` value.
|
|
||||||
The nature of floating point representation is such that exact evaluations of
|
|
||||||
equality are not guaranteed.
|
|
||||||
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_EQUAL_FLOAT (expected, actual)`
|
|
||||||
|
|
||||||
Asserts that the ?actual?value is "close enough to be considered equal" to the
|
|
||||||
`expected` value. If you are curious about the details, refer to the Advanced
|
|
||||||
Asserting section for more details on this. Omitting a user-specified delta in a
|
|
||||||
floating point assertion is both a shorthand convenience and a requirement of
|
|
||||||
code generation conventions for CMock.
|
|
||||||
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_EQUAL_FLOAT_ARRAY (expected, actual, num_elements)`
|
|
||||||
|
|
||||||
See Array assertion section for details. Note that individual array element
|
|
||||||
float comparisons are executed using T?EST_ASSERT_EQUAL_FLOAT?.That is, user
|
|
||||||
specified delta comparison values requires a custom-implemented floating point
|
|
||||||
array assertion.
|
|
||||||
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_FLOAT_IS_INF (actual)`
|
|
||||||
|
|
||||||
Asserts that `actual` parameter is equivalent to positive infinity floating
|
|
||||||
point representation.
|
|
||||||
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_FLOAT_IS_NEG_INF (actual)`
|
|
||||||
|
|
||||||
Asserts that `actual` parameter is equivalent to negative infinity floating
|
|
||||||
point representation.
|
|
||||||
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_FLOAT_IS_NAN (actual)`
|
|
||||||
|
|
||||||
Asserts that `actual` parameter is a Not A Number floating point representation.
|
|
||||||
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_FLOAT_IS_DETERMINATE (actual)`
|
|
||||||
|
|
||||||
Asserts that ?actual?parameter is a floating point representation usable for
|
|
||||||
mathematical operations. That is, the `actual` parameter is neither positive
|
|
||||||
infinity nor negative infinity nor Not A Number floating point representations.
|
|
||||||
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_FLOAT_IS_NOT_INF (actual)`
|
|
||||||
|
|
||||||
Asserts that `actual` parameter is a value other than positive infinity floating
|
|
||||||
point representation.
|
|
||||||
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_FLOAT_IS_NOT_NEG_INF (actual)`
|
|
||||||
|
|
||||||
Asserts that `actual` parameter is a value other than negative infinity floating
|
|
||||||
point representation.
|
|
||||||
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_FLOAT_IS_NOT_NAN (actual)`
|
|
||||||
|
|
||||||
Asserts that `actual` parameter is a value other than Not A Number floating
|
|
||||||
point representation.
|
|
||||||
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE (actual)`
|
|
||||||
|
|
||||||
Asserts that `actual` parameter is not usable for mathematical operations. That
|
|
||||||
is, the `actual` parameter is either positive infinity or negative infinity or
|
|
||||||
Not A Number floating point representations.
|
|
||||||
|
|
||||||
|
|
||||||
### Double (If enabled)
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_DOUBLE_WITHIN (delta, expected, actual)`
|
|
||||||
|
|
||||||
Asserts that the `actual` value is within +/- `delta` of the `expected` value.
|
|
||||||
The nature of floating point representation is such that exact evaluations of
|
|
||||||
equality are not guaranteed.
|
|
||||||
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_EQUAL_DOUBLE (expected, actual)`
|
|
||||||
|
|
||||||
Asserts that the `actual` value is "close enough to be considered equal" to the
|
|
||||||
`expected` value. If you are curious about the details, refer to the Advanced
|
|
||||||
Asserting section for more details. Omitting a user-specified delta in a
|
|
||||||
floating point assertion is both a shorthand convenience and a requirement of
|
|
||||||
code generation conventions for CMock.
|
|
||||||
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_EQUAL_DOUBLE_ARRAY (expected, actual, num_elements)`
|
|
||||||
|
|
||||||
See Array assertion section for details. Note that individual array element
|
|
||||||
double comparisons are executed using `TEST_ASSERT_EQUAL_DOUBLE`.That is, user
|
|
||||||
specified delta comparison values requires a custom implemented double array
|
|
||||||
assertion.
|
|
||||||
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_DOUBLE_IS_INF (actual)`
|
|
||||||
|
|
||||||
Asserts that `actual` parameter is equivalent to positive infinity floating
|
|
||||||
point representation.
|
|
||||||
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_DOUBLE_IS_NEG_INF (actual)`
|
|
||||||
|
|
||||||
Asserts that `actual` parameter is equivalent to negative infinity floating point
|
|
||||||
representation.
|
|
||||||
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_DOUBLE_IS_NAN (actual)`
|
|
||||||
|
|
||||||
Asserts that `actual` parameter is a Not A Number floating point representation.
|
|
||||||
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_DOUBLE_IS_DETERMINATE (actual)`
|
|
||||||
|
|
||||||
Asserts that `actual` parameter is a floating point representation usable for
|
|
||||||
mathematical operations. That is, the ?actual?parameter is neither positive
|
|
||||||
infinity nor negative infinity nor Not A Number floating point representations.
|
|
||||||
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_DOUBLE_IS_NOT_INF (actual)`
|
|
||||||
|
|
||||||
Asserts that `actual` parameter is a value other than positive infinity floating
|
|
||||||
point representation.
|
|
||||||
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF (actual)`
|
|
||||||
|
|
||||||
Asserts that `actual` parameter is a value other than negative infinity floating
|
|
||||||
point representation.
|
|
||||||
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_DOUBLE_IS_NOT_NAN (actual)`
|
|
||||||
|
|
||||||
Asserts that `actual` parameter is a value other than Not A Number floating
|
|
||||||
point representation.
|
|
||||||
|
|
||||||
|
|
||||||
##### `TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE (actual)`
|
|
||||||
|
|
||||||
Asserts that `actual` parameter is not usable for mathematical operations. That
|
|
||||||
is, the `actual` parameter is either positive infinity or negative infinity or
|
|
||||||
Not A Number floating point representations.
|
|
||||||
|
|
||||||
|
|
||||||
## Advanced Asserting: Details On Tricky Assertions
|
|
||||||
|
|
||||||
This section helps you understand how to deal with some of the trickier
|
|
||||||
assertion situations you may run into. It will give you a glimpse into some of
|
|
||||||
the under-the-hood details of Unity's assertion mechanisms. If you're one of
|
|
||||||
those people who likes to know what is going on in the background, read on. If
|
|
||||||
not, feel free to ignore the rest of this document until you need it.
|
|
||||||
|
|
||||||
|
|
||||||
### How do the EQUAL assertions work for FLOAT and DOUBLE?
|
|
||||||
|
|
||||||
As you may know, directly checking for equality between a pair of floats or a
|
|
||||||
pair of doubles is sloppy at best and an outright no-no at worst. Floating point
|
|
||||||
values can often be represented in multiple ways, particularly after a series of
|
|
||||||
operations on a value. Initializing a variable to the value of 2.0 is likely to
|
|
||||||
result in a floating point representation of 2 x 20,but a series of
|
|
||||||
mathematical operations might result in a representation of 8 x 2-2
|
|
||||||
that also evaluates to a value of 2. At some point repeated operations cause
|
|
||||||
equality checks to fail.
|
|
||||||
|
|
||||||
So Unity doesn't do direct floating point comparisons for equality. Instead, it
|
|
||||||
checks if two floating point values are "really close." If you leave Unity
|
|
||||||
running with defaults, "really close" means "within a significant bit or two."
|
|
||||||
Under the hood, `TEST_ASSERT_EQUAL_FLOAT` is really `TEST_ASSERT_FLOAT_WITHIN`
|
|
||||||
with the `delta` parameter calculated on the fly. For single precision, delta is
|
|
||||||
the expected value multiplied by 0.00001, producing a very small proportional
|
|
||||||
range around the expected value.
|
|
||||||
|
|
||||||
If you are expecting a value of 20,000.0 the delta is calculated to be 0.2. So
|
|
||||||
any value between 19,999.8 and 20,000.2 will satisfy the equality check. This
|
|
||||||
works out to be roughly a single bit of range for a single-precision number, and
|
|
||||||
that's just about as tight a tolerance as you can reasonably get from a floating
|
|
||||||
point value.
|
|
||||||
|
|
||||||
So what happens when it's zero? Zero - even more than other floating point
|
|
||||||
values - can be represented many different ways. It doesn't matter if you have
|
|
||||||
0 x 20 or 0 x 263.It's still zero, right? Luckily, if you
|
|
||||||
subtract these values from each other, they will always produce a difference of
|
|
||||||
zero, which will still fall between 0 plus or minus a delta of 0. So it still
|
|
||||||
works!
|
|
||||||
|
|
||||||
Double precision floating point numbers use a much smaller multiplier, again
|
|
||||||
approximating a single bit of error.
|
|
||||||
|
|
||||||
If you don't like these ranges and you want to make your floating point equality
|
|
||||||
assertions less strict, you can change these multipliers to whatever you like by
|
|
||||||
defining UNITY_FLOAT_PRECISION and UNITY_DOUBLE_PRECISION. See Unity
|
|
||||||
documentation for more.
|
|
||||||
|
|
||||||
|
|
||||||
### How do we deal with targets with non-standard int sizes?
|
|
||||||
|
|
||||||
It's "fun" that C is a standard where something as fundamental as an integer
|
|
||||||
varies by target. According to the C standard, an `int` is to be the target's
|
|
||||||
natural register size, and it should be at least 16-bits and a multiple of a
|
|
||||||
byte. It also guarantees an order of sizes:
|
|
||||||
|
|
||||||
```C
|
|
||||||
char <= short <= int <= long <= long long
|
|
||||||
```
|
|
||||||
|
|
||||||
Most often, `int` is 32-bits. In many cases in the embedded world, `int` is
|
|
||||||
16-bits. There are rare microcontrollers out there that have 24-bit integers,
|
|
||||||
and this remains perfectly standard C.
|
|
||||||
|
|
||||||
To make things even more interesting, there are compilers and targets out there
|
|
||||||
that have a hard choice to make. What if their natural register size is 10-bits
|
|
||||||
or 12-bits? Clearly they can't fulfill _both_ the requirement to be at least
|
|
||||||
16-bits AND the requirement to match the natural register size. In these
|
|
||||||
situations, they often choose the natural register size, leaving us with
|
|
||||||
something like this:
|
|
||||||
|
|
||||||
```C
|
|
||||||
char (8 bit) <= short (12 bit) <= int (12 bit) <= long (16 bit)
|
|
||||||
```
|
|
||||||
|
|
||||||
Um... yikes. It's obviously breaking a rule or two... but they had to break SOME
|
|
||||||
rules, so they made a choice.
|
|
||||||
|
|
||||||
When the C99 standard rolled around, it introduced alternate standard-size types.
|
|
||||||
It also introduced macros for pulling in MIN/MAX values for your integer types.
|
|
||||||
It's glorious! Unfortunately, many embedded compilers can't be relied upon to
|
|
||||||
use the C99 types (Sometimes because they have weird register sizes as described
|
|
||||||
above. Sometimes because they don't feel like it?).
|
|
||||||
|
|
||||||
A goal of Unity from the beginning was to support every combination of
|
|
||||||
microcontroller or microprocessor and C compiler. Over time, we've gotten really
|
|
||||||
close to this. There are a few tricks that you should be aware of, though, if
|
|
||||||
you're going to do this effectively on some of these more idiosyncratic targets.
|
|
||||||
|
|
||||||
First, when setting up Unity for a new target, you're going to want to pay
|
|
||||||
special attention to the macros for automatically detecting types
|
|
||||||
(where available) or manually configuring them yourself. You can get information
|
|
||||||
on both of these in Unity's documentation.
|
|
||||||
|
|
||||||
What about the times where you suddenly need to deal with something odd, like a
|
|
||||||
24-bit `int`? The simplest solution is to use the next size up. If you have a
|
|
||||||
24-bit `int`, configure Unity to use 32-bit integers. If you have a 12-bit
|
|
||||||
`int`, configure Unity to use 16 bits. There are two ways this is going to
|
|
||||||
affect you:
|
|
||||||
|
|
||||||
1. When Unity displays errors for you, it's going to pad the upper unused bits
|
|
||||||
with zeros.
|
|
||||||
2. You're going to have to be careful of assertions that perform signed
|
|
||||||
operations, particularly `TEST_ASSERT_INT_WITHIN`.Such assertions might wrap
|
|
||||||
your `int` in the wrong place, and you could experience false failures. You can
|
|
||||||
always back down to a simple `TEST_ASSERT` and do the operations yourself.
|
|
||||||
|
|
||||||
|
|
||||||
*Find The Latest of This And More at [ThrowTheSwitch.org](https://throwtheswitch.org)*
|
|
433
test/vendor/ceedling/docs/UnityConfigurationGuide.md
vendored
433
test/vendor/ceedling/docs/UnityConfigurationGuide.md
vendored
@ -1,433 +0,0 @@
|
|||||||
# Unity Configuration Guide
|
|
||||||
|
|
||||||
## C Standards, Compilers and Microcontrollers
|
|
||||||
|
|
||||||
The embedded software world contains its challenges. Compilers support different
|
|
||||||
revisions of the C Standard. They ignore requirements in places, sometimes to
|
|
||||||
make the language more usable in some special regard. Sometimes it's to simplify
|
|
||||||
their support. Sometimes it's due to specific quirks of the microcontroller they
|
|
||||||
are targeting. Simulators add another dimension to this menagerie.
|
|
||||||
|
|
||||||
Unity is designed to run on almost anything that is targeted by a C compiler. It
|
|
||||||
would be awesome if this could be done with zero configuration. While there are
|
|
||||||
some targets that come close to this dream, it is sadly not universal. It is
|
|
||||||
likely that you are going to need at least a couple of the configuration options
|
|
||||||
described in this document.
|
|
||||||
|
|
||||||
All of Unity's configuration options are `#defines`. Most of these are simple
|
|
||||||
definitions. A couple are macros with arguments. They live inside the
|
|
||||||
unity_internals.h header file. We don't necessarily recommend opening that file
|
|
||||||
unless you really need to. That file is proof that a cross-platform library is
|
|
||||||
challenging to build. From a more positive perspective, it is also proof that a
|
|
||||||
great deal of complexity can be centralized primarily to one place to
|
|
||||||
provide a more consistent and simple experience elsewhere.
|
|
||||||
|
|
||||||
|
|
||||||
### Using These Options
|
|
||||||
|
|
||||||
It doesn't matter if you're using a target-specific compiler and a simulator or
|
|
||||||
a native compiler. In either case, you've got a couple choices for configuring
|
|
||||||
these options:
|
|
||||||
|
|
||||||
1. Because these options are specified via C defines, you can pass most of these
|
|
||||||
options to your compiler through command line compiler flags. Even if you're
|
|
||||||
using an embedded target that forces you to use their overbearing IDE for all
|
|
||||||
configuration, there will be a place somewhere in your project to configure
|
|
||||||
defines for your compiler.
|
|
||||||
2. You can create a custom `unity_config.h` configuration file (present in your
|
|
||||||
toolchain's search paths). In this file, you will list definitions and macros
|
|
||||||
specific to your target. All you must do is define `UNITY_INCLUDE_CONFIG_H` and
|
|
||||||
Unity will rely on `unity_config.h` for any further definitions it may need.
|
|
||||||
|
|
||||||
|
|
||||||
## The Options
|
|
||||||
|
|
||||||
### Integer Types
|
|
||||||
|
|
||||||
If you've been a C developer for long, you probably already know that C's
|
|
||||||
concept of an integer varies from target to target. The C Standard has rules
|
|
||||||
about the `int` matching the register size of the target microprocessor. It has
|
|
||||||
rules about the `int` and how its size relates to other integer types. An `int`
|
|
||||||
on one target might be 16 bits while on another target it might be 64. There are
|
|
||||||
more specific types in compilers compliant with C99 or later, but that's
|
|
||||||
certainly not every compiler you are likely to encounter. Therefore, Unity has a
|
|
||||||
number of features for helping to adjust itself to match your required integer
|
|
||||||
sizes. It starts off by trying to do it automatically.
|
|
||||||
|
|
||||||
|
|
||||||
##### `UNITY_EXCLUDE_STDINT_H`
|
|
||||||
|
|
||||||
The first thing that Unity does to guess your types is check `stdint.h`.
|
|
||||||
This file includes defines like `UINT_MAX` that Unity can use to
|
|
||||||
learn a lot about your system. It's possible you don't want it to do this
|
|
||||||
(um. why not?) or (more likely) it's possible that your system doesn't
|
|
||||||
support `stdint.h`. If that's the case, you're going to want to define this.
|
|
||||||
That way, Unity will know to skip the inclusion of this file and you won't
|
|
||||||
be left with a compiler error.
|
|
||||||
|
|
||||||
_Example:_
|
|
||||||
#define UNITY_EXCLUDE_STDINT_H
|
|
||||||
|
|
||||||
|
|
||||||
##### `UNITY_EXCLUDE_LIMITS_H`
|
|
||||||
|
|
||||||
The second attempt to guess your types is to check `limits.h`. Some compilers
|
|
||||||
that don't support `stdint.h` could include `limits.h` instead. If you don't
|
|
||||||
want Unity to check this file either, define this to make it skip the inclusion.
|
|
||||||
|
|
||||||
_Example:_
|
|
||||||
#define UNITY_EXCLUDE_LIMITS_H
|
|
||||||
|
|
||||||
|
|
||||||
If you've disabled both of the automatic options above, you're going to have to
|
|
||||||
do the configuration yourself. Don't worry. Even this isn't too bad... there are
|
|
||||||
just a handful of defines that you are going to specify if you don't like the
|
|
||||||
defaults.
|
|
||||||
|
|
||||||
|
|
||||||
##### `UNITY_INT_WIDTH`
|
|
||||||
|
|
||||||
Define this to be the number of bits an `int` takes up on your system. The
|
|
||||||
default, if not autodetected, is 32 bits.
|
|
||||||
|
|
||||||
_Example:_
|
|
||||||
#define UNITY_INT_WIDTH 16
|
|
||||||
|
|
||||||
|
|
||||||
##### `UNITY_LONG_WIDTH`
|
|
||||||
|
|
||||||
Define this to be the number of bits a `long` takes up on your system. The
|
|
||||||
default, if not autodetected, is 32 bits. This is used to figure out what kind
|
|
||||||
of 64-bit support your system can handle. Does it need to specify a `long` or a
|
|
||||||
`long long` to get a 64-bit value. On 16-bit systems, this option is going to be
|
|
||||||
ignored.
|
|
||||||
|
|
||||||
_Example:_
|
|
||||||
#define UNITY_LONG_WIDTH 16
|
|
||||||
|
|
||||||
|
|
||||||
##### `UNITY_POINTER_WIDTH`
|
|
||||||
|
|
||||||
Define this to be the number of bits a pointer takes up on your system. The
|
|
||||||
default, if not autodetected, is 32-bits. If you're getting ugly compiler
|
|
||||||
warnings about casting from pointers, this is the one to look at.
|
|
||||||
|
|
||||||
_Example:_
|
|
||||||
#define UNITY_POINTER_WIDTH 64
|
|
||||||
|
|
||||||
|
|
||||||
##### `UNITY_SUPPORT_64`
|
|
||||||
|
|
||||||
Unity will automatically include 64-bit support if it auto-detects it, or if
|
|
||||||
your `int`, `long`, or pointer widths are greater than 32-bits. Define this to
|
|
||||||
enable 64-bit support if none of the other options already did it for you. There
|
|
||||||
can be a significant size and speed impact to enabling 64-bit support on small
|
|
||||||
targets, so don't define it if you don't need it.
|
|
||||||
|
|
||||||
_Example:_
|
|
||||||
#define UNITY_SUPPORT_64
|
|
||||||
|
|
||||||
|
|
||||||
### Floating Point Types
|
|
||||||
|
|
||||||
In the embedded world, it's not uncommon for targets to have no support for
|
|
||||||
floating point operations at all or to have support that is limited to only
|
|
||||||
single precision. We are able to guess integer sizes on the fly because integers
|
|
||||||
are always available in at least one size. Floating point, on the other hand, is
|
|
||||||
sometimes not available at all. Trying to include `float.h` on these platforms
|
|
||||||
would result in an error. This leaves manual configuration as the only option.
|
|
||||||
|
|
||||||
|
|
||||||
##### `UNITY_INCLUDE_FLOAT`
|
|
||||||
|
|
||||||
##### `UNITY_EXCLUDE_FLOAT`
|
|
||||||
|
|
||||||
##### `UNITY_INCLUDE_DOUBLE`
|
|
||||||
|
|
||||||
##### `UNITY_EXCLUDE_DOUBLE`
|
|
||||||
|
|
||||||
By default, Unity guesses that you will want single precision floating point
|
|
||||||
support, but not double precision. It's easy to change either of these using the
|
|
||||||
include and exclude options here. You may include neither, either, or both, as
|
|
||||||
suits your needs. For features that are enabled, the following floating point
|
|
||||||
options also become available.
|
|
||||||
|
|
||||||
_Example:_
|
|
||||||
|
|
||||||
//what manner of strange processor is this?
|
|
||||||
#define UNITY_EXCLUDE_FLOAT
|
|
||||||
#define UNITY_INCLUDE_DOUBLE
|
|
||||||
|
|
||||||
|
|
||||||
##### `UNITY_EXCLUDE_FLOAT_PRINT`
|
|
||||||
|
|
||||||
Unity aims for as small of a footprint as possible and avoids most standard
|
|
||||||
library calls (some embedded platforms don’t have a standard library!). Because
|
|
||||||
of this, its routines for printing integer values are minimalist and hand-coded.
|
|
||||||
Therefore, the display of floating point values during a failure are optional.
|
|
||||||
By default, Unity will print the actual results of floating point assertion
|
|
||||||
failure (e.g. ”Expected 4.56 Was 4.68”). To not include this extra support, you
|
|
||||||
can use this define to instead respond to a failed assertion with a message like
|
|
||||||
”Values Not Within Delta”. If you would like verbose failure messages for floating
|
|
||||||
point assertions, use these options to give more explicit failure messages.
|
|
||||||
|
|
||||||
_Example:_
|
|
||||||
#define UNITY_EXCLUDE_FLOAT_PRINT
|
|
||||||
|
|
||||||
|
|
||||||
##### `UNITY_FLOAT_TYPE`
|
|
||||||
|
|
||||||
If enabled, Unity assumes you want your `FLOAT` asserts to compare standard C
|
|
||||||
floats. If your compiler supports a specialty floating point type, you can
|
|
||||||
always override this behavior by using this definition.
|
|
||||||
|
|
||||||
_Example:_
|
|
||||||
#define UNITY_FLOAT_TYPE float16_t
|
|
||||||
|
|
||||||
|
|
||||||
##### `UNITY_DOUBLE_TYPE`
|
|
||||||
|
|
||||||
If enabled, Unity assumes you want your `DOUBLE` asserts to compare standard C
|
|
||||||
doubles. If you would like to change this, you can specify something else by
|
|
||||||
using this option. For example, defining `UNITY_DOUBLE_TYPE` to `long double`
|
|
||||||
could enable gargantuan floating point types on your 64-bit processor instead of
|
|
||||||
the standard `double`.
|
|
||||||
|
|
||||||
_Example:_
|
|
||||||
#define UNITY_DOUBLE_TYPE long double
|
|
||||||
|
|
||||||
|
|
||||||
##### `UNITY_FLOAT_PRECISION`
|
|
||||||
|
|
||||||
##### `UNITY_DOUBLE_PRECISION`
|
|
||||||
|
|
||||||
If you look up `UNITY_ASSERT_EQUAL_FLOAT` and `UNITY_ASSERT_EQUAL_DOUBLE` as
|
|
||||||
documented in the big daddy Unity Assertion Guide, you will learn that they are
|
|
||||||
not really asserting that two values are equal but rather that two values are
|
|
||||||
"close enough" to equal. "Close enough" is controlled by these precision
|
|
||||||
configuration options. If you are working with 32-bit floats and/or 64-bit
|
|
||||||
doubles (the normal on most processors), you should have no need to change these
|
|
||||||
options. They are both set to give you approximately 1 significant bit in either
|
|
||||||
direction. The float precision is 0.00001 while the double is 10-12.
|
|
||||||
For further details on how this works, see the appendix of the Unity Assertion
|
|
||||||
Guide.
|
|
||||||
|
|
||||||
_Example:_
|
|
||||||
#define UNITY_FLOAT_PRECISION 0.001f
|
|
||||||
|
|
||||||
|
|
||||||
### Toolset Customization
|
|
||||||
|
|
||||||
In addition to the options listed above, there are a number of other options
|
|
||||||
which will come in handy to customize Unity's behavior for your specific
|
|
||||||
toolchain. It is possible that you may not need to touch any of these... but
|
|
||||||
certain platforms, particularly those running in simulators, may need to jump
|
|
||||||
through extra hoops to run properly. These macros will help in those
|
|
||||||
situations.
|
|
||||||
|
|
||||||
|
|
||||||
##### `UNITY_OUTPUT_CHAR(a)`
|
|
||||||
|
|
||||||
##### `UNITY_OUTPUT_FLUSH()`
|
|
||||||
|
|
||||||
##### `UNITY_OUTPUT_START()`
|
|
||||||
|
|
||||||
##### `UNITY_OUTPUT_COMPLETE()`
|
|
||||||
|
|
||||||
By default, Unity prints its results to `stdout` as it runs. This works
|
|
||||||
perfectly fine in most situations where you are using a native compiler for
|
|
||||||
testing. It works on some simulators as well so long as they have `stdout`
|
|
||||||
routed back to the command line. There are times, however, where the simulator
|
|
||||||
will lack support for dumping results or you will want to route results
|
|
||||||
elsewhere for other reasons. In these cases, you should define the
|
|
||||||
`UNITY_OUTPUT_CHAR` macro. This macro accepts a single character at a time (as
|
|
||||||
an `int`, since this is the parameter type of the standard C `putchar` function
|
|
||||||
most commonly used). You may replace this with whatever function call you like.
|
|
||||||
|
|
||||||
_Example:_
|
|
||||||
Say you are forced to run your test suite on an embedded processor with no
|
|
||||||
`stdout` option. You decide to route your test result output to a custom serial
|
|
||||||
`RS232_putc()` function you wrote like thus:
|
|
||||||
#include "RS232_header.h"
|
|
||||||
...
|
|
||||||
#define UNITY_OUTPUT_CHAR(a) RS232_putc(a)
|
|
||||||
#define UNITY_OUTPUT_START() RS232_config(115200,1,8,0)
|
|
||||||
#define UNITY_OUTPUT_FLUSH() RS232_flush()
|
|
||||||
#define UNITY_OUTPUT_COMPLETE() RS232_close()
|
|
||||||
|
|
||||||
_Note:_
|
|
||||||
`UNITY_OUTPUT_FLUSH()` can be set to the standard out flush function simply by
|
|
||||||
specifying `UNITY_USE_FLUSH_STDOUT`. No other defines are required.
|
|
||||||
|
|
||||||
|
|
||||||
##### `UNITY_WEAK_ATTRIBUTE`
|
|
||||||
|
|
||||||
##### `UNITY_WEAK_PRAGMA`
|
|
||||||
|
|
||||||
##### `UNITY_NO_WEAK`
|
|
||||||
|
|
||||||
For some targets, Unity can make the otherwise required setUp() and tearDown()
|
|
||||||
functions optional. This is a nice convenience for test writers since setUp and
|
|
||||||
tearDown don’t often actually do anything. If you’re using gcc or clang, this
|
|
||||||
option is automatically defined for you. Other compilers can also support this
|
|
||||||
behavior, if they support a C feature called weak functions. A weak function is
|
|
||||||
a function that is compiled into your executable unless a non-weak version of
|
|
||||||
the same function is defined elsewhere. If a non-weak version is found, the weak
|
|
||||||
version is ignored as if it never existed. If your compiler supports this feature,
|
|
||||||
you can let Unity know by defining UNITY_WEAK_ATTRIBUTE or UNITY_WEAK_PRAGMA as
|
|
||||||
the function attributes that would need to be applied to identify a function as
|
|
||||||
weak. If your compiler lacks support for weak functions, you will always need to
|
|
||||||
define setUp and tearDown functions (though they can be and often will be just
|
|
||||||
empty). You can also force Unity to NOT use weak functions by defining
|
|
||||||
UNITY_NO_WEAK. The most common options for this feature are:
|
|
||||||
|
|
||||||
_Example:_
|
|
||||||
#define UNITY_WEAK_ATTRIBUTE weak
|
|
||||||
#define UNITY_WEAK_ATTRIBUTE __attribute__((weak))
|
|
||||||
#define UNITY_WEAK_PRAGMA
|
|
||||||
#define UNITY_NO_WEAK
|
|
||||||
|
|
||||||
|
|
||||||
##### `UNITY_PTR_ATTRIBUTE`
|
|
||||||
|
|
||||||
Some compilers require a custom attribute to be assigned to pointers, like
|
|
||||||
`near` or `far`. In these cases, you can give Unity a safe default for these by
|
|
||||||
defining this option with the attribute you would like.
|
|
||||||
|
|
||||||
_Example:_
|
|
||||||
#define UNITY_PTR_ATTRIBUTE __attribute__((far))
|
|
||||||
#define UNITY_PTR_ATTRIBUTE near
|
|
||||||
|
|
||||||
|
|
||||||
##### `UNITY_PRINT_EOL`
|
|
||||||
|
|
||||||
By default, Unity outputs \n at the end of each line of output. This is easy
|
|
||||||
to parse by the scripts, by Ceedling, etc, but it might not be ideal for YOUR
|
|
||||||
system. Feel free to override this and to make it whatever you wish.
|
|
||||||
|
|
||||||
_Example:_
|
|
||||||
#define UNITY_PRINT_EOL { UNITY_OUTPUT_CHAR('\r'); UNITY_OUTPUT_CHAR('\n') }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
##### `UNITY_EXCLUDE_DETAILS`
|
|
||||||
|
|
||||||
This is an option for if you absolutely must squeeze every byte of memory out of
|
|
||||||
your system. Unity stores a set of internal scratchpads which are used to pass
|
|
||||||
extra detail information around. It's used by systems like CMock in order to
|
|
||||||
report which function or argument flagged an error. If you're not using CMock and
|
|
||||||
you're not using these details for other things, then you can exclude them.
|
|
||||||
|
|
||||||
_Example:_
|
|
||||||
#define UNITY_EXCLUDE_DETAILS
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
##### `UNITY_EXCLUDE_SETJMP`
|
|
||||||
|
|
||||||
If your embedded system doesn't support the standard library setjmp, you can
|
|
||||||
exclude Unity's reliance on this by using this define. This dropped dependence
|
|
||||||
comes at a price, though. You will be unable to use custom helper functions for
|
|
||||||
your tests, and you will be unable to use tools like CMock. Very likely, if your
|
|
||||||
compiler doesn't support setjmp, you wouldn't have had the memory space for those
|
|
||||||
things anyway, though... so this option exists for those situations.
|
|
||||||
|
|
||||||
_Example:_
|
|
||||||
#define UNITY_EXCLUDE_SETJMP
|
|
||||||
|
|
||||||
##### `UNITY_OUTPUT_COLOR`
|
|
||||||
|
|
||||||
If you want to add color using ANSI escape codes you can use this define.
|
|
||||||
t
|
|
||||||
_Example:_
|
|
||||||
#define UNITY_OUTPUT_COLOR
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Getting Into The Guts
|
|
||||||
|
|
||||||
There will be cases where the options above aren't quite going to get everything
|
|
||||||
perfect. They are likely sufficient for any situation where you are compiling
|
|
||||||
and executing your tests with a native toolchain (e.g. clang on Mac). These
|
|
||||||
options may even get you through the majority of cases encountered in working
|
|
||||||
with a target simulator run from your local command line. But especially if you
|
|
||||||
must run your test suite on your target hardware, your Unity configuration will
|
|
||||||
require special help. This special help will usually reside in one of two
|
|
||||||
places: the `main()` function or the `RUN_TEST` macro. Let's look at how these
|
|
||||||
work.
|
|
||||||
|
|
||||||
|
|
||||||
##### `main()`
|
|
||||||
|
|
||||||
Each test module is compiled and run on its own, separate from the other test
|
|
||||||
files in your project. Each test file, therefore, has a `main` function. This
|
|
||||||
`main` function will need to contain whatever code is necessary to initialize
|
|
||||||
your system to a workable state. This is particularly true for situations where
|
|
||||||
you must set up a memory map or initialize a communication channel for the
|
|
||||||
output of your test results.
|
|
||||||
|
|
||||||
A simple main function looks something like this:
|
|
||||||
|
|
||||||
int main(void) {
|
|
||||||
UNITY_BEGIN();
|
|
||||||
RUN_TEST(test_TheFirst);
|
|
||||||
RUN_TEST(test_TheSecond);
|
|
||||||
RUN_TEST(test_TheThird);
|
|
||||||
return UNITY_END();
|
|
||||||
}
|
|
||||||
|
|
||||||
You can see that our main function doesn't bother taking any arguments. For our
|
|
||||||
most barebones case, we'll never have arguments because we just run all the
|
|
||||||
tests each time. Instead, we start by calling `UNITY_BEGIN`. We run each test
|
|
||||||
(in whatever order we wish). Finally, we call `UNITY_END`, returning its return
|
|
||||||
value (which is the total number of failures).
|
|
||||||
|
|
||||||
It should be easy to see that you can add code before any test cases are run or
|
|
||||||
after all the test cases have completed. This allows you to do any needed
|
|
||||||
system-wide setup or teardown that might be required for your special
|
|
||||||
circumstances.
|
|
||||||
|
|
||||||
|
|
||||||
##### `RUN_TEST`
|
|
||||||
|
|
||||||
The `RUN_TEST` macro is called with each test case function. Its job is to
|
|
||||||
perform whatever setup and teardown is necessary for executing a single test
|
|
||||||
case function. This includes catching failures, calling the test module's
|
|
||||||
`setUp()` and `tearDown()` functions, and calling `UnityConcludeTest()`. If
|
|
||||||
using CMock or test coverage, there will be additional stubs in use here. A
|
|
||||||
simple minimalist RUN_TEST macro looks something like this:
|
|
||||||
|
|
||||||
#define RUN_TEST(testfunc) \
|
|
||||||
UNITY_NEW_TEST(#testfunc) \
|
|
||||||
if (TEST_PROTECT()) { \
|
|
||||||
setUp(); \
|
|
||||||
testfunc(); \
|
|
||||||
} \
|
|
||||||
if (TEST_PROTECT() && (!TEST_IS_IGNORED)) \
|
|
||||||
tearDown(); \
|
|
||||||
UnityConcludeTest();
|
|
||||||
|
|
||||||
So that's quite a macro, huh? It gives you a glimpse of what kind of stuff Unity
|
|
||||||
has to deal with for every single test case. For each test case, we declare that
|
|
||||||
it is a new test. Then we run `setUp` and our test function. These are run
|
|
||||||
within a `TEST_PROTECT` block, the function of which is to handle failures that
|
|
||||||
occur during the test. Then, assuming our test is still running and hasn't been
|
|
||||||
ignored, we run `tearDown`. No matter what, our last step is to conclude this
|
|
||||||
test before moving on to the next.
|
|
||||||
|
|
||||||
Let's say you need to add a call to `fsync` to force all of your output data to
|
|
||||||
flush to a file after each test. You could easily insert this after your
|
|
||||||
`UnityConcludeTest` call. Maybe you want to write an xml tag before and after
|
|
||||||
each result set. Again, you could do this by adding lines to this macro. Updates
|
|
||||||
to this macro are for the occasions when you need an action before or after
|
|
||||||
every single test case throughout your entire suite of tests.
|
|
||||||
|
|
||||||
|
|
||||||
## Happy Porting
|
|
||||||
|
|
||||||
The defines and macros in this guide should help you port Unity to just about
|
|
||||||
any C target we can imagine. If you run into a snag or two, don't be afraid of
|
|
||||||
asking for help on the forums. We love a good challenge!
|
|
||||||
|
|
||||||
|
|
||||||
*Find The Latest of This And More at [ThrowTheSwitch.org](https://throwtheswitch.org)*
|
|
@ -1,192 +0,0 @@
|
|||||||
# Unity - Getting Started
|
|
||||||
|
|
||||||
## Welcome
|
|
||||||
|
|
||||||
Congratulations. You're now the proud owner of your very own pile of bits! What
|
|
||||||
are you going to do with all these ones and zeros? This document should be able
|
|
||||||
to help you decide just that.
|
|
||||||
|
|
||||||
Unity is a unit test framework. The goal has been to keep it small and
|
|
||||||
functional. The core Unity test framework is three files: a single C file and a
|
|
||||||
couple header files. These team up to provide functions and macros to make
|
|
||||||
testing easier.
|
|
||||||
|
|
||||||
Unity was designed to be cross-platform. It works hard to stick with C standards
|
|
||||||
while still providing support for the many embedded C compilers that bend the
|
|
||||||
rules. Unity has been used with many compilers, including GCC, IAR, Clang,
|
|
||||||
Green Hills, Microchip, and MS Visual Studio. It's not much work to get it to
|
|
||||||
work with a new target.
|
|
||||||
|
|
||||||
|
|
||||||
### Overview of the Documents
|
|
||||||
|
|
||||||
#### Unity Assertions reference
|
|
||||||
|
|
||||||
This document will guide you through all the assertion options provided by
|
|
||||||
Unity. This is going to be your unit testing bread and butter. You'll spend more
|
|
||||||
time with assertions than any other part of Unity.
|
|
||||||
|
|
||||||
|
|
||||||
#### Unity Assertions Cheat Sheet
|
|
||||||
|
|
||||||
This document contains an abridged summary of the assertions described in the
|
|
||||||
previous document. It's perfect for printing and referencing while you
|
|
||||||
familiarize yourself with Unity's options.
|
|
||||||
|
|
||||||
|
|
||||||
#### Unity Configuration Guide
|
|
||||||
|
|
||||||
This document is the one to reference when you are going to use Unity with a new
|
|
||||||
target or compiler. It'll guide you through the configuration options and will
|
|
||||||
help you customize your testing experience to meet your needs.
|
|
||||||
|
|
||||||
|
|
||||||
#### Unity Helper Scripts
|
|
||||||
|
|
||||||
This document describes the helper scripts that are available for simplifying
|
|
||||||
your testing workflow. It describes the collection of optional Ruby scripts
|
|
||||||
included in the auto directory of your Unity installation. Neither Ruby nor
|
|
||||||
these scripts are necessary for using Unity. They are provided as a convenience
|
|
||||||
for those who wish to use them.
|
|
||||||
|
|
||||||
|
|
||||||
#### Unity License
|
|
||||||
|
|
||||||
What's an open source project without a license file? This brief document
|
|
||||||
describes the terms you're agreeing to when you use this software. Basically, we
|
|
||||||
want it to be useful to you in whatever context you want to use it, but please
|
|
||||||
don't blame us if you run into problems.
|
|
||||||
|
|
||||||
|
|
||||||
### Overview of the Folders
|
|
||||||
|
|
||||||
If you have obtained Unity through Github or something similar, you might be
|
|
||||||
surprised by just how much stuff you suddenly have staring you in the face.
|
|
||||||
Don't worry, Unity itself is very small. The rest of it is just there to make
|
|
||||||
your life easier. You can ignore it or use it at your convenience. Here's an
|
|
||||||
overview of everything in the project.
|
|
||||||
|
|
||||||
- `src` - This is the code you care about! This folder contains a C file and two
|
|
||||||
header files. These three files _are_ Unity.
|
|
||||||
- `docs` - You're reading this document, so it's possible you have found your way
|
|
||||||
into this folder already. This is where all the handy documentation can be
|
|
||||||
found.
|
|
||||||
- `examples` - This contains a few examples of using Unity.
|
|
||||||
- `extras` - These are optional add ons to Unity that are not part of the core
|
|
||||||
project. If you've reached us through James Grenning's book, you're going to
|
|
||||||
want to look here.
|
|
||||||
- `test` - This is how Unity and its scripts are all tested. If you're just using
|
|
||||||
Unity, you'll likely never need to go in here. If you are the lucky team member
|
|
||||||
who gets to port Unity to a new toolchain, this is a good place to verify
|
|
||||||
everything is configured properly.
|
|
||||||
- `auto` - Here you will find helpful Ruby scripts for simplifying your test
|
|
||||||
workflow. They are purely optional and are not required to make use of Unity.
|
|
||||||
|
|
||||||
|
|
||||||
## How to Create A Test File
|
|
||||||
|
|
||||||
Test files are C files. Most often you will create a single test file for each C
|
|
||||||
module that you want to test. The test file should include unity.h and the
|
|
||||||
header for your C module to be tested.
|
|
||||||
|
|
||||||
Next, a test file will include a `setUp()` and `tearDown()` function. The setUp
|
|
||||||
function can contain anything you would like to run before each test. The
|
|
||||||
tearDown function can contain anything you would like to run after each test.
|
|
||||||
Both functions accept no arguments and return nothing. You may leave either or
|
|
||||||
both of these blank if you have no need for them. If you're using a compiler
|
|
||||||
that is configured to make these functions optional, you may leave them off
|
|
||||||
completely. Not sure? Give it a try. If you compiler complains that it can't
|
|
||||||
find setUp or tearDown when it links, you'll know you need to at least include
|
|
||||||
an empty function for these.
|
|
||||||
|
|
||||||
The majority of the file will be a series of test functions. Test functions
|
|
||||||
follow the convention of starting with the word "test_" or "spec_". You don't HAVE
|
|
||||||
to name them this way, but it makes it clear what functions are tests for other
|
|
||||||
developers. Also, the automated scripts that come with Unity or Ceedling will default
|
|
||||||
to looking for test functions to be prefixed this way. Test functions take no arguments
|
|
||||||
and return nothing. All test accounting is handled internally in Unity.
|
|
||||||
|
|
||||||
Finally, at the bottom of your test file, you will write a `main()` function.
|
|
||||||
This function will call `UNITY_BEGIN()`, then `RUN_TEST` for each test, and
|
|
||||||
finally `UNITY_END()`.This is what will actually trigger each of those test
|
|
||||||
functions to run, so it is important that each function gets its own `RUN_TEST`
|
|
||||||
call.
|
|
||||||
|
|
||||||
Remembering to add each test to the main function can get to be tedious. If you
|
|
||||||
enjoy using helper scripts in your build process, you might consider making use
|
|
||||||
of our handy generate_test_runner.rb script. This will create the main function
|
|
||||||
and all the calls for you, assuming that you have followed the suggested naming
|
|
||||||
conventions. In this case, there is no need for you to include the main function
|
|
||||||
in your test file at all.
|
|
||||||
|
|
||||||
When you're done, your test file will look something like this:
|
|
||||||
|
|
||||||
```C
|
|
||||||
#include "unity.h"
|
|
||||||
#include "file_to_test.h"
|
|
||||||
|
|
||||||
void setUp(void) {
|
|
||||||
// set stuff up here
|
|
||||||
}
|
|
||||||
|
|
||||||
void tearDown(void) {
|
|
||||||
// clean stuff up here
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_function_should_doBlahAndBlah(void) {
|
|
||||||
//test stuff
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_function_should_doAlsoDoBlah(void) {
|
|
||||||
//more test stuff
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(void) {
|
|
||||||
UNITY_BEGIN();
|
|
||||||
RUN_TEST(test_function_should_doBlahAndBlah);
|
|
||||||
RUN_TEST(test_function_should_doAlsoDoBlah);
|
|
||||||
return UNITY_END();
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
It's possible that you will need more customization than this, eventually.
|
|
||||||
For that sort of thing, you're going to want to look at the configuration guide.
|
|
||||||
This should be enough to get you going, though.
|
|
||||||
|
|
||||||
|
|
||||||
## How to Build and Run A Test File
|
|
||||||
|
|
||||||
This is the single biggest challenge to picking up a new unit testing framework,
|
|
||||||
at least in a language like C or C++. These languages are REALLY good at getting
|
|
||||||
you "close to the metal" (why is the phrase metal? Wouldn't it be more accurate
|
|
||||||
to say "close to the silicon"?). While this feature is usually a good thing, it
|
|
||||||
can make testing more challenging.
|
|
||||||
|
|
||||||
You have two really good options for toolchains. Depending on where you're
|
|
||||||
coming from, it might surprise you that neither of these options is running the
|
|
||||||
unit tests on your hardware.
|
|
||||||
There are many reasons for this, but here's a short version:
|
|
||||||
- On hardware, you have too many constraints (processing power, memory, etc),
|
|
||||||
- On hardware, you don't have complete control over all registers,
|
|
||||||
- On hardware, unit testing is more challenging,
|
|
||||||
- Unit testing isn't System testing. Keep them separate.
|
|
||||||
|
|
||||||
Instead of running your tests on your actual hardware, most developers choose to
|
|
||||||
develop them as native applications (using gcc or MSVC for example) or as
|
|
||||||
applications running on a simulator. Either is a good option. Native apps have
|
|
||||||
the advantages of being faster and easier to set up. Simulator apps have the
|
|
||||||
advantage of working with the same compiler as your target application. The
|
|
||||||
options for configuring these are discussed in the configuration guide.
|
|
||||||
|
|
||||||
To get either to work, you might need to make a few changes to the file
|
|
||||||
containing your register set (discussed later).
|
|
||||||
|
|
||||||
In either case, a test is built by linking unity, the test file, and the C
|
|
||||||
file(s) being tested. These files create an executable which can be run as the
|
|
||||||
test set for that module. Then, this process is repeated for the next test file.
|
|
||||||
This flexibility of separating tests into individual executables allows us to
|
|
||||||
much more thoroughly unit test our system and it keeps all the test code out of
|
|
||||||
our final release!
|
|
||||||
|
|
||||||
|
|
||||||
*Find The Latest of This And More at [ThrowTheSwitch.org](https://throwtheswitch.org)*
|
|
260
test/vendor/ceedling/docs/UnityHelperScriptsGuide.md
vendored
260
test/vendor/ceedling/docs/UnityHelperScriptsGuide.md
vendored
@ -1,260 +0,0 @@
|
|||||||
# Unity Helper Scripts
|
|
||||||
|
|
||||||
## With a Little Help From Our Friends
|
|
||||||
|
|
||||||
Sometimes what it takes to be a really efficient C programmer is a little non-C.
|
|
||||||
The Unity project includes a couple of Ruby scripts for making your life just a tad
|
|
||||||
easier. They are completely optional. If you choose to use them, you'll need a
|
|
||||||
copy of Ruby, of course. Just install whatever the latest version is, and it is
|
|
||||||
likely to work. You can find Ruby at [ruby-lang.org](https://ruby-labg.org/).
|
|
||||||
|
|
||||||
|
|
||||||
### `generate_test_runner.rb`
|
|
||||||
|
|
||||||
Are you tired of creating your own `main` function in your test file? Do you
|
|
||||||
keep forgetting to add a `RUN_TEST` call when you add a new test case to your
|
|
||||||
suite? Do you want to use CMock or other fancy add-ons but don't want to figure
|
|
||||||
out how to create your own `RUN_TEST` macro?
|
|
||||||
|
|
||||||
Well then we have the perfect script for you!
|
|
||||||
|
|
||||||
The `generate_test_runner` script processes a given test file and automatically
|
|
||||||
creates a separate test runner file that includes ?main?to execute the test
|
|
||||||
cases within the scanned test file. All you do then is add the generated runner
|
|
||||||
to your list of files to be compiled and linked, and presto you're done!
|
|
||||||
|
|
||||||
This script searches your test file for void function signatures having a
|
|
||||||
function name beginning with "test" or "spec". It treats each of these
|
|
||||||
functions as a test case and builds up a test suite of them. For example, the
|
|
||||||
following includes three test cases:
|
|
||||||
|
|
||||||
```C
|
|
||||||
void testVerifyThatUnityIsAwesomeAndWillMakeYourLifeEasier(void)
|
|
||||||
{
|
|
||||||
ASSERT_TRUE(1);
|
|
||||||
}
|
|
||||||
void test_FunctionName_should_WorkProperlyAndReturn8(void) {
|
|
||||||
ASSERT_EQUAL_INT(8, FunctionName());
|
|
||||||
}
|
|
||||||
void spec_Function_should_DoWhatItIsSupposedToDo(void) {
|
|
||||||
ASSERT_NOT_NULL(Function(5));
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
You can run this script a couple of ways. The first is from the command line:
|
|
||||||
|
|
||||||
```Shell
|
|
||||||
ruby generate_test_runner.rb TestFile.c NameOfRunner.c
|
|
||||||
```
|
|
||||||
|
|
||||||
Alternatively, if you include only the test file parameter, the script will copy
|
|
||||||
the name of the test file and automatically append "_Runner" to the name of the
|
|
||||||
generated file. The example immediately below will create TestFile_Runner.c.
|
|
||||||
|
|
||||||
```Shell
|
|
||||||
ruby generate_test_runner.rb TestFile.c
|
|
||||||
```
|
|
||||||
|
|
||||||
You can also add a [YAML](http://www.yaml.org/) file to configure extra options.
|
|
||||||
Conveniently, this YAML file is of the same format as that used by Unity and
|
|
||||||
CMock. So if you are using YAML files already, you can simply pass the very same
|
|
||||||
file into the generator script.
|
|
||||||
|
|
||||||
```Shell
|
|
||||||
ruby generate_test_runner.rb TestFile.c my_config.yml
|
|
||||||
```
|
|
||||||
|
|
||||||
The contents of the YAML file `my_config.yml` could look something like the
|
|
||||||
example below. If you're wondering what some of these options do, you're going
|
|
||||||
to love the next section of this document.
|
|
||||||
|
|
||||||
```YAML
|
|
||||||
:unity:
|
|
||||||
:includes:
|
|
||||||
- stdio.h
|
|
||||||
- microdefs.h
|
|
||||||
:cexception: 1
|
|
||||||
:suit_setup: "blah = malloc(1024);"
|
|
||||||
:suite_teardown: "free(blah);"
|
|
||||||
```
|
|
||||||
|
|
||||||
If you would like to force your generated test runner to include one or more
|
|
||||||
header files, you can just include those at the command line too. Just make sure
|
|
||||||
these are _after_ the YAML file, if you are using one:
|
|
||||||
|
|
||||||
```Shell
|
|
||||||
ruby generate_test_runner.rb TestFile.c my_config.yml extras.h
|
|
||||||
```
|
|
||||||
|
|
||||||
Another option, particularly if you are already using Ruby to orchestrate your
|
|
||||||
builds - or more likely the Ruby-based build tool Rake - is requiring this
|
|
||||||
script directly. Anything that you would have specified in a YAML file can be
|
|
||||||
passed to the script as part of a hash. Let's push the exact same requirement
|
|
||||||
set as we did above but this time through Ruby code directly:
|
|
||||||
|
|
||||||
```Ruby
|
|
||||||
require "generate_test_runner.rb"
|
|
||||||
options = {
|
|
||||||
:includes => ["stdio.h", "microdefs.h"],
|
|
||||||
:cexception => 1,
|
|
||||||
:suite_setup => "blah = malloc(1024);",
|
|
||||||
:suite_teardown => "free(blah);"
|
|
||||||
}
|
|
||||||
UnityTestRunnerGenerator.new.run(testfile, runner_name, options)
|
|
||||||
```
|
|
||||||
|
|
||||||
If you have multiple files to generate in a build script (such as a Rakefile),
|
|
||||||
you might want to instantiate a generator object with your options and call it
|
|
||||||
to generate each runner afterwards. Like thus:
|
|
||||||
|
|
||||||
```Ruby
|
|
||||||
gen = UnityTestRunnerGenerator.new(options)
|
|
||||||
test_files.each do |f|
|
|
||||||
gen.run(f, File.basename(f,'.c')+"Runner.c"
|
|
||||||
end
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Options accepted by generate_test_runner.rb:
|
|
||||||
|
|
||||||
The following options are available when executing `generate_test_runner`. You
|
|
||||||
may pass these as a Ruby hash directly or specify them in a YAML file, both of
|
|
||||||
which are described above. In the `examples` directory, Example 3's Rakefile
|
|
||||||
demonstrates using a Ruby hash.
|
|
||||||
|
|
||||||
|
|
||||||
##### `:includes`
|
|
||||||
|
|
||||||
This option specifies an array of file names to be `#include`'d at the top of
|
|
||||||
your runner C file. You might use it to reference custom types or anything else
|
|
||||||
universally needed in your generated runners.
|
|
||||||
|
|
||||||
|
|
||||||
##### `:suite_setup`
|
|
||||||
|
|
||||||
Define this option with C code to be executed _before any_ test cases are run.
|
|
||||||
|
|
||||||
Alternatively, if your C compiler supports weak symbols, you can leave this
|
|
||||||
option unset and instead provide a `void suiteSetUp(void)` function in your test
|
|
||||||
suite. The linker will look for this symbol and fall back to a Unity-provided
|
|
||||||
stub if it is not found.
|
|
||||||
|
|
||||||
|
|
||||||
##### `:suite_teardown`
|
|
||||||
|
|
||||||
Define this option with C code to be executed _after all_ test cases have
|
|
||||||
finished. An integer variable `num_failures` is available for diagnostics.
|
|
||||||
The code should end with a `return` statement; the value returned will become
|
|
||||||
the exit code of `main`. You can normally just return `num_failures`.
|
|
||||||
|
|
||||||
Alternatively, if your C compiler supports weak symbols, you can leave this
|
|
||||||
option unset and instead provide a `int suiteTearDown(int num_failures)`
|
|
||||||
function in your test suite. The linker will look for this symbol and fall
|
|
||||||
back to a Unity-provided stub if it is not found.
|
|
||||||
|
|
||||||
|
|
||||||
##### `:enforce_strict_ordering`
|
|
||||||
|
|
||||||
This option should be defined if you have the strict order feature enabled in
|
|
||||||
CMock (see CMock documentation). This generates extra variables required for
|
|
||||||
everything to run smoothly. If you provide the same YAML to the generator as
|
|
||||||
used in CMock's configuration, you've already configured the generator properly.
|
|
||||||
|
|
||||||
##### `:mock_prefix` and `:mock_suffix`
|
|
||||||
|
|
||||||
Unity automatically generates calls to Init, Verify and Destroy for every file
|
|
||||||
included in the main test file that starts with the given mock prefix and ends
|
|
||||||
with the given mock suffix, file extension not included. By default, Unity
|
|
||||||
assumes a `Mock` prefix and no suffix.
|
|
||||||
|
|
||||||
##### `:plugins`
|
|
||||||
|
|
||||||
This option specifies an array of plugins to be used (of course, the array can
|
|
||||||
contain only a single plugin). This is your opportunity to enable support for
|
|
||||||
CException support, which will add a check for unhandled exceptions in each
|
|
||||||
test, reporting a failure if one is detected. To enable this feature using Ruby:
|
|
||||||
|
|
||||||
```Ruby
|
|
||||||
:plugins => [ :cexception ]
|
|
||||||
```
|
|
||||||
|
|
||||||
Or as a yaml file:
|
|
||||||
|
|
||||||
```YAML
|
|
||||||
:plugins:
|
|
||||||
-:cexception
|
|
||||||
```
|
|
||||||
|
|
||||||
If you are using CMock, it is very likely that you are already passing an array
|
|
||||||
of plugins to CMock. You can just use the same array here. This script will just
|
|
||||||
ignore the plugins that don't require additional support.
|
|
||||||
|
|
||||||
|
|
||||||
### `unity_test_summary.rb`
|
|
||||||
|
|
||||||
A Unity test file contains one or more test case functions. Each test case can
|
|
||||||
pass, fail, or be ignored. Each test file is run individually producing results
|
|
||||||
for its collection of test cases. A given project will almost certainly be
|
|
||||||
composed of multiple test files. Therefore, the suite of tests is comprised of
|
|
||||||
one or more test cases spread across one or more test files. This script
|
|
||||||
aggregates individual test file results to generate a summary of all executed
|
|
||||||
test cases. The output includes how many tests were run, how many were ignored,
|
|
||||||
and how many failed. In addition, the output includes a listing of which
|
|
||||||
specific tests were ignored and failed. A good example of the breadth and
|
|
||||||
details of these results can be found in the `examples` directory. Intentionally
|
|
||||||
ignored and failing tests in this project generate corresponding entries in the
|
|
||||||
summary report.
|
|
||||||
|
|
||||||
If you're interested in other (prettier?) output formats, check into the
|
|
||||||
Ceedling build tool project (ceedling.sourceforge.net) that works with Unity and
|
|
||||||
CMock and supports xunit-style xml as well as other goodies.
|
|
||||||
|
|
||||||
This script assumes the existence of files ending with the extensions
|
|
||||||
`.testpass` and `.testfail`.The contents of these files includes the test
|
|
||||||
results summary corresponding to each test file executed with the extension set
|
|
||||||
according to the presence or absence of failures for that test file. The script
|
|
||||||
searches a specified path for these files, opens each one it finds, parses the
|
|
||||||
results, and aggregates and prints a summary. Calling it from the command line
|
|
||||||
looks like this:
|
|
||||||
|
|
||||||
```Shell
|
|
||||||
ruby unity_test_summary.rb build/test/
|
|
||||||
```
|
|
||||||
|
|
||||||
You can optionally specify a root path as well. This is really helpful when you
|
|
||||||
are using relative paths in your tools' setup, but you want to pull the summary
|
|
||||||
into an IDE like Eclipse for clickable shortcuts.
|
|
||||||
|
|
||||||
```Shell
|
|
||||||
ruby unity_test_summary.rb build/test/ ~/projects/myproject/
|
|
||||||
```
|
|
||||||
|
|
||||||
Or, if you're more of a Windows sort of person:
|
|
||||||
|
|
||||||
```Shell
|
|
||||||
ruby unity_test_summary.rb build\teat\ C:\projects\myproject\
|
|
||||||
```
|
|
||||||
|
|
||||||
When configured correctly, you'll see a final summary, like so:
|
|
||||||
|
|
||||||
```Shell
|
|
||||||
--------------------------
|
|
||||||
UNITY IGNORED TEST SUMMARY
|
|
||||||
--------------------------
|
|
||||||
blah.c:22:test_sandwiches_should_HaveBreadOnTwoSides:IGNORE
|
|
||||||
|
|
||||||
-------------------------
|
|
||||||
UNITY FAILED TEST SUMMARY
|
|
||||||
-------------------------
|
|
||||||
blah.c:87:test_sandwiches_should_HaveCondiments:FAIL:Expected 1 was 0
|
|
||||||
meh.c:38:test_soda_should_BeCalledPop:FAIL:Expected "pop" was "coke"
|
|
||||||
|
|
||||||
--------------------------
|
|
||||||
OVERALL UNITY TEST SUMMARY
|
|
||||||
--------------------------
|
|
||||||
45 TOTAL TESTS 2 TOTAL FAILURES 1 IGNORED
|
|
||||||
```
|
|
||||||
|
|
||||||
How convenient is that?
|
|
||||||
|
|
||||||
|
|
||||||
*Find The Latest of This And More at [ThrowTheSwitch.org](https://throwtheswitch.org)*
|
|
@ -9,7 +9,7 @@ class BuildInvokerUtils
|
|||||||
##
|
##
|
||||||
# Processes exceptions and tries to display a useful message for the user.
|
# Processes exceptions and tries to display a useful message for the user.
|
||||||
#
|
#
|
||||||
# ==== Attriboops...utes
|
# ==== Attributes
|
||||||
#
|
#
|
||||||
# * _exception_: The exception given by a rescue statement.
|
# * _exception_: The exception given by a rescue statement.
|
||||||
# * _context_: A symbol representing where in the build the exception
|
# * _context_: A symbol representing where in the build the exception
|
||||||
|
@ -4,28 +4,32 @@ class CacheinatorHelper
|
|||||||
constructor :file_wrapper, :yaml_wrapper
|
constructor :file_wrapper, :yaml_wrapper
|
||||||
|
|
||||||
def diff_cached_config?(cached_filepath, hash)
|
def diff_cached_config?(cached_filepath, hash)
|
||||||
return true if ( not @file_wrapper.exist?(cached_filepath) )
|
return false if ( not @file_wrapper.exist?(cached_filepath) )
|
||||||
return true if ( (@file_wrapper.exist?(cached_filepath)) and (!(@yaml_wrapper.load(cached_filepath) == hash)) )
|
return true if (@yaml_wrapper.load(cached_filepath) != hash)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
def diff_cached_defines?(cached_filepath, files)
|
def diff_cached_defines?(cached_filepath, files)
|
||||||
|
changed_defines = false
|
||||||
current_defines = COLLECTION_DEFINES_TEST_AND_VENDOR.reject(&:empty?)
|
current_defines = COLLECTION_DEFINES_TEST_AND_VENDOR.reject(&:empty?)
|
||||||
|
|
||||||
current_dependency = Hash[files.collect { |source| [source, current_defines.dup] }]
|
current_dependencies = Hash[files.collect { |source| [source, current_defines.dup] }]
|
||||||
if not @file_wrapper.exist?(cached_filepath)
|
if not @file_wrapper.exist?(cached_filepath)
|
||||||
@yaml_wrapper.dump(cached_filepath, current_dependency)
|
@yaml_wrapper.dump(cached_filepath, current_dependencies)
|
||||||
return false
|
return changed_defines
|
||||||
end
|
end
|
||||||
|
|
||||||
dependencies = @yaml_wrapper.load(cached_filepath)
|
dependencies = @yaml_wrapper.load(cached_filepath)
|
||||||
if dependencies.values_at(*current_dependency.keys) != current_dependency.values
|
common_dependencies = current_dependencies.select { |file, defines| dependencies.has_key?(file) }
|
||||||
dependencies.merge!(current_dependency)
|
|
||||||
@yaml_wrapper.dump(cached_filepath, dependencies)
|
if dependencies.values_at(*common_dependencies.keys) != common_dependencies.values
|
||||||
return true
|
changed_defines = true
|
||||||
end
|
end
|
||||||
|
|
||||||
return false
|
dependencies.merge!(current_dependencies)
|
||||||
|
@yaml_wrapper.dump(cached_filepath, dependencies)
|
||||||
|
|
||||||
|
return changed_defines
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -54,6 +54,7 @@ class Configurator
|
|||||||
:test_fixture,
|
:test_fixture,
|
||||||
:test_includes_preprocessor,
|
:test_includes_preprocessor,
|
||||||
:test_file_preprocessor,
|
:test_file_preprocessor,
|
||||||
|
:test_file_preprocessor_directives,
|
||||||
:test_dependencies_generator,
|
:test_dependencies_generator,
|
||||||
:release_compiler,
|
:release_compiler,
|
||||||
:release_assembler,
|
:release_assembler,
|
||||||
@ -183,17 +184,22 @@ class Configurator
|
|||||||
@rake_plugins = @configurator_plugins.find_rake_plugins(config, paths_hash)
|
@rake_plugins = @configurator_plugins.find_rake_plugins(config, paths_hash)
|
||||||
@script_plugins = @configurator_plugins.find_script_plugins(config, paths_hash)
|
@script_plugins = @configurator_plugins.find_script_plugins(config, paths_hash)
|
||||||
config_plugins = @configurator_plugins.find_config_plugins(config, paths_hash)
|
config_plugins = @configurator_plugins.find_config_plugins(config, paths_hash)
|
||||||
plugin_defaults = @configurator_plugins.find_plugin_defaults(config, paths_hash)
|
plugin_yml_defaults = @configurator_plugins.find_plugin_yml_defaults(config, paths_hash)
|
||||||
|
plugin_hash_defaults = @configurator_plugins.find_plugin_hash_defaults(config, paths_hash)
|
||||||
|
|
||||||
config_plugins.each do |plugin|
|
config_plugins.each do |plugin|
|
||||||
plugin_config = @yaml_wrapper.load(plugin)
|
plugin_config = @yaml_wrapper.load(plugin)
|
||||||
config.deep_merge(plugin_config)
|
config.deep_merge(plugin_config)
|
||||||
end
|
end
|
||||||
|
|
||||||
plugin_defaults.each do |defaults|
|
plugin_yml_defaults.each do |defaults|
|
||||||
@configurator_builder.populate_defaults( config, @yaml_wrapper.load(defaults) )
|
@configurator_builder.populate_defaults( config, @yaml_wrapper.load(defaults) )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
plugin_hash_defaults.each do |defaults|
|
||||||
|
@configurator_builder.populate_defaults( config, defaults )
|
||||||
|
end
|
||||||
|
|
||||||
# special plugin setting for results printing
|
# special plugin setting for results printing
|
||||||
config[:plugins][:display_raw_test_results] = true if (config[:plugins][:display_raw_test_results].nil?)
|
config[:plugins][:display_raw_test_results] = true if (config[:plugins][:display_raw_test_results].nil?)
|
||||||
|
|
||||||
@ -203,10 +209,19 @@ class Configurator
|
|||||||
|
|
||||||
def merge_imports(config)
|
def merge_imports(config)
|
||||||
if config[:import]
|
if config[:import]
|
||||||
until config[:import].empty?
|
if config[:import].is_a? Array
|
||||||
path = config[:import].shift
|
until config[:import].empty?
|
||||||
path = @system_wrapper.module_eval(path) if (path =~ RUBY_STRING_REPLACEMENT_PATTERN)
|
path = config[:import].shift
|
||||||
config.deep_merge!(@yaml_wrapper.load(path))
|
path = @system_wrapper.module_eval(path) if (path =~ RUBY_STRING_REPLACEMENT_PATTERN)
|
||||||
|
config.deep_merge!(@yaml_wrapper.load(path))
|
||||||
|
end
|
||||||
|
else
|
||||||
|
config[:import].each_value do |path|
|
||||||
|
if !path.nil?
|
||||||
|
path = @system_wrapper.module_eval(path) if (path =~ RUBY_STRING_REPLACEMENT_PATTERN)
|
||||||
|
config.deep_merge!(@yaml_wrapper.load(path))
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
config.delete(:import)
|
config.delete(:import)
|
||||||
@ -222,7 +237,11 @@ class Configurator
|
|||||||
interstitial = ((key == :path) ? File::PATH_SEPARATOR : '')
|
interstitial = ((key == :path) ? File::PATH_SEPARATOR : '')
|
||||||
items = ((value.class == Array) ? hash[key] : [value])
|
items = ((value.class == Array) ? hash[key] : [value])
|
||||||
|
|
||||||
items.each { |item| item.replace( @system_wrapper.module_eval( item ) ) if (item =~ RUBY_STRING_REPLACEMENT_PATTERN) }
|
items.each do |item|
|
||||||
|
if item.is_a? String and item =~ RUBY_STRING_REPLACEMENT_PATTERN
|
||||||
|
item.replace( @system_wrapper.module_eval( item ) )
|
||||||
|
end
|
||||||
|
end
|
||||||
hash[key] = items.join( interstitial )
|
hash[key] = items.join( interstitial )
|
||||||
|
|
||||||
@system_wrapper.env_set( key.to_s.upcase, hash[key] )
|
@system_wrapper.env_set( key.to_s.upcase, hash[key] )
|
||||||
|
@ -250,8 +250,8 @@ class ConfiguratorBuilder
|
|||||||
def collect_test_support_source_include_vendor_paths(in_hash)
|
def collect_test_support_source_include_vendor_paths(in_hash)
|
||||||
return {
|
return {
|
||||||
:collection_paths_test_support_source_include_vendor =>
|
:collection_paths_test_support_source_include_vendor =>
|
||||||
in_hash[:collection_paths_test_support_source_include] +
|
get_vendor_paths(in_hash) +
|
||||||
get_vendor_paths(in_hash)
|
in_hash[:collection_paths_test_support_source_include]
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -384,14 +384,26 @@ class ConfiguratorBuilder
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def get_vendor_defines(in_hash)
|
||||||
|
defines = in_hash[:unity_defines].clone
|
||||||
|
defines.concat(in_hash[:cmock_defines]) if (in_hash[:project_use_mocks])
|
||||||
|
defines.concat(in_hash[:cexception_defines]) if (in_hash[:project_use_exceptions])
|
||||||
|
|
||||||
|
return defines
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def collect_vendor_defines(in_hash)
|
||||||
|
return {:collection_defines_vendor => get_vendor_defines(in_hash)}
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
def collect_test_and_vendor_defines(in_hash)
|
def collect_test_and_vendor_defines(in_hash)
|
||||||
test_defines = in_hash[:defines_test].clone
|
defines = in_hash[:defines_test].clone
|
||||||
|
vendor_defines = get_vendor_defines(in_hash)
|
||||||
|
defines.concat(vendor_defines) if vendor_defines
|
||||||
|
|
||||||
test_defines.concat(in_hash[:unity_defines])
|
return {:collection_defines_test_and_vendor => defines}
|
||||||
test_defines.concat(in_hash[:cmock_defines]) if (in_hash[:project_use_mocks])
|
|
||||||
test_defines.concat(in_hash[:cexception_defines]) if (in_hash[:project_use_exceptions])
|
|
||||||
|
|
||||||
return {:collection_defines_test_and_vendor => test_defines}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@ -418,28 +430,33 @@ class ConfiguratorBuilder
|
|||||||
# Note: Symbols passed to compiler at command line can change Unity and CException behavior / configuration;
|
# Note: Symbols passed to compiler at command line can change Unity and CException behavior / configuration;
|
||||||
# we also handle those dependencies elsewhere in compilation dependencies
|
# we also handle those dependencies elsewhere in compilation dependencies
|
||||||
|
|
||||||
objects = [UNITY_C_FILE]
|
sources = [UNITY_C_FILE]
|
||||||
|
|
||||||
in_hash[:files_support].each { |file| objects << File.basename(file) }
|
in_hash[:files_support].each { |file| sources << file }
|
||||||
|
|
||||||
# we don't include paths here because use of plugins or mixing different compilers may require different build paths
|
# we don't include paths here because use of plugins or mixing different compilers may require different build paths
|
||||||
objects << CEXCEPTION_C_FILE if (in_hash[:project_use_exceptions])
|
sources << CEXCEPTION_C_FILE if (in_hash[:project_use_exceptions])
|
||||||
objects << CMOCK_C_FILE if (in_hash[:project_use_mocks])
|
sources << CMOCK_C_FILE if (in_hash[:project_use_mocks])
|
||||||
|
|
||||||
# if we're using mocks & a unity helper is defined & that unity helper includes a source file component (not only a header of macros),
|
# if we're using mocks & a unity helper is defined & that unity helper includes a source file component (not only a header of macros),
|
||||||
# then link in the unity_helper object file too
|
# then link in the unity_helper object file too
|
||||||
if ( in_hash[:project_use_mocks] and in_hash[:cmock_unity_helper] )
|
if ( in_hash[:project_use_mocks] and in_hash[:cmock_unity_helper] )
|
||||||
in_hash[:cmock_unity_helper].each do |helper|
|
in_hash[:cmock_unity_helper].each do |helper|
|
||||||
if @file_wrapper.exist?(helper.ext(in_hash[:extension_source]))
|
if @file_wrapper.exist?(helper.ext(in_hash[:extension_source]))
|
||||||
objects << File.basename(helper)
|
sources << helper
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# create object files from all the sources
|
||||||
|
objects = sources.map { |file| File.basename(file) }
|
||||||
|
|
||||||
# no build paths here so plugins can remap if necessary (i.e. path mapping happens at runtime)
|
# no build paths here so plugins can remap if necessary (i.e. path mapping happens at runtime)
|
||||||
objects.map! { |object| object.ext(in_hash[:extension_object]) }
|
objects.map! { |object| object.ext(in_hash[:extension_object]) }
|
||||||
|
|
||||||
return { :collection_test_fixture_extra_link_objects => objects }
|
return { :collection_all_support => sources,
|
||||||
|
:collection_test_fixture_extra_link_objects => objects
|
||||||
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@ class ConfiguratorPlugins
|
|||||||
|
|
||||||
if is_script_plugin
|
if is_script_plugin
|
||||||
@system_wrapper.add_load_path( File.join( path, 'lib') )
|
@system_wrapper.add_load_path( File.join( path, 'lib') )
|
||||||
|
@system_wrapper.add_load_path( File.join( path, 'config') )
|
||||||
end
|
end
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
@ -92,7 +93,7 @@ class ConfiguratorPlugins
|
|||||||
|
|
||||||
|
|
||||||
# gather up and return default .yml filepaths that exist on-disk
|
# gather up and return default .yml filepaths that exist on-disk
|
||||||
def find_plugin_defaults(config, plugin_paths)
|
def find_plugin_yml_defaults(config, plugin_paths)
|
||||||
defaults_with_path = []
|
defaults_with_path = []
|
||||||
|
|
||||||
config[:plugins][:enabled].each do |plugin|
|
config[:plugins][:enabled].each do |plugin|
|
||||||
@ -108,4 +109,23 @@ class ConfiguratorPlugins
|
|||||||
return defaults_with_path
|
return defaults_with_path
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# gather up and return
|
||||||
|
def find_plugin_hash_defaults(config, plugin_paths)
|
||||||
|
defaults_hash= []
|
||||||
|
|
||||||
|
config[:plugins][:enabled].each do |plugin|
|
||||||
|
if path = plugin_paths[(plugin + '_path').to_sym]
|
||||||
|
default_path = File.join(path, "config", "defaults_#{plugin}.rb")
|
||||||
|
if @file_wrapper.exist?(default_path)
|
||||||
|
@system_wrapper.require_file( "defaults_#{plugin}.rb")
|
||||||
|
|
||||||
|
object = eval("get_default_config()")
|
||||||
|
defaults_hash << object
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return defaults_hash
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -39,6 +39,7 @@ class ConfiguratorSetup
|
|||||||
flattened_config.merge!(@configurator_builder.collect_headers(flattened_config))
|
flattened_config.merge!(@configurator_builder.collect_headers(flattened_config))
|
||||||
flattened_config.merge!(@configurator_builder.collect_release_existing_compilation_input(flattened_config))
|
flattened_config.merge!(@configurator_builder.collect_release_existing_compilation_input(flattened_config))
|
||||||
flattened_config.merge!(@configurator_builder.collect_all_existing_compilation_input(flattened_config))
|
flattened_config.merge!(@configurator_builder.collect_all_existing_compilation_input(flattened_config))
|
||||||
|
flattened_config.merge!(@configurator_builder.collect_vendor_defines(flattened_config))
|
||||||
flattened_config.merge!(@configurator_builder.collect_test_and_vendor_defines(flattened_config))
|
flattened_config.merge!(@configurator_builder.collect_test_and_vendor_defines(flattened_config))
|
||||||
flattened_config.merge!(@configurator_builder.collect_release_and_vendor_defines(flattened_config))
|
flattened_config.merge!(@configurator_builder.collect_release_and_vendor_defines(flattened_config))
|
||||||
flattened_config.merge!(@configurator_builder.collect_release_artifact_extra_link_objects(flattened_config))
|
flattened_config.merge!(@configurator_builder.collect_release_artifact_extra_link_objects(flattened_config))
|
||||||
|
@ -95,3 +95,5 @@ NULL_FILE_PATH = '/dev/null'
|
|||||||
|
|
||||||
TESTS_BASE_PATH = TEST_ROOT_NAME
|
TESTS_BASE_PATH = TEST_ROOT_NAME
|
||||||
RELEASE_BASE_PATH = RELEASE_ROOT_NAME
|
RELEASE_BASE_PATH = RELEASE_ROOT_NAME
|
||||||
|
|
||||||
|
VENDORS_FILES = %w(unity UnityHelper cmock CException).freeze
|
||||||
|
77
test/vendor/ceedling/lib/ceedling/defaults.rb
vendored
77
test/vendor/ceedling/lib/ceedling/defaults.rb
vendored
@ -7,17 +7,20 @@ CEEDLING_VENDOR = File.expand_path(File.dirname(__FILE__) + '/../../vendor') unl
|
|||||||
CEEDLING_PLUGINS = [] unless defined? CEEDLING_PLUGINS
|
CEEDLING_PLUGINS = [] unless defined? CEEDLING_PLUGINS
|
||||||
|
|
||||||
DEFAULT_TEST_COMPILER_TOOL = {
|
DEFAULT_TEST_COMPILER_TOOL = {
|
||||||
:executable => FilePathUtils.os_executable_ext('gcc').freeze,
|
:executable => ENV['CC'].nil? ? FilePathUtils.os_executable_ext('gcc').freeze : ENV['CC'].split[0],
|
||||||
:name => 'default_test_compiler'.freeze,
|
:name => 'default_test_compiler'.freeze,
|
||||||
:stderr_redirect => StdErrRedirect::NONE.freeze,
|
:stderr_redirect => StdErrRedirect::NONE.freeze,
|
||||||
:background_exec => BackgroundExec::NONE.freeze,
|
:background_exec => BackgroundExec::NONE.freeze,
|
||||||
:optional => false.freeze,
|
:optional => false.freeze,
|
||||||
:arguments => [
|
:arguments => [
|
||||||
|
ENV['CC'].nil? ? "" : ENV['CC'].split[1..-1],
|
||||||
|
ENV['CPPFLAGS'].nil? ? "" : ENV['CPPFLAGS'].split,
|
||||||
{"-I\"$\"" => 'COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR'}.freeze,
|
{"-I\"$\"" => 'COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR'}.freeze,
|
||||||
{"-I\"$\"" => 'COLLECTION_PATHS_TEST_TOOLCHAIN_INCLUDE'}.freeze,
|
{"-I\"$\"" => 'COLLECTION_PATHS_TEST_TOOLCHAIN_INCLUDE'}.freeze,
|
||||||
{"-D$" => 'COLLECTION_DEFINES_TEST_AND_VENDOR'}.freeze,
|
{"-D$" => 'COLLECTION_DEFINES_TEST_AND_VENDOR'}.freeze,
|
||||||
"-DGNU_COMPILER".freeze,
|
"-DGNU_COMPILER".freeze,
|
||||||
"-g".freeze,
|
"-g".freeze,
|
||||||
|
ENV['CFLAGS'].nil? ? "" : ENV['CFLAGS'].split,
|
||||||
"-c \"${1}\"".freeze,
|
"-c \"${1}\"".freeze,
|
||||||
"-o \"${2}\"".freeze,
|
"-o \"${2}\"".freeze,
|
||||||
# gcc's list file output options are complex; no use of ${3} parameter in default config
|
# gcc's list file output options are complex; no use of ${3} parameter in default config
|
||||||
@ -27,16 +30,21 @@ DEFAULT_TEST_COMPILER_TOOL = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DEFAULT_TEST_LINKER_TOOL = {
|
DEFAULT_TEST_LINKER_TOOL = {
|
||||||
:executable => FilePathUtils.os_executable_ext('gcc').freeze,
|
:executable => ENV['CCLD'].nil? ? FilePathUtils.os_executable_ext('gcc').freeze : ENV['CCLD'].split[0],
|
||||||
:name => 'default_test_linker'.freeze,
|
:name => 'default_test_linker'.freeze,
|
||||||
:stderr_redirect => StdErrRedirect::NONE.freeze,
|
:stderr_redirect => StdErrRedirect::NONE.freeze,
|
||||||
:background_exec => BackgroundExec::NONE.freeze,
|
:background_exec => BackgroundExec::NONE.freeze,
|
||||||
:optional => false.freeze,
|
:optional => false.freeze,
|
||||||
:arguments => [
|
:arguments => [
|
||||||
|
ENV['CCLD'].nil? ? "" : ENV['CCLD'].split[1..-1],
|
||||||
|
ENV['CFLAGS'].nil? ? "" : ENV['CFLAGS'].split,
|
||||||
|
ENV['LDFLAGS'].nil? ? "" : ENV['LDFLAGS'].split,
|
||||||
"\"${1}\"".freeze,
|
"\"${1}\"".freeze,
|
||||||
|
"${5}".freeze,
|
||||||
"-o \"${2}\"".freeze,
|
"-o \"${2}\"".freeze,
|
||||||
"".freeze,
|
"".freeze,
|
||||||
"${4}".freeze
|
"${4}".freeze,
|
||||||
|
ENV['LDLIBS'].nil? ? "" : ENV['LDLIBS'].split
|
||||||
].freeze
|
].freeze
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,12 +58,14 @@ DEFAULT_TEST_FIXTURE_TOOL = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DEFAULT_TEST_INCLUDES_PREPROCESSOR_TOOL = {
|
DEFAULT_TEST_INCLUDES_PREPROCESSOR_TOOL = {
|
||||||
:executable => FilePathUtils.os_executable_ext('gcc').freeze,
|
:executable => ENV['CC'].nil? ? FilePathUtils.os_executable_ext('gcc').freeze : ENV['CC'].split[0],
|
||||||
:name => 'default_test_includes_preprocessor'.freeze,
|
:name => 'default_test_includes_preprocessor'.freeze,
|
||||||
:stderr_redirect => StdErrRedirect::NONE.freeze,
|
:stderr_redirect => StdErrRedirect::NONE.freeze,
|
||||||
:background_exec => BackgroundExec::NONE.freeze,
|
:background_exec => BackgroundExec::NONE.freeze,
|
||||||
:optional => false.freeze,
|
:optional => false.freeze,
|
||||||
:arguments => [
|
:arguments => [
|
||||||
|
ENV['CC'].nil? ? "" : ENV['CC'].split[1..-1],
|
||||||
|
ENV['CPPFLAGS'].nil? ? "" : ENV['CPPFLAGS'].split,
|
||||||
'-E'.freeze, # OSX clang
|
'-E'.freeze, # OSX clang
|
||||||
'-MM'.freeze,
|
'-MM'.freeze,
|
||||||
'-MG'.freeze,
|
'-MG'.freeze,
|
||||||
@ -67,18 +77,38 @@ DEFAULT_TEST_INCLUDES_PREPROCESSOR_TOOL = {
|
|||||||
{"-D$" => 'COLLECTION_DEFINES_TEST_AND_VENDOR'}.freeze,
|
{"-D$" => 'COLLECTION_DEFINES_TEST_AND_VENDOR'}.freeze,
|
||||||
{"-D$" => 'DEFINES_TEST_PREPROCESS'}.freeze,
|
{"-D$" => 'DEFINES_TEST_PREPROCESS'}.freeze,
|
||||||
"-DGNU_COMPILER".freeze, # OSX clang
|
"-DGNU_COMPILER".freeze, # OSX clang
|
||||||
'-w'.freeze,
|
|
||||||
# '-nostdinc'.freeze, # disabled temporarily due to stdio access violations on OSX
|
# '-nostdinc'.freeze, # disabled temporarily due to stdio access violations on OSX
|
||||||
"\"${1}\"".freeze
|
"\"${1}\"".freeze
|
||||||
].freeze
|
].freeze
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFAULT_TEST_FILE_PREPROCESSOR_TOOL = {
|
DEFAULT_TEST_FILE_PREPROCESSOR_TOOL = {
|
||||||
:executable => FilePathUtils.os_executable_ext('gcc').freeze,
|
:executable => ENV['CC'].nil? ? FilePathUtils.os_executable_ext('gcc').freeze : ENV['CC'].split[0],
|
||||||
:name => 'default_test_file_preprocessor'.freeze,
|
:name => 'default_test_file_preprocessor'.freeze,
|
||||||
:stderr_redirect => StdErrRedirect::NONE.freeze,
|
:stderr_redirect => StdErrRedirect::NONE.freeze,
|
||||||
:background_exec => BackgroundExec::NONE.freeze,
|
:background_exec => BackgroundExec::NONE.freeze,
|
||||||
:optional => false.freeze,
|
:optional => false.freeze,
|
||||||
|
:arguments => [
|
||||||
|
ENV['CC'].nil? ? "" : ENV['CC'].split[1..-1],
|
||||||
|
ENV['CPPFLAGS'].nil? ? "" : ENV['CPPFLAGS'].split,
|
||||||
|
'-E'.freeze,
|
||||||
|
{"-I\"$\"" => 'COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR'}.freeze,
|
||||||
|
{"-I\"$\"" => 'COLLECTION_PATHS_TEST_TOOLCHAIN_INCLUDE'}.freeze,
|
||||||
|
{"-D$" => 'COLLECTION_DEFINES_TEST_AND_VENDOR'}.freeze,
|
||||||
|
{"-D$" => 'DEFINES_TEST_PREPROCESS'}.freeze,
|
||||||
|
"-DGNU_COMPILER".freeze,
|
||||||
|
# '-nostdinc'.freeze, # disabled temporarily due to stdio access violations on OSX
|
||||||
|
"\"${1}\"".freeze,
|
||||||
|
"-o \"${2}\"".freeze
|
||||||
|
].freeze
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFAULT_TEST_FILE_PREPROCESSOR_DIRECTIVES_TOOL = {
|
||||||
|
:executable => FilePathUtils.os_executable_ext('gcc').freeze,
|
||||||
|
:name => 'default_test_file_preprocessor_directives'.freeze,
|
||||||
|
:stderr_redirect => StdErrRedirect::NONE.freeze,
|
||||||
|
:background_exec => BackgroundExec::NONE.freeze,
|
||||||
|
:optional => false.freeze,
|
||||||
:arguments => [
|
:arguments => [
|
||||||
'-E'.freeze,
|
'-E'.freeze,
|
||||||
{"-I\"$\"" => 'COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR'}.freeze,
|
{"-I\"$\"" => 'COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR'}.freeze,
|
||||||
@ -86,6 +116,7 @@ DEFAULT_TEST_FILE_PREPROCESSOR_TOOL = {
|
|||||||
{"-D$" => 'COLLECTION_DEFINES_TEST_AND_VENDOR'}.freeze,
|
{"-D$" => 'COLLECTION_DEFINES_TEST_AND_VENDOR'}.freeze,
|
||||||
{"-D$" => 'DEFINES_TEST_PREPROCESS'}.freeze,
|
{"-D$" => 'DEFINES_TEST_PREPROCESS'}.freeze,
|
||||||
"-DGNU_COMPILER".freeze,
|
"-DGNU_COMPILER".freeze,
|
||||||
|
'-fdirectives-only'.freeze,
|
||||||
# '-nostdinc'.freeze, # disabled temporarily due to stdio access violations on OSX
|
# '-nostdinc'.freeze, # disabled temporarily due to stdio access violations on OSX
|
||||||
"\"${1}\"".freeze,
|
"\"${1}\"".freeze,
|
||||||
"-o \"${2}\"".freeze
|
"-o \"${2}\"".freeze
|
||||||
@ -100,12 +131,14 @@ else
|
|||||||
end
|
end
|
||||||
|
|
||||||
DEFAULT_TEST_DEPENDENCIES_GENERATOR_TOOL = {
|
DEFAULT_TEST_DEPENDENCIES_GENERATOR_TOOL = {
|
||||||
:executable => FilePathUtils.os_executable_ext('gcc').freeze,
|
:executable => ENV['CC'].nil? ? FilePathUtils.os_executable_ext('gcc').freeze : ENV['CC'].split[0],
|
||||||
:name => 'default_test_dependencies_generator'.freeze,
|
:name => 'default_test_dependencies_generator'.freeze,
|
||||||
:stderr_redirect => StdErrRedirect::NONE.freeze,
|
:stderr_redirect => StdErrRedirect::NONE.freeze,
|
||||||
:background_exec => BackgroundExec::NONE.freeze,
|
:background_exec => BackgroundExec::NONE.freeze,
|
||||||
:optional => false.freeze,
|
:optional => false.freeze,
|
||||||
:arguments => [
|
:arguments => [
|
||||||
|
ENV['CC'].nil? ? "" : ENV['CC'].split[1..-1],
|
||||||
|
ENV['CPPFLAGS'].nil? ? "" : ENV['CPPFLAGS'].split,
|
||||||
'-E'.freeze,
|
'-E'.freeze,
|
||||||
{"-I\"$\"" => 'COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR'}.freeze,
|
{"-I\"$\"" => 'COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR'}.freeze,
|
||||||
{"-I\"$\"" => 'COLLECTION_PATHS_TEST_TOOLCHAIN_INCLUDE'}.freeze,
|
{"-I\"$\"" => 'COLLECTION_PATHS_TEST_TOOLCHAIN_INCLUDE'}.freeze,
|
||||||
@ -123,12 +156,14 @@ DEFAULT_TEST_DEPENDENCIES_GENERATOR_TOOL = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DEFAULT_RELEASE_DEPENDENCIES_GENERATOR_TOOL = {
|
DEFAULT_RELEASE_DEPENDENCIES_GENERATOR_TOOL = {
|
||||||
:executable => FilePathUtils.os_executable_ext('gcc').freeze,
|
:executable => ENV['CC'].nil? ? FilePathUtils.os_executable_ext('gcc').freeze : ENV['CC'].split[0],
|
||||||
:name => 'default_release_dependencies_generator'.freeze,
|
:name => 'default_release_dependencies_generator'.freeze,
|
||||||
:stderr_redirect => StdErrRedirect::NONE.freeze,
|
:stderr_redirect => StdErrRedirect::NONE.freeze,
|
||||||
:background_exec => BackgroundExec::NONE.freeze,
|
:background_exec => BackgroundExec::NONE.freeze,
|
||||||
:optional => false.freeze,
|
:optional => false.freeze,
|
||||||
:arguments => [
|
:arguments => [
|
||||||
|
ENV['CC'].nil? ? "" : ENV['CC'].split[1..-1],
|
||||||
|
ENV['CPPFLAGS'].nil? ? "" : ENV['CPPFLAGS'].split,
|
||||||
'-E'.freeze,
|
'-E'.freeze,
|
||||||
{"-I\"$\"" => 'COLLECTION_PATHS_SOURCE_INCLUDE_VENDOR'}.freeze,
|
{"-I\"$\"" => 'COLLECTION_PATHS_SOURCE_INCLUDE_VENDOR'}.freeze,
|
||||||
{"-I\"$\"" => 'COLLECTION_PATHS_RELEASE_TOOLCHAIN_INCLUDE'}.freeze,
|
{"-I\"$\"" => 'COLLECTION_PATHS_RELEASE_TOOLCHAIN_INCLUDE'}.freeze,
|
||||||
@ -147,16 +182,19 @@ DEFAULT_RELEASE_DEPENDENCIES_GENERATOR_TOOL = {
|
|||||||
|
|
||||||
|
|
||||||
DEFAULT_RELEASE_COMPILER_TOOL = {
|
DEFAULT_RELEASE_COMPILER_TOOL = {
|
||||||
:executable => FilePathUtils.os_executable_ext('gcc').freeze,
|
:executable => ENV['CC'].nil? ? FilePathUtils.os_executable_ext('gcc').freeze : ENV['CC'].split[0],
|
||||||
:name => 'default_release_compiler'.freeze,
|
:name => 'default_release_compiler'.freeze,
|
||||||
:stderr_redirect => StdErrRedirect::NONE.freeze,
|
:stderr_redirect => StdErrRedirect::NONE.freeze,
|
||||||
:background_exec => BackgroundExec::NONE.freeze,
|
:background_exec => BackgroundExec::NONE.freeze,
|
||||||
:optional => false.freeze,
|
:optional => false.freeze,
|
||||||
:arguments => [
|
:arguments => [
|
||||||
|
ENV['CC'].nil? ? "" : ENV['CC'].split[1..-1],
|
||||||
|
ENV['CPPFLAGS'].nil? ? "" : ENV['CPPFLAGS'].split,
|
||||||
{"-I\"$\"" => 'COLLECTION_PATHS_SOURCE_INCLUDE_VENDOR'}.freeze,
|
{"-I\"$\"" => 'COLLECTION_PATHS_SOURCE_INCLUDE_VENDOR'}.freeze,
|
||||||
{"-I\"$\"" => 'COLLECTION_PATHS_RELEASE_TOOLCHAIN_INCLUDE'}.freeze,
|
{"-I\"$\"" => 'COLLECTION_PATHS_RELEASE_TOOLCHAIN_INCLUDE'}.freeze,
|
||||||
{"-D$" => 'COLLECTION_DEFINES_RELEASE_AND_VENDOR'}.freeze,
|
{"-D$" => 'COLLECTION_DEFINES_RELEASE_AND_VENDOR'}.freeze,
|
||||||
"-DGNU_COMPILER".freeze,
|
"-DGNU_COMPILER".freeze,
|
||||||
|
ENV['CFLAGS'].nil? ? "" : ENV['CFLAGS'].split,
|
||||||
"-c \"${1}\"".freeze,
|
"-c \"${1}\"".freeze,
|
||||||
"-o \"${2}\"".freeze,
|
"-o \"${2}\"".freeze,
|
||||||
# gcc's list file output options are complex; no use of ${3} parameter in default config
|
# gcc's list file output options are complex; no use of ${3} parameter in default config
|
||||||
@ -166,12 +204,14 @@ DEFAULT_RELEASE_COMPILER_TOOL = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DEFAULT_RELEASE_ASSEMBLER_TOOL = {
|
DEFAULT_RELEASE_ASSEMBLER_TOOL = {
|
||||||
:executable => FilePathUtils.os_executable_ext('as').freeze,
|
:executable => ENV['AS'].nil? ? FilePathUtils.os_executable_ext('as').freeze : ENV['AS'].split[0],
|
||||||
:name => 'default_release_assembler'.freeze,
|
:name => 'default_release_assembler'.freeze,
|
||||||
:stderr_redirect => StdErrRedirect::NONE.freeze,
|
:stderr_redirect => StdErrRedirect::NONE.freeze,
|
||||||
:background_exec => BackgroundExec::NONE.freeze,
|
:background_exec => BackgroundExec::NONE.freeze,
|
||||||
:optional => false.freeze,
|
:optional => false.freeze,
|
||||||
:arguments => [
|
:arguments => [
|
||||||
|
ENV['AS'].nil? ? "" : ENV['AS'].split[1..-1],
|
||||||
|
ENV['ASFLAGS'].nil? ? "" : ENV['ASFLAGS'].split,
|
||||||
{"-I\"$\"" => 'COLLECTION_PATHS_SOURCE_AND_INCLUDE'}.freeze,
|
{"-I\"$\"" => 'COLLECTION_PATHS_SOURCE_AND_INCLUDE'}.freeze,
|
||||||
"\"${1}\"".freeze,
|
"\"${1}\"".freeze,
|
||||||
"-o \"${2}\"".freeze,
|
"-o \"${2}\"".freeze,
|
||||||
@ -179,16 +219,21 @@ DEFAULT_RELEASE_ASSEMBLER_TOOL = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DEFAULT_RELEASE_LINKER_TOOL = {
|
DEFAULT_RELEASE_LINKER_TOOL = {
|
||||||
:executable => FilePathUtils.os_executable_ext('gcc').freeze,
|
:executable => ENV['CCLD'].nil? ? FilePathUtils.os_executable_ext('gcc').freeze : ENV['CCLD'].split[0],
|
||||||
:name => 'default_release_linker'.freeze,
|
:name => 'default_release_linker'.freeze,
|
||||||
:stderr_redirect => StdErrRedirect::NONE.freeze,
|
:stderr_redirect => StdErrRedirect::NONE.freeze,
|
||||||
:background_exec => BackgroundExec::NONE.freeze,
|
:background_exec => BackgroundExec::NONE.freeze,
|
||||||
:optional => false.freeze,
|
:optional => false.freeze,
|
||||||
:arguments => [
|
:arguments => [
|
||||||
|
ENV['CCLD'].nil? ? "" : ENV['CCLD'].split[1..-1],
|
||||||
|
ENV['CFLAGS'].nil? ? "" : ENV['CFLAGS'].split,
|
||||||
|
ENV['LDFLAGS'].nil? ? "" : ENV['LDFLAGS'].split,
|
||||||
"\"${1}\"".freeze,
|
"\"${1}\"".freeze,
|
||||||
|
"${5}".freeze,
|
||||||
"-o \"${2}\"".freeze,
|
"-o \"${2}\"".freeze,
|
||||||
"".freeze,
|
"".freeze,
|
||||||
"${4}".freeze
|
"${4}".freeze,
|
||||||
|
ENV['LDLIBS'].nil? ? "" : ENV['LDLIBS'].split
|
||||||
].freeze
|
].freeze
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,6 +250,7 @@ DEFAULT_TOOLS_TEST_PREPROCESSORS = {
|
|||||||
:tools => {
|
:tools => {
|
||||||
:test_includes_preprocessor => DEFAULT_TEST_INCLUDES_PREPROCESSOR_TOOL,
|
:test_includes_preprocessor => DEFAULT_TEST_INCLUDES_PREPROCESSOR_TOOL,
|
||||||
:test_file_preprocessor => DEFAULT_TEST_FILE_PREPROCESSOR_TOOL,
|
:test_file_preprocessor => DEFAULT_TEST_FILE_PREPROCESSOR_TOOL,
|
||||||
|
:test_file_preprocessor_directives => DEFAULT_TEST_FILE_PREPROCESSOR_DIRECTIVES_TOOL,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -245,8 +291,10 @@ DEFAULT_CEEDLING_CONFIG = {
|
|||||||
:compile_threads => 1,
|
:compile_threads => 1,
|
||||||
:test_threads => 1,
|
:test_threads => 1,
|
||||||
:use_test_preprocessor => false,
|
:use_test_preprocessor => false,
|
||||||
|
:use_preprocessor_directives => false,
|
||||||
:use_deep_dependencies => false,
|
:use_deep_dependencies => false,
|
||||||
:generate_deep_dependencies => true, # only applicable if use_deep_dependencies is true
|
:generate_deep_dependencies => true, # only applicable if use_deep_dependencies is true
|
||||||
|
:auto_link_deep_dependencies => false,
|
||||||
:test_file_prefix => 'test_',
|
:test_file_prefix => 'test_',
|
||||||
:options_paths => [],
|
:options_paths => [],
|
||||||
:release_build => false,
|
:release_build => false,
|
||||||
@ -263,6 +311,7 @@ DEFAULT_CEEDLING_CONFIG = {
|
|||||||
:source => [], # must be populated by user
|
:source => [], # must be populated by user
|
||||||
:support => [],
|
:support => [],
|
||||||
:include => [],
|
:include => [],
|
||||||
|
:libraries => [],
|
||||||
:test_toolchain_include => [],
|
:test_toolchain_include => [],
|
||||||
:release_toolchain_include => [],
|
:release_toolchain_include => [],
|
||||||
},
|
},
|
||||||
@ -290,6 +339,8 @@ DEFAULT_CEEDLING_CONFIG = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
:libraries => {
|
:libraries => {
|
||||||
|
:flag => '-l${1}',
|
||||||
|
:path_flag => '-L ${1}',
|
||||||
:test => [],
|
:test => [],
|
||||||
:test_preprocess => [],
|
:test_preprocess => [],
|
||||||
:release => [],
|
:release => [],
|
||||||
@ -303,6 +354,7 @@ DEFAULT_CEEDLING_CONFIG = {
|
|||||||
:source => '.c',
|
:source => '.c',
|
||||||
:assembly => '.s',
|
:assembly => '.s',
|
||||||
:object => '.o',
|
:object => '.o',
|
||||||
|
:libraries => ['.a','.so'],
|
||||||
:executable => ( SystemWrapper.windows? ? EXTENSION_WIN_EXE : EXTENSION_NONWIN_EXE ),
|
:executable => ( SystemWrapper.windows? ? EXTENSION_WIN_EXE : EXTENSION_NONWIN_EXE ),
|
||||||
:map => '.map',
|
:map => '.map',
|
||||||
:list => '.lst',
|
:list => '.lst',
|
||||||
@ -345,6 +397,7 @@ DEFAULT_CEEDLING_CONFIG = {
|
|||||||
},
|
},
|
||||||
:test_includes_preprocessor => { :arguments => [] },
|
:test_includes_preprocessor => { :arguments => [] },
|
||||||
:test_file_preprocessor => { :arguments => [] },
|
:test_file_preprocessor => { :arguments => [] },
|
||||||
|
:test_file_preprocessor_directives => { :arguments => [] },
|
||||||
:test_dependencies_generator => { :arguments => [] },
|
:test_dependencies_generator => { :arguments => [] },
|
||||||
:release_compiler => { :arguments => [] },
|
:release_compiler => { :arguments => [] },
|
||||||
:release_linker => { :arguments => [] },
|
:release_linker => { :arguments => [] },
|
||||||
|
@ -86,13 +86,12 @@ class Dependinator
|
|||||||
|
|
||||||
|
|
||||||
def enhance_results_dependencies(result_filepath)
|
def enhance_results_dependencies(result_filepath)
|
||||||
@rake_wrapper[result_filepath].enhance( [@configurator.project_test_force_rebuild_filepath] ) if (@project_config_manager.test_config_changed ||
|
@rake_wrapper[result_filepath].enhance( [@configurator.project_test_force_rebuild_filepath] ) if @project_config_manager.test_config_changed
|
||||||
@project_config_manager.test_defines_changed)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
def setup_test_executable_dependencies(test, objects)
|
def enhance_test_executable_dependencies(test, objects)
|
||||||
@rake_wrapper.create_file_task( @file_path_utils.form_test_executable_filepath(test), objects )
|
@rake_wrapper[ @file_path_utils.form_test_executable_filepath(test) ].enhance( objects )
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -25,10 +25,12 @@ class FileFinderHelper
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
case (complain)
|
if file_to_find.nil?
|
||||||
when :error then blow_up(file_name, extra_message) if (file_to_find.nil?)
|
case (complain)
|
||||||
when :warn then gripe(file_name, extra_message) if (file_to_find.nil?)
|
when :error then blow_up(file_name, extra_message)
|
||||||
#when :ignore then
|
when :warn then gripe(file_name, extra_message)
|
||||||
|
#when :ignore then
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return file_to_find
|
return file_to_find
|
||||||
|
@ -21,9 +21,11 @@ class FilePathUtils
|
|||||||
|
|
||||||
# standardize path to use '/' path separator & have no trailing path separator
|
# standardize path to use '/' path separator & have no trailing path separator
|
||||||
def self.standardize(path)
|
def self.standardize(path)
|
||||||
path.strip!
|
if path.is_a? String
|
||||||
path.gsub!(/\\/, '/')
|
path.strip!
|
||||||
path.chomp!('/')
|
path.gsub!(/\\/, '/')
|
||||||
|
path.chomp!('/')
|
||||||
|
end
|
||||||
return path
|
return path
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -33,15 +33,15 @@ class FileWrapper
|
|||||||
end
|
end
|
||||||
|
|
||||||
def rm_f(filepath, options={})
|
def rm_f(filepath, options={})
|
||||||
FileUtils.rm_f(filepath, options)
|
FileUtils.rm_f(filepath, **options)
|
||||||
end
|
end
|
||||||
|
|
||||||
def rm_r(filepath, options={})
|
def rm_r(filepath, options={})
|
||||||
FileUtils.rm_r(filepath, options={})
|
FileUtils.rm_r(filepath, **options={})
|
||||||
end
|
end
|
||||||
|
|
||||||
def cp(source, destination, options={})
|
def cp(source, destination, options={})
|
||||||
FileUtils.cp(source, destination, options)
|
FileUtils.cp(source, destination, **options)
|
||||||
end
|
end
|
||||||
|
|
||||||
def compare(from, to)
|
def compare(from, to)
|
||||||
@ -59,7 +59,7 @@ class FileWrapper
|
|||||||
end
|
end
|
||||||
|
|
||||||
def touch(filepath, options={})
|
def touch(filepath, options={})
|
||||||
FileUtils.touch(filepath, options)
|
FileUtils.touch(filepath, **options)
|
||||||
end
|
end
|
||||||
|
|
||||||
def write(filepath, contents, flags='w')
|
def write(filepath, contents, flags='w')
|
||||||
|
@ -101,19 +101,21 @@ class Generator
|
|||||||
shell_result = ex.shell_result
|
shell_result = ex.shell_result
|
||||||
raise ex
|
raise ex
|
||||||
ensure
|
ensure
|
||||||
|
arg_hash[:shell_command] = command[:line]
|
||||||
arg_hash[:shell_result] = shell_result
|
arg_hash[:shell_result] = shell_result
|
||||||
@plugin_manager.post_compile_execute(arg_hash)
|
@plugin_manager.post_compile_execute(arg_hash)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def generate_executable_file(tool, context, objects, executable, map='', libraries=[])
|
def generate_executable_file(tool, context, objects, executable, map='', libraries=[], libpaths=[])
|
||||||
shell_result = {}
|
shell_result = {}
|
||||||
arg_hash = { :tool => tool,
|
arg_hash = { :tool => tool,
|
||||||
:context => context,
|
:context => context,
|
||||||
:objects => objects,
|
:objects => objects,
|
||||||
:executable => executable,
|
:executable => executable,
|
||||||
:map => map,
|
:map => map,
|
||||||
:libraries => libraries
|
:libraries => libraries,
|
||||||
|
:libpaths => libpaths
|
||||||
}
|
}
|
||||||
|
|
||||||
@plugin_manager.pre_link_execute(arg_hash)
|
@plugin_manager.pre_link_execute(arg_hash)
|
||||||
@ -125,7 +127,8 @@ class Generator
|
|||||||
arg_hash[:objects],
|
arg_hash[:objects],
|
||||||
arg_hash[:executable],
|
arg_hash[:executable],
|
||||||
arg_hash[:map],
|
arg_hash[:map],
|
||||||
arg_hash[:libraries]
|
arg_hash[:libraries],
|
||||||
|
arg_hash[:libpaths]
|
||||||
)
|
)
|
||||||
@streaminator.stdout_puts("Command: #{command}", Verbosity::DEBUG)
|
@streaminator.stdout_puts("Command: #{command}", Verbosity::DEBUG)
|
||||||
|
|
||||||
|
@ -37,6 +37,10 @@ class GeneratorTestResults
|
|||||||
elements = extract_line_elements(line, results[:source][:file])
|
elements = extract_line_elements(line, results[:source][:file])
|
||||||
results[:successes] << elements[0]
|
results[:successes] << elements[0]
|
||||||
results[:stdout] << elements[1] if (!elements[1].nil?)
|
results[:stdout] << elements[1] if (!elements[1].nil?)
|
||||||
|
when /(:PASS \(.* ms\)$)/
|
||||||
|
elements = extract_line_elements(line, results[:source][:file])
|
||||||
|
results[:successes] << elements[0]
|
||||||
|
results[:stdout] << elements[1] if (!elements[1].nil?)
|
||||||
when /(:FAIL)/
|
when /(:FAIL)/
|
||||||
elements = extract_line_elements(line, results[:source][:file])
|
elements = extract_line_elements(line, results[:source][:file])
|
||||||
results[:failures] << elements[0]
|
results[:failures] << elements[0]
|
||||||
@ -73,6 +77,7 @@ class GeneratorTestResults
|
|||||||
# handle anything preceding filename in line as extra output to be collected
|
# handle anything preceding filename in line as extra output to be collected
|
||||||
stdout = nil
|
stdout = nil
|
||||||
stdout_regex = /(.+)#{Regexp.escape(filename)}.+/i
|
stdout_regex = /(.+)#{Regexp.escape(filename)}.+/i
|
||||||
|
unity_test_time = 0
|
||||||
|
|
||||||
if (line =~ stdout_regex)
|
if (line =~ stdout_regex)
|
||||||
stdout = $1.clone
|
stdout = $1.clone
|
||||||
@ -82,8 +87,14 @@ class GeneratorTestResults
|
|||||||
# collect up test results minus and extra output
|
# collect up test results minus and extra output
|
||||||
elements = (line.strip.split(':'))[1..-1]
|
elements = (line.strip.split(':'))[1..-1]
|
||||||
|
|
||||||
return {:test => elements[1], :line => elements[0].to_i, :message => (elements[3..-1].join(':')).strip}, stdout if elements.size >= 3
|
# find timestamp if available
|
||||||
return {:test => '???', :line => -1, :message => nil} #fallback safe option. TODO better handling
|
if (elements[-1] =~ / \((\d*(?:\.\d*)?) ms\)/)
|
||||||
|
unity_test_time = $1.to_f / 1000
|
||||||
|
elements[-1].sub!(/ \((\d*(?:\.\d*)?) ms\)/, '')
|
||||||
|
end
|
||||||
|
|
||||||
|
return {:test => elements[1], :line => elements[0].to_i, :message => (elements[3..-1].join(':')).strip, :unity_test_time => unity_test_time}, stdout if elements.size >= 3
|
||||||
|
return {:test => '???', :line => -1, :message => nil, :unity_test_time => unity_test_time} #fallback safe option. TODO better handling
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -44,13 +44,15 @@ class GeneratorTestRunner
|
|||||||
def generate(module_name, runner_filepath, test_cases, mock_list, test_file_includes=[])
|
def generate(module_name, runner_filepath, test_cases, mock_list, test_file_includes=[])
|
||||||
require 'generate_test_runner.rb'
|
require 'generate_test_runner.rb'
|
||||||
|
|
||||||
|
header_extension = @configurator.extension_header
|
||||||
|
|
||||||
#actually build the test runner using Unity's test runner generator
|
#actually build the test runner using Unity's test runner generator
|
||||||
#(there is no need to use preprocessor here because we've already looked up test cases and are passing them in here)
|
#(there is no need to use preprocessor here because we've already looked up test cases and are passing them in here)
|
||||||
@test_runner_generator ||= UnityTestRunnerGenerator.new( @configurator.get_runner_config )
|
@test_runner_generator ||= UnityTestRunnerGenerator.new( @configurator.get_runner_config )
|
||||||
@test_runner_generator.generate( module_name,
|
@test_runner_generator.generate( module_name,
|
||||||
runner_filepath,
|
runner_filepath,
|
||||||
test_cases,
|
test_cases,
|
||||||
mock_list,
|
mock_list.map{|f| File.basename(f,'.*')+header_extension},
|
||||||
test_file_includes)
|
test_file_includes.map{|f| File.basename(f,'.*')+header_extension})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
49
test/vendor/ceedling/lib/ceedling/objects.yml
vendored
49
test/vendor/ceedling/lib/ceedling/objects.yml
vendored
@ -17,11 +17,11 @@ reportinator:
|
|||||||
|
|
||||||
rake_utils:
|
rake_utils:
|
||||||
compose:
|
compose:
|
||||||
- rake_wrapper
|
- rake_wrapper
|
||||||
|
|
||||||
system_utils:
|
system_utils:
|
||||||
compose:
|
compose:
|
||||||
- system_wrapper
|
- system_wrapper
|
||||||
|
|
||||||
file_path_utils:
|
file_path_utils:
|
||||||
compose:
|
compose:
|
||||||
@ -203,13 +203,13 @@ generator_helper:
|
|||||||
|
|
||||||
generator_test_results:
|
generator_test_results:
|
||||||
compose:
|
compose:
|
||||||
- configurator
|
- configurator
|
||||||
- generator_test_results_sanity_checker
|
- generator_test_results_sanity_checker
|
||||||
- yaml_wrapper
|
- yaml_wrapper
|
||||||
|
|
||||||
generator_test_results_sanity_checker:
|
generator_test_results_sanity_checker:
|
||||||
compose:
|
compose:
|
||||||
- configurator
|
- configurator
|
||||||
- streaminator
|
- streaminator
|
||||||
|
|
||||||
generator_test_runner:
|
generator_test_runner:
|
||||||
@ -223,43 +223,46 @@ dependinator:
|
|||||||
- configurator
|
- configurator
|
||||||
- project_config_manager
|
- project_config_manager
|
||||||
- test_includes_extractor
|
- test_includes_extractor
|
||||||
- file_path_utils
|
- file_path_utils
|
||||||
- rake_wrapper
|
- rake_wrapper
|
||||||
- file_wrapper
|
- file_wrapper
|
||||||
|
|
||||||
preprocessinator:
|
preprocessinator:
|
||||||
compose:
|
compose:
|
||||||
- preprocessinator_helper
|
- preprocessinator_helper
|
||||||
- preprocessinator_includes_handler
|
- preprocessinator_includes_handler
|
||||||
- preprocessinator_file_handler
|
- preprocessinator_file_handler
|
||||||
- task_invoker
|
- task_invoker
|
||||||
- file_path_utils
|
- file_path_utils
|
||||||
- yaml_wrapper
|
- yaml_wrapper
|
||||||
|
- project_config_manager
|
||||||
|
- configurator
|
||||||
|
|
||||||
preprocessinator_helper:
|
preprocessinator_helper:
|
||||||
compose:
|
compose:
|
||||||
- configurator
|
- configurator
|
||||||
- test_includes_extractor
|
- test_includes_extractor
|
||||||
- task_invoker
|
- task_invoker
|
||||||
- file_finder
|
- file_finder
|
||||||
- file_path_utils
|
- file_path_utils
|
||||||
|
|
||||||
preprocessinator_includes_handler:
|
preprocessinator_includes_handler:
|
||||||
compose:
|
compose:
|
||||||
- configurator
|
- configurator
|
||||||
- tool_executor
|
- tool_executor
|
||||||
- task_invoker
|
- task_invoker
|
||||||
- file_path_utils
|
- file_path_utils
|
||||||
- yaml_wrapper
|
- yaml_wrapper
|
||||||
- file_wrapper
|
- file_wrapper
|
||||||
|
- file_finder
|
||||||
|
|
||||||
preprocessinator_file_handler:
|
preprocessinator_file_handler:
|
||||||
compose:
|
compose:
|
||||||
- preprocessinator_extractor
|
- preprocessinator_extractor
|
||||||
- configurator
|
- configurator
|
||||||
- tool_executor
|
- tool_executor
|
||||||
- file_path_utils
|
- file_path_utils
|
||||||
- file_wrapper
|
- file_wrapper
|
||||||
|
|
||||||
preprocessinator_extractor:
|
preprocessinator_extractor:
|
||||||
|
|
||||||
|
@ -1,29 +1,38 @@
|
|||||||
|
|
||||||
class Preprocessinator
|
class Preprocessinator
|
||||||
|
|
||||||
attr_reader :preprocess_file_proc
|
constructor :preprocessinator_helper, :preprocessinator_includes_handler, :preprocessinator_file_handler, :task_invoker, :file_path_utils, :yaml_wrapper, :project_config_manager, :configurator
|
||||||
|
|
||||||
constructor :preprocessinator_helper, :preprocessinator_includes_handler, :preprocessinator_file_handler, :task_invoker, :file_path_utils, :yaml_wrapper
|
|
||||||
|
|
||||||
|
|
||||||
def setup
|
def setup
|
||||||
# fashion ourselves callbacks @preprocessinator_helper can use
|
# fashion ourselves callbacks @preprocessinator_helper can use
|
||||||
@preprocess_includes_proc = Proc.new { |filepath| self.preprocess_shallow_includes(filepath) }
|
@preprocess_includes_proc = Proc.new { |filepath| self.preprocess_shallow_includes(filepath) }
|
||||||
@preprocess_file_proc = Proc.new { |filepath| self.preprocess_file(filepath) }
|
@preprocess_mock_file_proc = Proc.new { |filepath| self.preprocess_file(filepath) }
|
||||||
|
@preprocess_test_file_directives_proc = Proc.new { |filepath| self.preprocess_file_directives(filepath) }
|
||||||
|
@preprocess_test_file_proc = Proc.new { |filepath| self.preprocess_file(filepath) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def preprocess_shallow_source_includes(test)
|
||||||
|
@preprocessinator_helper.preprocess_source_includes(test)
|
||||||
|
end
|
||||||
|
|
||||||
def preprocess_test_and_invoke_test_mocks(test)
|
def preprocess_test_and_invoke_test_mocks(test)
|
||||||
@preprocessinator_helper.preprocess_includes(test, @preprocess_includes_proc)
|
@preprocessinator_helper.preprocess_includes(test, @preprocess_includes_proc)
|
||||||
|
|
||||||
mocks_list = @preprocessinator_helper.assemble_mocks_list(test)
|
mocks_list = @preprocessinator_helper.assemble_mocks_list(test)
|
||||||
|
|
||||||
@preprocessinator_helper.preprocess_mockable_headers(mocks_list, @preprocess_file_proc)
|
@project_config_manager.process_test_defines_change(mocks_list)
|
||||||
|
|
||||||
|
@preprocessinator_helper.preprocess_mockable_headers(mocks_list, @preprocess_mock_file_proc)
|
||||||
|
|
||||||
@task_invoker.invoke_test_mocks(mocks_list)
|
@task_invoker.invoke_test_mocks(mocks_list)
|
||||||
|
|
||||||
@preprocessinator_helper.preprocess_test_file(test, @preprocess_file_proc)
|
if (@configurator.project_use_preprocessor_directives)
|
||||||
|
@preprocessinator_helper.preprocess_test_file(test, @preprocess_test_file_directives_proc)
|
||||||
|
else
|
||||||
|
@preprocessinator_helper.preprocess_test_file(test, @preprocess_test_file_proc)
|
||||||
|
end
|
||||||
|
|
||||||
return mocks_list
|
return mocks_list
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -39,4 +48,9 @@ class Preprocessinator
|
|||||||
@preprocessinator_file_handler.preprocess_file( filepath, @yaml_wrapper.load(@file_path_utils.form_preprocessed_includes_list_filepath(filepath)) )
|
@preprocessinator_file_handler.preprocess_file( filepath, @yaml_wrapper.load(@file_path_utils.form_preprocessed_includes_list_filepath(filepath)) )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def preprocess_file_directives(filepath)
|
||||||
|
@preprocessinator_includes_handler.invoke_shallow_includes_list( filepath )
|
||||||
|
@preprocessinator_file_handler.preprocess_file_directives( filepath,
|
||||||
|
@yaml_wrapper.load( @file_path_utils.form_preprocessed_includes_list_filepath( filepath ) ) )
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -16,6 +16,7 @@ class PreprocessinatorExtractor
|
|||||||
|
|
||||||
lines = []
|
lines = []
|
||||||
File.readlines(filepath).each do |line|
|
File.readlines(filepath).each do |line|
|
||||||
|
line.encode!('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '')
|
||||||
if found_file and not line =~ not_pragma
|
if found_file and not line =~ not_pragma
|
||||||
lines << line
|
lines << line
|
||||||
else
|
else
|
||||||
@ -27,4 +28,28 @@ class PreprocessinatorExtractor
|
|||||||
|
|
||||||
return lines
|
return lines
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def extract_base_file_from_preprocessed_directives(filepath)
|
||||||
|
# preprocessing by way of toolchain preprocessor eliminates directives only
|
||||||
|
# like #ifdef's and leave other code
|
||||||
|
|
||||||
|
# iterate through all lines and only get last chunk of file after a last
|
||||||
|
# '#'line containing file name of our filepath
|
||||||
|
|
||||||
|
base_name = File.basename(filepath)
|
||||||
|
pattern = /^#.*(\s|\/|\\|\")#{Regexp.escape(base_name)}/
|
||||||
|
found_file = false # have we found the file we care about?
|
||||||
|
|
||||||
|
lines = []
|
||||||
|
File.readlines(filepath).each do |line|
|
||||||
|
line.encode!('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '')
|
||||||
|
lines << line
|
||||||
|
|
||||||
|
if line =~ pattern
|
||||||
|
lines = []
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return lines
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -18,4 +18,17 @@ class PreprocessinatorFileHandler
|
|||||||
@file_wrapper.write(preprocessed_filepath, contents.join("\n"))
|
@file_wrapper.write(preprocessed_filepath, contents.join("\n"))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def preprocess_file_directives(filepath, includes)
|
||||||
|
preprocessed_filepath = @file_path_utils.form_preprocessed_file_filepath(filepath)
|
||||||
|
|
||||||
|
command = @tool_executor.build_command_line(@configurator.tools_test_file_preprocessor_directives, [], filepath, preprocessed_filepath)
|
||||||
|
@tool_executor.exec(command[:line], command[:options])
|
||||||
|
|
||||||
|
contents = @preprocessinator_extractor.extract_base_file_from_preprocessed_directives(preprocessed_filepath)
|
||||||
|
|
||||||
|
includes.each{|include| contents.unshift("#include \"#{include}\"")}
|
||||||
|
|
||||||
|
@file_wrapper.write(preprocessed_filepath, contents.join("\n"))
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -15,6 +15,10 @@ class PreprocessinatorHelper
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def preprocess_source_includes(test)
|
||||||
|
@test_includes_extractor.parse_test_file_source_include(test)
|
||||||
|
end
|
||||||
|
|
||||||
def assemble_mocks_list(test)
|
def assemble_mocks_list(test)
|
||||||
return @file_path_utils.form_mocks_source_filelist( @test_includes_extractor.lookup_raw_mock_list(test) )
|
return @file_path_utils.form_mocks_source_filelist( @test_includes_extractor.lookup_raw_mock_list(test) )
|
||||||
end
|
end
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
class PreprocessinatorIncludesHandler
|
class PreprocessinatorIncludesHandler
|
||||||
|
|
||||||
constructor :configurator, :tool_executor, :task_invoker, :file_path_utils, :yaml_wrapper, :file_wrapper
|
constructor :configurator, :tool_executor, :task_invoker, :file_path_utils, :yaml_wrapper, :file_wrapper, :file_finder
|
||||||
@@makefile_cache = {}
|
@@makefile_cache = {}
|
||||||
|
|
||||||
# shallow includes: only those headers a source file explicitly includes
|
# shallow includes: only those headers a source file explicitly includes
|
||||||
@ -65,6 +65,7 @@ class PreprocessinatorIncludesHandler
|
|||||||
to_process = [filepath]
|
to_process = [filepath]
|
||||||
ignore_list = []
|
ignore_list = []
|
||||||
list = []
|
list = []
|
||||||
|
all_mocks = []
|
||||||
|
|
||||||
include_paths = @configurator.project_config_hash[:collection_paths_include]
|
include_paths = @configurator.project_config_hash[:collection_paths_include]
|
||||||
include_paths = [] if include_paths.nil?
|
include_paths = [] if include_paths.nil?
|
||||||
@ -73,12 +74,10 @@ class PreprocessinatorIncludesHandler
|
|||||||
while to_process.length > 0
|
while to_process.length > 0
|
||||||
target = to_process.shift()
|
target = to_process.shift()
|
||||||
ignore_list << target
|
ignore_list << target
|
||||||
# puts "[HELL] Processing: \t\t#{target}"
|
new_deps, new_to_process, all_mocks = extract_includes_helper(target, include_paths, ignore_list, all_mocks)
|
||||||
new_deps, new_to_process = extract_includes_helper(target, include_paths, ignore_list)
|
|
||||||
list += new_deps
|
list += new_deps
|
||||||
to_process += new_to_process
|
to_process += new_to_process
|
||||||
if (!@configurator.project_config_hash.has_key?(:project_auto_link_deep_dependencies) or
|
if !@configurator.project_config_hash[:project_auto_link_deep_dependencies]
|
||||||
!@configurator.project_config_hash[:project_auto_link_deep_dependencies])
|
|
||||||
break
|
break
|
||||||
else
|
else
|
||||||
list = list.uniq()
|
list = list.uniq()
|
||||||
@ -89,93 +88,102 @@ class PreprocessinatorIncludesHandler
|
|||||||
return list
|
return list
|
||||||
end
|
end
|
||||||
|
|
||||||
def extract_includes_helper(filepath, include_paths, ignore_list)
|
def extract_includes_helper(filepath, include_paths, ignore_list, mocks)
|
||||||
# Extract the dependencies from the make rule
|
# Extract the dependencies from the make rule
|
||||||
hdr_ext = @configurator.extension_header
|
|
||||||
make_rule = self.form_shallow_dependencies_rule(filepath)
|
make_rule = self.form_shallow_dependencies_rule(filepath)
|
||||||
dependencies = make_rule.split.find_all {|path| path.end_with?(hdr_ext) }.uniq
|
target_file = make_rule.split[0].gsub(':', '').gsub('\\','/')
|
||||||
dependencies.map! {|hdr| hdr.gsub('\\','/') }
|
base = File.basename(target_file, File.extname(target_file))
|
||||||
|
make_rule_dependencies = make_rule.gsub(/.*\b#{Regexp.escape(base)}\S*/, '').gsub(/\\$/, '')
|
||||||
|
|
||||||
|
# Extract the headers dependencies from the make rule
|
||||||
|
hdr_ext = @configurator.extension_header
|
||||||
|
headers_dependencies = make_rule_dependencies.split.find_all {|path| path.end_with?(hdr_ext) }.uniq
|
||||||
|
headers_dependencies.map! {|hdr| hdr.gsub('\\','/') }
|
||||||
|
full_path_headers_dependencies = extract_full_path_dependencies(headers_dependencies)
|
||||||
|
|
||||||
# Separate the real files form the annotated ones and remove the '@@@@'
|
# Extract the sources dependencies from the make rule
|
||||||
annotated_headers, real_headers = dependencies.partition {|hdr| hdr =~ /^@@@@/ }
|
src_ext = @configurator.extension_source
|
||||||
annotated_headers.map! {|hdr| hdr.gsub('@@@@','') }
|
sources_dependencies = make_rule_dependencies.split.find_all {|path| path.end_with?(src_ext) }.uniq
|
||||||
# Matching annotated_headers values against real_headers to ensure that
|
sources_dependencies.map! {|src| src.gsub('\\','/') }
|
||||||
# annotated_headers contain full path entries (as returned by make rule)
|
full_path_sources_dependencies = extract_full_path_dependencies(sources_dependencies)
|
||||||
annotated_headers.map! {|hdr| real_headers.find {|real_hdr| !real_hdr.match(/(.*\/)?#{Regexp.escape(hdr)}/).nil? } }
|
|
||||||
annotated_headers = annotated_headers.compact
|
|
||||||
|
|
||||||
# Find which of our annotated headers are "real" dependencies. This is
|
list = full_path_headers_dependencies + full_path_sources_dependencies
|
||||||
# intended to weed out dependencies that have been removed due to build
|
|
||||||
# options defined in the project yaml and/or in the headers themselves.
|
mock_prefix = @configurator.project_config_hash[:cmock_mock_prefix]
|
||||||
list = annotated_headers.find_all do |annotated_header|
|
# Creating list of mocks
|
||||||
# find the index of the "real" include that matches the annotated one.
|
mocks += full_path_headers_dependencies.find_all do |header|
|
||||||
idx = real_headers.find_index do |real_header|
|
File.basename(header) =~ /^#{mock_prefix}.*$/
|
||||||
real_header =~ /^(.*\/)?#{Regexp.escape(annotated_header)}$/
|
|
||||||
end
|
|
||||||
# If we found a real include, delete it from the array and return it,
|
|
||||||
# otherwise return nil. Since nil is falsy this has the effect of making
|
|
||||||
# find_all return only the annotated headers for which a real include was
|
|
||||||
# found/deleted
|
|
||||||
idx ? real_headers.delete_at(idx) : nil
|
|
||||||
end.compact
|
end.compact
|
||||||
|
|
||||||
# Extract direct dependencies that were also added
|
# ignore real file when both mock and real file exist
|
||||||
src_ext = @configurator.extension_source
|
mocks.each do |mock|
|
||||||
sdependencies = make_rule.split.find_all {|path| path.end_with?(src_ext) }.uniq
|
list.each do |filename|
|
||||||
sdependencies.map! {|hdr| hdr.gsub('\\','/') }
|
if File.basename(filename) == File.basename(mock).sub(mock_prefix, '')
|
||||||
list += sdependencies
|
ignore_list << filename
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end.compact
|
||||||
|
|
||||||
|
# Filtering list of final includes to only include mocks and anything that is NOT in the ignore_list
|
||||||
|
list = list.select do |item|
|
||||||
|
mocks.include? item or !(ignore_list.any? { |ignore_item| !item.match(/^(.*\/)?#{Regexp.escape(ignore_item)}$/).nil? })
|
||||||
|
end
|
||||||
|
|
||||||
to_process = []
|
to_process = []
|
||||||
|
|
||||||
if @configurator.project_config_hash.has_key?(:project_auto_link_deep_dependencies) && @configurator.project_config_hash[:project_auto_link_deep_dependencies]
|
if @configurator.project_config_hash[:project_auto_link_deep_dependencies]
|
||||||
# Creating list of mocks
|
|
||||||
mocks = annotated_headers.find_all do |annotated_header|
|
|
||||||
File.basename(annotated_header) =~ /^#{@configurator.project_config_hash[:cmock_mock_prefix]}.*$/
|
|
||||||
end.compact
|
|
||||||
|
|
||||||
# Creating list of headers that should be recursively pre-processed
|
# Creating list of headers that should be recursively pre-processed
|
||||||
# Skipping mocks and unity.h
|
# Skipping mocks and vendor headers
|
||||||
headers_to_deep_link = annotated_headers.select do |annotated_header|
|
headers_to_deep_link = full_path_headers_dependencies.select do |hdr|
|
||||||
!(mocks.include? annotated_header) and (annotated_header.match(/^(.*\/)?unity\.h$/).nil?)
|
!(mocks.include? hdr) and (hdr.match(/^(.*\/)(#{VENDORS_FILES.join('|')}) + #{Regexp.escape(hdr_ext)}$/).nil?)
|
||||||
end
|
|
||||||
headers_to_deep_link.map! {|hdr| File.expand_path(hdr)}
|
|
||||||
|
|
||||||
mocks.each do |mock|
|
|
||||||
dirname = File.dirname(mock)
|
|
||||||
#basename = File.basename(mock).delete_prefix(@configurator.project_config_hash[:cmock_mock_prefix])
|
|
||||||
basename = File.basename(mock).sub(@configurator.project_config_hash[:cmock_mock_prefix], '')
|
|
||||||
if dirname != "."
|
|
||||||
ignore_list << File.join(dirname, basename)
|
|
||||||
else
|
|
||||||
ignore_list << basename
|
|
||||||
end
|
|
||||||
end.compact
|
|
||||||
|
|
||||||
# Filtering list of final includes to only include mocks and anything that is NOT in the ignore_list
|
|
||||||
list = list.select do |item|
|
|
||||||
mocks.include? item or !(ignore_list.any? { |ignore_item| !item.match(/^(.*\/)?#{Regexp.escape(ignore_item)}$/).nil? })
|
|
||||||
end
|
end
|
||||||
|
headers_to_deep_link.map! {|hdr| File.expand_path(hdr) }
|
||||||
|
headers_to_deep_link.compact!
|
||||||
|
|
||||||
headers_to_deep_link.each do |hdr|
|
headers_to_deep_link.each do |hdr|
|
||||||
if (ignore_list.none? {|ignore_header| hdr.match(/^(.*\/)?#{Regexp.escape(ignore_header)}$/)} and
|
if (ignore_list.none? {|ignore_header| hdr.match(/^(.*\/)?#{Regexp.escape(ignore_header)}$/)} and
|
||||||
include_paths.none? {|include_path| hdr =~ /^#{include_path}\.*/})
|
include_paths.none? {|include_path| hdr =~ /^#{include_path}\.*/})
|
||||||
if File.exist?(hdr)
|
if File.exist?(hdr)
|
||||||
to_process << hdr
|
to_process << hdr
|
||||||
#source_file = hdr.delete_suffix(hdr_ext) + src_ext
|
src = @file_finder.find_compilation_input_file(hdr, :ignore)
|
||||||
source_file = hdr.chomp(hdr_ext) + src_ext
|
to_process << src if src
|
||||||
if source_file != hdr and File.exist?(source_file)
|
|
||||||
to_process << source_file
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return list, to_process
|
return list, to_process, mocks
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def write_shallow_includes_list(filepath, list)
|
def write_shallow_includes_list(filepath, list)
|
||||||
@yaml_wrapper.dump(filepath, list)
|
@yaml_wrapper.dump(filepath, list)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def extract_full_path_dependencies(dependencies)
|
||||||
|
# Separate the real files form the annotated ones and remove the '@@@@'
|
||||||
|
annotated_files, real_files = dependencies.partition {|file| file =~ /^@@@@/}
|
||||||
|
annotated_files.map! {|file| file.gsub('@@@@','') }
|
||||||
|
# Matching annotated_files values against real_files to ensure that
|
||||||
|
# annotated_files contain full path entries (as returned by make rule)
|
||||||
|
annotated_files.map! {|file| real_files.find {|real| !real.match(/^(.*\/)?#{Regexp.escape(file)}$/).nil?}}
|
||||||
|
annotated_files = annotated_files.compact
|
||||||
|
|
||||||
|
# Find which of our annotated files are "real" dependencies. This is
|
||||||
|
# intended to weed out dependencies that have been removed due to build
|
||||||
|
# options defined in the project yaml and/or in the files themselves.
|
||||||
|
return annotated_files.find_all do |annotated_file|
|
||||||
|
# find the index of the "real" file that matches the annotated one.
|
||||||
|
idx = real_files.find_index do |real_file|
|
||||||
|
real_file =~ /^(.*\/)?#{Regexp.escape(annotated_file)}$/
|
||||||
|
end
|
||||||
|
# If we found a real file, delete it from the array and return it,
|
||||||
|
# otherwise return nil. Since nil is falsy this has the effect of making
|
||||||
|
# find_all return only the annotated filess for which a real file was
|
||||||
|
# found/deleted
|
||||||
|
idx ? real_files.delete_at(idx) : nil
|
||||||
|
end.compact
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -21,9 +21,15 @@ class ProjectConfigManager
|
|||||||
@options_files << File.basename( option_filepath )
|
@options_files << File.basename( option_filepath )
|
||||||
config_hash.deep_merge!( @yaml_wrapper.load( option_filepath ) )
|
config_hash.deep_merge!( @yaml_wrapper.load( option_filepath ) )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def filter_internal_sources(sources)
|
||||||
|
filtered_sources = sources.clone
|
||||||
|
filtered_sources.delete_if { |item| item =~ /#{CMOCK_MOCK_PREFIX}.+#{Regexp.escape(EXTENSION_SOURCE)}$/ }
|
||||||
|
filtered_sources.delete_if { |item| item =~ /#{VENDORS_FILES.map{|source| '\b' + Regexp.escape(source.ext(EXTENSION_SOURCE)) + '\b'}.join('|')}$/ }
|
||||||
|
return filtered_sources
|
||||||
|
end
|
||||||
|
|
||||||
def process_release_config_change
|
def process_release_config_change
|
||||||
# has project configuration changed since last release build
|
# has project configuration changed since last release build
|
||||||
@release_config_changed = @cacheinator.diff_cached_release_config?( @config_hash )
|
@release_config_changed = @cacheinator.diff_cached_release_config?( @config_hash )
|
||||||
@ -40,7 +46,7 @@ class ProjectConfigManager
|
|||||||
@test_defines_changed = @cacheinator.diff_cached_test_defines?( files )
|
@test_defines_changed = @cacheinator.diff_cached_test_defines?( files )
|
||||||
if @test_defines_changed
|
if @test_defines_changed
|
||||||
# update timestamp for rake task prerequisites
|
# update timestamp for rake task prerequisites
|
||||||
@file_wrapper.touch( @configurator.project_test_force_rebuild_filepath )
|
@file_wrapper.touch( @configurator.project_test_force_rebuild_filepath, :mtime => Time.now + 10 )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -10,7 +10,6 @@ $LOAD_PATH.unshift( CEEDLING_LIB )
|
|||||||
$LOAD_PATH.unshift( File.join(CEEDLING_VENDOR, 'unity/auto') )
|
$LOAD_PATH.unshift( File.join(CEEDLING_VENDOR, 'unity/auto') )
|
||||||
$LOAD_PATH.unshift( File.join(CEEDLING_VENDOR, 'diy/lib') )
|
$LOAD_PATH.unshift( File.join(CEEDLING_VENDOR, 'diy/lib') )
|
||||||
$LOAD_PATH.unshift( File.join(CEEDLING_VENDOR, 'cmock/lib') )
|
$LOAD_PATH.unshift( File.join(CEEDLING_VENDOR, 'cmock/lib') )
|
||||||
$LOAD_PATH.unshift( File.join(CEEDLING_VENDOR, 'deep_merge/lib') )
|
|
||||||
|
|
||||||
require 'rake'
|
require 'rake'
|
||||||
|
|
||||||
|
@ -56,15 +56,40 @@ class ReleaseInvoker
|
|||||||
end
|
end
|
||||||
|
|
||||||
def convert_libraries_to_arguments(libraries)
|
def convert_libraries_to_arguments(libraries)
|
||||||
args = (libraries || []) + ((defined? LIBRARIES_SYSTEM) ? LIBRARIES_SYSTEM : [])
|
args = ((libraries || []) + ((defined? LIBRARIES_SYSTEM) ? LIBRARIES_SYSTEM : [])).flatten
|
||||||
if (defined? LIBRARIES_FLAG)
|
if (defined? LIBRARIES_FLAG)
|
||||||
args.map! {|v| LIBRARIES_FLAG.gsub(/\$\{1\}/, v) }
|
args.map! {|v| LIBRARIES_FLAG.gsub(/\$\{1\}/, v) }
|
||||||
end
|
end
|
||||||
return args
|
return args
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def get_library_paths_to_arguments()
|
||||||
|
paths = (defined? PATHS_LIBRARIES) ? (PATHS_LIBRARIES || []).clone : []
|
||||||
|
if (defined? LIBRARIES_PATH_FLAG)
|
||||||
|
paths.map! {|v| LIBRARIES_PATH_FLAG.gsub(/\$\{1\}/, v) }
|
||||||
|
end
|
||||||
|
return paths
|
||||||
|
end
|
||||||
|
|
||||||
def sort_objects_and_libraries(both)
|
def sort_objects_and_libraries(both)
|
||||||
extension = "\\" + ((defined? EXTENSION_SUBPROJECTS) ? EXTENSION_SUBPROJECTS : ".LIBRARY")
|
extension = if ((defined? EXTENSION_SUBPROJECTS) && (defined? EXTENSION_LIBRARIES))
|
||||||
|
extension_libraries = if (EXTENSION_LIBRARIES.class == Array)
|
||||||
|
EXTENSION_LIBRARIES.join(")|(?:\\")
|
||||||
|
else
|
||||||
|
EXTENSION_LIBRARIES
|
||||||
|
end
|
||||||
|
"(?:\\#{EXTENSION_SUBPROJECTS})|(?:\\#{extension_libraries})"
|
||||||
|
elsif (defined? EXTENSION_SUBPROJECTS)
|
||||||
|
"\\#{EXTENSION_SUBPROJECTS}"
|
||||||
|
elsif (defined? EXTENSION_LIBRARIES)
|
||||||
|
if (EXTENSION_LIBRARIES.class == Array)
|
||||||
|
"(?:\\#{EXTENSION_LIBRARIES.join(")|(?:\\")})"
|
||||||
|
else
|
||||||
|
"\\#{EXTENSION_LIBRARIES}"
|
||||||
|
end
|
||||||
|
else
|
||||||
|
"\\.LIBRARY"
|
||||||
|
end
|
||||||
sorted_objects = both.group_by {|v| v.match(/.+#{extension}$/) ? :libraries : :objects }
|
sorted_objects = both.group_by {|v| v.match(/.+#{extension}$/) ? :libraries : :objects }
|
||||||
libraries = sorted_objects[:libraries] || []
|
libraries = sorted_objects[:libraries] || []
|
||||||
objects = sorted_objects[:objects] || []
|
objects = sorted_objects[:objects] || []
|
||||||
|
@ -2,6 +2,17 @@
|
|||||||
RELEASE_COMPILE_TASK_ROOT = RELEASE_TASK_ROOT + 'compile:' unless defined?(RELEASE_COMPILE_TASK_ROOT)
|
RELEASE_COMPILE_TASK_ROOT = RELEASE_TASK_ROOT + 'compile:' unless defined?(RELEASE_COMPILE_TASK_ROOT)
|
||||||
RELEASE_ASSEMBLE_TASK_ROOT = RELEASE_TASK_ROOT + 'assemble:' unless defined?(RELEASE_ASSEMBLE_TASK_ROOT)
|
RELEASE_ASSEMBLE_TASK_ROOT = RELEASE_TASK_ROOT + 'assemble:' unless defined?(RELEASE_ASSEMBLE_TASK_ROOT)
|
||||||
|
|
||||||
|
# If GCC and Releasing a Library, Update Tools to Automatically Have Necessary Tags
|
||||||
|
if (TOOLS_RELEASE_COMPILER[:executable] == DEFAULT_RELEASE_COMPILER_TOOL[:executable])
|
||||||
|
if (File.extname(PROJECT_RELEASE_BUILD_TARGET) == '.so')
|
||||||
|
TOOLS_RELEASE_COMPILER[:arguments] << "-fPIC" unless TOOLS_RELEASE_COMPILER[:arguments].include?("-fPIC")
|
||||||
|
TOOLS_RELEASE_LINKER[:arguments] << "-shared" unless TOOLS_RELEASE_LINKER[:arguments].include?("-shared")
|
||||||
|
elsif (File.extname(PROJECT_RELEASE_BUILD_TARGET) == '.a')
|
||||||
|
TOOLS_RELEASE_COMPILER[:arguments] << "-fPIC" unless TOOLS_RELEASE_COMPILER[:arguments].include?("-fPIC")
|
||||||
|
TOOLS_RELEASE_LINKER[:executable] = 'ar'
|
||||||
|
TOOLS_RELEASE_LINKER[:arguments] = ['rcs', '${2}', '${1}'].compact
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if (RELEASE_BUILD_USE_ASSEMBLY)
|
if (RELEASE_BUILD_USE_ASSEMBLY)
|
||||||
rule(/#{PROJECT_RELEASE_BUILD_OUTPUT_ASM_PATH}\/#{'.+\\'+EXTENSION_OBJECT}$/ => [
|
rule(/#{PROJECT_RELEASE_BUILD_OUTPUT_ASM_PATH}\/#{'.+\\'+EXTENSION_OBJECT}$/ => [
|
||||||
@ -37,16 +48,18 @@ end
|
|||||||
|
|
||||||
rule(/#{PROJECT_RELEASE_BUILD_TARGET}/) do |bin_file|
|
rule(/#{PROJECT_RELEASE_BUILD_TARGET}/) do |bin_file|
|
||||||
objects, libraries = @ceedling[:release_invoker].sort_objects_and_libraries(bin_file.prerequisites)
|
objects, libraries = @ceedling[:release_invoker].sort_objects_and_libraries(bin_file.prerequisites)
|
||||||
tool = TOOLS_RELEASE_LINKER.clone
|
tool = TOOLS_RELEASE_LINKER.clone
|
||||||
lib_args = @ceedling[:release_invoker].convert_libraries_to_arguments(libraries)
|
lib_args = @ceedling[:release_invoker].convert_libraries_to_arguments(libraries)
|
||||||
map_file = @ceedling[:configurator].project_release_build_map
|
lib_paths = @ceedling[:release_invoker].get_library_paths_to_arguments()
|
||||||
|
map_file = @ceedling[:configurator].project_release_build_map
|
||||||
@ceedling[:generator].generate_executable_file(
|
@ceedling[:generator].generate_executable_file(
|
||||||
tool,
|
tool,
|
||||||
RELEASE_SYM,
|
RELEASE_SYM,
|
||||||
objects,
|
objects,
|
||||||
bin_file.name,
|
bin_file.name,
|
||||||
map_file,
|
map_file,
|
||||||
lib_args )
|
lib_args,
|
||||||
|
lib_paths )
|
||||||
@ceedling[:release_invoker].artifactinate( bin_file.name, map_file, @ceedling[:configurator].release_build_artifacts )
|
@ceedling[:release_invoker].artifactinate( bin_file.name, map_file, @ceedling[:configurator].release_build_artifacts )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -34,16 +34,16 @@ end
|
|||||||
|
|
||||||
|
|
||||||
rule(/#{PROJECT_TEST_BUILD_OUTPUT_PATH}\/#{'.+\\'+EXTENSION_EXECUTABLE}$/) do |bin_file|
|
rule(/#{PROJECT_TEST_BUILD_OUTPUT_PATH}\/#{'.+\\'+EXTENSION_EXECUTABLE}$/) do |bin_file|
|
||||||
|
|
||||||
lib_args = @ceedling[:test_invoker].convert_libraries_to_arguments()
|
lib_args = @ceedling[:test_invoker].convert_libraries_to_arguments()
|
||||||
|
lib_paths = @ceedling[:test_invoker].get_library_paths_to_arguments()
|
||||||
@ceedling[:generator].generate_executable_file(
|
@ceedling[:generator].generate_executable_file(
|
||||||
TOOLS_TEST_LINKER,
|
TOOLS_TEST_LINKER,
|
||||||
TEST_SYM,
|
TEST_SYM,
|
||||||
bin_file.prerequisites,
|
bin_file.prerequisites,
|
||||||
bin_file.name,
|
bin_file.name,
|
||||||
@ceedling[:file_path_utils].form_test_build_map_filepath( bin_file.name ),
|
@ceedling[:file_path_utils].form_test_build_map_filepath( bin_file.name ),
|
||||||
lib_args )
|
lib_args,
|
||||||
|
lib_paths )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@ -66,8 +66,7 @@ namespace TEST_SYM do
|
|||||||
@ceedling[:file_finder].find_test_from_file_path(test)
|
@ceedling[:file_finder].find_test_from_file_path(test)
|
||||||
end
|
end
|
||||||
]) do |test|
|
]) do |test|
|
||||||
@ceedling[:rake_wrapper][:directories].reenable if @ceedling[:task_invoker].first_run == false && @ceedling[:project_config_manager].test_defines_changed
|
@ceedling[:rake_wrapper][:test_deps].invoke
|
||||||
@ceedling[:rake_wrapper][:directories].invoke
|
|
||||||
@ceedling[:test_invoker].setup_and_invoke([test.source])
|
@ceedling[:test_invoker].setup_and_invoke([test.source])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -25,8 +25,8 @@ class Setupinator
|
|||||||
@ceedling[:configurator].populate_cmock_defaults( config_hash )
|
@ceedling[:configurator].populate_cmock_defaults( config_hash )
|
||||||
@ceedling[:configurator].find_and_merge_plugins( config_hash )
|
@ceedling[:configurator].find_and_merge_plugins( config_hash )
|
||||||
@ceedling[:configurator].merge_imports( config_hash )
|
@ceedling[:configurator].merge_imports( config_hash )
|
||||||
@ceedling[:configurator].tools_setup( config_hash )
|
|
||||||
@ceedling[:configurator].eval_environment_variables( config_hash )
|
@ceedling[:configurator].eval_environment_variables( config_hash )
|
||||||
|
@ceedling[:configurator].tools_setup( config_hash )
|
||||||
@ceedling[:configurator].eval_paths( config_hash )
|
@ceedling[:configurator].eval_paths( config_hash )
|
||||||
@ceedling[:configurator].standardize_paths( config_hash )
|
@ceedling[:configurator].standardize_paths( config_hash )
|
||||||
@ceedling[:configurator].validate( config_hash )
|
@ceedling[:configurator].validate( config_hash )
|
||||||
|
@ -46,25 +46,31 @@ class TaskInvoker
|
|||||||
return @rake_utils.task_invoked?(regex)
|
return @rake_utils.task_invoked?(regex)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def reset_rake_task_for_changed_defines(file)
|
||||||
|
if !(file =~ /#{VENDORS_FILES.map{|ignore| '\b' + ignore.ext(File.extname(file)) + '\b'}.join('|')}$/)
|
||||||
|
@rake_wrapper[file].clear_actions if @first_run == false && @project_config_manager.test_defines_changed
|
||||||
|
@rake_wrapper[file].reenable if @first_run == false && @project_config_manager.test_defines_changed
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def invoke_test_mocks(mocks)
|
def invoke_test_mocks(mocks)
|
||||||
@dependinator.enhance_mock_dependencies( mocks )
|
@dependinator.enhance_mock_dependencies( mocks )
|
||||||
mocks.each { |mock|
|
mocks.each { |mock|
|
||||||
@rake_wrapper[mock].reenable if @first_run == false && @project_config_manager.test_defines_changed
|
reset_rake_task_for_changed_defines( mock )
|
||||||
@rake_wrapper[mock].invoke
|
@rake_wrapper[mock].invoke
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def invoke_test_runner(runner)
|
def invoke_test_runner(runner)
|
||||||
@dependinator.enhance_runner_dependencies( runner )
|
@dependinator.enhance_runner_dependencies( runner )
|
||||||
@rake_wrapper[runner].reenable if @first_run == false && @project_config_manager.test_defines_changed
|
reset_rake_task_for_changed_defines( runner )
|
||||||
@rake_wrapper[runner].invoke
|
@rake_wrapper[runner].invoke
|
||||||
end
|
end
|
||||||
|
|
||||||
def invoke_test_shallow_include_lists(files)
|
def invoke_test_shallow_include_lists(files)
|
||||||
@dependinator.enhance_shallow_include_lists_dependencies( files )
|
@dependinator.enhance_shallow_include_lists_dependencies( files )
|
||||||
par_map(PROJECT_COMPILE_THREADS, files) do |file|
|
par_map(PROJECT_COMPILE_THREADS, files) do |file|
|
||||||
@rake_wrapper[file].reenable if @first_run == false && @project_config_manager.test_defines_changed
|
reset_rake_task_for_changed_defines( file )
|
||||||
@rake_wrapper[file].invoke
|
@rake_wrapper[file].invoke
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -72,7 +78,7 @@ class TaskInvoker
|
|||||||
def invoke_test_preprocessed_files(files)
|
def invoke_test_preprocessed_files(files)
|
||||||
@dependinator.enhance_preprocesed_file_dependencies( files )
|
@dependinator.enhance_preprocesed_file_dependencies( files )
|
||||||
par_map(PROJECT_COMPILE_THREADS, files) do |file|
|
par_map(PROJECT_COMPILE_THREADS, files) do |file|
|
||||||
@rake_wrapper[file].reenable if @first_run == false && @project_config_manager.test_defines_changed
|
reset_rake_task_for_changed_defines( file )
|
||||||
@rake_wrapper[file].invoke
|
@rake_wrapper[file].invoke
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -80,14 +86,14 @@ class TaskInvoker
|
|||||||
def invoke_test_dependencies_files(files)
|
def invoke_test_dependencies_files(files)
|
||||||
@dependinator.enhance_dependencies_dependencies( files )
|
@dependinator.enhance_dependencies_dependencies( files )
|
||||||
par_map(PROJECT_COMPILE_THREADS, files) do |file|
|
par_map(PROJECT_COMPILE_THREADS, files) do |file|
|
||||||
@rake_wrapper[file].reenable if @first_run == false && @project_config_manager.test_defines_changed
|
reset_rake_task_for_changed_defines( file )
|
||||||
@rake_wrapper[file].invoke
|
@rake_wrapper[file].invoke
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def invoke_test_objects(objects)
|
def invoke_test_objects(objects)
|
||||||
par_map(PROJECT_COMPILE_THREADS, objects) do |object|
|
par_map(PROJECT_COMPILE_THREADS, objects) do |object|
|
||||||
@rake_wrapper[object].reenable if @first_run == false && @project_config_manager.test_defines_changed
|
reset_rake_task_for_changed_defines( object )
|
||||||
@rake_wrapper[object].invoke
|
@rake_wrapper[object].invoke
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -98,7 +104,6 @@ class TaskInvoker
|
|||||||
|
|
||||||
def invoke_test_results(result)
|
def invoke_test_results(result)
|
||||||
@dependinator.enhance_results_dependencies( result )
|
@dependinator.enhance_results_dependencies( result )
|
||||||
@rake_wrapper[result].reenable if @first_run == false && @project_config_manager.test_defines_changed
|
|
||||||
@rake_wrapper[result].invoke
|
@rake_wrapper[result].invoke
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -4,28 +4,10 @@ require 'ceedling/version'
|
|||||||
|
|
||||||
desc "Display build environment version info."
|
desc "Display build environment version info."
|
||||||
task :version do
|
task :version do
|
||||||
puts " Ceedling:: #{Ceedling::Version::CEEDLING}"
|
puts " Ceedling:: #{Ceedling::Version::CEEDLING}"
|
||||||
|
puts " Unity:: #{Ceedling::Version::UNITY}"
|
||||||
[
|
puts " CMock:: #{Ceedling::Version::CMOCK}"
|
||||||
['CException', File.join( CEEDLING_VENDOR, CEXCEPTION_ROOT_PATH)],
|
puts " CException:: #{Ceedling::Version::CEXCEPTION}"
|
||||||
[' CMock', File.join( CEEDLING_VENDOR, CMOCK_ROOT_PATH)],
|
|
||||||
[' Unity', File.join( CEEDLING_VENDOR, UNITY_ROOT_PATH)],
|
|
||||||
].each do |tool|
|
|
||||||
name = tool[0]
|
|
||||||
base_path = tool[1]
|
|
||||||
|
|
||||||
version_string = begin
|
|
||||||
@ceedling[:file_wrapper].read( File.join(base_path, 'release', 'version.info') ).strip
|
|
||||||
rescue
|
|
||||||
"UNKNOWN"
|
|
||||||
end
|
|
||||||
build_string = begin
|
|
||||||
@ceedling[:file_wrapper].read( File.join(base_path, 'release', 'build.info') ).strip
|
|
||||||
rescue
|
|
||||||
"UNKNOWN"
|
|
||||||
end
|
|
||||||
puts "#{name}:: #{version_string.empty? ? '#.#.' : (version_string + '.')}#{build_string.empty? ? '?' : build_string}"
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "Set verbose output (silent:[#{Verbosity::SILENT}] - obnoxious:[#{Verbosity::OBNOXIOUS}])."
|
desc "Set verbose output (silent:[#{Verbosity::SILENT}] - obnoxious:[#{Verbosity::OBNOXIOUS}])."
|
||||||
@ -65,6 +47,12 @@ task :sanity_checks, :level do |t, args|
|
|||||||
@ceedling[:configurator].sanity_checks = check_level
|
@ceedling[:configurator].sanity_checks = check_level
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# non advertised catch for calling upgrade in the wrong place
|
||||||
|
task :upgrade do
|
||||||
|
puts "WARNING: You're currently IN your project directory. Take a step out and try"
|
||||||
|
puts "again if you'd like to perform an upgrade."
|
||||||
|
end
|
||||||
|
|
||||||
# list expanded environment variables
|
# list expanded environment variables
|
||||||
if (not ENVIRONMENT.empty?)
|
if (not ENVIRONMENT.empty?)
|
||||||
desc "List all configured environment variables."
|
desc "List all configured environment variables."
|
||||||
@ -73,7 +61,7 @@ task :environment do
|
|||||||
ENVIRONMENT.each do |env|
|
ENVIRONMENT.each do |env|
|
||||||
env.each_key do |key|
|
env.each_key do |key|
|
||||||
name = key.to_s.upcase
|
name = key.to_s.upcase
|
||||||
env_list.push(" - #{name}: \"#{env[key]}\"")
|
env_list.push(" - #{name}: \"#{env[key]}\"")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
env_list.sort.each do |env_line|
|
env_list.sort.each do |env_line|
|
||||||
@ -88,7 +76,7 @@ namespace :options do
|
|||||||
option = File.basename(option_path, '.yml')
|
option = File.basename(option_path, '.yml')
|
||||||
|
|
||||||
desc "Merge #{option} project options."
|
desc "Merge #{option} project options."
|
||||||
task option.downcase.to_sym do
|
task option.to_sym do
|
||||||
hash = @ceedling[:project_config_manager].merge_options( @ceedling[:setupinator].config_hash, option_path )
|
hash = @ceedling[:project_config_manager].merge_options( @ceedling[:setupinator].config_hash, option_path )
|
||||||
@ceedling[:setupinator].do_setup( hash )
|
@ceedling[:setupinator].do_setup( hash )
|
||||||
if @ceedling[:configurator].project_release_build
|
if @ceedling[:configurator].project_release_build
|
||||||
@ -97,6 +85,23 @@ namespace :options do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# This is to give nice errors when typing options
|
||||||
|
rule /^options:.*/ do |t, args|
|
||||||
|
filename = t.to_s.split(':')[-1] + '.yml'
|
||||||
|
filelist = COLLECTION_PROJECT_OPTIONS.map{|s| File.basename(s) }
|
||||||
|
@ceedling[:file_finder].find_file_from_list(filename, filelist, :error)
|
||||||
|
end
|
||||||
|
|
||||||
|
# This will output the fully-merged tools options to their own project.yml file
|
||||||
|
desc "Export tools options to a new project file"
|
||||||
|
task :export, :filename do |t, args|
|
||||||
|
outfile = args.filename || 'tools.yml'
|
||||||
|
toolcfg = {}
|
||||||
|
@ceedling[:configurator].project_config_hash.each_pair do |k,v|
|
||||||
|
toolcfg[k] = v if (k.to_s[0..5] == 'tools_')
|
||||||
|
end
|
||||||
|
File.open(outfile,'w') {|f| f << toolcfg.to_yaml({:indentation => 2})}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -45,26 +45,35 @@ task(:clobber => [:clean]) do
|
|||||||
@ceedling[:streaminator].stdout_puts("\nClobbering all generated files...\n(For large projects, this task may take a long time to complete)\n\n")
|
@ceedling[:streaminator].stdout_puts("\nClobbering all generated files...\n(For large projects, this task may take a long time to complete)\n\n")
|
||||||
begin
|
begin
|
||||||
CLOBBER.each { |fn| REMOVE_FILE_PROC.call(fn) }
|
CLOBBER.each { |fn| REMOVE_FILE_PROC.call(fn) }
|
||||||
|
@ceedling[:rake_wrapper][:directories].invoke
|
||||||
|
@ceedling[:dependinator].touch_force_rebuild_files
|
||||||
rescue
|
rescue
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# create a directory task for each of the paths, so we know how to build them
|
||||||
PROJECT_BUILD_PATHS.each { |path| directory(path) }
|
PROJECT_BUILD_PATHS.each { |path| directory(path) }
|
||||||
|
|
||||||
# create directories that hold build output and generated files & touching rebuild dependency sources
|
# create a single directory task which verifies all the others get built
|
||||||
task(:directories => PROJECT_BUILD_PATHS) { @ceedling[:dependinator].touch_force_rebuild_files }
|
task :directories => PROJECT_BUILD_PATHS
|
||||||
|
|
||||||
|
# when the force file doesn't exist, it probably means we clobbered or are on a fresh
|
||||||
|
# install. In either case, stuff was deleted, so assume we want to rebuild it all
|
||||||
|
file @ceedling[:configurator].project_test_force_rebuild_filepath do
|
||||||
|
unless File.exists?(@ceedling[:configurator].project_test_force_rebuild_filepath)
|
||||||
|
@ceedling[:dependinator].touch_force_rebuild_files
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# list paths discovered at load time
|
# list paths discovered at load time
|
||||||
namespace :paths do
|
namespace :paths do
|
||||||
|
standard_paths = ['test','source','include']
|
||||||
paths = @ceedling[:setupinator].config_hash[:paths]
|
paths = @ceedling[:setupinator].config_hash[:paths].keys.map{|n| n.to_s.downcase}
|
||||||
paths.each_key do |section|
|
paths = (paths + standard_paths).uniq
|
||||||
name = section.to_s.downcase
|
paths.each do |name|
|
||||||
path_list = Object.const_get("COLLECTION_PATHS_#{name.upcase}")
|
path_list = Object.const_get("COLLECTION_PATHS_#{name.upcase}")
|
||||||
|
|
||||||
if (path_list.size != 0)
|
if (path_list.size != 0) || (standard_paths.include?(name))
|
||||||
desc "List all collected #{name} paths."
|
desc "List all collected #{name} paths."
|
||||||
task(name.to_sym) { puts "#{name} paths:"; path_list.sort.each {|path| puts " - #{path}" } }
|
task(name.to_sym) { puts "#{name} paths:"; path_list.sort.each {|path| puts " - #{path}" } }
|
||||||
end
|
end
|
||||||
@ -77,10 +86,11 @@ end
|
|||||||
namespace :files do
|
namespace :files do
|
||||||
|
|
||||||
categories = [
|
categories = [
|
||||||
['test', COLLECTION_ALL_TESTS],
|
['test', COLLECTION_ALL_TESTS],
|
||||||
['source', COLLECTION_ALL_SOURCE],
|
['source', COLLECTION_ALL_SOURCE],
|
||||||
['header', COLLECTION_ALL_HEADERS]
|
['include', COLLECTION_ALL_HEADERS],
|
||||||
]
|
['support', COLLECTION_ALL_SUPPORT]
|
||||||
|
]
|
||||||
|
|
||||||
using_assembly = (defined?(TEST_BUILD_USE_ASSEMBLY) && TEST_BUILD_USE_ASSEMBLY) ||
|
using_assembly = (defined?(TEST_BUILD_USE_ASSEMBLY) && TEST_BUILD_USE_ASSEMBLY) ||
|
||||||
(defined?(RELEASE_BUILD_USE_ASSEMBLY) && RELEASE_BUILD_USE_ASSEMBLY)
|
(defined?(RELEASE_BUILD_USE_ASSEMBLY) && RELEASE_BUILD_USE_ASSEMBLY)
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
require 'ceedling/constants'
|
require 'ceedling/constants'
|
||||||
|
|
||||||
task :test => [:directories] do
|
task :test_deps => [:directories]
|
||||||
|
|
||||||
|
task :test => [:test_deps] do
|
||||||
Rake.application['test:all'].invoke
|
Rake.application['test:all'].invoke
|
||||||
end
|
end
|
||||||
|
|
||||||
namespace TEST_SYM do
|
namespace TEST_SYM do
|
||||||
|
|
||||||
desc "Run all unit tests (also just 'test' works)."
|
desc "Run all unit tests (also just 'test' works)."
|
||||||
task :all => [:directories] do
|
task :all => [:test_deps] do
|
||||||
@ceedling[:test_invoker].setup_and_invoke(COLLECTION_ALL_TESTS)
|
@ceedling[:test_invoker].setup_and_invoke(COLLECTION_ALL_TESTS)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -21,17 +23,17 @@ namespace TEST_SYM do
|
|||||||
end
|
end
|
||||||
|
|
||||||
desc "Run tests for changed files."
|
desc "Run tests for changed files."
|
||||||
task :delta => [:directories] do
|
task :delta => [:test_deps] do
|
||||||
@ceedling[:test_invoker].setup_and_invoke(COLLECTION_ALL_TESTS, TEST_SYM, {:force_run => false})
|
@ceedling[:test_invoker].setup_and_invoke(COLLECTION_ALL_TESTS, TEST_SYM, {:force_run => false})
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "Just build tests without running."
|
desc "Just build tests without running."
|
||||||
task :build_only => [:directories] do
|
task :build_only => [:test_deps] do
|
||||||
@ceedling[:test_invoker].setup_and_invoke(COLLECTION_ALL_TESTS, TEST_SYM, {:build_only => true})
|
@ceedling[:test_invoker].setup_and_invoke(COLLECTION_ALL_TESTS, TEST_SYM, {:build_only => true})
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "Run tests by matching regular expression pattern."
|
desc "Run tests by matching regular expression pattern."
|
||||||
task :pattern, [:regex] => [:directories] do |t, args|
|
task :pattern, [:regex] => [:test_deps] do |t, args|
|
||||||
matches = []
|
matches = []
|
||||||
|
|
||||||
COLLECTION_ALL_TESTS.each { |test| matches << test if (test =~ /#{args.regex}/) }
|
COLLECTION_ALL_TESTS.each { |test| matches << test if (test =~ /#{args.regex}/) }
|
||||||
@ -44,7 +46,7 @@ namespace TEST_SYM do
|
|||||||
end
|
end
|
||||||
|
|
||||||
desc "Run tests whose test path contains [dir] or [dir] substring."
|
desc "Run tests whose test path contains [dir] or [dir] substring."
|
||||||
task :path, [:dir] => [:directories] do |t, args|
|
task :path, [:dir] => [:test_deps] do |t, args|
|
||||||
matches = []
|
matches = []
|
||||||
|
|
||||||
COLLECTION_ALL_TESTS.each { |test| matches << test if File.dirname(test).include?(args.dir.gsub(/\\/, '/')) }
|
COLLECTION_ALL_TESTS.each { |test| matches << test if File.dirname(test).include?(args.dir.gsub(/\\/, '/')) }
|
||||||
|
@ -19,6 +19,11 @@ class TestIncludesExtractor
|
|||||||
gather_and_store_includes( test, extract_from_file(test) )
|
gather_and_store_includes( test, extract_from_file(test) )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# open, scan for, and sort & store includes of test file
|
||||||
|
def parse_test_file_source_include(test)
|
||||||
|
return extract_source_include_from_file(test)
|
||||||
|
end
|
||||||
|
|
||||||
# mocks with no file extension
|
# mocks with no file extension
|
||||||
def lookup_raw_mock_list(test)
|
def lookup_raw_mock_list(test)
|
||||||
file_key = form_file_key(test)
|
file_key = form_file_key(test)
|
||||||
@ -65,6 +70,27 @@ class TestIncludesExtractor
|
|||||||
return includes.uniq
|
return includes.uniq
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def extract_source_include_from_file(file)
|
||||||
|
source_includes = []
|
||||||
|
source_extension = @configurator.extension_source
|
||||||
|
|
||||||
|
contents = @file_wrapper.read(file)
|
||||||
|
|
||||||
|
# remove line comments
|
||||||
|
contents = contents.gsub(/\/\/.*$/, '')
|
||||||
|
# remove block comments
|
||||||
|
contents = contents.gsub(/\/\*.*?\*\//m, '')
|
||||||
|
|
||||||
|
contents.split("\n").each do |line|
|
||||||
|
# look for include statement
|
||||||
|
scan_results = line.scan(/#include\s+\"\s*(.+#{'\\'+source_extension})\s*\"/)
|
||||||
|
|
||||||
|
source_includes << scan_results[0][0] if (scan_results.size > 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
return source_includes.uniq
|
||||||
|
end
|
||||||
|
|
||||||
def gather_and_store_includes(file, includes)
|
def gather_and_store_includes(file, includes)
|
||||||
mock_prefix = @configurator.cmock_mock_prefix
|
mock_prefix = @configurator.cmock_mock_prefix
|
||||||
header_extension = @configurator.extension_header
|
header_extension = @configurator.extension_header
|
||||||
|
@ -23,49 +23,24 @@ class TestInvoker
|
|||||||
@mocks = []
|
@mocks = []
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_test_definition_str(test)
|
|
||||||
return "-D" + File.basename(test, File.extname(test)).upcase.sub(/@.*$/, "")
|
|
||||||
end
|
|
||||||
|
|
||||||
def get_tools_compilers
|
|
||||||
tools_compilers = Hash.new
|
|
||||||
tools_compilers["for unit test"] = TOOLS_TEST_COMPILER if defined? TOOLS_TEST_COMPILER
|
|
||||||
tools_compilers["for gcov"] = TOOLS_GCOV_COMPILER if defined? TOOLS_GCOV_COMPILER
|
|
||||||
return tools_compilers
|
|
||||||
end
|
|
||||||
|
|
||||||
def add_test_definition(test)
|
|
||||||
test_definition_str = get_test_definition_str(test)
|
|
||||||
get_tools_compilers.each do |tools_compiler_key, tools_compiler_value|
|
|
||||||
tools_compiler_value[:arguments].push("-D#{File.basename(test, ".*").strip.upcase.sub(/@.*$/, "")}")
|
|
||||||
@streaminator.stdout_puts("Add the definition value in the build option #{tools_compiler_value[:arguments][-1]} #{tools_compiler_key}", Verbosity::OBNOXIOUS)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def delete_test_definition(test)
|
|
||||||
test_definition_str = get_test_definition_str(test)
|
|
||||||
get_tools_compilers.each do |tools_compiler_key, tools_compiler_value|
|
|
||||||
num_options = tools_compiler_value[:arguments].size
|
|
||||||
@streaminator.stdout_puts("Delete the definition value in the build option #{tools_compiler_value[:arguments][-1]} #{tools_compiler_key}", Verbosity::OBNOXIOUS)
|
|
||||||
tools_compiler_value[:arguments].delete_if{|i| i == test_definition_str}
|
|
||||||
if num_options > tools_compiler_value[:arguments].size + 1
|
|
||||||
@streaminator.stderr_puts("WARNING: duplicated test definition.")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Convert libraries configuration form YAML configuration
|
# Convert libraries configuration form YAML configuration
|
||||||
# into a string that can be given to the compiler.
|
# into a string that can be given to the compiler.
|
||||||
def convert_libraries_to_arguments()
|
def convert_libraries_to_arguments()
|
||||||
if @configurator.project_config_hash.has_key?(:libraries_test)
|
args = ((@configurator.project_config_hash[:libraries_test] || []) + ((defined? LIBRARIES_SYSTEM) ? LIBRARIES_SYSTEM : [])).flatten
|
||||||
lib_args = @configurator.project_config_hash[:libraries_test]
|
if (defined? LIBRARIES_FLAG)
|
||||||
lib_args.flatten!
|
args.map! {|v| LIBRARIES_FLAG.gsub(/\$\{1\}/, v) }
|
||||||
lib_flag = @configurator.project_config_hash[:libraries_flag]
|
|
||||||
lib_args.map! {|v| lib_flag.gsub(/\$\{1\}/, v) } if (defined? lib_flag)
|
|
||||||
return lib_args
|
|
||||||
end
|
end
|
||||||
|
return args
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def get_library_paths_to_arguments()
|
||||||
|
paths = (defined? PATHS_LIBRARIES) ? (PATHS_LIBRARIES || []).clone : []
|
||||||
|
if (defined? LIBRARIES_PATH_FLAG)
|
||||||
|
paths.map! {|v| LIBRARIES_PATH_FLAG.gsub(/\$\{1\}/, v) }
|
||||||
|
end
|
||||||
|
return paths
|
||||||
|
end
|
||||||
|
|
||||||
def setup_and_invoke(tests, context=TEST_SYM, options={:force_run => true, :build_only => false})
|
def setup_and_invoke(tests, context=TEST_SYM, options={:force_run => true, :build_only => false})
|
||||||
|
|
||||||
@ -83,18 +58,25 @@ class TestInvoker
|
|||||||
test_name ="#{File.basename(test)}".chomp('.c')
|
test_name ="#{File.basename(test)}".chomp('.c')
|
||||||
def_test_key="defines_#{test_name.downcase}"
|
def_test_key="defines_#{test_name.downcase}"
|
||||||
|
|
||||||
# Re-define the project out path and pre-processor defines.
|
if @configurator.project_config_hash.has_key?(def_test_key.to_sym) || @configurator.defines_use_test_definition
|
||||||
if @configurator.project_config_hash.has_key?(def_test_key.to_sym)
|
|
||||||
@project_config_manager.test_config_changed
|
|
||||||
defs_bkp = Array.new(COLLECTION_DEFINES_TEST_AND_VENDOR)
|
defs_bkp = Array.new(COLLECTION_DEFINES_TEST_AND_VENDOR)
|
||||||
printf " ************** Specific test definitions for #{test_name} !!! \n"
|
tst_defs_cfg = Array.new(defs_bkp)
|
||||||
tst_defs_cfg = @configurator.project_config_hash[def_test_key.to_sym]
|
if @configurator.project_config_hash.has_key?(def_test_key.to_sym)
|
||||||
|
tst_defs_cfg.replace(@configurator.project_config_hash[def_test_key.to_sym])
|
||||||
|
tst_defs_cfg .concat(COLLECTION_DEFINES_VENDOR) if COLLECTION_DEFINES_VENDOR
|
||||||
|
end
|
||||||
|
if @configurator.defines_use_test_definition
|
||||||
|
tst_defs_cfg << File.basename(test, ".*").strip.upcase.sub(/@.*$/, "")
|
||||||
|
end
|
||||||
|
COLLECTION_DEFINES_TEST_AND_VENDOR.replace(tst_defs_cfg)
|
||||||
|
end
|
||||||
|
|
||||||
|
# redefine the project out path and preprocessor defines
|
||||||
|
if @configurator.project_config_hash.has_key?(def_test_key.to_sym)
|
||||||
|
@streaminator.stdout_puts("Updating test definitions for #{test_name}", Verbosity::NORMAL)
|
||||||
orig_path = @configurator.project_test_build_output_path
|
orig_path = @configurator.project_test_build_output_path
|
||||||
@configurator.project_config_hash[:project_test_build_output_path] = File.join(@configurator.project_test_build_output_path, test_name)
|
@configurator.project_config_hash[:project_test_build_output_path] = File.join(@configurator.project_test_build_output_path, test_name)
|
||||||
@file_wrapper.mkdir(@configurator.project_test_build_output_path)
|
@file_wrapper.mkdir(@configurator.project_test_build_output_path)
|
||||||
COLLECTION_DEFINES_TEST_AND_VENDOR.replace(tst_defs_cfg)
|
|
||||||
# printf " * new defines = #{COLLECTION_DEFINES_TEST_AND_VENDOR}\n"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# collect up test fixture pieces & parts
|
# collect up test fixture pieces & parts
|
||||||
@ -103,16 +85,15 @@ class TestInvoker
|
|||||||
sources = @test_invoker_helper.extract_sources( test )
|
sources = @test_invoker_helper.extract_sources( test )
|
||||||
extras = @configurator.collection_test_fixture_extra_link_objects
|
extras = @configurator.collection_test_fixture_extra_link_objects
|
||||||
core = [test] + mock_list + sources
|
core = [test] + mock_list + sources
|
||||||
objects = @file_path_utils.form_test_build_objects_filelist( [runner] + core + extras )
|
objects = @file_path_utils.form_test_build_objects_filelist( [runner] + core + extras ).uniq
|
||||||
results_pass = @file_path_utils.form_pass_results_filepath( test )
|
results_pass = @file_path_utils.form_pass_results_filepath( test )
|
||||||
results_fail = @file_path_utils.form_fail_results_filepath( test )
|
results_fail = @file_path_utils.form_fail_results_filepath( test )
|
||||||
|
|
||||||
@project_config_manager.process_test_defines_change(sources)
|
# identify all the objects shall not be linked and then remove them from objects list.
|
||||||
|
no_link_objects = @file_path_utils.form_test_build_objects_filelist(@preprocessinator.preprocess_shallow_source_includes( test ))
|
||||||
|
objects = objects.uniq - no_link_objects
|
||||||
|
|
||||||
# add the definition value in the build option for the unit test
|
@project_config_manager.process_test_defines_change(@project_config_manager.filter_internal_sources(sources))
|
||||||
if @configurator.defines_use_test_definition
|
|
||||||
add_test_definition(test)
|
|
||||||
end
|
|
||||||
|
|
||||||
# clean results files so we have a missing file with which to kick off rake's dependency rules
|
# clean results files so we have a missing file with which to kick off rake's dependency rules
|
||||||
@test_invoker_helper.clean_results( {:pass => results_pass, :fail => results_fail}, options )
|
@test_invoker_helper.clean_results( {:pass => results_pass, :fail => results_fail}, options )
|
||||||
@ -129,7 +110,7 @@ class TestInvoker
|
|||||||
@dependinator.enhance_test_build_object_dependencies( objects )
|
@dependinator.enhance_test_build_object_dependencies( objects )
|
||||||
|
|
||||||
# associate object files with executable
|
# associate object files with executable
|
||||||
@dependinator.setup_test_executable_dependencies( test, objects )
|
@dependinator.enhance_test_executable_dependencies( test, objects )
|
||||||
|
|
||||||
# build test objects
|
# build test objects
|
||||||
@task_invoker.invoke_test_objects( objects )
|
@task_invoker.invoke_test_objects( objects )
|
||||||
@ -146,18 +127,14 @@ class TestInvoker
|
|||||||
rescue => e
|
rescue => e
|
||||||
@build_invoker_utils.process_exception( e, context )
|
@build_invoker_utils.process_exception( e, context )
|
||||||
ensure
|
ensure
|
||||||
# delete the definition value in the build option for the unit test
|
|
||||||
if @configurator.defines_use_test_definition
|
|
||||||
delete_test_definition(test)
|
|
||||||
end
|
|
||||||
@plugin_manager.post_test( test )
|
@plugin_manager.post_test( test )
|
||||||
# restore the project test defines
|
# restore the project test defines
|
||||||
if @configurator.project_config_hash.has_key?(def_test_key.to_sym)
|
if @configurator.project_config_hash.has_key?(def_test_key.to_sym) || @configurator.defines_use_test_definition
|
||||||
# @configurator.project_config_hash[:defines_test] =
|
|
||||||
COLLECTION_DEFINES_TEST_AND_VENDOR.replace(defs_bkp)
|
COLLECTION_DEFINES_TEST_AND_VENDOR.replace(defs_bkp)
|
||||||
# printf " ---- Restored defines at #{defs_bkp}"
|
if @configurator.project_config_hash.has_key?(def_test_key.to_sym)
|
||||||
@configurator.project_config_hash[:project_test_build_output_path] = orig_path
|
@configurator.project_config_hash[:project_test_build_output_path] = orig_path
|
||||||
printf " ************** Restored defines and build path\n"
|
@streaminator.stdout_puts("Restored defines and build path to standard", Verbosity::NORMAL)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ class TestInvokerHelper
|
|||||||
def process_deep_dependencies(files)
|
def process_deep_dependencies(files)
|
||||||
return if (not @configurator.project_use_deep_dependencies)
|
return if (not @configurator.project_use_deep_dependencies)
|
||||||
|
|
||||||
dependencies_list = @file_path_utils.form_test_dependencies_filelist( files )
|
dependencies_list = @file_path_utils.form_test_dependencies_filelist( files ).uniq
|
||||||
|
|
||||||
if @configurator.project_generate_deep_dependencies
|
if @configurator.project_generate_deep_dependencies
|
||||||
@task_invoker.invoke_test_dependencies_files( dependencies_list )
|
@task_invoker.invoke_test_dependencies_files( dependencies_list )
|
||||||
|
52
test/vendor/ceedling/lib/ceedling/version.rb
vendored
52
test/vendor/ceedling/lib/ceedling/version.rb
vendored
@ -2,35 +2,53 @@
|
|||||||
# @private
|
# @private
|
||||||
module Ceedling
|
module Ceedling
|
||||||
module Version
|
module Version
|
||||||
# Check for local or global version of vendor directory in order to look up versions
|
{ "UNITY" => File.join("unity","src","unity.h"),
|
||||||
{
|
"CMOCK" => File.join("cmock","src","cmock.h"),
|
||||||
"CEXCEPTION" => File.join("vendor","c_exception","lib","CException.h"),
|
"CEXCEPTION" => File.join("c_exception","lib","CException.h")
|
||||||
"CMOCK" => File.join("vendor","cmock","src","cmock.h"),
|
|
||||||
"UNITY" => File.join("vendor","unity","src","unity.h"),
|
|
||||||
}.each_pair do |name, path|
|
}.each_pair do |name, path|
|
||||||
filename = if (File.exist?(File.join("..","..",path)))
|
# Check for local or global version of vendor directory in order to look up versions
|
||||||
File.join("..","..",path)
|
path1 = File.expand_path( File.join("..","..","vendor",path) )
|
||||||
elsif (File.exist?(File.join(File.dirname(__FILE__),"..","..",path)))
|
path2 = File.expand_path( File.join(File.dirname(__FILE__),"..","..","vendor",path) )
|
||||||
File.join(File.dirname(__FILE__),"..","..",path)
|
filename = if (File.exists?(path1))
|
||||||
|
path1
|
||||||
|
elsif (File.exists?(path2))
|
||||||
|
path2
|
||||||
|
elsif File.exists?(CEEDLING_VENDOR)
|
||||||
|
path3 = File.expand_path( File.join(CEEDLING_VENDOR,path) )
|
||||||
|
if (File.exists?(path3))
|
||||||
|
path3
|
||||||
|
else
|
||||||
|
basepath = File.join( CEEDLING_VENDOR, path.split(/\\\//)[0], 'release')
|
||||||
|
begin
|
||||||
|
[ @ceedling[:file_wrapper].read( File.join(base_path, 'release', 'version.info') ).strip,
|
||||||
|
@ceedling[:file_wrapper].read( File.join(base_path, 'release', 'build.info') ).strip ].join('.')
|
||||||
|
rescue
|
||||||
|
"#{name}"
|
||||||
|
end
|
||||||
|
end
|
||||||
else
|
else
|
||||||
eval "#{name} = 'unknown'"
|
module_eval("#{name} = 'unknown'")
|
||||||
continue
|
continue
|
||||||
end
|
end
|
||||||
|
|
||||||
# Actually look up the versions
|
# Actually look up the versions
|
||||||
a = [0,0,0]
|
a = [0,0,0]
|
||||||
File.readlines(filename) do |line|
|
begin
|
||||||
["VERSION_MAJOR", "VERSION_MINOR", "VERSION_BUILD"].each_with_index do |field, i|
|
File.readlines(filename).each do |line|
|
||||||
m = line.match(/#{name}_#{field}\s+(\d+)/)
|
["VERSION_MAJOR", "VERSION_MINOR", "VERSION_BUILD"].each_with_index do |field, i|
|
||||||
a[i] = m[1] unless (m.nil?)
|
m = line.match(/#{name}_#{field}\s+(\d+)/)
|
||||||
|
a[i] = m[1] unless (m.nil?)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
rescue
|
||||||
|
abort("Can't collect data for vendor component: \"#{filename}\" . \nPlease check your setup.")
|
||||||
end
|
end
|
||||||
|
|
||||||
# Make a constant from each, so that we can use it elsewhere
|
# splat it to return the final value
|
||||||
eval "#{name} = '#{a.join(".")}'"
|
eval("#{name} = '#{a.join(".")}'")
|
||||||
end
|
end
|
||||||
|
|
||||||
GEM = "0.29.0"
|
GEM = "0.31.1"
|
||||||
CEEDLING = GEM
|
CEEDLING = GEM
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
15
test/vendor/ceedling/lib/ceedling/version.rb.erb
vendored
15
test/vendor/ceedling/lib/ceedling/version.rb.erb
vendored
@ -1,15 +0,0 @@
|
|||||||
# @private
|
|
||||||
module Ceedling
|
|
||||||
module Version
|
|
||||||
# @private
|
|
||||||
GEM = "0.27.0"
|
|
||||||
# @private
|
|
||||||
CEEDLING = "<%= versions["CEEDLING"] %>"
|
|
||||||
# @private
|
|
||||||
CEXCEPTION = "<%= versions["CEXCEPTION"] %>"
|
|
||||||
# @private
|
|
||||||
CMOCK = "<%= versions["CMOCK"] %>"
|
|
||||||
# @private
|
|
||||||
UNITY = "<%= versions["UNITY"] %>"
|
|
||||||
end
|
|
||||||
end
|
|
@ -32,12 +32,16 @@ rule(/#{BULLSEYE_BUILD_OUTPUT_PATH}\/#{'.+\\'+EXTENSION_OBJECT}$/ => [
|
|||||||
end
|
end
|
||||||
|
|
||||||
rule(/#{BULLSEYE_BUILD_OUTPUT_PATH}\/#{'.+\\'+EXTENSION_EXECUTABLE}$/) do |bin_file|
|
rule(/#{BULLSEYE_BUILD_OUTPUT_PATH}\/#{'.+\\'+EXTENSION_EXECUTABLE}$/) do |bin_file|
|
||||||
|
lib_args = @ceedling[:test_invoker].convert_libraries_to_arguments()
|
||||||
|
lib_paths = @ceedling[:test_invoker].get_library_paths_to_arguments()
|
||||||
@ceedling[:generator].generate_executable_file(
|
@ceedling[:generator].generate_executable_file(
|
||||||
TOOLS_BULLSEYE_LINKER,
|
TOOLS_BULLSEYE_LINKER,
|
||||||
BULLSEYE_SYM,
|
BULLSEYE_SYM,
|
||||||
bin_file.prerequisites,
|
bin_file.prerequisites,
|
||||||
bin_file.name,
|
bin_file.name,
|
||||||
@ceedling[:file_path_utils].form_test_build_map_filepath(bin_file.name)
|
@ceedling[:file_path_utils].form_test_build_map_filepath(bin_file.name),
|
||||||
|
lib_args,
|
||||||
|
lib_paths
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -69,7 +73,7 @@ namespace BULLSEYE_SYM do
|
|||||||
task source_coverage: COLLECTION_ALL_SOURCE.pathmap("#{BULLSEYE_BUILD_OUTPUT_PATH}/%n#{@ceedling[:configurator].extension_object}")
|
task source_coverage: COLLECTION_ALL_SOURCE.pathmap("#{BULLSEYE_BUILD_OUTPUT_PATH}/%n#{@ceedling[:configurator].extension_object}")
|
||||||
|
|
||||||
desc 'Run code coverage for all tests'
|
desc 'Run code coverage for all tests'
|
||||||
task all: [:directories] do
|
task all: [:test_deps] do
|
||||||
@ceedling[:configurator].replace_flattened_config(@ceedling[BULLSEYE_SYM].config)
|
@ceedling[:configurator].replace_flattened_config(@ceedling[BULLSEYE_SYM].config)
|
||||||
@ceedling[BULLSEYE_SYM].enableBullseye(true)
|
@ceedling[BULLSEYE_SYM].enableBullseye(true)
|
||||||
@ceedling[:test_invoker].setup_and_invoke(COLLECTION_ALL_TESTS, BULLSEYE_SYM)
|
@ceedling[:test_invoker].setup_and_invoke(COLLECTION_ALL_TESTS, BULLSEYE_SYM)
|
||||||
@ -81,18 +85,18 @@ namespace BULLSEYE_SYM do
|
|||||||
message = "\nOops! '#{BULLSEYE_ROOT_NAME}:*' isn't a real task. " +
|
message = "\nOops! '#{BULLSEYE_ROOT_NAME}:*' isn't a real task. " +
|
||||||
"Use a real test or source file name (no path) in place of the wildcard.\n" +
|
"Use a real test or source file name (no path) in place of the wildcard.\n" +
|
||||||
"Example: rake #{BULLSEYE_ROOT_NAME}:foo.c\n\n"
|
"Example: rake #{BULLSEYE_ROOT_NAME}:foo.c\n\n"
|
||||||
|
|
||||||
@ceedling[:streaminator].stdout_puts( message )
|
@ceedling[:streaminator].stdout_puts( message )
|
||||||
end
|
end
|
||||||
|
|
||||||
desc 'Run tests by matching regular expression pattern.'
|
desc 'Run tests by matching regular expression pattern.'
|
||||||
task :pattern, [:regex] => [:directories] do |_t, args|
|
task :pattern, [:regex] => [:test_deps] do |_t, args|
|
||||||
matches = []
|
matches = []
|
||||||
|
|
||||||
COLLECTION_ALL_TESTS.each do |test|
|
COLLECTION_ALL_TESTS.each do |test|
|
||||||
matches << test if test =~ /#{args.regex}/
|
matches << test if test =~ /#{args.regex}/
|
||||||
end
|
end
|
||||||
|
|
||||||
if !matches.empty?
|
if !matches.empty?
|
||||||
@ceedling[:configurator].replace_flattened_config(@ceedling[BULLSEYE_SYM].config)
|
@ceedling[:configurator].replace_flattened_config(@ceedling[BULLSEYE_SYM].config)
|
||||||
@ceedling[BULLSEYE_SYM].enableBullseye(true)
|
@ceedling[BULLSEYE_SYM].enableBullseye(true)
|
||||||
@ -104,13 +108,13 @@ namespace BULLSEYE_SYM do
|
|||||||
end
|
end
|
||||||
|
|
||||||
desc 'Run tests whose test path contains [dir] or [dir] substring.'
|
desc 'Run tests whose test path contains [dir] or [dir] substring.'
|
||||||
task :path, [:dir] => [:directories] do |_t, args|
|
task :path, [:dir] => [:test_deps] do |_t, args|
|
||||||
matches = []
|
matches = []
|
||||||
|
|
||||||
COLLECTION_ALL_TESTS.each do |test|
|
COLLECTION_ALL_TESTS.each do |test|
|
||||||
matches << test if File.dirname(test).include?(args.dir.tr('\\', '/'))
|
matches << test if File.dirname(test).include?(args.dir.tr('\\', '/'))
|
||||||
end
|
end
|
||||||
|
|
||||||
if !matches.empty?
|
if !matches.empty?
|
||||||
@ceedling[:configurator].replace_flattened_config(@ceedling[BULLSEYE_SYM].config)
|
@ceedling[:configurator].replace_flattened_config(@ceedling[BULLSEYE_SYM].config)
|
||||||
@ceedling[BULLSEYE_SYM].enableBullseye(true)
|
@ceedling[BULLSEYE_SYM].enableBullseye(true)
|
||||||
@ -122,13 +126,13 @@ namespace BULLSEYE_SYM do
|
|||||||
end
|
end
|
||||||
|
|
||||||
desc 'Run code coverage for changed files'
|
desc 'Run code coverage for changed files'
|
||||||
task delta: [:directories] do
|
task delta: [:test_deps] do
|
||||||
@ceedling[:configurator].replace_flattened_config(@ceedling[BULLSEYE_SYM].config)
|
@ceedling[:configurator].replace_flattened_config(@ceedling[BULLSEYE_SYM].config)
|
||||||
@ceedling[BULLSEYE_SYM].enableBullseye(true)
|
@ceedling[BULLSEYE_SYM].enableBullseye(true)
|
||||||
@ceedling[:test_invoker].setup_and_invoke(COLLECTION_ALL_TESTS, BULLSEYE_SYM, {:force_run => false})
|
@ceedling[:test_invoker].setup_and_invoke(COLLECTION_ALL_TESTS, BULLSEYE_SYM, {:force_run => false})
|
||||||
@ceedling[:configurator].restore_config
|
@ceedling[:configurator].restore_config
|
||||||
end
|
end
|
||||||
|
|
||||||
# use a rule to increase efficiency for large projects
|
# use a rule to increase efficiency for large projects
|
||||||
# bullseye test tasks by regex
|
# bullseye test tasks by regex
|
||||||
rule(/^#{BULLSEYE_TASK_ROOT}\S+$/ => [
|
rule(/^#{BULLSEYE_TASK_ROOT}\S+$/ => [
|
||||||
@ -138,7 +142,7 @@ namespace BULLSEYE_SYM do
|
|||||||
@ceedling[:file_finder].find_test_from_file_path(test)
|
@ceedling[:file_finder].find_test_from_file_path(test)
|
||||||
end
|
end
|
||||||
]) do |test|
|
]) do |test|
|
||||||
@ceedling[:rake_wrapper][:directories].invoke
|
@ceedling[:rake_wrapper][:test_deps].invoke
|
||||||
@ceedling[:configurator].replace_flattened_config(@ceedling[BULLSEYE_SYM].config)
|
@ceedling[:configurator].replace_flattened_config(@ceedling[BULLSEYE_SYM].config)
|
||||||
@ceedling[BULLSEYE_SYM].enableBullseye(true)
|
@ceedling[BULLSEYE_SYM].enableBullseye(true)
|
||||||
@ceedling[:test_invoker].setup_and_invoke([test.source], BULLSEYE_SYM)
|
@ceedling[:test_invoker].setup_and_invoke([test.source], BULLSEYE_SYM)
|
||||||
@ -159,11 +163,11 @@ end
|
|||||||
end
|
end
|
||||||
|
|
||||||
namespace UTILS_SYM do
|
namespace UTILS_SYM do
|
||||||
|
|
||||||
desc "Open Bullseye code coverage browser"
|
desc "Open Bullseye code coverage browser"
|
||||||
task BULLSEYE_SYM do
|
task BULLSEYE_SYM do
|
||||||
command = @ceedling[:tool_executor].build_command_line(TOOLS_BULLSEYE_BROWSER, [])
|
command = @ceedling[:tool_executor].build_command_line(TOOLS_BULLSEYE_BROWSER, [])
|
||||||
@ceedling[:tool_executor].exec(command[:line], command[:options])
|
@ceedling[:tool_executor].exec(command[:line], command[:options])
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
420
test/vendor/ceedling/plugins/gcov/README.md
vendored
420
test/vendor/ceedling/plugins/gcov/README.md
vendored
@ -7,95 +7,427 @@ Plugin for integrating GNU GCov code coverage tool into Ceedling projects.
|
|||||||
Currently only designed for the gcov command (like LCOV for example). In the
|
Currently only designed for the gcov command (like LCOV for example). In the
|
||||||
future we could configure this to work with other code coverage tools.
|
future we could configure this to work with other code coverage tools.
|
||||||
|
|
||||||
This plugin currently uses `gcovr` to generate HTML and/or XML reports as a
|
This plugin currently uses [gcovr](https://www.gcovr.com/) and / or
|
||||||
utility. The normal gcov plugin _must_ be run first for this report to generate.
|
[ReportGenerator](https://danielpalme.github.io/ReportGenerator/)
|
||||||
|
as utilities to generate HTML, XML, JSON, or Text reports. The normal gcov
|
||||||
|
plugin _must_ be run first for these reports to generate.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
Gcovr can be installed via pip like so:
|
gcovr can be installed via pip like so:
|
||||||
|
|
||||||
```
|
```sh
|
||||||
pip install gcovr
|
pip install gcovr
|
||||||
```
|
```
|
||||||
|
|
||||||
|
ReportGenerator can be installed via .NET Core like so:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
dotnet tool install -g dotnet-reportgenerator-globaltool
|
||||||
|
```
|
||||||
|
|
||||||
|
It is not required to install both `gcovr` and `ReportGenerator`. Either utility
|
||||||
|
may be installed to create reports.
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
The gcov plugin supports configuration options via your `project.yml` provided
|
The gcov plugin supports configuration options via your `project.yml` provided
|
||||||
by Ceedling.
|
by Ceedling.
|
||||||
|
|
||||||
Generation of HTML reports may be enabled or disabled with the following
|
### Utilities
|
||||||
config. Set to `true` to enable or set to `false` to disable.
|
|
||||||
|
|
||||||
```
|
Gcovr and / or ReportGenerator may be enabled to create coverage reports.
|
||||||
|
|
||||||
|
```yaml
|
||||||
:gcov:
|
:gcov:
|
||||||
:html_report: true
|
:utilities:
|
||||||
|
- gcovr # Use gcovr to create the specified reports (default).
|
||||||
|
- ReportGenerator # Use ReportGenerator to create the specified reports.
|
||||||
```
|
```
|
||||||
|
|
||||||
Generation of XML reports may be enabled or disabled with the following
|
### Reports
|
||||||
config. Set to `true` to enable or set to `false` to disable.
|
|
||||||
|
|
||||||
```
|
Various reports are available and may be enabled with the following
|
||||||
|
configuration item. See the specific report sections in this README
|
||||||
|
for additional options and information. All generated reports will be found in `build/artifacts/gcov`.
|
||||||
|
|
||||||
|
```yaml
|
||||||
:gcov:
|
:gcov:
|
||||||
:xml_report: true
|
# Specify one or more reports to generate.
|
||||||
|
# Defaults to HtmlBasic.
|
||||||
|
:reports:
|
||||||
|
# Make an HTML summary report.
|
||||||
|
# Supported utilities: gcovr, ReportGenerator
|
||||||
|
- HtmlBasic
|
||||||
|
|
||||||
|
# Make an HTML report with line by line coverage of each source file.
|
||||||
|
# Supported utilities: gcovr, ReportGenerator
|
||||||
|
- HtmlDetailed
|
||||||
|
|
||||||
|
# Make a Text report, which may be output to the console with gcovr or a file in both gcovr and ReportGenerator.
|
||||||
|
# Supported utilities: gcovr, ReportGenerator
|
||||||
|
- Text
|
||||||
|
|
||||||
|
# Make a Cobertura XML report.
|
||||||
|
# Supported utilities: gcovr, ReportGenerator
|
||||||
|
- Cobertura
|
||||||
|
|
||||||
|
# Make a SonarQube XML report.
|
||||||
|
# Supported utilities: gcovr, ReportGenerator
|
||||||
|
- SonarQube
|
||||||
|
|
||||||
|
# Make a JSON report.
|
||||||
|
# Supported utilities: gcovr
|
||||||
|
- JSON
|
||||||
|
|
||||||
|
# Make a detailed HTML report with CSS and JavaScript included in every HTML page. Useful for build servers.
|
||||||
|
# Supported utilities: ReportGenerator
|
||||||
|
- HtmlInline
|
||||||
|
|
||||||
|
# Make a detailed HTML report with a light theme and CSS and JavaScript included in every HTML page for Azure DevOps.
|
||||||
|
# Supported utilities: ReportGenerator
|
||||||
|
- HtmlInlineAzure
|
||||||
|
|
||||||
|
# Make a detailed HTML report with a dark theme and CSS and JavaScript included in every HTML page for Azure DevOps.
|
||||||
|
# Supported utilities: ReportGenerator
|
||||||
|
- HtmlInlineAzureDark
|
||||||
|
|
||||||
|
# Make a single HTML file containing a chart with historic coverage information.
|
||||||
|
# Supported utilities: ReportGenerator
|
||||||
|
- HtmlChart
|
||||||
|
|
||||||
|
# Make a detailed HTML report in a single file.
|
||||||
|
# Supported utilities: ReportGenerator
|
||||||
|
- MHtml
|
||||||
|
|
||||||
|
# Make SVG and PNG files that show line and / or branch coverage information.
|
||||||
|
# Supported utilities: ReportGenerator
|
||||||
|
- Badges
|
||||||
|
|
||||||
|
# Make a single CSV file containing coverage information per file.
|
||||||
|
# Supported utilities: ReportGenerator
|
||||||
|
- CsvSummary
|
||||||
|
|
||||||
|
# Make a single TEX file containing a summary for all files and detailed reports for each files.
|
||||||
|
# Supported utilities: ReportGenerator
|
||||||
|
- Latex
|
||||||
|
|
||||||
|
# Make a single TEX file containing a summary for all files.
|
||||||
|
# Supported utilities: ReportGenerator
|
||||||
|
- LatexSummary
|
||||||
|
|
||||||
|
# Make a single PNG file containing a chart with historic coverage information.
|
||||||
|
# Supported utilities: ReportGenerator
|
||||||
|
- PngChart
|
||||||
|
|
||||||
|
# Command line output interpreted by TeamCity.
|
||||||
|
# Supported utilities: ReportGenerator
|
||||||
|
- TeamCitySummary
|
||||||
|
|
||||||
|
# Make a text file in lcov format.
|
||||||
|
# Supported utilities: ReportGenerator
|
||||||
|
- lcov
|
||||||
|
|
||||||
|
# Make a XML file containing a summary for all classes and detailed reports for each class.
|
||||||
|
# Supported utilities: ReportGenerator
|
||||||
|
- Xml
|
||||||
|
|
||||||
|
# Make a single XML file containing a summary for all files.
|
||||||
|
# Supported utilities: ReportGenerator
|
||||||
|
- XmlSummary
|
||||||
```
|
```
|
||||||
|
|
||||||
There are two types of gcovr HTML reports that can be configured in your
|
### Gcovr HTML Reports
|
||||||
`project.yml`. To create a basic HTML report, with only the overall file
|
|
||||||
information, use the following config.
|
|
||||||
|
|
||||||
```
|
Generation of Gcovr HTML reports may be modified with the following configuration items.
|
||||||
|
|
||||||
|
```yaml
|
||||||
:gcov:
|
:gcov:
|
||||||
:html_report_type: basic
|
# Set to 'true' to enable HTML reports or set to 'false' to disable.
|
||||||
|
# Defaults to enabled. (gcovr --html)
|
||||||
|
# Deprecated - See the :reports: configuration option.
|
||||||
|
:html_report: [true|false]
|
||||||
|
|
||||||
|
# Gcovr supports generating two types of HTML reports. Use 'basic' to create
|
||||||
|
# an HTML report with only the overall file information. Use 'detailed' to create
|
||||||
|
# an HTML report with line by line coverage of each source file.
|
||||||
|
# Defaults to 'basic'. Set to 'detailed' for (gcovr --html-details).
|
||||||
|
# Deprecated - See the :reports: configuration option.
|
||||||
|
:html_report_type: [basic|detailed]
|
||||||
|
|
||||||
|
|
||||||
|
:gcovr:
|
||||||
|
# HTML report filename.
|
||||||
|
:html_artifact_filename: <output>
|
||||||
|
|
||||||
|
# Use 'title' as title for the HTML report.
|
||||||
|
# Default is 'Head'. (gcovr --html-title)
|
||||||
|
:html_title: <title>
|
||||||
|
|
||||||
|
# If the coverage is below MEDIUM, the value is marked as low coverage in the HTML report.
|
||||||
|
# MEDIUM has to be lower than or equal to value of html_high_threshold.
|
||||||
|
# If MEDIUM is equal to value of html_high_threshold the report has only high and low coverage.
|
||||||
|
# Default is 75.0. (gcovr --html-medium-threshold)
|
||||||
|
:html_medium_threshold: 75
|
||||||
|
|
||||||
|
# If the coverage is below HIGH, the value is marked as medium coverage in the HTML report.
|
||||||
|
# HIGH has to be greater than or equal to value of html_medium_threshold.
|
||||||
|
# If HIGH is equal to value of html_medium_threshold the report has only high and low coverage.
|
||||||
|
# Default is 90.0. (gcovr -html-high-threshold)
|
||||||
|
:html_high_threshold: 90
|
||||||
|
|
||||||
|
# Set to 'true' to use absolute paths to link the 'detailed' reports.
|
||||||
|
# Defaults to relative links. (gcovr --html-absolute-paths)
|
||||||
|
:html_absolute_paths: [true|false]
|
||||||
|
|
||||||
|
# Override the declared HTML report encoding. Defaults to UTF-8. (gcovr --html-encoding)
|
||||||
|
:html_encoding: <html_encoding>
|
||||||
```
|
```
|
||||||
|
|
||||||
To create a detailed HTML report, with line by line breakdown of the
|
### Cobertura XML Reports
|
||||||
coverage, use the following config.
|
|
||||||
|
|
||||||
```
|
Generation of Cobertura XML reports may be modified with the following configuration items.
|
||||||
|
|
||||||
|
```yaml
|
||||||
:gcov:
|
:gcov:
|
||||||
:html_report_type: detailed
|
# Set to 'true' to enable Cobertura XML reports or set to 'false' to disable.
|
||||||
|
# Defaults to disabled. (gcovr --xml)
|
||||||
|
# Deprecated - See the :reports: configuration option.
|
||||||
|
:xml_report: [true|false]
|
||||||
|
|
||||||
|
|
||||||
|
:gcovr:
|
||||||
|
# Set to 'true' to pretty-print the Cobertura XML report, otherwise set to 'false'.
|
||||||
|
# Defaults to disabled. (gcovr --xml-pretty)
|
||||||
|
:xml_pretty: [true|false]
|
||||||
|
:cobertura_pretty: [true|false]
|
||||||
|
|
||||||
|
# Cobertura XML report filename.
|
||||||
|
:xml_artifact_filename: <output>
|
||||||
|
:cobertura_artifact_filename: <output>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### SonarQube XML Reports
|
||||||
|
|
||||||
|
Generation of SonarQube XML reports may be modified with the following configuration items.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
:gcov:
|
||||||
|
:gcovr:
|
||||||
|
# SonarQube XML report filename.
|
||||||
|
:sonarqube_artifact_filename: <output>
|
||||||
|
```
|
||||||
|
|
||||||
|
### JSON Reports
|
||||||
|
|
||||||
|
Generation of JSON reports may be modified with the following configuration items.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
:gcov:
|
||||||
|
:gcovr:
|
||||||
|
# Set to 'true' to pretty-print the JSON report, otherwise set 'false'.
|
||||||
|
# Defaults to disabled. (gcovr --json-pretty)
|
||||||
|
:json_pretty: [true|false]
|
||||||
|
|
||||||
|
# JSON report filename.
|
||||||
|
:json_artifact_filename: <output>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Text Reports
|
||||||
|
|
||||||
|
Generation of text reports may be modified with the following configuration items.
|
||||||
|
Text reports may be printed to the console or output to a file.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
:gcov:
|
||||||
|
:gcovr:
|
||||||
|
# Text report filename.
|
||||||
|
# The text report is printed to the console when no filename is provided.
|
||||||
|
:text_artifact_filename: <output>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Common Report Options
|
||||||
|
|
||||||
There are a number of options to control which files are considered part of
|
There are a number of options to control which files are considered part of
|
||||||
the coverage report. Most often, we only care about coverage on our source code, and not
|
the coverage report. Most often, we only care about coverage on our source code, and not
|
||||||
on tests or automatically generated mocks, runners, etc. However, there are times
|
on tests or automatically generated mocks, runners, etc. However, there are times
|
||||||
where this isn't true... or there are times where we've moved ceedling's directory
|
where this isn't true... or there are times where we've moved ceedling's directory
|
||||||
structure so that the project file isn't at the root of the project anymore. In these
|
structure so that the project file isn't at the root of the project anymore. In these
|
||||||
cases, you may need to tweak the following:
|
cases, you may need to tweak `report_include`, `report_exclude`, and `exclude_directories`.
|
||||||
|
|
||||||
```
|
One important note about `report_root`: gcovr will take only a single root folder, unlike
|
||||||
:gcov:
|
Ceedling's ability to take as many as you like. So you will need to choose a folder which is
|
||||||
:report_root: "."
|
|
||||||
:report_exclude: "^build|^vendor|^test|^support"
|
|
||||||
:report_include: "^src"
|
|
||||||
```
|
|
||||||
|
|
||||||
One important note about html_report_root: gcovr will only take a single root folder, unlike
|
|
||||||
Ceedling's ability to take as many as you like. So you will need to choose a folder which is
|
|
||||||
a superset of ALL the folders you want, and then use the include or exclude options to set up
|
a superset of ALL the folders you want, and then use the include or exclude options to set up
|
||||||
patterns of files to pay attention to or ignore. It's not ideal, but it works.
|
patterns of files to pay attention to or ignore. It's not ideal, but it works.
|
||||||
|
|
||||||
Finally, there are a number of settings which can be specified in order to adjust the
|
Finally, there are a number of settings which can be specified to adjust the
|
||||||
default behaviors of gcov:
|
default behaviors of gcovr:
|
||||||
|
|
||||||
```
|
```yaml
|
||||||
:gcov:
|
:gcov:
|
||||||
:html_medium_threshold: 75
|
:gcovr:
|
||||||
:html_high_threshold: 90
|
# The root directory of your source files. Defaults to ".", the current directory.
|
||||||
:fail_under_line: 30
|
# File names are reported relative to this root. The report_root is the default report_include.
|
||||||
:fail_under_branch: 30
|
:report_root: "."
|
||||||
|
|
||||||
|
# Load the specified configuration file.
|
||||||
|
# Defaults to gcovr.cfg in the report_root directory. (gcovr --config)
|
||||||
|
:config_file: <config_file>
|
||||||
|
|
||||||
|
# Exit with a status of 2 if the total line coverage is less than MIN.
|
||||||
|
# Can be ORed with exit status of 'fail_under_branch' option. (gcovr --fail-under-line)
|
||||||
|
:fail_under_line: 30
|
||||||
|
|
||||||
|
# Exit with a status of 4 if the total branch coverage is less than MIN.
|
||||||
|
# Can be ORed with exit status of 'fail_under_line' option. (gcovr --fail-under-branch)
|
||||||
|
:fail_under_branch: 30
|
||||||
|
|
||||||
|
# Select the source file encoding.
|
||||||
|
# Defaults to the system default encoding (UTF-8). (gcovr --source-encoding)
|
||||||
|
:source_encoding: <source_encoding>
|
||||||
|
|
||||||
|
# Report the branch coverage instead of the line coverage. For text report only. (gcovr --branches).
|
||||||
|
:branches: [true|false]
|
||||||
|
|
||||||
|
# Sort entries by increasing number of uncovered lines.
|
||||||
|
# For text and HTML report. (gcovr --sort-uncovered)
|
||||||
|
:sort_uncovered: [true|false]
|
||||||
|
|
||||||
|
# Sort entries by increasing percentage of uncovered lines.
|
||||||
|
# For text and HTML report. (gcovr --sort-percentage)
|
||||||
|
:sort_percentage: [true|false]
|
||||||
|
|
||||||
|
# Print a small report to stdout with line & branch percentage coverage.
|
||||||
|
# This is in addition to other reports. (gcovr --print-summary).
|
||||||
|
:print_summary: [true|false]
|
||||||
|
|
||||||
|
# Keep only source files that match this filter. (gcovr --filter).
|
||||||
|
:report_include: "^src"
|
||||||
|
|
||||||
|
# Exclude source files that match this filter. (gcovr --exclude).
|
||||||
|
:report_exclude: "^vendor.*|^build.*|^test.*|^lib.*"
|
||||||
|
|
||||||
|
# Keep only gcov data files that match this filter. (gcovr --gcov-filter).
|
||||||
|
:gcov_filter: <gcov_filter>
|
||||||
|
|
||||||
|
# Exclude gcov data files that match this filter. (gcovr --gcov-exclude).
|
||||||
|
:gcov_exclude: <gcov_exclude>
|
||||||
|
|
||||||
|
# Exclude directories that match this regex while searching
|
||||||
|
# raw coverage files. (gcovr --exclude-directories).
|
||||||
|
:exclude_directories: <exclude_dirs>
|
||||||
|
|
||||||
|
# Use a particular gcov executable. (gcovr --gcov-executable).
|
||||||
|
:gcov_executable: <gcov_cmd>
|
||||||
|
|
||||||
|
# Exclude branch coverage from lines without useful
|
||||||
|
# source code. (gcovr --exclude-unreachable-branches).
|
||||||
|
:exclude_unreachable_branches: [true|false]
|
||||||
|
|
||||||
|
# For branch coverage, exclude branches that the compiler
|
||||||
|
# generates for exception handling. (gcovr --exclude-throw-branches).
|
||||||
|
:exclude_throw_branches: [true|false]
|
||||||
|
|
||||||
|
# Use existing gcov files for analysis. Default: False. (gcovr --use-gcov-files)
|
||||||
|
:use_gcov_files: [true|false]
|
||||||
|
|
||||||
|
# Skip lines with parse errors in GCOV files instead of
|
||||||
|
# exiting with an error. (gcovr --gcov-ignore-parse-errors).
|
||||||
|
:gcov_ignore_parse_errors: [true|false]
|
||||||
|
|
||||||
|
# Override normal working directory detection. (gcovr --object-directory)
|
||||||
|
:object_directory: <objdir>
|
||||||
|
|
||||||
|
# Keep gcov files after processing. (gcovr --keep).
|
||||||
|
:keep: [true|false]
|
||||||
|
|
||||||
|
# Delete gcda files after processing. (gcovr --delete).
|
||||||
|
:delete: [true|false]
|
||||||
|
|
||||||
|
# Set the number of threads to use in parallel. (gcovr -j).
|
||||||
|
:num_parallel_threads: <num_threads>
|
||||||
|
|
||||||
|
# When scanning the code coverage, if any files are found that do not have
|
||||||
|
# associated coverage data, the command will abort with an error message.
|
||||||
|
:abort_on_uncovered: true
|
||||||
|
|
||||||
|
# When using the ``abort_on_uncovered`` option, the files in this list will not
|
||||||
|
# trigger a failure.
|
||||||
|
# Ceedling globs described in the Ceedling packet ``Path`` section can be used
|
||||||
|
# when directories are placed on the list. Globs are limited to matching directories
|
||||||
|
# and not files.
|
||||||
|
:uncovered_ignore_list: []
|
||||||
```
|
```
|
||||||
|
|
||||||
These HTML and XML reports will be found in `build/artifacts/gcov`.
|
### ReportGenerator Configuration
|
||||||
|
|
||||||
|
The ReportGenerator utility may be configured with the following configuration items.
|
||||||
|
All generated reports may be found in `build/artifacts/gcov/ReportGenerator`.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
:gcov:
|
||||||
|
:report_generator:
|
||||||
|
# Optional directory for storing persistent coverage information.
|
||||||
|
# Can be used in future reports to show coverage evolution.
|
||||||
|
:history_directory: <history_directory>
|
||||||
|
|
||||||
|
# Optional plugin files for custom reports or custom history storage (separated by semicolon).
|
||||||
|
:plugins: CustomReports.dll
|
||||||
|
|
||||||
|
# Optional list of assemblies that should be included or excluded in the report (separated by semicolon)..
|
||||||
|
# Exclusion filters take precedence over inclusion filters.
|
||||||
|
# Wildcards are allowed, but not regular expressions.
|
||||||
|
:assembly_filters: "+Included;-Excluded"
|
||||||
|
|
||||||
|
# Optional list of classes that should be included or excluded in the report (separated by semicolon)..
|
||||||
|
# Exclusion filters take precedence over inclusion filters.
|
||||||
|
# Wildcards are allowed, but not regular expressions.
|
||||||
|
:class_filters: "+Included;-Excluded"
|
||||||
|
|
||||||
|
# Optional list of files that should be included or excluded in the report (separated by semicolon)..
|
||||||
|
# Exclusion filters take precedence over inclusion filters.
|
||||||
|
# Wildcards are allowed, but not regular expressions.
|
||||||
|
:file_filters: "-./vendor/*;-./build/*;-./test/*;-./lib/*;+./src/*"
|
||||||
|
|
||||||
|
# The verbosity level of the log messages.
|
||||||
|
# Values: Verbose, Info, Warning, Error, Off
|
||||||
|
:verbosity: Warning
|
||||||
|
|
||||||
|
# Optional tag or build version.
|
||||||
|
:tag: <tag>
|
||||||
|
|
||||||
|
# Optional list of one or more regular expressions to exclude gcov notes files that match these filters.
|
||||||
|
:gcov_exclude:
|
||||||
|
- <exclude_regex1>
|
||||||
|
- <exclude_regex2>
|
||||||
|
|
||||||
|
# Optionally use a particular gcov executable. Defaults to gcov.
|
||||||
|
:gcov_executable: <gcov_cmd>
|
||||||
|
|
||||||
|
# Optionally set the number of threads to use in parallel. Defaults to 1.
|
||||||
|
:num_parallel_threads: <num_threads>
|
||||||
|
|
||||||
|
# Optional list of one or more command line arguments to pass to Report Generator.
|
||||||
|
# Useful for configuring Risk Hotspots and Other Settings.
|
||||||
|
# https://github.com/danielpalme/ReportGenerator/wiki/Settings
|
||||||
|
:custom_args:
|
||||||
|
- <custom_arg1>
|
||||||
|
- <custom_arg2>
|
||||||
|
```
|
||||||
|
|
||||||
## Example Usage
|
## Example Usage
|
||||||
|
|
||||||
```
|
```sh
|
||||||
ceedling gcov:all utils:gcov
|
ceedling gcov:all utils:gcov
|
||||||
```
|
```
|
||||||
|
|
||||||
## To-Do list
|
## To-Do list
|
||||||
|
|
||||||
- Generate overall report (combined statistics from all files with coverage)
|
- Generate overall report (combined statistics from all files with coverage)
|
||||||
- Generate coverage output files
|
|
||||||
- Easier option override for better customisation
|
## Citations
|
||||||
|
|
||||||
|
Most of the comment text which describes the options was taken from the
|
||||||
|
[Gcovr User Guide](https://www.gcovr.com/en/stable/guide.html) and the
|
||||||
|
[ReportGenerator Wiki](https://github.com/danielpalme/ReportGenerator/wiki).
|
||||||
|
The text is repeated here to provide the most accurate option functionality.
|
||||||
|
@ -1,73 +0,0 @@
|
|||||||
---
|
|
||||||
|
|
||||||
:tools:
|
|
||||||
:gcov_compiler:
|
|
||||||
:executable: gcc
|
|
||||||
:arguments:
|
|
||||||
- -g
|
|
||||||
- -fprofile-arcs
|
|
||||||
- -ftest-coverage
|
|
||||||
- -I"$": COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR
|
|
||||||
- -I"$": COLLECTION_PATHS_TEST_TOOLCHAIN_INCLUDE
|
|
||||||
- -D$: COLLECTION_DEFINES_TEST_AND_VENDOR
|
|
||||||
- -DGCOV_COMPILER
|
|
||||||
- -DCODE_COVERAGE
|
|
||||||
- -c "${1}"
|
|
||||||
- -o "${2}"
|
|
||||||
:gcov_linker:
|
|
||||||
:executable: gcc
|
|
||||||
:arguments:
|
|
||||||
- -fprofile-arcs
|
|
||||||
- -ftest-coverage
|
|
||||||
- ${1}
|
|
||||||
- -o ${2}
|
|
||||||
- ${3}
|
|
||||||
:gcov_fixture:
|
|
||||||
:executable: ${1}
|
|
||||||
:gcov_report:
|
|
||||||
:executable: gcov
|
|
||||||
:arguments:
|
|
||||||
- -n
|
|
||||||
- -p
|
|
||||||
- -b
|
|
||||||
- -o "$": GCOV_BUILD_OUTPUT_PATH
|
|
||||||
- "\"${1}\""
|
|
||||||
:gcov_post_report:
|
|
||||||
:executable: gcovr
|
|
||||||
:optional: TRUE
|
|
||||||
:arguments:
|
|
||||||
- -p
|
|
||||||
- -b
|
|
||||||
- ${1}
|
|
||||||
- --html
|
|
||||||
- -o GcovCoverageResults.html
|
|
||||||
:gcov_post_report_basic:
|
|
||||||
:executable: gcovr
|
|
||||||
:optional: TRUE
|
|
||||||
:arguments:
|
|
||||||
- -p
|
|
||||||
- -b
|
|
||||||
- ${1}
|
|
||||||
- --html
|
|
||||||
- -o "$": GCOV_ARTIFACTS_FILE
|
|
||||||
:gcov_post_report_advanced:
|
|
||||||
:executable: gcovr
|
|
||||||
:optional: TRUE
|
|
||||||
:arguments:
|
|
||||||
- -p
|
|
||||||
- -b
|
|
||||||
- ${1}
|
|
||||||
- --html
|
|
||||||
- --html-details
|
|
||||||
- -o "$": GCOV_ARTIFACTS_FILE
|
|
||||||
:gcov_post_report_xml:
|
|
||||||
:executable: gcovr
|
|
||||||
:optional: TRUE
|
|
||||||
:arguments:
|
|
||||||
- -p
|
|
||||||
- -b
|
|
||||||
- ${1}
|
|
||||||
- --xml
|
|
||||||
- -o "$": GCOV_ARTIFACTS_FILE_XML
|
|
||||||
|
|
||||||
...
|
|
99
test/vendor/ceedling/plugins/gcov/gcov.rake
vendored
99
test/vendor/ceedling/plugins/gcov/gcov.rake
vendored
@ -1,3 +1,6 @@
|
|||||||
|
require 'reportgenerator_reportinator'
|
||||||
|
require 'gcovr_reportinator'
|
||||||
|
|
||||||
directory(GCOV_BUILD_OUTPUT_PATH)
|
directory(GCOV_BUILD_OUTPUT_PATH)
|
||||||
directory(GCOV_RESULTS_PATH)
|
directory(GCOV_RESULTS_PATH)
|
||||||
directory(GCOV_ARTIFACTS_PATH)
|
directory(GCOV_ARTIFACTS_PATH)
|
||||||
@ -16,7 +19,7 @@ rule(/#{GCOV_BUILD_OUTPUT_PATH}\/#{'.+\\' + EXTENSION_OBJECT}$/ => [
|
|||||||
end
|
end
|
||||||
]) do |object|
|
]) do |object|
|
||||||
|
|
||||||
if File.basename(object.source) =~ /^(#{PROJECT_TEST_FILE_PREFIX}|#{CMOCK_MOCK_PREFIX}|#{GCOV_IGNORE_SOURCES.join('|')})/i
|
if File.basename(object.source) =~ /^(#{PROJECT_TEST_FILE_PREFIX}|#{CMOCK_MOCK_PREFIX})|(#{VENDORS_FILES.map{|source| '\b' + source + '\b'}.join('|')})/
|
||||||
@ceedling[:generator].generate_object_file(
|
@ceedling[:generator].generate_object_file(
|
||||||
TOOLS_GCOV_COMPILER,
|
TOOLS_GCOV_COMPILER,
|
||||||
OPERATION_COMPILE_SYM,
|
OPERATION_COMPILE_SYM,
|
||||||
@ -32,14 +35,15 @@ end
|
|||||||
|
|
||||||
rule(/#{GCOV_BUILD_OUTPUT_PATH}\/#{'.+\\' + EXTENSION_EXECUTABLE}$/) do |bin_file|
|
rule(/#{GCOV_BUILD_OUTPUT_PATH}\/#{'.+\\' + EXTENSION_EXECUTABLE}$/) do |bin_file|
|
||||||
lib_args = @ceedling[:test_invoker].convert_libraries_to_arguments()
|
lib_args = @ceedling[:test_invoker].convert_libraries_to_arguments()
|
||||||
|
lib_paths = @ceedling[:test_invoker].get_library_paths_to_arguments()
|
||||||
@ceedling[:generator].generate_executable_file(
|
@ceedling[:generator].generate_executable_file(
|
||||||
TOOLS_GCOV_LINKER,
|
TOOLS_GCOV_LINKER,
|
||||||
GCOV_SYM,
|
GCOV_SYM,
|
||||||
bin_file.prerequisites,
|
bin_file.prerequisites,
|
||||||
bin_file.name,
|
bin_file.name,
|
||||||
|
@ceedling[:file_path_utils].form_test_build_map_filepath(bin_file.name),
|
||||||
lib_args,
|
lib_args,
|
||||||
@ceedling[:file_path_utils].form_test_build_map_filepath(bin_file.name)
|
lib_paths
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -71,7 +75,7 @@ namespace GCOV_SYM do
|
|||||||
task source_coverage: COLLECTION_ALL_SOURCE.pathmap("#{GCOV_BUILD_OUTPUT_PATH}/%n#{@ceedling[:configurator].extension_object}")
|
task source_coverage: COLLECTION_ALL_SOURCE.pathmap("#{GCOV_BUILD_OUTPUT_PATH}/%n#{@ceedling[:configurator].extension_object}")
|
||||||
|
|
||||||
desc 'Run code coverage for all tests'
|
desc 'Run code coverage for all tests'
|
||||||
task all: [:directories] do
|
task all: [:test_deps] do
|
||||||
@ceedling[:configurator].replace_flattened_config(@ceedling[GCOV_SYM].config)
|
@ceedling[:configurator].replace_flattened_config(@ceedling[GCOV_SYM].config)
|
||||||
@ceedling[:test_invoker].setup_and_invoke(COLLECTION_ALL_TESTS, GCOV_SYM)
|
@ceedling[:test_invoker].setup_and_invoke(COLLECTION_ALL_TESTS, GCOV_SYM)
|
||||||
@ceedling[:configurator].restore_config
|
@ceedling[:configurator].restore_config
|
||||||
@ -87,7 +91,7 @@ namespace GCOV_SYM do
|
|||||||
end
|
end
|
||||||
|
|
||||||
desc 'Run tests by matching regular expression pattern.'
|
desc 'Run tests by matching regular expression pattern.'
|
||||||
task :pattern, [:regex] => [:directories] do |_t, args|
|
task :pattern, [:regex] => [:test_deps] do |_t, args|
|
||||||
matches = []
|
matches = []
|
||||||
|
|
||||||
COLLECTION_ALL_TESTS.each do |test|
|
COLLECTION_ALL_TESTS.each do |test|
|
||||||
@ -104,7 +108,7 @@ namespace GCOV_SYM do
|
|||||||
end
|
end
|
||||||
|
|
||||||
desc 'Run tests whose test path contains [dir] or [dir] substring.'
|
desc 'Run tests whose test path contains [dir] or [dir] substring.'
|
||||||
task :path, [:dir] => [:directories] do |_t, args|
|
task :path, [:dir] => [:test_deps] do |_t, args|
|
||||||
matches = []
|
matches = []
|
||||||
|
|
||||||
COLLECTION_ALL_TESTS.each do |test|
|
COLLECTION_ALL_TESTS.each do |test|
|
||||||
@ -121,7 +125,7 @@ namespace GCOV_SYM do
|
|||||||
end
|
end
|
||||||
|
|
||||||
desc 'Run code coverage for changed files'
|
desc 'Run code coverage for changed files'
|
||||||
task delta: [:directories] do
|
task delta: [:test_deps] do
|
||||||
@ceedling[:configurator].replace_flattened_config(@ceedling[GCOV_SYM].config)
|
@ceedling[:configurator].replace_flattened_config(@ceedling[GCOV_SYM].config)
|
||||||
@ceedling[:test_invoker].setup_and_invoke(COLLECTION_ALL_TESTS, GCOV_SYM, force_run: false)
|
@ceedling[:test_invoker].setup_and_invoke(COLLECTION_ALL_TESTS, GCOV_SYM, force_run: false)
|
||||||
@ceedling[:configurator].restore_config
|
@ceedling[:configurator].restore_config
|
||||||
@ -136,7 +140,7 @@ namespace GCOV_SYM do
|
|||||||
@ceedling[:file_finder].find_test_from_file_path(test)
|
@ceedling[:file_finder].find_test_from_file_path(test)
|
||||||
end
|
end
|
||||||
]) do |test|
|
]) do |test|
|
||||||
@ceedling[:rake_wrapper][:directories].invoke
|
@ceedling[:rake_wrapper][:test_deps].invoke
|
||||||
@ceedling[:configurator].replace_flattened_config(@ceedling[GCOV_SYM].config)
|
@ceedling[:configurator].replace_flattened_config(@ceedling[GCOV_SYM].config)
|
||||||
@ceedling[:test_invoker].setup_and_invoke([test.source], GCOV_SYM)
|
@ceedling[:test_invoker].setup_and_invoke([test.source], GCOV_SYM)
|
||||||
@ceedling[:configurator].restore_config
|
@ceedling[:configurator].restore_config
|
||||||
@ -154,67 +158,52 @@ if PROJECT_USE_DEEP_DEPENDENCIES
|
|||||||
end
|
end
|
||||||
|
|
||||||
namespace UTILS_SYM do
|
namespace UTILS_SYM do
|
||||||
def gcov_args_builder(opts)
|
# Report Creation Utilities
|
||||||
args = ""
|
UTILITY_NAME_GCOVR = "gcovr"
|
||||||
args += "-r \"#{opts[:gcov_report_root] || '.'}\" "
|
UTILITY_NAME_REPORT_GENERATOR = "ReportGenerator"
|
||||||
args += "-f \"#{opts[:gcov_report_include]}\" " unless opts[:gcov_report_include].nil?
|
UTILITY_NAMES = [UTILITY_NAME_GCOVR, UTILITY_NAME_REPORT_GENERATOR]
|
||||||
args += "-e \"#{opts[:gcov_report_exclude] || GCOV_FILTER_EXCLUDE}\" "
|
|
||||||
[ :gcov_fail_under_line, :gcov_fail_under_branch, :gcov_html_medium_threshold, :gcov_html_high_threshold].each do |opt|
|
# Returns true is the given utility is enabled, otherwise returns false.
|
||||||
args += "--#{opt.to_s.gsub('_','-').sub(/:?gcov-/,'')} #{opts[opt]} " unless opts[opt].nil?
|
def is_utility_enabled(opts, utility_name)
|
||||||
end
|
return !(opts.nil?) && !(opts[:gcov_utilities].nil?) && (opts[:gcov_utilities].map(&:upcase).include? utility_name.upcase)
|
||||||
return args
|
|
||||||
end
|
end
|
||||||
|
|
||||||
desc 'Create gcov code coverage html report (must run ceedling gcov first)'
|
|
||||||
task GCOV_SYM do
|
|
||||||
|
|
||||||
|
desc "Create gcov code coverage html/xml/json/text report(s). (Note: Must run 'ceedling gcov' first)."
|
||||||
|
task GCOV_SYM do
|
||||||
|
# Get the gcov options from project.yml.
|
||||||
|
opts = @ceedling[:configurator].project_config_hash
|
||||||
|
|
||||||
|
# Create the artifacts output directory.
|
||||||
if !File.directory? GCOV_ARTIFACTS_PATH
|
if !File.directory? GCOV_ARTIFACTS_PATH
|
||||||
FileUtils.mkdir_p GCOV_ARTIFACTS_PATH
|
FileUtils.mkdir_p GCOV_ARTIFACTS_PATH
|
||||||
end
|
end
|
||||||
|
|
||||||
args = gcov_args_builder(@ceedling[:configurator].project_config_hash)
|
# Remove unsupported reporting utilities.
|
||||||
|
if !(opts[:gcov_utilities].nil?)
|
||||||
if @ceedling[:configurator].project_config_hash[:gcov_html_report].nil?
|
opts[:gcov_utilities].reject! { |item| !(UTILITY_NAMES.map(&:upcase).include? item.upcase) }
|
||||||
puts "In your project.yml, define: \n\n:gcov:\n :html_report:\n\n to true or false to refine this feature."
|
|
||||||
puts "For now, assumimg you want an html report generated."
|
|
||||||
html_enabled = true
|
|
||||||
else
|
|
||||||
html_enabled = @ceedling[:configurator].project_config_hash[:gcov_html_report]
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if @ceedling[:configurator].project_config_hash[:gcov_xml_report].nil?
|
# Default to gcovr when no reporting utilities are specified.
|
||||||
puts "In your project.yml, define: \n\n:gcov:\n :xml_report:\n\n to true or false to refine this feature."
|
if opts[:gcov_utilities].nil? || opts[:gcov_utilities].empty?
|
||||||
puts "For now, assumimg you do not want an xml report generated."
|
opts[:gcov_utilities] = [UTILITY_NAME_GCOVR]
|
||||||
xml_enabled = false
|
|
||||||
else
|
|
||||||
xml_enabled = @ceedling[:configurator].project_config_hash[:gcov_xml_report]
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if html_enabled
|
if opts[:gcov_reports].nil?
|
||||||
if @ceedling[:configurator].project_config_hash[:gcov_html_report_type] == 'basic'
|
opts[:gcov_reports] = []
|
||||||
puts "Creating a basic html report of gcov results in #{GCOV_ARTIFACTS_FILE}..."
|
|
||||||
command = @ceedling[:tool_executor].build_command_line(TOOLS_GCOV_POST_REPORT_BASIC, [], args)
|
|
||||||
@ceedling[:tool_executor].exec(command[:line], command[:options])
|
|
||||||
elsif @ceedling[:configurator].project_config_hash[:gcov_html_report_type] == 'detailed'
|
|
||||||
puts "Creating a detailed html report of gcov results in #{GCOV_ARTIFACTS_FILE}..."
|
|
||||||
command = @ceedling[:tool_executor].build_command_line(TOOLS_GCOV_POST_REPORT_ADVANCED, [], args)
|
|
||||||
@ceedling[:tool_executor].exec(command[:line], command[:options])
|
|
||||||
|
|
||||||
else
|
|
||||||
puts "In your project.yml, define: \n\n:gcov:\n :html_report_type:\n\n to basic or detailed to refine this feature."
|
|
||||||
puts "For now, just creating basic."
|
|
||||||
puts "Creating a basic html report of gcov results in #{GCOV_ARTIFACTS_FILE}..."
|
|
||||||
command = @ceedling[:tool_executor].build_command_line(TOOLS_GCOV_POST_REPORT_BASIC, [], args)
|
|
||||||
@ceedling[:tool_executor].exec(command[:line], command[:options])
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if xml_enabled
|
gcovr_reportinator = GcovrReportinator.new(@ceedling)
|
||||||
puts "Creating an xml report of gcov results in #{GCOV_ARTIFACTS_FILE_XML}..."
|
gcovr_reportinator.support_deprecated_options(opts)
|
||||||
command = @ceedling[:tool_executor].build_command_line(TOOLS_GCOV_POST_REPORT_XML, [], filter)
|
|
||||||
@ceedling[:tool_executor].exec(command[:line], command[:options])
|
if is_utility_enabled(opts, UTILITY_NAME_GCOVR)
|
||||||
|
gcovr_reportinator.make_reports(opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
if is_utility_enabled(opts, UTILITY_NAME_REPORT_GENERATOR)
|
||||||
|
reportgenerator_reportinator = ReportGeneratorReportinator.new(@ceedling)
|
||||||
|
reportgenerator_reportinator.make_reports(opts)
|
||||||
end
|
end
|
||||||
|
|
||||||
puts "Done."
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
33
test/vendor/ceedling/plugins/gcov/lib/gcov.rb
vendored
33
test/vendor/ceedling/plugins/gcov/lib/gcov.rb
vendored
@ -82,10 +82,7 @@ class Gcov < Plugin
|
|||||||
banner = @ceedling[:plugin_reportinator].generate_banner "#{GCOV_ROOT_NAME.upcase}: CODE COVERAGE SUMMARY"
|
banner = @ceedling[:plugin_reportinator].generate_banner "#{GCOV_ROOT_NAME.upcase}: CODE COVERAGE SUMMARY"
|
||||||
@ceedling[:streaminator].stdout_puts "\n" + banner
|
@ceedling[:streaminator].stdout_puts "\n" + banner
|
||||||
|
|
||||||
coverage_sources = sources.clone
|
coverage_sources = @ceedling[:project_config_manager].filter_internal_sources(sources)
|
||||||
coverage_sources.delete_if { |item| item =~ /#{CMOCK_MOCK_PREFIX}.+#{EXTENSION_SOURCE}$/ }
|
|
||||||
coverage_sources.delete_if { |item| item =~ /#{GCOV_IGNORE_SOURCES.join('|')}#{EXTENSION_SOURCE}$/ }
|
|
||||||
|
|
||||||
coverage_sources.each do |source|
|
coverage_sources.each do |source|
|
||||||
basename = File.basename(source)
|
basename = File.basename(source)
|
||||||
command = @ceedling[:tool_executor].build_command_line(TOOLS_GCOV_REPORT, [], [basename])
|
command = @ceedling[:tool_executor].build_command_line(TOOLS_GCOV_REPORT, [], [basename])
|
||||||
@ -98,9 +95,35 @@ class Gcov < Plugin
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ignore_path_list = @ceedling[:file_system_utils].collect_paths(@ceedling[:configurator].project_config_hash[:gcov_uncovered_ignore_list] || [])
|
||||||
|
ignore_uncovered_list = @ceedling[:file_wrapper].instantiate_file_list
|
||||||
|
ignore_path_list.each do |path|
|
||||||
|
if File.exists?(path) and not File.directory?(path)
|
||||||
|
ignore_uncovered_list.include(path)
|
||||||
|
else
|
||||||
|
ignore_uncovered_list.include(File.join(path, "*#{EXTENSION_SOURCE}"))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
found_uncovered = false
|
||||||
COLLECTION_ALL_SOURCE.each do |source|
|
COLLECTION_ALL_SOURCE.each do |source|
|
||||||
unless coverage_sources.include?(source)
|
unless coverage_sources.include?(source)
|
||||||
@ceedling[:streaminator].stdout_puts("Could not find coverage results for " + source + "\n")
|
v = Verbosity::DEBUG
|
||||||
|
msg = "Could not find coverage results for " + source
|
||||||
|
if ignore_uncovered_list.include?(source)
|
||||||
|
msg += " [IGNORED]"
|
||||||
|
else
|
||||||
|
found_uncovered = true
|
||||||
|
v = Verbosity::NORMAL
|
||||||
|
end
|
||||||
|
msg += "\n"
|
||||||
|
@ceedling[:streaminator].stdout_puts(msg, v)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if found_uncovered
|
||||||
|
if @ceedling[:configurator].project_config_hash[:gcov_abort_on_uncovered]
|
||||||
|
@ceedling[:streaminator].stderr_puts("There were files with no coverage results: aborting.\n")
|
||||||
|
exit(-1)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,19 +1,48 @@
|
|||||||
|
|
||||||
GCOV_ROOT_NAME = 'gcov'.freeze
|
GCOV_ROOT_NAME = 'gcov'.freeze
|
||||||
GCOV_TASK_ROOT = GCOV_ROOT_NAME + ':'
|
GCOV_TASK_ROOT = GCOV_ROOT_NAME + ':'
|
||||||
GCOV_SYM = GCOV_ROOT_NAME.to_sym
|
GCOV_SYM = GCOV_ROOT_NAME.to_sym
|
||||||
|
|
||||||
GCOV_BUILD_PATH = File.join(PROJECT_BUILD_ROOT, GCOV_ROOT_NAME)
|
GCOV_BUILD_PATH = File.join(PROJECT_BUILD_ROOT, GCOV_ROOT_NAME)
|
||||||
GCOV_BUILD_OUTPUT_PATH = File.join(GCOV_BUILD_PATH, "out")
|
GCOV_BUILD_OUTPUT_PATH = File.join(GCOV_BUILD_PATH, "out")
|
||||||
GCOV_RESULTS_PATH = File.join(GCOV_BUILD_PATH, "results")
|
GCOV_RESULTS_PATH = File.join(GCOV_BUILD_PATH, "results")
|
||||||
GCOV_DEPENDENCIES_PATH = File.join(GCOV_BUILD_PATH, "dependencies")
|
GCOV_DEPENDENCIES_PATH = File.join(GCOV_BUILD_PATH, "dependencies")
|
||||||
GCOV_ARTIFACTS_PATH = File.join(PROJECT_BUILD_ARTIFACTS_ROOT, GCOV_ROOT_NAME)
|
GCOV_ARTIFACTS_PATH = File.join(PROJECT_BUILD_ARTIFACTS_ROOT, GCOV_ROOT_NAME)
|
||||||
|
GCOV_REPORT_GENERATOR_PATH = File.join(GCOV_ARTIFACTS_PATH, "ReportGenerator")
|
||||||
|
|
||||||
GCOV_ARTIFACTS_FILE = File.join(GCOV_ARTIFACTS_PATH, "GcovCoverageResults.html")
|
GCOV_ARTIFACTS_FILE_HTML = File.join(GCOV_ARTIFACTS_PATH, "GcovCoverageResults.html")
|
||||||
GCOV_ARTIFACTS_FILE_XML = File.join(GCOV_ARTIFACTS_PATH, "GcovCoverageResults.xml")
|
GCOV_ARTIFACTS_FILE_COBERTURA = File.join(GCOV_ARTIFACTS_PATH, "GcovCoverageCobertura.xml")
|
||||||
|
GCOV_ARTIFACTS_FILE_SONARQUBE = File.join(GCOV_ARTIFACTS_PATH, "GcovCoverageSonarQube.xml")
|
||||||
|
GCOV_ARTIFACTS_FILE_JSON = File.join(GCOV_ARTIFACTS_PATH, "GcovCoverage.json")
|
||||||
|
|
||||||
GCOV_IGNORE_SOURCES = %w(unity cmock cexception).freeze
|
GCOV_FILTER_EXCLUDE_PATHS = ['vendor', 'build', 'test', 'lib']
|
||||||
|
|
||||||
GCOV_FILTER_EXCLUDE = '^vendor.*|^build.*|^test.*|^lib.*'
|
# gcovr supports regular expressions.
|
||||||
|
GCOV_FILTER_EXCLUDE = GCOV_FILTER_EXCLUDE_PATHS.map{|path| '^'.concat(*path).concat('.*')}.join('|')
|
||||||
|
|
||||||
|
# ReportGenerator supports text with wildcard characters.
|
||||||
|
GCOV_REPORT_GENERATOR_FILE_FILTERS = GCOV_FILTER_EXCLUDE_PATHS.map{|path| File.join('-.', *path, '*')}.join(';')
|
||||||
|
|
||||||
|
# Report Types
|
||||||
|
class ReportTypes
|
||||||
|
HTML_BASIC = "HtmlBasic"
|
||||||
|
HTML_DETAILED = "HtmlDetailed"
|
||||||
|
HTML_CHART = "HtmlChart"
|
||||||
|
HTML_INLINE = "HtmlInline"
|
||||||
|
HTML_INLINE_AZURE = "HtmlInlineAzure"
|
||||||
|
HTML_INLINE_AZURE_DARK = "HtmlInlineAzureDark"
|
||||||
|
MHTML = "MHtml"
|
||||||
|
TEXT = "Text"
|
||||||
|
COBERTURA = "Cobertura"
|
||||||
|
SONARQUBE = "SonarQube"
|
||||||
|
JSON = "JSON"
|
||||||
|
BADGES = "Badges"
|
||||||
|
CSV_SUMMARY = "CsvSummary"
|
||||||
|
LATEX = "Latex"
|
||||||
|
LATEX_SUMMARY = "LatexSummary"
|
||||||
|
PNG_CHART = "PngChart"
|
||||||
|
TEAM_CITY_SUMMARY = "TeamCitySummary"
|
||||||
|
LCOV = "lcov"
|
||||||
|
XML = "Xml"
|
||||||
|
XML_SUMMARY = "XmlSummary"
|
||||||
|
end
|
||||||
|
@ -44,7 +44,7 @@ class JunitTestsReport < Plugin
|
|||||||
def write_header( results, stream )
|
def write_header( results, stream )
|
||||||
results[:counts][:time] = @time_result.reduce(0, :+)
|
results[:counts][:time] = @time_result.reduce(0, :+)
|
||||||
stream.puts '<?xml version="1.0" encoding="utf-8" ?>'
|
stream.puts '<?xml version="1.0" encoding="utf-8" ?>'
|
||||||
stream.puts('<testsuites tests="%<total>d" failures="%<failed>d" skipped="%<ignored>d" time="%<time>f">' % results[:counts])
|
stream.puts('<testsuites tests="%<total>d" failures="%<failed>d" time="%<time>.3f">' % results[:counts])
|
||||||
end
|
end
|
||||||
|
|
||||||
def write_footer( stream )
|
def write_footer( stream )
|
||||||
@ -53,7 +53,7 @@ class JunitTestsReport < Plugin
|
|||||||
|
|
||||||
def reorganise_results( results )
|
def reorganise_results( results )
|
||||||
# Reorganise the output by test suite instead of by result
|
# Reorganise the output by test suite instead of by result
|
||||||
suites = Hash.new{ |h,k| h[k] = {collection: [], total: 0, success: 0, failed: 0, ignored: 0, stdout: []} }
|
suites = Hash.new{ |h,k| h[k] = {collection: [], total: 0, success: 0, failed: 0, ignored: 0, errors: 0, stdout: []} }
|
||||||
results[:successes].each do |result|
|
results[:successes].each do |result|
|
||||||
source = result[:source]
|
source = result[:source]
|
||||||
name = source[:file].sub(/\..{1,4}$/, "")
|
name = source[:file].sub(/\..{1,4}$/, "")
|
||||||
@ -85,7 +85,7 @@ class JunitTestsReport < Plugin
|
|||||||
|
|
||||||
def write_suite( suite, stream )
|
def write_suite( suite, stream )
|
||||||
suite[:time] = @time_result.shift
|
suite[:time] = @time_result.shift
|
||||||
stream.puts(' <testsuite name="%<name>s" tests="%<total>d" failures="%<failed>d" skipped="%<ignored>d" time="%<time>f">' % suite)
|
stream.puts(' <testsuite name="%<name>s" tests="%<total>d" failures="%<failed>d" skipped="%<ignored>d" errors="%<errors>d" time="%<time>.3f">' % suite)
|
||||||
|
|
||||||
suite[:collection].each do |test|
|
suite[:collection].each do |test|
|
||||||
write_test( test, stream )
|
write_test( test, stream )
|
||||||
@ -108,12 +108,17 @@ class JunitTestsReport < Plugin
|
|||||||
end
|
end
|
||||||
|
|
||||||
def write_test( test, stream )
|
def write_test( test, stream )
|
||||||
test[:test].gsub!('"', '"')
|
test[:test].gsub!(/&/, '&')
|
||||||
|
test[:test].gsub!(/</, '<')
|
||||||
|
test[:test].gsub!(/>/, '>')
|
||||||
|
test[:test].gsub!(/"/, '"')
|
||||||
|
test[:test].gsub!(/'/, ''')
|
||||||
|
|
||||||
case test[:result]
|
case test[:result]
|
||||||
when :success
|
when :success
|
||||||
stream.puts(' <testcase name="%<test>s" />' % test)
|
stream.puts(' <testcase name="%<test>s" time="%<unity_test_time>.3f"/>' % test)
|
||||||
when :failed
|
when :failed
|
||||||
stream.puts(' <testcase name="%<test>s">' % test)
|
stream.puts(' <testcase name="%<test>s" time="%<unity_test_time>.3f">' % test)
|
||||||
if test[:message].empty?
|
if test[:message].empty?
|
||||||
stream.puts(' <failure />')
|
stream.puts(' <failure />')
|
||||||
else
|
else
|
||||||
@ -121,7 +126,7 @@ class JunitTestsReport < Plugin
|
|||||||
end
|
end
|
||||||
stream.puts(' </testcase>')
|
stream.puts(' </testcase>')
|
||||||
when :ignored
|
when :ignored
|
||||||
stream.puts(' <testcase name="%<test>s">' % test)
|
stream.puts(' <testcase name="%<test>s" time="%<unity_test_time>.3f">' % test)
|
||||||
stream.puts(' <skipped />')
|
stream.puts(' <skipped />')
|
||||||
stream.puts(' </testcase>')
|
stream.puts(' </testcase>')
|
||||||
end
|
end
|
||||||
|
@ -18,6 +18,14 @@ class ModuleGenerator < Plugin
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def stub_from_header(module_name, optz={})
|
||||||
|
require "cmock.rb" #From CMock
|
||||||
|
stuboptz = divine_options(optz)
|
||||||
|
pathname = optz[:path_inc] || optz[:path_src] || "src"
|
||||||
|
filename = File.expand_path(optz[:module_root_path], File.join(pathname, module_name + ".h"))
|
||||||
|
CMock.new(stuboptz).setup_skeletons(filename)
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def divine_options(optz={})
|
def divine_options(optz={})
|
||||||
@ -37,6 +45,8 @@ class ModuleGenerator < Plugin
|
|||||||
:boilerplates => ((defined? MODULE_GENERATOR_BOILERPLATES) ? MODULE_GENERATOR_BOILERPLATES : {} ),
|
:boilerplates => ((defined? MODULE_GENERATOR_BOILERPLATES) ? MODULE_GENERATOR_BOILERPLATES : {} ),
|
||||||
:naming => ((defined? MODULE_GENERATOR_NAMING ) ? MODULE_GENERATOR_NAMING : nil ),
|
:naming => ((defined? MODULE_GENERATOR_NAMING ) ? MODULE_GENERATOR_NAMING : nil ),
|
||||||
:update_svn => ((defined? MODULE_GENERATOR_UPDATE_SVN ) ? MODULE_GENERATOR_UPDATE_SVN : false ),
|
:update_svn => ((defined? MODULE_GENERATOR_UPDATE_SVN ) ? MODULE_GENERATOR_UPDATE_SVN : false ),
|
||||||
|
:skeleton_path=> ((defined? MODULE_GENERATOR_SOURCE_ROOT ) ? MODULE_GENERATOR_SOURCE_ROOT.gsub('\\', '/').sub(/^\//, '').sub(/\/$/, '') : "src" ),
|
||||||
|
:test_define => ((defined? MODULE_GENERATOR_TEST_DEFINE ) ? MODULE_GENERATOR_TEST_DEFINE : "TEST" ),
|
||||||
}
|
}
|
||||||
|
|
||||||
# Read Boilerplate template file.
|
# Read Boilerplate template file.
|
||||||
@ -44,15 +54,15 @@ class ModuleGenerator < Plugin
|
|||||||
|
|
||||||
bf = MODULE_GENERATOR_BOILERPLATE_FILES
|
bf = MODULE_GENERATOR_BOILERPLATE_FILES
|
||||||
|
|
||||||
if !bf[:src].nil? && File.exists?(bf[:src])
|
if !bf[:src].nil? && File.exists?(bf[:src])
|
||||||
unity_generator_options[:boilerplates][:src] = File.read(bf[:src])
|
unity_generator_options[:boilerplates][:src] = File.read(bf[:src])
|
||||||
end
|
end
|
||||||
|
|
||||||
if !bf[:inc].nil? && File.exists?(bf[:inc])
|
if !bf[:inc].nil? && File.exists?(bf[:inc])
|
||||||
unity_generator_options[:boilerplates][:inc] = File.read(bf[:inc])
|
unity_generator_options[:boilerplates][:inc] = File.read(bf[:inc])
|
||||||
end
|
end
|
||||||
|
|
||||||
if !bf[:tst].nil? && File.exists?(bf[:tst])
|
if !bf[:tst].nil? && File.exists?(bf[:tst])
|
||||||
unity_generator_options[:boilerplates][:tst] = File.read(bf[:tst])
|
unity_generator_options[:boilerplates][:tst] = File.read(bf[:tst])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -26,6 +26,21 @@ namespace :module do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
desc "Generate module stubs from header"
|
||||||
|
task :stub, :module_path do |t, args|
|
||||||
|
files = [args[:module_path]] + (args.extras || [])
|
||||||
|
optz = { :module_root_path => "" }
|
||||||
|
files.each do |v|
|
||||||
|
module_root_path, module_name = v.split(module_root_separator, 2)
|
||||||
|
if module_name
|
||||||
|
optz[:module_root_path] = module_root_path
|
||||||
|
v = module_name
|
||||||
|
end
|
||||||
|
# Otherwise, go through the normal procedure
|
||||||
|
@ceedling[:module_generator].stub_from_header(v, optz)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
desc "Destroy module (source, header and test files)"
|
desc "Destroy module (source, header and test files)"
|
||||||
task :destroy, :module_path do |t, args|
|
task :destroy, :module_path do |t, args|
|
||||||
files = [args[:module_path]] + (args.extras || [])
|
files = [args[:module_path]] + (args.extras || [])
|
||||||
|
@ -20,7 +20,7 @@ class Subprojects < Plugin
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
#gather information about the subprojects
|
# Gather information about the subprojects
|
||||||
@subprojects = {}
|
@subprojects = {}
|
||||||
@subproject_lookup_by_path = {}
|
@subproject_lookup_by_path = {}
|
||||||
SUBPROJECTS_PATHS.each do |subproj|
|
SUBPROJECTS_PATHS.each do |subproj|
|
||||||
@ -84,7 +84,7 @@ class Subprojects < Plugin
|
|||||||
Object.send(:remove_const, constant.to_sym) if (Object.const_defined? constant)
|
Object.send(:remove_const, constant.to_sym) if (Object.const_defined? constant)
|
||||||
Object.const_set(constant, new_value)
|
Object.const_set(constant, new_value)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# end blocks always executed following rake run
|
# end blocks always executed following rake run
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
xml_tests_report
|
xml_tests_report
|
||||||
====================
|
================
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ extern "C"
|
|||||||
|
|
||||||
#define CEXCEPTION_VERSION_MAJOR 1
|
#define CEXCEPTION_VERSION_MAJOR 1
|
||||||
#define CEXCEPTION_VERSION_MINOR 3
|
#define CEXCEPTION_VERSION_MINOR 3
|
||||||
#define CEXCEPTION_VERSION_BUILD 2
|
#define CEXCEPTION_VERSION_BUILD 3
|
||||||
#define CEXCEPTION_VERSION ((CEXCEPTION_VERSION_MAJOR << 16) | (CEXCEPTION_VERSION_MINOR << 8) | CEXCEPTION_VERSION_BUILD)
|
#define CEXCEPTION_VERSION ((CEXCEPTION_VERSION_MAJOR << 16) | (CEXCEPTION_VERSION_MINOR << 8) | CEXCEPTION_VERSION_BUILD)
|
||||||
|
|
||||||
//To Use CException, you have a number of options:
|
//To Use CException, you have a number of options:
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
18
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
|||||||
1.3.1
|
|
||||||
|
|
@ -2,13 +2,11 @@
|
|||||||
# CMock Project - Automatic Mock Generation for C
|
# CMock Project - Automatic Mock Generation for C
|
||||||
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
|
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
|
||||||
# [Released under MIT License. Please refer to license.txt for details]
|
# [Released under MIT License. Please refer to license.txt for details]
|
||||||
# ==========================================
|
# ==========================================
|
||||||
|
|
||||||
# Setup our load path:
|
# Setup our load path:
|
||||||
[
|
[
|
||||||
'lib',
|
'lib'
|
||||||
].each do |dir|
|
].each do |dir|
|
||||||
$LOAD_PATH.unshift( File.join( File.expand_path(File.dirname(__FILE__)) + '/../', dir) )
|
$:.unshift(File.join(__dir__ + '/../', dir))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -12,5 +12,5 @@
|
|||||||
'./vendor/unity/auto/',
|
'./vendor/unity/auto/',
|
||||||
'./test/system/'
|
'./test/system/'
|
||||||
].each do |dir|
|
].each do |dir|
|
||||||
$LOAD_PATH.unshift( File.join( File.expand_path(File.dirname(__FILE__) + "/../"), dir) )
|
$:.unshift(File.join(File.expand_path(File.dirname(__FILE__) + '/../'), dir))
|
||||||
end
|
end
|
||||||
|
81
test/vendor/ceedling/vendor/cmock/lib/cmock.rb
vendored
81
test/vendor/ceedling/vendor/cmock/lib/cmock.rb
vendored
@ -4,49 +4,63 @@
|
|||||||
# [Released under MIT License. Please refer to license.txt for details]
|
# [Released under MIT License. Please refer to license.txt for details]
|
||||||
# ==========================================
|
# ==========================================
|
||||||
|
|
||||||
[ "../config/production_environment",
|
['../config/production_environment',
|
||||||
"cmock_header_parser",
|
'cmock_header_parser',
|
||||||
"cmock_generator",
|
'cmock_generator',
|
||||||
"cmock_file_writer",
|
'cmock_file_writer',
|
||||||
"cmock_config",
|
'cmock_config',
|
||||||
"cmock_plugin_manager",
|
'cmock_plugin_manager',
|
||||||
"cmock_generator_utils",
|
'cmock_generator_utils',
|
||||||
"cmock_unityhelper_parser"].each {|req| require "#{File.expand_path(File.dirname(__FILE__))}/#{req}"}
|
'cmock_unityhelper_parser'].each { |req| require "#{__dir__}/#{req}" }
|
||||||
|
|
||||||
class CMock
|
class CMock
|
||||||
|
def initialize(options = nil)
|
||||||
def initialize(options=nil)
|
|
||||||
cm_config = CMockConfig.new(options)
|
cm_config = CMockConfig.new(options)
|
||||||
cm_unityhelper = CMockUnityHelperParser.new(cm_config)
|
cm_unityhelper = CMockUnityHelperParser.new(cm_config)
|
||||||
cm_writer = CMockFileWriter.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_gen_plugins = CMockPluginManager.new(cm_config, cm_gen_utils)
|
||||||
@cm_parser = CMockHeaderParser.new(cm_config)
|
@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)
|
@silent = (cm_config.verbosity < 2)
|
||||||
end
|
end
|
||||||
|
|
||||||
def setup_mocks(files)
|
def setup_mocks(files, folder = nil)
|
||||||
[files].flatten.each do |src|
|
[files].flatten.each do |src|
|
||||||
generate_mock src
|
generate_mock(src, folder)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def setup_skeletons(files)
|
||||||
|
[files].flatten.each do |src|
|
||||||
|
generate_skeleton src
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private ###############################
|
private ###############################
|
||||||
|
|
||||||
def generate_mock(src)
|
def generate_mock(src, folder)
|
||||||
name = File.basename(src, '.h')
|
name = File.basename(src, '.*')
|
||||||
|
ext = File.extname(src)
|
||||||
puts "Creating mock for #{name}..." unless @silent
|
puts "Creating mock for #{name}..." unless @silent
|
||||||
@cm_generator.create_mock(name, @cm_parser.parse(name, File.read(src)))
|
@cm_generator.create_mock(name, @cm_parser.parse(name, File.read(src)), ext, folder)
|
||||||
|
end
|
||||||
|
|
||||||
|
def generate_skeleton(src)
|
||||||
|
name = File.basename(src, '.*')
|
||||||
|
puts "Creating skeleton for #{name}..." unless @silent
|
||||||
|
@cm_generator.create_skeleton(name, @cm_parser.parse(name, File.read(src)))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def option_maker(options, key, val)
|
def option_maker(options, key, val)
|
||||||
options = options || {}
|
options ||= {}
|
||||||
options[key.to_sym] =
|
options[key.to_sym] =
|
||||||
if val.chr == ":"
|
if val.chr == ':'
|
||||||
val[1..-1].to_sym
|
val[1..-1].to_sym
|
||||||
elsif val.include? ";"
|
elsif val.include? ';'
|
||||||
val.split(';')
|
val.split(';')
|
||||||
elsif val == 'true'
|
elsif val == 'true'
|
||||||
true
|
true
|
||||||
@ -60,12 +74,12 @@ def option_maker(options, key, val)
|
|||||||
options
|
options
|
||||||
end
|
end
|
||||||
|
|
||||||
# Command Line Support ###############################
|
# Command Line Support ###############################
|
||||||
|
|
||||||
if ($0 == __FILE__)
|
if $0 == __FILE__
|
||||||
usage = "usage: ruby #{__FILE__} (-oOptionsFile) File(s)ToMock"
|
usage = "usage: ruby #{__FILE__} (-oOptionsFile) File(s)ToMock"
|
||||||
|
|
||||||
if (!ARGV[0])
|
unless ARGV[0]
|
||||||
puts usage
|
puts usage
|
||||||
exit 1
|
exit 1
|
||||||
end
|
end
|
||||||
@ -73,14 +87,25 @@ if ($0 == __FILE__)
|
|||||||
options = {}
|
options = {}
|
||||||
filelist = []
|
filelist = []
|
||||||
ARGV.each do |arg|
|
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/,'') )
|
options.merge! CMockConfig.load_config_file_from_yaml(arg.gsub(/^-o/, ''))
|
||||||
elsif (arg =~ /^--([a-zA-Z0-9._\\\/:\s]+)=\"?([a-zA-Z0-9._\-\\\/:\s\;]+)\"?/)
|
elsif arg == '--skeleton'
|
||||||
options = option_maker(options, $1, $2)
|
options[:skeleton] = true
|
||||||
|
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
|
else
|
||||||
filelist << arg
|
filelist << arg
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
CMock.new(options).setup_mocks(filelist)
|
if options[:skeleton]
|
||||||
|
CMock.new(options).setup_skeletons(filelist)
|
||||||
|
else
|
||||||
|
CMock.new(options).setup_mocks(filelist)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -5,99 +5,120 @@
|
|||||||
# ==========================================
|
# ==========================================
|
||||||
|
|
||||||
class CMockConfig
|
class CMockConfig
|
||||||
|
CMOCK_DEFAULT_OPTIONS =
|
||||||
|
{
|
||||||
|
:framework => :unity,
|
||||||
|
:mock_path => 'mocks',
|
||||||
|
:mock_prefix => 'Mock',
|
||||||
|
:mock_suffix => '',
|
||||||
|
:skeleton_path => '',
|
||||||
|
:weak => '',
|
||||||
|
:subdir => nil,
|
||||||
|
:plugins => [],
|
||||||
|
:strippables => ['(?:__attribute__\s*\(+.*?\)+)'],
|
||||||
|
:attributes => %w[__ramfunc __irq __fiq register extern],
|
||||||
|
:c_calling_conventions => %w[__stdcall __cdecl __fastcall],
|
||||||
|
:enforce_strict_ordering => false,
|
||||||
|
:fail_on_unexpected_calls => true,
|
||||||
|
:unity_helper_path => false,
|
||||||
|
:treat_as => {},
|
||||||
|
:treat_as_array => {},
|
||||||
|
:treat_as_void => [],
|
||||||
|
:memcmp_if_unknown => true,
|
||||||
|
:when_no_prototypes => :warn, # the options being :ignore, :warn, or :error
|
||||||
|
:when_ptr => :compare_data, # the options being :compare_ptr, :compare_data, or :smart
|
||||||
|
:verbosity => 2, # the options being 0 errors only, 1 warnings and errors, 2 normal info, 3 verbose
|
||||||
|
:treat_externs => :exclude, # the options being :include or :exclude
|
||||||
|
:treat_inlines => :exclude, # the options being :include or :exclude
|
||||||
|
:callback_include_count => true,
|
||||||
|
:callback_after_arg_check => false,
|
||||||
|
:includes => nil,
|
||||||
|
:includes_h_pre_orig_header => nil,
|
||||||
|
:includes_h_post_orig_header => nil,
|
||||||
|
:includes_c_pre_header => nil,
|
||||||
|
:includes_c_post_header => nil,
|
||||||
|
:orig_header_include_fmt => '#include "%s"',
|
||||||
|
:array_size_type => [],
|
||||||
|
:array_size_name => 'size|len',
|
||||||
|
:skeleton => false,
|
||||||
|
:exclude_setjmp_h => false,
|
||||||
|
|
||||||
CMockDefaultOptions =
|
# Format to look for inline functions.
|
||||||
{
|
# This is a combination of "static" and "inline" keywords ("static inline", "inline static", "inline", "static")
|
||||||
:framework => :unity,
|
# There are several possibilities:
|
||||||
:mock_path => 'mocks',
|
# - sometimes they appear together, sometimes individually,
|
||||||
:mock_prefix => 'Mock',
|
# - The keywords can appear before or after the return type (this is a compiler warning but people do weird stuff),
|
||||||
:mock_suffix => '',
|
# so we check for word boundaries when searching for them
|
||||||
:weak => '',
|
# - We first remove "static inline" combinations and boil down to single inline or static statements
|
||||||
:subdir => nil,
|
:inline_function_patterns => ['(static\s+inline|inline\s+static)\s*', '(\bstatic\b|\binline\b)\s*'] # Last part (\s*) is just to remove whitespaces (only to prettify the output)
|
||||||
:plugins => [],
|
}.freeze
|
||||||
:strippables => ['(?:__attribute__\s*\(+.*?\)+)'],
|
|
||||||
:attributes => ['__ramfunc', '__irq', '__fiq', 'register', 'extern'],
|
|
||||||
:c_calling_conventions => ['__stdcall', '__cdecl', '__fastcall'],
|
|
||||||
:enforce_strict_ordering => false,
|
|
||||||
:fail_on_unexpected_calls => true,
|
|
||||||
:unity_helper_path => false,
|
|
||||||
:treat_as => {},
|
|
||||||
:treat_as_array => {},
|
|
||||||
:treat_as_void => [],
|
|
||||||
:memcmp_if_unknown => true,
|
|
||||||
:when_no_prototypes => :warn, #the options being :ignore, :warn, or :error
|
|
||||||
:when_ptr => :compare_data, #the options being :compare_ptr, :compare_data, or :smart
|
|
||||||
:verbosity => 2, #the options being 0 errors only, 1 warnings and errors, 2 normal info, 3 verbose
|
|
||||||
:treat_externs => :exclude, #the options being :include or :exclude
|
|
||||||
:callback_include_count => true,
|
|
||||||
:callback_after_arg_check => false,
|
|
||||||
:includes => nil,
|
|
||||||
:includes_h_pre_orig_header => nil,
|
|
||||||
:includes_h_post_orig_header => nil,
|
|
||||||
:includes_c_pre_header => nil,
|
|
||||||
:includes_c_post_header => nil,
|
|
||||||
:orig_header_include_fmt => "#include \"%s\"",
|
|
||||||
:array_size_type => [],
|
|
||||||
:array_size_name => 'size|len',
|
|
||||||
}
|
|
||||||
|
|
||||||
def initialize(options=nil)
|
def initialize(options = nil)
|
||||||
case(options)
|
case options
|
||||||
when NilClass then options = CMockDefaultOptions.clone
|
when NilClass then options = CMOCK_DEFAULT_OPTIONS.dup
|
||||||
when String then options = CMockDefaultOptions.clone.merge(load_config_file_from_yaml(options))
|
when String then options = CMOCK_DEFAULT_OPTIONS.dup.merge(load_config_file_from_yaml(options))
|
||||||
when Hash then options = CMockDefaultOptions.clone.merge(options)
|
when Hash then options = CMOCK_DEFAULT_OPTIONS.dup.merge(options)
|
||||||
else raise "If you specify arguments, it should be a filename or a hash of options"
|
else raise 'If you specify arguments, it should be a filename or a hash of options'
|
||||||
end
|
end
|
||||||
|
|
||||||
#do some quick type verification
|
# do some quick type verification
|
||||||
[:plugins, :attributes, :treat_as_void].each do |opt|
|
%i[plugins attributes treat_as_void].each do |opt|
|
||||||
unless (options[opt].class == Array)
|
unless options[opt].class == Array
|
||||||
options[opt] = []
|
options[opt] = []
|
||||||
puts "WARNING: :#{opt.to_s} should be an array." unless (options[:verbosity] < 1)
|
puts "WARNING: :#{opt} should be an array." unless options[:verbosity] < 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
[:includes, :includes_h_pre_orig_header, :includes_h_post_orig_header, :includes_c_pre_header, :includes_c_post_header].each do |opt|
|
%i[includes includes_h_pre_orig_header includes_h_post_orig_header includes_c_pre_header includes_c_post_header].each do |opt|
|
||||||
unless (options[opt].nil? or (options[opt].class == Array))
|
unless options[opt].nil? || (options[opt].class == Array)
|
||||||
options[opt] = []
|
options[opt] = []
|
||||||
puts "WARNING: :#{opt.to_s} should be an array." unless (options[:verbosity] < 1)
|
puts "WARNING: :#{opt} should be an array." unless options[:verbosity] < 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
options[:unity_helper_path] ||= options[:unity_helper]
|
options[:unity_helper_path] ||= options[:unity_helper]
|
||||||
options[:unity_helper_path] = [options[:unity_helper_path]] if options[:unity_helper_path].is_a? String
|
options[:unity_helper_path] = [options[:unity_helper_path]] if options[:unity_helper_path].is_a? String
|
||||||
options[:includes_c_post_header] = ((options[:includes_c_post_header] || []) + (options[:unity_helper_path] || [])).uniq
|
|
||||||
|
if options[:unity_helper_path]
|
||||||
|
require 'pathname'
|
||||||
|
includes1 = options[:includes_c_post_header] || []
|
||||||
|
includes2 = options[:unity_helper_path].map do |path|
|
||||||
|
Pathname(path).relative_path_from(Pathname(options[:mock_path])).to_s
|
||||||
|
end
|
||||||
|
options[:includes_c_post_header] = (includes1 + includes2).uniq
|
||||||
|
end
|
||||||
|
|
||||||
options[:plugins].compact!
|
options[:plugins].compact!
|
||||||
options[:plugins].map! {|p| p.to_sym}
|
options[:plugins].map!(&:to_sym)
|
||||||
@options = options
|
@options = options
|
||||||
|
|
||||||
treat_as_map = standard_treat_as_map()#.clone
|
treat_as_map = standard_treat_as_map # .clone
|
||||||
treat_as_map.merge!(@options[:treat_as])
|
treat_as_map.merge!(@options[:treat_as])
|
||||||
@options[:treat_as] = treat_as_map
|
@options[:treat_as] = treat_as_map
|
||||||
|
|
||||||
@options.each_key do |key|
|
@options.each_key do |key|
|
||||||
unless methods.include?(key)
|
unless methods.include?(key)
|
||||||
eval("def #{key.to_s}() return @options[:#{key.to_s}] end")
|
eval("def #{key}() return @options[:#{key}] end")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def load_config_file_from_yaml yaml_filename
|
def load_config_file_from_yaml(yaml_filename)
|
||||||
self.class.load_config_file_from_yaml yaml_filename
|
self.class.load_config_file_from_yaml yaml_filename
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.load_config_file_from_yaml yaml_filename
|
def self.load_config_file_from_yaml(yaml_filename)
|
||||||
require 'yaml'
|
require 'yaml'
|
||||||
require 'fileutils'
|
require 'fileutils'
|
||||||
YAML.load_file(yaml_filename)[:cmock]
|
YAML.load_file(yaml_filename)[:cmock]
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_path(path)
|
def path(new_path)
|
||||||
@src_path = path
|
@src_path = new_path
|
||||||
end
|
end
|
||||||
|
|
||||||
def load_unity_helper
|
def load_unity_helper
|
||||||
return nil unless (@options[:unity_helper_path])
|
return nil unless @options[:unity_helper_path]
|
||||||
|
|
||||||
return @options[:unity_helper_path].inject("") do |unity_helper, filename|
|
@options[:unity_helper_path].inject('') do |unity_helper, filename|
|
||||||
unity_helper + "\n" + File.new(filename).read
|
unity_helper + "\n" + File.new(filename).read
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
# ==========================================
|
# ==========================================
|
||||||
|
|
||||||
class CMockFileWriter
|
class CMockFileWriter
|
||||||
|
|
||||||
attr_reader :config
|
attr_reader :config
|
||||||
|
|
||||||
def initialize(config)
|
def initialize(config)
|
||||||
@ -13,32 +12,36 @@ class CMockFileWriter
|
|||||||
end
|
end
|
||||||
|
|
||||||
def create_subdir(subdir)
|
def create_subdir(subdir)
|
||||||
if !Dir.exists?("#{@config.mock_path}/")
|
require 'fileutils'
|
||||||
require 'fileutils'
|
FileUtils.mkdir_p "#{@config.mock_path}/" unless Dir.exist?("#{@config.mock_path}/")
|
||||||
FileUtils.mkdir_p "#{@config.mock_path}/"
|
FileUtils.mkdir_p "#{@config.mock_path}/#{subdir + '/' if subdir}" if subdir && !Dir.exist?("#{@config.mock_path}/#{subdir + '/' if subdir}")
|
||||||
end
|
|
||||||
if subdir && !Dir.exists?("#{@config.mock_path}/#{subdir+'/' if subdir}")
|
|
||||||
require 'fileutils'
|
|
||||||
FileUtils.mkdir_p "#{@config.mock_path}/#{subdir+'/' if subdir}"
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_file(filename, subdir)
|
def create_file(filename, subdir)
|
||||||
raise "Where's the block of data to create?" unless block_given?
|
raise "Where's the block of data to create?" unless block_given?
|
||||||
full_file_name_temp = "#{@config.mock_path}/#{subdir+'/' if subdir}#{filename}.new"
|
|
||||||
full_file_name_done = "#{@config.mock_path}/#{subdir+'/' if subdir}#{filename}"
|
full_file_name_temp = "#{@config.mock_path}/#{subdir + '/' if subdir}#{filename}.new"
|
||||||
|
full_file_name_done = "#{@config.mock_path}/#{subdir + '/' if subdir}#{filename}"
|
||||||
File.open(full_file_name_temp, 'w') do |file|
|
File.open(full_file_name_temp, 'w') do |file|
|
||||||
yield(file, filename)
|
yield(file, filename)
|
||||||
end
|
end
|
||||||
update_file(full_file_name_done, full_file_name_temp)
|
update_file(full_file_name_done, full_file_name_temp)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def append_file(filename, subdir)
|
||||||
|
raise "Where's the block of data to create?" unless block_given?
|
||||||
|
|
||||||
|
full_file_name = "#{@config.skeleton_path}/#{subdir + '/' if subdir}#{filename}"
|
||||||
|
File.open(full_file_name, 'a') do |file|
|
||||||
|
yield(file, filename)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private ###################################
|
private ###################################
|
||||||
|
|
||||||
def update_file(dest, src)
|
def update_file(dest, src)
|
||||||
require 'fileutils'
|
require 'fileutils'
|
||||||
FileUtils.rm(dest) if (File.exist?(dest))
|
FileUtils.rm(dest, :force => true)
|
||||||
FileUtils.cp(src, dest)
|
FileUtils.mv(src, dest)
|
||||||
FileUtils.rm(src)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -5,8 +5,7 @@
|
|||||||
# ==========================================
|
# ==========================================
|
||||||
|
|
||||||
class CMockGenerator
|
class CMockGenerator
|
||||||
|
attr_accessor :config, :file_writer, :module_name, :module_ext, :clean_mock_name, :mock_name, :utils, :plugins, :weak, :ordered
|
||||||
attr_accessor :config, :file_writer, :module_name, :clean_mock_name, :mock_name, :utils, :plugins, :weak, :ordered
|
|
||||||
|
|
||||||
def initialize(config, file_writer, utils, plugins)
|
def initialize(config, file_writer, utils, plugins)
|
||||||
@file_writer = file_writer
|
@file_writer = file_writer
|
||||||
@ -16,89 +15,147 @@ class CMockGenerator
|
|||||||
@prefix = @config.mock_prefix
|
@prefix = @config.mock_prefix
|
||||||
@suffix = @config.mock_suffix
|
@suffix = @config.mock_suffix
|
||||||
@weak = @config.weak
|
@weak = @config.weak
|
||||||
@ordered = @config.enforce_strict_ordering
|
@include_inline = @config.treat_inlines
|
||||||
@framework = @config.framework.to_s
|
@ordered = @config.enforce_strict_ordering
|
||||||
|
@framework = @config.framework.to_s
|
||||||
@fail_on_unexpected_calls = @config.fail_on_unexpected_calls
|
@fail_on_unexpected_calls = @config.fail_on_unexpected_calls
|
||||||
|
@exclude_setjmp_h = @config.exclude_setjmp_h
|
||||||
|
@subdir = @config.subdir
|
||||||
|
|
||||||
@subdir = @config.subdir
|
@includes_h_pre_orig_header = (@config.includes || @config.includes_h_pre_orig_header || []).map { |h| h =~ /</ ? h : "\"#{h}\"" }
|
||||||
|
@includes_h_post_orig_header = (@config.includes_h_post_orig_header || []).map { |h| h =~ /</ ? h : "\"#{h}\"" }
|
||||||
@includes_h_pre_orig_header = (@config.includes || @config.includes_h_pre_orig_header || []).map{|h| h =~ /</ ? h : "\"#{h}\""}
|
@includes_c_pre_header = (@config.includes_c_pre_header || []).map { |h| h =~ /</ ? h : "\"#{h}\"" }
|
||||||
@includes_h_post_orig_header = (@config.includes_h_post_orig_header || []).map{|h| h =~ /</ ? h : "\"#{h}\""}
|
@includes_c_post_header = (@config.includes_c_post_header || []).map { |h| h =~ /</ ? h : "\"#{h}\"" }
|
||||||
@includes_c_pre_header = (@config.includes_c_pre_header || []).map{|h| h =~ /</ ? h : "\"#{h}\""}
|
|
||||||
@includes_c_post_header = (@config.includes_c_post_header || []).map{|h| h =~ /</ ? h : "\"#{h}\""}
|
|
||||||
|
|
||||||
here = File.dirname __FILE__
|
here = File.dirname __FILE__
|
||||||
unity_path_in_ceedling = "#{here}/../../unity" # path to Unity from within Ceedling
|
unity_path_in_ceedling = "#{here}/../../unity" # path to Unity from within Ceedling
|
||||||
unity_path_in_cmock = "#{here}/../vendor/unity" # path to Unity from within CMock
|
unity_path_in_cmock = "#{here}/../vendor/unity" # path to Unity from within CMock
|
||||||
# path to Unity as specified by env var
|
# path to Unity as specified by env var
|
||||||
unity_path_in_env = ENV.has_key?("UNITY_DIR") ? File.expand_path(ENV.fetch("UNITY_DIR")) : nil
|
unity_path_in_env = ENV.key?('UNITY_DIR') ? File.expand_path(ENV.fetch('UNITY_DIR')) : nil
|
||||||
|
|
||||||
if unity_path_in_env and File.exist? unity_path_in_env
|
if unity_path_in_env && File.exist?(unity_path_in_env)
|
||||||
require "#{unity_path_in_env}/auto/type_sanitizer"
|
require "#{unity_path_in_env}/auto/type_sanitizer"
|
||||||
elsif File.exist? unity_path_in_ceedling
|
elsif File.exist? unity_path_in_ceedling
|
||||||
require "#{unity_path_in_ceedling}/auto/type_sanitizer"
|
require "#{unity_path_in_ceedling}/auto/type_sanitizer"
|
||||||
elsif File.exist? unity_path_in_cmock
|
elsif File.exist? unity_path_in_cmock
|
||||||
require "#{unity_path_in_cmock}/auto/type_sanitizer"
|
require "#{unity_path_in_cmock}/auto/type_sanitizer"
|
||||||
else
|
else
|
||||||
raise "Failed to find an instance of Unity to pull in type_sanitizer module!"
|
raise 'Failed to find an instance of Unity to pull in type_sanitizer module!'
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_mock(module_name, parsed_stuff)
|
def create_mock(module_name, parsed_stuff, module_ext = nil, folder = nil)
|
||||||
@module_name = module_name
|
# determine the name for our new mock
|
||||||
@mock_name = @prefix + @module_name + @suffix
|
mock_name = @prefix + module_name + @suffix
|
||||||
@clean_mock_name = TypeSanitizer.sanitize_c_identifier(@mock_name)
|
|
||||||
create_mock_subdir()
|
# determine the folder our mock will reside
|
||||||
create_mock_header_file(parsed_stuff)
|
mock_folder = if folder && @subdir
|
||||||
create_mock_source_file(parsed_stuff)
|
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)
|
||||||
|
mock_project = {
|
||||||
|
:module_name => module_name,
|
||||||
|
:module_ext => '.h',
|
||||||
|
:parsed_stuff => parsed_stuff,
|
||||||
|
:skeleton => true
|
||||||
|
}
|
||||||
|
|
||||||
|
create_skeleton_source_file(mock_project)
|
||||||
end
|
end
|
||||||
|
|
||||||
private if $ThisIsOnlyATest.nil? ##############################
|
private if $ThisIsOnlyATest.nil? ##############################
|
||||||
|
|
||||||
def create_mock_subdir()
|
def create_mock_subdir(mock_project)
|
||||||
@file_writer.create_subdir(@subdir)
|
@file_writer.create_subdir(mock_project[:folder])
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_mock_header_file(parsed_stuff)
|
def create_using_statement(file, function)
|
||||||
@file_writer.create_file(@mock_name + ".h", @subdir) do |file, filename|
|
file << "using namespace #{function[:namespace].join('::')};\n" unless function[:namespace].empty?
|
||||||
create_mock_header_header(file, filename)
|
end
|
||||||
create_mock_header_service_call_declarations(file)
|
|
||||||
create_typedefs(file, parsed_stuff[:typedefs])
|
def create_mock_header_file(mock_project)
|
||||||
parsed_stuff[:functions].each do |function|
|
if @include_inline == :include
|
||||||
|
@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_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)
|
file << @plugins.run(:mock_function_declarations, function)
|
||||||
end
|
end
|
||||||
create_mock_header_footer(file)
|
create_mock_header_footer(file)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_mock_source_file(parsed_stuff)
|
def create_mock_source_file(mock_project)
|
||||||
@file_writer.create_file(@mock_name + ".c", @subdir) do |file, filename|
|
@file_writer.create_file(mock_project[:mock_name] + '.c', mock_project[:folder]) do |file, filename|
|
||||||
create_source_header_section(file, filename, parsed_stuff[:functions])
|
create_source_header_section(file, filename, mock_project)
|
||||||
create_instance_structure(file, parsed_stuff[:functions])
|
create_instance_structure(file, mock_project)
|
||||||
create_extern_declarations(file)
|
create_extern_declarations(file)
|
||||||
create_mock_verify_function(file, parsed_stuff[:functions])
|
create_mock_verify_function(file, mock_project)
|
||||||
create_mock_init_function(file)
|
create_mock_init_function(file, mock_project)
|
||||||
create_mock_destroy_function(file, parsed_stuff[:functions])
|
create_mock_destroy_function(file, mock_project)
|
||||||
parsed_stuff[:functions].each do |function|
|
mock_project[:parsed_stuff][:functions].each do |function|
|
||||||
create_mock_implementation(file, function)
|
create_mock_implementation(file, function)
|
||||||
create_mock_interfaces(file, function)
|
create_mock_interfaces(file, function)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_mock_header_header(file, filename)
|
def create_skeleton_source_file(mock_project)
|
||||||
define_name = @clean_mock_name.upcase
|
filename = "#{@config.mock_path}/#{@subdir + '/' if @subdir}#{mock_project[:module_name]}.c"
|
||||||
orig_filename = (@subdir ? @subdir + "/" : "") + @module_name + ".h"
|
existing = File.exist?(filename) ? File.read(filename) : ''
|
||||||
|
@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, 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 << "/* AUTOGENERATED FILE. DO NOT EDIT. */\n"
|
||||||
file << "#ifndef _#{define_name}_H\n"
|
file << "#ifndef _#{define_name}_H\n"
|
||||||
file << "#define _#{define_name}_H\n\n"
|
file << "#define _#{define_name}_H\n\n"
|
||||||
file << "#include \"#{@framework}.h\"\n"
|
file << "#include \"#{@framework}.h\"\n"
|
||||||
@includes_h_pre_orig_header.each {|inc| file << "#include #{inc}\n"}
|
@includes_h_pre_orig_header.each { |inc| file << "#include #{inc}\n" }
|
||||||
file << @config.orig_header_include_fmt.gsub(/%s/, "#{orig_filename}") + "\n"
|
file << @config.orig_header_include_fmt.gsub(/%s/, orig_filename.to_s) + "\n"
|
||||||
@includes_h_post_orig_header.each {|inc| file << "#include #{inc}\n"}
|
@includes_h_post_orig_header.each { |inc| file << "#include #{inc}\n" }
|
||||||
plugin_includes = @plugins.run(:include_files)
|
plugin_includes = @plugins.run(:include_files)
|
||||||
file << plugin_includes if (!plugin_includes.empty?)
|
file << plugin_includes unless plugin_includes.empty?
|
||||||
file << "\n"
|
file << "\n"
|
||||||
file << "/* Ignore the following warnings, since we are copying code */\n"
|
file << "/* Ignore the following warnings, since we are copying code */\n"
|
||||||
file << "#if defined(__GNUC__) && !defined(__ICC) && !defined(__TMS470__)\n"
|
file << "#if defined(__GNUC__) && !defined(__ICC) && !defined(__TMS470__)\n"
|
||||||
@ -114,16 +171,16 @@ class CMockGenerator
|
|||||||
file << "\n"
|
file << "\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_typedefs(file, typedefs)
|
def create_typedefs(file, mock_project)
|
||||||
file << "\n"
|
file << "\n"
|
||||||
typedefs.each {|typedef| file << "#{typedef}\n" }
|
mock_project[:parsed_stuff][:typedefs].each { |typedef| file << "#{typedef}\n" }
|
||||||
file << "\n\n"
|
file << "\n\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_mock_header_service_call_declarations(file)
|
def create_mock_header_service_call_declarations(file, mock_project)
|
||||||
file << "void #{@clean_mock_name}_Init(void);\n"
|
file << "void #{mock_project[:clean_name]}_Init(void);\n"
|
||||||
file << "void #{@clean_mock_name}_Destroy(void);\n"
|
file << "void #{mock_project[:clean_name]}_Destroy(void);\n"
|
||||||
file << "void #{@clean_mock_name}_Verify(void);\n\n"
|
file << "void #{mock_project[:clean_name]}_Verify(void);\n\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_mock_header_footer(header)
|
def create_mock_header_footer(header)
|
||||||
@ -137,21 +194,23 @@ class CMockGenerator
|
|||||||
header << "#endif\n"
|
header << "#endif\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_source_header_section(file, filename, functions)
|
def create_source_header_section(file, filename, mock_project)
|
||||||
header_file = (@subdir ? @subdir + '/' : '') + filename.gsub(".c",".h")
|
header_file = (mock_project[:folder] || '') + filename.gsub('.c', mock_project[:module_ext])
|
||||||
file << "/* AUTOGENERATED FILE. DO NOT EDIT. */\n"
|
file << "/* AUTOGENERATED FILE. DO NOT EDIT. */\n" unless mock_project[:parsed_stuff][:functions].empty?
|
||||||
file << "#include <string.h>\n"
|
file << "#include <string.h>\n"
|
||||||
file << "#include <stdlib.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"
|
file << "#include \"cmock.h\"\n"
|
||||||
@includes_c_pre_header.each {|inc| file << "#include #{inc}\n"}
|
@includes_c_pre_header.each { |inc| file << "#include #{inc}\n" }
|
||||||
file << "#include \"#{header_file}\"\n"
|
file << "#include \"#{header_file}\"\n"
|
||||||
@includes_c_post_header.each {|inc| file << "#include #{inc}\n"}
|
@includes_c_post_header.each { |inc| file << "#include #{inc}\n" }
|
||||||
file << "\n"
|
file << "\n"
|
||||||
strs = []
|
strs = []
|
||||||
functions.each do |func|
|
mock_project[:parsed_stuff][:functions].each do |func|
|
||||||
strs << func[:name]
|
strs << func[:name]
|
||||||
func[:args].each {|arg| strs << arg[:name] }
|
func[:args].each { |arg| strs << arg[:name] }
|
||||||
end
|
end
|
||||||
strs.uniq.sort.each do |str|
|
strs.uniq.sort.each do |str|
|
||||||
file << "static const char* CMockString_#{str} = \"#{str}\";\n"
|
file << "static const char* CMockString_#{str} = \"#{str}\";\n"
|
||||||
@ -159,15 +218,16 @@ class CMockGenerator
|
|||||||
file << "\n"
|
file << "\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_instance_structure(file, functions)
|
def create_instance_structure(file, mock_project)
|
||||||
|
functions = mock_project[:parsed_stuff][:functions]
|
||||||
functions.each do |function|
|
functions.each do |function|
|
||||||
file << "typedef struct _CMOCK_#{function[:name]}_CALL_INSTANCE\n{\n"
|
file << "typedef struct _CMOCK_#{function[:name]}_CALL_INSTANCE\n{\n"
|
||||||
file << " UNITY_LINE_TYPE LineNumber;\n"
|
file << " UNITY_LINE_TYPE LineNumber;\n"
|
||||||
file << @plugins.run(:instance_typedefs, function)
|
file << @plugins.run(:instance_typedefs, function)
|
||||||
file << "\n} CMOCK_#{function[:name]}_CALL_INSTANCE;\n\n"
|
file << "\n} CMOCK_#{function[:name]}_CALL_INSTANCE;\n\n"
|
||||||
end
|
end
|
||||||
file << "static struct #{@clean_mock_name}Instance\n{\n"
|
file << "static struct #{mock_project[:clean_name]}Instance\n{\n"
|
||||||
if (functions.size == 0)
|
if functions.empty?
|
||||||
file << " unsigned char placeHolder;\n"
|
file << " unsigned char placeHolder;\n"
|
||||||
end
|
end
|
||||||
functions.each do |function|
|
functions.each do |function|
|
||||||
@ -178,17 +238,19 @@ class CMockGenerator
|
|||||||
end
|
end
|
||||||
|
|
||||||
def create_extern_declarations(file)
|
def create_extern_declarations(file)
|
||||||
file << "extern jmp_buf AbortFrame;\n"
|
unless @exclude_setjmp_h
|
||||||
if (@ordered)
|
file << "extern jmp_buf AbortFrame;\n"
|
||||||
|
end
|
||||||
|
if @ordered
|
||||||
file << "extern int GlobalExpectCount;\n"
|
file << "extern int GlobalExpectCount;\n"
|
||||||
file << "extern int GlobalVerifyOrder;\n"
|
file << "extern int GlobalVerifyOrder;\n"
|
||||||
end
|
end
|
||||||
file << "\n"
|
file << "\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_mock_verify_function(file, functions)
|
def create_mock_verify_function(file, mock_project)
|
||||||
file << "void #{@clean_mock_name}_Verify(void)\n{\n"
|
file << "void #{mock_project[:clean_name]}_Verify(void)\n{\n"
|
||||||
verifications = functions.collect do |function|
|
verifications = mock_project[:parsed_stuff][:functions].collect do |function|
|
||||||
v = @plugins.run(:mock_verify, function)
|
v = @plugins.run(:mock_verify, function)
|
||||||
v.empty? ? v : [" call_instance = Mock.#{function[:name]}_CallInstance;\n", v]
|
v.empty? ? v : [" call_instance = Mock.#{function[:name]}_CallInstance;\n", v]
|
||||||
end.join
|
end.join
|
||||||
@ -200,23 +262,23 @@ class CMockGenerator
|
|||||||
file << "}\n\n"
|
file << "}\n\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_mock_init_function(file)
|
def create_mock_init_function(file, mock_project)
|
||||||
file << "void #{@clean_mock_name}_Init(void)\n{\n"
|
file << "void #{mock_project[:clean_name]}_Init(void)\n{\n"
|
||||||
file << " #{@clean_mock_name}_Destroy();\n"
|
file << " #{mock_project[:clean_name]}_Destroy();\n"
|
||||||
file << "}\n\n"
|
file << "}\n\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_mock_destroy_function(file, functions)
|
def create_mock_destroy_function(file, mock_project)
|
||||||
file << "void #{@clean_mock_name}_Destroy(void)\n{\n"
|
file << "void #{mock_project[:clean_name]}_Destroy(void)\n{\n"
|
||||||
file << " CMock_Guts_MemFreeAll();\n"
|
file << " CMock_Guts_MemFreeAll();\n"
|
||||||
file << " memset(&Mock, 0, sizeof(Mock));\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)
|
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
|
end
|
||||||
|
|
||||||
if (@ordered)
|
if @ordered
|
||||||
file << " GlobalExpectCount = 0;\n"
|
file << " GlobalExpectCount = 0;\n"
|
||||||
file << " GlobalVerifyOrder = 0;\n"
|
file << " GlobalVerifyOrder = 0;\n"
|
||||||
end
|
end
|
||||||
@ -229,17 +291,28 @@ class CMockGenerator
|
|||||||
(function[:return][:type]) +
|
(function[:return][:type]) +
|
||||||
(function[:c_calling_convention] ? " #{function[:c_calling_convention]}" : '')
|
(function[:c_calling_convention] ? " #{function[:c_calling_convention]}" : '')
|
||||||
args_string = function[:args_string]
|
args_string = function[:args_string]
|
||||||
args_string += (", " + function[:var_arg]) unless (function[:var_arg].nil?)
|
args_string += (', ' + function[:var_arg]) unless function[:var_arg].nil?
|
||||||
|
|
||||||
|
# Encapsulate in namespace(s) if applicable
|
||||||
|
function[:namespace].each do |ns|
|
||||||
|
file << "namespace #{ns} {\n"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Determine class prefix (if any)
|
||||||
|
cls_pre = ''
|
||||||
|
unless function[:class].nil?
|
||||||
|
cls_pre = "#{function[:class]}::"
|
||||||
|
end
|
||||||
|
|
||||||
# Create mock function
|
# Create mock function
|
||||||
if (not @weak.empty?)
|
unless @weak.empty?
|
||||||
file << "#if defined (__IAR_SYSTEMS_ICC__)\n"
|
file << "#if defined (__IAR_SYSTEMS_ICC__)\n"
|
||||||
file << "#pragma weak #{function[:name]}\n"
|
file << "#pragma weak #{function[:unscoped_name]}\n"
|
||||||
file << "#else\n"
|
file << "#else\n"
|
||||||
file << "#{function_mod_and_rettype} #{function[:name]}(#{args_string}) #{weak};\n"
|
file << "#{function_mod_and_rettype} #{function[:unscoped_name]}(#{args_string}) #{weak};\n"
|
||||||
file << "#endif\n\n"
|
file << "#endif\n\n"
|
||||||
end
|
end
|
||||||
file << "#{function_mod_and_rettype} #{function[:name]}(#{args_string})\n"
|
file << "#{function_mod_and_rettype} #{cls_pre}#{function[:unscoped_name]}(#{args_string})\n"
|
||||||
file << "{\n"
|
file << "{\n"
|
||||||
file << " UNITY_LINE_TYPE cmock_line = TEST_LINE_NUM;\n"
|
file << " UNITY_LINE_TYPE cmock_line = TEST_LINE_NUM;\n"
|
||||||
file << " CMOCK_#{function[:name]}_CALL_INSTANCE* cmock_call_instance;\n"
|
file << " CMOCK_#{function[:name]}_CALL_INSTANCE* cmock_call_instance;\n"
|
||||||
@ -249,7 +322,7 @@ class CMockGenerator
|
|||||||
file << @plugins.run(:mock_implementation_precheck, function)
|
file << @plugins.run(:mock_implementation_precheck, function)
|
||||||
file << " UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringCalledMore);\n"
|
file << " UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringCalledMore);\n"
|
||||||
file << " cmock_line = cmock_call_instance->LineNumber;\n"
|
file << " cmock_line = cmock_call_instance->LineNumber;\n"
|
||||||
if (@ordered)
|
if @ordered
|
||||||
file << " if (cmock_call_instance->CallOrder > ++GlobalVerifyOrder)\n"
|
file << " if (cmock_call_instance->CallOrder > ++GlobalVerifyOrder)\n"
|
||||||
file << " UNITY_TEST_FAIL(cmock_line, CMockStringCalledEarly);\n"
|
file << " UNITY_TEST_FAIL(cmock_line, CMockStringCalledEarly);\n"
|
||||||
file << " if (cmock_call_instance->CallOrder < GlobalVerifyOrder)\n"
|
file << " if (cmock_call_instance->CallOrder < GlobalVerifyOrder)\n"
|
||||||
@ -257,12 +330,39 @@ class CMockGenerator
|
|||||||
end
|
end
|
||||||
file << @plugins.run(:mock_implementation, function)
|
file << @plugins.run(:mock_implementation, function)
|
||||||
file << " UNITY_CLR_DETAILS();\n"
|
file << " UNITY_CLR_DETAILS();\n"
|
||||||
file << " return cmock_call_instance->ReturnVal;\n" unless (function[:return][:void?])
|
file << " return cmock_call_instance->ReturnVal;\n" unless function[:return][:void?]
|
||||||
file << "}\n\n"
|
file << "}\n"
|
||||||
|
|
||||||
|
# Close any namespace(s) opened above
|
||||||
|
function[:namespace].each do
|
||||||
|
file << "}\n"
|
||||||
|
end
|
||||||
|
|
||||||
|
file << "\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_mock_interfaces(file, function)
|
def create_mock_interfaces(file, function)
|
||||||
file << @utils.code_add_argument_loader(function)
|
file << @utils.code_add_argument_loader(function)
|
||||||
file << @plugins.run(:mock_interfaces, function)
|
file << @plugins.run(:mock_interfaces, function)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def create_function_skeleton(file, function, existing)
|
||||||
|
# prepare return value and arguments
|
||||||
|
function_mod_and_rettype = (function[:modifier].empty? ? '' : "#{function[:modifier]} ") +
|
||||||
|
(function[:return][:type]) +
|
||||||
|
(function[:c_calling_convention] ? " #{function[:c_calling_convention]}" : '')
|
||||||
|
args_string = function[:args_string]
|
||||||
|
args_string += (', ' + function[:var_arg]) unless function[:var_arg].nil?
|
||||||
|
|
||||||
|
decl = "#{function_mod_and_rettype} #{function[:name]}(#{args_string})"
|
||||||
|
|
||||||
|
return if existing.include?(decl)
|
||||||
|
|
||||||
|
file << "#{decl}\n"
|
||||||
|
file << "{\n"
|
||||||
|
file << " /*TODO: Implement Me!*/\n"
|
||||||
|
function[:args].each { |arg| file << " (void)#{arg[:name]};\n" }
|
||||||
|
file << " return (#{(function[:return][:type])})0;\n" unless function[:return][:void?]
|
||||||
|
file << "}\n\n"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
# ==========================================
|
# ==========================================
|
||||||
|
|
||||||
class CMockGeneratorPluginArray
|
class CMockGeneratorPluginArray
|
||||||
|
|
||||||
attr_reader :priority
|
attr_reader :priority
|
||||||
attr_accessor :config, :utils, :unity_helper, :ordered
|
attr_accessor :config, :utils, :unity_helper, :ordered
|
||||||
def initialize(config, utils)
|
def initialize(config, utils)
|
||||||
@ -18,46 +17,47 @@ class CMockGeneratorPluginArray
|
|||||||
end
|
end
|
||||||
|
|
||||||
def instance_typedefs(function)
|
def instance_typedefs(function)
|
||||||
function[:args].inject("") do |all, arg|
|
function[:args].inject('') do |all, arg|
|
||||||
(arg[:ptr?]) ? all + " int Expected_#{arg[:name]}_Depth;\n" : all
|
arg[:ptr?] ? all + " int Expected_#{arg[:name]}_Depth;\n" : all
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def mock_function_declarations(function)
|
def mock_function_declarations(function)
|
||||||
return nil unless function[:contains_ptr?]
|
return nil unless function[:contains_ptr?]
|
||||||
args_call = function[:args].map{|m| m[:ptr?] ? "#{m[:name]}, #{m[:name]}_Depth" : "#{m[:name]}"}.join(', ')
|
|
||||||
|
args_call = function[:args].map { |m| m[:ptr?] ? "#{m[:name]}, #{m[:name]}_Depth" : (m[:name]).to_s }.join(', ')
|
||||||
args_string = function[:args].map do |m|
|
args_string = function[:args].map do |m|
|
||||||
type = @utils.arg_type_with_const(m)
|
type = @utils.arg_type_with_const(m)
|
||||||
m[:ptr?] ? "#{type} #{m[:name]}, int #{m[:name]}_Depth" : "#{type} #{m[:name]}"
|
m[:ptr?] ? "#{type} #{m[:name]}, int #{m[:name]}_Depth" : "#{type} #{m[:name]}"
|
||||||
end.join(', ')
|
end.join(', ')
|
||||||
if (function[:return][:void?])
|
if function[:return][:void?]
|
||||||
return "#define #{function[:name]}_ExpectWithArray(#{args_call}) #{function[:name]}_CMockExpectWithArray(__LINE__, #{args_call})\n" +
|
return "#define #{function[:name]}_ExpectWithArray(#{args_call}) #{function[:name]}_CMockExpectWithArray(__LINE__, #{args_call})\n" \
|
||||||
"void #{function[:name]}_CMockExpectWithArray(UNITY_LINE_TYPE cmock_line, #{args_string});\n"
|
"void #{function[:name]}_CMockExpectWithArray(UNITY_LINE_TYPE cmock_line, #{args_string});\n"
|
||||||
else
|
else
|
||||||
return "#define #{function[:name]}_ExpectWithArrayAndReturn(#{args_call}, cmock_retval) #{function[:name]}_CMockExpectWithArrayAndReturn(__LINE__, #{args_call}, cmock_retval)\n" +
|
return "#define #{function[:name]}_ExpectWithArrayAndReturn(#{args_call}, cmock_retval) #{function[:name]}_CMockExpectWithArrayAndReturn(__LINE__, #{args_call}, cmock_retval)\n" \
|
||||||
"void #{function[:name]}_CMockExpectWithArrayAndReturn(UNITY_LINE_TYPE cmock_line, #{args_string}, #{function[:return][:str]});\n"
|
"void #{function[:name]}_CMockExpectWithArrayAndReturn(UNITY_LINE_TYPE cmock_line, #{args_string}, #{function[:return][:str]});\n"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def mock_interfaces(function)
|
def mock_interfaces(function)
|
||||||
return nil unless function[:contains_ptr?]
|
return nil unless function[:contains_ptr?]
|
||||||
|
|
||||||
lines = []
|
lines = []
|
||||||
func_name = function[:name]
|
func_name = function[:name]
|
||||||
args_string = function[:args].map do |m|
|
args_string = function[:args].map do |m|
|
||||||
type = @utils.arg_type_with_const(m)
|
type = @utils.arg_type_with_const(m)
|
||||||
m[:ptr?] ? "#{type} #{m[:name]}, int #{m[:name]}_Depth" : "#{type} #{m[:name]}"
|
m[:ptr?] ? "#{type} #{m[:name]}, int #{m[:name]}_Depth" : "#{type} #{m[:name]}"
|
||||||
end.join(', ')
|
end.join(', ')
|
||||||
call_string = function[:args].map{|m| m[:ptr?] ? "#{m[:name]}, #{m[:name]}_Depth" : m[:name]}.join(', ')
|
call_string = function[:args].map { |m| m[:ptr?] ? "#{m[:name]}, #{m[:name]}_Depth" : m[:name] }.join(', ')
|
||||||
if (function[:return][:void?])
|
lines << if function[:return][:void?]
|
||||||
lines << "void #{func_name}_CMockExpectWithArray(UNITY_LINE_TYPE cmock_line, #{args_string})\n"
|
"void #{func_name}_CMockExpectWithArray(UNITY_LINE_TYPE cmock_line, #{args_string})\n"
|
||||||
else
|
else
|
||||||
lines << "void #{func_name}_CMockExpectWithArrayAndReturn(UNITY_LINE_TYPE cmock_line, #{args_string}, #{function[:return][:str]})\n"
|
"void #{func_name}_CMockExpectWithArrayAndReturn(UNITY_LINE_TYPE cmock_line, #{args_string}, #{function[:return][:str]})\n"
|
||||||
end
|
end
|
||||||
lines << "{\n"
|
lines << "{\n"
|
||||||
lines << @utils.code_add_base_expectation(func_name)
|
lines << @utils.code_add_base_expectation(func_name)
|
||||||
lines << " CMockExpectParameters_#{func_name}(cmock_call_instance, #{call_string});\n"
|
lines << " CMockExpectParameters_#{func_name}(cmock_call_instance, #{call_string});\n"
|
||||||
lines << " cmock_call_instance->ReturnVal = cmock_to_return;\n" unless (function[:return][:void?])
|
lines << " cmock_call_instance->ReturnVal = cmock_to_return;\n" unless function[:return][:void?]
|
||||||
lines << "}\n\n"
|
lines << "}\n\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
# ==========================================
|
# ==========================================
|
||||||
|
|
||||||
class CMockGeneratorPluginCallback
|
class CMockGeneratorPluginCallback
|
||||||
|
|
||||||
attr_accessor :include_count
|
attr_accessor :include_count
|
||||||
attr_reader :priority
|
attr_reader :priority
|
||||||
attr_reader :config, :utils
|
attr_reader :config, :utils
|
||||||
@ -20,7 +19,7 @@ class CMockGeneratorPluginCallback
|
|||||||
|
|
||||||
def instance_structure(function)
|
def instance_structure(function)
|
||||||
func_name = function[:name]
|
func_name = function[:name]
|
||||||
" int #{func_name}_CallbackBool;\n" \
|
" char #{func_name}_CallbackBool;\n" \
|
||||||
" CMOCK_#{func_name}_CALLBACK #{func_name}_CallbackFunctionPointer;\n" \
|
" CMOCK_#{func_name}_CALLBACK #{func_name}_CallbackFunctionPointer;\n" \
|
||||||
" int #{func_name}_CallbackCalls;\n"
|
" int #{func_name}_CallbackCalls;\n"
|
||||||
end
|
end
|
||||||
@ -30,7 +29,7 @@ class CMockGeneratorPluginCallback
|
|||||||
return_type = function[:return][:type]
|
return_type = function[:return][:type]
|
||||||
action = @config.callback_after_arg_check ? 'AddCallback' : 'Stub'
|
action = @config.callback_after_arg_check ? 'AddCallback' : 'Stub'
|
||||||
style = (@include_count ? 1 : 0) | (function[:args].empty? ? 0 : 2)
|
style = (@include_count ? 1 : 0) | (function[:args].empty? ? 0 : 2)
|
||||||
styles = [ "void", "int cmock_num_calls", function[:args_string], "#{function[:args_string]}, int cmock_num_calls" ]
|
styles = ['void', 'int cmock_num_calls', function[:args_string], "#{function[:args_string]}, int cmock_num_calls"]
|
||||||
"typedef #{return_type} (* CMOCK_#{func_name}_CALLBACK)(#{styles[style]});\n" \
|
"typedef #{return_type} (* CMOCK_#{func_name}_CALLBACK)(#{styles[style]});\n" \
|
||||||
"void #{func_name}_AddCallback(CMOCK_#{func_name}_CALLBACK Callback);\n" \
|
"void #{func_name}_AddCallback(CMOCK_#{func_name}_CALLBACK Callback);\n" \
|
||||||
"void #{func_name}_Stub(CMOCK_#{func_name}_CALLBACK Callback);\n" \
|
"void #{func_name}_Stub(CMOCK_#{func_name}_CALLBACK Callback);\n" \
|
||||||
@ -60,29 +59,30 @@ class CMockGeneratorPluginCallback
|
|||||||
" UNITY_CLR_DETAILS();\n" \
|
" UNITY_CLR_DETAILS();\n" \
|
||||||
" return;\n }\n"
|
" return;\n }\n"
|
||||||
else
|
else
|
||||||
" #{function[:return][:type]} ret = #{generate_call(function)};\n" \
|
" #{function[:return][:type]} cmock_cb_ret = #{generate_call(function)};\n" \
|
||||||
" UNITY_CLR_DETAILS();\n" \
|
" UNITY_CLR_DETAILS();\n" \
|
||||||
" return ret;\n }\n"
|
" return cmock_cb_ret;\n }\n"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def mock_interfaces(function)
|
def mock_interfaces(function)
|
||||||
func_name = function[:name]
|
func_name = function[:name]
|
||||||
has_ignore = @config.plugins.include? :ignore
|
has_ignore = @config.plugins.include? :ignore
|
||||||
lines = ""
|
lines = ''
|
||||||
lines << "void #{func_name}_AddCallback(CMOCK_#{func_name}_CALLBACK Callback)\n{\n"
|
lines << "void #{func_name}_AddCallback(CMOCK_#{func_name}_CALLBACK Callback)\n{\n"
|
||||||
lines << " Mock.#{func_name}_IgnoreBool = (int)0;\n" if has_ignore
|
lines << " Mock.#{func_name}_IgnoreBool = (char)0;\n" if has_ignore
|
||||||
lines << " Mock.#{func_name}_CallbackBool = (int)1;\n"
|
lines << " Mock.#{func_name}_CallbackBool = (char)1;\n"
|
||||||
lines << " Mock.#{func_name}_CallbackFunctionPointer = Callback;\n}\n\n"
|
lines << " Mock.#{func_name}_CallbackFunctionPointer = Callback;\n}\n\n"
|
||||||
lines << "void #{func_name}_Stub(CMOCK_#{func_name}_CALLBACK Callback)\n{\n"
|
lines << "void #{func_name}_Stub(CMOCK_#{func_name}_CALLBACK Callback)\n{\n"
|
||||||
lines << " Mock.#{func_name}_IgnoreBool = (int)0;\n" if has_ignore
|
lines << " Mock.#{func_name}_IgnoreBool = (char)0;\n" if has_ignore
|
||||||
lines << " Mock.#{func_name}_CallbackBool = (int)0;\n"
|
lines << " Mock.#{func_name}_CallbackBool = (char)0;\n"
|
||||||
lines << " Mock.#{func_name}_CallbackFunctionPointer = Callback;\n}\n\n"
|
lines << " Mock.#{func_name}_CallbackFunctionPointer = Callback;\n}\n\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
def mock_verify(function)
|
def mock_verify(function)
|
||||||
func_name = function[:name]
|
func_name = function[:name]
|
||||||
" if (Mock.#{func_name}_CallbackFunctionPointer != NULL)\n call_instance = CMOCK_GUTS_NONE;\n"
|
" if (Mock.#{func_name}_CallbackFunctionPointer != NULL)\n {\n" \
|
||||||
|
" call_instance = CMOCK_GUTS_NONE;\n" \
|
||||||
|
" (void)call_instance;\n }\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
# ==========================================
|
# ==========================================
|
||||||
|
|
||||||
class CMockGeneratorPluginCexception
|
class CMockGeneratorPluginCexception
|
||||||
|
|
||||||
attr_reader :priority
|
attr_reader :priority
|
||||||
attr_reader :config, :utils
|
attr_reader :config, :utils
|
||||||
|
|
||||||
@ -13,39 +12,39 @@ class CMockGeneratorPluginCexception
|
|||||||
@config = config
|
@config = config
|
||||||
@utils = utils
|
@utils = utils
|
||||||
@priority = 7
|
@priority = 7
|
||||||
|
raise 'Error: cexception is not supported without setjmp support' if @config.exclude_setjmp_h
|
||||||
end
|
end
|
||||||
|
|
||||||
def include_files
|
def include_files
|
||||||
return "#include \"CException.h\"\n"
|
"#include \"CException.h\"\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
def instance_typedefs(function)
|
def instance_typedefs(_function)
|
||||||
" CEXCEPTION_T ExceptionToThrow;\n"
|
" CEXCEPTION_T ExceptionToThrow;\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
def mock_function_declarations(function)
|
def mock_function_declarations(function)
|
||||||
if (function[:args_string] == "void")
|
if function[:args_string] == 'void'
|
||||||
return "#define #{function[:name]}_ExpectAndThrow(cmock_to_throw) #{function[:name]}_CMockExpectAndThrow(__LINE__, cmock_to_throw)\n" +
|
"#define #{function[:name]}_ExpectAndThrow(cmock_to_throw) #{function[:name]}_CMockExpectAndThrow(__LINE__, cmock_to_throw)\n" \
|
||||||
"void #{function[:name]}_CMockExpectAndThrow(UNITY_LINE_TYPE cmock_line, CEXCEPTION_T cmock_to_throw);\n"
|
"void #{function[:name]}_CMockExpectAndThrow(UNITY_LINE_TYPE cmock_line, CEXCEPTION_T cmock_to_throw);\n"
|
||||||
else
|
else
|
||||||
return "#define #{function[:name]}_ExpectAndThrow(#{function[:args_call]}, cmock_to_throw) #{function[:name]}_CMockExpectAndThrow(__LINE__, #{function[:args_call]}, cmock_to_throw)\n" +
|
"#define #{function[:name]}_ExpectAndThrow(#{function[:args_call]}, cmock_to_throw) #{function[:name]}_CMockExpectAndThrow(__LINE__, #{function[:args_call]}, cmock_to_throw)\n" \
|
||||||
"void #{function[:name]}_CMockExpectAndThrow(UNITY_LINE_TYPE cmock_line, #{function[:args_string]}, CEXCEPTION_T cmock_to_throw);\n"
|
"void #{function[:name]}_CMockExpectAndThrow(UNITY_LINE_TYPE cmock_line, #{function[:args_string]}, CEXCEPTION_T cmock_to_throw);\n"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def mock_implementation(function)
|
def mock_implementation(_function)
|
||||||
" if (cmock_call_instance->ExceptionToThrow != CEXCEPTION_NONE)\n {\n" +
|
" if (cmock_call_instance->ExceptionToThrow != CEXCEPTION_NONE)\n {\n" \
|
||||||
" UNITY_CLR_DETAILS();\n" +
|
" UNITY_CLR_DETAILS();\n" \
|
||||||
" Throw(cmock_call_instance->ExceptionToThrow);\n }\n"
|
" Throw(cmock_call_instance->ExceptionToThrow);\n }\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
def mock_interfaces(function)
|
def mock_interfaces(function)
|
||||||
arg_insert = (function[:args_string] == "void") ? "" : "#{function[:args_string]}, "
|
arg_insert = function[:args_string] == 'void' ? '' : "#{function[:args_string]}, "
|
||||||
[ "void #{function[:name]}_CMockExpectAndThrow(UNITY_LINE_TYPE cmock_line, #{arg_insert}CEXCEPTION_T cmock_to_throw)\n{\n",
|
["void #{function[:name]}_CMockExpectAndThrow(UNITY_LINE_TYPE cmock_line, #{arg_insert}CEXCEPTION_T cmock_to_throw)\n{\n",
|
||||||
@utils.code_add_base_expectation(function[:name]),
|
@utils.code_add_base_expectation(function[:name]),
|
||||||
@utils.code_call_argument_loader(function),
|
@utils.code_call_argument_loader(function),
|
||||||
" cmock_call_instance->ExceptionToThrow = cmock_to_throw;\n",
|
" cmock_call_instance->ExceptionToThrow = cmock_to_throw;\n",
|
||||||
"}\n\n" ].join
|
"}\n\n"].join
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
# ==========================================
|
# ==========================================
|
||||||
|
|
||||||
class CMockGeneratorPluginExpect
|
class CMockGeneratorPluginExpect
|
||||||
|
|
||||||
attr_reader :priority
|
attr_reader :priority
|
||||||
attr_accessor :config, :utils, :unity_helper, :ordered
|
attr_accessor :config, :utils, :unity_helper, :ordered
|
||||||
|
|
||||||
@ -17,7 +16,7 @@ class CMockGeneratorPluginExpect
|
|||||||
@unity_helper = @utils.helpers[:unity_helper]
|
@unity_helper = @utils.helpers[:unity_helper]
|
||||||
@priority = 5
|
@priority = 5
|
||||||
|
|
||||||
if (@config.plugins.include? :expect_any_args)
|
if @config.plugins.include? :expect_any_args
|
||||||
alias :mock_implementation :mock_implementation_might_check_args
|
alias :mock_implementation :mock_implementation_might_check_args
|
||||||
else
|
else
|
||||||
alias :mock_implementation :mock_implementation_always_check_args
|
alias :mock_implementation :mock_implementation_always_check_args
|
||||||
@ -25,9 +24,9 @@ class CMockGeneratorPluginExpect
|
|||||||
end
|
end
|
||||||
|
|
||||||
def instance_typedefs(function)
|
def instance_typedefs(function)
|
||||||
lines = ""
|
lines = ''
|
||||||
lines << " #{function[:return][:type]} ReturnVal;\n" unless (function[:return][:void?])
|
lines << " #{function[:return][:type]} ReturnVal;\n" unless function[:return][:void?]
|
||||||
lines << " int CallOrder;\n" if (@ordered)
|
lines << " int CallOrder;\n" if @ordered
|
||||||
function[:args].each do |arg|
|
function[:args].each do |arg|
|
||||||
lines << " #{arg[:type]} Expected_#{arg[:name]};\n"
|
lines << " #{arg[:type]} Expected_#{arg[:name]};\n"
|
||||||
end
|
end
|
||||||
@ -35,27 +34,25 @@ class CMockGeneratorPluginExpect
|
|||||||
end
|
end
|
||||||
|
|
||||||
def mock_function_declarations(function)
|
def mock_function_declarations(function)
|
||||||
if (function[:args].empty?)
|
if function[:args].empty?
|
||||||
if (function[:return][:void?])
|
if function[:return][:void?]
|
||||||
return "#define #{function[:name]}_Expect() #{function[:name]}_CMockExpect(__LINE__)\n" +
|
"#define #{function[:name]}_Expect() #{function[:name]}_CMockExpect(__LINE__)\n" \
|
||||||
"void #{function[:name]}_CMockExpect(UNITY_LINE_TYPE cmock_line);\n"
|
"void #{function[:name]}_CMockExpect(UNITY_LINE_TYPE cmock_line);\n"
|
||||||
else
|
else
|
||||||
return "#define #{function[:name]}_ExpectAndReturn(cmock_retval) #{function[:name]}_CMockExpectAndReturn(__LINE__, cmock_retval)\n" +
|
"#define #{function[:name]}_ExpectAndReturn(cmock_retval) #{function[:name]}_CMockExpectAndReturn(__LINE__, cmock_retval)\n" \
|
||||||
"void #{function[:name]}_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]});\n"
|
"void #{function[:name]}_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]});\n"
|
||||||
end
|
end
|
||||||
|
elsif function[:return][:void?]
|
||||||
|
"#define #{function[:name]}_Expect(#{function[:args_call]}) #{function[:name]}_CMockExpect(__LINE__, #{function[:args_call]})\n" \
|
||||||
|
"void #{function[:name]}_CMockExpect(UNITY_LINE_TYPE cmock_line, #{function[:args_string]});\n"
|
||||||
else
|
else
|
||||||
if (function[:return][:void?])
|
"#define #{function[:name]}_ExpectAndReturn(#{function[:args_call]}, cmock_retval) #{function[:name]}_CMockExpectAndReturn(__LINE__, #{function[:args_call]}, cmock_retval)\n" \
|
||||||
return "#define #{function[:name]}_Expect(#{function[:args_call]}) #{function[:name]}_CMockExpect(__LINE__, #{function[:args_call]})\n" +
|
"void #{function[:name]}_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:args_string]}, #{function[:return][:str]});\n"
|
||||||
"void #{function[:name]}_CMockExpect(UNITY_LINE_TYPE cmock_line, #{function[:args_string]});\n"
|
|
||||||
else
|
|
||||||
return "#define #{function[:name]}_ExpectAndReturn(#{function[:args_call]}, cmock_retval) #{function[:name]}_CMockExpectAndReturn(__LINE__, #{function[:args_call]}, cmock_retval)\n" +
|
|
||||||
"void #{function[:name]}_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:args_string]}, #{function[:return][:str]});\n"
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def mock_implementation_always_check_args(function)
|
def mock_implementation_always_check_args(function)
|
||||||
lines = ""
|
lines = ''
|
||||||
function[:args].each do |arg|
|
function[:args].each do |arg|
|
||||||
lines << @utils.code_verify_an_arg_expectation(function, arg)
|
lines << @utils.code_verify_an_arg_expectation(function, arg)
|
||||||
end
|
end
|
||||||
@ -63,7 +60,8 @@ class CMockGeneratorPluginExpect
|
|||||||
end
|
end
|
||||||
|
|
||||||
def mock_implementation_might_check_args(function)
|
def mock_implementation_might_check_args(function)
|
||||||
return "" if (function[:args].empty?)
|
return '' if function[:args].empty?
|
||||||
|
|
||||||
lines = " if (!cmock_call_instance->ExpectAnyArgsBool)\n {\n"
|
lines = " if (!cmock_call_instance->ExpectAnyArgsBool)\n {\n"
|
||||||
function[:args].each do |arg|
|
function[:args].each do |arg|
|
||||||
lines << @utils.code_verify_an_arg_expectation(function, arg)
|
lines << @utils.code_verify_an_arg_expectation(function, arg)
|
||||||
@ -73,31 +71,30 @@ class CMockGeneratorPluginExpect
|
|||||||
end
|
end
|
||||||
|
|
||||||
def mock_interfaces(function)
|
def mock_interfaces(function)
|
||||||
lines = ""
|
lines = ''
|
||||||
func_name = function[:name]
|
func_name = function[:name]
|
||||||
if (function[:return][:void?])
|
lines << if function[:return][:void?]
|
||||||
if (function[:args_string] == "void")
|
if function[:args_string] == 'void'
|
||||||
lines << "void #{func_name}_CMockExpect(UNITY_LINE_TYPE cmock_line)\n{\n"
|
"void #{func_name}_CMockExpect(UNITY_LINE_TYPE cmock_line)\n{\n"
|
||||||
else
|
else
|
||||||
lines << "void #{func_name}_CMockExpect(UNITY_LINE_TYPE cmock_line, #{function[:args_string]})\n{\n"
|
"void #{func_name}_CMockExpect(UNITY_LINE_TYPE cmock_line, #{function[:args_string]})\n{\n"
|
||||||
end
|
end
|
||||||
else
|
elsif function[:args_string] == 'void'
|
||||||
if (function[:args_string] == "void")
|
"void #{func_name}_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]})\n{\n"
|
||||||
lines << "void #{func_name}_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]})\n{\n"
|
else
|
||||||
else
|
"void #{func_name}_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:args_string]}, #{function[:return][:str]})\n{\n"
|
||||||
lines << "void #{func_name}_CMockExpectAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:args_string]}, #{function[:return][:str]})\n{\n"
|
end
|
||||||
end
|
|
||||||
end
|
|
||||||
lines << @utils.code_add_base_expectation(func_name)
|
lines << @utils.code_add_base_expectation(func_name)
|
||||||
lines << @utils.code_call_argument_loader(function)
|
lines << @utils.code_call_argument_loader(function)
|
||||||
lines << @utils.code_assign_argument_quickly("cmock_call_instance->ReturnVal", function[:return]) unless (function[:return][:void?])
|
lines << @utils.code_assign_argument_quickly('cmock_call_instance->ReturnVal', function[:return]) unless function[:return][:void?]
|
||||||
lines << "}\n\n"
|
lines << "}\n\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
def mock_verify(function)
|
def mock_verify(function)
|
||||||
" UNITY_SET_DETAIL(CMockString_#{function[:name]});\n" +
|
" if (CMOCK_GUTS_NONE != call_instance)\n" \
|
||||||
" UNITY_TEST_ASSERT(CMOCK_GUTS_NONE == call_instance, cmock_line, CMockStringCalledLess);\n" +
|
" {\n" \
|
||||||
" UNITY_CLR_DETAILS();\n"
|
" UNITY_SET_DETAIL(CMockString_#{function[:name]});\n" \
|
||||||
|
" UNITY_TEST_FAIL(cmock_line, CMockStringCalledLess);\n" \
|
||||||
|
" }\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
# ==========================================
|
# ==========================================
|
||||||
|
|
||||||
class CMockGeneratorPluginExpectAnyArgs
|
class CMockGeneratorPluginExpectAnyArgs
|
||||||
|
|
||||||
attr_reader :priority
|
attr_reader :priority
|
||||||
attr_reader :config, :utils
|
attr_reader :config, :utils
|
||||||
|
|
||||||
@ -15,39 +14,37 @@ class CMockGeneratorPluginExpectAnyArgs
|
|||||||
@priority = 3
|
@priority = 3
|
||||||
end
|
end
|
||||||
|
|
||||||
def instance_typedefs(function)
|
def instance_typedefs(_function)
|
||||||
" int ExpectAnyArgsBool;\n"
|
" char ExpectAnyArgsBool;\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
def mock_function_declarations(function)
|
def mock_function_declarations(function)
|
||||||
unless (function[:args].empty?)
|
if function[:args].empty?
|
||||||
if (function[:return][:void?])
|
''
|
||||||
return "#define #{function[:name]}_ExpectAnyArgs() #{function[:name]}_CMockExpectAnyArgs(__LINE__)\n" +
|
elsif function[:return][:void?]
|
||||||
"void #{function[:name]}_CMockExpectAnyArgs(UNITY_LINE_TYPE cmock_line);\n"
|
"#define #{function[:name]}_ExpectAnyArgs() #{function[:name]}_CMockExpectAnyArgs(__LINE__)\n" \
|
||||||
else
|
"void #{function[:name]}_CMockExpectAnyArgs(UNITY_LINE_TYPE cmock_line);\n"
|
||||||
return "#define #{function[:name]}_ExpectAnyArgsAndReturn(cmock_retval) #{function[:name]}_CMockExpectAnyArgsAndReturn(__LINE__, cmock_retval)\n" +
|
|
||||||
"void #{function[:name]}_CMockExpectAnyArgsAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]});\n"
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
""
|
"#define #{function[:name]}_ExpectAnyArgsAndReturn(cmock_retval) #{function[:name]}_CMockExpectAnyArgsAndReturn(__LINE__, cmock_retval)\n" \
|
||||||
|
"void #{function[:name]}_CMockExpectAnyArgsAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]});\n"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def mock_interfaces(function)
|
def mock_interfaces(function)
|
||||||
lines = ""
|
lines = ''
|
||||||
unless (function[:args].empty?)
|
unless function[:args].empty?
|
||||||
if (function[:return][:void?])
|
lines << if function[:return][:void?]
|
||||||
lines << "void #{function[:name]}_CMockExpectAnyArgs(UNITY_LINE_TYPE cmock_line)\n{\n"
|
"void #{function[:name]}_CMockExpectAnyArgs(UNITY_LINE_TYPE cmock_line)\n{\n"
|
||||||
else
|
else
|
||||||
lines << "void #{function[:name]}_CMockExpectAnyArgsAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]})\n{\n"
|
"void #{function[:name]}_CMockExpectAnyArgsAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]})\n{\n"
|
||||||
end
|
end
|
||||||
lines << @utils.code_add_base_expectation(function[:name], true)
|
lines << @utils.code_add_base_expectation(function[:name], true)
|
||||||
unless (function[:return][:void?])
|
unless function[:return][:void?]
|
||||||
lines << " cmock_call_instance->ReturnVal = cmock_to_return;\n"
|
lines << " cmock_call_instance->ReturnVal = cmock_to_return;\n"
|
||||||
end
|
end
|
||||||
lines << " cmock_call_instance->ExpectAnyArgsBool = (int)1;\n"
|
lines << " cmock_call_instance->ExpectAnyArgsBool = (char)1;\n"
|
||||||
lines << "}\n\n"
|
lines << "}\n\n"
|
||||||
end
|
end
|
||||||
return lines
|
lines
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
# ==========================================
|
# ==========================================
|
||||||
|
|
||||||
class CMockGeneratorPluginIgnore
|
class CMockGeneratorPluginIgnore
|
||||||
|
|
||||||
attr_reader :priority
|
attr_reader :priority
|
||||||
attr_reader :config, :utils
|
attr_reader :config, :utils
|
||||||
|
|
||||||
@ -16,56 +15,70 @@ class CMockGeneratorPluginIgnore
|
|||||||
end
|
end
|
||||||
|
|
||||||
def instance_structure(function)
|
def instance_structure(function)
|
||||||
if (function[:return][:void?])
|
if function[:return][:void?]
|
||||||
" int #{function[:name]}_IgnoreBool;\n"
|
" char #{function[:name]}_IgnoreBool;\n"
|
||||||
else
|
else
|
||||||
" int #{function[:name]}_IgnoreBool;\n #{function[:return][:type]} #{function[:name]}_FinalReturn;\n"
|
" char #{function[:name]}_IgnoreBool;\n #{function[:return][:type]} #{function[:name]}_FinalReturn;\n"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def mock_function_declarations(function)
|
def mock_function_declarations(function)
|
||||||
if (function[:return][:void?])
|
lines = if function[:return][:void?]
|
||||||
return "#define #{function[:name]}_Ignore() #{function[:name]}_CMockIgnore()\n" +
|
"#define #{function[:name]}_Ignore() #{function[:name]}_CMockIgnore()\n" \
|
||||||
"void #{function[:name]}_CMockIgnore(void);\n"
|
"void #{function[:name]}_CMockIgnore(void);\n"
|
||||||
else
|
else
|
||||||
return "#define #{function[:name]}_IgnoreAndReturn(cmock_retval) #{function[:name]}_CMockIgnoreAndReturn(__LINE__, cmock_retval)\n" +
|
"#define #{function[:name]}_IgnoreAndReturn(cmock_retval) #{function[:name]}_CMockIgnoreAndReturn(__LINE__, cmock_retval)\n" \
|
||||||
"void #{function[:name]}_CMockIgnoreAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]});\n"
|
"void #{function[:name]}_CMockIgnoreAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]});\n"
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
def mock_implementation_precheck(function)
|
def mock_implementation_precheck(function)
|
||||||
lines = " if (Mock.#{function[:name]}_IgnoreBool)\n {\n"
|
lines = " if (Mock.#{function[:name]}_IgnoreBool)\n {\n"
|
||||||
lines << " UNITY_CLR_DETAILS();\n"
|
lines << " UNITY_CLR_DETAILS();\n"
|
||||||
if (function[:return][:void?])
|
if function[:return][:void?]
|
||||||
lines << " return;\n }\n"
|
lines << " return;\n }\n"
|
||||||
else
|
else
|
||||||
retval = function[:return].merge( { :name => "cmock_call_instance->ReturnVal"} )
|
retval = function[:return].merge(:name => 'cmock_call_instance->ReturnVal')
|
||||||
lines << " if (cmock_call_instance == NULL)\n return Mock.#{function[:name]}_FinalReturn;\n"
|
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 << ' ' + @utils.code_assign_argument_quickly("Mock.#{function[:name]}_FinalReturn", retval) unless retval[:void?]
|
||||||
lines << " return cmock_call_instance->ReturnVal;\n }\n"
|
lines << " return cmock_call_instance->ReturnVal;\n }\n"
|
||||||
end
|
end
|
||||||
lines
|
lines
|
||||||
end
|
end
|
||||||
|
|
||||||
def mock_interfaces(function)
|
def mock_interfaces(function)
|
||||||
lines = ""
|
lines = ''
|
||||||
if (function[:return][:void?])
|
lines << if function[:return][:void?]
|
||||||
lines << "void #{function[:name]}_CMockIgnore(void)\n{\n"
|
"void #{function[:name]}_CMockIgnore(void)\n{\n"
|
||||||
else
|
else
|
||||||
lines << "void #{function[:name]}_CMockIgnoreAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]})\n{\n"
|
"void #{function[:name]}_CMockIgnoreAndReturn(UNITY_LINE_TYPE cmock_line, #{function[:return][:str]})\n{\n"
|
||||||
end
|
end
|
||||||
if (!function[:return][:void?])
|
unless function[:return][:void?]
|
||||||
lines << @utils.code_add_base_expectation(function[:name], false)
|
lines << @utils.code_add_base_expectation(function[:name], false)
|
||||||
end
|
end
|
||||||
unless (function[:return][:void?])
|
unless function[:return][:void?]
|
||||||
lines << " cmock_call_instance->ReturnVal = cmock_to_return;\n"
|
lines << " cmock_call_instance->ReturnVal = cmock_to_return;\n"
|
||||||
end
|
end
|
||||||
lines << " Mock.#{function[:name]}_IgnoreBool = (int)1;\n"
|
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"
|
||||||
|
unless function[:return][:void?]
|
||||||
|
lines << " if(Mock.#{function[:name]}_IgnoreBool)\n"
|
||||||
|
lines << " Mock.#{function[:name]}_CallInstance = CMock_Guts_MemNext(Mock.#{function[:name]}_CallInstance);\n"
|
||||||
|
end
|
||||||
|
lines << " Mock.#{function[:name]}_IgnoreBool = (char)0;\n"
|
||||||
lines << "}\n\n"
|
lines << "}\n\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
def mock_ignore(function)
|
def mock_ignore(function)
|
||||||
" Mock.#{function[:name]}_IgnoreBool = (int) 1;\n"
|
" Mock.#{function[:name]}_IgnoreBool = (char) 1;\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
def mock_verify(function)
|
def mock_verify(function)
|
||||||
|
@ -2,21 +2,21 @@ class CMockGeneratorPluginIgnoreArg
|
|||||||
attr_reader :priority
|
attr_reader :priority
|
||||||
attr_accessor :utils
|
attr_accessor :utils
|
||||||
|
|
||||||
def initialize(config, utils)
|
def initialize(_config, utils)
|
||||||
@utils = utils
|
@utils = utils
|
||||||
@priority = 10
|
@priority = 10
|
||||||
end
|
end
|
||||||
|
|
||||||
def instance_typedefs(function)
|
def instance_typedefs(function)
|
||||||
lines = ""
|
lines = ''
|
||||||
function[:args].each do |arg|
|
function[:args].each do |arg|
|
||||||
lines << " int IgnoreArg_#{arg[:name]};\n"
|
lines << " char IgnoreArg_#{arg[:name]};\n"
|
||||||
end
|
end
|
||||||
lines
|
lines
|
||||||
end
|
end
|
||||||
|
|
||||||
def mock_function_declarations(function)
|
def mock_function_declarations(function)
|
||||||
lines = ""
|
lines = ''
|
||||||
function[:args].each do |arg|
|
function[:args].each do |arg|
|
||||||
lines << "#define #{function[:name]}_IgnoreArg_#{arg[:name]}()"
|
lines << "#define #{function[:name]}_IgnoreArg_#{arg[:name]}()"
|
||||||
lines << " #{function[:name]}_CMockIgnoreArg_#{arg[:name]}(__LINE__)\n"
|
lines << " #{function[:name]}_CMockIgnoreArg_#{arg[:name]}(__LINE__)\n"
|
||||||
@ -31,8 +31,8 @@ class CMockGeneratorPluginIgnoreArg
|
|||||||
function[:args].each do |arg|
|
function[:args].each do |arg|
|
||||||
lines << "void #{func_name}_CMockIgnoreArg_#{arg[:name]}(UNITY_LINE_TYPE cmock_line)\n"
|
lines << "void #{func_name}_CMockIgnoreArg_#{arg[:name]}(UNITY_LINE_TYPE cmock_line)\n"
|
||||||
lines << "{\n"
|
lines << "{\n"
|
||||||
lines << " CMOCK_#{func_name}_CALL_INSTANCE* cmock_call_instance = " +
|
lines << " CMOCK_#{func_name}_CALL_INSTANCE* cmock_call_instance = " \
|
||||||
"(CMOCK_#{func_name}_CALL_INSTANCE*)CMock_Guts_GetAddressFor(CMock_Guts_MemEndOfChain(Mock.#{func_name}_CallInstance));\n"
|
"(CMOCK_#{func_name}_CALL_INSTANCE*)CMock_Guts_GetAddressFor(CMock_Guts_MemEndOfChain(Mock.#{func_name}_CallInstance));\n"
|
||||||
lines << " UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringIgnPreExp);\n"
|
lines << " UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringIgnPreExp);\n"
|
||||||
lines << " cmock_call_instance->IgnoreArg_#{arg[:name]} = 1;\n"
|
lines << " cmock_call_instance->IgnoreArg_#{arg[:name]} = 1;\n"
|
||||||
lines << "}\n\n"
|
lines << "}\n\n"
|
||||||
|
@ -2,41 +2,41 @@ class CMockGeneratorPluginReturnThruPtr
|
|||||||
attr_reader :priority
|
attr_reader :priority
|
||||||
attr_accessor :utils
|
attr_accessor :utils
|
||||||
|
|
||||||
def initialize(config, utils)
|
def initialize(_config, utils)
|
||||||
@utils = utils
|
@utils = utils
|
||||||
@priority = 9
|
@priority = 9
|
||||||
end
|
end
|
||||||
|
|
||||||
def instance_typedefs(function)
|
def instance_typedefs(function)
|
||||||
lines = ""
|
lines = ''
|
||||||
function[:args].each do |arg|
|
function[:args].each do |arg|
|
||||||
if (@utils.ptr_or_str?(arg[:type]) and not arg[:const?])
|
next unless @utils.ptr_or_str?(arg[:type]) && !(arg[:const?])
|
||||||
lines << " int ReturnThruPtr_#{arg[:name]}_Used;\n"
|
|
||||||
lines << " #{arg[:type]} ReturnThruPtr_#{arg[:name]}_Val;\n"
|
lines << " char ReturnThruPtr_#{arg[:name]}_Used;\n"
|
||||||
lines << " int ReturnThruPtr_#{arg[:name]}_Size;\n"
|
lines << " #{arg[:type]} ReturnThruPtr_#{arg[:name]}_Val;\n"
|
||||||
end
|
lines << " size_t ReturnThruPtr_#{arg[:name]}_Size;\n"
|
||||||
end
|
end
|
||||||
lines
|
lines
|
||||||
end
|
end
|
||||||
|
|
||||||
def mock_function_declarations(function)
|
def mock_function_declarations(function)
|
||||||
lines = ""
|
lines = ''
|
||||||
function[:args].each do |arg|
|
function[:args].each do |arg|
|
||||||
if (@utils.ptr_or_str?(arg[:type]) and not arg[:const?])
|
next unless @utils.ptr_or_str?(arg[:type]) && !(arg[:const?])
|
||||||
lines << "#define #{function[:name]}_ReturnThruPtr_#{arg[:name]}(#{arg[:name]})"
|
|
||||||
# If the pointer type actually contains an asterisk, we can do sizeof the type (super safe), otherwise
|
lines << "#define #{function[:name]}_ReturnThruPtr_#{arg[:name]}(#{arg[:name]})"
|
||||||
# we need to do a sizeof the dereferenced pointer (which could be a problem if give the wrong size
|
# If the pointer type actually contains an asterisk, we can do sizeof the type (super safe), otherwise
|
||||||
if (arg[:type][-1] == '*')
|
# we need to do a sizeof the dereferenced pointer (which could be a problem if give the wrong size
|
||||||
lines << " #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(__LINE__, #{arg[:name]}, sizeof(#{arg[:type][0..-2]}))\n"
|
lines << if arg[:type][-1] == '*'
|
||||||
else
|
" #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(__LINE__, #{arg[:name]}, sizeof(#{arg[:type][0..-2]}))\n"
|
||||||
lines << " #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(__LINE__, #{arg[:name]}, sizeof(*#{arg[:name]}))\n"
|
else
|
||||||
end
|
" #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(__LINE__, #{arg[:name]}, sizeof(*#{arg[:name]}))\n"
|
||||||
lines << "#define #{function[:name]}_ReturnArrayThruPtr_#{arg[:name]}(#{arg[:name]}, cmock_len)"
|
end
|
||||||
lines << " #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(__LINE__, #{arg[:name]}, (int)(cmock_len * (int)sizeof(*#{arg[:name]})))\n"
|
lines << "#define #{function[:name]}_ReturnArrayThruPtr_#{arg[:name]}(#{arg[:name]}, cmock_len)"
|
||||||
lines << "#define #{function[:name]}_ReturnMemThruPtr_#{arg[:name]}(#{arg[:name]}, cmock_size)"
|
lines << " #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(__LINE__, #{arg[:name]}, cmock_len * sizeof(*#{arg[:name]}))\n"
|
||||||
lines << " #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(__LINE__, #{arg[:name]}, cmock_size)\n"
|
lines << "#define #{function[:name]}_ReturnMemThruPtr_#{arg[:name]}(#{arg[:name]}, cmock_size)"
|
||||||
lines << "void #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(UNITY_LINE_TYPE cmock_line, #{arg[:type]} #{arg[:name]}, int cmock_size);\n"
|
lines << " #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(__LINE__, #{arg[:name]}, cmock_size)\n"
|
||||||
end
|
lines << "void #{function[:name]}_CMockReturnMemThruPtr_#{arg[:name]}(UNITY_LINE_TYPE cmock_line, #{arg[:type]} #{arg[:name]}, size_t cmock_size);\n"
|
||||||
end
|
end
|
||||||
lines
|
lines
|
||||||
end
|
end
|
||||||
@ -46,17 +46,17 @@ class CMockGeneratorPluginReturnThruPtr
|
|||||||
func_name = function[:name]
|
func_name = function[:name]
|
||||||
function[:args].each do |arg|
|
function[:args].each do |arg|
|
||||||
arg_name = arg[:name]
|
arg_name = arg[:name]
|
||||||
if (@utils.ptr_or_str?(arg[:type]) and not arg[:const?])
|
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 << "{\n"
|
lines << "void #{func_name}_CMockReturnMemThruPtr_#{arg_name}(UNITY_LINE_TYPE cmock_line, #{arg[:type]} #{arg_name}, size_t cmock_size)\n"
|
||||||
lines << " CMOCK_#{func_name}_CALL_INSTANCE* cmock_call_instance = " +
|
lines << "{\n"
|
||||||
"(CMOCK_#{func_name}_CALL_INSTANCE*)CMock_Guts_GetAddressFor(CMock_Guts_MemEndOfChain(Mock.#{func_name}_CallInstance));\n"
|
lines << " CMOCK_#{func_name}_CALL_INSTANCE* cmock_call_instance = " \
|
||||||
lines << " UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringPtrPreExp);\n"
|
"(CMOCK_#{func_name}_CALL_INSTANCE*)CMock_Guts_GetAddressFor(CMock_Guts_MemEndOfChain(Mock.#{func_name}_CallInstance));\n"
|
||||||
lines << " cmock_call_instance->ReturnThruPtr_#{arg_name}_Used = 1;\n"
|
lines << " UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringPtrPreExp);\n"
|
||||||
lines << " cmock_call_instance->ReturnThruPtr_#{arg_name}_Val = #{arg_name};\n"
|
lines << " cmock_call_instance->ReturnThruPtr_#{arg_name}_Used = 1;\n"
|
||||||
lines << " cmock_call_instance->ReturnThruPtr_#{arg_name}_Size = cmock_size;\n"
|
lines << " cmock_call_instance->ReturnThruPtr_#{arg_name}_Val = #{arg_name};\n"
|
||||||
lines << "}\n\n"
|
lines << " cmock_call_instance->ReturnThruPtr_#{arg_name}_Size = cmock_size;\n"
|
||||||
end
|
lines << "}\n\n"
|
||||||
end
|
end
|
||||||
lines
|
lines
|
||||||
end
|
end
|
||||||
@ -65,14 +65,14 @@ class CMockGeneratorPluginReturnThruPtr
|
|||||||
lines = []
|
lines = []
|
||||||
function[:args].each do |arg|
|
function[:args].each do |arg|
|
||||||
arg_name = arg[:name]
|
arg_name = arg[:name]
|
||||||
if (@utils.ptr_or_str?(arg[:type]) and not arg[:const?])
|
next unless @utils.ptr_or_str?(arg[:type]) && !(arg[:const?])
|
||||||
lines << " if (cmock_call_instance->ReturnThruPtr_#{arg_name}_Used)\n"
|
|
||||||
lines << " {\n"
|
lines << " if (cmock_call_instance->ReturnThruPtr_#{arg_name}_Used)\n"
|
||||||
lines << " UNITY_TEST_ASSERT_NOT_NULL(#{arg_name}, cmock_line, CMockStringPtrIsNULL);\n"
|
lines << " {\n"
|
||||||
lines << " memcpy((void*)#{arg_name}, (void*)cmock_call_instance->ReturnThruPtr_#{arg_name}_Val,\n"
|
lines << " UNITY_TEST_ASSERT_NOT_NULL(#{arg_name}, cmock_line, CMockStringPtrIsNULL);\n"
|
||||||
lines << " cmock_call_instance->ReturnThruPtr_#{arg_name}_Size);\n"
|
lines << " memcpy((void*)#{arg_name}, (void*)cmock_call_instance->ReturnThruPtr_#{arg_name}_Val,\n"
|
||||||
lines << " }\n"
|
lines << " cmock_call_instance->ReturnThruPtr_#{arg_name}_Size);\n"
|
||||||
end
|
lines << " }\n"
|
||||||
end
|
end
|
||||||
lines
|
lines
|
||||||
end
|
end
|
||||||
|
@ -5,10 +5,9 @@
|
|||||||
# ==========================================
|
# ==========================================
|
||||||
|
|
||||||
class CMockGeneratorUtils
|
class CMockGeneratorUtils
|
||||||
|
|
||||||
attr_accessor :config, :helpers, :ordered, :ptr_handling, :arrays, :cexception
|
attr_accessor :config, :helpers, :ordered, :ptr_handling, :arrays, :cexception
|
||||||
|
|
||||||
def initialize(config, helpers={})
|
def initialize(config, helpers = {})
|
||||||
@config = config
|
@config = config
|
||||||
@ptr_handling = @config.when_ptr
|
@ptr_handling = @config.when_ptr
|
||||||
@ordered = @config.enforce_strict_ordering
|
@ordered = @config.enforce_strict_ordering
|
||||||
@ -16,9 +15,10 @@ class CMockGeneratorUtils
|
|||||||
@cexception = @config.plugins.include? :cexception
|
@cexception = @config.plugins.include? :cexception
|
||||||
@expect_any = @config.plugins.include? :expect_any_args
|
@expect_any = @config.plugins.include? :expect_any_args
|
||||||
@return_thru_ptr = @config.plugins.include? :return_thru_ptr
|
@return_thru_ptr = @config.plugins.include? :return_thru_ptr
|
||||||
@ignore_arg = @config.plugins.include? :ignore_arg
|
@ignore_arg = @config.plugins.include? :ignore_arg
|
||||||
@ignore = @config.plugins.include? :ignore
|
@ignore = @config.plugins.include? :ignore
|
||||||
@treat_as = @config.treat_as
|
@ignore_stateless = @config.plugins.include? :ignore_stateless
|
||||||
|
@treat_as = @config.treat_as
|
||||||
@helpers = helpers
|
@helpers = helpers
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -36,78 +36,78 @@ class CMockGeneratorUtils
|
|||||||
end
|
end
|
||||||
|
|
||||||
def code_verify_an_arg_expectation(function, arg)
|
def code_verify_an_arg_expectation(function, arg)
|
||||||
if (@arrays)
|
if @arrays
|
||||||
case(@ptr_handling)
|
case @ptr_handling
|
||||||
when :smart then code_verify_an_arg_expectation_with_smart_arrays(function, arg)
|
when :smart then code_verify_an_arg_expectation_with_smart_arrays(function, arg)
|
||||||
when :compare_data then code_verify_an_arg_expectation_with_normal_arrays(function, arg)
|
when :compare_data then code_verify_an_arg_expectation_with_normal_arrays(function, arg)
|
||||||
when :compare_ptr then raise "ERROR: the array plugin doesn't enjoy working with :compare_ptr only. Disable one option."
|
when :compare_ptr then raise "ERROR: the array plugin doesn't enjoy working with :compare_ptr only. Disable one option."
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
code_verify_an_arg_expectation_with_no_arrays(function, arg)
|
code_verify_an_arg_expectation_with_no_arrays(function, arg)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def code_add_base_expectation(func_name, global_ordering_supported=true)
|
def code_add_base_expectation(func_name, global_ordering_supported = true)
|
||||||
lines = " CMOCK_MEM_INDEX_TYPE cmock_guts_index = CMock_Guts_MemNew(sizeof(CMOCK_#{func_name}_CALL_INSTANCE));\n"
|
lines = " CMOCK_MEM_INDEX_TYPE cmock_guts_index = CMock_Guts_MemNew(sizeof(CMOCK_#{func_name}_CALL_INSTANCE));\n"
|
||||||
lines << " CMOCK_#{func_name}_CALL_INSTANCE* cmock_call_instance = (CMOCK_#{func_name}_CALL_INSTANCE*)CMock_Guts_GetAddressFor(cmock_guts_index);\n"
|
lines << " CMOCK_#{func_name}_CALL_INSTANCE* cmock_call_instance = (CMOCK_#{func_name}_CALL_INSTANCE*)CMock_Guts_GetAddressFor(cmock_guts_index);\n"
|
||||||
lines << " UNITY_TEST_ASSERT_NOT_NULL(cmock_call_instance, cmock_line, CMockStringOutOfMemory);\n"
|
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 << " 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}_CallInstance = CMock_Guts_MemChain(Mock.#{func_name}_CallInstance, cmock_guts_index);\n"
|
||||||
lines << " Mock.#{func_name}_IgnoreBool = (int)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->LineNumber = cmock_line;\n"
|
||||||
lines << " cmock_call_instance->CallOrder = ++GlobalExpectCount;\n" if (@ordered and global_ordering_supported)
|
lines << " cmock_call_instance->CallOrder = ++GlobalExpectCount;\n" if @ordered && global_ordering_supported
|
||||||
lines << " cmock_call_instance->ExceptionToThrow = CEXCEPTION_NONE;\n" if (@cexception)
|
lines << " cmock_call_instance->ExceptionToThrow = CEXCEPTION_NONE;\n" if @cexception
|
||||||
lines << " cmock_call_instance->ExpectAnyArgsBool = (int)0;\n" if (@expect_any)
|
lines << " cmock_call_instance->ExpectAnyArgsBool = (char)0;\n" if @expect_any
|
||||||
lines
|
lines
|
||||||
end
|
end
|
||||||
|
|
||||||
def code_add_an_arg_expectation(arg, depth=1)
|
def code_add_an_arg_expectation(arg, depth = 1)
|
||||||
lines = code_assign_argument_quickly("cmock_call_instance->Expected_#{arg[:name]}", arg)
|
lines = code_assign_argument_quickly("cmock_call_instance->Expected_#{arg[:name]}", arg)
|
||||||
lines << " cmock_call_instance->Expected_#{arg[:name]}_Depth = #{arg[:name]}_Depth;\n" if (@arrays and (depth.class == String))
|
lines << " cmock_call_instance->Expected_#{arg[:name]}_Depth = #{arg[:name]}_Depth;\n" if @arrays && (depth.class == String)
|
||||||
lines << " cmock_call_instance->IgnoreArg_#{arg[:name]} = 0;\n" if (@ignore_arg)
|
lines << " cmock_call_instance->IgnoreArg_#{arg[:name]} = 0;\n" if @ignore_arg
|
||||||
lines << " cmock_call_instance->ReturnThruPtr_#{arg[:name]}_Used = 0;\n" if (@return_thru_ptr and ptr_or_str?(arg[:type]) and not arg[:const?])
|
lines << " cmock_call_instance->ReturnThruPtr_#{arg[:name]}_Used = 0;\n" if @return_thru_ptr && ptr_or_str?(arg[:type]) && !(arg[:const?])
|
||||||
lines
|
lines
|
||||||
end
|
end
|
||||||
|
|
||||||
def code_assign_argument_quickly(dest, arg)
|
def code_assign_argument_quickly(dest, arg)
|
||||||
if (arg[:ptr?] or @treat_as.include?(arg[:type]))
|
if arg[:ptr?] || @treat_as.include?(arg[:type])
|
||||||
" #{dest} = #{arg[:name]};\n"
|
" #{dest} = #{arg[:name]};\n"
|
||||||
else
|
else
|
||||||
assert_expr = "sizeof(#{arg[:name]}) == sizeof(#{arg[:type]}) ? 1 : -1"
|
assert_expr = "sizeof(#{arg[:name]}) == sizeof(#{arg[:type]}) ? 1 : -1"
|
||||||
comment = "/* add #{arg[:type]} to :treat_as_array if this causes an error */"
|
comment = "/* add #{arg[:type]} to :treat_as_array if this causes an error */"
|
||||||
" memcpy((void*)(&#{dest}), (void*)(&#{arg[:name]}),\n" +
|
" memcpy((void*)(&#{dest}), (void*)(&#{arg[:name]}),\n" \
|
||||||
" sizeof(#{arg[:type]}[#{assert_expr}])); #{comment}\n"
|
" sizeof(#{arg[:type]}[#{assert_expr}])); #{comment}\n"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def code_add_argument_loader(function)
|
def code_add_argument_loader(function)
|
||||||
if (function[:args_string] != "void")
|
if function[:args_string] != 'void'
|
||||||
if (@arrays)
|
if @arrays
|
||||||
args_string = function[:args].map do |m|
|
args_string = function[:args].map do |m|
|
||||||
type = arg_type_with_const(m)
|
type = arg_type_with_const(m)
|
||||||
m[:ptr?] ? "#{type} #{m[:name]}, int #{m[:name]}_Depth" : "#{type} #{m[:name]}"
|
m[:ptr?] ? "#{type} #{m[:name]}, int #{m[:name]}_Depth" : "#{type} #{m[:name]}"
|
||||||
end.join(', ')
|
end.join(', ')
|
||||||
"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" \
|
||||||
"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{\n" +
|
||||||
function[:args].inject("") { |all, arg| all + code_add_an_arg_expectation(arg, (arg[:ptr?] ? "#{arg[:name]}_Depth" : 1) ) } +
|
function[:args].inject('') { |all, arg| all + code_add_an_arg_expectation(arg, (arg[:ptr?] ? "#{arg[:name]}_Depth" : 1)) } +
|
||||||
"}\n\n"
|
"}\n\n"
|
||||||
else
|
else
|
||||||
"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" \
|
||||||
"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{\n" +
|
||||||
function[:args].inject("") { |all, arg| all + code_add_an_arg_expectation(arg) } +
|
function[:args].inject('') { |all, arg| all + code_add_an_arg_expectation(arg) } +
|
||||||
"}\n\n"
|
"}\n\n"
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
""
|
''
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def code_call_argument_loader(function)
|
def code_call_argument_loader(function)
|
||||||
if (function[:args_string] != "void")
|
if function[:args_string] != 'void'
|
||||||
args = function[:args].map do |m|
|
args = function[:args].map do |m|
|
||||||
if (@arrays and m[:ptr?] and not m[:array_data?])
|
if @arrays && m[:ptr?] && !(m[:array_data?])
|
||||||
"#{m[:name]}, 1"
|
"#{m[:name]}, 1"
|
||||||
elsif (@arrays and m[:array_size?])
|
elsif @arrays && m[:array_size?]
|
||||||
"#{m[:name]}, #{m[:name]}"
|
"#{m[:name]}, #{m[:name]}"
|
||||||
else
|
else
|
||||||
m[:name]
|
m[:name]
|
||||||
@ -115,60 +115,60 @@ class CMockGeneratorUtils
|
|||||||
end
|
end
|
||||||
" CMockExpectParameters_#{function[:name]}(cmock_call_instance, #{args.join(', ')});\n"
|
" CMockExpectParameters_#{function[:name]}(cmock_call_instance, #{args.join(', ')});\n"
|
||||||
else
|
else
|
||||||
""
|
''
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def ptr_or_str?(arg_type)
|
def ptr_or_str?(arg_type)
|
||||||
return (arg_type.include? '*' or
|
(arg_type.include?('*') ||
|
||||||
@treat_as.fetch(arg_type, "").include? '*')
|
@treat_as.fetch(arg_type, '').include?('*'))
|
||||||
end
|
end
|
||||||
|
|
||||||
#private ######################
|
# private ######################
|
||||||
|
|
||||||
def lookup_expect_type(function, arg)
|
def lookup_expect_type(_function, arg)
|
||||||
c_type = arg[:type]
|
c_type = arg[:type]
|
||||||
arg_name = arg[:name]
|
arg_name = arg[:name]
|
||||||
expected = "cmock_call_instance->Expected_#{arg_name}"
|
expected = "cmock_call_instance->Expected_#{arg_name}"
|
||||||
ignore = "cmock_call_instance->IgnoreArg_#{arg_name}"
|
ignore = "cmock_call_instance->IgnoreArg_#{arg_name}"
|
||||||
unity_func = if ((arg[:ptr?]) and ((c_type =~ /\*\*/) or (@ptr_handling == :compare_ptr)))
|
unity_func = if (arg[:ptr?]) && ((c_type =~ /\*\*/) || (@ptr_handling == :compare_ptr))
|
||||||
['UNITY_TEST_ASSERT_EQUAL_PTR', '']
|
['UNITY_TEST_ASSERT_EQUAL_PTR', '']
|
||||||
else
|
else
|
||||||
(@helpers.nil? or @helpers[:unity_helper].nil?) ? ["UNITY_TEST_ASSERT_EQUAL",''] : @helpers[:unity_helper].get_helper(c_type)
|
@helpers.nil? || @helpers[:unity_helper].nil? ? ['UNITY_TEST_ASSERT_EQUAL', ''] : @helpers[:unity_helper].get_helper(c_type)
|
||||||
end
|
end
|
||||||
return c_type, arg_name, expected, ignore, unity_func[0], unity_func[1]
|
[c_type, arg_name, expected, ignore, unity_func[0], unity_func[1]]
|
||||||
end
|
end
|
||||||
|
|
||||||
def code_verify_an_arg_expectation_with_no_arrays(function, arg)
|
def code_verify_an_arg_expectation_with_no_arrays(function, arg)
|
||||||
c_type, arg_name, expected, ignore, unity_func, pre = lookup_expect_type(function, arg)
|
c_type, arg_name, expected, ignore, unity_func, pre = lookup_expect_type(function, arg)
|
||||||
lines = ""
|
lines = ''
|
||||||
lines << " if (!#{ignore})\n" if @ignore_arg
|
lines << " if (!#{ignore})\n" if @ignore_arg
|
||||||
lines << " {\n"
|
lines << " {\n"
|
||||||
lines << " UNITY_SET_DETAILS(CMockString_#{function[:name]},CMockString_#{arg_name});\n"
|
lines << " UNITY_SET_DETAILS(CMockString_#{function[:name]},CMockString_#{arg_name});\n"
|
||||||
case(unity_func)
|
case unity_func
|
||||||
when "UNITY_TEST_ASSERT_EQUAL_MEMORY"
|
when 'UNITY_TEST_ASSERT_EQUAL_MEMORY'
|
||||||
c_type_local = c_type.gsub(/\*$/,'')
|
c_type_local = c_type.gsub(/\*$/, '')
|
||||||
lines << " UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type_local}), cmock_line, CMockStringMismatch);\n"
|
lines << " UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type_local}), cmock_line, CMockStringMismatch);\n"
|
||||||
when "UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY"
|
when 'UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY'
|
||||||
if (pre == '&')
|
if pre == '&'
|
||||||
lines << " UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type.sub('*','')}), cmock_line, CMockStringMismatch);\n"
|
lines << " UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type.sub('*', '')}), cmock_line, CMockStringMismatch);\n"
|
||||||
else
|
|
||||||
lines << " if (#{pre}#{expected} == NULL)\n"
|
|
||||||
lines << " { UNITY_TEST_ASSERT_NULL(#{pre}#{arg_name}, cmock_line, CMockStringExpNULL); }\n"
|
|
||||||
lines << " else\n"
|
|
||||||
lines << " { UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type.sub('*','')}), cmock_line, CMockStringMismatch); }\n"
|
|
||||||
end
|
|
||||||
when /_ARRAY/
|
|
||||||
if (pre == '&')
|
|
||||||
lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, 1, cmock_line, CMockStringMismatch);\n"
|
|
||||||
else
|
|
||||||
lines << " if (#{pre}#{expected} == NULL)\n"
|
|
||||||
lines << " { UNITY_TEST_ASSERT_NULL(#{pre}#{arg_name}, cmock_line, CMockStringExpNULL); }\n"
|
|
||||||
lines << " else\n"
|
|
||||||
lines << " { #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, 1, cmock_line, CMockStringMismatch); }\n"
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, CMockStringMismatch);\n"
|
lines << " if (#{pre}#{expected} == NULL)\n"
|
||||||
|
lines << " { UNITY_TEST_ASSERT_NULL(#{pre}#{arg_name}, cmock_line, CMockStringExpNULL); }\n"
|
||||||
|
lines << " else\n"
|
||||||
|
lines << " { UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type.sub('*', '')}), cmock_line, CMockStringMismatch); }\n"
|
||||||
|
end
|
||||||
|
when /_ARRAY/
|
||||||
|
if pre == '&'
|
||||||
|
lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, 1, cmock_line, CMockStringMismatch);\n"
|
||||||
|
else
|
||||||
|
lines << " if (#{pre}#{expected} == NULL)\n"
|
||||||
|
lines << " { UNITY_TEST_ASSERT_NULL(#{pre}#{arg_name}, cmock_line, CMockStringExpNULL); }\n"
|
||||||
|
lines << " else\n"
|
||||||
|
lines << " { #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, 1, cmock_line, CMockStringMismatch); }\n"
|
||||||
|
end
|
||||||
|
else
|
||||||
|
lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, CMockStringMismatch);\n"
|
||||||
end
|
end
|
||||||
lines << " }\n"
|
lines << " }\n"
|
||||||
lines
|
lines
|
||||||
@ -176,78 +176,75 @@ class CMockGeneratorUtils
|
|||||||
|
|
||||||
def code_verify_an_arg_expectation_with_normal_arrays(function, arg)
|
def code_verify_an_arg_expectation_with_normal_arrays(function, arg)
|
||||||
c_type, arg_name, expected, ignore, unity_func, pre = lookup_expect_type(function, arg)
|
c_type, arg_name, expected, ignore, unity_func, pre = lookup_expect_type(function, arg)
|
||||||
depth_name = (arg[:ptr?]) ? "cmock_call_instance->Expected_#{arg_name}_Depth" : 1
|
depth_name = arg[:ptr?] ? "cmock_call_instance->Expected_#{arg_name}_Depth" : 1
|
||||||
lines = ""
|
lines = ''
|
||||||
lines << " if (!#{ignore})\n" if @ignore_arg
|
lines << " if (!#{ignore})\n" if @ignore_arg
|
||||||
lines << " {\n"
|
lines << " {\n"
|
||||||
lines << " UNITY_SET_DETAILS(CMockString_#{function[:name]},CMockString_#{arg_name});\n"
|
lines << " UNITY_SET_DETAILS(CMockString_#{function[:name]},CMockString_#{arg_name});\n"
|
||||||
lines << " if (#{pre}#{expected} != #{pre}#{arg_name}) {\n"
|
case unity_func
|
||||||
case(unity_func)
|
when 'UNITY_TEST_ASSERT_EQUAL_MEMORY'
|
||||||
when "UNITY_TEST_ASSERT_EQUAL_MEMORY"
|
c_type_local = c_type.gsub(/\*$/, '')
|
||||||
c_type_local = c_type.gsub(/\*$/,'')
|
lines << " UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type_local}), cmock_line, CMockStringMismatch);\n"
|
||||||
lines << " UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type_local}), cmock_line, CMockStringMismatch);\n"
|
when 'UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY'
|
||||||
when "UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY"
|
if pre == '&'
|
||||||
if (pre == '&')
|
lines << " UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type.sub('*', '')}), cmock_line, CMockStringMismatch);\n"
|
||||||
lines << " UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type.sub('*','')}), cmock_line, CMockStringMismatch);\n"
|
|
||||||
else
|
|
||||||
lines << " if (#{pre}#{expected} == NULL)\n"
|
|
||||||
lines << " { UNITY_TEST_ASSERT_NULL(#{pre}#{arg_name}, cmock_line, CMockStringExpNULL); }\n"
|
|
||||||
lines << " else\n"
|
|
||||||
lines << " { UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type.sub('*','')}), #{depth_name}, cmock_line, CMockStringMismatch); }\n"
|
|
||||||
end
|
|
||||||
when /_ARRAY/
|
|
||||||
if (pre == '&')
|
|
||||||
lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, #{depth_name}, cmock_line, CMockStringMismatch);\n"
|
|
||||||
else
|
|
||||||
lines << " if (#{pre}#{expected} == NULL)\n"
|
|
||||||
lines << " { UNITY_TEST_ASSERT_NULL(#{pre}#{arg_name}, cmock_line, CMockStringExpNULL); }\n"
|
|
||||||
lines << " else\n"
|
|
||||||
lines << " { #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, #{depth_name}, cmock_line, CMockStringMismatch); }\n"
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, CMockStringMismatch);\n"
|
lines << " if (#{pre}#{expected} == NULL)\n"
|
||||||
|
lines << " { UNITY_TEST_ASSERT_NULL(#{pre}#{arg_name}, cmock_line, CMockStringExpNULL); }\n"
|
||||||
|
lines << " else\n"
|
||||||
|
lines << " { UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type.sub('*', '')}), #{depth_name}, cmock_line, CMockStringMismatch); }\n"
|
||||||
|
end
|
||||||
|
when /_ARRAY/
|
||||||
|
if pre == '&'
|
||||||
|
lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, #{depth_name}, cmock_line, CMockStringMismatch);\n"
|
||||||
|
else
|
||||||
|
lines << " if (#{pre}#{expected} == NULL)\n"
|
||||||
|
lines << " { UNITY_TEST_ASSERT_NULL(#{pre}#{arg_name}, cmock_line, CMockStringExpNULL); }\n"
|
||||||
|
lines << " else\n"
|
||||||
|
lines << " { #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, #{depth_name}, cmock_line, CMockStringMismatch); }\n"
|
||||||
|
end
|
||||||
|
else
|
||||||
|
lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, CMockStringMismatch);\n"
|
||||||
end
|
end
|
||||||
lines << " }\n }\n"
|
lines << " }\n"
|
||||||
lines
|
lines
|
||||||
end
|
end
|
||||||
|
|
||||||
def code_verify_an_arg_expectation_with_smart_arrays(function, arg)
|
def code_verify_an_arg_expectation_with_smart_arrays(function, arg)
|
||||||
c_type, arg_name, expected, ignore, unity_func, pre = lookup_expect_type(function, arg)
|
c_type, arg_name, expected, ignore, unity_func, pre = lookup_expect_type(function, arg)
|
||||||
depth_name = (arg[:ptr?]) ? "cmock_call_instance->Expected_#{arg_name}_Depth" : 1
|
depth_name = arg[:ptr?] ? "cmock_call_instance->Expected_#{arg_name}_Depth" : 1
|
||||||
lines = ""
|
lines = ''
|
||||||
lines << " if (!#{ignore})\n" if @ignore_arg
|
lines << " if (!#{ignore})\n" if @ignore_arg
|
||||||
lines << " {\n"
|
lines << " {\n"
|
||||||
lines << " UNITY_SET_DETAILS(CMockString_#{function[:name]},CMockString_#{arg_name});\n"
|
lines << " UNITY_SET_DETAILS(CMockString_#{function[:name]},CMockString_#{arg_name});\n"
|
||||||
lines << " if (#{pre}#{expected} != #{pre}#{arg_name}) {\n"
|
case unity_func
|
||||||
case(unity_func)
|
when 'UNITY_TEST_ASSERT_EQUAL_MEMORY'
|
||||||
when "UNITY_TEST_ASSERT_EQUAL_MEMORY"
|
c_type_local = c_type.gsub(/\*$/, '')
|
||||||
c_type_local = c_type.gsub(/\*$/,'')
|
lines << " UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type_local}), cmock_line, CMockStringMismatch);\n"
|
||||||
lines << " UNITY_TEST_ASSERT_EQUAL_MEMORY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type_local}), cmock_line, CMockStringMismatch);\n"
|
when 'UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY'
|
||||||
when "UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY"
|
if pre == '&'
|
||||||
if (pre == '&')
|
lines << " UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type.sub('*', '')}), #{depth_name}, cmock_line, CMockStringMismatch);\n"
|
||||||
lines << " UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type.sub('*','')}), #{depth_name}, cmock_line, CMockStringMismatch);\n"
|
|
||||||
else
|
|
||||||
lines << " if (#{pre}#{expected} == NULL)\n"
|
|
||||||
lines << " { UNITY_TEST_ASSERT_NULL(#{arg_name}, cmock_line, CMockStringExpNULL); }\n"
|
|
||||||
lines << ((depth_name != 1) ? " else if (#{depth_name} == 0)\n { UNITY_TEST_ASSERT_EQUAL_PTR(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, CMockStringMismatch); }\n" : "")
|
|
||||||
lines << " else\n"
|
|
||||||
lines << " { UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type.sub('*','')}), #{depth_name}, cmock_line, CMockStringMismatch); }\n"
|
|
||||||
end
|
|
||||||
when /_ARRAY/
|
|
||||||
if (pre == '&')
|
|
||||||
lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, #{depth_name}, cmock_line, CMockStringMismatch);\n"
|
|
||||||
else
|
|
||||||
lines << " if (#{pre}#{expected} == NULL)\n"
|
|
||||||
lines << " { UNITY_TEST_ASSERT_NULL(#{pre}#{arg_name}, cmock_line, CMockStringExpNULL); }\n"
|
|
||||||
lines << ((depth_name != 1) ? " else if (#{depth_name} == 0)\n { UNITY_TEST_ASSERT_EQUAL_PTR(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, CMockStringMismatch); }\n" : "")
|
|
||||||
lines << " else\n"
|
|
||||||
lines << " { #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, #{depth_name}, cmock_line, CMockStringMismatch); }\n"
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, CMockStringMismatch);\n"
|
lines << " if (#{pre}#{expected} == NULL)\n"
|
||||||
|
lines << " { UNITY_TEST_ASSERT_NULL(#{arg_name}, cmock_line, CMockStringExpNULL); }\n"
|
||||||
|
lines << (depth_name != 1 ? " else if (#{depth_name} == 0)\n { UNITY_TEST_ASSERT_EQUAL_PTR(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, CMockStringMismatch); }\n" : '')
|
||||||
|
lines << " else\n"
|
||||||
|
lines << " { UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY((void*)(#{pre}#{expected}), (void*)(#{pre}#{arg_name}), sizeof(#{c_type.sub('*', '')}), #{depth_name}, cmock_line, CMockStringMismatch); }\n"
|
||||||
|
end
|
||||||
|
when /_ARRAY/
|
||||||
|
if pre == '&'
|
||||||
|
lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, #{depth_name}, cmock_line, CMockStringMismatch);\n"
|
||||||
|
else
|
||||||
|
lines << " if (#{pre}#{expected} == NULL)\n"
|
||||||
|
lines << " { UNITY_TEST_ASSERT_NULL(#{pre}#{arg_name}, cmock_line, CMockStringExpNULL); }\n"
|
||||||
|
lines << (depth_name != 1 ? " else if (#{depth_name} == 0)\n { UNITY_TEST_ASSERT_EQUAL_PTR(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, CMockStringMismatch); }\n" : '')
|
||||||
|
lines << " else\n"
|
||||||
|
lines << " { #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, #{depth_name}, cmock_line, CMockStringMismatch); }\n"
|
||||||
|
end
|
||||||
|
else
|
||||||
|
lines << " #{unity_func}(#{pre}#{expected}, #{pre}#{arg_name}, cmock_line, CMockStringMismatch);\n"
|
||||||
end
|
end
|
||||||
lines << " }\n }\n"
|
lines << " }\n"
|
||||||
lines
|
lines
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -5,54 +5,217 @@
|
|||||||
# ==========================================
|
# ==========================================
|
||||||
|
|
||||||
class CMockHeaderParser
|
class CMockHeaderParser
|
||||||
|
attr_accessor :funcs, :c_attr_noconst, :c_attributes, :treat_as_void, :treat_externs, :treat_inlines, :inline_function_patterns
|
||||||
attr_accessor :funcs, :c_attr_noconst, :c_attributes, :treat_as_void, :treat_externs
|
|
||||||
|
|
||||||
def initialize(cfg)
|
def initialize(cfg)
|
||||||
@funcs = []
|
|
||||||
@c_strippables = cfg.strippables
|
@c_strippables = cfg.strippables
|
||||||
@c_attr_noconst = cfg.attributes.uniq - ['const']
|
@c_attr_noconst = cfg.attributes.uniq - ['const']
|
||||||
@c_attributes = ['const'] + c_attr_noconst
|
@c_attributes = ['const'] + c_attr_noconst
|
||||||
@c_calling_conventions = cfg.c_calling_conventions.uniq
|
@c_calling_conventions = cfg.c_calling_conventions.uniq
|
||||||
@treat_as_array = cfg.treat_as_array
|
@treat_as_array = cfg.treat_as_array
|
||||||
@treat_as_void = (['void'] + cfg.treat_as_void).uniq
|
@treat_as_void = (['void'] + cfg.treat_as_void).uniq
|
||||||
@declaration_parse_matcher = /([\w\s\*\(\),\[\]]+??)\(([\w\s\*\(\),\.\[\]+-]*)\)$/m
|
@function_declaration_parse_base_match = '([\w\s\*\(\),\[\]]+??)\(([\w\s\*\(\),\.\[\]+\-\/]*)\)'
|
||||||
@standards = (['int','short','char','long','unsigned','signed'] + cfg.treat_as.keys).uniq
|
@declaration_parse_matcher = /#{@function_declaration_parse_base_match}$/m
|
||||||
|
@standards = (%w[int short char long unsigned signed] + cfg.treat_as.keys).uniq
|
||||||
@array_size_name = cfg.array_size_name
|
@array_size_name = cfg.array_size_name
|
||||||
@array_size_type = (['int', 'size_t'] + cfg.array_size_type).uniq
|
@array_size_type = (%w[int size_t] + cfg.array_size_type).uniq
|
||||||
@when_no_prototypes = cfg.when_no_prototypes
|
@when_no_prototypes = cfg.when_no_prototypes
|
||||||
@local_as_void = @treat_as_void
|
@local_as_void = @treat_as_void
|
||||||
@verbosity = cfg.verbosity
|
@verbosity = cfg.verbosity
|
||||||
@treat_externs = cfg.treat_externs
|
@treat_externs = cfg.treat_externs
|
||||||
@c_strippables += ['extern'] if (@treat_externs == :include) #we'll need to remove the attribute if we're allowing externs
|
@treat_inlines = cfg.treat_inlines
|
||||||
|
@inline_function_patterns = cfg.inline_function_patterns
|
||||||
|
@c_strippables += ['extern'] if @treat_externs == :include # we'll need to remove the attribute if we're allowing externs
|
||||||
|
@c_strippables += ['inline'] if @treat_inlines == :include # we'll need to remove the attribute if we're allowing inlines
|
||||||
end
|
end
|
||||||
|
|
||||||
def parse(name, source)
|
def parse(name, source)
|
||||||
@module_name = name.gsub(/\W/,'')
|
parse_project = {
|
||||||
@typedefs = []
|
:module_name => name.gsub(/\W/, ''),
|
||||||
@funcs = []
|
:typedefs => [],
|
||||||
|
:functions => [],
|
||||||
|
:normalized_source => nil
|
||||||
|
}
|
||||||
|
|
||||||
function_names = []
|
function_names = []
|
||||||
|
|
||||||
parse_functions( import_source(source) ).map do |decl|
|
all_funcs = parse_functions(import_source(source, parse_project)).map { |item| [item] }
|
||||||
func = parse_declaration(decl)
|
all_funcs += parse_cpp_functions(import_source(source, parse_project, true))
|
||||||
unless (function_names.include? func[:name])
|
all_funcs.map do |decl|
|
||||||
@funcs << func
|
func = parse_declaration(parse_project, *decl)
|
||||||
|
unless function_names.include? func[:name]
|
||||||
|
parse_project[:functions] << func
|
||||||
function_names << func[:name]
|
function_names << func[:name]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
parse_project[:normalized_source] = if @treat_inlines == :include
|
||||||
|
transform_inline_functions(source)
|
||||||
|
else
|
||||||
|
''
|
||||||
|
end
|
||||||
|
|
||||||
{ :includes => nil,
|
{ :includes => nil,
|
||||||
:functions => @funcs,
|
:functions => parse_project[:functions],
|
||||||
:typedefs => @typedefs
|
:typedefs => parse_project[:typedefs],
|
||||||
}
|
:normalized_source => parse_project[:normalized_source] }
|
||||||
end
|
end
|
||||||
|
|
||||||
private if $ThisIsOnlyATest.nil? ################
|
private if $ThisIsOnlyATest.nil? ################
|
||||||
|
|
||||||
def import_source(source)
|
# 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
|
||||||
|
# we assign a string first because (no joke) if Ruby 1.9.3 sees this line as a regex, it will crash.
|
||||||
|
r = '\\{([^\\{\\}]*|\\g<0>)*\\}'
|
||||||
|
source.gsub!(/#{r}/m, '{ }')
|
||||||
|
else
|
||||||
|
while source.gsub!(/\{[^\{\}]*\{[^\{\}]*\}[^\{\}]*\}/m, '{ }')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
source
|
||||||
|
end
|
||||||
|
|
||||||
|
# Return the number of pairs of braces/square brackets in the function provided by the user
|
||||||
|
# +source+:: String containing the function to be processed
|
||||||
|
def count_number_of_pairs_of_braces_in_function(source)
|
||||||
|
is_function_start_found = false
|
||||||
|
curr_level = 0
|
||||||
|
total_pairs = 0
|
||||||
|
|
||||||
|
source.each_char do |c|
|
||||||
|
if c == '{'
|
||||||
|
curr_level += 1
|
||||||
|
total_pairs += 1
|
||||||
|
is_function_start_found = true
|
||||||
|
elsif c == '}'
|
||||||
|
curr_level -= 1
|
||||||
|
end
|
||||||
|
|
||||||
|
break if is_function_start_found && curr_level == 0 # We reached the end of the inline function body
|
||||||
|
end
|
||||||
|
|
||||||
|
if curr_level != 0
|
||||||
|
total_pairs = 0 # Something is fishy about this source, not enough closing braces?
|
||||||
|
end
|
||||||
|
|
||||||
|
total_pairs
|
||||||
|
end
|
||||||
|
|
||||||
|
# Transform inline functions to regular functions in the source by the user
|
||||||
|
# +source+:: String containing the source to be processed
|
||||||
|
def transform_inline_functions(source)
|
||||||
|
inline_function_regex_formats = []
|
||||||
|
square_bracket_pair_regex_format = /\{[^\{\}]*\}/ # Regex to match one whole block enclosed by two square brackets
|
||||||
|
|
||||||
|
# Convert user provided string patterns to regex
|
||||||
|
# Use word bounderies before and after the user regex to limit matching to actual word iso part of a word
|
||||||
|
@inline_function_patterns.each do |user_format_string|
|
||||||
|
user_regex = Regexp.new(user_format_string)
|
||||||
|
word_boundary_before_user_regex = /\b/
|
||||||
|
cleanup_spaces_after_user_regex = /[ ]*\b/
|
||||||
|
inline_function_regex_formats << Regexp.new(word_boundary_before_user_regex.source + user_regex.source + cleanup_spaces_after_user_regex.source)
|
||||||
|
end
|
||||||
|
|
||||||
# let's clean up the encoding in case they've done anything weird with the characters we might find
|
# 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)
|
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,
|
||||||
|
# remove them later on in this function
|
||||||
|
source.gsub!(/\s*\\\s*/m, ' ')
|
||||||
|
|
||||||
|
# Just looking for static|inline in the gsub is a bit too aggressive (functions that are named like this, ...), so we try to be a bit smarter
|
||||||
|
# Instead, look for an inline pattern (f.e. "static inline") and parse it.
|
||||||
|
# Below is a small explanation on how the general mechanism works:
|
||||||
|
# - Everything before the match should just be copied, we don't want
|
||||||
|
# to touch anything but the inline functions.
|
||||||
|
# - Remove the implementation of the inline function (this is enclosed
|
||||||
|
# in square brackets) and replace it with ";" to complete the
|
||||||
|
# transformation to normal/non-inline function.
|
||||||
|
# To ensure proper removal of the function body, we count the number of square-bracket pairs
|
||||||
|
# and remove the pairs one-by-one.
|
||||||
|
# - 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
|
||||||
|
|
||||||
|
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
|
||||||
|
if /(#define\s*)\z/ =~ inline_function_match.pre_match
|
||||||
|
# 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]?)/, '')
|
||||||
|
inspected_source += stripped_pre_match
|
||||||
|
source = stripped_post_match
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
# 2. Determine if we are dealing with an inline function declaration iso function definition
|
||||||
|
# If the start of the post-match string is a function-declaration-like string (something ending with semicolon after the function arguments),
|
||||||
|
# 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
|
||||||
|
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 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?
|
||||||
|
|
||||||
|
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)
|
||||||
|
end
|
||||||
|
inspected_source += inline_function_match.pre_match
|
||||||
|
source = inline_function_stripped
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
# 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, 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)
|
||||||
|
|
||||||
# void must be void for cmock _ExpectAndReturn calls to process properly, not some weird typedef which equates to void
|
# void must be void for cmock _ExpectAndReturn calls to process properly, not some weird typedef which equates to void
|
||||||
# to a certain extent, this action assumes we're chewing on pre-processed header files, otherwise we'll most likely just get stuff from @treat_as_void
|
# to a certain extent, this action assumes we're chewing on pre-processed header files, otherwise we'll most likely just get stuff from @treat_as_void
|
||||||
@ -62,13 +225,18 @@ class CMockHeaderParser
|
|||||||
@local_as_void += void_types.flatten.uniq.compact
|
@local_as_void += void_types.flatten.uniq.compact
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# If user wants to mock inline functions,
|
||||||
|
# remove the (user specific) inline keywords before removing anything else to avoid missing an inline function
|
||||||
|
if @treat_inlines == :include
|
||||||
|
@inline_function_patterns.each do |user_format_string|
|
||||||
|
source.gsub!(/#{user_format_string}/, '') # remove user defined inline function patterns
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# smush multiline macros into single line (checking for continuation character at end of line '\')
|
# smush multiline macros into single line (checking for continuation character at end of line '\')
|
||||||
source.gsub!(/\s*\\\s*/m, ' ')
|
source.gsub!(/\s*\\\s*/m, ' ')
|
||||||
|
|
||||||
#remove comments (block and line, in three steps to ensure correct precedence)
|
remove_comments_from_source(source)
|
||||||
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 assembler pragma sections
|
# remove assembler pragma sections
|
||||||
source.gsub!(/^\s*#\s*pragma\s+asm\s+.*?#\s*pragma\s+endasm/m, '')
|
source.gsub!(/^\s*#\s*pragma\s+asm\s+.*?#\s*pragma\s+endasm/m, '')
|
||||||
@ -84,66 +252,123 @@ class CMockHeaderParser
|
|||||||
# forward declared structs are removed before struct definitions so they don't mess up real thing later. we leave structs keywords in function prototypes
|
# forward declared structs are removed before struct definitions so they don't mess up real thing later. we leave structs keywords in function prototypes
|
||||||
source.gsub!(/^[\w\s]*struct[^;\{\}\(\)]+;/m, '') # remove forward declared structs
|
source.gsub!(/^[\w\s]*struct[^;\{\}\(\)]+;/m, '') # remove forward declared structs
|
||||||
source.gsub!(/^[\w\s]*(enum|union|struct|typedef)[\w\s]*\{[^\}]+\}[\w\s\*\,]*;/m, '') # remove struct, union, and enum definitions and typedefs with braces
|
source.gsub!(/^[\w\s]*(enum|union|struct|typedef)[\w\s]*\{[^\}]+\}[\w\s\*\,]*;/m, '') # remove struct, union, and enum definitions and typedefs with braces
|
||||||
source.gsub!(/(\W)(?:register|auto|static|restrict)(\W)/, '\1\2') # remove problem keywords
|
# remove problem keywords
|
||||||
|
source.gsub!(/(\W)(?:register|auto|restrict)(\W)/, '\1\2')
|
||||||
|
source.gsub!(/(\W)(?:static)(\W)/, '\1\2') unless cpp
|
||||||
|
|
||||||
source.gsub!(/\s*=\s*['"a-zA-Z0-9_\.]+\s*/, '') # remove default value statements from argument lists
|
source.gsub!(/\s*=\s*['"a-zA-Z0-9_\.]+\s*/, '') # remove default value statements from argument lists
|
||||||
source.gsub!(/^(?:[\w\s]*\W)?typedef\W[^;]*/m, '') # remove typedef statements
|
source.gsub!(/^(?:[\w\s]*\W)?typedef\W[^;]*/m, '') # remove typedef statements
|
||||||
source.gsub!(/\)(\w)/, ') \1') # add space between parenthese and alphanumeric
|
source.gsub!(/\)(\w)/, ') \1') # add space between parenthese and alphanumeric
|
||||||
source.gsub!(/(^|\W+)(?:#{@c_strippables.join('|')})(?=$|\W+)/,'\1') unless @c_strippables.empty? # remove known attributes slated to be stripped
|
source.gsub!(/(^|\W+)(?:#{@c_strippables.join('|')})(?=$|\W+)/, '\1') unless @c_strippables.empty? # remove known attributes slated to be stripped
|
||||||
|
|
||||||
#scan standalone function pointers and remove them, because they can just be ignored
|
# scan standalone function pointers and remove them, because they can just be ignored
|
||||||
source.gsub!(/\w+\s*\(\s*\*\s*\w+\s*\)\s*\([^)]*\)\s*;/,';')
|
source.gsub!(/\w+\s*\(\s*\*\s*\w+\s*\)\s*\([^)]*\)\s*;/, ';')
|
||||||
|
|
||||||
#scan for functions which return function pointers, because they are a pain
|
# scan for functions which return function pointers, because they are a pain
|
||||||
source.gsub!(/([\w\s\*]+)\(*\(\s*\*([\w\s\*]+)\s*\(([\w\s\*,]*)\)\)\s*\(([\w\s\*,]*)\)\)*/) do |m|
|
source.gsub!(/([\w\s\*]+)\(*\(\s*\*([\w\s\*]+)\s*\(([\w\s\*,]*)\)\)\s*\(([\w\s\*,]*)\)\)*/) do |_m|
|
||||||
functype = "cmock_#{@module_name}_func_ptr#{@typedefs.size + 1}"
|
functype = "cmock_#{parse_project[:module_name]}_func_ptr#{parse_project[:typedefs].size + 1}"
|
||||||
@typedefs << "typedef #{$1.strip}(*#{functype})(#{$4});"
|
unless cpp # only collect once
|
||||||
"#{functype} #{$2.strip}(#{$3});"
|
parse_project[:typedefs] << "typedef #{Regexp.last_match(1).strip}(*#{functype})(#{Regexp.last_match(4)});"
|
||||||
end
|
"#{functype} #{Regexp.last_match(2).strip}(#{Regexp.last_match(3)});"
|
||||||
|
|
||||||
# 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)
|
|
||||||
#we assign a string first because (no joke) if Ruby 1.9.3 sees this line as a regex, it will crash.
|
|
||||||
r = "\\{([^\\{\\}]*|\\g<0>)*\\}"
|
|
||||||
source.gsub!(/#{r}/m, '{ }')
|
|
||||||
else
|
|
||||||
while source.gsub!(/\{[^\{\}]*\{[^\{\}]*\}[^\{\}]*\}/m, '{ }')
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# remove function definitions by stripping off the arguments right now
|
source = remove_nested_pairs_of_braces(source) unless cpp
|
||||||
source.gsub!(/\([^\)]*\)\s*\{[^\}]*\}/m, ";")
|
|
||||||
|
|
||||||
#drop extra white space to make the rest go faster
|
if @treat_inlines == :include
|
||||||
|
# Functions having "{ }" at this point are/were inline functions,
|
||||||
|
# User wants them in so 'disguise' them as normal functions with the ";"
|
||||||
|
source.gsub!('{ }', ';')
|
||||||
|
end
|
||||||
|
|
||||||
|
# remove function definitions by stripping off the arguments right now
|
||||||
|
source.gsub!(/\([^\)]*\)\s*\{[^\}]*\}/m, ';')
|
||||||
|
|
||||||
|
# drop extra white space to make the rest go faster
|
||||||
source.gsub!(/^\s+/, '') # remove extra white space from beginning of line
|
source.gsub!(/^\s+/, '') # remove extra white space from beginning of line
|
||||||
source.gsub!(/\s+$/, '') # remove extra white space from end of line
|
source.gsub!(/\s+$/, '') # remove extra white space from end of line
|
||||||
source.gsub!(/\s*\(\s*/, '(') # remove extra white space from before left parens
|
source.gsub!(/\s*\(\s*/, '(') # remove extra white space from before left parens
|
||||||
source.gsub!(/\s*\)\s*/, ')') # remove extra white space from before right parens
|
source.gsub!(/\s*\)\s*/, ')') # remove extra white space from before right parens
|
||||||
source.gsub!(/\s+/, ' ') # remove remaining extra white space
|
source.gsub!(/\s+/, ' ') # remove remaining extra white space
|
||||||
|
|
||||||
#split lines on semicolons and remove things that are obviously not what we are looking for
|
# split lines on semicolons and remove things that are obviously not what we are looking for
|
||||||
src_lines = source.split(/\s*;\s*/).uniq
|
src_lines = source.split(/\s*;\s*/)
|
||||||
src_lines.delete_if {|line| line.strip.length == 0} # remove blank lines
|
src_lines = src_lines.uniq unless cpp # must retain closing braces for class/namespace
|
||||||
src_lines.delete_if {|line| !(line =~ /[\w\s\*]+\(+\s*\*[\*\s]*[\w\s]+(?:\[[\w\s]*\]\s*)+\)+\s*\((?:[\w\s\*]*,?)*\s*\)/).nil?} #remove function pointer arrays
|
src_lines.delete_if { |line| line.strip.empty? } # remove blank lines
|
||||||
if (@treat_externs == :include)
|
src_lines.delete_if { |line| !(line =~ /[\w\s\*]+\(+\s*\*[\*\s]*[\w\s]+(?:\[[\w\s]*\]\s*)+\)+\s*\((?:[\w\s\*]*,?)*\s*\)/).nil? } # remove function pointer arrays
|
||||||
src_lines.delete_if {|line| !(line =~ /(?:^|\s+)(?:inline)\s+/).nil?} # remove inline functions
|
|
||||||
else
|
unless @treat_externs == :include
|
||||||
src_lines.delete_if {|line| !(line =~ /(?:^|\s+)(?:extern|inline)\s+/).nil?} # remove inline and extern functions
|
src_lines.delete_if { |line| !(line =~ /(?:^|\s+)(?:extern)\s+/).nil? } # remove extern functions
|
||||||
end
|
end
|
||||||
src_lines.delete_if {|line| line.empty? } #drop empty lines
|
|
||||||
|
unless @treat_inlines == :include
|
||||||
|
src_lines.delete_if { |line| !(line =~ /(?:^|\s+)(?:inline)\s+/).nil? } # remove inline functions
|
||||||
|
end
|
||||||
|
|
||||||
|
src_lines.delete_if(&:empty?) # drop empty lines
|
||||||
|
end
|
||||||
|
|
||||||
|
# Rudimentary C++ parser - does not handle all situations - e.g.:
|
||||||
|
# * A namespace function appears after a class with private members (should be parsed)
|
||||||
|
# * Anonymous namespace (shouldn't parse anything - no matter how nested - within it)
|
||||||
|
# * A class nested within another class
|
||||||
|
def parse_cpp_functions(source)
|
||||||
|
funcs = []
|
||||||
|
|
||||||
|
ns = []
|
||||||
|
pub = false
|
||||||
|
source.each do |line|
|
||||||
|
# Search for namespace, class, opening and closing braces
|
||||||
|
line.scan(/(?:(?:\b(?:namespace|class)\s+(?:\S+)\s*)?{)|}/).each do |item|
|
||||||
|
if item == '}'
|
||||||
|
ns.pop
|
||||||
|
else
|
||||||
|
token = item.strip.sub(/\s+/, ' ')
|
||||||
|
ns << token
|
||||||
|
|
||||||
|
pub = false if token.start_with? 'class'
|
||||||
|
pub = true if token.start_with? 'namespace'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
pub = true if line =~ /public:/
|
||||||
|
pub = false if line =~ /private:/ || line =~ /protected:/
|
||||||
|
|
||||||
|
# ignore non-public and non-static
|
||||||
|
next unless pub
|
||||||
|
next unless line =~ /\bstatic\b/
|
||||||
|
|
||||||
|
line.sub!(/^.*static/, '')
|
||||||
|
next unless line =~ @declaration_parse_matcher
|
||||||
|
|
||||||
|
tmp = ns.reject { |item| item == '{' }
|
||||||
|
|
||||||
|
# Identify class name, if any
|
||||||
|
cls = nil
|
||||||
|
if tmp[-1].start_with? 'class '
|
||||||
|
cls = tmp.pop.sub(/class (\S+) {/, '\1')
|
||||||
|
end
|
||||||
|
|
||||||
|
# Assemble list of namespaces
|
||||||
|
tmp.each { |item| item.sub!(/(?:namespace|class) (\S+) {/, '\1') }
|
||||||
|
|
||||||
|
funcs << [line.strip.gsub(/\s+/, ' '), tmp, cls]
|
||||||
|
end
|
||||||
|
funcs
|
||||||
end
|
end
|
||||||
|
|
||||||
def parse_functions(source)
|
def parse_functions(source)
|
||||||
funcs = []
|
funcs = []
|
||||||
source.each {|line| funcs << line.strip.gsub(/\s+/, ' ') if (line =~ @declaration_parse_matcher)}
|
source.each { |line| funcs << line.strip.gsub(/\s+/, ' ') if line =~ @declaration_parse_matcher }
|
||||||
if funcs.empty?
|
if funcs.empty?
|
||||||
case @when_no_prototypes
|
case @when_no_prototypes
|
||||||
when :error
|
when :error
|
||||||
raise "ERROR: No function prototypes found!"
|
raise 'ERROR: No function prototypes found!'
|
||||||
when :warn
|
when :warn
|
||||||
puts "WARNING: No function prototypes found!" unless (@verbosity < 1)
|
puts 'WARNING: No function prototypes found!' unless @verbosity < 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return funcs
|
funcs
|
||||||
end
|
end
|
||||||
|
|
||||||
def parse_type_and_name(arg)
|
def parse_type_and_name(arg)
|
||||||
@ -151,8 +376,8 @@ class CMockHeaderParser
|
|||||||
# to remove 'const' only when it applies to the pointer itself, not when it
|
# to remove 'const' only when it applies to the pointer itself, not when it
|
||||||
# applies to the type pointed to. For non-pointer types, remove any
|
# applies to the type pointed to. For non-pointer types, remove any
|
||||||
# occurrence of 'const'.
|
# occurrence of 'const'.
|
||||||
arg.gsub!(/(\w)\*/,'\1 *') # pull asterisks away from preceding word
|
arg.gsub!(/(\w)\*/, '\1 *') # pull asterisks away from preceding word
|
||||||
arg.gsub!(/\*(\w)/,'* \1') # pull asterisks away from following word
|
arg.gsub!(/\*(\w)/, '* \1') # pull asterisks away from following word
|
||||||
arg_array = arg.split
|
arg_array = arg.split
|
||||||
arg_info = divine_ptr_and_const(arg)
|
arg_info = divine_ptr_and_const(arg)
|
||||||
arg_info[:name] = arg_array[-1]
|
arg_info[:name] = arg_array[-1]
|
||||||
@ -177,15 +402,15 @@ class CMockHeaderParser
|
|||||||
end
|
end
|
||||||
|
|
||||||
arg_info[:modifier] = attr_array.join(' ')
|
arg_info[:modifier] = attr_array.join(' ')
|
||||||
arg_info[:type] = type_array.join(' ').gsub(/\s+\*/,'*') # remove space before asterisks
|
arg_info[:type] = type_array.join(' ').gsub(/\s+\*/, '*') # remove space before asterisks
|
||||||
return arg_info
|
arg_info
|
||||||
end
|
end
|
||||||
|
|
||||||
def parse_args(arg_list)
|
def parse_args(arg_list)
|
||||||
args = []
|
args = []
|
||||||
arg_list.split(',').each do |arg|
|
arg_list.split(',').each do |arg|
|
||||||
arg.strip!
|
arg.strip!
|
||||||
return args if (arg =~ /^\s*((\.\.\.)|(void))\s*$/) # we're done if we reach void by itself or ...
|
return args if arg =~ /^\s*((\.\.\.)|(void))\s*$/ # we're done if we reach void by itself or ...
|
||||||
|
|
||||||
arg_info = parse_type_and_name(arg)
|
arg_info = parse_type_and_name(arg)
|
||||||
arg_info.delete(:modifier) # don't care about this
|
arg_info.delete(:modifier) # don't care about this
|
||||||
@ -193,7 +418,7 @@ class CMockHeaderParser
|
|||||||
|
|
||||||
# in C, array arguments implicitly degrade to pointers
|
# in C, array arguments implicitly degrade to pointers
|
||||||
# make the translation explicit here to simplify later logic
|
# make the translation explicit here to simplify later logic
|
||||||
if @treat_as_array[arg_info[:type]] and not arg_info[:ptr?] then
|
if @treat_as_array[arg_info[:type]] && !(arg_info[:ptr?])
|
||||||
arg_info[:type] = "#{@treat_as_array[arg_info[:type]]}*"
|
arg_info[:type] = "#{@treat_as_array[arg_info[:type]]}*"
|
||||||
arg_info[:type] = "const #{arg_info[:type]}" if arg_info[:const?]
|
arg_info[:type] = "const #{arg_info[:type]}" if arg_info[:const?]
|
||||||
arg_info[:ptr?] = true
|
arg_info[:ptr?] = true
|
||||||
@ -203,31 +428,35 @@ class CMockHeaderParser
|
|||||||
end
|
end
|
||||||
|
|
||||||
# Try to find array pair in parameters following this pattern : <type> * <name>, <@array_size_type> <@array_size_name>
|
# Try to find array pair in parameters following this pattern : <type> * <name>, <@array_size_type> <@array_size_name>
|
||||||
args.each_with_index {|val, index|
|
args.each_with_index do |val, index|
|
||||||
next_index = index + 1
|
next_index = index + 1
|
||||||
if (args.length > next_index)
|
next unless args.length > next_index
|
||||||
if (val[:ptr?] == true and args[next_index][:name].match(@array_size_name) and @array_size_type.include?(args[next_index][:type]))
|
|
||||||
val[:array_data?] = true
|
|
||||||
args[next_index][:array_size?] = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
}
|
|
||||||
|
|
||||||
return args
|
if (val[:ptr?] == true) && args[next_index][:name].match(@array_size_name) && @array_size_type.include?(args[next_index][:type])
|
||||||
|
val[:array_data?] = true
|
||||||
|
args[next_index][:array_size?] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
args
|
||||||
end
|
end
|
||||||
|
|
||||||
def divine_ptr(arg)
|
def divine_ptr(arg)
|
||||||
return false unless arg.include? '*'
|
return false unless arg.include? '*'
|
||||||
# treat "const char *" and similar as a string, not a pointer
|
# treat "const char *" and similar as a string, not a pointer
|
||||||
return false if /(^|\s)(const\s+)?char(\s+const)?\s*\*(?!.*\*)/ =~ arg
|
return false if /(^|\s)(const\s+)?char(\s+const)?\s*\*(?!.*\*)/ =~ arg
|
||||||
return true
|
|
||||||
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
def divine_const(arg)
|
def divine_const(arg)
|
||||||
# a non-pointer arg containing "const" is a constant
|
# a non-pointer arg containing "const" is a constant
|
||||||
# an arg containing "const" before the last * is a pointer to a constant
|
# an arg containing "const" before the last * is a pointer to a constant
|
||||||
return ( arg.include?('*') ? (/(^|\s|\*)const(\s(\w|\s)*)?\*(?!.*\*)/ =~ arg)
|
if arg.include?('*') ? (/(^|\s|\*)const(\s(\w|\s)*)?\*(?!.*\*)/ =~ arg) : (/(^|\s)const(\s|$)/ =~ arg)
|
||||||
: (/(^|\s)const(\s|$)/ =~ arg) ) ? true : false
|
true
|
||||||
|
else
|
||||||
|
false
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def divine_ptr_and_const(arg)
|
def divine_ptr_and_const(arg)
|
||||||
@ -237,128 +466,158 @@ class CMockHeaderParser
|
|||||||
divination[:const?] = divine_const(arg)
|
divination[:const?] = divine_const(arg)
|
||||||
|
|
||||||
# an arg containing "const" after the last * is a constant pointer
|
# an arg containing "const" after the last * is a constant pointer
|
||||||
divination[:const_ptr?] = (/\*(?!.*\*)\s*const(\s|$)/ =~ arg) ? true : false
|
divination[:const_ptr?] = /\*(?!.*\*)\s*const(\s|$)/ =~ arg ? true : false
|
||||||
|
|
||||||
return divination
|
divination
|
||||||
end
|
end
|
||||||
|
|
||||||
def clean_args(arg_list)
|
def clean_args(arg_list, parse_project)
|
||||||
if ((@local_as_void.include?(arg_list.strip)) or (arg_list.empty?))
|
if @local_as_void.include?(arg_list.strip) || arg_list.empty?
|
||||||
return 'void'
|
'void'
|
||||||
else
|
else
|
||||||
c=0
|
c = 0
|
||||||
arg_list.gsub!(/(\w+)(?:\s*\[\s*\(*[\s\w+-]*\)*\s*\])+/,'*\1') # magically turn brackets into asterisks, also match for parentheses that come from macros
|
# magically turn brackets into asterisks, also match for parentheses that come from macros
|
||||||
arg_list.gsub!(/\s+\*/,'*') # remove space to place asterisks with type (where they belong)
|
arg_list.gsub!(/(\w+)(?:\s*\[[^\[\]]*\])+/, '*\1')
|
||||||
arg_list.gsub!(/\*(\w)/,'* \1') # pull asterisks away from arg to place asterisks with type (where they belong)
|
# remove space to place asterisks with type (where they belong)
|
||||||
|
arg_list.gsub!(/\s+\*/, '*')
|
||||||
|
# pull asterisks away from arg to place asterisks with type (where they belong)
|
||||||
|
arg_list.gsub!(/\*(\w)/, '* \1')
|
||||||
|
|
||||||
#scan argument list for function pointers and replace them with custom types
|
# 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|
|
arg_list.gsub!(/([\w\s\*]+)\(+\s*\*[\*\s]*([\w\s]*)\s*\)+\s*\(((?:[\w\s\*]*,?)*)\s*\)*/) do |_m|
|
||||||
|
functype = "cmock_#{parse_project[:module_name]}_func_ptr#{parse_project[:typedefs].size + 1}"
|
||||||
functype = "cmock_#{@module_name}_func_ptr#{@typedefs.size + 1}"
|
funcret = Regexp.last_match(1).strip
|
||||||
funcret = $1.strip
|
funcname = Regexp.last_match(2).strip
|
||||||
funcname = $2.strip
|
funcargs = Regexp.last_match(3).strip
|
||||||
funcargs = $3.strip
|
|
||||||
funconst = ''
|
funconst = ''
|
||||||
if (funcname.include? 'const')
|
if funcname.include? 'const'
|
||||||
funcname.gsub!('const','').strip!
|
funcname.gsub!('const', '').strip!
|
||||||
funconst = 'const '
|
funconst = 'const '
|
||||||
end
|
end
|
||||||
@typedefs << "typedef #{funcret}(*#{functype})(#{funcargs});"
|
parse_project[:typedefs] << "typedef #{funcret}(*#{functype})(#{funcargs});"
|
||||||
funcname = "cmock_arg#{c+=1}" if (funcname.empty?)
|
funcname = "cmock_arg#{c += 1}" if funcname.empty?
|
||||||
"#{functype} #{funconst}#{funcname}"
|
"#{functype} #{funconst}#{funcname}"
|
||||||
end
|
end
|
||||||
|
|
||||||
#automatically name unnamed arguments (those that only had a type)
|
# scan argument list for function pointers with shorthand notation and replace them with custom types
|
||||||
arg_list.split(/\s*,\s*/).map { |arg|
|
arg_list.gsub!(/([\w\s\*]+)+\s+(\w+)\s*\(((?:[\w\s\*]*,?)*)\s*\)*/) do |_m|
|
||||||
|
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
|
||||||
|
funconst = ''
|
||||||
|
if funcname.include? 'const'
|
||||||
|
funcname.gsub!('const', '').strip!
|
||||||
|
funconst = 'const '
|
||||||
|
end
|
||||||
|
parse_project[:typedefs] << "typedef #{funcret}(*#{functype})(#{funcargs});"
|
||||||
|
funcname = "cmock_arg#{c += 1}" if funcname.empty?
|
||||||
|
"#{functype} #{funconst}#{funcname}"
|
||||||
|
end
|
||||||
|
|
||||||
|
# automatically name unnamed arguments (those that only had a type)
|
||||||
|
arg_list.split(/\s*,\s*/).map do |arg|
|
||||||
parts = (arg.split - ['struct', 'union', 'enum', 'const', 'const*'])
|
parts = (arg.split - ['struct', 'union', 'enum', 'const', 'const*'])
|
||||||
if ((parts.size < 2) or (parts[-1][-1].chr == '*') or (@standards.include?(parts[-1])))
|
if (parts.size < 2) || (parts[-1][-1].chr == '*') || @standards.include?(parts[-1])
|
||||||
"#{arg} cmock_arg#{c+=1}"
|
"#{arg} cmock_arg#{c += 1}"
|
||||||
else
|
else
|
||||||
arg
|
arg
|
||||||
end
|
end
|
||||||
}.join(', ')
|
end.join(', ')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def parse_declaration(declaration)
|
def parse_declaration(parse_project, declaration, namespace = [], classname = nil)
|
||||||
decl = {}
|
decl = {}
|
||||||
|
decl[:namespace] = namespace
|
||||||
|
decl[:class] = classname
|
||||||
|
|
||||||
regex_match = @declaration_parse_matcher.match(declaration)
|
regex_match = @declaration_parse_matcher.match(declaration)
|
||||||
raise "Failed parsing function declaration: '#{declaration}'" if regex_match.nil?
|
raise "Failed parsing function declaration: '#{declaration}'" if regex_match.nil?
|
||||||
|
|
||||||
#grab argument list
|
# grab argument list
|
||||||
args = regex_match[2].strip
|
args = regex_match[2].strip
|
||||||
|
|
||||||
#process function attributes, return type, and name
|
# process function attributes, return type, and name
|
||||||
parsed = parse_type_and_name(regex_match[1])
|
parsed = parse_type_and_name(regex_match[1])
|
||||||
|
|
||||||
decl[:name] = parsed[:name]
|
# Record original name without scope prefix
|
||||||
|
decl[:unscoped_name] = parsed[:name]
|
||||||
|
|
||||||
|
# Prefix name with namespace scope (if any) and then class
|
||||||
|
decl[:name] = namespace.join('_')
|
||||||
|
unless classname.nil?
|
||||||
|
decl[:name] << '_' unless decl[:name].empty?
|
||||||
|
decl[:name] << classname
|
||||||
|
end
|
||||||
|
# Add original name to complete fully scoped name
|
||||||
|
decl[:name] << '_' unless decl[:name].empty?
|
||||||
|
decl[:name] << decl[:unscoped_name]
|
||||||
|
|
||||||
decl[:modifier] = parsed[:modifier]
|
decl[:modifier] = parsed[:modifier]
|
||||||
unless parsed[:c_calling_convention].nil?
|
unless parsed[:c_calling_convention].nil?
|
||||||
decl[:c_calling_convention] = parsed[:c_calling_convention]
|
decl[:c_calling_convention] = parsed[:c_calling_convention]
|
||||||
end
|
end
|
||||||
|
|
||||||
rettype = parsed[:type]
|
rettype = parsed[:type]
|
||||||
rettype = 'void' if (@local_as_void.include?(rettype.strip))
|
rettype = 'void' if @local_as_void.include?(rettype.strip)
|
||||||
decl[:return] = { :type => rettype,
|
decl[:return] = { :type => rettype,
|
||||||
:name => 'cmock_to_return',
|
:name => 'cmock_to_return',
|
||||||
:str => "#{rettype} cmock_to_return",
|
:str => "#{rettype} cmock_to_return",
|
||||||
:void? => (rettype == 'void'),
|
:void? => (rettype == 'void'),
|
||||||
:ptr? => parsed[:ptr?],
|
:ptr? => parsed[:ptr?] || false,
|
||||||
:const? => parsed[:const?],
|
:const? => parsed[:const?] || false,
|
||||||
:const_ptr? => parsed[:const_ptr?]
|
:const_ptr? => parsed[:const_ptr?] || false }
|
||||||
}
|
|
||||||
|
|
||||||
#remove default argument statements from mock definitions
|
# remove default argument statements from mock definitions
|
||||||
args.gsub!(/=\s*[a-zA-Z0-9_\.]+\s*/, ' ')
|
args.gsub!(/=\s*[a-zA-Z0-9_\.]+\s*/, ' ')
|
||||||
|
|
||||||
#check for var args
|
# check for var args
|
||||||
if (args =~ /\.\.\./)
|
if args =~ /\.\.\./
|
||||||
decl[:var_arg] = args.match( /[\w\s]*\.\.\./ ).to_s.strip
|
decl[:var_arg] = args.match(/[\w\s]*\.\.\./).to_s.strip
|
||||||
if (args =~ /\,[\w\s]*\.\.\./)
|
args = if args =~ /\,[\w\s]*\.\.\./
|
||||||
args = args.gsub!(/\,[\w\s]*\.\.\./,'')
|
args.gsub!(/\,[\w\s]*\.\.\./, '')
|
||||||
else
|
else
|
||||||
args = 'void'
|
'void'
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
decl[:var_arg] = nil
|
decl[:var_arg] = nil
|
||||||
end
|
end
|
||||||
args = clean_args(args)
|
args = clean_args(args, parse_project)
|
||||||
decl[:args_string] = args
|
decl[:args_string] = args
|
||||||
decl[:args] = parse_args(args)
|
decl[:args] = parse_args(args)
|
||||||
decl[:args_call] = decl[:args].map{|a| a[:name]}.join(', ')
|
decl[:args_call] = decl[:args].map { |a| a[:name] }.join(', ')
|
||||||
decl[:contains_ptr?] = decl[:args].inject(false) {|ptr, arg| arg[:ptr?] ? true : ptr }
|
decl[:contains_ptr?] = decl[:args].inject(false) { |ptr, arg| arg[:ptr?] ? true : ptr }
|
||||||
|
|
||||||
if (decl[:return][:type].nil? or decl[:name].nil? or decl[:args].nil? or
|
if decl[:return][:type].nil? || decl[:name].nil? || decl[:args].nil? ||
|
||||||
decl[:return][:type].empty? or decl[:name].empty?)
|
decl[:return][:type].empty? || decl[:name].empty?
|
||||||
raise "Failed Parsing Declaration Prototype!\n" +
|
raise "Failed Parsing Declaration Prototype!\n" \
|
||||||
" declaration: '#{declaration}'\n" +
|
" declaration: '#{declaration}'\n" \
|
||||||
" modifier: '#{decl[:modifier]}'\n" +
|
" modifier: '#{decl[:modifier]}'\n" \
|
||||||
" return: #{prototype_inspect_hash(decl[:return])}\n" +
|
" return: #{prototype_inspect_hash(decl[:return])}\n" \
|
||||||
" function: '#{decl[:name]}'\n" +
|
" function: '#{decl[:name]}'\n" \
|
||||||
" args: #{prototype_inspect_array_of_hashes(decl[:args])}\n"
|
" args: #{prototype_inspect_array_of_hashes(decl[:args])}\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
return decl
|
decl
|
||||||
end
|
end
|
||||||
|
|
||||||
def prototype_inspect_hash(hash)
|
def prototype_inspect_hash(hash)
|
||||||
pairs = []
|
pairs = []
|
||||||
hash.each_pair { |name, value| pairs << ":#{name} => #{"'" if (value.class == String)}#{value}#{"'" if (value.class == String)}" }
|
hash.each_pair { |name, value| pairs << ":#{name} => #{"'" if value.class == String}#{value}#{"'" if value.class == String}" }
|
||||||
return "{#{pairs.join(', ')}}"
|
"{#{pairs.join(', ')}}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def prototype_inspect_array_of_hashes(array)
|
def prototype_inspect_array_of_hashes(array)
|
||||||
hashes = []
|
hashes = []
|
||||||
array.each { |hash| hashes << prototype_inspect_hash(hash) }
|
array.each { |hash| hashes << prototype_inspect_hash(hash) }
|
||||||
case (array.size)
|
case array.size
|
||||||
when 0
|
when 0
|
||||||
return "[]"
|
return '[]'
|
||||||
when 1
|
when 1
|
||||||
return "[#{hashes[0]}]"
|
return "[#{hashes[0]}]"
|
||||||
else
|
else
|
||||||
return "[\n #{hashes.join("\n ")}\n ]\n"
|
return "[\n #{hashes.join("\n ")}\n ]\n"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -4,10 +4,7 @@
|
|||||||
# [Released under MIT License. Please refer to license.txt for details]
|
# [Released under MIT License. Please refer to license.txt for details]
|
||||||
# ==========================================
|
# ==========================================
|
||||||
|
|
||||||
require 'thread'
|
|
||||||
|
|
||||||
class CMockPluginManager
|
class CMockPluginManager
|
||||||
|
|
||||||
attr_accessor :plugins
|
attr_accessor :plugins
|
||||||
|
|
||||||
def initialize(config, utils)
|
def initialize(config, utils)
|
||||||
@ -15,41 +12,39 @@ class CMockPluginManager
|
|||||||
plugins_to_load = [:expect, config.plugins].flatten.uniq.compact
|
plugins_to_load = [:expect, config.plugins].flatten.uniq.compact
|
||||||
plugins_to_load.each do |plugin|
|
plugins_to_load.each do |plugin|
|
||||||
plugin_name = plugin.to_s
|
plugin_name = plugin.to_s
|
||||||
object_name = "CMockGeneratorPlugin" + camelize(plugin_name)
|
object_name = 'CMockGeneratorPlugin' + camelize(plugin_name)
|
||||||
self.class.plugin_require_mutex.synchronize { load_plugin(plugin_name, object_name, config, utils) }
|
self.class.mutex.synchronize { load_plugin(plugin_name, object_name, config, utils) }
|
||||||
end
|
end
|
||||||
@plugins.sort! {|a,b| a.priority <=> b.priority }
|
@plugins.sort! { |a, b| a.priority <=> b.priority }
|
||||||
end
|
end
|
||||||
|
|
||||||
def run(method, args=nil)
|
def run(method, args = nil)
|
||||||
if args.nil?
|
if args.nil?
|
||||||
return @plugins.collect{ |plugin| plugin.send(method) if plugin.respond_to?(method) }.flatten.join
|
@plugins.collect { |plugin| plugin.send(method) if plugin.respond_to?(method) }.flatten.join
|
||||||
else
|
else
|
||||||
return @plugins.collect{ |plugin| plugin.send(method, args) if plugin.respond_to?(method) }.flatten.join
|
@plugins.collect { |plugin| plugin.send(method, args) if plugin.respond_to?(method) }.flatten.join
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def camelize(lower_case_and_underscored_word)
|
def camelize(lower_case_and_underscored_word)
|
||||||
lower_case_and_underscored_word.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
|
lower_case_and_underscored_word.gsub(/\/(.?)/) { '::' + Regexp.last_match(1).upcase }.gsub(/(^|_)(.)/) { Regexp.last_match(2).upcase }
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
def self.mutex
|
||||||
|
|
||||||
def self.plugin_require_mutex
|
|
||||||
@mutex ||= Mutex.new
|
@mutex ||= Mutex.new
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
def load_plugin(plugin_name, object_name, config, utils)
|
def load_plugin(plugin_name, object_name, config, utils)
|
||||||
begin
|
unless Object.const_defined? object_name
|
||||||
unless (Object.const_defined? object_name)
|
file_name = "#{__dir__}/cmock_generator_plugin_#{plugin_name.downcase}.rb"
|
||||||
file_name = "#{File.expand_path(File.dirname(__FILE__))}/cmock_generator_plugin_#{plugin_name.downcase}.rb"
|
require file_name
|
||||||
require file_name
|
|
||||||
end
|
|
||||||
class_name = Object.const_get(object_name)
|
|
||||||
@plugins << class_name.new(config, utils)
|
|
||||||
rescue
|
|
||||||
file_name = "#{File.expand_path(File.dirname(__FILE__))}/cmock_generator_plugin_#{plugin_name.downcase}.rb"
|
|
||||||
raise "ERROR: CMock unable to load plugin '#{plugin_name}' '#{object_name}' #{file_name}"
|
|
||||||
end
|
end
|
||||||
|
class_name = Object.const_get(object_name)
|
||||||
|
@plugins << class_name.new(config, utils)
|
||||||
|
rescue StandardError
|
||||||
|
file_name = "#{__dir__}/cmock_generator_plugin_#{plugin_name.downcase}.rb"
|
||||||
|
raise "ERROR: CMock unable to load plugin '#{plugin_name}' '#{object_name}' #{file_name}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -2,74 +2,76 @@
|
|||||||
# CMock Project - Automatic Mock Generation for C
|
# CMock Project - Automatic Mock Generation for C
|
||||||
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
|
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
|
||||||
# [Released under MIT License. Please refer to license.txt for details]
|
# [Released under MIT License. Please refer to license.txt for details]
|
||||||
# ==========================================
|
# ==========================================
|
||||||
|
|
||||||
class CMockUnityHelperParser
|
class CMockUnityHelperParser
|
||||||
|
|
||||||
attr_accessor :c_types
|
attr_accessor :c_types
|
||||||
|
|
||||||
def initialize(config)
|
def initialize(config)
|
||||||
@config = config
|
@config = config
|
||||||
@fallback = @config.plugins.include?(:array) ? 'UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY' : 'UNITY_TEST_ASSERT_EQUAL_MEMORY'
|
@fallback = @config.plugins.include?(:array) ? 'UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY' : 'UNITY_TEST_ASSERT_EQUAL_MEMORY'
|
||||||
@c_types = map_C_types.merge(import_source)
|
@c_types = map_c_types.merge(import_source)
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_helper(ctype)
|
def get_helper(ctype)
|
||||||
lookup = ctype.gsub(/(?:^|(\S?)(\s*)|(\W))const(?:$|(\s*)(\S)|(\W))/,'\1\3\5\6').strip.gsub(/\s+/,'_')
|
lookup = ctype.gsub(/(?:^|(\S?)(\s*)|(\W))const(?:$|(\s*)(\S)|(\W))/, '\1\3\5\6').strip.gsub(/\s+/, '_')
|
||||||
return [@c_types[lookup], ''] if (@c_types[lookup])
|
return [@c_types[lookup], ''] if @c_types[lookup]
|
||||||
if (lookup =~ /\*$/)
|
|
||||||
lookup = lookup.gsub(/\*$/,'')
|
if lookup =~ /\*$/
|
||||||
return [@c_types[lookup], '*'] if (@c_types[lookup])
|
lookup = lookup.gsub(/\*$/, '')
|
||||||
|
return [@c_types[lookup], '*'] if @c_types[lookup]
|
||||||
else
|
else
|
||||||
lookup = lookup + '*'
|
lookup += '*'
|
||||||
return [@c_types[lookup], '&'] if (@c_types[lookup])
|
return [@c_types[lookup], '&'] if @c_types[lookup]
|
||||||
end
|
end
|
||||||
return ['UNITY_TEST_ASSERT_EQUAL_PTR', ''] if (ctype =~ /cmock_\w+_ptr\d+/)
|
return ['UNITY_TEST_ASSERT_EQUAL_PTR', ''] if ctype =~ /cmock_\w+_ptr\d+/
|
||||||
raise("Don't know how to test #{ctype} and memory tests are disabled!") unless @config.memcmp_if_unknown
|
raise("Don't know how to test #{ctype} and memory tests are disabled!") unless @config.memcmp_if_unknown
|
||||||
return (lookup =~ /\*$/) ? [@fallback, '&'] : [@fallback, '']
|
|
||||||
|
lookup =~ /\*$/ ? [@fallback, '&'] : [@fallback, '']
|
||||||
end
|
end
|
||||||
|
|
||||||
private ###########################
|
private ###########################
|
||||||
|
|
||||||
def map_C_types
|
def map_c_types
|
||||||
c_types = {}
|
c_types = {}
|
||||||
@config.treat_as.each_pair do |ctype, expecttype|
|
@config.treat_as.each_pair do |ctype, expecttype|
|
||||||
c_type = ctype.gsub(/\s+/,'_')
|
c_type = ctype.gsub(/\s+/, '_')
|
||||||
if (expecttype =~ /\*/)
|
if expecttype =~ /\*/
|
||||||
c_types[c_type] = "UNITY_TEST_ASSERT_EQUAL_#{expecttype.gsub(/\*/,'')}_ARRAY"
|
c_types[c_type] = "UNITY_TEST_ASSERT_EQUAL_#{expecttype.delete('*')}_ARRAY"
|
||||||
else
|
else
|
||||||
c_types[c_type] = "UNITY_TEST_ASSERT_EQUAL_#{expecttype}"
|
c_types[c_type] = "UNITY_TEST_ASSERT_EQUAL_#{expecttype}"
|
||||||
c_types[c_type+'*'] ||= "UNITY_TEST_ASSERT_EQUAL_#{expecttype}_ARRAY"
|
c_types[c_type + '*'] ||= "UNITY_TEST_ASSERT_EQUAL_#{expecttype}_ARRAY"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
c_types
|
c_types
|
||||||
end
|
end
|
||||||
|
|
||||||
def import_source
|
def import_source
|
||||||
source = @config.load_unity_helper
|
source = @config.load_unity_helper
|
||||||
return {} if source.nil?
|
return {} if source.nil?
|
||||||
|
|
||||||
c_types = {}
|
c_types = {}
|
||||||
source = source.gsub(/\/\/.*$/, '') #remove line comments
|
source = source.gsub(/\/\/.*$/, '') # remove line comments
|
||||||
source = source.gsub(/\/\*.*?\*\//m, '') #remove block comments
|
source = source.gsub(/\/\*.*?\*\//m, '') # remove block comments
|
||||||
|
|
||||||
#scan for comparison helpers
|
# scan for comparison helpers
|
||||||
match_regex = Regexp.new('^\s*#define\s+(UNITY_TEST_ASSERT_EQUAL_(\w+))\s*\(' + Array.new(4,'\s*\w+\s*').join(',') + '\)')
|
match_regex = Regexp.new('^\s*#define\s+(UNITY_TEST_ASSERT_EQUAL_(\w+))\s*\(' + Array.new(4, '\s*\w+\s*').join(',') + '\)')
|
||||||
pairs = source.scan(match_regex).flatten.compact
|
pairs = source.scan(match_regex).flatten.compact
|
||||||
(pairs.size/2).times do |i|
|
(pairs.size / 2).times do |i|
|
||||||
expect = pairs[i*2]
|
expect = pairs[i * 2]
|
||||||
ctype = pairs[(i*2)+1]
|
ctype = pairs[(i * 2) + 1]
|
||||||
c_types[ctype] = expect unless expect.include?("_ARRAY")
|
c_types[ctype] = expect unless expect.include?('_ARRAY')
|
||||||
end
|
end
|
||||||
|
|
||||||
#scan for array variants of those helpers
|
# scan for array variants of those helpers
|
||||||
match_regex = Regexp.new('^\s*#define\s+(UNITY_TEST_ASSERT_EQUAL_(\w+_ARRAY))\s*\(' + Array.new(5,'\s*\w+\s*').join(',') + '\)')
|
match_regex = Regexp.new('^\s*#define\s+(UNITY_TEST_ASSERT_EQUAL_(\w+_ARRAY))\s*\(' + Array.new(5, '\s*\w+\s*').join(',') + '\)')
|
||||||
pairs = source.scan(match_regex).flatten.compact
|
pairs = source.scan(match_regex).flatten.compact
|
||||||
(pairs.size/2).times do |i|
|
(pairs.size / 2).times do |i|
|
||||||
expect = pairs[i*2]
|
expect = pairs[i * 2]
|
||||||
ctype = pairs[(i*2)+1]
|
ctype = pairs[(i * 2) + 1]
|
||||||
c_types[ctype.gsub('_ARRAY','*')] = expect
|
c_types[ctype.gsub('_ARRAY', '*')] = expect
|
||||||
end
|
end
|
||||||
|
|
||||||
c_types
|
c_types
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
217
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
|||||||
2.4.6
|
|
||||||
|
|
90
test/vendor/ceedling/vendor/cmock/src/cmock.c
vendored
90
test/vendor/ceedling/vendor/cmock/src/cmock.c
vendored
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
#include "cmock.h"
|
#include "cmock.h"
|
||||||
|
|
||||||
//public constants to be used by mocks
|
/* public constants to be used by mocks */
|
||||||
const char* CMockStringOutOfMemory = "CMock has run out of memory. Please allocate more.";
|
const char* CMockStringOutOfMemory = "CMock has run out of memory. Please allocate more.";
|
||||||
const char* CMockStringCalledMore = "Called more times than expected.";
|
const char* CMockStringCalledMore = "Called more times than expected.";
|
||||||
const char* CMockStringCalledLess = "Called fewer times than expected.";
|
const char* CMockStringCalledLess = "Called fewer times than expected.";
|
||||||
@ -19,7 +19,7 @@ const char* CMockStringPtrIsNULL = "Pointer is NULL.";
|
|||||||
const char* CMockStringExpNULL = "Expected NULL.";
|
const char* CMockStringExpNULL = "Expected NULL.";
|
||||||
const char* CMockStringMismatch = "Function called with unexpected argument value.";
|
const char* CMockStringMismatch = "Function called with unexpected argument value.";
|
||||||
|
|
||||||
//private variables
|
/* private variables */
|
||||||
#ifdef CMOCK_MEM_DYNAMIC
|
#ifdef CMOCK_MEM_DYNAMIC
|
||||||
static unsigned char* CMock_Guts_Buffer = NULL;
|
static unsigned char* CMock_Guts_Buffer = NULL;
|
||||||
static CMOCK_MEM_INDEX_TYPE CMock_Guts_BufferSize = CMOCK_MEM_ALIGN_SIZE;
|
static CMOCK_MEM_INDEX_TYPE CMock_Guts_BufferSize = CMOCK_MEM_ALIGN_SIZE;
|
||||||
@ -30,37 +30,37 @@ static CMOCK_MEM_INDEX_TYPE CMock_Guts_BufferSize = CMOCK_MEM_SIZE + CMOCK_MEM
|
|||||||
static CMOCK_MEM_INDEX_TYPE CMock_Guts_FreePtr = CMOCK_MEM_ALIGN_SIZE;
|
static CMOCK_MEM_INDEX_TYPE CMock_Guts_FreePtr = CMOCK_MEM_ALIGN_SIZE;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//-------------------------------------------------------
|
/*-------------------------------------------------------
|
||||||
// CMock_Guts_MemNew
|
* CMock_Guts_MemNew
|
||||||
//-------------------------------------------------------
|
*-------------------------------------------------------*/
|
||||||
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemNew(CMOCK_MEM_INDEX_TYPE size)
|
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemNew(CMOCK_MEM_INDEX_TYPE size)
|
||||||
{
|
{
|
||||||
CMOCK_MEM_INDEX_TYPE index;
|
CMOCK_MEM_INDEX_TYPE index;
|
||||||
|
|
||||||
//verify arguments valid (we must be allocating space for at least 1 byte, and the existing chain must be in memory somewhere)
|
/* verify arguments valid (we must be allocating space for at least 1 byte, and the existing chain must be in memory somewhere) */
|
||||||
if (size < 1)
|
if (size < 1)
|
||||||
return CMOCK_GUTS_NONE;
|
return CMOCK_GUTS_NONE;
|
||||||
|
|
||||||
//verify we have enough room
|
/* verify we have enough room */
|
||||||
size = size + CMOCK_MEM_INDEX_SIZE;
|
size = size + CMOCK_MEM_INDEX_SIZE;
|
||||||
if (size & CMOCK_MEM_ALIGN_MASK)
|
if (size & CMOCK_MEM_ALIGN_MASK)
|
||||||
size = (size + CMOCK_MEM_ALIGN_MASK) & ~CMOCK_MEM_ALIGN_MASK;
|
size = (size + CMOCK_MEM_ALIGN_MASK) & ~CMOCK_MEM_ALIGN_MASK;
|
||||||
if ((CMock_Guts_BufferSize - CMock_Guts_FreePtr) < size)
|
if ((CMock_Guts_BufferSize - CMock_Guts_FreePtr) < size)
|
||||||
{
|
{
|
||||||
#ifndef CMOCK_MEM_DYNAMIC
|
#ifndef CMOCK_MEM_DYNAMIC
|
||||||
return CMOCK_GUTS_NONE; // nothing we can do; our static buffer is out of memory
|
return CMOCK_GUTS_NONE; /* nothing we can do; our static buffer is out of memory */
|
||||||
#else
|
#else
|
||||||
// our dynamic buffer does not have enough room; request more via realloc()
|
/* our dynamic buffer does not have enough room; request more via realloc() */
|
||||||
CMOCK_MEM_INDEX_TYPE new_buffersize = CMock_Guts_BufferSize + CMOCK_MEM_SIZE + size;
|
CMOCK_MEM_INDEX_TYPE new_buffersize = CMock_Guts_BufferSize + CMOCK_MEM_SIZE + size;
|
||||||
unsigned char* new_buffer = realloc(CMock_Guts_Buffer, (size_t)new_buffersize);
|
unsigned char* new_buffer = realloc(CMock_Guts_Buffer, (size_t)new_buffersize);
|
||||||
if (new_buffer == NULL)
|
if (new_buffer == NULL)
|
||||||
return CMOCK_GUTS_NONE; // realloc() failed; out of memory
|
return CMOCK_GUTS_NONE; /* realloc() failed; out of memory */
|
||||||
CMock_Guts_Buffer = new_buffer;
|
CMock_Guts_Buffer = new_buffer;
|
||||||
CMock_Guts_BufferSize = new_buffersize;
|
CMock_Guts_BufferSize = new_buffersize;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
//determine where we're putting this new block, and init its pointer to be the end of the line
|
/* determine where we're putting this new block, and init its pointer to be the end of the line */
|
||||||
index = CMock_Guts_FreePtr + CMOCK_MEM_INDEX_SIZE;
|
index = CMock_Guts_FreePtr + CMOCK_MEM_INDEX_SIZE;
|
||||||
*(CMOCK_MEM_INDEX_TYPE*)(&CMock_Guts_Buffer[CMock_Guts_FreePtr]) = CMOCK_GUTS_NONE;
|
*(CMOCK_MEM_INDEX_TYPE*)(&CMock_Guts_Buffer[CMock_Guts_FreePtr]) = CMOCK_GUTS_NONE;
|
||||||
CMock_Guts_FreePtr += size;
|
CMock_Guts_FreePtr += size;
|
||||||
@ -68,9 +68,9 @@ CMOCK_MEM_INDEX_TYPE CMock_Guts_MemNew(CMOCK_MEM_INDEX_TYPE size)
|
|||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------
|
/*-------------------------------------------------------
|
||||||
// CMock_Guts_MemChain
|
* CMock_Guts_MemChain
|
||||||
//-------------------------------------------------------
|
*-------------------------------------------------------*/
|
||||||
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_MemChain(CMOCK_MEM_INDEX_TYPE root_index, CMOCK_MEM_INDEX_TYPE obj_index)
|
||||||
{
|
{
|
||||||
CMOCK_MEM_INDEX_TYPE index;
|
CMOCK_MEM_INDEX_TYPE index;
|
||||||
@ -80,12 +80,12 @@ CMOCK_MEM_INDEX_TYPE CMock_Guts_MemChain(CMOCK_MEM_INDEX_TYPE root_index, CMOCK_
|
|||||||
|
|
||||||
if (root_index == CMOCK_GUTS_NONE)
|
if (root_index == CMOCK_GUTS_NONE)
|
||||||
{
|
{
|
||||||
//if there is no root currently, we return this object as the root of the chain
|
/* if there is no root currently, we return this object as the root of the chain */
|
||||||
return obj_index;
|
return obj_index;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//reject illegal nodes
|
/* reject illegal nodes */
|
||||||
if ((root_index < CMOCK_MEM_ALIGN_SIZE) || (root_index >= CMock_Guts_FreePtr))
|
if ((root_index < CMOCK_MEM_ALIGN_SIZE) || (root_index >= CMock_Guts_FreePtr))
|
||||||
{
|
{
|
||||||
return CMOCK_GUTS_NONE;
|
return CMOCK_GUTS_NONE;
|
||||||
@ -98,7 +98,7 @@ CMOCK_MEM_INDEX_TYPE CMock_Guts_MemChain(CMOCK_MEM_INDEX_TYPE root_index, CMOCK_
|
|||||||
root = (void*)(&CMock_Guts_Buffer[root_index]);
|
root = (void*)(&CMock_Guts_Buffer[root_index]);
|
||||||
obj = (void*)(&CMock_Guts_Buffer[obj_index]);
|
obj = (void*)(&CMock_Guts_Buffer[obj_index]);
|
||||||
|
|
||||||
//find the end of the existing chain and add us
|
/* find the end of the existing chain and add us */
|
||||||
next = root;
|
next = root;
|
||||||
do {
|
do {
|
||||||
index = *(CMOCK_MEM_INDEX_TYPE*)((CMOCK_MEM_PTR_AS_INT)next - CMOCK_MEM_INDEX_SIZE);
|
index = *(CMOCK_MEM_INDEX_TYPE*)((CMOCK_MEM_PTR_AS_INT)next - CMOCK_MEM_INDEX_SIZE);
|
||||||
@ -112,21 +112,21 @@ CMOCK_MEM_INDEX_TYPE CMock_Guts_MemChain(CMOCK_MEM_INDEX_TYPE root_index, CMOCK_
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------
|
/*-------------------------------------------------------
|
||||||
// CMock_Guts_MemNext
|
* CMock_Guts_MemNext
|
||||||
//-------------------------------------------------------
|
*-------------------------------------------------------*/
|
||||||
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemNext(CMOCK_MEM_INDEX_TYPE previous_item_index)
|
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemNext(CMOCK_MEM_INDEX_TYPE previous_item_index)
|
||||||
{
|
{
|
||||||
CMOCK_MEM_INDEX_TYPE index;
|
CMOCK_MEM_INDEX_TYPE index;
|
||||||
void* previous_item;
|
void* previous_item;
|
||||||
|
|
||||||
//There is nothing "next" if the pointer isn't from our buffer
|
/* There is nothing "next" if the pointer isn't from our buffer */
|
||||||
if ((previous_item_index < CMOCK_MEM_ALIGN_SIZE) || (previous_item_index >= CMock_Guts_FreePtr))
|
if ((previous_item_index < CMOCK_MEM_ALIGN_SIZE) || (previous_item_index >= CMock_Guts_FreePtr))
|
||||||
return CMOCK_GUTS_NONE;
|
return CMOCK_GUTS_NONE;
|
||||||
previous_item = (void*)(&CMock_Guts_Buffer[previous_item_index]);
|
previous_item = (void*)(&CMock_Guts_Buffer[previous_item_index]);
|
||||||
|
|
||||||
//if the pointer is good, then use it to look up the next index
|
/* if the pointer is good, then use it to look up the next index
|
||||||
//(we know the first element always goes in zero, so NEXT must always be > 1)
|
* (we know the first element always goes in zero, so NEXT must always be > 1) */
|
||||||
index = *(CMOCK_MEM_INDEX_TYPE*)((CMOCK_MEM_PTR_AS_INT)previous_item - CMOCK_MEM_INDEX_SIZE);
|
index = *(CMOCK_MEM_INDEX_TYPE*)((CMOCK_MEM_PTR_AS_INT)previous_item - CMOCK_MEM_INDEX_SIZE);
|
||||||
if ((index > 1) && (index < CMock_Guts_FreePtr))
|
if ((index > 1) && (index < CMock_Guts_FreePtr))
|
||||||
return index;
|
return index;
|
||||||
@ -134,9 +134,9 @@ CMOCK_MEM_INDEX_TYPE CMock_Guts_MemNext(CMOCK_MEM_INDEX_TYPE previous_item_index
|
|||||||
return CMOCK_GUTS_NONE;
|
return CMOCK_GUTS_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------
|
/*-------------------------------------------------------
|
||||||
// CMock_Guts_MemEndOfChain
|
* CMock_Guts_MemEndOfChain
|
||||||
//-------------------------------------------------------
|
*-------------------------------------------------------*/
|
||||||
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemEndOfChain(CMOCK_MEM_INDEX_TYPE root_index)
|
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemEndOfChain(CMOCK_MEM_INDEX_TYPE root_index)
|
||||||
{
|
{
|
||||||
CMOCK_MEM_INDEX_TYPE index = root_index;
|
CMOCK_MEM_INDEX_TYPE index = root_index;
|
||||||
@ -152,9 +152,9 @@ CMOCK_MEM_INDEX_TYPE CMock_Guts_MemEndOfChain(CMOCK_MEM_INDEX_TYPE root_index)
|
|||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------
|
/*-------------------------------------------------------
|
||||||
// CMock_GetAddressFor
|
* CMock_GetAddressFor
|
||||||
//-------------------------------------------------------
|
*-------------------------------------------------------*/
|
||||||
void* CMock_Guts_GetAddressFor(CMOCK_MEM_INDEX_TYPE index)
|
void* CMock_Guts_GetAddressFor(CMOCK_MEM_INDEX_TYPE index)
|
||||||
{
|
{
|
||||||
if ((index >= CMOCK_MEM_ALIGN_SIZE) && (index < CMock_Guts_FreePtr))
|
if ((index >= CMOCK_MEM_ALIGN_SIZE) && (index < CMock_Guts_FreePtr))
|
||||||
@ -167,41 +167,41 @@ void* CMock_Guts_GetAddressFor(CMOCK_MEM_INDEX_TYPE index)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------
|
/*-------------------------------------------------------
|
||||||
// CMock_Guts_MemBytesCapacity
|
* CMock_Guts_MemBytesCapacity
|
||||||
//-------------------------------------------------------
|
*-------------------------------------------------------*/
|
||||||
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesCapacity(void)
|
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesCapacity(void)
|
||||||
{
|
{
|
||||||
return (sizeof(CMock_Guts_Buffer) - CMOCK_MEM_ALIGN_SIZE);
|
return (sizeof(CMock_Guts_Buffer) - CMOCK_MEM_ALIGN_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------
|
/*-------------------------------------------------------
|
||||||
// CMock_Guts_MemBytesFree
|
* CMock_Guts_MemBytesFree
|
||||||
//-------------------------------------------------------
|
*-------------------------------------------------------*/
|
||||||
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesFree(void)
|
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesFree(void)
|
||||||
{
|
{
|
||||||
return CMock_Guts_BufferSize - CMock_Guts_FreePtr;
|
return CMock_Guts_BufferSize - CMock_Guts_FreePtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------
|
/*-------------------------------------------------------
|
||||||
// CMock_Guts_MemBytesUsed
|
* CMock_Guts_MemBytesUsed
|
||||||
//-------------------------------------------------------
|
*-------------------------------------------------------*/
|
||||||
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesUsed(void)
|
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesUsed(void)
|
||||||
{
|
{
|
||||||
return CMock_Guts_FreePtr - CMOCK_MEM_ALIGN_SIZE;
|
return CMock_Guts_FreePtr - CMOCK_MEM_ALIGN_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------
|
/*-------------------------------------------------------
|
||||||
// CMock_Guts_MemFreeAll
|
* CMock_Guts_MemFreeAll
|
||||||
//-------------------------------------------------------
|
*-------------------------------------------------------*/
|
||||||
void CMock_Guts_MemFreeAll(void)
|
void CMock_Guts_MemFreeAll(void)
|
||||||
{
|
{
|
||||||
CMock_Guts_FreePtr = CMOCK_MEM_ALIGN_SIZE; //skip the very beginning
|
CMock_Guts_FreePtr = CMOCK_MEM_ALIGN_SIZE; /* skip the very beginning */
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------
|
/*-------------------------------------------------------
|
||||||
// CMock_Guts_MemFreeFinal
|
* CMock_Guts_MemFreeFinal
|
||||||
//-------------------------------------------------------
|
*-------------------------------------------------------*/
|
||||||
void CMock_Guts_MemFreeFinal(void)
|
void CMock_Guts_MemFreeFinal(void)
|
||||||
{
|
{
|
||||||
CMock_Guts_FreePtr = CMOCK_MEM_ALIGN_SIZE;
|
CMock_Guts_FreePtr = CMOCK_MEM_ALIGN_SIZE;
|
||||||
|
33
test/vendor/ceedling/vendor/cmock/src/cmock.h
vendored
33
test/vendor/ceedling/vendor/cmock/src/cmock.h
vendored
@ -11,30 +11,37 @@
|
|||||||
|
|
||||||
#define CMOCK_VERSION_MAJOR 2
|
#define CMOCK_VERSION_MAJOR 2
|
||||||
#define CMOCK_VERSION_MINOR 5
|
#define CMOCK_VERSION_MINOR 5
|
||||||
#define CMOCK_VERSION_BUILD 0
|
#define CMOCK_VERSION_BUILD 4
|
||||||
#define CMOCK_VERSION ((CMOCK_VERSION_MAJOR << 16) | (CMOCK_VERSION_MINOR << 8) | CMOCK_VERSION_BUILD)
|
#define CMOCK_VERSION ((CMOCK_VERSION_MAJOR << 16) | (CMOCK_VERSION_MINOR << 8) | CMOCK_VERSION_BUILD)
|
||||||
|
|
||||||
//should be big enough to index full range of CMOCK_MEM_MAX
|
/* should be big enough to index full range of CMOCK_MEM_MAX */
|
||||||
#ifndef CMOCK_MEM_INDEX_TYPE
|
#ifndef CMOCK_MEM_INDEX_TYPE
|
||||||
#define CMOCK_MEM_INDEX_TYPE unsigned int
|
#include <stddef.h>
|
||||||
|
#define CMOCK_MEM_INDEX_TYPE size_t
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define CMOCK_GUTS_NONE (0)
|
#define CMOCK_GUTS_NONE (0)
|
||||||
|
|
||||||
//-------------------------------------------------------
|
#if defined __GNUC__
|
||||||
// Memory API
|
# 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_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_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_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_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_MemBytesCapacity(void) CMOCK_FUNCTION_ATTR(const);
|
||||||
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesFree(void);
|
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesFree(void) CMOCK_FUNCTION_ATTR(pure);
|
||||||
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesUsed(void);
|
CMOCK_MEM_INDEX_TYPE CMock_Guts_MemBytesUsed(void) CMOCK_FUNCTION_ATTR(pure);
|
||||||
void CMock_Guts_MemFreeAll(void);
|
void CMock_Guts_MemFreeAll(void);
|
||||||
void CMock_Guts_MemFreeFinal(void);
|
void CMock_Guts_MemFreeFinal(void);
|
||||||
|
|
||||||
#endif //CMOCK_FRAMEWORK
|
#endif /* end of CMOCK_FRAMEWORK_H */
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
#include "unity.h"
|
#include "unity.h"
|
||||||
|
|
||||||
//These are constants that the generated mocks have access to
|
/* These are constants that the generated mocks have access to */
|
||||||
extern const char* CMockStringOutOfMemory;
|
extern const char* CMockStringOutOfMemory;
|
||||||
extern const char* CMockStringCalledMore;
|
extern const char* CMockStringCalledMore;
|
||||||
extern const char* CMockStringCalledLess;
|
extern const char* CMockStringCalledLess;
|
||||||
@ -22,8 +22,8 @@ extern const char* CMockStringPtrIsNULL;
|
|||||||
extern const char* CMockStringExpNULL;
|
extern const char* CMockStringExpNULL;
|
||||||
extern const char* CMockStringMismatch;
|
extern const char* CMockStringMismatch;
|
||||||
|
|
||||||
//define CMOCK_MEM_DYNAMIC to grab memory as needed with malloc
|
/* define CMOCK_MEM_DYNAMIC to grab memory as needed with malloc
|
||||||
//when you do that, CMOCK_MEM_SIZE is used for incremental size instead of total
|
* when you do that, CMOCK_MEM_SIZE is used for incremental size instead of total */
|
||||||
#ifdef CMOCK_MEM_STATIC
|
#ifdef CMOCK_MEM_STATIC
|
||||||
#undef CMOCK_MEM_DYNAMIC
|
#undef CMOCK_MEM_DYNAMIC
|
||||||
#endif
|
#endif
|
||||||
@ -32,7 +32,7 @@ extern const char* CMockStringMismatch;
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//this is used internally during pointer arithmetic. make sure this type is the same size as the target's pointer type
|
/* this is used internally during pointer arithmetic. make sure this type is the same size as the target's pointer type */
|
||||||
#ifndef CMOCK_MEM_PTR_AS_INT
|
#ifndef CMOCK_MEM_PTR_AS_INT
|
||||||
#ifdef UNITY_POINTER_WIDTH
|
#ifdef UNITY_POINTER_WIDTH
|
||||||
#ifdef UNITY_INT_WIDTH
|
#ifdef UNITY_INT_WIDTH
|
||||||
@ -60,7 +60,7 @@ extern const char* CMockStringMismatch;
|
|||||||
#define CMOCK_MEM_PTR_AS_INT unsigned long
|
#define CMOCK_MEM_PTR_AS_INT unsigned long
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//0 for no alignment, 1 for 16-bit, 2 for 32-bit, 3 for 64-bit
|
/* 0 for no alignment, 1 for 16-bit, 2 for 32-bit, 3 for 64-bit */
|
||||||
#ifndef CMOCK_MEM_ALIGN
|
#ifndef CMOCK_MEM_ALIGN
|
||||||
#ifdef UNITY_LONG_WIDTH
|
#ifdef UNITY_LONG_WIDTH
|
||||||
#if (UNITY_LONG_WIDTH == 16)
|
#if (UNITY_LONG_WIDTH == 16)
|
||||||
@ -77,15 +77,15 @@ extern const char* CMockStringMismatch;
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//amount of memory to allow cmock to use in its internal heap
|
/* amount of memory to allow cmock to use in its internal heap */
|
||||||
#ifndef CMOCK_MEM_SIZE
|
#ifndef CMOCK_MEM_SIZE
|
||||||
#define CMOCK_MEM_SIZE (32768)
|
#define CMOCK_MEM_SIZE (32768)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//automatically calculated defs for easier reading
|
/* automatically calculated defs for easier reading */
|
||||||
#define CMOCK_MEM_ALIGN_SIZE (CMOCK_MEM_INDEX_TYPE)(1u << CMOCK_MEM_ALIGN)
|
#define CMOCK_MEM_ALIGN_SIZE (CMOCK_MEM_INDEX_TYPE)(1u << CMOCK_MEM_ALIGN)
|
||||||
#define CMOCK_MEM_ALIGN_MASK (CMOCK_MEM_INDEX_TYPE)(CMOCK_MEM_ALIGN_SIZE - 1)
|
#define CMOCK_MEM_ALIGN_MASK (CMOCK_MEM_INDEX_TYPE)(CMOCK_MEM_ALIGN_SIZE - 1)
|
||||||
#define CMOCK_MEM_INDEX_SIZE (CMOCK_MEM_INDEX_TYPE)(CMOCK_MEM_PTR_AS_INT)((sizeof(CMOCK_MEM_INDEX_TYPE) > CMOCK_MEM_ALIGN_SIZE) ? sizeof(CMOCK_MEM_INDEX_TYPE) : CMOCK_MEM_ALIGN_SIZE)
|
#define CMOCK_MEM_INDEX_SIZE (CMOCK_MEM_INDEX_TYPE)(CMOCK_MEM_PTR_AS_INT)((sizeof(CMOCK_MEM_INDEX_TYPE) > CMOCK_MEM_ALIGN_SIZE) ? sizeof(CMOCK_MEM_INDEX_TYPE) : CMOCK_MEM_ALIGN_SIZE)
|
||||||
|
|
||||||
|
|
||||||
#endif //CMOCK_FRAMEWORK_INTERNALS
|
#endif /* end of CMOCK_FRAMEWORK_INTERNALS_H */
|
||||||
|
@ -1,17 +1,12 @@
|
|||||||
###################################################################################
|
#
|
||||||
# #
|
# build script written by : Michael Brockus.
|
||||||
# NAME: meson.build #
|
# github repo author: Mike Karlesky, Mark VanderVoord, Greg Williams.
|
||||||
# #
|
#
|
||||||
# AUTHOR: Mike Karlesky, Mark VanderVoord, Greg Williams. #
|
# license: MIT
|
||||||
# WRITTEN BY: Michael Brockus. #
|
#
|
||||||
# #
|
|
||||||
# License: MIT #
|
|
||||||
# #
|
|
||||||
###################################################################################
|
|
||||||
|
|
||||||
cmock_dir = include_directories('.')
|
cmock_dir = include_directories('.')
|
||||||
|
|
||||||
cmock_lib = static_library(meson.project_name(),
|
cmock_lib = static_library(meson.project_name(),
|
||||||
sources: ['cmock.c'],
|
files('cmock.c'),
|
||||||
dependencies: [unity_dep],
|
dependencies: [unity_dep],
|
||||||
include_directories: cmock_dir)
|
include_directories: cmock_dir)
|
||||||
|
@ -1,211 +0,0 @@
|
|||||||
module DeepMerge
|
|
||||||
|
|
||||||
MAJOR_VERSION = 0
|
|
||||||
MINOR_VERSION = 1
|
|
||||||
FIX_VERSION = 0
|
|
||||||
VERSION = "#{MAJOR_VERSION}.#{MINOR_VERSION}.#{FIX_VERSION}"
|
|
||||||
|
|
||||||
class InvalidParameter < StandardError; end
|
|
||||||
|
|
||||||
DEFAULT_FIELD_KNOCKOUT_PREFIX = '--'
|
|
||||||
|
|
||||||
module DeepMergeHash
|
|
||||||
# ko_hash_merge! will merge and knockout elements prefixed with DEFAULT_FIELD_KNOCKOUT_PREFIX
|
|
||||||
def ko_deep_merge!(source, options = {})
|
|
||||||
default_opts = {:knockout_prefix => "--", :preserve_unmergeables => false}
|
|
||||||
DeepMerge::deep_merge!(source, self, default_opts.merge(options))
|
|
||||||
end
|
|
||||||
|
|
||||||
# deep_merge! will merge and overwrite any unmergeables in destination hash
|
|
||||||
def deep_merge!(source, options = {})
|
|
||||||
default_opts = {:preserve_unmergeables => false}
|
|
||||||
DeepMerge::deep_merge!(source, self, default_opts.merge(options))
|
|
||||||
end
|
|
||||||
|
|
||||||
# deep_merge will merge and skip any unmergeables in destination hash
|
|
||||||
def deep_merge(source, options = {})
|
|
||||||
default_opts = {:preserve_unmergeables => true}
|
|
||||||
DeepMerge::deep_merge!(source, self, default_opts.merge(options))
|
|
||||||
end
|
|
||||||
|
|
||||||
end # DeepMergeHashExt
|
|
||||||
|
|
||||||
# Deep Merge core documentation.
|
|
||||||
# deep_merge! method permits merging of arbitrary child elements. The two top level
|
|
||||||
# elements must be hashes. These hashes can contain unlimited (to stack limit) levels
|
|
||||||
# of child elements. These child elements to not have to be of the same types.
|
|
||||||
# Where child elements are of the same type, deep_merge will attempt to merge them together.
|
|
||||||
# Where child elements are not of the same type, deep_merge will skip or optionally overwrite
|
|
||||||
# the destination element with the contents of the source element at that level.
|
|
||||||
# So if you have two hashes like this:
|
|
||||||
# source = {:x => [1,2,3], :y => 2}
|
|
||||||
# dest = {:x => [4,5,'6'], :y => [7,8,9]}
|
|
||||||
# dest.deep_merge!(source)
|
|
||||||
# Results: {:x => [1,2,3,4,5,'6'], :y => 2}
|
|
||||||
# By default, "deep_merge!" will overwrite any unmergeables and merge everything else.
|
|
||||||
# To avoid this, use "deep_merge" (no bang/exclamation mark)
|
|
||||||
#
|
|
||||||
# Options:
|
|
||||||
# Options are specified in the last parameter passed, which should be in hash format:
|
|
||||||
# hash.deep_merge!({:x => [1,2]}, {:knockout_prefix => '--'})
|
|
||||||
# :preserve_unmergeables DEFAULT: false
|
|
||||||
# Set to true to skip any unmergeable elements from source
|
|
||||||
# :knockout_prefix DEFAULT: nil
|
|
||||||
# Set to string value to signify prefix which deletes elements from existing element
|
|
||||||
# :sort_merged_arrays DEFAULT: false
|
|
||||||
# Set to true to sort all arrays that are merged together
|
|
||||||
# :unpack_arrays DEFAULT: nil
|
|
||||||
# Set to string value to run "Array::join" then "String::split" against all arrays
|
|
||||||
# :merge_debug DEFAULT: false
|
|
||||||
# Set to true to get console output of merge process for debugging
|
|
||||||
#
|
|
||||||
# Selected Options Details:
|
|
||||||
# :knockout_prefix => The purpose of this is to provide a way to remove elements
|
|
||||||
# from existing Hash by specifying them in a special way in incoming hash
|
|
||||||
# source = {:x => ['--1', '2']}
|
|
||||||
# dest = {:x => ['1', '3']}
|
|
||||||
# dest.ko_deep_merge!(source)
|
|
||||||
# Results: {:x => ['2','3']}
|
|
||||||
# Additionally, if the knockout_prefix is passed alone as a string, it will cause
|
|
||||||
# the entire element to be removed:
|
|
||||||
# source = {:x => '--'}
|
|
||||||
# dest = {:x => [1,2,3]}
|
|
||||||
# dest.ko_deep_merge!(source)
|
|
||||||
# Results: {:x => ""}
|
|
||||||
# :unpack_arrays => The purpose of this is to permit compound elements to be passed
|
|
||||||
# in as strings and to be converted into discrete array elements
|
|
||||||
# irsource = {:x => ['1,2,3', '4']}
|
|
||||||
# dest = {:x => ['5','6','7,8']}
|
|
||||||
# dest.deep_merge!(source, {:unpack_arrays => ','})
|
|
||||||
# Results: {:x => ['1','2','3','4','5','6','7','8'}
|
|
||||||
# Why: If receiving data from an HTML form, this makes it easy for a checkbox
|
|
||||||
# to pass multiple values from within a single HTML element
|
|
||||||
#
|
|
||||||
# There are many tests for this library - and you can learn more about the features
|
|
||||||
# and usages of deep_merge! by just browsing the test examples
|
|
||||||
def DeepMerge.deep_merge!(source, dest, options = {})
|
|
||||||
# turn on this line for stdout debugging text
|
|
||||||
merge_debug = options[:merge_debug] || false
|
|
||||||
overwrite_unmergeable = !options[:preserve_unmergeables]
|
|
||||||
knockout_prefix = options[:knockout_prefix] || nil
|
|
||||||
if knockout_prefix == "" then raise InvalidParameter, "knockout_prefix cannot be an empty string in deep_merge!"; end
|
|
||||||
if knockout_prefix && !overwrite_unmergeable then raise InvalidParameter, "overwrite_unmergeable must be true if knockout_prefix is specified in deep_merge!"; end
|
|
||||||
# if present: we will split and join arrays on this char before merging
|
|
||||||
array_split_char = options[:unpack_arrays] || false
|
|
||||||
# request that we sort together any arrays when they are merged
|
|
||||||
sort_merged_arrays = options[:sort_merged_arrays] || false
|
|
||||||
di = options[:debug_indent] || ''
|
|
||||||
# do nothing if source is nil
|
|
||||||
if source.nil? || (source.respond_to?(:blank?) && source.blank?) then return dest; end
|
|
||||||
# if dest doesn't exist, then simply copy source to it
|
|
||||||
if dest.nil? && overwrite_unmergeable then dest = source; return dest; end
|
|
||||||
|
|
||||||
puts "#{di}Source class: #{source.class.inspect} :: Dest class: #{dest.class.inspect}" if merge_debug
|
|
||||||
if source.kind_of?(Hash)
|
|
||||||
puts "#{di}Hashes: #{source.inspect} :: #{dest.inspect}" if merge_debug
|
|
||||||
source.each do |src_key, src_value|
|
|
||||||
if dest.kind_of?(Hash)
|
|
||||||
puts "#{di} looping: #{src_key.inspect} => #{src_value.inspect} :: #{dest.inspect}" if merge_debug
|
|
||||||
if not dest[src_key].nil?
|
|
||||||
puts "#{di} ==>merging: #{src_key.inspect} => #{src_value.inspect} :: #{dest[src_key].inspect}" if merge_debug
|
|
||||||
dest[src_key] = deep_merge!(src_value, dest[src_key], options.merge(:debug_indent => di + ' '))
|
|
||||||
else # dest[src_key] doesn't exist so we want to create and overwrite it (but we do this via deep_merge!)
|
|
||||||
puts "#{di} ==>merging over: #{src_key.inspect} => #{src_value.inspect}" if merge_debug
|
|
||||||
# note: we rescue here b/c some classes respond to "dup" but don't implement it (Numeric, TrueClass, FalseClass, NilClass among maybe others)
|
|
||||||
begin
|
|
||||||
src_dup = src_value.dup # we dup src_value if possible because we're going to merge into it (since dest is empty)
|
|
||||||
rescue TypeError
|
|
||||||
src_dup = src_value
|
|
||||||
end
|
|
||||||
dest[src_key] = deep_merge!(src_value, src_dup, options.merge(:debug_indent => di + ' '))
|
|
||||||
end
|
|
||||||
else # dest isn't a hash, so we overwrite it completely (if permitted)
|
|
||||||
if overwrite_unmergeable
|
|
||||||
puts "#{di} overwriting dest: #{src_key.inspect} => #{src_value.inspect} -over-> #{dest.inspect}" if merge_debug
|
|
||||||
dest = overwrite_unmergeables(source, dest, options)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
elsif source.kind_of?(Array)
|
|
||||||
puts "#{di}Arrays: #{source.inspect} :: #{dest.inspect}" if merge_debug
|
|
||||||
# if we are instructed, join/split any source arrays before processing
|
|
||||||
if array_split_char
|
|
||||||
puts "#{di} split/join on source: #{source.inspect}" if merge_debug
|
|
||||||
source = source.join(array_split_char).split(array_split_char)
|
|
||||||
if dest.kind_of?(Array) then dest = dest.join(array_split_char).split(array_split_char); end
|
|
||||||
end
|
|
||||||
# if there's a naked knockout_prefix in source, that means we are to truncate dest
|
|
||||||
if source.index(knockout_prefix) then dest = clear_or_nil(dest); source.delete(knockout_prefix); end
|
|
||||||
if dest.kind_of?(Array)
|
|
||||||
if knockout_prefix
|
|
||||||
print "#{di} knocking out: " if merge_debug
|
|
||||||
# remove knockout prefix items from both source and dest
|
|
||||||
source.delete_if do |ko_item|
|
|
||||||
retval = false
|
|
||||||
item = ko_item.respond_to?(:gsub) ? ko_item.gsub(%r{^#{knockout_prefix}}, "") : ko_item
|
|
||||||
if item != ko_item
|
|
||||||
print "#{ko_item} - " if merge_debug
|
|
||||||
dest.delete(item)
|
|
||||||
dest.delete(ko_item)
|
|
||||||
retval = true
|
|
||||||
end
|
|
||||||
retval
|
|
||||||
end
|
|
||||||
puts if merge_debug
|
|
||||||
end
|
|
||||||
puts "#{di} merging arrays: #{source.inspect} :: #{dest.inspect}" if merge_debug
|
|
||||||
dest = dest | source
|
|
||||||
if sort_merged_arrays then dest.sort!; end
|
|
||||||
elsif overwrite_unmergeable
|
|
||||||
puts "#{di} overwriting dest: #{source.inspect} -over-> #{dest.inspect}" if merge_debug
|
|
||||||
dest = overwrite_unmergeables(source, dest, options)
|
|
||||||
end
|
|
||||||
else # src_hash is not an array or hash, so we'll have to overwrite dest
|
|
||||||
puts "#{di}Others: #{source.inspect} :: #{dest.inspect}" if merge_debug
|
|
||||||
dest = overwrite_unmergeables(source, dest, options)
|
|
||||||
end
|
|
||||||
puts "#{di}Returning #{dest.inspect}" if merge_debug
|
|
||||||
dest
|
|
||||||
end # deep_merge!
|
|
||||||
|
|
||||||
# allows deep_merge! to uniformly handle overwriting of unmergeable entities
|
|
||||||
def DeepMerge::overwrite_unmergeables(source, dest, options)
|
|
||||||
merge_debug = options[:merge_debug] || false
|
|
||||||
overwrite_unmergeable = !options[:preserve_unmergeables]
|
|
||||||
knockout_prefix = options[:knockout_prefix] || false
|
|
||||||
di = options[:debug_indent] || ''
|
|
||||||
if knockout_prefix && overwrite_unmergeable
|
|
||||||
if source.kind_of?(String) # remove knockout string from source before overwriting dest
|
|
||||||
src_tmp = source.gsub(%r{^#{knockout_prefix}},"")
|
|
||||||
elsif source.kind_of?(Array) # remove all knockout elements before overwriting dest
|
|
||||||
src_tmp = source.delete_if {|ko_item| ko_item.kind_of?(String) && ko_item.match(%r{^#{knockout_prefix}}) }
|
|
||||||
else
|
|
||||||
src_tmp = source
|
|
||||||
end
|
|
||||||
if src_tmp == source # if we didn't find a knockout_prefix then we just overwrite dest
|
|
||||||
puts "#{di}#{src_tmp.inspect} -over-> #{dest.inspect}" if merge_debug
|
|
||||||
dest = src_tmp
|
|
||||||
else # if we do find a knockout_prefix, then we just delete dest
|
|
||||||
puts "#{di}\"\" -over-> #{dest.inspect}" if merge_debug
|
|
||||||
dest = ""
|
|
||||||
end
|
|
||||||
elsif overwrite_unmergeable
|
|
||||||
dest = source
|
|
||||||
end
|
|
||||||
dest
|
|
||||||
end
|
|
||||||
|
|
||||||
def DeepMerge::clear_or_nil(obj)
|
|
||||||
if obj.respond_to?(:clear)
|
|
||||||
obj.clear
|
|
||||||
else
|
|
||||||
obj = nil
|
|
||||||
end
|
|
||||||
obj
|
|
||||||
end
|
|
||||||
|
|
||||||
end # module DeepMerge
|
|
||||||
|
|
||||||
class Hash
|
|
||||||
include DeepMerge::DeepMergeHash
|
|
||||||
end
|
|
@ -13,7 +13,9 @@ require 'fileutils'
|
|||||||
require 'pathname'
|
require 'pathname'
|
||||||
|
|
||||||
# TEMPLATE_TST
|
# TEMPLATE_TST
|
||||||
TEMPLATE_TST ||= '#include "unity.h"
|
TEMPLATE_TST ||= '#ifdef TEST
|
||||||
|
|
||||||
|
#include "unity.h"
|
||||||
|
|
||||||
%2$s#include "%1$s.h"
|
%2$s#include "%1$s.h"
|
||||||
|
|
||||||
@ -25,10 +27,12 @@ void tearDown(void)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_%1$s_NeedToImplement(void)
|
void test_%4$s_NeedToImplement(void)
|
||||||
{
|
{
|
||||||
TEST_IGNORE_MESSAGE("Need to Implement %1$s");
|
TEST_IGNORE_MESSAGE("Need to Implement %1$s");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // TEST
|
||||||
'.freeze
|
'.freeze
|
||||||
|
|
||||||
# TEMPLATE_SRC
|
# TEMPLATE_SRC
|
||||||
@ -163,24 +167,23 @@ class UnityModuleGenerator
|
|||||||
files
|
files
|
||||||
end
|
end
|
||||||
|
|
||||||
|
############################
|
||||||
|
def neutralize_filename(name, start_cap = true)
|
||||||
|
return name if name.empty?
|
||||||
|
name = name.split(/(?:\s+|_|(?=[A-Z][a-z]))|(?<=[a-z])(?=[A-Z])/).map { |v| v.capitalize }.join('_')
|
||||||
|
name = name[0].downcase + name[1..-1] unless start_cap
|
||||||
|
return name
|
||||||
|
end
|
||||||
|
|
||||||
############################
|
############################
|
||||||
def create_filename(part1, part2 = '')
|
def create_filename(part1, part2 = '')
|
||||||
if part2.empty?
|
name = part2.empty? ? part1 : part1 + '_' + part2
|
||||||
case (@options[:naming])
|
case (@options[:naming])
|
||||||
when 'bumpy' then part1
|
when 'bumpy' then neutralize_filename(name,false).delete('_')
|
||||||
when 'camel' then part1
|
when 'camel' then neutralize_filename(name).delete('_')
|
||||||
when 'snake' then part1.downcase
|
when 'snake' then neutralize_filename(name).downcase
|
||||||
when 'caps' then part1.upcase
|
when 'caps' then neutralize_filename(name).upcase
|
||||||
else part1
|
else name
|
||||||
end
|
|
||||||
else
|
|
||||||
case (@options[:naming])
|
|
||||||
when 'bumpy' then part1 + part2
|
|
||||||
when 'camel' then part1 + part2
|
|
||||||
when 'snake' then part1.downcase + '_' + part2.downcase
|
|
||||||
when 'caps' then part1.upcase + '_' + part2.upcase
|
|
||||||
else part1 + '_' + part2
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -208,7 +211,8 @@ class UnityModuleGenerator
|
|||||||
f.write("#{file[:boilerplate]}\n" % [file[:name]]) unless file[:boilerplate].nil?
|
f.write("#{file[:boilerplate]}\n" % [file[:name]]) unless file[:boilerplate].nil?
|
||||||
f.write(file[:template] % [file[:name],
|
f.write(file[:template] % [file[:name],
|
||||||
file[:includes].map { |ff| "#include \"#{ff}\"\n" }.join,
|
file[:includes].map { |ff| "#include \"#{ff}\"\n" }.join,
|
||||||
file[:name].upcase])
|
file[:name].upcase.gsub(/-/, '_'),
|
||||||
|
file[:name].gsub(/-/, '_')])
|
||||||
end
|
end
|
||||||
if @options[:update_svn]
|
if @options[:update_svn]
|
||||||
`svn add \"#{file[:path]}\"`
|
`svn add \"#{file[:path]}\"`
|
||||||
|
@ -42,7 +42,9 @@ class UnityTestRunnerGenerator
|
|||||||
main_export_decl: '',
|
main_export_decl: '',
|
||||||
cmdline_args: false,
|
cmdline_args: false,
|
||||||
omit_begin_end: false,
|
omit_begin_end: false,
|
||||||
use_param_tests: false
|
use_param_tests: false,
|
||||||
|
include_extensions: '(?:hpp|hh|H|h)',
|
||||||
|
source_extensions: '(?:cpp|cc|ino|C|c)'
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -92,7 +94,7 @@ class UnityTestRunnerGenerator
|
|||||||
create_suite_setup(output)
|
create_suite_setup(output)
|
||||||
create_suite_teardown(output)
|
create_suite_teardown(output)
|
||||||
create_reset(output)
|
create_reset(output)
|
||||||
create_run_test(output)
|
create_run_test(output) unless tests.empty?
|
||||||
create_args_wrappers(output, tests)
|
create_args_wrappers(output, tests)
|
||||||
create_main(output, input_file, tests, used_mocks)
|
create_main(output, input_file, tests, used_mocks)
|
||||||
end
|
end
|
||||||
@ -108,7 +110,7 @@ class UnityTestRunnerGenerator
|
|||||||
tests_and_line_numbers = []
|
tests_and_line_numbers = []
|
||||||
|
|
||||||
# contains characters which will be substituted from within strings, doing
|
# contains characters which will be substituted from within strings, doing
|
||||||
# this prevents these characters from interferring with scrubbers
|
# this prevents these characters from interfering with scrubbers
|
||||||
# @ is not a valid C character, so there should be no clashes with files genuinely containing these markers
|
# @ is not a valid C character, so there should be no clashes with files genuinely containing these markers
|
||||||
substring_subs = { '{' => '@co@', '}' => '@cc@', ';' => '@ss@', '/' => '@fs@' }
|
substring_subs = { '{' => '@co@', '}' => '@cc@', ';' => '@ss@', '/' => '@fs@' }
|
||||||
substring_re = Regexp.union(substring_subs.keys)
|
substring_re = Regexp.union(substring_subs.keys)
|
||||||
@ -128,7 +130,7 @@ class UnityTestRunnerGenerator
|
|||||||
|
|
||||||
lines.each_with_index do |line, _index|
|
lines.each_with_index do |line, _index|
|
||||||
# find tests
|
# find tests
|
||||||
next unless line =~ /^((?:\s*TEST_CASE\s*\(.*?\)\s*)*)\s*void\s+((?:#{@options[:test_prefix]}).*)\s*\(\s*(.*)\s*\)/m
|
next unless line =~ /^((?:\s*(?:TEST_CASE|TEST_RANGE)\s*\(.*?\)\s*)*)\s*void\s+((?:#{@options[:test_prefix]}).*)\s*\(\s*(.*)\s*\)/m
|
||||||
|
|
||||||
arguments = Regexp.last_match(1)
|
arguments = Regexp.last_match(1)
|
||||||
name = Regexp.last_match(2)
|
name = Regexp.last_match(2)
|
||||||
@ -139,6 +141,20 @@ class UnityTestRunnerGenerator
|
|||||||
if @options[:use_param_tests] && !arguments.empty?
|
if @options[:use_param_tests] && !arguments.empty?
|
||||||
args = []
|
args = []
|
||||||
arguments.scan(/\s*TEST_CASE\s*\((.*)\)\s*$/) { |a| args << a[0] }
|
arguments.scan(/\s*TEST_CASE\s*\((.*)\)\s*$/) { |a| args << a[0] }
|
||||||
|
|
||||||
|
arguments.scan(/\s*TEST_RANGE\s*\((.*)\)\s*$/).flatten.each do |range_str|
|
||||||
|
args += range_str.scan(/\[\s*(-?\d+.?\d*),\s*(-?\d+.?\d*),\s*(-?\d+.?\d*)\s*\]/).map do |arg_values_str|
|
||||||
|
arg_values_str.map do |arg_value_str|
|
||||||
|
arg_value_str.include?('.') ? arg_value_str.to_f : arg_value_str.to_i
|
||||||
|
end
|
||||||
|
end.map do |arg_values|
|
||||||
|
(arg_values[0]..arg_values[1]).step(arg_values[2]).to_a
|
||||||
|
end.reduce do |result, arg_range_expanded|
|
||||||
|
result.product(arg_range_expanded)
|
||||||
|
end.map do |arg_combinations|
|
||||||
|
arg_combinations.flatten.join(', ')
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
tests_and_line_numbers << { test: name, args: args, call: call, params: params, line_number: 0 }
|
tests_and_line_numbers << { test: name, args: args, call: call, params: params, line_number: 0 }
|
||||||
@ -170,9 +186,9 @@ class UnityTestRunnerGenerator
|
|||||||
|
|
||||||
# parse out includes
|
# parse out includes
|
||||||
includes = {
|
includes = {
|
||||||
local: source.scan(/^\s*#include\s+\"\s*(.+)\.[hH]\s*\"/).flatten,
|
local: source.scan(/^\s*#include\s+\"\s*(.+\.#{@options[:include_extensions]})\s*\"/).flatten,
|
||||||
system: source.scan(/^\s*#include\s+<\s*(.+)\s*>/).flatten.map { |inc| "<#{inc}>" },
|
system: source.scan(/^\s*#include\s+<\s*(.+)\s*>/).flatten.map { |inc| "<#{inc}>" },
|
||||||
linkonly: source.scan(/^TEST_FILE\(\s*\"\s*(.+)\.[cC]\w*\s*\"/).flatten
|
linkonly: source.scan(/^TEST_FILE\(\s*\"\s*(.+\.#{@options[:source_extensions]})\s*\"/).flatten
|
||||||
}
|
}
|
||||||
includes
|
includes
|
||||||
end
|
end
|
||||||
@ -181,7 +197,7 @@ class UnityTestRunnerGenerator
|
|||||||
mock_headers = []
|
mock_headers = []
|
||||||
includes.each do |include_path|
|
includes.each do |include_path|
|
||||||
include_file = File.basename(include_path)
|
include_file = File.basename(include_path)
|
||||||
mock_headers << include_path if include_file =~ /^#{@options[:mock_prefix]}.*#{@options[:mock_suffix]}$/i
|
mock_headers << include_path if include_file =~ /^#{@options[:mock_prefix]}.*#{@options[:mock_suffix]}\.h$/i
|
||||||
end
|
end
|
||||||
mock_headers
|
mock_headers
|
||||||
end
|
end
|
||||||
@ -190,7 +206,7 @@ class UnityTestRunnerGenerator
|
|||||||
@options[:has_setup] = source =~ /void\s+#{@options[:setup_name]}\s*\(/
|
@options[:has_setup] = source =~ /void\s+#{@options[:setup_name]}\s*\(/
|
||||||
@options[:has_teardown] = source =~ /void\s+#{@options[:teardown_name]}\s*\(/
|
@options[:has_teardown] = source =~ /void\s+#{@options[:teardown_name]}\s*\(/
|
||||||
@options[:has_suite_setup] ||= (source =~ /void\s+suiteSetUp\s*\(/)
|
@options[:has_suite_setup] ||= (source =~ /void\s+suiteSetUp\s*\(/)
|
||||||
@options[:has_suite_teardown] ||= (source =~ /void\s+suiteTearDown\s*\(/)
|
@options[:has_suite_teardown] ||= (source =~ /int\s+suiteTearDown\s*\(int\s+([a-zA-Z0-9_])+\s*\)/)
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_header(output, mocks, testfile_includes = [])
|
def create_header(output, mocks, testfile_includes = [])
|
||||||
@ -205,14 +221,14 @@ class UnityTestRunnerGenerator
|
|||||||
output.puts("#include \"#{File.basename(@options[:header_file])}\"")
|
output.puts("#include \"#{File.basename(@options[:header_file])}\"")
|
||||||
else
|
else
|
||||||
@options[:includes].flatten.uniq.compact.each do |inc|
|
@options[:includes].flatten.uniq.compact.each do |inc|
|
||||||
output.puts("#include #{inc.include?('<') ? inc : "\"#{inc.gsub('.h', '')}.h\""}")
|
output.puts("#include #{inc.include?('<') ? inc : "\"#{inc}\""}")
|
||||||
end
|
end
|
||||||
testfile_includes.each do |inc|
|
testfile_includes.each do |inc|
|
||||||
output.puts("#include #{inc.include?('<') ? inc : "\"#{inc.gsub('.h', '')}.h\""}")
|
output.puts("#include #{inc.include?('<') ? inc : "\"#{inc}\""}")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
mocks.each do |mock|
|
mocks.each do |mock|
|
||||||
output.puts("#include \"#{mock.gsub('.h', '')}.h\"")
|
output.puts("#include \"#{mock}\"")
|
||||||
end
|
end
|
||||||
output.puts('#include "CException.h"') if @options[:plugins].include?(:cexception)
|
output.puts('#include "CException.h"') if @options[:plugins].include?(:cexception)
|
||||||
|
|
||||||
@ -247,7 +263,7 @@ class UnityTestRunnerGenerator
|
|||||||
output.puts(' GlobalOrderError = NULL;')
|
output.puts(' GlobalOrderError = NULL;')
|
||||||
end
|
end
|
||||||
|
|
||||||
mocks = mock_headers.map { |mock| File.basename(mock) }
|
mocks = mock_headers.map { |mock| File.basename(mock, '.*') }
|
||||||
mocks.each do |mock|
|
mocks.each do |mock|
|
||||||
mock_clean = TypeSanitizer.sanitize_c_identifier(mock)
|
mock_clean = TypeSanitizer.sanitize_c_identifier(mock)
|
||||||
output.puts(" #{mock_clean}_Init();")
|
output.puts(" #{mock_clean}_Init();")
|
||||||
@ -325,8 +341,8 @@ class UnityTestRunnerGenerator
|
|||||||
|
|
||||||
def create_run_test(output)
|
def create_run_test(output)
|
||||||
require 'erb'
|
require 'erb'
|
||||||
template = ERB.new(File.read(File.join(__dir__, 'run_test.erb')))
|
template = ERB.new(File.read(File.join(__dir__, 'run_test.erb')), nil, '<>')
|
||||||
output.puts(template.result(binding))
|
output.puts("\n" + template.result(binding))
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_args_wrappers(output, tests)
|
def create_args_wrappers(output, tests)
|
||||||
@ -346,7 +362,7 @@ class UnityTestRunnerGenerator
|
|||||||
end
|
end
|
||||||
|
|
||||||
def create_main(output, filename, tests, used_mocks)
|
def create_main(output, filename, tests, used_mocks)
|
||||||
output.puts("\n\n/*=======MAIN=====*/")
|
output.puts("\n/*=======MAIN=====*/")
|
||||||
main_name = @options[:main_name].to_sym == :auto ? "main_#{filename.gsub('.c', '')}" : (@options[:main_name]).to_s
|
main_name = @options[:main_name].to_sym == :auto ? "main_#{filename.gsub('.c', '')}" : (@options[:main_name]).to_s
|
||||||
if @options[:cmdline_args]
|
if @options[:cmdline_args]
|
||||||
if main_name != 'main'
|
if main_name != 'main'
|
||||||
@ -410,7 +426,7 @@ class UnityTestRunnerGenerator
|
|||||||
output.puts(' return suiteTearDown(UnityEnd());')
|
output.puts(' return suiteTearDown(UnityEnd());')
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
output.puts(' return UnityEnd();') if not @options[:omit_begin_end]
|
output.puts(' return UnityEnd();') unless @options[:omit_begin_end]
|
||||||
end
|
end
|
||||||
output.puts('}')
|
output.puts('}')
|
||||||
end
|
end
|
||||||
@ -423,10 +439,10 @@ class UnityTestRunnerGenerator
|
|||||||
output.puts("#include \"#{@options[:framework]}.h\"")
|
output.puts("#include \"#{@options[:framework]}.h\"")
|
||||||
output.puts('#include "cmock.h"') unless used_mocks.empty?
|
output.puts('#include "cmock.h"') unless used_mocks.empty?
|
||||||
@options[:includes].flatten.uniq.compact.each do |inc|
|
@options[:includes].flatten.uniq.compact.each do |inc|
|
||||||
output.puts("#include #{inc.include?('<') ? inc : "\"#{inc.gsub('.h', '')}.h\""}")
|
output.puts("#include #{inc.include?('<') ? inc : "\"#{inc}\""}")
|
||||||
end
|
end
|
||||||
testfile_includes.each do |inc|
|
testfile_includes.each do |inc|
|
||||||
output.puts("#include #{inc.include?('<') ? inc : "\"#{inc.gsub('.h', '')}.h\""}")
|
output.puts("#include #{inc.include?('<') ? inc : "\"#{inc}\""}")
|
||||||
end
|
end
|
||||||
output.puts "\n"
|
output.puts "\n"
|
||||||
tests.each do |test|
|
tests.each do |test|
|
||||||
@ -449,13 +465,13 @@ if $0 == __FILE__
|
|||||||
when '-cexception'
|
when '-cexception'
|
||||||
options[:plugins] = [:cexception]
|
options[:plugins] = [:cexception]
|
||||||
true
|
true
|
||||||
when /\.*\.ya?ml/
|
when /\.*\.ya?ml$/
|
||||||
options = UnityTestRunnerGenerator.grab_config(arg)
|
options = UnityTestRunnerGenerator.grab_config(arg)
|
||||||
true
|
true
|
||||||
when /--(\w+)=\"?(.*)\"?/
|
when /--(\w+)=\"?(.*)\"?/
|
||||||
options[Regexp.last_match(1).to_sym] = Regexp.last_match(2)
|
options[Regexp.last_match(1).to_sym] = Regexp.last_match(2)
|
||||||
true
|
true
|
||||||
when /\.*\.h/
|
when /\.*\.(?:hpp|hh|H|h)$/
|
||||||
options[:includes] << arg
|
options[:includes] << arg
|
||||||
true
|
true
|
||||||
else false
|
else false
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*=======Test Runner Used To Run Each Test=====*/
|
/*=======Test Runner Used To Run Each Test=====*/
|
||||||
static void run_test(UnityTestFunction func, const char* name, int line_num)
|
static void run_test(UnityTestFunction func, const char* name, UNITY_LINE_TYPE line_num)
|
||||||
{
|
{
|
||||||
Unity.CurrentTestName = name;
|
Unity.CurrentTestName = name;
|
||||||
Unity.CurrentTestLineNumber = line_num;
|
Unity.CurrentTestLineNumber = line_num;
|
||||||
@ -16,13 +16,14 @@ static void run_test(UnityTestFunction func, const char* name, int line_num)
|
|||||||
<% if @options[:plugins].include?(:cexception) %>
|
<% if @options[:plugins].include?(:cexception) %>
|
||||||
CEXCEPTION_T e;
|
CEXCEPTION_T e;
|
||||||
Try {
|
Try {
|
||||||
<% end %>
|
|
||||||
<%= @options[:setup_name] %>();
|
<%= @options[:setup_name] %>();
|
||||||
func();
|
func();
|
||||||
<% if @options[:plugins].include?(:cexception) %>
|
|
||||||
} Catch(e) {
|
} Catch(e) {
|
||||||
TEST_ASSERT_EQUAL_HEX32_MESSAGE(CEXCEPTION_NONE, e, "Unhandled Exception!");
|
TEST_ASSERT_EQUAL_HEX32_MESSAGE(CEXCEPTION_NONE, e, "Unhandled Exception!");
|
||||||
}
|
}
|
||||||
|
<% else %>
|
||||||
|
<%= @options[:setup_name] %>();
|
||||||
|
func();
|
||||||
<% end %>
|
<% end %>
|
||||||
}
|
}
|
||||||
if (TEST_PROTECT())
|
if (TEST_PROTECT())
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
122
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
|||||||
2.4.3
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
|||||||
###################################################################################
|
|
||||||
# #
|
|
||||||
# NAME: CMakeLists.txt #
|
|
||||||
# #
|
|
||||||
# AUTHOR: Mike Karlesky, Mark VanderVoord, Greg Williams. #
|
|
||||||
# WRITTEN BY: Michael Brockus. #
|
|
||||||
# #
|
|
||||||
# License: MIT #
|
|
||||||
# #
|
|
||||||
###################################################################################
|
|
||||||
cmake_minimum_required(VERSION 3.0 FATAL_ERROR)
|
|
||||||
|
|
||||||
|
|
||||||
add_library(unity STATIC "unity.c")
|
|
||||||
|
|
||||||
install(TARGETS unity EXPORT unityConfig
|
|
||||||
ARCHIVE DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}/${CMAKE_INSTALL_LIBDIR}"
|
|
||||||
LIBRARY DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}/${CMAKE_INSTALL_LIBDIR}"
|
|
||||||
RUNTIME DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}/${CMAKE_INSTALL_BINDIR}"
|
|
||||||
INCLUDES DESTINATION "${CMAKE_INSTALL_LIBDIR}")
|
|
||||||
|
|
||||||
|
|
@ -1,16 +1,11 @@
|
|||||||
###################################################################################
|
#
|
||||||
# #
|
# build script written by : Michael Brockus.
|
||||||
# NAME: meson.build #
|
# github repo author: Mike Karlesky, Mark VanderVoord, Greg Williams.
|
||||||
# #
|
#
|
||||||
# AUTHOR: Mike Karlesky, Mark VanderVoord, Greg Williams. #
|
# license: MIT
|
||||||
# WRITTEN BY: Michael Brockus. #
|
#
|
||||||
# #
|
|
||||||
# License: MIT #
|
|
||||||
# #
|
|
||||||
###################################################################################
|
|
||||||
|
|
||||||
unity_dir = include_directories('.')
|
unity_dir = include_directories('.')
|
||||||
|
|
||||||
unity_lib = static_library(meson.project_name(),
|
unity_lib = static_library(meson.project_name(),
|
||||||
sources: ['unity.c'],
|
files('unity.c'),
|
||||||
include_directories: unity_dir)
|
include_directories: unity_dir)
|
||||||
|
273
test/vendor/ceedling/vendor/unity/src/unity.c
vendored
273
test/vendor/ceedling/vendor/unity/src/unity.c
vendored
@ -1,6 +1,6 @@
|
|||||||
/* =========================================================================
|
/* =========================================================================
|
||||||
Unity Project - A Test Framework for C
|
Unity Project - A Test Framework for C
|
||||||
Copyright (c) 2007-19 Mike Karlesky, Mark VanderVoord, Greg Williams
|
Copyright (c) 2007-21 Mike Karlesky, Mark VanderVoord, Greg Williams
|
||||||
[Released under MIT License. Please refer to license.txt for details]
|
[Released under MIT License. Please refer to license.txt for details]
|
||||||
============================================================================ */
|
============================================================================ */
|
||||||
|
|
||||||
@ -21,7 +21,7 @@ void UNITY_OUTPUT_CHAR(int);
|
|||||||
/* Helpful macros for us to use here in Assert functions */
|
/* Helpful macros for us to use here in Assert functions */
|
||||||
#define UNITY_FAIL_AND_BAIL { Unity.CurrentTestFailed = 1; UNITY_OUTPUT_FLUSH(); TEST_ABORT(); }
|
#define UNITY_FAIL_AND_BAIL { Unity.CurrentTestFailed = 1; UNITY_OUTPUT_FLUSH(); TEST_ABORT(); }
|
||||||
#define UNITY_IGNORE_AND_BAIL { Unity.CurrentTestIgnored = 1; UNITY_OUTPUT_FLUSH(); TEST_ABORT(); }
|
#define UNITY_IGNORE_AND_BAIL { Unity.CurrentTestIgnored = 1; UNITY_OUTPUT_FLUSH(); TEST_ABORT(); }
|
||||||
#define RETURN_IF_FAIL_OR_IGNORE if (Unity.CurrentTestFailed || Unity.CurrentTestIgnored) return
|
#define RETURN_IF_FAIL_OR_IGNORE if (Unity.CurrentTestFailed || Unity.CurrentTestIgnored) TEST_ABORT()
|
||||||
|
|
||||||
struct UNITY_STORAGE_T Unity;
|
struct UNITY_STORAGE_T Unity;
|
||||||
|
|
||||||
@ -43,6 +43,7 @@ static const char PROGMEM UnityStrWas[] = " Was ";
|
|||||||
static const char PROGMEM UnityStrGt[] = " to be greater than ";
|
static const char PROGMEM UnityStrGt[] = " to be greater than ";
|
||||||
static const char PROGMEM UnityStrLt[] = " to be less than ";
|
static const char PROGMEM UnityStrLt[] = " to be less than ";
|
||||||
static const char PROGMEM UnityStrOrEqual[] = "or equal to ";
|
static const char PROGMEM UnityStrOrEqual[] = "or equal to ";
|
||||||
|
static const char PROGMEM UnityStrNotEqual[] = " to be not equal to ";
|
||||||
static const char PROGMEM UnityStrElement[] = " Element ";
|
static const char PROGMEM UnityStrElement[] = " Element ";
|
||||||
static const char PROGMEM UnityStrByte[] = " Byte ";
|
static const char PROGMEM UnityStrByte[] = " Byte ";
|
||||||
static const char PROGMEM UnityStrMemory[] = " Memory Mismatch.";
|
static const char PROGMEM UnityStrMemory[] = " Memory Mismatch.";
|
||||||
@ -66,9 +67,10 @@ static const char PROGMEM UnityStrBreaker[] = "------------------
|
|||||||
static const char PROGMEM UnityStrResultsTests[] = " Tests ";
|
static const char PROGMEM UnityStrResultsTests[] = " Tests ";
|
||||||
static const char PROGMEM UnityStrResultsFailures[] = " Failures ";
|
static const char PROGMEM UnityStrResultsFailures[] = " Failures ";
|
||||||
static const char PROGMEM UnityStrResultsIgnored[] = " Ignored ";
|
static const char PROGMEM UnityStrResultsIgnored[] = " Ignored ";
|
||||||
|
#ifndef UNITY_EXCLUDE_DETAILS
|
||||||
static const char PROGMEM UnityStrDetail1Name[] = UNITY_DETAIL1_NAME " ";
|
static const char PROGMEM UnityStrDetail1Name[] = UNITY_DETAIL1_NAME " ";
|
||||||
static const char PROGMEM UnityStrDetail2Name[] = " " UNITY_DETAIL2_NAME " ";
|
static const char PROGMEM UnityStrDetail2Name[] = " " UNITY_DETAIL2_NAME " ";
|
||||||
|
#endif
|
||||||
/*-----------------------------------------------
|
/*-----------------------------------------------
|
||||||
* Pretty Printers & Test Result Output Handlers
|
* Pretty Printers & Test Result Output Handlers
|
||||||
*-----------------------------------------------*/
|
*-----------------------------------------------*/
|
||||||
@ -146,121 +148,6 @@ void UnityPrint(const char* string)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-----------------------------------------------*/
|
|
||||||
#ifdef UNITY_INCLUDE_PRINT_FORMATTED
|
|
||||||
void UnityPrintFormatted(const char* format, ...)
|
|
||||||
{
|
|
||||||
const char* pch = format;
|
|
||||||
va_list va;
|
|
||||||
va_start(va, format);
|
|
||||||
|
|
||||||
if (pch != NULL)
|
|
||||||
{
|
|
||||||
while (*pch)
|
|
||||||
{
|
|
||||||
/* format identification character */
|
|
||||||
if (*pch == '%')
|
|
||||||
{
|
|
||||||
pch++;
|
|
||||||
|
|
||||||
if (pch != NULL)
|
|
||||||
{
|
|
||||||
switch (*pch)
|
|
||||||
{
|
|
||||||
case 'd':
|
|
||||||
case 'i':
|
|
||||||
{
|
|
||||||
const int number = va_arg(va, int);
|
|
||||||
UnityPrintNumber((UNITY_INT)number);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#ifndef UNITY_EXCLUDE_FLOAT_PRINT
|
|
||||||
case 'f':
|
|
||||||
case 'g':
|
|
||||||
{
|
|
||||||
const double number = va_arg(va, double);
|
|
||||||
UnityPrintFloat((UNITY_DOUBLE)number);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
case 'u':
|
|
||||||
{
|
|
||||||
const unsigned int number = va_arg(va, unsigned int);
|
|
||||||
UnityPrintNumberUnsigned((UNITY_UINT)number);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'b':
|
|
||||||
{
|
|
||||||
const unsigned int number = va_arg(va, unsigned int);
|
|
||||||
const UNITY_UINT mask = (UNITY_UINT)0 - (UNITY_UINT)1;
|
|
||||||
UNITY_OUTPUT_CHAR('0');
|
|
||||||
UNITY_OUTPUT_CHAR('b');
|
|
||||||
UnityPrintMask(mask, (UNITY_UINT)number);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'x':
|
|
||||||
case 'X':
|
|
||||||
case 'p':
|
|
||||||
{
|
|
||||||
const unsigned int number = va_arg(va, unsigned int);
|
|
||||||
UNITY_OUTPUT_CHAR('0');
|
|
||||||
UNITY_OUTPUT_CHAR('x');
|
|
||||||
UnityPrintNumberHex((UNITY_UINT)number, 8);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'c':
|
|
||||||
{
|
|
||||||
const int ch = va_arg(va, int);
|
|
||||||
UnityPrintChar((const char *)&ch);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 's':
|
|
||||||
{
|
|
||||||
const char * string = va_arg(va, const char *);
|
|
||||||
UnityPrint(string);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case '%':
|
|
||||||
{
|
|
||||||
UnityPrintChar(pch);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
/* print the unknown format character */
|
|
||||||
UNITY_OUTPUT_CHAR('%');
|
|
||||||
UnityPrintChar(pch);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#ifdef UNITY_OUTPUT_COLOR
|
|
||||||
/* print ANSI escape code */
|
|
||||||
else if ((*pch == 27) && (*(pch + 1) == '['))
|
|
||||||
{
|
|
||||||
pch += UnityPrintAnsiEscapeString(pch);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
else if (*pch == '\n')
|
|
||||||
{
|
|
||||||
UNITY_PRINT_EOL();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
UnityPrintChar(pch);
|
|
||||||
}
|
|
||||||
|
|
||||||
pch++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
va_end(va);
|
|
||||||
}
|
|
||||||
#endif /* ! UNITY_INCLUDE_PRINT_FORMATTED */
|
|
||||||
|
|
||||||
/*-----------------------------------------------*/
|
/*-----------------------------------------------*/
|
||||||
void UnityPrintLen(const char* string, const UNITY_UINT32 length)
|
void UnityPrintLen(const char* string, const UNITY_UINT32 length)
|
||||||
{
|
{
|
||||||
@ -558,7 +445,7 @@ void UnityPrintFloat(const UNITY_DOUBLE input_number)
|
|||||||
|
|
||||||
/* build up buffer in reverse order */
|
/* build up buffer in reverse order */
|
||||||
digits = 0;
|
digits = 0;
|
||||||
while ((n != 0) || (digits < (decimals + 1)))
|
while ((n != 0) || (digits <= decimals))
|
||||||
{
|
{
|
||||||
buf[digits++] = (char)('0' + n % 10);
|
buf[digits++] = (char)('0' + n % 10);
|
||||||
n /= 10;
|
n /= 10;
|
||||||
@ -680,6 +567,10 @@ static void UnityAddMsgIfSpecified(const char* msg)
|
|||||||
if (msg)
|
if (msg)
|
||||||
{
|
{
|
||||||
UnityPrint(UnityStrSpacer);
|
UnityPrint(UnityStrSpacer);
|
||||||
|
|
||||||
|
#ifdef UNITY_PRINT_TEST_CONTEXT
|
||||||
|
UNITY_PRINT_TEST_CONTEXT();
|
||||||
|
#endif
|
||||||
#ifndef UNITY_EXCLUDE_DETAILS
|
#ifndef UNITY_EXCLUDE_DETAILS
|
||||||
if (Unity.CurrentDetail1)
|
if (Unity.CurrentDetail1)
|
||||||
{
|
{
|
||||||
@ -863,9 +754,10 @@ void UnityAssertGreaterOrLessOrEqualNumber(const UNITY_INT threshold,
|
|||||||
UnityTestResultsFailBegin(lineNumber);
|
UnityTestResultsFailBegin(lineNumber);
|
||||||
UnityPrint(UnityStrExpected);
|
UnityPrint(UnityStrExpected);
|
||||||
UnityPrintNumberByStyle(actual, style);
|
UnityPrintNumberByStyle(actual, style);
|
||||||
if (compare & UNITY_GREATER_THAN) { UnityPrint(UnityStrGt); }
|
if (compare & UNITY_GREATER_THAN) { UnityPrint(UnityStrGt); }
|
||||||
if (compare & UNITY_SMALLER_THAN) { UnityPrint(UnityStrLt); }
|
if (compare & UNITY_SMALLER_THAN) { UnityPrint(UnityStrLt); }
|
||||||
if (compare & UNITY_EQUAL_TO) { UnityPrint(UnityStrOrEqual); }
|
if (compare & UNITY_EQUAL_TO) { UnityPrint(UnityStrOrEqual); }
|
||||||
|
if (compare == UNITY_NOT_EQUAL) { UnityPrint(UnityStrNotEqual); }
|
||||||
UnityPrintNumberByStyle(threshold, style);
|
UnityPrintNumberByStyle(threshold, style);
|
||||||
UnityAddMsgIfSpecified(msg);
|
UnityAddMsgIfSpecified(msg);
|
||||||
UNITY_FAIL_AND_BAIL;
|
UNITY_FAIL_AND_BAIL;
|
||||||
@ -1110,7 +1002,7 @@ void UnityAssertFloatSpecial(const UNITY_FLOAT actual,
|
|||||||
is_trait = !isinf(actual) && !isnan(actual);
|
is_trait = !isinf(actual) && !isnan(actual);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default: /* including UNITY_FLOAT_INVALID_TRAIT */
|
||||||
trait_index = 0;
|
trait_index = 0;
|
||||||
trait_names[0] = UnityStrInvalidFloatTrait;
|
trait_names[0] = UnityStrInvalidFloatTrait;
|
||||||
break;
|
break;
|
||||||
@ -1250,7 +1142,7 @@ void UnityAssertDoubleSpecial(const UNITY_DOUBLE actual,
|
|||||||
is_trait = !isinf(actual) && !isnan(actual);
|
is_trait = !isinf(actual) && !isnan(actual);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default: /* including UNITY_FLOAT_INVALID_TRAIT */
|
||||||
trait_index = 0;
|
trait_index = 0;
|
||||||
trait_names[0] = UnityStrInvalidFloatTrait;
|
trait_names[0] = UnityStrInvalidFloatTrait;
|
||||||
break;
|
break;
|
||||||
@ -1731,6 +1623,133 @@ UNITY_INTERNAL_PTR UnityDoubleToPtr(const double num)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*-----------------------------------------------
|
||||||
|
* printf helper function
|
||||||
|
*-----------------------------------------------*/
|
||||||
|
#ifdef UNITY_INCLUDE_PRINT_FORMATTED
|
||||||
|
static void UnityPrintFVA(const char* format, va_list va)
|
||||||
|
{
|
||||||
|
const char* pch = format;
|
||||||
|
if (pch != NULL)
|
||||||
|
{
|
||||||
|
while (*pch)
|
||||||
|
{
|
||||||
|
/* format identification character */
|
||||||
|
if (*pch == '%')
|
||||||
|
{
|
||||||
|
pch++;
|
||||||
|
|
||||||
|
if (pch != NULL)
|
||||||
|
{
|
||||||
|
switch (*pch)
|
||||||
|
{
|
||||||
|
case 'd':
|
||||||
|
case 'i':
|
||||||
|
{
|
||||||
|
const int number = va_arg(va, int);
|
||||||
|
UnityPrintNumber((UNITY_INT)number);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#ifndef UNITY_EXCLUDE_FLOAT_PRINT
|
||||||
|
case 'f':
|
||||||
|
case 'g':
|
||||||
|
{
|
||||||
|
const double number = va_arg(va, double);
|
||||||
|
UnityPrintFloat((UNITY_DOUBLE)number);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
case 'u':
|
||||||
|
{
|
||||||
|
const unsigned int number = va_arg(va, unsigned int);
|
||||||
|
UnityPrintNumberUnsigned((UNITY_UINT)number);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'b':
|
||||||
|
{
|
||||||
|
const unsigned int number = va_arg(va, unsigned int);
|
||||||
|
const UNITY_UINT mask = (UNITY_UINT)0 - (UNITY_UINT)1;
|
||||||
|
UNITY_OUTPUT_CHAR('0');
|
||||||
|
UNITY_OUTPUT_CHAR('b');
|
||||||
|
UnityPrintMask(mask, (UNITY_UINT)number);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'x':
|
||||||
|
case 'X':
|
||||||
|
case 'p':
|
||||||
|
{
|
||||||
|
const unsigned int number = va_arg(va, unsigned int);
|
||||||
|
UNITY_OUTPUT_CHAR('0');
|
||||||
|
UNITY_OUTPUT_CHAR('x');
|
||||||
|
UnityPrintNumberHex((UNITY_UINT)number, 8);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'c':
|
||||||
|
{
|
||||||
|
const int ch = va_arg(va, int);
|
||||||
|
UnityPrintChar((const char *)&ch);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 's':
|
||||||
|
{
|
||||||
|
const char * string = va_arg(va, const char *);
|
||||||
|
UnityPrint(string);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case '%':
|
||||||
|
{
|
||||||
|
UnityPrintChar(pch);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
/* print the unknown format character */
|
||||||
|
UNITY_OUTPUT_CHAR('%');
|
||||||
|
UnityPrintChar(pch);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef UNITY_OUTPUT_COLOR
|
||||||
|
/* print ANSI escape code */
|
||||||
|
else if ((*pch == 27) && (*(pch + 1) == '['))
|
||||||
|
{
|
||||||
|
pch += UnityPrintAnsiEscapeString(pch);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
else if (*pch == '\n')
|
||||||
|
{
|
||||||
|
UNITY_PRINT_EOL();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UnityPrintChar(pch);
|
||||||
|
}
|
||||||
|
|
||||||
|
pch++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnityPrintF(const UNITY_LINE_TYPE line, const char* format, ...)
|
||||||
|
{
|
||||||
|
UnityTestResultsBegin(Unity.TestFile, line);
|
||||||
|
UnityPrint("INFO");
|
||||||
|
if(format != NULL)
|
||||||
|
{
|
||||||
|
UnityPrint(": ");
|
||||||
|
va_list va;
|
||||||
|
va_start(va, format);
|
||||||
|
UnityPrintFVA(format, va);
|
||||||
|
va_end(va);
|
||||||
|
}
|
||||||
|
UNITY_PRINT_EOL();
|
||||||
|
}
|
||||||
|
#endif /* ! UNITY_INCLUDE_PRINT_FORMATTED */
|
||||||
|
|
||||||
|
|
||||||
/*-----------------------------------------------
|
/*-----------------------------------------------
|
||||||
* Control Functions
|
* Control Functions
|
||||||
*-----------------------------------------------*/
|
*-----------------------------------------------*/
|
||||||
@ -1746,6 +1765,9 @@ void UnityFail(const char* msg, const UNITY_LINE_TYPE line)
|
|||||||
{
|
{
|
||||||
UNITY_OUTPUT_CHAR(':');
|
UNITY_OUTPUT_CHAR(':');
|
||||||
|
|
||||||
|
#ifdef UNITY_PRINT_TEST_CONTEXT
|
||||||
|
UNITY_PRINT_TEST_CONTEXT();
|
||||||
|
#endif
|
||||||
#ifndef UNITY_EXCLUDE_DETAILS
|
#ifndef UNITY_EXCLUDE_DETAILS
|
||||||
if (Unity.CurrentDetail1)
|
if (Unity.CurrentDetail1)
|
||||||
{
|
{
|
||||||
@ -1800,6 +1822,8 @@ void UnityMessage(const char* msg, const UNITY_LINE_TYPE line)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*-----------------------------------------------*/
|
/*-----------------------------------------------*/
|
||||||
|
/* If we have not defined our own test runner, then include our default test runner to make life easier */
|
||||||
|
#ifndef UNITY_SKIP_DEFAULT_RUNNER
|
||||||
void UnityDefaultTestRun(UnityTestFunction Func, const char* FuncName, const int FuncLineNum)
|
void UnityDefaultTestRun(UnityTestFunction Func, const char* FuncName, const int FuncLineNum)
|
||||||
{
|
{
|
||||||
Unity.CurrentTestName = FuncName;
|
Unity.CurrentTestName = FuncName;
|
||||||
@ -1819,6 +1843,7 @@ void UnityDefaultTestRun(UnityTestFunction Func, const char* FuncName, const int
|
|||||||
UNITY_EXEC_TIME_STOP();
|
UNITY_EXEC_TIME_STOP();
|
||||||
UnityConcludeTest();
|
UnityConcludeTest();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*-----------------------------------------------*/
|
/*-----------------------------------------------*/
|
||||||
void UnitySetTestFile(const char* filename)
|
void UnitySetTestFile(const char* filename)
|
||||||
|
56
test/vendor/ceedling/vendor/unity/src/unity.h
vendored
56
test/vendor/ceedling/vendor/unity/src/unity.h
vendored
@ -1,6 +1,6 @@
|
|||||||
/* ==========================================
|
/* ==========================================
|
||||||
Unity Project - A Test Framework for C
|
Unity Project - A Test Framework for C
|
||||||
Copyright (c) 2007-19 Mike Karlesky, Mark VanderVoord, Greg Williams
|
Copyright (c) 2007-21 Mike Karlesky, Mark VanderVoord, Greg Williams
|
||||||
[Released under MIT License. Please refer to license.txt for details]
|
[Released under MIT License. Please refer to license.txt for details]
|
||||||
========================================== */
|
========================================== */
|
||||||
|
|
||||||
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
#define UNITY_VERSION_MAJOR 2
|
#define UNITY_VERSION_MAJOR 2
|
||||||
#define UNITY_VERSION_MINOR 5
|
#define UNITY_VERSION_MINOR 5
|
||||||
#define UNITY_VERSION_BUILD 0
|
#define UNITY_VERSION_BUILD 4
|
||||||
#define UNITY_VERSION ((UNITY_VERSION_MAJOR << 16) | (UNITY_VERSION_MINOR << 8) | UNITY_VERSION_BUILD)
|
#define UNITY_VERSION ((UNITY_VERSION_MAJOR << 16) | (UNITY_VERSION_MINOR << 8) | UNITY_VERSION_BUILD)
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
@ -104,6 +104,9 @@ void verifyTest(void);
|
|||||||
#define TEST_IGNORE() UNITY_TEST_IGNORE(__LINE__, NULL)
|
#define TEST_IGNORE() UNITY_TEST_IGNORE(__LINE__, NULL)
|
||||||
#define TEST_MESSAGE(message) UnityMessage((message), __LINE__)
|
#define TEST_MESSAGE(message) UnityMessage((message), __LINE__)
|
||||||
#define TEST_ONLY()
|
#define TEST_ONLY()
|
||||||
|
#ifdef UNITY_INCLUDE_PRINT_FORMATTED
|
||||||
|
#define TEST_PRINTF(message, ...) UnityPrintF(__LINE__, (message), __VA_ARGS__)
|
||||||
|
#endif
|
||||||
|
|
||||||
/* It is not necessary for you to call PASS. A PASS condition is assumed if nothing fails.
|
/* It is not necessary for you to call PASS. A PASS condition is assumed if nothing fails.
|
||||||
* This method allows you to abort a test immediately with a PASS state, ignoring the remainder of the test. */
|
* This method allows you to abort a test immediately with a PASS state, ignoring the remainder of the test. */
|
||||||
@ -125,6 +128,8 @@ void verifyTest(void);
|
|||||||
#define TEST_ASSERT_FALSE(condition) UNITY_TEST_ASSERT( !(condition), __LINE__, " Expected FALSE Was TRUE")
|
#define TEST_ASSERT_FALSE(condition) UNITY_TEST_ASSERT( !(condition), __LINE__, " Expected FALSE Was TRUE")
|
||||||
#define TEST_ASSERT_NULL(pointer) UNITY_TEST_ASSERT_NULL( (pointer), __LINE__, " Expected NULL")
|
#define TEST_ASSERT_NULL(pointer) UNITY_TEST_ASSERT_NULL( (pointer), __LINE__, " Expected NULL")
|
||||||
#define TEST_ASSERT_NOT_NULL(pointer) UNITY_TEST_ASSERT_NOT_NULL((pointer), __LINE__, " Expected Non-NULL")
|
#define TEST_ASSERT_NOT_NULL(pointer) UNITY_TEST_ASSERT_NOT_NULL((pointer), __LINE__, " Expected Non-NULL")
|
||||||
|
#define TEST_ASSERT_EMPTY(pointer) UNITY_TEST_ASSERT_EMPTY( (pointer), __LINE__, " Expected Empty")
|
||||||
|
#define TEST_ASSERT_NOT_EMPTY(pointer) UNITY_TEST_ASSERT_NOT_EMPTY((pointer), __LINE__, " Expected Non-Empty")
|
||||||
|
|
||||||
/* Integers (of all sizes) */
|
/* Integers (of all sizes) */
|
||||||
#define TEST_ASSERT_EQUAL_INT(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, NULL)
|
#define TEST_ASSERT_EQUAL_INT(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, NULL)
|
||||||
@ -145,10 +150,28 @@ void verifyTest(void);
|
|||||||
#define TEST_ASSERT_EQUAL_HEX64(expected, actual) UNITY_TEST_ASSERT_EQUAL_HEX64((expected), (actual), __LINE__, NULL)
|
#define TEST_ASSERT_EQUAL_HEX64(expected, actual) UNITY_TEST_ASSERT_EQUAL_HEX64((expected), (actual), __LINE__, NULL)
|
||||||
#define TEST_ASSERT_EQUAL_CHAR(expected, actual) UNITY_TEST_ASSERT_EQUAL_CHAR((expected), (actual), __LINE__, NULL)
|
#define TEST_ASSERT_EQUAL_CHAR(expected, actual) UNITY_TEST_ASSERT_EQUAL_CHAR((expected), (actual), __LINE__, NULL)
|
||||||
#define TEST_ASSERT_BITS(mask, expected, actual) UNITY_TEST_ASSERT_BITS((mask), (expected), (actual), __LINE__, NULL)
|
#define TEST_ASSERT_BITS(mask, expected, actual) UNITY_TEST_ASSERT_BITS((mask), (expected), (actual), __LINE__, NULL)
|
||||||
#define TEST_ASSERT_BITS_HIGH(mask, actual) UNITY_TEST_ASSERT_BITS((mask), (UNITY_UINT32)(-1), (actual), __LINE__, NULL)
|
#define TEST_ASSERT_BITS_HIGH(mask, actual) UNITY_TEST_ASSERT_BITS((mask), (UNITY_UINT)(-1), (actual), __LINE__, NULL)
|
||||||
#define TEST_ASSERT_BITS_LOW(mask, actual) UNITY_TEST_ASSERT_BITS((mask), (UNITY_UINT32)(0), (actual), __LINE__, NULL)
|
#define TEST_ASSERT_BITS_LOW(mask, actual) UNITY_TEST_ASSERT_BITS((mask), (UNITY_UINT)(0), (actual), __LINE__, NULL)
|
||||||
#define TEST_ASSERT_BIT_HIGH(bit, actual) UNITY_TEST_ASSERT_BITS(((UNITY_UINT32)1 << (bit)), (UNITY_UINT32)(-1), (actual), __LINE__, NULL)
|
#define TEST_ASSERT_BIT_HIGH(bit, actual) UNITY_TEST_ASSERT_BITS(((UNITY_UINT)1 << (bit)), (UNITY_UINT)(-1), (actual), __LINE__, NULL)
|
||||||
#define TEST_ASSERT_BIT_LOW(bit, actual) UNITY_TEST_ASSERT_BITS(((UNITY_UINT32)1 << (bit)), (UNITY_UINT32)(0), (actual), __LINE__, NULL)
|
#define TEST_ASSERT_BIT_LOW(bit, actual) UNITY_TEST_ASSERT_BITS(((UNITY_UINT)1 << (bit)), (UNITY_UINT)(0), (actual), __LINE__, NULL)
|
||||||
|
|
||||||
|
/* Integer Not Equal To (of all sizes) */
|
||||||
|
#define TEST_ASSERT_NOT_EQUAL_INT(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_INT((threshold), (actual), __LINE__, NULL)
|
||||||
|
#define TEST_ASSERT_NOT_EQUAL_INT8(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_INT8((threshold), (actual), __LINE__, NULL)
|
||||||
|
#define TEST_ASSERT_NOT_EQUAL_INT16(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_INT16((threshold), (actual), __LINE__, NULL)
|
||||||
|
#define TEST_ASSERT_NOT_EQUAL_INT32(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_INT32((threshold), (actual), __LINE__, NULL)
|
||||||
|
#define TEST_ASSERT_NOT_EQUAL_INT64(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_INT64((threshold), (actual), __LINE__, NULL)
|
||||||
|
#define TEST_ASSERT_NOT_EQUAL_UINT(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_UINT((threshold), (actual), __LINE__, NULL)
|
||||||
|
#define TEST_ASSERT_NOT_EQUAL_UINT8(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_UINT8((threshold), (actual), __LINE__, NULL)
|
||||||
|
#define TEST_ASSERT_NOT_EQUAL_UINT16(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_UINT16((threshold), (actual), __LINE__, NULL)
|
||||||
|
#define TEST_ASSERT_NOT_EQUAL_UINT32(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_UINT32((threshold), (actual), __LINE__, NULL)
|
||||||
|
#define TEST_ASSERT_NOT_EQUAL_UINT64(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_UINT64((threshold), (actual), __LINE__, NULL)
|
||||||
|
#define TEST_ASSERT_NOT_EQUAL_size_t(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_UINT((threshold), (actual), __LINE__, NULL)
|
||||||
|
#define TEST_ASSERT_NOT_EQUAL_HEX8(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_HEX8((threshold), (actual), __LINE__, NULL)
|
||||||
|
#define TEST_ASSERT_NOT_EQUAL_HEX16(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_HEX16((threshold), (actual), __LINE__, NULL)
|
||||||
|
#define TEST_ASSERT_NOT_EQUAL_HEX32(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_HEX32((threshold), (actual), __LINE__, NULL)
|
||||||
|
#define TEST_ASSERT_NOT_EQUAL_HEX64(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_HEX64((threshold), (actual), __LINE__, NULL)
|
||||||
|
#define TEST_ASSERT_NOT_EQUAL_CHAR(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_CHAR((threshold), (actual), __LINE__, NULL)
|
||||||
|
|
||||||
/* Integer Greater Than/ Less Than (of all sizes) */
|
/* Integer Greater Than/ Less Than (of all sizes) */
|
||||||
#define TEST_ASSERT_GREATER_THAN(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT((threshold), (actual), __LINE__, NULL)
|
#define TEST_ASSERT_GREATER_THAN(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT((threshold), (actual), __LINE__, NULL)
|
||||||
@ -373,6 +396,8 @@ void verifyTest(void);
|
|||||||
#define TEST_ASSERT_FALSE_MESSAGE(condition, message) UNITY_TEST_ASSERT( !(condition), __LINE__, (message))
|
#define TEST_ASSERT_FALSE_MESSAGE(condition, message) UNITY_TEST_ASSERT( !(condition), __LINE__, (message))
|
||||||
#define TEST_ASSERT_NULL_MESSAGE(pointer, message) UNITY_TEST_ASSERT_NULL( (pointer), __LINE__, (message))
|
#define TEST_ASSERT_NULL_MESSAGE(pointer, message) UNITY_TEST_ASSERT_NULL( (pointer), __LINE__, (message))
|
||||||
#define TEST_ASSERT_NOT_NULL_MESSAGE(pointer, message) UNITY_TEST_ASSERT_NOT_NULL((pointer), __LINE__, (message))
|
#define TEST_ASSERT_NOT_NULL_MESSAGE(pointer, message) UNITY_TEST_ASSERT_NOT_NULL((pointer), __LINE__, (message))
|
||||||
|
#define TEST_ASSERT_EMPTY_MESSAGE(pointer, message) UNITY_TEST_ASSERT_EMPTY( (pointer), __LINE__, (message))
|
||||||
|
#define TEST_ASSERT_NOT_EMPTY_MESSAGE(pointer, message) UNITY_TEST_ASSERT_NOT_EMPTY((pointer), __LINE__, (message))
|
||||||
|
|
||||||
/* Integers (of all sizes) */
|
/* Integers (of all sizes) */
|
||||||
#define TEST_ASSERT_EQUAL_INT_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, (message))
|
#define TEST_ASSERT_EQUAL_INT_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, (message))
|
||||||
@ -398,6 +423,25 @@ void verifyTest(void);
|
|||||||
#define TEST_ASSERT_BIT_LOW_MESSAGE(bit, actual, message) UNITY_TEST_ASSERT_BITS(((UNITY_UINT32)1 << (bit)), (UNITY_UINT32)(0), (actual), __LINE__, (message))
|
#define TEST_ASSERT_BIT_LOW_MESSAGE(bit, actual, message) UNITY_TEST_ASSERT_BITS(((UNITY_UINT32)1 << (bit)), (UNITY_UINT32)(0), (actual), __LINE__, (message))
|
||||||
#define TEST_ASSERT_EQUAL_CHAR_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_CHAR((expected), (actual), __LINE__, (message))
|
#define TEST_ASSERT_EQUAL_CHAR_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_CHAR((expected), (actual), __LINE__, (message))
|
||||||
|
|
||||||
|
/* Integer Not Equal To (of all sizes) */
|
||||||
|
#define TEST_ASSERT_NOT_EQUAL_INT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_INT((threshold), (actual), __LINE__, (message))
|
||||||
|
#define TEST_ASSERT_NOT_EQUAL_INT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_INT8((threshold), (actual), __LINE__, (message))
|
||||||
|
#define TEST_ASSERT_NOT_EQUAL_INT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_INT16((threshold), (actual), __LINE__, (message))
|
||||||
|
#define TEST_ASSERT_NOT_EQUAL_INT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_INT32((threshold), (actual), __LINE__, (message))
|
||||||
|
#define TEST_ASSERT_NOT_EQUAL_INT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_INT64((threshold), (actual), __LINE__, (message))
|
||||||
|
#define TEST_ASSERT_NOT_EQUAL_UINT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_UINT((threshold), (actual), __LINE__, (message))
|
||||||
|
#define TEST_ASSERT_NOT_EQUAL_UINT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_UINT8((threshold), (actual), __LINE__, (message))
|
||||||
|
#define TEST_ASSERT_NOT_EQUAL_UINT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_UINT16((threshold), (actual), __LINE__, (message))
|
||||||
|
#define TEST_ASSERT_NOT_EQUAL_UINT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_UINT32((threshold), (actual), __LINE__, (message))
|
||||||
|
#define TEST_ASSERT_NOT_EQUAL_UINT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_UINT64((threshold), (actual), __LINE__, (message))
|
||||||
|
#define TEST_ASSERT_NOT_EQUAL_size_t_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_UINT((threshold), (actual), __LINE__, (message))
|
||||||
|
#define TEST_ASSERT_NOT_EQUAL_HEX8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_HEX8((threshold), (actual), __LINE__, (message))
|
||||||
|
#define TEST_ASSERT_NOT_EQUAL_HEX16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_HEX16((threshold), (actual), __LINE__, (message))
|
||||||
|
#define TEST_ASSERT_NOT_EQUAL_HEX32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_HEX32((threshold), (actual), __LINE__, (message))
|
||||||
|
#define TEST_ASSERT_NOT_EQUAL_HEX64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_HEX64((threshold), (actual), __LINE__, (message))
|
||||||
|
#define TEST_ASSERT_NOT_EQUAL_CHAR_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_CHAR((threshold), (actual), __LINE__, (message))
|
||||||
|
|
||||||
|
|
||||||
/* Integer Greater Than/ Less Than (of all sizes) */
|
/* Integer Greater Than/ Less Than (of all sizes) */
|
||||||
#define TEST_ASSERT_GREATER_THAN_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT((threshold), (actual), __LINE__, (message))
|
#define TEST_ASSERT_GREATER_THAN_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT((threshold), (actual), __LINE__, (message))
|
||||||
#define TEST_ASSERT_GREATER_THAN_INT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT((threshold), (actual), __LINE__, (message))
|
#define TEST_ASSERT_GREATER_THAN_INT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT((threshold), (actual), __LINE__, (message))
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/* ==========================================
|
/* ==========================================
|
||||||
Unity Project - A Test Framework for C
|
Unity Project - A Test Framework for C
|
||||||
Copyright (c) 2007-19 Mike Karlesky, Mark VanderVoord, Greg Williams
|
Copyright (c) 2007-21 Mike Karlesky, Mark VanderVoord, Greg Williams
|
||||||
[Released under MIT License. Please refer to license.txt for details]
|
[Released under MIT License. Please refer to license.txt for details]
|
||||||
========================================== */
|
========================================== */
|
||||||
|
|
||||||
@ -40,6 +40,26 @@
|
|||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(__GNUC__) || defined(__clang__)
|
||||||
|
#define UNITY_FUNCTION_ATTR(a) __attribute__((a))
|
||||||
|
#else
|
||||||
|
#define UNITY_FUNCTION_ATTR(a) /* ignore */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef UNITY_NORETURN
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
#if __cplusplus >= 201103L
|
||||||
|
#define UNITY_NORETURN [[ noreturn ]]
|
||||||
|
#endif
|
||||||
|
#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
|
||||||
|
#include <stdnoreturn.h>
|
||||||
|
#define UNITY_NORETURN noreturn
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#ifndef UNITY_NORETURN
|
||||||
|
#define UNITY_NORETURN UNITY_FUNCTION_ATTR(noreturn)
|
||||||
|
#endif
|
||||||
|
|
||||||
/*-------------------------------------------------------
|
/*-------------------------------------------------------
|
||||||
* Guess Widths If Not Specified
|
* Guess Widths If Not Specified
|
||||||
*-------------------------------------------------------*/
|
*-------------------------------------------------------*/
|
||||||
@ -327,7 +347,7 @@ typedef UNITY_FLOAT_TYPE UNITY_FLOAT;
|
|||||||
UnityPrintNumberUnsigned(execTimeMs); \
|
UnityPrintNumberUnsigned(execTimeMs); \
|
||||||
UnityPrint(" ms)"); \
|
UnityPrint(" ms)"); \
|
||||||
}
|
}
|
||||||
#elif defined(__unix__)
|
#elif defined(__unix__) || defined(__APPLE__)
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#define UNITY_TIME_TYPE struct timespec
|
#define UNITY_TIME_TYPE struct timespec
|
||||||
#define UNITY_GET_TIME(t) clock_gettime(CLOCK_MONOTONIC, &t)
|
#define UNITY_GET_TIME(t) clock_gettime(CLOCK_MONOTONIC, &t)
|
||||||
@ -421,6 +441,7 @@ typedef enum
|
|||||||
UNITY_GREATER_OR_EQUAL = 0x2 + UNITY_EQUAL_TO,
|
UNITY_GREATER_OR_EQUAL = 0x2 + UNITY_EQUAL_TO,
|
||||||
UNITY_SMALLER_THAN = 0x4,
|
UNITY_SMALLER_THAN = 0x4,
|
||||||
UNITY_SMALLER_OR_EQUAL = 0x4 + UNITY_EQUAL_TO,
|
UNITY_SMALLER_OR_EQUAL = 0x4 + UNITY_EQUAL_TO,
|
||||||
|
UNITY_NOT_EQUAL = 0x0,
|
||||||
UNITY_UNKNOWN
|
UNITY_UNKNOWN
|
||||||
} UNITY_COMPARISON_T;
|
} UNITY_COMPARISON_T;
|
||||||
|
|
||||||
@ -479,7 +500,12 @@ void UnityBegin(const char* filename);
|
|||||||
int UnityEnd(void);
|
int UnityEnd(void);
|
||||||
void UnitySetTestFile(const char* filename);
|
void UnitySetTestFile(const char* filename);
|
||||||
void UnityConcludeTest(void);
|
void UnityConcludeTest(void);
|
||||||
|
|
||||||
|
#ifndef RUN_TEST
|
||||||
void UnityDefaultTestRun(UnityTestFunction Func, const char* FuncName, const int FuncLineNum);
|
void UnityDefaultTestRun(UnityTestFunction Func, const char* FuncName, const int FuncLineNum);
|
||||||
|
#else
|
||||||
|
#define UNITY_SKIP_DEFAULT_RUNNER
|
||||||
|
#endif
|
||||||
|
|
||||||
/*-------------------------------------------------------
|
/*-------------------------------------------------------
|
||||||
* Details Support
|
* Details Support
|
||||||
@ -503,6 +529,10 @@ void UnityDefaultTestRun(UnityTestFunction Func, const char* FuncName, const int
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef UNITY_PRINT_TEST_CONTEXT
|
||||||
|
void UNITY_PRINT_TEST_CONTEXT(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
/*-------------------------------------------------------
|
/*-------------------------------------------------------
|
||||||
* Test Output
|
* Test Output
|
||||||
*-------------------------------------------------------*/
|
*-------------------------------------------------------*/
|
||||||
@ -510,7 +540,7 @@ void UnityDefaultTestRun(UnityTestFunction Func, const char* FuncName, const int
|
|||||||
void UnityPrint(const char* string);
|
void UnityPrint(const char* string);
|
||||||
|
|
||||||
#ifdef UNITY_INCLUDE_PRINT_FORMATTED
|
#ifdef UNITY_INCLUDE_PRINT_FORMATTED
|
||||||
void UnityPrintFormatted(const char* format, ...);
|
void UnityPrintF(const UNITY_LINE_TYPE line, const char* format, ...);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void UnityPrintLen(const char* string, const UNITY_UINT32 length);
|
void UnityPrintLen(const char* string, const UNITY_UINT32 length);
|
||||||
@ -601,8 +631,14 @@ void UnityAssertNumbersArrayWithin(const UNITY_UINT delta,
|
|||||||
const UNITY_DISPLAY_STYLE_T style,
|
const UNITY_DISPLAY_STYLE_T style,
|
||||||
const UNITY_FLAGS_T flags);
|
const UNITY_FLAGS_T flags);
|
||||||
|
|
||||||
|
#ifndef UNITY_EXCLUDE_SETJMP_H
|
||||||
|
UNITY_NORETURN void UnityFail(const char* message, const UNITY_LINE_TYPE line);
|
||||||
|
UNITY_NORETURN void UnityIgnore(const char* message, const UNITY_LINE_TYPE line);
|
||||||
|
#else
|
||||||
void UnityFail(const char* message, const UNITY_LINE_TYPE line);
|
void UnityFail(const char* message, const UNITY_LINE_TYPE line);
|
||||||
void UnityIgnore(const char* message, const UNITY_LINE_TYPE line);
|
void UnityIgnore(const char* message, const UNITY_LINE_TYPE line);
|
||||||
|
#endif
|
||||||
|
|
||||||
void UnityMessage(const char* message, const UNITY_LINE_TYPE line);
|
void UnityMessage(const char* message, const UNITY_LINE_TYPE line);
|
||||||
|
|
||||||
#ifndef UNITY_EXCLUDE_FLOAT
|
#ifndef UNITY_EXCLUDE_FLOAT
|
||||||
@ -691,11 +727,8 @@ extern const char UnityStrErrShorthand[];
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#ifdef UNITY_SUPPORT_VARIADIC_MACROS
|
#ifdef UNITY_SUPPORT_VARIADIC_MACROS
|
||||||
#define RUN_TEST(...) UnityDefaultTestRun(RUN_TEST_FIRST(__VA_ARGS__), RUN_TEST_SECOND(__VA_ARGS__))
|
#define RUN_TEST(...) RUN_TEST_AT_LINE(__VA_ARGS__, __LINE__, throwaway)
|
||||||
#define RUN_TEST_FIRST(...) RUN_TEST_FIRST_HELPER(__VA_ARGS__, throwaway)
|
#define RUN_TEST_AT_LINE(func, line, ...) UnityDefaultTestRun(func, #func, line)
|
||||||
#define RUN_TEST_FIRST_HELPER(first, ...) (first), #first
|
|
||||||
#define RUN_TEST_SECOND(...) RUN_TEST_SECOND_HELPER(__VA_ARGS__, __LINE__, throwaway)
|
|
||||||
#define RUN_TEST_SECOND_HELPER(first, second, ...) (second)
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -753,9 +786,11 @@ int UnityTestMatches(void);
|
|||||||
* Test Asserts
|
* Test Asserts
|
||||||
*-------------------------------------------------------*/
|
*-------------------------------------------------------*/
|
||||||
|
|
||||||
#define UNITY_TEST_ASSERT(condition, line, message) if (condition) {} else {UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), (message));}
|
#define UNITY_TEST_ASSERT(condition, line, message) do {if (condition) {} else {UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), (message));}} while(0)
|
||||||
#define UNITY_TEST_ASSERT_NULL(pointer, line, message) UNITY_TEST_ASSERT(((pointer) == NULL), (UNITY_LINE_TYPE)(line), (message))
|
#define UNITY_TEST_ASSERT_NULL(pointer, line, message) UNITY_TEST_ASSERT(((pointer) == NULL), (UNITY_LINE_TYPE)(line), (message))
|
||||||
#define UNITY_TEST_ASSERT_NOT_NULL(pointer, line, message) UNITY_TEST_ASSERT(((pointer) != NULL), (UNITY_LINE_TYPE)(line), (message))
|
#define UNITY_TEST_ASSERT_NOT_NULL(pointer, line, message) UNITY_TEST_ASSERT(((pointer) != NULL), (UNITY_LINE_TYPE)(line), (message))
|
||||||
|
#define UNITY_TEST_ASSERT_EMPTY(pointer, line, message) UNITY_TEST_ASSERT(((pointer[0]) == 0), (UNITY_LINE_TYPE)(line), (message))
|
||||||
|
#define UNITY_TEST_ASSERT_NOT_EMPTY(pointer, line, message) UNITY_TEST_ASSERT(((pointer[0]) != 0), (UNITY_LINE_TYPE)(line), (message))
|
||||||
|
|
||||||
#define UNITY_TEST_ASSERT_EQUAL_INT(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT)
|
#define UNITY_TEST_ASSERT_EQUAL_INT(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT)
|
||||||
#define UNITY_TEST_ASSERT_EQUAL_INT8(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_INT8 )(expected), (UNITY_INT)(UNITY_INT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8)
|
#define UNITY_TEST_ASSERT_EQUAL_INT8(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_INT8 )(expected), (UNITY_INT)(UNITY_INT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8)
|
||||||
@ -771,6 +806,19 @@ int UnityTestMatches(void);
|
|||||||
#define UNITY_TEST_ASSERT_EQUAL_CHAR(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_INT8 )(expected), (UNITY_INT)(UNITY_INT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR)
|
#define UNITY_TEST_ASSERT_EQUAL_CHAR(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_INT8 )(expected), (UNITY_INT)(UNITY_INT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR)
|
||||||
#define UNITY_TEST_ASSERT_BITS(mask, expected, actual, line, message) UnityAssertBits((UNITY_INT)(mask), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line))
|
#define UNITY_TEST_ASSERT_BITS(mask, expected, actual, line, message) UnityAssertBits((UNITY_INT)(mask), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line))
|
||||||
|
|
||||||
|
#define UNITY_TEST_ASSERT_NOT_EQUAL_INT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT)
|
||||||
|
#define UNITY_TEST_ASSERT_NOT_EQUAL_INT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8)
|
||||||
|
#define UNITY_TEST_ASSERT_NOT_EQUAL_INT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT16)(threshold), (UNITY_INT)(UNITY_INT16)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16)
|
||||||
|
#define UNITY_TEST_ASSERT_NOT_EQUAL_INT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT32)(threshold), (UNITY_INT)(UNITY_INT32)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32)
|
||||||
|
#define UNITY_TEST_ASSERT_NOT_EQUAL_UINT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT)
|
||||||
|
#define UNITY_TEST_ASSERT_NOT_EQUAL_UINT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8)
|
||||||
|
#define UNITY_TEST_ASSERT_NOT_EQUAL_UINT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16)
|
||||||
|
#define UNITY_TEST_ASSERT_NOT_EQUAL_UINT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32)
|
||||||
|
#define UNITY_TEST_ASSERT_NOT_EQUAL_HEX8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8)
|
||||||
|
#define UNITY_TEST_ASSERT_NOT_EQUAL_HEX16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16)
|
||||||
|
#define UNITY_TEST_ASSERT_NOT_EQUAL_HEX32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32)
|
||||||
|
#define UNITY_TEST_ASSERT_NOT_EQUAL_CHAR(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR)
|
||||||
|
|
||||||
#define UNITY_TEST_ASSERT_GREATER_THAN_INT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT)
|
#define UNITY_TEST_ASSERT_GREATER_THAN_INT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT)
|
||||||
#define UNITY_TEST_ASSERT_GREATER_THAN_INT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8)
|
#define UNITY_TEST_ASSERT_GREATER_THAN_INT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8)
|
||||||
#define UNITY_TEST_ASSERT_GREATER_THAN_INT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT16)(threshold), (UNITY_INT)(UNITY_INT16)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16)
|
#define UNITY_TEST_ASSERT_GREATER_THAN_INT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT16)(threshold), (UNITY_INT)(UNITY_INT16)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16)
|
||||||
@ -841,7 +889,7 @@ int UnityTestMatches(void);
|
|||||||
#define UNITY_TEST_ASSERT_INT16_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT16)(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16, UNITY_ARRAY_TO_ARRAY)
|
#define UNITY_TEST_ASSERT_INT16_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT16)(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16, UNITY_ARRAY_TO_ARRAY)
|
||||||
#define UNITY_TEST_ASSERT_INT32_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT32)(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32, UNITY_ARRAY_TO_ARRAY)
|
#define UNITY_TEST_ASSERT_INT32_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT32)(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32, UNITY_ARRAY_TO_ARRAY)
|
||||||
#define UNITY_TEST_ASSERT_UINT_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin( (delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT, UNITY_ARRAY_TO_ARRAY)
|
#define UNITY_TEST_ASSERT_UINT_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin( (delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT, UNITY_ARRAY_TO_ARRAY)
|
||||||
#define UNITY_TEST_ASSERT_UINT8_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin( (UNITY_UINT16)(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8, UNITY_ARRAY_TO_ARRAY)
|
#define UNITY_TEST_ASSERT_UINT8_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT16)(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8, UNITY_ARRAY_TO_ARRAY)
|
||||||
#define UNITY_TEST_ASSERT_UINT16_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT16)(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16, UNITY_ARRAY_TO_ARRAY)
|
#define UNITY_TEST_ASSERT_UINT16_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT16)(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16, UNITY_ARRAY_TO_ARRAY)
|
||||||
#define UNITY_TEST_ASSERT_UINT32_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT32)(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32, UNITY_ARRAY_TO_ARRAY)
|
#define UNITY_TEST_ASSERT_UINT32_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT32)(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32, UNITY_ARRAY_TO_ARRAY)
|
||||||
#define UNITY_TEST_ASSERT_HEX8_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT8 )(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8, UNITY_ARRAY_TO_ARRAY)
|
#define UNITY_TEST_ASSERT_HEX8_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT8 )(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8, UNITY_ARRAY_TO_ARRAY)
|
||||||
@ -900,6 +948,9 @@ int UnityTestMatches(void);
|
|||||||
#define UNITY_TEST_ASSERT_INT64_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((delta), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64)
|
#define UNITY_TEST_ASSERT_INT64_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((delta), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64)
|
||||||
#define UNITY_TEST_ASSERT_UINT64_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((delta), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64)
|
#define UNITY_TEST_ASSERT_UINT64_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((delta), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64)
|
||||||
#define UNITY_TEST_ASSERT_HEX64_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((delta), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64)
|
#define UNITY_TEST_ASSERT_HEX64_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((delta), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64)
|
||||||
|
#define UNITY_TEST_ASSERT_NOT_EQUAL_INT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64)
|
||||||
|
#define UNITY_TEST_ASSERT_NOT_EQUAL_UINT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64)
|
||||||
|
#define UNITY_TEST_ASSERT_NOT_EQUAL_HEX64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64)
|
||||||
#define UNITY_TEST_ASSERT_GREATER_THAN_INT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64)
|
#define UNITY_TEST_ASSERT_GREATER_THAN_INT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64)
|
||||||
#define UNITY_TEST_ASSERT_GREATER_THAN_UINT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64)
|
#define UNITY_TEST_ASSERT_GREATER_THAN_UINT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64)
|
||||||
#define UNITY_TEST_ASSERT_GREATER_THAN_HEX64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64)
|
#define UNITY_TEST_ASSERT_GREATER_THAN_HEX64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user