cucumber-core 1.0.0.beta.3 → 1.0.0.beta.4

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 (36) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +6 -0
  3. data/HISTORY.md +20 -0
  4. data/README.md +121 -3
  5. data/cucumber-core.gemspec +1 -0
  6. data/lib/cucumber/core.rb +19 -13
  7. data/lib/cucumber/core/ast/data_table.rb +1 -1
  8. data/lib/cucumber/core/ast/examples_table.rb +5 -4
  9. data/lib/cucumber/core/ast/feature.rb +7 -1
  10. data/lib/cucumber/core/ast/scenario.rb +1 -1
  11. data/lib/cucumber/core/ast/step.rb +2 -2
  12. data/lib/cucumber/core/compiler.rb +7 -0
  13. data/lib/cucumber/core/gherkin/ast_builder.rb +15 -10
  14. data/lib/cucumber/core/platform.rb +0 -15
  15. data/lib/cucumber/core/report/summary.rb +26 -0
  16. data/lib/cucumber/core/test/case.rb +1 -1
  17. data/lib/cucumber/core/test/filters.rb +2 -47
  18. data/lib/cucumber/core/test/filters/locations_filter.rb +21 -0
  19. data/lib/cucumber/core/test/filters/name_filter.rb +27 -0
  20. data/lib/cucumber/core/test/hooks.rb +17 -0
  21. data/lib/cucumber/core/test/mapper.rb +14 -2
  22. data/lib/cucumber/core/test/result.rb +40 -30
  23. data/lib/cucumber/core/test/timer.rb +3 -1
  24. data/lib/cucumber/core/version.rb +1 -1
  25. data/spec/cucumber/core/ast/examples_table_spec.rb +19 -12
  26. data/spec/cucumber/core/ast/outline_step_spec.rb +3 -3
  27. data/spec/cucumber/core/gherkin/parser_spec.rb +18 -0
  28. data/spec/cucumber/core/test/action_spec.rb +3 -2
  29. data/spec/cucumber/core/test/duration_matcher.rb +19 -0
  30. data/spec/cucumber/core/test/mapper_spec.rb +30 -10
  31. data/spec/cucumber/core/test/result_spec.rb +47 -5
  32. data/spec/cucumber/core/test/runner_spec.rb +3 -2
  33. data/spec/cucumber/core/test/timer_spec.rb +13 -0
  34. data/spec/cucumber/core_spec.rb +33 -49
  35. data/spec/readme_spec.rb +36 -0
  36. metadata +26 -3
@@ -4,27 +4,12 @@ require 'rbconfig'
4
4
 
5
5
  module Cucumber
6
6
  unless defined?(Cucumber::VERSION)
7
- VERSION = '2.0'
8
- BINARY = File.expand_path(File.dirname(__FILE__) + '/../../bin/cucumber')
9
- LIBDIR = File.expand_path(File.dirname(__FILE__) + '/../../lib')
10
7
  JRUBY = defined?(JRUBY_VERSION)
11
8
  IRONRUBY = defined?(RUBY_ENGINE) && RUBY_ENGINE == "ironruby"
12
9
  WINDOWS = RbConfig::CONFIG['host_os'] =~ /mswin|mingw/
13
10
  OS_X = RbConfig::CONFIG['host_os'] =~ /darwin/
14
11
  WINDOWS_MRI = WINDOWS && !JRUBY && !IRONRUBY
15
- RAILS = defined?(Rails)
16
- RUBY_BINARY = File.join(RbConfig::CONFIG['bindir'], RbConfig::CONFIG['ruby_install_name'])
17
12
  RUBY_2_0 = RUBY_VERSION =~ /^2\.0/
18
13
  RUBY_1_9 = RUBY_VERSION =~ /^1\.9/
19
-
20
- class << self
21
- attr_accessor :use_full_backtrace
22
-
23
- # @private
24
- def file_mode(m, encoding="UTF-8")
25
- "#{m}:#{encoding}"
26
- end
27
- end
28
- self.use_full_backtrace = false
29
14
  end
