lib/assert_same.rb in assert_same-0.2 vs lib/assert_same.rb in assert_same-0.3

- old
+ new

@@ -1,12 +1,58 @@ # Copyright (c) 2010-2011 Pluron, Inc. require 'test/unit/testcase' require 'text_diff' require 'pathname' -class Test::Unit::TestCase +$assert_same_options = [] +if RUBY_VERSION >= "1.9.0" + + # Test/Unit from Ruby 1.9 can't accept additional options like it did in 1.8: + # ruby test.rb -- --foo + # Now it has a strict option parser that considers all additional options as files. + # The right way to have an option now is to explicitly add it to Test/Unit parser. + module Test::Unit + + module AssertSameOption + def setup_options(parser, options) + super + parser.on '--no-interactive', 'assert_same: non-interactive mode' do |flag| + $assert_same_options << "--no-interactive" + puts $assert_same_options + end + parser.on '--no-canonicalize', 'assert_same: turn off canonicalization' do |flag| + $assert_same_options << "--no-canonicalize" + end + parser.on '--autoaccept', 'assert_same: automatically accept new actual values' do |flag| + $assert_same_options << "--autoaccept" + end + end + + def non_options(files, options) + super + end + end + + class Runner < MiniTest::Unit + include Test::Unit::AssertSameOption + end + + end + +else + + # In Ruby 1.8 additional test options are simply passed via ARGV + $assert_same_options << "--no-interactive" if ARGV.include?("--no-interactive") + $assert_same_options << "--no-canonicalize" if ARGV.include?("--no-canonicalize") + $assert_same_options << "--autoaccept" if ARGV.include?("--autoaccept") + +end + + +module Test::Unit::Assertions + #Hash[filename][line_number] = offset #For each line in the original file we store its offset (+N or -N lines) #relative to the actual file @@file_offsets = Hash.new { |hash, key| hash[key] = {} } @@ -36,18 +82,25 @@ # --no-interactive skips all questions and just reports failures # --autoaccept prints diffs and automatically accepts all new actual values # --no-canonicalize turns off expected and actual value canonicalization (see below for details) # # Additional options can be passed during both single test file run and rake test run: + # In Ruby 1.8: # ruby test/unit/foo_test.rb -- --autoaccept # ruby test/unit/foo_test.rb -- --no-interactive # # rake test TESTOPTS="-- --autoaccept" # rake test:units TESTOPTS="-- --no-canonicalize --autoaccept" # + # In Ruby 1.9: + # ruby test/unit/foo_test.rb --autoaccept + # ruby test/unit/foo_test.rb --no-interactive # + # rake test TESTOPTS="--autoaccept" + # rake test:units TESTOPTS="--no-canonicalize --autoaccept" # + # # == Canonicalization == # # Before comparing expected and actual strings, assert_same canonicalizes both using these rules: # - indentation is ignored (except for indentation # relative to the first line of the expected/actual string) @@ -57,11 +110,14 @@ # - trailing whitespaces are ignored # # You can turn canonicalization off with --no-canonicalize option. This is useful # when you need to regenerate expected test strings. # To regenerate the whole test suite, run: + # In Ruby 1.8: # rake test TESTOPTS="-- --no-canonicalize --autoaccept" + # In Ruby 1.9: + # rake test TESTOPTS="--no-canonicalize --autoaccept" # # Example of assert_same with comments: # assert_same something, <<-END # # some tree # foo 1 @@ -116,32 +172,31 @@ end # interactive mode is turned on by default, except when # - --no-interactive is given # - STDIN is not a terminal device (i.e. we can't ask any questions) - interactive = !ARGV.include?("--no-interactive") && STDIN.tty? - canonicalize = !ARGV.include?("--no-canonicalize") - autoaccept = ARGV.include?("--autoaccept") + interactive = !$assert_same_options.include?("--no-interactive") && STDIN.tty? + canonicalize = !$assert_same_options.include?("--no-canonicalize") + autoaccept = $assert_same_options.include?("--autoaccept") is_same_canonicalized, is_same, diff_canonicalized, diff = compare_for_assert_same(expected, actual) if (canonicalize and !is_same_canonicalized) or (!canonicalize and !is_same) diff_to_report = canonicalize ? diff_canonicalized : diff if interactive # print method name and short backtrace - failure = Test::Unit::Failure.new(name, filter_backtrace(caller(0)), diff_to_report) - puts "\n#{failure}" + soft_fail(diff_to_report) if autoaccept accept = true else print "Accept the new value: yes to all, no to all, yes, no? [Y/N/y/n] (y): " STDOUT.flush response = STDIN.gets.strip accept = ["", "y", "Y"].include? response - ARGV << "--autoaccept" if response == "Y" - ARGV << "--no-interactive" if response == "N" + $assert_same_options << "--autoaccept" if response == "Y" + $assert_same_options << "--no-interactive" if response == "N" end if accept if [:expecting_string, :autofill_expected_value].include? mode accept_string(actual, mode) @@ -152,21 +207,47 @@ end if accept # when change is accepted, we should not report it as a failure because # we want the test method to continue executing (in case there're more # assert_same's in the method) - add_assertion + succeed else - raise Test::Unit::AssertionFailedError.new(diff_to_report) + fail(diff) end else - add_assertion + succeed end end private + def succeed + if RUBY_VERSION < "1.9.0" + add_assertion + else + true + end + end + + def soft_fail(diff) + if RUBY_VERSION < "1.9.0" + failure = Test::Unit::Failure.new(name, filter_backtrace(caller(0)), diff) + puts "\n#{failure}" + else + failure = MiniTest::Assertion.new(diff) + puts "\n#{failure}" + end + end + + def fail(diff) + if RUBY_VERSION < "1.9.0" + raise Test::Unit::AssertionFailedError.new(diff) + else + raise MiniTest::Assertion.new(diff) + end + end + def accept_string(actual, mode) file, method, line = get_caller_location(:depth => 3) # read source file, construct the new source, replacing everything # between "do" and "end" in assert_same's block @@ -207,10 +288,10 @@ actual_length = actual.split("\n").length actual_length += 1 if mode == :autofill_expected_value # END marker after actual value @@file_offsets[file][line.to_i] = actual_length - expected_length source_file = File.open(file, "w+") - source_file.write(source) + source_file.write(source.join('')) source_file.fsync source_file.close end def accept_file(actual, log_file)