cucumber-core 0.1.0

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 (69) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +1 -0
  3. data/.rspec +1 -0
  4. data/.ruby-gemset +1 -0
  5. data/.travis.yml +16 -0
  6. data/Gemfile +2 -0
  7. data/LICENSE +20 -0
  8. data/README.md +9 -0
  9. data/Rakefile +24 -0
  10. data/cucumber-core.gemspec +32 -0
  11. data/lib/cucumber/core.rb +37 -0
  12. data/lib/cucumber/core/ast.rb +13 -0
  13. data/lib/cucumber/core/ast/background.rb +33 -0
  14. data/lib/cucumber/core/ast/comment.rb +17 -0
  15. data/lib/cucumber/core/ast/data_table.rb +326 -0
  16. data/lib/cucumber/core/ast/describes_itself.rb +16 -0
  17. data/lib/cucumber/core/ast/doc_string.rb +83 -0
  18. data/lib/cucumber/core/ast/empty_background.rb +12 -0
  19. data/lib/cucumber/core/ast/examples_table.rb +95 -0
  20. data/lib/cucumber/core/ast/feature.rb +62 -0
  21. data/lib/cucumber/core/ast/location.rb +140 -0
  22. data/lib/cucumber/core/ast/multiline_argument.rb +33 -0
  23. data/lib/cucumber/core/ast/names.rb +19 -0
  24. data/lib/cucumber/core/ast/outline_step.rb +51 -0
  25. data/lib/cucumber/core/ast/scenario.rb +43 -0
  26. data/lib/cucumber/core/ast/scenario_outline.rb +44 -0
  27. data/lib/cucumber/core/ast/step.rb +38 -0
  28. data/lib/cucumber/core/ast/tag.rb +14 -0
  29. data/lib/cucumber/core/compiler.rb +136 -0
  30. data/lib/cucumber/core/gherkin/ast_builder.rb +315 -0
  31. data/lib/cucumber/core/gherkin/document.rb +20 -0
  32. data/lib/cucumber/core/gherkin/parser.rb +45 -0
  33. data/lib/cucumber/core/gherkin/writer.rb +220 -0
  34. data/lib/cucumber/core/gherkin/writer/helpers.rb +178 -0
  35. data/lib/cucumber/core/platform.rb +30 -0
  36. data/lib/cucumber/core/test/case.rb +143 -0
  37. data/lib/cucumber/core/test/filters.rb +48 -0
  38. data/lib/cucumber/core/test/filters/tag_filter.rb +110 -0
  39. data/lib/cucumber/core/test/hook_compiler.rb +109 -0
  40. data/lib/cucumber/core/test/mapper.rb +56 -0
  41. data/lib/cucumber/core/test/mapping.rb +67 -0
  42. data/lib/cucumber/core/test/result.rb +191 -0
  43. data/lib/cucumber/core/test/runner.rb +149 -0
  44. data/lib/cucumber/core/test/step.rb +69 -0
  45. data/lib/cucumber/core/test/timer.rb +31 -0
  46. data/lib/cucumber/core/version.rb +9 -0
  47. data/lib/cucumber/initializer.rb +18 -0
  48. data/spec/capture_warnings.rb +68 -0
  49. data/spec/coverage.rb +10 -0
  50. data/spec/cucumber/core/ast/data_table_spec.rb +139 -0
  51. data/spec/cucumber/core/ast/doc_string_spec.rb +77 -0
  52. data/spec/cucumber/core/ast/examples_table_spec.rb +87 -0
  53. data/spec/cucumber/core/ast/location_spec.rb +105 -0
  54. data/spec/cucumber/core/ast/outline_step_spec.rb +77 -0
  55. data/spec/cucumber/core/ast/step_spec.rb +44 -0
  56. data/spec/cucumber/core/compiler_spec.rb +249 -0
  57. data/spec/cucumber/core/gherkin/parser_spec.rb +182 -0
  58. data/spec/cucumber/core/gherkin/writer_spec.rb +332 -0
  59. data/spec/cucumber/core/test/case_spec.rb +416 -0
  60. data/spec/cucumber/core/test/hook_compiler_spec.rb +78 -0
  61. data/spec/cucumber/core/test/mapper_spec.rb +68 -0
  62. data/spec/cucumber/core/test/mapping_spec.rb +103 -0
  63. data/spec/cucumber/core/test/result_spec.rb +178 -0
  64. data/spec/cucumber/core/test/runner_spec.rb +265 -0
  65. data/spec/cucumber/core/test/step_spec.rb +58 -0
  66. data/spec/cucumber/core/test/timer_spec.rb +13 -0
  67. data/spec/cucumber/core_spec.rb +419 -0
  68. data/spec/cucumber/initializer_spec.rb +49 -0
  69. metadata +221 -0
