aslakhellesoy-cucumber 0.0.1 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. data/License.txt +1 -1
  2. data/Manifest.txt +38 -24
  3. data/README.textile +31 -0
  4. data/TODO.txt +30 -0
  5. data/config/hoe.rb +6 -7
  6. data/examples/java/README.textile +52 -0
  7. data/examples/java/Rakefile +12 -0
  8. data/examples/java/features/hello.feature +11 -0
  9. data/examples/java/features/steps/hello_steps.rb +25 -0
  10. data/examples/java/features/steps/tree_steps.rb +14 -0
  11. data/examples/java/features/tree.feature +9 -0
  12. data/examples/java/src/cucumber/demo/Hello.java +15 -0
  13. data/examples/pure_ruby/Rakefile +6 -0
  14. data/examples/pure_ruby/features/addition.rb +23 -0
  15. data/examples/pure_ruby/{steps → features/steps}/addition_steps.rb +0 -0
  16. data/examples/simple_norwegian/Rakefile +6 -0
  17. data/examples/simple_norwegian/{steg → features/steps}/matte_steg.rb.rb +0 -0
  18. data/examples/simple_norwegian/{summering.story → features/summering.feature} +4 -1
  19. data/examples/web/Rakefile +6 -0
  20. data/examples/web/features/search.feature +9 -0
  21. data/examples/web/features/steps/stories_steps.rb +51 -0
  22. data/gem_tasks/treetop.rake +8 -14
  23. data/lib/cucumber.rb +10 -3
  24. data/lib/cucumber/cli.rb +29 -19
  25. data/lib/cucumber/core_ext/proc.rb +13 -5
  26. data/lib/cucumber/executor.rb +8 -10
  27. data/lib/cucumber/formatters/ansicolor.rb +2 -2
  28. data/lib/cucumber/formatters/html_formatter.rb +6 -6
  29. data/lib/cucumber/formatters/pretty_formatter.rb +68 -15
  30. data/lib/cucumber/{parser/languages.yml → languages.yml} +0 -4
  31. data/lib/cucumber/rake/task.rb +24 -26
  32. data/lib/cucumber/step_mother.rb +3 -3
  33. data/lib/cucumber/tree.rb +8 -117
  34. data/lib/cucumber/tree/feature.rb +45 -0
  35. data/lib/cucumber/tree/features.rb +21 -0
  36. data/lib/cucumber/tree/scenario.rb +79 -0
  37. data/lib/cucumber/tree/step.rb +133 -0
  38. data/lib/cucumber/tree/table.rb +26 -0
  39. data/lib/cucumber/{parser → tree}/top_down_visitor.rb +5 -8
  40. data/lib/cucumber/treetop_parser/feature.treetop.erb +98 -0
  41. data/lib/cucumber/treetop_parser/feature_en.rb +923 -0
  42. data/lib/cucumber/treetop_parser/feature_fr.rb +923 -0
  43. data/lib/cucumber/treetop_parser/feature_no.rb +923 -0
  44. data/lib/cucumber/treetop_parser/feature_parser.rb +32 -0
  45. data/lib/cucumber/treetop_parser/feature_pt.rb +923 -0
  46. data/lib/cucumber/version.rb +2 -2
  47. data/script/console +1 -1
  48. data/spec/cucumber/executor_spec.rb +9 -9
  49. data/spec/cucumber/formatters/{stories.html → features.html} +9 -9
  50. data/spec/cucumber/formatters/html_formatter_spec.rb +11 -11
  51. data/spec/cucumber/{sell_cucumbers.story → sell_cucumbers.feature} +1 -1
  52. data/spec/spec_helper.rb +8 -1
  53. metadata +61 -30
  54. data/README.txt +0 -78
  55. data/examples/Rakefile +0 -7
  56. data/examples/pure_ruby/addition.rb +0 -16
  57. data/examples/simple/addition.story +0 -12
  58. data/examples/simple/division.story +0 -17
  59. data/examples/simple/steps/addition_steps.rb +0 -43
  60. data/examples/web/run_stories.story +0 -10
  61. data/examples/web/steps/stories_steps.rb +0 -39
  62. data/lib/cucumber/parser/nodes.rb +0 -88
  63. data/lib/cucumber/parser/story_parser.rb +0 -13
  64. data/lib/cucumber/parser/story_parser.treetop.erb +0 -41
  65. data/lib/cucumber/parser/story_parser_en.rb +0 -554
  66. data/lib/cucumber/parser/story_parser_fr.rb +0 -554
  67. data/lib/cucumber/parser/story_parser_no.rb +0 -554
  68. data/lib/cucumber/parser/story_parser_pt.rb +0 -554
  69. data/lib/cucumber/ruby_tree.rb +0 -14
  70. data/lib/cucumber/ruby_tree/nodes.rb +0 -68
