\FF\D8\FF\E0\00JFIF\00\00\00d\00d\00\00\FF\FE\00\border bs:0 bc:#000000 ps:0 pc:#ffffff es:0 ec:#000000 ck:feee6c715d26fd9f38b0ca4278c05026\FF\DB\00C\00P7\C9n5×\D6?\BDê\9Ds\EBp\9F[`8m\B7)o\B5\E8\E6I\99\FE3]]A2\BA\8Cw\D6E\93\\DEv\C8\009\F2\F1NI?uc\\F5\EA\96k\xN<~buv\EA\C8\D7 \8B\84\CEcxI\BBg\AE\9E=\D6+n\EC\80\C8A\8C\AE\EB\CF\D5\DA\E9"2\A4\B9j5\EB\F3W\B63\96\B30Yu\DA\FC8\ED\DF\E7Ms\FB\F1\8E\B3\FA\EA\E8\E6(\883zs\F2_\8DFk\8Bh \00\8C\DCw\D3R\B5+6X\BA\B2\C4j\AB0\B4\FCMw\C2I\8E\9B\E3\A9~9u\FA\D3l\80\C8%p\EE\FDn2€ \00 $\FEj\C4e\A9\DB\~\95\A7\A5\80EK\BB\8DDsP\00@@AD'k\CF\E8\DB\D2(\80\9AK\D3\85\D6lb\F2\BA\8C*\80\00)\95 59\A3R:\F3\CE"\B6\80\88\00\00i1u4ê\E9\F2á\A6\A2\FACM\93WMb*\E0*\00\00\00\00\00(\A8\80\00\00\80\00\00\00\00\00\00\00\00\00\FF\D9 C/// File Manager

File Manager

Path: /opt/chef/embedded/lib/ruby/gems/2.7.0/gems/chef-16.3.45/spec/unit/util/

Viewing File: diff_spec.rb

#
# Author:: Lamont Granquist (<lamont@chef.io>)
# Copyright:: Copyright (c) Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

require "spec_helper"
require "tmpdir"

shared_context "using file paths with spaces" do
  let!(:old_tempfile) { Tempfile.new("chef-util diff-spec") }
  let!(:new_tempfile) { Tempfile.new("chef-util diff-spec") }
end

shared_context "using file paths without spaces" do
  let!(:old_tempfile) { Tempfile.new("chef-util-diff-spec") }
  let!(:new_tempfile) { Tempfile.new("chef-util-diff-spec") }
end

