File indexing completed on 2024-11-24 04:54:32
0001 /* 0002 SPDX-License-Identifier: MPL-2.0 0003 */ 0004 0005 /* Copyright (c) 2015 Brian R. Bondy. Distributed under the MPL2 license. 0006 * This Source Code Form is subject to the terms of the Mozilla Public 0007 * License, v. 2.0. If a copy of the MPL was not distributed with this 0008 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 0009 0010 #include <string.h> 0011 #include <fstream> 0012 #include <sstream> 0013 #include <string> 0014 #include <algorithm> 0015 #include <cerrno> 0016 #include <iostream> 0017 #include <set> 0018 #include "./CppUnitLite/TestHarness.h" 0019 #include "./ad_block_client.h" 0020 #include "./util.h" 0021 0022 using std::set; 0023 using std::string; 0024 using std::cout; 0025 using std::endl; 0026 0027 void printSet(const set<string> &domainSet) { 0028 std::for_each(domainSet.begin(), domainSet.end(), [](string const &s) { 0029 cout << s.c_str() << " "; 0030 }); 0031 } 0032 0033 bool testOptionsWithFilter(Filter *f, const char *input, 0034 FilterOption expectedOption, FilterOption expectedAntiOption, 0035 const set<string> &expectedDomains, 0036 const set<string> &expectedAntiDomains) { 0037 if (f->filterOption != expectedOption) { 0038 cout << input << endl << "Actual options: " << f->filterOption 0039 << endl << "Expected: " << expectedOption << endl; 0040 return false; 0041 } 0042 if (f->antiFilterOption != expectedAntiOption) { 0043 cout << input << endl << "Actual anti options: " << f->antiFilterOption 0044 << endl << "Expected: " << expectedAntiOption << endl; 0045 return false; 0046 } 0047 if (expectedDomains.size() > 0 && expectedAntiDomains.size() == 0 && 0048 !f->isDomainOnlyFilter()) { 0049 cout << input << endl << "Domain only filter should be set." 0050 << endl << "Actual domain count: " << f->getDomainCount() 0051 << endl << "Actual anti domain count: " << f->getDomainCount(true) 0052 << endl << "Expected: " << expectedDomains.size() 0053 << endl << "Expected anti: " << expectedAntiDomains.size(); 0054 return false; 0055 } else if ((expectedDomains.size() == 0 || 0056 expectedAntiDomains.size() != 0) && 0057 f->isDomainOnlyFilter()) { 0058 cout << input << endl << "Domain only filter should NOT be set." 0059 << endl << "Actual domain count: " << f->getDomainCount() 0060 << endl << "Actual anti domain count: " << f->getDomainCount(true) 0061 << endl << "Expected: " << expectedDomains.size() 0062 << endl << "Expected anti: " << expectedAntiDomains.size(); 0063 return false; 0064 } 0065 if (expectedDomains.size() != f->getDomainCount()) { 0066 cout << input << endl << "Actual domain count: " << f->getDomainCount() 0067 << endl << "Expected: " << expectedDomains.size() << endl; 0068 return false; 0069 } 0070 if (expectedAntiDomains.size() != f->getDomainCount(true)) { 0071 cout << input << endl << "Actual anti domain count: " 0072 << f->getDomainCount(false) << endl << "Expected: " 0073 << expectedAntiDomains.size() << endl; 0074 return false; 0075 } 0076 0077 bool ret = true; 0078 std::for_each(expectedDomains.begin(), expectedDomains.end(), 0079 [&f, &expectedDomains, &ret, input](string const &s) { 0080 if (!f->containsDomain(s.c_str(), s.size(), false)) { 0081 cout << input << endl << "Actual domains: " 0082 << (f->domainList ? f->domainList : "") << endl << "Expected: "; 0083 printSet(expectedDomains); 0084 cout << endl; 0085 cout << "Not found: " << s.c_str() << endl; 0086 ret = false; 0087 } 0088 }); 0089 if (!ret) { 0090 return false; 0091 } 0092 0093 std::for_each(expectedAntiDomains.begin(), expectedAntiDomains.end(), 0094 [&f, &expectedAntiDomains, &ret, input](string const &s) { 0095 if (!f->containsDomain(s.c_str(), s.size(), true)) { 0096 cout << input << endl << "Actual anti domains: " 0097 << (f->domainList ? f->domainList : "") << endl << "Expected: "; 0098 printSet(expectedAntiDomains); 0099 cout << endl; 0100 ret = false; 0101 } 0102 }); 0103 if (!ret) { 0104 return false; 0105 } 0106 0107 return true; 0108 } 0109 0110 bool testOptions(const char *rawOptions, FilterOption expectedOption, 0111 FilterOption expectedAntiOption, 0112 set<string> &&expectedDomains, // NOLINT 0113 set<string> &&expectedAntiDomains) { // NOLINT 0114 Filter f; 0115 f.parseOptions(rawOptions); 0116 return testOptionsWithFilter(&f, rawOptions, expectedOption, 0117 expectedAntiOption, expectedDomains, expectedAntiDomains); 0118 } 0119 0120 bool testFilterOptions(const char *input, FilterOption expectedOption, 0121 FilterOption expectedAntiOption, 0122 set<string> &&expectedDomains, // NOLINT 0123 set<string> &&expectedAntiDomains) { // NOLINT 0124 Filter f; 0125 parseFilter(input, &f); 0126 return testOptionsWithFilter(&f, input, expectedOption, 0127 expectedAntiOption, expectedDomains, expectedAntiDomains); 0128 } 0129 0130 // Option parsing should split options properly 0131 TEST(options, splitOptions) { 0132 CHECK(testOptions("subdocument,third-party", 0133 static_cast<FilterOption>(FOThirdParty | FOSubdocument), 0134 FONoFilterOption, 0135 {}, 0136 {})); 0137 0138 CHECK(testOptions( 0139 "object-subrequest,script,domain=~msnbc.msn.com|~www.nbcnews.com", 0140 static_cast<FilterOption>(FOObjectSubrequest | FOScript), 0141 FONoFilterOption, 0142 {}, 0143 { 0144 "msnbc.msn.com", 0145 "www.nbcnews.com" 0146 })); 0147 0148 CHECK(testOptions("~document,xbl,domain=~foo|bar|baz|foo.xbl|gar,~collapse", 0149 FOXBL, 0150 static_cast<FilterOption>(FODocument | FOCollapse), 0151 { 0152 "bar", 0153 "baz", 0154 "foo.xbl", 0155 "gar" 0156 }, 0157 { 0158 "foo" 0159 })); 0160 0161 0162 CHECK(testOptions("domain=~example.com|foo.example.com,script", 0163 FOScript, 0164 FONoFilterOption, 0165 { 0166 "foo.example.com" 0167 }, 0168 { 0169 "example.com" 0170 })); 0171 } 0172 0173 // domain rule types should be properly parsed 0174 TEST(options, domainOptionStrings) { 0175 CHECK(testOptions("domain=example.com", 0176 FONoFilterOption, 0177 FONoFilterOption, 0178 { 0179 "example.com" 0180 }, 0181 {})); 0182 0183 CHECK(testOptions("domain=example.com|example.net", 0184 FONoFilterOption, 0185 FONoFilterOption, 0186 { 0187 "example.com", 0188 "example.net" 0189 }, 0190 {})); 0191 0192 CHECK(testOptions("domain=~example.com", 0193 FONoFilterOption, 0194 FONoFilterOption, 0195 { }, 0196 { 0197 "example.com" 0198 })); 0199 0200 CHECK(testOptions("domain=example.com|~foo.example.com", 0201 FONoFilterOption, 0202 FONoFilterOption, 0203 { 0204 "example.com", 0205 }, 0206 { 0207 "foo.example.com" 0208 })); 0209 0210 CHECK(testOptions("domain=~foo.example.com|example.com", 0211 FONoFilterOption, 0212 FONoFilterOption, 0213 { 0214 "example.com", 0215 }, 0216 { 0217 "foo.example.com" 0218 })); 0219 0220 CHECK(testOptions("domain=~msnbc.msn.com|~www.nbcnews.com", 0221 FONoFilterOption, 0222 FONoFilterOption, 0223 { }, 0224 { 0225 "msnbc.msn.com", 0226 "www.nbcnews.com" 0227 })) 0228 } 0229 0230 // parseFilter for full rules properly extracts options 0231 TEST(options, optionsFromFilter) { 0232 CHECK(testFilterOptions("domain=foo.bar", 0233 FONoFilterOption, 0234 FONoFilterOption, 0235 {}, 0236 {})) 0237 0238 CHECK(testFilterOptions("+Ads/$~stylesheet", 0239 FONoFilterOption, 0240 FOStylesheet, 0241 {}, 0242 {})) 0243 0244 CHECK(testFilterOptions("-advertising-$domain=~advertise.bingads.domain.com", 0245 FONoFilterOption, 0246 FONoFilterOption, 0247 { }, 0248 { 0249 "advertise.bingads.domain.com" 0250 })) 0251 0252 CHECK(testFilterOptions(".se/?placement=$script,third-party", 0253 static_cast<FilterOption>(FOScript| FOThirdParty), 0254 FONoFilterOption, 0255 {}, 0256 {})) 0257 0258 CHECK(testFilterOptions("https:$ping", 0259 static_cast<FilterOption>(FOPing), 0260 FONoFilterOption, 0261 {}, 0262 {})) 0263 0264 CHECK(testFilterOptions("https:$popup", 0265 static_cast<FilterOption>(FOPopup), 0266 FONoFilterOption, 0267 {}, 0268 {})) 0269 0270 CHECK(testFilterOptions( 0271 "||tst.net^$object-subrequest,third-party,domain=domain1.com|domain5.com", 0272 static_cast<FilterOption>(FOObjectSubrequest | FOThirdParty), 0273 FONoFilterOption, 0274 { 0275 "domain1.com", 0276 "domain5.com" 0277 }, 0278 {})) 0279 }