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
@@ -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