1 // Copyright 2015 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "courgette/label_manager.h"
17 #include "base/notreached.h"
18 #include "courgette/image_utils.h"
19 #include "testing/gtest/include/gtest/gtest.h"
25 class TestLabelManager : public LabelManager {
27 void SetLabels(const LabelVector& labels) { labels_ = labels; }
30 void CheckLabelManagerContent(LabelManager* label_manager,
31 const std::map<RVA, int32_t>& expected) {
32 EXPECT_EQ(expected.size(), label_manager->Labels().size());
33 for (const auto& rva_and_count : expected) {
34 Label* label = label_manager->Find(rva_and_count.first);
35 EXPECT_TRUE(label != nullptr);
36 EXPECT_EQ(rva_and_count.first, label->rva_);
37 EXPECT_EQ(rva_and_count.second, label->count_);
41 // Instantiates a LabelVector with |n| instances. The |rva_| fields are assigned
42 // 0, ..., |n| - 1. The other fields are uninitialized.
43 LabelVector CreateLabelVectorBasic(size_t n) {
46 for (size_t i = 0; i < n; ++i)
47 labels.push_back(Label(i));
51 // Instantiates a list of Labels, one per character |ch| in |encoded_index|.
52 // - |rva_| is assigned 0, 1, 2, ...
53 // - |count_| is assigned 1.
54 // - |index_| depends on |ch|: '.' => kNoIndex, 'A' => 0, ..., 'Z' => 25.
55 // Each letter (except '.') can appear at most once in |encoded_index|.
56 // For example, |encoded_index| = "A.E" initializes 3 Labels:
57 // [{rva_: 0, count_: 1, index_: 0},
58 // {rva_: 1, count_: 1, index_: kNoIndex},
59 // {rva_: 2, count_: 1, index_: 4}].
60 LabelVector CreateLabelVectorWithIndexes(const std::string& encoded_index) {
62 size_t n = encoded_index.size();
64 std::set<char> used_ch;
65 for (size_t i = 0; i < n; ++i) {
66 int index = Label::kNoIndex;
67 char ch = encoded_index[i];
69 // Sanity check for test case.
70 if (ch < 'A' || ch > 'Z' || used_ch.find(ch) != used_ch.end())
71 NOTREACHED() << "Malformed test case: " << encoded_index;
75 labels.push_back(Label(i, index, 1));
80 // Returns a string encoding for |index_| assignments for |label_| instances,
81 // with kNoIndex => '.', 0 => 'A', ..., '25' => 'Z'. Fails if any |index_|
82 // does not fit the above.
83 std::string EncodeLabelIndexes(const LabelVector& labels) {
85 encoded.reserve(labels.size());
86 for (const Label& label : labels) {
87 if (label.index_ == Label::kNoIndex)
89 else if (label.index_ >= 0 && label.index_ <= 'Z' - 'A')
90 encoded += static_cast<char>(label.index_ + 'A');
99 TEST(LabelManagerTest, GetLabelIndexBound) {
101 EXPECT_EQ(0, LabelManager::GetLabelIndexBound(labels0));
103 LabelVector labels1_uninit = CreateLabelVectorBasic(1);
104 ASSERT_EQ(1U, labels1_uninit.size());
105 EXPECT_EQ(0, LabelManager::GetLabelIndexBound(labels1_uninit));
107 LabelVector labels1_init = CreateLabelVectorBasic(1);
108 ASSERT_EQ(1U, labels1_init.size());
109 labels1_init[0].index_ = 99;
110 EXPECT_EQ(100, LabelManager::GetLabelIndexBound(labels1_init));
112 LabelVector labels6_mixed = CreateLabelVectorBasic(6);
113 ASSERT_EQ(6U, labels6_mixed.size());
114 labels6_mixed[1].index_ = 5;
115 labels6_mixed[2].index_ = 2;
116 labels6_mixed[4].index_ = 15;
117 labels6_mixed[5].index_ = 7;
118 EXPECT_EQ(16, LabelManager::GetLabelIndexBound(labels6_mixed));
121 TEST(LabelManagerTest, Basic) {
122 static const RVA kTestTargetsRaw[] = {
126 0x04000010, // Redundant.
128 0x04000030, // Redundant.
129 0xFEEDF00D, // Redundant.
131 0x04000010, // Redundant.
134 std::vector<RVA> test_targets(std::begin(kTestTargetsRaw),
135 std::end(kTestTargetsRaw));
136 TrivialRvaVisitor visitor(test_targets);
138 // Preallocate targets, then populate.
139 TestLabelManager label_manager;
140 label_manager.Read(&visitor);
142 static const std::pair<RVA, int32_t> kExpected1Raw[] = {
143 {0x00000110, 1}, {0x04000010, 3}, {0x04000020, 1},
144 {0x04000030, 2}, {0xABCD1234, 1}, {0xFEEDF00D, 2}};
145 std::map<RVA, int32_t> expected1(std::begin(kExpected1Raw),
146 std::end(kExpected1Raw));
148 CheckLabelManagerContent(&label_manager, expected1);
150 // Expect to *not* find labels for various RVAs that were never added.
151 EXPECT_EQ(nullptr, label_manager.Find(RVA(0x00000000)));
152 EXPECT_EQ(nullptr, label_manager.Find(RVA(0x0400000F)));
153 EXPECT_EQ(nullptr, label_manager.Find(RVA(0x04000011)));
154 EXPECT_EQ(nullptr, label_manager.Find(RVA(0x5F3759DF)));
155 EXPECT_EQ(nullptr, label_manager.Find(RVA(0xFEEDFFF0)));
156 EXPECT_EQ(nullptr, label_manager.Find(RVA(0xFFFFFFFF)));
159 TEST(LabelManagerTest, Single) {
160 const RVA kRva = 12U;
161 for (int dup = 1; dup < 8; ++dup) {
162 // Test data: |dup| copies of kRva.
163 std::vector<RVA> test_targets(dup, kRva);
164 TrivialRvaVisitor visitor(test_targets);
165 TestLabelManager label_manager;
166 label_manager.Read(&visitor);
167 EXPECT_EQ(1U, label_manager.Labels().size()); // Deduped to 1 Label.
169 Label* label = label_manager.Find(kRva);
170 EXPECT_NE(nullptr, label);
171 EXPECT_EQ(kRva, label->rva_);
172 EXPECT_EQ(dup, label->count_);
174 for (RVA rva = 0U; rva < 16U; ++rva) {
176 EXPECT_EQ(nullptr, label_manager.Find(rva));
181 TEST(LabelManagerTest, Empty) {
182 std::vector<RVA> empty_test_targets;
183 TrivialRvaVisitor visitor(empty_test_targets);
184 TestLabelManager label_manager;
185 label_manager.Read(&visitor);
186 EXPECT_EQ(0U, label_manager.Labels().size());
187 for (RVA rva = 0U; rva < 16U; ++rva)
188 EXPECT_EQ(nullptr, label_manager.Find(rva));
191 TEST(LabelManagerTest, EmptyAssign) {
192 TestLabelManager label_manager_empty;
193 label_manager_empty.DefaultAssignIndexes();
194 label_manager_empty.UnassignIndexes();
195 label_manager_empty.AssignRemainingIndexes();
198 TEST(LabelManagerTest, TrivialAssign) {
199 for (size_t size = 0; size < 20; ++size) {
200 TestLabelManager label_manager;
201 label_manager.SetLabels(CreateLabelVectorBasic(size));
204 for (size_t i = 0; i < size; ++i)
205 EXPECT_EQ(Label::kNoIndex, label_manager.Labels()[i].index_);
208 label_manager.DefaultAssignIndexes();
209 for (size_t i = 0; i < size; ++i)
210 EXPECT_EQ(static_cast<int>(i), label_manager.Labels()[i].index_);
212 // Heuristic assign, but since everything's assigned, so no change.
213 label_manager.AssignRemainingIndexes();
214 for (size_t i = 0; i < size; ++i)
215 EXPECT_EQ(static_cast<int>(i), label_manager.Labels()[i].index_);
218 label_manager.UnassignIndexes();
219 for (size_t i = 0; i < size; ++i)
220 EXPECT_EQ(Label::kNoIndex, label_manager.Labels()[i].index_);
224 // Tests SimpleIndexAssigner fill strategies independently.
225 TEST(LabelManagerTest, SimpleIndexAssigner) {
226 using SimpleIndexAssigner = LabelManager::SimpleIndexAssigner;
227 // See CreateLabelVectorWithIndexes() explanation on how we encode LabelVector
228 // |index_| values as a string.
229 const struct TestCase {
231 const char* expect_forward;
232 const char* expect_backward;
233 const char* expect_in;
236 {".", "A", "A", "A"},
237 {"....", "ABCD", "ABCD", "ABCD"},
238 {"A...", "ABCD", "ABCD", "ABCD"},
239 {".A..", ".ABC", ".ACD", "BACD"},
240 {"...A", "...A", "...A", "BCDA"},
241 {"C...", "CD.A", "C..D", "CABD"},
242 {".C..", "ACD.", "BC.D", "ACBD"},
243 {"...C", "AB.C", ".ABC", "ABDC"},
244 {"D...", "D.AB", "D...", "DABC"},
245 {".D..", "AD..", "CD..", "ADBC"},
246 {"...D", "ABCD", "ABCD", "ABCD"},
247 {"Z...", "Z.AB", "Z...", "ZABC"},
248 {".Z..", "AZ..", "YZ..", "AZBC"},
249 {"...Z", "ABCZ", "WXYZ", "ABCZ"},
250 {"..AZ..", "..AZ..", "..AZ..", "BCAZDE"},
251 {"..ZA..", "..ZABC", "XYZA..", "BCZADE"},
252 {"A....Z", "ABCDEZ", "AVWXYZ", "ABCDEZ"},
253 {"Z....A", "Z....A", "Z....A", "ZBCDEA"},
254 {"..CD..", "ABCDEF", "ABCDEF", "ABCDEF"},
255 {"..DC..", "ABDC..", "..DCEF", "ABDCEF"},
256 {"..MN..", "ABMN..", "KLMN..", "ABMNCD"},
257 {"..NM..", "ABNM..", "..NM..", "ABNMCD"},
258 {".B.D.F.", "ABCDEFG", "ABCDEFG", "ABCDEFG"},
259 {".D.G.J.", "ADEGHJ.", "CDFGIJ.", "ADBGCJE"},
260 {".D.Z.J.", "ADEZ.JK", "CDYZIJ.", "ADBZCJE"},
261 {".B..E..", "ABCDEFG", "ABCDEFG", "ABCDEFG"},
262 {".B..D..", "ABC.DEF", "AB.CDFG", "ABCEDFG"},
264 const int kNumFuns = 3;
265 // TestCase member variable pointers to enable iteration.
266 const char* TestCase::*expect_ptr[kNumFuns] = {
267 &TestCase::expect_forward,
268 &TestCase::expect_backward,
271 // SimpleIndexAssigner member function pointers to enable iteration.
272 void (SimpleIndexAssigner::*fun_ptrs[kNumFuns])() = {
273 &SimpleIndexAssigner::DoForwardFill,
274 &SimpleIndexAssigner::DoBackwardFill,
275 &SimpleIndexAssigner::DoInFill
277 for (const auto& test_case : kTestCases) {
278 // Loop over {forward fill, backward fill, infill}.
279 for (int i = 0; i < kNumFuns; ++i) {
280 std::string expect = test_case.*(expect_ptr[i]);
281 LabelVector labels = CreateLabelVectorWithIndexes(test_case.input);
282 SimpleIndexAssigner assigner(&labels);
283 (assigner.*(fun_ptrs[i]))();
284 std::string result = EncodeLabelIndexes(labels);
285 EXPECT_EQ(expect, result);
290 // Tests integrated AssignRemainingIndexes().
291 TEST(LabelManagerTest, AssignRemainingIndexes) {
299 {"ABCDEFG", "ABCDEFG"},
300 {"THEQUICKBROWNFXJMPSVLAZYDG", "THEQUICKBROWNFXJMPSVLAZYDG"},
301 // Forward fill only.
303 {".......", "ABCDEFG"},
304 {"....E..", "ABCDEFG"}, // "E" is at right place.
305 {".D.B.H.F.", "ADEBCHIFG"},
306 {"ZN....", "ZNOPQR"}, // "Z" exists, so 'OPQR" are defined.
307 {"H.D...A..", "HIDEFGABC"},
308 {"...K.DE..H..Z", "ABCKLDEFGHIJZ"}, // "Z" exists, so "L" defined.
315 {"....AC", "BDEFAC"},
316 {"ED...C...B....A", "EDFGHCIJKBLMNOA"},
317 // Forward fill and infill.
318 {"E..", "EBA"}, // Forward: "A"; in: "B".
319 {"Z....", "ZDABC"}, // Forward: "ABC"; in: "D".
320 {".E.....", "AEFGBCD"}, // Forward: "A", "FG"; in: "BCD".
321 {"....C..", "ABFGCDE"}, // Forward: "AB", "DE"; in: "FG".
322 {"...Z...", "ABCZDEF"}, // Forward: "ABC"; in: "DEF".
323 {"...A...", "EFGABCD"}, // Forward: "BCD"; in: "EFG".
324 // Backward fill only.
327 {"BA...Z", "BAWXYZ"},
328 {"ANM..Z....L...T", "ANMXYZHIJKLQRST"},
329 {"....G..Z...LAH", "CDEFGXYZIJKLAH"},
330 // Forward fill and backward fill.
331 {"..ZA..", "XYZABC"}, // Forward: "BC"; backward: "XY".
332 {".....ZD", "ABCXYZD"}, // Forward: "ABC"; backward: "XY".
333 {"DA.....", "DABCEFG"}, // Forward: "BC"; backward: "EFG".
334 // Backward fill and infill.
335 {"G....DA", "GEFBCDA"}, // Backward: "BC"; in: "EF".
336 {"..ZBA..", "XYZBACD"}, // Backward: "XY"; in: "CD".
338 {".....ZED.", "ABCXYZEDF"}, // Forward: "ABC"; backward: "XY"; in: "F".
339 {".....GD.", "ABCHFGDE"}, // Forward: "ABC", "E"; backward: "F"; in: "H".
340 {"..FE..GD..", "ABFECHGDIJ"}, // Forward: "AB"; backward: "IJ"; in: "CH".
342 for (const auto& test_case : kTestCases) {
343 TestLabelManager label_manager;
344 label_manager.SetLabels(CreateLabelVectorWithIndexes(test_case.input));
346 label_manager.AssignRemainingIndexes();
347 std::string result = EncodeLabelIndexes(label_manager.Labels());
348 EXPECT_EQ(test_case.expect, result);
352 } // namespace courgette