openstudio_measure_tester 0.3.3 → 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7f5a572a08e1cf50dac9d00cbd082413321ee167bdf987176f0aa57ac8762ffc
4
- data.tar.gz: 2d5465eec4d31216ba26a4a4907998bd29fa9650f592b7369474c2c8e5077820
3
+ metadata.gz: 465198d56107ba3fea7daa6d6cedbcfe060fa60278bb1fc8b9a5ceeedc5ee7bc
4
+ data.tar.gz: 81208f4245ce75e3d2af1a39594c653945761a70e39770c177dd55ef9ef2e72a
5
5
  SHA512:
6
- metadata.gz: 4c7ade21a3fe0b0a77395cb0a4c647b000ef34037c50b67202dfb92662d6659e7c9980569b3ba76da67edba2a4f2a60523f8d933871ea4a0058d9485e1a8bc33
7
- data.tar.gz: d46a3c20cabc1415ca754c3e9b5bffaf09615ae215674fe4555412319de76e02d5a1b4f97ce2da0e1075f41bb4296d9b989c0837e0a73ef207befca1073ca2d5
6
+ metadata.gz: 6312f7014254ec2600047a481575a01e396cec8f37f8225e917434a041314c728ee50378258d10d1d66ddec32f2b70e89911d919de276fe6636c6861451b984f
7
+ data.tar.gz: 8940105a13d6ec4d4bf87223e556762931995818f3ad5e802c8be57bb92195edcecd62819b93c842a9f3272013883d6eaecc10d059466a28c65ea76916f7eedb
data/.gitignore CHANGED
@@ -21,8 +21,10 @@ Gemfile.lock
21
21
  /rubocop-results.xml
22
22
  !spec/files/rubocop-results.xml
23
23
  spec/files/rubocop/rubocop.json
24
+ spec/files/minitest/minitest.json
24
25
  spec/**/.rubocop.yml
25
26
 
27
+
26
28
  # mac and rbenv stuff
27
29
  .DS_Store
28
30
  .ruby-version
