test-loop 9.1.0 → 9.1.1
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.
- data/README.md +18 -12
- data/bin/test-loop +2 -232
- data/lib/test/loop.rb +230 -0
- metadata +5 -20
data/README.md
CHANGED
@@ -9,17 +9,6 @@ detects and tests changes in your application in an efficient manner:
|
|
9
9
|
3. Avoids running unchanged test blocks inside changed test files.
|
10
10
|
|
11
11
|
|
12
|
-
> IMPORTANT note for Ruby on Rails users!
|
13
|
-
> ---------------------------------------
|
14
|
-
>
|
15
|
-
> Ensure that your `config/environments/test.rb` file disables class caching:
|
16
|
-
>
|
17
|
-
> config.cache_classes = false
|
18
|
-
>
|
19
|
-
> Otherwise, test-loop will appear to ignore class-level changes in your
|
20
|
-
> models, controllers, helpers, etc. thereby causing you great frustration!
|
21
|
-
|
22
|
-
|
23
12
|
Features
|
24
13
|
--------
|
25
14
|
|
@@ -67,7 +56,7 @@ If installed as a Ruby gem:
|
|
67
56
|
|
68
57
|
If installed as a Git clone:
|
69
58
|
|
70
|
-
ruby bin/test-loop
|
59
|
+
env RUBYLIB=lib ruby bin/test-loop
|
71
60
|
|
72
61
|
|
73
62
|
Operation
|
@@ -193,6 +182,23 @@ you can query and modify the `Test::Loop` OpenStruct configuration as follows:
|
|
193
182
|
end
|
194
183
|
|
195
184
|
|
185
|
+
Known issues
|
186
|
+
------------
|
187
|
+
|
188
|
+
* Ensure that your `config/environments/test.rb` file disables class caching:
|
189
|
+
|
190
|
+
config.cache_classes = false
|
191
|
+
|
192
|
+
Otherwise, test-loop will appear to ignore class-level changes in your
|
193
|
+
models, controllers, helpers, etc. thereby causing you great frustration!
|
194
|
+
|
195
|
+
* SQLite3 [raises `SQLite3::BusyException: database is locked` errors](
|
196
|
+
https://github.com/sunaku/test-loop/issues/2 ) because test-loop runs your
|
197
|
+
test files in parallel. You can work around this by using an [in-memory
|
198
|
+
adapter for SQLite3]( https://github.com/mvz/memory_test_fix ) or by using
|
199
|
+
different database software (such as MySQL) for your test environment.
|
200
|
+
|
201
|
+
|
196
202
|
License
|
197
203
|
-------
|
198
204
|
|
data/bin/test-loop
CHANGED
@@ -1,233 +1,3 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
|
4
|
-
# https://github.com/sunaku/test-loop#readme
|
5
|
-
#
|
6
|
-
####
|
7
|
-
#
|
8
|
-
# (the ISC license)
|
9
|
-
#
|
10
|
-
# Copyright 2010 Suraj N. Kurapati <sunaku@gmail.com>
|
11
|
-
#
|
12
|
-
# Permission to use, copy, modify, and/or distribute this software for any
|
13
|
-
# purpose with or without fee is hereby granted, provided that the above
|
14
|
-
# copyright notice and this permission notice appear in all copies.
|
15
|
-
#
|
16
|
-
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
17
|
-
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
18
|
-
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
19
|
-
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
20
|
-
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
21
|
-
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
22
|
-
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
23
|
-
#
|
24
|
-
|
25
|
-
require 'ostruct'
|
26
|
-
require 'diff/lcs'
|
27
|
-
require 'ansi'
|
28
|
-
|
29
|
-
module Test
|
30
|
-
Loop = OpenStruct.new
|
31
|
-
|
32
|
-
Loop.overhead_file_globs = ['{test,spec}/{test,spec}_helper.rb']
|
33
|
-
|
34
|
-
Loop.reabsorb_file_globs = Loop.overhead_file_globs +
|
35
|
-
['config/**/*.{rb,yml}', 'Gemfile.lock']
|
36
|
-
|
37
|
-
Loop.test_file_matchers = {
|
38
|
-
# source files that correspond to test files
|
39
|
-
'{lib,app}/**/*.rb' => lambda do |path|
|
40
|
-
extn = File.extname(path)
|
41
|
-
base = File.basename(path, extn)
|
42
|
-
"{test,spec}/**/#{base}_{test,spec}#{extn}"
|
43
|
-
end,
|
44
|
-
|
45
|
-
# the actual test files themselves
|
46
|
-
'{test,spec}/**/*_{test,spec}.rb' => lambda {|path| path }
|
47
|
-
}
|
48
|
-
|
49
|
-
Loop.test_name_parser = lambda do |line|
|
50
|
-
case line
|
51
|
-
when /^\s*def\s+test_(\w+)/ then $1
|
52
|
-
when /^\s*(test|context|should|describe|it)\b.+?(['"])(.*?)\2/ then $3
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
Loop.before_each_test = lambda do |test_file, log_file, test_names|
|
57
|
-
unless test_names.empty?
|
58
|
-
test_name_pattern = test_names.map do |name|
|
59
|
-
# sanitize string interpolations and invalid method name characters
|
60
|
-
name.gsub(/\#\{.*?\}/, ' ').strip.gsub(/\W+/, '.*')
|
61
|
-
end.join('|')
|
62
|
-
|
63
|
-
case File.basename(test_file)
|
64
|
-
when /(\b|_)test(\b|_)/ # Test::Unit
|
65
|
-
ARGV.push '--name', "/#{test_name_pattern}/"
|
66
|
-
when /(\b|_)spec(\b|_)/ # RSpec
|
67
|
-
ARGV.push '--example', test_name_pattern
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
Loop.after_each_test =
|
73
|
-
lambda {|test_file, log_file, run_status, started_at, elapsed_time|}
|
74
|
-
|
75
|
-
class << Loop
|
76
|
-
def run
|
77
|
-
init_test_loop
|
78
|
-
register_signals
|
79
|
-
load_user_config
|
80
|
-
absorb_overhead
|
81
|
-
run_test_loop
|
82
|
-
rescue Exception => error
|
83
|
-
STDERR.puts error.inspect, error.backtrace
|
84
|
-
pause_momentarily
|
85
|
-
reload_master_process
|
86
|
-
end
|
87
|
-
|
88
|
-
private
|
89
|
-
|
90
|
-
EXEC_VECTOR = [$0, *ARGV].map {|s| s.dup.freeze }.freeze
|
91
|
-
|
92
|
-
def notify message
|
93
|
-
# using print() because puts() is not an atomic operation
|
94
|
-
print "test-loop: #{message}\n"
|
95
|
-
end
|
96
|
-
|
97
|
-
def register_signals
|
98
|
-
# puts newline to shield normal output from control-key interference:
|
99
|
-
# some shells like BASH emit text when control-key combos are pressed
|
100
|
-
trap(:INT) { puts; kill_master_and_workers }
|
101
|
-
trap(:QUIT) { puts; reload_master_process }
|
102
|
-
trap(:TSTP) { puts; forcibly_run_all_tests }
|
103
|
-
end
|
104
|
-
|
105
|
-
def kill_master_and_workers
|
106
|
-
Process.kill :KILL, -$$
|
107
|
-
end
|
108
|
-
|
109
|
-
def reload_master_process
|
110
|
-
notify 'Restarting loop...'
|
111
|
-
exec(*EXEC_VECTOR)
|
112
|
-
end
|
113
|
-
|
114
|
-
def pause_momentarily
|
115
|
-
sleep 1
|
116
|
-
end
|
117
|
-
|
118
|
-
def load_user_config
|
119
|
-
if File.exist? config_file = File.join(Dir.pwd, '.test-loop')
|
120
|
-
notify 'Loading configuration...'
|
121
|
-
load config_file
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
def absorb_overhead
|
126
|
-
notify 'Absorbing overhead...'
|
127
|
-
$LOAD_PATH.unshift 'lib', 'test', 'spec'
|
128
|
-
Dir[*overhead_file_globs].each do |file|
|
129
|
-
require File.basename(file, File.extname(file))
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
def init_test_loop
|
134
|
-
@running_files = []
|
135
|
-
@running_files_lock = Mutex.new
|
136
|
-
@lines_by_file = {} # path => readlines
|
137
|
-
@last_ran_at = @started_at = Time.now
|
138
|
-
end
|
139
|
-
|
140
|
-
def forcibly_run_all_tests
|
141
|
-
@last_ran_at = Time.at(0)
|
142
|
-
@lines_by_file.clear
|
143
|
-
end
|
144
|
-
|
145
|
-
def run_test_loop
|
146
|
-
notify 'Ready for testing!'
|
147
|
-
loop do
|
148
|
-
# figure out what test files need to be run
|
149
|
-
test_files = test_file_matchers.map do |source_glob, test_matcher|
|
150
|
-
Dir[source_glob].select {|file| File.mtime(file) > @last_ran_at }.
|
151
|
-
map {|path| Dir[test_matcher.call path] }
|
152
|
-
end.flatten.uniq
|
153
|
-
|
154
|
-
test_files = @running_files_lock.
|
155
|
-
synchronize { test_files - @running_files }
|
156
|
-
|
157
|
-
# fork worker processes to run the test files in parallel
|
158
|
-
@last_ran_at = Time.now
|
159
|
-
test_files.each {|file| run_test_file file }
|
160
|
-
|
161
|
-
# reabsorb test execution overhead as necessary
|
162
|
-
reload_master_process if Dir[*reabsorb_file_globs].
|
163
|
-
any? {|file| File.mtime(file) > @started_at }
|
164
|
-
|
165
|
-
pause_momentarily
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
def run_test_file test_file
|
170
|
-
@running_files_lock.synchronize { @running_files.push test_file }
|
171
|
-
log_file = test_file + '.log'
|
172
|
-
|
173
|
-
# cache the contents of the test file for diffing below
|
174
|
-
new_lines = File.readlines(test_file)
|
175
|
-
old_lines = @lines_by_file[test_file] || new_lines
|
176
|
-
@lines_by_file[test_file] = new_lines
|
177
|
-
|
178
|
-
worker_pid = fork do
|
179
|
-
# capture test output in log file because tests are run in parallel
|
180
|
-
# which makes it difficult to understand interleaved output thereof
|
181
|
-
$stdout.reopen log_file, 'w'
|
182
|
-
$stdout.sync = true
|
183
|
-
$stderr.reopen $stdout
|
184
|
-
|
185
|
-
# determine which test blocks have changed inside the test file
|
186
|
-
test_names = Diff::LCS.diff(old_lines, new_lines).flatten.map do |change|
|
187
|
-
catch :found do
|
188
|
-
# search backwards from the line that changed up to
|
189
|
-
# the first line in the file for test definitions
|
190
|
-
change.position.downto(0) do |i|
|
191
|
-
if test_name = test_name_parser.call(new_lines[i])
|
192
|
-
throw :found, test_name
|
193
|
-
end
|
194
|
-
end; nil # prevent unsuccessful search from returning an integer
|
195
|
-
end
|
196
|
-
end.compact.uniq
|
197
|
-
|
198
|
-
# tell the testing framework to run only the changed test blocks
|
199
|
-
before_each_test.call test_file, log_file, test_names
|
200
|
-
|
201
|
-
# after loading the user's test file, the at_exit() hook of the
|
202
|
-
# user's testing framework will take care of running the tests and
|
203
|
-
# reflecting any failures in the worker process' exit status
|
204
|
-
load $0 = test_file # set $0 because Test::Unit outputs it
|
205
|
-
end
|
206
|
-
|
207
|
-
# monitor and report on the worker's progress
|
208
|
-
Thread.new do
|
209
|
-
notify "TEST #{test_file}"
|
210
|
-
|
211
|
-
# wait for worker to finish
|
212
|
-
Process.waitpid worker_pid
|
213
|
-
run_status = $?
|
214
|
-
elapsed_time = Time.now - @last_ran_at
|
215
|
-
|
216
|
-
# report test results along with any failure logs
|
217
|
-
if run_status.success?
|
218
|
-
notify ANSI::Code.green("PASS #{test_file}")
|
219
|
-
else
|
220
|
-
notify ANSI::Code.red("FAIL #{test_file}")
|
221
|
-
STDERR.print File.read(log_file)
|
222
|
-
end
|
223
|
-
|
224
|
-
after_each_test.call \
|
225
|
-
test_file, log_file, run_status, @last_ran_at, elapsed_time
|
226
|
-
|
227
|
-
@running_files_lock.synchronize { @running_files.delete test_file }
|
228
|
-
end
|
229
|
-
end
|
230
|
-
end
|
231
|
-
end
|
232
|
-
|
233
|
-
Test::Loop.run if $0 == __FILE__
|
2
|
+
require 'test/loop'
|
3
|
+
Test::Loop.run
|
data/lib/test/loop.rb
ADDED
@@ -0,0 +1,230 @@
|
|
1
|
+
#
|
2
|
+
# test-loop - Continuous testing for Ruby with fork/eval
|
3
|
+
# https://github.com/sunaku/test-loop#readme
|
4
|
+
#
|
5
|
+
####
|
6
|
+
#
|
7
|
+
# (the ISC license)
|
8
|
+
#
|
9
|
+
# Copyright 2010 Suraj N. Kurapati <sunaku@gmail.com>
|
10
|
+
#
|
11
|
+
# Permission to use, copy, modify, and/or distribute this software for any
|
12
|
+
# purpose with or without fee is hereby granted, provided that the above
|
13
|
+
# copyright notice and this permission notice appear in all copies.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
16
|
+
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
17
|
+
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
18
|
+
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
19
|
+
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
20
|
+
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
21
|
+
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
22
|
+
#
|
23
|
+
|
24
|
+
require 'ostruct'
|
25
|
+
require 'diff/lcs'
|
26
|
+
require 'ansi'
|
27
|
+
|
28
|
+
module Test
|
29
|
+
Loop = OpenStruct.new
|
30
|
+
|
31
|
+
Loop.overhead_file_globs = ['{test,spec}/{test,spec}_helper.rb']
|
32
|
+
|
33
|
+
Loop.reabsorb_file_globs = Loop.overhead_file_globs +
|
34
|
+
['config/**/*.{rb,yml}', 'Gemfile.lock']
|
35
|
+
|
36
|
+
Loop.test_file_matchers = {
|
37
|
+
# source files that correspond to test files
|
38
|
+
'{lib,app}/**/*.rb' => lambda do |path|
|
39
|
+
extn = File.extname(path)
|
40
|
+
base = File.basename(path, extn)
|
41
|
+
"{test,spec}/**/#{base}_{test,spec}#{extn}"
|
42
|
+
end,
|
43
|
+
|
44
|
+
# the actual test files themselves
|
45
|
+
'{test,spec}/**/*_{test,spec}.rb' => lambda {|path| path }
|
46
|
+
}
|
47
|
+
|
48
|
+
Loop.test_name_parser = lambda do |line|
|
49
|
+
case line
|
50
|
+
when /^\s*def\s+test_(\w+)/ then $1
|
51
|
+
when /^\s*(test|context|should|describe|it)\b.+?(['"])(.*?)\2/ then $3
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
Loop.before_each_test = lambda do |test_file, log_file, test_names|
|
56
|
+
unless test_names.empty?
|
57
|
+
test_name_pattern = test_names.map do |name|
|
58
|
+
# sanitize string interpolations and invalid method name characters
|
59
|
+
name.gsub(/\#\{.*?\}/, ' ').strip.gsub(/\W+/, '.*')
|
60
|
+
end.join('|')
|
61
|
+
|
62
|
+
case File.basename(test_file)
|
63
|
+
when /(\b|_)test(\b|_)/ # Test::Unit
|
64
|
+
ARGV.push '--name', "/#{test_name_pattern}/"
|
65
|
+
when /(\b|_)spec(\b|_)/ # RSpec
|
66
|
+
ARGV.push '--example', test_name_pattern
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
Loop.after_each_test =
|
72
|
+
lambda {|test_file, log_file, run_status, started_at, elapsed_time|}
|
73
|
+
|
74
|
+
class << Loop
|
75
|
+
def run
|
76
|
+
init_test_loop
|
77
|
+
register_signals
|
78
|
+
load_user_config
|
79
|
+
absorb_overhead
|
80
|
+
run_test_loop
|
81
|
+
rescue Exception => error
|
82
|
+
STDERR.puts error.inspect, error.backtrace
|
83
|
+
pause_momentarily
|
84
|
+
reload_master_process
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
EXEC_VECTOR = [$0, *ARGV].map {|s| s.dup.freeze }.freeze
|
90
|
+
|
91
|
+
def notify message
|
92
|
+
# using print() because puts() is not an atomic operation
|
93
|
+
print "test-loop: #{message}\n"
|
94
|
+
end
|
95
|
+
|
96
|
+
def register_signals
|
97
|
+
# puts newline to shield normal output from control-key interference:
|
98
|
+
# some shells like BASH emit text when control-key combos are pressed
|
99
|
+
trap(:INT) { puts; kill_master_and_workers }
|
100
|
+
trap(:QUIT) { puts; reload_master_process }
|
101
|
+
trap(:TSTP) { puts; forcibly_run_all_tests }
|
102
|
+
end
|
103
|
+
|
104
|
+
def kill_master_and_workers
|
105
|
+
Process.kill :KILL, -$$
|
106
|
+
end
|
107
|
+
|
108
|
+
def reload_master_process
|
109
|
+
notify 'Restarting loop...'
|
110
|
+
exec(*EXEC_VECTOR)
|
111
|
+
end
|
112
|
+
|
113
|
+
def pause_momentarily
|
114
|
+
sleep 1
|
115
|
+
end
|
116
|
+
|
117
|
+
def load_user_config
|
118
|
+
if File.exist? config_file = File.join(Dir.pwd, '.test-loop')
|
119
|
+
notify 'Loading configuration...'
|
120
|
+
load config_file
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def absorb_overhead
|
125
|
+
notify 'Absorbing overhead...'
|
126
|
+
$LOAD_PATH.unshift 'lib', 'test', 'spec'
|
127
|
+
Dir[*overhead_file_globs].each do |file|
|
128
|
+
require File.basename(file, File.extname(file))
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def init_test_loop
|
133
|
+
@running_files = []
|
134
|
+
@running_files_lock = Mutex.new
|
135
|
+
@lines_by_file = {} # path => readlines
|
136
|
+
@last_ran_at = @started_at = Time.now
|
137
|
+
end
|
138
|
+
|
139
|
+
def forcibly_run_all_tests
|
140
|
+
@last_ran_at = Time.at(0)
|
141
|
+
@lines_by_file.clear
|
142
|
+
end
|
143
|
+
|
144
|
+
def run_test_loop
|
145
|
+
notify 'Ready for testing!'
|
146
|
+
loop do
|
147
|
+
# figure out what test files need to be run
|
148
|
+
test_files = test_file_matchers.map do |source_glob, test_matcher|
|
149
|
+
Dir[source_glob].select {|file| File.mtime(file) > @last_ran_at }.
|
150
|
+
map {|path| Dir[test_matcher.call path] }
|
151
|
+
end.flatten.uniq
|
152
|
+
|
153
|
+
test_files = @running_files_lock.
|
154
|
+
synchronize { test_files - @running_files }
|
155
|
+
|
156
|
+
# fork worker processes to run the test files in parallel
|
157
|
+
@last_ran_at = Time.now
|
158
|
+
test_files.each {|file| run_test_file file }
|
159
|
+
|
160
|
+
# reabsorb test execution overhead as necessary
|
161
|
+
reload_master_process if Dir[*reabsorb_file_globs].
|
162
|
+
any? {|file| File.mtime(file) > @started_at }
|
163
|
+
|
164
|
+
pause_momentarily
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def run_test_file test_file
|
169
|
+
@running_files_lock.synchronize { @running_files.push test_file }
|
170
|
+
log_file = test_file + '.log'
|
171
|
+
|
172
|
+
# cache the contents of the test file for diffing below
|
173
|
+
new_lines = File.readlines(test_file)
|
174
|
+
old_lines = @lines_by_file[test_file] || new_lines
|
175
|
+
@lines_by_file[test_file] = new_lines
|
176
|
+
|
177
|
+
worker_pid = fork do
|
178
|
+
# capture test output in log file because tests are run in parallel
|
179
|
+
# which makes it difficult to understand interleaved output thereof
|
180
|
+
$stdout.reopen log_file, 'w'
|
181
|
+
$stdout.sync = true
|
182
|
+
$stderr.reopen $stdout
|
183
|
+
|
184
|
+
# determine which test blocks have changed inside the test file
|
185
|
+
test_names = Diff::LCS.diff(old_lines, new_lines).flatten.map do |change|
|
186
|
+
catch :found do
|
187
|
+
# search backwards from the line that changed up to
|
188
|
+
# the first line in the file for test definitions
|
189
|
+
change.position.downto(0) do |i|
|
190
|
+
if test_name = test_name_parser.call(new_lines[i])
|
191
|
+
throw :found, test_name
|
192
|
+
end
|
193
|
+
end; nil # prevent unsuccessful search from returning an integer
|
194
|
+
end
|
195
|
+
end.compact.uniq
|
196
|
+
|
197
|
+
# tell the testing framework to run only the changed test blocks
|
198
|
+
before_each_test.call test_file, log_file, test_names
|
199
|
+
|
200
|
+
# after loading the user's test file, the at_exit() hook of the
|
201
|
+
# user's testing framework will take care of running the tests and
|
202
|
+
# reflecting any failures in the worker process' exit status
|
203
|
+
load $0 = test_file # set $0 because Test::Unit outputs it
|
204
|
+
end
|
205
|
+
|
206
|
+
# monitor and report on the worker's progress
|
207
|
+
Thread.new do
|
208
|
+
notify "TEST #{test_file}"
|
209
|
+
|
210
|
+
# wait for worker to finish
|
211
|
+
Process.waitpid worker_pid
|
212
|
+
run_status = $?
|
213
|
+
elapsed_time = Time.now - @last_ran_at
|
214
|
+
|
215
|
+
# report test results along with any failure logs
|
216
|
+
if run_status.success?
|
217
|
+
notify ANSI::Code.green("PASS #{test_file}")
|
218
|
+
else
|
219
|
+
notify ANSI::Code.red("FAIL #{test_file}")
|
220
|
+
STDERR.print File.read(log_file)
|
221
|
+
end
|
222
|
+
|
223
|
+
after_each_test.call \
|
224
|
+
test_file, log_file, run_status, @last_ran_at, elapsed_time
|
225
|
+
|
226
|
+
@running_files_lock.synchronize { @running_files.delete test_file }
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
metadata
CHANGED
@@ -1,12 +1,8 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: test-loop
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
prerelease:
|
5
|
-
|
6
|
-
- 9
|
7
|
-
- 1
|
8
|
-
- 0
|
9
|
-
version: 9.1.0
|
4
|
+
prerelease:
|
5
|
+
version: 9.1.1
|
10
6
|
platform: ruby
|
11
7
|
authors:
|
12
8
|
- Suraj N. Kurapati
|
@@ -14,7 +10,7 @@ autorequire:
|
|
14
10
|
bindir: bin
|
15
11
|
cert_chain: []
|
16
12
|
|
17
|
-
date: 2011-
|
13
|
+
date: 2011-03-15 00:00:00 -07:00
|
18
14
|
default_executable:
|
19
15
|
dependencies:
|
20
16
|
- !ruby/object:Gem::Dependency
|
@@ -25,10 +21,6 @@ dependencies:
|
|
25
21
|
requirements:
|
26
22
|
- - ">="
|
27
23
|
- !ruby/object:Gem::Version
|
28
|
-
segments:
|
29
|
-
- 1
|
30
|
-
- 1
|
31
|
-
- 2
|
32
24
|
version: 1.1.2
|
33
25
|
type: :runtime
|
34
26
|
version_requirements: *id001
|
@@ -40,10 +32,6 @@ dependencies:
|
|
40
32
|
requirements:
|
41
33
|
- - ">="
|
42
34
|
- !ruby/object:Gem::Version
|
43
|
-
segments:
|
44
|
-
- 1
|
45
|
-
- 2
|
46
|
-
- 2
|
47
35
|
version: 1.2.2
|
48
36
|
type: :runtime
|
49
37
|
version_requirements: *id002
|
@@ -58,6 +46,7 @@ extra_rdoc_files: []
|
|
58
46
|
files:
|
59
47
|
- README.md
|
60
48
|
- bin/test-loop
|
49
|
+
- lib/test/loop.rb
|
61
50
|
has_rdoc: true
|
62
51
|
homepage: http://github.com/sunaku/test-loop
|
63
52
|
licenses: []
|
@@ -72,21 +61,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
72
61
|
requirements:
|
73
62
|
- - ">="
|
74
63
|
- !ruby/object:Gem::Version
|
75
|
-
segments:
|
76
|
-
- 0
|
77
64
|
version: "0"
|
78
65
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
79
66
|
none: false
|
80
67
|
requirements:
|
81
68
|
- - ">="
|
82
69
|
- !ruby/object:Gem::Version
|
83
|
-
segments:
|
84
|
-
- 0
|
85
70
|
version: "0"
|
86
71
|
requirements: []
|
87
72
|
|
88
73
|
rubyforge_project:
|
89
|
-
rubygems_version: 1.
|
74
|
+
rubygems_version: 1.6.2
|
90
75
|
signing_key:
|
91
76
|
specification_version: 3
|
92
77
|
summary: Continuous testing for Ruby with fork/eval
|