zeus-edge 0.12.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/lib/zeus/m.rb ADDED
@@ -0,0 +1,346 @@
1
+ # This is very largely based on @qrush's M, but there are many modifications.
2
+
3
+ # we need to load all dependencies up front, because bundler will
4
+ # remove us from the load path soon.
5
+ require "rubygems"
6
+ require "zeus/m/test_collection"
7
+ require "zeus/m/test_method"
8
+
9
+ # the Gemfile may specify a version of method_source, but we also want to require it here.
10
+ # To avoid possible "you've activated X; gemfile specifies Y" errors, we actually scan
11
+ # Gemfile.lock for a specific version, and require exactly that version if present.
12
+ gemfile_lock = ROOT_PATH + "/Gemfile.lock"
13
+ if File.exists?(gemfile_lock)
14
+ version = File.read(ROOT_PATH + "/Gemfile.lock").
15
+ scan(/\bmethod_source\s*\(([\d\.]+)\)/).flatten[0]
16
+
17
+ gem "method_source", version if version
18
+ end
19
+
20
+ require 'method_source'
21
+
22
+ module Zeus
23
+ #`m` stands for metal, which is a better test/unit test runner that can run
24
+ #tests by line number.
25
+ #
26
+ #[![m ci](https://secure.travis-ci.org/qrush/m.png)](http://travis-ci.org/qrush/m)
27
+ #
28
+ #![Rush is a heavy metal band. Look it up on Wikipedia.](https://raw.github.com/qrush/m/master/rush.jpg)
29
+ #
30
+ #<sub>[Rush at the Bristol Colston Hall May 1979](http://www.flickr.com/photos/8507625@N02/3468299995/)</sub>
31
+ ### Install
32
+ #
33
+ ### Usage
34
+ #
35
+ #Basically, I was sick of using the `-n` flag to grab one test to run. Instead, I
36
+ #prefer how RSpec's test runner allows tests to be run by line number.
37
+ #
38
+ #Given this file:
39
+ #
40
+ # $ cat -n test/example_test.rb
41
+ # 1 require 'test/unit'
42
+ # 2
43
+ # 3 class ExampleTest < Test::Unit::TestCase
44
+ # 4 def test_apple
45
+ # 5 assert_equal 1, 1
46
+ # 6 end
47
+ # 7
48
+ # 8 def test_banana
49
+ # 9 assert_equal 1, 1
50
+ # 10 end
51
+ # 11 end
52
+ #
53
+ #You can run a test by line number, using format `m TEST_FILE:LINE_NUMBER_OF_TEST`:
54
+ #
55
+ # $ m test/example_test.rb:4
56
+ # Run options: -n /test_apple/
57
+ #
58
+ # # Running tests:
59
+ #
60
+ # .
61
+ #
62
+ # Finished tests in 0.000525s, 1904.7619 tests/s, 1904.7619 assertions/s.
63
+ #
64
+ # 1 tests, 1 assertions, 0 failures, 0 errors, 0 skips
65
+ #
66
+ #Hit the wrong line number? No problem, `m` helps you out:
67
+ #
68
+ # $ m test/example_test.rb:2
69
+ # No tests found on line 2. Valid tests to run:
70
+ #
71
+ # test_apple: m test/examples/test_unit_example_test.rb:4
72
+ # test_banana: m test/examples/test_unit_example_test.rb:8
73
+ #
74
+ #Want to run the whole test? Just leave off the line number.
75
+ #
76
+ # $ m test/example_test.rb
77
+ # Run options:
78
+ #
79
+ # # Running tests:
80
+ #
81
+ # ..
82
+ #
83
+ # Finished tests in 0.001293s, 1546.7904 tests/s, 3093.5808 assertions/s.
84
+ #
85
+ # 1 tests, 2 assertions, 0 failures, 0 errors, 0 skips
86
+ #
87
+ #### Supports
88
+ #
89
+ #`m` works with a few Ruby test frameworks:
90
+ #
91
+ #* `Test::Unit`
92
+ #* `ActiveSupport::TestCase`
93
+ #* `MiniTest::Unit::TestCase`
94
+ #
95
+ ### License
96
+ #
97
+ #This gem is MIT licensed, please see `LICENSE` for more information.
98
+
99
+ ### M, your metal test runner
100
+ # Maybe this gem should have a longer name? Metal?
101
+ module M
102
+ VERSION = "1.2.1" unless defined?(VERSION)
103
+
104
+ # Accept arguments coming from bin/m and run tests.
105
+ def self.run(argv)
106
+ Runner.new(argv).run
107
+ end
108
+
109
+ ### Runner is in charge of running your tests.
110
+ # Instead of slamming all of this junk in an `M` class, it's here instead.
111
+ class Runner
112
+ def initialize(argv)
113
+ @argv = argv
114
+ end
115
+
116
+ # There's two steps to running our tests:
117
+ # 1. Parsing the given input for the tests we need to find (or groups of tests)
118
+ # 2. Run those tests we found that match what you wanted
119
+ def run
120
+ parse
121
+ execute
122
+ end
123
+
124
+ private
125
+
126
+ def parse
127
+ # With no arguments,
128
+ if @argv.empty?
129
+ # Just shell out to `rake test`.
130
+ require 'rake'
131
+ Rake::Task['test'].invoke
132
+ exit
133
+ else
134
+ parse_options! @argv
135
+
136
+ # Parse out ARGV, it should be coming in in a format like `test/test_file.rb:9`
137
+ _, line = @argv.first.split(':')
138
+ @line ||= line.nil? ? nil : line.to_i
139
+
140
+ @files = []
141
+ @argv.each do |arg|
142
+ add_file(arg)
143
+ end
144
+ end
145
+ end
146
+
147
+ def add_file(arg)
148
+ file = arg.split(':').first
149
+ if Dir.exist?(file)
150
+ files = Dir.glob("#{file}/**/*test*.rb")
151
+ @files.concat(files)
152
+ else
153
+ files = Dir.glob(file)
154
+ files == [] and abort "Couldn't find test file '#{file}'!"
155
+ @files.concat(files)
156
+ end
157
+ end
158
+
159
+ def parse_options!(argv)
160
+ require 'optparse'
161
+
162
+ OptionParser.new do |opts|
163
+ opts.banner = 'Options:'
164
+ opts.version = M::VERSION
165
+
166
+ opts.on '-h', '--help', 'Display this help.' do
167
+ puts "Usage: m [OPTIONS] [FILES]\n\n", opts
168
+ exit
169
+ end
170
+
171
+ opts.on '--version', 'Display the version.' do
172
+ puts "m #{M::VERSION}"
173
+ exit
174
+ end
175
+
176
+ opts.on '-l', '--line LINE', Integer, 'Line number for file.' do |line|
177
+ @line = line
178
+ end
179
+
180
+ opts.on '-n', '--name NAME', String, 'Name or pattern for test methods to run.' do |name|
181
+ if name[0] == "/" && name[-1] == "/"
182
+ @test_name = Regexp.new(name[1..-2])
183
+ else
184
+ @test_name = name
185
+ end
186
+ end
187
+
188
+ opts.parse! argv
189
+ end
190
+ end
191
+
192
+ def execute
193
+ generate_tests_to_run
194
+
195
+ test_arguments = build_test_arguments
196
+
197
+ # directly run the tests from here and exit with the status of the tests passing or failing
198
+ case framework
199
+ when :minitest
200
+ exit MiniTest::Unit.runner.run test_arguments
201
+ when :testunit1, :testunit2
202
+ exit Test::Unit::AutoRunner.run(false, nil, test_arguments)
203
+ else
204
+ not_supported
205
+ end
206
+ end
207
+
208
+ def generate_tests_to_run
209
+ # Locate tests to run that may be inside of this line. There could be more than one!
210
+ all_tests = tests
211
+ if @line
212
+ @tests_to_run = all_tests.within(@line)
213
+ end
214
+ end
215
+
216
+ def build_test_arguments
217
+ if @line
218
+ abort_with_no_test_found_by_line_number if @tests_to_run.empty?
219
+
220
+ # assemble the regexp to run these tests,
221
+ test_names = @tests_to_run.map(&:name).join('|')
222
+
223
+ # set up the args needed for the runner
224
+ ["-n", "/(#{test_names})/"]
225
+ elsif user_specified_name?
226
+ abort_with_no_test_found_by_name unless tests.contains?(@test_name)
227
+
228
+ test_names = test_name_to_s
229
+ ["-n", test_names]
230
+ else
231
+ []
232
+ end
233
+ end
234
+
235
+ def abort_with_no_test_found_by_line_number
236
+ abort_with_valid_tests_msg "No tests found on line #{@line}. "
237
+ end
238
+
239
+ def abort_with_no_test_found_by_name
240
+ abort_with_valid_tests_msg "No test name matches '#{test_name_to_s}'. "
241
+ end
242
+
243
+ def abort_with_valid_tests_msg message=""
244
+ message << "Valid tests to run:\n\n"
245
+ # For every test ordered by line number,
246
+ # spit out the test name and line number where it starts,
247
+ tests.by_line_number do |test|
248
+ message << "#{sprintf("%0#{tests.column_size}s", test.name)}: zeus test #{@files[0]}:#{test.start_line}\n"
249
+ end
250
+
251
+ # fail like a good unix process should.
252
+ abort message
253
+ end
254
+
255
+ def test_name_to_s
256
+ @test_name.is_a?(Regexp)? "/#{@test_name.source}/" : @test_name
257
+ end
258
+
259
+ def user_specified_name?
260
+ !@test_name.nil?
261
+ end
262
+
263
+ def framework
264
+ @framework ||= begin
265
+ if defined?(MiniTest)
266
+ :minitest
267
+ elsif defined?(Test)
268
+ if Test::Unit::TestCase.respond_to?(:test_suites)
269
+ :testunit2
270
+ else
271
+ :testunit1
272
+ end
273
+ end
274
+ end
275
+ end
276
+
277
+ # Finds all test suites in this test file, with test methods included.
278
+ def suites
279
+ # Since we're not using `ruby -Itest -Ilib` to run the tests, we need to add this directory to the `LOAD_PATH`
280
+ $:.unshift "./test", "./lib"
281
+
282
+ if framework == :testunit1
283
+ Test::Unit::TestCase.class_eval {
284
+ @@test_suites = {}
285
+ def self.inherited(klass)
286
+ @@test_suites[klass] = true
287
+ end
288
+ def self.test_suites
289
+ @@test_suites.keys
290
+ end
291
+ def self.test_methods
292
+ public_instance_methods(true).grep(/^test/).map(&:to_s)
293
+ end
294
+ }
295
+ end
296
+
297
+ begin
298
+ # Fire up the Ruby files. Let's hope they actually have tests.
299
+ @files.each { |f| load f }
300
+ rescue LoadError => e
301
+ # Fail with a happier error message instead of spitting out a backtrace from this gem
302
+ abort "Failed loading test file:\n#{e.message}"
303
+ end
304
+
305
+ # Figure out what test framework we're using
306
+ case framework
307
+ when :minitest
308
+ suites = MiniTest::Unit::TestCase.test_suites
309
+ when :testunit1, :testunit2
310
+ suites = Test::Unit::TestCase.test_suites
311
+ else
312
+ not_supported
313
+ end
314
+
315
+ # Use some janky internal APIs to group test methods by test suite.
316
+ suites.inject({}) do |suites, suite_class|
317
+ # End up with a hash of suite class name to an array of test methods, so we can later find them and ignore empty test suites
318
+ suites[suite_class] = suite_class.test_methods if suite_class.test_methods.size > 0
319
+ suites
320
+ end
321
+ end
322
+
323
+ # Shoves tests together in our custom container and collection classes.
324
+ # Memoize it since it's unnecessary to do this more than one for a given file.
325
+ def tests
326
+ @tests ||= begin
327
+ # With each suite and array of tests,
328
+ # and with each test method present in this test file,
329
+ # shove a new test method into this collection.
330
+ suites.inject(TestCollection.new) do |collection, (suite_class, test_methods)|
331
+ test_methods.each do |test_method|
332
+ find_locations = (@files.size == 1 && @line)
333
+ collection << TestMethod.create(suite_class, test_method, find_locations)
334
+ end
335
+ collection
336
+ end
337
+ end
338
+ end
339
+
340
+ # Fail loudly if this isn't supported
341
+ def not_supported
342
+ abort "This test framework is not supported! Please open up an issue at https://github.com/qrush/m !"
343
+ end
344
+ end
345
+ end
346
+ end
data/lib/zeus/plan.rb ADDED
File without changes
data/lib/zeus/rails.rb ADDED
@@ -0,0 +1,220 @@
1
+ ROOT_PATH = File.expand_path(Dir.pwd)
2
+ ENV_PATH = File.expand_path('config/environment', ROOT_PATH)
3
+ BOOT_PATH = File.expand_path('config/boot', ROOT_PATH)
4
+ APP_PATH = File.expand_path('config/application', ROOT_PATH)
5
+
6
+ require 'zeus'
7
+ require 'zeus/m'
8
+
9
+ module Zeus
10
+ class Rails < Plan
11
+ def deprecated
12
+ puts "Zeus 0.11.0 changed zeus.json. You'll have to rm zeus.json && zeus init."
13
+ end
14
+ alias_method :spec_helper, :deprecated
15
+ alias_method :testrb, :deprecated
16
+ alias_method :rspec, :deprecated
17
+
18
+
19
+ def after_fork
20
+ reconnect_activerecord
21
+ restart_girl_friday
22
+ reconnect_redis
23
+ end
24
+
25
+ def _monkeypatch_rake
26
+ require 'rake/testtask'
27
+ Rake::TestTask.class_eval {
28
+
29
+ # Create the tasks defined by this task lib.
30
+ def define
31
+ desc "Run tests" + (@name==:test ? "" : " for #{@name}")
32
+ task @name do
33
+ # ruby "#{ruby_opts_string} #{run_code} #{file_list_string} #{option_list}"
34
+ rails_env = ENV['RAILS_ENV']
35
+ rubyopt = ENV['RUBYOPT']
36
+ ENV['RAILS_ENV'] = nil
37
+ ENV['RUBYOPT'] = nil # bundler sets this to require bundler :|
38
+ puts "zeus test #{file_list_string}"
39
+ system "zeus test #{file_list_string}"
40
+ ENV['RAILS_ENV'] = rails_env
41
+ ENV['RUBYOPT'] = rubyopt
42
+ end
43
+ self
44
+ end
45
+
46
+ alias_method :_original_define, :define
47
+
48
+ def self.inherited(klass)
49
+ return unless klass.name == "TestTaskWithoutDescription"
50
+ klass.class_eval {
51
+ def self.method_added(sym)
52
+ class_eval do
53
+ if !@rails_hack_reversed
54
+ @rails_hack_reversed = true
55
+ alias_method :define, :_original_define
56
+ def desc(*)
57
+ end
58
+ end
59
+ end
60
+ end
61
+ }
62
+ end
63
+ }
64
+ end
65
+
66
+ def boot
67
+ _monkeypatch_rake
68
+
69
+ require BOOT_PATH
70
+ # config/application.rb normally requires 'rails/all'.
71
+ # Some 'alternative' ORMs such as Mongoid give instructions to switch this require
72
+ # out for a list of railties, not including ActiveRecord.
73
+ # We grep config/application.rb for all requires of rails/all or railties, and require them.
74
+ rails_components = File.read(APP_PATH + ".rb").
75
+ scan(/^\s*require\s*['"](.*railtie.*|rails\/all)['"]/).flatten
76
+
77
+ rails_components = ["rails/all"] if rails_components == []
78
+ rails_components.each do |component|
79
+ require component
80
+ end
81
+ end
82
+
83
+ def default_bundle
84
+ Bundler.require(:default)
85
+ end
86
+
87
+ def development_environment
88
+ Bundler.require(:development)
89
+ ::Rails.env = ENV['RAILS_ENV'] = "development"
90
+ require APP_PATH
91
+ ::Rails.application.require_environment!
92
+ end
93
+
94
+ def prerake
95
+ require 'rake'
96
+ end
97
+
98
+ def rake
99
+ Rake.application.run
100
+ end
101
+
102
+ def generate
103
+ load_rails_generators
104
+ require 'rails/commands/generate'
105
+ end
106
+
107
+ def destroy
108
+ load_rails_generators
109
+ require 'rails/commands/destroy'
110
+ end
111
+
112
+ def runner
113
+ require 'rails/commands/runner'
114
+ end
115
+
116
+ def console
117
+ require 'rails/commands/console'
118
+ ::Rails::Console.start(::Rails.application)
119
+ end
120
+
121
+ def dbconsole
122
+ require 'rails/commands/dbconsole'
123
+
124
+ meth = ::Rails::DBConsole.method(:start)
125
+
126
+ # `Rails::DBConsole.start` has been changed to load faster in
127
+ # https://github.com/rails/rails/commit/346bb018499cde6699fcce6c68dd7e9be45c75e1
128
+ #
129
+ # This will work with both versions.
130
+ if meth.arity.zero?
131
+ ::Rails::DBConsole.start
132
+ else
133
+ ::Rails::DBConsole.start(::Rails.application)
134
+ end
135
+ end
136
+
137
+ def server
138
+ require 'rails/commands/server'
139
+ server = ::Rails::Server.new
140
+ Dir.chdir(::Rails.application.root)
141
+ server.start
142
+ end
143
+
144
+ def test_environment
145
+ Bundler.require(:test)
146
+
147
+ ::Rails.env = ENV['RAILS_ENV'] = 'test'
148
+ require APP_PATH
149
+
150
+ $rails_rake_task = 'yup' # lie to skip eager loading
151
+ ::Rails.application.require_environment!
152
+ $rails_rake_task = nil
153
+
154
+ $LOAD_PATH.unshift ".", "./lib", "./test", "./spec"
155
+ end
156
+
157
+ def test_helper
158
+ if File.exists?(ROOT_PATH + "/spec/spec_helper.rb")
159
+ require 'spec_helper'
160
+ elsif File.exist?(ROOT_PATH + "/test/minitest_helper.rb")
161
+ require 'minitest_helper'
162
+ else
163
+ require 'test_helper'
164
+ end
165
+ end
166
+
167
+ def test
168
+ if defined?(RSpec)
169
+ exit RSpec::Core::Runner.run(ARGV)
170
+ else
171
+ Zeus::M.run(ARGV)
172
+ end
173
+ end
174
+
175
+ def cucumber_environment
176
+ require 'cucumber/rspec/disable_option_parser'
177
+ require 'cucumber/cli/main'
178
+ @cucumber_runtime = Cucumber::Runtime.new
179
+ end
180
+
181
+ def cucumber
182
+ cucumber_main = Cucumber::Cli::Main.new(ARGV.dup)
183
+ exit cucumber_main.execute!(@cucumber_runtime)
184
+ end
185
+
186
+
187
+ private
188
+
189
+ def restart_girl_friday
190
+ return unless defined?(GirlFriday::WorkQueue)
191
+ # The Actor is run in a thread, and threads don't persist post-fork.
192
+ # We just need to restart each one in the newly-forked process.
193
+ ObjectSpace.each_object(GirlFriday::WorkQueue) do |obj|
194
+ obj.send(:start)
195
+ end
196
+ end
197
+
198
+ def reconnect_activerecord
199
+ ActiveRecord::Base.clear_all_connections! rescue nil
200
+ ActiveRecord::Base.establish_connection rescue nil
201
+ end
202
+
203
+ def reconnect_redis
204
+ return unless defined?(Redis::Client)
205
+ ObjectSpace.each_object(Redis::Client) do |client|
206
+ client.connect
207
+ end
208
+ end
209
+
210
+ def load_rails_generators
211
+ require 'rails/generators'
212
+ ::Rails.application.load_generators
213
+ rescue LoadError # Rails 3.0 doesn't require this block to be run, but 3.2+ does
214
+ end
215
+
216
+ end
217
+ end
218
+
219
+ Zeus.plan ||= Zeus::Rails.new
220
+