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
@@ -32,7 +32,7 @@ module Cucumber
32
32
  let(:name) { 'a <color> cucumber' }
33
33
 
34
34
  it "replaces the argument" do
35
- row = ExamplesTable::Row.new({'color' => 'green'}, 1, location)
35
+ row = ExamplesTable::Row.new({'color' => 'green'}, 1, location, language)
36
36
  expect( outline_step.to_step(row).name ).to eq 'a green cucumber'
37
37
  end
38
38
 
@@ -49,7 +49,7 @@ module Cucumber
49
49
  expect( visitor ).to receive(:data_table) do |data_table|
50
50
  expect( data_table.raw ).to eq [['x', 'y'], ['a', 'a replacement']]
51
51
  end
52
- row = ExamplesTable::Row.new({'arg' => 'replacement'}, 1, location)
52
+ row = ExamplesTable::Row.new({'arg' => 'replacement'}, 1, location, language)
53
53
  step = outline_step.to_step(row)
54
54
  step.describe_to(visitor)
55
55
  end
@@ -67,7 +67,7 @@ module Cucumber
67
67
  expect( visitor ).to receive(:doc_string) do |doc_string|
68
68
  expect( doc_string.content ).to eq "a replacement that needs replacing"
69
69
  end
70
- row = ExamplesTable::Row.new({'arg' => 'replacement'}, 1, location)
70
+ row = ExamplesTable::Row.new({'arg' => 'replacement'}, 1, location, language)
71
71
  step = outline_step.to_step(row)
72
72
  step.describe_to(visitor)
73
73
  end
@@ -27,6 +27,24 @@ module Cucumber
27
27
  end
28
28
  end
29
29
 
30
+ RSpec::Matchers.define :a_null_feature do
31
+ match do |actual|
32
+ allow( visitor ).to receive(:feature).and_throw
33
+
34
+ actual.describe_to( visitor )
35
+ end
36
+ end
37
+
38
+ context "for empty files" do
39
+ let(:source) { Gherkin::Document.new(path, '') }
40
+ let(:path) { 'path_to/the.feature' }
41
+
42
+ it "creates a NullFeature" do
43
+ expect( receiver ).to receive(:feature).with(a_null_feature)
44
+ parse
45
+ end
46
+ end
47
+
30
48
  include Writer
31
49
  def self.source(&block)
32
50
  let(:source) { gherkin(&block) }
@@ -1,4 +1,5 @@
1
1
  require 'cucumber/core/test/action'
2
+ require 'cucumber/core/test/duration_matcher'
2
3
 
3
4
  module Cucumber
4
5
  module Core
@@ -76,13 +77,13 @@ module Cucumber
76
77
  it "records the nanoseconds duration of the execution on the result" do
77
78
  mapping = Action.new { }
78
79
  duration = mapping.execute(last_result).duration
79
- expect( duration ).to eq 1
80
+ expect( duration ).to be_duration 1
80
81
  end
81
82
 
82
83
  it "records the duration of a failed execution" do
83
84
  mapping = Action.new { raise StandardError }
84
85
  duration = mapping.execute(last_result).duration
85
- expect( duration ).to eq 1
86
+ expect( duration ).to be_duration 1
86
87
  end
87
88
  end
88
89
 
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require 'cucumber/core/test/result'
3
+ require 'rspec/expectations'
4
+
5
+ module Cucumber::Core::Test
6
+ RSpec::Matchers.define :be_duration do |expected|
7
+ match do |actual|
8
+ actual.tap { |duration| @nanoseconds = duration.nanoseconds }
9
+ @nanoseconds == expected
10
+ end
11
+ end
12
+
13
+ RSpec::Matchers.define :an_unknown_duration do
14
+ match do |actual|
15
+ actual.tap { raise "#tap block was executed, not an UnknownDuration" }
16
+ expect(actual).to respond_to(:nanoseconds)
17
+ end
18
+ end
19
+ end
@@ -97,15 +97,19 @@ module Cucumber
97
97
  it "adds hooks in the right order" do
98
98
  log = double
99
99
  allow(mappings).to receive(:test_case) do |test_case, mapper|
100
- mapper.before { log.before }
101
- mapper.after { log.after }
100
+ mapper.before { log.before_hook_1 }
101
+ mapper.before { log.before_hook_2 }
102
+ mapper.after { log.after_hook_1 }
103
+ mapper.after { log.after_hook_2 }
102
104
  end
103
- mapped_step = test_step.with_mapping { log.step }
105
+ mapped_step = test_step.with_mapping { log.step_1 }
104
106
  test_case = Case.new([mapped_step], source)
105
107
 