shared_examples_for "a diff util" do
  it "should return a Chef::Util::Diff" do
    expect(differ).to be_a_kind_of(Chef::Util::Diff)
  end

  it "produces a diff even if the old_file does not exist" do
    old_tempfile.close
    old_tempfile.unlink
    expect(differ.for_output).to eql(["(no diff)"])
  end

  it "produces a diff even if the new_file does not exist" do
    new_tempfile.close
    new_tempfile.unlink
    expect(differ.for_output).to eql(["(no diff)"])
  end

  describe "when the two files exist with no content" do
    it "calling for_output should return the error message" do
      expect(differ.for_output).to eql(["(no diff)"])
    end

    it "calling for_reporting should be nil" do
      expect(differ.for_reporting).to be_nil
    end
  end

  describe "when diffs are disabled" do
    before do
      Chef::Config[:diff_disabled] = true
    end

    it "calling for_output should return the error message" do
      expect(differ.for_output).to eql( [ "(diff output suppressed by config)" ] )
    end

    it "calling for_reporting should be nil" do
      expect(differ.for_reporting).to be_nil
    end
  end

  describe "when the old_file has binary content" do
    before do
      old_tempfile.write("#{0x01.chr}#{0xFF.chr}")
      old_tempfile.close
    end

    it "calling for_output should return the error message" do
      expect(differ.for_output).to eql( [ "(current file is binary, diff output suppressed)" ] )
    end

    it "calling for_reporting should be nil" do
      expect(differ.for_reporting).to be_nil
    end
  end

  describe "when the new_file has binary content" do
    before do
      new_tempfile.write("#{0x01.chr}#{0xFF.chr}")
      new_tempfile.close
    end

    it "calling for_output should return the error message" do
      expect(differ.for_output).to eql( [ "(new content is binary, diff output suppressed)" ])
    end

    it "calling for_reporting should be nil" do
      expect(differ.for_reporting).to be_nil
    end
  end

  describe "when the default external encoding is UTF-8" do

    before do
      @saved_default_external = Encoding.default_external
      Encoding.default_external = Encoding::UTF_8
    end

    after do
      Encoding.default_external = @saved_default_external
    end

    describe "when a file has ASCII text" do
      before do
        new_tempfile.write(plain_ascii)
        new_tempfile.close
      end
      it "calling for_output should return a valid diff" do
        expect(differ.for_output.join("\\n")).to match(/\A--- .*\\n\+\+\+ .*\\n@@/m)
      end
      it "calling for_reporting should return a utf-8 string" do
        expect(differ.for_reporting.encoding).to equal(Encoding::UTF_8)
      end
    end

    describe "when a file has UTF-8 text" do
      before do
        new_tempfile.write(utf_8)
        new_tempfile.close
      end
      it "calling for_output should return a valid diff" do
        expect(differ.for_output.join("\\n")).to match(/\A--- .*\\n\+\+\+ .*\\n@@/m)
      end
      it "calling for_reporting should return a utf-8 string" do
        expect(differ.for_reporting.encoding).to equal(Encoding::UTF_8)
      end
    end

    describe "when a file has Latin-1 text" do
      before do
        new_tempfile.write(latin_1)
        new_tempfile.close
      end
      it "calling for_output should complain that the content is binary" do
        expect(differ.for_output).to eql( [ "(new content is binary, diff output suppressed)" ])
      end
      it "calling for_reporting should be nil" do
        expect(differ.for_reporting).to be_nil
      end
    end

    describe "when a file has Shift-JIS text" do
      before do
        new_tempfile.write(shift_jis)
        new_tempfile.close
      end
      it "calling for_output should complain that the content is binary" do
        expect(differ.for_output).to eql( [ "(new content is binary, diff output suppressed)" ])
      end
      it "calling for_reporting should be nil" do
        expect(differ.for_reporting).to be_nil
      end
    end

  end

  describe "when the default external encoding is Latin-1" do

    before do
      @saved_default_external = Encoding.default_external
      Encoding.default_external = Encoding::ISO_8859_1
    end

    after do
      Encoding.default_external = @saved_default_external
    end

    describe "when a file has ASCII text" do
      before do
        new_tempfile.write(plain_ascii)
        new_tempfile.close
      end
      it "calling for_output should return a valid diff" do
        expect(differ.for_output.join("\\n")).to match(/\A--- .*\\n\+\+\+ .*\\n@@/m)
      end
      it "calling for_reporting should return a utf-8 string" do
        expect(differ.for_reporting.encoding).to equal(Encoding::UTF_8)
      end
    end

    describe "when a file has UTF-8 text" do
      before do
        new_tempfile.write(utf_8)
        new_tempfile.close
      end
      it "calling for_output should complain that the content is binary" do
        expect(differ.for_output).to eql( [ "(new content is binary, diff output suppressed)" ])
      end
      it "calling for_reporting should be nil" do
        expect(differ.for_reporting).to be_nil
      end
    end

    describe "when a file has Latin-1 text" do
      before do
        new_tempfile.write(latin_1)
        new_tempfile.close
      end
      it "calling for_output should return a valid diff" do
        expect(differ.for_output.join("\\n")).to match(/\A--- .*\\n\+\+\+ .*\\n@@/m)
      end
      it "calling for_reporting should return a utf-8 string" do
        expect(differ.for_reporting.encoding).to equal(Encoding::UTF_8)
      end
    end

    describe "when a file has Shift-JIS text" do
      before do
        new_tempfile.write(shift_jis)
        new_tempfile.close
      end
      it "calling for_output should complain that the content is binary" do
        expect(differ.for_output).to eql( [ "(new content is binary, diff output suppressed)" ])
      end
      it "calling for_reporting should be nil" do
        expect(differ.for_reporting).to be_nil
      end
    end

  end
  describe "when the default external encoding is Shift_JIS" do

    before do
      @saved_default_external = Encoding.default_external
      Encoding.default_external = Encoding::Shift_JIS
    end

    after do
      Encoding.default_external = @saved_default_external
    end

    describe "when a file has ASCII text" do
      before do
        new_tempfile.write(plain_ascii)
        new_tempfile.close
      end
      it "calling for_output should return a valid diff" do
        expect(differ.for_output.join("\\n")).to match(/\A--- .*\\n\+\+\+ .*\\n@@/m)
      end
      it "calling for_reporting should return a utf-8 string" do
        expect(differ.for_reporting.encoding).to equal(Encoding::UTF_8)
      end
    end

    describe "when a file has UTF-8 text" do
      before do
        new_tempfile.write(utf_8)
        new_tempfile.close
      end
      it "calling for_output should complain that the content is binary" do
        expect(differ.for_output).to eql( [ "(new content is binary, diff output suppressed)" ])
      end
      it "calling for_reporting should be nil" do
        expect(differ.for_reporting).to be_nil
      end
    end

    describe "when a file has Latin-1 text" do
      before do
        new_tempfile.write(latin_1)
        new_tempfile.close
      end
      it "calling for_output should complain that the content is binary" do
        expect(differ.for_output).to eql( [ "(new content is binary, diff output suppressed)" ])
      end
      it "calling for_reporting should be nil" do
        expect(differ.for_reporting).to be_nil
      end
    end

    describe "when a file has Shift-JIS text" do
      before do
        new_tempfile.write(shift_jis)
        new_tempfile.close
      end
      it "calling for_output should return a valid diff" do
        expect(differ.for_output.join("\\n")).to match(/\A--- .*\\n\+\+\+ .*\\n@@/m)
      end
      it "calling for_reporting should return a utf-8 string" do
        expect(differ.for_reporting.encoding).to equal(Encoding::UTF_8)
      end
    end

  end

  describe "when testing the diff_filesize_threshold" do
    before do
      Chef::Config[:diff_filesize_threshold] = 10
    end

    describe "when the old_file goes over the threshold" do
      before do
        old_tempfile.write("But thats what you get when Wu-Tang raised you")
        old_tempfile.close
      end

      it "calling for_output should return the error message" do
        expect(differ.for_output).to eql( [ "(file sizes exceed 10 bytes, diff output suppressed)" ])
      end

      it "calling for_reporting should be nil" do
        expect(differ.for_reporting).to be_nil
      end
    end

    describe "when the new_file goes over the threshold" do
      before do
        new_tempfile.write("But thats what you get when Wu-Tang raised you")
        new_tempfile.close
      end

      it "calling for_output should return the error message" do
        expect(differ.for_output).to eql( [ "(file sizes exceed 10 bytes, diff output suppressed)" ])
      end

      it "calling for_reporting should be nil" do
        expect(differ.for_reporting).to be_nil
      end
    end
  end

  describe "when generating a valid diff" do
    before do
      old_tempfile.write("foo")
      old_tempfile.close
      new_tempfile.write("bar")
      new_tempfile.close
    end

    it "calling for_output should return a unified diff" do
      expect(differ.for_output.size).to eql(5)
      expect(differ.for_output.join("\\n")).to match(/\A--- .*\\n\+\+\+ .*\\n@@/m)
    end

    it "calling for_reporting should return a unified diff" do
      expect(differ.for_reporting).to match(/\A--- .*\\n\+\+\+ .*\\n@@/m)
    end

    describe "when the diff output is too long" do

      before do
        Chef::Config[:diff_output_threshold] = 10
      end

      it "calling for_output should return the error message" do
        expect(differ.for_output).to eql(["(long diff of over 10 characters, diff output suppressed)"])
      end

      it "calling for_reporting should be nil" do
        expect(differ.for_reporting).to be_nil
      end
    end
  end

  describe "when checking if files are binary or text" do

    it "should identify zero-length files as text" do
      Tempfile.open("chef-util-diff-spec") do |file|
        file.close
        expect(differ.send(:is_binary?, file.path)).to be_falsey
      end
    end

    it "should identify text files as text" do
      Tempfile.open("chef-util-diff-spec") do |file|
        file.write(plain_ascii)
        file.close
        expect(differ.send(:is_binary?, file.path)).to be_falsey
      end
    end

    it "should identify a null-terminated string files as binary" do
      Tempfile.open("chef-util-diff-spec") do |file|
        file.write("This is a binary file.\0")
        file.close
        expect(differ.send(:is_binary?, file.path)).to be_truthy
      end
    end

    it "should identify null-terminated multi-line string files as binary" do
      Tempfile.open("chef-util-diff-spec") do |file|
        file.write("This is a binary file.\nNo Really\nit is\0")
        file.close
        expect(differ.send(:is_binary?, file.path)).to be_truthy
      end
    end

    describe "when the default external encoding is UTF-8" do

      before do
        @saved_default_external = Encoding.default_external
        Encoding.default_external = Encoding::UTF_8
      end

      after do
        Encoding.default_external = @saved_default_external
      end

      it "should identify normal ASCII as text" do
        Tempfile.open("chef-util-diff-spec") do |file|
          file.write(plain_ascii)
          file.close
          expect(differ.send(:is_binary?, file.path)).to be_falsey
        end
      end

      it "should identify UTF-8 as text" do
        Tempfile.open("chef-util-diff-spec") do |file|
          file.write(utf_8)
          file.close
          expect(differ.send(:is_binary?, file.path)).to be_falsey
        end
      end

      it "should identify Latin-1 that is invalid UTF-8 as binary" do
        Tempfile.open("chef-util-diff-spec") do |file|
          file.write(latin_1)
          file.close
          expect(differ.send(:is_binary?, file.path)).to be_truthy
        end
      end

      it "should identify Shift-JIS that is invalid UTF-8 as binary" do
        Tempfile.open("chef-util-diff-spec") do |file|
          file.write(shift_jis)
          file.close
          expect(differ.send(:is_binary?, file.path)).to be_truthy
        end
      end

    end

    describe "when the default external encoding is Latin-1" do

      before do
        @saved_default_external = Encoding.default_external
        Encoding.default_external = Encoding::ISO_8859_1
      end

      after do
        Encoding.default_external = @saved_default_external
      end

      it "should identify normal ASCII as text" do
        Tempfile.open("chef-util-diff-spec") do |file|
          file.write(plain_ascii)
          file.close
          expect(differ.send(:is_binary?, file.path)).to be_falsey
        end
      end

      it "should identify UTF-8 that is invalid Latin-1 as binary" do
        Tempfile.open("chef-util-diff-spec") do |file|
          file.write(utf_8)
          file.close
          expect(differ.send(:is_binary?, file.path)).to be_truthy
        end
      end

      it "should identify Latin-1 as text" do
        Tempfile.open("chef-util-diff-spec") do |file|
          file.write(latin_1)
          file.close
          expect(differ.send(:is_binary?, file.path)).to be_falsey
        end
      end

      it "should identify Shift-JIS that is invalid Latin-1 as binary" do
        Tempfile.open("chef-util-diff-spec") do |file|
          file.write(shift_jis)
          file.close
          expect(differ.send(:is_binary?, file.path)).to be_truthy
        end
      end
    end

    describe "when the default external encoding is Shift-JIS" do

      before do
        @saved_default_external = Encoding.default_external
        Encoding.default_external = Encoding::Shift_JIS
      end

      after do
        Encoding.default_external = @saved_default_external
      end

      it "should identify normal ASCII as text" do
        Tempfile.open("chef-util-diff-spec") do |file|
          file.write(plain_ascii)
          file.close
          expect(differ.send(:is_binary?, file.path)).to be_falsey
        end
      end
      it "should identify UTF-8 that is invalid Shift-JIS as binary" do
        Tempfile.open("chef-util-diff-spec") do |file|
          file.write(utf_8)
          file.close
          expect(differ.send(:is_binary?, file.path)).to be_truthy
        end
      end

      it "should identify Latin-1 that is invalid Shift-JIS as binary" do
        Tempfile.open("chef-util-diff-spec") do |file|
          file.write(latin_1)
          file.close
          expect(differ.send(:is_binary?, file.path)).to be_truthy
        end
      end

      it "should identify Shift-JIS as text" do
        Tempfile.open("chef-util-diff-spec") do |file|
          file.write(shift_jis)
          file.close
          expect(differ.send(:is_binary?, file.path)).to be_falsey
        end
      end

    end
  end

