nukumber 0.4.1
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.
- data/bin/nukumber +14 -0
- data/lib/nukumber.rb +29 -0
- data/lib/nukumber/builder.rb +104 -0
- data/lib/nukumber/cli.rb +101 -0
- data/lib/nukumber/errors.rb +18 -0
- data/lib/nukumber/helpers.rb +5 -0
- data/lib/nukumber/hooks.rb +23 -0
- data/lib/nukumber/model.rb +9 -0
- data/lib/nukumber/model/background.rb +17 -0
- data/lib/nukumber/model/examples.rb +16 -0
- data/lib/nukumber/model/feature.rb +33 -0
- data/lib/nukumber/model/feature_element.rb +47 -0
- data/lib/nukumber/model/scenario.rb +20 -0
- data/lib/nukumber/model/scenario_outline.rb +21 -0
- data/lib/nukumber/model/step.rb +15 -0
- data/lib/nukumber/model/table.rb +53 -0
- data/lib/nukumber/reporter.rb +54 -0
- data/lib/nukumber/reporter/colour.rb +138 -0
- data/lib/nukumber/reporter/html.rb +143 -0
- data/lib/nukumber/reporter/html_css.rb +169 -0
- data/lib/nukumber/reporter/mono.rb +19 -0
- data/lib/nukumber/runtime.rb +237 -0
- data/lib/nukumber/version.rb +7 -0
- metadata +117 -0
@@ -0,0 +1,237 @@
|
|
1
|
+
module Nukumber
|
2
|
+
|
3
|
+
class Runtime
|
4
|
+
|
5
|
+
def initialize(dirs, filenames, filters, reporter)
|
6
|
+
|
7
|
+
@reporter = reporter
|
8
|
+
|
9
|
+
builder = Nukumber::GherkinBuilder.new
|
10
|
+
|
11
|
+
if filters.empty?
|
12
|
+
filter_f = builder
|
13
|
+
else
|
14
|
+
filter_f = Gherkin::Formatter::FilterFormatter.new(builder, filters)
|
15
|
+
end
|
16
|
+
tag_f = Gherkin::Formatter::TagCountFormatter.new(filter_f, {})
|
17
|
+
parser = Gherkin::Parser::Parser.new(tag_f)
|
18
|
+
|
19
|
+
parse_feature_files(parser, dirs, filenames)
|
20
|
+
validate_features(builder.features)
|
21
|
+
|
22
|
+
$before_hooks = {}
|
23
|
+
$after_hooks = {}
|
24
|
+
old_methods = Object.private_methods
|
25
|
+
|
26
|
+
# Load all user-space Ruby files
|
27
|
+
Dir[Dir.pwd + "/#{dirs[:features]}/#{dirs[:support]}/env.rb"].each { |f| load f }
|
28
|
+
Dir[Dir.pwd + "/#{dirs[:features]}/#{dirs[:support]}/*.rb"].each { |f| load f }
|
29
|
+
Dir[Dir.pwd + "/#{dirs[:features]}/#{dirs[:definitions]}/*.rb"].each { |f| load f }
|
30
|
+
|
31
|
+
user_methods = Object.private_methods - old_methods
|
32
|
+
|
33
|
+
@expected_steps = []
|
34
|
+
@tests_passed = []
|
35
|
+
@tests_failed = []
|
36
|
+
@tests_pending = []
|
37
|
+
@tests_undefined = []
|
38
|
+
|
39
|
+
# Run all relevant features
|
40
|
+
builder.features.each { |feature| run_feature feature }
|
41
|
+
|
42
|
+
# Report
|
43
|
+
@reporter.final_report(@tests_passed, @tests_failed, @tests_pending, @tests_undefined)
|
44
|
+
|
45
|
+
# Provide code snippets as appropriate
|
46
|
+
@reporter.print_skeleton_code @tests_undefined unless @tests_undefined.empty?
|
47
|
+
|
48
|
+
@reporter.terminate
|
49
|
+
|
50
|
+
user_methods.each { |method_sym| Object.send(:remove_method, method_sym) }
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
def pass (step_name)
|
55
|
+
raise "Tried to pass without a step name" unless step_name.is_a? String
|
56
|
+
if @expected_steps.empty?
|
57
|
+
raise "Tried to pass unexpected step \"#{step_name}\" (expected test to be finished)"
|
58
|
+
elsif @expected_steps.first.name != step_name
|
59
|
+
raise "Tried to pass unexpected step \"#{step_name}\" (expected \"#{@expected_steps.first.name}\")"
|
60
|
+
else
|
61
|
+
@reporter.print_step(@expected_steps.first, :passed) unless @executing_element.is_a? Nukumber::Model::ScenarioOutline
|
62
|
+
@expected_steps.shift
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def pending (*)
|
67
|
+
raise Nukumber::PendingTestError
|
68
|
+
end
|
69
|
+
|
70
|
+
def fail (err_msg = nil)
|
71
|
+
err_msg = ": #{err_msg}" unless err_msg.nil?
|
72
|
+
if @expected_steps.empty?
|
73
|
+
raise "Failed after all steps completed#{err_msg}"
|
74
|
+
else
|
75
|
+
raise "Failed step \"#{@expected_steps.first.name}\"#{err_msg}"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def parse_feature_files(parser, dirs, filenames)
|
82
|
+
Dir[Dir.pwd + "/#{dirs[:features]}/*.feature"].each do |ff_path|
|
83
|
+
unless filenames.empty?
|
84
|
+
skip = false
|
85
|
+
filenames.each { |f| skip = true unless ff_path.include? f }
|
86
|
+
next if skip
|
87
|
+
end
|
88
|
+
$feature_file_path = ff_path # TODO: this global is crap
|
89
|
+
parser.parse(IO.read(ff_path), ff_path, 0)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def validate_features(features)
|
94
|
+
features.each do |f|
|
95
|
+
f.feature_elements.each do |e|
|
96
|
+
id = "#{e.name}, #{f.file_path}:#{e.line}"
|
97
|
+
if e.is_a? Nukumber::Model::ScenarioOutline and e.examples.nil?
|
98
|
+
raise Nukumber::SyntaxError, "Missing examples from element: #{id}"
|
99
|
+
end
|
100
|
+
if e.is_a? Nukumber::Model::ScenarioOutline and e.examples.table.rows.empty?
|
101
|
+
raise Nukumber::SyntaxError, "Example table from element has no rows: #{id}"
|
102
|
+
end
|
103
|
+
e.steps.each do |s|
|
104
|
+
if !s.args.empty? and s.args.rows.empty?
|
105
|
+
raise Nukumber::SyntaxError, "Arguments table in element has no rows: #{id}"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def check_for_element_method(element)
|
113
|
+
raise Nukumber::UndefinedTestError unless respond_to?(element.shortsym, true) or respond_to?(element.longsym, true)
|
114
|
+
end
|
115
|
+
|
116
|
+
def run_feature(feature)
|
117
|
+
@reporter.begin_feature feature
|
118
|
+
|
119
|
+
all_elements = []
|
120
|
+
all_elements << feature.background unless feature.background.nil?
|
121
|
+
all_elements += feature.feature_elements
|
122
|
+
|
123
|
+
# find undefined tests
|
124
|
+
all_elements.each do |element|
|
125
|
+
begin
|
126
|
+
check_for_element_method(element)
|
127
|
+
rescue Nukumber::UndefinedTestError
|
128
|
+
@tests_undefined << element
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# and attempt to run tests
|
133
|
+
@background_undefined = false
|
134
|
+
all_elements.each do |element|
|
135
|
+
begin
|
136
|
+
check_for_element_method element
|
137
|
+
@reporter.begin_element element
|
138
|
+
@executing_element = element
|
139
|
+
run_outline_element(element) if element.is_a? Nukumber::Model::ScenarioOutline
|
140
|
+
run_single_element(element) unless element.is_a? Nukumber::Model::ScenarioOutline
|
141
|
+
rescue Nukumber::UndefinedTestError
|
142
|
+
@reporter.undefined_element(element)
|
143
|
+
@background_undefined = true if element.is_a? Nukumber::Model::Background
|
144
|
+
next
|
145
|
+
rescue
|
146
|
+
return if element.is_a? Nukumber::Model::Background
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
end
|
151
|
+
|
152
|
+
def run_single_element(element)
|
153
|
+
if element.is_a? Nukumber::Model::Background
|
154
|
+
elements_at_stake = element.feature.feature_elements
|
155
|
+
else
|
156
|
+
elements_at_stake = [element]
|
157
|
+
end
|
158
|
+
$example = nil
|
159
|
+
status = nil
|
160
|
+
begin
|
161
|
+
before_hooks(element)
|
162
|
+
execute_element(element)
|
163
|
+
@tests_passed << element unless element.is_a? Nukumber::Model::Background
|
164
|
+
status = :passed
|
165
|
+
rescue Nukumber::PendingTestError
|
166
|
+
@expected_steps.each { |s| @reporter.print_step(s, :pending) }
|
167
|
+
@tests_pending += elements_at_stake
|
168
|
+
status = :pending
|
169
|
+
raise RuntimeError if element.is_a? Nukumber::Model::Background
|
170
|
+
rescue => e
|
171
|
+
@reporter.print_step(@expected_steps.first, :failed) unless @expected_steps.empty?
|
172
|
+
@expected_steps.shift
|
173
|
+
@expected_steps.each { |s| @reporter.print_step(s, :pending) }
|
174
|
+
@reporter.error(e, element)
|
175
|
+
@tests_failed += elements_at_stake
|
176
|
+
status = :failed
|
177
|
+
raise RuntimeError if element.is_a? Nukumber::Model::Background
|
178
|
+
ensure
|
179
|
+
after_hooks(element, status)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
def run_outline_element(element)
|
184
|
+
element.examples.table.rows.size.times do |i|
|
185
|
+
$example = element.examples.table.row_hash(i)
|
186
|
+
status = nil
|
187
|
+
begin
|
188
|
+
before_hooks(element)
|
189
|
+
execute_element(element)
|
190
|
+
@reporter.print_example(element.examples.table, i, :passed)
|
191
|
+
@tests_passed << element
|
192
|
+
status = :passed
|
193
|
+
rescue Nukumber::PendingTestError
|
194
|
+
@reporter.print_example(element.examples.table, i, :pending)
|
195
|
+
@tests_pending << element
|
196
|
+
status = :pending
|
197
|
+
rescue => e
|
198
|
+
@reporter.print_example(element.examples.table, i, :failed)
|
199
|
+
@reporter.error(e, element)
|
200
|
+
@tests_failed << element
|
201
|
+
status = :failed
|
202
|
+
ensure
|
203
|
+
after_hooks(element, status)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
def before_hooks(element)
|
209
|
+
$before_hooks[:each].each { |p| self.instance_eval &p } if $before_hooks[:each]
|
210
|
+
element.tags.each do |t|
|
211
|
+
$before_hooks[t.to_sym].each { |p| self.instance_eval &p } if $before_hooks[t.to_sym]
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
def after_hooks(element, status)
|
216
|
+
element.tags.each do |t|
|
217
|
+
$after_hooks[t.to_sym].each { |p| instance_exec(element, status, &p) } if $after_hooks[t.to_sym]
|
218
|
+
end
|
219
|
+
$after_hooks[:each].each { |p| instance_exec(element, status, &p) } if $after_hooks[:each]
|
220
|
+
end
|
221
|
+
|
222
|
+
def execute_element(element)
|
223
|
+
@expected_steps = element.steps.clone
|
224
|
+
$args = element.step_args
|
225
|
+
raise Nukumber::PendingTestError if @background_undefined
|
226
|
+
|
227
|
+
send(element.shortsym) if respond_to?(element.shortsym, true)
|
228
|
+
send(element.longsym) if respond_to?(element.longsym, true)
|
229
|
+
|
230
|
+
unless @expected_steps.empty?
|
231
|
+
raise "Last #{@expected_steps.size > 1 ? "#{@expected_steps.size} steps" : 'step'} not passed"
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
end
|
236
|
+
|
237
|
+
end
|
metadata
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: nukumber
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.4.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Ibrahim Sha'ath
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-10-29 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: gherkin
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 2.11.1
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 2.11.1
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: nokogiri
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '1.5'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '1.5'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rake
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 0.9.2
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.9.2
|
62
|
+
description: Specify your tests using Gherkin, but avoid the hassle of step definitions
|
63
|
+
email: nukumber@ibrahimshaath.co.uk
|
64
|
+
executables:
|
65
|
+
- nukumber
|
66
|
+
extensions: []
|
67
|
+
extra_rdoc_files: []
|
68
|
+
files:
|
69
|
+
- lib/nukumber/builder.rb
|
70
|
+
- lib/nukumber/cli.rb
|
71
|
+
- lib/nukumber/errors.rb
|
72
|
+
- lib/nukumber/helpers.rb
|
73
|
+
- lib/nukumber/hooks.rb
|
74
|
+
- lib/nukumber/model/background.rb
|
75
|
+
- lib/nukumber/model/examples.rb
|
76
|
+
- lib/nukumber/model/feature.rb
|
77
|
+
- lib/nukumber/model/feature_element.rb
|
78
|
+
- lib/nukumber/model/scenario.rb
|
79
|
+
- lib/nukumber/model/scenario_outline.rb
|
80
|
+
- lib/nukumber/model/step.rb
|
81
|
+
- lib/nukumber/model/table.rb
|
82
|
+
- lib/nukumber/model.rb
|
83
|
+
- lib/nukumber/reporter/colour.rb
|
84
|
+
- lib/nukumber/reporter/html.rb
|
85
|
+
- lib/nukumber/reporter/html_css.rb
|
86
|
+
- lib/nukumber/reporter/mono.rb
|
87
|
+
- lib/nukumber/reporter.rb
|
88
|
+
- lib/nukumber/runtime.rb
|
89
|
+
- lib/nukumber/version.rb
|
90
|
+
- lib/nukumber.rb
|
91
|
+
- bin/nukumber
|
92
|
+
homepage: https://github.com/ibsh/nukumber
|
93
|
+
licenses: []
|
94
|
+
post_install_message:
|
95
|
+
rdoc_options: []
|
96
|
+
require_paths:
|
97
|
+
- lib
|
98
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
99
|
+
none: false
|
100
|
+
requirements:
|
101
|
+
- - ! '>='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
requirements: []
|
111
|
+
rubyforge_project:
|
112
|
+
rubygems_version: 1.8.24
|
113
|
+
signing_key:
|
114
|
+
specification_version: 3
|
115
|
+
summary: Run Gherkin feature files a bit more simply
|
116
|
+
test_files: []
|
117
|
+
has_rdoc:
|