aslakhellesoy-cucumber 0.1.99.23 → 0.1.100.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. data/History.txt +2 -6
  2. data/Manifest.txt +8 -2
  3. data/examples/i18n/et/features/jagamine.feature +9 -0
  4. data/examples/jbehave/README.textile +4 -1
  5. data/examples/jbehave/features/trading.feature +4 -0
  6. data/examples/jbehave/pom.xml +5 -0
  7. data/examples/jbehave/src/main/java/cukes/jbehave/examples/trader/scenarios/TraderSteps.java +6 -1
  8. data/examples/selenium/features/step_definitons/search_steps.rb +13 -0
  9. data/examples/selenium/features/support/env.rb +19 -0
  10. data/examples/selenium_webrat/Rakefile +6 -0
  11. data/examples/selenium_webrat/features/search.feature +9 -0
  12. data/examples/selenium_webrat/features/step_definitons/search_steps.rb +13 -0
  13. data/examples/selenium_webrat/features/support/env.rb +41 -0
  14. data/examples/self_test/features/background/failing_background.feature +1 -0
  15. data/examples/self_test/features/step_definitions/sample_steps.rb +1 -1
  16. data/examples/self_test/features/support/tag_count_formatter.rb +1 -1
  17. data/features/background.feature +9 -11
  18. data/features/cucumber_cli.feature +24 -1
  19. data/features/cucumber_cli_outlines.feature +10 -19
  20. data/features/report_called_undefined_steps.feature +2 -0
  21. data/gem_tasks/rspec.rake +2 -0
  22. data/lib/cucumber.rb +7 -15
  23. data/lib/cucumber/ast.rb +3 -3
  24. data/lib/cucumber/ast/background.rb +28 -66
  25. data/lib/cucumber/ast/examples.rb +15 -3
  26. data/lib/cucumber/ast/feature.rb +20 -24
  27. data/lib/cucumber/ast/feature_element.rb +46 -0
  28. data/lib/cucumber/ast/features.rb +2 -21
  29. data/lib/cucumber/ast/outline_table.rb +46 -14
  30. data/lib/cucumber/ast/py_string.rb +8 -3
  31. data/lib/cucumber/ast/scenario.rb +34 -73
  32. data/lib/cucumber/ast/scenario_outline.rb +40 -42
  33. data/lib/cucumber/ast/step.rb +53 -89
  34. data/lib/cucumber/ast/step_collection.rb +66 -0
  35. data/lib/cucumber/ast/step_invocation.rb +106 -0
  36. data/lib/cucumber/ast/table.rb +38 -19
  37. data/lib/cucumber/ast/tags.rb +4 -11
  38. data/lib/cucumber/ast/visitor.rb +31 -19
  39. data/lib/cucumber/broadcaster.rb +1 -1
  40. data/lib/cucumber/cli/configuration.rb +24 -16
  41. data/lib/cucumber/cli/language_help_formatter.rb +4 -4
  42. data/lib/cucumber/cli/main.rb +5 -4
  43. data/lib/cucumber/core_ext/proc.rb +2 -2
  44. data/lib/cucumber/formatter/ansicolor.rb +0 -1
  45. data/lib/cucumber/formatter/console.rb +18 -34
  46. data/lib/cucumber/formatter/html.rb +13 -10
  47. data/lib/cucumber/formatter/pretty.rb +48 -36
  48. data/lib/cucumber/formatter/profile.rb +6 -6
  49. data/lib/cucumber/formatter/progress.rb +12 -20
  50. data/lib/cucumber/formatter/rerun.rb +5 -5
  51. data/lib/cucumber/jbehave.rb +21 -26
  52. data/lib/cucumber/parser/feature.rb +26 -29
  53. data/lib/cucumber/parser/feature.tt +17 -12
  54. data/lib/cucumber/parser/treetop_ext.rb +13 -13
  55. data/lib/cucumber/platform.rb +0 -1
  56. data/lib/cucumber/rails/world.rb +2 -2
  57. data/lib/cucumber/rake/task.rb +0 -1
  58. data/lib/cucumber/step_definition.rb +21 -12
  59. data/lib/cucumber/step_match.rb +49 -0
  60. data/lib/cucumber/step_mother.rb +98 -80
  61. data/lib/cucumber/version.rb +2 -2
  62. data/lib/cucumber/world.rb +42 -0
  63. data/rails_generators/cucumber/templates/paths.rb +1 -1
  64. data/rails_generators/cucumber/templates/webrat_steps.rb +17 -17
  65. data/rails_generators/feature/feature_generator.rb +4 -0
  66. data/rails_generators/feature/templates/steps.erb +0 -4
  67. data/spec/cucumber/ast/background_spec.rb +32 -41
  68. data/spec/cucumber/ast/feature_factory.rb +10 -1
  69. data/spec/cucumber/ast/feature_spec.rb +7 -30
  70. data/spec/cucumber/ast/scenario_outline_spec.rb +3 -0
  71. data/spec/cucumber/ast/scenario_spec.rb +8 -25
  72. data/spec/cucumber/ast/step_collection_spec.rb +8 -0
  73. data/spec/cucumber/ast/step_spec.rb +37 -29
  74. data/spec/cucumber/ast/tags_spec.rb +2 -18
  75. data/spec/cucumber/cli/configuration_spec.rb +7 -0
  76. data/spec/cucumber/cli/main_spec.rb +1 -1
  77. data/spec/cucumber/parser/feature_parser_spec.rb +6 -5
  78. data/spec/cucumber/step_definition_spec.rb +5 -5
  79. data/spec/cucumber/step_mother_spec.rb +6 -6
  80. data/spec/cucumber/world/pending_spec.rb +1 -1
  81. metadata +17 -5
  82. data/lib/cucumber/ast/filter.rb +0 -22
  83. data/lib/cucumber/ast/steps.rb +0 -13
