cJSON/auto/generate_module.rb
Max Bruckner ab77a80e9b Squashed 'tests/unity/' changes from 1f52255..f96c055
f96c055 this is a minor release
2c7629a Documentation Updates
b8bfb01 Add support for AStyle in test makefile. It’s going to assume you have it installed.
e36d8b5 Merge pull request #276 from wolf99/pdf-to-markdown
1e43967 Add EACH_EQUAL changes
e2cc679 Add newlines after headings for best practice, trim trailing spaces & convert sneaky incorrectly coded chars
192d517 Remove PDFs
c48f6c9 Add Github Markdown versions of documents
2a5b24f Finished updating all Ruby scripts to match our coding standard. Woo!
3e0a712 Started to flesh out rubocop settings for this project. Added rakefile tasks to do so. Updated first script to make it compliant.
23f9c16 Another round of fixing things that the stylizer “corrected” for me.
3a6cca3 Fixed things that the stylizer “autocorrected” to wrong. ;)
3062c39 Starting to enforce our coding style. The first step is that we’ve pulled in Rubocop to check out Ruby syntax. There is likely a bit of customization to do yet AND there is definitely that backlog of todo’s that we just told it to ignore.
550d58b Attempt to fix remaining issues with casting
ee038c2 Ha! Forgot to add the correct comment style
d6b3508 Clean up some const issues, particularly when moving between single and double pointers
4ffafce Finish updating documentation to match
083564b Update docs to also understand the new Each Equal handlers
0dddf49 also update strings to support each element of an array.
a11a137 Added memory each equal assertion
d8d67a7 Added each_equal assertions for float and double
b7956ea Added more tests for all the numerical types when performing each_equal assertions
7fe3191 Added some tests to prove this works. Still work in progress
56eeacd prepare for comparing value to array by setting up explicit compare of array to array in ints
7b80885 Merge pull request #272 from FSMaxB/gcc43-wconversion
0781e74 Add our coding standard to documentation
c3658a0 Dropped support for pre-2.0 versions of Ruby (not even rubylang supports them anymore)
8a45ccf Use custom mock prefix when searching for mock header files. #263
689610b reorder includes in generated test runners
43c7511 stdlib.h explicitly called in fixtures when malloc used, now. (Fixes issue #268)
1c556d2 Fix -Wconversion with gcc-4.3
8723d50 Turn UNITY_OUTPUT_FLUSH off by default. Added a quick-define for the most common case: UNITY_USE_FLUSH_STDOUT. Clarified documentation. Fixes issue #269
c67a4ff - Add ability to detect TEST_FILE(“filename.c”) specifications in test files
41ee499 Tiny tweaks to make Unity fit in more smoothly with Ceedling

git-subtree-dir: tests/unity
git-subtree-split: f96c05532b3e00c9ca77e58fc07f9401cd46510d
2017-04-27 02:54:33 +02:00

309 lines
11 KiB
Ruby

# ==========================================
# 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]
# ==========================================
# This script creates all the files with start code necessary for a new module.
# A simple module only requires a source file, header file, and test file.
# Triad modules require a source, header, and test file for each triad type (like model, conductor, and hardware).
require 'rubygems'
require 'fileutils'
require 'pathname'
# TEMPLATE_TST
TEMPLATE_TST ||= '#include "unity.h"
%2$s#include "%1$s.h"
void setUp(void)
{
}
void tearDown(void)
{
}
void test_%1$s_NeedToImplement(void)
{
TEST_IGNORE_MESSAGE("Need to Implement %1$s");
}
'.freeze
# TEMPLATE_SRC
TEMPLATE_SRC ||= '%2$s#include "%1$s.h"
'.freeze
# TEMPLATE_INC
TEMPLATE_INC ||= '#ifndef _%3$s_H
#define _%3$s_H
%2$s
#endif // _%3$s_H
'.freeze
class UnityModuleGenerator
############################
def initialize(options = nil)
here = File.expand_path(File.dirname(__FILE__)) + '/'
@options = UnityModuleGenerator.default_options
case options
when NilClass then @options
when String then @options.merge!(UnityModuleGenerator.grab_config(options))
when Hash then @options.merge!(options)
else raise 'If you specify arguments, it should be a filename or a hash of options'
end
# Create default file paths if none were provided
@options[:path_src] = here + '../src/' if @options[:path_src].nil?
@options[:path_inc] = @options[:path_src] if @options[:path_inc].nil?
@options[:path_tst] = here + '../test/' if @options[:path_tst].nil?
@options[:path_src] += '/' unless @options[:path_src][-1] == 47
@options[:path_inc] += '/' unless @options[:path_inc][-1] == 47
@options[:path_tst] += '/' unless @options[:path_tst][-1] == 47
# Built in patterns
@patterns = {
'src' => {
'' => { inc: [] }
},
'test' => {
'' => { inc: [] }
},
'dh' => {
'Driver' => { inc: [create_filename('%1$s', 'Hardware.h')] },
'Hardware' => { inc: [] }
},
'dih' => {
'Driver' => { inc: [create_filename('%1$s', 'Hardware.h'), create_filename('%1$s', 'Interrupt.h')] },
'Interrupt' => { inc: [create_filename('%1$s', 'Hardware.h')] },
'Hardware' => { inc: [] }
},
'mch' => {
'Model' => { inc: [] },
'Conductor' => { inc: [create_filename('%1$s', 'Model.h'), create_filename('%1$s', 'Hardware.h')] },
'Hardware' => { inc: [] }
},
'mvp' => {
'Model' => { inc: [] },
'Presenter' => { inc: [create_filename('%1$s', 'Model.h'), create_filename('%1$s', 'View.h')] },
'View' => { inc: [] }
}
}
end
############################
def self.default_options
{
pattern: 'src',
includes: {
src: [],
inc: [],
tst: []
},
update_svn: false,
boilerplates: {},
test_prefix: 'Test',
mock_prefix: 'Mock'
}
end
############################
def self.grab_config(config_file)
options = default_options
unless config_file.nil? || config_file.empty?
require 'yaml'
yaml_guts = YAML.load_file(config_file)
options.merge!(yaml_guts[:unity] || yaml_guts[:cmock])
raise "No :unity or :cmock section found in #{config_file}" unless options
end
options
end
############################
def files_to_operate_on(module_name, pattern = nil)
# strip any leading path information from the module name and save for later
subfolder = File.dirname(module_name)
module_name = File.basename(module_name)
# create triad definition
prefix = @options[:test_prefix] || 'Test'
triad = [{ ext: '.c', path: @options[:path_src], prefix: '', template: TEMPLATE_SRC, inc: :src, boilerplate: @options[:boilerplates][:src] },
{ ext: '.h', path: @options[:path_inc], prefix: '', template: TEMPLATE_INC, inc: :inc, boilerplate: @options[:boilerplates][:inc] },
{ ext: '.c', path: @options[:path_tst], prefix: prefix, template: TEMPLATE_TST, inc: :tst, boilerplate: @options[:boilerplates][:tst] }]
# prepare the pattern for use
pattern = (pattern || @options[:pattern] || 'src').downcase
patterns = @patterns[pattern]
raise "ERROR: The design pattern '#{pattern}' specified isn't one that I recognize!" if patterns.nil?
# single file patterns (currently just 'test') can reject the other parts of the triad
triad.select! { |v| v[:inc] == :tst } if pattern == 'test'
# Assemble the path/names of the files we need to work with.
files = []
triad.each do |cfg|
patterns.each_pair do |pattern_file, pattern_traits|
submodule_name = create_filename(module_name, pattern_file)
filename = cfg[:prefix] + submodule_name + cfg[:ext]
files << {
path: (Pathname.new("#{cfg[:path]}#{subfolder}") + filename).cleanpath,
name: submodule_name,
template: cfg[:template],
boilerplate: cfg[:boilerplate],
includes: case (cfg[:inc])
when :src then (@options[:includes][:src] || []) | (pattern_traits[:inc].map { |f| format(f, module_name) })
when :inc then (@options[:includes][:inc] || [])
when :tst then (@options[:includes][:tst] || []) | (pattern_traits[:inc].map { |f| format("#{@options[:mock_prefix]}#{f}", module_name) })
end
}
end
end
files
end
############################
def create_filename(part1, part2 = '')
if part2.empty?
case (@options[:naming])
when 'bumpy' then part1
when 'camel' then part1
when 'snake' then part1.downcase
when 'caps' then part1.upcase
else part1.downcase
end
else
case (@options[:naming])
when 'bumpy' then part1 + part2
when 'camel' then part1 + part2
when 'snake' then part1.downcase + '_' + part2.downcase
when 'caps' then part1.upcase + '_' + part2.upcase
else part1.downcase + '_' + part2.downcase
end
end
end
############################
def generate(module_name, pattern = nil)
files = files_to_operate_on(module_name, pattern)
# Abort if all of the module files already exist
all_files_exist = true
files.each do |file|
all_files_exist = false unless File.exist?(file[:path])
end
raise "ERROR: File #{files[0][:name]} already exists. Exiting." if all_files_exist
# Create Source Modules
files.each_with_index do |file, _i|
# If this file already exists, don't overwrite it.
if File.exist?(file[:path])
puts "File #{file[:path]} already exists!"
next
end
# Create the path first if necessary.
FileUtils.mkdir_p(File.dirname(file[:path]), verbose: false)
File.open(file[:path], 'w') do |f|
f.write("#{file[:boilerplate]}\n" % [file[:name]]) unless file[:boilerplate].nil?
f.write(file[:template] % [file[:name],
file[:includes].map { |ff| "#include \"#{ff}\"\n" }.join,
file[:name].upcase])
end
if @options[:update_svn]
`svn add \"#{file[:path]}\"`
if $!.exitstatus.zero?
puts "File #{file[:path]} created and added to source control"
else
puts "File #{file[:path]} created but FAILED adding to source control!"
end
else
puts "File #{file[:path]} created"
end
end
puts 'Generate Complete'
end
############################
def destroy(module_name, pattern = nil)
files_to_operate_on(module_name, pattern).each do |filespec|
file = filespec[:path]
if File.exist?(file)
if @options[:update_svn]
`svn delete \"#{file}\" --force`
puts "File #{file} deleted and removed from source control"
else
FileUtils.remove(file)
puts "File #{file} deleted"
end
else
puts "File #{file} does not exist so cannot be removed."
end
end
puts 'Destroy Complete'
end
end
############################
# Handle As Command Line If Called That Way
if $0 == __FILE__
destroy = false
options = {}
module_name = nil
# Parse the command line parameters.
ARGV.each do |arg|
case arg
when /^-d/ then destroy = true
when /^-u/ then options[:update_svn] = true
when /^-p\"?(\w+)\"?/ then options[:pattern] = Regexp.last_match(1)
when /^-s\"?(.+)\"?/ then options[:path_src] = Regexp.last_match(1)
when /^-i\"?(.+)\"?/ then options[:path_inc] = Regexp.last_match(1)
when /^-t\"?(.+)\"?/ then options[:path_tst] = Regexp.last_match(1)
when /^-n\"?(.+)\"?/ then options[:naming] = Regexp.last_match(1)
when /^-y\"?(.+)\"?/ then options = UnityModuleGenerator.grab_config(Regexp.last_match(1))
when /^(\w+)/
raise "ERROR: You can't have more than one Module name specified!" unless module_name.nil?
module_name = arg
when /^-(h|-help)/
ARGV = [].freeze
else
raise "ERROR: Unknown option specified '#{arg}'"
end
end
unless ARGV[0]
puts ["\nGENERATE MODULE\n-------- ------",
"\nUsage: ruby generate_module [options] module_name",
" -i\"include\" sets the path to output headers to 'include' (DEFAULT ../src)",
" -s\"../src\" sets the path to output source to '../src' (DEFAULT ../src)",
" -t\"C:/test\" sets the path to output source to 'C:/test' (DEFAULT ../test)",
' -p"MCH" sets the output pattern to MCH.',
' dh - driver hardware.',
' dih - driver interrupt hardware.',
' mch - model conductor hardware.',
' mvp - model view presenter.',
' src - just a source module, header and test. (DEFAULT)',
' test - just a test file.',
' -d destroy module instead of creating it.',
' -n"camel" sets the file naming convention.',
' bumpy - BumpyCaseFilenames.',
' camel - camelCaseFilenames.',
' snake - snake_case_filenames. (DEFAULT)',
' caps - CAPS_CASE_FILENAMES.',
' -u update subversion too (requires subversion command line)',
' -y"my.yml" selects a different yaml config file for module generation',
''].join("\n")
exit
end
raise 'ERROR: You must have a Module name specified! (use option -h for help)' if module_name.nil?
if destroy
UnityModuleGenerator.new(options).destroy(module_name)
else
UnityModuleGenerator.new(options).generate(module_name)
end
end