mirror of
https://github.com/ThrowTheSwitch/Unity.git
synced 2025-06-19 21:38:30 +08:00
Merge pull request #57 from ThrowTheSwitch/bug/encoding
Support different encoding styles and force to something we can work with
This commit is contained in:
@ -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 <stdio.h>')
|
||||
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
|
||||
|
Reference in New Issue
Block a user