aslakhellesoy-cucumber 0.0.1 → 0.1.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 (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