diff --git a/auto/generate_test_runner.rb b/auto/generate_test_runner.rb new file mode 100644 index 0000000..d20d83b --- /dev/null +++ b/auto/generate_test_runner.rb @@ -0,0 +1,177 @@ + +class UnityTestRunnerGenerator + + def run(input_file, output_file, additional_includes=[], tab=' ') + @tab = tab + tests = [] + includes = [] + used_mocks = [] + + module_name = File.basename(input_file) + + File.open(input_file, 'r') do |input| + tests = find_tests(input) + includes = find_includes(input) + used_mocks = find_mocks(includes) + end + + File.open(output_file, 'w') do |output| + create_header(output, used_mocks, additional_includes) + create_externs(output, tests, used_mocks) + create_mock_management(output, used_mocks) + create_runtest(output, used_mocks) + create_main(output, module_name, tests) + end + + all_files_used = [input_file, output_file] + all_files_used += includes.map {|filename| filename + '.c'} unless includes.empty? + all_files_used += additional_includes unless additional_includes.empty? + return all_files_used.uniq + end + + def find_tests(input_file) + input_file.rewind + tests = [] + source = input_file.read() + source = source.gsub(/\/\/.*$/, '') #remove line comments + source = source.gsub(/\/\*.*?\*\//m, '') #remove block comments + lines = source.split(/(^\s*\#.*$) # Treat preprocessor directives as a logical line + | (;|\{|\}) /x) # Match ;, {, and } as end of lines + lines.each do |line| + if line =~ /^\s*void\s+test(.*?)\s*\(\s*void\s*\)/ + tests << "test" + $1 + end + end + return tests + end + + def find_includes(input_file) + input_file.rewind + includes = [] + input_file.readlines.each do |line| + scan_results = line.scan(/^#include\s+\"\s*(.+)\.h\s*\"/) + includes << scan_results[0][0] if (scan_results.size > 0) + end + return includes + end + + def find_mocks(includes) + mock_headers = [] + includes.each do |include_file| + mock_headers << include_file if include_file.include? "Mock" + end + return mock_headers + end + + def create_header(output, mocks, additional_includes=[]) + output.puts('/* AUTOGENERATED FILE. DO NOT EDIT. */') + output.puts('#include "unity.h"') + additional_includes.each do |includes| + output.puts("#include \"#{includes}.h\"") + end + mocks.each do |mock| + output.puts("#include \"#{mock}.h\"") + end + output.puts('#include ') + output.puts('#include ') + output.puts('') + output.puts('jmp_buf AbortFrame;') + output.puts('') + output.puts('char MessageBuffer[50];') + end + + + def create_externs(output, tests, mocks) + output.puts('') + + output.puts("extern void setUp(void);") + output.puts("extern void tearDown(void);") + + output.puts('') + + tests.each do |test| + output.puts("extern void #{test}(void);") + end + + output.puts('') + end + + + def create_mock_management(output, mocks) + unless (mocks.empty?) + output.puts("static void CMock_Init(void)") + output.puts("{") + mocks.each do |mock| + output.puts("#{@tab}#{mock}_Init();") + end + output.puts("}\n") + + output.puts("static void CMock_Verify(void)") + output.puts("{") + mocks.each do |mock| + output.puts("#{@tab}#{mock}_Verify();") + end + output.puts("}\n") + + output.puts("static void CMock_Destroy(void)") + output.puts("{") + mocks.each do |mock| + output.puts("#{@tab}#{mock}_Destroy();") + end + output.puts("}\n") + end + end + + + def create_runtest(output, used_mocks) + output.puts("static void runTest(UnityTestFunction test)") + output.puts("{") + output.puts("#{@tab}if (TEST_PROTECT())") + output.puts("#{@tab}{") + output.puts("#{@tab}#{@tab}CMock_Init();") unless (used_mocks.empty?) + output.puts("#{@tab}#{@tab}setUp();") + output.puts("#{@tab}#{@tab}test();") + output.puts("#{@tab}}") + output.puts("#{@tab}TEST_WRAP(CMock_Verify());") unless (used_mocks.empty?) + output.puts("#{@tab}CMock_Destroy();") unless (used_mocks.empty?) + output.puts("#{@tab}tearDown();") + output.puts("}") + end + + + def create_main(output, module_name, tests) + output.puts() + output.puts() + output.puts("int main(void)") + output.puts("{") + output.puts("#{@tab}Unity.TestFile = \"#{module_name}\";") + output.puts("#{@tab}UnityBegin();") + output.puts() + + output.puts("#{@tab}// RUN_TEST calls runTest") + tests.each do |test| + output.puts("#{@tab}RUN_TEST(#{test});") + end + + output.puts() + output.puts("#{@tab}UnityEnd();") + output.puts("#{@tab}return 0;") + output.puts("}") + end + +end + + +if ($0 == __FILE__) + usage = "usage: ruby #{__FILE__} input_test_file output_test_runner" + + if !ARGV[0] + puts usage + exit 1 + end + + ARGV[1] = ARGV[0].gsub(".c","_sRunner.c") if (!ARGV[1]) + + UnityTestRunnerGenerator.new + UnityTestRunnerGenerator.run(ARGV[0], ARGV[1]) +end diff --git a/rakefile_helper.rb b/rakefile_helper.rb index ae863ea..3b1331d 100644 --- a/rakefile_helper.rb +++ b/rakefile_helper.rb @@ -1,5 +1,6 @@ require 'yaml' require 'lib/cmock' +require 'auto/generate_test_runner' def Kernel.is_windows? processor, platform, *rest = RUBY_PLATFORM.split("-") @@ -116,6 +117,15 @@ module RakefileHelpers obj_list << header.ext(OBJ_EXTENSION) end + # Generate and build the test runner + runner_name = test_base + '_Runner.c' + runner_path = SYSTEST_BUILD_DIR + runner_name + test_gen = UnityTestRunnerGenerator.new + test_gen.run(test, runner_path) + compile(config, runner_path) + obj_list << runner_name.ext(OBJ_EXTENSION) + + # Build the test file compile(config, test) obj_list << test_base.ext(OBJ_EXTENSION) diff --git a/test/system/source/MySwankApp.c b/test/system/source/MySwankApp.c index 7ea2f76..e8d2eea 100644 --- a/test/system/source/MySwankApp.c +++ b/test/system/source/MySwankApp.c @@ -4,7 +4,9 @@ int main(void) { - printf("Hello world!\n"); + int a = 123, b = 456; + printf("What is %d + %d?\n", a, b); Add(123, 456); + printf("Now that's swankadelic!\n"); return 0; } diff --git a/test/system/source/Stuff.c b/test/system/source/Stuff.c index 221f2eb..560c2ec 100644 --- a/test/system/source/Stuff.c +++ b/test/system/source/Stuff.c @@ -2,5 +2,5 @@ void ReportAnswer(int answer) { - printf("The answer is %d!\n", answer); + printf("The answer is %d.\n", answer); } diff --git a/test/system/test/SimpleTest.c b/test/system/test/SimpleTest.c index 3c652d0..33ebf5a 100644 --- a/test/system/test/SimpleTest.c +++ b/test/system/test/SimpleTest.c @@ -32,44 +32,3 @@ void test_Simple_Add_ShouldSumValues(void) ReportAnswer_Expect(-10); TEST_ASSERT_EQUAL(-10, Add(-90, 80)); } - -/////////////////////////////////////////////////////////////////////////// -// TEST SUPPORT - -static void CMock_Init(void) -{ - MockStuff_Init(); -} -static void CMock_Verify(void) -{ - MockStuff_Verify(); -} -static void CMock_Destroy(void) -{ - MockStuff_Destroy(); -} - -static void runTest(UnityTestFunction test) -{ - if (TEST_PROTECT()) - { - CMock_Init(); - test(); - TEST_WRAP(CMock_Verify()); - CMock_Destroy(); - } -} - -int main(void) -{ - Unity.TestFile = "SimpleTest.c"; - UnityBegin(); - - // RUN_TEST calls runTest - RUN_TEST(test_Simple_Add_ShouldSumValues); - - UnityEnd(); - - return 0; -} -