19750e409Sopenharmony_ci# ========================================== 29750e409Sopenharmony_ci# Unity Project - A Test Framework for C 39750e409Sopenharmony_ci# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams 49750e409Sopenharmony_ci# [Released under MIT License. Please refer to license.txt for details] 59750e409Sopenharmony_ci# ========================================== 69750e409Sopenharmony_ci 79750e409Sopenharmony_ci# This script creates all the files with start code necessary for a new module. 89750e409Sopenharmony_ci# A simple module only requires a source file, header file, and test file. 99750e409Sopenharmony_ci# Triad modules require a source, header, and test file for each triad type (like model, conductor, and hardware). 109750e409Sopenharmony_ci 119750e409Sopenharmony_cirequire 'rubygems' 129750e409Sopenharmony_cirequire 'fileutils' 139750e409Sopenharmony_cirequire 'pathname' 149750e409Sopenharmony_ci 159750e409Sopenharmony_ci# TEMPLATE_TST 169750e409Sopenharmony_ciTEMPLATE_TST ||= '#include "unity.h" 179750e409Sopenharmony_ci%2$s#include "%1$s.h" 189750e409Sopenharmony_ci 199750e409Sopenharmony_civoid setUp(void) 209750e409Sopenharmony_ci{ 219750e409Sopenharmony_ci} 229750e409Sopenharmony_ci 239750e409Sopenharmony_civoid tearDown(void) 249750e409Sopenharmony_ci{ 259750e409Sopenharmony_ci} 269750e409Sopenharmony_ci 279750e409Sopenharmony_civoid test_%1$s_NeedToImplement(void) 289750e409Sopenharmony_ci{ 299750e409Sopenharmony_ci TEST_IGNORE_MESSAGE("Need to Implement %1$s"); 309750e409Sopenharmony_ci} 319750e409Sopenharmony_ci'.freeze 329750e409Sopenharmony_ci 339750e409Sopenharmony_ci# TEMPLATE_SRC 349750e409Sopenharmony_ciTEMPLATE_SRC ||= '%2$s#include "%1$s.h" 359750e409Sopenharmony_ci'.freeze 369750e409Sopenharmony_ci 379750e409Sopenharmony_ci# TEMPLATE_INC 389750e409Sopenharmony_ciTEMPLATE_INC ||= '#ifndef _%3$s_H 399750e409Sopenharmony_ci#define _%3$s_H 409750e409Sopenharmony_ci%2$s 419750e409Sopenharmony_ci 429750e409Sopenharmony_ci#endif // _%3$s_H 439750e409Sopenharmony_ci'.freeze 449750e409Sopenharmony_ci 459750e409Sopenharmony_ciclass UnityModuleGenerator 469750e409Sopenharmony_ci ############################ 479750e409Sopenharmony_ci def initialize(options = nil) 489750e409Sopenharmony_ci here = File.expand_path(File.dirname(__FILE__)) + '/' 499750e409Sopenharmony_ci 509750e409Sopenharmony_ci @options = UnityModuleGenerator.default_options 519750e409Sopenharmony_ci case options 529750e409Sopenharmony_ci when NilClass then @options 539750e409Sopenharmony_ci when String then @options.merge!(UnityModuleGenerator.grab_config(options)) 549750e409Sopenharmony_ci when Hash then @options.merge!(options) 559750e409Sopenharmony_ci else raise 'If you specify arguments, it should be a filename or a hash of options' 569750e409Sopenharmony_ci end 579750e409Sopenharmony_ci 589750e409Sopenharmony_ci # Create default file paths if none were provided 599750e409Sopenharmony_ci @options[:path_src] = here + '../src/' if @options[:path_src].nil? 609750e409Sopenharmony_ci @options[:path_inc] = @options[:path_src] if @options[:path_inc].nil? 619750e409Sopenharmony_ci @options[:path_tst] = here + '../test/' if @options[:path_tst].nil? 629750e409Sopenharmony_ci @options[:path_src] += '/' unless @options[:path_src][-1] == 47 639750e409Sopenharmony_ci @options[:path_inc] += '/' unless @options[:path_inc][-1] == 47 649750e409Sopenharmony_ci @options[:path_tst] += '/' unless @options[:path_tst][-1] == 47 659750e409Sopenharmony_ci 669750e409Sopenharmony_ci # Built in patterns 679750e409Sopenharmony_ci @patterns = { 689750e409Sopenharmony_ci 'src' => { 699750e409Sopenharmony_ci '' => { inc: [] } 709750e409Sopenharmony_ci }, 719750e409Sopenharmony_ci 'test' => { 729750e409Sopenharmony_ci '' => { inc: [] } 739750e409Sopenharmony_ci }, 749750e409Sopenharmony_ci 'dh' => { 759750e409Sopenharmony_ci 'Driver' => { inc: [create_filename('%1$s', 'Hardware.h')] }, 769750e409Sopenharmony_ci 'Hardware' => { inc: [] } 779750e409Sopenharmony_ci }, 789750e409Sopenharmony_ci 'dih' => { 799750e409Sopenharmony_ci 'Driver' => { inc: [create_filename('%1$s', 'Hardware.h'), create_filename('%1$s', 'Interrupt.h')] }, 809750e409Sopenharmony_ci 'Interrupt' => { inc: [create_filename('%1$s', 'Hardware.h')] }, 819750e409Sopenharmony_ci 'Hardware' => { inc: [] } 829750e409Sopenharmony_ci }, 839750e409Sopenharmony_ci 'mch' => { 849750e409Sopenharmony_ci 'Model' => { inc: [] }, 859750e409Sopenharmony_ci 'Conductor' => { inc: [create_filename('%1$s', 'Model.h'), create_filename('%1$s', 'Hardware.h')] }, 869750e409Sopenharmony_ci 'Hardware' => { inc: [] } 879750e409Sopenharmony_ci }, 889750e409Sopenharmony_ci 'mvp' => { 899750e409Sopenharmony_ci 'Model' => { inc: [] }, 909750e409Sopenharmony_ci 'Presenter' => { inc: [create_filename('%1$s', 'Model.h'), create_filename('%1$s', 'View.h')] }, 919750e409Sopenharmony_ci 'View' => { inc: [] } 929750e409Sopenharmony_ci } 939750e409Sopenharmony_ci } 949750e409Sopenharmony_ci end 959750e409Sopenharmony_ci 969750e409Sopenharmony_ci ############################ 979750e409Sopenharmony_ci def self.default_options 989750e409Sopenharmony_ci { 999750e409Sopenharmony_ci pattern: 'src', 1009750e409Sopenharmony_ci includes: { 1019750e409Sopenharmony_ci src: [], 1029750e409Sopenharmony_ci inc: [], 1039750e409Sopenharmony_ci tst: [] 1049750e409Sopenharmony_ci }, 1059750e409Sopenharmony_ci update_svn: false, 1069750e409Sopenharmony_ci boilerplates: {}, 1079750e409Sopenharmony_ci test_prefix: 'Test', 1089750e409Sopenharmony_ci mock_prefix: 'Mock' 1099750e409Sopenharmony_ci } 1109750e409Sopenharmony_ci end 1119750e409Sopenharmony_ci 1129750e409Sopenharmony_ci ############################ 1139750e409Sopenharmony_ci def self.grab_config(config_file) 1149750e409Sopenharmony_ci options = default_options 1159750e409Sopenharmony_ci unless config_file.nil? || config_file.empty? 1169750e409Sopenharmony_ci require 'yaml' 1179750e409Sopenharmony_ci yaml_guts = YAML.load_file(config_file) 1189750e409Sopenharmony_ci options.merge!(yaml_guts[:unity] || yaml_guts[:cmock]) 1199750e409Sopenharmony_ci raise "No :unity or :cmock section found in #{config_file}" unless options 1209750e409Sopenharmony_ci end 1219750e409Sopenharmony_ci options 1229750e409Sopenharmony_ci end 1239750e409Sopenharmony_ci 1249750e409Sopenharmony_ci ############################ 1259750e409Sopenharmony_ci def files_to_operate_on(module_name, pattern = nil) 1269750e409Sopenharmony_ci # strip any leading path information from the module name and save for later 1279750e409Sopenharmony_ci subfolder = File.dirname(module_name) 1289750e409Sopenharmony_ci module_name = File.basename(module_name) 1299750e409Sopenharmony_ci 1309750e409Sopenharmony_ci # create triad definition 1319750e409Sopenharmony_ci prefix = @options[:test_prefix] || 'Test' 1329750e409Sopenharmony_ci triad = [{ ext: '.c', path: @options[:path_src], prefix: '', template: TEMPLATE_SRC, inc: :src, boilerplate: @options[:boilerplates][:src] }, 1339750e409Sopenharmony_ci { ext: '.h', path: @options[:path_inc], prefix: '', template: TEMPLATE_INC, inc: :inc, boilerplate: @options[:boilerplates][:inc] }, 1349750e409Sopenharmony_ci { ext: '.c', path: @options[:path_tst], prefix: prefix, template: TEMPLATE_TST, inc: :tst, boilerplate: @options[:boilerplates][:tst] }] 1359750e409Sopenharmony_ci 1369750e409Sopenharmony_ci # prepare the pattern for use 1379750e409Sopenharmony_ci pattern = (pattern || @options[:pattern] || 'src').downcase 1389750e409Sopenharmony_ci patterns = @patterns[pattern] 1399750e409Sopenharmony_ci raise "ERROR: The design pattern '#{pattern}' specified isn't one that I recognize!" if patterns.nil? 1409750e409Sopenharmony_ci 1419750e409Sopenharmony_ci # single file patterns (currently just 'test') can reject the other parts of the triad 1429750e409Sopenharmony_ci triad.select! { |v| v[:inc] == :tst } if pattern == 'test' 1439750e409Sopenharmony_ci 1449750e409Sopenharmony_ci # Assemble the path/names of the files we need to work with. 1459750e409Sopenharmony_ci files = [] 1469750e409Sopenharmony_ci triad.each do |cfg| 1479750e409Sopenharmony_ci patterns.each_pair do |pattern_file, pattern_traits| 1489750e409Sopenharmony_ci submodule_name = create_filename(module_name, pattern_file) 1499750e409Sopenharmony_ci filename = cfg[:prefix] + submodule_name + cfg[:ext] 1509750e409Sopenharmony_ci files << { 1519750e409Sopenharmony_ci path: (Pathname.new("#{cfg[:path]}#{subfolder}") + filename).cleanpath, 1529750e409Sopenharmony_ci name: submodule_name, 1539750e409Sopenharmony_ci template: cfg[:template], 1549750e409Sopenharmony_ci boilerplate: cfg[:boilerplate], 1559750e409Sopenharmony_ci includes: case (cfg[:inc]) 1569750e409Sopenharmony_ci when :src then (@options[:includes][:src] || []) | (pattern_traits[:inc].map { |f| format(f, module_name) }) 1579750e409Sopenharmony_ci when :inc then (@options[:includes][:inc] || []) 1589750e409Sopenharmony_ci when :tst then (@options[:includes][:tst] || []) | (pattern_traits[:inc].map { |f| format("#{@options[:mock_prefix]}#{f}", module_name) }) 1599750e409Sopenharmony_ci end 1609750e409Sopenharmony_ci } 1619750e409Sopenharmony_ci end 1629750e409Sopenharmony_ci end 1639750e409Sopenharmony_ci 1649750e409Sopenharmony_ci files 1659750e409Sopenharmony_ci end 1669750e409Sopenharmony_ci 1679750e409Sopenharmony_ci ############################ 1689750e409Sopenharmony_ci def create_filename(part1, part2 = '') 1699750e409Sopenharmony_ci if part2.empty? 1709750e409Sopenharmony_ci case (@options[:naming]) 1719750e409Sopenharmony_ci when 'bumpy' then part1 1729750e409Sopenharmony_ci when 'camel' then part1 1739750e409Sopenharmony_ci when 'snake' then part1.downcase 1749750e409Sopenharmony_ci when 'caps' then part1.upcase 1759750e409Sopenharmony_ci else part1 1769750e409Sopenharmony_ci end 1779750e409Sopenharmony_ci else 1789750e409Sopenharmony_ci case (@options[:naming]) 1799750e409Sopenharmony_ci when 'bumpy' then part1 + part2 1809750e409Sopenharmony_ci when 'camel' then part1 + part2 1819750e409Sopenharmony_ci when 'snake' then part1.downcase + '_' + part2.downcase 1829750e409Sopenharmony_ci when 'caps' then part1.upcase + '_' + part2.upcase 1839750e409Sopenharmony_ci else part1 + '_' + part2 1849750e409Sopenharmony_ci end 1859750e409Sopenharmony_ci end 1869750e409Sopenharmony_ci end 1879750e409Sopenharmony_ci 1889750e409Sopenharmony_ci ############################ 1899750e409Sopenharmony_ci def generate(module_name, pattern = nil) 1909750e409Sopenharmony_ci files = files_to_operate_on(module_name, pattern) 1919750e409Sopenharmony_ci 1929750e409Sopenharmony_ci # Abort if all of the module files already exist 1939750e409Sopenharmony_ci all_files_exist = true 1949750e409Sopenharmony_ci files.each do |file| 1959750e409Sopenharmony_ci all_files_exist = false unless File.exist?(file[:path]) 1969750e409Sopenharmony_ci end 1979750e409Sopenharmony_ci raise "ERROR: File #{files[0][:name]} already exists. Exiting." if all_files_exist 1989750e409Sopenharmony_ci 1999750e409Sopenharmony_ci # Create Source Modules 2009750e409Sopenharmony_ci files.each_with_index do |file, _i| 2019750e409Sopenharmony_ci # If this file already exists, don't overwrite it. 2029750e409Sopenharmony_ci if File.exist?(file[:path]) 2039750e409Sopenharmony_ci puts "File #{file[:path]} already exists!" 2049750e409Sopenharmony_ci next 2059750e409Sopenharmony_ci end 2069750e409Sopenharmony_ci # Create the path first if necessary. 2079750e409Sopenharmony_ci FileUtils.mkdir_p(File.dirname(file[:path]), verbose: false) 2089750e409Sopenharmony_ci File.open(file[:path], 'w') do |f| 2099750e409Sopenharmony_ci f.write("#{file[:boilerplate]}\n" % [file[:name]]) unless file[:boilerplate].nil? 2109750e409Sopenharmony_ci f.write(file[:template] % [file[:name], 2119750e409Sopenharmony_ci file[:includes].map { |ff| "#include \"#{ff}\"\n" }.join, 2129750e409Sopenharmony_ci file[:name].upcase]) 2139750e409Sopenharmony_ci end 2149750e409Sopenharmony_ci if @options[:update_svn] 2159750e409Sopenharmony_ci `svn add \"#{file[:path]}\"` 2169750e409Sopenharmony_ci if $!.exitstatus.zero? 2179750e409Sopenharmony_ci puts "File #{file[:path]} created and added to source control" 2189750e409Sopenharmony_ci else 2199750e409Sopenharmony_ci puts "File #{file[:path]} created but FAILED adding to source control!" 2209750e409Sopenharmony_ci end 2219750e409Sopenharmony_ci else 2229750e409Sopenharmony_ci puts "File #{file[:path]} created" 2239750e409Sopenharmony_ci end 2249750e409Sopenharmony_ci end 2259750e409Sopenharmony_ci puts 'Generate Complete' 2269750e409Sopenharmony_ci end 2279750e409Sopenharmony_ci 2289750e409Sopenharmony_ci ############################ 2299750e409Sopenharmony_ci def destroy(module_name, pattern = nil) 2309750e409Sopenharmony_ci files_to_operate_on(module_name, pattern).each do |filespec| 2319750e409Sopenharmony_ci file = filespec[:path] 2329750e409Sopenharmony_ci if File.exist?(file) 2339750e409Sopenharmony_ci if @options[:update_svn] 2349750e409Sopenharmony_ci `svn delete \"#{file}\" --force` 2359750e409Sopenharmony_ci puts "File #{file} deleted and removed from source control" 2369750e409Sopenharmony_ci else 2379750e409Sopenharmony_ci FileUtils.remove(file) 2389750e409Sopenharmony_ci puts "File #{file} deleted" 2399750e409Sopenharmony_ci end 2409750e409Sopenharmony_ci else 2419750e409Sopenharmony_ci puts "File #{file} does not exist so cannot be removed." 2429750e409Sopenharmony_ci end 2439750e409Sopenharmony_ci end 2449750e409Sopenharmony_ci puts 'Destroy Complete' 2459750e409Sopenharmony_ci end 2469750e409Sopenharmony_ciend 2479750e409Sopenharmony_ci 2489750e409Sopenharmony_ci############################ 2499750e409Sopenharmony_ci# Handle As Command Line If Called That Way 2509750e409Sopenharmony_ciif $0 == __FILE__ 2519750e409Sopenharmony_ci destroy = false 2529750e409Sopenharmony_ci options = {} 2539750e409Sopenharmony_ci module_name = nil 2549750e409Sopenharmony_ci 2559750e409Sopenharmony_ci # Parse the command line parameters. 2569750e409Sopenharmony_ci ARGV.each do |arg| 2579750e409Sopenharmony_ci case arg 2589750e409Sopenharmony_ci when /^-d/ then destroy = true 2599750e409Sopenharmony_ci when /^-u/ then options[:update_svn] = true 2609750e409Sopenharmony_ci when /^-p\"?(\w+)\"?/ then options[:pattern] = Regexp.last_match(1) 2619750e409Sopenharmony_ci when /^-s\"?(.+)\"?/ then options[:path_src] = Regexp.last_match(1) 2629750e409Sopenharmony_ci when /^-i\"?(.+)\"?/ then options[:path_inc] = Regexp.last_match(1) 2639750e409Sopenharmony_ci when /^-t\"?(.+)\"?/ then options[:path_tst] = Regexp.last_match(1) 2649750e409Sopenharmony_ci when /^-n\"?(.+)\"?/ then options[:naming] = Regexp.last_match(1) 2659750e409Sopenharmony_ci when /^-y\"?(.+)\"?/ then options = UnityModuleGenerator.grab_config(Regexp.last_match(1)) 2669750e409Sopenharmony_ci when /^(\w+)/ 2679750e409Sopenharmony_ci raise "ERROR: You can't have more than one Module name specified!" unless module_name.nil? 2689750e409Sopenharmony_ci module_name = arg 2699750e409Sopenharmony_ci when /^-(h|-help)/ 2709750e409Sopenharmony_ci ARGV = [].freeze 2719750e409Sopenharmony_ci else 2729750e409Sopenharmony_ci raise "ERROR: Unknown option specified '#{arg}'" 2739750e409Sopenharmony_ci end 2749750e409Sopenharmony_ci end 2759750e409Sopenharmony_ci 2769750e409Sopenharmony_ci unless ARGV[0] 2779750e409Sopenharmony_ci puts ["\nGENERATE MODULE\n-------- ------", 2789750e409Sopenharmony_ci "\nUsage: ruby generate_module [options] module_name", 2799750e409Sopenharmony_ci " -i\"include\" sets the path to output headers to 'include' (DEFAULT ../src)", 2809750e409Sopenharmony_ci " -s\"../src\" sets the path to output source to '../src' (DEFAULT ../src)", 2819750e409Sopenharmony_ci " -t\"C:/test\" sets the path to output source to 'C:/test' (DEFAULT ../test)", 2829750e409Sopenharmony_ci ' -p"MCH" sets the output pattern to MCH.', 2839750e409Sopenharmony_ci ' dh - driver hardware.', 2849750e409Sopenharmony_ci ' dih - driver interrupt hardware.', 2859750e409Sopenharmony_ci ' mch - model conductor hardware.', 2869750e409Sopenharmony_ci ' mvp - model view presenter.', 2879750e409Sopenharmony_ci ' src - just a source module, header and test. (DEFAULT)', 2889750e409Sopenharmony_ci ' test - just a test file.', 2899750e409Sopenharmony_ci ' -d destroy module instead of creating it.', 2909750e409Sopenharmony_ci ' -n"camel" sets the file naming convention.', 2919750e409Sopenharmony_ci ' bumpy - BumpyCaseFilenames.', 2929750e409Sopenharmony_ci ' camel - camelCaseFilenames.', 2939750e409Sopenharmony_ci ' snake - snake_case_filenames.', 2949750e409Sopenharmony_ci ' caps - CAPS_CASE_FILENAMES.', 2959750e409Sopenharmony_ci ' -u update subversion too (requires subversion command line)', 2969750e409Sopenharmony_ci ' -y"my.yml" selects a different yaml config file for module generation', 2979750e409Sopenharmony_ci ''].join("\n") 2989750e409Sopenharmony_ci exit 2999750e409Sopenharmony_ci end 3009750e409Sopenharmony_ci 3019750e409Sopenharmony_ci raise 'ERROR: You must have a Module name specified! (use option -h for help)' if module_name.nil? 3029750e409Sopenharmony_ci if destroy 3039750e409Sopenharmony_ci UnityModuleGenerator.new(options).destroy(module_name) 3049750e409Sopenharmony_ci else 3059750e409Sopenharmony_ci UnityModuleGenerator.new(options).generate(module_name) 3069750e409Sopenharmony_ci end 3079750e409Sopenharmony_ci 3089750e409Sopenharmony_ciend 309