@@ -0,0 +1,67 @@
1
+ require 'cucumber/core/test/result'
2
+ require 'cucumber/core/test/timer'
3
+ require 'cucumber/core/test/result'
4
+
5
+ module Cucumber
6
+ module Core
7
+ module Test
8
+
9
+ class Mapping
10
+ def initialize(&block)
11
+ raise ArgumentError, "Passing a block to execute the mapping is mandatory." unless block
12
+ @block = block
13
+ @timer = Timer.new
14
+ end
15
+
16
+ def skip
17
+ skipped
18
+ end
19
+
20
+ def execute
21
+ @timer.start
22
+ @block.call
23
+ passed
24
+ rescue Result::Pending => exception
25
+ pending(exception)
26
+ rescue Exception => exception
27
+ failed(exception)
28
+ end
29
+
30
+ private
31
+
32
+ def passed
33
+ Result::Passed.new(@timer.duration)
34
+ end
35
+
36
+ def failed(exception)
37
+ Result::Failed.new(@timer.duration, exception)
38
+ end
39
+
40
+ def skipped
41
+ Result::Skipped.new
42
+ end
43
+
44
+ def pending(exception)
45
+ exception.with_duration(@timer.duration)
46
+ end
47
+ end
48
+
49
+ class UndefinedMapping
50
+ def execute
51
+ undefined
52
+ end
53
+
54
+ def skip
55
+ undefined
56
+ end
57
+
58
+ private
59
+
60
+ def undefined
61
+ Result::Undefined.new
62
+ end
63
+ end
64
+
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,191 @@
1
+ # encoding: UTF-8¬
2
+ require 'cucumber/initializer'
3
+
4
+ module Cucumber
5
+ module Core
6
+ module Test
7
+ module Result
8
+ def self.status_queries(status)
9
+ Module.new do
10
+ [:passed, :failed, :undefined, :unknown, :skipped, :pending].each do |possible_status|
11
+ define_method("#{possible_status}?") do
12
+ possible_status == status
13
+ end
14
+ end
15
+ end
16
+ end
17
+
18
+ Unknown = Class.new do
19
+ include Result.status_queries :unknown
20
+
21
+ def describe_to(visitor, *args)
22
+ self
23
+ end
24
+ end
25
+
26
+ class Passed
27
+ include Result.status_queries :passed
28
+ include Cucumber.initializer(:duration)
29
+ attr_reader :duration
30
+
31
+ def initialize(duration)
32
+ raise ArgumentError unless duration
33
+ super
34
+ end
35
+
36
+ def describe_to(visitor, *args)
37
+ visitor.passed(*args)
38
+ visitor.duration(duration, *args)
39
+ self
40
+ end
41
+
42
+ def to_s
43
+ "✓"
44
+ end
45
+ end
46
+
47
+ class Failed
48
+ include Result.status_queries :failed
49
+ include Cucumber.initializer(:duration, :exception)
50
+ attr_reader :duration, :exception
51
+
52
+ def initialize(duration, exception)
53
+ raise ArgumentError unless duration
54
+ raise ArgumentError unless exception
55
+ super
56
+ end
57
+
58
+ def describe_to(visitor, *args)
59
+ visitor.failed(*args)
60
+ visitor.duration(duration, *args)
61
+ visitor.exception(exception, *args) if exception
62
+ self
63
+ end
64
+
65
+ def to_s
66
+ "✗"
67
+ end
68
+
69
+ def with_duration(new_duration)
70
+ self.class.new(new_duration, exception)
71
+ end
72
+
73
+ end
74
+
75
+ Undefined = Class.new do
76
+ include Result.status_queries :undefined
77
+ include Cucumber.initializer(:duration)
78
+ attr_reader :duration
79
+
80
+ def initialize(duration = 0)
81
+ super
82
+ end
83
+
84
+ def describe_to(visitor, *args)
85
+ visitor.undefined(*args)
86
+ self
87
+ end
88
+
89
+ def to_s
90
+ "✗"
91
+ end
92
+
93
+ def with_duration(new_duration)
94
+ self.class.new(new_duration)
95
+ end
96
+ end
97
+
98
+ Skipped = Class.new do
99
+ include Result.status_queries :skipped
100
+
101
+ def describe_to(visitor, *args)
102
+ visitor.skipped(*args)
103
+ self
104
+ end
105
+
106
+ def to_s
107
+ "-"
108
+ end
109
+ end
110
+
111
+ class Pending < StandardError
112
+ include Result.status_queries :pending
113
+ attr_reader :message, :duration
114
+
115
+ def initialize(message, duration = :unknown, backtrace=nil)
116
+ raise ArgumentError unless message
117
+ @message, @duration = message, duration
118
+ super(message)
119
+ set_backtrace(backtrace) if backtrace
120
+ end
121
+
122
+ def describe_to(visitor, *args)
123
+ visitor.pending(self, *args)
124
+ visitor.duration(duration, *args) unless duration == :unknown
125
+ self
126
+ end
127
+
128
+ def to_s
129
+ "P"
130
+ end
131
+
132
+ def with_duration(new_duration)
133
+ self.class.new(message, new_duration, backtrace)
134
+ end
135
+ end
136
+
137
+ class Summary
138
+ attr_reader :total_failed,
139
+ :total_passed,
140
+ :total_skipped,
141
+ :total_undefined,
142
+ :exceptions,
143
+ :durations
144
+
145
+ def initialize
146
+ @total_failed =
147
+ @total_passed =
148
+ @total_skipped =
149
+ @total_undefined = 0
150
+ @exceptions = []
151
+ @durations = []
152
+ end
153
+
154
+ def failed(*args)
155
+ @total_failed += 1
156
+ self
157
+ end
158
+
159
+ def passed(*args)
160
+ @total_passed += 1
161
+ self
162
+ end
163
+
164
+ def skipped(*args)
165
+ @total_skipped +=1
166
+ self
167
+ end
168
+
169
+ def undefined(*args)
170
+ @total_undefined += 1
171
+ self
172
+ end
173
+
174
+ def exception(exception)
175
+ @exceptions << exception
176
+ self
177
+ end
178
+
179
+ def duration(duration)
180
+ @durations << duration
181
+ self
182
+ end
183
+
184
+ def total
185
+ total_passed + total_failed + total_skipped + total_undefined
186
+ end
187
+ end
188
+ end
189
+ end
190
+ end
191
+ end
@@ -0,0 +1,149 @@
1
+ require 'cucumber/initializer'
2
+ require 'cucumber/core/test/timer'
3
+
4
+ module Cucumber
5
+ module Core
6
+ module Test
7
+ class Runner
8
+ module StepRunner
9
+ class Default
10
+ def initialize
11
+ @timer = Timer.new.start
12
+ end
13
+
14
+ def execute(test_step)
15
+ status.execute(test_step, self)
16
+ end
17
+
18
+ def result
19
+ status.result(@timer.duration)
20
+ end
21
+
22
+ def failed(step_result)
23
+ @status = Failing.new(step_result)
24
+ self
25
+ end
26
+
27
+ def passed(step_result)
28
+ @status = Passing.new
29
+ self
30
+ end
31
+
32
+ def pending(message, step_result)
33
+ @status = Pending.new(step_result)
34
+ self
35
+ end
36
+
37
+ def undefined(step_result)
38
+ failed(step_result)
39
+ self
40
+ end
41
+
42
+ def exception(step_exception, step_result)
43
+ self
44
+ end
45
+
46
+ def duration(step_duration, step_result)
47
+ self
48
+ end
49
+
50
+ private
51
+
52
+ def status
53
+ @status ||= Unknown.new
54
+ end
55
+ end
56
+
57
+ class DryRun
58
+ def execute(test_step)
59
+ step_result = test_step.skip
60
+ @case_result = Result::Undefined.new if step_result.undefined?
61
+ step_result
62
+ end
63
+
64
+ def result
65
+ @case_result ||= Result::Skipped.new
66
+ end
67
+ end
68
+
69
+ class Unknown
70
+ def execute(test_step, monitor)
71
+ result = test_step.execute
72
+ result.describe_to(monitor, result)
73
+ end
74
+
75
+ def result(duration)
76
+ Result::Unknown.new
77
+ end
78
+ end
79
+
80
+ class Passing < Unknown
81
+ def result(duration)
82
+ Result::Passed.new(duration)
83
+ end
84
+ end
85
+
86
+ Failing = Struct.new(:step_result) do
87
+ def execute(test_step, monitor)
88
+ test_step.skip
89
+ end
90
+
91
+ def result(duration)
92
+ step_result.with_duration(duration)
93
+ end
94
+ end
95
+
96
+ Pending = Class.new(Failing)
97
+ end
98
+
99
+ STEP_RUNNER_STRATEGY = {
100
+ default: StepRunner::Default,
101
+ dry_run: StepRunner::DryRun
102
+ }
103
+
104
+ attr_reader :report, :step_runner_class
105
+ private :report, :step_runner_class
106
+ def initialize(report, run_options = {})
107
+ @report = report
108
+
109
+ run_mode = run_options.fetch(:run_mode) { :default }
110
+ @step_runner_class = STEP_RUNNER_STRATEGY.fetch(run_mode) do
111
+ raise ArgumentError, "No strategy for run mode: #{run_mode.inspect}"
112
+ end
113
+ end
114
+
115
+ def test_case(test_case, &descend)
116
+ report.before_test_case(test_case)
117
+ descend.call
118
+ report.after_test_case(test_case, current_case_result)
119
+ @current_step_runner = nil
120
+ end
121
+
122
+ def test_step(test_step)
123
+ report.before_test_step test_step
124
+ step_result = current_step_runner.execute(test_step)
125
+ report.after_test_step test_step, step_result
126
+ end
127
+
128
+ def around_hook(hook, &continue)
129
+ hook.call(continue)
130
+ end
131
+
132
+ def done
133
+ report.done
134
+ self
135
+ end
136
+
137
+ private
138
+
139
+ def current_case_result
140
+ current_step_runner.result
141
+ end
142
+
143
+ def current_step_runner
144
+ @current_step_runner ||= step_runner_class.new
145
+ end
146
+ end
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,69 @@
1
+ require 'cucumber/initializer'
2
+ require 'cucumber/core/test/result'
3
+ require 'cucumber/core/test/mapping'
4
+
5
+ module Cucumber
6
+ module Core
7
+ module Test
8
+ class Step
9
+ include Cucumber.initializer(:source)
10
+
11
+ def initialize(source, mapping = Test::UndefinedMapping.new)
12
+ raise ArgumentError if source.any?(&:nil?)
13
+ @mapping = mapping
14
+ super(source)
15
+ end
16
+
17
+ def describe_to(visitor, *args)
18
+ visitor.test_step(self, *args)
19
+ end
20
+
21
+ def describe_source_to(visitor, *args)
22
+ source.each do |node|
23
+ node.describe_to(visitor, *args)
24
+ end
25
+ end
26
+
27
+ def name
28
+ step.name
29
+ end
30
+
31
+ def multiline_arg
32
+ step.multiline_arg
33
+ end
34
+
35
+ def skip
36
+ @mapping.skip
37
+ end
38
+
39
+ def execute
40
+ @mapping.execute
41
+ end
42
+
43
+ def map(&block)
44
+ self.class.new(source, Test::Mapping.new(&block))
45
+ end
46
+
47
+ def location
48
+ step.location
49
+ end
50
+
51
+ def match_locations?(queried_locations)
52
+ return true if queried_locations.include? location
53
+ source.any? { |s| s.match_locations?(queried_locations) }
54
+ end
55
+
56
+ def inspect
57
+ "#{self.class}: #{location}"
58
+ end
59
+
60
+ private
61
+
62
+ def step
63
+ source.last
64
+ end
65
+
66
+ end
67
+ end
68
+ end
69
+ end