2019-04-19 15:38:03 +09:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2018-07-23 20:59:21 +02:00
|
|
|
require_relative "shared_examples"
|
|
|
|
|
2024-02-18 15:11:11 -08:00
|
|
|
RSpec.describe UnpackStrategy::Directory do
|
2023-03-08 23:14:46 +00:00
|
|
|
let(:path) do
|
2018-07-23 20:59:21 +02:00
|
|
|
mktmpdir.tap do |path|
|
|
|
|
FileUtils.touch path/"file"
|
|
|
|
FileUtils.ln_s "file", path/"symlink"
|
2024-10-03 15:50:23 -04:00
|
|
|
FileUtils.ln path/"file", path/"hardlink"
|
2019-05-17 00:41:57 +02:00
|
|
|
FileUtils.mkdir path/"folder"
|
|
|
|
FileUtils.ln_s "folder", path/"folderSymlink"
|
2018-07-23 20:59:21 +02:00
|
|
|
end
|
2023-03-08 23:14:46 +00:00
|
|
|
end
|
2018-09-20 09:07:56 +01:00
|
|
|
|
2018-07-23 20:59:21 +02:00
|
|
|
let(:unpack_dir) { mktmpdir }
|
|
|
|
|
2024-10-05 17:19:53 -04:00
|
|
|
shared_examples "extract directory" do |move:|
|
|
|
|
subject(:strategy) { described_class.new(path, move:) }
|
2018-07-23 20:59:21 +02:00
|
|
|
|
2024-10-05 17:19:53 -04:00
|
|
|
it "does not follow symlinks" do
|
|
|
|
strategy.extract(to: unpack_dir)
|
|
|
|
expect(unpack_dir/"symlink").to be_a_symlink
|
|
|
|
end
|
2019-05-17 00:41:57 +02:00
|
|
|
|
2024-10-05 17:19:53 -04:00
|
|
|
it "does not follow top level symlinks to directories" do
|
|
|
|
strategy.extract(to: unpack_dir)
|
|
|
|
expect(unpack_dir/"folderSymlink").to be_a_symlink
|
|
|
|
end
|
|
|
|
|
|
|
|
it "preserves permissions of contained files" do
|
|
|
|
FileUtils.chmod 0644, path/"file"
|
|
|
|
|
|
|
|
strategy.extract(to: unpack_dir)
|
|
|
|
expect((unpack_dir/"file").stat.mode & 0777).to eq 0644
|
|
|
|
end
|
|
|
|
|
|
|
|
it "preserves permissions of contained subdirectories" do
|
|
|
|
FileUtils.mkdir unpack_dir/"folder"
|
|
|
|
FileUtils.chmod 0755, unpack_dir/"folder"
|
|
|
|
FileUtils.chmod 0700, path/"folder"
|
|
|
|
|
|
|
|
strategy.extract(to: unpack_dir)
|
|
|
|
expect((unpack_dir/"folder").stat.mode & 0777).to eq 0700
|
|
|
|
end
|
2024-10-03 15:50:23 -04:00
|
|
|
|
2024-10-05 17:19:53 -04:00
|
|
|
it "preserves permissions of the destination directory" do
|
|
|
|
FileUtils.chmod 0700, path
|
|
|
|
FileUtils.chmod 0755, unpack_dir
|
2018-07-23 20:59:21 +02:00
|
|
|
|
2024-10-05 17:19:53 -04:00
|
|
|
strategy.extract(to: unpack_dir)
|
|
|
|
expect(unpack_dir.stat.mode & 0777).to eq 0755
|
|
|
|
end
|
|
|
|
|
|
|
|
it "preserves mtime of contained files and directories" do
|
|
|
|
FileUtils.mkdir unpack_dir/"folder"
|
|
|
|
FileUtils.touch path/"folder", mtime: Time.utc(2000, 1, 2, 3, 4, 5, 678999), nocreate: true
|
|
|
|
mtimes = path.children.to_h { |child| [child.basename, child.lstat.mtime] }
|
|
|
|
|
|
|
|
strategy.extract(to: unpack_dir)
|
|
|
|
expect(unpack_dir.children.to_h { |child| [child.basename, child.lstat.mtime] }).to eq mtimes
|
|
|
|
end
|
|
|
|
|
|
|
|
it "preserves unrelated destination files and subdirectories" do
|
|
|
|
FileUtils.touch unpack_dir/"existing_file"
|
|
|
|
FileUtils.mkdir unpack_dir/"existing_folder"
|
|
|
|
|
|
|
|
strategy.extract(to: unpack_dir)
|
|
|
|
expect(unpack_dir/"existing_file").to be_a_file
|
|
|
|
expect(unpack_dir/"existing_folder").to be_a_directory
|
|
|
|
end
|
|
|
|
|
|
|
|
it "overwrites destination files/symlinks with source files/symlinks" do
|
|
|
|
FileUtils.mkdir unpack_dir/"existing_folder"
|
|
|
|
FileUtils.ln_s unpack_dir/"existing_folder", unpack_dir/"symlink"
|
|
|
|
(unpack_dir/"file").write "existing contents"
|
|
|
|
|
|
|
|
strategy.extract(to: unpack_dir)
|
|
|
|
expect((unpack_dir/"file").read).to be_empty
|
|
|
|
expect((unpack_dir/"symlink").readlink).to eq Pathname("file")
|
|
|
|
end
|
|
|
|
|
|
|
|
it "fails when overwriting a directory with a file" do
|
|
|
|
FileUtils.mkdir unpack_dir/"file"
|
|
|
|
expect { strategy.extract(to: unpack_dir) }.to raise_error(/Is a directory|cannot overwrite directory/i)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "fails when overwriting a nested directory with a file" do
|
|
|
|
FileUtils.touch path/"folder/nested"
|
|
|
|
FileUtils.mkdir_p unpack_dir/"folder/nested"
|
|
|
|
expect { strategy.extract(to: unpack_dir) }.to raise_error(/Is a directory|cannot overwrite directory/i)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context "with `move: false`" do
|
|
|
|
include_examples "extract directory", move: false
|
2018-07-23 20:59:21 +02:00
|
|
|
end
|
|
|
|
|
2024-10-05 17:19:53 -04:00
|
|
|
context "with `move: true`" do
|
|
|
|
include_examples "extract directory", move: true
|
2018-07-23 20:59:21 +02:00
|
|
|
|
2024-10-05 17:19:53 -04:00
|
|
|
it "preserves hardlinks" do
|
|
|
|
strategy.extract(to: unpack_dir)
|
|
|
|
expect((unpack_dir/"file").stat.ino).to eq (unpack_dir/"hardlink").stat.ino
|
|
|
|
end
|
|
|
|
|
|
|
|
# NOTE: We don't test `move: false` because system cp behaviour is inconsistent,
|
|
|
|
# e.g. Ventura cp does not error but Sequoia and Linux cp will error
|
|
|
|
it "fails when overwriting a file with a directory" do
|
|
|
|
FileUtils.touch unpack_dir/"folder"
|
|
|
|
expect { strategy.extract(to: unpack_dir) }.to raise_error(/cannot overwrite non-directory/i)
|
|
|
|
end
|
2018-07-23 20:59:21 +02:00
|
|
|
end
|
|
|
|
end
|