# frozen_string_literal: true require "rubygems" require "pathname" require "psych" if RUBY_VERSION >= "1.9" if ENV["COVERAGE"] require "simplecov" def require_do(resource) require resource yield if block_given? rescue LoadError nil end formatters = [SimpleCov::Formatter::HTMLFormatter] require_do("simplecov-rcov") { formatters << SimpleCov::Formatter::RcovFormatter } require_do("simplecov-vim/formatter") { formatters << SimpleCov::Formatter::VimFormatter } require_do("simplecov-sublime-ruby-coverage") { formatters << SimpleCov::Formatter::SublimeRubyCoverageFormatter } SimpleCov.start do formatter SimpleCov::Formatter::MultiFormatter.new(formatters) end end file = Pathname.new(__FILE__).expand_path path = file.parent parent = path.parent $:.unshift parent.join("lib") module CaptureSubprocessIO def _synchronize yield end def capture_subprocess_io _synchronize { _capture_subprocess_io { yield } } end def _capture_subprocess_io require "tempfile" captured_stdout, captured_stderr = Tempfile.new("out"), Tempfile.new("err") orig_stdout, orig_stderr = $stdout.dup, $stderr.dup $stdout.reopen captured_stdout $stderr.reopen captured_stderr yield $stdout.rewind $stderr.rewind [captured_stdout.read, captured_stderr.read] ensure captured_stdout.unlink captured_stderr.unlink $stdout.reopen orig_stdout $stderr.reopen orig_stderr end private :_capture_subprocess_io end require "diff-lcs" module Diff::LCS::SpecHelper def hello "hello" end def hello_ary %w[h e l l o] end def seq1 %w[a b c e h j l m n p] end def skipped_seq1 %w[a h n p] end def seq2 %w[b c d e f j k l m r s t] end def skipped_seq2 %w[d f k r s t] end def word_sequence %w[abcd efgh ijkl mnopqrstuvwxyz] end def correct_lcs %w[b c e j l m] end # standard:disable Layout/ExtraSpacing def correct_forward_diff [ [ ["-", 0, "a"] ], [ ["+", 2, "d"] ], [ ["-", 4, "h"], ["+", 4, "f"] ], [ ["+", 6, "k"] ], [ ["-", 8, "n"], ["+", 9, "r"], ["-", 9, "p"], ["+", 10, "s"], ["+", 11, "t"] ] ] end def correct_backward_diff [ [ ["+", 0, "a"] ], [ ["-", 2, "d"] ], [ ["-", 4, "f"], ["+", 4, "h"] ], [ ["-", 6, "k"] ], [ ["-", 9, "r"], ["+", 8, "n"], ["-", 10, "s"], ["+", 9, "p"], ["-", 11, "t"] ] ] end def correct_forward_sdiff [ ["-", [0, "a"], [0, nil]], ["=", [1, "b"], [0, "b"]], ["=", [2, "c"], [1, "c"]], ["+", [3, nil], [2, "d"]], ["=", [3, "e"], [3, "e"]], ["!", [4, "h"], [4, "f"]], ["=", [5, "j"], [5, "j"]], ["+", [6, nil], [6, "k"]], ["=", [6, "l"], [7, "l"]], ["=", [7, "m"], [8, "m"]], ["!", [8, "n"], [9, "r"]], ["!", [9, "p"], [10, "s"]], ["+", [10, nil], [11, "t"]] ] end # standard:enable Layout/ExtraSpacing def reverse_sdiff(forward_sdiff) forward_sdiff.map { |line| line[1], line[2] = line[2], line[1] case line[0] when "-" then line[0] = "+" when "+" then line[0] = "-" end line } end def change_diff(diff) map_diffs(diff, Diff::LCS::Change) end def context_diff(diff) map_diffs(diff, Diff::LCS::ContextChange) end def format_diffs(diffs) diffs.map { |e| if e.is_a?(Array) e.map { |f| f.to_a.join }.join(", ") else e.to_a.join end }.join("\n") end def map_diffs(diffs, klass = Diff::LCS::ContextChange) diffs.map do |chunks| if klass == Diff::LCS::ContextChange klass.from_a(chunks) else chunks.map { |changes| klass.from_a(changes) } end end end def balanced_traversal(s1, s2, callback_type) callback = __send__(callback_type) Diff::LCS.traverse_balanced(s1, s2, callback) callback end def balanced_reverse(change_result) new_result = [] change_result.each do |line| line = [line[0], line[2], line[1]] case line[0] when "<" line[0] = ">" when ">" line[0] = "<" end new_result << line end new_result.sort_by { |line| [line[1], line[2]] } end def map_to_no_change(change_result) new_result = [] change_result.each do |line| case line[0] when "!" new_result << ["<", line[1], line[2]] new_result << [">", line[1] + 1, line[2]] else new_result << line end end new_result end def simple_callback callbacks = Object.new class << callbacks attr_reader :matched_a attr_reader :matched_b attr_reader :discards_a attr_reader :discards_b attr_reader :done_a attr_reader :done_b def reset @matched_a = [] @matched_b = [] @discards_a = [] @discards_b = [] @done_a = [] @done_b = [] end def match(event) @matched_a << event.old_element @matched_b << event.new_element end def discard_b(event) @discards_b << event.new_element end def discard_a(event) @discards_a << event.old_element end def finished_a(event) @done_a << [ event.old_element, event.old_position, event.new_element, event.new_position ] end def finished_b(event) @done_b << [ event.old_element, event.old_position, event.new_element, event.new_position ] end end callbacks.reset callbacks end def simple_callback_no_finishers simple = simple_callback class << simple undef :finished_a undef :finished_b end simple end def balanced_callback cb = Object.new class << cb attr_reader :result def reset @result = [] end def match(event) @result << ["=", event.old_position, event.new_position] end def discard_a(event) @result << ["<", event.old_position, event.new_position] end def discard_b(event) @result << [">", event.old_position, event.new_position] end def change(event) @result << ["!", event.old_position, event.new_position] end end cb.reset cb end def balanced_callback_no_change balanced = balanced_callback class << balanced undef :change end balanced end module Matchers extend RSpec::Matchers::DSL matcher :be_nil_or_match_values do |ii, s1, s2| match do |ee| expect(ee).to(satisfy { |vee| vee.nil? || s1[ii] == s2[ee] }) end end matcher :correctly_map_sequence do |s1| match do |actual| actual.each_index { |ii| expect(actual[ii]).to be_nil_or_match_values(ii, s1, @s2) } end chain :to_other_sequence do |s2| @s2 = s2 end end end end RSpec.configure do |conf| conf.include Diff::LCS::SpecHelper conf.alias_it_should_behave_like_to :it_has_behavior, "has behavior:" # standard:disable Style/HashSyntax conf.filter_run_excluding :broken => true # standard:enable Style/HashSyntax end