@@ -12,11 +12,13 @@ Feature: Cucumber command line
12
12
  Given a step definition that calls an undefined step # features/step_definitions/sample_steps.rb:19
13
13
  Undefined step: "this does not exist" (Cucumber::Undefined)
14
14
  ./features/step_definitions/sample_steps.rb:20:in `/^a step definition that calls an undefined step$/'
15
+ features/call_undefined_step_from_step_def.feature:4:in `Given a step definition that calls an undefined step'
15
16
 
16
17
  Scenario: Call via another # features/call_undefined_step_from_step_def.feature:6
17
18
  Given call step "a step definition that calls an undefined step" # features/step_definitions/sample_steps.rb:23
18
19
  Undefined step: "this does not exist" (Cucumber::Undefined)
19
20
  ./features/step_definitions/sample_steps.rb:20:in `/^a step definition that calls an undefined step$/'
21
+ features/call_undefined_step_from_step_def.feature:7:in `Given call step "a step definition that calls an undefined step"'
20
22
 
21
23
  2 scenarios
22
24
  2 undefined steps
data/gem_tasks/rspec.rake CHANGED
@@ -31,5 +31,7 @@ if require_spec
31
31
  Spec::Rake::SpecTask.new do |t|
32
32
  t.spec_opts = ['--options', "spec/spec.opts"]
33
33
  t.spec_files = FileList['spec/**/*_spec.rb']
34
+ t.rcov = ENV['RCOV']
35
+ t.rcov_opts = %w{--exclude osx\/objc,gems\/,spec\/}
34
36
  end
35
37
  end
data/lib/cucumber.rb CHANGED
@@ -44,24 +44,16 @@ module Cucumber
44
44
  alias_steps(keywords)
45
45
  end
46
46
 
