Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 69 additions & 83 deletions auto/generate_test_runner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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 <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
Expand All @@ -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]

Expand All @@ -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'});")
Expand All @@ -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]
Expand All @@ -234,15 +229,15 @@ 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)
output.puts(" #{mock_clean}_Verify();")
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)
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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'
Expand All @@ -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

Expand All @@ -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\""}")
Expand Down
1 change: 1 addition & 0 deletions src/unity.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
============================================================================ */

#include "unity.h"
#include "unity_setup_stubs.h"
#include <stddef.h>

#ifdef AVR
Expand Down
44 changes: 22 additions & 22 deletions src/unity.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
66 changes: 66 additions & 0 deletions src/unity_runner_common.h
Original file line number Diff line number Diff line change
@@ -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
Loading