gurke 1.0.1 → 2.0.0.dev.1.b17

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.
@@ -0,0 +1,45 @@
1
+ module Gurke
2
+ #
3
+ module DSL
4
+ def step(pattern, method_name = nil, opts = {}, &block)
5
+ if method_name.is_a?(Hash) && opts.empty?
6
+ method_name, opts = nil, method_name
7
+ end
8
+
9
+ if method_name && block_given?
10
+ raise ArgumentError.new <<-EOF.strip
11
+ You can either specify a method name or given a block, not both.
12
+ EOF
13
+ end
14
+
15
+ _define_step(pattern, method_name, opts, &block)
16
+ end
17
+
18
+ def _define_step(pattern, method_name, opts, &block)
19
+ step = StepDefinition.new(pattern, opts)
20
+
21
+ define_method("match: #{step.method_name}") do |name, s = nil|
22
+ step.match(name, s)
23
+ end
24
+
25
+ if block_given?
26
+ define_method("#{step.method_name}", &block)
27
+ elsif method_name
28
+ alias_method "#{step.method_name}", method_name
29
+ end
30
+ end
31
+
32
+ # rubocop:disable MethodName
33
+ def Given(pattern, method_name = nil, opts = {}, &block)
34
+ step pattern, method_name, opts.merge(type: :given), &block
35
+ end
36
+
37
+ def When(pattern, method_name = nil, opts = {}, &block)
38
+ step pattern, method_name, opts.merge(type: :when), &block
39
+ end
40
+
41
+ def Then(pattern, method_name = nil, opts = {}, &block)
42
+ step pattern, method_name, opts.merge(type: :then), &block
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,55 @@
1
+ module Gurke
2
+ #
3
+ class Feature
4
+ #
5
+ # Return path to file containing this feature.
6
+ #
7
+ # @return [String] File path.
8
+ #
9
+ attr_reader :file
10
+
11
+ # Return line number where this feature is defined.
12
+ #
13
+ # @return [Fixnum] Line number.
14
+ #
15
+ attr_reader :line
16
+
17
+ attr_reader :tags
18
+
19
+ # @api private
20
+ attr_reader :raw
21
+
22
+ # @api private
23
+ def initialize(file, line, tags, raw)
24
+ @file, @line, @tags, @raw = file, line, tags, raw
25
+ end
26
+
27
+ def name
28
+ raw.name
29
+ end
30
+
31
+ def description
32
+ raw.description
33
+ end
34
+
35
+ # Return list of scenarios this feature specifies.
36
+ #
37
+ # @return [Array<Scenario>] Scenarios.
38
+ #
39
+ def scenarios
40
+ @scenarios ||= []
41
+ end
42
+
43
+ def backgrounds
44
+ @backgrounds ||= []
45
+ end
46
+
47
+ # Return name of this feature.
48
+ #
49
+ # @return [String] Feature name.
50
+ #
51
+ def name
52
+ raw.name
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,98 @@
1
+ require 'colorize'
2
+
3
+ # Colorize colors:
4
+ # :black, :red, :green, :yellow, :blue,
5
+ # :magenta, :cyan, :white, :default, :light_black,
6
+ # :light_red, :light_green, :light_yellow, :light_blue,
7
+ # :light_magenta, :light_cyan, :light_white
8
+
9
+ module Gurke
10
+ #
11
+ class Reporter
12
+ def start_features(*)
13
+ end
14
+
15
+ def start_feature(feature)
16
+ io.puts "#{yellow('Feature')}: #{feature.name}"
17
+ io.puts ' ' + light_black(feature.description.split("\n").join("\n "))
18
+ io.puts
19
+ end
20
+
21
+ def start_scenario(scenario, feature)
22
+ io.puts " #{yellow('Scenario')}: #{scenario.name}"
23
+ io.puts light_black(' Background:') if feature.backgrounds.any?
24
+ end
25
+
26
+ def start_background(*)
27
+ @background = true
28
+ end
29
+
30
+ def finish_background(*)
31
+ @background = false
32
+ end
33
+
34
+ def start_step(step, *)
35
+ io.print ' ' if @background
36
+ io.print ' '
37
+ io.print yellow(step.keyword)
38
+ io.print step.name.gsub(/"(.*?)"/, cyan('\0'))
39
+ end
40
+
41
+ def finish_step(step, *)
42
+ case step.state
43
+ when :pending
44
+ print_braces yellow('pending')
45
+ when :failed
46
+ print_braces red('failure')
47
+ io.puts
48
+ io.puts red(" #{step.exception.class}:")
49
+
50
+ msg = step.exception.message.split("\n").join("\n ")
51
+ io.puts red(" #{msg}")
52
+
53
+ io.puts red(" #{step.exception.backtrace.join("\n ")}")
54
+ when :success
55
+ print_braces green('success')
56
+ else
57
+ print_braces cyan('skipped')
58
+ end
59
+ io.puts
60
+ io.flush
61
+ end
62
+
63
+ def finish_scenario(*)
64
+ io.puts
65
+ end
66
+
67
+ def finish_feature(*)
68
+ io.puts
69
+ end
70
+
71
+ def finish_features(features)
72
+ scenarios = features.map(&:scenarios).flatten
73
+
74
+ io.puts " #{scenarios.size} scenarios: "\
75
+ "#{scenarios.select(&:failed?).size} failing, "\
76
+ "#{scenarios.select(&:pending?).size} pending"
77
+ io.puts
78
+ end
79
+
80
+ private
81
+
82
+ def print_braces(str)
83
+ io.print " (#{str})"
84
+ end
85
+
86
+ def io
87
+ $stdout
88
+ end
89
+
90
+ [:black, :red, :green, :yellow, :blue,
91
+ :magenta, :cyan, :white, :default, :light_black,
92
+ :light_red, :light_green, :light_yellow, :light_blue,
93
+ :light_magenta, :light_cyan, :light_white].each do |color|
94
+
95
+ define_method(color){|str| io.tty? ? str.send(color) : str }
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,5 @@
1
+ require 'rspec/expectations'
2
+
3
+ Gurke.configure do |c|
4
+ c.include RSpec::Matchers
5
+ end
@@ -0,0 +1,156 @@
1
+ module Gurke
2
+ #
3
+ class Runner
4
+ attr_reader :builder
5
+ attr_reader :files
6
+ attr_reader :options
7
+
8
+ def initialize(files, options = {})
9
+ @options = options
10
+ @files = files
11
+ @builder = Builder.new options
12
+ end
13
+
14
+ def reporter
15
+ @reporter ||= Reporter.new
16
+ end
17
+
18
+ def run
19
+ files.each{|f| builder.parse(f) }
20
+
21
+ with_hooks(:features, nil, nil) do
22
+ run_features builder.features
23
+ end
24
+
25
+ !builder.features
26
+ .map(&:scenarios)
27
+ .flatten
28
+ .any?{|s| s.failed? || s.pending? }
29
+ end
30
+
31
+ def run_features(features)
32
+ reporter.start_features(features)
33
+
34
+ features.each do |feature|
35
+ run_feature(feature)
36
+ end
37
+
38
+ reporter.finish_features(features)
39
+ end
40
+
41
+ def run_feature(feature)
42
+ reporter.start_feature(feature)
43
+
44
+ feature.scenarios.each do |scenario|
45
+ run_scenario(scenario, feature)
46
+ end
47
+
48
+ reporter.finish_feature(feature)
49
+ end
50
+
51
+ def run_scenario(scenario, feature)
52
+ reporter.start_scenario(scenario, feature)
53
+
54
+ world = world_for(scenario, feature)
55
+
56
+ with_hooks(:scenario, scenario, world) do
57
+ feature.backgrounds.each do |b|
58
+ run_background(b, scenario, feature, world)
59
+ end
60
+ scenario.steps.each{|s| run_step(s, scenario, feature, world) }
61
+ end
62
+
63
+ reporter.finish_scenario(scenario, feature)
64
+ end
65
+
66
+ def run_background(background, scenario, feature, world)
67
+ reporter.start_background(background)
68
+
69
+ background.steps.each{|s| run_step(s, scenario, feature, world) }
70
+
71
+ reporter.finish_background(background)
72
+ end
73
+
74
+ def run_step(step, scenario, feature, world)
75
+ reporter.start_step(step, scenario, feature)
76
+
77
+ result = nil
78
+ with_filtered_backtrace do
79
+ match = Steps.find_step(step, world, step.type)
80
+
81
+ if scenario.pending? || scenario.failed?
82
+ result = StepResult.new(step, :skipped)
83
+ return
84
+ end
85
+
86
+ m = world.method(match.method_name)
87
+ world.send match.method_name, *(match.params + [step])[0...m.arity]
88
+ end
89
+
90
+ result = StepResult.new(step, :success)
91
+ rescue StepPending => e
92
+ scenario.pending! e
93
+ result = StepResult.new(step, :pending, e)
94
+ rescue => e
95
+ scenario.failed! e
96
+ result = StepResult.new(step, :failed, e)
97
+ ensure
98
+ reporter.finish_step(result, scenario, feature)
99
+ end
100
+
101
+ def with_hooks(scope, _context, world, &block)
102
+ Configuration::BEFORE_HOOKS.for(scope).each do |hook|
103
+ hook.run(world)
104
+ end
105
+ Configuration::AROUND_HOOKS.for(scope).reduce(block) do |blk, hook|
106
+ proc { hook.run(world, blk) }
107
+ end.call
108
+ Configuration::AFTER_HOOKS.for(scope).each do |hook|
109
+ hook.run(world)
110
+ end
111
+ end
112
+
113
+ def world_for(scenario, _feature)
114
+ scenario.send(:world)
115
+ end
116
+
117
+ def with_filtered_backtrace
118
+ yield
119
+ rescue => e
120
+ unless options[:backtrace]
121
+ base = File.expand_path(Gurke.root.dirname)
122
+ e.backtrace.select!{|l| File.expand_path(l)[0...base.size] == base }
123
+ end
124
+ raise
125
+ end
126
+
127
+ #
128
+ class StepResult
129
+ attr_reader :step, :exception, :state
130
+
131
+ def initialize(step, state, err = nil)
132
+ @step, @state, @exception = step, state, err
133
+ end
134
+
135
+ Gurke::Step.public_instance_methods(false).each do |m|
136
+ define_method(m){|*args| step.send m, *args }
137
+ end
138
+
139
+ def failed?
140
+ @state == :failed
141
+ end
142
+
143
+ def pending?
144
+ @state == :pending
145
+ end
146
+
147
+ def skipped?
148
+ @state == :skipped
149
+ end
150
+
151
+ def success?
152
+ @state == :success
153
+ end
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,84 @@
1
+ module Gurke
2
+ #
3
+ class Scenario
4
+ #
5
+ # Return path to file containing this scenario.
6
+ #
7
+ # @return [String] File path.
8
+ #
9
+ attr_reader :file
10
+
11
+ # Return line number where the scenario is defined.
12
+ #
13
+ # @return [Fixnum] Line number.
14
+ #
15
+ attr_reader :line
16
+
17
+ attr_reader :tags
18
+
19
+ # @api private
20
+ attr_reader :raw
21
+
22
+ # @api private
23
+ def initialize(file, line, tags, raw)
24
+ @file, @line, @tags, @raw = file, line, tags, raw
25
+ end
26
+
27
+ # Return list of this scenario's steps.
28
+ #
29
+ # This does not include background steps.
30
+ #
31
+ # @return [Array<Step>] Steps.
32
+ #
33
+ def steps
34
+ @steps ||= []
35
+ end
36
+
37
+ # Return name of the scenario.
38
+ #
39
+ # @return [String] Scenario name.
40
+ #
41
+ def name
42
+ raw.name
43
+ end
44
+
45
+ def pending?
46
+ @state == :pending
47
+ end
48
+
49
+ def failed?
50
+ @state == :failed
51
+ end
52
+
53
+ attr_reader :exception
54
+
55
+ # @api private
56
+ def failed!(error)
57
+ @exception = error
58
+ @state = :failed
59
+ end
60
+
61
+ # @api private
62
+ def pending!(error)
63
+ return if failed?
64
+
65
+ @exception = error
66
+ @state = :pending
67
+ end
68
+
69
+ private
70
+
71
+ def world
72
+ @world ||= begin
73
+ cls = Class.new
74
+ cls.send :include, Gurke.world
75
+
76
+ Gurke.config.inclusions.each do |incl|
77
+ cls.send :include, incl.mod
78
+ end
79
+ cls.send :include, Gurke::Steps
80
+ cls.new
81
+ end
82
+ end
83
+ end
84
+ end