106
- expect( log ).to receive(:before).ordered
107
- expect( log ).to receive(:step).ordered
108
- expect( log ).to receive(:after).ordered
108
+ expect( log ).to receive(:before_hook_1).ordered
109
+ expect( log ).to receive(:before_hook_2).ordered
110
+ expect( log ).to receive(:step_1).ordered
111
+ expect( log ).to receive(:after_hook_2).ordered
112
+ expect( log ).to receive(:after_hook_1).ordered
109
113
 
110
114
  allow(receiver).to receive(:test_case).and_yield(receiver)
111
115
  allow(receiver).to receive(:test_step) do |test_step|
@@ -128,7 +132,7 @@ module Cucumber
128
132
  expect( scenario ).to receive(:describe_to)
129
133
  expect( visitor ).to receive(:before_hook) do |hook, hook_args|
130
134
  expect( args ).to eq(hook_args)
131
- expect( hook.location.to_s ).to eq("#{__FILE__}:121")
135
+ expect( hook.location.to_s ).to eq("#{__FILE__}:125")
132
136
  end
133
137
  test_step.describe_source_to(visitor, args)
134
138
  end
@@ -148,7 +152,7 @@ module Cucumber
148
152
  expect( scenario ).to receive(:describe_to)
149
153
  expect( visitor ).to receive(:after_hook) do |hook, hook_args|
150
154
  expect( args ).to eq(hook_args)
151
- expect( hook.location.to_s ).to eq("#{__FILE__}:141")
155
+ expect( hook.location.to_s ).to eq("#{__FILE__}:145")
152
156
  end
153
157
  test_step.describe_source_to(visitor, args)
154
158
  end
@@ -168,7 +172,24 @@ module Cucumber
168
172
  expect( visitor ).to receive(:step).ordered
169
173
  expect( visitor ).to receive(:after_step_hook) do |hook, hook_args|
170
174
  expect( args ).to eq(hook_args)
171
- expect( hook.location.to_s ).to eq("#{__FILE__}:160")
175
+ expect( hook.location.to_s ).to eq("#{__FILE__}:164")
176
+ end.once.ordered
177
+ expect( visitor ).to receive(:step).ordered
178
+ test_case.describe_to mapper
179
+ end
180
+
181
+ it "prepends before_step hooks to the test step" do
182
+ allow(mappings).to receive(:test_step) do |test_step, mapper|
183
+ mapper.before {}
184
+ end
185
+ args = double('args')
186
+ visitor = double('visitor')
187
+ allow(receiver).to receive(:test_case) do |test_case|
188
+ test_case.test_steps.first.describe_source_to(visitor, args)
189
+ end
190
+ expect( visitor ).to receive(:before_step_hook) do |hook, hook_args|
191
+ expect( args ).to eq(hook_args)
192
+ expect( hook.location.to_s ).to eq("#{__FILE__}:183")
172
193
  end.once.ordered
173
194
  expect( visitor ).to receive(:step).ordered
174
195
  test_case.describe_to mapper
@@ -180,4 +201,3 @@ module Cucumber
180
201
  end
181
202
  end
182
203
  end
183
-
@@ -1,5 +1,6 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  require 'cucumber/core/test/result'
3
+ require 'cucumber/core/test/duration_matcher'
3
4
 
4
5
  module Cucumber::Core::Test
5
6
  describe Result do
@@ -9,7 +10,7 @@ module Cucumber::Core::Test
9
10
 
10
11
  describe Result::Passed do
11
12
  subject(:result) { Result::Passed.new(duration) }
12
- let(:duration) { 1 * 1000 * 1000 }
13
+ let(:duration) { Result::Duration.new(1 * 1000 * 1000) }
13
14
 
14
15
  it "describes itself to a visitor" do
15
16
  expect( visitor ).to receive(:passed).with(args)
@@ -38,7 +39,7 @@ module Cucumber::Core::Test
38
39
 
39
40
  describe Result::Failed do
40
41
  subject(:result) { Result::Failed.new(duration, exception) }
41
- let(:duration) { 1 * 1000 * 1000 }
42
+ let(:duration) { Result::Duration.new(1 * 1000 * 1000) }
42
43
  let(:exception) { StandardError.new("error message") }
43
44
 
44
45
  it "describes itself to a visitor" do
@@ -84,6 +85,7 @@ module Cucumber::Core::Test
84
85
 
85
86
  it "describes itself to a visitor" do
86
87
  expect( visitor ).to receive(:undefined).with(args)
88
+ expect( visitor ).to receive(:duration).with(an_unknown_duration, args)
87
89
  result.describe_to(visitor, args)
88
90
  end
89
91
 
@@ -99,6 +101,7 @@ module Cucumber::Core::Test
99
101
 
100
102
  it "describes itself to a visitor" do
101
103
  expect( visitor ).to receive(:skipped).with(args)
104
+ expect( visitor ).to receive(:duration).with(an_unknown_duration, args)
102
105
  result.describe_to(visitor, args)
103
106
  end
104
107
 