data/.rubocop.yml CHANGED
@@ -1,6 +1,451 @@
1
- AllCops:
2
- Exclude:
3
- - 'spec/test_measures/**/*'
4
- require: rubocop-performance
5
- inherit_from:
6
- - http://s3.amazonaws.com/openstudio-resources/styles/rubocop_v4.yml
1
+ Gemspec/OrderedDependencies:
2
+ Enabled: true
3
+
4
+
5
+ # This file was regenerated by Nicholas Long on 4/4/2025.
6
+ # The version that was on AWS S3 is going to be removed, but should
7
+ # probably wait until 6 months after this is released to ensure
8
+ # old versions are not still in use. (If you see this message after Jan 1, 2026,
9
+ # then remove this comment and delete the AWS rubocop configs.
10
+ # http://s3.amazonaws.com/openstudio-resources/styles/
11
+ Layout:
12
+ Severity: error
13
+ Lint:
14
+ Severity: error
15
+ Metrics:
16
+ Severity: error
17
+ Naming:
18
+ Severity: warning
19
+ Style:
20
+ Severity: error
21
+
22
+ # ==================== Layout ====================
23
+ Layout/BlockAlignment:
24
+ Enabled: true
25
+
26
+ # Need to allow indented case statements
27
+ # Configuration parameters: IndentWhenRelativeTo, SupportedStyles, IndentOneStep.
28
+ Layout/CaseIndentation:
29
+ Enabled: false
30
+
31
+ Layout/EmptyLineAfterGuardClause:
32
+ Enabled: true
33
+
34
+ Layout/EmptyLines:
35
+ Enabled: true
36
+
37
+ Layout/EmptyLinesAroundBlockBody:
38
+ Enabled: true
39
+
40
+ Layout/EmptyLinesAroundClassBody:
41
+ Enabled: true
42
+
43
+ Layout/EmptyLinesAroundExceptionHandlingKeywords:
44
+ Enabled: true
45
+
46
+ Layout/EmptyLinesAroundMethodBody:
47
+ Enabled: true
48
+
49
+ Layout/ExtraSpacing:
50
+ Enabled: true
51
+
52
+ Layout/FirstArrayElementIndentation:
53
+ Enabled: true
54
+
55
+ Layout/FirstHashElementIndentation:
56
+ Enabled: true
57
+
58
+ Layout/LeadingCommentSpace:
59
+ Enabled: true
60
+
61
+ # Allow long lines to encourage sufficiently
62
+ # detailed user-facing log messages.
63
+ Layout/LineLength:
64
+ Enabled: true
65
+ Max: 1200
66
+ Severity: warning
67
+
68
+ Layout/MultilineMethodCallIndentation:
69
+ EnforcedStyle: aligned
70
+ Enabled: true
71
+
72
+ Layout/SpaceAfterComma:
73
+ Enabled: true
74
+
75
+ Layout/SpaceAroundOperators:
76
+ Enabled: true
77
+
78
+ Layout/SpaceBeforeBlockBraces:
79
+ Enabled: true
80
+
81
+ Layout/SpaceInsideBlockBraces:
82
+ Enabled: true
83
+
84
+ Layout/TrailingEmptyLines:
85
+ Enabled: true
86
+
87
+ Layout/TrailingWhitespace:
88
+ Enabled: true
89
+
90
+ # ==================== Linters ====================
91
+ Lint/AmbiguousOperator:
92
+ Enabled: true
93
+
94
+ Lint/AmbiguousRegexpLiteral:
95
+ Enabled: true
96
+
97
+ Lint/DeprecatedClassMethods:
98
+ Enabled: true
99
+
100
+ # Allow empty when branches to give
101
+ # a space to clearly document the
102
+ # reason that nothing is happening.
103
+ Lint/EmptyWhen:
104
+ Enabled: false
105
+
106
+ Lint/MissingSuper:
107
+ Enabled: true
108
+
109
+ Lint/NestedMethodDefinition:
110
+ Enabled: true
111
+
112
+ Lint/ParenthesesAsGroupedExpression:
113
+ Enabled: true
114
+
115
+ Lint/RequireParentheses:
116
+ Enabled: true
117
+
118
+ Lint/RedundantRequireStatement:
119
+ Enabled: true
120
+
121
+ Lint/RedundantStringCoercion:
122
+ Enabled: true
123
+
124
+ Lint/SelfAssignment:
125
+ Enabled: true
126
+
127
+ Lint/ShadowingOuterLocalVariable:
128
+ Enabled: true
129
+
130
+ # NL 2020-05-03: Allow catching StandardError
131
+ # TC renamed from Lint/HandleExceptions to Lint/SuppressedException for v4 style
132
+ Lint/SuppressedException:
133
+ Enabled: false
134
+
135
+ Lint/UnreachableCode:
136
+ Enabled: false
137
+
138
+ # Disable checks for unused block arguments
139
+ Lint/UnusedBlockArgument:
140
+ Enabled: false
141
+
142
+ # Disable checks for ununsed method arguments
143
+ Lint/UnusedMethodArgument:
144
+ Enabled: false
145
+
146
+
147
+ # Allow variable initialization to indicate
148
+ # what variable is going to be set by the next
149
+ # block of code.
150
+ Lint/UselessAssignment:
151
+ Enabled: false
152
+
153
+ # ==================== Metrics ====================
154
+ # NL 2020-05-03: Drastically increase the length of assignment branch condition
155
+ Metrics/AbcSize:
156
+ Max: 250
157
+ Enabled: true
158
+ Severity: warning
159
+
160
+ # NL 2020-05-03: Quintuple the length of allowable blocks
161
+ Metrics/BlockLength:
162
+ Max: 250
163
+ Severity: warning
164
+ Enabled: true
165
+
166
+ Metrics/BlockNesting:
167
+ Max: 5
168
+ Enabled: true
169
+
170
+ Metrics/ClassLength:
171
+ Max: 500
172
+ CountComments: false
173
+ Severity: warning
174
+ Enabled: true
175
+
176
+ # NL 2020-05-03: Increase the allowable cyclomatic complexity
177
+ Metrics/CyclomaticComplexity:
178
+ Max: 100
179
+ Severity: warning
180
+ Enabled: true
181
+
182
+ Metrics/MethodLength:
183
+ Max: 350
184
+ CountComments: false
185
+ Severity: warning
186
+ Enabled: true
187
+
188
+ Metrics/ModuleLength:
189
+ Max: 500
190
+ CountComments: false
191
+ Severity: warning
192
+
193
+ # Longer parameter list limits for methods that
194
+ # add HVAC systems
195
+ Metrics/ParameterLists:
196
+ Max: 15
197
+ Severity: warning
198
+ Enabled: true
199
+
200
+ # NL 2020-05-03: increase tolerance
201
+ Metrics/PerceivedComplexity:
202
+ Max: 100
203
+ Severity: warning
204
+ Enabled: true
205
+
206
+ # ==================== Naming ====================
207
+ # Intentionally allow set_foo because these methods do not
208
+ # have corresponding getters.
209
+ Naming/AccessorMethodName:
210
+ Enabled: false
211
+
212
+ Naming/BlockParameterName:
213
+ Enabled: true
214
+
215
+ Naming/ClassAndModuleCamelCase:
216
+ Enabled: true
217
+
218
+ Naming/FileName:
219
+ Enabled: true
220
+
221
+ Naming/MethodName:
222
+ Enabled: true
223
+
224
+ Naming/MethodParameterName:
225
+ Enabled: true
226
+
227
+ Naming/VariableName:
228
+ Enabled: true
229
+
230
+ # Allow variables like coeff_1 for legibility
231
+ Naming/VariableNumber:
232
+ Enabled: true
233
+
234
+ # ==================== Performance ====================
235
+ # These are disabled because they are in a separate gem.
236
+ # Performance` cops have been extracted to the `rubocop-performance` gem.
237
+
238
+ # NL 2020-05-03: match -> match? or =~ -> match? breaks certain OpenStudio measures.
239
+ # Performance/RegexpMatch:
240
+ # Enabled: false
241
+
242
+ # NL 2020-05-03: Allow gsub (instead of the preferred tr)
243
+ # Performance/StringReplacement:
244
+ # Enabled: false
245
+
246
+ # ==================== Security ====================
247
+ Security/Eval:
248
+ Enabled: true
249
+
250
+ # ==================== Styles ====================
251
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
252
+
253
+ Style/AccessorGrouping:
254
+ Enabled: true
255
+
256
+ Style/AndOr:
257
+ Enabled: true
258
+
259
+ Style/CaseLikeIf:
260
+ Enabled: true
261
+
262
+ Style/ClassAndModuleChildren:
263
+ Enabled: false
264
+
265
+ Style/ClassVars:
266
+ Enabled: false
267
+
268
+ Style/ColonMethodCall:
269
+ Enabled: true
270
+
271
+ Style/CombinableLoops:
272
+ Enabled: true
273
+
274
+ Style/CommentAnnotation:
275
+ Enabled: true
276
+
277
+ Style/CommentedKeyword:
278
+ Enabled: true
279
+
280
+ # Allow this syntax -- do not autocorrect.
281
+ # a = if true
282
+ # 1
283
+ # else
284
+ # 2
285
+ # end
286
+ Style/ConditionalAssignment:
287
+ Enabled: false
288
+
289
+ # Documentation will be covered by YARD.
290
+ Style/Documentation:
291
+ Enabled: false
292
+
293
+ Style/EachWithObject:
294
+ Enabled: false
295
+
296
+ Style/EmptyElse:
297
+ Enabled: true
298
+
299
+
300
+ Style/FloatDivision:
301
+ Enabled: true
302
+
303
+ # Allow for i in 0..3 loops
304
+ Style/For:
305
+ Enabled: false
306
+
307
+ Style/FormatString:
308
+ Enabled: true
309
+
310
+ # NL 2020-05-08: Do not add the frozen_string_literal: true to the top of the files.
311
+ Style/FrozenStringLiteralComment:
312
+ Enabled: false
313
+
314
+ # Configuration parameters: AllowedVariables.
315
+ Style/GlobalVars:
316
+ Enabled: false
317
+
318
+ # Disabled because in most of this codebase, the current approach is more readable.
319
+ Style/GuardClause:
320
+ Enabled: false
321
+
322
+ # Allow duplication inside conditional branches to keep
323
+ # code that does certain tasks more consolidated.
324
+ Style/IdenticalConditionalBranches:
325
+ Enabled: false
326
+
327
+ Style/HashEachMethods:
328
+ Enabled: true
329
+
330
+ Style/HashSyntax:
331
+ Enabled: true
332
+
333
+ # Allow this type of nesting for logic clarity.
334
+ Style/IfInsideElse:
335
+ Enabled: false
336
+
337
+ # Do not force people to use one-line if statements.
338
+ Style/IfUnlessModifier:
339
+ Enabled: false
340
+
341
+ Style/InverseMethods:
342
+ Enabled: true
343
+
344
+ Style/MethodCallWithoutArgsParentheses:
345
+ Enabled: true
346
+
347
+ Style/MultilineIfThen:
348
+ Enabled: true
349
+
350
+ # Allow multiple comparisons via || for clarity
351
+ Style/MultipleComparison:
352
+ Enabled: false
353
+
354
+ # Allow negatives
355
+ # https://rubocop.readthedocs.io/en/latest/cops_style/#stylenegatedif
356
+ Style/NegatedIf:
357
+ Enabled: false
358
+
359
+ # Do not force people to use Next.
360
+ Style/Next:
361
+ Enabled: false
362
+
363
+ Style/Not:
364
+ Enabled: true
365
+
366
+ # Do not convert 10000 to 10_000
367
+ Style/NumericLiterals:
368
+ Enabled: false
369
+
370
+ # Do not force using .zero?
371
+ Style/NumericPredicate:
372
+ Enabled: false
373
+
374
+ Style/OptionalBooleanParameter:
375
+ Enabled: true
376
+
377
+ Style/PreferredHashMethods:
378
+ Enabled: true
379
+
380
+ Style/RedundantFileExtensionInRequire:
381
+ Enabled: true
382
+
383
+ Style/RedundantFreeze:
384
+ Enabled: true
385
+
386
+ Style/RedundantParentheses:
387
+ Enabled: true
388
+
389
+ Style/RedundantRegexpEscape:
390
+ Enabled: true
391
+
392
+ # encourage explicit returns for clarity
393
+ Style/RedundantReturn:
394
+ Enabled: false
395
+
396
+ Style/RegexpLiteral:
397
+ Enabled: true
398
+
399
+ # Do NOT use &. for Safe Navigation
400
+ Style/SafeNavigation:
401
+ Enabled: false
402
+
403
+ Style/SelfAssignment:
404
+ Enabled: true
405
+
406
+ Style/SignalException:
407
+ Enabled: true
408
+
409
+ Style/SlicingWithRange:
410
+ Enabled: true
411
+
412
+ Style/SoleNestedConditional:
413
+ Enabled: true
414
+
415
+ # Do NOT enable this because it appears $? is different than $CHILD_STATUS.
416
+ Style/SpecialGlobalVars:
417
+ Enabled: false
418
+
419
+ Style/StringConcatenation:
420
+ Enabled: true
421
+
422
+ Style/StringLiterals:
423
+ Enabled: true
424
+
425
+ Style/StringLiteralsInInterpolation:
426
+ Enabled: true
427
+
428
+ # Do not use %w, %W, %i, etc
429
+ # Prefer [:a, :b, :c] over %i[a b c]
430
+ Style/SymbolArray:
431
+ EnforcedStyle: brackets
432
+ Enabled: true
433
+
434
+ Style/SymbolProc:
435
+ Enabled: true
436
+
437
+ Style/TrailingCommaInArrayLiteral:
438
+ Enabled: true
439
+
440
+ Style/TrailingCommaInHashLiteral:
441
+ Enabled: true
442
+
443
+ # Do not use %w, %W, %i, etc
444
+ # Prefer ['a', 'b', 'c'] over %w[a b c]
445
+ Style/WordArray:
446
+ Enabled: true
447
+ EnforcedStyle: brackets
448
+
449
+ Style/ZeroLengthPredicate:
450
+ Enabled: true
451
+
data/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
1
+ # Version 0.4.1
2
+
3
+ * Switch rubocop and simplecov to development dependencies
4
+ * Update rubocop syntax
5
+ * Updates to support rubocop's new format
6
+
7
+ # Version 0.4.0
8
+
9
+ * Upgrade to Ruby 3.2.2
10
+ * Updating gem versions of rubocop and simplecov
11
+
1
12
  # Version 0.3.3