47
- # Sets up additional aliases for Given, When and Then.
48
- # Try adding the following to your <tt>support/env.rb</tt>:
49
- #
50
- # # Given When Then in Norwegian
51
- # Cucumber.alias_steps %w{Gitt Naar Saa}
52
- #
53
- # You cannot use special characters here, because methods
54
- # with special characters is not valid Ruby code
47
+ # Sets up additional method aliases for Given, When and Then.
48
+ # This does *not* affect how feature files are parsed. If you
49
+ # want to create aliases in the parser, you have to do this in
50
+ # languages.yml. For example:
55
51
  #
52
+ # and: And|With
56
53
  def alias_steps(keywords)
57
54
  keywords.each do |adverb|
58
- StepMother.class_eval do
59
- alias_method adverb, :register_step_definition
60
- end
61
-
62
- StepMother::WorldMethods.class_eval do
63
- alias_method adverb, :__cucumber_invoke
64
- end
55
+ StepMother.alias_adverb(adverb)
56
+ World.alias_adverb(adverb)
65
57
  end
66
58
  end
67
59
  end
data/lib/cucumber/ast.rb CHANGED
@@ -2,17 +2,17 @@ require 'cucumber/ast/comment'
2
2
  require 'cucumber/ast/tags'
3
3
  require 'cucumber/ast/features'
4
4
  require 'cucumber/ast/feature'
5
+ require 'cucumber/ast/background'
5
6
  require 'cucumber/ast/scenario'
6
7
  require 'cucumber/ast/scenario_outline'
7
- require 'cucumber/ast/background'
8
- require 'cucumber/ast/steps'
8
+ require 'cucumber/ast/step_invocation'
9
+ require 'cucumber/ast/step_collection'
9
10
  require 'cucumber/ast/step'
10
11
  require 'cucumber/ast/table'
11
12
  require 'cucumber/ast/py_string'
12
13
  require 'cucumber/ast/outline_table'
13
14
  require 'cucumber/ast/examples'
14
15
  require 'cucumber/ast/visitor'
15
- require 'cucumber/ast/filter'
16
16
 
17
17
  module Cucumber
18
18
  # Classes in this module represent the Abstract Syntax Tree (AST)
@@ -1,88 +1,50 @@
1
+ require 'cucumber/ast/feature_element'
2
+
1
3
  module Cucumber
2
4
  module Ast
3
- class Background < Scenario
4
-
5
- attr_accessor :world
6
- attr_reader :status
5
+ class Background
6
+ include FeatureElement
7
+ attr_writer :feature
7
8
 
8
9
  def initialize(comment, line, keyword, steps)
9
- @record_executed_steps = true
10
- super(comment, Tags.new(1, []), line, keyword, "", steps)
10
+ @comment, @line, @keyword, @steps = comment, line, keyword, StepCollection.new(steps)
11
+ attach_steps(steps)
12
+ @step_invocations = @steps.step_invocations(true)
11
13
  end
12
14
 
13
- def accept(visitor)
14
- @world = visitor.new_world
15
- if already_visited_steps?
16
- @status = execute_steps(visitor)
15
+ def step_collection(step_invocations)
16
+ unless(@first_collection_created)
17
+ @first_collection_created = true
18
+ @step_invocations.dup(step_invocations)
17
19
  else
18
- @status = visit_background_and_steps(visitor, @steps)
19
- @steps_visited = true
20
+ @steps.step_invocations(true).dup(step_invocations)
20
21
  end
21
22
  end
22
23
 
23
- def step_executed(step)
24
- @feature.step_executed(step) if @feature && @record_executed_steps
24
+ def accept(visitor)
25
+ visitor.visit_comment(@comment)
26
+ visitor.visit_background_name(@keyword, "", file_colon_line(@line), source_indent(text_length))
27
+ visitor.step_mother.before_and_after(self)
28
+ visitor.visit_steps(@step_invocations)
29
+ @failed = @step_invocations.detect{|step_invocation| step_invocation.exception}
30
+ end
31
+
32
+ def failed?
33
+ @failed
25
34
  end
26
35
 
