test.rb 6.1 KB
Newer Older
J
Justin Collins 已提交
1 2 3
#Set paths
TEST_PATH = File.expand_path(File.dirname(__FILE__))
$LOAD_PATH.unshift "#{TEST_PATH}/../lib"
4

5 6
begin
  require 'simplecov'
7 8 9 10 11 12
  SimpleCov.start do
    add_filter 'lib/ruby_parser/ruby18_parser.rb'
    add_filter 'lib/ruby_parser/ruby19_parser.rb'
    add_filter 'lib/ruby_parser/ruby_lexer.rb'
    add_filter 'lib/ruby_parser/ruby_parser_extras.rb'
  end
13 14 15 16
rescue LoadError => e
  $stderr.puts "Install simplecov for test coverage report"
end

J
Justin Collins 已提交
17 18
require 'brakeman'
require 'brakeman/scanner'
19
require 'test/unit'
J
Justin Collins 已提交
20

21
#Helper methods for running scans
J
Justin Collins 已提交
22 23 24 25
module BrakemanTester
  class << self
    #Run scan on app at the given path
    def run_scan path, name = nil, opts = {}
J
Justin Collins 已提交
26
      opts.merge! :app_path => "#{TEST_PATH}/apps/#{path}",
27 28
        :quiet => false,
        :url_safe_methods => [:ensure_valid_proto!]
J
Justin Collins 已提交
29

J
Justin Collins 已提交
30
      announce "Processing #{name} application..."
J
Justin Collins 已提交
31

32
      Brakeman.run(opts).report.to_test
J
Justin Collins 已提交
33
    end
J
Justin Collins 已提交
34

J
Justin Collins 已提交
35 36 37 38 39 40 41 42 43
    #Make an announcement
    def announce msg
      $stderr.puts "-" * 40
      $stderr.puts msg
      $stderr.puts "-" * 40
    end
  end
end

44
#Helpers for finding warnings in the report
J
Justin Collins 已提交
45
module BrakemanTester::FindWarning
J
Justin Collins 已提交
46 47 48 49
  def assert_warning opts
    warnings = find opts
    assert_not_equal 0, warnings.length, "No warning found"
    assert_equal 1, warnings.length, "Matched more than one warning"
J
Justin Collins 已提交
50
  end
J
Justin Collins 已提交
51

J
Justin Collins 已提交
52 53 54 55 56
  def assert_no_warning opts
    warnings = find opts
    assert_equal 0, warnings.length, "Unexpected warning found"
  end

J
Justin Collins 已提交
57 58 59
  def find opts = {}, &block
    t = opts[:type]
    if t.nil? or t == :warning
J
Justin Collins 已提交
60 61
      warnings = report[:warnings]
    else
J
Justin Collins 已提交
62
      warnings = report[(t.to_s << "_warnings").to_sym]
J
Justin Collins 已提交
63 64 65 66
    end

    opts.delete :type

J
Justin Collins 已提交
67
    result = if block
J
Justin Collins 已提交
68 69 70 71 72 73 74 75 76 77 78 79 80
      warnings.select block
    else
      warnings.select do |w|
        flag = true
        opts.each do |k,v|
          unless v === w.send(k)
            flag = false
            break
          end
        end
        flag
      end
    end
J
Justin Collins 已提交
81 82

    result
J
Justin Collins 已提交
83 84 85
  end
end

86 87 88 89 90 91 92 93 94 95 96 97 98 99
#Check that the number of warnings reported are as expected.
#This is mainly to look for new warnings that are not being tested.
module BrakemanTester::CheckExpected
  def test_number_of_warnings
    expected.each do |type, number|
      if type == :warning
        warnings = report[:warnings]
      else
        warnings = report[(type.to_s << "_warnings").to_sym]
      end

      assert_equal number, warnings.length, "Expected #{number} #{type} warnings, but found #{warnings.length}"
    end
  end
100 101

  def test_zero_errors
J
Justin Collins 已提交
102 103 104 105 106 107 108 109 110 111 112 113
    assert_equal 0, report[:errors].length
  end
end

module BrakemanTester::RescanTestHelper
  attr_reader :original, :rescan, :rescanner

  #Takes care of copying files to a temporary directory, scanning the files,
  #performing operations in the block (if provided), then rescanning the files
  #given in `changed`.
  #
  #Provide an array of changed files for rescanning.