2
13
 
3
14
  * Update license
data/LICENSE.md CHANGED
@@ -1,4 +1,4 @@
1
- OpenStudio(R), Copyright (c) 2008, 2023 Alliance for Sustainable Energy, LLC.
1
+ OpenStudio(R), Copyright (c) 2008, 2024 Alliance for Sustainable Energy, LLC.
2
2
 
3
3
  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
4
4
 
data/cspell.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "version": "0.2",
3
+ "ignorePaths": [],
4
+ "dictionaryDefinitions": [],
5
+ "dictionaries": [],
6
+ "words": [
7
+ "Adak",
8
+ "ASHRAE",
9
+ "autocalculate",
10
+ "autorun",
11
+ "Condns",
12
+ "curdir",
13
+ "Drybulb",
14
+ "energyplus",
15
+ "Floorto",
16
+ "Goldwasser",
17
+ "HVAC",
18
+ "openstudio",
19
+ "Placemark",
20
+ "popen",
21
+ "roundto",
22
+ "snakecase",
23
+ "Timestep",
24
+ "weatherlocation",
25
+ "wmoundefined"
26
+ ],
27
+ "ignoreWords": [],
28
+ "import": []
29
+ }
@@ -7,13 +7,7 @@
7
7
 
8
8
  module OpenStudioMeasureTester
9
9
  class Coverage
10
- attr_reader :total_percent_coverage
11
- attr_reader :total_lines
12
- attr_reader :total_relevant_lines
13
- attr_reader :covered_lines
14
- attr_reader :missed_lines
15
- attr_reader :avg_hits_per_line
16
- attr_reader :measure_coverages
10
+ attr_reader :total_percent_coverage, :total_lines, :total_relevant_lines, :covered_lines, :missed_lines, :avg_hits_per_line, :measure_coverages
17
11
 
