aslakhellesoy-cucumber 0.0.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.
Files changed (74) hide show
  1. data/History.txt +4 -0
  2. data/License.txt +20 -0
  3. data/Manifest.txt +73 -0
  4. data/README.txt +78 -0
  5. data/Rakefile +4 -0
  6. data/bin/cucumber +3 -0
  7. data/config/hoe.rb +70 -0
  8. data/config/requirements.rb +15 -0
  9. data/examples/Rakefile +7 -0
  10. data/examples/pure_ruby/addition.rb +16 -0
  11. data/examples/pure_ruby/steps/addition_steps.rb +43 -0
  12. data/examples/simple/addition.story +12 -0
  13. data/examples/simple/division.story +17 -0
  14. data/examples/simple/steps/addition_steps.rb +43 -0
  15. data/examples/simple_norwegian/steg/matte_steg.rb.rb +31 -0
  16. data/examples/simple_norwegian/summering.story +10 -0
  17. data/examples/web/run_stories.story +10 -0
  18. data/examples/web/steps/stories_steps.rb +39 -0
  19. data/gem_tasks/deployment.rake +34 -0
  20. data/gem_tasks/environment.rake +7 -0
  21. data/gem_tasks/fix_cr_lf.rake +10 -0
  22. data/gem_tasks/rspec.rake +21 -0
  23. data/gem_tasks/treetop.rake +33 -0
  24. data/gem_tasks/website.rake +17 -0
  25. data/lib/cucumber.rb +17 -0
  26. data/lib/cucumber/cli.rb +118 -0
  27. data/lib/cucumber/core_ext/proc.rb +35 -0
  28. data/lib/cucumber/core_ext/string.rb +17 -0
  29. data/lib/cucumber/executor.rb +85 -0
  30. data/lib/cucumber/formatters.rb +1 -0
  31. data/lib/cucumber/formatters/ansicolor.rb +89 -0
  32. data/lib/cucumber/formatters/html_formatter.rb +271 -0
  33. data/lib/cucumber/formatters/pretty_formatter.rb +66 -0
  34. data/lib/cucumber/formatters/progress_formatter.rb +41 -0
  35. data/lib/cucumber/parser/languages.yml +35 -0
  36. data/lib/cucumber/parser/nodes.rb +88 -0
  37. data/lib/cucumber/parser/story_parser.rb +13 -0
  38. data/lib/cucumber/parser/story_parser.treetop.erb +41 -0
  39. data/lib/cucumber/parser/story_parser_en.rb +554 -0
  40. data/lib/cucumber/parser/story_parser_fr.rb +554 -0
  41. data/lib/cucumber/parser/story_parser_no.rb +554 -0
  42. data/lib/cucumber/parser/story_parser_pt.rb +554 -0
  43. data/lib/cucumber/parser/top_down_visitor.rb +26 -0
  44. data/lib/cucumber/rails/world.rb +69 -0
  45. data/lib/cucumber/rake/task.rb +74 -0
  46. data/lib/cucumber/ruby_tree.rb +14 -0
  47. data/lib/cucumber/ruby_tree/nodes.rb +68 -0
  48. data/lib/cucumber/step_methods.rb +39 -0
  49. data/lib/cucumber/step_mother.rb +38 -0
  50. data/lib/cucumber/tree.rb +127 -0
  51. data/lib/cucumber/version.rb +9 -0
  52. data/script/console +10 -0
  53. data/script/console.cmd +1 -0
  54. data/script/destroy +14 -0
  55. data/script/destroy.cmd +1 -0
  56. data/script/generate +14 -0
  57. data/script/generate.cmd +1 -0
  58. data/script/txt2html +74 -0
  59. data/script/txt2html.cmd +1 -0
  60. data/setup.rb +1585 -0
  61. data/spec/cucumber/core_ext/string_spec.rb +20 -0
  62. data/spec/cucumber/executor_spec.rb +55 -0
  63. data/spec/cucumber/formatters/ansicolor_spec.rb +18 -0
  64. data/spec/cucumber/formatters/html_formatter_spec.rb +59 -0
  65. data/spec/cucumber/formatters/stories.html +274 -0
  66. data/spec/cucumber/sell_cucumbers.story +9 -0
  67. data/spec/spec.opts +2 -0
  68. data/spec/spec_helper.rb +7 -0
  69. data/website/index.html +11 -0
  70. data/website/index.txt +39 -0
  71. data/website/javascripts/rounded_corners_lite.inc.js +285 -0
  72. data/website/stylesheets/screen.css +138 -0
  73. data/website/template.html.erb +48 -0
  74. metadata +157 -0
