From d9b0edf2827d7703722d16b64487be1d1ad71006 Mon Sep 17 00:00:00 2001 From: Mark VanderVoord Date: Mon, 21 Oct 2019 14:21:52 -0400 Subject: [PATCH 01/11] Switch from the inconsistent use of weak symbols to handling setup, etc in script generators --- auto/generate_test_runner.rb | 75 +++++++++++++++++++----------------- src/unity.h | 33 ++++------------ src/unity_internals.h | 16 -------- 3 files changed, 48 insertions(+), 76 deletions(-) diff --git a/auto/generate_test_runner.rb b/auto/generate_test_runner.rb index 6dc90e0..c7ec600 100644 --- a/auto/generate_test_runner.rb +++ b/auto/generate_test_runner.rb @@ -58,6 +58,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() # build runner file generate(input_file, output_file, tests, used_mocks, testfile_includes) @@ -165,11 +166,17 @@ class UnityTestRunnerGenerator mock_headers end + def find_setup_and_teardown(source) + @has_setup = source =~ /void\s+#{@options[setup_name]}\s*\(/ + @has_teardown = source =~ /void\s+#{@options[teardown_name]}\s*\(/ + @has_suite_setup = (!@options[:suite_setup].nil?) || (source =~ /void\s+suiteSetUp\s*\(/) + @has_suite_teardown = (!@options[:suite_teardown].nil?) || (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') @@ -204,8 +211,8 @@ class UnityTestRunnerGenerator def create_externs(output, tests, _mocks) output.puts("\n/*=======External Functions This Runner Calls=====*/") - output.puts("extern void #{@options[:setup_name]}(void);") - output.puts("extern void #{@options[:teardown_name]}(void);") + output.puts("extern void #{@options[:setup_name]}(void);") if @has_setup + output.puts("extern void #{@options[:teardown_name]}(void);") if @has_teardown output.puts("\n#ifdef __cplusplus\nextern \"C\"\n{\n#endif") if @options[:externc] tests.each do |test| output.puts("extern void #{test[:test]}(#{test[:call] || 'void'});") @@ -252,37 +259,31 @@ class UnityTestRunnerGenerator end def create_suite_setup(output) - output.puts("\n/*=======Suite Setup=====*/") - output.puts('static void suite_setup(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]) + if @has_suite_setup + if @options[:suite_setup].nil? + output.puts("\n/*=======Suite Setup=====*/") + output.puts('static void suiteSetUp(void)') + output.puts('{') + output.puts(@options[:suite_setup]) + output.puts('}') + else + output.puts('extern void suiteSetUp(void);') + end end - output.puts('}') end def create_suite_teardown(output) - output.puts("\n/*=======Suite Teardown=====*/") - output.puts('static int suite_teardown(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]) + if (@has_suite_teardown) + if @options[:suite_teardown].nil? + output.puts("\n/*=======Suite Teardown=====*/") + output.puts('static int suite_teardown(int num_failures)') + output.puts('{') + output.puts(@options[:suite_teardown]) + output.puts('}') + else + output.puts('extern int suite_teardown(int num_failures);') + end end - output.puts('}') end def create_runtest(output, used_mocks) @@ -304,13 +305,13 @@ class UnityTestRunnerGenerator output.puts(' { \\') output.puts(' CEXCEPTION_T e; \\') if cexception output.puts(' Try { \\') if cexception - output.puts(" #{@options[:setup_name]}(); \\") + output.puts(" #{@options[:setup_name]}(); \\") if @has_setup 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(" #{@options[:teardown_name]}(); \\") if @has_teardown output.puts(' CMock_Verify(); \\') unless used_mocks.empty? output.puts(' } \\') output.puts(' CMock_Destroy(); \\') unless used_mocks.empty? @@ -327,9 +328,9 @@ class UnityTestRunnerGenerator 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(" #{@options[:teardown_name]}();") if @has_teardown output.puts(' CMock_Init();') unless used_mocks.empty? - output.puts(" #{@options[:setup_name]}();") + output.puts(" #{@options[:setup_name]}();") if @has_setup output.puts('}') end @@ -375,7 +376,7 @@ class UnityTestRunnerGenerator output.puts("int #{main_name}(void)") output.puts('{') end - output.puts(' suite_setup();') + output.puts(' suiteSetUp();') if @has_suite_setup output.puts(" UnityBegin(\"#{filename.gsub(/\\/, '\\\\\\')}\");") if @options[:use_param_tests] tests.each do |test| @@ -390,7 +391,11 @@ class UnityTestRunnerGenerator end output.puts output.puts(' CMock_Guts_MemFreeFinal();') unless used_mocks.empty? - output.puts(' return suite_teardown(UnityEnd());') + if (@has_suite_teardown) + output.puts(' return suiteTearDown(UnityEnd());') + else + output.puts(' return UnityEnd();') + end output.puts('}') end diff --git a/src/unity.h b/src/unity.h index d1f8a1b..f97d141 100644 --- a/src/unity.h +++ b/src/unity.h @@ -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 *------------------------------------------------------- diff --git a/src/unity_internals.h b/src/unity_internals.h index 0dd08fb..0995281 100644 --- a/src/unity_internals.h +++ b/src/unity_internals.h @@ -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 *-------------------------------------------------------*/ From 9fdcc2d3ff86cda3b448c68ccad8e0cf272d4257 Mon Sep 17 00:00:00 2001 From: Mark VanderVoord Date: Mon, 21 Oct 2019 14:29:52 -0400 Subject: [PATCH 02/11] Catch up documentation to match these changes. --- docs/UnityConfigurationGuide.md | 34 ++------------------------------ docs/UnityGettingStartedGuide.md | 13 ++++++------ 2 files changed, 9 insertions(+), 38 deletions(-) diff --git a/docs/UnityConfigurationGuide.md b/docs/UnityConfigurationGuide.md index 75dbf67..68fb106 100644 --- a/docs/UnityConfigurationGuide.md +++ b/docs/UnityConfigurationGuide.md @@ -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 diff --git a/docs/UnityGettingStartedGuide.md b/docs/UnityGettingStartedGuide.md index eb7041d..c054b36 100644 --- a/docs/UnityGettingStartedGuide.md +++ b/docs/UnityGettingStartedGuide.md @@ -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. From c19e3f99ce0fdc65d705e150f241a6e4dd7e2c92 Mon Sep 17 00:00:00 2001 From: Mark VanderVoord Date: Mon, 21 Oct 2019 14:45:56 -0400 Subject: [PATCH 03/11] missed function call arguments --- auto/generate_test_runner.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/auto/generate_test_runner.rb b/auto/generate_test_runner.rb index c7ec600..f6e6a73 100644 --- a/auto/generate_test_runner.rb +++ b/auto/generate_test_runner.rb @@ -58,7 +58,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() + find_setup_and_teardown(source) # build runner file generate(input_file, output_file, tests, used_mocks, testfile_includes) From cb8744c4969cef513ce2da977f21a5ee9a9d39cc Mon Sep 17 00:00:00 2001 From: Mark VanderVoord Date: Mon, 21 Oct 2019 14:59:31 -0400 Subject: [PATCH 04/11] More argument fixing (I hate flying blind... can't wait to get back on my laptop) --- auto/generate_test_runner.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/auto/generate_test_runner.rb b/auto/generate_test_runner.rb index f6e6a73..bd61d5d 100644 --- a/auto/generate_test_runner.rb +++ b/auto/generate_test_runner.rb @@ -167,8 +167,8 @@ class UnityTestRunnerGenerator end def find_setup_and_teardown(source) - @has_setup = source =~ /void\s+#{@options[setup_name]}\s*\(/ - @has_teardown = source =~ /void\s+#{@options[teardown_name]}\s*\(/ + @has_setup = source =~ /void\s+#{@options[:setup_name]}\s*\(/ + @has_teardown = source =~ /void\s+#{@options[:teardown_name]}\s*\(/ @has_suite_setup = (!@options[:suite_setup].nil?) || (source =~ /void\s+suiteSetUp\s*\(/) @has_suite_teardown = (!@options[:suite_teardown].nil?) || (source =~ /void\s+suiteTearDown\s*\(/) end From 2d8a69e0d1809bd20dd5374009d30b45835962e3 Mon Sep 17 00:00:00 2001 From: Mark VanderVoord Date: Tue, 22 Oct 2019 06:27:26 -0400 Subject: [PATCH 05/11] update handling of when suite_setup/teardown in use --- auto/generate_test_runner.rb | 45 +++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/auto/generate_test_runner.rb b/auto/generate_test_runner.rb index bd61d5d..f8c93fc 100644 --- a/auto/generate_test_runner.rb +++ b/auto/generate_test_runner.rb @@ -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 @@ -167,10 +176,10 @@ class UnityTestRunnerGenerator end def find_setup_and_teardown(source) - @has_setup = source =~ /void\s+#{@options[:setup_name]}\s*\(/ - @has_teardown = source =~ /void\s+#{@options[:teardown_name]}\s*\(/ - @has_suite_setup = (!@options[:suite_setup].nil?) || (source =~ /void\s+suiteSetUp\s*\(/) - @has_suite_teardown = (!@options[:suite_teardown].nil?) || (source =~ /void\s+suiteTearDown\s*\(/) + @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 = []) @@ -211,8 +220,8 @@ class UnityTestRunnerGenerator def create_externs(output, tests, _mocks) output.puts("\n/*=======External Functions This Runner Calls=====*/") - output.puts("extern void #{@options[:setup_name]}(void);") if @has_setup - output.puts("extern void #{@options[:teardown_name]}(void);") if @has_teardown + output.puts("extern void #{@options[:setup_name]}(void);") if @options[:has_setup] + output.puts("extern void #{@options[:teardown_name]}(void);") if @options[:has_teardown] output.puts("\n#ifdef __cplusplus\nextern \"C\"\n{\n#endif") if @options[:externc] tests.each do |test| output.puts("extern void #{test[:test]}(#{test[:call] || 'void'});") @@ -259,7 +268,7 @@ class UnityTestRunnerGenerator end def create_suite_setup(output) - if @has_suite_setup + if @options[:has_suite_setup] if @options[:suite_setup].nil? output.puts("\n/*=======Suite Setup=====*/") output.puts('static void suiteSetUp(void)') @@ -273,7 +282,7 @@ class UnityTestRunnerGenerator end def create_suite_teardown(output) - if (@has_suite_teardown) + if @options[:has_suite_teardown] if @options[:suite_teardown].nil? output.puts("\n/*=======Suite Teardown=====*/") output.puts('static int suite_teardown(int num_failures)') @@ -305,13 +314,13 @@ class UnityTestRunnerGenerator output.puts(' { \\') output.puts(' CEXCEPTION_T e; \\') if cexception output.puts(' Try { \\') if cexception - output.puts(" #{@options[:setup_name]}(); \\") if @has_setup + output.puts(" #{@options[:setup_name]}(); \\") if @options[:has_setup] 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]}(); \\") if @has_teardown + output.puts(" #{@options[:teardown_name]}(); \\") if @options[:has_teardown] output.puts(' CMock_Verify(); \\') unless used_mocks.empty? output.puts(' } \\') output.puts(' CMock_Destroy(); \\') unless used_mocks.empty? @@ -328,9 +337,9 @@ class UnityTestRunnerGenerator output.puts('{') output.puts(' CMock_Verify();') unless used_mocks.empty? output.puts(' CMock_Destroy();') unless used_mocks.empty? - output.puts(" #{@options[:teardown_name]}();") if @has_teardown + output.puts(" #{@options[:teardown_name]}();") if @options[:has_teardown] output.puts(' CMock_Init();') unless used_mocks.empty? - output.puts(" #{@options[:setup_name]}();") if @has_setup + output.puts(" #{@options[:setup_name]}();") if @options[:has_setup] output.puts('}') end @@ -376,7 +385,7 @@ class UnityTestRunnerGenerator output.puts("int #{main_name}(void)") output.puts('{') end - output.puts(' suiteSetUp();') if @has_suite_setup + output.puts(' suiteSetUp();') if @options[:has_suite_setup] output.puts(" UnityBegin(\"#{filename.gsub(/\\/, '\\\\\\')}\");") if @options[:use_param_tests] tests.each do |test| @@ -391,7 +400,7 @@ class UnityTestRunnerGenerator end output.puts output.puts(' CMock_Guts_MemFreeFinal();') unless used_mocks.empty? - if (@has_suite_teardown) + if @options[:has_suite_teardown] output.puts(' return suiteTearDown(UnityEnd());') else output.puts(' return UnityEnd();') From ac427b28fc85727228cd7c261ff834d0fc7ec98b Mon Sep 17 00:00:00 2001 From: Mark VanderVoord Date: Tue, 22 Oct 2019 06:37:28 -0400 Subject: [PATCH 06/11] Fixed backwards case. --- auto/generate_test_runner.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/auto/generate_test_runner.rb b/auto/generate_test_runner.rb index f8c93fc..19fa6c1 100644 --- a/auto/generate_test_runner.rb +++ b/auto/generate_test_runner.rb @@ -269,7 +269,7 @@ class UnityTestRunnerGenerator def create_suite_setup(output) if @options[:has_suite_setup] - if @options[:suite_setup].nil? + if !@options[:suite_setup].nil? output.puts("\n/*=======Suite Setup=====*/") output.puts('static void suiteSetUp(void)') output.puts('{') @@ -283,7 +283,7 @@ class UnityTestRunnerGenerator def create_suite_teardown(output) if @options[:has_suite_teardown] - if @options[:suite_teardown].nil? + if !@options[:suite_teardown].nil? output.puts("\n/*=======Suite Teardown=====*/") output.puts('static int suite_teardown(int num_failures)') output.puts('{') From ff697ad29c31d92103c307b6c9946f1e36cf2222 Mon Sep 17 00:00:00 2001 From: Mark VanderVoord Date: Tue, 22 Oct 2019 06:45:47 -0400 Subject: [PATCH 07/11] suite setup and teardown no longer static (simplifies test-supplied instance) --- auto/generate_test_runner.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/auto/generate_test_runner.rb b/auto/generate_test_runner.rb index 19fa6c1..9c8cb35 100644 --- a/auto/generate_test_runner.rb +++ b/auto/generate_test_runner.rb @@ -271,7 +271,7 @@ class UnityTestRunnerGenerator if @options[:has_suite_setup] if !@options[:suite_setup].nil? output.puts("\n/*=======Suite Setup=====*/") - output.puts('static void suiteSetUp(void)') + output.puts('void suiteSetUp(void)') output.puts('{') output.puts(@options[:suite_setup]) output.puts('}') @@ -285,7 +285,7 @@ class UnityTestRunnerGenerator if @options[:has_suite_teardown] if !@options[:suite_teardown].nil? output.puts("\n/*=======Suite Teardown=====*/") - output.puts('static int suite_teardown(int num_failures)') + output.puts('int suite_teardown(int num_failures)') output.puts('{') output.puts(@options[:suite_teardown]) output.puts('}') From 5fc72fbca19153252704fc7d646a744622b8fd8f Mon Sep 17 00:00:00 2001 From: Mark VanderVoord Date: Tue, 22 Oct 2019 06:52:25 -0400 Subject: [PATCH 08/11] fix name of teardown function --- auto/generate_test_runner.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/auto/generate_test_runner.rb b/auto/generate_test_runner.rb index 9c8cb35..34762cf 100644 --- a/auto/generate_test_runner.rb +++ b/auto/generate_test_runner.rb @@ -285,12 +285,12 @@ class UnityTestRunnerGenerator if @options[:has_suite_teardown] if !@options[:suite_teardown].nil? output.puts("\n/*=======Suite Teardown=====*/") - output.puts('int suite_teardown(int num_failures)') + output.puts('int suiteTearDown(int num_failures)') output.puts('{') output.puts(@options[:suite_teardown]) output.puts('}') else - output.puts('extern int suite_teardown(int num_failures);') + output.puts('extern int suiteTearDown(int num_failures);') end end end From 68cc45a91849b4b176067e1434a8c4f94eaf5e56 Mon Sep 17 00:00:00 2001 From: John Lindgren Date: Tue, 22 Oct 2019 15:04:03 -0400 Subject: [PATCH 09/11] Make sure setUp/tearDown are always defined. --- auto/generate_test_runner.rb | 60 +++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 28 deletions(-) diff --git a/auto/generate_test_runner.rb b/auto/generate_test_runner.rb index 34762cf..0d8bc94 100644 --- a/auto/generate_test_runner.rb +++ b/auto/generate_test_runner.rb @@ -85,6 +85,8 @@ 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) @@ -220,8 +222,8 @@ class UnityTestRunnerGenerator def create_externs(output, tests, _mocks) output.puts("\n/*=======External Functions This Runner Calls=====*/") - output.puts("extern void #{@options[:setup_name]}(void);") if @options[:has_setup] - output.puts("extern void #{@options[:teardown_name]}(void);") if @options[:has_teardown] + output.puts("extern void #{@options[:setup_name]}(void);") + output.puts("extern void #{@options[:teardown_name]}(void);") output.puts("\n#ifdef __cplusplus\nextern \"C\"\n{\n#endif") if @options[:externc] tests.each do |test| output.puts("extern void #{test[:test]}(#{test[:call] || 'void'});") @@ -267,32 +269,34 @@ 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) - if @options[:has_suite_setup] - if !@options[:suite_setup].nil? - output.puts("\n/*=======Suite Setup=====*/") - output.puts('void suiteSetUp(void)') - output.puts('{') - output.puts(@options[:suite_setup]) - output.puts('}') - else - output.puts('extern void suiteSetUp(void);') - end - end + return if @options[:suite_setup].nil? + output.puts("\n/*=======Suite Setup=====*/") + output.puts('void suiteSetUp(void)') + output.puts('{') + output.puts(@options[:suite_setup]) + output.puts('}') end def create_suite_teardown(output) - if @options[:has_suite_teardown] - if !@options[:suite_teardown].nil? - output.puts("\n/*=======Suite Teardown=====*/") - output.puts('int suiteTearDown(int num_failures)') - output.puts('{') - output.puts(@options[:suite_teardown]) - output.puts('}') - else - output.puts('extern int suiteTearDown(int num_failures);') - end - end + return if @options[:suite_teardown].nil? + output.puts("\n/*=======Suite Teardown=====*/") + output.puts('int suiteTearDown(int num_failures)') + output.puts('{') + output.puts(@options[:suite_teardown]) + output.puts('}') end def create_runtest(output, used_mocks) @@ -314,13 +318,13 @@ class UnityTestRunnerGenerator output.puts(' { \\') output.puts(' CEXCEPTION_T e; \\') if cexception output.puts(' Try { \\') if cexception - output.puts(" #{@options[:setup_name]}(); \\") if @options[:has_setup] + 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]}(); \\") if @options[:has_teardown] + output.puts(" #{@options[:teardown_name]}(); \\") output.puts(' CMock_Verify(); \\') unless used_mocks.empty? output.puts(' } \\') output.puts(' CMock_Destroy(); \\') unless used_mocks.empty? @@ -337,9 +341,9 @@ class UnityTestRunnerGenerator output.puts('{') output.puts(' CMock_Verify();') unless used_mocks.empty? output.puts(' CMock_Destroy();') unless used_mocks.empty? - output.puts(" #{@options[:teardown_name]}();") if @options[:has_teardown] + output.puts(" #{@options[:teardown_name]}();") output.puts(' CMock_Init();') unless used_mocks.empty? - output.puts(" #{@options[:setup_name]}();") if @options[:has_setup] + output.puts(" #{@options[:setup_name]}();") output.puts('}') end From d10cf6645d24dfb782f38f4badf47c9d0426ffd3 Mon Sep 17 00:00:00 2001 From: John Lindgren Date: Tue, 22 Oct 2019 15:05:34 -0400 Subject: [PATCH 10/11] Remove unnecessary #includes. --- auto/generate_test_runner.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/auto/generate_test_runner.rb b/auto/generate_test_runner.rb index 0d8bc94..7484e6f 100644 --- a/auto/generate_test_runner.rb +++ b/auto/generate_test_runner.rb @@ -190,10 +190,6 @@ class UnityTestRunnerGenerator output.puts("\n/*=======Automagically Detected Files To Include=====*/") output.puts("#include \"#{@options[:framework]}.h\"") output.puts('#include "cmock.h"') unless mocks.empty? - output.puts('#ifndef UNITY_EXCLUDE_SETJMP_H') - output.puts('#include ') - output.puts('#endif') - output.puts('#include ') if @options[:defines] && !@options[:defines].empty? @options[:defines].each { |d| output.puts("#ifndef #{d}\n#define #{d}\n#endif /* #{d} */") } end From 277e844beda748a68e522d66b4890c5c7a108b53 Mon Sep 17 00:00:00 2001 From: John Lindgren Date: Tue, 22 Oct 2019 15:18:20 -0400 Subject: [PATCH 11/11] Convert RUN_TEST() to a function (generated from an ERB template). Converting RUN_TEST() from a macro to a function significantly reduces the size of the compiled binary. On amd64, the largest test runner in the test suite (testsample_DefaultsThroughCommandLine_runner.o) was reduced from 3.4 kB to 2.4 kB (stripped). --- auto/generate_test_runner.rb | 108 ++++++++++-------------- auto/run_test.erb | 36 ++++++++ test/tests/test_generate_test_runner.rb | 14 +-- 3 files changed, 87 insertions(+), 71 deletions(-) create mode 100644 auto/run_test.erb diff --git a/auto/generate_test_runner.rb b/auto/generate_test_runner.rb index 7484e6f..9016f9a 100644 --- a/auto/generate_test_runner.rb +++ b/auto/generate_test_runner.rb @@ -89,7 +89,9 @@ class UnityTestRunnerGenerator 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 @@ -186,7 +188,6 @@ class UnityTestRunnerGenerator 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("#include \"#{@options[:framework]}.h\"") output.puts('#include "cmock.h"') unless mocks.empty? @@ -229,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('{') @@ -295,54 +294,39 @@ class UnityTestRunnerGenerator 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 @@ -359,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' @@ -387,16 +367,16 @@ class UnityTestRunnerGenerator end 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? diff --git a/auto/run_test.erb b/auto/run_test.erb new file mode 100644 index 0000000..3d3b6d1 --- /dev/null +++ b/auto/run_test.erb @@ -0,0 +1,36 @@ +/*=======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(); +} diff --git a/test/tests/test_generate_test_runner.rb b/test/tests/test_generate_test_runner.rb index a3536d3..0b51bcd 100644 --- a/test/tests/test_generate_test_runner.rb +++ b/test/tests/test_generate_test_runner.rb @@ -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\)' ], }