mirror of
https://github.com/ThrowTheSwitch/Unity.git
synced 2026-01-23 08:25:58 +01:00
Compare commits
44 Commits
docs/unity
...
platform_m
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a1b1600e43 | ||
|
|
3f7564ea3b | ||
|
|
bd32847abf | ||
|
|
88069f045c | ||
|
|
8b0daf153f | ||
|
|
b175905940 | ||
|
|
7d0bcc892e | ||
|
|
dcef17bf43 | ||
|
|
d3804d0661 | ||
|
|
4403d97d14 | ||
|
|
24c175f64f | ||
|
|
a4d0150758 | ||
|
|
de387ef073 | ||
|
|
cf13244043 | ||
|
|
955809048c | ||
|
|
2775e1b058 | ||
|
|
710bb58c6a | ||
|
|
f3b2de4da2 | ||
|
|
cb03c3afa7 | ||
|
|
09075ea0f3 | ||
|
|
f9c4038341 | ||
|
|
5109be3881 | ||
|
|
20bb4355d7 | ||
|
|
7a9e25b445 | ||
|
|
aa3ca2d572 | ||
|
|
5baa4580ee | ||
|
|
c97a2705b3 | ||
|
|
5dd2be96fa | ||
|
|
d593817630 | ||
|
|
1b9199ee38 | ||
|
|
8a5918b81d | ||
|
|
924d656188 | ||
|
|
30b1a05c33 | ||
|
|
e271a76a11 | ||
|
|
8a6623990a | ||
|
|
b35f6b0851 | ||
|
|
a7639eeb54 | ||
|
|
7a31075b77 | ||
|
|
cd354d9458 | ||
|
|
36259d46b6 | ||
|
|
5e4c587ff5 | ||
|
|
1807cb972d | ||
|
|
278b8dd3e2 | ||
|
|
43a3256747 |
3
.github/workflows/main.yml
vendored
3
.github/workflows/main.yml
vendored
@@ -15,6 +15,9 @@ jobs:
|
||||
unit-tests:
|
||||
name: "Unit Tests"
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
ruby: ['2.7', '3.0', '3.1', '3.2']
|
||||
steps:
|
||||
# Install Ruby Testing Tools
|
||||
- name: Setup Ruby Testing Tools
|
||||
|
||||
@@ -76,6 +76,7 @@ target_include_directories(${PROJECT_NAME}
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
|
||||
$<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_FIXTURE_ENABLED}>:${CMAKE_CURRENT_SOURCE_DIR}/extras/fixture/src>>
|
||||
)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
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
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
14
README.md
14
README.md
@@ -1,6 +1,6 @@
|
||||
# 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.
|
||||
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][].
|
||||
|
||||
You can also find the [change log][] and [known issues][] in our documentation.
|
||||
|
||||
## Getting Started
|
||||
|
||||
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.
|
||||
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_UINT8(expected, actual)
|
||||
@@ -72,7 +74,8 @@ Like INT, there are variants for different sizes also.
|
||||
TEST_ASSERT_EQUAL_HEX64(expected, actual)
|
||||
|
||||
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)
|
||||
|
||||
@@ -214,7 +217,8 @@ Fails if the pointer is equal to NULL
|
||||
TEST_ASSERT_EQUAL_MEMORY(expected, actual, len)
|
||||
|
||||
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
|
||||
|
||||
@@ -224,5 +228,7 @@ This is useful for specifying more information about the problem.
|
||||
|
||||
[CI]: https://github.com/ThrowTheSwitch/Unity/workflows/CI/badge.svg
|
||||
[getting started guide]: docs/UnityGettingStartedGuide.md
|
||||
[change log]: docs/UnityChangeLog.md
|
||||
[known issues]: docs/UnityKnownIssues.md
|
||||
[docs]: docs/
|
||||
[UnityAssertionsReference.md]: docs/UnityAssertionsReference.md
|
||||
|
||||
@@ -12,7 +12,7 @@ def report(message)
|
||||
if !$colour_output
|
||||
$stdout.puts(message)
|
||||
else
|
||||
message = message.join('\n') if message.class == Array
|
||||
message = message.join('\n') if message.instance_of?(Array)
|
||||
message.each_line do |line|
|
||||
line.chomp!
|
||||
colour = case line
|
||||
|
||||
@@ -13,7 +13,7 @@ require 'fileutils'
|
||||
require 'pathname'
|
||||
|
||||
# TEMPLATE_TST
|
||||
TEMPLATE_TST ||= '#ifdef TEST
|
||||
TEMPLATE_TST ||= '#ifdef %5$s
|
||||
|
||||
#include "unity.h"
|
||||
|
||||
@@ -32,7 +32,7 @@ void test_%4$s_NeedToImplement(void)
|
||||
TEST_IGNORE_MESSAGE("Need to Implement %1$s");
|
||||
}
|
||||
|
||||
#endif // TEST
|
||||
#endif // %5$s
|
||||
'.freeze
|
||||
|
||||
# TEMPLATE_SRC
|
||||
@@ -108,7 +108,8 @@ class UnityModuleGenerator
|
||||
update_svn: false,
|
||||
boilerplates: {},
|
||||
test_prefix: 'Test',
|
||||
mock_prefix: 'Mock'
|
||||
mock_prefix: 'Mock',
|
||||
test_define: 'TEST'
|
||||
}
|
||||
end
|
||||
|
||||
@@ -132,9 +133,9 @@ class UnityModuleGenerator
|
||||
|
||||
# create triad definition
|
||||
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: '.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
|
||||
pattern = (pattern || @options[:pattern] || 'src').downcase
|
||||
@@ -154,6 +155,7 @@ class UnityModuleGenerator
|
||||
path: (Pathname.new("#{cfg[:path]}#{subfolder}") + filename).cleanpath,
|
||||
name: submodule_name,
|
||||
template: cfg[:template],
|
||||
test_define: cfg[:test_define],
|
||||
boilerplate: cfg[:boilerplate],
|
||||
includes: case (cfg[:inc])
|
||||
when :src then (@options[:includes][:src] || []) | (pattern_traits[:inc].map { |f| format(f, module_name) })
|
||||
@@ -168,18 +170,19 @@ class UnityModuleGenerator
|
||||
end
|
||||
|
||||
############################
|
||||
def neutralize_filename(name, start_cap = true)
|
||||
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(&:capitalize).join('_')
|
||||
name = name[0].downcase + name[1..-1] unless start_cap
|
||||
name = name[0].downcase + name[1..] unless start_cap
|
||||
name
|
||||
end
|
||||
|
||||
############################
|
||||
def create_filename(part1, part2 = '')
|
||||
name = part2.empty? ? part1 : part1 + '_' + part2
|
||||
name = part2.empty? ? part1 : "#{part1}_#{part2}"
|
||||
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 'snake' then neutralize_filename(name).downcase
|
||||
when 'caps' then neutralize_filename(name).upcase
|
||||
@@ -212,7 +215,8 @@ class UnityModuleGenerator
|
||||
f.write(file[:template] % [file[:name],
|
||||
file[:includes].map { |ff| "#include \"#{ff}\"\n" }.join,
|
||||
file[:name].upcase.tr('-', '_'),
|
||||
file[:name].tr('-', '_')])
|
||||
file[:name].tr('-', '_'),
|
||||
file[:test_define]])
|
||||
end
|
||||
if @options[:update_svn]
|
||||
`svn add \"#{file[:path]}\"`
|
||||
@@ -260,12 +264,12 @@ if $0 == __FILE__
|
||||
case arg
|
||||
when /^-d/ then destroy = true
|
||||
when /^-u/ then options[:update_svn] = true
|
||||
when /^-p\"?(\w+)\"?/ then options[:pattern] = 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 /^-t\"?(.+)\"?/ then options[:path_tst] = 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 /^-p"?(\w+)"?/ then options[:pattern] = 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 /^-t"?(.+)"?/ then options[:path_tst] = 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 /^(\w+)/
|
||||
raise "ERROR: You can't have more than one Module name specified!" unless module_name.nil?
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@ class UnityTestRunnerGenerator
|
||||
cmdline_args: false,
|
||||
omit_begin_end: false,
|
||||
use_param_tests: false,
|
||||
use_system_files: true,
|
||||
include_extensions: '(?:hpp|hh|H|h)',
|
||||
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)
|
||||
tests = find_tests(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)
|
||||
testfile_includes = (testfile_includes - used_mocks)
|
||||
testfile_includes.delete_if { |inc| inc =~ /(unity|cmock)/ }
|
||||
@@ -80,7 +81,7 @@ class UnityTestRunnerGenerator
|
||||
|
||||
# determine which files were used to return them
|
||||
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 += headers[:linkonly] unless headers[:linkonly].empty?
|
||||
all_files_used.uniq
|
||||
@@ -132,8 +133,8 @@ class UnityTestRunnerGenerator
|
||||
|
||||
lines.each_with_index do |line, _index|
|
||||
# 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|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]}).*)\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)
|
||||
name = Regexp.last_match(2)
|
||||
@@ -143,25 +144,38 @@ class UnityTestRunnerGenerator
|
||||
|
||||
if @options[:use_param_tests] && !arguments.empty?
|
||||
args = []
|
||||
type_and_args = arguments.split(/TEST_(CASE|RANGE)/)
|
||||
for i in (1...type_and_args.length).step(2)
|
||||
if type_and_args[i] == "CASE"
|
||||
type_and_args = arguments.split(/TEST_(CASE|RANGE|MATRIX)/)
|
||||
(1...type_and_args.length).step(2).each do |i|
|
||||
case type_and_args[i]
|
||||
when 'CASE'
|
||||
args << type_and_args[i + 1].sub(/^\s*\(\s*(.*?)\s*\)\s*$/m, '\1')
|
||||
next
|
||||
end
|
||||
|
||||
# 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|
|
||||
exclude_end = arg_values_str[0] == '<' && arg_values_str[-1] == '>'
|
||||
arg_values_str[1...-1].map do |arg_value_str|
|
||||
arg_value_str.include?('.') ? arg_value_str.to_f : arg_value_str.to_i
|
||||
end.push(exclude_end)
|
||||
end.map do |arg_values|
|
||||
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|
|
||||
result.nil? ? arg_range_expanded.map { |a| [a] } : result.product(arg_range_expanded)
|
||||
end.map do |arg_combinations|
|
||||
arg_combinations.flatten.join(', ')
|
||||
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|
|
||||
exclude_end = arg_values_str[0] == '<' && arg_values_str[-1] == '>'
|
||||
arg_values_str[1...-1].map do |arg_value_str|
|
||||
arg_value_str.include?('.') ? arg_value_str.to_f : arg_value_str.to_i
|
||||
end.push(exclude_end)
|
||||
end.map do |arg_values|
|
||||
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|
|
||||
result.nil? ? arg_range_expanded.map { |a| [a] } : result.product(arg_range_expanded)
|
||||
end.map do |arg_combinations|
|
||||
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
|
||||
@@ -175,7 +189,7 @@ class UnityTestRunnerGenerator
|
||||
source_lines = source.split("\n")
|
||||
source_index = 0
|
||||
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|\()/
|
||||
|
||||
source_index += index
|
||||
@@ -194,12 +208,11 @@ class UnityTestRunnerGenerator
|
||||
source.gsub!(/\/\/.*$/, '') # remove line comments (all that remain)
|
||||
|
||||
# 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}>" },
|
||||
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
|
||||
|
||||
def find_mocks(includes)
|
||||
@@ -356,7 +369,7 @@ class UnityTestRunnerGenerator
|
||||
require 'erb'
|
||||
file = File.read(File.join(__dir__, 'run_test.erb'))
|
||||
template = ERB.new(file, trim_mode: '<>')
|
||||
output.puts("\n" + template.result(binding))
|
||||
output.puts("\n#{template.result(binding)}")
|
||||
end
|
||||
|
||||
def create_args_wrappers(output, tests)
|
||||
@@ -446,7 +459,7 @@ class UnityTestRunnerGenerator
|
||||
end
|
||||
|
||||
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("#ifndef _#{filename}")
|
||||
output.puts("#define _#{filename}\n\n")
|
||||
@@ -485,7 +498,7 @@ if $0 == __FILE__
|
||||
when /\.*\.ya?ml$/
|
||||
options = UnityTestRunnerGenerator.grab_config(arg)
|
||||
true
|
||||
when /--(\w+)=\"?(.*)\"?/
|
||||
when /--(\w+)="?(.*)"?/
|
||||
options[Regexp.last_match(1).to_sym] = Regexp.last_match(2)
|
||||
true
|
||||
when /\.*\.(?:hpp|hh|H|h)$/
|
||||
|
||||
@@ -56,7 +56,7 @@ class ParseOutput
|
||||
# Set the flag to indicate if there will be an XML output file or not
|
||||
def 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
|
||||
|
||||
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
|
||||
def push_xml_output_suite_info
|
||||
# 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)
|
||||
# Push back the closing tag
|
||||
@array_list.push '</testsuite>'
|
||||
@@ -83,20 +83,20 @@ class ParseOutput
|
||||
|
||||
# Pushes xml output data to the array list, which will be written later
|
||||
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
|
||||
|
||||
# Pushes xml output data to the array list, which will be written later
|
||||
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 ' <failure type="ASSERT FAILED">' + reason + '</failure>'
|
||||
@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 ' </testcase>'
|
||||
end
|
||||
|
||||
# Pushes xml output data to the array list, which will be written later
|
||||
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 ' <skipped type="TEST IGNORED">' + reason + '</skipped>'
|
||||
@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 ' </testcase>'
|
||||
end
|
||||
|
||||
@@ -144,7 +144,7 @@ class ParseOutput
|
||||
test_name = array[1]
|
||||
test_suite_verify(class_name)
|
||||
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
|
||||
|
||||
@@ -189,12 +189,12 @@ class ParseOutput
|
||||
def test_failed(array)
|
||||
# ':' symbol will be valid in function args now
|
||||
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
|
||||
test_time = get_test_time(array[last_item])
|
||||
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]
|
||||
|
||||
if test_name.start_with? 'TEST('
|
||||
@@ -217,7 +217,7 @@ class ParseOutput
|
||||
def test_ignored(array)
|
||||
# ':' symbol will be valid in function args now
|
||||
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
|
||||
test_time = get_test_time(array[last_item])
|
||||
@@ -268,7 +268,7 @@ class ParseOutput
|
||||
def process(file_name)
|
||||
@array_list = []
|
||||
|
||||
puts 'Parsing file: ' + file_name
|
||||
puts "Parsing file: #{file_name}"
|
||||
|
||||
@test_passed = 0
|
||||
@test_failed = 0
|
||||
@@ -333,17 +333,17 @@ class ParseOutput
|
||||
@test_ignored += 1
|
||||
elsif line_array.size >= 4
|
||||
# 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 += 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 += 1
|
||||
elsif line_array[@result_usual_idx..-2].any? { |l| l.include? 'IGNORE' }
|
||||
test_ignored(line_array)
|
||||
@test_ignored += 1
|
||||
elsif line_array[@result_usual_idx..-1].any? { |l| l.include? 'IGNORE' }
|
||||
line_array.push('No reason given (' + get_test_time(line_array[@result_usual_idx..-1]).to_s + ' ms)')
|
||||
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..])} ms)")
|
||||
test_ignored(line_array)
|
||||
@test_ignored += 1
|
||||
end
|
||||
@@ -353,9 +353,9 @@ class ParseOutput
|
||||
puts ''
|
||||
puts '=================== SUMMARY ====================='
|
||||
puts ''
|
||||
puts 'Tests Passed : ' + @test_passed.to_s
|
||||
puts 'Tests Failed : ' + @test_failed.to_s
|
||||
puts 'Tests Ignored : ' + @test_ignored.to_s
|
||||
puts "Tests Passed : #{@test_passed}"
|
||||
puts "Tests Failed : #{@test_failed}"
|
||||
puts "Tests Ignored : #{@test_ignored}"
|
||||
|
||||
return unless @xml_out
|
||||
|
||||
|
||||
@@ -99,7 +99,7 @@ class UnityToJUnit
|
||||
test_file = if test_file_str.length < 2
|
||||
result_file
|
||||
else
|
||||
test_file_str[0] + ':' + test_file_str[1]
|
||||
"#{test_file_str[0]}:#{test_file_str[1]}"
|
||||
end
|
||||
result_output[:source][:path] = File.dirname(test_file)
|
||||
result_output[:source][:file] = File.basename(test_file)
|
||||
|
||||
@@ -15,6 +15,7 @@ module RakefileHelpers
|
||||
|
||||
file = 'test_file_filter.yml'
|
||||
return unless File.exist?(file)
|
||||
|
||||
filters = YamlHelper.load_file(file)
|
||||
@all_files = filters[:all_files]
|
||||
@only_files = filters[:only_files]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module TypeSanitizer
|
||||
def self.sanitize_c_identifier(unsanitized)
|
||||
# convert filename to valid C identifier by replacing invalid chars with '_'
|
||||
unsanitized.gsub(/[-\/\\\.\,\s]/, '_')
|
||||
unsanitized.gsub(/[-\/\\.,\s]/, '_')
|
||||
end
|
||||
end
|
||||
|
||||
@@ -86,7 +86,11 @@ class UnityTestSummary
|
||||
def get_details(_result_file, lines)
|
||||
results = { failures: [], ignores: [], successes: [] }
|
||||
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(/\//, '\\')
|
||||
case status
|
||||
when 'IGNORE' then results[:ignores] << line_out
|
||||
@@ -108,7 +112,7 @@ if $0 == __FILE__
|
||||
|
||||
# parse out the command options
|
||||
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
|
||||
uts = UnityTestSummary.new(opts)
|
||||
@@ -124,7 +128,7 @@ if $0 == __FILE__
|
||||
uts.targets = results
|
||||
|
||||
# set the root path
|
||||
args[1] ||= Dir.pwd + '/'
|
||||
args[1] ||= "#{Dir.pwd}/"
|
||||
uts.root = ARGV[1]
|
||||
|
||||
# run the summarizer
|
||||
|
||||
@@ -8,8 +8,11 @@ require 'yaml'
|
||||
|
||||
module YamlHelper
|
||||
def self.load(body)
|
||||
YAML.respond_to?(:unsafe_load) ?
|
||||
YAML.unsafe_load(body) : YAML.load(body)
|
||||
if YAML.respond_to?(:unsafe_load)
|
||||
YAML.unsafe_load(body)
|
||||
else
|
||||
YAML.load(body)
|
||||
end
|
||||
end
|
||||
|
||||
def self.load_file(file)
|
||||
|
||||
93
docs/UnityChangeLog.md
Normal file
93
docs/UnityChangeLog.md
Normal 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
|
||||
@@ -222,6 +222,17 @@ _Example:_
|
||||
#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
|
||||
|
||||
#### `UNITY_EXCLUDE_STDDEF_H`
|
||||
@@ -399,6 +410,68 @@ _Example:_
|
||||
#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`
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
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.
|
||||
If you provide one of the following macros, some of default definitions will not be
|
||||
defined:
|
||||
@@ -456,8 +529,10 @@ defined:
|
||||
|---|---|
|
||||
| `UNITY_EXCLUDE_TEST_CASE` | `TEST_CASE` |
|
||||
| `UNITY_EXCLUDE_TEST_RANGE` | `TEST_RANGE` |
|
||||
| `UNITY_EXCLUDE_TEST_MATRIX` | `TEST_MATRIX` |
|
||||
| `TEST_CASE` | `TEST_CASE` |
|
||||
| `TEST_RANGE` | `TEST_RANGE` |
|
||||
| `TEST_MATRIX` | `TEST_MATRIX` |
|
||||
|
||||
`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
|
||||
|
||||
@@ -220,7 +220,7 @@ If we use replace comment before test function with the following code:
|
||||
|
||||
```C
|
||||
TEST_CASE(1, 2, 5)
|
||||
TEST_CASE(3, 7, 20)
|
||||
TEST_CASE(10, 7, 20)
|
||||
```
|
||||
|
||||
script will generate 2 test calls:
|
||||
@@ -296,6 +296,93 @@ TEST_CASE(4, 8, 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`
|
||||
|
||||
A Unity test file contains one or more test case functions.
|
||||
|
||||
13
docs/UnityKnownIssues.md
Normal file
13
docs/UnityKnownIssues.md
Normal 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
|
||||
@@ -17,7 +17,7 @@ def load_configuration(config_file)
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
def configure_toolchain(config_file = DEFAULT_CONFIG_FILE)
|
||||
@@ -27,7 +27,7 @@ def configure_toolchain(config_file = DEFAULT_CONFIG_FILE)
|
||||
end
|
||||
|
||||
def unit_test_files
|
||||
path = $cfg['compiler']['unit_tests_path'] + 'Test*' + C_EXTENSION
|
||||
path = "#{$cfg['compiler']['unit_tests_path']}Test*#{C_EXTENSION}"
|
||||
path.tr!('\\', '/')
|
||||
FileList.new(path)
|
||||
end
|
||||
@@ -42,7 +42,7 @@ def extract_headers(filename)
|
||||
includes = []
|
||||
lines = File.readlines(filename)
|
||||
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?
|
||||
end
|
||||
includes
|
||||
@@ -57,12 +57,11 @@ def find_source_file(header, paths)
|
||||
end
|
||||
|
||||
def tackit(strings)
|
||||
result = if strings.is_a?(Array)
|
||||
"\"#{strings.join}\""
|
||||
else
|
||||
strings
|
||||
end
|
||||
result
|
||||
if strings.is_a?(Array)
|
||||
"\"#{strings.join}\""
|
||||
else
|
||||
strings
|
||||
end
|
||||
end
|
||||
|
||||
def squash(prefix, items)
|
||||
@@ -80,7 +79,7 @@ def build_compiler_fields
|
||||
end
|
||||
options = squash('', $cfg['compiler']['options'])
|
||||
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 }
|
||||
end
|
||||
@@ -105,18 +104,18 @@ def build_linker_fields
|
||||
''
|
||||
else
|
||||
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 }
|
||||
end
|
||||
|
||||
def link_it(exe_name, obj_list)
|
||||
linker = build_linker_fields
|
||||
cmd_str = "#{linker[:command]}#{linker[:options]}#{linker[:includes]} " +
|
||||
(obj_list.map { |obj| "#{$cfg['linker']['object_files']['path']}#{obj} " }).join +
|
||||
$cfg['linker']['bin_files']['prefix'] + ' ' +
|
||||
$cfg['linker']['bin_files']['destination'] +
|
||||
exe_name + $cfg['linker']['bin_files']['extension']
|
||||
cmd_str = "#{linker[:command]}#{linker[:options]}#{linker[:includes]}"
|
||||
cmd_str += " #{(obj_list.map { |obj| "#{$cfg['linker']['object_files']['path']}#{obj}" }).join(' ')}"
|
||||
cmd_str += " #{$cfg['linker']['bin_files']['prefix']} "
|
||||
cmd_str += $cfg['linker']['bin_files']['destination']
|
||||
cmd_str += exe_name + $cfg['linker']['bin_files']['extension']
|
||||
execute(cmd_str)
|
||||
end
|
||||
|
||||
@@ -126,7 +125,7 @@ def build_simulator_fields
|
||||
command = if $cfg['simulator']['path'].nil?
|
||||
''
|
||||
else
|
||||
(tackit($cfg['simulator']['path']) + ' ')
|
||||
"#{tackit($cfg['simulator']['path'])} "
|
||||
end
|
||||
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)
|
||||
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?
|
||||
runner_path = $cfg['compiler']['build_path'] + runner_name
|
||||
test_gen = UnityTestRunnerGenerator.new($cfg_file)
|
||||
|
||||
40
extras/bdd/readme.md
Normal file
40
extras/bdd/readme.md
Normal 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
|
||||
// ...
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
44
extras/bdd/src/unity_bdd.h
Normal file
44
extras/bdd/src/unity_bdd.h
Normal 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
|
||||
9
extras/bdd/test/meson.build
Normal file
9
extras/bdd/test/meson.build
Normal 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
128
extras/bdd/test/test_bdd.c
Normal 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();
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Unity",
|
||||
"version": "2.5.2",
|
||||
"version": "2.6.0",
|
||||
"keywords": "unit-testing, testing, tdd, testing-framework",
|
||||
"description": "Simple Unit Testing for C",
|
||||
"homepage": "http://www.throwtheswitch.org/unity",
|
||||
|
||||
@@ -25,7 +25,9 @@ project('unity', 'c',
|
||||
|
||||
build_fixture = get_option('extension_fixture')
|
||||
build_memory = get_option('extension_memory')
|
||||
support_double = get_option('support_double')
|
||||
|
||||
unity_args = []
|
||||
unity_src = []
|
||||
unity_inc = []
|
||||
|
||||
@@ -42,8 +44,13 @@ if build_memory
|
||||
subdir('extras/memory/src')
|
||||
endif
|
||||
|
||||
if support_double
|
||||
unity_args += '-DUNITY_INCLUDE_DOUBLE'
|
||||
endif
|
||||
|
||||
unity_lib = static_library(meson.project_name(),
|
||||
sources: unity_src,
|
||||
c_args: unity_args,
|
||||
include_directories: unity_inc,
|
||||
install: not meson.is_subproject(),
|
||||
)
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
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('support_double', type: 'boolean', value: 'false', description: 'Whether to enable double precision floating point assertions.')
|
||||
|
||||
57
src/unity.c
57
src/unity.c
@@ -356,11 +356,11 @@ void UnityPrintFloat(const UNITY_DOUBLE input_number)
|
||||
{
|
||||
UnityPrint("0");
|
||||
}
|
||||
else if (isnan(number))
|
||||
else if (UNITY_IS_NAN(number))
|
||||
{
|
||||
UnityPrint("nan");
|
||||
}
|
||||
else if (isinf(number))
|
||||
else if (UNITY_IS_INF(number))
|
||||
{
|
||||
UnityPrint("inf");
|
||||
}
|
||||
@@ -895,15 +895,15 @@ void UnityAssertEqualIntArray(UNITY_INTERNAL_PTR expected,
|
||||
#ifndef UNITY_EXCLUDE_FLOAT
|
||||
/* Wrap this define in a function with variable types as float or double */
|
||||
#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; \
|
||||
(diff) = (actual) - (expected); \
|
||||
if ((diff) < 0) (diff) = -(diff); \
|
||||
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 */
|
||||
#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
|
||||
#define UNITY_NAN_CHECK 0
|
||||
#endif
|
||||
@@ -954,12 +954,12 @@ void UnityAssertWithinFloatArray(const UNITY_FLOAT delta,
|
||||
#endif
|
||||
}
|
||||
|
||||
if (isinf(in_delta))
|
||||
if (UNITY_IS_INF(in_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 */
|
||||
UnityPrintPointlessAndBail();
|
||||
@@ -1098,23 +1098,24 @@ void UnityAssertFloatSpecial(const UNITY_FLOAT actual,
|
||||
{
|
||||
case UNITY_FLOAT_IS_INF:
|
||||
case UNITY_FLOAT_IS_NOT_INF:
|
||||
is_trait = isinf(actual) && (actual > 0);
|
||||
is_trait = UNITY_IS_INF(actual) && (actual > 0);
|
||||
break;
|
||||
case UNITY_FLOAT_IS_NEG_INF:
|
||||
case UNITY_FLOAT_IS_NOT_NEG_INF:
|
||||
is_trait = isinf(actual) && (actual < 0);
|
||||
is_trait = UNITY_IS_INF(actual) && (actual < 0);
|
||||
break;
|
||||
|
||||
case UNITY_FLOAT_IS_NAN:
|
||||
case UNITY_FLOAT_IS_NOT_NAN:
|
||||
is_trait = isnan(actual) ? 1 : 0;
|
||||
is_trait = UNITY_IS_NAN(actual) ? 1 : 0;
|
||||
break;
|
||||
|
||||
case UNITY_FLOAT_IS_DET: /* A determinate number is non infinite and not NaN. */
|
||||
case UNITY_FLOAT_IS_NOT_DET:
|
||||
is_trait = !isinf(actual) && !isnan(actual);
|
||||
is_trait = !UNITY_IS_INF(actual) && !UNITY_IS_NAN(actual);
|
||||
break;
|
||||
|
||||
case UNITY_FLOAT_INVALID_TRAIT: /* Supress warning */
|
||||
default: /* including UNITY_FLOAT_INVALID_TRAIT */
|
||||
trait_index = 0;
|
||||
trait_names[0] = UnityStrInvalidFloatTrait;
|
||||
@@ -1181,12 +1182,12 @@ void UnityAssertWithinDoubleArray(const UNITY_DOUBLE delta,
|
||||
#endif
|
||||
}
|
||||
|
||||
if (isinf(in_delta))
|
||||
if (UNITY_IS_INF(in_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 */
|
||||
UnityPrintPointlessAndBail();
|
||||
@@ -1324,23 +1325,24 @@ void UnityAssertDoubleSpecial(const UNITY_DOUBLE actual,
|
||||
{
|
||||
case UNITY_FLOAT_IS_INF:
|
||||
case UNITY_FLOAT_IS_NOT_INF:
|
||||
is_trait = isinf(actual) && (actual > 0);
|
||||
is_trait = UNITY_IS_INF(actual) && (actual > 0);
|
||||
break;
|
||||
case UNITY_FLOAT_IS_NEG_INF:
|
||||
case UNITY_FLOAT_IS_NOT_NEG_INF:
|
||||
is_trait = isinf(actual) && (actual < 0);
|
||||
is_trait = UNITY_IS_INF(actual) && (actual < 0);
|
||||
break;
|
||||
|
||||
case UNITY_FLOAT_IS_NAN:
|
||||
case UNITY_FLOAT_IS_NOT_NAN:
|
||||
is_trait = isnan(actual) ? 1 : 0;
|
||||
is_trait = UNITY_IS_NAN(actual) ? 1 : 0;
|
||||
break;
|
||||
|
||||
case UNITY_FLOAT_IS_DET: /* A determinate number is non infinite and not NaN. */
|
||||
case UNITY_FLOAT_IS_NOT_DET:
|
||||
is_trait = !isinf(actual) && !isnan(actual);
|
||||
is_trait = !UNITY_IS_INF(actual) && !UNITY_IS_NAN(actual);
|
||||
break;
|
||||
|
||||
case UNITY_FLOAT_INVALID_TRAIT: /* Supress warning */
|
||||
default: /* including UNITY_FLOAT_INVALID_TRAIT */
|
||||
trait_index = 0;
|
||||
trait_names[0] = UnityStrInvalidFloatTrait;
|
||||
@@ -1607,8 +1609,8 @@ void UnityAssertEqualString(const char* expected,
|
||||
}
|
||||
}
|
||||
else
|
||||
{ /* handle case of one pointers being null (if both null, test should pass) */
|
||||
if (expected != actual)
|
||||
{ /* fail if either null but not if both */
|
||||
if (expected || actual)
|
||||
{
|
||||
Unity.CurrentTestFailed = 1;
|
||||
}
|
||||
@@ -1647,8 +1649,8 @@ void UnityAssertEqualStringLen(const char* expected,
|
||||
}
|
||||
}
|
||||
else
|
||||
{ /* handle case of one pointers being null (if both null, test should pass) */
|
||||
if (expected != actual)
|
||||
{ /* fail if either null but not if both */
|
||||
if (expected || actual)
|
||||
{
|
||||
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_OUTPUT_CHAR('0');
|
||||
UNITY_OUTPUT_CHAR('x');
|
||||
UnityPrintNumberHex(number, 8);
|
||||
UnityPrintNumberHex(number, UNITY_MAX_NIBBLES);
|
||||
break;
|
||||
}
|
||||
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('x');
|
||||
UnityPrintNumberHex((UNITY_UINT)number, 8);
|
||||
UnityPrintNumberHex((UNITY_UINT)number, nibbles_to_print);
|
||||
break;
|
||||
}
|
||||
case 'c':
|
||||
|
||||
24
src/unity.h
24
src/unity.h
@@ -9,8 +9,8 @@
|
||||
#define UNITY
|
||||
|
||||
#define UNITY_VERSION_MAJOR 2
|
||||
#define UNITY_VERSION_MINOR 5
|
||||
#define UNITY_VERSION_BUILD 4
|
||||
#define UNITY_VERSION_MINOR 6
|
||||
#define UNITY_VERSION_BUILD 0
|
||||
#define UNITY_VERSION ((UNITY_VERSION_MAJOR << 16) | (UNITY_VERSION_MINOR << 8) | UNITY_VERSION_BUILD)
|
||||
|
||||
#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
|
||||
|
||||
* 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
|
||||
* - 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_ONLY()
|
||||
#ifdef UNITY_INCLUDE_PRINT_FORMATTED
|
||||
#define TEST_PRINTF(message, ...) UnityPrintF(__LINE__, (message), __VA_ARGS__)
|
||||
#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.
|
||||
@@ -113,9 +113,19 @@ void verifyTest(void);
|
||||
#define TEST_PASS() TEST_ABORT()
|
||||
#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") */
|
||||
#define TEST_FILE(a)
|
||||
/*-------------------------------------------------------
|
||||
* Build Directives
|
||||
*-------------------------------------------------------
|
||||
|
||||
* 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)
|
||||
|
||||
@@ -241,16 +241,25 @@
|
||||
#endif
|
||||
typedef UNITY_FLOAT_TYPE UNITY_FLOAT;
|
||||
|
||||
/* isinf & isnan macros should be provided by math.h */
|
||||
#ifndef isinf
|
||||
/* The value of Inf - Inf is NaN */
|
||||
#define isinf(n) (isnan((n) - (n)) && !isnan(n))
|
||||
#endif
|
||||
|
||||
/* isnan macro should be provided by math.h. Override if not macro */
|
||||
#ifndef UNITY_IS_NAN
|
||||
#ifndef isnan
|
||||
/* NaN is the only floating point value that does NOT equal itself.
|
||||
* 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
|
||||
@@ -759,13 +768,25 @@ extern const char UnityStrErrShorthand[];
|
||||
* Test Running Macros
|
||||
*-------------------------------------------------------*/
|
||||
|
||||
#ifdef UNITY_TEST_PROTECT
|
||||
#define TEST_PROTECT() UNITY_TEST_PROTECT()
|
||||
#else
|
||||
#ifndef UNITY_EXCLUDE_SETJMP_H
|
||||
#define TEST_PROTECT() (setjmp(Unity.AbortFrame) == 0)
|
||||
#define TEST_ABORT() longjmp(Unity.AbortFrame, 1)
|
||||
#else
|
||||
#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
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Automatically enable variadic macros support, if it not enabled before */
|
||||
#ifndef UNITY_SUPPORT_VARIADIC_MACROS
|
||||
@@ -793,6 +814,9 @@ extern const char UnityStrErrShorthand[];
|
||||
#if !defined(TEST_RANGE) && !defined(UNITY_EXCLUDE_TEST_RANGE)
|
||||
#define TEST_RANGE(...)
|
||||
#endif
|
||||
#if !defined(TEST_MATRIX) && !defined(UNITY_EXCLUDE_TEST_MATRIX)
|
||||
#define TEST_MATRIX(...)
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#inherit_from: .rubocop_todo.yml
|
||||
|
||||
AllCops:
|
||||
TargetRubyVersion: 2.3
|
||||
TargetRubyVersion: 3.0
|
||||
|
||||
# These are areas where ThrowTheSwitch's coding style diverges from the Ruby standard
|
||||
Style/SpecialGlobalVars:
|
||||
@@ -28,6 +28,8 @@ Style/EvalWithLocation:
|
||||
Enabled: false
|
||||
Style/MixinUsage:
|
||||
Enabled: false
|
||||
Style/OptionalBooleanParameter:
|
||||
Enabled: false
|
||||
|
||||
# These are also places we diverge... but we will likely comply down the road
|
||||
Style/IfUnlessModifier:
|
||||
@@ -36,10 +38,12 @@ Style/FormatStringToken:
|
||||
Enabled: false
|
||||
|
||||
# This is disabled because it seems to get confused over nested hashes
|
||||
Layout/AlignHash:
|
||||
Layout/HashAlignment:
|
||||
Enabled: false
|
||||
EnforcedHashRocketStyle: table
|
||||
EnforcedColonStyle: table
|
||||
Layout/LineLength:
|
||||
Enabled: false
|
||||
|
||||
# We purposefully use these insecure features because they're what makes Ruby awesome
|
||||
Security/Eval:
|
||||
@@ -64,8 +68,6 @@ Metrics/ClassLength:
|
||||
Enabled: false
|
||||
Metrics/CyclomaticComplexity:
|
||||
Enabled: false
|
||||
Metrics/LineLength:
|
||||
Enabled: false
|
||||
Metrics/MethodLength:
|
||||
Enabled: false
|
||||
Metrics/ModuleLength:
|
||||
|
||||
2
test/testdata/testRunnerGeneratorSmall.c
vendored
2
test/testdata/testRunnerGeneratorSmall.c
vendored
@@ -4,7 +4,7 @@
|
||||
#include "unity.h"
|
||||
#include "Defs.h"
|
||||
|
||||
TEST_FILE("some_file.c")
|
||||
TEST_SOURCE_FILE("some_file.c")
|
||||
|
||||
/* Notes about prefixes:
|
||||
test - normal default prefix. these are "always run" tests for this procedure
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <setjmp.h>
|
||||
#include <stdio.h>
|
||||
#include "unity.h"
|
||||
#include "types_for_test.h"
|
||||
|
||||
/* Include Passthroughs for Linking Tests */
|
||||
void putcharSpy(int c) { (void)putchar(c);}
|
||||
@@ -209,6 +210,14 @@ TEST_RANGE([2,
|
||||
TEST_CASE(
|
||||
|
||||
6 , 7)
|
||||
TEST_MATRIX([7,
|
||||
8 ,
|
||||
|
||||
9, 10],
|
||||
[
|
||||
11]
|
||||
|
||||
)
|
||||
void test_SpaceInTestCase(unsigned index, unsigned bigger)
|
||||
{
|
||||
TEST_ASSERT_EQUAL_UINT32(NextExpectedSpaceIndex, index);
|
||||
@@ -216,3 +225,84 @@ void test_SpaceInTestCase(unsigned index, unsigned bigger)
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,10 +7,14 @@
|
||||
#ifndef TEST_RANGE
|
||||
#define TEST_RANGE(...)
|
||||
#endif
|
||||
#ifndef TEST_MATRIX
|
||||
#define TEST_MATRIX(...)
|
||||
#endif
|
||||
|
||||
TEST_CASE(1, 2, 5)
|
||||
TEST_CASE(10, 7, 20)
|
||||
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)
|
||||
{
|
||||
TEST_ASSERT_GREATER_THAN_INT(a + b, c);
|
||||
|
||||
14
test/tests/types_for_test.h
Normal file
14
test/tests/types_for_test.h
Normal 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,
|
||||
};
|
||||
Reference in New Issue
Block a user