18
12
  def initialize(path_to_results)
19
13
  @path_to_results = path_to_results
@@ -31,9 +25,9 @@ module OpenStudioMeasureTester
31
25
  unless File.exist? measure_file
32
26
  # magically try to find the path name by dropping the first element of array. This is
33
27
  # mainly needed for the testing framework as we are committing the .resultset.json which may
34
- # have been generated by any user, esp since the file names are fully qualified in the .resultsset.json,
28
+ # have been generated by any user, esp since the file names are fully qualified in the .resultset.json,
35
29
  puts "Trying to determine the file path of unknown measure #{measure_file}"
36
- measure_file = measure_file.split('/')[1..-1].join('/') until File.exist?(measure_file) || measure_file.split('/').empty?
30
+ measure_file = measure_file.split('/')[1..].join('/') until File.exist?(measure_file) || measure_file.split('/').empty?
37
31
  end
38
32
 
39
33
  # file should exist now. Read from the class name
@@ -74,12 +68,12 @@ module OpenStudioMeasureTester
74
68
  # the classname, then to go through and grab all the other files that exist for the same measure class name.
75
69
  # Two passes because the order of the files in .resultset.json is not guaranteed to have measure.rb first.
76
70
  measure_maps = {}
77
- coverage_results['coverage'].keys.each do |key|
71
+ coverage_results['coverage'].each_key do |key|
78
72
  parts = key.split('/')
79
73
  if parts.last == 'measure.rb'
80
74
  class_name = parse_class_name(key)
81
75
  measure_maps[class_name] = {
82
- class_name: class_name,
76
+ class_name:,
83
77
  root_path: File.dirname(key),
84
78
  files: [key]
85
79
  }
@@ -87,7 +81,7 @@ module OpenStudioMeasureTester
87
81
  end
88
82
 
89
83
  # second pass, add other files.
90
- coverage_results['coverage'].keys.each do |key|
84
+ coverage_results['coverage'].each_key do |key|
91
85
  next if key.split('/').last == 'measure.rb'
92
86
 
93
87
  measure_maps.each do |m_key, m_value|
@@ -120,7 +114,7 @@ module OpenStudioMeasureTester
120
114
  cov_results_by_line.delete(nil)
121
115
 
122
116
  cov = cov_results_by_line.count { |x| x > 0 }
123
- fhash['percent_coverage'] = ((cov.to_f / cov_results_by_line.size.to_f) * 100).round(2)
117
+ fhash['percent_coverage'] = ((cov.to_f / cov_results_by_line.size) * 100).round(2)
124
118
  fhash['missed_lines'] = cov_results_by_line.size - cov
125
119
  fhash['relevant_lines'] = cov_results_by_line.size
126
120
  fhash['covered_lines'] = cov
@@ -132,7 +126,7 @@ module OpenStudioMeasureTester
132
126
  mhash['files'] << fhash
133
127
  end
134
128
 
135
- mhash['percent_coverage'] = (mhash['covered_lines'].to_f / mhash['relevant_lines'].to_f * 100).round(2)
129
+ mhash['percent_coverage'] = (mhash['covered_lines'].to_f / mhash['relevant_lines'] * 100).round(2)
136
130
  @measure_coverages[class_name] = mhash
137
131
  @total_lines += mhash['total_lines']
138
132
  @total_relevant_lines += mhash['relevant_lines']
@@ -144,7 +138,7 @@ module OpenStudioMeasureTester
144
138
  lines = @total_relevant_lines # unnecessary but breaks formatting otherwise
145
139
  # lines can be zero if coverage doesn't run correctly
146
140
  if lines != 0
147
- @total_percent_coverage = (@total_covered_lines.to_f / lines.to_f * 100).round(2)
141
+ @total_percent_coverage = (@total_covered_lines.to_f / lines * 100).round(2)
148
142
  end
149
143
  pp "Total Coverage: #{@total_percent_coverage}"
150
144
 
@@ -22,7 +22,7 @@ module OpenStudioMeasureTester
22
22
  end
23
23
 
24
24
  def render
25
- rendered = ERB.new(@template, 0, nil, '@html').result(binding)
25
+ rendered = ERB.new(@template, trim_mode: nil, eoutvar: '@html').result(binding)
26
26
  save_dir = "#{@test_results_directory}/dashboard"
27
27
 
28
28
  # Render the dashboard
