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 }