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