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/line_info.h"
16 :
17 : #include "gmock/gmock.h"
18 : #include "gtest/gtest.h"
19 : #include "syzygy/core/unittest_util.h"
20 :
21 : namespace grinder {
22 :
23 : namespace {
24 :
25 : const wchar_t kCoverageInstrumentedTestDllPdb[] =
26 : L"coverage_instrumented_test_dll.pdb";
27 :
28 : class TestLineInfo : public LineInfo {
29 : public:
30 : using LineInfo::source_files_;
31 : using LineInfo::source_lines_;
32 :
33 E : void ResetVisitedLines() {
34 E : for (size_t i = 0; i < source_lines_.size(); ++i) {
35 E : source_lines_[i].visited = false;
36 E : }
37 E : }
38 :
39 E : void GetVisitedLines(std::vector<size_t>* visited_lines) const {
40 E : DCHECK(visited_lines != NULL);
41 E : visited_lines->clear();
42 E : for (size_t i = 0; i < source_lines_.size(); ++i) {
43 E : if (source_lines_[i].visited)
44 E : visited_lines->push_back(source_lines_[i].line_number);
45 E : }
46 E : }
47 : };
48 :
49 : class LineInfoTest : public testing::Test {
50 : public:
51 E : virtual void SetUp() OVERRIDE {
52 E : testing::Test::SetUp();
53 :
54 : pdb_path_ = testing::GetExeTestDataRelativePath(
55 E : kCoverageInstrumentedTestDllPdb);
56 :
57 :
58 E : std::wstring static_pdb_path(L"syzygy/grinder/test_data/");
59 E : static_pdb_path.append(kCoverageInstrumentedTestDllPdb);
60 E : static_pdb_path_ = testing::GetSrcRelativePath(static_pdb_path.c_str());
61 E : }
62 :
63 : FilePath pdb_path_;
64 : FilePath static_pdb_path_;
65 : };
66 :
67 : void PushBackSourceLine(
68 : TestLineInfo* line_info,
69 : const std::string* source_file_name,
70 : size_t line_number,
71 : uint32 address,
72 E : size_t size) {
73 E : DCHECK(line_info != NULL);
74 : line_info->source_lines_.push_back(LineInfo::SourceLine(
75 : source_file_name,
76 : line_number,
77 : core::RelativeAddress(address),
78 E : size));
79 E : }
80 :
81 : #define EXPECT_LINES_VISITED(line_info, ...) \
82 : { \
83 : const size_t kLineNumbers[] = { __VA_ARGS__ }; \
84 : std::vector<size_t> visited, expected; \
85 : expected.assign(kLineNumbers, kLineNumbers + arraysize(kLineNumbers)); \
86 : line_info.GetVisitedLines(&visited); \
87 : std::sort(expected.begin(), expected.end()); \
88 : std::sort(visited.begin(), visited.end()); \
89 : EXPECT_THAT(expected, ::testing::ContainerEq(visited)); \
90 : }
91 :
92 : #define EXPECT_NO_LINES_VISITED(line_info) \
93 : { \
94 : std::vector<size_t> visited; \
95 : line_info.GetVisitedLines(&visited); \
96 : EXPECT_EQ(0u, visited.size()); \
97 : }
98 :
99 : } // namespace
100 :
101 E : TEST_F(LineInfoTest, InitDynamicPdb) {
102 E : TestLineInfo line_info;
103 E : EXPECT_TRUE(line_info.Init(pdb_path_));
104 E : }
105 :
106 E : TEST_F(LineInfoTest, InitStaticPdb) {
107 E : TestLineInfo line_info;
108 E : EXPECT_TRUE(line_info.Init(static_pdb_path_));
109 :
110 : // The expected values were taken by running "pdb_dumper --dump-modules
111 : // syzygy/grinder/test_data/coverage_instrumented_test_dll.pdb" and running
112 : // through the following filters:
113 : // grep "line at" | sed 's/(.*$//' | uniq | sort | uniq | wc -l
114 E : EXPECT_EQ(138u, line_info.source_files().size());
115 : // grep "line at" | wc -l
116 E : EXPECT_EQ(8379u, line_info.source_lines().size());
117 E : }
118 :
119 E : TEST_F(LineInfoTest, Visit) {
120 E : TestLineInfo line_info;
121 :
122 : // Create a single dummy source file.
123 E : std::string source_file("foo.cc");
124 :
125 : // The first two entries have identical ranges, and map multiple lines to
126 : // those ranges.
127 E : PushBackSourceLine(&line_info, &source_file, 1, 4096, 2);
128 E : PushBackSourceLine(&line_info, &source_file, 2, 4096, 2);
129 E : PushBackSourceLine(&line_info, &source_file, 3, 4098, 2);
130 E : PushBackSourceLine(&line_info, &source_file, 5, 4100, 2);
131 : // Leave a gap between these two entries.
132 E : PushBackSourceLine(&line_info, &source_file, 6, 4104, 6);
133 E : PushBackSourceLine(&line_info, &source_file, 7, 4110, 2);
134 :
135 : // So, our line info looks like this:
136 : // 1,2 3 5 6 7 <-- line numbers
137 : // +----+----+----+----+----+----+
138 : // |0,1 | 2 | 3 |gap | 4 | 5 | <-- source_lines_ indices
139 : // +----+----+----+----+----+----+
140 : // 4096 4098 4100 4102 4104 4110 4112 <-- address ranges
141 :
142 : // Visit a repeated BB (multiple lines).
143 E : EXPECT_TRUE(line_info.Visit(core::RelativeAddress(4096), 2));
144 E : EXPECT_LINES_VISITED(line_info, 1, 2);
145 :
146 : // Visit a range spanning multiple BBs (we don't reset the previously
147 : // visited lines to ensure that stats are kept correctly across multiple
148 : // calls to LineInfo::Visit).
149 E : EXPECT_TRUE(line_info.Visit(core::RelativeAddress(4098), 4));
150 E : EXPECT_LINES_VISITED(line_info, 1, 2, 3, 5);
151 :
152 : // Visit a gap and no blocks.
153 E : line_info.ResetVisitedLines();
154 E : EXPECT_TRUE(line_info.Visit(core::RelativeAddress(4102), 2));
155 E : EXPECT_NO_LINES_VISITED(line_info);
156 :
157 : // Visit a range spanning a gap (at the left) and a BB.
158 E : line_info.ResetVisitedLines();
159 E : EXPECT_TRUE(line_info.Visit(core::RelativeAddress(4102), 8));
160 E : EXPECT_LINES_VISITED(line_info, 6);
161 :
162 : // Visit a range spanning a gap (at the right) and a BB.
163 E : line_info.ResetVisitedLines();
164 E : EXPECT_TRUE(line_info.Visit(core::RelativeAddress(4100), 4));
165 E : EXPECT_LINES_VISITED(line_info, 5);
166 :
167 : // Visit a range spanning 2 BBs with a gap in the middle.
168 E : line_info.ResetVisitedLines();
169 E : EXPECT_TRUE(line_info.Visit(core::RelativeAddress(4100), 10));
170 E : EXPECT_LINES_VISITED(line_info, 5, 6);
171 :
172 : // Visit a range only partially spanning a single BB.
173 E : line_info.ResetVisitedLines();
174 E : EXPECT_TRUE(line_info.Visit(core::RelativeAddress(4100), 1));
175 E : EXPECT_LINES_VISITED(line_info, 5);
176 :
177 : // Visit a range partially spanning a BB on the left.
178 E : line_info.ResetVisitedLines();
179 E : EXPECT_TRUE(line_info.Visit(core::RelativeAddress(4108), 4));
180 E : EXPECT_LINES_VISITED(line_info, 6, 7);
181 :
182 : // Visit a range partially spanning a BB on the right.
183 E : line_info.ResetVisitedLines();
184 E : EXPECT_TRUE(line_info.Visit(core::RelativeAddress(4104), 7));
185 E : EXPECT_LINES_VISITED(line_info, 6, 7);
186 E : }
187 :
188 : } // namespace grinder
|