diff --git a/auto/generate_test_runner.rb b/auto/generate_test_runner.rb index 6dc90e05..e0370edb 100644 --- a/auto/generate_test_runner.rb +++ b/auto/generate_test_runner.rb @@ -75,9 +75,12 @@ def generate(input_file, output_file, tests, used_mocks, testfile_includes) 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_args_wrappers(output, tests) create_main(output, input_file, tests, used_mocks) end @@ -167,15 +170,10 @@ def find_mocks(includes) 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('#define UNITY_RUNNER_USE_CEXCEPTION') if @options[:plugins].include?(:cexception) + output.puts('#include "unity_runner_common.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 @@ -192,7 +190,6 @@ def create_header(output, mocks, testfile_includes = []) mocks.each do |mock| output.puts("#include \"#{mock.gsub('.h', '')}.h\"") end - output.puts('#include "CException.h"') if @options[:plugins].include?(:cexception) return unless @options[:enforce_strict_ordering] @@ -204,8 +201,8 @@ def create_header(output, mocks, testfile_includes = []) 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 @options[:setup_name] != 'setUp' + output.puts("extern void #{@options[:teardown_name]}(void);") if @options[:teardown_name] != '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'});") @@ -215,10 +212,8 @@ def create_externs(output, tests, _mocks) 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('void UnityRunner_Init(void)') output.puts('{') if @options[:enforce_strict_ordering] @@ -234,7 +229,7 @@ def create_mock_management(output, mock_headers) end output.puts("}\n") - output.puts('static void CMock_Verify(void)') + output.puts('void UnityRunner_Verify(void)') output.puts('{') mocks.each do |mock| mock_clean = TypeSanitizer.sanitize_c_identifier(mock) @@ -242,7 +237,7 @@ def create_mock_management(output, mock_headers) end output.puts("}\n") - output.puts('static void CMock_Destroy(void)') + output.puts('void UnityRunner_Destroy(void)') output.puts('{') mocks.each do |mock| mock_clean = TypeSanitizer.sanitize_c_identifier(mock) @@ -251,9 +246,25 @@ def create_mock_management(output, mock_headers) output.puts("}\n") end + def create_setup(output) + output.puts("\n/*=======Test Setup=====*/") + output.puts('void UnityRunner_SetUp(void)') + output.puts('{') + output.puts(" #{@options[:setup_name]}();") + output.puts('}') + end + + def create_teardown(output) + output.puts("\n/*=======Test Teardown=====*/") + output.puts('void UnityRunner_TearDown(void)') + output.puts('{') + output.puts(" #{@options[:teardown_name]}();") + output.puts('}') + end + def create_suite_setup(output) output.puts("\n/*=======Suite Setup=====*/") - output.puts('static void suite_setup(void)') + output.puts('void UnityRunner_SuiteSetUp(void)') output.puts('{') if @options[:suite_setup].nil? # New style, call suiteSetUp() if we can use weak symbols @@ -269,7 +280,7 @@ def create_suite_setup(output) def create_suite_teardown(output) output.puts("\n/*=======Suite Teardown=====*/") - output.puts('static int suite_teardown(int num_failures)') + output.puts('int UnityRunner_SuiteTearDown(int num_failures)') output.puts('{') if @options[:suite_teardown].nil? # New style, call suiteTearDown() if we can use weak symbols @@ -285,54 +296,33 @@ def create_suite_teardown(output) 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(" #{@options[:setup_name]}();") + output.puts(' UnityRunner_TearDown();') + output.puts(' UnityRunner_Verify();') + output.puts(' UnityRunner_Destroy();') + output.puts(' UnityRunner_Init();') + output.puts(' UnityRunner_SetUp();') output.puts('}') 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 +339,20 @@ def create_main(output, filename, tests, used_mocks) 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 +361,22 @@ def create_main(output, filename, tests, used_mocks) output.puts("int #{main_name}(void)") output.puts('{') end - output.puts(' suite_setup();') + output.puts(' UnityRunner_SuiteSetUp();') 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(" UnityRunner_RunTest(#{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(" UnityRunner_RunTest(#{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());') + output.puts(' return UnityRunner_SuiteTearDown(UnityEnd());') output.puts('}') end @@ -399,7 +385,7 @@ def create_h_file(output, filename, tests, testfile_includes, used_mocks) output.puts('/* AUTOGENERATED FILE. DO NOT EDIT. */') output.puts("#ifndef _#{filename}") output.puts("#define _#{filename}\n\n") - output.puts("#include \"#{@options[:framework]}.h\"") + output.puts('#include "unity.h"') output.puts('#include "cmock.h"') unless used_mocks.empty? @options[:includes].flatten.uniq.compact.each do |inc| output.puts("#include #{inc.include?('<') ? inc : "\"#{inc.gsub('.h', '')}.h\""}") diff --git a/src/unity.c b/src/unity.c index 9883fd75..2d82ef0d 100644 --- a/src/unity.c +++ b/src/unity.c @@ -5,6 +5,7 @@ ============================================================================ */ #include "unity.h" +#include "unity_setup_stubs.h" #include #ifdef AVR diff --git a/src/unity.h b/src/unity.h index d1f8a1b8..535b6f84 100644 --- a/src/unity.h +++ b/src/unity.h @@ -34,28 +34,28 @@ void tearDown(void); 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 +/* Stubs of the above four functions are provided as weak symbols in + * unity_setup_stubs.h. */ + +/*------------------------------------------------------- + * Test Runner Interface + *-------------------------------------------------------*/ + +/* These functions are provided by the generated test runner. */ +void UnityRunner_Init(void); +void UnityRunner_Verify(void); +void UnityRunner_Destroy(void); + +/* These functions generally just wrap the normal setup/teardown functions, + * but could do something else depending on the test runner configuration. */ +void UnityRunner_SetUp(void); +void UnityRunner_TearDown(void); +void UnityRunner_SuiteSetUp(void); +int UnityRunner_SuiteTearDown(int num_failures); + +/* A modified version of UnityDefaultTestRun() that interfaces with the + * rest of the test runner interface. */ +void UnityRunner_RunTest(UnityTestFunction func, const char* name, int line_num); /*------------------------------------------------------- * Configuration Options diff --git a/src/unity_runner_common.h b/src/unity_runner_common.h new file mode 100644 index 00000000..34ace57a --- /dev/null +++ b/src/unity_runner_common.h @@ -0,0 +1,66 @@ +/* ========================================== + Unity Project - A Test Framework for C + Copyright (c) 2007-14 Mike Karlesky, Mark VanderVoord, Greg Williams + [Released under MIT License. Please refer to license.txt for details] +========================================== */ + +#ifndef UNITY_RUNNER_COMMON_H +#define UNITY_RUNNER_COMMON_H + +/* This file defines the non-generated portion of each test runner. */ + +#include "unity.h" + +#ifdef __WIN32__ +#include "unity_setup_stubs.h" +#endif + +#ifdef UNITY_RUNNER_USE_CEXCEPTION +#include "CException.h" +#endif + +/*-----------------------------------------------*/ +void UnityRunner_RunTest(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(); + UnityRunner_Init(); + + if (TEST_PROTECT()) + { +#ifdef UNITY_RUNNER_USE_CEXCEPTION + CEXCEPTION_T e; + Try { +#endif + + UnityRunner_SetUp(); + func(); + +#ifdef UNITY_RUNNER_USE_CEXCEPTION + } Catch(e) { + TEST_ASSERT_EQUAL_HEX32_MESSAGE(CEXCEPTION_NONE, e, "Unhandled Exception!"); + } +#endif + } + + if (TEST_PROTECT()) + { + UnityRunner_TearDown(); + UnityRunner_Verify(); + } + + UnityRunner_Destroy(); + UNITY_EXEC_TIME_STOP(); + UnityConcludeTest(); +} + +#endif diff --git a/src/unity_setup_stubs.h b/src/unity_setup_stubs.h new file mode 100644 index 00000000..186ff475 --- /dev/null +++ b/src/unity_setup_stubs.h @@ -0,0 +1,46 @@ +/* ========================================== + Unity Project - A Test Framework for C + Copyright (c) 2007-19 Mike Karlesky, Mark VanderVoord, Greg Williams + [Released under MIT License. Please refer to license.txt for details] +========================================== */ + +#ifndef UNITY_SETUP_STUBS_H +#define UNITY_SETUP_STUBS_H + +#include "unity.h" + +/* If the compiler supports it, this header provides stub implementations + * of the following functions as weak symbols: + * + * - setUp() + * - tearDown() + * - suiteSetUp() + * - suiteTearDown() + * + * This header is always included by unity.c, which is sufficient when + * targeting GNU/Linux and other ELF targets. On some other platforms + * (MinGW for example), weak function implementations need to be in the + * same translation unit they are called from, so this header is also + * included by each test runner via unity_runner_common.h. + * + * If neither UNITY_WEAK_ATTRIBUTE nor UNITY_WEAK_PRAGMA is defined, the + * compiler is assumed to have no support for weak symbols, and this + * header has no effect. */ + +#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 diff --git a/test/tests/test_generate_test_runner.rb b/test/tests/test_generate_test_runner.rb index a3536d36..0b51bcd4 100644 --- a/test/tests/test_generate_test_runner.rb +++ b/test/tests/test_generate_test_runner.rb @@ -149,7 +149,7 @@ '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 @@ '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 @@ '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 @@ '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 @@ '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 @@ '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 @@ 'paratest_ShouldHandleParameterizedTests\(125\)', 'paratest_ShouldHandleParameterizedTests\(5\)', 'paratest_ShouldHandleParameterizedTests2\(7\)', - 'paratest_ShouldHandleNonParameterizedTestsWhenParameterizationValid\(RUN_TEST_NO_ARGS\)', + 'paratest_ShouldHandleNonParameterizedTestsWhenParameterizationValid', 'paratest_ShouldHandleParameterizedTestsThatFail\(17\)' ], }