lib/command-unit.rb in command-unit-0.0.0 vs lib/command-unit.rb in command-unit-0.0.1
- old
+ new
@@ -1,70 +1,165 @@
module CommandUnit
+ @@scenario_count = 0
+
@@scenarios = []
@@current_scenario = nil
attr_reader :current_scenario
- def scenario(description, &block)
- @@scenarios.push Scenario.new(description, &block)
+ def scenario(namespace_or_description, description_or_nil=nil, &block)
+ raise "You must provide a description (String) for each scenario." if namespace_or_description.nil? or description_or_nil.is_a? Symbol
+ raise "namespace must be a symbol, if you meant it as a description, use a string instead." if description_or_nil.is_a? String and not namespace_or_description.is_a? Symbol
+
+ if description_or_nil.nil?
+ description = namespace_or_description
+ namespace = nil
+ else
+ description = description_or_nil
+ namespace = namespace_or_description
+ end
+
+ @@scenarios.push Scenario.new(namespace, description, &block)
+ return @@scenarios.last
end
- def run
- @@scenarios.each do |scenario|
- scenario.run
+ def run(namespace_or_scenario_or_nowt = nil)
+ if namespace_or_scenario_or_nowt.nil?
+ # Run the lot...
+ @@scenarios.each do |scenario|
+ scenario.run
+ end
+ else
+ if namespace_or_scenario_or_nowt.is_a? Symbol
+ @@scenarios.each do |scenario|
+ next unless scenario.namespace == namespace_or_scenario_or_nowt
+ scenario.run
+ end
+ elsif namespace_or_scenario.is_a? Scenario
+ namespace_or_scenario_or_nowt.run
+ else
+ raise "You must pass either a Scenario, a Symbol (namespace), or nil into run. You passed a #{namespace_or_scenario_or_nowt.class}"
+ end
end
end
+ require 'stringio'
+
+ def capture_stdout
+ out = StringIO.new
+ $stdout = out
+ yield
+ r = out.string
+ return r
+ ensure
+ $stdout = STDOUT
+ end
+
+ def ensure_inside_scenario
+ raise "#{caller[0]} must be called from inside a scenario block" if @@current_scenario == nil
+ end
+
+ def scenario_set_up(&scenario_set_up_block)
+ ensure_inside_scenario
+ @@current_scenario.scenario_set_up_block = scenario_set_up_block
+ end
+
+ def scenario_tear_down(&scenario_tear_down_block)
+ ensure_inside_scenario
+ @@current_scenario.scenario_tear_down_block = scenario_tear_down_block
+ end
+
+ def tear_down(&tear_down_block)
+ ensure_inside_scenario
+ @@current_scenario.tear_down_block = tear_down_block
+ end
+
def set_up(&set_up_block)
- raise 'set_up must be called from inside a scenario block' if @@current_scenario == nil
+ ensure_inside_scenario
@@current_scenario.set_up_block = set_up_block
end
def when_i(desc, &when_i_block)
- raise 'when_i must be called from inside a scenario block' if @@current_scenario == nil
+ ensure_inside_scenario
@@current_scenario.add_test Test.new(desc, &when_i_block)
end
def i_expect(desc, &i_expect_block)
- raise 'i_expect must be called from inside a scenario block' if @@current_scenario == nil
+ ensure_inside_scenario
@@current_scenario.current_test.add_expectation Expectation.new(desc, &i_expect_block)
end
+ def success(desc = '')
+ ExpectationResult.new(desc, true)
+ end
+
+ def failure(desc = '')
+ ExpectationResult.new(desc, false)
+ end
+
class Scenario
- def initialize(desc, &block)
+ def initialize(namespace, desc, &block)
+ @namespace = namespace
+ @id = @@scenario_count += 1
@desc = desc
@block = block
@set_up_block = nil
@tests = []
@current_test = nil
@tear_down_block = nil
+ @scenario_set_up_block = nil
+ @scenario_tear_down_block = nil
+ @tests_run = 0
+ @expectations_run = 0
+ @expectations_met = 0
+ @expectations_not_met = 0
+ @inconclusive_expectations = 0
end
def run
- puts "Running scenario: #{@desc}"
+ puts "\nRunning scenario #{@id}: #{@desc}"
@@current_scenario = self
@block.call
+ context = {}
+ @scenario_set_up_block.call(context) unless @scenario_set_up_block.nil?
@tests.each do |test|
- puts "When I #{test.when_i_text}"
- context = {}
+ puts "\tWhen I #{test.when_i_text}"
+ @tests_run += 1
@set_up_block.call(context) unless @set_up_block.nil?
test.when_i_block.call(context) unless test.when_i_block.nil?
- print 'I expect '
test.expectations.each do |expectation|
- puts expectation.desc
- expectation.block.call(context) unless expectation.block.nil?
+ print "\t\tI expect #{expectation.desc}..."
+ result = expectation.block.call(context)
+ @expectations_run += 1
+ if result.respond_to? :success?
+ if result.success?
+ @expectations_met +=1
+ puts "Success! #{result.message}"
+ else
+ @expectations_not_met +=1
+ puts "Failure! #{result.message}"
+ end
+ else
+ @inconclusive_expectations += 1
+ puts "Inconclusive! #{result}"
+ end
end
+ @tear_down_block.call(context) unless @tear_down_block.nil?
end
+ @scenario_tear_down_block.call(context) unless @scenario_tear_down_block.nil?
@@current_scenario = nil
+
+ puts "Scenario #{@id} finished, #{@tests_run} tests, #{@expectations_run} expectations with #{@expectations_met} successful and #{@expectations_not_met} failures."
end
def add_test(test)
@tests.push test
@current_test = test
end
- attr_accessor :desc, :block, :set_up_block, :tests, :tear_down_block, :current_test
+ attr_accessor :desc, :block, :set_up_block, :tests, :tear_down_block, :current_test,
+ :scenario_set_up_block, :scenario_tear_down_block, :namespace
end
class Test
def initialize(when_i_text, &when_i_block)
@when_i_text = when_i_text
@@ -83,6 +178,17 @@
@block = expectaton_block
end
attr_accessor :desc, :block
end
-end
\ No newline at end of file
+ class ExpectationResult
+ def initialize(description, expectation_met)
+ @message = description
+ @success = expectation_met
+ end
+ attr_reader :message
+ def success?
+ @success
+ end
+
+ end
+end