@@ -111,8 +114,8 @@ module Cucumber::Core::Test
111
114
 
112
115
  describe Result::Summary do
113
116
  let(:summary) { Result::Summary.new }
114
- let(:failed) { Result::Failed.new(10, exception) }
115
- let(:passed) { Result::Passed.new(11) }
117
+ let(:failed) { Result::Failed.new(Result::Duration.new(10), exception) }
118
+ let(:passed) { Result::Passed.new(Result::Duration.new(11)) }
116
119
  let(:skipped) { Result::Skipped.new }
117
120
  let(:unknown) { Result::Unknown.new }
118
121
  let(:undefined) { Result::Undefined.new }
@@ -142,6 +145,23 @@ module Cucumber::Core::Test
142
145
  expect( summary.total ).to eq 1
143
146
  end
144
147
 
148
+ it "counts abitrary raisable results" do
149
+ flickering = Class.new(Result::Raisable) do
150
+ def describe_to(visitor, *args)
151
+ visitor.flickering(*args)
152
+ end
153
+ end
154
+
155
+ flickering.new.describe_to summary
156
+ expect( summary.total_flickering ).to eq 1
157
+ expect( summary.total ).to eq 1
158
+ end
159
+
160
+ it "returns zero for a status where no messges have been received" do
161
+ expect( summary.total_passed ).to eq 0
162
+ expect( summary.total_ponies ).to eq 0
163
+ end
164
+
145
165
  it "doesn't count unknown results" do
146
166
  unknown.describe_to summary
147
167
  expect( summary.total ).to eq 0
@@ -158,7 +178,8 @@ module Cucumber::Core::Test
158
178
 
159
179
  it "records durations" do
160
180
  [passed, failed].each { |r| r.describe_to summary }
161
- expect( summary.durations ).to eq [11, 10]
181
+ expect( summary.durations[0] ).to be_duration 11
182
+ expect( summary.durations[1] ).to be_duration 10
162
183
  end
163
184
 
164
185
  it "records exceptions" do
@@ -166,5 +187,26 @@ module Cucumber::Core::Test
166
187
  expect( summary.exceptions ).to eq [exception]
167
188
  end
168
189
  end
190
+
191
+ describe Result::Duration do
192
+ subject(:duration) { Result::Duration.new(10) }
193
+
194
+ it "#nanoseconds can be accessed in #tap" do
195
+ expect( duration.tap { |duration| @duration = duration.nanoseconds } ).to eq duration
196
+ expect( @duration ).to eq 10
197
+ end
198
+ end
199
+
200
+ describe Result::UnknownDuration do
201
+ subject(:duration) { Result::UnknownDuration.new }
202
+
203
+ it "#tap does not execute the passed block" do
204
+ expect( duration.tap { raise "tap executed block" } ).to eq duration
205
+ end
206
+
207
+ it "accessing #nanoseconds outside #tap block raises exception" do
208
+ expect { duration.nanoseconds }.to raise_error(RuntimeError)
209
+ end
210
+ end
169
211
  end
170
212
  end
@@ -1,6 +1,7 @@
1
1
  require 'cucumber/core/test/runner'
2
2
  require 'cucumber/core/test/case'
3
3
  require 'cucumber/core/test/step'
4
+ require 'cucumber/core/test/duration_matcher'
4
5
 
5
6
  module Cucumber::Core::Test
6
7
  describe Runner do
@@ -33,7 +34,7 @@ module Cucumber::Core::Test
33
34
 
34
35
  it "records the nanoseconds duration of the execution on the result" do
35
36
  expect( report ).to receive(:after_test_case) do |reported_test_case, result|
36
- expect( result.duration ).to eq 1
37
+ expect( result.duration ).to be_duration 1
37
38
  end
38
39
  test_case.describe_to runner
39
40
  end
@@ -44,7 +45,7 @@ module Cucumber::Core::Test
44
45
 
45
46
  it "records the duration" do
46
47
  expect( report ).to receive(:after_test_case) do |reported_test_case, result|
47
- expect( result.duration ).to eq 1
48
+ expect( result.duration ).to be_duration 1
48
49
  end
49
50
  test_case.describe_to runner
50
51
  end
@@ -1,9 +1,22 @@
1
1
  require 'cucumber/core/test/timer'
2
+ require 'cucumber/core/test/duration_matcher'
2
3
 
3
4
  module Cucumber
4
5
  module Core
5
6
  module Test
6
7
  describe Timer do
8
+ before do
9
+ time = double
10
+ allow( Time ).to receive(:now) { time }
11
+ allow( time ).to receive(:nsec).and_return(946752000, 946752001)
12
+ allow( time ).to receive(:to_i).and_return(1377009235, 1377009235)
13
+ end
14
+
15
+ it "returns a Result::Duration object" do
16
+ timer = Timer.new.start
17
+ expect( timer.duration ).to be_duration 1
18
+ end
19
+
7
20
  it "would be slow to test" do