30
15
  end
@@ -0,0 +1,26 @@
1
+ module Cucumber
2
+ module Core
3
+ module Report
4
+ class Summary
5
+ attr_reader :test_cases, :test_steps
6
+
7
+ def initialize
8
+ @test_cases = Test::Result::Summary.new
9
+ @test_steps = Test::Result::Summary.new
10
+ end
11
+
12
+ def after_test_case(test_case, result)
13
+ result.describe_to test_cases
14
+ end
15
+
16
+ def after_test_step(test_step, result)
17
+ result.describe_to test_steps
18
+ end
19
+
20
+ def method_missing(*)
21
+ end
22
+
23
+ end
24
+ end
25
+ end
26
+ end
@@ -6,7 +6,7 @@ module Cucumber
6
6
  module Test
7
7
  class Case
8
8
  include Cucumber.initializer(:test_steps, :source, :around_hooks)
9
- attr_reader :source
9
+ attr_reader :source, :test_steps
10
10
 
11
11
  def initialize(test_steps, source, around_hooks = [])
12
12
  super(test_steps, source, around_hooks)
@@ -1,48 +1,3 @@
1
+ require 'cucumber/core/test/filters/locations_filter'
2
+ require 'cucumber/core/test/filters/name_filter'
1
3
  require 'cucumber/core/test/filters/tag_filter'
2
- module Cucumber
3
- module Core
4
- module Test
5
-
6
- class LocationsFilter
7
- def initialize(locations, receiver)
8
- @receiver = receiver
9
- @locations = locations
10
- end
11
-
12
- def test_case(test_case)
13
- if test_case.match_locations?(@locations)
14
- test_case.describe_to @receiver
15
- end
16
- self
17
- end
18
-
19
- def done
20
- @receiver.done
21
- self
22
- end
23
- end
24
-
25
- class NameFilter
26
- include Cucumber.initializer(:name_regexps, :receiver)
27
-
28
- def test_case(test_case)
29
- if accept?(test_case)
30
- test_case.describe_to(receiver)
31
- end
32
- self
33
- end
34
-
35
- def done
36
- @receiver.done
37
- self
38
- end
39
-
40
- private
41
-
42
- def accept?(test_case)
43
- name_regexps.empty? || name_regexps.any? { |name_regexp| test_case.match_name?(name_regexp) }
44
- end
45
- end
46
- end
47
- end
48
- end
@@ -0,0 +1,21 @@
1
+ module Cucumber
2
+ module Core
3
+ module Test
4
+ class LocationsFilter
5
+ include Cucumber.initializer(:locations, :receiver)
6
+
7
+ def test_case(test_case)
8
+ if test_case.match_locations?(@locations)
9
+ test_case.describe_to @receiver
10
+ end
11
+ self
12
+ end
13
+
14
+ def done
15
+ @receiver.done
16
+ self
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,27 @@
1
+ module Cucumber
2
+ module Core
3
+ module Test
4
+ class NameFilter
5
+ include Cucumber.initializer(:name_regexps, :receiver)
6
+
7
+ def test_case(test_case)
8
+ if accept?(test_case)
9
+ test_case.describe_to(receiver)
10
+ end
11
+ self
12
+ end
13
+
14
+ def done
15
+ @receiver.done
16
+ self
17
+ end
18
+
19
+ private
20
+
21
+ def accept?(test_case)
22
+ name_regexps.empty? || name_regexps.any? { |name_regexp| test_case.match_name?(name_regexp) }
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -53,6 +53,23 @@ module Cucumber
53
53
  end
54
54
  end
55
55
 
56
+ class BeforeStepHook
57
+ include Cucumber.initializer(:location)
58
+ public :location
59
+
60
+ def name
61
+ "BeforeStep hook"
62
+ end
63
+
64
+ def match_locations?(queried_locations)
65
+ queried_locations.any? { |other_location| other_location.match?(location) }
66
+ end
67
+
68
+ def describe_to(visitor, *args)
69
+ visitor.before_step_hook(self, *args)
70
+ end
71
+ end
72
+
56
73
  class AfterStepHook
