Skip to content

Commit

Permalink
More simplification (back to original Bacon impl.
Browse files Browse the repository at this point in the history
  • Loading branch information
alloy committed Feb 29, 2012
1 parent 28c83c1 commit b8286f0
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 68 deletions.
5 changes: 5 additions & 0 deletions bin/macbacon
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ opts = OptionParser.new("", 24, ' ') { |opts|
Bacon.const_set :Backtraces, false
}

opts.on("-c", "--concurrent", "runs multiple specs concurrently on multiple threads") {
require 'mac_bacon'
Bacon::Dispatch.concurrent = true
}

opts.on("-a", "--automatic", "gather tests from ./test/, include ./lib/") {
$LOAD_PATH.unshift "lib" if File.directory? "lib"
automatic = true
Expand Down
119 changes: 74 additions & 45 deletions lib/mac_bacon.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,31 @@ module Bacon
raise NameError, "no such context: #{name.inspect}"
}

# TODO convert these to normal accessors
RestrictName = // unless defined? RestrictName
RestrictContext = // unless defined? RestrictContext

Backtraces = true unless defined? Backtraces

module Dispatch
class << self
attr_accessor :concurrent
alias_method :concurrent?, :concurrent

# Performs the block synchronously on the main thread.
def on_main_thread(&block)
if ::Dispatch::Queue.current.to_s == ::Dispatch::Queue.main.to_s
block.call
else
::Dispatch::Queue.main.sync do
block.call
end
end
end
end
end
# TODO for now we only work on concurrency
Dispatch.concurrent = true

module SpecDoxOutput
def handle_context_begin(context)
# Nested contexts do _not_ have an extra line between them and their parent.
Expand Down Expand Up @@ -164,60 +184,52 @@ def initialize(context, description, block, before_filters, after_filters)
@postponed_blocks_count = 0
@ran_spec_block = false
@ran_after_filters = false
@finished = false

self.class.specifications << self
end

def postponed?
@postponed_blocks_count != 0
end

def run_before_filters
execute_block { @before_filters.each { |f| @context.instance_eval(&f) } }
end

def run_spec_block
# If an exception occurred, we definitely don't need to perform the actual spec anymore
execute_block { @context.instance_eval(&@block) } unless @exception
end

def run_after_filters
execute_block { @after_filters.each { |f| @context.instance_eval(&f) } }
end

def run
# TODO this should probably be done differently in a parallel setup
Bacon.handle_specification_begin(self)

run_before_filters
@before_filters.each { |f| @context.instance_eval(&f) }

@number_of_requirements_before = Should.requirements.size
run_spec_block
finish_spec
end

def finish_spec
@context.instance_eval(&@block)


if passed? && Should.requirements.size == @number_of_requirements_before
# the specification did not contain any requirements, so it flunked
execute_block { raise Error.new(:missing, "empty specification: #{@context.class.name} #{@description}") }
raise Error.new(:missing, "empty specification: #{@context.class.name} #{@description}")
end
run_after_filters
exit_spec
end

def exit_spec
cancel_scheduled_requests!
Bacon.handle_specification_end(error_message || '')
@context.class.specification_did_finish(self)
end
@finished = true
# TODO
#Bacon::Dispatch.on_main_thread do
puts 'OHJA!'
Bacon.handle_specification_end(error_message || '')
#end

#Bacon::Dispatch.on_main_thread do
::Dispatch::Queue.main.async do
@context.class.specification_did_finish(self)
end

def execute_block
rescue Object => e
@exception = e
ensure
begin
yield
@after_filters.each { |f| @context.instance_eval(&f) }
rescue Object => e
@exception = e
end
end

def finished?
@finished
end

def passed?
@exception.nil?
end
Expand Down Expand Up @@ -317,25 +329,42 @@ def init_context(name, context_depth, before = nil, after = nil, &block)
end

def run
# TODO
#return unless name =~ RestrictContext
if spec = current_specification
spec.performSelector("run", withObject:nil, afterDelay:0)
else
Bacon.context_did_finish(self)
queue = ::Dispatch::Queue.concurrent
group = ::Dispatch::Group.new
p group
puts "START OF CONTEXT #{name}"
@specifications.each do |spec|
queue.async(group) do
#begin
spec.run
#rescue Object => e
#p e, e.message, e.backtrace
#thread = ::Dispatch::Queue.current
#Bacon::Dispatch.on_main_thread do
#raise RuntimeError, "An error occurred on thread `#{thread}', this should really not happen! The error was: #{e.message}.", e.backtrace
#end
#end
end
end
group.wait
puts "END OF CONTEXT #{name}"
Bacon.context_did_finish(self)
end

def current_specification
@specifications[@current_specification_index]
end

def specification_did_finish(spec)
if (@current_specification_index + 1) < @specifications.size
@current_specification_index += 1
run
unless Bacon::Dispatch.concurrent?
if (@current_specification_index + 1) < @specifications.size
@current_specification_index += 1
run
else
Bacon.context_did_finish(self)
end
else
Bacon.context_did_finish(self)
# TODO notify the delegates?
end
end

Expand Down
4 changes: 4 additions & 0 deletions test/spec_bacon.rb
Original file line number Diff line number Diff line change
Expand Up @@ -257,20 +257,24 @@ def equal_string(x)

describe "before/after" do
before do
p 'before 1'
@a = 1
@b = 2
end

before do
p 'before 2'
@a = 2
end

after do
p 'after 1'
@a.should.equal 2
@a = 3
end

after do
p 'after 1'
@a.should.equal 3
end

Expand Down
46 changes: 23 additions & 23 deletions test/spec_helper.rb
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
$:.unshift File.expand_path('../../lib', __FILE__)
require 'mac_bacon'

module Bacon
class Specification
alias_method :_real_finish_spec, :finish_spec
end
#module Bacon
#class Specification
#alias_method :_real_finish_spec, :finish_spec
#end

class Context
def failures_before
@failures_before
end
#class Context
#def failures_before
#@failures_before
#end

def expect_spec_to_fail!
@failures_before = Bacon::Counter[:failed]
Bacon::Specification.class_eval do
def finish_spec
@exception_occurred.should == true
@exception_occurred = nil
Bacon::Counter[:failed].should == @context.failures_before + 1
Bacon::Counter[:failed] = @context.failures_before
self.class.class_eval { alias_method :finish_spec, :_real_finish_spec }
_real_finish_spec
end
end
end
end
end
#def expect_spec_to_fail!
#@failures_before = Bacon::Counter[:failed]
#Bacon::Specification.class_eval do
#def finish_spec
#@exception_occurred.should == true
#@exception_occurred = nil
#Bacon::Counter[:failed].should == @context.failures_before + 1
#Bacon::Counter[:failed] = @context.failures_before
#self.class.class_eval { alias_method :finish_spec, :_real_finish_spec }
#_real_finish_spec
#end
#end
#end
#end
#end

0 comments on commit b8286f0

Please sign in to comment.