diff --git a/lib/difftastic.rb b/lib/difftastic.rb index 593f172..acda050 100644 --- a/lib/difftastic.rb +++ b/lib/difftastic.rb @@ -25,6 +25,10 @@ def self.execute(command) `#{executable} #{command}` end + def self.capture(*arguments) + IO.popen([executable, *arguments], &:read) + end + def self.platform [:cpu, :os].map { |m| Gem::Platform.local.__send__(m) }.join("-") end diff --git a/lib/difftastic/differ.rb b/lib/difftastic/differ.rb index e1f327d..e7f2c40 100644 --- a/lib/difftastic/differ.rb +++ b/lib/difftastic/differ.rb @@ -298,9 +298,9 @@ def diff_files(old_file, new_file) ("--tab-width=#{@tab_width}" if @tab_width), ("--display=#{@display}" if @display), ("--width=#{@width}" if @width), - ].compact! + ].compact - result = Difftastic.execute(options.join(" ")).lstrip.sub(/\n{2}\z/, "") + result = Difftastic.capture(*options).lstrip.sub(/\n{2}\z/, "") unless @show_paths new_line_index = (result.index("\n") || 0) + 1 diff --git a/test/shell_test.rb b/test/shell_test.rb new file mode 100644 index 0000000..01b4b34 --- /dev/null +++ b/test/shell_test.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +require_relative "test_helper" +require "tmpdir" + +class ShellTest < Minitest::Spec + it "diff_files with spaces, quotes and command substitution in paths" do + Dir.mktmpdir do |dir| + Dir.chdir(dir) do + File.write("a $(touch injected).txt", "A") + File.write("b 'quoted\".txt", "B") + + output = Difftastic::Differ.new(color: :never, tab_width: 2).diff_files("a $(touch injected).txt", "b 'quoted\".txt") + + assert_equal "1 A 1 B", output + end + end + end + + it "diff_files does not run command substitution in paths" do + Dir.mktmpdir do |dir| + Dir.chdir(dir) do + File.write("a $(touch injected).txt", "A") + File.write("b.txt", "B") + + Difftastic::Differ.new(color: :never, tab_width: 2).diff_files("a $(touch injected).txt", "b.txt") + + refute File.exist?("injected") + end + end + end + + it "diff_strings with a temporary directory containing a space" do + original_tmpdir = ENV["TMPDIR"] + + Dir.mktmpdir do |parent| + dir = File.join(parent, "with space") + Dir.mkdir(dir, 0o700) + ENV["TMPDIR"] = dir + + output = Difftastic::Differ.new(color: :never, tab_width: 2).diff_strings("A", "B") + + assert_equal "1 A 1 B", output + ensure + ENV["TMPDIR"] = original_tmpdir + end + end + + it "diff_strings with every option set" do + differ = Difftastic::Differ.new(color: :never, context: 3, background: :dark, syntax_highlight: :off, tab_width: 2, width: 80) + + assert_equal "1 A 1 B", differ.diff_strings("A", "B") + end +end