Skip to content

Commit c25e5e0

Browse files
committed
test: add tests for spaces in the git binary path or the working dir
1 parent 5f43a1a commit c25e5e0

File tree

4 files changed

+163
-14
lines changed

4 files changed

+163
-14
lines changed

lib/git/base.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ def self.root_of_worktree(working_dir)
8787
result = working_dir
8888
status = nil
8989

90+
raise ArgumentError, "'#{working_dir}' does not exist" unless Dir.exist?(working_dir)
91+
9092
begin
9193
result, status = Open3.capture2e(Git::Base.config.binary_path, "-c", "core.quotePath=true", "-c", "color.ui=false", "rev-parse", "--show-toplevel", chdir: File.expand_path(working_dir))
9294
result = result.chomp

tests/test_helper.rb

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,3 +218,56 @@ def run_command(*command, timeout: nil, raise_errors: true, error_message: "#{co
218218
CommandResult.new(status, out_buffer.string, err_buffer.string)
219219
end
220220
end
221+
222+
# Replace the default git binary with the given script
223+
#
224+
# This method creates a temporary directory and writes the given script to a file
225+
# named `git` in a subdirectory named `bin`. This subdirectory name can be changed by
226+
# passing a different value for the `subdir` parameter.
227+
#
228+
# On non-windows platforms, make sure the script starts with a hash bang. On windows,
229+
# make sure the script has a `.bat` extension.
230+
#
231+
# On non-windows platforms, the script is made executable.
232+
#
233+
# `Git::Base.config.binary_path` set to the path to the script.
234+
#
235+
# The block is called passing the path to the mocked git binary.
236+
#
237+
# `Git::Base.config.binary_path` is reset to its original value after the block
238+
# returns.
239+
#
240+
# @example mocked_git_script = <<~GIT_SCRIPT #!/bin/sh puts 'git version 1.2.3'
241+
# GIT_SCRIPT
242+
#
243+
# mock_git_binary(mocked_git_script) do
244+
# # Run Git commands here -- they will call the mocked git script
245+
# end
246+
#
247+
# @param script [String] The bash script to run instead of the real git binary
248+
#
249+
# @param subdir [String] The subdirectory to place the mocked git binary in
250+
#
251+
# @yield Call the block while the git binary is mocked
252+
#
253+
# @yieldparam git_binary_path [String] The path to the mocked git binary
254+
#
255+
# @yieldreturn [void] the return value of the block is ignored
256+
#
257+
# @return [void]
258+
#
259+
def mock_git_binary(script, subdir: 'bin')
260+
Dir.mktmpdir do |binary_dir|
261+
binary_name = windows_platform? ? 'git.bat' : 'git'
262+
git_binary_path = File.join(binary_dir, subdir, binary_name)
263+
FileUtils.mkdir_p(File.dirname(git_binary_path))
264+
File.write(git_binary_path, script)
265+
File.chmod(0755, git_binary_path) unless windows_platform?
266+
saved_binary_path = Git::Base.config.binary_path
267+
Git::Base.config.binary_path = git_binary_path
268+
269+
yield git_binary_path
270+
271+
Git::Base.config.binary_path = saved_binary_path
272+
end
273+
end
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
require 'test_helper'
2+
3+
class TestGitBaseRootOfWorktree < Test::Unit::TestCase
4+
def mocked_git_script(toplevel) = <<~GIT_SCRIPT
5+
#!/bin/sh
6+
# Loop through the arguments and check for the "rev-parse --show-toplevel" args
7+
for arg in "$@"; do
8+
if [ "$arg" = "version" ]; then
9+
echo "git version 1.2.3"
10+
exit 0
11+
elif [ "$arg" = "rev-parse" ]; then
12+
REV_PARSE_ARG=true
13+
elif [ "$REV_PARSE_ARG" = "true" ] && [ $arg = "--show-toplevel" ]; then
14+
echo #{toplevel}
15+
exit 0
16+
fi
17+
done
18+
exit 1
19+
GIT_SCRIPT
20+
21+
def test_root_of_worktree
22+
omit('Only implemented for non-windows platforms') if windows_platform?
23+
24+
in_temp_dir do |toplevel|
25+
`git init`
26+
27+
mock_git_binary(mocked_git_script(toplevel)) do
28+
working_dir = File.join(toplevel, 'config')
29+
Dir.mkdir(working_dir)
30+
31+
assert_equal(toplevel, Git::Base.root_of_worktree(working_dir))
32+
end
33+
end
34+
end
35+
36+
def test_working_dir_has_spaces
37+
omit('Only implemented for non-windows platforms') if windows_platform?
38+
39+
in_temp_dir do |toplevel|
40+
`git init`
41+
42+
mock_git_binary(mocked_git_script(toplevel)) do
43+
working_dir = File.join(toplevel, 'app config')
44+
Dir.mkdir(working_dir)
45+
46+
assert_equal(toplevel, Git::Base.root_of_worktree(working_dir))
47+
end
48+
end
49+
end
50+
51+
def test_working_dir_does_not_exist
52+
assert_raise ArgumentError do
53+
Git::Base.root_of_worktree('/path/to/nonexistent/work_dir')
54+
end
55+
end
56+
57+
def mocked_git_script2 = <<~GIT_SCRIPT
58+
#!/bin/sh
59+
# Loop through the arguments and check for the "rev-parse --show-toplevel" args
60+
for arg in "$@"; do
61+
if [ "$arg" = "version" ]; then
62+
echo "git version 1.2.3"
63+
exit 0
64+
elif [ "$arg" = "rev-parse" ]; then
65+
REV_PARSE_ARG=true
66+
elif [ "$REV_PARSE_ARG" = "true" ] && [ $arg = "--show-toplevel" ]; then
67+
echo fatal: not a git repository 1>&2
68+
exit 128
69+
fi
70+
done
71+
exit 1
72+
GIT_SCRIPT
73+
74+
def test_working_dir_not_in_work_tree
75+
omit('Only implemented for non-windows platforms') if windows_platform?
76+
77+
in_temp_dir do |temp_dir|
78+
toplevel = File.join(temp_dir, 'my_repo')
79+
Dir.mkdir(toplevel) do
80+
`git init`
81+
end
82+
83+
mock_git_binary(mocked_git_script2) do
84+
assert_raise ArgumentError do
85+
Git::Base.root_of_worktree(temp_dir)
86+
end
87+
end
88+
end
89+
end
90+
end

tests/units/test_git_binary_version.rb

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
require 'test_helper'
22

33
class TestGitBinaryVersion < Test::Unit::TestCase
4-
def windows_mocked_git_binary = <<~GIT_SCRIPT
4+
def mocked_git_script_windows = <<~GIT_SCRIPT
55
@echo off
66
# Loop through the arguments and check for the version command
77
for %%a in (%*) do (
@@ -13,7 +13,7 @@ def windows_mocked_git_binary = <<~GIT_SCRIPT
1313
exit /b 1
1414
GIT_SCRIPT
1515

16-
def linux_mocked_git_binary = <<~GIT_SCRIPT
16+
def mocked_git_script_linux = <<~GIT_SCRIPT
1717
#!/bin/sh
1818
# Loop through the arguments and check for the version command
1919
for arg in "$@"; do
@@ -25,24 +25,28 @@ def linux_mocked_git_binary = <<~GIT_SCRIPT
2525
exit 1
2626
GIT_SCRIPT
2727

28-
def test_binary_version_windows
29-
omit('Only implemented for Windows') unless windows_platform?
28+
def mocked_git_script
29+
if windows_platform?
30+
mocked_git_script_windows
31+
else
32+
mocked_git_script_linux
33+
end
34+
end
3035

36+
def test_binary_version
3137
in_temp_dir do |path|
32-
git_binary_path = File.join(path, 'my_git.bat')
33-
File.write(git_binary_path, windows_mocked_git_binary)
34-
assert_equal([1, 2, 3], Git.binary_version(git_binary_path))
38+
mock_git_binary(mocked_git_script) do |git_binary_path|
39+
assert_equal([1, 2, 3], Git.binary_version(git_binary_path))
40+
end
3541
end
3642
end
3743

38-
def test_binary_version_linux
39-
omit('Only implemented for Linux') if windows_platform?
40-
44+
def test_binary_version_with_spaces
4145
in_temp_dir do |path|
42-
git_binary_path = File.join(path, 'my_git.bat')
43-
File.write(git_binary_path, linux_mocked_git_binary)
44-
File.chmod(0755, git_binary_path)
45-
assert_equal([1, 2, 3], Git.binary_version(git_binary_path))
46+
subdir = 'Git Bin Directory'
47+
mock_git_binary(mocked_git_script, subdir: subdir) do |git_binary_path|
48+
assert_equal([1, 2, 3], Git.binary_version(git_binary_path))
49+
end
4650
end
4751
end
4852

0 commit comments

Comments
 (0)