rspec-launchbox 0.0.1 → 0.0.2
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/lib/rspec/launchbox.rb +6 -0
- data/lib/rspec/launchbox/describe_executable.rb +152 -15
- data/lib/rspec/launchbox/version.rb +1 -1
- data/spec/describe_executable_spec.rb +34 -2
- data/spec/spec_helper.rb +0 -4
- data/spec/timeouts_spec.rb +20 -8
- metadata +2 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0317ed423bdb78223cf5eb3678021c69c7470d96
|
4
|
+
data.tar.gz: b0fc8a904edfae7244cda86a3d9c02328615edb5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3d34ae9818ab4e61b2249e394a3cddd6d332e4b5d0b1e78125111d54dfe298861288597d82da2c7aa8b8515e28a8ac25a2258283d749b629c04cf35a0d8da9e1
|
7
|
+
data.tar.gz: 915e466f46865992e1f347218f879cf2b5dedd95d95f3eb11160699007743e20cda055e0823b0dfd4e7d7ada3da3a9e21e813612427d2e02f814b5e28332fb85
|
data/lib/rspec/launchbox.rb
CHANGED
@@ -5,3 +5,9 @@ require 'rspec/its'
|
|
5
5
|
require 'rspec/launchbox/timeout_matchers.rb'
|
6
6
|
require 'rspec/launchbox/in_presence_of.rb'
|
7
7
|
require 'rspec/launchbox/describe_executable.rb'
|
8
|
+
|
9
|
+
include RSpec::DescribeExecutable
|
10
|
+
RSpec.configure do |c|
|
11
|
+
c.extend RSpec::InPresenceOf
|
12
|
+
c.include RSpec::Matchers::Timeout
|
13
|
+
end
|
@@ -1,32 +1,118 @@
|
|
1
1
|
module RSpec
|
2
|
+
# #describe_executable method and some
|
3
|
+
# pretty expectations regarding streams.
|
2
4
|
module DescribeExecutable
|
5
|
+
# Expectations regarding streams,
|
6
|
+
# i.e. stderr, stdout.
|
7
|
+
# Meant to be extended in #describe_stderr and
|
8
|
+
# #describe_stdout
|
9
|
+
module Stream
|
10
|
+
# Expects lines in the specified stream
|
11
|
+
# to include each of the specified lines
|
12
|
+
# @param [Array] lines
|
13
|
+
# @example
|
14
|
+
# describe_stderr do
|
15
|
+
# it_is_expected_to_have_line 'cannot load shared library'
|
16
|
+
# end
|
17
|
+
def it_is_expected_to_have_line(*lines)
|
18
|
+
it "is expected to have line(s) matching '#{lines}'" do
|
19
|
+
expect(_watch_stream.lines.map(&:chomp)).to include *lines
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
alias_method :it_is_expected_to_have_lines, :it_is_expected_to_have_line
|
24
|
+
alias_method :has_line, :it_is_expected_to_have_lines
|
25
|
+
alias_method :has_lines, :it_is_expected_to_have_line
|
26
|
+
|
27
|
+
# Expects some lines in the specified stream
|
28
|
+
# to match specified pattern
|
29
|
+
# @param [Regex, String] lines
|
30
|
+
# @see #it_is_expected_to_have_line
|
31
|
+
def it_is_expected_to_have_lines_matching(pat)
|
32
|
+
it "is expected to have line(s) matching pattern '#{pat}'" do
|
33
|
+
__grep = _watch_stream.lines.grep(pat)
|
34
|
+
expect(__grep.size).to be > 0
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
alias_method :has_line_matching, :it_is_expected_to_have_lines_matching
|
39
|
+
|
40
|
+
# Expects lines in the specified stream
|
41
|
+
# *not* to include each of the specified lines
|
42
|
+
# @param [Regex, String] lines
|
43
|
+
# @see #it_is_expected_to_have_line
|
44
|
+
def it_is_expected_not_to_have_line(*lines)
|
45
|
+
it "is expected not to have line(s) matching '#{lines}'" do
|
46
|
+
expect(_watch_stream.lines.map(&:chomp)).not_to include *lines
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
alias_method :it_is_expected_not_to_have_lines, :it_is_expected_not_to_have_line
|
51
|
+
alias_method :has_no_line, :it_is_expected_not_to_have_line
|
52
|
+
|
53
|
+
# Expects *none of* the lines in the specified stream
|
54
|
+
# to match specified pattern
|
55
|
+
# @param [Regex, String] lines
|
56
|
+
# @see #it_is_expected_to_have_line
|
57
|
+
def it_is_expected_not_to_have_lines_matching(pat)
|
58
|
+
it "is expected not to have line(s) matching pattern '#{pat}'" do
|
59
|
+
__grep = _watch_stream.lines.grep(pat)
|
60
|
+
expect(__grep.size).to be 0
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
alias_method :has_no_line_matching, :it_is_expected_not_to_have_lines_matching
|
65
|
+
end
|
66
|
+
|
3
67
|
# Outmost describe block.
|
4
68
|
# @param [String] cmd executable name
|
5
69
|
# @yields block like ordinary #describe
|
6
70
|
# @example
|
7
71
|
# describe_executable 'ls' do
|
8
|
-
#
|
72
|
+
# describe_stdout do
|
9
73
|
# it { is_expected.to be_a String }
|
10
74
|
# end
|
11
75
|
# end
|
12
76
|
def describe_executable(cmd, &block)
|
13
|
-
$_command_line = cmd
|
14
|
-
$_process_stdout = ''
|
15
77
|
RSpec.describe "#{$_command_line} executable" do
|
78
|
+
$_command_line = cmd
|
79
|
+
$_flags = []
|
80
|
+
$_process_stdout = ''
|
81
|
+
$_process_stderr = ''
|
82
|
+
|
16
83
|
before(:each) do
|
84
|
+
$_command_line = cmd
|
85
|
+
$_process_stdout = ''
|
86
|
+
$_process_pid = nil
|
87
|
+
$_piper_o, $_pipew_o = IO.pipe
|
88
|
+
$_piper_e, $_pipew_e = IO.pipe
|
89
|
+
$_process_pid = fork do
|
90
|
+
$_piper_o.close
|
91
|
+
$_piper_e.close
|
92
|
+
$stdout.reopen $_pipew_o
|
93
|
+
$stderr.reopen $_pipew_e
|
94
|
+
exec($_command_line + ' ' + $_flags.join(' '))
|
95
|
+
end
|
96
|
+
$_pipew_o.close
|
97
|
+
$_pipew_e.close
|
17
98
|
Thread.abort_on_exception = true
|
18
99
|
Thread.new do
|
19
|
-
|
20
|
-
|
100
|
+
maybe_read = [$_piper_o, $_piper_e]
|
101
|
+
can_read = []
|
102
|
+
loop do
|
103
|
+
can_read = select([$_piper_o, $_piper_e]).first.map!(&:fileno)
|
104
|
+
$_process_stdout << ($_piper_o.read(16) || '') if can_read.include? $_piper_o.fileno
|
105
|
+
$_process_stderr << ($_piper_e.read(16) || '') if can_read.include? $_piper_e.fileno
|
106
|
+
maybe_read.delete_if { |io| io.eof? }
|
107
|
+
break if maybe_read.empty?
|
21
108
|
end
|
22
|
-
end
|
23
|
-
sleep 1
|
109
|
+
end.join
|
24
110
|
end
|
25
111
|
|
26
112
|
after(:each) do
|
27
|
-
`
|
113
|
+
`kill -INT #{$_process_pid} &>/dev/null`
|
28
114
|
sleep 0.1
|
29
|
-
`
|
115
|
+
`kill -KILL #{$_process_pid} &>/dev/null`
|
30
116
|
end
|
31
117
|
|
32
118
|
class_eval &block
|
@@ -37,14 +123,30 @@ module RSpec
|
|
37
123
|
# sets it's subject to process stdout
|
38
124
|
# @yields block like ordinary describe
|
39
125
|
# @see #describe_executable for an example
|
40
|
-
def
|
126
|
+
def describe_stdout(&block)
|
41
127
|
describe "it's stdout" do
|
128
|
+
let(:_watch_stream) { $_process_stdout.dup }
|
129
|
+
extend Stream
|
130
|
+
|
42
131
|
subject { $_process_stdout }
|
43
132
|
|
44
133
|
class_eval &block
|
45
134
|
end
|
46
135
|
end
|
47
136
|
|
137
|
+
# Same as #describe_stdout
|
138
|
+
# for stderr
|
139
|
+
def describe_stderr(&block)
|
140
|
+
describe "it's stderr" do
|
141
|
+
let(:_watch_stream) { $_process_stderr.dup }
|
142
|
+
extend Stream
|
143
|
+
|
144
|
+
subject { $_process_stderr }
|
145
|
+
|
146
|
+
class_eval &block
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
48
150
|
# Opens new 'context',
|
49
151
|
# where options are appended to
|
50
152
|
# command line before execution.
|
@@ -53,19 +155,54 @@ module RSpec
|
|
53
155
|
# @example
|
54
156
|
# describe_executable 'ls' do
|
55
157
|
# given_option '-a' do
|
56
|
-
#
|
158
|
+
# describe_stdout do
|
57
159
|
# #you need rspec-its gem for `its`
|
58
160
|
# its(:lines) { is_expected.to include ".\n" }
|
161
|
+
# # much prettier:
|
162
|
+
# has_line '.'
|
59
163
|
# end
|
60
164
|
# end
|
61
165
|
# end
|
62
|
-
def given_option(flag,
|
63
|
-
context "given option #{flag}
|
64
|
-
|
65
|
-
|
166
|
+
def given_option(flag, &block)
|
167
|
+
context "given option #{flag}" do
|
168
|
+
before(:context) do
|
169
|
+
$_flags << flag
|
170
|
+
end
|
171
|
+
|
172
|
+
after(:context) do
|
173
|
+
$_flags.pop
|
174
|
+
end
|
175
|
+
|
176
|
+
class_eval &block
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
# Waits for `timeout` seconds, then
|
181
|
+
# sends signal to the process.
|
182
|
+
# @param [Integer] timeout
|
183
|
+
# @param [Hash] options
|
184
|
+
# @option options [Symbol | String] signal
|
185
|
+
# @example
|
186
|
+
# describe_executable 'some_long_running_executable' do
|
187
|
+
# running_for(10, signal: :INT) do
|
188
|
+
# describe_stdout do
|
189
|
+
# #...
|
190
|
+
# end
|
191
|
+
# end
|
192
|
+
# end
|
193
|
+
def running_for(timeout, options = {}, &block)
|
194
|
+
$_signal = options[:signal] && options[:signal].to_s.upcase.prepend('-')
|
195
|
+
context "when sent #{$_signal} after #{timeout} seconds" do
|
196
|
+
before(:each) do
|
197
|
+
Thread.new do
|
198
|
+
sleep timeout
|
199
|
+
`kill #{$_signal} #{$_process_pid} &>/dev/null`
|
200
|
+
end.join
|
201
|
+
end
|
66
202
|
|
67
203
|
class_eval &block
|
68
204
|
end
|
69
205
|
end
|
70
206
|
end
|
207
|
+
|
71
208
|
end
|
@@ -1,14 +1,46 @@
|
|
1
1
|
describe_executable 'ls' do
|
2
|
-
|
2
|
+
describe_stdout do
|
3
3
|
it { is_expected.to be_a String }
|
4
4
|
it { is_expected.not_to be_empty }
|
5
|
+
it_is_expected_to_have_line 'spec'
|
6
|
+
it_is_expected_to_have_line 'spec', 'lib'
|
7
|
+
it_is_expected_not_to_have_line 'blaargs'
|
8
|
+
it_is_expected_to_have_lines_matching /spec/
|
9
|
+
it_is_expected_not_to_have_lines_matching /blaargh/
|
5
10
|
end
|
6
11
|
|
7
12
|
given_option '-a' do
|
8
|
-
|
13
|
+
describe_stdout do
|
9
14
|
it { is_expected.to be_a String }
|
10
15
|
its(:lines) { is_expected.to include ".\n" }
|
11
16
|
its(:lines) { is_expected.not_to include "ohwowwhatisit\n" }
|
12
17
|
end
|
13
18
|
end
|
19
|
+
|
20
|
+
given_option '-h' do
|
21
|
+
describe_stdout do
|
22
|
+
it 'command line should be cleaned up after each example' do
|
23
|
+
expect($_command_line).not_to include '-a'
|
24
|
+
end
|
25
|
+
its(:lines) { is_expected.not_to include ".\n" }
|
26
|
+
end
|
27
|
+
|
28
|
+
given_option '-a' do
|
29
|
+
describe_stdout do
|
30
|
+
its(:lines) { is_expected.to include ".\n" }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
given_option '1>&2' do
|
36
|
+
describe_stderr do
|
37
|
+
its(:lines) { is_expected.to include "spec\n" }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
running_for(2, signal: :INT) do
|
42
|
+
describe_stdout do
|
43
|
+
it { is_expected.to be_a String }
|
44
|
+
end
|
45
|
+
end
|
14
46
|
end
|
data/spec/spec_helper.rb
CHANGED
data/spec/timeouts_spec.rb
CHANGED
@@ -1,15 +1,23 @@
|
|
1
1
|
describe '#persist' do
|
2
2
|
context 'with jush value passed' do
|
3
3
|
it 'raises exceptions' do
|
4
|
-
|
4
|
+
begin
|
5
|
+
expect(5).to persist 5
|
6
|
+
rescue RuntimeError => e
|
7
|
+
raise e unless e.message.include? 'Block expected'
|
8
|
+
end
|
5
9
|
end
|
6
10
|
end
|
7
11
|
context 'with block passed' do
|
8
12
|
context 'with no boundary' do
|
9
13
|
it 'd' do
|
10
|
-
|
11
|
-
|
12
|
-
|
14
|
+
begin
|
15
|
+
expect do
|
16
|
+
'string'
|
17
|
+
end.to persist
|
18
|
+
rescue RuntimeError => e
|
19
|
+
raise e unless e.message.include? 'Expected'
|
20
|
+
end
|
13
21
|
end
|
14
22
|
end
|
15
23
|
|
@@ -29,10 +37,14 @@ describe '#persist' do
|
|
29
37
|
|
30
38
|
context 'with block which raises exception' do
|
31
39
|
it 'rethrows' do
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
40
|
+
begin
|
41
|
+
expect do
|
42
|
+
'string'
|
43
|
+
fail 'Exception in subject block'
|
44
|
+
end.to persist.at_most(1)
|
45
|
+
rescue RuntimeError => e
|
46
|
+
raise e unless e.message.include? 'Exception in subject block'
|
47
|
+
end
|
36
48
|
end
|
37
49
|
end
|
38
50
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rspec-launchbox
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- d-theus
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-02-
|
11
|
+
date: 2015-02-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -118,4 +118,3 @@ test_files:
|
|
118
118
|
- spec/in-presence-of_spec.rb
|
119
119
|
- spec/spec_helper.rb
|
120
120
|
- spec/timeouts_spec.rb
|
121
|
-
has_rdoc:
|