From d3c18c26ad358ca3bc7f669f0860959d77ae3324 Mon Sep 17 00:00:00 2001 From: Mark VanderVoord Date: Fri, 28 Feb 2014 10:37:47 -0500 Subject: [PATCH] support different encoding styles and force to something we can work with. --- auto/generate_test_runner.rb | 115 +++++++++++++++++------------------ 1 file changed, 55 insertions(+), 60 deletions(-) diff --git a/auto/generate_test_runner.rb b/auto/generate_test_runner.rb index 6a612eb..0eedb7d 100644 --- a/auto/generate_test_runner.rb +++ b/auto/generate_test_runner.rb @@ -2,8 +2,9 @@ # Unity Project - A Test Framework for C # Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams # [Released under MIT License. Please refer to license.txt for details] -# ========================================== +# ========================================== +$QUICK_RUBY_VERSION = RUBY_VERSION.split('.').inject(0){|vv,v| vv * 100 + v.to_i } File.expand_path(File.join(File.dirname(__FILE__),'colour_prompt')) class UnityTestRunnerGenerator @@ -17,7 +18,7 @@ class UnityTestRunnerGenerator else raise "If you specify arguments, it should be a filename or a hash of options" end end - + def self.grab_config(config_file) options = { :includes => [], :plugins => [], :framework => :unity } unless (config_file.nil? or config_file.empty?) @@ -33,27 +34,27 @@ class UnityTestRunnerGenerator tests = [] testfile_includes = [] used_mocks = [] - + @options.merge!(options) unless options.nil? module_name = File.basename(input_file) - + #pull required data from source file - File.open(input_file, 'r') do |input| - tests = find_tests(input) - testfile_includes = find_includes(input) - used_mocks = find_mocks(testfile_includes) - end + source = File.read(input_file) + source = source.force_encoding("ISO-8859-1").encode("utf-8", replace: nil) if ($QUICK_RUBY_VERSION > 10900) + tests = find_tests(source) + testfile_includes = find_includes(source) + used_mocks = find_mocks(testfile_includes) #build runner file generate(input_file, output_file, tests, used_mocks, testfile_includes) - + #determine which files were used to return them all_files_used = [input_file, output_file] all_files_used += testfile_includes.map {|filename| filename + '.c'} unless testfile_includes.empty? all_files_used += @options[:includes] unless @options[:includes].empty? return all_files_used.uniq end - + def generate(input_file, output_file, tests, used_mocks, testfile_includes) File.open(output_file, 'w') do |output| create_header(output, used_mocks, testfile_includes) @@ -64,15 +65,13 @@ class UnityTestRunnerGenerator create_main(output, input_file, tests) end end - - def find_tests(input_file) + + def find_tests(source) tests_raw = [] tests_args = [] tests_and_line_numbers = [] - - input_file.rewind - source_raw = input_file.read - source_scrubbed = source_raw.gsub(/\/\/.*$/, '') # remove line comments + + source_scrubbed = source.gsub(/\/\/.*$/, '') # remove line comments source_scrubbed = source_scrubbed.gsub(/\/\*.*?\*\//m, '') # remove block comments lines = source_scrubbed.split(/(^\s*\#.*$) # Treat preprocessor directives as a logical line | (;|\{|\}) /x) # Match ;, {, and } as end of lines @@ -94,7 +93,7 @@ class UnityTestRunnerGenerator end #determine line numbers and create tests to run - source_lines = source_raw.split("\n") + source_lines = source.split("\n") source_index = 0; tests_and_line_numbers.size.times do |i| source_lines[source_index..-1].each_with_index do |line, index| @@ -105,36 +104,32 @@ class UnityTestRunnerGenerator end end end - + return tests_and_line_numbers end - def find_includes(input_file) - input_file.rewind - - #read in file - source = input_file.read - + def find_includes(source) + #remove comments (block and line, in three steps to ensure correct precedence) source.gsub!(/\/\/(?:.+\/\*|\*(?:$|[^\/])).*$/, '') # remove line comments that comment out the start of blocks - source.gsub!(/\/\*.*?\*\//m, '') # remove block comments + source.gsub!(/\/\*.*?\*\//m, '') # remove block comments source.gsub!(/\/\/.*$/, '') # remove line comments (all that remain) - + #parse out includes - includes = source.scan(/^\s*#include\s+\"\s*(.+)\.[hH]\s*\"/).flatten - brackets_includes = source.scan(/^\s*#include\s+<\s*(.+)\s*>/).flatten - brackets_includes.each { |inc| includes << '<' + inc +'>' } - return includes + includes = source.scan(/^\s*#include\s+\"\s*(.+)\.[hH]\s*\"/).flatten + brackets_includes = source.scan(/^\s*#include\s+<\s*(.+)\s*>/).flatten + brackets_includes.each { |inc| includes << '<' + inc +'>' } + return includes end - + def find_mocks(includes) mock_headers = [] includes.each do |include_file| mock_headers << File.basename(include_file) if (include_file =~ /^mock/i) end - return mock_headers + return mock_headers end - + def create_header(output, mocks, testfile_includes) output.puts('/* AUTOGENERATED FILE. DO NOT EDIT. */') create_runtest(output, mocks) @@ -148,21 +143,21 @@ class UnityTestRunnerGenerator output.puts('#include ') output.puts('#include "CException.h"') if @options[:plugins].include?(:cexception) testfile_includes.delete("unity").delete("cmock") - testrunner_includes = testfile_includes - mocks - testrunner_includes.each do |inc| - output.puts("#include #{inc.include?('<') ? inc : "\"#{inc.gsub('.h','')}.h\""}") + testrunner_includes = testfile_includes - mocks + testrunner_includes.each do |inc| + output.puts("#include #{inc.include?('<') ? inc : "\"#{inc.gsub('.h','')}.h\""}") end mocks.each do |mock| output.puts("#include \"#{mock.gsub('.h','')}.h\"") end if @options[:enforce_strict_ordering] - output.puts('') - output.puts('int GlobalExpectCount;') - output.puts('int GlobalVerifyOrder;') - output.puts('char* GlobalOrderError;') + output.puts('') + output.puts('int GlobalExpectCount;') + output.puts('int GlobalVerifyOrder;') + output.puts('char* GlobalOrderError;') end end - + def create_externs(output, tests, mocks) output.puts("\n//=======External Functions This Runner Calls=====") output.puts("extern void setUp(void);") @@ -172,7 +167,7 @@ class UnityTestRunnerGenerator end output.puts('') end - + def create_mock_management(output, mocks) unless (mocks.empty?) output.puts("\n//=======Mock Management=====") @@ -180,8 +175,8 @@ class UnityTestRunnerGenerator output.puts("{") if @options[:enforce_strict_ordering] output.puts(" GlobalExpectCount = 0;") - output.puts(" GlobalVerifyOrder = 0;") - output.puts(" GlobalOrderError = NULL;") + output.puts(" GlobalVerifyOrder = 0;") + output.puts(" GlobalOrderError = NULL;") end mocks.each do |mock| mock_clean = mock.gsub(/(?:-|\s+)/, "_") @@ -206,7 +201,7 @@ class UnityTestRunnerGenerator output.puts("}\n") end end - + def create_suite_setup_and_teardown(output) unless (@options[:suite_setup].nil?) output.puts("\n//=======Suite Setup=====") @@ -223,13 +218,13 @@ class UnityTestRunnerGenerator output.puts("}") end 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_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} \")\""}; \\") @@ -239,7 +234,7 @@ class UnityTestRunnerGenerator output.puts(" { \\") output.puts(" CEXCEPTION_T e; \\") if cexception output.puts(" Try { \\") if cexception - output.puts(" CMock_Init(); \\") unless (used_mocks.empty?) + output.puts(" CMock_Init(); \\") unless (used_mocks.empty?) output.puts(" setUp(); \\") output.puts(" TestFunc(#{va_args2}); \\") output.puts(" CMock_Verify(); \\") unless (used_mocks.empty?) @@ -253,7 +248,7 @@ class UnityTestRunnerGenerator output.puts(" UnityConcludeTest(); \\") output.puts("}\n") end - + def create_reset(output, used_mocks) output.puts("\n//=======Test Reset Option=====") output.puts("void resetTest()") @@ -261,11 +256,11 @@ class UnityTestRunnerGenerator output.puts(" CMock_Verify();") unless (used_mocks.empty?) output.puts(" CMock_Destroy();") unless (used_mocks.empty?) output.puts(" tearDown();") - output.puts(" CMock_Init();") unless (used_mocks.empty?) + output.puts(" CMock_Init();") unless (used_mocks.empty?) output.puts(" setUp();") output.puts("}") end - + def create_main(output, filename, tests) output.puts("\n\n//=======MAIN=====") output.puts("int main(void)") @@ -294,18 +289,18 @@ end if ($0 == __FILE__) options = { :includes => [] } yaml_file = nil - + #parse out all the options first - ARGV.reject! do |arg| + ARGV.reject! do |arg| case(arg) - when '-cexception' + when '-cexception' options[:plugins] = [:cexception]; true when /\.*\.yml/ options = UnityTestRunnerGenerator.grab_config(arg); true else false end - end - + end + #make sure there is at least one parameter left (the input file) if !ARGV[0] puts ["usage: ruby #{__FILE__} (yaml) (options) input_test_file output_test_runner (includes)", @@ -313,12 +308,12 @@ if ($0 == __FILE__) " -cexception - include cexception support"].join("\n") exit 1 end - + #create the default test runner name if not specified ARGV[1] = ARGV[0].gsub(".c","_Runner.c") if (!ARGV[1]) - + #everything else is an include file options[:includes] ||= (ARGV.slice(2..-1).flatten.compact) if (ARGV.size > 2) - + UnityTestRunnerGenerator.new(options).run(ARGV[0], ARGV[1]) end