openstudio_measure_tester 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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