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