shell_mock 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -3
- data/README.md +52 -22
- data/lib/shell_mock.rb +20 -13
- data/lib/shell_mock/backtick_monkey_patch.rb +33 -0
- data/lib/shell_mock/call_verifier.rb +21 -21
- data/lib/shell_mock/command_stub.rb +17 -10
- data/lib/shell_mock/exec_monkey_patch.rb +33 -0
- data/lib/shell_mock/monkey_patch.rb +21 -14
- data/lib/shell_mock/monkey_patches.rb +4 -91
- data/lib/shell_mock/spawn_monkey_patch.rb +45 -0
- data/lib/shell_mock/stub_registry.rb +6 -3
- data/lib/shell_mock/system_monkey_patch.rb +33 -0
- data/lib/shell_mock/version.rb +1 -1
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b756c372c9477ca0a21a3894fb4d07c35e87c14e
|
4
|
+
data.tar.gz: 565cb68f40d84a3f2d97ccaa50cad9aa41f16eb1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 40cf06dcafcc3e976cedac4a59623a1d47fc4c4f90f437a149d90f26ef62a3b200b6a342273bdd96036070107fa031d234a34a6fc56b457c9b0be99645257383
|
7
|
+
data.tar.gz: 9cdd1c5d0e1a1d8630aa03506493b2e847ad142fe47b4a56bfd5623522b1e8268369e045ea55fa9518f596b77a002730d3e50b5dc4e1d7597848b4a5e87baf5c
|
data/CHANGELOG.md
CHANGED
@@ -1,12 +1,20 @@
|
|
1
1
|
## ROADMAP 1.0.0
|
2
2
|
|
3
|
-
*
|
4
|
-
*
|
3
|
+
* convert `CommandStub#and_exit` to `CommandStub#will_exit`
|
4
|
+
* convert `CommandStub#and_output` to `CommandStub#will_output`
|
5
|
+
* convert `CommandStub#and_return` to `CommandStub#will_return`
|
6
|
+
* add `CommandStub#will_cause(&blk)` for specifying desired side effects
|
7
|
+
* add `CommandStub#will_stdout(str)` & `CommandStub#will_stderr(str)`. these will work differently for backtick than it will for system & exec.
|
5
8
|
* maybe add `CommandStub#with_stdin(str)` for `spawn`?
|
6
9
|
|
10
|
+
## RELEASE 0.5.0
|
11
|
+
|
12
|
+
* FEATURE: `CommandStub#and_output` can be used on command stubs to set the output of a command without setting the exit status.
|
13
|
+
* ENHANCEMENT: `Kernel#spawn`, `Kernel.spawn`, & `Process.spawn` are now implemented well enough that `Open3.capture3` behaves as though spawn is not being monkey-patched when ShellMock is enabled (and therefore, spawn most definitely is being monkey-patched). This should apply to all of `Open3`'s methods, since they all delegate to `Open3.popen_run` or `Open3.pipeline_run`, both of which internally use `Kernel#spawn`, **however I only have a spec for `Open3.capture3`**.
|
14
|
+
|
7
15
|
## RELEASE 0.4.0
|
8
16
|
|
9
|
-
* FEATURE: `Kernel#spawn` and `Kernel.spawn` are now supported
|
17
|
+
* FEATURE: `Kernel#spawn` and `Kernel.spawn` are now supported
|
10
18
|
|
11
19
|
## RELEASE 0.3.3
|
12
20
|
|
data/README.md
CHANGED
@@ -1,50 +1,80 @@
|
|
1
1
|
# ShellMock
|
2
|
+
[](http://badge.fury.io/rb/shell_mock)
|
3
|
+
[](http://travis-ci.org/yarmiganosca/shell_mock)
|
2
4
|
|
3
5
|
It's [webmock](http://github.com/bblimke/webmock) for shell commands. It's pretty simple. You can do things like this:
|
4
6
|
|
5
7
|
```ruby
|
6
8
|
require 'shell_mock/rspec'
|
7
9
|
|
8
|
-
describe '
|
9
|
-
|
10
|
+
RSpec.describe "shelling out to run 'ls'" do
|
11
|
+
before { ShellMock.enable }
|
12
|
+
after { ShellMock.disable }
|
10
13
|
|
11
|
-
|
14
|
+
let(:stub) { ShellMock.stub_command('ls') }
|
12
15
|
|
13
|
-
|
16
|
+
it "works"
|
17
|
+
expect(system('ls')).to eq true
|
18
|
+
|
19
|
+
expect(stub).to have_been_called
|
20
|
+
end
|
14
21
|
end
|
15
22
|
```
|
16
23
|
|
17
|
-
|
24
|
+
This:
|
25
|
+
1. enables ShellMock's monkey patches during the test
|
26
|
+
2. creates a command stub that will match the command `"ls"` (by default it will exit `0` and have no output)
|
27
|
+
3. shells out to run `"ls"` (in this case using `Kernel#system`)
|
28
|
+
4. correctly expects that our command stub for `"ls"` will have recorded an invocation
|
18
29
|
|
19
|
-
###
|
30
|
+
### You can narrow what invocations are matched to your command stub:
|
20
31
|
|
21
|
-
|
32
|
+
**Match env vars as well as the command:** `ShellMock.stub_command('ls').with_env({'FOO' => 'bar'})`
|
22
33
|
|
23
|
-
|
34
|
+
**Provide a more complete invocation:** `ShellMock.stub_command('ls $HOME')`
|
24
35
|
|
25
|
-
|
36
|
+
Shelling out to run `"ls"` won't match this command stub, but shelling out to run `"ls $HOME"` will. ShellMock always matches as strictly as possible, so if you stubbed `"ls"` and `"ls $HOME"`, invocations of `"ls $HOME'` would only ever match against the latter.
|
26
37
|
|
27
|
-
|
38
|
+
### Setting the behavior of the command invocation:
|
28
39
|
|
29
|
-
|
40
|
+
**Have the mock command invocation write to stdout:** `ShellMock.stub_command('ls').and_output("\n")`
|
30
41
|
|
31
|
-
|
42
|
+
**Set the mock command invocation's exit status:** `ShellMock.stub_command('ls').and_exit(2)`
|
32
43
|
|
33
|
-
|
44
|
+
If you want to both write to stdout and set the exit code (a common pair), `ShellMock.stub_command('ls').and_return("\n")` will both have the command invocation write the passed string to stdout, and will set the mock command invocation's exit status to `0`.
|
34
45
|
|
35
|
-
###
|
46
|
+
### Specifying the expected number of command invocations:
|
36
47
|
|
37
|
-
|
38
|
-
require 'shell_mock/rspec'
|
48
|
+
**Called exactly once:** `expect(stub).to have_been_called.once`
|
39
49
|
|
40
|
-
|
41
|
-
stub = ShellMock.stub_commmand('ls').and_return("\n")
|
50
|
+
**Not called:** `expect(stub).to have_been_called.never`
|
42
51
|
|
43
|
-
|
52
|
+
**Not called (using RSpec expectation negation):** `expect(stub).to_not have_been_called`
|
44
53
|
|
45
|
-
|
46
|
-
|
47
|
-
|
54
|
+
**Called exactly `n` times:** `expect(stub).to have_been_called.times(n)`
|
55
|
+
|
56
|
+
**Called more than `n` times:** `expect(stub).to have_been_called.more_than(n)`
|
57
|
+
|
58
|
+
**Called fewer than `n` times:** `expect(stub).to have_been_called.fewer_than(n)`
|
59
|
+
|
60
|
+
`less_than` can be used as an alias for `fewer_than`
|
61
|
+
## Limitations
|
62
|
+
|
63
|
+
Currently, only exact string matches of the stubbed command string are supported. Basic regex support or more complex matching for arguments and flags may be added later.
|
64
|
+
|
65
|
+
ShellMock supports stubbing these ways of shelling out in Ruby:
|
66
|
+
* [`` Kernel#` ``](https://ruby-doc.org/core/Kernel.html#method-i-60) (aka "backticks")
|
67
|
+
* [`%x` command literal](https://ruby-doc.org/docs/ruby-doc-bundle/Manual/man-1.4/syntax.html#command) (which delegates to backticks)
|
68
|
+
* [`Kernel#system`](https://ruby-doc.org/core/Kernel.html#method-i-system)
|
69
|
+
* [`Kernel#exec`](https://ruby-doc.org/core/Kernel.html#method-i-exec)
|
70
|
+
* [`Kernel#spawn`](https://ruby-doc.org/core/Kernel.html#method-i-spawn)
|
71
|
+
* [`Process.spawn`](https://ruby-doc.org/core/Process.html#method-c-spawn)
|
72
|
+
* [the `Open3` module](https://ruby-doc.org/stdlib/libdoc/open3/rdoc/Open3.html) (since all its methods use `spawn`)
|
73
|
+
|
74
|
+
ShellMock currently DOES NOT support stubbing these ways of shelling out in Ruby (but will):
|
75
|
+
* [`IO.popen`](https://ruby-doc.org/core/IO.html#method-c-popen)
|
76
|
+
* [`PTY.spawn`](https://ruby-doc.org/stdlib/libdoc/pty/rdoc/PTY.html#method-c-spawn)
|
77
|
+
* [passing a string that starts with `"|"`](https://devver.wordpress.com/2009/07/13/a-dozen-or-so-ways-to-start-sub-processes-in-ruby-part-2/) to [`Kernel#open`](https://ruby-doc.org/core/Kernel.html#method-i-open)
|
48
78
|
|
49
79
|
## Installation
|
50
80
|
|
data/lib/shell_mock.rb
CHANGED
@@ -24,32 +24,39 @@ module ShellMock
|
|
24
24
|
@let_commands_run
|
25
25
|
end
|
26
26
|
|
27
|
+
# smell; this is a mistake of a method that will only confuse people
|
27
28
|
def self.dont_let_commands_run?
|
28
29
|
!let_commands_run?
|
29
30
|
end
|
30
31
|
|
31
32
|
def self.enable
|
32
|
-
ShellMock.monkey_patches.each
|
33
|
-
|
34
|
-
|
35
|
-
|
33
|
+
ShellMock.monkey_patches.each(&:enable)
|
34
|
+
|
35
|
+
@enabled = true
|
36
|
+
|
37
|
+
true
|
36
38
|
end
|
37
39
|
|
38
40
|
def self.disable
|
39
|
-
ShellMock.monkey_patches.each
|
40
|
-
patch.disable_for(Kernel.eigenclass) if Kernel.respond_to?(patch.alias_for_original, true)
|
41
|
-
patch.disable_for(Kernel) if Object.new.respond_to?(patch.alias_for_original, true)
|
42
|
-
end
|
41
|
+
ShellMock.monkey_patches.each(&:disable)
|
43
42
|
|
44
43
|
StubRegistry.clear
|
44
|
+
|
45
|
+
@enabled = false
|
46
|
+
|
47
|
+
true
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.enabled?
|
51
|
+
@enabled
|
45
52
|
end
|
46
53
|
|
47
54
|
def self.monkey_patches
|
48
|
-
[
|
49
|
-
SpawnMonkeyPatch,
|
50
|
-
SystemMonkeyPatch,
|
51
|
-
ExecMonkeyPatch,
|
52
|
-
BacktickMonkeyPatch
|
55
|
+
@monkey_patches ||= [
|
56
|
+
SpawnMonkeyPatch.new,
|
57
|
+
SystemMonkeyPatch.new,
|
58
|
+
ExecMonkeyPatch.new,
|
59
|
+
BacktickMonkeyPatch.new,
|
53
60
|
]
|
54
61
|
end
|
55
62
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'shell_mock/monkey_patch'
|
2
|
+
require 'shell_mock/stub_registry'
|
3
|
+
require 'shell_mock/no_stub_specified'
|
4
|
+
|
5
|
+
module ShellMock
|
6
|
+
class BacktickMonkeyPatch < MonkeyPatch
|
7
|
+
def method_name
|
8
|
+
"`"
|
9
|
+
end
|
10
|
+
|
11
|
+
def interpolatable_name
|
12
|
+
:backtick
|
13
|
+
end
|
14
|
+
|
15
|
+
def override(command)
|
16
|
+
stub = StubRegistry.stub_matching({}, command, {})
|
17
|
+
|
18
|
+
if stub
|
19
|
+
stub.called_with({}, command, {})
|
20
|
+
|
21
|
+
stub.side_effect.call
|
22
|
+
|
23
|
+
__un_shell_mocked_backtick(stub.to_oneliner)
|
24
|
+
else
|
25
|
+
if ShellMock.let_commands_run?
|
26
|
+
__un_shell_mocked_backtick(command)
|
27
|
+
else
|
28
|
+
raise NoStubSpecified.new({}, command, {})
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -1,21 +1,26 @@
|
|
1
1
|
module ShellMock
|
2
2
|
class CallVerifier
|
3
3
|
def initialize
|
4
|
-
|
4
|
+
more_than(0)
|
5
5
|
end
|
6
6
|
|
7
|
-
def
|
8
|
-
|
7
|
+
def times(n)
|
8
|
+
match_calls_when { |calls| calls == n }
|
9
9
|
|
10
|
-
|
10
|
+
self
|
11
11
|
end
|
12
12
|
|
13
|
-
def
|
14
|
-
|
13
|
+
def fewer_than(n)
|
14
|
+
match_calls_when { |calls| calls < n }
|
15
|
+
|
16
|
+
self
|
15
17
|
end
|
18
|
+
alias less_than fewer_than
|
16
19
|
|
17
|
-
def
|
18
|
-
|
20
|
+
def more_than(n)
|
21
|
+
match_calls_when { |calls| calls > n }
|
22
|
+
|
23
|
+
self
|
19
24
|
end
|
20
25
|
|
21
26
|
def once
|
@@ -26,28 +31,23 @@ module ShellMock
|
|
26
31
|
times(0)
|
27
32
|
end
|
28
33
|
|
29
|
-
def
|
30
|
-
|
34
|
+
def matches?(command_stub)
|
35
|
+
@command_stub = command_stub
|
31
36
|
|
32
|
-
|
37
|
+
condition.call(command_stub.calls)
|
33
38
|
end
|
34
39
|
|
35
|
-
def
|
36
|
-
|
37
|
-
|
38
|
-
self
|
40
|
+
def failure_message
|
41
|
+
"#{command_stub.command} was expected."
|
39
42
|
end
|
40
|
-
alias less_than fewer_than
|
41
|
-
|
42
|
-
def more_than(n)
|
43
|
-
match_calls_when { |calls| calls.size > n }
|
44
43
|
|
45
|
-
|
44
|
+
def failure_message_when_negated
|
45
|
+
"#{command_stub.command} was not expected."
|
46
46
|
end
|
47
47
|
|
48
48
|
private
|
49
49
|
|
50
|
-
attr_reader :
|
50
|
+
attr_reader :command_stub, :condition
|
51
51
|
|
52
52
|
def match_calls_when(&blk)
|
53
53
|
@condition = blk
|
@@ -3,7 +3,7 @@ require 'shell_mock/stub_registry'
|
|
3
3
|
|
4
4
|
module ShellMock
|
5
5
|
class CommandStub
|
6
|
-
attr_reader :command, :
|
6
|
+
attr_reader :command, :output, :exitstatus, :env, :options, :side_effect
|
7
7
|
|
8
8
|
def initialize(command)
|
9
9
|
@command = command
|
@@ -21,19 +21,24 @@ module ShellMock
|
|
21
21
|
self
|
22
22
|
end
|
23
23
|
|
24
|
-
def
|
24
|
+
def with_options(options)
|
25
25
|
@options = options
|
26
26
|
|
27
27
|
self
|
28
28
|
end
|
29
29
|
|
30
|
-
def
|
31
|
-
@
|
32
|
-
@exitstatus = 0
|
30
|
+
def and_output(output)
|
31
|
+
@output = output
|
33
32
|
|
34
33
|
self
|
35
34
|
end
|
36
35
|
|
36
|
+
def and_return(output)
|
37
|
+
self.
|
38
|
+
and_output(output).
|
39
|
+
and_exit(0)
|
40
|
+
end
|
41
|
+
|
37
42
|
def and_exit(exitstatus)
|
38
43
|
@exitstatus = exitstatus
|
39
44
|
|
@@ -41,24 +46,26 @@ module ShellMock
|
|
41
46
|
end
|
42
47
|
|
43
48
|
def calls
|
44
|
-
@calls ||=
|
49
|
+
@calls ||= 0
|
45
50
|
|
46
51
|
marshaled_signatures.each do |marshaled_signature|
|
47
|
-
@calls
|
52
|
+
@calls += 1
|
48
53
|
end
|
49
54
|
|
50
55
|
@calls
|
51
56
|
end
|
52
57
|
|
53
58
|
def called_with(env, command, options)
|
54
|
-
|
59
|
+
writer.puts("called\n")
|
60
|
+
end
|
55
61
|
|
56
|
-
|
62
|
+
def to_oneliner
|
63
|
+
"echo '#{output}' && exit #{exitstatus}"
|
57
64
|
end
|
58
65
|
|
59
66
|
private
|
60
67
|
|
61
|
-
attr_reader :reader
|
68
|
+
attr_reader :reader, :writer
|
62
69
|
|
63
70
|
def marshaled_signatures
|
64
71
|
messages = ""
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'shell_mock/monkey_patch'
|
2
|
+
require 'shell_mock/stub_registry'
|
3
|
+
require 'shell_mock/no_stub_specified'
|
4
|
+
|
5
|
+
module ShellMock
|
6
|
+
class ExecMonkeyPatch < MonkeyPatch
|
7
|
+
def method_name
|
8
|
+
:exec
|
9
|
+
end
|
10
|
+
|
11
|
+
def override(env, command = nil, **options)
|
12
|
+
env, command = {}, env if command.nil?
|
13
|
+
|
14
|
+
# other arg manipulation can go here if necessary
|
15
|
+
|
16
|
+
stub = StubRegistry.stub_matching(env, command, options)
|
17
|
+
|
18
|
+
if stub
|
19
|
+
stub.called_with(env, command, options)
|
20
|
+
|
21
|
+
stub.side_effect.call
|
22
|
+
|
23
|
+
__un_shell_mocked_exec(stub.to_oneliner)
|
24
|
+
else
|
25
|
+
if ShellMock.let_commands_run?
|
26
|
+
__un_shell_mocked_exec(env, command, **options)
|
27
|
+
else
|
28
|
+
raise NoStubSpecified.new(env, command, options)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -2,42 +2,49 @@ require 'shell_mock/no_stub_specified'
|
|
2
2
|
|
3
3
|
module ShellMock
|
4
4
|
class MonkeyPatch
|
5
|
-
|
5
|
+
def enable
|
6
|
+
enable_for(Kernel.eigenclass) unless Kernel.respond_to?(method_alias, true)
|
7
|
+
enable_for(Kernel) unless Object.new.respond_to?(method_alias, true)
|
8
|
+
end
|
9
|
+
|
10
|
+
def disable
|
11
|
+
disable_for(Kernel.eigenclass) if Kernel.respond_to?(method_alias, true)
|
12
|
+
disable_for(Kernel) if Object.new.respond_to?(method_alias, true)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
6
16
|
|
7
|
-
def
|
8
|
-
|
9
|
-
@alias_for_original = "__un_shell_mocked_#{interpolatable_name}"
|
10
|
-
@replacement = "__shell_mocked_#{interpolatable_name}"
|
11
|
-
@block = block
|
17
|
+
def method_alias
|
18
|
+
"__un_shell_mocked_#{interpolatable_name}"
|
12
19
|
end
|
13
20
|
|
14
|
-
def
|
15
|
-
|
21
|
+
def interpolatable_name
|
22
|
+
method_name
|
16
23
|
end
|
17
24
|
|
18
25
|
def enable_for(class_or_module)
|
19
|
-
class_or_module.send(:alias_method,
|
26
|
+
class_or_module.send(:alias_method, method_alias, method_name)
|
20
27
|
|
21
28
|
begin
|
22
29
|
# so we don't have to see method redefinition warnings
|
23
|
-
class_or_module.send(:remove_method,
|
30
|
+
class_or_module.send(:remove_method, method_name)
|
24
31
|
rescue NameError
|
25
32
|
end
|
26
33
|
|
27
|
-
class_or_module.send(:define_method,
|
34
|
+
class_or_module.send(:define_method, method_name, &method(:override))
|
28
35
|
end
|
29
36
|
|
30
37
|
def disable_for(class_or_module)
|
31
38
|
begin
|
32
39
|
# so we don't have to see method redefinition warnings
|
33
|
-
class_or_module.send(:remove_method,
|
40
|
+
class_or_module.send(:remove_method, method_name)
|
34
41
|
rescue NameError
|
35
42
|
end
|
36
43
|
|
37
|
-
class_or_module.send(:alias_method,
|
44
|
+
class_or_module.send(:alias_method, method_name, method_alias)
|
38
45
|
|
39
46
|
begin
|
40
|
-
class_or_module.send(:remove_method,
|
47
|
+
class_or_module.send(:remove_method, method_alias)
|
41
48
|
rescue NameError
|
42
49
|
end
|
43
50
|
end
|
@@ -1,91 +1,4 @@
|
|
1
|
-
require 'shell_mock/
|
2
|
-
require 'shell_mock/
|
3
|
-
require 'shell_mock/
|
4
|
-
|
5
|
-
module ShellMock
|
6
|
-
SpawnMonkeyPatch = MonkeyPatch.new(:spawn) do |env, command = nil, **options|
|
7
|
-
env, command = {}, env if command.nil?
|
8
|
-
|
9
|
-
# other arg manipulation can go here if necessary
|
10
|
-
|
11
|
-
stub = StubRegistry.stub_matching(env, command, options)
|
12
|
-
|
13
|
-
if stub
|
14
|
-
stub.side_effect.call
|
15
|
-
stub.called_with(env, command, options)
|
16
|
-
|
17
|
-
__un_shell_mocked_spawn("exit #{stub.exitstatus}")
|
18
|
-
else
|
19
|
-
if ShellMock.let_commands_run?
|
20
|
-
__un_shell_mocked_spawn(env, command, **options)
|
21
|
-
else
|
22
|
-
raise NoStubSpecified.new(env, command, options)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
SystemMonkeyPatch = MonkeyPatch.new(:system) do |env, command = nil, **options|
|
28
|
-
env, command = {}, env if command.nil?
|
29
|
-
|
30
|
-
# other arg manipulation can go here if necessary
|
31
|
-
|
32
|
-
stub = StubRegistry.stub_matching(env, command, options)
|
33
|
-
|
34
|
-
if stub
|
35
|
-
stub.side_effect.call
|
36
|
-
stub.called_with(env, command, options)
|
37
|
-
__un_shell_mocked_backtick("exit #{stub.exitstatus}")
|
38
|
-
|
39
|
-
return stub.exitstatus == 0
|
40
|
-
else
|
41
|
-
if ShellMock.let_commands_run?
|
42
|
-
__un_shell_mocked_system(env, command, **options)
|
43
|
-
else
|
44
|
-
raise NoStubSpecified.new(env, command, options)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
# This feels very boilerplatey because Kernel::system and Kernel::exec
|
50
|
-
# have very similar if not identical method signatures. I'm not sure
|
51
|
-
# whether extracting the commonalities would be worth it or would just
|
52
|
-
# confuse.
|
53
|
-
ExecMonkeyPatch = MonkeyPatch.new(:exec) do |env, command = nil, **options|
|
54
|
-
env, command = {}, env if command.nil?
|
55
|
-
|
56
|
-
# other arg manipulation can go here if necessary
|
57
|
-
|
58
|
-
stub = StubRegistry.stub_matching(env, command, options)
|
59
|
-
|
60
|
-
if stub
|
61
|
-
stub.side_effect.call
|
62
|
-
stub.called_with(env, command, options)
|
63
|
-
|
64
|
-
exit stub.exitstatus
|
65
|
-
else
|
66
|
-
if ShellMock.let_commands_run?
|
67
|
-
__un_shell_mocked_exec(env, command, **options)
|
68
|
-
else
|
69
|
-
raise NoStubSpecified.new(env, command, options)
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
BacktickMonkeyPatch = MonkeyPatch.new('`', :backtick) do |command|
|
75
|
-
stub = StubRegistry.stub_matching({}, command, {})
|
76
|
-
|
77
|
-
if stub
|
78
|
-
stub.side_effect.call
|
79
|
-
stub.called_with({}, command, {})
|
80
|
-
__un_shell_mocked_backtick("exit #{stub.exitstatus}")
|
81
|
-
|
82
|
-
return stub.expected_output
|
83
|
-
else
|
84
|
-
if ShellMock.let_commands_run?
|
85
|
-
__un_shell_mocked_backtick(command)
|
86
|
-
else
|
87
|
-
raise NoStubSpecified.new({}, command, {})
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
1
|
+
require 'shell_mock/spawn_monkey_patch'
|
2
|
+
require 'shell_mock/system_monkey_patch'
|
3
|
+
require 'shell_mock/backtick_monkey_patch'
|
4
|
+
require 'shell_mock/exec_monkey_patch'
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'shell_mock/monkey_patch'
|
2
|
+
require 'shell_mock/stub_registry'
|
3
|
+
require 'shell_mock/no_stub_specified'
|
4
|
+
|
5
|
+
module ShellMock
|
6
|
+
class SpawnMonkeyPatch < MonkeyPatch
|
7
|
+
def method_name
|
8
|
+
:spawn
|
9
|
+
end
|
10
|
+
|
11
|
+
def override(env, command = nil, **options)
|
12
|
+
env, command = {}, env if command.nil?
|
13
|
+
|
14
|
+
# other arg manipulation can go here if necessary
|
15
|
+
|
16
|
+
stub = StubRegistry.stub_matching(env, command, options)
|
17
|
+
|
18
|
+
if stub
|
19
|
+
stub.called_with(env, command, options)
|
20
|
+
|
21
|
+
stub.side_effect.call
|
22
|
+
|
23
|
+
__un_shell_mocked_spawn(stub.to_oneliner, **options)
|
24
|
+
else
|
25
|
+
if ShellMock.let_commands_run?
|
26
|
+
__un_shell_mocked_spawn(env, command, **options)
|
27
|
+
else
|
28
|
+
raise NoStubSpecified.new(env, command, options)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def enable
|
34
|
+
enable_for(Process.eigenclass) unless Process.respond_to?(method_alias, true)
|
35
|
+
|
36
|
+
super
|
37
|
+
end
|
38
|
+
|
39
|
+
def disable
|
40
|
+
super
|
41
|
+
|
42
|
+
disable_for(Process.eigenclass) if Process.respond_to?(method_alias, true)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -9,11 +9,14 @@ module ShellMock
|
|
9
9
|
|
10
10
|
def stub_matching(env, command, options)
|
11
11
|
matching_stubs = command_stubs.select do |command_stub|
|
12
|
-
command_stub.
|
13
|
-
command_stub.
|
14
|
-
command_stub.
|
12
|
+
command_stub.command == command &&
|
13
|
+
command_stub.env <= env &&
|
14
|
+
command_stub.options <= options
|
15
15
|
end
|
16
16
|
|
17
|
+
# question: Should we increment all the stubs that match?
|
18
|
+
# What should users expect when they register a stub that
|
19
|
+
# wholly "covers" another already-registered stub?
|
17
20
|
matching_stubs.max_by do |command_stub|
|
18
21
|
[env.size, options.size]
|
19
22
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'shell_mock/monkey_patch'
|
2
|
+
require 'shell_mock/stub_registry'
|
3
|
+
require 'shell_mock/no_stub_specified'
|
4
|
+
|
5
|
+
module ShellMock
|
6
|
+
class SystemMonkeyPatch < MonkeyPatch
|
7
|
+
def method_name
|
8
|
+
:system
|
9
|
+
end
|
10
|
+
|
11
|
+
def override(env, command = nil, **options)
|
12
|
+
env, command = {}, env if command.nil?
|
13
|
+
|
14
|
+
# other arg manipulation can go here if necessary
|
15
|
+
|
16
|
+
stub = StubRegistry.stub_matching(env, command, options)
|
17
|
+
|
18
|
+
if stub
|
19
|
+
stub.called_with(env, command, options)
|
20
|
+
|
21
|
+
stub.side_effect.call
|
22
|
+
|
23
|
+
__un_shell_mocked_system(stub.to_oneliner)
|
24
|
+
else
|
25
|
+
if ShellMock.let_commands_run?
|
26
|
+
__un_shell_mocked_system(env, command, **options)
|
27
|
+
else
|
28
|
+
raise NoStubSpecified.new(env, command, options)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/shell_mock/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shell_mock
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Hoffman
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-09-
|
11
|
+
date: 2018-09-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -114,15 +114,19 @@ files:
|
|
114
114
|
- bin/console
|
115
115
|
- bin/setup
|
116
116
|
- lib/shell_mock.rb
|
117
|
+
- lib/shell_mock/backtick_monkey_patch.rb
|
117
118
|
- lib/shell_mock/call_verifier.rb
|
118
119
|
- lib/shell_mock/command_stub.rb
|
119
120
|
- lib/shell_mock/core_ext/module.rb
|
121
|
+
- lib/shell_mock/exec_monkey_patch.rb
|
120
122
|
- lib/shell_mock/monkey_patch.rb
|
121
123
|
- lib/shell_mock/monkey_patches.rb
|
122
124
|
- lib/shell_mock/no_stub_specified.rb
|
123
125
|
- lib/shell_mock/rspec.rb
|
124
126
|
- lib/shell_mock/rspec/matchers.rb
|
127
|
+
- lib/shell_mock/spawn_monkey_patch.rb
|
125
128
|
- lib/shell_mock/stub_registry.rb
|
129
|
+
- lib/shell_mock/system_monkey_patch.rb
|
126
130
|
- lib/shell_mock/version.rb
|
127
131
|
- shell_mock.gemspec
|
128
132
|
homepage: http://www.github.com/yarmiganosca/shell_mock
|