Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

unity 2.6 release candidate #656

Merged
merged 12 commits into from
Nov 13, 2023
3 changes: 3 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion LICENSE.txt
Original file line number Diff line number Diff line change
@@ -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
Expand Down
14 changes: 10 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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.
Expand Down Expand Up @@ -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)
Expand All @@ -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)

Expand Down Expand Up @@ -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

Expand All @@ -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
2 changes: 1 addition & 1 deletion auto/colour_reporter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
36 changes: 20 additions & 16 deletions auto/generate_module.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
require 'pathname'

# TEMPLATE_TST
TEMPLATE_TST ||= '#ifdef TEST
TEMPLATE_TST ||= '#ifdef %5$s

#include "unity.h"

Expand All @@ -32,7 +32,7 @@
TEST_IGNORE_MESSAGE("Need to Implement %1$s");
}

#endif // TEST
#endif // %5$s
'.freeze

# TEMPLATE_SRC
Expand Down Expand Up @@ -108,7 +108,8 @@ def self.default_options
update_svn: false,
boilerplates: {},
test_prefix: 'Test',
mock_prefix: 'Mock'
mock_prefix: 'Mock',
test_define: 'TEST'
}
end

Expand All @@ -132,9 +133,9 @@ def files_to_operate_on(module_name, pattern = nil)

# 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
Expand All @@ -154,6 +155,7 @@ def files_to_operate_on(module_name, pattern = nil)
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) })
Expand All @@ -168,18 +170,19 @@ def files_to_operate_on(module_name, pattern = nil)
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
Expand Down Expand Up @@ -212,7 +215,8 @@ def generate(module_name, pattern = nil)
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]}\"`
Expand Down Expand Up @@ -260,12 +264,12 @@ def destroy(module_name, pattern = nil)
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?

Expand Down
32 changes: 16 additions & 16 deletions auto/generate_test_runner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ def self.default_options
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)'
}
Expand All @@ -69,7 +70,7 @@ def run(input_file, output_file, options = nil)
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)/ }
Expand All @@ -80,7 +81,7 @@ def run(input_file, output_file, options = nil)

# 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
Expand Down Expand Up @@ -144,12 +145,12 @@ def find_tests(source)
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|
Expand All @@ -163,13 +164,13 @@ def find_tests(source)
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|
Expand All @@ -188,7 +189,7 @@ def find_tests(source)
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
Expand All @@ -207,12 +208,11 @@ def find_includes(source)
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)
Expand Down Expand Up @@ -369,7 +369,7 @@ def create_run_test(output)
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)
Expand Down Expand Up @@ -459,7 +459,7 @@ def create_main(output, filename, tests, used_mocks)
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")
Expand Down Expand Up @@ -498,7 +498,7 @@ def create_h_file(output, filename, tests, testfile_includes, used_mocks)
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)$/
Expand Down
Loading
Loading