27
- def already_visited_steps?
28
- @steps_visited
36
+ def text_length
37
+ @keyword.jlength
29
38
  end
30
39
 
31
- def to_sexp #:nodoc:
40
+ def to_sexp
32
41
  sexp = [:background, @line, @keyword]
33
42
  comment = @comment.to_sexp
34
43
  sexp += [comment] if comment
35
- tags = @tags.to_sexp
36
- sexp += tags if tags.any?
37
- steps = @steps.map{|step| step.to_sexp}
44
+ steps = @steps.to_sexp
38
45
  sexp += steps if steps.any?
39
46
  sexp
40
47
  end
41
-
42
- private
43
-
44
- def visit_background_and_steps(visitor, steps)
45
- visitor.visit_comment(@comment)
46
- visitor.visit_scenario_name(@keyword, @name, file_line(@line), source_indent(text_length))
47
-
48
- previous = :passed
49
- steps.each do |step|
50
- step.previous = previous
51
- step.world = @world
52
- visitor.visit_step(step)
53
- previous = step.status
54
- end
55
- previous
56
- end
57
-
58
- def execute_steps(visitor)
59
- previous = :passed
60
- executed_steps = []
61
- exception = nil
62
- @steps.each do |step|
63
- executed_step, previous, _ = step.execute_as_new(@world, previous, visitor, @line)
64
- executed_steps << executed_step
65
- exception ||= executed_step.exception
66
- end
67
- @steps = executed_steps
68
-
69
- if exception && @status != :failed
70
- without_recording_steps do
71
- @steps_visited = false
72
- #Since the steps have already been executed they will not be re-run, they will just be displayed
73
- visitor.visit_background(self)
74
- end
75
- end
76
-
77
- previous
78
- end
79
-
80
- def without_recording_steps
81
- @record_executed_steps = false
82
- yield
83
- @record_executed_steps = true
84
- end
85
-
86
48
  end
87
49
  end
88
- end
50
+ end
@@ -10,12 +10,24 @@ module Cucumber
10
10
  visitor.visit_outline_table(@outline_table)
11
11
  end
12
12
 
13
+ def descend?(visitor)
14
+ @outline_table.descend?(visitor)
15
+ end
16
+
17
+ def skip_invoke!
18
+ @outline_table.skip_invoke!
19
+ end
20
+
21
+ def matches_scenario_names?(scenario_names)
22
+ scenario_names.detect{|name| name == @name}
23
+ end
24
+
13
25
  def each_example_row(&proc)
14
- @outline_table.each_cells_row(&proc)
26
+ @outline_table.cells_rows[1..-1].each(&proc)
15
27
  end
16
28
 
17
- def at_lines?(lines)
18
- lines.empty? || lines.index(@line) || @outline_table.at_lines?(lines)
29
+ def matches_lines?(lines)
30
+ lines.index(@line) || @outline_table.matches_lines?(lines)
19
31
  end
20
32
 
21
33
  def to_sexp
@@ -5,23 +5,13 @@ module Cucumber
5
5
  attr_accessor :file
6
6
  attr_writer :features, :lines
7
7
 
8
- def initialize(comment, tags, name, feature_elements, background = nil)
9
- @comment, @tags, @name, @feature_elements, @background = comment, tags, name, feature_elements, background
10
- feature_elements.each do |feature_element|
11
- feature_element.feature = self
12
- feature_element.background = background if background
13
- end
14
- background.feature = self if background
8
+ def initialize(background, comment, tags, name, feature_elements)
9
+ @background, @comment, @tags, @name, @feature_elements = background, comment, tags, name, feature_elements
15
10
  @lines = []
16
- end
17
11
 
18
- def tagged_with?(tag_names, check_elements=true)
19
- @tags.among?(tag_names) ||
20
- (check_elements && @feature_elements.detect{|e| e.tagged_with?(tag_names)})
21
- end
22
-
23
- def matches_scenario_names?(scenario_names)
24
- @feature_elements.detect{|e| e.matches_scenario_names?(scenario_names)}
12
+ @feature_elements.each do |feature_element|
13
+ feature_element.feature = self
14
+ end
25
15
  end
