1
0
mirror of https://github.com/ThrowTheSwitch/Unity.git synced 2026-01-23 16:35:58 +01:00

45 Commits

Author SHA1 Message Date
Mark VanderVoord
bf560290f6 Merge pull request #656 from ThrowTheSwitch/platform_matrix
unity 2.6 release candidate
2023-11-13 17:06:15 -05:00
Mark VanderVoord
a1b1600e43 Update change log and known issues.
Fix bug with infinity and NaN handling.
2023-11-13 17:03:07 -05:00
Mark VanderVoord
3f7564ea3b Catch up on Ruby style and formatting changes. 2023-11-12 19:07:32 -05:00
Mark VanderVoord
bd32847abf Merge branch 'master' into platform_matrix 2023-11-08 00:16:40 -05:00
Mark VanderVoord
88069f045c Fix docs issues.
Update scripts to match latest rubocop.
Fix hex length of unity printf feature.
2023-11-07 23:48:48 -05:00
Mark VanderVoord
8b0daf153f Merge pull request #675 from nfarid/include-dir
Allowing #including <unity/unity.h>
2023-11-07 22:53:12 -05:00
Mark VanderVoord
b175905940 Merge pull request #701 from stevebroshar/replace-pointer-comparison-with-null-checking
Use null check instead of pointer comparison
2023-10-09 16:15:15 -04:00
SteveBroshar
7d0bcc892e use null check instead of pointer compar 2023-10-08 15:47:22 -05:00
Mark VanderVoord
dcef17bf43 Merge pull request #698 from dreamer-coding-555/add_bdd_feature
Adding bdd feature to Unity test framework
2023-09-19 09:08:12 -04:00
Mark VanderVoord
d3804d0661 Merge pull request #695 from fkjagodzinski/dev/add-user-defined-protect-and-abort
Allow user-defined TEST_PROTECT & TEST_ABORT macros
2023-09-19 07:37:15 -04:00
Michael Gene Brockus (Dreamer)
4403d97d14 Create meson.build 2023-09-15 10:22:26 -06:00
Michael Gene Brockus (Dreamer)
24c175f64f Create readme.md 2023-09-15 10:20:26 -06:00
Michael Gene Brockus (Dreamer)
a4d0150758 Rename bdd.h to unity_bdd.h 2023-09-15 10:13:06 -06:00
Michael Gene Brockus (Dreamer)
de387ef073 Create test_bdd.c 2023-09-15 10:12:34 -06:00
Michael Gene Brockus (Dreamer)
cf13244043 adding stdio 2023-09-15 09:54:32 -06:00
Michael Gene Brockus (Dreamer)
955809048c Create bdd.h 2023-09-15 09:53:34 -06:00
Mark VanderVoord
2775e1b058 Merge pull request #694 from cmachida/master
fix: TEST_PRINTF(): printing 64-bit hex numbers or pointers
2023-09-15 10:39:16 -04:00
Filip Jagodzinski
710bb58c6a Allow user-defined TEST_PROTECT & TEST_ABORT macros
However rare, this update covers real-world use cases where:
- Unity is used to provide the assertion macros only, and an external
  test harness/runner is used for test orchestration/reporting.
- Calling longjmp on a given platform is possible, but has a
  platform-specific (or implementation-specific) set of prerequisites,
e.g. privileged access level.

Enable project-specific customisation of TEST_PROTECT and TEST_ABORT
macros.
- Use the user-defined UNITY_TEST_ABORT if available; fall back to
  default behaviour otherwise.
- Use the user-defined UNITY_TEST_PROTECT if available; fall back to
  default behaviour otherwise.
- These may be defined independently.
2023-09-04 13:36:00 +02:00
cmachida
f3b2de4da2 fix: TEST_PRINTF(): printing 64-bit hex numbers or pointers 2023-08-25 17:19:21 +00:00
Mark VanderVoord
cb03c3afa7 Merge pull request #680 from JamesB192/23g06-unhandled-enumeration
Squash warnings about unhandled enumeration.
2023-08-16 11:04:42 -04:00
Mark VanderVoord
09075ea0f3 Merge pull request #692 from epsilonrt/master
fix: fixes TEST_PRINTF() expansion error #691
2023-08-16 11:02:49 -04:00
Mark VanderVoord
f9c4038341 Merge pull request #690 from ThrowTheSwitch/feature/updated-build-directives
Add/update build directives
2023-08-16 10:15:59 -04:00
Mike Karlesky
5109be3881 Missed renames of TEST_FILE() directive 2023-08-15 21:16:02 -04:00
Mark VanderVoord
20bb4355d7 Merge pull request #685 from jonhenneberg/test_matix_feature
Thanks to @jonhenneberg (especially) and @AJIOB for your work on the TEST_MATRIX feature!
2023-08-13 09:24:03 -04:00
epsilonrt
7a9e25b445 fix: fixes TEST_PRINTF() expansion error #691
fixes TEST_PRINTF() expansion error when no variadic arguments are passed
2023-08-08 22:15:56 +02:00
Michael Karlesky
aa3ca2d572 Add/update build directives
* Renamed macro `TEST_FILE()` to `TEST_SOURCE_FILE()`
* Added macro `TEST_INCLUDE_PATH()`
* Added full comment block for documentation
2023-07-29 20:20:33 -04:00
Jon Hanghøj Henneberg
5baa4580ee Fix file endings 2023-07-15 22:19:46 +02:00
Jon Hanghøj Henneberg
c97a2705b3 Add tests for TEST_MATRIX 2023-07-14 17:04:54 +02:00
Jon Hanghøj Henneberg
5dd2be96fa Add TEST_MATRIX to docs 2023-07-14 17:04:54 +02:00
Jon Hanghøj Henneberg
d593817630 Add TEST_MATIX option for parameterization
Added matrix option for parameterization that generates cases based on
the product of the given arguments.
2023-07-13 22:39:58 +02:00
Mark VanderVoord
1b9199ee38 Merge pull request #684 from detly/expose_assert_options
Expose double support as an option.
2023-07-13 07:36:18 -04:00
Jason Heeris
8a5918b81d Expose double support as an option. 2023-07-13 15:27:48 +08:00
Mark VanderVoord
924d656188 Merge pull request #681 from AJIOB/docs-typo-fix
Fix TEST_CASE description typo
2023-07-10 23:28:47 -04:00
Alex Overchenko
30b1a05c33 Fix TEST_CASE description typo 2023-07-08 23:15:15 +03:00
James Browning
e271a76a11 Squash warnings about unhandled enumeration. 2023-07-06 02:23:04 -07:00
Mark VanderVoord
8a6623990a Merge pull request #677 from ThrowTheSwitch/docs/unity_assertion_reference_fixes
Assertion reference documentation improvements
2023-06-12 14:51:33 -04:00
nfarid
b35f6b0851 Add CMAKE_INSTALL_INCLUDEDIR to INSTALL_INTERFACE's include directory
This allows one to #include <unity/unity.h>
2023-05-30 11:40:39 +01:00
Mark VanderVoord
a7639eeb54 Bump rubocop up to newer ruby versions (in progress) 2023-02-16 16:40:23 -05:00
Mark VanderVoord
7a31075b77 Bump years. 2023-02-06 16:26:36 -05:00
Mark VanderVoord
cd354d9458 Merge branch 'master' into platform_matrix 2023-02-06 15:32:39 -05:00
Mark VanderVoord
36259d46b6 Merge PR #545 2023-02-06 15:15:43 -05:00
Mark VanderVoord
5e4c587ff5 Merge branch 'master' into platform_matrix 2023-02-06 15:03:04 -05:00
Mark VanderVoord
1807cb972d Merge branch 'master' into platform_matrix 2023-02-06 14:52:01 -05:00
Mark VanderVoord
278b8dd3e2 Pull in PR #553.
Bump release.
2023-02-06 14:49:29 -05:00
Mark VanderVoord
43a3256747 Test across multiple versions of Ruby 2023-01-16 16:41:21 -05:00
33 changed files with 826 additions and 142 deletions

View File

@@ -15,6 +15,9 @@ jobs:
unit-tests: unit-tests:
name: "Unit Tests" name: "Unit Tests"
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy:
matrix:
ruby: ['2.7', '3.0', '3.1', '3.2']
steps: steps:
# Install Ruby Testing Tools # Install Ruby Testing Tools
- name: Setup Ruby Testing Tools - name: Setup Ruby Testing Tools

View File

@@ -76,6 +76,7 @@ target_include_directories(${PROJECT_NAME}
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src> $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}> $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}> $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
$<BUILD_INTERFACE:$<$<BOOL:${UNITY_EXTENSION_MEMORY_ENABLED}>:${CMAKE_CURRENT_SOURCE_DIR}/extras/memory/src>> $<BUILD_INTERFACE:$<$<BOOL:${UNITY_EXTENSION_MEMORY_ENABLED}>:${CMAKE_CURRENT_SOURCE_DIR}/extras/memory/src>>
$<BUILD_INTERFACE:$<$<BOOL:${UNITY_EXTENSION_FIXTURE_ENABLED}>:${CMAKE_CURRENT_SOURCE_DIR}/extras/fixture/src>> $<BUILD_INTERFACE:$<$<BOOL:${UNITY_EXTENSION_FIXTURE_ENABLED}>:${CMAKE_CURRENT_SOURCE_DIR}/extras/fixture/src>>
) )

View File

