summaryrefslogtreecommitdiff
path: root/spec/ruby/core/kernel/system_spec.rb
blob: c6bc4416e78729617e611e19fcb354df93f03fa5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
require File.expand_path('../../../spec_helper', __FILE__)
require File.expand_path('../fixtures/classes', __FILE__)

describe :kernel_system, shared: true do
  it "executes the specified command in a subprocess" do
    lambda { @object.system("echo a") }.should output_to_fd("a\n")

    $?.should be_an_instance_of Process::Status
    $?.success?.should == true
  end

  it "returns true when the command exits with a zero exit status" do
    @object.system(ruby_cmd('exit 0')).should == true

    $?.should be_an_instance_of Process::Status
    $?.success?.should == true
    $?.exitstatus.should == 0
  end

  it "returns false when the command exits with a non-zero exit status" do
    @object.system(ruby_cmd('exit 1')).should == false

    $?.should be_an_instance_of Process::Status
    $?.success?.should == false
    $?.exitstatus.should == 1
  end

  ruby_version_is "2.6" do
    it "raises RuntimeError when `exception: true` is given and the command exits with a non-zero exit status" do
      lambda { @object.system(ruby_cmd('exit 1'), exception: true) }.should raise_error(RuntimeError)
    end

    it "raises Errno::ENOENT when `exception: true` is given and the specified command does not exist" do
      lambda { @object.system('feature_14386', exception: true) }.should raise_error(Errno::ENOENT)
    end
  end

  it "returns nil when command execution fails" do
    @object.system("sad").should be_nil

    $?.should be_an_instance_of Process::Status
    $?.pid.should be_kind_of(Integer)
    $?.exitstatus.should == 127
  end

  it "does not write to stderr when command execution fails" do
    lambda { @object.system("sad") }.should output_to_fd("", STDERR)
  end

  platform_is_not :windows do
    before :each do
      @shell = ENV['SHELL']
    end

    after :each do
      ENV['SHELL'] = @shell
    end

    it "executes with `sh` if the command contains shell characters" do
      lambda { @object.system("echo $0") }.should output_to_fd("sh\n")
    end

    it "ignores SHELL env var and always uses `sh`" do
      ENV['SHELL'] = "/bin/fakeshell"
      lambda { @object.system("echo $0") }.should output_to_fd("sh\n")
    end
  end

  before :each do
    ENV['TEST_SH_EXPANSION'] = 'foo'
    @shell_var = '$TEST_SH_EXPANSION'
    platform_is :windows do
      @shell_var = '%TEST_SH_EXPANSION%'
    end
  end

  after :each do
    ENV.delete('TEST_SH_EXPANSION')
  end

  it "expands shell variables when given a single string argument" do
    lambda { @object.system("echo #{@shell_var}") }.should output_to_fd("foo\n")
  end

  platform_is_not :windows do
    it "does not expand shell variables when given multiples arguments" do
      lambda { @object.system("echo", @shell_var) }.should output_to_fd("#{@shell_var}\n")
    end
  end

  platform_is :windows do
    it "does expand shell variables when given multiples arguments" do
      # See https://bugs.ruby-lang.org/issues/12231
      lambda { @object.system("echo", @shell_var) }.should output_to_fd("foo\n")
    end
  end

  platform_is :windows do
    it "runs commands starting with any number of @ using shell" do
      `#{ruby_cmd("p system 'does_not_exist'")} 2>NUL`.chomp.should == "nil"
      @object.system('@does_not_exist 2>NUL').should == false
      @object.system("@@@#{ruby_cmd('exit 0')}").should == true
    end
  end
end

describe "Kernel#system" do
  it "is a private method" do
    Kernel.should have_private_instance_method(:system)
  end

  it_behaves_like :kernel_system, :system, KernelSpecs::Method.new
end

describe "Kernel.system" do
  it_behaves_like :kernel_system, :system, Kernel
end