57
74
  include Cucumber.initializer(:location)
58
75
  public :location
@@ -33,7 +33,7 @@ module Cucumber
33
33
  hook_factory = HookFactory.new(test_step.source)
34
34
  mapper = StepMapper.new(test_step)
35
35
  test_step.describe_to mapping_definition, StepMapper::DSL.new(mapper, hook_factory)
36
- test_steps.push(*[mapper.test_step] + mapper.after_step_hooks)
36
+ test_steps.push(*(mapper.before_step_hooks + [mapper.test_step] + mapper.after_step_hooks))
37
37
  self
38
38
  end
39
39
 
@@ -65,7 +65,7 @@ module Cucumber
65
65
 
66
66
  # Run this block of code after the scenario
67
67
  def after(&block)
68
- mapper.after_hooks << hook_factory.after(block)
68
+ mapper.after_hooks.unshift(hook_factory.after(block))
69
69
  self
70
70
  end
71
71
 
@@ -83,6 +83,10 @@ module Cucumber
83
83
 
84
84
  attr_accessor :test_step
85
85
 
86
+ def before_step_hooks
87
+ @before_step_hooks ||= []
88
+ end
89
+
86
90
  def after_step_hooks
87
91
  @after_step_hooks ||= []
88
92
  end
@@ -91,6 +95,10 @@ module Cucumber
91
95
  class DSL
92
96
  include Cucumber.initializer(:mapper, :hook_factory)
93
97
 
98
+ def before(&block)
99
+ mapper.before_step_hooks << hook_factory.before_step(block)
100
+ end
101
+
94
102
  # Define the step with a block of code to be executed
95
103
  def map(&block)
96
104
  mapper.test_step = mapper.test_step.with_mapping(&block)
@@ -117,6 +125,10 @@ module Cucumber
117
125
  build_hook_step(block, Hooks::BeforeHook, Test::UnskippableAction)
118
126
  end
119
127
 
128
+ def before_step(block)
129
+ build_hook_step(block, Hooks::BeforeStepHook, Test::UnskippableAction)
130
+ end
131
+
120
132
  def after_step(block)
121
133
  build_hook_step(block, Hooks::AfterStepHook, Test::Action)
122
134
  end
@@ -81,7 +81,7 @@ module Cucumber
81
81
  class Raisable < StandardError
82
82
  attr_reader :message, :duration
83
83
 
84
- def initialize(message = "", duration = :unknown, backtrace = nil)
84
+ def initialize(message = "", duration = UnknownDuration.new, backtrace = nil)
85
85
  @message, @duration = message, duration
86
86
  super(message)
87
87
  set_backtrace(backtrace) if backtrace
@@ -101,7 +101,7 @@ module Cucumber
101
101
 
102
102
  def describe_to(visitor, *args)
103
103
  visitor.undefined(*args)
104
- visitor.duration(duration, *args) unless duration == :unknown
104
+ visitor.duration(duration, *args)
105
105
  self
106
106
  end
107
107
 
@@ -116,7 +116,7 @@ module Cucumber
116
116
 
117
117
  def describe_to(visitor, *args)
118
118
  visitor.skipped(*args)
119
- visitor.duration(duration, *args) unless duration == :unknown
119
+ visitor.duration(duration, *args)
120
120
  self
121
121
  end
122
122
 
@@ -131,7 +131,7 @@ module Cucumber
131
131
 
132
132
  def describe_to(visitor, *args)
133
133
  visitor.pending(self, *args)
134
- visitor.duration(duration, *args) unless duration == :unknown
134
+ visitor.duration(duration, *args)
135
135
  self
136
136
  end
137
137
 
@@ -151,54 +151,64 @@ module Cucumber
151
151
  # => 1
152
152
  #
153
153
  class Summary
154
- attr_reader :total_failed,
155
- :total_passed,
156
- :total_skipped,
157
- :total_undefined,
158
- :exceptions,
159
- :durations
154
+ attr_reader :exceptions, :durations
160
155
 
