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