@@ -0,0 +1,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ # *******************************************************************************
4
+ # OpenStudio(R), Copyright (c) Alliance for Sustainable Energy, LLC.
5
+ # See also https://openstudio.net/license
6
+ # *******************************************************************************
7
+
8
+ module OpenStudioMeasureTester
9
+ class GithubActionsReport
10
+ attr_reader :minitest_summary_table, :all_annotations
11
+
12
+ # @param test_results_directory [String]: The directory
13
+ def initialize(test_results_directory)
14
+ @test_results_directory = test_results_directory
15
+ file = File.read("#{@test_results_directory}/combined_results.json")
16
+ @hash = JSON.parse(file)
17
+ @minitest_summary_table = nil
18
+ @all_annotations = []
19
+ end
20
+
21
+ def write_step_summary(msg)
22
+ puts msg
23
+ if !ENV['GITHUB_STEP_SUMMARY'].nil?
24
+ File.write(ENV['GITHUB_STEP_SUMMARY'], "#{msg}\n", mode: 'a+')
25
+ end
26
+ end
27
+
28
+ def hash_to_markdown(h, header0, header1)
29
+ n0 = [h.keys.map(&:to_s).map(&:size).max, header0.size].max
30
+ n1 = [h.values.map(&:to_s).map(&:size).max, header1.size].max
31
+
32
+ content = [
33
+ "| #{header0.ljust(n0)} | #{header1.ljust(n1)} |",
34
+ "| #{'-' * n0} | #{'-' * n1} |"
35
+ ] + h.map { |k, v| "| #{k.ljust(n0)} | #{v.to_s.ljust(n1)} |" }
36
+ return content.join("\n")
37
+ end
38
+
39
+ def make_minitest_step_summary_table
40
+ write_step_summary('## Minitest')
41
+ write_step_summary('')
42
+
43
+ total_tests = @hash['minitest']['total_tests']
44
+ total_assertions = @hash['minitest']['total_assertions']
45
+ total_errors = @hash['minitest']['total_errors']
46
+ total_failures = @hash['minitest']['total_failures']
47
+ total_skipped = @hash['minitest']['total_skipped']
48
+ total_compatibility_errors = @hash['minitest']['total_compatibility_errors']
49
+ total_load_errors = @hash['minitest'].fetch('total_load_errors', []).count
50
+
51
+ passed = total_tests - (total_failures + total_errors + total_skipped)
52
+ pct = passed.to_f / (total_tests - total_skipped)
53
+
54
+ h = {
55
+ 'Total Tests' => total_tests,
56
+ 'Load Error' => total_load_errors,
57
+ 'Passed' => passed,
58
+ 'Success Rate' => format('%.2f%%', (pct * 100.0)),
59
+ 'Failures' => total_failures,
60
+ 'Errors' => total_errors,
61
+ 'Skipped' => total_skipped,
62
+ 'Incompatible' => total_compatibility_errors,
63
+ 'Total Assertions' => total_assertions
64
+ }
65
+
66
+ @minitest_summary_table = hash_to_markdown(h, 'Metric', 'Value')
67
+
68
+ write_step_summary(@minitest_summary_table)
69
+ write_step_summary('')
70
+ end
71
+
72
+ def make_minitest_annotations
73
+ @all_annotations = []
74
+
75
+ report_xmls = Dir["#{@test_results_directory}/minitest/reports/TEST-*.xml"]
76
+ report_xmls.each do |report_xml|
77
+ doc = REXML::Document.new(File.open(report_xml)).root
78
+ testsuite_element = doc.elements['testsuite']
79
+ filepath = testsuite_element.attributes['filepath']
80
+ testsuite_element.elements.each('testcase') do |testcase|
81
+ test_name = testcase.attributes['name']
82
+ line = testcase.attributes['lineno'].to_i
83
+ tested_class = testcase.attributes['classname']
84
+
85
+ testcase.elements.each('failure') do |x|
86
+ title = x.attributes['type']
87
+ message = x.attributes['message']
88
+ annot = "::error file=#{filepath},line=#{line},endLine=#{line + 1},title=#{title}::#{tested_class}.#{test_name}: #{message}"
89
+ @all_annotations << annot
90
+ end
91
+ testcase.elements.each('error') do |x|
92
+ title = x.attributes['type']
93
+ message = x.attributes['message']
94
+ annot = "::error file=#{filepath},line=#{line},endLine=#{line + 1},title=#{title}::#{message}"
95
+ @all_annotations << annot
96
+ end
97
+ testcase.elements.each('skipped') do |x|
98
+ title = x.attributes['type']
99
+ message = x.attributes['message']
100
+ annot = "::warning file=#{filepath},line=#{line},endLine=#{line + 1},title=#{title}::#{message}"
101
+ @all_annotations << annot
102
+ end
103
+ end
104
+ end
105
+ @all_annotations.each { |a| puts a }
106
+ nil
107
+ end
108
+ end
109
+ end
@@ -7,16 +7,7 @@
7
7
 
8
8
  module OpenStudioMeasureTester
9
9
  class MinitestResult
10
- attr_reader :error_status
11
-
12
- attr_reader :total_assertions
13
- attr_reader :total_errors
14
- attr_reader :total_failures
15
- attr_reader :total_skipped
16
- attr_reader :total_tests
17
- attr_reader :total_compatibility_errors
18
- attr_reader :measure_results
19
- attr_reader :summary
10
+ attr_reader :error_status, :total_assertions, :total_errors, :total_failures, :total_skipped, :total_tests, :total_compatibility_errors, :measure_results, :summary
20
11
 
21
12
  def initialize(path_to_results)
22
13
  @path_to_results = path_to_results
@@ -79,7 +70,7 @@ module OpenStudioMeasureTester
79
70
  doc = REXML::Document.new(File.open(report_xmls[0])).root
80
71
 
81
72
  if doc
82
- # Note: only 1 failure and 1 error possible per test
73
+ # NOTE: only 1 failure and 1 error possible per test
83
74
  testsuite_element = doc.elements['testsuite']
84
75
  errors, failures, skipped = parse_measure(testsuite_element)
85
76
 
@@ -127,8 +118,6 @@ module OpenStudioMeasureTester
127
118
  @summary[:total_load_errors] = @total_load_errors
128
119
  @summary[:by_measure] = @measure_results
129
120
 
130
- # pp @summary
131
-
132
121
  FileUtils.mkdir "#{@path_to_results}/" unless Dir.exist? "#{@path_to_results}/"
133
122
  File.open("#{@path_to_results}/minitest.json", 'w') do |file|
134
123
  file << JSON.pretty_generate(summary)
@@ -148,7 +137,7 @@ module OpenStudioMeasureTester
148
137
  elsif testcase.elements['failure']
149
138
  failures << testcase.elements['failure']
150
139
  elsif testcase.elements['skipped']
151
- skipped << 'Skipped test: ' + testcase.elements['skipped'].attributes['type']
140
+ skipped << "Skipped test: #{testcase.elements['skipped'].attributes['type']}"
152
141
  end
153
142
  end
154
143
 
@@ -7,8 +7,7 @@
7
7
 
8
8
  module OpenStudioMeasureTester
9
9
  class OpenStudioStyle
10
- attr_reader :results
11
- attr_reader :measure_messages
10
+ attr_reader :results, :measure_messages
12
11
 
