Skip to content

Commit 4df1548

Browse files
Add specs for Process.run (#16306)
The tested behaviours differ greatly between platforms. So there are lots of flag-based skips. And I'm not sure these specs work 100% correctly on all platforms. Besides the typical CI machines, I've only tested it on FreeBSD. We still need specs even for this platform-specific behaviour to ensure the aspects that we control in our system bindings are correct (e.g. #6464). The `$PATH` related specs are also a preparation for implementing a native fallback for `execvpe`.
1 parent afbb875 commit 4df1548

File tree

1 file changed

+109
-0
lines changed

1 file changed

+109
-0
lines changed

spec/std/process_spec.cr

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,14 @@ private def standing_command
4646
{% end %}
4747
end
4848

49+
private def path_search_command
50+
{% if flag?(:win32) %}
51+
{"cmd.exe"}
52+
{% else %}
53+
{"true"}
54+
{% end %}
55+
end
56+
4957
private def newline
5058
{% if flag?(:win32) %}
5159
"\r\n"
@@ -379,6 +387,107 @@ describe Process do
379387
end
380388
end
381389
{% end %}
390+
391+
if {{ flag?(:win32) }}
392+
it "finds binary in parent `$PATH`, not `env`" do
393+
Process.run(*print_env_command, env: {"PATH" => ""})
394+
end
395+
else
396+
# FIXME: This behaviour is incorrect. It should lookup the command in
397+
# the parent process' `$PATH`, without any changes from `env`.
398+
# https://github.com/crystal-lang/crystal/issues/6464#issuecomment-3391000914
399+
it "finds binary in `env`" do
400+
expect_raises(File::NotFoundError) do
401+
Process.run(*print_env_command, env: {"PATH" => ""})
402+
end
403+
end
404+
end
405+
406+
it "errors on invalid key" do
407+
{% begin %}
408+
expect_raises({% if flag?(:win32) %}ArgumentError, "Invalid env key" {% else %} RuntimeError, "Invalid argument"{% end %}) do
409+
Process.run(*print_env_command, env: {"" => "baz"})
410+
end
411+
expect_raises({% if flag?(:win32) %}ArgumentError, "Invalid env key" {% else %} RuntimeError, "Invalid argument"{% end %}) do
412+
Process.run(*print_env_command, env: {"foo=bar" => "baz"})
413+
end
414+
{% end %}
415+
end
416+
417+
it "errors on zero char in key" do
418+
expect_raises({{ flag?(:win32) }} ? ArgumentError : RuntimeError, "String `key` contains null byte") do
419+
Process.run(*print_env_command, env: {"foo\0" => "baz"})
420+
end
421+
end
422+
423+
it "errors on zero char in value" do
424+
expect_raises({{ flag?(:win32) }} ? ArgumentError : RuntimeError, "String `value` contains null byte") do
425+
Process.run(*print_env_command, env: {"foo" => "baz\0"})
426+
end
427+
end
428+
end
429+
430+
it "errors with empty command" do
431+
{% begin %}
432+
expect_raises({% if flag?(:win32) %} IO::Error, "The parameter is incorrect" {% else %} File::NotFoundError{% end %}) do
433+
Process.run("")
434+
end
435+
{% end %}
436+
end
437+
438+
it "errors with too long command" do
439+
pending! unless {{ flag?(:linux) }}
440+
441+
path_max = {% if LibC.has_constant?(:PATH_MAX) %}
442+
LibC::PATH_MAX
443+
{% else %}
444+
10_000
445+
{% end %}
446+
447+
expect_raises(IO::Error, /File ?name too long/) do
448+
Process.run("a" * (path_max + 1))
449+
end
450+
451+
# The pathname itself is not too long, but it will be when combined with
452+
# any path prefix.
453+
expect_raises(IO::Error, /File ?name too long/) do
454+
Process.run("a" * path_max)
455+
end
456+
end
457+
458+
describe "$PATH" do
459+
it "works with unset $PATH" do
460+
with_env("PATH": nil) do
461+
Process.run(*path_search_command)
462+
end
463+
end
464+
465+
it "errors with empty $PATH" do
466+
pending! if {{ flag?(:win32) }}
467+
with_env("PATH": "") do
468+
expect_raises(File::NotFoundError) do
469+
Process.run(*path_search_command)
470+
end
471+
end
472+
end
473+
474+
it "empty path entry means current directory" do
475+
pending! unless {{ flag?(:unix) }}
476+
477+
with_tempfile("crystal-spec-run") do |dir|
478+
Dir.mkdir dir
479+
File.write(Path[dir, "foo"], "#!/bin/sh\necho bar")
480+
File.chmod(Path[dir, "foo"], 0o555)
481+
unless {{ flag?(:darwin) }}
482+
expect_raises(File::NotFoundError) do
483+
Process.run("foo", chdir: dir)
484+
end
485+
end
486+
with_env("PATH": ":") do
487+
Process.run("foo", chdir: dir)
488+
end
489+
end
490+
end
382491
end
383492

384493
it "can link processes together" do

0 commit comments

Comments
 (0)