未验证 提交 addd60ed 编写于 作者: M Mark VanderVoord 提交者: GitHub

Merge pull request #454 from jlindgren90/common-run-test

Convert RUN_TEST() to a function
......@@ -8,10 +8,19 @@ class UnityTestRunnerGenerator
def initialize(options = nil)
@options = UnityTestRunnerGenerator.default_options
case options
when NilClass then @options
when String then @options.merge!(UnityTestRunnerGenerator.grab_config(options))
when Hash then @options.merge!(options)
else raise 'If you specify arguments, it should be a filename or a hash of options'
when NilClass
@options
when String
@options.merge!(UnityTestRunnerGenerator.grab_config(options))
when Hash
# Check if some of these have been specified
@options[:has_setup] = !options[:setup_name].nil?
@options[:has_teardown] = !options[:teardown_name].nil?
@options[:has_suite_setup] = !options[:suite_setup].nil?
@options[:has_suite_teardown] = !options[:suite_teardown].nil?
@options.merge!(options)
else
raise 'If you specify arguments, it should be a filename or a hash of options'
end
require_relative 'type_sanitizer'
end
......@@ -58,6 +67,7 @@ class UnityTestRunnerGenerator
used_mocks = find_mocks(testfile_includes)
testfile_includes = (testfile_includes - used_mocks)
testfile_includes.delete_if { |inc| inc =~ /(unity|cmock)/ }
find_setup_and_teardown(source)
# build runner file
generate(input_file, output_file, tests, used_mocks, testfile_includes)
......@@ -75,9 +85,13 @@ class UnityTestRunnerGenerator
create_header(output, used_mocks, testfile_includes)
create_externs(output, tests, used_mocks)
create_mock_management(output, used_mocks)
create_setup(output)
create_teardown(output)
create_suite_setup(output)
create_suite_teardown(output)
create_reset(output, used_mocks)
create_reset(output)
create_run_test(output)
create_args_wrappers(output, tests)
create_main(output, input_file, tests, used_mocks)
end
......@@ -165,17 +179,18 @@ class UnityTestRunnerGenerator
mock_headers
end
def find_setup_and_teardown(source)
@options[:has_setup] = source =~ /void\s+#{@options[:setup_name]}\s*\(/
@options[:has_teardown] = source =~ /void\s+#{@options[:teardown_name]}\s*\(/
@options[:has_suite_setup] ||= (source =~ /void\s+suiteSetUp\s*\(/)
@options[:has_suite_teardown] ||= (source =~ /void\s+suiteTearDown\s*\(/)
end
def create_header(output, mocks, testfile_includes = [])
output.puts('/* AUTOGENERATED FILE. DO NOT EDIT. */')
create_runtest(output, mocks)
output.puts("\n/*=======Automagically Detected Files To Include=====*/")
output.puts('#define UNITY_INCLUDE_SETUP_STUBS') if @options[:suite_setup].nil?
output.puts("#include \"#{@options[:framework]}.h\"")
output.puts('#include "cmock.h"') unless mocks.empty?
output.puts('#ifndef UNITY_EXCLUDE_SETJMP_H')
output.puts('#include <setjmp.h>')
output.puts('#endif')
output.puts('#include <stdio.h>')
if @options[:defines] && !@options[:defines].empty?
@options[:defines].each { |d| output.puts("#ifndef #{d}\n#define #{d}\n#endif /* #{d} */") }
end
......@@ -215,8 +230,6 @@ class UnityTestRunnerGenerator
end
def create_mock_management(output, mock_headers)
return if mock_headers.empty?
output.puts("\n/*=======Mock Management=====*/")
output.puts('static void CMock_Init(void)')
output.puts('{')
......@@ -251,88 +264,69 @@ class UnityTestRunnerGenerator
output.puts("}\n")
end
def create_setup(output)
return if @options[:has_setup]
output.puts("\n/*=======Setup (stub)=====*/")
output.puts("void #{@options[:setup_name]}(void) {}")
end
def create_teardown(output)
return if @options[:has_teardown]
output.puts("\n/*=======Teardown (stub)=====*/")
output.puts("void #{@options[:teardown_name]}(void) {}")
end
def create_suite_setup(output)
return if @options[:suite_setup].nil?
output.puts("\n/*=======Suite Setup=====*/")
output.puts('static void suite_setup(void)')
output.puts('void suiteSetUp(void)')
output.puts('{')
if @options[:suite_setup].nil?
# New style, call suiteSetUp() if we can use weak symbols
output.puts('#if defined(UNITY_WEAK_ATTRIBUTE) || defined(UNITY_WEAK_PRAGMA)')
output.puts(' suiteSetUp();')
output.puts('#endif')
else
# Old style, C code embedded in the :suite_setup option
output.puts(@options[:suite_setup])
end
output.puts(@options[:suite_setup])
output.puts('}')
end
def create_suite_teardown(output)
return if @options[:suite_teardown].nil?
output.puts("\n/*=======Suite Teardown=====*/")
output.puts('static int suite_teardown(int num_failures)')
output.puts('int suiteTearDown(int num_failures)')
output.puts('{')
if @options[:suite_teardown].nil?
# New style, call suiteTearDown() if we can use weak symbols
output.puts('#if defined(UNITY_WEAK_ATTRIBUTE) || defined(UNITY_WEAK_PRAGMA)')
output.puts(' return suiteTearDown(num_failures);')
output.puts('#else')
output.puts(' return num_failures;')
output.puts('#endif')
else
# Old style, C code embedded in the :suite_teardown option
output.puts(@options[:suite_teardown])
end
output.puts(@options[:suite_teardown])
output.puts('}')
end
def create_runtest(output, used_mocks)
cexception = @options[:plugins].include? :cexception
va_args1 = @options[:use_param_tests] ? ', ...' : ''
va_args2 = @options[:use_param_tests] ? '__VA_ARGS__' : ''
output.puts("\n/*=======Test Runner Used To Run Each Test Below=====*/")
output.puts('#define RUN_TEST_NO_ARGS') if @options[:use_param_tests]
output.puts("#define RUN_TEST(TestFunc, TestLineNum#{va_args1}) \\")
output.puts('{ \\')
output.puts(" Unity.CurrentTestName = #TestFunc#{va_args2.empty? ? '' : " \"(\" ##{va_args2} \")\""}; \\")
output.puts(' Unity.CurrentTestLineNumber = TestLineNum; \\')
output.puts(' if (UnityTestMatches()) { \\') if @options[:cmdline_args]
output.puts(' Unity.NumberOfTests++; \\')
output.puts(' UNITY_EXEC_TIME_START(); \\')
output.puts(' CMock_Init(); \\') unless used_mocks.empty?
output.puts(' UNITY_CLR_DETAILS(); \\') unless used_mocks.empty?
output.puts(' if (TEST_PROTECT()) \\')
output.puts(' { \\')
output.puts(' CEXCEPTION_T e; \\') if cexception
output.puts(' Try { \\') if cexception
output.puts(" #{@options[:setup_name]}(); \\")
output.puts(" TestFunc(#{va_args2}); \\")
output.puts(' } Catch(e) { TEST_ASSERT_EQUAL_HEX32_MESSAGE(CEXCEPTION_NONE, e, "Unhandled Exception!"); } \\') if cexception
output.puts(' } \\')
output.puts(' if (TEST_PROTECT()) \\')
output.puts(' { \\')
output.puts(" #{@options[:teardown_name]}(); \\")
output.puts(' CMock_Verify(); \\') unless used_mocks.empty?
output.puts(' } \\')
output.puts(' CMock_Destroy(); \\') unless used_mocks.empty?
output.puts(' UNITY_EXEC_TIME_STOP(); \\')
output.puts(' UnityConcludeTest(); \\')
output.puts(' } \\') if @options[:cmdline_args]
output.puts("}\n")
end
def create_reset(output, used_mocks)
def create_reset(output)
output.puts("\n/*=======Test Reset Option=====*/")
output.puts("void #{@options[:test_reset_name]}(void);")
output.puts("void #{@options[:test_reset_name]}(void)")
output.puts('{')
output.puts(' CMock_Verify();') unless used_mocks.empty?
output.puts(' CMock_Destroy();') unless used_mocks.empty?
output.puts(" #{@options[:teardown_name]}();")
output.puts(' CMock_Init();') unless used_mocks.empty?
output.puts(' CMock_Verify();')
output.puts(' CMock_Destroy();')
output.puts(' CMock_Init();')
output.puts(" #{@options[:setup_name]}();")
output.puts('}')
end
def create_run_test(output)
require 'erb'
template = ERB.new(File.read(File.join(__dir__, 'run_test.erb')))
output.puts(template.result(binding))
end
def create_args_wrappers(output, tests)
return unless @options[:use_param_tests]
output.puts("\n/*=======Parameterized Test Wrappers=====*/")
tests.each do |test|
next if test[:args].nil? || test[:args].empty?
test[:args].each.with_index(1) do |args, idx|
output.puts("static void runner_args#{idx}_#{test[:test]}(void)")
output.puts('{')
output.puts(" #{test[:test]}(#{args});")
output.puts("}\n")
end
end
end
def create_main(output, filename, tests, used_mocks)
output.puts("\n\n/*=======MAIN=====*/")
main_name = @options[:main_name].to_sym == :auto ? "main_#{filename.gsub('.c', '')}" : (@options[:main_name]).to_s
......@@ -349,24 +343,20 @@ class UnityTestRunnerGenerator
output.puts(' {')
output.puts(" UnityPrint(\"#{filename.gsub('.c', '')}.\");")
output.puts(' UNITY_PRINT_EOL();')
if @options[:use_param_tests]
tests.each do |test|
if test[:args].nil? || test[:args].empty?
output.puts(" UnityPrint(\" #{test[:test]}(RUN_TEST_NO_ARGS)\");")
tests.each do |test|
if (!@options[:use_param_tests]) || test[:args].nil? || test[:args].empty?
output.puts(" UnityPrint(\" #{test[:test]}\");")
output.puts(' UNITY_PRINT_EOL();')
else
test[:args].each do |args|
output.puts(" UnityPrint(\" #{test[:test]}(#{args})\");")
output.puts(' UNITY_PRINT_EOL();')
else
test[:args].each do |args|
output.puts(" UnityPrint(\" #{test[:test]}(#{args})\");")
output.puts(' UNITY_PRINT_EOL();')
end
end
end
else
tests.each { |test| output.puts(" UnityPrint(\" #{test[:test]}\");\n UNITY_PRINT_EOL();") }
end
output.puts(' return 0;')
output.puts(' return 0;')
output.puts(' }')
output.puts(' return parse_status;')
output.puts(' return parse_status;')
output.puts(' }')
else
if main_name != 'main'
......@@ -375,22 +365,26 @@ class UnityTestRunnerGenerator
output.puts("int #{main_name}(void)")
output.puts('{')
end
output.puts(' suite_setup();')
output.puts(' suiteSetUp();') if @options[:has_suite_setup]
output.puts(" UnityBegin(\"#{filename.gsub(/\\/, '\\\\\\')}\");")
if @options[:use_param_tests]
tests.each do |test|
if test[:args].nil? || test[:args].empty?
output.puts(" RUN_TEST(#{test[:test]}, #{test[:line_number]}, RUN_TEST_NO_ARGS);")
else
test[:args].each { |args| output.puts(" RUN_TEST(#{test[:test]}, #{test[:line_number]}, #{args});") }
tests.each do |test|
if (!@options[:use_param_tests]) || test[:args].nil? || test[:args].empty?
output.puts(" run_test(#{test[:test]}, \"#{test[:test]}\", #{test[:line_number]});")
else
test[:args].each.with_index(1) do |args, idx|
wrapper = "runner_args#{idx}_#{test[:test]}"
testname = "#{test[:test]}(#{args})".dump
output.puts(" run_test(#{wrapper}, #{testname}, #{test[:line_number]});")
end
end
else
tests.each { |test| output.puts(" RUN_TEST(#{test[:test]}, #{test[:line_number]});") }
end
output.puts
output.puts(' CMock_Guts_MemFreeFinal();') unless used_mocks.empty?
output.puts(' return suite_teardown(UnityEnd());')
if @options[:has_suite_teardown]
output.puts(' return suiteTearDown(UnityEnd());')
else
output.puts(' return UnityEnd();')
end
output.puts('}')
end
......
/*=======Test Runner Used To Run Each Test=====*/
static void run_test(UnityTestFunction func, const char* name, int line_num)
{
Unity.CurrentTestName = name;
Unity.CurrentTestLineNumber = line_num;
#ifdef UNITY_USE_COMMAND_LINE_ARGS
if (!UnityTestMatches())
return;
#endif
Unity.NumberOfTests++;
UNITY_CLR_DETAILS();
UNITY_EXEC_TIME_START();
CMock_Init();
if (TEST_PROTECT())
{
<% if @options[:plugins].include?(:cexception) %>
CEXCEPTION_T e;
Try {
<% end %>
<%= @options[:setup_name] %>();
func();
<% if @options[:plugins].include?(:cexception) %>
} Catch(e) {
TEST_ASSERT_EQUAL_HEX32_MESSAGE(CEXCEPTION_NONE, e, "Unhandled Exception!");
}
<% end %>
}
if (TEST_PROTECT())
{
<%= @options[:teardown_name] %>();
CMock_Verify();
}
CMock_Destroy();
UNITY_EXEC_TIME_STOP();
UnityConcludeTest();
}
......@@ -119,10 +119,10 @@ Define this to be the number of bits a pointer takes up on your system. The
default, if not autodetected, is 32-bits. If you're getting ugly compiler
warnings about casting from pointers, this is the one to look at.
_Hint:_ In order to support exotic processors (for example TI C55x with a pointer
_Hint:_ In order to support exotic processors (for example TI C55x with a pointer
width of 23-bit), choose the next power of two (in this case 32-bit).
_Supported values:_ 16, 32 and 64
_Supported values:_ 16, 32 and 64
_Example:_
```C
......@@ -343,36 +343,6 @@ _Note:_
specifying `UNITY_USE_FLUSH_STDOUT`. No other defines are required.
##### `UNITY_WEAK_ATTRIBUTE`
##### `UNITY_WEAK_PRAGMA`
##### `UNITY_NO_WEAK`
For some targets, Unity can make the otherwise required setUp() and tearDown()
functions optional. This is a nice convenience for test writers since setUp and
tearDown don’t often actually do anything. If you’re using gcc or clang, this
option is automatically defined for you. Other compilers can also support this
behavior, if they support a C feature called weak functions. A weak function is
a function that is compiled into your executable unless a non-weak version of
the same function is defined elsewhere. If a non-weak version is found, the weak
version is ignored as if it never existed. If your compiler supports this feature,
you can let Unity know by defining UNITY_WEAK_ATTRIBUTE or UNITY_WEAK_PRAGMA as
the function attributes that would need to be applied to identify a function as
weak. If your compiler lacks support for weak functions, you will always need to
define setUp and tearDown functions (though they can be and often will be just
empty). You can also force Unity to NOT use weak functions by defining
UNITY_NO_WEAK. The most common options for this feature are:
_Example:_
```C
#define UNITY_WEAK_ATTRIBUTE weak
#define UNITY_WEAK_ATTRIBUTE __attribute__((weak))
#define UNITY_WEAK_PRAGMA
#define UNITY_NO_WEAK
```
##### `UNITY_PTR_ATTRIBUTE`
Some compilers require a custom attribute to be assigned to pointers, like
......
......@@ -93,8 +93,9 @@ Next, a test file will include a `setUp()` and `tearDown()` function. The setUp
function can contain anything you would like to run before each test. The
tearDown function can contain anything you would like to run after each test.
Both functions accept no arguments and return nothing. You may leave either or
both of these blank if you have no need for them. If you're using a compiler
that is configured to make these functions optional, you may leave them off
both of these blank if you have no need for them.
If you're using Ceedling or the test runner generator script, you may leave these off
completely. Not sure? Give it a try. If you compiler complains that it can't
find setUp or tearDown when it links, you'll know you need to at least include
an empty function for these.
......@@ -103,7 +104,7 @@ The majority of the file will be a series of test functions. Test functions
follow the convention of starting with the word "test_" or "spec_". You don't HAVE
to name them this way, but it makes it clear what functions are tests for other
developers. Also, the automated scripts that come with Unity or Ceedling will default
to looking for test functions to be prefixed this way. Test functions take no arguments
to looking for test functions to be prefixed this way. Test functions take no arguments
and return nothing. All test accounting is handled internally in Unity.
Finally, at the bottom of your test file, you will write a `main()` function.
......@@ -156,7 +157,7 @@ This should be enough to get you going, though.
### Running Test Functions
When writing your own `main()` functions, for a test-runner. There are two ways
to execute the test.
to execute the test.
The classic variant
``` c
......@@ -170,8 +171,8 @@ These macros perform the necessary setup before the test is called and
handles cleanup and result tabulation afterwards.
### Ignoring Test Functions
There are times when a test is incomplete or not valid for some reason.
At these times, TEST_IGNORE can be called. Control will immediately be
There are times when a test is incomplete or not valid for some reason.
At these times, TEST_IGNORE can be called. Control will immediately be
returned to the caller of the test, and no failures will be returned.
This is useful when your test runners are automatically generated.
......
......@@ -24,39 +24,22 @@ extern "C"
* Test Setup / Teardown
*-------------------------------------------------------*/
/* These functions are intended to be called before and after each test. */
/* These functions are intended to be called before and after each test.
* If using unity directly, these will need to be provided for each test
* executable built. If you are using the test runner generator and/or
* Ceedling, these are optional. */
void setUp(void);
void tearDown(void);
/* These functions are intended to be called at the beginning and end of an
* entire test suite. suiteTearDown() is passed the number of tests that
* failed, and its return value becomes the exit code of main(). */
* failed, and its return value becomes the exit code of main(). If using
* Unity directly, you're in charge of calling these if they are desired.
* If using Ceedling or the test runner generator, these will be called
* automatically if they exist. */
void suiteSetUp(void);
int suiteTearDown(int num_failures);
/* If the compiler supports it, the following block provides stub
* implementations of the above functions as weak symbols. Note that on
* some platforms (MinGW for example), weak function implementations need
* to be in the same translation unit they are called from. This can be
* achieved by defining UNITY_INCLUDE_SETUP_STUBS before including unity.h. */
#ifdef UNITY_INCLUDE_SETUP_STUBS
#ifdef UNITY_WEAK_ATTRIBUTE
UNITY_WEAK_ATTRIBUTE void setUp(void) { }
UNITY_WEAK_ATTRIBUTE void tearDown(void) { }
UNITY_WEAK_ATTRIBUTE void suiteSetUp(void) { }
UNITY_WEAK_ATTRIBUTE int suiteTearDown(int num_failures) { return num_failures; }
#elif defined(UNITY_WEAK_PRAGMA)
#pragma weak setUp
void setUp(void) { }
#pragma weak tearDown
void tearDown(void) { }
#pragma weak suiteSetUp
void suiteSetUp(void) { }
#pragma weak suiteTearDown
int suiteTearDown(int num_failures) { return num_failures; }
#endif
#endif
/*-------------------------------------------------------
* Configuration Options
*-------------------------------------------------------
......
......@@ -372,22 +372,6 @@ typedef UNITY_FLOAT_TYPE UNITY_FLOAT;
#define UNITY_COUNTER_TYPE UNITY_UINT
#endif
/*-------------------------------------------------------
* Language Features Available
*-------------------------------------------------------*/
#if !defined(UNITY_WEAK_ATTRIBUTE) && !defined(UNITY_WEAK_PRAGMA)
# if defined(__GNUC__) || defined(__ghs__) /* __GNUC__ includes clang */
# if !(defined(__WIN32__) && defined(__clang__)) && !defined(__TMS470__)
# define UNITY_WEAK_ATTRIBUTE __attribute__((weak))
# endif
# endif
#endif
#ifdef UNITY_NO_WEAK
# undef UNITY_WEAK_ATTRIBUTE
# undef UNITY_WEAK_PRAGMA
#endif
/*-------------------------------------------------------
* Internal Structs Needed
*-------------------------------------------------------*/
......
......@@ -149,7 +149,7 @@ RUNNER_TESTS = [
'paratest_ShouldHandleParameterizedTests\(125\)',
'paratest_ShouldHandleParameterizedTests\(5\)',
'paratest_ShouldHandleParameterizedTests2\(7\)',
'paratest_ShouldHandleNonParameterizedTestsWhenParameterizationValid\(RUN_TEST_NO_ARGS\)',
'paratest_ShouldHandleNonParameterizedTestsWhenParameterizationValid',
],
:to_fail => [ 'paratest_ShouldHandleParameterizedTestsThatFail\(17\)' ],
:to_ignore => [ ],
......@@ -165,7 +165,7 @@ RUNNER_TESTS = [
'paratest_ShouldHandleParameterizedTests\(125\)',
'paratest_ShouldHandleParameterizedTests\(5\)',
'paratest_ShouldHandleParameterizedTests2\(7\)',
'paratest_ShouldHandleNonParameterizedTestsWhenParameterizationValid\(RUN_TEST_NO_ARGS\)',
'paratest_ShouldHandleNonParameterizedTestsWhenParameterizationValid',
],
:to_fail => [ 'paratest_ShouldHandleParameterizedTestsThatFail\(17\)' ],
:to_ignore => [ ],
......@@ -184,7 +184,7 @@ RUNNER_TESTS = [
'paratest_ShouldHandleParameterizedTests\(125\)',
'paratest_ShouldHandleParameterizedTests\(5\)',
'paratest_ShouldHandleParameterizedTests2\(7\)',
'paratest_ShouldHandleNonParameterizedTestsWhenParameterizationValid\(RUN_TEST_NO_ARGS\)',
'paratest_ShouldHandleNonParameterizedTestsWhenParameterizationValid',
],
:to_fail => [ 'paratest_ShouldHandleParameterizedTestsThatFail\(17\)' ],
:to_ignore => [ ],
......@@ -473,7 +473,7 @@ RUNNER_TESTS = [
'paratest_ShouldHandleParameterizedTests\(125\)',
'paratest_ShouldHandleParameterizedTests\(5\)',
'paratest_ShouldHandleParameterizedTests2\(7\)',
'paratest_ShouldHandleNonParameterizedTestsWhenParameterizationValid\(RUN_TEST_NO_ARGS\)',
'paratest_ShouldHandleNonParameterizedTestsWhenParameterizationValid',
],
:to_fail => [ 'paratest_ShouldHandleParameterizedTestsThatFail\(17\)' ],
:to_ignore => [ ],
......@@ -489,7 +489,7 @@ RUNNER_TESTS = [
'paratest_ShouldHandleParameterizedTests\(125\)',
'paratest_ShouldHandleParameterizedTests\(5\)',
'paratest_ShouldHandleParameterizedTests2\(7\)',
'paratest_ShouldHandleNonParameterizedTestsWhenParameterizationValid\(RUN_TEST_NO_ARGS\)',
'paratest_ShouldHandleNonParameterizedTestsWhenParameterizationValid',
],
:to_fail => [ 'paratest_ShouldHandleParameterizedTestsThatFail\(17\)' ],
:to_ignore => [ ],
......@@ -508,7 +508,7 @@ RUNNER_TESTS = [
'paratest_ShouldHandleParameterizedTests\(125\)',
'paratest_ShouldHandleParameterizedTests\(5\)',
'paratest_ShouldHandleParameterizedTests2\(7\)',
'paratest_ShouldHandleNonParameterizedTestsWhenParameterizationValid\(RUN_TEST_NO_ARGS\)',
'paratest_ShouldHandleNonParameterizedTestsWhenParameterizationValid',
],
:to_fail => [ 'paratest_ShouldHandleParameterizedTestsThatFail\(17\)' ],
:to_ignore => [ ],
......@@ -1099,7 +1099,7 @@ RUNNER_TESTS = [
'paratest_ShouldHandleParameterizedTests\(125\)',
'paratest_ShouldHandleParameterizedTests\(5\)',
'paratest_ShouldHandleParameterizedTests2\(7\)',
'paratest_ShouldHandleNonParameterizedTestsWhenParameterizationValid\(RUN_TEST_NO_ARGS\)',
'paratest_ShouldHandleNonParameterizedTestsWhenParameterizationValid',
'paratest_ShouldHandleParameterizedTestsThatFail\(17\)'
],
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册