aslakhellesoy-cucumber 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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