@@ -1,6 +1,6 @@
1
1
  module Cucumber
2
2
  module Rake
3
- # Defines a task for running stories.
3
+ # Defines a task for running features.
4
4
  # TODO: Base on http://github.com/dchelimsky/rspec/tree/master/lib/spec/rake/spectask.rb
5
5
  class Task
6
6
  LIB = File.expand_path(File.dirname(__FILE__) + '/../..')
@@ -9,52 +9,50 @@ module Cucumber
9
9
  attr_accessor :libs
10
10
  attr_accessor :step_list
11
11
  attr_accessor :step_pattern
12
- attr_accessor :story_list
13
- attr_accessor :story_pattern
12
+ attr_accessor :feature_list
13
+ attr_accessor :feature_pattern
14
14
  attr_accessor :cucumber_opts
15
15
 
16
16
  # Define a task
17
- def initialize(stories_path = "stories")
18
- @stories_path = stories_path
17
+ def initialize(task_name = "features", desc = "Run Features")
18
+ @task_name, @desc = task_name, desc
19
19
  @libs = [LIB]
20
20
 
21
21
  yield self if block_given?
22
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?
23
+ @feature_pattern = "features/**/*.feature" if feature_pattern.nil? && feature_list.nil?
24
+ @step_pattern = "features/**/*.rb" if step_pattern.nil? && step_list.nil?
25
25
  define_tasks
26
26
  end
27
27
 
28
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)
29
+ desc @desc
30
+ task @task_name do
31
+ args = []
32
+ args << '-I'
33
+ args << '"%s"' % libs.join(File::PATH_SEPARATOR)
34
+ args << '"%s"' % BINARY
35
+ args << (ENV['CUCUMBER_OPTS'] || cucumber_opts)
37
36
 
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
37
+ step_files.each do |step_file|
38
+ args << '--require'
39
+ args << step_file
46
40
  end
41
+ args << feature_files
42
+ args.flatten!
43
+ args.compact!
44
+ ruby(args.join(" ")) # ruby(*args) is broken on Windows
47
45
  end
48
46
  end
49
47
 
50
48
 
51
- def story_files # :nodoc:
49
+ def feature_files # :nodoc:
52
50
  if ENV['STORY']
53
51
  FileList[ ENV['STORY'] ]
54
52
  else
55
53
  result = []
56
- result += story_list.to_a if story_list
57
- result += FileList[story_pattern].to_a if story_pattern
54
+ result += feature_list.to_a if feature_list
55
+ result += FileList[feature_pattern].to_a if feature_pattern
58
56
  FileList[result]
59
57
  end
60
58
  end
@@ -1,10 +1,10 @@
1
- require 'cucumber/parser/top_down_visitor'
1
+ require 'cucumber/tree/top_down_visitor'
2
2
  require 'cucumber/core_ext/proc'
3
3
 
4
4
  module Cucumber
5
5
  # A StepMother keeps track of step procs and assigns them
6
6
  # to each step when visiting the tree.
7
- class StepMother < Parser::TopDownVisitor
7
+ class StepMother < Tree::TopDownVisitor
8
8
  def initialize
9
9
  @step_procs = {}
10
10
  end
@@ -29,7 +29,7 @@ module Cucumber
29
29
  # Do we then have to attach ourself to the step instead?
30
30
  # What would we gain from a pull design?
31
31
  @step_procs.each do |regexp, proc|
32
- if step.name =~ regexp
32
+ if step.respond_to?(:name) && step.name =~ regexp
33
33
  step.attach(regexp, proc, $~.captures)
34
34
  end
35
35
  end
@@ -1,127 +1,18 @@
1
+ %w{features feature scenario step table top_down_visitor}.each{|f| require "cucumber/tree/#{f}"}
1
2
  require 'cucumber/core_ext/proc'
2
3
  require 'cucumber/core_ext/string'
3
4
 
