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

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