diff options
author | Mark VanderVoord <mvandervoord@gmail.com> | 2023-11-13 17:06:15 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-11-13 17:06:15 -0500 |
commit | bf560290f6020737eafaa8b5cbd2177c3956c03f (patch) | |
tree | 20804f31674c85b2e86fb352ce7f40ba1db12f78 | |
parent | 8b0daf153f03ef234386027d30cfa64a37a18d4d (diff) | |
parent | a1b1600e4361cdf98bdb57e7d32a1cafa6eb90bf (diff) | |
download | ThrowTheSwitch-Unity-bf560290f6020737eafaa8b5cbd2177c3956c03f.tar.gz |
Merge pull request #656 from ThrowTheSwitch/platform_matrix
unity 2.6 release candidate
-rw-r--r-- | .github/workflows/main.yml | 3 | ||||
-rw-r--r-- | LICENSE.txt | 2 | ||||
-rw-r--r-- | README.md | 14 | ||||
-rw-r--r-- | auto/colour_reporter.rb | 2 | ||||
-rw-r--r-- | auto/generate_module.rb | 36 | ||||
-rwxr-xr-x | auto/generate_test_runner.rb | 32 | ||||
-rw-r--r-- | auto/parse_output.rb | 38 | ||||
-rwxr-xr-x | auto/stylize_as_junit.rb | 2 | ||||
-rw-r--r-- | auto/test_file_filter.rb | 1 | ||||
-rw-r--r-- | auto/type_sanitizer.rb | 2 | ||||
-rw-r--r-- | auto/unity_test_summary.rb | 10 | ||||
-rw-r--r-- | auto/yaml_helper.rb | 7 | ||||
-rw-r--r-- | docs/UnityChangeLog.md | 93 | ||||
-rw-r--r-- | docs/UnityConfigurationGuide.md | 11 | ||||
-rw-r--r-- | docs/UnityKnownIssues.md | 13 | ||||
-rw-r--r-- | examples/example_3/rakefile_helper.rb | 35 | ||||
-rw-r--r-- | library.json | 2 | ||||
-rw-r--r-- | src/unity.c | 43 | ||||
-rw-r--r-- | src/unity.h | 4 | ||||
-rw-r--r-- | src/unity_internals.h | 23 | ||||
-rw-r--r-- | test/.rubocop.yml | 10 |
21 files changed, 262 insertions, 121 deletions
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index fcae2ad..ce948bd 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -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 diff --git a/LICENSE.txt b/LICENSE.txt index b9a329d..a541b84 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -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 @@ -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 diff --git a/auto/colour_reporter.rb b/auto/colour_reporter.rb index 1c3bc21..b86b76c 100644 --- a/auto/colour_reporter.rb +++ b/auto/colour_reporter.rb @@ -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 diff --git a/auto/generate_module.rb b/auto/generate_module.rb index 7151586..7b33c72 100644 --- a/auto/generate_module.rb +++ b/auto/generate_module.rb @@ -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? diff --git a/auto/generate_test_runner.rb b/auto/generate_test_runner.rb index 69f3ff5..057c02f 100755 --- a/auto/generate_test_runner.rb +++ b/auto/generate_test_runner.rb @@ -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 @@ -144,12 +145,12 @@ class UnityTestRunnerGenerator if @options[:use_param_tests] && !arguments.empty? args = [] 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| case type_and_args[i] - when "CASE" + when 'CASE' args << type_and_args[i + 1].sub(/^\s*\(\s*(.*?)\s*\)\s*$/m, '\1') - when "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| exclude_end = arg_values_str[0] == '<' && arg_values_str[-1] == '>' arg_values_str[1...-1].map do |arg_value_str| @@ -163,13 +164,13 @@ class UnityTestRunnerGenerator arg_combinations.flatten.join(', ') end - when "MATRIX" - single_arg_regex_string = /(?:(?:"(?:\\"|[^\\])*?")+|(?:'\\?.')+|(?:[^\s\]\["'\,]|\[[\d\S_-]+\])+)/.source + 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) + ("#{arg_values_str},").scan(arg_elements_regex) end.reduce do |result, arg_range_expanded| result.product(arg_range_expanded) end.map do |arg_combinations| @@ -188,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 @@ -207,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_SOURCE_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) @@ -369,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) @@ -459,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") @@ -498,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)$/ diff --git a/auto/parse_output.rb b/auto/parse_output.rb index 864104b..aa306e2 100644 --- a/auto/parse_output.rb +++ b/auto/parse_output.rb @@ -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 diff --git a/auto/stylize_as_junit.rb b/auto/stylize_as_junit.rb index e01f791..e4b911e 100755 --- a/auto/stylize_as_junit.rb +++ b/auto/stylize_as_junit.rb @@ -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) diff --git a/auto/test_file_filter.rb b/auto/test_file_filter.rb index 3cc32de..f4834a1 100644 --- a/auto/test_file_filter.rb +++ b/auto/test_file_filter.rb @@ -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] diff --git a/auto/type_sanitizer.rb b/auto/type_sanitizer.rb index dafb882..3d1db09 100644 --- a/auto/type_sanitizer.rb +++ b/auto/type_sanitizer.rb @@ -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 diff --git a/auto/unity_test_summary.rb b/auto/unity_test_summary.rb index b3fe8a6..03d67a6 100644 --- a/auto/unity_test_summary.rb +++ b/auto/unity_test_summary.rb @@ -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 diff --git a/auto/yaml_helper.rb b/auto/yaml_helper.rb index e5a0865..3296ba0 100644 --- a/auto/yaml_helper.rb +++ b/auto/yaml_helper.rb @@ -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) diff --git a/docs/UnityChangeLog.md b/docs/UnityChangeLog.md new file mode 100644 index 0000000..9c3bb7b --- /dev/null +++ b/docs/UnityChangeLog.md @@ -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 diff --git a/docs/UnityConfigurationGuide.md b/docs/UnityConfigurationGuide.md index e56b4a4..953851f 100644 --- a/docs/UnityConfigurationGuide.md +++ b/docs/UnityConfigurationGuide.md @@ -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` diff --git a/docs/UnityKnownIssues.md b/docs/UnityKnownIssues.md new file mode 100644 index 0000000..3449319 --- /dev/null +++ b/docs/UnityKnownIssues.md @@ -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 diff --git a/examples/example_3/rakefile_helper.rb b/examples/example_3/rakefile_helper.rb index 4906075..cbc4549 100644 --- a/examples/example_3/rakefile_helper.rb +++ b/examples/example_3/rakefile_helper.rb @@ -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) diff --git a/library.json b/library.json index b571294..914f5f6 100644 --- a/library.json +++ b/library.json @@ -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", diff --git a/src/unity.c b/src/unity.c index e455f57..cc2e5ce 100644 --- a/src/unity.c +++ b/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,21 +1098,21 @@ 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 */ @@ -1182,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(); @@ -1325,21 +1325,21 @@ 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 */ @@ -2031,14 +2031,7 @@ 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'); - if (length_mod == UNITY_LENGTH_MODIFIER_LONG_LONG) - { - UnityPrintNumberHex(number, 16); - } - else - { - UnityPrintNumberHex(number, 8); - } + UnityPrintNumberHex(number, UNITY_MAX_NIBBLES); break; } case 'p': diff --git a/src/unity.h b/src/unity.h index 2785c72..265e548 100644 --- a/src/unity.h +++ b/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 diff --git a/src/unity_internals.h b/src/unity_internals.h index 11d9abb..65938ff 100644 --- a/src/unity_internals.h +++ b/src/unity_internals.h @@ -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 diff --git a/test/.rubocop.yml b/test/.rubocop.yml index 6c9542f..a3b811b 100644 --- a/test/.rubocop.yml +++ b/test/.rubocop.yml @@ -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: |