161
156
  def initialize
162
- @total_failed =
163
- @total_passed =
164
- @total_skipped =
165
- @total_undefined = 0
157
+ @totals = Hash.new { 0 }
166
158
  @exceptions = []
167
159
  @durations = []
168
160
  end
169
161
 
170
- def failed(*args)
171
- @total_failed += 1
172
- self
162
+ def method_missing(name, *args)
163
+ if name =~ /^total_/
164
+ get_total(name)
165
+ else
166
+ increment_total(name)
167
+ end
173
168
  end
174
169
 
175
- def passed(*args)
176
- @total_passed += 1
170
+ def exception(exception)
171
+ @exceptions << exception
177
172
  self
178
173
  end
179
174
 
180
- def skipped(*args)
181
- @total_skipped +=1
175
+ def duration(duration)
176
+ @durations << duration
182
177
  self
183
178
  end
184
179
 
185
- def undefined(*args)
186
- @total_undefined += 1
187
- self
180
+ def total
181
+ @totals.reduce(0) { |total, status| total += status[1] }
188
182
  end
189
183
 
190
- def exception(exception)
191
- @exceptions << exception
184
+ private
185
+
186
+ def get_total(method_name)
187
+ status = method_name.to_s.gsub('total_', '').to_sym
188
+ return @totals.fetch(status) { 0 }
189
+ end
190
+
191
+ def increment_total(status)
192
+ @totals[status] += 1
192
193
  self
193
194
  end
195
+ end
194
196
 
195
- def duration(duration)
196
- @durations << duration
197
+ class Duration
198
+ attr_reader :nanoseconds
199
+
200
+ def initialize(nanoseconds)
201
+ @nanoseconds = nanoseconds
202
+ end
203
+ end
204
+
205
+ class UnknownDuration
206
+ def tap(&block)
197
207
  self
198
208
  end
199
209
 
200
- def total
201
- total_passed + total_failed + total_skipped + total_undefined
210
+ def nanoseconds
211
+ raise "#nanoseconds only allowed to be used in #tap block"
202
212
  end
203
213
  end
204
214
  end
@@ -1,3 +1,5 @@
1
+ require 'cucumber/core/test/result'
2
+
1
3
  module Cucumber
2
4
  module Core
3
5
  module Test
@@ -8,7 +10,7 @@ module Cucumber
8
10
  end
9
11
 
10
12
  def duration
11
- nsec
13
+ Result::Duration.new(nsec)
12
14
  end
13
15
 
14
16
  def nsec
@@ -2,7 +2,7 @@ module Cucumber
2
2
  module Core
3
3
  class Version
4
4
  def self.to_s
5
- "1.0.0.beta.3"
5
+ "1.0.0.beta.4"
6
6
  end
7
7
  end
8
8
  end
@@ -3,6 +3,7 @@ require 'cucumber/core/ast/examples_table'
3
3
  module Cucumber::Core::Ast
4
4
  describe ExamplesTable do
5
5
  let(:location) { double(:to_s => 'file.feature:8') }
6
+ let(:language) { double }
6
7
 
7
8
  describe ExamplesTable::Header do
8
9
  let(:header) { ExamplesTable::Header.new(%w{foo bar baz}, location) }
@@ -15,7 +16,7 @@ module Cucumber::Core::Ast
15
16
 
16
17
  context 'building a row' do
17
18
  it 'includes the header values as keys' do
18
- expect( header.build_row(%w{1 2 3}, 1, location) ).to eq ExamplesTable::Row.new({'foo' => '1', 'bar' => '2', 'baz' => '3'}, 1, location)
19
+ expect( header.build_row(%w{1 2 3}, 1, location, language) ).to eq ExamplesTable::Row.new({'foo' => '1', 'bar' => '2', 'baz' => '3'}, 1, location, language)
19
20
  end
20
21
  end
21
22
  end
@@ -23,15 +24,21 @@ module Cucumber::Core::Ast
23
24
 
24
25
  describe 'location' do
25
26
  it 'knows the file and line number' do
