1# Copyright (c) 2021-2022 Huawei Device Co., Ltd. 2# Licensed under the Apache License, Version 2.0 (the "License"); 3# you may not use this file except in compliance with the License. 4# You may obtain a copy of the License at 5# 6# http://www.apache.org/licenses/LICENSE-2.0 7# 8# Unless required by applicable law or agreed to in writing, software 9# distributed under the License is distributed on an "AS IS" BASIS, 10# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11# See the License for the specific language governing permissions and 12# limitations under the License. 13 14# frozen_string_literal: true 15 16# 17# Huawei Technologies Co.,Ltd. 18class Summary 19 def initialize(spec) 20 @spec = spec 21 22 # Tests 23 @total = 0 24 @accepted = [] 25 @orphaned = [] 26 27 # Assertions 28 @testable = 0 29 @non_testable = 0 30 @covered = 0 31 @not_covered = 0 32 33 # Coverage 34 @coverage_by_groups = [] 35 @coverage_metric = 0 36 37 @uncovered_assertions = [] 38 end 39 40 def report 41 { 42 'tests' => { 43 'total' => @total, 44 'counted_for_coverage' => @accepted.length, 45 'orphaned' => @orphaned.length 46 }, 47 'assertions' => { 48 'testable' => @testable, 49 'non_testable' => @non_testable, 50 'covered' => @covered, 51 'not_covered' => @not_covered 52 }, 53 'coverage_by_groups' => @coverage_by_groups, 54 'coverage_metric' => @testable.zero? ? 0 : (@covered.to_f / @testable).round(2) 55 } 56 end 57 58 def uncovered 59 { 'groups' => @uncovered_assertions } 60 end 61 62 def compute 63 @spec.data['groups'].each do |g| 64 compute_for_group(g) 65 end 66 67 @accepted = @accepted.uniq 68 @orphaned = @spec.orphaned.map { |f| f['file'] }.uniq 69 @total = (@accepted + @orphaned).uniq.length 70 end 71 72 private 73 74 def compute_for_group(group) 75 testable_count = 0 76 non_testable_count = 0 77 covered_count = 0 78 not_covered_count = 0 79 uncovered_for_group = { 'title' => group['title'] } # object stores uncovered assertions for the group 80 81 %w[instructions description_tests exceptions_tests verification_tests].each do |k| 82 not_covered_assertions = [] 83 84 group[k]&.each do |assertion| 85 if assertion['non_testable'] 86 non_testable_count += 1 87 else 88 testable_count += 1 89 if assertion['tests'].length.positive? 90 covered_count += 1 91 @accepted += assertion['tests'] 92 else 93 not_covered_count += 1 94 not_covered_assertions << assertion 95 end 96 end 97 end 98 99 send(k, not_covered_assertions, uncovered_for_group) if not_covered_assertions.length.positive? 100 end 101 102 # collect uncovered assertions 103 @uncovered_assertions << uncovered_for_group if not_covered_count.positive? 104 105 # update coverage metric for the group 106 group_metric = testable_count.positive? ? (covered_count.to_f / testable_count).round(2) : 'Not testable' 107 group['coverage_metric'] = group_metric 108 @coverage_by_groups << { 'title' => group['title'], 'coverage_metric' => group_metric } 109 110 # update counters 111 @testable += testable_count 112 @non_testable += non_testable_count 113 @covered += covered_count 114 @not_covered += not_covered_count 115 end 116 117 # The following methods make not covered assertions look like in ISA 118 # by formatting and removing extra fields added by us. 119 def instructions(not_covered_assertions, uncovered_for_group) 120 uncovered_for_group['instructions'] = not_covered_assertions.map { |a| except(a, %w[tests non_testable]) } 121 end 122 123 def description_tests(not_covered_assertions, uncovered_for_group) 124 uncovered_for_group['description'] = not_covered_assertions.map do |a| 125 a['assertion'] 126 end.join('. ').gsub(/\n/, ' ').rstrip 127 end 128 129 def exceptions_tests(not_covered_assertions, uncovered_for_group) 130 uncovered_for_group['exceptions'] = not_covered_assertions.map { |a| a['exception'] } 131 end 132 133 def verification_tests(not_covered_assertions, uncovered_for_group) 134 uncovered_for_group['verification'] = not_covered_assertions.map { |a| a['verification'] } 135 end 136 137 # delete specified keys from hash 138 def except(hash, keys) 139 hash.dup.tap do |x| 140 keys.each { |key| x.delete(key) } 141 end 142 end 143end 144