19750e409Sopenharmony_ci# ========================================== 29750e409Sopenharmony_ci# Unity Project - A Test Framework for C 39750e409Sopenharmony_ci# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams 49750e409Sopenharmony_ci# [Released under MIT License. Please refer to license.txt for details] 59750e409Sopenharmony_ci# ========================================== 69750e409Sopenharmony_ci 79750e409Sopenharmony_ciFile.expand_path(File.join(File.dirname(__FILE__), 'colour_prompt')) 89750e409Sopenharmony_ci 99750e409Sopenharmony_ciclass UnityTestRunnerGenerator 109750e409Sopenharmony_ci def initialize(options = nil) 119750e409Sopenharmony_ci @options = UnityTestRunnerGenerator.default_options 129750e409Sopenharmony_ci case options 139750e409Sopenharmony_ci when NilClass then @options 149750e409Sopenharmony_ci when String then @options.merge!(UnityTestRunnerGenerator.grab_config(options)) 159750e409Sopenharmony_ci when Hash then @options.merge!(options) 169750e409Sopenharmony_ci else raise 'If you specify arguments, it should be a filename or a hash of options' 179750e409Sopenharmony_ci end 189750e409Sopenharmony_ci require "#{File.expand_path(File.dirname(__FILE__))}/type_sanitizer" 199750e409Sopenharmony_ci end 209750e409Sopenharmony_ci 219750e409Sopenharmony_ci def self.default_options 229750e409Sopenharmony_ci { 239750e409Sopenharmony_ci includes: [], 249750e409Sopenharmony_ci defines: [], 259750e409Sopenharmony_ci plugins: [], 269750e409Sopenharmony_ci framework: :unity, 279750e409Sopenharmony_ci test_prefix: 'test|spec|should', 289750e409Sopenharmony_ci mock_prefix: 'Mock', 299750e409Sopenharmony_ci setup_name: 'setUp', 309750e409Sopenharmony_ci teardown_name: 'tearDown', 319750e409Sopenharmony_ci main_name: 'main', # set to :auto to automatically generate each time 329750e409Sopenharmony_ci main_export_decl: '', 339750e409Sopenharmony_ci cmdline_args: false, 349750e409Sopenharmony_ci use_param_tests: false 359750e409Sopenharmony_ci } 369750e409Sopenharmony_ci end 379750e409Sopenharmony_ci 389750e409Sopenharmony_ci def self.grab_config(config_file) 399750e409Sopenharmony_ci options = default_options 409750e409Sopenharmony_ci unless config_file.nil? || config_file.empty? 419750e409Sopenharmony_ci require 'yaml' 429750e409Sopenharmony_ci yaml_guts = YAML.load_file(config_file) 439750e409Sopenharmony_ci options.merge!(yaml_guts[:unity] || yaml_guts[:cmock]) 449750e409Sopenharmony_ci raise "No :unity or :cmock section found in #{config_file}" unless options 459750e409Sopenharmony_ci end 469750e409Sopenharmony_ci options 479750e409Sopenharmony_ci end 489750e409Sopenharmony_ci 499750e409Sopenharmony_ci def run(input_file, output_file, options = nil) 509750e409Sopenharmony_ci @options.merge!(options) unless options.nil? 519750e409Sopenharmony_ci 529750e409Sopenharmony_ci # pull required data from source file 539750e409Sopenharmony_ci source = File.read(input_file) 549750e409Sopenharmony_ci source = source.force_encoding('ISO-8859-1').encode('utf-8', replace: nil) 559750e409Sopenharmony_ci tests = find_tests(source) 569750e409Sopenharmony_ci headers = find_includes(source) 579750e409Sopenharmony_ci testfile_includes = (headers[:local] + headers[:system]) 589750e409Sopenharmony_ci used_mocks = find_mocks(testfile_includes) 599750e409Sopenharmony_ci testfile_includes = (testfile_includes - used_mocks) 609750e409Sopenharmony_ci testfile_includes.delete_if { |inc| inc =~ /(unity|cmock)/ } 619750e409Sopenharmony_ci 629750e409Sopenharmony_ci # build runner file 639750e409Sopenharmony_ci generate(input_file, output_file, tests, used_mocks, testfile_includes) 649750e409Sopenharmony_ci 659750e409Sopenharmony_ci # determine which files were used to return them 669750e409Sopenharmony_ci all_files_used = [input_file, output_file] 679750e409Sopenharmony_ci all_files_used += testfile_includes.map { |filename| filename + '.c' } unless testfile_includes.empty? 689750e409Sopenharmony_ci all_files_used += @options[:includes] unless @options[:includes].empty? 699750e409Sopenharmony_ci all_files_used += headers[:linkonly] unless headers[:linkonly].empty? 709750e409Sopenharmony_ci all_files_used.uniq 719750e409Sopenharmony_ci end 729750e409Sopenharmony_ci 739750e409Sopenharmony_ci def generate(input_file, output_file, tests, used_mocks, testfile_includes) 749750e409Sopenharmony_ci File.open(output_file, 'w') do |output| 759750e409Sopenharmony_ci create_header(output, used_mocks, testfile_includes) 769750e409Sopenharmony_ci create_externs(output, tests, used_mocks) 779750e409Sopenharmony_ci create_mock_management(output, used_mocks) 789750e409Sopenharmony_ci create_suite_setup(output) 799750e409Sopenharmony_ci create_suite_teardown(output) 809750e409Sopenharmony_ci create_reset(output, used_mocks) 819750e409Sopenharmony_ci create_main(output, input_file, tests, used_mocks) 829750e409Sopenharmony_ci end 839750e409Sopenharmony_ci 849750e409Sopenharmony_ci return unless @options[:header_file] && !@options[:header_file].empty? 859750e409Sopenharmony_ci 869750e409Sopenharmony_ci File.open(@options[:header_file], 'w') do |output| 879750e409Sopenharmony_ci create_h_file(output, @options[:header_file], tests, testfile_includes, used_mocks) 889750e409Sopenharmony_ci end 899750e409Sopenharmony_ci end 909750e409Sopenharmony_ci 919750e409Sopenharmony_ci def find_tests(source) 929750e409Sopenharmony_ci tests_and_line_numbers = [] 939750e409Sopenharmony_ci 949750e409Sopenharmony_ci source_scrubbed = source.clone 959750e409Sopenharmony_ci source_scrubbed = source_scrubbed.gsub(/"[^"\n]*"/, '') # remove things in strings 969750e409Sopenharmony_ci source_scrubbed = source_scrubbed.gsub(/\/\/.*$/, '') # remove line comments 979750e409Sopenharmony_ci source_scrubbed = source_scrubbed.gsub(/\/\*.*?\*\//m, '') # remove block comments 989750e409Sopenharmony_ci lines = source_scrubbed.split(/(^\s*\#.*$) # Treat preprocessor directives as a logical line 999750e409Sopenharmony_ci | (;|\{|\}) /x) # Match ;, {, and } as end of lines 1009750e409Sopenharmony_ci 1019750e409Sopenharmony_ci lines.each_with_index do |line, _index| 1029750e409Sopenharmony_ci # find tests 1039750e409Sopenharmony_ci next unless line =~ /^((?:\s*TEST_CASE\s*\(.*?\)\s*)*)\s*void\s+((?:#{@options[:test_prefix]}).*)\s*\(\s*(.*)\s*\)/ 1049750e409Sopenharmony_ci arguments = Regexp.last_match(1) 1059750e409Sopenharmony_ci name = Regexp.last_match(2) 1069750e409Sopenharmony_ci call = Regexp.last_match(3) 1079750e409Sopenharmony_ci params = Regexp.last_match(4) 1089750e409Sopenharmony_ci args = nil 1099750e409Sopenharmony_ci if @options[:use_param_tests] && !arguments.empty? 1109750e409Sopenharmony_ci args = [] 1119750e409Sopenharmony_ci arguments.scan(/\s*TEST_CASE\s*\((.*)\)\s*$/) { |a| args << a[0] } 1129750e409Sopenharmony_ci end 1139750e409Sopenharmony_ci tests_and_line_numbers << { test: name, args: args, call: call, params: params, line_number: 0 } 1149750e409Sopenharmony_ci end 1159750e409Sopenharmony_ci tests_and_line_numbers.uniq! { |v| v[:test] } 1169750e409Sopenharmony_ci 1179750e409Sopenharmony_ci # determine line numbers and create tests to run 1189750e409Sopenharmony_ci source_lines = source.split("\n") 1199750e409Sopenharmony_ci source_index = 0 1209750e409Sopenharmony_ci tests_and_line_numbers.size.times do |i| 1219750e409Sopenharmony_ci source_lines[source_index..-1].each_with_index do |line, index| 1229750e409Sopenharmony_ci next unless line =~ /\s+#{tests_and_line_numbers[i][:test]}(?:\s|\()/ 1239750e409Sopenharmony_ci source_index += index 1249750e409Sopenharmony_ci tests_and_line_numbers[i][:line_number] = source_index + 1 1259750e409Sopenharmony_ci break 1269750e409Sopenharmony_ci end 1279750e409Sopenharmony_ci end 1289750e409Sopenharmony_ci 1299750e409Sopenharmony_ci tests_and_line_numbers 1309750e409Sopenharmony_ci end 1319750e409Sopenharmony_ci 1329750e409Sopenharmony_ci def find_includes(source) 1339750e409Sopenharmony_ci # remove comments (block and line, in three steps to ensure correct precedence) 1349750e409Sopenharmony_ci source.gsub!(/\/\/(?:.+\/\*|\*(?:$|[^\/])).*$/, '') # remove line comments that comment out the start of blocks 1359750e409Sopenharmony_ci source.gsub!(/\/\*.*?\*\//m, '') # remove block comments 1369750e409Sopenharmony_ci source.gsub!(/\/\/.*$/, '') # remove line comments (all that remain) 1379750e409Sopenharmony_ci 1389750e409Sopenharmony_ci # parse out includes 1399750e409Sopenharmony_ci includes = { 1409750e409Sopenharmony_ci local: source.scan(/^\s*#include\s+\"\s*(.+)\.[hH]\s*\"/).flatten, 1419750e409Sopenharmony_ci system: source.scan(/^\s*#include\s+<\s*(.+)\s*>/).flatten.map { |inc| "<#{inc}>" }, 1429750e409Sopenharmony_ci linkonly: source.scan(/^TEST_FILE\(\s*\"\s*(.+)\.[cC]\w*\s*\"/).flatten 1439750e409Sopenharmony_ci } 1449750e409Sopenharmony_ci includes 1459750e409Sopenharmony_ci end 1469750e409Sopenharmony_ci 1479750e409Sopenharmony_ci def find_mocks(includes) 1489750e409Sopenharmony_ci mock_headers = [] 1499750e409Sopenharmony_ci includes.each do |include_path| 1509750e409Sopenharmony_ci include_file = File.basename(include_path) 1519750e409Sopenharmony_ci mock_headers << include_path if include_file =~ /^#{@options[:mock_prefix]}/i 1529750e409Sopenharmony_ci end 1539750e409Sopenharmony_ci mock_headers 1549750e409Sopenharmony_ci end 1559750e409Sopenharmony_ci 1569750e409Sopenharmony_ci def create_header(output, mocks, testfile_includes = []) 1579750e409Sopenharmony_ci output.puts('/* AUTOGENERATED FILE. DO NOT EDIT. */') 1589750e409Sopenharmony_ci create_runtest(output, mocks) 1599750e409Sopenharmony_ci output.puts("\n/*=======Automagically Detected Files To Include=====*/") 1609750e409Sopenharmony_ci output.puts('#ifdef __WIN32__') 1619750e409Sopenharmony_ci output.puts('#define UNITY_INCLUDE_SETUP_STUBS') 1629750e409Sopenharmony_ci output.puts('#endif') 1639750e409Sopenharmony_ci output.puts("#include \"#{@options[:framework]}.h\"") 1649750e409Sopenharmony_ci output.puts('#include "cmock.h"') unless mocks.empty? 1659750e409Sopenharmony_ci output.puts('#include <setjmp.h>') 1669750e409Sopenharmony_ci output.puts('#include <stdio.h>') 1679750e409Sopenharmony_ci if @options[:defines] && !@options[:defines].empty? 1689750e409Sopenharmony_ci @options[:defines].each { |d| output.puts("#define #{d}") } 1699750e409Sopenharmony_ci end 1709750e409Sopenharmony_ci if @options[:header_file] && !@options[:header_file].empty? 1719750e409Sopenharmony_ci output.puts("#include \"#{File.basename(@options[:header_file])}\"") 1729750e409Sopenharmony_ci else 1739750e409Sopenharmony_ci @options[:includes].flatten.uniq.compact.each do |inc| 1749750e409Sopenharmony_ci output.puts("#include #{inc.include?('<') ? inc : "\"#{inc.gsub('.h', '')}.h\""}") 1759750e409Sopenharmony_ci end 1769750e409Sopenharmony_ci testfile_includes.each do |inc| 1779750e409Sopenharmony_ci output.puts("#include #{inc.include?('<') ? inc : "\"#{inc.gsub('.h', '')}.h\""}") 1789750e409Sopenharmony_ci end 1799750e409Sopenharmony_ci end 1809750e409Sopenharmony_ci mocks.each do |mock| 1819750e409Sopenharmony_ci output.puts("#include \"#{mock.gsub('.h', '')}.h\"") 1829750e409Sopenharmony_ci end 1839750e409Sopenharmony_ci output.puts('#include "CException.h"') if @options[:plugins].include?(:cexception) 1849750e409Sopenharmony_ci 1859750e409Sopenharmony_ci return unless @options[:enforce_strict_ordering] 1869750e409Sopenharmony_ci 1879750e409Sopenharmony_ci output.puts('') 1889750e409Sopenharmony_ci output.puts('int GlobalExpectCount;') 1899750e409Sopenharmony_ci output.puts('int GlobalVerifyOrder;') 1909750e409Sopenharmony_ci output.puts('char* GlobalOrderError;') 1919750e409Sopenharmony_ci end 1929750e409Sopenharmony_ci 1939750e409Sopenharmony_ci def create_externs(output, tests, _mocks) 1949750e409Sopenharmony_ci output.puts("\n/*=======External Functions This Runner Calls=====*/") 1959750e409Sopenharmony_ci output.puts("extern void #{@options[:setup_name]}(void);") 1969750e409Sopenharmony_ci output.puts("extern void #{@options[:teardown_name]}(void);") 1979750e409Sopenharmony_ci tests.each do |test| 1989750e409Sopenharmony_ci output.puts("extern void #{test[:test]}(#{test[:call] || 'void'});") 1999750e409Sopenharmony_ci end 2009750e409Sopenharmony_ci output.puts('') 2019750e409Sopenharmony_ci end 2029750e409Sopenharmony_ci 2039750e409Sopenharmony_ci def create_mock_management(output, mock_headers) 2049750e409Sopenharmony_ci return if mock_headers.empty? 2059750e409Sopenharmony_ci 2069750e409Sopenharmony_ci output.puts("\n/*=======Mock Management=====*/") 2079750e409Sopenharmony_ci output.puts('static void CMock_Init(void)') 2089750e409Sopenharmony_ci output.puts('{') 2099750e409Sopenharmony_ci 2109750e409Sopenharmony_ci if @options[:enforce_strict_ordering] 2119750e409Sopenharmony_ci output.puts(' GlobalExpectCount = 0;') 2129750e409Sopenharmony_ci output.puts(' GlobalVerifyOrder = 0;') 2139750e409Sopenharmony_ci output.puts(' GlobalOrderError = NULL;') 2149750e409Sopenharmony_ci end 2159750e409Sopenharmony_ci 2169750e409Sopenharmony_ci mocks = mock_headers.map { |mock| File.basename(mock) } 2179750e409Sopenharmony_ci mocks.each do |mock| 2189750e409Sopenharmony_ci mock_clean = TypeSanitizer.sanitize_c_identifier(mock) 2199750e409Sopenharmony_ci output.puts(" #{mock_clean}_Init();") 2209750e409Sopenharmony_ci end 2219750e409Sopenharmony_ci output.puts("}\n") 2229750e409Sopenharmony_ci 2239750e409Sopenharmony_ci output.puts('static void CMock_Verify(void)') 2249750e409Sopenharmony_ci output.puts('{') 2259750e409Sopenharmony_ci mocks.each do |mock| 2269750e409Sopenharmony_ci mock_clean = TypeSanitizer.sanitize_c_identifier(mock) 2279750e409Sopenharmony_ci output.puts(" #{mock_clean}_Verify();") 2289750e409Sopenharmony_ci end 2299750e409Sopenharmony_ci output.puts("}\n") 2309750e409Sopenharmony_ci 2319750e409Sopenharmony_ci output.puts('static void CMock_Destroy(void)') 2329750e409Sopenharmony_ci output.puts('{') 2339750e409Sopenharmony_ci mocks.each do |mock| 2349750e409Sopenharmony_ci mock_clean = TypeSanitizer.sanitize_c_identifier(mock) 2359750e409Sopenharmony_ci output.puts(" #{mock_clean}_Destroy();") 2369750e409Sopenharmony_ci end 2379750e409Sopenharmony_ci output.puts("}\n") 2389750e409Sopenharmony_ci end 2399750e409Sopenharmony_ci 2409750e409Sopenharmony_ci def create_suite_setup(output) 2419750e409Sopenharmony_ci output.puts("\n/*=======Suite Setup=====*/") 2429750e409Sopenharmony_ci output.puts('static void suite_setup(void)') 2439750e409Sopenharmony_ci output.puts('{') 2449750e409Sopenharmony_ci if @options[:suite_setup].nil? 2459750e409Sopenharmony_ci # New style, call suiteSetUp() if we can use weak symbols 2469750e409Sopenharmony_ci output.puts('#if defined(UNITY_WEAK_ATTRIBUTE) || defined(UNITY_WEAK_PRAGMA)') 2479750e409Sopenharmony_ci output.puts(' suiteSetUp();') 2489750e409Sopenharmony_ci output.puts('#endif') 2499750e409Sopenharmony_ci else 2509750e409Sopenharmony_ci # Old style, C code embedded in the :suite_setup option 2519750e409Sopenharmony_ci output.puts(@options[:suite_setup]) 2529750e409Sopenharmony_ci end 2539750e409Sopenharmony_ci output.puts('}') 2549750e409Sopenharmony_ci end 2559750e409Sopenharmony_ci 2569750e409Sopenharmony_ci def create_suite_teardown(output) 2579750e409Sopenharmony_ci output.puts("\n/*=======Suite Teardown=====*/") 2589750e409Sopenharmony_ci output.puts('static int suite_teardown(int num_failures)') 2599750e409Sopenharmony_ci output.puts('{') 2609750e409Sopenharmony_ci if @options[:suite_teardown].nil? 2619750e409Sopenharmony_ci # New style, call suiteTearDown() if we can use weak symbols 2629750e409Sopenharmony_ci output.puts('#if defined(UNITY_WEAK_ATTRIBUTE) || defined(UNITY_WEAK_PRAGMA)') 2639750e409Sopenharmony_ci output.puts(' return suiteTearDown(num_failures);') 2649750e409Sopenharmony_ci output.puts('#else') 2659750e409Sopenharmony_ci output.puts(' return num_failures;') 2669750e409Sopenharmony_ci output.puts('#endif') 2679750e409Sopenharmony_ci else 2689750e409Sopenharmony_ci # Old style, C code embedded in the :suite_teardown option 2699750e409Sopenharmony_ci output.puts(@options[:suite_teardown]) 2709750e409Sopenharmony_ci end 2719750e409Sopenharmony_ci output.puts('}') 2729750e409Sopenharmony_ci end 2739750e409Sopenharmony_ci 2749750e409Sopenharmony_ci def create_runtest(output, used_mocks) 2759750e409Sopenharmony_ci cexception = @options[:plugins].include? :cexception 2769750e409Sopenharmony_ci va_args1 = @options[:use_param_tests] ? ', ...' : '' 2779750e409Sopenharmony_ci va_args2 = @options[:use_param_tests] ? '__VA_ARGS__' : '' 2789750e409Sopenharmony_ci output.puts("\n/*=======Test Runner Used To Run Each Test Below=====*/") 2799750e409Sopenharmony_ci output.puts('#define RUN_TEST_NO_ARGS') if @options[:use_param_tests] 2809750e409Sopenharmony_ci output.puts("#define RUN_TEST(TestFunc, TestLineNum#{va_args1}) \\") 2819750e409Sopenharmony_ci output.puts('{ \\') 2829750e409Sopenharmony_ci output.puts(" Unity.CurrentTestName = #TestFunc#{va_args2.empty? ? '' : " \"(\" ##{va_args2} \")\""}; \\") 2839750e409Sopenharmony_ci output.puts(' Unity.CurrentTestLineNumber = TestLineNum; \\') 2849750e409Sopenharmony_ci output.puts(' if (UnityTestMatches()) { \\') if @options[:cmdline_args] 2859750e409Sopenharmony_ci output.puts(' Unity.NumberOfTests++; \\') 2869750e409Sopenharmony_ci output.puts(' CMock_Init(); \\') unless used_mocks.empty? 2879750e409Sopenharmony_ci output.puts(' UNITY_CLR_DETAILS(); \\') unless used_mocks.empty? 2889750e409Sopenharmony_ci output.puts(' if (TEST_PROTECT()) \\') 2899750e409Sopenharmony_ci output.puts(' { \\') 2909750e409Sopenharmony_ci output.puts(' CEXCEPTION_T e; \\') if cexception 2919750e409Sopenharmony_ci output.puts(' Try { \\') if cexception 2929750e409Sopenharmony_ci output.puts(" #{@options[:setup_name]}(); \\") 2939750e409Sopenharmony_ci output.puts(" TestFunc(#{va_args2}); \\") 2949750e409Sopenharmony_ci output.puts(' } Catch(e) { TEST_ASSERT_EQUAL_HEX32_MESSAGE(CEXCEPTION_NONE, e, "Unhandled Exception!"); } \\') if cexception 2959750e409Sopenharmony_ci output.puts(' } \\') 2969750e409Sopenharmony_ci output.puts(' if (TEST_PROTECT()) \\') 2979750e409Sopenharmony_ci output.puts(' { \\') 2989750e409Sopenharmony_ci output.puts(" #{@options[:teardown_name]}(); \\") 2999750e409Sopenharmony_ci output.puts(' CMock_Verify(); \\') unless used_mocks.empty? 3009750e409Sopenharmony_ci output.puts(' } \\') 3019750e409Sopenharmony_ci output.puts(' CMock_Destroy(); \\') unless used_mocks.empty? 3029750e409Sopenharmony_ci output.puts(' UnityConcludeTest(); \\') 3039750e409Sopenharmony_ci output.puts(' } \\') if @options[:cmdline_args] 3049750e409Sopenharmony_ci output.puts("}\n") 3059750e409Sopenharmony_ci end 3069750e409Sopenharmony_ci 3079750e409Sopenharmony_ci def create_reset(output, used_mocks) 3089750e409Sopenharmony_ci output.puts("\n/*=======Test Reset Option=====*/") 3099750e409Sopenharmony_ci output.puts('void resetTest(void);') 3109750e409Sopenharmony_ci output.puts('void resetTest(void)') 3119750e409Sopenharmony_ci output.puts('{') 3129750e409Sopenharmony_ci output.puts(' CMock_Verify();') unless used_mocks.empty? 3139750e409Sopenharmony_ci output.puts(' CMock_Destroy();') unless used_mocks.empty? 3149750e409Sopenharmony_ci output.puts(" #{@options[:teardown_name]}();") 3159750e409Sopenharmony_ci output.puts(' CMock_Init();') unless used_mocks.empty? 3169750e409Sopenharmony_ci output.puts(" #{@options[:setup_name]}();") 3179750e409Sopenharmony_ci output.puts('}') 3189750e409Sopenharmony_ci end 3199750e409Sopenharmony_ci 3209750e409Sopenharmony_ci def create_main(output, filename, tests, used_mocks) 3219750e409Sopenharmony_ci output.puts("\n\n/*=======MAIN=====*/") 3229750e409Sopenharmony_ci main_name = @options[:main_name].to_sym == :auto ? "main_#{filename.gsub('.c', '')}" : (@options[:main_name]).to_s 3239750e409Sopenharmony_ci if @options[:cmdline_args] 3249750e409Sopenharmony_ci if main_name != 'main' 3259750e409Sopenharmony_ci output.puts("#{@options[:main_export_decl]} int #{main_name}(int argc, char** argv);") 3269750e409Sopenharmony_ci end 3279750e409Sopenharmony_ci output.puts("#{@options[:main_export_decl]} int #{main_name}(int argc, char** argv)") 3289750e409Sopenharmony_ci output.puts('{') 3299750e409Sopenharmony_ci output.puts(' int parse_status = UnityParseOptions(argc, argv);') 3309750e409Sopenharmony_ci output.puts(' if (parse_status != 0)') 3319750e409Sopenharmony_ci output.puts(' {') 3329750e409Sopenharmony_ci output.puts(' if (parse_status < 0)') 3339750e409Sopenharmony_ci output.puts(' {') 3349750e409Sopenharmony_ci output.puts(" UnityPrint(\"#{filename.gsub('.c', '')}.\");") 3359750e409Sopenharmony_ci output.puts(' UNITY_PRINT_EOL();') 3369750e409Sopenharmony_ci if @options[:use_param_tests] 3379750e409Sopenharmony_ci tests.each do |test| 3389750e409Sopenharmony_ci if test[:args].nil? || test[:args].empty? 3399750e409Sopenharmony_ci output.puts(" UnityPrint(\" #{test[:test]}(RUN_TEST_NO_ARGS)\");") 3409750e409Sopenharmony_ci output.puts(' UNITY_PRINT_EOL();') 3419750e409Sopenharmony_ci else 3429750e409Sopenharmony_ci test[:args].each do |args| 3439750e409Sopenharmony_ci output.puts(" UnityPrint(\" #{test[:test]}(#{args})\");") 3449750e409Sopenharmony_ci output.puts(' UNITY_PRINT_EOL();') 3459750e409Sopenharmony_ci end 3469750e409Sopenharmony_ci end 3479750e409Sopenharmony_ci end 3489750e409Sopenharmony_ci else 3499750e409Sopenharmony_ci tests.each { |test| output.puts(" UnityPrint(\" #{test[:test]}\");\n UNITY_PRINT_EOL();") } 3509750e409Sopenharmony_ci end 3519750e409Sopenharmony_ci output.puts(' return 0;') 3529750e409Sopenharmony_ci output.puts(' }') 3539750e409Sopenharmony_ci output.puts(' return parse_status;') 3549750e409Sopenharmony_ci output.puts(' }') 3559750e409Sopenharmony_ci else 3569750e409Sopenharmony_ci if main_name != 'main' 3579750e409Sopenharmony_ci output.puts("#{@options[:main_export_decl]} int #{main_name}(void);") 3589750e409Sopenharmony_ci end 3599750e409Sopenharmony_ci output.puts("int #{main_name}(void)") 3609750e409Sopenharmony_ci output.puts('{') 3619750e409Sopenharmony_ci end 3629750e409Sopenharmony_ci output.puts(' suite_setup();') 3639750e409Sopenharmony_ci output.puts(" UnityBegin(\"#{filename.gsub(/\\/, '\\\\\\')}\");") 3649750e409Sopenharmony_ci if @options[:use_param_tests] 3659750e409Sopenharmony_ci tests.each do |test| 3669750e409Sopenharmony_ci if test[:args].nil? || test[:args].empty? 3679750e409Sopenharmony_ci output.puts(" RUN_TEST(#{test[:test]}, #{test[:line_number]}, RUN_TEST_NO_ARGS);") 3689750e409Sopenharmony_ci else 3699750e409Sopenharmony_ci test[:args].each { |args| output.puts(" RUN_TEST(#{test[:test]}, #{test[:line_number]}, #{args});") } 3709750e409Sopenharmony_ci end 3719750e409Sopenharmony_ci end 3729750e409Sopenharmony_ci else 3739750e409Sopenharmony_ci tests.each { |test| output.puts(" RUN_TEST(#{test[:test]}, #{test[:line_number]});") } 3749750e409Sopenharmony_ci end 3759750e409Sopenharmony_ci output.puts 3769750e409Sopenharmony_ci output.puts(' CMock_Guts_MemFreeFinal();') unless used_mocks.empty? 3779750e409Sopenharmony_ci output.puts(" return suite_teardown(UnityEnd());") 3789750e409Sopenharmony_ci output.puts('}') 3799750e409Sopenharmony_ci end 3809750e409Sopenharmony_ci 3819750e409Sopenharmony_ci def create_h_file(output, filename, tests, testfile_includes, used_mocks) 3829750e409Sopenharmony_ci filename = File.basename(filename).gsub(/[-\/\\\.\,\s]/, '_').upcase 3839750e409Sopenharmony_ci output.puts('/* AUTOGENERATED FILE. DO NOT EDIT. */') 3849750e409Sopenharmony_ci output.puts("#ifndef _#{filename}") 3859750e409Sopenharmony_ci output.puts("#define _#{filename}\n\n") 3869750e409Sopenharmony_ci output.puts("#include \"#{@options[:framework]}.h\"") 3879750e409Sopenharmony_ci output.puts('#include "cmock.h"') unless used_mocks.empty? 3889750e409Sopenharmony_ci @options[:includes].flatten.uniq.compact.each do |inc| 3899750e409Sopenharmony_ci output.puts("#include #{inc.include?('<') ? inc : "\"#{inc.gsub('.h', '')}.h\""}") 3909750e409Sopenharmony_ci end 3919750e409Sopenharmony_ci testfile_includes.each do |inc| 3929750e409Sopenharmony_ci output.puts("#include #{inc.include?('<') ? inc : "\"#{inc.gsub('.h', '')}.h\""}") 3939750e409Sopenharmony_ci end 3949750e409Sopenharmony_ci output.puts "\n" 3959750e409Sopenharmony_ci tests.each do |test| 3969750e409Sopenharmony_ci if test[:params].nil? || test[:params].empty? 3979750e409Sopenharmony_ci output.puts("void #{test[:test]}(void);") 3989750e409Sopenharmony_ci else 3999750e409Sopenharmony_ci output.puts("void #{test[:test]}(#{test[:params]});") 4009750e409Sopenharmony_ci end 4019750e409Sopenharmony_ci end 4029750e409Sopenharmony_ci output.puts("#endif\n\n") 4039750e409Sopenharmony_ci end 4049750e409Sopenharmony_ciend 4059750e409Sopenharmony_ci 4069750e409Sopenharmony_ciif $0 == __FILE__ 4079750e409Sopenharmony_ci options = { includes: [] } 4089750e409Sopenharmony_ci 4099750e409Sopenharmony_ci # parse out all the options first (these will all be removed as we go) 4109750e409Sopenharmony_ci ARGV.reject! do |arg| 4119750e409Sopenharmony_ci case arg 4129750e409Sopenharmony_ci when '-cexception' 4139750e409Sopenharmony_ci options[:plugins] = [:cexception] 4149750e409Sopenharmony_ci true 4159750e409Sopenharmony_ci when /\.*\.ya?ml/ 4169750e409Sopenharmony_ci options = UnityTestRunnerGenerator.grab_config(arg) 4179750e409Sopenharmony_ci true 4189750e409Sopenharmony_ci when /--(\w+)=\"?(.*)\"?/ 4199750e409Sopenharmony_ci options[Regexp.last_match(1).to_sym] = Regexp.last_match(2) 4209750e409Sopenharmony_ci true 4219750e409Sopenharmony_ci when /\.*\.h/ 4229750e409Sopenharmony_ci options[:includes] << arg 4239750e409Sopenharmony_ci true 4249750e409Sopenharmony_ci else false 4259750e409Sopenharmony_ci end 4269750e409Sopenharmony_ci end 4279750e409Sopenharmony_ci 4289750e409Sopenharmony_ci # make sure there is at least one parameter left (the input file) 4299750e409Sopenharmony_ci unless ARGV[0] 4309750e409Sopenharmony_ci puts ["\nusage: ruby #{__FILE__} (files) (options) input_test_file (output)", 4319750e409Sopenharmony_ci "\n input_test_file - this is the C file you want to create a runner for", 4329750e409Sopenharmony_ci ' output - this is the name of the runner file to generate', 4339750e409Sopenharmony_ci ' defaults to (input_test_file)_Runner', 4349750e409Sopenharmony_ci ' files:', 4359750e409Sopenharmony_ci ' *.yml / *.yaml - loads configuration from here in :unity or :cmock', 4369750e409Sopenharmony_ci ' *.h - header files are added as #includes in runner', 4379750e409Sopenharmony_ci ' options:', 4389750e409Sopenharmony_ci ' -cexception - include cexception support', 4399750e409Sopenharmony_ci ' --setup_name="" - redefine setUp func name to something else', 4409750e409Sopenharmony_ci ' --teardown_name="" - redefine tearDown func name to something else', 4419750e409Sopenharmony_ci ' --main_name="" - redefine main func name to something else', 4429750e409Sopenharmony_ci ' --test_prefix="" - redefine test prefix from default test|spec|should', 4439750e409Sopenharmony_ci ' --suite_setup="" - code to execute for setup of entire suite', 4449750e409Sopenharmony_ci ' --suite_teardown="" - code to execute for teardown of entire suite', 4459750e409Sopenharmony_ci ' --use_param_tests=1 - enable parameterized tests (disabled by default)', 4469750e409Sopenharmony_ci ' --header_file="" - path/name of test header file to generate too'].join("\n") 4479750e409Sopenharmony_ci exit 1 4489750e409Sopenharmony_ci end 4499750e409Sopenharmony_ci 4509750e409Sopenharmony_ci # create the default test runner name if not specified 4519750e409Sopenharmony_ci ARGV[1] = ARGV[0].gsub('.c', '_Runner.c') unless ARGV[1] 4529750e409Sopenharmony_ci 4539750e409Sopenharmony_ci UnityTestRunnerGenerator.new(options).run(ARGV[0], ARGV[1]) 4549750e409Sopenharmony_ciend 455