rspec-launchbox 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|