sleeping_king_studios-tasks 0.1.0.rc.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +26 -0
- data/DEVELOPMENT.md +50 -0
- data/LICENSE +22 -0
- data/README.md +405 -0
- data/lib/sleeping_king_studios/tasks.rb +27 -0
- data/lib/sleeping_king_studios/tasks/apps.rb +49 -0
- data/lib/sleeping_king_studios/tasks/apps/app_configuration.rb +68 -0
- data/lib/sleeping_king_studios/tasks/apps/applications_task.rb +28 -0
- data/lib/sleeping_king_studios/tasks/apps/bundle.rb +8 -0
- data/lib/sleeping_king_studios/tasks/apps/bundle/install_runner.rb +21 -0
- data/lib/sleeping_king_studios/tasks/apps/bundle/install_task.rb +39 -0
- data/lib/sleeping_king_studios/tasks/apps/bundle/update_runner.rb +21 -0
- data/lib/sleeping_king_studios/tasks/apps/bundle/update_task.rb +39 -0
- data/lib/sleeping_king_studios/tasks/apps/ci.rb +8 -0
- data/lib/sleeping_king_studios/tasks/apps/ci/results_reporter.rb +69 -0
- data/lib/sleeping_king_studios/tasks/apps/ci/rspec_task.rb +29 -0
- data/lib/sleeping_king_studios/tasks/apps/ci/rspec_wrapper.rb +42 -0
- data/lib/sleeping_king_studios/tasks/apps/ci/rubocop_task.rb +29 -0
- data/lib/sleeping_king_studios/tasks/apps/ci/rubocop_wrapper.rb +29 -0
- data/lib/sleeping_king_studios/tasks/apps/ci/simplecov_task.rb +68 -0
- data/lib/sleeping_king_studios/tasks/apps/ci/step_wrapper.rb +49 -0
- data/lib/sleeping_king_studios/tasks/apps/ci/steps_runner.rb +37 -0
- data/lib/sleeping_king_studios/tasks/apps/ci/steps_task.rb +92 -0
- data/lib/sleeping_king_studios/tasks/ci.rb +8 -0
- data/lib/sleeping_king_studios/tasks/ci/cucumber_parser.rb +118 -0
- data/lib/sleeping_king_studios/tasks/ci/cucumber_results.rb +191 -0
- data/lib/sleeping_king_studios/tasks/ci/cucumber_runner.rb +53 -0
- data/lib/sleeping_king_studios/tasks/ci/cucumber_task.rb +47 -0
- data/lib/sleeping_king_studios/tasks/ci/results_helpers.rb +44 -0
- data/lib/sleeping_king_studios/tasks/ci/rspec_each_results.rb +118 -0
- data/lib/sleeping_king_studios/tasks/ci/rspec_each_task.rb +156 -0
- data/lib/sleeping_king_studios/tasks/ci/rspec_results.rb +126 -0
- data/lib/sleeping_king_studios/tasks/ci/rspec_runner.rb +62 -0
- data/lib/sleeping_king_studios/tasks/ci/rspec_task.rb +71 -0
- data/lib/sleeping_king_studios/tasks/ci/rubocop_results.rb +80 -0
- data/lib/sleeping_king_studios/tasks/ci/rubocop_runner.rb +46 -0
- data/lib/sleeping_king_studios/tasks/ci/rubocop_task.rb +44 -0
- data/lib/sleeping_king_studios/tasks/ci/simplecov_results.rb +62 -0
- data/lib/sleeping_king_studios/tasks/ci/simplecov_task.rb +25 -0
- data/lib/sleeping_king_studios/tasks/ci/steps_runner.rb +69 -0
- data/lib/sleeping_king_studios/tasks/ci/steps_task.rb +93 -0
- data/lib/sleeping_king_studios/tasks/configuration.rb +114 -0
- data/lib/sleeping_king_studios/tasks/file.rb +8 -0
- data/lib/sleeping_king_studios/tasks/file/new_task.rb +238 -0
- data/lib/sleeping_king_studios/tasks/process_runner.rb +70 -0
- data/lib/sleeping_king_studios/tasks/task.rb +95 -0
- data/lib/sleeping_king_studios/tasks/task_group.rb +37 -0
- data/lib/sleeping_king_studios/tasks/version.rb +58 -0
- metadata +271 -0
@@ -0,0 +1,29 @@
|
|
1
|
+
# lib/sleeping_king_studios/tasks/apps/ci/rubocop_task.rb
|
2
|
+
|
3
|
+
require 'sleeping_king_studios/tasks/apps/ci'
|
4
|
+
require 'sleeping_king_studios/tasks/apps/ci/steps_task'
|
5
|
+
|
6
|
+
module SleepingKingStudios::Tasks::Apps::Ci
|
7
|
+
# Defines a Thor task for running the RuboCop linter for each application.
|
8
|
+
class RuboCopTask < SleepingKingStudios::Tasks::Task
|
9
|
+
def self.description
|
10
|
+
'Runs the RuboCop linter for each application.'
|
11
|
+
end # class method description
|
12
|
+
|
13
|
+
def self.task_name
|
14
|
+
'rubocop'
|
15
|
+
end # class method task_name
|
16
|
+
|
17
|
+
option :quiet,
|
18
|
+
:aliases => '-q',
|
19
|
+
:type => :boolean,
|
20
|
+
:default => false,
|
21
|
+
:desc => 'Do not write lint results to STDOUT.'
|
22
|
+
|
23
|
+
def call *applications
|
24
|
+
SleepingKingStudios::Tasks::Apps::Ci::StepsTask.
|
25
|
+
new(options.merge('only' => %w(rubocop))).
|
26
|
+
call(*applications)
|
27
|
+
end # method call
|
28
|
+
end # class
|
29
|
+
end # module
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# lib/sleeping_king_studios/tasks/apps/ci/rubocop_wrapper.rb
|
2
|
+
|
3
|
+
require 'sleeping_king_studios/tasks/apps/ci'
|
4
|
+
require 'sleeping_king_studios/tasks/apps/ci/step_wrapper'
|
5
|
+
require 'sleeping_king_studios/tasks/ci/rubocop_results'
|
6
|
+
|
7
|
+
module SleepingKingStudios::Tasks::Apps::Ci
|
8
|
+
# Wrapper class for calling a RuboCop Ci task for a specific application.
|
9
|
+
class RuboCopWrapper < SleepingKingStudios::Tasks::Apps::Ci::StepWrapper
|
10
|
+
def call application
|
11
|
+
super
|
12
|
+
|
13
|
+
run_step(*source_files)
|
14
|
+
end # method call
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def source_files
|
19
|
+
config =
|
20
|
+
SleepingKingStudios::Tasks::Apps.configuration[current_application]
|
21
|
+
|
22
|
+
config.source_files + config.spec_files
|
23
|
+
end # method source_files
|
24
|
+
|
25
|
+
def step_key
|
26
|
+
:rubocop
|
27
|
+
end # method step_key
|
28
|
+
end # module
|
29
|
+
end # module
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# lib/sleeping_king_studios/tasks/apps/ci/simplecov_task.rb
|
2
|
+
|
3
|
+
require 'sleeping_king_studios/tasks/apps/ci'
|
4
|
+
require 'sleeping_king_studios/tasks/ci/simplecov_results'
|
5
|
+
require 'sleeping_king_studios/tasks/task'
|
6
|
+
|
7
|
+
module SleepingKingStudios::Tasks::Apps::Ci
|
8
|
+
# Defines a Thor task for aggregating SimpleCov coverage results across
|
9
|
+
# applications.
|
10
|
+
class SimpleCovTask < SleepingKingStudios::Tasks::Task
|
11
|
+
RESULTS_STRUCT =
|
12
|
+
Struct.new(
|
13
|
+
:covered_lines,
|
14
|
+
:covered_percent,
|
15
|
+
:missed_lines,
|
16
|
+
:total_lines
|
17
|
+
) # end struct
|
18
|
+
|
19
|
+
def self.configure_simplecov!
|
20
|
+
require 'simplecov'
|
21
|
+
require 'simplecov-json'
|
22
|
+
|
23
|
+
::SimpleCov.configure do
|
24
|
+
command_name "#{command_name}:#{ENV['APP_NAME']}" if ENV['APP_NAME']
|
25
|
+
|
26
|
+
self.formatter =
|
27
|
+
::SimpleCov::Formatter::MultiFormatter.new(
|
28
|
+
[formatter, ::SimpleCov::Formatter::JSONFormatter]
|
29
|
+
) # end formatter
|
30
|
+
end # configure
|
31
|
+
end # class method configure_simplecov!
|
32
|
+
|
33
|
+
def self.description
|
34
|
+
'Aggregates the SimpleCov results for all applications.'
|
35
|
+
end # class method description
|
36
|
+
|
37
|
+
def self.task_name
|
38
|
+
'simplecov'
|
39
|
+
end # class method task_name
|
40
|
+
|
41
|
+
def call _application = nil
|
42
|
+
results = load_report :report => File.join('coverage', 'coverage.json')
|
43
|
+
results = convert_results_to_object(results)
|
44
|
+
|
45
|
+
SleepingKingStudios::Tasks::Ci::SimpleCovResults.new(results)
|
46
|
+
end # method call
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def load_report report:
|
51
|
+
raw = File.read report
|
52
|
+
json = JSON.parse raw
|
53
|
+
|
54
|
+
json['metrics']
|
55
|
+
rescue
|
56
|
+
{}
|
57
|
+
end # method load_report
|
58
|
+
|
59
|
+
def convert_results_to_object hsh
|
60
|
+
RESULTS_STRUCT.new(
|
61
|
+
hsh.fetch('covered_lines', 0),
|
62
|
+
hsh.fetch('covered_percent', 0.0),
|
63
|
+
hsh.fetch('total_lines', 0) - hsh.fetch('covered_lines', 0),
|
64
|
+
hsh.fetch('total_lines', 0)
|
65
|
+
) # end object
|
66
|
+
end # method convert_results_to_object
|
67
|
+
end # module
|
68
|
+
end # module
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# lib/sleeping_king_studios/tasks/apps/ci/step_wrapper.rb
|
2
|
+
|
3
|
+
require 'sleeping_king_studios/tasks/apps/applications_task'
|
4
|
+
require 'sleeping_king_studios/tasks/apps/ci'
|
5
|
+
|
6
|
+
module SleepingKingStudios::Tasks::Apps::Ci
|
7
|
+
# Wrapper class for calling a configured task for a specific application.
|
8
|
+
class StepWrapper < SleepingKingStudios::Tasks::Task
|
9
|
+
include SleepingKingStudios::Tasks::Apps::ApplicationsTask
|
10
|
+
|
11
|
+
def call application, *_rest
|
12
|
+
@current_application = application
|
13
|
+
@step_config = nil
|
14
|
+
end # method call
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
attr_reader :current_application
|
19
|
+
|
20
|
+
def build_step
|
21
|
+
require step_config.fetch(:require) if step_config.key?(:require)
|
22
|
+
|
23
|
+
step_class = Object.const_get(step_config.fetch :class)
|
24
|
+
|
25
|
+
step_class.new(step_options)
|
26
|
+
end # method
|
27
|
+
|
28
|
+
def run_step *args
|
29
|
+
return if skip_step?
|
30
|
+
|
31
|
+
build_step.call(*args)
|
32
|
+
end # method run_step
|
33
|
+
|
34
|
+
def skip_step?
|
35
|
+
step_config == false
|
36
|
+
end # method skip_step?
|
37
|
+
|
38
|
+
def step_config
|
39
|
+
config = SleepingKingStudios::Tasks.configuration
|
40
|
+
steps = config.ci.steps_with_options
|
41
|
+
|
42
|
+
steps.fetch(step_key, false)
|
43
|
+
end # method step_config
|
44
|
+
|
45
|
+
def step_options
|
46
|
+
options
|
47
|
+
end # method step_options
|
48
|
+
end # class
|
49
|
+
end # module
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# lib/sleeping_king_studios/tasks/apps/ci/steps_runner.rb
|
2
|
+
|
3
|
+
require 'sleeping_king_studios/tasks/apps/applications_task'
|
4
|
+
require 'sleeping_king_studios/tasks/ci/steps_runner'
|
5
|
+
|
6
|
+
module SleepingKingStudios::Tasks::Apps::Ci
|
7
|
+
# Abstract base class for running a sequence of tasks for a specific
|
8
|
+
# application from a configured list.
|
9
|
+
class StepsRunner < SleepingKingStudios::Tasks::Ci::StepsRunner
|
10
|
+
include SleepingKingStudios::Tasks::Apps::ApplicationsTask
|
11
|
+
|
12
|
+
def call application
|
13
|
+
@current_application = application
|
14
|
+
|
15
|
+
super application
|
16
|
+
end # method call
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
attr_reader :current_application
|
21
|
+
|
22
|
+
def ci_steps
|
23
|
+
SleepingKingStudios::Tasks::Apps.configuration[current_application].
|
24
|
+
ci.steps_with_options
|
25
|
+
end # method ci_steps
|
26
|
+
|
27
|
+
def skip_step? _name, config
|
28
|
+
return true if config == false
|
29
|
+
|
30
|
+
if options.fetch('global', false)
|
31
|
+
!config.fetch(:global, false)
|
32
|
+
else
|
33
|
+
config.fetch(:global, false)
|
34
|
+
end # if-else
|
35
|
+
end # method skip_step?
|
36
|
+
end # class
|
37
|
+
end # module
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# lib/sleeping_king_studios/tasks/apps/ci/steps_task.rb
|
2
|
+
|
3
|
+
require 'sleeping_king_studios/tasks/apps/applications_task'
|
4
|
+
require 'sleeping_king_studios/tasks/apps/ci'
|
5
|
+
require 'sleeping_king_studios/tasks/apps/ci/results_reporter'
|
6
|
+
require 'sleeping_king_studios/tasks/apps/ci/steps_runner'
|
7
|
+
|
8
|
+
module SleepingKingStudios::Tasks::Apps::Ci
|
9
|
+
# Thor task for running each step in the CI suite for each application and
|
10
|
+
# generating a report.
|
11
|
+
class StepsTask < SleepingKingStudios::Tasks::Task
|
12
|
+
include SleepingKingStudios::Tasks::Apps::ApplicationsTask
|
13
|
+
|
14
|
+
def self.description
|
15
|
+
'Runs the configured steps for each application.'
|
16
|
+
end # class method description
|
17
|
+
|
18
|
+
option :except,
|
19
|
+
:type => :array,
|
20
|
+
:default => [],
|
21
|
+
:desc => 'Exclude steps from the CI process.'
|
22
|
+
option :only,
|
23
|
+
:type => :array,
|
24
|
+
:default => [],
|
25
|
+
:desc => 'Run only the specified steps from the CI process.'
|
26
|
+
option :quiet,
|
27
|
+
:aliases => '-q',
|
28
|
+
:type => :boolean,
|
29
|
+
:default => false,
|
30
|
+
:desc => 'Do not write intermediate results to STDOUT.'
|
31
|
+
|
32
|
+
def call *applications
|
33
|
+
filtered = filter_applications :only => applications
|
34
|
+
results = run_steps(filtered)
|
35
|
+
globals = run_global_steps
|
36
|
+
|
37
|
+
aggregate_results(results) if filtered.count > 1
|
38
|
+
|
39
|
+
(results['Totals'] ||= {}).update(globals)
|
40
|
+
|
41
|
+
say "\n" unless quiet?
|
42
|
+
|
43
|
+
reporter = ResultsReporter.new(self)
|
44
|
+
reporter.call(results)
|
45
|
+
|
46
|
+
results
|
47
|
+
end # method call
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def aggregate_results results
|
52
|
+
totals = Hash.new { |hsh, key| hsh[key] = 0 }
|
53
|
+
|
54
|
+
results.each do |_, app_results|
|
55
|
+
app_results.each do |step, step_results|
|
56
|
+
next if step_results.nil?
|
57
|
+
|
58
|
+
next totals[step] = step_results unless totals.key?(step)
|
59
|
+
|
60
|
+
totals[step] = totals[step].merge(step_results)
|
61
|
+
end # each
|
62
|
+
end # each
|
63
|
+
|
64
|
+
results['Totals'] = totals
|
65
|
+
end # method aggregate_results
|
66
|
+
|
67
|
+
def run_global_steps
|
68
|
+
opts = options.merge 'global' => true
|
69
|
+
runner = SleepingKingStudios::Tasks::Apps::Ci::StepsRunner.new(opts)
|
70
|
+
|
71
|
+
runner.call(nil)
|
72
|
+
end # method run_global_steps
|
73
|
+
|
74
|
+
def run_steps applications
|
75
|
+
results = Hash.new { |hsh, key| hsh[key] = {} }
|
76
|
+
|
77
|
+
applications.each do |name, _|
|
78
|
+
results[name] = run_steps_for_application(name)
|
79
|
+
end # each
|
80
|
+
|
81
|
+
results
|
82
|
+
end # method run_steps
|
83
|
+
|
84
|
+
def run_steps_for_application name
|
85
|
+
steps_runner.call(name)
|
86
|
+
end # method run_steps_for_application
|
87
|
+
|
88
|
+
def steps_runner
|
89
|
+
SleepingKingStudios::Tasks::Apps::Ci::StepsRunner.new(options)
|
90
|
+
end # method steps_runner
|
91
|
+
end # class
|
92
|
+
end # module
|
@@ -0,0 +1,118 @@
|
|
1
|
+
# lib/sleeping_king_studios/tasks/ci/cucumber_parser.rb
|
2
|
+
|
3
|
+
require 'sleeping_king_studios/tasks/ci'
|
4
|
+
|
5
|
+
module SleepingKingStudios::Tasks::Ci
|
6
|
+
# Parses the output from cucumber --format=json into a summary report.
|
7
|
+
module CucumberParser
|
8
|
+
class << self
|
9
|
+
def parse results
|
10
|
+
@report = build_report
|
11
|
+
|
12
|
+
results.each { |feature| parse_feature(feature) }
|
13
|
+
|
14
|
+
report['duration'] = report['duration'] / (1.0 * 10**9)
|
15
|
+
|
16
|
+
report
|
17
|
+
end # class method parse
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
attr_reader :report
|
22
|
+
|
23
|
+
def build_report
|
24
|
+
{
|
25
|
+
'scenario_count' => 0,
|
26
|
+
'failing_scenarios' => [],
|
27
|
+
'pending_scenarios' => [],
|
28
|
+
'step_count' => 0,
|
29
|
+
'failing_step_count' => 0,
|
30
|
+
'pending_step_count' => 0,
|
31
|
+
'duration' => 0
|
32
|
+
} # end report
|
33
|
+
end # method build report
|
34
|
+
|
35
|
+
def parse_feature feature
|
36
|
+
feature['elements'].each do |scenario|
|
37
|
+
parse_scenario(scenario, feature)
|
38
|
+
end # each
|
39
|
+
end # method parse_feature
|
40
|
+
|
41
|
+
# rubocop:disable Metrics/MethodLength
|
42
|
+
def parse_scenario scenario, feature
|
43
|
+
failing = false
|
44
|
+
pending = false
|
45
|
+
|
46
|
+
scenario['steps'].each do |step|
|
47
|
+
status = parse_step(step)
|
48
|
+
|
49
|
+
failing ||= status == 'failed'
|
50
|
+
pending ||= status == 'pending' || status == 'skipped'
|
51
|
+
end # each
|
52
|
+
|
53
|
+
report_scenario(
|
54
|
+
scenario,
|
55
|
+
feature,
|
56
|
+
:failing => failing,
|
57
|
+
:pending => pending
|
58
|
+
) # end report scenario
|
59
|
+
end # method parse_scenario
|
60
|
+
# rubocop:enable Metrics/MethodLength
|
61
|
+
|
62
|
+
def parse_step step
|
63
|
+
report['step_count'] += 1
|
64
|
+
report['duration'] += step_duration(step)
|
65
|
+
|
66
|
+
status = step_status(step) || 'failed'
|
67
|
+
|
68
|
+
if status == 'failed'
|
69
|
+
report['failing_step_count'] += 1
|
70
|
+
elsif status == 'pending' || status == 'skipped'
|
71
|
+
report['pending_step_count'] += 1
|
72
|
+
end # if
|
73
|
+
|
74
|
+
status
|
75
|
+
end # method parse_step
|
76
|
+
|
77
|
+
# rubocop:disable Metrics/MethodLength
|
78
|
+
def report_scenario scenario, feature, failing:, pending:
|
79
|
+
report['scenario_count'] += 1
|
80
|
+
|
81
|
+
return unless failing || pending
|
82
|
+
|
83
|
+
hsh =
|
84
|
+
{
|
85
|
+
'location' => "#{feature['uri']}:#{scenario['line']}",
|
86
|
+
'description' => "#{scenario['keyword']}: #{scenario['name']}"
|
87
|
+
}
|
88
|
+
|
89
|
+
if failing
|
90
|
+
report['failing_scenarios'] << hsh
|
91
|
+
else
|
92
|
+
report['pending_scenarios'] << hsh
|
93
|
+
end # if-else
|
94
|
+
end # method report_scenario
|
95
|
+
# rubocop:enable Metrics/MethodLength
|
96
|
+
|
97
|
+
def step_duration hsh
|
98
|
+
return 0 if hsh.nil? || hsh.empty?
|
99
|
+
|
100
|
+
result = hsh['result']
|
101
|
+
|
102
|
+
return 0 if result.nil? || result.empty?
|
103
|
+
|
104
|
+
result['duration'] || 0
|
105
|
+
end # method step_duration
|
106
|
+
|
107
|
+
def step_status hsh
|
108
|
+
return nil if hsh.nil? || hsh.empty?
|
109
|
+
|
110
|
+
result = hsh['result']
|
111
|
+
|
112
|
+
return nil if result.nil? || result.empty?
|
113
|
+
|
114
|
+
result['status']
|
115
|
+
end # method step_status
|
116
|
+
end # class
|
117
|
+
end # module
|
118
|
+
end # module
|
@@ -0,0 +1,191 @@
|
|
1
|
+
# lib/sleeping_king_studios/tasks/ci/cucumber_results.rb
|
2
|
+
|
3
|
+
require 'sleeping_king_studios/tasks/ci'
|
4
|
+
|
5
|
+
module SleepingKingStudios::Tasks::Ci
|
6
|
+
# rubocop:disable Metrics/ClassLength
|
7
|
+
|
8
|
+
# Encapsulates the results of a Cucumber call.
|
9
|
+
class CucumberResults
|
10
|
+
# @param results [Hash] The raw results of the RSpec call.
|
11
|
+
def initialize results
|
12
|
+
@results = results
|
13
|
+
end # constructor
|
14
|
+
|
15
|
+
# @param other [RSpecResults] The other results object to compare.
|
16
|
+
#
|
17
|
+
# @return [Boolean] True if the results are equal, otherwise false.
|
18
|
+
def == other
|
19
|
+
if other.is_a?(Hash)
|
20
|
+
empty? ? other.empty? : to_h == other
|
21
|
+
elsif other.is_a?(CucumberResults)
|
22
|
+
to_h == other.to_h
|
23
|
+
else
|
24
|
+
false
|
25
|
+
end # if-elsif-else
|
26
|
+
end # method ==
|
27
|
+
|
28
|
+
# @return [Float] The duration value.
|
29
|
+
def duration
|
30
|
+
@results.fetch('duration', 0.0)
|
31
|
+
end # method duration
|
32
|
+
|
33
|
+
# @return [Boolean] True if there are no scenarios, otherwise false.
|
34
|
+
def empty?
|
35
|
+
scenario_count.zero?
|
36
|
+
end # method empty?
|
37
|
+
|
38
|
+
# @return [Boolean] True if there are any failing scenarios, otherwise
|
39
|
+
# false.
|
40
|
+
def failing?
|
41
|
+
!failing_scenario_count.zero?
|
42
|
+
end # method failing?
|
43
|
+
|
44
|
+
# @return [Integer] The list of failing scenarios.
|
45
|
+
def failing_scenarios
|
46
|
+
@results.fetch('failing_scenarios', [])
|
47
|
+
end # method failing_scenarios
|
48
|
+
|
49
|
+
# @return [Integer] The number of failing scenarios.
|
50
|
+
def failing_scenario_count
|
51
|
+
failing_scenarios.count
|
52
|
+
end # method failing_scenario_count
|
53
|
+
|
54
|
+
# @return [Integer] The number of failing steps.
|
55
|
+
def failing_step_count
|
56
|
+
@results.fetch('failing_step_count', 0)
|
57
|
+
end # method failing_step_count
|
58
|
+
|
59
|
+
# Adds the given result values and returns a new results object with the
|
60
|
+
# sums.
|
61
|
+
#
|
62
|
+
# @param other [RSpecResults] The results to add.
|
63
|
+
#
|
64
|
+
# @return [RSpecResults] The total results.
|
65
|
+
def merge other
|
66
|
+
merged = {}
|
67
|
+
|
68
|
+
keys.each do |key|
|
69
|
+
merged[key] = public_send(key) + other.public_send(key)
|
70
|
+
end # each
|
71
|
+
|
72
|
+
self.class.new(merged)
|
73
|
+
end # method merge
|
74
|
+
|
75
|
+
# @return [Boolean] True if there are any pending scenarios, otherwise
|
76
|
+
# false.
|
77
|
+
def pending?
|
78
|
+
!pending_scenario_count.zero?
|
79
|
+
end # method pending?
|
80
|
+
|
81
|
+
# @return [Integer] The number of pending scenarios.
|
82
|
+
def pending_scenario_count
|
83
|
+
pending_scenarios.count
|
84
|
+
end # method pending_scenario_count
|
85
|
+
|
86
|
+
# @return [Integer] The list of pending scenarios.
|
87
|
+
def pending_scenarios
|
88
|
+
@results.fetch('pending_scenarios', [])
|
89
|
+
end # method pending_scenarios
|
90
|
+
|
91
|
+
# @return [Integer] The number of pending steps.
|
92
|
+
def pending_step_count
|
93
|
+
@results.fetch('pending_step_count', 0)
|
94
|
+
end # method pending_step_count
|
95
|
+
|
96
|
+
# @return [Integer] The total number of scenarios.
|
97
|
+
def scenario_count
|
98
|
+
@results.fetch('scenario_count', 0)
|
99
|
+
end # method scenario_count
|
100
|
+
|
101
|
+
# @return [String] A brief summary of the scenario results.
|
102
|
+
def scenarios_summary
|
103
|
+
build_summary(
|
104
|
+
'scenario',
|
105
|
+
scenario_count,
|
106
|
+
failing_scenario_count,
|
107
|
+
pending_scenario_count
|
108
|
+
) # end build_summary
|
109
|
+
end # method scenarios_summary
|
110
|
+
|
111
|
+
# @return [Integer] The total number of steps.
|
112
|
+
def step_count
|
113
|
+
@results.fetch('step_count', 0)
|
114
|
+
end # method step_count
|
115
|
+
|
116
|
+
# @return [String] A brief summary of the scenario results.
|
117
|
+
def steps_summary
|
118
|
+
build_summary(
|
119
|
+
'step',
|
120
|
+
step_count,
|
121
|
+
failing_step_count,
|
122
|
+
pending_step_count
|
123
|
+
) # end build_summary
|
124
|
+
end # method steps_summary
|
125
|
+
|
126
|
+
# @return [String] A brief summary of the results.
|
127
|
+
def summary
|
128
|
+
str = scenarios_summary
|
129
|
+
|
130
|
+
str << ', '
|
131
|
+
|
132
|
+
str << steps_summary
|
133
|
+
|
134
|
+
str << " in #{duration.round(2)} seconds"
|
135
|
+
end # method summary
|
136
|
+
alias_method :to_s, :summary
|
137
|
+
|
138
|
+
# @return [Hash] The hash representation of the results.
|
139
|
+
def to_h
|
140
|
+
hsh = {}
|
141
|
+
|
142
|
+
keys.each { |key| hsh[key] = public_send(key) }
|
143
|
+
|
144
|
+
hsh
|
145
|
+
end # method to_h
|
146
|
+
|
147
|
+
private
|
148
|
+
|
149
|
+
def build_summary name, count, failing_count, pending_count
|
150
|
+
str = pluralize(count, name)
|
151
|
+
|
152
|
+
return str if failing_count.zero? && pending_count.zero?
|
153
|
+
|
154
|
+
str << build_summary_details(failing_count, pending_count)
|
155
|
+
end # method build_summary
|
156
|
+
|
157
|
+
def build_summary_details failing_count, pending_count
|
158
|
+
str = ' ('
|
159
|
+
|
160
|
+
str << pluralize(failing_count, 'failure') unless failing_count.zero?
|
161
|
+
|
162
|
+
str << ', ' if !failing_count.zero? && !pending_count.zero?
|
163
|
+
|
164
|
+
str << "#{pending_count} pending" unless pending_count.zero?
|
165
|
+
|
166
|
+
str << ')'
|
167
|
+
end # method build_summary_details
|
168
|
+
|
169
|
+
def keys
|
170
|
+
%w(
|
171
|
+
duration
|
172
|
+
step_count
|
173
|
+
pending_step_count
|
174
|
+
failing_step_count
|
175
|
+
scenario_count
|
176
|
+
pending_scenarios
|
177
|
+
failing_scenarios
|
178
|
+
) # end keys
|
179
|
+
end # method keys
|
180
|
+
|
181
|
+
def pluralize count, singular, plural = nil
|
182
|
+
"#{count} #{tools.integer.pluralize count, singular, plural}"
|
183
|
+
end # method pluralize
|
184
|
+
|
185
|
+
def tools
|
186
|
+
SleepingKingStudios::Tools::Toolbelt.instance
|
187
|
+
end # method tools
|
188
|
+
end # class
|
189
|
+
|
190
|
+
# rubocop:enable Metrics/ClassLength
|
191
|
+
end # module
|