scmd 3.0.0 → 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ data.tar.gz: 41ab93becdd3b11aa43cf2b7465bb06740176732
4
+ metadata.gz: d8df11392ad93610a721cdfb7c85aa4a2bc3b0a2
5
+ SHA512:
6
+ data.tar.gz: c069015a2af2701ac855f12384c2941b39ede49b7e89b9157a83be6214b83034106405a1ad0c52fc016007b65a4d3ced67cb118008a6d7c0fa5cbf56fa3eb0ed
7
+ metadata.gz: cce48d3004f825e93f42b5e1a397ed5c7dbaff2a4fddcfce0e8acba3586b56286ba9a3dd7952136b73aacdb2eb51cd9ebf3435d35719dfc2cc0384a87193fec6
data/README.md CHANGED
@@ -121,6 +121,71 @@ reader.gets # => "test\n"
121
121
 
122
122
  For all the possible options see [posix-spawn](https://github.com/rtomayko/posix-spawn#status).
123
123
 
124
+ ## Testing
125
+
126
+ Scmd comes with some testing utilities built in. Specifically this includes a command spy and a "test mode" API on the main `Scmd` namespace.
127
+
128
+ ### Command Spy
129
+
130
+ ```ruby
131
+ require 'scmd/command_spy'
132
+ spy = Scmd::CommandSpy.new(cmd_str)
133
+ spy.exitstatus = 1
134
+ spy.stdout = 'some test output'
135
+ Assert.stub(Scmd, :new).with(cmd_str){ spy }
136
+
137
+ cmd = Scmd.new(cmd_str) # => spy
138
+ cmd.run('some input')
139
+
140
+ cmd.run_called? # => true
141
+ cmd.run_calls.size # => 1
142
+ cmd.run_calls.first.input # => 'some input'
143
+ ```
144
+
145
+ The spy is useful for stubbing out system commands that you don't want to call or aren't safe to call in the test suite. It responds to the same API that commands do but doesn't run any system commands.
146
+
147
+ ### "Test Mode" API
148
+
149
+ ```ruby
150
+ Scmd.add_command(cmd_str){ |cmd| cmd.stdout = 'some output' } # => raises NoMethodError
151
+
152
+ ENV['SCMD_TEST_MODE'] = '1'
153
+ Scmd.add_command(cmd_str){ |cmd| cmd.stdout = 'some output' }
154
+ Scmd.add_command(cmd_str).with({:env => { :SOME_ENV_VAR => '1' }}) do |cmd|
155
+ cmd.stdout = 'some other output'
156
+ end
157
+ Scmd.commands.empty? # => false
158
+
159
+ cmd = Scmd.new(cmd_str)
160
+ cmd.class # => Scmd::CommandSpy
161
+ cmd.stdout # => 'some output'
162
+ cmd.run('some input')
163
+ Scmd.calls.size # => 1
164
+ Scmd.calls.last.class # => Scmd::Call
165
+ Scmd.calls.last.cmd_str # => cmd_str
166
+ Scmd.calls.last.input # => 'some input'
167
+ Scmd.calls.last.cmd.class # => Scmd::CommandSpy
168
+
169
+ cmd = Scmd.new(cmd_str, {:env => { 'SOME_ENV_VAR' => '1' }})
170
+ cmd.class # => Scmd::CommandSpy
171
+ cmd.stdout # => 'some other output'
172
+ cmd.run('some input')
173
+ Scmd.calls.size # => 2
174
+ Scmd.calls.last.class # => Scmd::Call
175
+ Scmd.calls.last.cmd_str # => cmd_str
176
+ Scmd.calls.last.input # => 'some input'
177
+ Scmd.calls.last.cmd.class # => Scmd::CommandSpy
178
+ Scmd.calls.last.cmd.env # => { 'SOME_ENV_VAR' => '1' }
179
+
180
+ Scmd.reset
181
+ Scmd.commands.empty? # => true
182
+ Scmd.calls.empty? # => true
183
+ ```
184
+
185
+ Use these singleton methods on the `Scmd` namespace to add specific command spies in specific contexts and to track command calls (runs, starts). Use `reset` to reset the state of things.
186
+
187
+ **Note:** these methods are only available when test mode is enabled (when the `SCMD_TEST_MODE` env var has a non-falsey value). Otherwise these methods will raise `NoMethodError`.
188
+
124
189
  ## Installation
125
190
 
126
191
  Add this line to your application's Gemfile:
@@ -3,8 +3,46 @@ require 'scmd/command'
3
3
 
4
4
  module Scmd
5
5
 
6
- def self.new(*args, &block)
7
- Command.new(*args, &block)
6
+ # Scmd can be run in "test mode". This means that command spies will be used
7
+ # in place of "live" commands, each time a command is run or started will be
8
+ # logged in a collection and option-specific spies can be added and used to
9
+ # "stub" spies with specific attributes in specific contexts.
10
+
11
+ def self.new(*args)
12
+ if !ENV['SCMD_TEST_MODE']
13
+ Command.new(*args)
14
+ else
15
+ self.commands.get(*args)
16
+ end
17
+ end
18
+
19
+ def self.commands
20
+ raise NoMethodError if !ENV['SCMD_TEST_MODE']
21
+ @commands ||= begin
22
+ require 'scmd/stored_commands'
23
+ StoredCommands.new
24
+ end
25
+ end
26
+
27
+ def self.calls
28
+ raise NoMethodError if !ENV['SCMD_TEST_MODE']
29
+ @calls ||= []
30
+ end
31
+
32
+ def self.reset
33
+ raise NoMethodError if !ENV['SCMD_TEST_MODE']
34
+ self.calls.clear
35
+ self.commands.remove_all
36
+ end
37
+
38
+ def self.add_command(cmd_str, &block)
39
+ self.commands.add(cmd_str, &block)
40
+ end
41
+
42
+ class Call < Struct.new(:cmd_str, :input, :cmd)
43
+ def initialize(cmd_spy, input)
44
+ super(cmd_spy.cmd_str, input, cmd_spy)
45
+ end
8
46
  end
9
47
 
10
48
  TimeoutError = Class.new(::RuntimeError)
@@ -88,10 +88,10 @@ module Scmd
88
88
  end
89
89
  end
90
90
 
91
- def kill(sig = nil)
91
+ def kill(signal = nil)
92
92
  return if !running?
93
93
 
94
- send_kill(sig)
94
+ send_kill(signal)
95
95
  wait # indefinitely until cmd is killed
96
96
  end
97
97
 
@@ -148,8 +148,8 @@ module Scmd
148
148
  send_signal 'TERM'
149
149
  end
150
150
 
151
- def send_kill(sig = nil)
152
- send_signal(sig || 'KILL')
151
+ def send_kill(signal = nil)
152
+ send_signal(signal || 'KILL')
153
153
  end
154
154
 
155
155
  def send_signal(sig)
@@ -0,0 +1,121 @@
1
+ require 'scmd'
2
+
3
+ module Scmd
4
+
5
+ class CommandSpy
6
+
7
+ attr_reader :cmd_str, :env, :options
8
+ attr_reader :run_calls, :run_bang_calls, :start_calls
9
+ attr_reader :wait_calls, :stop_calls, :kill_calls
10
+ attr_accessor :pid, :exitstatus, :stdout, :stderr
11
+
12
+ def initialize(cmd_str, opts = nil)
13
+ opts ||= {}
14
+ @cmd_str = cmd_str
15
+ @env = opts[:env]
16
+ @options = opts[:options]
17
+
18
+ @run_calls, @run_bang_calls, @start_calls = [], [], []
19
+ @wait_calls, @stop_calls, @kill_calls = [], [], []
20
+
21
+ @running = false
22
+
23
+ @stdout, @stderr, @pid, @exitstatus = '', '', 1, 0
24
+ end
25
+
26
+ def run(input = nil)
27
+ @run_calls.push(InputCall.new(input))
28
+ Scmd.calls.push(Scmd::Call.new(self, input))
29
+ self
30
+ end
31
+
32
+ def run_called?
33
+ !@run_calls.empty?
34
+ end
35
+
36
+ def run!(input = nil)
37
+ @run_bang_calls.push(InputCall.new(input))
38
+ Scmd.calls.push(Scmd::Call.new(self, input))
39
+ self
40
+ end
41
+
42
+ def run_bang_called?
43
+ !@run_bang_calls.empty?
44
+ end
45
+
46
+ def start(input = nil)
47
+ @start_calls.push(InputCall.new(input))
48
+ Scmd.calls.push(Scmd::Call.new(self, input))
49
+ @running = true
50
+ end
51
+
52
+ def start_called?
53
+ !@start_calls.empty?
54
+ end
55
+
56
+ def wait(timeout = nil)
57
+ @wait_calls.push(TimeoutCall.new(timeout))
58
+ @running = false
59
+ end
60
+
61
+ def wait_called?
62
+ !@wait_calls.empty?
63
+ end
64
+
65
+ def stop(timeout = nil)
66
+ @stop_calls.push(TimeoutCall.new(timeout))
67
+ @running = false
68
+ end
69
+
70
+ def stop_called?
71
+ !@stop_calls.empty?
72
+ end
73
+
74
+ def kill(signal = nil)
75
+ @kill_calls.push(SignalCall.new(signal))
76
+ @running = false
77
+ end
78
+
79
+ def kill_called?
80
+ !@kill_calls.empty?
81
+ end
82
+
83
+ def running?
84
+ !!@running
85
+ end
86
+
87
+ def success?
88
+ @exitstatus == 0
89
+ end
90
+
91
+ def to_s
92
+ @cmd_str.to_s
93
+ end
94
+
95
+ def ==(other_spy)
96
+ if other_spy.kind_of?(CommandSpy)
97
+ self.cmd_str == other_spy.cmd_str &&
98
+ self.env == other_spy.env &&
99
+ self.options == other_spy.options &&
100
+ self.run_calls == other_spy.run_calls &&
101
+ self.run_bang_calls == other_spy.run_bang_calls &&
102
+ self.start_calls == other_spy.start_calls &&
103
+ self.wait_calls == other_spy.wait_calls &&
104
+ self.stop_calls == other_spy.stop_calls &&
105
+ self.kill_calls == other_spy.kill_calls &&
106
+ self.pid == other_spy.pid &&
107
+ self.exitstatus == other_spy.exitstatus &&
108
+ self.stdout == other_spy.stdout &&
109
+ self.stderr == other_spy.stderr
110
+ else
111
+ super
112
+ end
113
+ end
114
+
115
+ InputCall = Struct.new(:input)
116
+ TimeoutCall = Struct.new(:timeout)
117
+ SignalCall = Struct.new(:signal)
118
+
119
+ end
120
+
121
+ end
@@ -0,0 +1,78 @@
1
+ require 'scmd/command_spy'
2
+
3
+ module Scmd
4
+
5
+ class StoredCommands
6
+
7
+ attr_reader :hash
8
+
9
+ def initialize
10
+ @hash = Hash.new{ |h, k| h[k] = Stub.new(k) }
11
+ end
12
+
13
+ def add(cmd_str, &block)
14
+ @hash[cmd_str].tap{ |s| s.set_default_proc(&block) }
15
+ end
16
+
17
+ def get(cmd_str, opts = nil)
18
+ @hash[cmd_str].call(opts)
19
+ end
20
+
21
+ def remove(cmd_str)
22
+ @hash.delete(cmd_str)
23
+ end
24
+
25
+ def remove_all
26
+ @hash.clear
27
+ end
28
+
29
+ def empty?
30
+ @hash.empty?
31
+ end
32
+
33
+ def ==(other_stored_commands)
34
+ if other_stored_commands.kind_of?(StoredCommands)
35
+ self.hash == other_stored_commands.hash
36
+ else
37
+ super
38
+ end
39
+ end
40
+
41
+ class Stub
42
+
43
+ attr_reader :cmd_str, :hash
44
+
45
+ def initialize(cmd_str)
46
+ @cmd_str = cmd_str
47
+ @default_proc = proc{ |cmd_spy| } # no-op
48
+ @hash = {}
49
+ end
50
+
51
+ def set_default_proc(&block)
52
+ @default_proc = block if block
53
+ end
54
+
55
+ def with(opts, &block)
56
+ @hash[opts] = block
57
+ self
58
+ end
59
+
60
+ def call(opts)
61
+ block = @hash[opts] || @default_proc
62
+ CommandSpy.new(@cmd_str, opts).tap(&block)
63
+ end
64
+
65
+ def ==(other_stub)
66
+ if other_stub.kind_of?(Stub)
67
+ self.cmd_str == other_stub.cmd_str &&
68
+ self.hash == other_stub.hash
69
+ else
70
+ super
71
+ end
72
+ end
73
+
74
+ end
75
+
76
+ end
77
+
78
+ end
@@ -1,3 +1,3 @@
1
1
  module Scmd
2
- VERSION = "3.0.0"
2
+ VERSION = "3.0.1"
3
3
  end
@@ -7,3 +7,5 @@ $LOAD_PATH.unshift(ROOT_PATH)
7
7
 
8
8
  # require pry for debugging (`binding.pry`)
9
9
  require 'pry'
10
+
11
+ require 'test/support/factory'
@@ -0,0 +1,6 @@
1
+ require 'assert/factory'
2
+
3
+ module Factory
4
+ extend Assert::Factory
5
+
6
+ end
@@ -0,0 +1,228 @@
1
+ require "assert"
2
+ require 'scmd/command_spy'
3
+
4
+ class Scmd::CommandSpy
5
+
6
+ class UnitTests < Assert::Context
7
+ desc "Scmd::CommandSpy"
8
+ setup do
9
+ @spy_class = Scmd::CommandSpy
10
+ end
11
+
12
+ end
13
+
14
+ class InitTests < UnitTests
15
+ setup do
16
+ @orig_scmd_test_mode = ENV['SCMD_TEST_MODE']
17
+ ENV['SCMD_TEST_MODE'] = '1'
18
+ Scmd.reset
19
+
20
+ @cmd_str = Factory.string
21
+ @spy = @spy_class.new(@cmd_str)
22
+ end
23
+ teardown do
24
+ Scmd.reset
25
+ ENV['SCMD_TEST_MODE'] = @orig_scmd_test_mode
26
+ end
27
+ subject{ @spy }
28
+
29
+ should have_readers :cmd_str, :env, :options
30
+ should have_readers :run_calls, :run_bang_calls, :start_calls
31
+ should have_readers :wait_calls, :stop_calls, :kill_calls
32
+ should have_accessors :pid, :exitstatus, :stdout, :stderr
33
+ should have_imeths :run, :run_called?, :run!, :run_bang_called?
34
+ should have_imeths :start, :start_called?
35
+ should have_imeths :wait, :wait_called?, :stop, :stop_called?
36
+ should have_imeths :kill, :kill_called?
37
+ should have_imeths :running?, :success?
38
+
39
+ should "know and return its cmd string" do
40
+ assert_equal @cmd_str, subject.cmd_str
41
+ assert_equal @cmd_str, subject.to_s
42
+ end
43
+
44
+ should "default its attrs" do
45
+ assert_nil subject.env
46
+ assert_nil subject.options
47
+
48
+ assert_equal [], subject.run_calls
49
+ assert_equal [], subject.run_bang_calls
50
+ assert_equal [], subject.start_calls
51
+ assert_equal [], subject.wait_calls
52
+ assert_equal [], subject.stop_calls
53
+ assert_equal [], subject.kill_calls
54
+
55
+ assert_equal 1, subject.pid
56
+ assert_equal 0, subject.exitstatus
57
+ assert_equal '', subject.stdout
58
+ assert_equal '', subject.stderr
59
+ end
60
+
61
+ should "allow specifying env and options" do
62
+ opts = { Factory.string => Factory.string }
63
+ cmd = Scmd::Command.new(Factory.string, {
64
+ :env => { :SCMD_TEST_VAR => 1 },
65
+ :options => opts
66
+ })
67
+ exp = { 'SCMD_TEST_VAR' => '1' }
68
+ assert_equal exp, cmd.env
69
+ assert_equal opts, cmd.options
70
+ end
71
+
72
+ should "know whether it is running or not" do
73
+ assert_false subject.running?
74
+
75
+ subject.run
76
+ assert_false subject.running?
77
+ subject.run!
78
+ assert_false subject.running?
79
+
80
+ subject.start
81
+ assert_true subject.running?
82
+ subject.stop
83
+ assert_false subject.running?
84
+
85
+ subject.start
86
+ subject.wait
87
+ assert_false subject.running?
88
+
89
+ subject.start
90
+ subject.kill
91
+ assert_false subject.running?
92
+ end
93
+
94
+ should "know if it was successful" do
95
+ assert_true subject.success?
96
+
97
+ subject.exitstatus = 1
98
+ assert_false subject.success?
99
+
100
+ subject.exitstatus = 0
101
+ assert_true subject.success?
102
+
103
+ subject.exitstatus = Factory.string
104
+ assert_false subject.success?
105
+ end
106
+
107
+ should "track its run calls" do
108
+ input = Factory.string
109
+ subject.run(input)
110
+
111
+ assert_equal 1, subject.run_calls.size
112
+ assert_kind_of InputCall, subject.run_calls.first
113
+ assert_equal input, subject.run_calls.first.input
114
+
115
+ assert_equal 1, Scmd.calls.size
116
+ assert_kind_of Scmd::Call, Scmd.calls.first
117
+ assert_equal @cmd_str, Scmd.calls.first.cmd_str
118
+ assert_equal input, Scmd.calls.first.input
119
+ assert_equal subject, Scmd.calls.first.cmd
120
+
121
+ subject.run(Factory.string)
122
+ assert_equal 2, subject.run_calls.size
123
+ assert_equal 2, Scmd.calls.size
124
+ end
125
+
126
+ should "track its run! calls" do
127
+ input = Factory.string
128
+ subject.run!(input)
129
+
130
+ assert_equal 1, subject.run_bang_calls.size
131
+ assert_kind_of InputCall, subject.run_bang_calls.first
132
+ assert_equal input, subject.run_bang_calls.first.input
133
+
134
+ assert_equal 1, Scmd.calls.size
135
+ assert_kind_of Scmd::Call, Scmd.calls.first
136
+ assert_equal @cmd_str, Scmd.calls.first.cmd_str
137
+ assert_equal input, Scmd.calls.first.input
138
+ assert_equal subject, Scmd.calls.first.cmd
139
+
140
+ subject.run!(Factory.string)
141
+ assert_equal 2, subject.run_bang_calls.size
142
+ assert_equal 2, Scmd.calls.size
143
+ end
144
+
145
+ should "track its start calls" do
146
+ input = Factory.string
147
+ subject.start(input)
148
+
149
+ assert_equal 1, subject.start_calls.size
150
+ assert_kind_of InputCall, subject.start_calls.first
151
+ assert_equal input, subject.start_calls.first.input
152
+
153
+ assert_equal 1, Scmd.calls.size
154
+ assert_kind_of Scmd::Call, Scmd.calls.first
155
+ assert_equal @cmd_str, Scmd.calls.first.cmd_str
156
+ assert_equal input, Scmd.calls.first.input
157
+ assert_equal subject, Scmd.calls.first.cmd
158
+
159
+ subject.start(Factory.string)
160
+ assert_equal 2, subject.start_calls.size
161
+ assert_equal 2, Scmd.calls.size
162
+ end
163
+
164
+ should "track its wait calls" do
165
+ timeout = Factory.string
166
+ subject.wait(timeout)
167
+
168
+ assert_equal 1, subject.wait_calls.size
169
+ assert_kind_of TimeoutCall, subject.wait_calls.first
170
+ assert_equal timeout, subject.wait_calls.first.timeout
171
+
172
+ subject.wait(Factory.string)
173
+ assert_equal 2, subject.wait_calls.size
174
+ end
175
+
176
+ should "track its stop calls" do
177
+ timeout = Factory.string
178
+ subject.stop(timeout)
179
+
180
+ assert_equal 1, subject.stop_calls.size
181
+ assert_kind_of TimeoutCall, subject.stop_calls.first
182
+ assert_equal timeout, subject.stop_calls.first.timeout
183
+
184
+ subject.stop(Factory.string)
185
+ assert_equal 2, subject.stop_calls.size
186
+ end
187
+
188
+ should "track its kill calls" do
189
+ signal = Factory.string
190
+ subject.kill(signal)
191
+
192
+ assert_equal 1, subject.kill_calls.size
193
+ assert_kind_of SignalCall, subject.kill_calls.first
194
+ assert_equal signal, subject.kill_calls.first.signal
195
+
196
+ subject.kill(Factory.string)
197
+ assert_equal 2, subject.kill_calls.size
198
+ end
199
+
200
+ should "know if it is equal to another cmd spy" do
201
+ spy1 = @spy_class.new(@cmd_str)
202
+ spy2 = @spy_class.new(@cmd_str)
203
+
204
+ assert_equal spy1, spy2
205
+
206
+ a = [
207
+ :cmd_str,
208
+ :env,
209
+ :options,
210
+ :run_calls,
211
+ :run_bang_calls,
212
+ :start_calls,
213
+ :wait_calls,
214
+ :stop_calls,
215
+ :kill_calls,
216
+ :pid,
217
+ :exitstatus,
218
+ :stdout,
219
+ :stderr
220
+ ].choice
221
+ Assert.stub(spy2, a){ Factory.string }
222
+
223
+ assert_not_equal spy1, spy2
224
+ end
225
+
226
+ end
227
+
228
+ end
@@ -8,7 +8,7 @@ class Scmd::Command
8
8
  setup do
9
9
  @cmd = Scmd::Command.new("echo hi")
10
10
  end
11
- subject { @cmd }
11
+ subject{ @cmd }
12
12
 
13
13
  should have_readers :cmd_str, :env, :options
14
14
  should have_readers :pid, :exitstatus, :stdout, :stderr
@@ -29,8 +29,8 @@ class Scmd::Command
29
29
  cmd = Scmd::Command.new("echo $SCMD_TEST_VAR", {
30
30
  :env => { :SCMD_TEST_VAR => 1 }
31
31
  })
32
- expected = { 'SCMD_TEST_VAR' => '1' }
33
- assert_equal expected, cmd.env
32
+ exp = { 'SCMD_TEST_VAR' => '1' }
33
+ assert_equal exp, cmd.env
34
34
  end
35
35
 
36
36
  should "default its options to an empty hash" do
@@ -2,6 +2,8 @@ require "assert"
2
2
  require 'scmd'
3
3
 
4
4
  require 'scmd/command'
5
+ require 'scmd/command_spy'
6
+ require 'scmd/stored_commands'
5
7
 
6
8
  module Scmd
7
9
 
@@ -9,10 +11,91 @@ module Scmd
9
11
  desc "Scmd"
10
12
  subject{ Scmd }
11
13
 
12
- should have_instance_method :new
14
+ should have_imeths :new, :commands, :calls, :reset, :add_command
15
+
16
+ end
17
+
18
+ class NonTestModeTests < UnitTests
19
+ desc "when NOT in test mode"
13
20
 
14
21
  should "build a `Command` with the `new` method" do
15
- assert_kind_of Scmd::Command, subject.new('echo hi')
22
+ assert_instance_of Scmd::Command, subject.new('echo hi')
23
+ end
24
+
25
+ should "raise no method error on the test mode API methods" do
26
+ [:commands, :calls, :reset].each do |meth|
27
+ assert_raises(NoMethodError) do
28
+ subject.send(meth)
29
+ end
30
+ end
31
+ assert_raises(NoMethodError) do
32
+ subject.add_command(Factory.string)
33
+ end
34
+ end
35
+
36
+ end
37
+
38
+ class TestModeTests < UnitTests
39
+ desc "when in test mode"
40
+ setup do
41
+ @orig_scmd_test_mode = ENV['SCMD_TEST_MODE']
42
+ ENV['SCMD_TEST_MODE'] = '1'
43
+ Scmd.reset
44
+ end
45
+ teardown do
46
+ Scmd.reset
47
+ ENV['SCMD_TEST_MODE'] = @orig_scmd_test_mode
48
+ end
49
+
50
+ should "get a command spy from the commands collection with the new` method" do
51
+ assert_equal Scmd::CommandSpy.new('echo hi'), subject.new('echo hi')
52
+ end
53
+
54
+ should "know its test mode API attrs" do
55
+ assert_equal StoredCommands.new, subject.commands
56
+ assert_equal [], subject.calls
57
+ end
58
+
59
+ should "clear/remove the test mode API attrs on `reset`" do
60
+ cmd_str = Factory.string
61
+ subject.commands.add(cmd_str)
62
+ subject.calls.push(cmd_str)
63
+ assert_not_empty subject.commands
64
+ assert_not_empty subject.calls
65
+
66
+ subject.reset
67
+ assert_empty subject.commands
68
+ assert_empty subject.calls
69
+ end
70
+
71
+ should "add stored commands using `add_command`" do
72
+ cmd_str = Factory.string
73
+ output = Factory.text
74
+ assert_not_equal output, subject.new(cmd_str).stdout
75
+
76
+ subject.add_command(cmd_str){ |cmd| cmd.stdout = output }
77
+ assert_equal output, subject.new(cmd_str).stdout
78
+ end
79
+
80
+ end
81
+
82
+ class CallTests < UnitTests
83
+ desc "Call"
84
+ setup do
85
+ @cmd_str = Factory.string
86
+ @input = Factory.text
87
+ @cmd = CommandSpy.new(@cmd_str)
88
+
89
+ @call = Call.new(@cmd, @input)
90
+ end
91
+ subject{ @call }
92
+
93
+ should have_accessors :cmd_str, :input, :cmd
94
+
95
+ should "know its attrs" do
96
+ assert_equal @cmd_str, subject.cmd_str
97
+ assert_equal @input, subject.input
98
+ assert_equal @cmd, subject.cmd
16
99
  end
17
100
 
18
101
  end
@@ -0,0 +1,146 @@
1
+ require 'assert'
2
+ require 'scmd/stored_commands'
3
+
4
+ require 'scmd/command_spy'
5
+
6
+ class Scmd::StoredCommands
7
+
8
+ class UnitTests < Assert::Context
9
+ desc "Scmd::StoredCommands"
10
+ setup do
11
+ @cmd_str = Factory.string
12
+ @opts = { Factory.string => Factory.string }
13
+ @output = Factory.text
14
+
15
+ @commands = Scmd::StoredCommands.new
16
+ end
17
+ subject{ @commands }
18
+
19
+ should have_imeths :add, :get, :remove, :remove_all, :empty?
20
+
21
+ should "allow adding and getting commands when yielded a command" do
22
+ yielded = nil
23
+ subject.add(@cmd_str) do |cmd|
24
+ yielded = cmd
25
+ cmd.stdout = @output
26
+ end
27
+ cmd_spy = subject.get(@cmd_str, {})
28
+
29
+ assert_instance_of Scmd::CommandSpy, yielded
30
+ assert_equal yielded, cmd_spy
31
+ assert_equal @output, cmd_spy.stdout
32
+ end
33
+
34
+ should "return a stub when adding a command" do
35
+ stub = subject.add(@cmd_str)
36
+ assert_instance_of Scmd::StoredCommands::Stub, stub
37
+
38
+ stub.with(@opts){ |cmd| cmd.stdout = @output }
39
+ cmd = subject.get(@cmd_str, @opts)
40
+ assert_equal @output, cmd.stdout
41
+
42
+ cmd = subject.get(@cmd_str, {})
43
+ assert_not_equal @output, cmd.stdout
44
+ end
45
+
46
+ should "return a unaltered cmd spy for a cmd str that isn't configured" do
47
+ cmd_spy = Scmd::CommandSpy.new(@cmd_str)
48
+ cmd = subject.get(@cmd_str)
49
+
50
+ assert_equal cmd_spy, cmd
51
+ end
52
+
53
+ should "not call a cmd block until it is retrieved" do
54
+ called = false
55
+ subject.add(@cmd_str){ called = true }
56
+ assert_false called
57
+ subject.get(@cmd_str)
58
+ assert_true called
59
+ end
60
+
61
+ should "allow removing a stub" do
62
+ subject.add(@cmd_str){ |cmd| cmd.stdout = @output }
63
+ cmd = subject.get(@cmd_str)
64
+ assert_equal @output, cmd.stdout
65
+
66
+ subject.remove(@cmd_str)
67
+ cmd = subject.get(@cmd_str)
68
+ assert_not_equal @output, cmd.stdout
69
+ end
70
+
71
+ should "allow removing all commands" do
72
+ subject.add(@cmd_str){ |cmd| cmd.stdout = @output }
73
+ other_cmd_str = Factory.string
74
+ subject.add(other_cmd_str){ |cmd| cmd.stdout = @output }
75
+
76
+ subject.remove_all
77
+ cmd = subject.get(@cmd_str)
78
+ assert_not_equal @output, cmd.stdout
79
+ cmd = subject.get(other_cmd_str)
80
+ assert_not_equal @output, cmd.stdout
81
+ end
82
+
83
+ should "know if it is empty or not" do
84
+ assert_empty subject
85
+
86
+ subject.add(@cmd_str)
87
+ assert_not_empty subject
88
+
89
+ subject.remove_all
90
+ assert_empty subject
91
+ end
92
+
93
+ should "know if it is equal to another stored commands or not" do
94
+ cmds1 = Scmd::StoredCommands.new
95
+ cmds2 = Scmd::StoredCommands.new
96
+ assert_equal cmds1, cmds2
97
+
98
+ cmds1.add(@cmd_str)
99
+ assert_not_equal cmds1, cmds2
100
+ end
101
+
102
+ end
103
+
104
+ class StubTests < UnitTests
105
+ desc "Stub"
106
+ setup do
107
+ @stub = Stub.new(@cmd_str)
108
+ end
109
+ subject{ @stub }
110
+
111
+ should have_readers :cmd_str, :hash
112
+ should have_imeths :set_default_proc, :with, :call
113
+
114
+ should "default its default command proc" do
115
+ cmd_spy = Scmd::CommandSpy.new(@cmd_str, @opts)
116
+ cmd = subject.call(@opts)
117
+ assert_equal cmd_spy, cmd
118
+ end
119
+
120
+ should "allow setting its default proc" do
121
+ subject.set_default_proc{ |cmd| cmd.stdout = @output }
122
+ cmd = subject.call(@opts)
123
+ assert_equal @output, cmd.stdout
124
+ end
125
+
126
+ should "allow setting commands for specific opts" do
127
+ cmd = subject.call(@opts)
128
+ assert_equal '', cmd.stdout
129
+
130
+ subject.with({}){ |cmd| cmd.stdout = @output }
131
+ cmd = subject.call({})
132
+ assert_equal @output, cmd.stdout
133
+ end
134
+
135
+ should "know if it is equal to another stub or not" do
136
+ stub1 = Stub.new(@cmd_str)
137
+ stub2 = Stub.new(@cmd_str)
138
+ assert_equal stub1, stub2
139
+
140
+ Assert.stub(stub1, [:cmd_str, :hash].choice){ Factory.string }
141
+ assert_not_equal stub1, stub2
142
+ end
143
+
144
+ end
145
+
146
+ end
metadata CHANGED
@@ -1,13 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: scmd
3
3
  version: !ruby/object:Gem::Version
4
- hash: 7
5
- prerelease:
6
- segments:
7
- - 3
8
- - 0
9
- - 0
10
- version: 3.0.0
4
+ version: 3.0.1
11
5
  platform: ruby
12
6
  authors:
13
7
  - Kelly Redding
@@ -16,38 +10,27 @@ autorequire:
16
10
  bindir: bin
17
11
  cert_chain: []
18
12
 
19
- date: 2015-10-12 00:00:00 Z
13
+ date: 2015-12-22 00:00:00 Z
20
14
  dependencies:
21
15
  - !ruby/object:Gem::Dependency
22
- requirement: &id001 !ruby/object:Gem::Requirement
23
- none: false
16
+ version_requirements: &id001 !ruby/object:Gem::Requirement
24
17
  requirements:
25
18
  - - ~>
26
19
  - !ruby/object:Gem::Version
27
- hash: 29
28
- segments:
29
- - 2
30
- - 15
31
20
  version: "2.15"
32
21
  type: :development
22
+ requirement: *id001
33
23
  name: assert
34
- version_requirements: *id001
35
24
  prerelease: false
36
25
  - !ruby/object:Gem::Dependency
37
- requirement: &id002 !ruby/object:Gem::Requirement
38
- none: false
26
+ version_requirements: &id002 !ruby/object:Gem::Requirement
39
27
  requirements:
40
28
  - - ~>
41
29
  - !ruby/object:Gem::Version
42
- hash: 5
43
- segments:
44
- - 0
45
- - 3
46
- - 11
47
30
  version: 0.3.11
48
31
  type: :runtime
32
+ requirement: *id002
49
33
  name: posix-spawn
50
- version_requirements: *id002
51
34
  prerelease: false
52
35
  description: Build and run system commands.
53
36
  email:
@@ -69,54 +52,55 @@ files:
69
52
  - bench/runner.rb
70
53
  - lib/scmd.rb
71
54
  - lib/scmd/command.rb
55
+ - lib/scmd/command_spy.rb
56
+ - lib/scmd/stored_commands.rb
72
57
  - lib/scmd/version.rb
73
58
  - log/.gitkeep
74
59
  - scmd.gemspec
75
60
  - script/bench.rb
76
61
  - test/helper.rb
77
62
  - test/support/bigger-than-64k.txt
63
+ - test/support/factory.rb
78
64
  - test/support/smaller-than-64k.txt
79
65
  - test/system/command_tests.rb
66
+ - test/unit/command_spy_tests.rb
80
67
  - test/unit/command_tests.rb
81
68
  - test/unit/scmd_tests.rb
69
+ - test/unit/stored_commands_tests.rb
82
70
  - tmp/.gitkeep
83
71
  homepage: http://github.com/redding/scmd
84
72
  licenses:
85
73
  - MIT
74
+ metadata: {}
75
+
86
76
  post_install_message:
87
77
  rdoc_options: []
88
78
 
89
79
  require_paths:
90
80
  - lib
91
81
  required_ruby_version: !ruby/object:Gem::Requirement
92
- none: false
93
82
  requirements:
94
- - - ">="
83
+ - &id003
84
+ - ">="
95
85
  - !ruby/object:Gem::Version
96
- hash: 3
97
- segments:
98
- - 0
99
86
  version: "0"
100
87
  required_rubygems_version: !ruby/object:Gem::Requirement
101
- none: false
102
88
  requirements:
103
- - - ">="
104
- - !ruby/object:Gem::Version
105
- hash: 3
106
- segments:
107
- - 0
108
- version: "0"
89
+ - *id003
109
90
  requirements: []
110
91
 
111
92
  rubyforge_project:
112
- rubygems_version: 1.8.25
93
+ rubygems_version: 2.5.1
113
94
  signing_key:
114
- specification_version: 3
95
+ specification_version: 4
115
96
  summary: Build and run system commands.
116
97
  test_files:
117
98
  - test/helper.rb
118
99
  - test/support/bigger-than-64k.txt
100
+ - test/support/factory.rb
119
101
  - test/support/smaller-than-64k.txt
120
102
  - test/system/command_tests.rb
103
+ - test/unit/command_spy_tests.rb
121
104
  - test/unit/command_tests.rb
122
105
  - test/unit/scmd_tests.rb
106
+ - test/unit/stored_commands_tests.rb