1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include "VtsCoverageProcessor.h"
17 
18 #include <dirent.h>
19 #include <fcntl.h>
20 #include <fstream>
21 #include <iostream>
22 #include <map>
23 #include <string>
24 #include <vector>
25 
26 #include <google/protobuf/text_format.h>
27 #include <test/vts/proto/VtsReportMessage.pb.h>
28 
29 using namespace std;
30 using google::protobuf::TextFormat;
31 
32 namespace android {
33 namespace vts {
34 
ParseCoverageData(const string & coverage_file,TestReportMessage * report_msg)35 void VtsCoverageProcessor::ParseCoverageData(const string& coverage_file,
36                                              TestReportMessage* report_msg) {
37   ifstream in(coverage_file, std::ios::in);
38   string msg_str((istreambuf_iterator<char>(in)), istreambuf_iterator<char>());
39   if (!TextFormat::MergeFromString(msg_str, report_msg)) {
40     cerr << "Can't parse a given coverage report: " << msg_str << endl;
41     exit(-1);
42   }
43 }
44 
UpdateCoverageData(const CoverageReportMessage & ref_msg,CoverageReportMessage * msg_to_be_updated)45 void VtsCoverageProcessor::UpdateCoverageData(
46     const CoverageReportMessage& ref_msg,
47     CoverageReportMessage* msg_to_be_updated) {
48   if (ref_msg.file_path() == msg_to_be_updated->file_path()) {
49     for (int line = 0; line < ref_msg.line_coverage_vector_size(); line++) {
50       if (line < msg_to_be_updated->line_coverage_vector_size()) {
51         if (ref_msg.line_coverage_vector(line) > 0 &&
52             msg_to_be_updated->line_coverage_vector(line) > 0) {
53           msg_to_be_updated->set_line_coverage_vector(line, 0);
54           msg_to_be_updated->set_covered_line_count(
55               msg_to_be_updated->covered_line_count() - 1);
56         }
57       } else {
58         cout << "Reached the end of line_coverage_vector." << endl;
59         break;
60       }
61     }
62     // Validate
63     if (msg_to_be_updated->covered_line_count() < 0) {
64       cerr << __func__ << ": covered_line_count should not be negative."
65            << endl;
66       exit(-1);
67     }
68   }
69 }
70 
MergeCoverage(const string & coverage_file_dir,const string & merged_coverage_file)71 void VtsCoverageProcessor::MergeCoverage(const string& coverage_file_dir,
72                                          const string& merged_coverage_file) {
73   DIR* coverage_dir = opendir(coverage_file_dir.c_str());
74   if (coverage_dir == 0) {
75     cerr << __func__ << ": " << coverage_file_dir << " does not exist." << endl;
76     return;
77   }
78   TestReportMessage merged_coverage_report;
79 
80   struct dirent* file;
81   while ((file = readdir(coverage_dir)) != NULL) {
82     if (file->d_type == DT_REG) {
83       string coverage_file = coverage_file_dir;
84       if (coverage_file_dir.substr(coverage_file_dir.size() - 1) != "/") {
85         coverage_file += "/";
86       }
87       string coverage_file_base_name = file->d_name;
88       coverage_file += coverage_file_base_name;
89       TestReportMessage coverage_report;
90       ParseCoverageData(coverage_file, &coverage_report);
91 
92       for (const auto& cov : coverage_report.coverage()) {
93         bool seen_cov = false;
94         for (int i = 0; i < merged_coverage_report.coverage_size(); i++) {
95           if (merged_coverage_report.coverage(i).file_path() ==
96               cov.file_path()) {
97             MergeCoverageMsg(cov, merged_coverage_report.mutable_coverage(i));
98             seen_cov = true;
99             break;
100           }
101         }
102         if (!seen_cov) {
103           *merged_coverage_report.add_coverage() = cov;
104         }
105       }
106     }
107   }
108 
109   PrintCoverageSummary(merged_coverage_report);
110   ofstream fout;
111   fout.open(merged_coverage_file);
112   fout << merged_coverage_report.DebugString();
113   fout.close();
114 }
115 
MergeCoverageMsg(const CoverageReportMessage & ref_coverage_msg,CoverageReportMessage * merged_coverage_msg)116 void VtsCoverageProcessor::MergeCoverageMsg(
117     const CoverageReportMessage& ref_coverage_msg,
118     CoverageReportMessage* merged_coverage_msg) {
119   // File path consistency check.
120   if (ref_coverage_msg.file_path() != merged_coverage_msg->file_path()) {
121     cerr << "Trying to merge coverage data for different files." << endl;
122     exit(-1);
123   }
124   if (ref_coverage_msg.line_coverage_vector_size() !=
125       merged_coverage_msg->line_coverage_vector_size()) {
126     cerr << "Trying to merge coverage data with different lines."
127          << "ref_coverage_msg: " << ref_coverage_msg.DebugString()
128          << "merged_coverage_msg: " << merged_coverage_msg->DebugString()
129          << endl;
130     exit(-1);
131   }
132   for (int i = 0; i < ref_coverage_msg.line_coverage_vector_size(); i++) {
133     if (i > merged_coverage_msg->line_coverage_vector_size() - 1) {
134       cerr << "Reach the end of coverage vector" << endl;
135       break;
136     }
137     int ref_line_count = ref_coverage_msg.line_coverage_vector(i);
138     int merged_line_count = merged_coverage_msg->line_coverage_vector(i);
139     if (ref_line_count > 0) {
140       if (merged_line_count == 0) {
141         merged_coverage_msg->set_covered_line_count(
142             merged_coverage_msg->covered_line_count() + 1);
143       }
144       merged_coverage_msg->set_line_coverage_vector(
145           i, merged_line_count + ref_line_count);
146     }
147   }
148 }
149 
CompareCoverage(const string & ref_msg_file,const string & new_msg_file)150 void VtsCoverageProcessor::CompareCoverage(const string& ref_msg_file,
151                                            const string& new_msg_file) {
152   TestReportMessage ref_coverage_report;
153   TestReportMessage new_coverage_report;
154   ParseCoverageData(ref_msg_file, &ref_coverage_report);
155   ParseCoverageData(new_msg_file, &new_coverage_report);
156   map<string, vector<int>> new_coverage_map;
157 
158   for (const auto& new_coverage : new_coverage_report.coverage()) {
159     bool seen_file = false;
160     for (const auto& ref_coverage : ref_coverage_report.coverage()) {
161       if (new_coverage.file_path() == ref_coverage.file_path()) {
162         int line = 0;
163         for (; line < new_coverage.line_coverage_vector_size(); line++) {
164           if (new_coverage.line_coverage_vector(line) > 0 &&
165               ref_coverage.line_coverage_vector(line) == 0) {
166             if (new_coverage_map.find(new_coverage.file_path()) !=
167                 new_coverage_map.end()) {
168               new_coverage_map[new_coverage.file_path()].push_back(line);
169             } else {
170               new_coverage_map.insert(std::pair<string, vector<int>>(
171                   new_coverage.file_path(), vector<int>{line}));
172             }
173           }
174         }
175         seen_file = true;
176         break;
177       }
178     }
179     if (!seen_file) {
180       vector<int> new_line;
181       for (int line = 0; line < new_coverage.line_coverage_vector_size();
182            line++) {
183         if (new_coverage.line_coverage_vector(line) > 0) {
184           new_line.push_back(line);
185         }
186       }
187       new_coverage_map.insert(
188           std::pair<string, vector<int>>(new_coverage.file_path(), new_line));
189     }
190   }
191   for (auto it = new_coverage_map.begin(); it != new_coverage_map.end(); it++) {
192     cout << it->first << ": " << endl;
193     for (int covered_line : it->second) {
194       cout << covered_line << endl;
195     }
196   }
197 }
198 
GetSubsetCoverage(const string & ref_msg_file,const string & full_msg_file,const string & result_msg_file)199 void VtsCoverageProcessor::GetSubsetCoverage(const string& ref_msg_file,
200                                              const string& full_msg_file,
201                                              const string& result_msg_file) {
202   TestReportMessage ref_coverage_report;
203   TestReportMessage full_coverage_report;
204   TestReportMessage result_coverage_report;
205   ParseCoverageData(ref_msg_file, &ref_coverage_report);
206   ParseCoverageData(full_msg_file, &full_coverage_report);
207 
208   for (const auto& ref_coverage : ref_coverage_report.coverage()) {
209     bool seen_file = false;
210     for (const auto& coverage : full_coverage_report.coverage()) {
211       if (coverage.file_path() == ref_coverage.file_path()) {
212         *result_coverage_report.add_coverage() = coverage;
213         seen_file = true;
214         break;
215       }
216     }
217     if (!seen_file) {
218       cout << ": missing coverage for file " << ref_coverage.file_path()
219            << endl;
220       CoverageReportMessage* empty_coverage =
221           result_coverage_report.add_coverage();
222       *empty_coverage = ref_coverage;
223       for (int line = 0; line < empty_coverage->line_coverage_vector_size();
224            line++) {
225         if (empty_coverage->line_coverage_vector(line) > 0) {
226           empty_coverage->set_line_coverage_vector(line, 0);
227         }
228       }
229       empty_coverage->set_covered_line_count(0);
230     }
231   }
232   PrintCoverageSummary(result_coverage_report);
233   ofstream fout;
234   fout.open(result_msg_file);
235   fout << result_coverage_report.DebugString();
236   fout.close();
237 }
238 
GetCoverageSummary(const string & coverage_msg_file)239 void VtsCoverageProcessor::GetCoverageSummary(const string& coverage_msg_file) {
240   TestReportMessage coverage_report;
241   ParseCoverageData(coverage_msg_file, &coverage_report);
242   PrintCoverageSummary(coverage_report);
243 }
244 
PrintCoverageSummary(const TestReportMessage & coverage_report)245 void VtsCoverageProcessor::PrintCoverageSummary(
246     const TestReportMessage& coverage_report) {
247   long total_lines_covered = GetTotalCoverageLine(coverage_report);
248   long total_code_lines = GetTotalCodeLine(coverage_report);
249   double coverage_rate = (double)total_lines_covered / total_code_lines;
250   cout << "total lines covered: " << total_lines_covered << endl;
251   cout << "total lines: " << total_code_lines << endl;
252   cout << "coverage rate: " << coverage_rate << endl;
253 }
254 
GetTotalCoverageLine(const TestReportMessage & msg) const255 long VtsCoverageProcessor::GetTotalCoverageLine(
256     const TestReportMessage& msg) const {
257   long total_coverage_line = 0;
258   for (const auto& coverage : msg.coverage()) {
259     total_coverage_line += coverage.covered_line_count();
260   }
261   return total_coverage_line;
262 }
263 
GetTotalCodeLine(const TestReportMessage & msg) const264 long VtsCoverageProcessor::GetTotalCodeLine(
265     const TestReportMessage& msg) const {
266   long total_line = 0;
267   for (const auto& coverage : msg.coverage()) {
268     total_line += coverage.total_line_count();
269   }
270   return total_line;
271 }
272 
273 }  // namespace vts
274 }  // namespace android
275