generate_test_runner.rb 5.6 KB
Newer Older
1 2 3

class UnityTestRunnerGenerator

4
  def run(input_file, output_file, additional_includes=[], tab='  ', options={})
5
    @tab = tab
6
    @options = options
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
    tests = []
    includes = []
    used_mocks = []
    
    module_name = File.basename(input_file)
    
    File.open(input_file, 'r') do |input|
      tests = find_tests(input)
      includes = find_includes(input)
      used_mocks = find_mocks(includes)
    end

    File.open(output_file, 'w') do |output|
      create_header(output, used_mocks, additional_includes)
      create_externs(output, tests, used_mocks)
      create_mock_management(output, used_mocks)
      create_runtest(output, used_mocks)
      create_main(output, module_name, tests)
    end
    
    all_files_used = [input_file, output_file]
    all_files_used += includes.map {|filename| filename + '.c'} unless includes.empty?
    all_files_used += additional_includes unless additional_includes.empty?
    return all_files_used.uniq
  end
  
  def find_tests(input_file)
    input_file.rewind
    tests = []
    source = input_file.read()
    source = source.gsub(/\/\/.*$/, '') #remove line comments
    source = source.gsub(/\/\*.*?\*\//m, '') #remove block comments
    lines = source.split(/(^\s*\#.*$)  # Treat preprocessor directives as a logical line
                              | (;|\{|\}) /x) # Match ;, {, and } as end of lines
    lines.each do |line|
      if line =~ /^\s*void\s+test(.*?)\s*\(\s*void\s*\)/
        tests << "test" + $1
      end
    end
    return tests
  end

  def find_includes(input_file)
    input_file.rewind
    includes = []
    input_file.readlines.each do |line|
      scan_results = line.scan(/^#include\s+\"\s*(.+)\.h\s*\"/)
      includes << scan_results[0][0] if (scan_results.size > 0)
    end
    return includes
  end
  
  def find_mocks(includes)
    mock_headers = []
    includes.each do |include_file|
62
      mock_headers << include_file if (include_file =~ /^mock/i)
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
    end
    return mock_headers  
  end
  
  def create_header(output, mocks, additional_includes=[])
    output.puts('/* AUTOGENERATED FILE. DO NOT EDIT. */')
    output.puts('#include "unity.h"')
    additional_includes.each do |includes|
      output.puts("#include \"#{includes}.h\"")
    end
    mocks.each do |mock|
      output.puts("#include \"#{mock}.h\"")
    end
    output.puts('#include <setjmp.h>')
    output.puts('#include <stdio.h>')
78 79
    output.puts('#include "Exception.h"') if @options.include?(:cexception)
    output.puts('#include "BullseyeCoverage.h"') if @options.include?(:coverage)
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
    output.puts('')    
    output.puts('char MessageBuffer[50];')
  end
  
  
  def create_externs(output, tests, mocks)
    output.puts('')

    output.puts("extern void setUp(void);")
    output.puts("extern void tearDown(void);")

    output.puts('')

    tests.each do |test|
      output.puts("extern void #{test}(void);")
    end
    
    output.puts('')
  end
  
  
  def create_mock_management(output, mocks)
    unless (mocks.empty?)
      output.puts("static void CMock_Init(void)")
      output.puts("{")
      mocks.each do |mock|
        output.puts("#{@tab}#{mock}_Init();")
      end
      output.puts("}\n")

      output.puts("static void CMock_Verify(void)")
      output.puts("{")
      mocks.each do |mock|
        output.puts("#{@tab}#{mock}_Verify();")
      end
      output.puts("}\n")

      output.puts("static void CMock_Destroy(void)")
      output.puts("{")
      mocks.each do |mock|
        output.puts("#{@tab}#{mock}_Destroy();")
      end
      output.puts("}\n")
    end
  end
  
  
  def create_runtest(output, used_mocks)
    output.puts("static void runTest(UnityTestFunction test)")
    output.puts("{")
    output.puts("#{@tab}if (TEST_PROTECT())")
    output.puts("#{@tab}{")
132 133 134 135 136 137 138
    output.puts("#{@tab}#{@tab}EXCEPTION_T e;") if @options.include?(:cexception)
    output.puts("#{@tab}#{@tab}Try {") if @options.include?(:cexception)
    output.puts("#{@tab}#{@tab}#{@tab}CMock_Init();") unless (used_mocks.empty?) 
    output.puts("#{@tab}#{@tab}#{@tab}setUp();")
    output.puts("#{@tab}#{@tab}#{@tab}test();")
    output.puts("#{@tab}#{@tab}#{@tab}CMock_Verify();") unless (used_mocks.empty?)
    output.puts("#{@tab}#{@tab}} Catch(e) { TEST_FAIL(\"Unhandled Exception!\"); }") if @options.include?(:cexception)
139 140
    output.puts("#{@tab}}")
    output.puts("#{@tab}CMock_Destroy();") unless (used_mocks.empty?)
141 142 143 144
    output.puts("#{@tab}if (TEST_PROTECT())")
    output.puts("#{@tab}{")
    output.puts("#{@tab}#{@tab}tearDown();")
    output.puts("#{@tab}}")
145 146 147 148 149 150 151
    output.puts("}")
  end
  
  
  def create_main(output, module_name, tests)
    output.puts()
    output.puts()
152
    output.puts("int main(void)")
153 154 155 156 157 158 159 160 161 162 163 164
    output.puts("{")
    output.puts("#{@tab}Unity.TestFile = \"#{module_name}\";")
    output.puts("#{@tab}UnityBegin();")
    output.puts()

    output.puts("#{@tab}// RUN_TEST calls runTest")  	
    tests.each do |test|
      output.puts("#{@tab}RUN_TEST(#{test});")
    end

    output.puts()
    output.puts("#{@tab}UnityEnd();")
165
    output.puts("#{@tab}cov_write();") if @options.include?(:coverage)
166
    output.puts("#{@tab}return 0;")
167 168 169 170 171 172 173 174 175 176 177 178 179 180
    output.puts("}")
  end

end


if ($0 == __FILE__)
  usage = "usage: ruby #{__FILE__} input_test_file output_test_runner"
  
  if !ARGV[0]
    puts usage
    exit 1
  end
  
181
  ARGV[1] = ARGV[0].gsub(".c","_Runner.c") if (!ARGV[1])
182
  
M
mvandervoord 已提交
183 184 185 186
  includes = []
  includes = ARGV.slice(2..-1) if (ARGV.size > 2)
  
  UnityTestRunnerGenerator.new.run(ARGV[0], ARGV[1], includes)
187
end