26
16
 
27
17
  def accept(visitor)
@@ -29,25 +19,31 @@ module Cucumber
29
19
  visitor.visit_comment(@comment)
30
20
  visitor.visit_tags(@tags)
31
21
  visitor.visit_feature_name(@name)
32
-
22
+ visitor.visit_background(@background) if @background
33
23
  @feature_elements.each do |feature_element|
34
- visitor.visit_feature_element(feature_element) if @features.visit?(feature_element, @lines)
24
+ visitor.visit_feature_element(feature_element) if feature_element.descend?(visitor)
35
25
  end
36
26
  end
37
27
 
38
- def scenario_executed(scenario)
39
- @features.scenario_executed(scenario) if @features
28
+ def descend?(visitor)
29
+ @feature_elements.detect{ |feature_element| feature_element.descend?(visitor) }
30
+ end
31
+
32
+ def has_tags?(tags)
33
+ @tags.has_tags?(tags)
40
34
  end
41
35
 
42
- def step_executed(step)
43
- @features.step_executed(step) if @features
36
+ def next_feature_element(feature_element, &proc)
37
+ index = @feature_elements.index(feature_element)
38
+ next_one = @feature_elements[index+1]
39
+ proc.call(next_one) if next_one
44
40
  end
45
41
 
46
42
  def backtrace_line(step_name, line)
47
- "#{file_line(line)}:in `#{step_name}'"
43
+ "#{file_colon_line(line)}:in `#{step_name}'"
48
44
  end
49
45
 
50
- def file_line(line)
46
+ def file_colon_line(line)
51
47
  "#{@file}:#{line}"
52
48
  end
53
49
 
@@ -58,7 +54,7 @@ module Cucumber
58
54
  tags = @tags.to_sexp
59
55
  sexp += tags if tags.any?
60
56
  sexp += [@background.to_sexp] if @background
61
- sexp += @feature_elements.map{|e| e.to_sexp}
57
+ sexp += @feature_elements.map{|fe| fe.to_sexp}
62
58
  sexp
63
59
  end
64
60
  end
@@ -0,0 +1,46 @@
1
+ module Cucumber
2
+ module FeatureElement
3
+ def attach_steps(steps)
4
+ steps.each {|step| step.feature_element = self}
5
+ end
6
+
7
+ def file_colon_line(line = @line)
8
+ @feature.file_colon_line(line) if @feature
9
+ end
10
+
11
+ def text_length
12
+ @keyword.jlength + @name.jlength
13
+ end
14
+
15
+ def matches_lines?(lines)
16
+ lines.index(@line) || @steps.matches_lines?(lines) || @tags.matches_lines?(lines)
17
+ end
18
+
19
+ def has_tags?(tags)
20
+ @tags.has_tags?(tags) || @feature.has_tags?(tags)
21
+ end
22
+
23
+ def matches_scenario_names?(scenario_names)
24
+ scenario_names.detect{|name| name == @name}
25
+ end
26
+
27
+ def backtrace_line(name = "#{@keyword} #{@name}", line = @line)
28
+ @feature.backtrace_line(name, line) if @feature
29
+ end
30
+
31
+ def source_indent(text_length)
32
+ max_line_length - text_length
33
+ end
34
+
35
+ def max_line_length
36
+ @steps.max_line_length(self)
37
+ end
38
+
39
+ # TODO: Remove when we use StepCollection everywhere
40
+ def previous_step(step)
41
+ i = @steps.index(step) || -1
42
+ @steps[i-1]
43
+ end
44
+
45
+ end
46
+ end
@@ -1,14 +1,8 @@
1
1
  module Cucumber
2
2
  module Ast
3
3
  class Features
4
- attr_reader :steps, :scenarios
5
-
6
- def initialize(filter)
7
- @filter = filter
8
-
4
+ def initialize
9
5
  @features = []