@@ -1,6 +1,6 @@
The MIT License (MIT) The MIT License (MIT)
Copyright (c) <year> 2007-21 Mike Karlesky, Mark VanderVoord, Greg Williams Copyright (c) <year> 2007-23 Mike Karlesky, Mark VanderVoord, Greg Williams
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@@ -1,6 +1,6 @@
# Unity Test ![CI][] # Unity Test ![CI][]
__Copyright (c) 2007 - 2021 Unity Project by Mike Karlesky, Mark VanderVoord, and Greg Williams__ __Copyright (c) 2007 - 2023 Unity Project by Mike Karlesky, Mark VanderVoord, and Greg Williams__
Welcome to the Unity Test Project, one of the main projects of ThrowTheSwitch.org. Welcome to the Unity Test Project, one of the main projects of ThrowTheSwitch.org.
Unity Test is a unit testing framework built for C, with a focus on working with embedded toolchains. Unity Test is a unit testing framework built for C, with a focus on working with embedded toolchains.
@@ -12,6 +12,8 @@ If you'd like to leave the hard work to us, you might be interested in Ceedling,
If you're new to Unity, we encourage you to tour the [getting started guide][]. If you're new to Unity, we encourage you to tour the [getting started guide][].
You can also find the [change log][] and [known issues][] in our documentation.
## Getting Started ## Getting Started
The [docs][] folder contains a [getting started guide][] and much more tips about using Unity. The [docs][] folder contains a [getting started guide][] and much more tips about using Unity.
@@ -54,7 +56,7 @@ The message is output stating why.
Compare two integers for equality and display errors as signed integers. Compare two integers for equality and display errors as signed integers.
A cast will be performed to your natural integer size so often this can just be used. A cast will be performed to your natural integer size so often this can just be used.
When you need to specify the exact size, like when comparing arrays, you can use a specific version: When you need to specify the exact size, you can use a specific version.
TEST_ASSERT_EQUAL_UINT(expected, actual) TEST_ASSERT_EQUAL_UINT(expected, actual)
TEST_ASSERT_EQUAL_UINT8(expected, actual) TEST_ASSERT_EQUAL_UINT8(expected, actual)
@@ -72,7 +74,8 @@ Like INT, there are variants for different sizes also.
TEST_ASSERT_EQUAL_HEX64(expected, actual) TEST_ASSERT_EQUAL_HEX64(expected, actual)
Compares two integers for equality and display errors as hexadecimal. Compares two integers for equality and display errors as hexadecimal.
Like the other integer comparisons, you can specify the size... here the size will also effect how many nibbles are shown (for example, `HEX16` will show 4 nibbles). Like the other integer comparisons, you can specify the size...
here the size will also effect how many nibbles are shown (for example, `HEX16` will show 4 nibbles).
TEST_ASSERT_EQUAL(expected, actual) TEST_ASSERT_EQUAL(expected, actual)
@@ -214,7 +217,8 @@ Fails if the pointer is equal to NULL
TEST_ASSERT_EQUAL_MEMORY(expected, actual, len) TEST_ASSERT_EQUAL_MEMORY(expected, actual, len)
Compare two blocks of memory. Compare two blocks of memory.
This is a good generic assertion for types that can't be coerced into acting like standard types... but since it's a memory compare, you have to be careful that your data types are packed. This is a good generic assertion for types that can't be coerced into acting like standard types...
but since it's a memory compare, you have to be careful that your data types are packed.
### \_MESSAGE ### \_MESSAGE
@@ -224,5 +228,7 @@ This is useful for specifying more information about the problem.
[CI]: https://github.com/ThrowTheSwitch/Unity/workflows/CI/badge.svg [CI]: https://github.com/ThrowTheSwitch/Unity/workflows/CI/badge.svg
[getting started guide]: docs/UnityGettingStartedGuide.md [getting started guide]: docs/UnityGettingStartedGuide.md
[change log]: docs/UnityChangeLog.md
[known issues]: docs/UnityKnownIssues.md
[docs]: docs/ [docs]: docs/
[UnityAssertionsReference.md]: docs/UnityAssertionsReference.md [UnityAssertionsReference.md]: docs/UnityAssertionsReference.md

View File

@@ -12,7 +12,7 @@ def report(message)
if !$colour_output if !$colour_output
$stdout.puts(message) $stdout.puts(message)
else else
message = message.join('\n') if message.class == Array message = message.join('\n') if message.instance_of?(Array)
message.each_line do |line| message.each_line do |line|
line.chomp! line.chomp!
colour = case line colour = case line

View File

@@ -13,7 +13,7 @@ require 'fileutils'
require 'pathname' require 'pathname'
# TEMPLATE_TST # TEMPLATE_TST
TEMPLATE_TST ||= '#ifdef TEST TEMPLATE_TST ||= '#ifdef %5$s
#include "unity.h" #include "unity.h"
@@ -32,7 +32,7 @@ void test_%4$s_NeedToImplement(void)
TEST_IGNORE_MESSAGE("Need to Implement %1$s"); TEST_IGNORE_MESSAGE("Need to Implement %1$s");
} }
#endif // TEST #endif // %5$s
'.freeze '.freeze
# TEMPLATE_SRC # TEMPLATE_SRC
@@ -108,7 +108,8 @@ class UnityModuleGenerator
update_svn: false, update_svn: false,
boilerplates: {}, boilerplates: {},
test_prefix: 'Test', test_prefix: 'Test',
mock_prefix: 'Mock' mock_prefix: 'Mock',
test_define: 'TEST'
} }
end end
@@ -132,9 +133,9 @@ class UnityModuleGenerator
# create triad definition # create triad definition
prefix = @options[:test_prefix] || 'Test' prefix = @options[:test_prefix] || 'Test'
triad = [{ ext: '.c', path: @options[:path_src], prefix: '', template: TEMPLATE_SRC, inc: :src, boilerplate: @options[:boilerplates][:src] }, triad = [{ ext: '.c', path: @options[:path_src], prefix: '', template: TEMPLATE_SRC, inc: :src, boilerplate: @options[:boilerplates][:src] },
{ ext: '.h', path: @options[:path_inc], prefix: '', template: TEMPLATE_INC, inc: :inc, boilerplate: @options[:boilerplates][:inc] }, { ext: '.h', path: @options[:path_inc], prefix: '', template: TEMPLATE_INC, inc: :inc, boilerplate: @options[:boilerplates][:inc] },
{ ext: '.c', path: @options[:path_tst], prefix: prefix, template: TEMPLATE_TST, inc: :tst, boilerplate: @options[:boilerplates][:tst] }] { ext: '.c', path: @options[:path_tst], prefix: prefix, template: TEMPLATE_TST, inc: :tst, boilerplate: @options[:boilerplates][:tst], test_define: @options[:test_define] }]
# prepare the pattern for use # prepare the pattern for use
pattern = (pattern || @options[:pattern] || 'src').downcase pattern = (pattern || @options[:pattern] || 'src').downcase
@@ -154,6 +155,7 @@ class UnityModuleGenerator
path: (Pathname.new("#{cfg[:path]}#{subfolder}") + filename).cleanpath, path: (Pathname.new("#{cfg[:path]}#{subfolder}") + filename).cleanpath,
name: submodule_name, name: submodule_name,
template: cfg[:template], template: cfg[:template],
test_define: cfg[:test_define],
boilerplate: cfg[:boilerplate], boilerplate: cfg[:boilerplate],
includes: case (cfg[:inc]) includes: case (cfg[:inc])
when :src then (@options[:includes][:src] || []) | (pattern_traits[:inc].map { |f| format(f, module_name) }) when :src then (@options[:includes][:src] || []) | (pattern_traits[:inc].map { |f| format(f, module_name) })
@@ -168,18 +170,19 @@ class UnityModuleGenerator
end end
############################ ############################
def neutralize_filename(name, start_cap = true) def neutralize_filename(name, start_cap: true)
return name if name.empty? return name if name.empty?
name = name.split(/(?:\s+|_|(?=[A-Z][a-z]))|(?<=[a-z])(?=[A-Z])/).map(&:capitalize).join('_') name = name.split(/(?:\s+|_|(?=[A-Z][a-z]))|(?<=[a-z])(?=[A-Z])/).map(&:capitalize).join('_')
name = name[0].downcase + name[1..-1] unless start_cap name = name[0].downcase + name[1..] unless start_cap
name name
end end
############################ ############################
def create_filename(part1, part2 = '') def create_filename(part1, part2 = '')
name = part2.empty? ? part1 : part1 + '_' + part2 name = part2.empty? ? part1 : "#{part1}_#{part2}"
case (@options[:naming]) case (@options[:naming])
when 'bumpy' then neutralize_filename(name, false).delete('_') when 'bumpy' then neutralize_filename(name, start_cap: false).delete('_')
when 'camel' then neutralize_filename(name).delete('_') when 'camel' then neutralize_filename(name).delete('_')
when 'snake' then neutralize_filename(name).downcase when 'snake' then neutralize_filename(name).downcase
when 'caps' then neutralize_filename(name).upcase when 'caps' then neutralize_filename(name).upcase
@@ -212,7 +215,8 @@ class UnityModuleGenerator
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.tr('-', '_'), file[:name].upcase.tr('-', '_'),
file[:name].tr('-', '_')]) file[:name].tr('-', '_'),
file[:test_define]])
end end
if @options[:update_svn] if @options[:update_svn]
`svn add \"#{file[:path]}\"` `svn add \"#{file[:path]}\"`
@@ -260,12 +264,12 @@ if $0 == __FILE__
case arg case arg
when /^-d/ then destroy = true when /^-d/ then destroy = true
when /^-u/ then options[:update_svn] = true when /^-u/ then options[:update_svn] = true
when /^-p\"?(\w+)\"?/ then options[:pattern] = Regexp.last_match(1) when /^-p"?(\w+)"?/ then options[:pattern] = Regexp.last_match(1)
when /^-s\"?(.+)\"?/ then options[:path_src] = Regexp.last_match(1) when /^-s"?(.+)"?/ then options[:path_src] = Regexp.last_match(1)
when /^-i\"?(.+)\"?/ then options[:path_inc] = Regexp.last_match(1) when /^-i"?(.+)"?/ then options[:path_inc] = Regexp.last_match(1)
when /^-t\"?(.+)\"?/ then options[:path_tst] = Regexp.last_match(1) when /^-t"?(.+)"?/ then options[:path_tst] = Regexp.last_match(1)
when /^-n\"?(.+)\"?/ then options[:naming] = Regexp.last_match(1) when /^-n"?(.+)"?/ then options[:naming] = Regexp.last_match(1)
when /^-y\"?(.+)\"?/ then options = UnityModuleGenerator.grab_config(Regexp.last_match(1)) when /^-y"?(.+)"?/ then options = UnityModuleGenerator.grab_config(Regexp.last_match(1))
when /^(\w+)/ when /^(\w+)/
raise "ERROR: You can't have more than one Module name specified!" unless module_name.nil? raise "ERROR: You can't have more than one Module name specified!" unless module_name.nil?

View File

