probatio 0.9.0 → 1.1.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 -1
- data/README.md +307 -0
- data/exe/proba +245 -1
- data/lib/probatio/assertions.rb +324 -0
- data/lib/probatio/debug.rb +35 -0
- data/lib/probatio/examples/a_plugin.rb +14 -0
- data/lib/probatio/examples/a_test.rb +126 -0
- data/lib/probatio/mangle.rb +42 -0
- data/lib/probatio/more.rb +151 -0
- data/lib/probatio/plug.rb +72 -0
- data/lib/probatio/plugins.rb +253 -0
- data/lib/probatio/waiters.rb +44 -0
- data/lib/probatio.rb +773 -157
- data/probatio.gemspec +2 -7
- metadata +17 -8
@@ -0,0 +1,72 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# probatio/plug.rb
|
4
|
+
|
5
|
+
|
6
|
+
module Probatio; class << self
|
7
|
+
|
8
|
+
def plugins; @plugins; end
|
9
|
+
|
10
|
+
def plug(x, position=:last)
|
11
|
+
|
12
|
+
@plugins.insert(determine_plugin_pos(position), x)
|
13
|
+
@plugouts = nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def unplug(old)
|
17
|
+
|
18
|
+
i =
|
19
|
+
plug_index(old) ||
|
20
|
+
fail(ArgumentError.new("Cannot locate plugin to remove"))
|
21
|
+
|
22
|
+
@plugins.delete_at(i)
|
23
|
+
@plugouts = nil
|
24
|
+
end
|
25
|
+
|
26
|
+
def replug(old, new)
|
27
|
+
|
28
|
+
i =
|
29
|
+
plug_index(old) ||
|
30
|
+
fail(ArgumentError.new("Cannot locate plugin to replace"))
|
31
|
+
|
32
|
+
@plugins[i] = new
|
33
|
+
@plugouts = nil
|
34
|
+
end
|
35
|
+
|
36
|
+
protected
|
37
|
+
|
38
|
+
def plugin_index(x)
|
39
|
+
|
40
|
+
return x \
|
41
|
+
if x.is_a?(Integer)
|
42
|
+
return @plugins.index { |pl| pl.respond_to?(x) } \
|
43
|
+
if x.is_a?(Symbol) || x.is_a?(String)
|
44
|
+
|
45
|
+
i = @plugins.index(x); return i if i
|
46
|
+
|
47
|
+
return @plugins.index { |pl| pl.is_a?(x) } if x.is_a?(Module)
|
48
|
+
|
49
|
+
nil
|
50
|
+
end
|
51
|
+
|
52
|
+
def determine_plugin_pos(pos)
|
53
|
+
|
54
|
+
return pos if pos.is_a?(Integer)
|
55
|
+
|
56
|
+
return 0 if pos == :first
|
57
|
+
#return @plugins.length if pos == :last
|
58
|
+
|
59
|
+
h = pos.is_a?(Hash) ? pos : {}
|
60
|
+
|
61
|
+
l = @plugins.length
|
62
|
+
|
63
|
+
if af = h[:after]
|
64
|
+
(@plugins.index { |pl| pl == af || (pl.is_a?(af) rescue nil) } || l) + 1
|
65
|
+
elsif bf = h[:before]
|
66
|
+
(@plugins.index { |pl| pl == bf || (pl.is_a?(bf) rescue nil) } || l)
|
67
|
+
else
|
68
|
+
l # last resort, put at the end...
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end; end
|
72
|
+
|
@@ -0,0 +1,253 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# probatio/plugins.rb
|
4
|
+
|
5
|
+
module Probatio::Colours
|
6
|
+
|
7
|
+
protected
|
8
|
+
|
9
|
+
def c; Probatio.c; end # colours or not...
|
10
|
+
end
|
11
|
+
|
12
|
+
class Probatio::Recorder
|
13
|
+
|
14
|
+
attr_reader :events
|
15
|
+
|
16
|
+
def record(ev)
|
17
|
+
|
18
|
+
(@events ||= []) << ev
|
19
|
+
end
|
20
|
+
|
21
|
+
def failures; @events.select { |ev| ev.name == 'test_fail' }; end
|
22
|
+
def successes; @events.select { |ev| ev.name == 'test_succeed' }; end
|
23
|
+
|
24
|
+
def test_leave_event(test_node)
|
25
|
+
|
26
|
+
@events.find { |e|
|
27
|
+
e.name == 'test_leave' &&
|
28
|
+
e.node_full_name == test_node.full_name }
|
29
|
+
end
|
30
|
+
|
31
|
+
def total_duration
|
32
|
+
|
33
|
+
@events.last.tstamp - @events.first.tstamp
|
34
|
+
end
|
35
|
+
|
36
|
+
def failed_tests; @events.select { |e| e.name == 'test_fail' }; end
|
37
|
+
|
38
|
+
def test_count; @events.count { |e| e.name == 'test_leave' }; end
|
39
|
+
def assertion_count; @events.count { |e| e.name == 'assertion_leave' }; end
|
40
|
+
def failure_count; @events.count { |e| e.name == 'test_fail' }; end
|
41
|
+
def pending_count; @events.count { |e| e.name == 'test_pending' }; end
|
42
|
+
|
43
|
+
def file_count
|
44
|
+
|
45
|
+
@events.map(&:path).compact.uniq.count
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
module Probatio
|
50
|
+
|
51
|
+
class << self
|
52
|
+
|
53
|
+
def recorder_plugin
|
54
|
+
|
55
|
+
@plugins.find { |pl| pl.respond_to?(:events) }
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
class Probatio::Chronometer
|
61
|
+
|
62
|
+
def record(ev)
|
63
|
+
|
64
|
+
# compute ev.leave_delta if ev is a "leave"
|
65
|
+
|
66
|
+
if ev.enter?
|
67
|
+
|
68
|
+
(@enters ||= []) << ev
|
69
|
+
|
70
|
+
elsif ev.leave?
|
71
|
+
|
72
|
+
e = @enters.pop
|
73
|
+
|
74
|
+
fail "ev mismatch #{ev.name} vs #{e.name}" \
|
75
|
+
if ( ! e) || (ev.type != e.type)
|
76
|
+
|
77
|
+
ev.leave_delta = ev.tstamp - e.tstamp
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
module Probatio::SeedReporter
|
83
|
+
|
84
|
+
def on_start(ev)
|
85
|
+
|
86
|
+
puts
|
87
|
+
puts "Run options: --seed #{Probatio.seed}"
|
88
|
+
puts
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
class Probatio::DotReporter
|
93
|
+
|
94
|
+
include Probatio::Colours
|
95
|
+
include Probatio::SeedReporter
|
96
|
+
|
97
|
+
def on_test_succeed(ev)
|
98
|
+
|
99
|
+
print c.dark_grey + '·' + c.reset
|
100
|
+
end
|
101
|
+
|
102
|
+
def on_test_fail(ev)
|
103
|
+
|
104
|
+
print c.red + 'x' + c.reset
|
105
|
+
end
|
106
|
+
|
107
|
+
def on_test_pending(ev)
|
108
|
+
|
109
|
+
print c.yellow + '.' + c.reset
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
class Probatio::VanillaSummarizer
|
114
|
+
|
115
|
+
def on_over(ev)
|
116
|
+
|
117
|
+
c = Probatio.c # colours or not
|
118
|
+
|
119
|
+
recorder = Probatio.plugins.find { |pl| pl.respond_to?(:failures) }
|
120
|
+
return unless recorder
|
121
|
+
|
122
|
+
if recorder.test_count == 0
|
123
|
+
puts c.dark_grey(" ¯\\_(ツ)_/¯")
|
124
|
+
else
|
125
|
+
puts
|
126
|
+
end
|
127
|
+
|
128
|
+
recorder.failures.each do |ev|
|
129
|
+
|
130
|
+
#puts
|
131
|
+
puts '-' * [ Probatio.term_width, 80 ].min
|
132
|
+
#puts ev.leaf.parent.to_s
|
133
|
+
#puts ev.leaf.head
|
134
|
+
#puts ev.leaf.trail
|
135
|
+
puts ev.error.trail
|
136
|
+
puts
|
137
|
+
#puts "%4d %s" % [ ev.error.line, c.dark_grey(ev.error.source_line) ]
|
138
|
+
#puts c.dark_grey(ev.error.path)
|
139
|
+
ev.error.source_lines.each do |i, l|
|
140
|
+
puts "%4s %s" % [
|
141
|
+
i == ev.error.line ? c.underlined(i.to_s) :
|
142
|
+
i % 5 == 0 ? c.dark_grey(i.to_s) :
|
143
|
+
c.white(i.to_s),
|
144
|
+
i == ev.error.line ? c.yellow(l) : c.dark_grey(l) ]
|
145
|
+
end
|
146
|
+
puts; puts c.dark_grey(ev.error.summary(' '))
|
147
|
+
#puts ev.error.inspect
|
148
|
+
#puts '.'
|
149
|
+
#puts ev.to_s
|
150
|
+
#puts
|
151
|
+
end
|
152
|
+
#puts '-' * 80 if recorder.failures.any?
|
153
|
+
|
154
|
+
r = Probatio.recorder_plugin
|
155
|
+
|
156
|
+
d = r.total_duration
|
157
|
+
|
158
|
+
tc = r.test_count
|
159
|
+
ac = r.assertion_count
|
160
|
+
|
161
|
+
fc = r.failure_count; fc = Probatio.c.red(fc.to_s) if fc > 0
|
162
|
+
pc = r.pending_count; pc = Probatio.c.yellow(pc.to_s) if pc > 0
|
163
|
+
|
164
|
+
tpc = tc / d
|
165
|
+
apc = ac / d
|
166
|
+
|
167
|
+
fic = r.file_count
|
168
|
+
|
169
|
+
puts
|
170
|
+
puts
|
171
|
+
print "Finished in #{Probatio.to_time_s(d)}, "
|
172
|
+
print "%0.3f tests/s, %0.3f assertions/s." % [ tpc, apc ]
|
173
|
+
puts
|
174
|
+
puts
|
175
|
+
print "#{tc} test#{s(tc)}, #{ac} assertion#{s(ac)}, "
|
176
|
+
print "#{fc} failure#{s(fc)}, #{pc} pending, "
|
177
|
+
print "#{fic} file#{s(fic)}."
|
178
|
+
puts
|
179
|
+
puts
|
180
|
+
end
|
181
|
+
|
182
|
+
protected
|
183
|
+
|
184
|
+
def s(count); count == 1 ? '' : 's'; end
|
185
|
+
end
|
186
|
+
|
187
|
+
class Probatio::ProbaOutputter
|
188
|
+
|
189
|
+
require 'rbconfig'
|
190
|
+
|
191
|
+
def on_over(ev)
|
192
|
+
|
193
|
+
# TODO unplug if --mute or some switch like that...
|
194
|
+
r = Probatio.recorder_plugin
|
195
|
+
|
196
|
+
flh = r.failed_tests.collect(&:to_h).each { |h| h.delete(:n) }
|
197
|
+
fls = Cerata.table_to_s(flh, ' ')
|
198
|
+
|
199
|
+
rb = {}
|
200
|
+
#
|
201
|
+
rv =
|
202
|
+
File.exist?('.ruby-version') &&
|
203
|
+
File.readlines('.ruby-version').find { |l| ! l.strip.start_with?('#') }
|
204
|
+
#
|
205
|
+
rb[:v] = ".ruby-version:#{rv.strip}" if rv
|
206
|
+
rb[:p] = File.join(
|
207
|
+
RbConfig::CONFIG['bindir'],
|
208
|
+
RbConfig::CONFIG['ruby_install_name'])
|
209
|
+
rb[:d] = RUBY_DESCRIPTION
|
210
|
+
rb[:l] = RUBY_PATCHLEVEL
|
211
|
+
#
|
212
|
+
#rb = Cerata.horizontal_h_to_s(rb)
|
213
|
+
rb = Cerata.vertical_h_to_s(rb, ' ')
|
214
|
+
|
215
|
+
env = Cerata.vertical_h_to_s(
|
216
|
+
ENV.filter { |k, _|
|
217
|
+
k.match?(/^(RUBY_|GEM_|(HOME|PATH|USER|SHELL|PWD)$)/) },
|
218
|
+
' ')
|
219
|
+
|
220
|
+
File.open(Probatio.opath, 'wb') do |o|
|
221
|
+
o << '# ' << Probatio.opath << "\n"
|
222
|
+
o << "{\n"
|
223
|
+
o << "argv: " << Cerata.horizontal_a_to_s(ARGV) << ",\n"
|
224
|
+
o << "failures:\n"
|
225
|
+
#o << " [\n"
|
226
|
+
#fls.each { |fl| o << ' ' << fl << ",\n" }
|
227
|
+
#o << " ],\n"
|
228
|
+
o << fls << ",\n"
|
229
|
+
o << "duration: #{Probatio.to_time_s(r.total_duration).inspect},\n"
|
230
|
+
o << "probatio: { v: #{Probatio::VERSION.inspect} },\n"
|
231
|
+
o << "ruby:\n#{rb},\n"
|
232
|
+
o << "some_env:\n#{env},\n"
|
233
|
+
o << "}\n"
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
class Probatio::Exitter
|
239
|
+
|
240
|
+
def on_exit(ev)
|
241
|
+
|
242
|
+
exit 1 if Probatio.recorder_plugin.failure_count > 0
|
243
|
+
exit 0
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
Probatio.plug(Probatio::Recorder.new)
|
248
|
+
Probatio.plug(Probatio::Chronometer.new)
|
249
|
+
Probatio.plug(Probatio::DotReporter.new)
|
250
|
+
Probatio.plug(Probatio::VanillaSummarizer.new)
|
251
|
+
Probatio.plug(Probatio::ProbaOutputter.new)
|
252
|
+
Probatio.plug(Probatio::Exitter.new)
|
253
|
+
|
@@ -0,0 +1,44 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# probatio/waiters.rb
|
4
|
+
|
5
|
+
module Probatio::Waiters
|
6
|
+
|
7
|
+
def wait_until(opts={}, &block)
|
8
|
+
|
9
|
+
timeout = opts[:timeout] || 14
|
10
|
+
frequency = opts[:frequency] || 0.1
|
11
|
+
|
12
|
+
start = Probatio.monow
|
13
|
+
|
14
|
+
loop do
|
15
|
+
|
16
|
+
sleep(frequency)
|
17
|
+
|
18
|
+
#return if block.call == true
|
19
|
+
r = block.call
|
20
|
+
return r if r
|
21
|
+
|
22
|
+
break if Probatio.monow - start > timeout
|
23
|
+
end
|
24
|
+
|
25
|
+
fail "timeout after #{timeout}s"
|
26
|
+
end
|
27
|
+
alias wait_for wait_until
|
28
|
+
|
29
|
+
def monow
|
30
|
+
|
31
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class Probatio::Section
|
36
|
+
|
37
|
+
include Probatio::Waiters
|
38
|
+
end
|
39
|
+
|
40
|
+
class Probatio::Context
|
41
|
+
|
42
|
+
include Probatio::Waiters
|
43
|
+
end
|
44
|
+
|