forked from damphyr/bare_unity
-
Notifications
You must be signed in to change notification settings - Fork 0
/
runner_generator.rb
139 lines (129 loc) · 4.09 KB
/
runner_generator.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#returns the source file as an Array of LOCs
#
#Preprocessor directives are considered one line
#and '{' and '}' also end a line along ';'.
def scrub_source_file source_raw
#remove comments (block and line, in three steps to ensure correct precedence)
source_raw.gsub!(/\/\/(?:.+\/\*|\*(?:$|[^\/])).*$/, '') # remove line comments that comment out the start of blocks
source_raw.gsub!(/\/\*.*?\*\//m, '') # remove block comments
source_raw.gsub!(/\/\/.*$/, '') # remove line comments (all that remain)
source_raw.split(/(^\s*\#.*$)| (;|\{|\}) /x)
end
#Scan the source file for test functions and return an array with information on the tests
def find_tests source_raw
lines=scrub_source_file(source_raw)
tests_and_line_numbers=[]
lines.each_with_index do |line, index|
#find tests
if line =~ /^((?:\s*TEST_CASE\s*\(.*?\)\s*)*)\s*void\s+(test.*?)\s*\(\s*(.*)\s*\)/
arguments = $1
name = $2
call = $3
tests_and_line_numbers << { :test => name, :call => call, :line_number => 0 }
end
end
#determine line numbers and create tests to run
source_lines = source_raw.split("\n")
source_index = 0;
tests_and_line_numbers.size.times do |i|
source_lines[source_index..-1].each_with_index do |line, index|
if (line =~ /#{tests_and_line_numbers[i][:test]}/)
source_index += index
tests_and_line_numbers[i][:line_number] = source_index + 1
break
end
end
end
return tests_and_line_numbers
end
#Scan the source file for includes and return them in an Array
def find_includes source_raw
source=scrub_source_file(source_raw).join("\n")
#parse out includes
includes = source.scan(/^\s*#include\s+\"\s*(.+\.[hH])\s*\"/).flatten
includes.map!{|inc| "\"#{inc.strip}\""}
brackets_includes = source.scan(/^\s*#include\s+<\s*(.+)\s*>/).flatten
brackets_includes.each { |inc| includes << '<' + inc +'>' }
return includes
end
#Parameters required for template generation
#
# template - the template file
# filename - the name of the test source file
# output - the filename for the runner
# tests - the list of test functions
# includes - the list of header files to include
def generate_runner_source params
require 'erb'
template_content=File.read(params['template'])
template=ERB.new(template_content)
template.result(binding)
end
def parse_command_line args
require 'optparse'
options = {'template'=>File.join(File.dirname(__FILE__),'unity_runner.erb')}
optp=OptionParser.new do |opts|
opts.banner = "Usage: #{$0} [options] source_file output_file"
opts.on("-t", "--template", "Specify the template to use. The default value is unity_runner.erb") do |v|
if File.exists?(v)
options['template'] = File.expand_path(v)
else
puts "The template #{v} cannot be found"
exit 1
end
end
opts.on_tail("-h", "--help", "Show this message") do
puts opts
exit 0
end
end
optp.parse!(args)
if args.size <2
puts optp.help
exit 1
else
options['filenames']=[]
while args.size!=1
options['filenames']<<File.expand_path(args.shift)
end
options['output']=File.expand_path(args.shift)
end
return options
end
def parse_test_source filename
if File.exists?(filename)
source_raw=File.read(filename)
tests=find_tests(source_raw)
tests.each{|tst| tst[:filename]=filename}
includes=find_includes(source_raw)
return tests,includes
else
puts "Cannot find test source #{filename}"
exit 1
end
end
if $0==__FILE__
cli_options=parse_command_line(ARGV)
tests=[]
includes=[]
cli_options['filenames'].each do |fname|
tsts,incs = *parse_test_source(fname)
tests+=tsts
includes+=incs
end
includes.uniq!
includes.delete('"unity.h"')
params={
'tests'=>tests,
'includes'=>includes
}
params.merge!(cli_options)
runner=generate_runner_source(params)
if Dir.exists?(File.dirname(params['output']))
File.open(params['output'],"wb") do |f|
f.write(runner)
end
else
put "Cannot create #{params['output']}. The directory needs to exist"
end
end