openstudio_measure_tester 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.
@@ -0,0 +1,167 @@
1
+ ########################################################################################################################
2
+ # OpenStudio(R), Copyright (c) 2008-2018, Alliance for Sustainable Energy, LLC. All rights reserved.
3
+ #
4
+ # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
5
+ # following conditions are met:
6
+ #
7
+ # (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
8
+ # disclaimer.
9
+ #
10
+ # (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
11
+ # following disclaimer in the documentation and/or other materials provided with the distribution.
12
+ #
13
+ # (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote
14
+ # products derived from this software without specific prior written permission from the respective party.
15
+ #
16
+ # (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative
17
+ # works may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without
18
+ # specific prior written permission from Alliance for Sustainable Energy, LLC.
19
+ #
20
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
21
+ # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER, THE UNITED STATES GOVERNMENT, OR ANY CONTRIBUTORS BE LIABLE FOR
23
+ # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24
+ # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25
+ # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
+ ########################################################################################################################
28
+
29
+ module OpenStudioMeasureTester
30
+ class OpenStudioTestingResult
31
+ attr_reader :results
32
+
33
+ # Pass in the results_dir where all the results are stored
34
+ # @param results_dir [String]: Directory where the results are scattered. Typically the root dir or where rake was executed
35
+ # @param test_results_dir [String]: Where the final results are to be stored
36
+ def initialize(results_dir, test_results_dir)
37
+ @results_dir = results_dir
38
+ @test_results_dir = test_results_dir
39
+ @results = {}
40
+
41
+ # get the repository info
42
+ g = Git.open(Dir.pwd)
43
+ config = g.config
44
+ repo_name = config['remote.origin.url'].split('/')[1].split('.')[0]
45
+ current_branch = g.branch.name
46
+ @results['repo_name'] = repo_name
47
+ @results['current_branch'] = current_branch
48
+ # TODO add failsafe
49
+
50
+ # check if the results data already exist, and if so, then load the file now to keep the results
51
+ load_results
52
+ aggregate_results
53
+ end
54
+
55
+ def aggregate_results
56
+ # TODO: check if we need this check of directories
57
+ if @test_results_dir != @results_dir
58
+ # coverage
59
+ if Dir.exist? "#{@results_dir}/coverage"
60
+ FileUtils.rm_rf "#{@test_results_dir}/coverage" if Dir.exist? "#{@test_results_dir}/coverage"
61
+ FileUtils.mv "#{@results_dir}/coverage", "#{@test_results_dir}/."
62
+
63
+ cov = OpenStudioMeasureTester::Coverage.new("#{@test_results_dir}/coverage")
64
+ @results["coverage"] = cov.to_hash
65
+ end
66
+
67
+ # minitest
68
+ if Dir.exist?("#{@results_dir}/test/html_reports") || Dir.exist?("#{@results_dir}/test/reports")
69
+ FileUtils.rm_rf "#{@test_results_dir}/minitest" if Dir.exist? "#{@test_results_dir}/minitest"
70
+ FileUtils.mkdir_p "#{@test_results_dir}/minitest"
71
+ FileUtils.mv "#{@results_dir}/test/html_reports", "#{@test_results_dir}/minitest/html_reports"
72
+ FileUtils.mv "#{@results_dir}/test/reports", "#{@test_results_dir}/minitest/reports"
73
+
74
+ # Delete the test folder if it is empty
75
+ FileUtils.rm_rf "#{@results_dir}/test" if Dir.entries("#{@results_dir}/test").size == 2
76
+
77
+ # Load in the data into the minitest object
78
+ mr = OpenStudioMeasureTester::MinitestResult.new("#{@test_results_dir}/minitest")
79
+ @results['minitest'] = mr.summary
80
+ end
81
+
82
+ # rubocop
83
+ if Dir.exist? "#{@results_dir}/rubocop"
84
+ FileUtils.rm_rf "#{@test_results_dir}/rubocop" if Dir.exist? "#{@test_results_dir}/rubocop"
85
+ FileUtils.mv "#{@results_dir}/rubocop", "#{@test_results_dir}/rubocop"
86
+
87
+ # need to create parser here!
88
+ # trying!!! &^&%##%@((@*&()))!!
89
+ rc = OpenStudioMeasureTester::RubocopResult.new("#{@test_results_dir}/rubocop")
90
+ @results['rubocop'] = rc.summary
91
+
92
+ end
93
+
94
+ # openstudio style
95
+ if Dir.exist? "#{@results_dir}/openstudio_style"
96
+ FileUtils.rm_rf "#{@test_results_dir}/openstudio_style" if Dir.exist? "#{@test_results_dir}/openstudio_style"
97
+ FileUtils.mv "#{@results_dir}/openstudio_style", "#{@test_results_dir}/openstudio_style"
98
+
99
+ # OpenStudio Style will have already run, so just grab the results out of the directory and jam into
100
+ # the @results hash
101
+ filename = "#{@test_results_dir}/openstudio_style/openstudio_style.json"
102
+ if File.exist? filename
103
+ @results['openstudio_style'] = JSON.parse(File.read(filename))
104
+ end
105
+ end
106
+ end
107
+ end
108
+
109
+ def load_results
110
+ filename = "#{@test_results_dir}/combined_results.json"
111
+ begin
112
+ @results = JSON.parse(File.read(filename)) if File.exist? filename
113
+ rescue
114
+ @results = {}
115
+ end
116
+ end
117
+
118
+ def save_results
119
+ File.open("#{@test_results_dir}/combined_results.json", 'w') do |file|
120
+ file << JSON.pretty_generate(@results)
121
+ end
122
+ end
123
+
124
+ # Return the exit code based on some arbitrary limit across all the tests
125
+ def exit_code
126
+ # there must be no unit test failures
127
+ # pp @results
128
+ final_exit_code = 0
129
+ if @results['rubocop']
130
+ if @results['rubocop']['total_errors'] > 0
131
+ puts 'RuboCop errors found.'
132
+ final_exit_code = 1
133
+ end
134
+ end
135
+
136
+ if @results['openstudio_style']
137
+ if @results['openstudio_style']['total_errors'] > 0
138
+ puts 'OpenStudio Style errors found.'
139
+ final_exit_code = 1
140
+ end
141
+ if @results['openstudio_style']['total_warnings'] > 10
142
+ puts 'More than 10 OpenStudio Style warnings found, reporting as error'
143
+ final_exit_code = 1
144
+ end
145
+ end
146
+
147
+ if @results['minitest']
148
+ if @results['minitest']['total_errors'] > 0 || @results['minitest']['total_failures'] > 0
149
+ puts 'Unit Test (MiniTest) errors/failures found.'
150
+ final_exit_code = 1
151
+ end
152
+ end
153
+
154
+ if @results['coverage']
155
+ if @results['coverage']['total_percent_coverage'] < 70
156
+ puts 'Code coverage is less than 70%, raising error.'
157
+ final_exit_code = 1
158
+ end
159
+ end
160
+
161
+ puts 'Open ./test_results/dashboard/index.html to view measure testing dashboard.'
162
+
163
+ return final_exit_code
164
+ end
165
+ end
166
+ end
167
+
@@ -0,0 +1,258 @@
1
+ ########################################################################################################################
2
+ # OpenStudio(R), Copyright (c) 2008-2018, Alliance for Sustainable Energy, LLC. All rights reserved.
3
+ #
4
+ # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
5
+ # following conditions are met:
6
+ #
7
+ # (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
8
+ # disclaimer.
9
+ #
10
+ # (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
11
+ # following disclaimer in the documentation and/or other materials provided with the distribution.
12
+ #
13
+ # (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote
14
+ # products derived from this software without specific prior written permission from the respective party.
15
+ #
16
+ # (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative
17
+ # works may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without
18
+ # specific prior written permission from Alliance for Sustainable Energy, LLC.
19
+ #
20
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
21
+ # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER, THE UNITED STATES GOVERNMENT, OR ANY CONTRIBUTORS BE LIABLE FOR
23
+ # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24
+ # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25
+ # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
+ ########################################################################################################################
28
+
29
+ require 'rake'
30
+ require 'rake/tasklib'
31
+ require 'rake/testtask'
32
+ require 'rubocop/rake_task'
33
+
34
+ require_relative '../openstudio_measure_tester'
35
+
36
+ module OpenStudioMeasureTester
37
+ class RakeTask < Rake::TaskLib
38
+ attr_accessor :name
39
+
40
+ def initialize(*args, &task_block)
41
+ @name = args.shift || :openstudio
42
+
43
+ setup_subtasks(@name)
44
+ end
45
+
46
+ private
47
+
48
+ # Prepare the current directory and the root directory to remove old test results before running
49
+ # the new tests
50
+ def pre_process_minitest(base_dir)
51
+ current_dir = Dir.pwd
52
+ test_results_dir = "#{base_dir}/test_results"
53
+
54
+ puts "Current directory is #{current_dir}"
55
+ puts "Pre-processing tests run in #{base_dir}"
56
+ puts "Test results will be stored in: #{test_results_dir}"
57
+
58
+ FileUtils.rm_rf "#{test_results_dir}/coverage" if Dir.exist? "#{test_results_dir}/coverage"
59
+ FileUtils.rm_rf "#{test_results_dir}/test/html_reports" if Dir.exist? "#{test_results_dir}/test/html_reports"
60
+ FileUtils.rm_rf "#{test_results_dir}/test/reports" if Dir.exist? "#{test_results_dir}/test/reports"
61
+ # remove the test directory if it is empty (size == 2 for . and ..)
62
+ if Dir.exist?("#{test_results_dir}/test") && Dir.entries("#{test_results_dir}/test").size == 2
63
+ FileUtils.rm_rf "#{test_results_dir}/test"
64
+ end
65
+ FileUtils.rm_rf "#{test_results_dir}/minitest" if Dir.exist? "#{test_results_dir}/minitest"
66
+ FileUtils.rm_rf "#{base_dir}/coverage" if Dir.exist? "#{base_dir}/coverage"
67
+ FileUtils.rm_rf "#{base_dir}/test" if Dir.exist? "#{base_dir}/test"
68
+ FileUtils.rm_rf "#{base_dir}/minitest" if Dir.exist? "#{base_dir}/minitest"
69
+ FileUtils.rm_rf "#{current_dir}/coverage" if Dir.exist? "#{current_dir}/coverage"
70
+ FileUtils.rm_rf "#{current_dir}/test" if Dir.exist? "#{current_dir}/test"
71
+ FileUtils.rm_rf "#{current_dir}/minitest" if Dir.exist? "#{current_dir}/minitest"
72
+
73
+ # Create the test_results directory to store all the results
74
+ FileUtils.mkdir_p "#{base_dir}/test_results"
75
+ end
76
+
77
+ # Rubocop stores the results (for now) in the test_results directory
78
+ def pre_process_rubocop(base_dir)
79
+ current_dir = Dir.pwd
80
+ test_results_dir = "#{base_dir}/test_results"
81
+
82
+ puts "Current directory is #{current_dir}"
83
+ puts "Pre-processing tests run in #{base_dir}"
84
+ puts "Test results will be stored in: #{test_results_dir}"
85
+
86
+ FileUtils.rm_rf "#{test_results_dir}/rubocop" if Dir.exist? "#{test_results_dir}/rubocop"
87
+ FileUtils.rm_rf "#{base_dir}/rubocop" if Dir.exist? "#{base_dir}/rubocop"
88
+ FileUtils.rm_rf "#{current_dir}/rubocop" if Dir.exist? "#{current_dir}/rubocop"
89
+
90
+ # Create the test_results directory to store all the results
91
+ FileUtils.mkdir_p "#{base_dir}/test_results"
92
+ end
93
+
94
+ # OpenStudio style check preparation
95
+ def pre_process_style(base_dir)
96
+ current_dir = Dir.pwd
97
+ test_results_dir = "#{base_dir}/test_results"
98
+
99
+ puts "Current directory is #{current_dir}"
100
+ puts "Pre-processing tests run in #{base_dir}"
101
+ puts "Test results will be stored in: #{test_results_dir}"
102
+
103
+ FileUtils.rm_rf "#{test_results_dir}/openstudio_style" if Dir.exist? "#{test_results_dir}/openstudio_style"
104
+ FileUtils.rm_rf "#{base_dir}/openstudio_style" if Dir.exist? "#{base_dir}/openstudio_style"
105
+ FileUtils.rm_rf "#{current_dir}/openstudio_style" if Dir.exist? "#{current_dir}/openstudio_style"
106
+
107
+ # Create the test_results directory to store all the results
108
+ FileUtils.mkdir_p "#{base_dir}/test_results"
109
+ end
110
+
111
+ def run_style(base_dir)
112
+ style = OpenStudioMeasureTester::OpenStudioStyle.new("#{base_dir}/**/measure.rb")
113
+ style.save_results
114
+ end
115
+
116
+ # Post process the various results and save them into the base_dir
117
+ def post_process_results(base_dir)
118
+ current_dir = Dir.pwd
119
+ test_results_dir = "#{base_dir}/test_results"
120
+
121
+ puts "Current directory: #{current_dir}"
122
+ puts "Post-processing tests run in: #{base_dir}"
123
+ puts "Test results will be stored in: #{test_results_dir}"
124
+
125
+ FileUtils.mkdir_p test_results_dir
126
+
127
+ results = OpenStudioMeasureTester::OpenStudioTestingResult.new(current_dir, test_results_dir)
128
+ results.save_results # one single file for dashboard
129
+
130
+ # call the create dashboard command now that we have results
131
+ dashboard(base_dir)
132
+
133
+ # return the results exit code
134
+ return results.exit_code
135
+ end
136
+
137
+ # Run ERB to create the dashboard
138
+ def dashboard(base_dir)
139
+ template = OpenStudioMeasureTester::Dashboard.new(base_dir)
140
+ template.render
141
+ end
142
+
143
+ def setup_subtasks(name)
144
+ namespace name do
145
+ task :prepare_minitest do
146
+ pre_process_minitest(Rake.application.original_dir)
147
+ end
148
+
149
+ task :prepare_rubocop do
150
+ # copy over the .rubocop.yml file
151
+ shared_rubocop_file = File.expand_path('../../.rubocop.yml', File.dirname(__FILE__))
152
+ dest_file = "#{Dir.pwd}/.rubocop.yml"
153
+ if shared_rubocop_file != dest_file
154
+ FileUtils.copy(shared_rubocop_file, dest_file)
155
+ end
156
+ pre_process_rubocop(Rake.application.original_dir)
157
+ end
158
+
159
+ task :prepare_style do
160
+ pre_process_style(Rake.application.original_dir)
161
+ end
162
+
163
+ task style_core: [] do
164
+ run_style(Rake.application.original_dir)
165
+ end
166
+
167
+ task :post_process_core do
168
+ post_process_results(Rake.application.original_dir)
169
+ end
170
+
171
+ Rake::TestTask.new(:test_core_command) do |task|
172
+ task.options = '--ci-reporter'
173
+ task.description = 'Run measures tests recursively from current directory'
174
+ task.pattern = [
175
+ "#{Rake.application.original_dir}/**/*_test.rb",
176
+ "#{Rake.application.original_dir}/**/*_Test.rb"
177
+ ]
178
+ task.verbose = true
179
+ end
180
+
181
+ task :test_core do
182
+ begin
183
+ Rake.application['openstudio:test_core_command'].invoke
184
+ rescue StandardError
185
+ puts 'Test failures in openstudio:test. Will continue to post-processing.'
186
+ ensure
187
+ Rake.application['openstudio:test_core_command'].reenable
188
+ end
189
+ end
190
+
191
+ # The .rubocop.yml file downloads the RuboCop rules from the OpenStudio-resources repo.
192
+ # This may cause an issue if the Gem directory does not have write access.
193
+ RuboCop::RakeTask.new(:rubocop_core) do |task|
194
+ task.options = ['--no-color', '--out=rubocop/rubocop-results.xml', '--format=simple']
195
+ task.formatters = ['RuboCop::Formatter::CheckstyleFormatter']
196
+ task.requires = ['rubocop/formatter/checkstyle_formatter']
197
+ # Run the rake at the original root directory
198
+ task.patterns = ["#{Rake.application.original_dir}/**/*.rb"]
199
+ # don't abort rake on failure
200
+ task.fail_on_error = false
201
+ end
202
+
203
+ desc 'Run OpenStudio Measure Unit Tests'
204
+ task test: ['openstudio:prepare_minitest', 'openstudio:test_core'] do
205
+ exit_status = post_process_results(Rake.application.original_dir)
206
+ exit exit_status
207
+ end
208
+
209
+ # Need to create a namespace so that we can have openstudio:rubocop and openstudio:rubocop:auto_correct.
210
+ namespace :rubocop do
211
+ task check: ['openstudio:prepare_rubocop', 'openstudio:rubocop_core'] do
212
+ exit_status = post_process_results(Rake.application.original_dir)
213
+ exit exit_status
214
+ end
215
+
216
+ desc 'Run RuboCop Auto Correct on Measures'
217
+ task auto_correct: 'openstudio:rubocop_core:auto_correct'
218
+ end
219
+
220
+ desc 'Run RuboCop on Measures'
221
+ task rubocop: 'openstudio:rubocop:check'
222
+
223
+ desc 'Run OpenStudio Style Checks'
224
+ task style: ['openstudio:prepare_style', 'openstudio:style_core'] do
225
+ exit_status = post_process_results(Rake.application.original_dir)
226
+ exit exit_status
227
+ end
228
+
229
+ desc 'Post process results into one directory'
230
+ task :post_process do
231
+ exit_status = post_process_results(Rake.application.original_dir)
232
+ exit exit_status
233
+ end
234
+
235
+ desc 'Generate dashboard'
236
+ task :dashboard do
237
+ dashboard(Rake.application.original_dir)
238
+ end
239
+
240
+ desc 'Run MiniTest, Coverage, RuboCop, and Style on measures, then dashboard results'
241
+ task all: ['openstudio:prepare_minitest',
242
+ 'openstudio:test_core',
243
+ 'openstudio:prepare_rubocop',
244
+ 'openstudio:rubocop_core',
245
+ 'openstudio:prepare_style',
246
+ 'openstudio:style_core'] do
247
+ exit_status = post_process_results(Rake.application.original_dir)
248
+ exit exit_status
249
+ end
250
+
251
+ # Hide the core tasks from being displayed when calling rake -T
252
+ Rake::Task['openstudio:rubocop_core'].clear_comments
253
+ Rake::Task['openstudio:test_core_command'].clear_comments
254
+ Rake::Task['openstudio:rubocop_core:auto_correct'].clear_comments
255
+ end
256
+ end
257
+ end
258
+ end
@@ -0,0 +1,213 @@
1
+ ########################################################################################################################
2
+ # OpenStudio(R), Copyright (c) 2008-2018, Alliance for Sustainable Energy, LLC. All rights reserved.
3
+ #
4
+ # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
5
+ # following conditions are met:
6
+ #
7
+ # (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
8
+ # disclaimer.
9
+ #
10
+ # (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
11
+ # following disclaimer in the documentation and/or other materials provided with the distribution.
12
+ #
13
+ # (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote
14
+ # products derived from this software without specific prior written permission from the respective party.
15
+ #
16
+ # (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative
17
+ # works may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without
18
+ # specific prior written permission from Alliance for Sustainable Energy, LLC.
19
+ #
20
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
21
+ # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER, THE UNITED STATES GOVERNMENT, OR ANY CONTRIBUTORS BE LIABLE FOR
23
+ # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24
+ # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25
+ # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
+ ########################################################################################################################
28
+
29
+ module OpenStudioMeasureTester
30
+ class RubocopResult
31
+ attr_reader :error_status
32
+
33
+ attr_reader :file_issues
34
+ attr_reader :file_info
35
+ attr_reader :file_warnings
36
+ attr_reader :file_errors
37
+
38
+ attr_reader :total_measures
39
+ attr_reader :total_files
40
+
41
+ attr_reader :total_issues
42
+ attr_reader :total_info
43
+ attr_reader :total_warnings
44
+ attr_reader :total_errors
45
+
46
+ attr_reader :summary
47
+ attr_reader :by_measure
48
+
49
+ def initialize(path_to_results)
50
+
51
+ @path_to_results = path_to_results
52
+ @error_status = false
53
+ @total_files = 0
54
+ @total_issues = 0
55
+ @total_errors = 0
56
+ @total_warnings = 0
57
+ @total_info = 0
58
+ @total_measures = 0
59
+
60
+ @summary = {}
61
+
62
+ @by_measure = {}
63
+
64
+ parse_results
65
+ to_file
66
+
67
+ end
68
+
69
+ def parse_results
70
+ # needs rescue
71
+ Dir["#{@path_to_results}/rubocop-results.xml"].each do |file|
72
+ puts "Parsing Rubocop report #{file}"
73
+ hash = Hash.from_xml(File.read(file))
74
+
75
+ # get measure names
76
+ measure_names = []
77
+ #cn= ''
78
+ hash['checkstyle']['file'].each do |key, data|
79
+ parts = key['name'].split('/')
80
+ if parts.last == 'measure.rb'
81
+ name = parts[-2]
82
+ measure_names << name
83
+ end
84
+ end
85
+
86
+ @total_measures = measure_names.length
87
+ @total_files = hash['checkstyle']['file'].length
88
+
89
+ measure_names.each do |measure_name|
90
+
91
+ #cn= ''
92
+ results = hash['checkstyle']['file'].select {|data| data['name'].include? measure_name }
93
+
94
+ mhash = {}
95
+ mhash['measure_issues'] = 0
96
+ mhash['measure_info'] = 0
97
+ mhash['measure_warnings'] = 0
98
+ mhash['measure_errors'] = 0
99
+ mhash['files'] = []
100
+
101
+ results.each do |key, data|
102
+ fhash = {}
103
+ fhash['file_name'] = key['name'].split('/')[-1]
104
+ fhash['violations'] = []
105
+
106
+ # get the class name
107
+ # if fhash['file_name'] == 'measure.rb'
108
+ # File.readlines(key['name']).each do |line|
109
+ # if (line.include? 'class') && line.split(' ')[0] == 'class'
110
+ # cn = line.split(' ')[1]
111
+ # break
112
+ # end
113
+ # end
114
+ # end
115
+
116
+ if key['error']
117
+ @file_issues = 0
118
+ @file_info = 0
119
+ @file_warnings = 0
120
+ @file_errors = 0
121
+
122
+ violations = []
123
+
124
+ if key['error'].class == Array
125
+ @file_issues = key['error'].length
126
+ key['error'].each do |s|
127
+
128
+ if s['severity'] === "info"
129
+ @file_info += 1
130
+ elsif s['severity'] === "warning"
131
+ @file_warnings += 1
132
+ elsif s['severity'] === "error" #TODO: look up complete list of codes
133
+ @file_errors += 1
134
+ end
135
+ violations << {line: s['line'], column: s['column'], severity: s['severity'], message: s['message']}
136
+ end
137
+ end
138
+
139
+ if key['error'].class == Hash
140
+ @file_issues = 1
141
+ if key['error']['severity'] === "info"
142
+ @file_info += 1
143
+ elsif key['error']['severity'] === "warning"
144
+ @file_warnings += 1
145
+ elsif key['error']['severity'] === "error"
146
+ @file_errors += 1
147
+ end
148
+ violations << {line: key['error']['line'], column: key['error']['column'], severity: key['error']['severity'], message: key['error']['message']}
149
+ end
150
+
151
+ fhash['issues'] = @file_issues
152
+ fhash['info'] = @file_info
153
+ fhash['warning'] = @file_warnings
154
+ fhash['error'] = @file_errors
155
+ fhash['violations'] = violations
156
+
157
+ mhash['measure_issues'] += @file_issues
158
+ mhash['measure_info'] += @file_info
159
+ mhash['measure_warnings'] += @file_warnings
160
+ mhash['measure_errors'] += @file_errors
161
+
162
+ @total_issues += @file_issues
163
+ @total_info += @file_info
164
+ @total_warnings += @file_warnings
165
+ @total_errors += @file_errors
166
+
167
+ end
168
+
169
+ mhash['files'] << fhash
170
+
171
+ end
172
+
173
+ #@summary << mhash
174
+ #@by_measure[cn] = mhash
175
+ @by_measure[measure_name] = mhash
176
+
177
+ end
178
+
179
+ end
180
+
181
+ puts "total files: #{total_files}"
182
+ puts "total issues: #{@total_issues} (#{@total_info} info, #{@total_warnings} warnings, #{@total_errors} errors)"
183
+
184
+ # TODO: still need to get errors ID'd
185
+ @error_status = true if @total_errors > 0
186
+
187
+ end
188
+
189
+ def to_hash
190
+ results = {};
191
+ results['total_measures'] = @total_measures
192
+ results['total_files'] = @total_files
193
+ results['total_issues'] = @total_issues
194
+ results['total_info'] = @total_info
195
+ results['total_warnings'] = @total_warnings
196
+ results['total_errors'] = @total_errors
197
+ results['by_measure'] = @by_measure
198
+
199
+ results
200
+ end
201
+
202
+ def to_file
203
+ # save as a json and have something else parse it/plot it.
204
+ res_hash = to_hash
205
+ @summary = res_hash
206
+ FileUtils.mkdir_p "#{@path_to_results}/" unless Dir.exist? "#{@path_to_results}/"
207
+ File.open("#{@path_to_results}/rubocop.json", 'w') do |file|
208
+ file << JSON.pretty_generate(res_hash)
209
+
210
+ end
211
+ end
212
+ end
213
+ end