@@ -45,6 +45,7 @@ class UnityTestRunnerGenerator
cmdline_args: false, cmdline_args: false,
omit_begin_end: false, omit_begin_end: false,
use_param_tests: false, use_param_tests: false,
use_system_files: true,
include_extensions: '(?:hpp|hh|H|h)', include_extensions: '(?:hpp|hh|H|h)',
source_extensions: '(?:cpp|cc|ino|C|c)' source_extensions: '(?:cpp|cc|ino|C|c)'
} }
@@ -69,7 +70,7 @@ class UnityTestRunnerGenerator
source = source.force_encoding('ISO-8859-1').encode('utf-8', replace: nil) source = source.force_encoding('ISO-8859-1').encode('utf-8', replace: nil)
tests = find_tests(source) tests = find_tests(source)
headers = find_includes(source) headers = find_includes(source)
testfile_includes = (headers[:local] + headers[:system]) testfile_includes = @options[:use_system_files] ? (headers[:local] + headers[:system]) : (headers[:local])
used_mocks = find_mocks(testfile_includes) used_mocks = find_mocks(testfile_includes)
testfile_includes = (testfile_includes - used_mocks) testfile_includes = (testfile_includes - used_mocks)
testfile_includes.delete_if { |inc| inc =~ /(unity|cmock)/ } testfile_includes.delete_if { |inc| inc =~ /(unity|cmock)/ }
@@ -80,7 +81,7 @@ class UnityTestRunnerGenerator
# determine which files were used to return them # determine which files were used to return them
all_files_used = [input_file, output_file] all_files_used = [input_file, output_file]
all_files_used += testfile_includes.map { |filename| filename + '.c' } unless testfile_includes.empty? all_files_used += testfile_includes.map { |filename| "#{filename}.c" } unless testfile_includes.empty?
all_files_used += @options[:includes] unless @options[:includes].empty? all_files_used += @options[:includes] unless @options[:includes].empty?
all_files_used += headers[:linkonly] unless headers[:linkonly].empty? all_files_used += headers[:linkonly] unless headers[:linkonly].empty?
all_files_used.uniq all_files_used.uniq
@@ -132,8 +133,8 @@ 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|TEST_RANGE)\s*\(.*?\)\s*)*)\s*void\s+((?:#{@options[:test_prefix]}).*)\s*\(\s*(.*)\s*\)/m next unless line =~ /^((?:\s*(?:TEST_(?:CASE|RANGE|MATRIX))\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]})\w*)\s*\(\s*(.*)\s*\)/m next unless line =~ /^((?:\s*(?:TEST_(?:CASE|RANGE|MATRIX))\s*\(.*?\)\s*)*)\s*void\s+((?:#{@options[:test_prefix]})\w*)\s*\(\s*(.*)\s*\)/m
arguments = Regexp.last_match(1) arguments = Regexp.last_match(1)
name = Regexp.last_match(2) name = Regexp.last_match(2)
@@ -143,25 +144,38 @@ class UnityTestRunnerGenerator
if @options[:use_param_tests] && !arguments.empty? if @options[:use_param_tests] && !arguments.empty?
args = [] args = []
type_and_args = arguments.split(/TEST_(CASE|RANGE)/) type_and_args = arguments.split(/TEST_(CASE|RANGE|MATRIX)/)
for i in (1...type_and_args.length).step(2) (1...type_and_args.length).step(2).each do |i|
if type_and_args[i] == "CASE" case type_and_args[i]
when 'CASE'
args << type_and_args[i + 1].sub(/^\s*\(\s*(.*?)\s*\)\s*$/m, '\1') args << type_and_args[i + 1].sub(/^\s*\(\s*(.*?)\s*\)\s*$/m, '\1')
next
end
# RANGE when 'RANGE'
args += type_and_args[i + 1].scan(/(\[|<)\s*(-?\d+.?\d*)\s*,\s*(-?\d+.?\d*)\s*,\s*(-?\d+.?\d*)\s*(\]|>)/m).map do |arg_values_str| args += type_and_args[i + 1].scan(/(\[|<)\s*(-?\d+.?\d*)\s*,\s*(-?\d+.?\d*)\s*,\s*(-?\d+.?\d*)\s*(\]|>)/m).map do |arg_values_str|
exclude_end = arg_values_str[0] == '<' && arg_values_str[-1] == '>' exclude_end = arg_values_str[0] == '<' && arg_values_str[-1] == '>'
arg_values_str[1...-1].map do |arg_value_str| arg_values_str[1...-1].map do |arg_value_str|
arg_value_str.include?('.') ? arg_value_str.to_f : arg_value_str.to_i arg_value_str.include?('.') ? arg_value_str.to_f : arg_value_str.to_i
end.push(exclude_end) end.push(exclude_end)
end.map do |arg_values| end.map do |arg_values|
Range.new(arg_values[0], arg_values[1], arg_values[3]).step(arg_values[2]).to_a Range.new(arg_values[0], arg_values[1], arg_values[3]).step(arg_values[2]).to_a
end.reduce(nil) do |result, arg_range_expanded| end.reduce(nil) do |result, arg_range_expanded|
result.nil? ? arg_range_expanded.map { |a| [a] } : result.product(arg_range_expanded) result.nil? ? arg_range_expanded.map { |a| [a] } : result.product(arg_range_expanded)
end.map do |arg_combinations| end.map do |arg_combinations|
arg_combinations.flatten.join(', ') arg_combinations.flatten.join(', ')
end
when 'MATRIX'
single_arg_regex_string = /(?:(?:"(?:\\"|[^\\])*?")+|(?:'\\?.')+|(?:[^\s\]\["',]|\[[\d\S_-]+\])+)/.source
args_regex = /\[((?:\s*#{single_arg_regex_string}\s*,?)*(?:\s*#{single_arg_regex_string})?\s*)\]/m
arg_elements_regex = /\s*(#{single_arg_regex_string})\s*,\s*/m
args += type_and_args[i + 1].scan(args_regex).flatten.map do |arg_values_str|
("#{arg_values_str},").scan(arg_elements_regex)
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 end
end end
@@ -175,7 +189,7 @@ class UnityTestRunnerGenerator
source_lines = source.split("\n") source_lines = source.split("\n")
source_index = 0 source_index = 0
tests_and_line_numbers.size.times do |i| tests_and_line_numbers.size.times do |i|
source_lines[source_index..-1].each_with_index do |line, index| source_lines[source_index..].each_with_index do |line, index|
next unless line =~ /\s+#{tests_and_line_numbers[i][:test]}(?:\s|\()/ next unless line =~ /\s+#{tests_and_line_numbers[i][:test]}(?:\s|\()/
source_index += index source_index += index
@@ -194,12 +208,11 @@ class UnityTestRunnerGenerator
source.gsub!(/\/\/.*$/, '') # remove line comments (all that remain) source.gsub!(/\/\/.*$/, '') # remove line comments (all that remain)
# parse out includes # parse out includes
includes = { {
local: source.scan(/^\s*#include\s+\"\s*(.+\.#{@options[:include_extensions]})\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*(.+\.#{@options[:source_extensions]})\s*\"/).flatten linkonly: source.scan(/^TEST_SOURCE_FILE\(\s*"\s*(.+\.#{@options[:source_extensions]})\s*"/).flatten
} }
includes
end end
def find_mocks(includes) def find_mocks(includes)
@@ -356,7 +369,7 @@ class UnityTestRunnerGenerator
require 'erb' require 'erb'
file = File.read(File.join(__dir__, 'run_test.erb')) file = File.read(File.join(__dir__, 'run_test.erb'))
template = ERB.new(file, trim_mode: '<>') template = ERB.new(file, trim_mode: '<>')
output.puts("\n" + template.result(binding)) output.puts("\n#{template.result(binding)}")
end end
def create_args_wrappers(output, tests) def create_args_wrappers(output, tests)
@@ -446,7 +459,7 @@ class UnityTestRunnerGenerator
end end
def create_h_file(output, filename, tests, testfile_includes, used_mocks) def create_h_file(output, filename, tests, testfile_includes, used_mocks)
filename = File.basename(filename).gsub(/[-\/\\\.\,\s]/, '_').upcase filename = File.basename(filename).gsub(/[-\/\\.,\s]/, '_').upcase
output.puts('/* AUTOGENERATED FILE. DO NOT EDIT. */') output.puts('/* AUTOGENERATED FILE. DO NOT EDIT. */')
output.puts("#ifndef _#{filename}") output.puts("#ifndef _#{filename}")
output.puts("#define _#{filename}\n\n") output.puts("#define _#{filename}\n\n")
@@ -485,7 +498,7 @@ if $0 == __FILE__
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 /\.*\.(?:hpp|hh|H|h)$/ when /\.*\.(?:hpp|hh|H|h)$/

View File

@@ -56,7 +56,7 @@ class ParseOutput
# Set the flag to indicate if there will be an XML output file or not # Set the flag to indicate if there will be an XML output file or not
def test_suite_name=(cli_arg) def test_suite_name=(cli_arg)
@real_test_suite_name = cli_arg @real_test_suite_name = cli_arg
puts 'Real test suite name will be \'' + @real_test_suite_name + '\'' puts "Real test suite name will be '#{@real_test_suite_name}'"
end end
def xml_encode_s(str) def xml_encode_s(str)
@@ -75,7 +75,7 @@ class ParseOutput
# Pushes the suite info as xml to the array list, which will be written later # Pushes the suite info as xml to the array list, which will be written later
def push_xml_output_suite_info def push_xml_output_suite_info
# Insert opening tag at front # Insert opening tag at front
heading = '<testsuite name=' + xml_encode_s(@real_test_suite_name) + ' tests="' + @total_tests.to_s + '" failures="' + @test_failed.to_s + '"' + ' skips="' + @test_ignored.to_s + '">' heading = "<testsuite name=#{xml_encode_s(@real_test_suite_name)} tests=\"#{@total_tests}\" failures=\"#{@test_failed}\" skips=\"#{@test_ignored}\">"
@array_list.insert(0, heading) @array_list.insert(0, heading)
# Push back the closing tag # Push back the closing tag
@array_list.push '</testsuite>' @array_list.push '</testsuite>'
@@ -83,20 +83,20 @@ class ParseOutput
# Pushes xml output data to the array list, which will be written later # Pushes xml output data to the array list, which will be written later
def push_xml_output_passed(test_name, execution_time = 0) def push_xml_output_passed(test_name, execution_time = 0)
@array_list.push ' <testcase classname=' + xml_encode_s(@test_suite) + ' name=' + xml_encode_s(test_name) + ' time=' + xml_encode_s((execution_time / 1000.0).to_s) + ' />' @array_list.push " <testcase classname=#{xml_encode_s(@test_suite)} name=#{xml_encode_s(test_name)} time=#{xml_encode_s((execution_time / 1000.0).to_s)} />"
end end
# Pushes xml output data to the array list, which will be written later # Pushes xml output data to the array list, which will be written later
def push_xml_output_failed(test_name, reason, execution_time = 0) def push_xml_output_failed(test_name, reason, execution_time = 0)
@array_list.push ' <testcase classname=' + xml_encode_s(@test_suite) + ' name=' + xml_encode_s(test_name) + ' time=' + xml_encode_s((execution_time / 1000.0).to_s) + '>' @array_list.push " <testcase classname=#{xml_encode_s(@test_suite)} name=#{xml_encode_s(test_name)} time=#{xml_encode_s((execution_time / 1000.0).to_s)} >"
@array_list.push ' <failure type="ASSERT FAILED">' + reason + '</failure>' @array_list.push " <failure type=\"ASSERT FAILED\">#{reason}</failure>"
@array_list.push ' </testcase>' @array_list.push ' </testcase>'
end end
# Pushes xml output data to the array list, which will be written later # Pushes xml output data to the array list, which will be written later
def push_xml_output_ignored(test_name, reason, execution_time = 0) def push_xml_output_ignored(test_name, reason, execution_time = 0)
@array_list.push ' <testcase classname=' + xml_encode_s(@test_suite) + ' name=' + xml_encode_s(test_name) + ' time=' + xml_encode_s((execution_time / 1000.0).to_s) + '>' @array_list.push " <testcase classname=#{xml_encode_s(@test_suite)} name=#{xml_encode_s(test_name)} time=#{xml_encode_s((execution_time / 1000.0).to_s)} >"
@array_list.push ' <skipped type="TEST IGNORED">' + reason + '</skipped>' @array_list.push " <skipped type=\"TEST IGNORED\">#{reason}</skipped>"
@array_list.push ' </testcase>' @array_list.push ' </testcase>'
end end
@@ -144,7 +144,7 @@ class ParseOutput
test_name = array[1] test_name = array[1]
test_suite_verify(class_name) test_suite_verify(class_name)
reason_array = array[2].split(':') reason_array = array[2].split(':')
reason = reason_array[-1].lstrip.chomp + ' at line: ' + reason_array[-4] reason = "#{reason_array[-1].lstrip.chomp} at line: #{reason_array[-4]}"
printf "%-40s FAILED\n", test_name printf "%-40s FAILED\n", test_name
@@ -189,12 +189,12 @@ class ParseOutput
def test_failed(array) def test_failed(array)
# ':' symbol will be valid in function args now # ':' symbol will be valid in function args now
real_method_name = array[@result_usual_idx - 1..-3].join(':') real_method_name = array[@result_usual_idx - 1..-3].join(':')
array = array[0..@result_usual_idx - 3] + [real_method_name] + array[-2..-1] array = array[0..@result_usual_idx - 3] + [real_method_name] + array[-2..]
last_item = array.length - 1 last_item = array.length - 1
test_time = get_test_time(array[last_item]) test_time = get_test_time(array[last_item])
test_name = array[last_item - 2] test_name = array[last_item - 2]
reason = array[last_item].chomp.lstrip + ' at line: ' + array[last_item - 3] reason = "#{array[last_item].chomp.lstrip} at line: #{array[last_item - 3]}"
class_name = array[@class_name_idx] class_name = array[@class_name_idx]
if test_name.start_with? 'TEST(' if test_name.start_with? 'TEST('
@@ -217,7 +217,7 @@ class ParseOutput
def test_ignored(array) def test_ignored(array)
# ':' symbol will be valid in function args now # ':' symbol will be valid in function args now
real_method_name = array[@result_usual_idx - 1..-3].join(':') real_method_name = array[@result_usual_idx - 1..-3].join(':')
array = array[0..@result_usual_idx - 3] + [real_method_name] + array[-2..-1] array = array[0..@result_usual_idx - 3] + [real_method_name] + array[-2..]
last_item = array.length - 1 last_item = array.length - 1
test_time = get_test_time(array[last_item]) test_time = get_test_time(array[last_item])
@@ -268,7 +268,7 @@ class ParseOutput
def process(file_name) def process(file_name)
@array_list = [] @array_list = []
puts 'Parsing file: ' + file_name puts "Parsing file: #{file_name}"
@test_passed = 0 @test_passed = 0
@test_failed = 0 @test_failed = 0
@@ -333,17 +333,17 @@ class ParseOutput
@test_ignored += 1 @test_ignored += 1
elsif line_array.size >= 4 elsif line_array.size >= 4
# We will check output from color compilation # We will check output from color compilation
if line_array[@result_usual_idx..-1].any? { |l| l.include? 'PASS' } if line_array[@result_usual_idx..].any? { |l| l.include? 'PASS' }
test_passed(line_array) test_passed(line_array)
@test_passed += 1 @test_passed += 1
elsif line_array[@result_usual_idx..-1].any? { |l| l.include? 'FAIL' } elsif line_array[@result_usual_idx..].any? { |l| l.include? 'FAIL' }
test_failed(line_array) test_failed(line_array)
@test_failed += 1 @test_failed += 1
elsif line_array[@result_usual_idx..-2].any? { |l| l.include? 'IGNORE' } elsif line_array[@result_usual_idx..-2].any? { |l| l.include? 'IGNORE' }
test_ignored(line_array) test_ignored(line_array)
@test_ignored += 1 @test_ignored += 1
elsif line_array[@result_usual_idx..-1].any? { |l| l.include? 'IGNORE' } elsif line_array[@result_usual_idx..].any? { |l| l.include? 'IGNORE' }
line_array.push('No reason given (' + get_test_time(line_array[@result_usual_idx..-1]).to_s + ' ms)') line_array.push("No reason given (#{get_test_time(line_array[@result_usual_idx..])} ms)")
test_ignored(line_array) test_ignored(line_array)
@test_ignored += 1 @test_ignored += 1
end end
@@ -353,9 +353,9 @@ class ParseOutput
puts '' puts ''
puts '=================== SUMMARY =====================' puts '=================== SUMMARY ====================='
puts '' puts ''
puts 'Tests Passed : ' + @test_passed.to_s puts "Tests Passed : #{@test_passed}"
puts 'Tests Failed : ' + @test_failed.to_s puts "Tests Failed : #{@test_failed}"
puts 'Tests Ignored : ' + @test_ignored.to_s puts "Tests Ignored : #{@test_ignored}"
return unless @xml_out return unless @xml_out

View File

@@ -99,7 +99,7 @@ class UnityToJUnit
test_file = if test_file_str.length < 2 test_file = if test_file_str.length < 2
result_file result_file
else else
test_file_str[0] + ':' + test_file_str[1] "#{test_file_str[0]}:#{test_file_str[1]}"
end end
result_output[:source][:path] = File.dirname(test_file) result_output[:source][:path] = File.dirname(test_file)
result_output[:source][:file] = File.basename(test_file) result_output[:source][:file] = File.basename(test_file)

View File

@@ -15,6 +15,7 @@ module RakefileHelpers
file = 'test_file_filter.yml' file = 'test_file_filter.yml'
return unless File.exist?(file) return unless File.exist?(file)
filters = YamlHelper.load_file(file) filters = YamlHelper.load_file(file)
@all_files = filters[:all_files] @all_files = filters[:all_files]
@only_files = filters[:only_files] @only_files = filters[:only_files]

View File

@@ -1,6 +1,6 @@
module TypeSanitizer module TypeSanitizer
def self.sanitize_c_identifier(unsanitized) def self.sanitize_c_identifier(unsanitized)
# convert filename to valid C identifier by replacing invalid chars with '_' # convert filename to valid C identifier by replacing invalid chars with '_'
unsanitized.gsub(/[-\/\\\.\,\s]/, '_') unsanitized.gsub(/[-\/\\.,\s]/, '_')
end end
end end

View File

@@ -86,7 +86,11 @@ class UnityTestSummary
def get_details(_result_file, lines) def get_details(_result_file, lines)
results = { failures: [], ignores: [], successes: [] } results = { failures: [], ignores: [], successes: [] }
lines.each do |line| lines.each do |line|
_src_file, _src_line, _test_name, status, _msg = line.split(/:/) status_match = line.match(/^[^:]+:[^:]+:\w+(?:\([^)]*\))?:([^:]+):?/)
next unless status_match
status = status_match.captures[0]
line_out = (@root && (@root != 0) ? "#{@root}#{line}" : line).gsub(/\//, '\\') line_out = (@root && (@root != 0) ? "#{@root}#{line}" : line).gsub(/\//, '\\')
case status case status
when 'IGNORE' then results[:ignores] << line_out when 'IGNORE' then results[:ignores] << line_out
@@ -108,7 +112,7 @@ if $0 == __FILE__
# parse out the command options # parse out the command options
opts, args = ARGV.partition { |v| v =~ /^--\w+/ } opts, args = ARGV.partition { |v| v =~ /^--\w+/ }
opts.map! { |v| v[2..-1].to_sym } opts.map! { |v| v[2..].to_sym }
# create an instance to work with # create an instance to work with
uts = UnityTestSummary.new(opts) uts = UnityTestSummary.new(opts)
@@ -124,7 +128,7 @@ if $0 == __FILE__
uts.targets = results uts.targets = results
# set the root path # set the root path
args[1] ||= Dir.pwd + '/' args[1] ||= "#{Dir.pwd}/"
uts.root = ARGV[1] uts.root = ARGV[1]
# run the summarizer # run the summarizer

View File

@@ -8,8 +8,11 @@ require 'yaml'
module YamlHelper module YamlHelper
def self.load(body) def self.load(body)
YAML.respond_to?(:unsafe_load) ? if YAML.respond_to?(:unsafe_load)
YAML.unsafe_load(body) : YAML.load(body) YAML.unsafe_load(body)
else
YAML.load(body)
end
end end
def self.load_file(file) def self.load_file(file)

93
docs/UnityChangeLog.md Normal file
View File

@@ -0,0 +1,93 @@
# Unity Test - Change Log
## A Note
This document captures significant features and fixes to the Unity project core source files
and scripts. More detail can be found in the history on Github.
This project is now tracking changes in more detail. Previous releases get less detailed as
we move back in histroy.
Prior to 2012, the project was hosted on SourceForge.net
Prior to 2008, the project was an internal project and not released to the public.
## Log
### Unity 2.6.0 ()
New Features:
- Fill out missing variations of arrays, within, etc.
- Add `TEST_PRINTF()`
- Add `TEST_MATRIX()` and `TEST_RANGE()` options and documentation
- Add support for searching `TEST_SOURCE_FILE()` for determining test dependencies
- Add Unity BDD plugin
- Add `UNITY_INCLUDE_EXEC_TIME` option to report test times
- Allow user to override test abort underlying mechanism
Significant Bugfixes:
- More portable validation of NaN and Infinity. Added `UNITY_IS_NAN` and `UNITY_IS_INF` options
- Add `UNITY_PROGMEM` configuration option
- Fix overflow detection of hex values when using arrays
- Fix scripts broken by Ruby standard changes
Other:
- Avoid pointer comparison when one is null to avoid compiler warnings
- Significant improvements to documentation
- Updates to match latest Ruby style specification
- Meson, CMake, PlatformIO builds
### Unity 2.5.2 (January 2021)
- improvements to RUN_TEST macro and generated RUN_TEST
- Fix `UNITY_TEST_ASSERT_BIT(S)_HIGH`
- Cleaner handling of details tracking by CMock
### Unity 2.5.1 (May 2020)
Mostly a bugfix and stability release.
Bonus Features:
- Optional TEST_PRINTF macro
- Improve self-testing procedures.
### Unity 2.5.0 (October 2019)
It's been a LONG time since the last release of Unity. Finally, here it is!
There are too many updates to list here, so some highlights:
- more standards compliant (without giving up on supporting ALL compilers, no matter how quirky)
- many more specialized assertions for better test feedback
- more examples for integrating into your world
- many many bugfixes and tweaks
### Unity 2.4.3 (November 2017)
- Allow suiteSetUp() and suiteTearDown() to be povided as normal C functions
- Fix & Expand Greater Than / Less Than assertions for integers
- Built-in option to colorize test results
- Documentation updates
### Unity 2.4.2 (September 2017)
- Fixed bug in UNTY_TEST_ASSERT_EACH_EQUAL_*
- Added TEST_ASSERT_GREATER_THAN and TEST_ASSERT_LESS_THAN
- Updated Module Generator to stop changing names when no style given
- Cleanup to custom float printing for accuracy
- Cleanup incorrect line numbers are partial name matching
- Reduce warnings from using popular function names as variable names
### Unity 2.4.1 (April 2017)
- test runner generator can inject defines as well as headers
- added a built-in floating point print routine instead of relying on printf
- updated to new coding and naming standard
- updated documentation to be markdown instead of pdf
- fixed many many little bugs, most of which were supplied by the community (you people are awesome!)
- coding standard actually enforced in CI
### Unity 2.4.0 (October, 2016)
- port from SourceForge and numerous bugfixes

View File

@@ -222,6 +222,17 @@ _Example:_
#define UNITY_FLOAT_PRECISION 0.001f #define UNITY_FLOAT_PRECISION 0.001f
``` ```
#### `UNITY_IS_NAN` and `UNITY_IS_INF`
If your toolchain defines `isnan` and `isinf` in `math.h` as macros, nothing needs to be done. If your toolchain doesn't define these, Unity
will create these macros itself. You may override either or both of these defines to specify how you want to evaluate if a number is NaN or Infinity.
_Example:_
```C
#define UNITY_IS_NAN(n) ((n != n) ? 1 : 0)
```
### Miscellaneous ### Miscellaneous
#### `UNITY_EXCLUDE_STDDEF_H` #### `UNITY_EXCLUDE_STDDEF_H`
@@ -399,6 +410,68 @@ _Example:_
#define UNITY_EXCLUDE_SETJMP #define UNITY_EXCLUDE_SETJMP
``` ```
#### `UNITY_TEST_PROTECT`
#### `UNITY_TEST_ABORT`
Unity handles test failures via `setjmp`/`longjmp` pair by default. As mentioned above, you can disable this with `UNITY_EXCLUDE_SETJMP`. You can also customise what happens on every `TEST_PROTECT` and `TEST_ABORT` call. This can be accomplished by providing user-defined `UNITY_TEST_PROTECT` and `UNITY_TEST_ABORT` macros (and these may be defined independently).
`UNITY_TEST_PROTECT` is used as an `if` statement expression, and has to evaluate to `true` on the first call (when saving stack environment with `setjmp`), and to `false` when it returns as a result of a `TEST_ABORT` (when restoring the stack environment with `longjmp`).
Whenever an assert macro fails, `TEST_ABORT` is used to restore the stack environment previously set by `TEST_PROTECT`. This part may be overriden with `UNITY_TEST_ABORT`, e.g. if custom failure handling is needed.
_Example 1:_
Calling `longjmp` on your target is possible, but has a platform-specific (or implementation-specific) set of prerequisites, e.g. privileged access level. You can extend the default behaviour of `TEST_PROTECT` and `TEST_ABORT` as:
`unity_config.h`:
```C
#include "my_custom_test_handlers.h"
#define UNITY_TEST_PROTECT() custom_test_protect()
#define UNITY_TEST_ABORT() custom_test_abort()
```
`my_custom_test_handlers.c`:
```C
int custom_test_protect(void) {
platform_specific_code();
return setjmp(Unity.AbortFrame) == 0;
}
UNITY_NORETURN void custom_test_abort(void) {
more_platform_specific_code();
longjmp(Unity.AbortFrame, 1);
}
```
_Example 2:_
Unity is used to provide the assertion macros only, and an external test harness/runner is used for test orchestration/reporting. In this case you can easily plug your code by overriding `TEST_ABORT` as:
`unity_config.h`:
```C
#include "my_custom_test_handlers.h"
#define UNITY_TEST_PROTECT() 1
#define UNITY_TEST_ABORT() custom_test_abort()
```
`my_custom_test_handlers.c`:
```C
void custom_test_abort(void) {
if (Unity.CurrentTestFailed == 1) {
custom_failed_test_handler();
} else if (Unity.CurrentTestIgnored == 1) {
custom_ignored_test_handler();
}
}
```
#### `UNITY_OUTPUT_COLOR` #### `UNITY_OUTPUT_COLOR`
If you want to add color using ANSI escape codes you can use this define. If you want to add color using ANSI escape codes you can use this define.
@@ -448,7 +521,7 @@ To enable it, use the following example:
#define UNITY_SUPPORT_TEST_CASES #define UNITY_SUPPORT_TEST_CASES
``` ```
You can manually provide required `TEST_CASE` or `TEST_RANGE` macro definitions You can manually provide required `TEST_CASE`, `TEST_RANGE` or `TEST_MATRIX` macro definitions
before including `unity.h`, and they won't be redefined. before including `unity.h`, and they won't be redefined.
If you provide one of the following macros, some of default definitions will not be If you provide one of the following macros, some of default definitions will not be
defined: defined:
@@ -456,8 +529,10 @@ defined:
|---|---| |---|---|
| `UNITY_EXCLUDE_TEST_CASE` | `TEST_CASE` | | `UNITY_EXCLUDE_TEST_CASE` | `TEST_CASE` |
| `UNITY_EXCLUDE_TEST_RANGE` | `TEST_RANGE` | | `UNITY_EXCLUDE_TEST_RANGE` | `TEST_RANGE` |
| `UNITY_EXCLUDE_TEST_MATRIX` | `TEST_MATRIX` |
| `TEST_CASE` | `TEST_CASE` | | `TEST_CASE` | `TEST_CASE` |
| `TEST_RANGE` | `TEST_RANGE` | | `TEST_RANGE` | `TEST_RANGE` |
| `TEST_MATRIX` | `TEST_MATRIX` |
`UNITY_EXCLUDE_TEST_*` defines is not processed by test runner generator script. `UNITY_EXCLUDE_TEST_*` defines is not processed by test runner generator script.
If you exclude one of them from definition, you should provide your own definition If you exclude one of them from definition, you should provide your own definition

View File

@@ -220,7 +220,7 @@ If we use replace comment before test function with the following code:
```C ```C
TEST_CASE(1, 2, 5) TEST_CASE(1, 2, 5)
TEST_CASE(3, 7, 20) TEST_CASE(10, 7, 20)
``` ```
script will generate 2 test calls: script will generate 2 test calls:
@@ -296,6 +296,93 @@ TEST_CASE(4, 8, 30)
TEST_CASE(4, 6, 30) TEST_CASE(4, 6, 30)
``` ```
##### `TEST_MATRIX`
Test matix is an advanced generator. It single call can be converted to zero,
one or few `TEST_CASE` equivalent commands.
That generator will create tests for all cobinations of the provided list. Each argument has to be given as a list of one or more elements in the format `[<parm1>, <param2>, ..., <paramN-1>, <paramN>]`.
All parameters supported by the `TEST_CASE` is supported as arguments:
- Numbers incl type specifiers e.g. `<1>`, `<1u>`, `<1l>`, `<2.3>`, or `<2.3f>`
- Strings incl string concatianion e.g. `<"string">`, or `<"partial" "string">`
- Chars e.g. `<'c'>`
- Enums e.g. `<ENUM_NAME>`
- Elements of arrays e.g. `<data[0]>`
Let's use our `test_demoParamFunction` test for checking, what ranges
will be generated for our single `TEST_RANGE` row:
```C
TEST_MATRIX([3, 4, 7], [10, 8, 2, 1],[30u, 20.0f])
```
Tests execution output will be similar to that text:
```Log
tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(3, 10, 30u):PASS
tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(3, 10, 20.0f):PASS
tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(3, 8, 30u):PASS
tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(3, 8, 20.0f):PASS
tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(3, 2, 30u):PASS
tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(3, 2, 20.0f):PASS
tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(3, 1, 30u):PASS
tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(3, 1, 20.0f):PASS
tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(4, 10, 30u):PASS
tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(4, 10, 20.0f):PASS
tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(4, 8, 30u):PASS
tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(4, 8, 20.0f):PASS
tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(4, 2, 30u):PASS
tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(4, 2, 20.0f):PASS
tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(4, 1, 30u):PASS
tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(4, 1, 20.0f):PASS
tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(7, 10, 30u):PASS
tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(7, 10, 20.0f):PASS
tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(7, 8, 30u):PASS
tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(7, 8, 20.0f):PASS
tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(7, 2, 30u):PASS
tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(7, 2, 20.0f):PASS
tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(7, 1, 30u):PASS
tests/test_unity_parameterizedDemo.c:18:test_demoParamFunction(7, 1, 20.0f):PASS
```
As we can see:
| Parameter | Format | Count of values |
|---|---|---|
| `a` | `[3, 4, 7]` | 2 |
| `b` | `[10, 8, 2, 1]` | 4 |
| `c` | `[30u, 20.0f]` | 2 |
We totally have 2 * 4 * 2 = 16 equal test cases, that can be written as following:
```C
TEST_CASE(3, 10, 30u)
TEST_CASE(3, 10, 20.0f)
TEST_CASE(3, 8, 30u)
TEST_CASE(3, 8, 20.0f)
TEST_CASE(3, 2, 30u)
TEST_CASE(3, 2, 20.0f)
TEST_CASE(3, 1, 30u)
TEST_CASE(3, 1, 20.0f)
TEST_CASE(4, 10, 30u)
TEST_CASE(4, 10, 20.0f)
TEST_CASE(4, 8, 30u)
TEST_CASE(4, 8, 20.0f)
TEST_CASE(4, 2, 30u)
TEST_CASE(4, 2, 20.0f)
TEST_CASE(4, 1, 30u)
TEST_CASE(4, 1, 20.0f)
TEST_CASE(7, 10, 30u)
TEST_CASE(7, 10, 20.0f)
TEST_CASE(7, 8, 30u)
TEST_CASE(7, 8, 20.0f)
TEST_CASE(7, 2, 30u)
TEST_CASE(7, 2, 20.0f)
TEST_CASE(7, 1, 30u)
TEST_CASE(7, 1, 20.0f)
```
### `unity_test_summary.rb` ### `unity_test_summary.rb`
A Unity test file contains one or more test case functions. A Unity test file contains one or more test case functions.

13
docs/UnityKnownIssues.md Normal file
View File

@@ -0,0 +1,13 @@
# Unity Test - Known Issues
## A Note
This project will do its best to keep track of significant bugs that might effect your usage of this
project and its supporting scripts. A more detailed and up-to-date list for cutting edge Unity can
be found on our Github repository.
## Issues
- No built-in validation of no-return functions
- Incomplete support for Printf-style formatting
- Incomplete support for VarArgs

View File

@@ -17,7 +17,7 @@ def load_configuration(config_file)
end end
def configure_clean def configure_clean
CLEAN.include($cfg['compiler']['build_path'] + '*.*') unless $cfg['compiler']['build_path'].nil? CLEAN.include("#{$cfg['compiler']['build_path']}*.*") unless $cfg['compiler']['build_path'].nil?
end end
def configure_toolchain(config_file = DEFAULT_CONFIG_FILE) def configure_toolchain(config_file = DEFAULT_CONFIG_FILE)
@@ -27,7 +27,7 @@ def configure_toolchain(config_file = DEFAULT_CONFIG_FILE)
end end
def unit_test_files def unit_test_files
path = $cfg['compiler']['unit_tests_path'] + 'Test*' + C_EXTENSION path = "#{$cfg['compiler']['unit_tests_path']}Test*#{C_EXTENSION}"
path.tr!('\\', '/') path.tr!('\\', '/')
FileList.new(path) FileList.new(path)
end end
@@ -42,7 +42,7 @@ def extract_headers(filename)
includes = [] includes = []
lines = File.readlines(filename) lines = File.readlines(filename)
lines.each do |line| lines.each do |line|
m = line.match(/^\s*#include\s+\"\s*(.+\.[hH])\s*\"/) m = line.match(/^\s*#include\s+"\s*(.+\.[hH])\s*"/)
includes << m[1] unless m.nil? includes << m[1] unless m.nil?
end end
includes includes
@@ -57,12 +57,11 @@ def find_source_file(header, paths)
end end
def tackit(strings) def tackit(strings)
result = if strings.is_a?(Array) if strings.is_a?(Array)
"\"#{strings.join}\"" "\"#{strings.join}\""
else else
strings strings
end end
result
end end
def squash(prefix, items) def squash(prefix, items)
@@ -80,7 +79,7 @@ def build_compiler_fields
end end
options = squash('', $cfg['compiler']['options']) options = squash('', $cfg['compiler']['options'])
includes = squash($cfg['compiler']['includes']['prefix'], $cfg['compiler']['includes']['items']) includes = squash($cfg['compiler']['includes']['prefix'], $cfg['compiler']['includes']['items'])
includes = includes.gsub(/\\ /, ' ').gsub(/\\\"/, '"').gsub(/\\$/, '') # Remove trailing slashes (for IAR) includes = includes.gsub(/\\ /, ' ').gsub(/\\"/, '"').gsub(/\\$/, '') # Remove trailing slashes (for IAR)
{ command: command, defines: defines, options: options, includes: includes } { command: command, defines: defines, options: options, includes: includes }
end end
@@ -105,18 +104,18 @@ def build_linker_fields
'' ''
else else
squash($cfg['linker']['includes']['prefix'], $cfg['linker']['includes']['items']) squash($cfg['linker']['includes']['prefix'], $cfg['linker']['includes']['items'])
end.gsub(/\\ /, ' ').gsub(/\\\"/, '"').gsub(/\\$/, '') # Remove trailing slashes (for IAR) end.gsub(/\\ /, ' ').gsub(/\\"/, '"').gsub(/\\$/, '') # Remove trailing slashes (for IAR)
{ command: command, options: options, includes: includes } { command: command, options: options, includes: includes }
end end
def link_it(exe_name, obj_list) def link_it(exe_name, obj_list)
linker = build_linker_fields linker = build_linker_fields
cmd_str = "#{linker[:command]}#{linker[:options]}#{linker[:includes]} " + cmd_str = "#{linker[:command]}#{linker[:options]}#{linker[:includes]}"
(obj_list.map { |obj| "#{$cfg['linker']['object_files']['path']}#{obj} " }).join + cmd_str += " #{(obj_list.map { |obj| "#{$cfg['linker']['object_files']['path']}#{obj}" }).join(' ')}"
$cfg['linker']['bin_files']['prefix'] + ' ' + cmd_str += " #{$cfg['linker']['bin_files']['prefix']} "
$cfg['linker']['bin_files']['destination'] + cmd_str += $cfg['linker']['bin_files']['destination']
exe_name + $cfg['linker']['bin_files']['extension'] cmd_str += exe_name + $cfg['linker']['bin_files']['extension']
execute(cmd_str) execute(cmd_str)
end end
@@ -126,7 +125,7 @@ def build_simulator_fields
command = if $cfg['simulator']['path'].nil? command = if $cfg['simulator']['path'].nil?
'' ''
else else
(tackit($cfg['simulator']['path']) + ' ') "#{tackit($cfg['simulator']['path'])} "
end end
pre_support = if $cfg['simulator']['pre_support'].nil? pre_support = if $cfg['simulator']['pre_support'].nil?
'' ''
@@ -189,7 +188,7 @@ def run_tests(test_files)
# Build the test runner (generate if configured to do so) # Build the test runner (generate if configured to do so)
test_base = File.basename(test, C_EXTENSION) test_base = File.basename(test, C_EXTENSION)
runner_name = test_base + '_Runner.c' runner_name = "#{test_base}_Runner.c"
if $cfg['compiler']['runner_path'].nil? if $cfg['compiler']['runner_path'].nil?
runner_path = $cfg['compiler']['build_path'] + runner_name runner_path = $cfg['compiler']['build_path'] + runner_name
test_gen = UnityTestRunnerGenerator.new($cfg_file) test_gen = UnityTestRunnerGenerator.new($cfg_file)

40
extras/bdd/readme.md Normal file
View File

@@ -0,0 +1,40 @@
# Unity Project - BDD Feature
Unity's Behavior-Driven Development (BDD) test feature. It allows developers to structure and describe various phases (Given, When, Then) of a test scenario in a BDD-style format.
## Introduction
This project is based on the Unity framework originally created by Mike Karlesky, Mark VanderVoord, and Greg Williams in 2007. The project extends Unity by providing macros to define BDD structures with descriptive elements. Feature added by Michael Gene Brockus (Dreamer).
## License
This project is distributed under the MIT License. See the [license.txt](license.txt) file for more information.
## Usage
### BDD Macros
The provided BDD macros allow you to structure your test scenarios in a descriptive manner. These macros are for descriptive purposes only and do not have functional behavior.
- `GIVEN(description)`: Describes the "Given" phase of a test scenario.
- `WHEN(description)`: Describes the "When" phase of a test scenario.
- `THEN(description)`: Describes the "Then" phase of a test scenario.
Example usage:
```c
GIVEN("a valid input") {
// Test setup and context
// ...
WHEN("the input is processed") {
// Perform the action
// ...
THEN("the expected outcome occurs") {
// Assert the outcome
// ...
}
}
}
```

View File

@@ -0,0 +1,44 @@
/* Copyright (c) 2023 Michael Gene Brockus (Dreamer) and Contributed to Unity Project
* ==========================================
* Unity Project - A Test Framework for C
* Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
* [Released under MIT License. Please refer to license.txt for details]
* ========================================== */
#ifndef UNITY_BDD_TEST_H_
#define UNITY_BDD_TEST_H_
#ifdef __cplusplus
extern "C"
{
#endif
#include <stdio.h>
/**
* @brief Macros for defining a Behavior-Driven Development (BDD) structure with descriptions.
*
* These macros provide a way to structure and describe different phases (Given, When, Then) of a
* test scenario in a BDD-style format. However, they don't have functional behavior by themselves
* and are used for descriptive purposes.
*/
#define GIVEN(description) \
if (0) { \
printf("Given %s\n", description); \
} else
#define WHEN(description) \
if (0) { \
printf("When %s\n", description); \
} else
#define THEN(description) \
if (0) { \
printf("Then %s\n", description); \
} else
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,9 @@
project('BDD Tester', 'c')
# Add Unity as a dependency
unity_dep = dependency('unity')
# Define your source files
sources = files('test_bdd.c')
executable('tester', sources, dependencies : unity_dep)

128
extras/bdd/test/test_bdd.c Normal file
View File

@@ -0,0 +1,128 @@
/* ==========================================
* Unity Project - A Test Framework for C
* Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
* [Released under MIT License. Please refer to license.txt for details]
* ========================================== */
#include "unity.h"
#include "unity_bdd.h"
void test_bdd_logic_test(void) {
GIVEN("a valid statement is passed")
{
// Set up the context
bool givenExecuted = true;
WHEN("a statement is true")
{
// Perform the login action
bool whenExecuted = true;
THEN("we validate everything was worked")
{
// Check the expected outcome
bool thenExecuted = true;
TEST_ASSERT_TRUE(givenExecuted);
TEST_ASSERT_TRUE(whenExecuted);
TEST_ASSERT_TRUE(thenExecuted);
}
}
}
} // end of case
void test_bdd_user_account(void) {
GIVEN("a user's account with sufficient balance")
{
// Set up the context
float accountBalance = 500.0;
float withdrawalAmount = 200.0;
WHEN("the user requests a withdrawal of $200")
{
// Perform the withdrawal action
if (accountBalance >= withdrawalAmount)
{
accountBalance -= withdrawalAmount;
} // end if
THEN("the withdrawal amount should be deducted from the account balance")
{
// Check the expected outcome
// Simulate the scenario
float compareBalance = 500.0;
TEST_ASSERT_LESS_THAN_FLOAT(accountBalance, compareBalance);
}
}
}
} // end of case
void test_bdd_empty_cart(void) {
GIVEN("a user with an empty shopping cart")
{
// Set up the context
int cartItemCount = 0;
WHEN("the user adds a product to the cart")
{
// Perform the action of adding a product
THEN("the cart item count should increase by 1")
{
// Check the expected outcome
cartItemCount++;
TEST_ASSERT_EQUAL_INT(cartItemCount, 1);
}
}
}
} // end of case
void test_bdd_valid_login(void) {
GIVEN("a registered user with valid credentials")
{
// Set up the context
const char* validUsername = "user123";
const char* validPassword = "pass456";
WHEN("the user provides correct username and password")
{
// Perform the action of user login
const char* inputUsername = "user123";
const char* inputPassword = "pass456";
THEN("the login should be successful")
{
// Check the expected outcome
// Simulate login validation
TEST_ASSERT_EQUAL_STRING(inputUsername, validUsername);
TEST_ASSERT_EQUAL_STRING(inputPassword, validPassword);
}
}
WHEN("the user provides incorrect password")
{
// Perform the action of user login
const char* inputUsername = "user123";
const char* inputPassword = "wrongpass";
THEN("the login should fail with an error message")
{
// Check the expected outcome
// Simulate login validation
TEST_ASSERT_EQUAL_STRING(inputUsername, validUsername);
// TEST_ASSERT_NOT_EQUAL_STRING(inputPassword, validPassword);
}
}
}
} // end of case
int main(void)
{
UnityBegin("test_bdd.c");
RUN_TEST(test_bdd_logic_test);
RUN_TEST(test_bdd_user_account);
RUN_TEST(test_bdd_empty_cart);
RUN_TEST(test_bdd_valid_login);
return UnityEnd();
}

View File

@@ -1,6 +1,6 @@
{ {
"name": "Unity", "name": "Unity",
"version": "2.5.2", "version": "2.6.0",
"keywords": "unit-testing, testing, tdd, testing-framework", "keywords": "unit-testing, testing, tdd, testing-framework",
"description": "Simple Unit Testing for C", "description": "Simple Unit Testing for C",
"homepage": "http://www.throwtheswitch.org/unity", "homepage": "http://www.throwtheswitch.org/unity",

View File

@@ -25,7 +25,9 @@ project('unity', 'c',
build_fixture = get_option('extension_fixture') build_fixture = get_option('extension_fixture')
build_memory = get_option('extension_memory') build_memory = get_option('extension_memory')
support_double = get_option('support_double')
unity_args = []
unity_src = [] unity_src = []
unity_inc = [] unity_inc = []
@@ -42,8 +44,13 @@ if build_memory
subdir('extras/memory/src') subdir('extras/memory/src')
endif endif
if support_double
unity_args += '-DUNITY_INCLUDE_DOUBLE'
endif
unity_lib = static_library(meson.project_name(), unity_lib = static_library(meson.project_name(),
sources: unity_src, sources: unity_src,
c_args: unity_args,
include_directories: unity_inc, include_directories: unity_inc,
install: not meson.is_subproject(), install: not meson.is_subproject(),
) )

View File

@@ -1,2 +1,3 @@
option('extension_fixture', type: 'boolean', value: 'false', description: 'Whether to enable the fixture extension.') option('extension_fixture', type: 'boolean', value: 'false', description: 'Whether to enable the fixture extension.')
option('extension_memory', type: 'boolean', value: 'false', description: 'Whether to enable the memory extension.') option('extension_memory', type: 'boolean', value: 'false', description: 'Whether to enable the memory extension.')
option('support_double', type: 'boolean', value: 'false', description: 'Whether to enable double precision floating point assertions.')

View File

@@ -356,11 +356,11 @@ void UnityPrintFloat(const UNITY_DOUBLE input_number)
{ {
UnityPrint("0"); UnityPrint("0");
} }
else if (isnan(number)) else if (UNITY_IS_NAN(number))
{ {
UnityPrint("nan"); UnityPrint("nan");
} }
else if (isinf(number)) else if (UNITY_IS_INF(number))
{ {
UnityPrint("inf"); UnityPrint("inf");
} }
@@ -895,15 +895,15 @@ void UnityAssertEqualIntArray(UNITY_INTERNAL_PTR expected,
#ifndef UNITY_EXCLUDE_FLOAT #ifndef UNITY_EXCLUDE_FLOAT
/* Wrap this define in a function with variable types as float or double */ /* Wrap this define in a function with variable types as float or double */
#define UNITY_FLOAT_OR_DOUBLE_WITHIN(delta, expected, actual, diff) \ #define UNITY_FLOAT_OR_DOUBLE_WITHIN(delta, expected, actual, diff) \
if (isinf(expected) && isinf(actual) && (((expected) < 0) == ((actual) < 0))) return 1; \ if (UNITY_IS_INF(expected) && UNITY_IS_INF(actual) && (((expected) < 0) == ((actual) < 0))) return 1; \
if (UNITY_NAN_CHECK) return 1; \ if (UNITY_NAN_CHECK) return 1; \
(diff) = (actual) - (expected); \ (diff) = (actual) - (expected); \
if ((diff) < 0) (diff) = -(diff); \ if ((diff) < 0) (diff) = -(diff); \
if ((delta) < 0) (delta) = -(delta); \ if ((delta) < 0) (delta) = -(delta); \
return !(isnan(diff) || isinf(diff) || ((diff) > (delta))) return !(UNITY_IS_NAN(diff) || UNITY_IS_INF(diff) || ((diff) > (delta)))
/* This first part of this condition will catch any NaN or Infinite values */ /* This first part of this condition will catch any NaN or Infinite values */
#ifndef UNITY_NAN_NOT_EQUAL_NAN #ifndef UNITY_NAN_NOT_EQUAL_NAN
#define UNITY_NAN_CHECK isnan(expected) && isnan(actual) #define UNITY_NAN_CHECK UNITY_IS_NAN(expected) && UNITY_IS_NAN(actual)
#else #else
#define UNITY_NAN_CHECK 0 #define UNITY_NAN_CHECK 0
#endif #endif
@@ -954,12 +954,12 @@ void UnityAssertWithinFloatArray(const UNITY_FLOAT delta,
#endif #endif
} }
if (isinf(in_delta)) if (UNITY_IS_INF(in_delta))
{ {
return; /* Arrays will be force equal with infinite delta */ return; /* Arrays will be force equal with infinite delta */
} }
if (isnan(in_delta)) if (UNITY_IS_NAN(in_delta))
{ {
/* Delta must be correct number */ /* Delta must be correct number */
UnityPrintPointlessAndBail(); UnityPrintPointlessAndBail();
@@ -1098,23 +1098,24 @@ void UnityAssertFloatSpecial(const UNITY_FLOAT actual,
{ {
case UNITY_FLOAT_IS_INF: case UNITY_FLOAT_IS_INF:
case UNITY_FLOAT_IS_NOT_INF: case UNITY_FLOAT_IS_NOT_INF:
is_trait = isinf(actual) && (actual > 0); is_trait = UNITY_IS_INF(actual) && (actual > 0);
break; break;
case UNITY_FLOAT_IS_NEG_INF: case UNITY_FLOAT_IS_NEG_INF:
case UNITY_FLOAT_IS_NOT_NEG_INF: case UNITY_FLOAT_IS_NOT_NEG_INF:
is_trait = isinf(actual) && (actual < 0); is_trait = UNITY_IS_INF(actual) && (actual < 0);
break; break;
case UNITY_FLOAT_IS_NAN: case UNITY_FLOAT_IS_NAN:
case UNITY_FLOAT_IS_NOT_NAN: case UNITY_FLOAT_IS_NOT_NAN:
is_trait = isnan(actual) ? 1 : 0; is_trait = UNITY_IS_NAN(actual) ? 1 : 0;
break; break;
case UNITY_FLOAT_IS_DET: /* A determinate number is non infinite and not NaN. */ case UNITY_FLOAT_IS_DET: /* A determinate number is non infinite and not NaN. */
case UNITY_FLOAT_IS_NOT_DET: case UNITY_FLOAT_IS_NOT_DET:
is_trait = !isinf(actual) && !isnan(actual); is_trait = !UNITY_IS_INF(actual) && !UNITY_IS_NAN(actual);
break; break;
case UNITY_FLOAT_INVALID_TRAIT: /* Supress warning */
default: /* including UNITY_FLOAT_INVALID_TRAIT */ default: /* including UNITY_FLOAT_INVALID_TRAIT */
trait_index = 0; trait_index = 0;
trait_names[0] = UnityStrInvalidFloatTrait; trait_names[0] = UnityStrInvalidFloatTrait;
@@ -1181,12 +1182,12 @@ void UnityAssertWithinDoubleArray(const UNITY_DOUBLE delta,
#endif #endif
} }
if (isinf(in_delta)) if (UNITY_IS_INF(in_delta))
{ {
return; /* Arrays will be force equal with infinite delta */ return; /* Arrays will be force equal with infinite delta */
} }
if (isnan(in_delta)) if (UNITY_IS_NAN(in_delta))
{ {
/* Delta must be correct number */ /* Delta must be correct number */
UnityPrintPointlessAndBail(); UnityPrintPointlessAndBail();
@@ -1324,23 +1325,24 @@ void UnityAssertDoubleSpecial(const UNITY_DOUBLE actual,
{ {
case UNITY_FLOAT_IS_INF: case UNITY_FLOAT_IS_INF:
case UNITY_FLOAT_IS_NOT_INF: case UNITY_FLOAT_IS_NOT_INF:
is_trait = isinf(actual) && (actual > 0); is_trait = UNITY_IS_INF(actual) && (actual > 0);
break; break;
case UNITY_FLOAT_IS_NEG_INF: case UNITY_FLOAT_IS_NEG_INF:
case UNITY_FLOAT_IS_NOT_NEG_INF: case UNITY_FLOAT_IS_NOT_NEG_INF:
is_trait = isinf(actual) && (actual < 0); is_trait = UNITY_IS_INF(actual) && (actual < 0);
break; break;
case UNITY_FLOAT_IS_NAN: case UNITY_FLOAT_IS_NAN:
case UNITY_FLOAT_IS_NOT_NAN: case UNITY_FLOAT_IS_NOT_NAN:
is_trait = isnan(actual) ? 1 : 0; is_trait = UNITY_IS_NAN(actual) ? 1 : 0;
break; break;
case UNITY_FLOAT_IS_DET: /* A determinate number is non infinite and not NaN. */ case UNITY_FLOAT_IS_DET: /* A determinate number is non infinite and not NaN. */
case UNITY_FLOAT_IS_NOT_DET: case UNITY_FLOAT_IS_NOT_DET:
is_trait = !isinf(actual) && !isnan(actual); is_trait = !UNITY_IS_INF(actual) && !UNITY_IS_NAN(actual);
break; break;
case UNITY_FLOAT_INVALID_TRAIT: /* Supress warning */
default: /* including UNITY_FLOAT_INVALID_TRAIT */ default: /* including UNITY_FLOAT_INVALID_TRAIT */
trait_index = 0; trait_index = 0;
trait_names[0] = UnityStrInvalidFloatTrait; trait_names[0] = UnityStrInvalidFloatTrait;
@@ -1607,8 +1609,8 @@ void UnityAssertEqualString(const char* expected,
} }
} }
else else
{ /* handle case of one pointers being null (if both null, test should pass) */ { /* fail if either null but not if both */
if (expected != actual) if (expected || actual)
{ {
Unity.CurrentTestFailed = 1; Unity.CurrentTestFailed = 1;
} }
@@ -1647,8 +1649,8 @@ void UnityAssertEqualStringLen(const char* expected,
} }
} }
else else
{ /* handle case of one pointers being null (if both null, test should pass) */ { /* fail if either null but not if both */
if (expected != actual) if (expected || actual)
{ {
Unity.CurrentTestFailed = 1; Unity.CurrentTestFailed = 1;
} }
@@ -2029,15 +2031,22 @@ static void UnityPrintFVA(const char* format, va_list va)
UNITY_EXTRACT_ARG(UNITY_UINT, number, length_mod, va, unsigned int); UNITY_EXTRACT_ARG(UNITY_UINT, number, length_mod, va, unsigned int);
UNITY_OUTPUT_CHAR('0'); UNITY_OUTPUT_CHAR('0');
UNITY_OUTPUT_CHAR('x'); UNITY_OUTPUT_CHAR('x');
UnityPrintNumberHex(number, 8); UnityPrintNumberHex(number, UNITY_MAX_NIBBLES);
break; break;
} }
case 'p': case 'p':
{ {
const unsigned int number = va_arg(va, unsigned int); UNITY_UINT number;
char nibbles_to_print = 8;
if (UNITY_POINTER_WIDTH == 64)
{
length_mod = UNITY_LENGTH_MODIFIER_LONG_LONG;
nibbles_to_print = 16;
}
UNITY_EXTRACT_ARG(UNITY_UINT, number, length_mod, va, unsigned int);
UNITY_OUTPUT_CHAR('0'); UNITY_OUTPUT_CHAR('0');
UNITY_OUTPUT_CHAR('x'); UNITY_OUTPUT_CHAR('x');
UnityPrintNumberHex((UNITY_UINT)number, 8); UnityPrintNumberHex((UNITY_UINT)number, nibbles_to_print);
break; break;
} }
case 'c': case 'c':

View File

@@ -9,8 +9,8 @@
#define UNITY #define UNITY
#define UNITY_VERSION_MAJOR 2 #define UNITY_VERSION_MAJOR 2
#define UNITY_VERSION_MINOR 5 #define UNITY_VERSION_MINOR 6
#define UNITY_VERSION_BUILD 4 #define UNITY_VERSION_BUILD 0
#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
@@ -89,7 +89,7 @@ void verifyTest(void);
* - define UNITY_SUPPORT_TEST_CASES to include the TEST_CASE macro, though really it's mostly about the runner generator script * - define UNITY_SUPPORT_TEST_CASES to include the TEST_CASE macro, though really it's mostly about the runner generator script
* Parameterized Tests * Parameterized Tests
* - you'll want to create a define of TEST_CASE(...) and/or TEST_RANGE(...) which basically evaluates to nothing * - you'll want to create a define of TEST_CASE(...), TEST_RANGE(...) and/or TEST_MATRIX(...) which basically evaluates to nothing
* Tests with Arguments * Tests with Arguments
* - you'll want to define UNITY_USE_COMMAND_LINE_ARGS if you have the test runner passing arguments to Unity * - you'll want to define UNITY_USE_COMMAND_LINE_ARGS if you have the test runner passing arguments to Unity
@@ -105,7 +105,7 @@ void verifyTest(void);
#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 #ifdef UNITY_INCLUDE_PRINT_FORMATTED
#define TEST_PRINTF(message, ...) UnityPrintF(__LINE__, (message), __VA_ARGS__) #define TEST_PRINTF(message, ...) UnityPrintF(__LINE__, (message), ##__VA_ARGS__)
#endif #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.
@@ -113,9 +113,19 @@ void verifyTest(void);
#define TEST_PASS() TEST_ABORT() #define TEST_PASS() TEST_ABORT()
#define TEST_PASS_MESSAGE(message) do { UnityMessage((message), __LINE__); TEST_ABORT(); } while (0) #define TEST_PASS_MESSAGE(message) do { UnityMessage((message), __LINE__); TEST_ABORT(); } while (0)
/* This macro does nothing, but it is useful for build tools (like Ceedling) to make use of this to figure out /*-------------------------------------------------------
* which files should be linked to in order to perform a test. Use it like TEST_FILE("sandwiches.c") */ * Build Directives
#define TEST_FILE(a) *-------------------------------------------------------
* These macros do nothing, but they are useful for additional build context.
* Tools (like Ceedling) can scan for these directives and make use of them for
* per-test-executable #include search paths and linking. */
/* Add source files to a test executable's compilation and linking. Ex: TEST_SOURCE_FILE("sandwiches.c") */
#define TEST_SOURCE_FILE(a)
/* Customize #include search paths for a test executable's compilation. Ex: TEST_INCLUDE_PATH("src/module_a/inc") */
#define TEST_INCLUDE_PATH(a)
/*------------------------------------------------------- /*-------------------------------------------------------
* Test Asserts (simple) * Test Asserts (simple)

View File

@@ -241,16 +241,25 @@
#endif #endif
typedef UNITY_FLOAT_TYPE UNITY_FLOAT; typedef UNITY_FLOAT_TYPE UNITY_FLOAT;
/* isinf & isnan macros should be provided by math.h */ /* isnan macro should be provided by math.h. Override if not macro */
#ifndef isinf #ifndef UNITY_IS_NAN
/* The value of Inf - Inf is NaN */
#define isinf(n) (isnan((n) - (n)) && !isnan(n))
#endif
#ifndef isnan #ifndef isnan
/* NaN is the only floating point value that does NOT equal itself. /* NaN is the only floating point value that does NOT equal itself.
* Therefore if n != n, then it is NaN. */ * Therefore if n != n, then it is NaN. */
#define isnan(n) ((n != n) ? 1 : 0) #define UNITY_IS_NAN(n) ((n != n) ? 1 : 0)
#else
#define UNITY_IS_NAN(n) isnan(n)
#endif
#endif
/* isinf macro should be provided by math.h. Override if not macro */
#ifndef UNITY_IS_INF
#ifndef isinf
/* The value of Inf - Inf is NaN */
#define UNITY_IS_INF(n) (UNITY_IS_NAN((n) - (n)) && !UNITY_IS_NAN(n))
#else
#define UNITY_IS_INF(n) isinf(n)
#endif
#endif #endif
#endif #endif
@@ -759,13 +768,25 @@ extern const char UnityStrErrShorthand[];
* Test Running Macros * Test Running Macros
*-------------------------------------------------------*/ *-------------------------------------------------------*/
#ifdef UNITY_TEST_PROTECT
#define TEST_PROTECT() UNITY_TEST_PROTECT()
#else
#ifndef UNITY_EXCLUDE_SETJMP_H #ifndef UNITY_EXCLUDE_SETJMP_H
#define TEST_PROTECT() (setjmp(Unity.AbortFrame) == 0) #define TEST_PROTECT() (setjmp(Unity.AbortFrame) == 0)
#define TEST_ABORT() longjmp(Unity.AbortFrame, 1)
#else #else
#define TEST_PROTECT() 1 #define TEST_PROTECT() 1
#endif
#endif
#ifdef UNITY_TEST_ABORT
#define TEST_ABORT() UNITY_TEST_ABORT()
#else
#ifndef UNITY_EXCLUDE_SETJMP_H
#define TEST_ABORT() longjmp(Unity.AbortFrame, 1)
#else
#define TEST_ABORT() return #define TEST_ABORT() return
#endif #endif
#endif
/* Automatically enable variadic macros support, if it not enabled before */ /* Automatically enable variadic macros support, if it not enabled before */
#ifndef UNITY_SUPPORT_VARIADIC_MACROS #ifndef UNITY_SUPPORT_VARIADIC_MACROS
@@ -793,6 +814,9 @@ extern const char UnityStrErrShorthand[];
#if !defined(TEST_RANGE) && !defined(UNITY_EXCLUDE_TEST_RANGE) #if !defined(TEST_RANGE) && !defined(UNITY_EXCLUDE_TEST_RANGE)
#define TEST_RANGE(...) #define TEST_RANGE(...)
#endif #endif
#if !defined(TEST_MATRIX) && !defined(UNITY_EXCLUDE_TEST_MATRIX)
#define TEST_MATRIX(...)
#endif
#endif #endif
#endif #endif

View File

@@ -3,7 +3,7 @@
#inherit_from: .rubocop_todo.yml #inherit_from: .rubocop_todo.yml
AllCops: AllCops:
TargetRubyVersion: 2.3 TargetRubyVersion: 3.0
# These are areas where ThrowTheSwitch's coding style diverges from the Ruby standard # These are areas where ThrowTheSwitch's coding style diverges from the Ruby standard
Style/SpecialGlobalVars: Style/SpecialGlobalVars:
@@ -28,6 +28,8 @@ Style/EvalWithLocation:
Enabled: false Enabled: false
Style/MixinUsage: Style/MixinUsage:
Enabled: false Enabled: false
Style/OptionalBooleanParameter:
Enabled: false
# These are also places we diverge... but we will likely comply down the road # These are also places we diverge... but we will likely comply down the road
Style/IfUnlessModifier: Style/IfUnlessModifier:
@@ -36,10 +38,12 @@ Style/FormatStringToken:
Enabled: false Enabled: false
# This is disabled because it seems to get confused over nested hashes # This is disabled because it seems to get confused over nested hashes
Layout/AlignHash: Layout/HashAlignment:
Enabled: false Enabled: false
EnforcedHashRocketStyle: table EnforcedHashRocketStyle: table
EnforcedColonStyle: table EnforcedColonStyle: table
Layout/LineLength:
Enabled: false
# We purposefully use these insecure features because they're what makes Ruby awesome # We purposefully use these insecure features because they're what makes Ruby awesome
Security/Eval: Security/Eval:
@@ -64,8 +68,6 @@ Metrics/ClassLength:
Enabled: false Enabled: false
Metrics/CyclomaticComplexity: Metrics/CyclomaticComplexity:
Enabled: false Enabled: false
Metrics/LineLength:
Enabled: false
Metrics/MethodLength: Metrics/MethodLength:
Enabled: false Enabled: false
Metrics/ModuleLength: Metrics/ModuleLength:

View File

@@ -4,7 +4,7 @@
#include "unity.h" #include "unity.h"
#include "Defs.h" #include "Defs.h"
TEST_FILE("some_file.c") TEST_SOURCE_FILE("some_file.c")
/* Notes about prefixes: /* Notes about prefixes:
test - normal default prefix. these are "always run" tests for this procedure test - normal default prefix. these are "always run" tests for this procedure

View File

@@ -7,6 +7,7 @@
#include <setjmp.h> #include <setjmp.h>
#include <stdio.h> #include <stdio.h>
#include "unity.h" #include "unity.h"
#include "types_for_test.h"
/* Include Passthroughs for Linking Tests */ /* Include Passthroughs for Linking Tests */
void putcharSpy(int c) { (void)putchar(c);} void putcharSpy(int c) { (void)putchar(c);}
@@ -209,6 +210,14 @@ TEST_RANGE([2,
TEST_CASE( TEST_CASE(
6 , 7) 6 , 7)
TEST_MATRIX([7,
8 ,
9, 10],
[
11]
)
void test_SpaceInTestCase(unsigned index, unsigned bigger) void test_SpaceInTestCase(unsigned index, unsigned bigger)
{ {
TEST_ASSERT_EQUAL_UINT32(NextExpectedSpaceIndex, index); TEST_ASSERT_EQUAL_UINT32(NextExpectedSpaceIndex, index);
@@ -216,3 +225,84 @@ void test_SpaceInTestCase(unsigned index, unsigned bigger)
NextExpectedSpaceIndex++; NextExpectedSpaceIndex++;
} }
TEST_MATRIX([1, 5, (2*2)+1, 4])
void test_SingleMatix(unsigned value)
{
TEST_ASSERT_LESS_OR_EQUAL(10, value);
}
TEST_MATRIX([2, 5l, 4u+3, 4ul], [-2, 3])
void test_TwoMatrices(unsigned first, signed second)
{
static unsigned idx = 0;
static const unsigned expected[] =
{
// -2 3
-4, 6, // 2
-10, 15, // 5
-14, 21, // 7
-8, 12, // 4
};
TEST_ASSERT_EQUAL_INT(expected[idx++], first * second);
}
TEST_MATRIX(["String1", "String,2", "Stri" "ng3", "String[4]", "String\"5\""], [-5, 12.5f])
void test_StringsAndNumbersMatrices(const char* str, float number)
{
static unsigned idx = 0;
static const char* expected[] =
{
"String1_-05.00",
"String1_+12.50",
"String,2_-05.00",
"String,2_+12.50",
"String3_-05.00",
"String3_+12.50",
"String[4]_-05.00",
"String[4]_+12.50",
"String\"5\"_-05.00",
"String\"5\"_+12.50",
};
char buf[200] = {0};
snprintf(buf, sizeof(buf), "%s_%+06.2f", str, number);
TEST_ASSERT_EQUAL_STRING(expected[idx++], buf);
}
TEST_MATRIX(
[ENUM_A, ENUM_4, ENUM_C],
[test_arr[0], 7.8f, test_arr[2]],
['a', 'f', '[', ']', '\'', '"'],
)
void test_EnumCharAndArrayMatrices(test_enum_t e, float n, char c)
{
static unsigned enum_idx = 0;
static const test_enum_t exp_enum[3] = {
ENUM_A, ENUM_4, ENUM_C,
};
static unsigned float_idx = 0;
float exp_float[3] = {0};
exp_float[0] = test_arr[0];
exp_float[1] = 7.8f;
exp_float[2] = test_arr[2];
static unsigned char_idx = 0;
static const test_enum_t exp_char[] = {
'a', 'f', '[', ']', '\'', '"'
};
TEST_ASSERT_EQUAL_INT(exp_enum[enum_idx], e);
TEST_ASSERT_EQUAL_FLOAT(exp_float[float_idx], n);
TEST_ASSERT_EQUAL_CHAR(exp_char[char_idx], c);
char_idx = (char_idx + 1) % 6;
if (char_idx == 0.0f)
{
float_idx = (float_idx + 1) % 3;
if (float_idx == 0.0f)
{
enum_idx = (enum_idx + 1) % 3;
}
}
}

View File

@@ -7,10 +7,14 @@
#ifndef TEST_RANGE #ifndef TEST_RANGE
#define TEST_RANGE(...) #define TEST_RANGE(...)
#endif #endif
#ifndef TEST_MATRIX
#define TEST_MATRIX(...)
#endif
TEST_CASE(1, 2, 5) TEST_CASE(1, 2, 5)
TEST_CASE(10, 7, 20) TEST_CASE(10, 7, 20)
TEST_RANGE([3, 4, 1], [10, 5, -2], <30, 31, 1>) TEST_RANGE([3, 4, 1], [10, 5, -2], <30, 31, 1>)
TEST_MATRIX([3, 4, 7], [10, 8, 2, 1],[30u, 20.0f])
void test_demoParamFunction(int a, int b, int c) void test_demoParamFunction(int a, int b, int c)
{ {
TEST_ASSERT_GREATER_THAN_INT(a + b, c); TEST_ASSERT_GREATER_THAN_INT(a + b, c);

View File

@@ -0,0 +1,14 @@
#pragma once
typedef enum {
ENUM_A,
ENUM_2,
ENUM_C,
ENUM_4,
} test_enum_t;
static const float test_arr[] = {
1.2f,
2.3f,
3.4f,
};