4
5
  module Cucumber
5
6
  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
7
+ def Feature(header, &proc)
8
+ feature = Feature.new("Feature: " + header, &proc)
9
+ feature.file, _, _ = *caller[0].split(':')
10
+ features << feature
11
+ feature
22
12
  end
23
13
 
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
14
+ def features #:nodoc:
15
+ @features ||= Tree::Features.new
125
16
  end
126
17
  end
127
18
  end
@@ -0,0 +1,45 @@
1
+ module Cucumber
2
+ module Tree
3
+ class Feature
4
+ attr_accessor :file
5
+
6
+ def initialize(header, &proc)
7
+ @header = header
8
+ @scenarios = []
9
+ instance_eval(&proc) if block_given?
10
+ end
11
+
12
+ def add_scenario(name, &proc)
13
+ scenario = Scenario.new(self, name, &proc)
14
+ @scenarios << scenario
15
+ scenario
16
+ end
17
+
18
+ def add_row_scenario(template_scenario, values, line)
19
+ scenario = RowScenario.new(self, template_scenario, values, line)
20
+ @scenarios << scenario
21
+ scenario
22
+ end
23
+
24
+ def Scenario(name, &proc)
25
+ add_scenario(name, &proc)
26
+ end
27
+
28
+ def Table(matrix = [], &proc)
29
+ table = Table.new(matrix)
30
+ proc.call(table)
31
+ template_scenario = @scenarios.last
32
+ matrix[1..-1].each do |row|
33
+ @scenarios << RowScenario.new(self, template_scenario, row, row.line)
34
+ end
35
+ end
36
+
37
+ def accept(visitor)
38
+ visitor.visit_header(@header)
39
+ @scenarios.each do |scenario|
40
+ visitor.visit_scenario(scenario)
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,21 @@
1
+ module Cucumber
2
+ module Tree
3
+ class Features
4
+ def initialize
5
+ @features = []
6
+ end
7
+
8
+ def length
9
+ @features.length
10
+ end
11
+
12
+ def <<(feature)
13
+ @features << feature
14
+ end
15
+
16
+ def accept(visitor)
17
+ @features.each{|feature| visitor.visit_feature(feature)}
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,79 @@
1
+ module Cucumber
2
+ module Tree
3
+ class BaseScenario
4
+ def file
5
+ @feature.file
6
+ end
7
+
8
+ def accept(visitor)
9
+ steps.each do |step|
10
+ visitor.visit_step(step)
11
+ end
12
+ end
13
+
14
+ def at_line?(l)
15
+ line == l || steps.map{|s| s.line}.index(l)
16
+ end
17
+ end
18
+
19
+ class Scenario < BaseScenario
20
+
21
+ # If a table follows, the header will be stored here. Weird, but convenient.
22
+ attr_accessor :table_header
23
+
24
+ def initialize(feature, name, &proc)
25
+ @feature, @name = feature, name
26
+ @steps = []
27
+ instance_eval(&proc) if block_given?
28
+ end
29
+
30
+ def row?
31
+ false
32
+ end
33
+
34
+ def add_step(keyword, name, line)
35
+ @steps << Step.new(self, keyword, name, line)
36
+ end
37
+
38
+ def Given(name)
39
+ add_step('Given', name, *caller[0].split(':')[1].to_i)
40
+ end
41
+
42
+ def When(name)
43
+ add_step('When', name, *caller[0].split(':')[1].to_i)
44
+ end
45
+
46
+ def Then(name)
47
+ add_step('Then', name, *caller[0].split(':')[1].to_i)
48
+ end
49
+
50
+ def And(name)
51
+ add_step('And', name, *caller[0].split(':')[1].to_i)
52
+ end
53
+
54
+ attr_reader :name, :steps, :line
55
+
56
+ end
57
+
58
+ class RowScenario < BaseScenario
59
+ attr_reader :line
60
+
61
+ def initialize(feature, template_scenario, values, line)
62
+ @feature, @template_scenario, @values, @line = feature, template_scenario, values, line
63
+ end
64
+
65
+ def row?
66
+ true
67
+ end
68
+
69
+ def steps
70
+ @steps ||= @template_scenario.steps.map do |template_step|
71
+ args = template_step.args.map do
72
+ @values.shift
73
+ end
74
+ RowStep.new(self, template_step.keyword, template_step.proc, args)
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,133 @@
1
+ module Cucumber
2
+ module Tree
3
+ class BaseStep
4
+ def self.new_id!
5
+ @next_id ||= -1
6
+ @next_id += 1
7
+ end
8
+
9
+ attr_reader :error
10
+ attr_accessor :args
11
+
12
+ def file
13
+ @scenario.file
14
+ end
15
+
16
+ def regexp
17
+ @regexp || //
18
+ end
19
+
20
+ PENDING = lambda do |*_|
21
+ raise Pending
22
+ end
23
+ PENDING.extend(CoreExt::CallIn)
24
+ PENDING.name = "PENDING"
25
+
26
+ def proc
27
+ @proc || PENDING
28
+ end
29
+
30
+ def attach(regexp, proc, args)
31
+ if @regexp
32
+ raise <<-EOM
33
+ "#{name}" matches several step definitions:
34
+
35
+ #{@proc.backtrace_line}
36
+ #{proc.backtrace_line}
37
+
38
+ Please give your steps unambiguous names
39
+ EOM
40
+ end
41
+ @regexp, @proc, @args = regexp, proc, args
42
+ end
43
+
44
+ if defined?(JRUBY_VERSION)
45
+ PENDING_ADJUSTMENT = 2
46
+ REGULAR_ADJUSTMENT = 1
47
+ else
48
+ PENDING_ADJUSTMENT = 3
49
+ REGULAR_ADJUSTMENT = 2
50
+ end
51
+
52
+ def execute_in(world)
53
+ strip_pos = nil
54
+ begin
55
+ proc.call_in(world, *@args)
56
+ rescue ArgCountError => e
57
+ e.backtrace[0] = @proc.backtrace_line
58
+ strip_pos = e.backtrace.index("#{__FILE__}:#{__LINE__ - 3}:in `execute_in'")
59
+ format_error(strip_pos, e)
60
+ rescue => e
61
+ method_line = "#{__FILE__}:#{__LINE__ - 6}:in `execute_in'"
62
+ method_line_pos = e.backtrace.index(method_line)
63
+ if method_line_pos
64
+ strip_pos = method_line_pos - (Pending === e ? PENDING_ADJUSTMENT : REGULAR_ADJUSTMENT)
65
+ else
66
+ # This happens with rails, because they screw up the backtrace
67
+ # before we get here (injecting erb stactrace and such)
68
+ end
69
+ format_error(strip_pos, e)
70
+ end
71
+ end
72
+
73
+ def format_error(strip_pos, e)
74
+ @error = e
75
+ # Remove lines underneath the plain text step
76
+ e.backtrace[strip_pos..-1] = nil unless strip_pos.nil?
77
+ e.backtrace.flatten
78
+ # Replace the step line with something more readable
79
+ e.backtrace.replace(e.backtrace.map{|l| l.gsub(/`#{proc.meth}'/, "`#{keyword} #{proc.name}'")})
80
+ if row?
81
+ e.backtrace << "#{file}:#{line}:in `#{proc.name}'"
82
+ else
83
+ e.backtrace << "#{file}:#{line}:in `#{keyword} #{name}'"
84
+ end
85
+ raise e
86
+ end
87
+
88
+ def id
89
+ @id ||= self.class.new_id!
90
+ end
91
+ end
92
+
93
+ class Step < BaseStep
94
+ attr_accessor :error
95
+
96
+ def row?
97
+ false
98
+ end
99
+
100
+ def initialize(scenario, keyword, name, line)
101
+ @scenario, @keyword, @name, @line = scenario, keyword, name, line
102
+ @args = []
103
+ end
104
+
105
+ def gzub(format=nil, &proc)
106
+ name.gzub(regexp, format, &proc)
107
+ end
108
+
109
+ attr_reader :keyword, :name, :line
110
+ end
111
+
112
+ class RowStep < BaseStep
113
+ attr_reader :keyword
114
+
115
+ def initialize(scenario, keyword, proc, args)
116
+ @scenario, @keyword, @proc, @args = scenario, keyword, proc, args
117
+ end
118
+
119
+ def gzub(format=nil, &proc)
120
+ raise "WWW"
121
+ end
122
+
123
+ def row?
124
+ true
125
+ end
126
+
127
+ def line
128
+ @scenario.line
129
+ end
130
+ end
131
+
132
+ end
133
+ end