10
- @scenarios = []
11
- @steps = Hash.new{|steps, status| steps[status] = []}
12
6
  end
13
7
 
14
8
  def add_feature(feature)
@@ -16,22 +10,9 @@ module Cucumber
16
10
  @features << feature
17
11
  end
18
12
 
19
- def visit?(node, lines)
20
- @filter.matched?(node) &&
21
- (lines.empty? ? true : node.at_lines?(lines))
22
- end
23
-
24
- def scenario_executed(scenario)
25
- @scenarios << scenario
26
- end
27
-
28
- def step_executed(step)
29
- @steps[step.status] << step
30
- end
31
-
32
13
  def accept(visitor)
33
14
  @features.each do |feature|
34
- visitor.visit_feature(feature) if visit?(feature, [])
15
+ visitor.visit_feature(feature) if feature.descend?(visitor)
35
16
  end
36
17
  end
37
18
  end
@@ -5,35 +5,67 @@ module Cucumber
5
5
  super(raw)
6
6
  @scenario_outline = scenario_outline
7
7
  @cells_class = ExampleCells
8
+
9
+ cells_rows.each do |cells|
10
+ cells.create_step_invocations!(scenario_outline)
11
+ end
8
12
  end
9
13
 
10
- def accept(visitor, status)
14
+ def accept(visitor)
11
15
  cells_rows.each_with_index do |row, n|
12
- should_visit = n == 0 ||
13
- row.at_lines?(visitor.current_feature_lines) ||
14
- @scenario_outline.at_header_or_step_lines?(visitor.current_feature_lines)
15
-
16
- if should_visit
17
- visitor.visit_table_row(row, status)
16
+ if n == 0 || matches?(visitor, row)
17
+ visitor.visit_table_row(row)
18
18
  end
19
19
  end
20
20
  nil
21
21
  end
22
22
 
23
- def execute_row(cells, visitor, &proc)
24
- @scenario_outline.execute_row(cells, visitor, &proc)
23
+ def descend?(visitor)
24
+ cells_rows.detect{|cells_row| cells_row.descend?(visitor)}
25
+ end
26
+
27
+ def matches?(visitor, cells)
28
+ @scenario_outline.matches_tags_and_name?(visitor) &&
29
+ (visitor.matches_lines?(cells) || visitor.matches_lines?(@scenario_outline))
30
+ end
31
+
32
+ def skip_invoke!
33
+ cells_rows.each do |cells|
34
+ cells.skip_invoke!
35
+ end
25
36
  end
26
37
 
27
38
  class ExampleCells < Cells
28
- def accept(visitor, status)
39
+ def create_step_invocations!(scenario_outline)
40
+ @step_invocations = scenario_outline.step_invocations(self)
41
+ end
42
+
43
+ def descend?(visitor)
44
+ @table.matches?(visitor, self)
45
+ end
46
+
47
+ def skip_invoke!
48
+ @step_invocations.each do |step_invocation|
49
+ step_invocation.skip_invoke!
50
+ end
51
+ end
52
+
53
+ def accept(visitor)
29
54
  if header?
30
55
  @cells.each do |cell|
31
- visitor.visit_table_cell(cell, :thead)
56
+ cell.status = :skipped
57
+ visitor.visit_table_cell(cell)
32
58
  end
33
- nil
34
59
  else
35
- exception = @table.execute_row(self, visitor) do |cell, status|
36
- visitor.visit_table_cell(cell, status)
60
+ visitor.step_mother.before_and_after(self) do
61
+ @step_invocations.each do |step_invocation|
62
+ step_invocation.invoke(visitor.step_mother, visitor.options)
63
+ @exception ||= step_invocation.exception
64
+ end
65
+
66
+ @cells.each do |cell|
67
+ visitor.visit_table_cell(cell)
68
+ end
37
69
  end
38
70
  end
39
71
  end