275 lines
9.6 KiB
C++
275 lines
9.6 KiB
C++
/*
|
|
* Copyright (C) 2018 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
#include "VtsCoverageProcessor.h"
|
|
|
|
#include <dirent.h>
|
|
#include <fcntl.h>
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include <map>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include <google/protobuf/text_format.h>
|
|
#include <test/vts/proto/VtsReportMessage.pb.h>
|
|
|
|
using namespace std;
|
|
using google::protobuf::TextFormat;
|
|
|
|
namespace android {
|
|
namespace vts {
|
|
|
|
void VtsCoverageProcessor::ParseCoverageData(const string& coverage_file,
|
|
TestReportMessage* report_msg) {
|
|
ifstream in(coverage_file, std::ios::in);
|
|
string msg_str((istreambuf_iterator<char>(in)), istreambuf_iterator<char>());
|
|
if (!TextFormat::MergeFromString(msg_str, report_msg)) {
|
|
cerr << "Can't parse a given coverage report: " << msg_str << endl;
|
|
exit(-1);
|
|
}
|
|
}
|
|
|
|
void VtsCoverageProcessor::UpdateCoverageData(
|
|
const CoverageReportMessage& ref_msg,
|
|
CoverageReportMessage* msg_to_be_updated) {
|
|
if (ref_msg.file_path() == msg_to_be_updated->file_path()) {
|
|
for (int line = 0; line < ref_msg.line_coverage_vector_size(); line++) {
|
|
if (line < msg_to_be_updated->line_coverage_vector_size()) {
|
|
if (ref_msg.line_coverage_vector(line) > 0 &&
|
|
msg_to_be_updated->line_coverage_vector(line) > 0) {
|
|
msg_to_be_updated->set_line_coverage_vector(line, 0);
|
|
msg_to_be_updated->set_covered_line_count(
|
|
msg_to_be_updated->covered_line_count() - 1);
|
|
}
|
|
} else {
|
|
cout << "Reached the end of line_coverage_vector." << endl;
|
|
break;
|
|
}
|
|
}
|
|
// Validate
|
|
if (msg_to_be_updated->covered_line_count() < 0) {
|
|
cerr << __func__ << ": covered_line_count should not be negative."
|
|
<< endl;
|
|
exit(-1);
|
|
}
|
|
}
|
|
}
|
|
|
|
void VtsCoverageProcessor::MergeCoverage(const string& coverage_file_dir,
|
|
const string& merged_coverage_file) {
|
|
DIR* coverage_dir = opendir(coverage_file_dir.c_str());
|
|
if (coverage_dir == 0) {
|
|
cerr << __func__ << ": " << coverage_file_dir << " does not exist." << endl;
|
|
return;
|
|
}
|
|
TestReportMessage merged_coverage_report;
|
|
|
|
struct dirent* file;
|
|
while ((file = readdir(coverage_dir)) != NULL) {
|
|
if (file->d_type == DT_REG) {
|
|
string coverage_file = coverage_file_dir;
|
|
if (coverage_file_dir.substr(coverage_file_dir.size() - 1) != "/") {
|
|
coverage_file += "/";
|
|
}
|
|
string coverage_file_base_name = file->d_name;
|
|
coverage_file += coverage_file_base_name;
|
|
TestReportMessage coverage_report;
|
|
ParseCoverageData(coverage_file, &coverage_report);
|
|
|
|
for (const auto& cov : coverage_report.coverage()) {
|
|
bool seen_cov = false;
|
|
for (int i = 0; i < merged_coverage_report.coverage_size(); i++) {
|
|
if (merged_coverage_report.coverage(i).file_path() ==
|
|
cov.file_path()) {
|
|
MergeCoverageMsg(cov, merged_coverage_report.mutable_coverage(i));
|
|
seen_cov = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!seen_cov) {
|
|
*merged_coverage_report.add_coverage() = cov;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
PrintCoverageSummary(merged_coverage_report);
|
|
ofstream fout;
|
|
fout.open(merged_coverage_file);
|
|
fout << merged_coverage_report.DebugString();
|
|
fout.close();
|
|
}
|
|
|
|
void VtsCoverageProcessor::MergeCoverageMsg(
|
|
const CoverageReportMessage& ref_coverage_msg,
|
|
CoverageReportMessage* merged_coverage_msg) {
|
|
// File path consistency check.
|
|
if (ref_coverage_msg.file_path() != merged_coverage_msg->file_path()) {
|
|
cerr << "Trying to merge coverage data for different files." << endl;
|
|
exit(-1);
|
|
}
|
|
if (ref_coverage_msg.line_coverage_vector_size() !=
|
|
merged_coverage_msg->line_coverage_vector_size()) {
|
|
cerr << "Trying to merge coverage data with different lines."
|
|
<< "ref_coverage_msg: " << ref_coverage_msg.DebugString()
|
|
<< "merged_coverage_msg: " << merged_coverage_msg->DebugString()
|
|
<< endl;
|
|
exit(-1);
|
|
}
|
|
for (int i = 0; i < ref_coverage_msg.line_coverage_vector_size(); i++) {
|
|
if (i > merged_coverage_msg->line_coverage_vector_size() - 1) {
|
|
cerr << "Reach the end of coverage vector" << endl;
|
|
break;
|
|
}
|
|
int ref_line_count = ref_coverage_msg.line_coverage_vector(i);
|
|
int merged_line_count = merged_coverage_msg->line_coverage_vector(i);
|
|
if (ref_line_count > 0) {
|
|
if (merged_line_count == 0) {
|
|
merged_coverage_msg->set_covered_line_count(
|
|
merged_coverage_msg->covered_line_count() + 1);
|
|
}
|
|
merged_coverage_msg->set_line_coverage_vector(
|
|
i, merged_line_count + ref_line_count);
|
|
}
|
|
}
|
|
}
|
|
|
|
void VtsCoverageProcessor::CompareCoverage(const string& ref_msg_file,
|
|
const string& new_msg_file) {
|
|
TestReportMessage ref_coverage_report;
|
|
TestReportMessage new_coverage_report;
|
|
ParseCoverageData(ref_msg_file, &ref_coverage_report);
|
|
ParseCoverageData(new_msg_file, &new_coverage_report);
|
|
map<string, vector<int>> new_coverage_map;
|
|
|
|
for (const auto& new_coverage : new_coverage_report.coverage()) {
|
|
bool seen_file = false;
|
|
for (const auto& ref_coverage : ref_coverage_report.coverage()) {
|
|
if (new_coverage.file_path() == ref_coverage.file_path()) {
|
|
int line = 0;
|
|
for (; line < new_coverage.line_coverage_vector_size(); line++) {
|
|
if (new_coverage.line_coverage_vector(line) > 0 &&
|
|
ref_coverage.line_coverage_vector(line) == 0) {
|
|
if (new_coverage_map.find(new_coverage.file_path()) !=
|
|
new_coverage_map.end()) {
|
|
new_coverage_map[new_coverage.file_path()].push_back(line);
|
|
} else {
|
|
new_coverage_map.insert(std::pair<string, vector<int>>(
|
|
new_coverage.file_path(), vector<int>{line}));
|
|
}
|
|
}
|
|
}
|
|
seen_file = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!seen_file) {
|
|
vector<int> new_line;
|
|
for (int line = 0; line < new_coverage.line_coverage_vector_size();
|
|
line++) {
|
|
if (new_coverage.line_coverage_vector(line) > 0) {
|
|
new_line.push_back(line);
|
|
}
|
|
}
|
|
new_coverage_map.insert(
|
|
std::pair<string, vector<int>>(new_coverage.file_path(), new_line));
|
|
}
|
|
}
|
|
for (auto it = new_coverage_map.begin(); it != new_coverage_map.end(); it++) {
|
|
cout << it->first << ": " << endl;
|
|
for (int covered_line : it->second) {
|
|
cout << covered_line << endl;
|
|
}
|
|
}
|
|
}
|
|
|
|
void VtsCoverageProcessor::GetSubsetCoverage(const string& ref_msg_file,
|
|
const string& full_msg_file,
|
|
const string& result_msg_file) {
|
|
TestReportMessage ref_coverage_report;
|
|
TestReportMessage full_coverage_report;
|
|
TestReportMessage result_coverage_report;
|
|
ParseCoverageData(ref_msg_file, &ref_coverage_report);
|
|
ParseCoverageData(full_msg_file, &full_coverage_report);
|
|
|
|
for (const auto& ref_coverage : ref_coverage_report.coverage()) {
|
|
bool seen_file = false;
|
|
for (const auto& coverage : full_coverage_report.coverage()) {
|
|
if (coverage.file_path() == ref_coverage.file_path()) {
|
|
*result_coverage_report.add_coverage() = coverage;
|
|
seen_file = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!seen_file) {
|
|
cout << ": missing coverage for file " << ref_coverage.file_path()
|
|
<< endl;
|
|
CoverageReportMessage* empty_coverage =
|
|
result_coverage_report.add_coverage();
|
|
*empty_coverage = ref_coverage;
|
|
for (int line = 0; line < empty_coverage->line_coverage_vector_size();
|
|
line++) {
|
|
if (empty_coverage->line_coverage_vector(line) > 0) {
|
|
empty_coverage->set_line_coverage_vector(line, 0);
|
|
}
|
|
}
|
|
empty_coverage->set_covered_line_count(0);
|
|
}
|
|
}
|
|
PrintCoverageSummary(result_coverage_report);
|
|
ofstream fout;
|
|
fout.open(result_msg_file);
|
|
fout << result_coverage_report.DebugString();
|
|
fout.close();
|
|
}
|
|
|
|
void VtsCoverageProcessor::GetCoverageSummary(const string& coverage_msg_file) {
|
|
TestReportMessage coverage_report;
|
|
ParseCoverageData(coverage_msg_file, &coverage_report);
|
|
PrintCoverageSummary(coverage_report);
|
|
}
|
|
|
|
void VtsCoverageProcessor::PrintCoverageSummary(
|
|
const TestReportMessage& coverage_report) {
|
|
long total_lines_covered = GetTotalCoverageLine(coverage_report);
|
|
long total_code_lines = GetTotalCodeLine(coverage_report);
|
|
double coverage_rate = (double)total_lines_covered / total_code_lines;
|
|
cout << "total lines covered: " << total_lines_covered << endl;
|
|
cout << "total lines: " << total_code_lines << endl;
|
|
cout << "coverage rate: " << coverage_rate << endl;
|
|
}
|
|
|
|
long VtsCoverageProcessor::GetTotalCoverageLine(
|
|
const TestReportMessage& msg) const {
|
|
long total_coverage_line = 0;
|
|
for (const auto& coverage : msg.coverage()) {
|
|
total_coverage_line += coverage.covered_line_count();
|
|
}
|
|
return total_coverage_line;
|
|
}
|
|
|
|
long VtsCoverageProcessor::GetTotalCodeLine(
|
|
const TestReportMessage& msg) const {
|
|
long total_line = 0;
|
|
for (const auto& coverage : msg.coverage()) {
|
|
total_line += coverage.total_line_count();
|
|
}
|
|
return total_line;
|
|
}
|
|
|
|
} // namespace vts
|
|
} // namespace android
|