@@ -0,0 +1,26 @@
1
+ module Cucumber
2
+ module Parser
3
+ class TopDownVisitor
4
+ def visit_stories(stories)
5
+ stories.accept(self)
6
+ end
7
+
8
+ def visit_story(story)
9
+ story.accept(self)
10
+ end
11
+
12
+ def visit_header(header)
13
+ end
14
+
15
+ def visit_narrative(narrative)
16
+ end
17
+
18
+ def visit_scenario(scenario)
19
+ scenario.accept(self)
20
+ end
21
+
22
+ def visit_step(step)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,69 @@
1
+ # Based on code from Brian Takita, Yurii Rashkovskii and Ben Mabey
2
+ # Adapted by Aslak Hellesøy
3
+
4
+ if defined?(ActiveRecord::Base)
5
+ require 'test_help'
6
+ else
7
+ require 'action_controller/test_process'
8
+ require 'action_controller/integration'
9
+ end
10
+ require 'test/unit/testresult'
11
+ require 'spec'
12
+ require 'spec/rails'
13
+
14
+ # These allow exceptions to come through as opposed to being caught and hvaing non-helpful responses returned.
15
+ ActionController::Base.class_eval do
16
+ def perform_action
17
+ perform_action_without_rescue
18
+ end
19
+ end
20
+ Dispatcher.class_eval do
21
+ def self.failsafe_response(output, status, exception = nil)
22
+ raise exception
23
+ end
24
+ end
25
+
26
+ # So that Test::Unit doesn't launch at the end - makes it think it has already been run.
27
+ Test::Unit.run = true
28
+
29
+ # Hack to stop RSpec from dumping the summary
30
+ Spec::Runner::Options.class_eval do
31
+ def examples_should_be_run?
32
+ false
33
+ end
34
+ end
35
+
36
+ ActionController::Integration::Session.send(:include, Spec::Matchers)
37
+ ActionController::Integration::Session.send(:include, Spec::Rails::Matchers)
38
+
39
+ module Cucumber
40
+ module Rails
41
+ class World < ActionController::IntegrationTest
42
+ if defined?(ActiveRecord::Base)
43
+ self.use_transactional_fixtures = true
44
+ else
45
+ def self.fixture_table_names; []; end # Workaround for projects that don't use ActiveRecord
46
+ end
47
+
48
+ def initialize #:nodoc:
49
+ @_result = Test::Unit::TestResult.new
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ World do
56
+ Cucumber::Rails::World.new
57
+ end
58
+
59
+ if defined?(ActiveRecord::Base)
60
+ Before do
61
+ ActiveRecord::Base.send :increment_open_transactions
62
+ ActiveRecord::Base.connection.begin_db_transaction
63
+ end
64
+
65
+ After do
66
+ ActiveRecord::Base.connection.rollback_db_transaction
67
+ ActiveRecord::Base.send :decrement_open_transactions
68
+ end
69
+ end
@@ -0,0 +1,74 @@
1
+ module Cucumber
2
+ module Rake
3
+ # Defines a task for running stories.
4
+ # TODO: Base on http://github.com/dchelimsky/rspec/tree/master/lib/spec/rake/spectask.rb
5
+ class Task
6
+ LIB = File.expand_path(File.dirname(__FILE__) + '/../..')
7
+ BINARY = File.expand_path(File.dirname(__FILE__) + '/../../../bin/cucumber')
8
+
9
+ attr_accessor :libs
10
+ attr_accessor :step_list
11
+ attr_accessor :step_pattern
12
+ attr_accessor :story_list
13
+ attr_accessor :story_pattern
14
+ attr_accessor :cucumber_opts
15
+
16
+ # Define a task
17
+ def initialize(stories_path = "stories")
18
+ @stories_path = stories_path
19
+ @libs = [LIB]
20
+
21
+ yield self if block_given?
22
+
23
+ @story_pattern = "#{@stories_path}/**/*.story" if story_pattern.nil? && story_list.nil?
24
+ @step_pattern = "#{@stories_path}/**/*.rb" if step_pattern.nil? && step_list.nil?
25
+ define_tasks
26
+ end
27
+
28
+ def define_tasks
29
+ namespace :cucumber do
30
+ desc "Run Cucumber Stories under #{@stories_path}"
31
+ task @stories_path do
32
+ args = []
33
+ args << '-I'
34
+ args << '"%s"' % libs.join(File::PATH_SEPARATOR)
35
+ args << '"%s"' % BINARY
36
+ args << (ENV['CUCUMBER_OPTS'] || cucumber_opts)
37
+
38
+ step_files.each do |step_file|
39
+ args << '--require'
40
+ args << step_file
41
+ end
42
+ args << story_files
43
+ args.flatten!
44
+ args.compact!
45
+ ruby(args.join(" ")) # ruby(*args) is broken on Windows
46
+ end
47
+ end
48
+ end
49
+
50
+
51
+ def story_files # :nodoc:
52
+ if ENV['STORY']
53
+ FileList[ ENV['STORY'] ]
54
+ else
55
+ result = []
56
+ result += story_list.to_a if story_list
57
+ result += FileList[story_pattern].to_a if story_pattern
58
+ FileList[result]
59
+ end
60
+ end
61
+
62
+ def step_files # :nodoc:
63
+ if ENV['STEPS']
64
+ FileList[ ENV['STEPS'] ]
65
+ else
66
+ result = []
67
+ result += step_list.to_a if step_list
68
+ result += FileList[step_pattern].to_a if step_pattern
69
+ FileList[result]
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,14 @@
1
+ require 'cucumber/ruby_tree/nodes'
2
+
3
+ module Cucumber
4
+ # Classes in this module implement the pure ruby stories in Cucumber.
5
+ module RubyTree
6
+ def Story(header, narrative, &proc)
7
+ stories << RubyStory.new(header, narrative, &proc)
8
+ end
9
+
10
+ def stories #:nodoc:
11
+ @stories ||= Tree::Stories.new
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,68 @@
1
+ require 'cucumber/tree'
2
+
3
+ module Cucumber
4
+ module RubyTree
5
+ class RubyStory
6
+ include Tree::Story
7
+
8
+ def initialize(header, narrative, &proc)
9
+ @header, @narrative = header, narrative
10
+ @scenarios = []
11
+ instance_eval(&proc)
12
+ end
13
+
14
+ def Scenario(name, &proc)
15
+ @scenarios << RubyScenario.new(name, &proc)
16
+ end
17
+
18
+ protected
19
+
20
+ attr_reader :header, :narrative, :scenarios
21
+
22
+ end
23
+
24
+ class RubyScenario
25
+ include Tree::Scenario
26
+
27
+ def initialize(name, &proc)
28
+ @name = name
29
+ @steps = []
30
+ @line = *caller[2].split(':')[1].to_i
31
+ instance_eval(&proc)
32
+ end
33
+
34
+ def Given(name)
35
+ @steps << RubyStep.new('Given', name)
36
+ end
37
+
38
+ def When(name)
39
+ @steps << RubyStep.new('When', name)
40
+ end
41
+
42
+ def Then(name)
43
+ @steps << RubyStep.new('Then', name)
44
+ end
45
+
46
+ def And(name)
47
+ @steps << RubyStep.new('And', name)
48
+ end
49
+
50
+ attr_reader :name, :steps, :line
51
+
52
+ end
53
+
54
+ class RubyStep
55
+ include Tree::Step
56
+ attr_accessor :error
57
+
58
+ def initialize(keyword, name)
59
+ @keyword, @name = keyword, name
60
+ @file, @line, _ = *caller[2].split(':')
61
+ end
62
+
63
+ attr_reader :keyword, :name, :file, :line
64
+
65
+ end
66
+ end
67
+ end
68
+
@@ -0,0 +1,39 @@
1
+ require 'cucumber/step_mother'
2
+
3
+ module Cucumber
4
+ module StepMethods
5
+ def World(&proc)
6
+ $executor.register_world_proc(&proc)
7
+ end
8
+
9
+ def Before(&proc)
10
+ $executor.register_before_proc(&proc)
11
+ end
12
+
13
+ def After(&proc)
14
+ $executor.register_after_proc(&proc)
15
+ end
16
+
17
+ def Given(key, &proc)
18
+ step_mother.register_step_proc(key, &proc)
19
+ end
20
+
21
+ def When(key, &proc)
22
+ step_mother.register_step_proc(key, &proc)
23
+ end
24
+
25
+ def Then(key, &proc)
26
+ step_mother.register_step_proc(key, &proc)
27
+ end
28
+
29
+ # Simple workaround for old skool steps
30
+ def steps_for(*_)
31
+ STDERR.puts "WARNING: In Cucumber the steps_for method is obsolete"
32
+ yield
33
+ end
34
+
35
+ def step_mother #:nodoc:
36
+ @step_mother ||= StepMother.new
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,38 @@
1
+ require 'cucumber/parser/top_down_visitor'
2
+ require 'cucumber/core_ext/proc'
3
+
4
+ module Cucumber
5
+ # A StepMother keeps track of step procs and assigns them
6
+ # to each step when visiting the tree.
7
+ class StepMother < Parser::TopDownVisitor
8
+ def initialize
9
+ @step_procs = {}
10
+ end
11
+
12
+ def register_step_proc(key, &proc)
13
+ regexp = case(key)
14
+ when String
15
+ Regexp.new("^#{key}$") # TODO: replace $variable with (.*)
16
+ when Regexp
17
+ key
18
+ else
19
+ raise "Step patterns must be Regexp or String, but was: #{key.inspect}"
20
+ end
21
+ proc.extend(CoreExt::CallIn)
22
+ proc.name = key.inspect
23
+ @step_procs[regexp] = proc
24
+ end
25
+
26
+ def visit_step(step)
27
+ # Maybe we shouldn't attach the regexp etc to
28
+ # the step? Maybe steps pull them out as needed?
29
+ # Do we then have to attach ourself to the step instead?
30
+ # What would we gain from a pull design?
31
+ @step_procs.each do |regexp, proc|
32
+ if step.name =~ regexp
33
+ step.attach(regexp, proc, $~.captures)
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,127 @@
1
+ require 'cucumber/core_ext/proc'
2
+ require 'cucumber/core_ext/string'
3
+
4
+ module Cucumber
5
+ module Tree
6
+ class Stories
7
+ def initialize
8
+ @stories = []
9
+ end
10
+
11
+ def length
12
+ @stories.length
13
+ end
14
+
15
+ def <<(story)
16
+ @stories << story
17
+ end
18
+
19
+ def accept(visitor)
20
+ @stories.each{|story| visitor.visit_story(story)}
21
+ end
22
+ end
23
+
24
+ module Story
25
+ def accept(visitor)
26
+ visitor.visit_header(header)
27
+ visitor.visit_narrative(narrative)
28
+ scenarios.each do |scenario|
29
+ visitor.visit_scenario(scenario)
30
+ end
31
+ end
32
+ end
33
+
34
+ module Scenario
35
+ def accept(visitor)
36
+ steps.each do |step|
37
+ visitor.visit_step(step)
38
+ end
39
+ end
40
+
41
+ def at_line?(l)
42
+ line == l || steps.map{|s| s.line}.index(l)
43
+ end
44
+ end
45
+
46
+ module Step
47
+ def self.included(base)
48
+ base.class_eval do
49
+ def self.new_id!
50
+ @next_id ||= -1
51
+ @next_id += 1
52
+ end
53
+ end
54
+ end
55
+
56
+ attr_reader :error
57
+
58
+ def regexp
59
+ @regexp || //
60
+ end
61
+
62
+ PENDING = lambda do |*_|
63
+ raise Pending
64
+ end
65
+ PENDING.extend(CoreExt::CallIn)
66
+ PENDING.name = "PENDING"
67
+
68
+ def proc
69
+ @proc || PENDING
70
+ end
71
+
72
+ def attach(regexp, proc, args)
73
+ if @regexp
74
+ raise <<-EOM
75
+ "#{name}" matches several step definitions:
76
+
77
+ #{@proc.backtrace_line}
78
+ #{proc.backtrace_line}
79
+
80
+ Please give your steps unambiguous names
81
+ EOM
82
+ end
83
+ @regexp, @proc, @args = regexp, proc, args
84
+ end
85
+
86
+ def execute_in(world)
87
+ strip_pos = nil
88
+ begin
89
+ proc.call_in(world, *@args)
90
+ rescue ArgCountError => e
91
+ e.backtrace[0] = @proc.backtrace_line
92
+ strip_pos = e.backtrace.index("#{__FILE__}:#{__LINE__-3}:in `execute_in'")
93
+ format_error(strip_pos, e)
94
+ rescue => e
95
+ method_line = "#{__FILE__}:#{__LINE__-6}:in `execute_in'"
96
+ method_line_pos = e.backtrace.index(method_line)
97
+ if method_line_pos
98
+ strip_pos = method_line_pos - (Pending === e ? 3 : 2)
99
+ else
100
+ # This happens with rails, because they screw up the backtrace
101
+ # before we get here (injecting erb stactrace and such)
102
+ end
103
+ format_error(strip_pos, e)
104
+ end
105
+ end
106
+
107
+ def format_error(strip_pos, e)
108
+ @error = e
109
+ # Remove lines underneath the plain text step
110
+ e.backtrace[strip_pos..-1] = nil unless strip_pos.nil?
111
+ e.backtrace.flatten
112
+ # Replace the step line with something more readable
113
+ e.backtrace.replace(e.backtrace.map{|l| l.gsub(/`#{proc.meth}'/, "`#{keyword} #{proc.name}'")})
114
+ e.backtrace << "#{file}:#{line}:in `#{keyword} #{name}'"
115
+ raise e
116
+ end
117
+
118
+ def gzub(format=nil, &proc)
119
+ name.gzub(regexp, format, &proc)
120
+ end
121
+
122
+ def id
123
+ @id ||= self.class.new_id!
124
+ end
125
+ end
126
+ end
127
+ end