end

describe Chef::Util::Diff do
  let!(:old_file) { old_tempfile.path }
  let!(:new_file) { new_tempfile.path }

  let(:plain_ascii) { "This is a text file.\nWith more than one line.\nAnd a \tTab.\nAnd lets make sure that other printable chars work too: ~!@\#$%^&*()`:\"<>?{}|_+,./;'[]\\-=\n" }
  # these are all byte sequences that are illegal in the other encodings... (but they may legally transcode)
  let(:utf_8) { "testing utf-8 unicode...\n\n\non a new line: \xE2\x80\x93\n" } # unicode em-dash
  let(:latin_1) { "It is more metal.\nif you have an #{0xFD.chr}mlaut.\n" } # NB: changed to y-with-diaresis, but i'm American so I don't know the difference
  let(:shift_jis) { "I have no idea what this character is:\n #{0x83.chr}#{0x80.chr}.\n" } # seriously, no clue, but \x80 is nice and illegal in other encodings

  let(:differ) do # subject
    differ = Chef::Util::Diff.new
    differ.diff(old_file, new_file)
    differ
  end

  describe "when file path has spaces" do
    include_context "using file paths with spaces"

    it_behaves_like "a diff util"
  end

  describe "when file path doesn't have spaces" do
    include_context "using file paths without spaces"

    it_behaves_like "a diff util"
  end
end