1*f17b710fSchristos# ========================================== 2*f17b710fSchristos# Unity Project - A Test Framework for C 3*f17b710fSchristos# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams 4*f17b710fSchristos# [Released under MIT License. Please refer to license.txt for details] 5*f17b710fSchristos# ========================================== 6*f17b710fSchristos 7*f17b710fSchristos# This script creates all the files with start code necessary for a new module. 8*f17b710fSchristos# A simple module only requires a source file, header file, and test file. 9*f17b710fSchristos# Triad modules require a source, header, and test file for each triad type (like model, conductor, and hardware). 10*f17b710fSchristos 11*f17b710fSchristosrequire 'rubygems' 12*f17b710fSchristosrequire 'fileutils' 13*f17b710fSchristos 14*f17b710fSchristosHERE = File.expand_path(File.dirname(__FILE__)) + '/' 15*f17b710fSchristos 16*f17b710fSchristos#help text when requested 17*f17b710fSchristosHELP_TEXT = [ "\nGENERATE MODULE\n-------- ------", 18*f17b710fSchristos "\nUsage: ruby generate_module [options] module_name", 19*f17b710fSchristos " -i\"include\" sets the path to output headers to 'include' (DEFAULT ../src)", 20*f17b710fSchristos " -s\"../src\" sets the path to output source to '../src' (DEFAULT ../src)", 21*f17b710fSchristos " -t\"C:/test\" sets the path to output source to 'C:/test' (DEFAULT ../test)", 22*f17b710fSchristos " -p\"MCH\" sets the output pattern to MCH.", 23*f17b710fSchristos " dh - driver hardware.", 24*f17b710fSchristos " dih - driver interrupt hardware.", 25*f17b710fSchristos " mch - model conductor hardware.", 26*f17b710fSchristos " mvp - model view presenter.", 27*f17b710fSchristos " src - just a single source module. (DEFAULT)", 28*f17b710fSchristos " -d destroy module instead of creating it.", 29*f17b710fSchristos " -u update subversion too (requires subversion command line)", 30*f17b710fSchristos " -y\"my.yml\" selects a different yaml config file for module generation", 31*f17b710fSchristos "" ].join("\n") 32*f17b710fSchristos 33*f17b710fSchristos#Built in patterns 34*f17b710fSchristosPATTERNS = { 'src' => {'' => { :inc => [] } }, 35*f17b710fSchristos 'dh' => {'Driver' => { :inc => ['%1$sHardware.h'] }, 36*f17b710fSchristos 'Hardware' => { :inc => [] } 37*f17b710fSchristos }, 38*f17b710fSchristos 'dih' => {'Driver' => { :inc => ['%1$sHardware.h', '%1$sInterrupt.h'] }, 39*f17b710fSchristos 'Interrupt'=> { :inc => ['%1$sHardware.h'] }, 40*f17b710fSchristos 'Hardware' => { :inc => [] } 41*f17b710fSchristos }, 42*f17b710fSchristos 'mch' => {'Model' => { :inc => [] }, 43*f17b710fSchristos 'Conductor'=> { :inc => ['%1$sModel.h', '%1$sHardware.h'] }, 44*f17b710fSchristos 'Hardware' => { :inc => [] } 45*f17b710fSchristos }, 46*f17b710fSchristos 'mvp' => {'Model' => { :inc => [] }, 47*f17b710fSchristos 'Presenter'=> { :inc => ['%1$sModel.h', '%1$sView.h'] }, 48*f17b710fSchristos 'View' => { :inc => [] } 49*f17b710fSchristos } 50*f17b710fSchristos } 51*f17b710fSchristos 52*f17b710fSchristos#TEMPLATE_TST 53*f17b710fSchristosTEMPLATE_TST = %q[#include "unity.h" 54*f17b710fSchristos%2$s#include "%1$s.h" 55*f17b710fSchristos 56*f17b710fSchristosvoid setUp(void) 57*f17b710fSchristos{ 58*f17b710fSchristos} 59*f17b710fSchristos 60*f17b710fSchristosvoid tearDown(void) 61*f17b710fSchristos{ 62*f17b710fSchristos} 63*f17b710fSchristos 64*f17b710fSchristosvoid test_%1$s_NeedToImplement(void) 65*f17b710fSchristos{ 66*f17b710fSchristos TEST_IGNORE(); 67*f17b710fSchristos} 68*f17b710fSchristos] 69*f17b710fSchristos 70*f17b710fSchristos#TEMPLATE_SRC 71*f17b710fSchristosTEMPLATE_SRC = %q[%2$s#include "%1$s.h" 72*f17b710fSchristos] 73*f17b710fSchristos 74*f17b710fSchristos#TEMPLATE_INC 75*f17b710fSchristosTEMPLATE_INC = %q[#ifndef _%3$s_H 76*f17b710fSchristos#define _%3$s_H%2$s 77*f17b710fSchristos 78*f17b710fSchristos#endif // _%3$s_H 79*f17b710fSchristos] 80*f17b710fSchristos 81*f17b710fSchristos# Parse the command line parameters. 82*f17b710fSchristosARGV.each do |arg| 83*f17b710fSchristos case(arg) 84*f17b710fSchristos when /^-d/ then @destroy = true 85*f17b710fSchristos when /^-u/ then @update_svn = true 86*f17b710fSchristos when /^-p(\w+)/ then @pattern = $1 87*f17b710fSchristos when /^-s(.+)/ then @path_src = $1 88*f17b710fSchristos when /^-i(.+)/ then @path_inc = $1 89*f17b710fSchristos when /^-t(.+)/ then @path_tst = $1 90*f17b710fSchristos when /^-y(.+)/ then @yaml_config = $1 91*f17b710fSchristos when /^(\w+)/ 92*f17b710fSchristos raise "ERROR: You can't have more than one Module name specified!" unless @module_name.nil? 93*f17b710fSchristos @module_name = arg 94*f17b710fSchristos when /^-(h|-help)/ 95*f17b710fSchristos puts HELP_TEXT 96*f17b710fSchristos exit 97*f17b710fSchristos else 98*f17b710fSchristos raise "ERROR: Unknown option specified '#{arg}'" 99*f17b710fSchristos end 100*f17b710fSchristosend 101*f17b710fSchristosraise "ERROR: You must have a Module name specified! (use option -h for help)" if @module_name.nil? 102*f17b710fSchristos 103*f17b710fSchristos#load yaml file if one was requested 104*f17b710fSchristosif @yaml_config 105*f17b710fSchristos require 'yaml' 106*f17b710fSchristos cfg = YAML.load_file(HERE + @yaml_config)[:generate_module] 107*f17b710fSchristos @path_src = cfg[:defaults][:path_src] if @path_src.nil? 108*f17b710fSchristos @path_inc = cfg[:defaults][:path_inc] if @path_inc.nil? 109*f17b710fSchristos @path_tst = cfg[:defaults][:path_tst] if @path_tst.nil? 110*f17b710fSchristos @update_svn = cfg[:defaults][:update_svn] if @update_svn.nil? 111*f17b710fSchristos @extra_inc = cfg[:includes] 112*f17b710fSchristos @boilerplates = cfg[:boilerplates] 113*f17b710fSchristoselse 114*f17b710fSchristos @boilerplates = {} 115*f17b710fSchristosend 116*f17b710fSchristos 117*f17b710fSchristos# Create default file paths if none were provided 118*f17b710fSchristos@path_src = HERE + "../src/" if @path_src.nil? 119*f17b710fSchristos@path_inc = @path_src if @path_inc.nil? 120*f17b710fSchristos@path_tst = HERE + "../test/" if @path_tst.nil? 121*f17b710fSchristos@path_src += '/' unless (@path_src[-1] == 47) 122*f17b710fSchristos@path_inc += '/' unless (@path_inc[-1] == 47) 123*f17b710fSchristos@path_tst += '/' unless (@path_tst[-1] == 47) 124*f17b710fSchristos@pattern = 'src' if @pattern.nil? 125*f17b710fSchristos@includes = { :src => [], :inc => [], :tst => [] } 126*f17b710fSchristos@includes.merge!(@extra_inc) unless @extra_inc.nil? 127*f17b710fSchristos 128*f17b710fSchristos#create triad definition 129*f17b710fSchristosTRIAD = [ { :ext => '.c', :path => @path_src, :template => TEMPLATE_SRC, :inc => :src, :boilerplate => @boilerplates[:src] }, 130*f17b710fSchristos { :ext => '.h', :path => @path_inc, :template => TEMPLATE_INC, :inc => :inc, :boilerplate => @boilerplates[:inc] }, 131*f17b710fSchristos { :ext => '.c', :path => @path_tst+'Test', :template => TEMPLATE_TST, :inc => :tst, :boilerplate => @boilerplates[:tst] }, 132*f17b710fSchristos ] 133*f17b710fSchristos 134*f17b710fSchristos#prepare the pattern for use 135*f17b710fSchristos@patterns = PATTERNS[@pattern.downcase] 136*f17b710fSchristosraise "ERROR: The design pattern specified isn't one that I recognize!" if @patterns.nil? 137*f17b710fSchristos 138*f17b710fSchristos# Assemble the path/names of the files we need to work with. 139*f17b710fSchristosfiles = [] 140*f17b710fSchristosTRIAD.each do |triad| 141*f17b710fSchristos @patterns.each_pair do |pattern_file, pattern_traits| 142*f17b710fSchristos files << { 143*f17b710fSchristos :path => "#{triad[:path]}#{@module_name}#{pattern_file}#{triad[:ext]}", 144*f17b710fSchristos :name => "#{@module_name}#{pattern_file}", 145*f17b710fSchristos :template => triad[:template], 146*f17b710fSchristos :boilerplate => triad[:boilerplate], 147*f17b710fSchristos :includes => case(triad[:inc]) 148*f17b710fSchristos when :src then @includes[:src] | pattern_traits[:inc].map{|f| f % [@module_name]} 149*f17b710fSchristos when :inc then @includes[:inc] 150*f17b710fSchristos when :tst then @includes[:tst] | pattern_traits[:inc].map{|f| "Mock#{f}"% [@module_name]} 151*f17b710fSchristos end 152*f17b710fSchristos } 153*f17b710fSchristos end 154*f17b710fSchristosend 155*f17b710fSchristos 156*f17b710fSchristos# destroy files if that was what was requested 157*f17b710fSchristosif @destroy 158*f17b710fSchristos files.each do |filespec| 159*f17b710fSchristos file = filespec[:path] 160*f17b710fSchristos if File.exist?(file) 161*f17b710fSchristos if @update_svn 162*f17b710fSchristos `svn delete \"#{file}\" --force` 163*f17b710fSchristos puts "File #{file} deleted and removed from source control" 164*f17b710fSchristos else 165*f17b710fSchristos FileUtils.remove(file) 166*f17b710fSchristos puts "File #{file} deleted" 167*f17b710fSchristos end 168*f17b710fSchristos else 169*f17b710fSchristos puts "File #{file} does not exist so cannot be removed." 170*f17b710fSchristos end 171*f17b710fSchristos end 172*f17b710fSchristos puts "Destroy Complete" 173*f17b710fSchristos exit 174*f17b710fSchristosend 175*f17b710fSchristos 176*f17b710fSchristos#Abort if any module already exists 177*f17b710fSchristosfiles.each do |file| 178*f17b710fSchristos raise "ERROR: File #{file[:name]} already exists. Exiting." if File.exist?(file[:path]) 179*f17b710fSchristosend 180*f17b710fSchristos 181*f17b710fSchristos# Create Source Modules 182*f17b710fSchristosfiles.each_with_index do |file, i| 183*f17b710fSchristos File.open(file[:path], 'w') do |f| 184*f17b710fSchristos f.write(file[:boilerplate] % [file[:name]]) unless file[:boilerplate].nil? 185*f17b710fSchristos f.write(file[:template] % [ file[:name], 186*f17b710fSchristos file[:includes].map{|f| "#include \"#{f}\"\n"}.join, 187*f17b710fSchristos file[:name].upcase ] 188*f17b710fSchristos ) 189*f17b710fSchristos end 190*f17b710fSchristos if (@update_svn) 191*f17b710fSchristos `svn add \"#{file[:path]}\"` 192*f17b710fSchristos if $?.exitstatus == 0 193*f17b710fSchristos puts "File #{file[:path]} created and added to source control" 194*f17b710fSchristos else 195*f17b710fSchristos puts "File #{file[:path]} created but FAILED adding to source control!" 196*f17b710fSchristos end 197*f17b710fSchristos else 198*f17b710fSchristos puts "File #{file[:path]} created" 199*f17b710fSchristos end 200*f17b710fSchristosend 201*f17b710fSchristos 202*f17b710fSchristosputs 'Generate Complete' 203