From 277e844beda748a68e522d66b4890c5c7a108b53 Mon Sep 17 00:00:00 2001 From: John Lindgren Date: Tue, 22 Oct 2019 15:18:20 -0400 Subject: [PATCH] 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\)' ], } -- GitLab