coulda 0.4.7 → 0.5.0

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/HISTORY CHANGED
@@ -64,3 +64,9 @@ Cleanup
64
64
  0.4.7
65
65
  -----
66
66
  - Aded a newline after a Feature has been printed via the coulda:print_features task
67
+
68
+ 0.5.0
69
+ -----
70
+ - Coulda::Features created from the Kernel::Feature method now create and return a subclass of Test::Unit::TestCase (or a subclass of the specified :testcase_class).
71
+ - The block passed to Kernel::Feature changes self to be the Test::Unit::TestCase subclass. That way, it's virtually identical to a "class Foo < Test::Unit::TestCase"
72
+ - Removed dependency on Jeremy McAnally's "pending" gem in favor of an implementation targetted specifically to Coulda's needs (File names and line numbers of the Given/When/Then/And that is unimplemented)
@@ -55,4 +55,4 @@ Thanks to
55
55
  ---------
56
56
  * David Chelimsky and Jim Weirich for turning me into the test-obsessed developer that I am.
57
57
  * Timothy King for putting up with my scotch-powered rambling while working on v0.4.0
58
- * We Are Titans (http://www.wearetitans.net/) for sponsoring v0.4.0
58
+ * We Are Titans (http://www.wearetitans.net/) for sponsoring v0.4.0 on up
data/Rakefile CHANGED
@@ -24,7 +24,6 @@ begin
24
24
  require 'jeweler'
25
25
  Jeweler::Tasks.new do |s|
26
26
  s.name = "coulda"
27
- s.version = "0.1.1"
28
27
  s.authors = ["Evan David Light"]
29
28
  s.email = "evan@tiggerpalace.com"
30
29
  s.summary = "Behaviour Driven Development derived from Cucumber but as an internal DSL with methods for reuse"
@@ -32,7 +31,7 @@ begin
32
31
  s.description = "Behaviour Driven Development derived from Cucumber but as an internal DSL with methods for reuse"
33
32
  end
34
33
  rescue LoadError
35
- puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
34
+ puts "Jeweler not available. Install it with: sudo gem install jeweler -s http://gems.github.com"
36
35
  end
37
36
 
38
37
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.4.7
1
+ 0.5.0
@@ -1,15 +1,15 @@
1
1
  # Generated by jeweler
2
- # DO NOT EDIT THIS FILE
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
4
  # -*- encoding: utf-8 -*-
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{coulda}
8
- s.version = "0.4.7"
8
+ s.version = "0.5.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Evan David Light"]
12
- s.date = %q{2009-11-30}
12
+ s.date = %q{2009-12-04}
13
13
  s.description = %q{Behaviour Driven Development derived from Cucumber but as an internal DSL with methods for reuse}
14
14
  s.email = %q{evan@tiggerpalace.com}
15
15
  s.extra_rdoc_files = [
@@ -34,18 +34,20 @@ Gem::Specification.new do |s|
34
34
  "lib/coulda.rb",
35
35
  "lib/coulda/feature.rb",
36
36
  "lib/coulda/scenario.rb",
37
- "lib/coulda/world.rb",
38
37
  "lib/coulda/tasks.rb",
38
+ "lib/coulda/pending.rb",
39
39
  "lib/coulda/tasks/print_features.rake",
40
40
  "lib/coulda/vendor/constantize.rb",
41
41
  "lib/coulda/vendor/underscore.rb",
42
+ "lib/coulda/world.rb",
42
43
  "test/feature_test.rb",
43
44
  "test/integration/using_coulda_test.rb",
44
45
  "test/regression/issue_1_test.rb",
46
+ "test/regression/pending_scenarios_test.rb",
45
47
  "test/scenario_test.rb",
46
48
  "test/test_helper.rb"
47
49
  ]
48
- s.homepage = %q{http://coulda.tiggerpalace.com/}
50
+ s.homepage = %q{http://evan.tiggerpalace.com/}
49
51
  s.rdoc_options = ["--charset=UTF-8"]
50
52
  s.require_paths = ["lib"]
51
53
  s.rubygems_version = %q{1.3.5}
@@ -54,6 +56,7 @@ Gem::Specification.new do |s|
54
56
  "test/feature_test.rb",
55
57
  "test/integration/using_coulda_test.rb",
56
58
  "test/regression/issue_1_test.rb",
59
+ "test/regression/pending_scenarios_test.rb",
57
60
  "test/scenario_test.rb",
58
61
  "test/test_helper.rb"
59
62
  ]
@@ -69,3 +72,4 @@ Gem::Specification.new do |s|
69
72
  else
70
73
  end
71
74
  end
75
+
@@ -4,21 +4,33 @@ end
4
4
 
5
5
  require 'test/unit'
6
6
 
7
- gem 'pending', '>= 0.1.1'
8
- require 'pending'
9
-
10
7
  require 'coulda/world'
11
8
  require 'coulda/feature'
12
9
  require 'coulda/scenario'
10
+ require 'coulda/pending'
13
11
  require 'coulda/vendor/constantize'
14
12
  require 'coulda/vendor/underscore'
15
13
 
16
14
  module Kernel
15
+ # Factory method for Test::Unit::TestCase subclasses
17
16
  def Feature(name, opts = {}, &block)
18
- f = Feature.new(name, opts)
19
- f.instance_eval &block if block_given?
20
- f.assert_presence_of_intent
21
- f
17
+ test_class = Class.new(opts[:testcase_class] || Test::Unit::TestCase)
18
+ Coulda::assign_class_to_const test_class, name
19
+ test_class.class_eval &block if block_given?
20
+ test_class.assert_presence_of_intent
21
+ World.register_feature(test_class, name)
22
+ test_class
23
+ end
24
+ end
25
+
26
+ module Coulda
27
+ def assign_class_to_const(test_class, potential_const)
28
+ base_name = potential_const
29
+ if potential_const !~ /^[a-zA-Z]/
30
+ base_name = "a_" + base_name
31
+ end
32
+ titleized_underscored_name = base_name.super_custom_underscore.gsub(/\b('?[a-z])/) { $1.upcase }
33
+ Object.const_set(titleized_underscored_name, test_class)
22
34
  end
23
35
  end
24
36
 
@@ -1,63 +1,57 @@
1
- module Coulda
2
- # The Feature class is composed of an intent and a series of zero or more Scenarios that describe the behavior
3
- # that satisfies the intent. Capturing intent is a key feature of Coulda. Intent defines the business value
4
- # the Feature is attempting to fulfill. It serves as a reminder for developers (and customers) as to why this
5
- # Feature was implemented and why this spec was written.
6
- class Feature
7
- include Test::Unit::Assertions
8
-
9
- attr_reader :scenarios, :name
10
- attr_accessor :current_scenario, :test_instance
11
-
12
- def initialize(name, opts = {})
13
- World.register_feature(self)
14
- @name = name
15
- @scenarios = []
16
- Scenario.testcase_class = opts[:testcase_class] if opts[:testcase_class]
17
- end
18
-
19
- %w[in_order_to as_a i_want_to].each do |intent|
20
- eval <<-HERE
21
- # An intent specifier
22
- def #{intent}(val = nil)
23
- val ? @#{intent} = val : @#{intent}
24
- end
25
- HERE
26
- end
1
+ module Test
2
+ module Unit
3
+ class TestCase
4
+ include Coulda
5
+
6
+ def self.scenarios
7
+ @scenarios ||= []
8
+ @scenarios
9
+ end
27
10
 
28
- %w[Given When Then And].each do |stmt|
29
- eval <<-HERE
30
- # Specifies a prereqisite, event, or expectation. May be used in any order within the spec
31
- def #{stmt}(text, &block)
32
- @current_scenario.statements << { :type => :#{stmt}, :text => text }
33
- @current_scenario.steps << block if block
34
- end
35
- HERE
36
- end
11
+ def self.current_scenario=(scenario)
12
+ @current_scenario = scenario
13
+ end
37
14
 
38
- # Creates a Scenario instance and adds it to the Feature
39
- def Scenario(scenario_name, &block)
40
- @scenarios << scenario = Scenario.new(scenario_name, self, &block)
41
- scenario
42
- end
15
+ def self.current_scenario
16
+ @current_scenario
17
+ end
43
18
 
44
- # Accessor to the Scenario-created TestCases
45
- def tests
46
- @scenarios.collect { |s| s.test_class }
47
- end
19
+ %w[in_order_to as_a i_want_to].each do |intent|
20
+ eval <<-HERE
21
+ # An intent specifier
22
+ def self.#{intent}(val = nil)
23
+ val ? @#{intent} = val : @#{intent}
24
+ end
25
+ HERE
26
+ end
48
27
 
28
+ %w[Given When Then And].each do |stmt|
29
+ eval <<-HERE
30
+ # Specifies a prereqisite, event, or expectation. May be used in any order within the spec
31
+ def self.#{stmt}(text, &block)
32
+ step = nil
33
+ if block_given?
34
+ current_scenario.steps << step = block
35
+ end
36
+ caller[0] =~ (/(.*):(.*)(:in)?/)
37
+ current_scenario.statements << { :type => :#{stmt}, :text => text, :block => step, :file => $1, :line => $2}
38
+ end
39
+ HERE
40
+ end
49
41
 
50
- # Raises an error if only some of the intent is captured (i.e., in_order_to and as_a without i_want_to)
51
- def assert_presence_of_intent
52
- presence = %w[in_order_to as_a i_want_to].map { |intent| instance_variable_get("@#{intent}") }
53
- if presence.any? { |p| p } && !presence.all? { |p| p }
54
- raise SyntaxError.new("Must have all or none of in_order, as_a, and i_want_to called in a Feature")
42
+ # Creates a Scenario instance and adds it to the Feature
43
+ def self.Scenario(scenario_name, &block)
44
+ @scenarios ||=[]
45
+ @scenarios << scenario = Scenario.new(scenario_name, self, &block)
46
+ scenario
55
47
  end
56
- end
57
48
 
58
- def method_missing(name, *args)
59
- if test_instance
60
- test_instance.__send__(name, *args)
49
+ # Raises an error if only some of the intent is captured (i.e., in_order_to and as_a without i_want_to)
50
+ def self.assert_presence_of_intent
51
+ presence = %w[in_order_to as_a i_want_to].map { |intent| instance_variable_get("@#{intent}") }
52
+ if presence.any? { |p| p } && !presence.all? { |p| p }
53
+ raise SyntaxError.new("Must have all or none of in_order, as_a, and i_want_to called in a Feature")
54
+ end
61
55
  end
62
56
  end
63
57
  end
@@ -0,0 +1,25 @@
1
+ module Test
2
+ module Unit
3
+ class TestCase
4
+ @@pending_cases = []
5
+ @@at_exit = false
6
+
7
+ # Loosely based upon Jeremy McAnally's pending
8
+
9
+ def pending(scenario, statement)
10
+ @@pending_cases << [scenario, statement]
11
+ print "P"
12
+
13
+ @@at_exit ||= begin
14
+ at_exit do
15
+ puts "\nPending Cases:"
16
+ @@pending_cases.each do |scenario, stmt|
17
+ puts "#{stmt[:file]}:#{stmt[:line]}: Scenario '#{scenario.name}': #{stmt[:type]} '#{stmt[:text]}'"
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+
@@ -1,33 +1,18 @@
1
1
  module Coulda
2
- # A factory for Test::Unit::TestCases (or their subclass).
2
+ # A factory for Test::Unit::TestCase test methods
3
3
  class Scenario
4
4
  attr_reader :name, :test_class
5
5
  attr_accessor :steps, :statements
6
6
 
7
- # Class-level method to set the subclass of Test::Unit::TestCase to use as the parent for
8
- # tests manufactured by Scenarios.
9
- def self.testcase_class=(klass)
10
- unless klass.ancestors.include?(Test::Unit::TestCase)
11
- raise Exception.new("class must inherit from Test::Unit:TestCase")
12
- end
13
- @testcase_class = klass
14
- end
15
-
16
- def self.testcase_class
17
- @testcase_class
18
- end
19
-
20
7
  def initialize(name, my_feature, &block)
21
8
  raise Exception.new("Scenario must have a name") unless name
22
9
  @name = name
23
10
  @statements = []
24
11
  @steps = []
25
12
  @pending = false
26
- @test_class = ::Class.new(Scenario.testcase_class || Test::Unit::TestCase)
27
- assign_test_class_to_const(my_feature)
28
- test_impl = nil
29
- if block
30
- create_and_provision_test_method_for my_feature, &block
13
+ @my_feature = my_feature
14
+ if block_given?
15
+ create_and_provision_test_method_using &block
31
16
  else
32
17
  @pending = true
33
18
  define_test_method_using { pending }
@@ -41,40 +26,31 @@ module Coulda
41
26
 
42
27
  private
43
28
 
44
- def create_and_provision_test_method_for(feature, &block)
45
- execute block, :within => feature
46
- inject_test_steps_into @test_class
29
+ def create_and_provision_test_method_using(&block)
30
+ collect_scenario_statements_from &block
47
31
  define_test_method_using do
48
- feature.test_instance = self
49
- self.class.test_steps.each do |s|
50
- feature.instance_eval &s
32
+ self.class.current_scenario.statements.each do |stmt|
33
+ if stmt[:block]
34
+ self.instance_eval &(stmt[:block])
35
+ else
36
+ pending self.class.current_scenario, stmt
37
+ break
38
+ end
51
39
  end
52
- feature.test_instance = nil
53
40
  end
54
41
  end
55
42
 
56
- def assign_test_class_to_const(my_feature)
57
- base_name = "#{my_feature.name}_#{@name}_#{rand(1_000_000_000)}"
58
- base_name = "letter_" + base_name if base_name =~ /^[^a-zA-Z]/
59
- titleized_underscored_name = base_name.super_custom_underscore.gsub(/\b('?[a-z])/) { $1.upcase }
60
- ::Module.const_set(titleized_underscored_name, @test_class)
43
+ def collect_scenario_statements_from(&block)
44
+ @my_feature.current_scenario = self
45
+ @my_feature.instance_eval &block
61
46
  end
62
47
 
63
48
  def define_test_method_using(&block)
64
- @test_class.send(:define_method, "test_#{@name.downcase.super_custom_underscore}", &block)
65
- end
66
-
67
- def execute(block, params = {})
68
- feature = params[:within]
69
- feature.current_scenario = self
70
- feature.instance_eval &block
71
- end
72
-
73
- def inject_test_steps_into(test_class)
74
- class << test_class
75
- attr_accessor :test_steps
49
+ scenario = self
50
+ @my_feature.send(:define_method, "test_#{@name.downcase.super_custom_underscore}") do
51
+ self.class.current_scenario = scenario
52
+ self.instance_eval &block
76
53
  end
77
- test_class.test_steps = @steps
78
54
  end
79
55
  end
80
56
  end
@@ -14,8 +14,8 @@ namespace :coulda do
14
14
  load file
15
15
  end
16
16
 
17
- Coulda::World.features.each do |feature|
18
- puts "Feature: #{feature.name}"
17
+ Coulda::World.features.each do |feature, name|
18
+ puts "Feature: #{name}"
19
19
  puts " In order to #{feature.in_order_to}" if feature.in_order_to
20
20
  puts " As a #{feature.as_a}" if feature.as_a
21
21
  puts " I want to #{feature.i_want_to}" if feature.i_want_to
@@ -1,7 +1,7 @@
1
1
  module Coulda
2
2
  class World
3
- def self.register_feature(feature)
4
- (@features ||= []) << feature
3
+ def self.register_feature(feature, name)
4
+ (@features ||= []) << [feature, name]
5
5
  end
6
6
 
7
7
  def self.features
@@ -1,7 +1,15 @@
1
1
  require File.join(File.dirname(__FILE__), "test_helper")
2
2
 
3
3
  class FeatureTest < Test::Unit::TestCase
4
+
5
+ should "be able to subclass any child class of TestCase" do
6
+ MyTestCase = Class.new(Test::Unit::TestCase)
7
+ feature = Feature "a child class", :testcase_class => MyTestCase
8
+ assert feature.ancestors.include? Test::Unit::TestCase
9
+ end
10
+
4
11
  context "A Feature" do
12
+ @@counter = 1
5
13
  setup do
6
14
  @feature = Feature "foobarblech#{@@counter}" do
7
15
  Scenario "" do
@@ -9,10 +17,11 @@ class FeatureTest < Test::Unit::TestCase
9
17
  Then "" do; end
10
18
  end
11
19
  end
20
+ @@counter += 1
12
21
  end
13
22
 
14
- should "contain tests" do
15
- assert(@feature.tests.first)
23
+ should "be a Test::Unit::TestCase by default" do
24
+ assert @feature.ancestors.include? Test::Unit::TestCase
16
25
  end
17
26
 
18
27
  %w[Given When Then And].each do |condition|
@@ -75,20 +84,18 @@ class FeatureTest < Test::Unit::TestCase
75
84
  end
76
85
  end
77
86
 
78
- should "not have any test" do
79
- assert(@feature_without_scenarios.tests.empty?)
87
+ should "not have any tests" do
88
+ assert @feature_without_scenarios.instance_methods.grep(/^test_/).empty?
80
89
  end
81
90
  end
82
91
 
83
92
  context "that does not have any errors" do
84
- @@counter = 1
85
93
  setup do
86
94
  @feature_without_errors = Feature @@counter.to_s do
87
95
  in_order_to "foo"
88
96
  as_a "bar"
89
97
  i_want_to "blech"
90
98
  end
91
- @@counter += 1
92
99
  end
93
100
 
94
101
  ### Integration tests
@@ -98,7 +105,7 @@ class FeatureTest < Test::Unit::TestCase
98
105
  @feature_without_errors.Scenario("pending scenario") {}
99
106
  test_name = "test_pending_scenario"
100
107
  test_name = test_name.to_sym if RUBY_VERSION =~ /^1.9/
101
- assert(@feature_without_errors.tests.first.instance_methods.include?(test_name), "Test is missing test method from scenario")
108
+ assert(@feature_without_errors.instance_methods.include?(test_name), "Test is missing test method from scenario")
102
109
  end
103
110
 
104
111
  should "create a Scenario" do
@@ -1,6 +1,10 @@
1
1
  require File.join(File.dirname(__FILE__), "..", "test_helper")
2
2
 
3
+ require 'rr'
4
+
3
5
  Feature "Using Coulda", :testcase_class => Test::Unit::TestCase do
6
+ include RR::Adapters::TestUnit
7
+
4
8
  in_order_to "perform lightweight integration/acceptance testing with Coulda"
5
9
  as_a "developer"
6
10
  i_want_to "have typical Coulda usage work"
@@ -10,8 +14,10 @@ Feature "Using Coulda", :testcase_class => Test::Unit::TestCase do
10
14
  end
11
15
 
12
16
  Scenario "A pending scenario with a Given/When/Then without a block" do
13
- Given "this scenario"
14
- When "an event happens" do; end
17
+ Given "this scenario which should be pending" do
18
+ mock(self).pending(anything, anything).times(1)
19
+ end
20
+ When "an event happens"
15
21
  Then "should not error/fail because it is pending" do; end
16
22
  end
17
23
 
@@ -1,5 +1,7 @@
1
1
  require File.join(File.dirname(__FILE__), "..", "test_helper")
2
2
 
3
+ require 'rr'
4
+
3
5
  module GivenSomething
4
6
  def given_something
5
7
  Given "something" do; end
@@ -8,9 +10,11 @@ end
8
10
 
9
11
  # http://github.com/elight/coulda/issues#issue/1
10
12
  class Issue1Test < Test::Unit::TestCase
13
+ include RR::Adapters::TestUnit
14
+
11
15
  context "A Feature that has a Scenario that invokes a 'Given/When/Then' called from a method" do
12
16
  setup do
13
- pendings_are_errors
17
+ stub(self).pending { raise Exception.new }
14
18
 
15
19
  @feature_without_errors = Feature "Issue 1 feature" do
16
20
  extend GivenSomething
@@ -28,7 +32,7 @@ class Issue1Test < Test::Unit::TestCase
28
32
  end
29
33
 
30
34
  should "pass" do
31
- assert(run_feature(@feature_without_errors.tests.first))
35
+ assert(run_feature(@feature_without_errors))
32
36
  end
33
37
  end
34
38
  end
@@ -0,0 +1,31 @@
1
+ require File.join(File.dirname(__FILE__), "..", "test_helper")
2
+ require 'rr'
3
+
4
+ # http://github.com/elight/coulda/issues#issue/1
5
+ class PendingScenariosTest < Test::Unit::TestCase
6
+ include RR::Adapters::TestUnit
7
+
8
+ context "A Scenario that has at least one pending step" do
9
+ @@counter = 0
10
+ setup do
11
+ @scenario = nil
12
+ @feature_without_errors = Feature "with a pending scenario step #{@@counter}" do
13
+ include RR::Adapters::TestUnit
14
+
15
+ @scenario = Scenario "my scenario" do
16
+ Given "something"
17
+ When "the when"
18
+ Then "the then" do
19
+ mock(self).pending
20
+ end
21
+ end
22
+ @@counter += 1
23
+ end
24
+ end
25
+
26
+ should "pass" do
27
+ assert(run_feature(@feature_without_errors))
28
+ end
29
+ end
30
+ end
31
+
@@ -18,15 +18,5 @@ class ScenarioTest < Test::Unit::TestCase
18
18
  end
19
19
  end
20
20
  end
21
-
22
- should "allow Test::Unit::TestCase class to subclass to be set" do
23
- Scenario.testcase_class = Test::Unit::TestCase
24
- end
25
-
26
- should "raise an Exception if provided a class that does not inherit from Test::Unit::TestCase" do
27
- assert_raises Exception do
28
- Scenario.testcase_class = Object
29
- end
30
- end
31
21
  end
32
22
 
@@ -21,7 +21,7 @@ end
21
21
 
22
22
  def pendings_are_errors
23
23
  Feature.class_eval do
24
- def pending
24
+ def pending(*args)
25
25
  raise Exception.new
26
26
  end
27
27
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: coulda
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.7
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Evan David Light
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-11-30 00:00:00 -05:00
12
+ date: 2009-12-04 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -49,18 +49,20 @@ files:
49
49
  - lib/coulda.rb
50
50
  - lib/coulda/feature.rb
51
51
  - lib/coulda/scenario.rb
52
- - lib/coulda/world.rb
53
52
  - lib/coulda/tasks.rb
53
+ - lib/coulda/pending.rb
54
54
  - lib/coulda/tasks/print_features.rake
55
55
  - lib/coulda/vendor/constantize.rb
56
56
  - lib/coulda/vendor/underscore.rb
57
+ - lib/coulda/world.rb
57
58
  - test/feature_test.rb
58
59
  - test/integration/using_coulda_test.rb
59
60
  - test/regression/issue_1_test.rb
61
+ - test/regression/pending_scenarios_test.rb
60
62
  - test/scenario_test.rb
61
63
  - test/test_helper.rb
62
64
  has_rdoc: true
63
- homepage: http://coulda.tiggerpalace.com/
65
+ homepage: http://evan.tiggerpalace.com/
64
66
  licenses: []
65
67
 
66
68
  post_install_message:
@@ -91,5 +93,6 @@ test_files:
91
93
  - test/feature_test.rb
92
94
  - test/integration/using_coulda_test.rb
93
95
  - test/regression/issue_1_test.rb
96
+ - test/regression/pending_scenarios_test.rb
94
97
  - test/scenario_test.rb
95
98
  - test/test_helper.rb