8
21
  # so we won't
9
22
  end
@@ -2,32 +2,13 @@ require 'report_api_spy'
2
2
  require 'cucumber/core'
3
3
  require 'cucumber/core/gherkin/writer'
4
4
  require 'cucumber/core/platform'
5
+ require 'cucumber/core/report/summary'
5
6
 
6
7
  module Cucumber
7
8
  describe Core do
8
9
  include Core
9
10
  include Core::Gherkin::Writer
10
11
 
11
- describe "parsing Gherkin" do
12
- it "calls the compiler with a valid AST" do
13
- compiler = double(done: nil)
14
- expect( compiler ).to receive(:feature) do |feature|
15
- expect( feature ).to respond_to(:describe_to)
16
- expect( feature ).to be_an_instance_of(Core::Ast::Feature)
17
- end
18
-
19
- gherkin = gherkin do
20
- feature do
21
- scenario do
22
- step
23
- end
24
- end
25
- end
26
-
27
- parse([gherkin], compiler)
28
- end
29
- end
30
-
31
12
  describe "compiling features to a test suite" do
32
13
 
33
14
  it "compiles two scenarios into two test cases" do
@@ -216,30 +197,6 @@ module Cucumber
216
197
  end
217
198
 
218
199
  describe "executing a test suite" do
219
- class SummaryReport
220
- attr_reader :test_cases, :test_steps
221
-
222
- def initialize
223
- @test_cases = Core::Test::Result::Summary.new
224
- @test_steps = Core::Test::Result::Summary.new
225
- end
226
-
227
- def before_test_case(*)
228
- yield if block_given?
229
- end
230
-
231
- def after_test_case(test_case, result)
232
- result.describe_to test_cases
233
- end
234
-
235
- def after_test_step(test_step, result)
236
- result.describe_to test_steps
237
- end
238
-
239
- def method_missing(*)
240
- end
241
- end
242
-
243
200
  context "without hooks" do
244
201
  class StepTestMappings
245
202
  Failure = Class.new(StandardError)
@@ -270,7 +227,7 @@ module Cucumber
270
227
  end
271
228
  end
272
229
  end
273
- report = SummaryReport.new
230
+ report = Core::Report::Summary.new
274
231
  mappings = StepTestMappings.new
275
232
 
276
233
  execute [gherkin], mappings, report
@@ -363,7 +320,7 @@ module Cucumber
363
320
  end
364
321
  end
365
322
  end
366
- report = SummaryReport.new
323
+ report = Core::Report::Summary.new
367
324
  mappings = HookTestMappings.new
368
325
 
369
326
  execute [gherkin], mappings, report
@@ -440,7 +397,7 @@ module Cucumber
440
397
  end
441
398
  end
442
399
  end
443
- report = SummaryReport.new
400
+ report = Core::Report::Summary.new
444
401
  mappings = AroundHookTestMappings.new
445
402
 
446
403
  execute [gherkin], mappings, report
@@ -481,7 +438,7 @@ module Cucumber
481
438
  end
482
439
  end
483
440
  end
484
- report = SummaryReport.new
441
+ report = Core::Report::Summary.new
485
442
  mappings = HookTestMappings.new
486
443
 
487
444
  execute [gherkin], mappings, report, [[Cucumber::Core::Test::TagFilter, ['@a']]]
@@ -500,13 +457,40 @@ module Cucumber
500
457
  end
501
458
  end
502
459
  end
503
- report = SummaryReport.new
460
+ report = Core::Report::Summary.new
504
461
  mappings = HookTestMappings.new
505
462
 
506
463
  execute [gherkin], mappings, report, [[Cucumber::Core::Test::NameFilter, [[/scenario/]]]]
507
464
 
508
465
  expect( report.test_cases.total ).to eq 1
509
466
  end
467
+
468
+ it "filters test cases by filename" do
469
+ documents = []
470
+ documents << gherkin("some.feature") do
471
+ feature 'some feature' do
472
+ scenario 'some scenario' do
473
+ step 'missing'
474
+ end
475
+ end
476
+ end
477
+ documents << gherkin("other.feature") do
478
+ feature 'other feature' do
479
+ scenario 'other scenario' do
480
+ step 'missing'
481
+ end
482
+ end
483
+ end
484
+
485
+ report = Core::Report::Summary.new
486
+ mappings = HookTestMappings.new
487
+ some_feature = Cucumber::Core::Ast::Location.new("some.feature")
488
+ filters = [[ Cucumber::Core::Test::LocationsFilter, [[some_feature]] ]]
489
+
490
+ execute documents, mappings, report, filters
491
+
492
+ expect( report.test_cases.total ).to eq 1
493
+ end
510
494
  end
511
495
  end
512
496
  end