1 : // Copyright 2012 Google Inc.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : #include "syzygy/grinder/lcov_writer.h"
16 :
17 : #include "base/file_util.h"
18 :
19 : namespace grinder {
20 :
21 E : bool LcovWriter::Add(const LineInfo& line_info) {
22 : // Multiple entries for the same source file are stored consecutively in
23 : // the LineInfo, hence we use this as a cache to prevent repeated lookups
24 : // of source file names in our SourceFileCoverageInfoMap.
25 E : const std::string* old_source_file_name = NULL;
26 E : SourceFileCoverageInfoMap::iterator source_it;
27 :
28 : LineInfo::SourceLines::const_iterator line_it =
29 E : line_info.source_lines().begin();
30 E : for (; line_it != line_info.source_lines().end(); ++line_it) {
31 E : DCHECK(line_it->source_file_name != NULL);
32 :
33 : // Different source file? Then insert/lookup in our map.
34 E : if (old_source_file_name != line_it->source_file_name) {
35 : // We don't care whether it already exists or not.
36 : source_it = source_file_coverage_info_map_.insert(
37 : std::make_pair(*line_it->source_file_name,
38 E : CoverageInfo())).first;
39 E : old_source_file_name = line_it->source_file_name;
40 : }
41 :
42 : // Insert/lookup the execution count by line number.
43 : LineExecutionCountMap::iterator line_exec_it =
44 : source_it->second.line_execution_count_map.insert(
45 E : std::make_pair(line_it->line_number, 0)).first;
46 :
47 : // Set the execution count. Since LineInfo only has a 'visited' boolean,
48 : // we simply leave the execution count as initialized, or set it to 1.
49 E : if (line_it->visited)
50 E : line_exec_it->second = 1;
51 E : }
52 :
53 E : return true;
54 E : }
55 :
56 E : bool LcovWriter::Write(const FilePath& path) const {
57 E : file_util::ScopedFILE file(file_util::OpenFile(path, "wb"));
58 E : if (file.get() == NULL) {
59 i : LOG(ERROR) << "Failed to open file for writing: " << path.value();
60 i : return false;
61 : }
62 :
63 E : if (!Write(file.get())) {
64 i : LOG(ERROR) << "Failed to write LCOV file.";
65 i : return false;
66 : }
67 :
68 E : return true;
69 E : }
70 :
71 E : bool LcovWriter::Write(FILE* file) const {
72 E : DCHECK(file != NULL);
73 :
74 : SourceFileCoverageInfoMap::const_iterator source_it =
75 E : source_file_coverage_info_map_.begin();
76 E : for (; source_it != source_file_coverage_info_map_.end(); ++source_it) {
77 E : if (::fprintf(file, "SF:%s\n", source_it->first.c_str()) < 0)
78 i : return false;
79 :
80 : // Iterate over the line execution data, keeping summary statistics as we
81 : // go.
82 E : size_t lines_executed = 0;
83 : LineExecutionCountMap::const_iterator line_it =
84 E : source_it->second.line_execution_count_map.begin();
85 : LineExecutionCountMap::const_iterator line_it_end =
86 E : source_it->second.line_execution_count_map.end();
87 E : for (; line_it != line_it_end; ++line_it) {
88 E : if (::fprintf(file, "DA:%d,%d\n", line_it->first, line_it->second) < 0)
89 i : return false;
90 E : if (line_it->second > 0)
91 E : ++lines_executed;
92 E : }
93 :
94 : // Output the summary statistics for this file.
95 : if (::fprintf(file, "LH:%d\n", lines_executed) < 0 ||
96 : ::fprintf(file, "LF:%d\n",
97 : source_it->second.line_execution_count_map.size()) < 0 ||
98 E : ::fprintf(file, "end_of_record\n") < 0) {
99 i : return false;
100 : }
101 E : }
102 :
103 E : return true;
104 E : }
105 :
106 : } // namespace grinder
|