26
- row = ExamplesTable::Row.new({}, 1, location)
27
+ row = ExamplesTable::Row.new({}, 1, location, language)
27
28
  expect( row.file_colon_line ).to eq 'file.feature:8'
28
29
  end
29
30
  end
30
31
 
32
+ describe 'language' do
33
+ it "has a language" do
34
+ expect( ExamplesTable::Row.new({}, 1, location, language) ).to respond_to(:language)
35
+ end
36
+ end
37
+
31
38
  describe "expanding a string" do
32
39
  context "when an argument matches" do
33
40
  it "replaces the argument with the value from the row" do
34
- row = ExamplesTable::Row.new({'arg' => 'replacement'}, 1, location)
41
+ row = ExamplesTable::Row.new({'arg' => 'replacement'}, 1, location, language)
35
42
  text = 'this <arg> a test'
36
43
  expect( row.expand(text) ).to eq 'this replacement a test'
37
44
  end
@@ -39,7 +46,7 @@ module Cucumber::Core::Ast
39
46
 
40
47
  context "when the replacement value is nil" do
41
48
  it "uses an empty string for the replacement" do
42
- row = ExamplesTable::Row.new({'color' => nil}, 1, location)
49
+ row = ExamplesTable::Row.new({'color' => nil}, 1, location, language)
43
50
  text = 'a <color> cucumber'
44
51
  expect( row.expand(text) ).to eq 'a cucumber'
45
52
  end
@@ -47,7 +54,7 @@ module Cucumber::Core::Ast
47
54
 
48
55
  context "when an argument does not match" do
49
56
  it "ignores the arguments that do not match" do
50
- row = ExamplesTable::Row.new({'x' => '1', 'y' => '2'}, 1, location)
57
+ row = ExamplesTable::Row.new({'x' => '1', 'y' => '2'}, 1, location, language)
51
58
  text = 'foo <x> bar <z>'
52
59
  expect( row.expand(text) ).to eq 'foo 1 bar <z>'
53
60
  end
@@ -56,7 +63,7 @@ module Cucumber::Core::Ast
56
63
 
57
64
  describe 'accesing the values' do
58
65
  it 'returns the actual row values' do
59
- row = ExamplesTable::Row.new({'x' => '1', 'y' => '2'}, 1, location)
66
+ row = ExamplesTable::Row.new({'x' => '1', 'y' => '2'}, 1, location, language)
60
67
  expect( row.values ).to eq ['1', '2']
61
68
  end
62
69
  end
@@ -65,20 +72,20 @@ module Cucumber::Core::Ast
65
72
  let(:data) { {} }
66
73
  let(:number) { double }
67
74
  let(:location) { double }
68
- let(:original) { ExamplesTable::Row.new(data, number, location) }
75
+ let(:original) { ExamplesTable::Row.new(data, number, location, language) }
69
76
 
70
77
  it 'is equal to another instance with the same data, number and location' do
71
- expect( original ).to eq ExamplesTable::Row.new(data, number, location)
78
+ expect( original ).to eq ExamplesTable::Row.new(data, number, location, language)
72
79
  end
73
80
 
74
81
  it 'is not equal to another instance with different data, number or location' do
75
- expect( original ).not_to eq ExamplesTable::Row.new({'x' => 'y'}, number, location)
76
- expect( original ).not_to eq ExamplesTable::Row.new(data, double, location)
77
- expect( original ).not_to eq ExamplesTable::Row.new(data, number, double)
82
+ expect( original ).not_to eq ExamplesTable::Row.new({'x' => 'y'}, number, location, language)
83
+ expect( original ).not_to eq ExamplesTable::Row.new(data, double, location, language)
84
+ expect( original ).not_to eq ExamplesTable::Row.new(data, number, double, double)
78
85
  end
79
86
 
80
87
  it 'is not equal to another type of object' do
81
- expect( original ).not_to eq double(data: data, number: number, location: location)
88
+ expect( original ).not_to eq double(data: data, number: number, location: location, language: language)
82
89
  end
83
90
 
84
91
  end