13
12
  CHECKS = [
14
13
  {
@@ -180,9 +179,9 @@ module OpenStudioMeasureTester
180
179
 
181
180
  def log_message(message, type = :syntax, severity = :info)
182
181
  new_message = {
183
- message: message,
184
- type: type,
185
- severity: severity
182
+ message:,
183
+ type:,
184
+ severity:
186
185
  }
187
186
  @measure_messages << new_message
188
187
  end
@@ -88,7 +88,7 @@ module OpenStudioMeasureTester
88
88
  # minitest
89
89
  if Dir.exist?("#{@orig_results_dir}/test/html_reports") || Dir.exist?("#{@orig_results_dir}/test/reports")
90
90
  puts 'Found Minitest Results, parsing'
91
- # Do not delete the compatibilty directory which is generated when the test is run
91
+ # Do not delete the compatibility directory which is generated when the test is run
92
92
  FileUtils.rm_rf "#{@test_results_dir}/minitest/html_reports" if Dir.exist? "#{@test_results_dir}/minitest/html_reports"
93
93
  FileUtils.rm_rf "#{@test_results_dir}/minitest/reports" if Dir.exist? "#{@test_results_dir}/minitest/reports"
94
94
 
@@ -135,8 +135,8 @@ module OpenStudioMeasureTester
135
135
  # there must be no unit test failures
136
136
  # pp @results
137
137
  final_exit_code = 0
138
- if @results['rubocop']
139
- # more than 10 errors per file on average
138
+ # more than 10 errors per file on average
139
+ if @results['rubocop'] && (@results['rubocop']['total_errors'].nonzero? && @results['rubocop']['total_files'].nonzero?)
140
140
  status = @results['rubocop']['total_errors'] / @results['rubocop']['total_files']
141
141
  if status > 10
142
142
  puts "More than 10 RuboCop errors per file found. Found #{status}"
@@ -159,11 +159,9 @@ module OpenStudioMeasureTester
159
159
  end
160
160
  end
161
161
 
162
- if @results['minitest']
163
- if @results['minitest'][:total_errors] > 0 || @results['minitest'][:total_failures] > 0
164
- puts 'Unit Test (Minitest) errors/failures found.'
165
- final_exit_code = 1
166
- end
162
+ if @results['minitest'] && (@results['minitest'][:total_errors] > 0 || @results['minitest'][:total_failures] > 0)
163
+ puts 'Unit Test (Minitest) errors/failures found.'
164
+ final_exit_code = 1
167
165
  end
168
166
 
169
167
  # if @results['coverage']
@@ -27,11 +27,11 @@ module OpenStudioMeasureTester
27
27
  def setup_subtasks(name)
28
28
  namespace name do
29
29
  ####################################### Minitest and Coverage #######################################
30
- desc 'new test task'
30
+ desc 'Run Minitest and Coverage on Measures'
31
31
  task :test do
32
32
  runner = OpenStudioMeasureTester::Runner.new(Rake.application.original_dir)
33
33
  # Need to pass in the current directory because the results of minitest and coverage end up going into
34
- # the root directorys
34
+ # the root directories
35
35
  exit runner.run_test(false, Dir.pwd, false)
36
36
  end
37
37
 
@@ -7,23 +7,7 @@
7
7
 
8
8
  module OpenStudioMeasureTester
9
9
  class RubocopResult
10
- attr_reader :error_status
11
-
12
- attr_reader :file_issues
13
- attr_reader :file_info
14
- attr_reader :file_warnings
15
- attr_reader :file_errors
16
-
17
- attr_reader :total_measures
18
- attr_reader :total_files
19
-
20
- attr_reader :total_issues
21
- attr_reader :total_info
22
- attr_reader :total_warnings
23
- attr_reader :total_errors
24
-
25
- attr_reader :summary
26
- attr_reader :by_measure
10
+ attr_reader :error_status, :file_issues, :file_info, :file_warnings, :file_errors, :total_measures, :total_files, :total_issues, :total_info, :total_warnings, :total_errors, :summary, :by_measure
27
11
 
28
12
  def initialize(path_to_results)
29
13
  @path_to_results = path_to_results
@@ -90,7 +74,8 @@ module OpenStudioMeasureTester
90
74
  doc.elements.each('//checkstyle/file') do |rc_file|
91
75
  # Allow processing when the file is just the measure.rb
92
76
  if rc_file.attributes['name'] != 'measure.rb'
93
- if !rc_file.attributes['name'].include? measure_name
77
+ parts = rc_file.attributes['name'].split(File::SEPARATOR)
78
+ if !parts.include? measure_name
94
79
  next
95
80
  end
96
81
  end
@@ -109,7 +94,7 @@ module OpenStudioMeasureTester
109
94
  if File.exist? rc_file.attributes['name']
110
95
  File.readlines(rc_file.attributes['name']).each do |line|
111
96
  if (line.include? 'class') && line.split(' ')[0] == 'class'
112
- cn = line.split(' ')[1].gsub /_?[tT]est\z/, ''
97
+ cn = line.split(' ')[1].gsub(/_?[tT]est\z/, '')
113
98
  break
114
99
  end
115
100
  end
@@ -126,11 +111,12 @@ module OpenStudioMeasureTester
126
111
  violations = []
127
112
  rc_file.elements.each('error') do |rc_error|
128
113
  @file_issues += 1
129
- if rc_error.attributes['severity'] == 'info'
114
+ case rc_error.attributes['severity']
115
+ when 'info'
130
116
  @file_info += 1
131
- elsif rc_error.attributes['severity'] == 'warning'
117
+ when 'warning'
132
118
  @file_warnings += 1
133
- elsif rc_error.attributes['severity'] == 'error'
119
+ when 'error'
134
120
  @file_errors += 1
135
121
  end
136
122
  violations << {
@@ -32,6 +32,12 @@ module OpenStudioMeasureTester
32
32
  template.render
33
33
  end
34
34
 
35
+ def github_actions_report
36
+ gha_reporter = OpenStudioMeasureTester::GithubActionsReport.new(test_results_dir)
37
+ gha_reporter.make_minitest_step_summary_table
38
+ gha_reporter.make_minitest_annotations
39
+ end
40
+
35
41
  # Prepare the current directory and the root directory to remove old test results before running
36
42
  # the new tests
37
43
  #
@@ -67,8 +73,10 @@ module OpenStudioMeasureTester
67
73
  # copy over the .rubocop.yml file into the root directory of where this is running.
68
74
  shared_rubocop_file = File.expand_path('../../.rubocop.yml', File.dirname(__FILE__))
69
75
  dest_file = "#{File.expand_path(@base_dir)}/.rubocop.yml"
70
- if shared_rubocop_file != dest_file
76
+ if !File.exist?(dest_file)
71
77
  FileUtils.copy(shared_rubocop_file, dest_file)
78
+ elsif File.read(shared_rubocop_file) != File.read(dest_file)
79
+ puts "Using specific custom .rubocop.yml rather than the OpenStudio-measure-tester-gem's one"
72
80
  end
73
81
 
74
82
  puts "Current directory is #{@base_dir}"
@@ -84,7 +92,7 @@ module OpenStudioMeasureTester
84
92
 
85
93
  # Post process the various results and save them into the base_dir
86
94
  #
87
- # @param original_results_directory [string] Location of the results from coverag and minitest
95
+ # @param original_results_directory [string] Location of the results from coverage and minitest
88
96
  def post_process_results(original_results_directory = nil)
89
97
  puts ' ========================= Starting Results Post Process ================================'
90
98
  puts "Current directory: #{@base_dir}"
@@ -96,6 +104,8 @@ module OpenStudioMeasureTester
96
104
  # call the create dashboard command now that we have results
97
105
  dashboard
98
106
 
107
+ github_actions_report if ENV['GITHUB_ACTIONS']
108
+
99
109
  # return the results exit code
100
110
  return results.exit_code
101
111
  end
@@ -144,8 +154,11 @@ module OpenStudioMeasureTester
144
154
  # out and output_path do not actually save the results, has to be appended after the formatter.
145
155
  # out: 'junk.xml',
146
156
  # output_path: 'junk.xml',
147
- auto_correct: auto_correct,
157
+ auto_correct:,
148
158
  color: false,
159
+ # cf #76 - Because we pass a glob to the Runner.run, we must pass
160
+ # force_exclusion to respect the files excluded in the .rubocop.yml
161
+ force_exclusion: true,
149
162
  formatters: ['simple', ['RuboCop::Formatter::CheckstyleFormatter', rubocop_results_file]]
150
163
  }
151
164
 
@@ -6,5 +6,5 @@
6
6
  # *******************************************************************************
7
7
 
8
8
  module OpenStudioMeasureTester
9
- VERSION = '0.3.3'.freeze
9
+ VERSION = '0.4.1'
10
10
  end
@@ -7,10 +7,10 @@
7
7
 
8
8
  require 'openstudio'
9
9
 
10
- require 'pp'
11
10
  require 'rexml/document'
12
11
  require 'minitest'
13
12
  require 'simplecov'
13
+ require 'json'
14
14
 
15
15
  begin
16
16
  require 'git'
@@ -36,6 +36,7 @@ require_relative 'openstudio_measure_tester/coverage'
36
36
  require_relative 'openstudio_measure_tester/rubocop_result'
37
37
  require_relative 'openstudio_measure_tester/openstudio_testing_result'
38
38
  require_relative 'openstudio_measure_tester/dashboard'
39
+ require_relative 'openstudio_measure_tester/github_actions_report'
39
40
  require_relative 'openstudio_measure_tester/runner'
40
41
 
41
42
  require_relative 'openstudio_measure_tester/rake_task'
@@ -27,18 +27,18 @@ Gem::Specification.new do |spec|
27
27
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
28
  spec.require_paths = ['lib']
29
29
 
30
- spec.required_ruby_version = '~> 2.7.0'
30
+ spec.required_ruby_version = '~> 3.2.2'
31
31
 
32
32
  spec.add_dependency 'git', '~> 1.12.0'
33
33
  spec.add_dependency 'minitest', '~> 5.14.0'
34
34
  spec.add_dependency 'minitest-reporters', '~> 1.4.2'
35
- spec.add_dependency 'rake', '~> 13.0'
36
35
  spec.add_dependency 'parser', '3.2.2.2'
37
- spec.add_dependency 'rubocop', '~> 1.15.0'
38
- spec.add_dependency 'rubocop-performance', '~> 1.11.3'
39
- spec.add_dependency 'rubocop-checkstyle_formatter', '~> 0.4.0'
40
- spec.add_dependency 'simplecov', '~> 0.18.2'
36
+ spec.add_dependency 'rake', '~> 13.0'
41
37
 
42
- spec.add_development_dependency 'bundler', '>= 2.1.0'
38
+ spec.add_development_dependency 'rubocop', '1.50'
39
+ spec.add_development_dependency 'rubocop-checkstyle_formatter', '0.6.0'
40
+ spec.add_development_dependency 'rubocop-performance', '1.20.0'
41
+ spec.add_development_dependency 'simplecov', '0.22.0'
42
+ spec.add_development_dependency 'bundler', '2.4.10'
43
43
  spec.add_development_dependency 'rspec', '~> 3.9'
44
44
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openstudio_measure_tester
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.3
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nicholas Long
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: exe
13
13
  cert_chain: []
14
- date: 2024-02-19 00:00:00.000000000 Z
14
+ date: 2025-04-09 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: git
@@ -56,103 +56,103 @@ dependencies:
56
56
  - !ruby/object:Gem::Version
57
57
  version: 1.4.2
58
58
  - !ruby/object:Gem::Dependency
59
- name: rake
59
+ name: parser
60
60
  requirement: !ruby/object:Gem::Requirement
61
61
  requirements:
62
- - - "~>"
62
+ - - '='
63
63
  - !ruby/object:Gem::Version
64
- version: '13.0'
64
+ version: 3.2.2.2
65
65
  type: :runtime
66
66
  prerelease: false
67
67
  version_requirements: !ruby/object:Gem::Requirement
68
68
  requirements:
69
- - - "~>"
69
+ - - '='
70
70
  - !ruby/object:Gem::Version
71
- version: '13.0'
71
+ version: 3.2.2.2
72
72
  - !ruby/object:Gem::Dependency
73
- name: parser
73
+ name: rake
74
74
  requirement: !ruby/object:Gem::Requirement
75
75
  requirements:
76
- - - '='
76
+ - - "~>"
77
77
  - !ruby/object:Gem::Version
78
- version: 3.2.2.2
78
+ version: '13.0'
79
79
  type: :runtime
80
80
  prerelease: false
81
81
  version_requirements: !ruby/object:Gem::Requirement
82
82
  requirements:
83
- - - '='
83
+ - - "~>"
84
84
  - !ruby/object:Gem::Version
85
- version: 3.2.2.2
85
+ version: '13.0'
86
86
  - !ruby/object:Gem::Dependency
87
87
  name: rubocop
88
88
  requirement: !ruby/object:Gem::Requirement
89
89
  requirements:
90
- - - "~>"
90
+ - - '='
91
91
  - !ruby/object:Gem::Version
92
- version: 1.15.0
93
- type: :runtime
92
+ version: '1.50'
93
+ type: :development
94
94
  prerelease: false
95
95
  version_requirements: !ruby/object:Gem::Requirement
96
96
  requirements:
97
- - - "~>"
97
+ - - '='
98
98
  - !ruby/object:Gem::Version
99
- version: 1.15.0
99
+ version: '1.50'
100
100
  - !ruby/object:Gem::Dependency
101
- name: rubocop-performance
101
+ name: rubocop-checkstyle_formatter
102
102
  requirement: !ruby/object:Gem::Requirement
103
103
  requirements:
104
- - - "~>"
104
+ - - '='
105
105
  - !ruby/object:Gem::Version
106
- version: 1.11.3
107
- type: :runtime
106
+ version: 0.6.0
107
+ type: :development
108
108
  prerelease: false
109
109
  version_requirements: !ruby/object:Gem::Requirement
110
110
  requirements:
111
- - - "~>"
111
+ - - '='
112
112
  - !ruby/object:Gem::Version
113
- version: 1.11.3
113
+ version: 0.6.0
114
114
  - !ruby/object:Gem::Dependency
115
- name: rubocop-checkstyle_formatter
115
+ name: rubocop-performance
116
116
  requirement: !ruby/object:Gem::Requirement
117
117
  requirements:
118
- - - "~>"
118
+ - - '='
119
119
  - !ruby/object:Gem::Version
120
- version: 0.4.0
121
- type: :runtime
120
+ version: 1.20.0
121
+ type: :development
122
122
  prerelease: false
123
123
  version_requirements: !ruby/object:Gem::Requirement
124
124
  requirements:
125
- - - "~>"
125
+ - - '='
126
126
  - !ruby/object:Gem::Version
127
- version: 0.4.0
127
+ version: 1.20.0
128
128
  - !ruby/object:Gem::Dependency
129
129
  name: simplecov
130
130
  requirement: !ruby/object:Gem::Requirement
131
131
  requirements:
132
- - - "~>"
132
+ - - '='
133
133
  - !ruby/object:Gem::Version
134
- version: 0.18.2
135
- type: :runtime
134
+ version: 0.22.0
135
+ type: :development
136
136
  prerelease: false
137
137
  version_requirements: !ruby/object:Gem::Requirement
138
138
  requirements:
139
- - - "~>"
139
+ - - '='
140
140
  - !ruby/object:Gem::Version
141
- version: 0.18.2
141
+ version: 0.22.0
142
142
  - !ruby/object:Gem::Dependency
143
143
  name: bundler
144
144
  requirement: !ruby/object:Gem::Requirement
145
145
  requirements:
146
- - - ">="
146
+ - - '='
147
147
  - !ruby/object:Gem::Version
148
- version: 2.1.0
148
+ version: 2.4.10
149
149
  type: :development
150
150
  prerelease: false
151
151
  version_requirements: !ruby/object:Gem::Requirement
152
152
  requirements:
153
- - - ">="
153
+ - - '='
154
154
  - !ruby/object:Gem::Version
155
- version: 2.1.0
155
+ version: 2.4.10
156
156
  - !ruby/object:Gem::Dependency
157
157
  name: rspec
158
158
  requirement: !ruby/object:Gem::Requirement
@@ -186,6 +186,7 @@ files:
186
186
  - bin/console
187
187
  - bin/run_measure_tests
188
188
  - bin/setup
189
+ - cspell.json
189
190
  - dashboard/css/bootstrap-grid.css
190
191
  - dashboard/css/bootstrap-grid.min.css
191
192
  - dashboard/css/bootstrap-reboot.css
@@ -200,6 +201,7 @@ files:
200
201
  - lib/openstudio_measure_tester/core_ext.rb
201
202
  - lib/openstudio_measure_tester/coverage.rb
202
203
  - lib/openstudio_measure_tester/dashboard.rb
204
+ - lib/openstudio_measure_tester/github_actions_report.rb
203
205
  - lib/openstudio_measure_tester/minitest_result.rb
204
206
  - lib/openstudio_measure_tester/openstudio_style.rb
205
207
  - lib/openstudio_measure_tester/openstudio_testing_result.rb
@@ -214,7 +216,7 @@ licenses: []
214
216
  metadata:
215
217
  bug_tracker_uri: https://github.com/NREL/OpenStudio-measure-tester-gem/issues
216
218
  changelog_uri: https://github.com/NREL/OpenStudio-measure-tester-gem/blob/develop/CHANGELOG.md
217
- source_code_uri: https://github.com/NREL/OpenStudio-measure-tester-gem/tree/v0.3.3
219
+ source_code_uri: https://github.com/NREL/OpenStudio-measure-tester-gem/tree/v0.4.1
218
220
  post_install_message:
219
221
  rdoc_options: []
220
222
  require_paths:
@@ -223,14 +225,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
223
225
  requirements:
224
226
  - - "~>"
225
227
  - !ruby/object:Gem::Version
226
- version: 2.7.0
228
+ version: 3.2.2
227
229
  required_rubygems_version: !ruby/object:Gem::Requirement
228
230
  requirements:
229
231
  - - ">="
230
232
  - !ruby/object:Gem::Version
231
233
  version: '0'
232
234
  requirements: []
233
- rubygems_version: 3.1.4
235
+ rubygems_version: 3.4.10
234
236
  signing_key:
235
237
  specification_version: 4
236
238
  summary: Testing framework for OpenStudio measures