1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "base/strings/string_number_conversions.h" 6 #include "base/strings/string_util.h" 7 #include "base/strings/utf_string_conversions.h" 8 #include "chrome/browser/enumerate_modules_model_win.h" 9 #include "testing/gtest/include/gtest/gtest.h" 10 11 typedef testing::Test EnumerateModulesTest; 12 13 // Set up some constants to use as default when creating the structs. 14 static const ModuleEnumerator::ModuleType kType = 15 ModuleEnumerator::LOADED_MODULE; 16 17 static const ModuleEnumerator::ModuleStatus kStatus = 18 ModuleEnumerator::NOT_MATCHED; 19 20 static const ModuleEnumerator::RecommendedAction kAction = 21 ModuleEnumerator::NONE; 22 23 static const ModuleEnumerator::OperatingSystem kOs = 24 ModuleEnumerator::ALL; 25 26 // This is a list of test cases to normalize. 27 static const struct NormalizationEntryList { 28 ModuleEnumerator::Module test_case; 29 ModuleEnumerator::Module expected; 30 } kNormalizationTestCases[] = { 31 { 32 // Only path normalization needed. 33 {kType, kStatus, L"c:\\foo\\bar.dll", L"", L"Prod", L"Desc", L"1.0", 34 L"Sig", kAction}, 35 {kType, kStatus, L"c:\\foo\\", L"bar.dll", L"Prod", L"Desc", L"1.0", 36 L"Sig", kAction}, 37 }, { 38 // Lower case normalization. 39 {kType, kStatus, L"C:\\Foo\\Bar.dll", L"", L"", L"", L"1.0", 40 L"", kAction}, 41 {kType, kStatus, L"c:\\foo\\", L"bar.dll", L"", L"", L"1.0", 42 L"", kAction}, 43 }, { 44 // Version can include strings after the version number. Strip that away. 45 {kType, kStatus, L"c:\\foo.dll", L"", L"", L"", L"1.0 asdf", 46 L"", kAction}, 47 {kType, kStatus, L"c:\\", L"foo.dll", L"", L"", L"1.0", 48 L"", kAction}, 49 }, { 50 // Corner case: No path (not sure this will ever happen). 51 {kType, kStatus, L"bar.dll", L"", L"", L"", L"", L"", kAction}, 52 {kType, kStatus, L"", L"bar.dll", L"", L"", L"", L"", kAction}, 53 }, { 54 // Error case: Missing filename (not sure this will ever happen). 55 {kType, kStatus, L"", L"", L"", L"", L"1.0", L"", kAction}, 56 {kType, kStatus, L"", L"", L"", L"", L"1.0", L"", kAction}, 57 }, 58 }; 59 60 TEST_F(EnumerateModulesTest, NormalizeEntry) { 61 for (size_t i = 0; i < arraysize(kNormalizationTestCases); ++i) { 62 ModuleEnumerator::Module test = kNormalizationTestCases[i].test_case; 63 EXPECT_FALSE(test.normalized); 64 ModuleEnumerator::NormalizeModule(&test); 65 ModuleEnumerator::Module expected = kNormalizationTestCases[i].expected; 66 67 SCOPED_TRACE("Test case no: " + base::IntToString(i)); 68 EXPECT_EQ(expected.type, test.type); 69 EXPECT_EQ(expected.status, test.status); 70 EXPECT_STREQ(expected.location.c_str(), test.location.c_str()); 71 EXPECT_STREQ(expected.name.c_str(), test.name.c_str()); 72 EXPECT_STREQ(expected.product_name.c_str(), test.product_name.c_str()); 73 EXPECT_STREQ(expected.description.c_str(), test.description.c_str()); 74 EXPECT_STREQ(expected.version.c_str(), test.version.c_str()); 75 EXPECT_STREQ(expected.digital_signer.c_str(), test.digital_signer.c_str()); 76 EXPECT_EQ(expected.recommended_action, test.recommended_action); 77 EXPECT_TRUE(test.normalized); 78 } 79 } 80 81 const ModuleEnumerator::Module kStandardModule = 82 { kType, kStatus, L"c:\\foo\\bar.dll", L"", L"Prod", L"Desc", L"1.0", L"Sig", 83 ModuleEnumerator::NONE }; 84 const ModuleEnumerator::Module kStandardModuleNoDescription = 85 { kType, kStatus, L"c:\\foo\\bar.dll", L"", L"Prod", L"", L"1.0", L"Sig", 86 ModuleEnumerator::NONE }; 87 const ModuleEnumerator::Module kStandardModuleNoSignature = 88 { kType, kStatus, L"c:\\foo\\bar.dll", L"", L"Prod", L"Desc", L"1.0", L"", 89 ModuleEnumerator::NONE }; 90 91 // Name, location, description and signature are compared by hashing. 92 static const char kMatchName[] = "88e8c9e0"; // "bar.dll". 93 static const char kNoMatchName[] = "barfoo.dll"; 94 static const char kMatchLocation[] = "e6ca7b1c"; // "c:\\foo\\". 95 static const char kNoMatchLocation[] = "c:\\foobar\\"; 96 static const char kMatchDesc[] = "5c4419a6"; // "Desc". 97 static const char kNoMatchDesc[] = "NoDesc"; 98 static const char kVersionHigh[] = "2.0"; 99 static const char kVersionLow[] = "0.5"; 100 static const char kMatchSignature[] = "7bfd87e1"; // "Sig". 101 static const char kNoMatchSignature[] = "giS"; 102 static const char kEmpty[] = ""; 103 104 const struct MatchingEntryList { 105 ModuleEnumerator::ModuleStatus expected_result; 106 ModuleEnumerator::Module test_case; 107 ModuleEnumerator::BlacklistEntry blacklist; 108 } kMatchineEntryList[] = { 109 // Each BlacklistEntry is: 110 // Filename, location, desc_or_signer, version from, version to, help_tip. 111 112 { // Matches: Name (location doesn't match) => Not enough for a match. 113 ModuleEnumerator::NOT_MATCHED, 114 kStandardModule, 115 { kMatchName, kNoMatchLocation, kEmpty, kEmpty, kEmpty, kOs, 116 ModuleEnumerator::SEE_LINK } 117 }, { // Matches: Name (location not given) => Suspected match. 118 ModuleEnumerator::SUSPECTED_BAD, 119 kStandardModule, 120 { kMatchName, kEmpty, kEmpty, kEmpty, kEmpty, kOs, 121 ModuleEnumerator::SEE_LINK } 122 }, { // Matches: Name, not version (location not given) => Not a match. 123 ModuleEnumerator::NOT_MATCHED, 124 kStandardModule, 125 { kMatchName, kEmpty, kEmpty, kVersionHigh, kVersionHigh, kOs, 126 ModuleEnumerator::SEE_LINK } 127 }, { // Matches: Name, location => Suspected match. 128 ModuleEnumerator::SUSPECTED_BAD, 129 kStandardModule, 130 { kMatchName, kMatchLocation, kEmpty, kEmpty, kEmpty, kOs, 131 ModuleEnumerator::SEE_LINK } 132 }, { // Matches: Name, location, (description not given) => Confirmed match. 133 ModuleEnumerator::CONFIRMED_BAD, 134 kStandardModuleNoDescription, // Note: No description. 135 { kMatchName, kMatchLocation, kEmpty, kEmpty, kEmpty, kOs, 136 ModuleEnumerator::SEE_LINK } 137 }, { // Matches: Name, location, (signature not given) => Confirmed match. 138 ModuleEnumerator::CONFIRMED_BAD, 139 kStandardModuleNoSignature, // Note: No signature. 140 { kMatchName, kMatchLocation, kEmpty, kEmpty, kEmpty, kOs, 141 ModuleEnumerator::SEE_LINK } 142 }, { // Matches: Name, location (not version) => Not a match. 143 ModuleEnumerator::NOT_MATCHED, 144 kStandardModule, 145 { kMatchName, kMatchLocation, kEmpty, kVersionHigh, kVersionLow, kOs, 146 ModuleEnumerator::SEE_LINK } 147 }, { // Matches: Name, location, signature => Confirmed match. 148 ModuleEnumerator::CONFIRMED_BAD, 149 kStandardModule, 150 { kMatchName, kMatchLocation, kMatchSignature, kEmpty, kEmpty, kOs, 151 ModuleEnumerator::SEE_LINK } 152 }, { // Matches: Name, location, signature (not version) => No match. 153 ModuleEnumerator::NOT_MATCHED, 154 kStandardModule, 155 { kMatchName, kMatchLocation, kMatchSignature, 156 kVersionLow, kVersionLow, kOs, ModuleEnumerator::SEE_LINK } 157 }, { // Matches: Name, location, description => Confirmed match. 158 ModuleEnumerator::CONFIRMED_BAD, 159 kStandardModule, 160 { kMatchName, kMatchLocation, kMatchDesc, kEmpty, kEmpty, kOs, 161 ModuleEnumerator::SEE_LINK } 162 }, { // Matches: Name, location, description (not version) => No match. 163 ModuleEnumerator::NOT_MATCHED, 164 kStandardModule, 165 { kMatchName, kMatchLocation, kMatchDesc, 166 kVersionHigh, kVersionHigh, kOs, ModuleEnumerator::SEE_LINK } 167 }, { // Matches: Name, location, signature, version => Confirmed match. 168 ModuleEnumerator::CONFIRMED_BAD, 169 kStandardModule, 170 { kMatchName, kMatchLocation, kMatchSignature, 171 kVersionLow, kVersionHigh, kOs, ModuleEnumerator::SEE_LINK } 172 }, { // Matches: Name, location, signature, version (lower) => Confirmed. 173 ModuleEnumerator::CONFIRMED_BAD, 174 kStandardModule, 175 { kMatchName, kMatchLocation, kMatchSignature, 176 kVersionLow, kEmpty, kOs, ModuleEnumerator::SEE_LINK } 177 }, { // Matches: Name, location, signature, version (upper) => Confirmed. 178 ModuleEnumerator::CONFIRMED_BAD, 179 kStandardModule, 180 { kMatchName, kMatchLocation, kMatchSignature, 181 kEmpty, kVersionHigh, kOs, ModuleEnumerator::SEE_LINK } 182 }, { // Matches: Name, Location, Version lower is inclusive => Confirmed. 183 ModuleEnumerator::CONFIRMED_BAD, 184 kStandardModule, 185 { kMatchName, kMatchLocation, kMatchSignature, 186 "1.0", "2.0", kOs, ModuleEnumerator::SEE_LINK } 187 }, { // Matches: Name, Location, Version higher is exclusive => No match. 188 ModuleEnumerator::NOT_MATCHED, 189 kStandardModule, 190 { kMatchName, kMatchLocation, kEmpty, 191 "0.0", "1.0", kOs, ModuleEnumerator::SEE_LINK } 192 }, { // All empty fields doesn't produce a match. 193 ModuleEnumerator::NOT_MATCHED, 194 { kType, kStatus, L"", L"", L"", L"", L""}, 195 { "a.dll", "", "", "", "", kOs, ModuleEnumerator::SEE_LINK } 196 }, 197 }; 198 199 TEST_F(EnumerateModulesTest, MatchFunction) { 200 for (size_t i = 0; i < arraysize(kMatchineEntryList); ++i) { 201 ModuleEnumerator::Module test = kMatchineEntryList[i].test_case; 202 ModuleEnumerator::NormalizeModule(&test); 203 ModuleEnumerator::BlacklistEntry blacklist = 204 kMatchineEntryList[i].blacklist; 205 206 SCOPED_TRACE("Test case no " + base::IntToString(i) + 207 ": '" + base::UTF16ToASCII(test.name) + "'"); 208 EXPECT_EQ(kMatchineEntryList[i].expected_result, 209 ModuleEnumerator::Match(test, blacklist)); 210 } 211 } 212 213 const struct CollapsePathList { 214 base::string16 expected_result; 215 base::string16 test_case; 216 } kCollapsePathList[] = { 217 // Negative testing (should not collapse this path). 218 { base::ASCIIToUTF16("c:\\a\\a.dll"), base::ASCIIToUTF16("c:\\a\\a.dll") }, 219 // These two are to test that we select the maximum collapsed path. 220 { base::ASCIIToUTF16("%foo%\\a.dll"), base::ASCIIToUTF16("c:\\foo\\a.dll") }, 221 { base::ASCIIToUTF16("%x%\\a.dll"), 222 base::ASCIIToUTF16("c:\\foo\\bar\\a.dll") }, 223 }; 224 225 TEST_F(EnumerateModulesTest, CollapsePath) { 226 scoped_refptr<ModuleEnumerator> module_enumerator(new ModuleEnumerator(NULL)); 227 module_enumerator->path_mapping_.clear(); 228 module_enumerator->path_mapping_.push_back( 229 std::make_pair(L"c:\\foo\\", L"%foo%")); 230 module_enumerator->path_mapping_.push_back( 231 std::make_pair(L"c:\\foo\\bar\\", L"%x%")); 232 233 for (size_t i = 0; i < arraysize(kCollapsePathList); ++i) { 234 ModuleEnumerator::Module module; 235 module.location = kCollapsePathList[i].test_case; 236 module_enumerator->CollapsePath(&module); 237 238 SCOPED_TRACE("Test case no " + base::IntToString(i) + ": '" + 239 base::UTF16ToASCII(kCollapsePathList[i].expected_result) + 240 "'"); 241 EXPECT_EQ(kCollapsePathList[i].expected_result, module.location); 242 } 243 } 244