114
  def before_rescan_of changed, app = "rails3.2"
J
Justin Collins 已提交
115 116 117 118 119
    changed = [changed] unless changed.is_a? Array

    Dir.mktmpdir do |dir|
      @dir = dir

120
      FileUtils.cp_r "#{TEST_PATH}/apps/#{app}/.", dir
J
Justin Collins 已提交
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
      @original = Brakeman.run :app_path => dir, :debug => false

      yield dir if block_given?

      @rescanner = Brakeman::Rescanner.new(@original.options, @original.processor, changed)
      @rescan = @rescanner.recheck

      assert_existing
    end
  end

  def fixed
    rescan.fixed_warnings
  end

  def new
    rescan.new_warnings
  end

  def existing
    rescan.existing_warnings
  end

  #Check how many fixed warnings were reported
  def assert_fixed expected
    assert_equal expected, fixed.length, "Expected #{expected} fixed warnings, but found #{fixed.length}"
  end

  #Check how many new warnings were reported
  def assert_new expected
    assert_equal expected, new.length, "Expected #{expected} new warnings, but found #{new.length}"
  end

  #Check how many existing warnings were reported
  def assert_existing
    expected = (@rescan.old_results.all_warnings.length - fixed.length)

    assert_equal expected, existing.length, "Expected #{expected} existing warnings, but found #{existing.length}"
  end

  def assert_changes expected = true
    assert_equal expected, rescanner.changes
  end

  def assert_reindex *types
    if types == [:none]
J
Justin Collins 已提交
167
      assert rescanner.reindex.empty?, "Expected no reindexing, got #{rescanner.reindex.inspect}"
J
Justin Collins 已提交
168 169 170 171 172 173 174 175 176 177 178 179
    else
      assert_equal Set.new(types), rescanner.reindex
    end
  end

  def full_path file
    File.expand_path file, @dir
  end

  def remove file
    path = full_path file

J
Justin Collins 已提交
180
    assert File.exist?(path), "Could not find #{path} to delete"
J
Justin Collins 已提交
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
    File.delete path
    assert_equal false, File.exist?(path)
  end

  def append file, code
    File.open full_path(file), "a" do |f|
      f.puts code
    end
  end

  def replace_with_sexp file
    path = full_path file
    parsed = parse File.read path

    output = yield parsed

    File.open path, "w" do |f|
      f.puts Ruby2Ruby.new.process output
    end
  end

  def replace file, pattern, replacement
    path = full_path file
    input = File.read path
    input.sub! pattern, replacement

    File.open path, "w" do |f|
      f.puts input
    end
  end

  def write_file file, content
    File.open full_path(file), "w+" do |f|
      f.puts content
    end
  end

  def remove_method file, method_name
    replace_with_sexp file do |parsed|
      class_body = parsed.body

222 223 224 225
      class_body.reject! do |node|
        node.is_a? Sexp and
        node.node_type == :defn and
        node.method_name == method_name
J
Justin Collins 已提交
226 227
      end

228 229
      parsed.body = class_body

J
Justin Collins 已提交
230 231 232 233 234 235 236 237
      parsed
    end
  end

  def add_method file, code
    parsed_method = parse code

    replace_with_sexp file do |parsed|
J
Justin Collins 已提交
238
      parsed.body = parsed.body << parsed_method
J
Justin Collins 已提交
239 240 241 242 243 244

      parsed
    end
  end

  def parse code
J
Justin Collins 已提交
245
    RubyParser.new.parse code
J
Justin Collins 已提交
246 247
  end
end
248

249 250 251 252 253 254 255
module BrakemanTester::DiffHelper
  def assert_fixed expected, diff = @diff
    assert_equal expected, diff[:fixed].length, "Expected #{expected} fixed warnings, but found #{diff[:fixed].length}"
  end

  def assert_new expected, diff = @diff
    assert_equal expected, diff[:new].length, "Expected #{expected} new warnings, but found #{diff[:new].length}"
256
  end
257 258
end

J
Justin Collins 已提交
259 260
Dir.glob "#{TEST_PATH}/tests/*.rb" do |file|
  require file
J
Justin Collins 已提交
261
end