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