c_project 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +18 -0
- data/bin/c_project +77 -0
- data/c_project.gemspec +25 -0
- data/lib/c_project/version.rb +3 -0
- data/lib/c_project.rb +5 -0
- data/templates/LICENCE.tt +23 -0
- data/templates/Makefile.tt +74 -0
- data/templates/README.md.tt +15 -0
- data/templates/src/CExceptionConfig.h.tt +8 -0
- data/templates/src/c_project.c.tt +16 -0
- data/templates/src/c_project.h.tt +8 -0
- data/templates/src/main.c.tt +15 -0
- data/templates/test/support/test_helper.c.tt +2 -0
- data/templates/test/support/test_helper.h.tt +13 -0
- data/templates/test/test_c_project.c.tt +41 -0
- data/templates/vendor/cexception/docs/license.txt +30 -0
- data/templates/vendor/cexception/docs/readme.txt +242 -0
- data/templates/vendor/cexception/lib/CException.c +43 -0
- data/templates/vendor/cexception/lib/CException.h +86 -0
- data/templates/vendor/cexception/release/build.info +2 -0
- data/templates/vendor/cexception/release/version.info +2 -0
- data/templates/vendor/commander.c/History.md +27 -0
- data/templates/vendor/commander.c/Makefile +8 -0
- data/templates/vendor/commander.c/Readme.md +103 -0
- data/templates/vendor/commander.c/package.json +9 -0
- data/templates/vendor/commander.c/src/commander.c +250 -0
- data/templates/vendor/commander.c/src/commander.h +88 -0
- data/templates/vendor/commander.c/test.c +34 -0
- data/templates/vendor/unity/.gitignore +1 -0
- data/templates/vendor/unity/auto/colour_prompt.rb +94 -0
- data/templates/vendor/unity/auto/colour_reporter.rb +39 -0
- data/templates/vendor/unity/auto/generate_config.yml +36 -0
- data/templates/vendor/unity/auto/generate_module.rb +202 -0
- data/templates/vendor/unity/auto/generate_test_runner.rb +316 -0
- data/templates/vendor/unity/auto/test_file_filter.rb +23 -0
- data/templates/vendor/unity/auto/unity_test_summary.rb +139 -0
- data/templates/vendor/unity/docs/Unity Summary.txt +216 -0
- data/templates/vendor/unity/docs/license.txt +31 -0
- data/templates/vendor/unity/release/build.info +2 -0
- data/templates/vendor/unity/release/version.info +2 -0
- data/templates/vendor/unity/src/unity.c +1146 -0
- data/templates/vendor/unity/src/unity.h +245 -0
- data/templates/vendor/unity/src/unity_internals.h +546 -0
- metadata +135 -0
@@ -0,0 +1,202 @@
|
|
1
|
+
# ==========================================
|
2
|
+
# Unity Project - A Test Framework for C
|
3
|
+
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
|
4
|
+
# [Released under MIT License. Please refer to license.txt for details]
|
5
|
+
# ==========================================
|
6
|
+
|
7
|
+
# This script creates all the files with start code necessary for a new module.
|
8
|
+
# A simple module only requires a source file, header file, and test file.
|
9
|
+
# Triad modules require a source, header, and test file for each triad type (like model, conductor, and hardware).
|
10
|
+
|
11
|
+
require 'rubygems'
|
12
|
+
require 'fileutils'
|
13
|
+
|
14
|
+
HERE = File.expand_path(File.dirname(__FILE__)) + '/'
|
15
|
+
|
16
|
+
#help text when requested
|
17
|
+
HELP_TEXT = [ "\nGENERATE MODULE\n-------- ------",
|
18
|
+
"\nUsage: ruby generate_module [options] module_name",
|
19
|
+
" -i\"include\" sets the path to output headers to 'include' (DEFAULT ../src)",
|
20
|
+
" -s\"../src\" sets the path to output source to '../src' (DEFAULT ../src)",
|
21
|
+
" -t\"C:/test\" sets the path to output source to 'C:/test' (DEFAULT ../test)",
|
22
|
+
" -p\"MCH\" sets the output pattern to MCH.",
|
23
|
+
" dh - driver hardware.",
|
24
|
+
" dih - driver interrupt hardware.",
|
25
|
+
" mch - model conductor hardware.",
|
26
|
+
" mvp - model view presenter.",
|
27
|
+
" src - just a single source module. (DEFAULT)",
|
28
|
+
" -d destroy module instead of creating it.",
|
29
|
+
" -u update subversion too (requires subversion command line)",
|
30
|
+
" -y\"my.yml\" selects a different yaml config file for module generation",
|
31
|
+
"" ].join("\n")
|
32
|
+
|
33
|
+
#Built in patterns
|
34
|
+
PATTERNS = { 'src' => {'' => { :inc => [] } },
|
35
|
+
'dh' => {'Driver' => { :inc => ['%1$sHardware.h'] },
|
36
|
+
'Hardware' => { :inc => [] }
|
37
|
+
},
|
38
|
+
'dih' => {'Driver' => { :inc => ['%1$sHardware.h', '%1$sInterrupt.h'] },
|
39
|
+
'Interrupt'=> { :inc => ['%1$sHardware.h'] },
|
40
|
+
'Hardware' => { :inc => [] }
|
41
|
+
},
|
42
|
+
'mch' => {'Model' => { :inc => [] },
|
43
|
+
'Conductor'=> { :inc => ['%1$sModel.h', '%1$sHardware.h'] },
|
44
|
+
'Hardware' => { :inc => [] }
|
45
|
+
},
|
46
|
+
'mvp' => {'Model' => { :inc => [] },
|
47
|
+
'Presenter'=> { :inc => ['%1$sModel.h', '%1$sView.h'] },
|
48
|
+
'View' => { :inc => [] }
|
49
|
+
}
|
50
|
+
}
|
51
|
+
|
52
|
+
#TEMPLATE_TST
|
53
|
+
TEMPLATE_TST = %q[#include "unity.h"
|
54
|
+
%2$s#include "%1$s.h"
|
55
|
+
|
56
|
+
void setUp(void)
|
57
|
+
{
|
58
|
+
}
|
59
|
+
|
60
|
+
void tearDown(void)
|
61
|
+
{
|
62
|
+
}
|
63
|
+
|
64
|
+
void test_%1$s_NeedToImplement(void)
|
65
|
+
{
|
66
|
+
TEST_IGNORE();
|
67
|
+
}
|
68
|
+
]
|
69
|
+
|
70
|
+
#TEMPLATE_SRC
|
71
|
+
TEMPLATE_SRC = %q[%2$s#include "%1$s.h"
|
72
|
+
]
|
73
|
+
|
74
|
+
#TEMPLATE_INC
|
75
|
+
TEMPLATE_INC = %q[#ifndef _%3$s_H
|
76
|
+
#define _%3$s_H%2$s
|
77
|
+
|
78
|
+
#endif // _%3$s_H
|
79
|
+
]
|
80
|
+
|
81
|
+
# Parse the command line parameters.
|
82
|
+
ARGV.each do |arg|
|
83
|
+
case(arg)
|
84
|
+
when /^-d/ then @destroy = true
|
85
|
+
when /^-u/ then @update_svn = true
|
86
|
+
when /^-p(\w+)/ then @pattern = $1
|
87
|
+
when /^-s(.+)/ then @path_src = $1
|
88
|
+
when /^-i(.+)/ then @path_inc = $1
|
89
|
+
when /^-t(.+)/ then @path_tst = $1
|
90
|
+
when /^-y(.+)/ then @yaml_config = $1
|
91
|
+
when /^(\w+)/
|
92
|
+
raise "ERROR: You can't have more than one Module name specified!" unless @module_name.nil?
|
93
|
+
@module_name = arg
|
94
|
+
when /^-(h|-help)/
|
95
|
+
puts HELP_TEXT
|
96
|
+
exit
|
97
|
+
else
|
98
|
+
raise "ERROR: Unknown option specified '#{arg}'"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
raise "ERROR: You must have a Module name specified! (use option -h for help)" if @module_name.nil?
|
102
|
+
|
103
|
+
#load yaml file if one was requested
|
104
|
+
if @yaml_config
|
105
|
+
require 'yaml'
|
106
|
+
cfg = YAML.load_file(HERE + @yaml_config)[:generate_module]
|
107
|
+
@path_src = cfg[:defaults][:path_src] if @path_src.nil?
|
108
|
+
@path_inc = cfg[:defaults][:path_inc] if @path_inc.nil?
|
109
|
+
@path_tst = cfg[:defaults][:path_tst] if @path_tst.nil?
|
110
|
+
@update_svn = cfg[:defaults][:update_svn] if @update_svn.nil?
|
111
|
+
@extra_inc = cfg[:includes]
|
112
|
+
@boilerplates = cfg[:boilerplates]
|
113
|
+
else
|
114
|
+
@boilerplates = {}
|
115
|
+
end
|
116
|
+
|
117
|
+
# Create default file paths if none were provided
|
118
|
+
@path_src = HERE + "../src/" if @path_src.nil?
|
119
|
+
@path_inc = @path_src if @path_inc.nil?
|
120
|
+
@path_tst = HERE + "../test/" if @path_tst.nil?
|
121
|
+
@path_src += '/' unless (@path_src[-1] == 47)
|
122
|
+
@path_inc += '/' unless (@path_inc[-1] == 47)
|
123
|
+
@path_tst += '/' unless (@path_tst[-1] == 47)
|
124
|
+
@pattern = 'src' if @pattern.nil?
|
125
|
+
@includes = { :src => [], :inc => [], :tst => [] }
|
126
|
+
@includes.merge!(@extra_inc) unless @extra_inc.nil?
|
127
|
+
|
128
|
+
#create triad definition
|
129
|
+
TRIAD = [ { :ext => '.c', :path => @path_src, :template => TEMPLATE_SRC, :inc => :src, :boilerplate => @boilerplates[:src] },
|
130
|
+
{ :ext => '.h', :path => @path_inc, :template => TEMPLATE_INC, :inc => :inc, :boilerplate => @boilerplates[:inc] },
|
131
|
+
{ :ext => '.c', :path => @path_tst+'Test', :template => TEMPLATE_TST, :inc => :tst, :boilerplate => @boilerplates[:tst] },
|
132
|
+
]
|
133
|
+
|
134
|
+
#prepare the pattern for use
|
135
|
+
@patterns = PATTERNS[@pattern.downcase]
|
136
|
+
raise "ERROR: The design pattern specified isn't one that I recognize!" if @patterns.nil?
|
137
|
+
|
138
|
+
# Assemble the path/names of the files we need to work with.
|
139
|
+
files = []
|
140
|
+
TRIAD.each do |triad|
|
141
|
+
@patterns.each_pair do |pattern_file, pattern_traits|
|
142
|
+
files << {
|
143
|
+
:path => "#{triad[:path]}#{@module_name}#{pattern_file}#{triad[:ext]}",
|
144
|
+
:name => "#{@module_name}#{pattern_file}",
|
145
|
+
:template => triad[:template],
|
146
|
+
:boilerplate => triad[:boilerplate],
|
147
|
+
:includes => case(triad[:inc])
|
148
|
+
when :src then @includes[:src] | pattern_traits[:inc].map{|f| f % [@module_name]}
|
149
|
+
when :inc then @includes[:inc]
|
150
|
+
when :tst then @includes[:tst] | pattern_traits[:inc].map{|f| "Mock#{f}"% [@module_name]}
|
151
|
+
end
|
152
|
+
}
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
# destroy files if that was what was requested
|
157
|
+
if @destroy
|
158
|
+
files.each do |filespec|
|
159
|
+
file = filespec[:path]
|
160
|
+
if File.exist?(file)
|
161
|
+
if @update_svn
|
162
|
+
`svn delete \"#{file}\" --force`
|
163
|
+
puts "File #{file} deleted and removed from source control"
|
164
|
+
else
|
165
|
+
FileUtils.remove(file)
|
166
|
+
puts "File #{file} deleted"
|
167
|
+
end
|
168
|
+
else
|
169
|
+
puts "File #{file} does not exist so cannot be removed."
|
170
|
+
end
|
171
|
+
end
|
172
|
+
puts "Destroy Complete"
|
173
|
+
exit
|
174
|
+
end
|
175
|
+
|
176
|
+
#Abort if any module already exists
|
177
|
+
files.each do |file|
|
178
|
+
raise "ERROR: File #{file[:name]} already exists. Exiting." if File.exist?(file[:path])
|
179
|
+
end
|
180
|
+
|
181
|
+
# Create Source Modules
|
182
|
+
files.each_with_index do |file, i|
|
183
|
+
File.open(file[:path], 'w') do |f|
|
184
|
+
f.write(file[:boilerplate] % [file[:name]]) unless file[:boilerplate].nil?
|
185
|
+
f.write(file[:template] % [ file[:name],
|
186
|
+
file[:includes].map{|f| "#include \"#{f}\"\n"}.join,
|
187
|
+
file[:name].upcase ]
|
188
|
+
)
|
189
|
+
end
|
190
|
+
if (@update_svn)
|
191
|
+
`svn add \"#{file[:path]}\"`
|
192
|
+
if $?.exitstatus == 0
|
193
|
+
puts "File #{file[:path]} created and added to source control"
|
194
|
+
else
|
195
|
+
puts "File #{file[:path]} created but FAILED adding to source control!"
|
196
|
+
end
|
197
|
+
else
|
198
|
+
puts "File #{file[:path]} created"
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
puts 'Generate Complete'
|
@@ -0,0 +1,316 @@
|
|
1
|
+
# ==========================================
|
2
|
+
# Unity Project - A Test Framework for C
|
3
|
+
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
|
4
|
+
# [Released under MIT License. Please refer to license.txt for details]
|
5
|
+
# ==========================================
|
6
|
+
|
7
|
+
File.expand_path(File.join(File.dirname(__FILE__),'colour_prompt'))
|
8
|
+
|
9
|
+
class UnityTestRunnerGenerator
|
10
|
+
|
11
|
+
def initialize(options = nil)
|
12
|
+
@options = { :includes => [], :plugins => [], :framework => :unity }
|
13
|
+
case(options)
|
14
|
+
when NilClass then @options
|
15
|
+
when String then @options.merge!(UnityTestRunnerGenerator.grab_config(options))
|
16
|
+
when Hash then @options.merge!(options)
|
17
|
+
else raise "If you specify arguments, it should be a filename or a hash of options"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.grab_config(config_file)
|
22
|
+
options = { :includes => [], :plugins => [], :framework => :unity }
|
23
|
+
unless (config_file.nil? or config_file.empty?)
|
24
|
+
require 'yaml'
|
25
|
+
yaml_guts = YAML.load_file(config_file)
|
26
|
+
options.merge!(yaml_guts[:unity] ? yaml_guts[:unity] : yaml_guts[:cmock])
|
27
|
+
raise "No :unity or :cmock section found in #{config_file}" unless options
|
28
|
+
end
|
29
|
+
return(options)
|
30
|
+
end
|
31
|
+
|
32
|
+
def run(input_file, output_file, options=nil)
|
33
|
+
tests = []
|
34
|
+
testfile_includes = []
|
35
|
+
used_mocks = []
|
36
|
+
|
37
|
+
@options.merge!(options) unless options.nil?
|
38
|
+
module_name = File.basename(input_file)
|
39
|
+
|
40
|
+
#pull required data from source file
|
41
|
+
File.open(input_file, 'r') do |input|
|
42
|
+
tests = find_tests(input)
|
43
|
+
testfile_includes = find_includes(input)
|
44
|
+
used_mocks = find_mocks(testfile_includes)
|
45
|
+
end
|
46
|
+
|
47
|
+
#build runner file
|
48
|
+
generate(input_file, output_file, tests, used_mocks)
|
49
|
+
|
50
|
+
#determine which files were used to return them
|
51
|
+
all_files_used = [input_file, output_file]
|
52
|
+
all_files_used += testfile_includes.map {|filename| filename + '.c'} unless testfile_includes.empty?
|
53
|
+
all_files_used += @options[:includes] unless @options[:includes].empty?
|
54
|
+
return all_files_used.uniq
|
55
|
+
end
|
56
|
+
|
57
|
+
def generate(input_file, output_file, tests, used_mocks)
|
58
|
+
File.open(output_file, 'w') do |output|
|
59
|
+
create_header(output, used_mocks)
|
60
|
+
create_externs(output, tests, used_mocks)
|
61
|
+
create_mock_management(output, used_mocks)
|
62
|
+
create_suite_setup_and_teardown(output)
|
63
|
+
create_reset(output, used_mocks)
|
64
|
+
create_main(output, input_file, tests)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def find_tests(input_file)
|
69
|
+
tests_raw = []
|
70
|
+
tests_args = []
|
71
|
+
tests_and_line_numbers = []
|
72
|
+
|
73
|
+
input_file.rewind
|
74
|
+
source_raw = input_file.read
|
75
|
+
source_scrubbed = source_raw.gsub(/\/\/.*$/, '') # remove line comments
|
76
|
+
source_scrubbed = source_scrubbed.gsub(/\/\*.*?\*\//m, '') # remove block comments
|
77
|
+
lines = source_scrubbed.split(/(^\s*\#.*$) # Treat preprocessor directives as a logical line
|
78
|
+
| (;|\{|\}) /x) # Match ;, {, and } as end of lines
|
79
|
+
|
80
|
+
lines.each_with_index do |line, index|
|
81
|
+
#find tests
|
82
|
+
if line =~ /^((?:\s*TEST_CASE\s*\(.*?\)\s*)*)\s*void\s+(test.*?)\s*\(\s*(.*)\s*\)/
|
83
|
+
arguments = $1
|
84
|
+
name = $2
|
85
|
+
call = $3
|
86
|
+
args = nil
|
87
|
+
if (@options[:use_param_tests] and !arguments.empty?)
|
88
|
+
args = []
|
89
|
+
arguments.scan(/\s*TEST_CASE\s*\((.*)\)\s*$/) {|a| args << a[0]}
|
90
|
+
end
|
91
|
+
tests_and_line_numbers << { :test => name, :args => args, :call => call, :line_number => 0 }
|
92
|
+
tests_args = []
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
#determine line numbers and create tests to run
|
97
|
+
source_lines = source_raw.split("\n")
|
98
|
+
source_index = 0;
|
99
|
+
tests_and_line_numbers.size.times do |i|
|
100
|
+
source_lines[source_index..-1].each_with_index do |line, index|
|
101
|
+
if (line =~ /#{tests_and_line_numbers[i][:test]}/)
|
102
|
+
source_index += index
|
103
|
+
tests_and_line_numbers[i][:line_number] = source_index + 1
|
104
|
+
break
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
return tests_and_line_numbers
|
110
|
+
end
|
111
|
+
|
112
|
+
def find_includes(input_file)
|
113
|
+
input_file.rewind
|
114
|
+
|
115
|
+
#read in file
|
116
|
+
source = input_file.read
|
117
|
+
|
118
|
+
#remove comments (block and line, in three steps to ensure correct precedence)
|
119
|
+
source.gsub!(/\/\/(?:.+\/\*|\*(?:$|[^\/])).*$/, '') # remove line comments that comment out the start of blocks
|
120
|
+
source.gsub!(/\/\*.*?\*\//m, '') # remove block comments
|
121
|
+
source.gsub!(/\/\/.*$/, '') # remove line comments (all that remain)
|
122
|
+
|
123
|
+
#parse out includes
|
124
|
+
return source.scan(/^\s*#include\s+\"\s*(.+)\.[hH]\s*\"/).flatten
|
125
|
+
end
|
126
|
+
|
127
|
+
def find_mocks(includes)
|
128
|
+
mock_headers = []
|
129
|
+
includes.each do |include_file|
|
130
|
+
mock_headers << File.basename(include_file) if (include_file =~ /^mock/i)
|
131
|
+
end
|
132
|
+
return mock_headers
|
133
|
+
end
|
134
|
+
|
135
|
+
def create_header(output, mocks)
|
136
|
+
output.puts('/* AUTOGENERATED FILE. DO NOT EDIT. */')
|
137
|
+
create_runtest(output, mocks)
|
138
|
+
output.puts("\n//=======Automagically Detected Files To Include=====")
|
139
|
+
output.puts("#include \"#{@options[:framework].to_s}.h\"")
|
140
|
+
output.puts('#include "cmock.h"') unless (mocks.empty?)
|
141
|
+
@options[:includes].flatten.uniq.compact.each do |inc|
|
142
|
+
output.puts("#include #{inc.include?('<') ? inc : "\"#{inc.gsub('.h','')}.h\""}")
|
143
|
+
end
|
144
|
+
output.puts('#include <setjmp.h>')
|
145
|
+
output.puts('#include <stdio.h>')
|
146
|
+
output.puts('#include "CException.h"') if @options[:plugins].include?(:cexception)
|
147
|
+
mocks.each do |mock|
|
148
|
+
output.puts("#include \"#{mock.gsub('.h','')}.h\"")
|
149
|
+
end
|
150
|
+
if @options[:enforce_strict_ordering]
|
151
|
+
output.puts('')
|
152
|
+
output.puts('int GlobalExpectCount;')
|
153
|
+
output.puts('int GlobalVerifyOrder;')
|
154
|
+
output.puts('char* GlobalOrderError;')
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def create_externs(output, tests, mocks)
|
159
|
+
output.puts("\n//=======External Functions This Runner Calls=====")
|
160
|
+
output.puts("extern void setUp(void);")
|
161
|
+
output.puts("extern void tearDown(void);")
|
162
|
+
tests.each do |test|
|
163
|
+
output.puts("extern void #{test[:test]}(#{test[:call] || 'void'});")
|
164
|
+
end
|
165
|
+
output.puts('')
|
166
|
+
end
|
167
|
+
|
168
|
+
def create_mock_management(output, mocks)
|
169
|
+
unless (mocks.empty?)
|
170
|
+
output.puts("\n//=======Mock Management=====")
|
171
|
+
output.puts("static void CMock_Init(void)")
|
172
|
+
output.puts("{")
|
173
|
+
if @options[:enforce_strict_ordering]
|
174
|
+
output.puts(" GlobalExpectCount = 0;")
|
175
|
+
output.puts(" GlobalVerifyOrder = 0;")
|
176
|
+
output.puts(" GlobalOrderError = NULL;")
|
177
|
+
end
|
178
|
+
mocks.each do |mock|
|
179
|
+
mock_clean = mock.gsub(/(?:-|\s+)/, "_")
|
180
|
+
output.puts(" #{mock_clean}_Init();")
|
181
|
+
end
|
182
|
+
output.puts("}\n")
|
183
|
+
|
184
|
+
output.puts("static void CMock_Verify(void)")
|
185
|
+
output.puts("{")
|
186
|
+
mocks.each do |mock|
|
187
|
+
mock_clean = mock.gsub(/(?:-|\s+)/, "_")
|
188
|
+
output.puts(" #{mock_clean}_Verify();")
|
189
|
+
end
|
190
|
+
output.puts("}\n")
|
191
|
+
|
192
|
+
output.puts("static void CMock_Destroy(void)")
|
193
|
+
output.puts("{")
|
194
|
+
mocks.each do |mock|
|
195
|
+
mock_clean = mock.gsub(/(?:-|\s+)/, "_")
|
196
|
+
output.puts(" #{mock_clean}_Destroy();")
|
197
|
+
end
|
198
|
+
output.puts("}\n")
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
def create_suite_setup_and_teardown(output)
|
203
|
+
unless (@options[:suite_setup].nil?)
|
204
|
+
output.puts("\n//=======Suite Setup=====")
|
205
|
+
output.puts("static int suite_setup(void)")
|
206
|
+
output.puts("{")
|
207
|
+
output.puts(@options[:suite_setup])
|
208
|
+
output.puts("}")
|
209
|
+
end
|
210
|
+
unless (@options[:suite_teardown].nil?)
|
211
|
+
output.puts("\n//=======Suite Teardown=====")
|
212
|
+
output.puts("static int suite_teardown(int num_failures)")
|
213
|
+
output.puts("{")
|
214
|
+
output.puts(@options[:suite_teardown])
|
215
|
+
output.puts("}")
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
def create_runtest(output, used_mocks)
|
220
|
+
cexception = @options[:plugins].include? :cexception
|
221
|
+
va_args1 = @options[:use_param_tests] ? ', ...' : ''
|
222
|
+
va_args2 = @options[:use_param_tests] ? '__VA_ARGS__' : ''
|
223
|
+
output.puts("\n//=======Test Runner Used To Run Each Test Below=====")
|
224
|
+
output.puts("#define RUN_TEST_NO_ARGS") if @options[:use_param_tests]
|
225
|
+
output.puts("#define RUN_TEST(TestFunc, TestLineNum#{va_args1}) \\")
|
226
|
+
output.puts("{ \\")
|
227
|
+
output.puts(" Unity.CurrentTestName = #TestFunc#{va_args2.empty? ? '' : " \"(\" ##{va_args2} \")\""}; \\")
|
228
|
+
output.puts(" Unity.CurrentTestLineNumber = TestLineNum; \\")
|
229
|
+
output.puts(" Unity.NumberOfTests++; \\")
|
230
|
+
output.puts(" if (TEST_PROTECT()) \\")
|
231
|
+
output.puts(" { \\")
|
232
|
+
output.puts(" CEXCEPTION_T e; \\") if cexception
|
233
|
+
output.puts(" Try { \\") if cexception
|
234
|
+
output.puts(" CMock_Init(); \\") unless (used_mocks.empty?)
|
235
|
+
output.puts(" setUp(); \\")
|
236
|
+
output.puts(" TestFunc(#{va_args2}); \\")
|
237
|
+
output.puts(" CMock_Verify(); \\") unless (used_mocks.empty?)
|
238
|
+
output.puts(" } Catch(e) { TEST_ASSERT_EQUAL_HEX32_MESSAGE(CEXCEPTION_NONE, e, \"Unhandled Exception!\"); } \\") if cexception
|
239
|
+
output.puts(" } \\")
|
240
|
+
output.puts(" CMock_Destroy(); \\") unless (used_mocks.empty?)
|
241
|
+
output.puts(" if (TEST_PROTECT() && !TEST_IS_IGNORED) \\")
|
242
|
+
output.puts(" { \\")
|
243
|
+
output.puts(" tearDown(); \\")
|
244
|
+
output.puts(" } \\")
|
245
|
+
output.puts(" UnityConcludeTest(); \\")
|
246
|
+
output.puts("}\n")
|
247
|
+
end
|
248
|
+
|
249
|
+
def create_reset(output, used_mocks)
|
250
|
+
output.puts("\n//=======Test Reset Option=====")
|
251
|
+
output.puts("void resetTest()")
|
252
|
+
output.puts("{")
|
253
|
+
output.puts(" CMock_Verify();") unless (used_mocks.empty?)
|
254
|
+
output.puts(" CMock_Destroy();") unless (used_mocks.empty?)
|
255
|
+
output.puts(" tearDown();")
|
256
|
+
output.puts(" CMock_Init();") unless (used_mocks.empty?)
|
257
|
+
output.puts(" setUp();")
|
258
|
+
output.puts("}")
|
259
|
+
end
|
260
|
+
|
261
|
+
def create_main(output, filename, tests)
|
262
|
+
output.puts("\n\n//=======MAIN=====")
|
263
|
+
output.puts("int main(void)")
|
264
|
+
output.puts("{")
|
265
|
+
output.puts(" suite_setup();") unless @options[:suite_setup].nil?
|
266
|
+
output.puts(" Unity.TestFile = \"#{filename}\";")
|
267
|
+
output.puts(" UnityBegin();")
|
268
|
+
if (@options[:use_param_tests])
|
269
|
+
tests.each do |test|
|
270
|
+
if ((test[:args].nil?) or (test[:args].empty?))
|
271
|
+
output.puts(" RUN_TEST(#{test[:test]}, #{test[:line_number]}, RUN_TEST_NO_ARGS);")
|
272
|
+
else
|
273
|
+
test[:args].each {|args| output.puts(" RUN_TEST(#{test[:test]}, #{test[:line_number]}, #{args});")}
|
274
|
+
end
|
275
|
+
end
|
276
|
+
else
|
277
|
+
tests.each { |test| output.puts(" RUN_TEST(#{test[:test]}, #{test[:line_number]});") }
|
278
|
+
end
|
279
|
+
output.puts()
|
280
|
+
output.puts(" return #{@options[:suite_teardown].nil? ? "" : "suite_teardown"}(UnityEnd());")
|
281
|
+
output.puts("}")
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
|
286
|
+
if ($0 == __FILE__)
|
287
|
+
options = { :includes => [] }
|
288
|
+
yaml_file = nil
|
289
|
+
|
290
|
+
#parse out all the options first
|
291
|
+
ARGV.reject! do |arg|
|
292
|
+
case(arg)
|
293
|
+
when '-cexception'
|
294
|
+
options[:plugins] = [:cexception]; true
|
295
|
+
when /\.*\.yml/
|
296
|
+
options = UnityTestRunnerGenerator.grab_config(arg); true
|
297
|
+
else false
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
#make sure there is at least one parameter left (the input file)
|
302
|
+
if !ARGV[0]
|
303
|
+
puts ["usage: ruby #{__FILE__} (yaml) (options) input_test_file output_test_runner (includes)",
|
304
|
+
" blah.yml - will use config options in the yml file (see docs)",
|
305
|
+
" -cexception - include cexception support"].join("\n")
|
306
|
+
exit 1
|
307
|
+
end
|
308
|
+
|
309
|
+
#create the default test runner name if not specified
|
310
|
+
ARGV[1] = ARGV[0].gsub(".c","_Runner.c") if (!ARGV[1])
|
311
|
+
|
312
|
+
#everything else is an include file
|
313
|
+
options[:includes] ||= (ARGV.slice(2..-1).flatten.compact) if (ARGV.size > 2)
|
314
|
+
|
315
|
+
UnityTestRunnerGenerator.new(options).run(ARGV[0], ARGV[1])
|
316
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# ==========================================
|
2
|
+
# Unity Project - A Test Framework for C
|
3
|
+
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
|
4
|
+
# [Released under MIT License. Please refer to license.txt for details]
|
5
|
+
# ==========================================
|
6
|
+
|
7
|
+
require'yaml'
|
8
|
+
|
9
|
+
module RakefileHelpers
|
10
|
+
class TestFileFilter
|
11
|
+
def initialize(all_files = false)
|
12
|
+
@all_files = all_files
|
13
|
+
if not @all_files == true
|
14
|
+
if File.exist?('test_file_filter.yml')
|
15
|
+
filters = YAML.load_file( 'test_file_filter.yml' )
|
16
|
+
@all_files, @only_files, @exclude_files =
|
17
|
+
filters[:all_files], filters[:only_files], filters[:exclude_files]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
attr_accessor :all_files, :only_files, :exclude_files
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
# ==========================================
|
2
|
+
# Unity Project - A Test Framework for C
|
3
|
+
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
|
4
|
+
# [Released under MIT License. Please refer to license.txt for details]
|
5
|
+
# ==========================================
|
6
|
+
|
7
|
+
#!/usr/bin/ruby
|
8
|
+
#
|
9
|
+
# unity_test_summary.rb
|
10
|
+
#
|
11
|
+
require 'fileutils'
|
12
|
+
require 'set'
|
13
|
+
|
14
|
+
class UnityTestSummary
|
15
|
+
include FileUtils::Verbose
|
16
|
+
|
17
|
+
attr_reader :report, :total_tests, :failures, :ignored
|
18
|
+
|
19
|
+
def initialize
|
20
|
+
@report = ''
|
21
|
+
@total_tests = 0
|
22
|
+
@failures = 0
|
23
|
+
@ignored = 0
|
24
|
+
end
|
25
|
+
|
26
|
+
def run
|
27
|
+
# Clean up result file names
|
28
|
+
results = @targets.map {|target| target.gsub(/\\/,'/')}
|
29
|
+
|
30
|
+
# Dig through each result file, looking for details on pass/fail:
|
31
|
+
failure_output = []
|
32
|
+
ignore_output = []
|
33
|
+
|
34
|
+
results.each do |result_file|
|
35
|
+
lines = File.readlines(result_file).map { |line| line.chomp }
|
36
|
+
if lines.length == 0
|
37
|
+
raise "Empty test result file: #{result_file}"
|
38
|
+
else
|
39
|
+
output = get_details(result_file, lines)
|
40
|
+
failure_output << output[:failures] unless output[:failures].empty?
|
41
|
+
ignore_output << output[:ignores] unless output[:ignores].empty?
|
42
|
+
tests,failures,ignored = parse_test_summary(lines)
|
43
|
+
@total_tests += tests
|
44
|
+
@failures += failures
|
45
|
+
@ignored += ignored
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
if @ignored > 0
|
50
|
+
@report += "\n"
|
51
|
+
@report += "--------------------------\n"
|
52
|
+
@report += "UNITY IGNORED TEST SUMMARY\n"
|
53
|
+
@report += "--------------------------\n"
|
54
|
+
@report += ignore_output.flatten.join("\n")
|
55
|
+
end
|
56
|
+
|
57
|
+
if @failures > 0
|
58
|
+
@report += "\n"
|
59
|
+
@report += "--------------------------\n"
|
60
|
+
@report += "UNITY FAILED TEST SUMMARY\n"
|
61
|
+
@report += "--------------------------\n"
|
62
|
+
@report += failure_output.flatten.join("\n")
|
63
|
+
end
|
64
|
+
|
65
|
+
@report += "\n"
|
66
|
+
@report += "--------------------------\n"
|
67
|
+
@report += "OVERALL UNITY TEST SUMMARY\n"
|
68
|
+
@report += "--------------------------\n"
|
69
|
+
@report += "#{@total_tests} TOTAL TESTS #{@failures} TOTAL FAILURES #{@ignored} IGNORED\n"
|
70
|
+
@report += "\n"
|
71
|
+
end
|
72
|
+
|
73
|
+
def set_targets(target_array)
|
74
|
+
@targets = target_array
|
75
|
+
end
|
76
|
+
|
77
|
+
def set_root_path(path)
|
78
|
+
@root = path
|
79
|
+
end
|
80
|
+
|
81
|
+
def usage(err_msg=nil)
|
82
|
+
puts "\nERROR: "
|
83
|
+
puts err_msg if err_msg
|
84
|
+
puts "\nUsage: unity_test_summary.rb result_file_directory/ root_path/"
|
85
|
+
puts " result_file_directory - The location of your results files."
|
86
|
+
puts " Defaults to current directory if not specified."
|
87
|
+
puts " Should end in / if specified."
|
88
|
+
puts " root_path - Helpful for producing more verbose output if using relative paths."
|
89
|
+
exit 1
|
90
|
+
end
|
91
|
+
|
92
|
+
protected
|
93
|
+
|
94
|
+
def get_details(result_file, lines)
|
95
|
+
results = { :failures => [], :ignores => [], :successes => [] }
|
96
|
+
lines.each do |line|
|
97
|
+
src_file,src_line,test_name,status,msg = line.split(/:/)
|
98
|
+
line_out = ((@root and (@root != 0)) ? "#{@root}#{line}" : line ).gsub(/\//, "\\")
|
99
|
+
case(status)
|
100
|
+
when 'IGNORE' then results[:ignores] << line_out
|
101
|
+
when 'FAIL' then results[:failures] << line_out
|
102
|
+
when 'PASS' then results[:successes] << line_out
|
103
|
+
end
|
104
|
+
end
|
105
|
+
return results
|
106
|
+
end
|
107
|
+
|
108
|
+
def parse_test_summary(summary)
|
109
|
+
if summary.find { |v| v =~ /(\d+) Tests (\d+) Failures (\d+) Ignored/ }
|
110
|
+
[$1.to_i,$2.to_i,$3.to_i]
|
111
|
+
else
|
112
|
+
raise "Couldn't parse test results: #{summary}"
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def here; File.expand_path(File.dirname(__FILE__)); end
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
if $0 == __FILE__
|
121
|
+
uts = UnityTestSummary.new
|
122
|
+
begin
|
123
|
+
#look in the specified or current directory for result files
|
124
|
+
ARGV[0] ||= './'
|
125
|
+
targets = "#{ARGV[0].gsub(/\\/, '/')}*.test*"
|
126
|
+
results = Dir[targets]
|
127
|
+
raise "No *.testpass or *.testfail files found in '#{targets}'" if results.empty?
|
128
|
+
uts.set_targets(results)
|
129
|
+
|
130
|
+
#set the root path
|
131
|
+
ARGV[1] ||= File.expand_path(File.dirname(__FILE__)) + '/'
|
132
|
+
uts.set_root_path(ARGV[1])
|
133
|
+
|
134
|
+
#run the summarizer
|
135
|
+
puts uts.run
|
136
|
+
rescue Exception => e
|
137
|
+
uts.usage e.message
|
138
|
+
end
|
139
|
+
end
|