File indexing completed on 2024-11-17 04:55:14

0001 /* This Source Code Form is subject to the terms of the Mozilla Public
0002  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
0003  * You can obtain one at http://mozilla.org/MPL/2.0/. */
0004 /* global describe, before, it */
0005 
0006 const assert = require('assert')
0007 const { AdBlockClient } = require('../..')
0008 const { FilterOptions } = require('../..')
0009 
0010 describe('matching', function () {
0011   describe('strange rules', function () {
0012     it('can start with a slash', function () {
0013       const client = new AdBlockClient()
0014       client.parse('/banner1.gif\n')
0015       assert(client.matches('http://www.brianbondy.com/public/banner1.gif', FilterOptions.image, 'slashdot.org'))
0016       assert(client.matches('http://www.brianbondy.com/public//banner1.gif', FilterOptions.image, 'slashdot.org'))
0017       assert(!client.matches('http://www.brianbondy.com/public/abanner1.gif', FilterOptions.image, 'slashdot.org'))
0018     })
0019 
0020     it('can start with a star', function () {
0021       const client = new AdBlockClient()
0022       client.parse('*/b/ss/*&aqe=$image,redirect=1x1-transparent.gif\n')
0023       assert(!client.matches('https://i.ytimg.com/vi/hxUAntt1z2c/hqdefault.jpg?custom=true&w=320&h=180&stc=true&jpg444=true&jpgq=90&sp=68&sigh=YNApXAOpSSoeEmCpXSLQwjnOdwY', FilterOptions.image, 'slashdot.org'))
0024       assert(client.matches('https://i.ytimg.com/b/ss/hxUAntt1z2c/hqdefault.jpg?a&aqe=$image,redirect=1x1-transparent.gif&dd', FilterOptions.image, 'slashdot.org'))
0025       assert(client.matches('https://i.ytimg.com/a/b/ss/hxUAntt1z2c/hqdefault.jpg?a&aqe=$image,redirect=1x1-transparent.gif&dd', FilterOptions.image, 'slashdot.org'))
0026       assert(!client.matches('https://i.ytimg.com/b/a/ss/hxUAntt1z2c/hqdefault.jpg?a&aqe=$image,redirect=1x1-transparent.gif&dd', FilterOptions.image, 'slashdot.org'))
0027     })
0028     it('can start with multiple stars', function () {
0029       const client = new AdBlockClient()
0030       client.parse('***/b/ss/*&aqe=$image,redirect=1x1-transparent.gif\n')
0031       assert(!client.matches('https://i.ytimg.com/vi/hxUAntt1z2c/hqdefault.jpg?custom=true&w=320&h=180&stc=true&jpg444=true&jpgq=90&sp=68&sigh=YNApXAOpSSoeEmCpXSLQwjnOdwY', FilterOptions.image, 'slashdot.org'))
0032       assert(client.matches('https://i.ytimg.com/b/ss/hxUAntt1z2c/hqdefault.jpg?a&aqe=$image,redirect=1x1-transparent.gif&dd', FilterOptions.image, 'slashdot.org'))
0033       assert(client.matches('https://i.ytimg.com/a/b/ss/hxUAntt1z2c/hqdefault.jpg?a&aqe=$image,redirect=1x1-transparent.gif&dd', FilterOptions.image, 'slashdot.org'))
0034       assert(!client.matches('https://i.ytimg.com/b/a/ss/hxUAntt1z2c/hqdefault.jpg?a&aqe=$image,redirect=1x1-transparent.gif&dd', FilterOptions.image, 'slashdot.org'))
0035     })
0036     it('can have multiple stars in the middle', function () {
0037       const client = new AdBlockClient()
0038       client.parse('a/********b\n')
0039       assert(client.matches('https://i.ytimg.com/a/d/e/f/b', FilterOptions.noFilterOption, 'slashdot.org'))
0040       assert(client.matches('https://i.ytimg.com/a/d/e/fb', FilterOptions.noFilterOption, 'slashdot.org'))
0041       assert(!client.matches('https://i.ytimg.com/a/d/e/fd', FilterOptions.noFilterOption, 'slashdot.org'))
0042     })
0043     it('can block everything with a single *', function () {
0044       const client = new AdBlockClient()
0045       client.parse('*')
0046       assert(client.matches('https://brianbondy.com/d', FilterOptions.noFilterOption, 'slashdot.org'))
0047       assert(client.matches('https://brianbondy.com', FilterOptions.noFilterOption, 'slashdot.org'))
0048     })
0049     it('can have no rule data', function () {
0050       const client = new AdBlockClient()
0051       client.parse('')
0052       assert(!client.matches('https://brianbondy.com/d', FilterOptions.noFilterOption, 'slashdot.org'))
0053       assert(!client.matches('https://brianbondy.com', FilterOptions.noFilterOption, 'slashdot.org'))
0054     })
0055     it('can have rule data with just a ^', function () {
0056       const client = new AdBlockClient()
0057       client.parse('^')
0058       assert(!client.matches('https://brianbondy.com', FilterOptions.noFilterOption, 'slashdot.org'))
0059       assert(!client.matches('https://brianbondy.com', FilterOptions.noFilterOption, 'slashdot.org'))
0060     })
0061   })
0062   describe('host anchored exception with matching first party exception', function () {
0063     before(function () {
0064       this.client = new AdBlockClient()
0065       this.client.parse('-google-analytics.\n@@||www.scrumpoker.online^$~third-party')
0066     })
0067     it('does not match', function () {
0068       assert(!this.client.matches('https://www.scrumpoker.online/js/angular-google-analytics.js', FilterOptions.script, 'www.scrumpoker.online'))
0069     })
0070     it('detects as a hash set save', function () {
0071       assert.strictEqual(this.client.getMatchingStats().numExceptionHashSetSaves, 1)
0072     })
0073   })
0074   describe('domain only host anchored filters', function () {
0075     before(function () {
0076       this.client = new AdBlockClient()
0077       this.client.parse('||imasdk.googleapis.com^$third-party\n@@||imasdk.googleapis.com/js/sdkloader/ima3.js$domain=cbc.ca|cbsnews.com|cbssports.com')
0078       const data = this.client.serialize()
0079       this.client2 = new AdBlockClient()
0080       this.client2.deserialize(data)
0081       // Just to make sure things work properly with repeated deserializes
0082       this.client2.deserialize(data)
0083     })
0084     it('should match exception filter from normal parsed list', function () {
0085       assert(!this.client2.matches('https://imasdk.googleapis.com/js/sdkloader/ima3.js?v=1.0fc2a9c5e010611944b364a71d43c8b5099f209f', FilterOptions.script, 'www.cbsnews.com'))
0086     })
0087     it('should match exception filter from deserialized list', function () {
0088       assert(!this.client.matches('https://imasdk.googleapis.com/js/sdkloader/ima3.js?v=1.0fc2a9c5e010611944b364a71d43c8b5099f209f', FilterOptions.script, 'www.cbsnews.com'))
0089     })
0090   })
0091   describe('host anchored exception with not matching first party exception', function () {
0092     before(function () {
0093       this.client = new AdBlockClient()
0094       this.client.parse('-google-analytics.\n@@||www.scrumpoker.online^$~third-party')
0095     })
0096     it('does match', function () {
0097       assert(this.client.matches('https://www.scrumpoker.online/js/angular-google-analytics.js', FilterOptions.script, 'www.brianbondy.com'))
0098     })
0099     it('detects as a hash set save', function () {
0100       assert.strictEqual(this.client.getMatchingStats().numExceptionHashSetSaves, 1)
0101     })
0102   })
0103   describe('no-fingerprint rules', function () {
0104     it('can match against a no-fingerprint rule', function () {
0105       const client = new AdBlockClient()
0106       client.parse('adv')
0107       assert(client.matches('https://brianbondy.com/adv', FilterOptions.noFilterOption, 'slashdot.org'))
0108       assert(!client.matches('https://brianbondy.com/omg', FilterOptions.noFilterOption, 'slashdot.org'))
0109     })
0110     it('can match against a no-fingerprint domain only rule', function () {
0111       const client = new AdBlockClient()
0112       client.parse('adv$domain=brianbondy.com')
0113       assert(client.matches('https://brianbondy.com/adv', FilterOptions.noFilterOption, 'brianbondy.com'))
0114       assert(client.matches('https://digg.com/adv', FilterOptions.noFilterOption, 'brianbondy.com'))
0115       assert(!client.matches('https://digg.com/adv', FilterOptions.noFilterOption, 'slashdot.org'))
0116       assert(!client.matches('https://brianbondy.com/adv', FilterOptions.noFilterOption, 'digg.com'))
0117     })
0118     it('can match against a no-fingerprint anti-domain only rule', function () {
0119       const client = new AdBlockClient()
0120       client.parse('adv$domain=~brianbondy.com')
0121       assert(!client.matches('https://brianbondy.com/adv', FilterOptions.noFilterOption, 'brianbondy.com'))
0122       assert(!client.matches('https://digg.com/adv', FilterOptions.noFilterOption, 'brianbondy.com'))
0123       assert(client.matches('https://digg.com/adv', FilterOptions.noFilterOption, 'slashdot.org'))
0124       assert(client.matches('https://brianbondy.com/adv', FilterOptions.noFilterOption, 'digg.com'))
0125     })
0126     it('can match against a no-fingerprint domain only exception rule', function () {
0127       const client = new AdBlockClient()
0128       client.parse('adv\n@@adv$domain=brianbondy.com')
0129       assert(!client.matches('https://brianbondy.com/adv', FilterOptions.noFilterOption, 'brianbondy.com'))
0130       assert(!client.matches('https://digg.com/adv', FilterOptions.noFilterOption, 'brianbondy.com'))
0131       assert(client.matches('https://digg.com/adv', FilterOptions.noFilterOption, 'slashdot.org'))
0132       assert(client.matches('https://brianbondy.com/adv', FilterOptions.noFilterOption, 'digg.com'))
0133     })
0134   })
0135   describe('findMatchingFilters return values', function () {
0136     before(function () {
0137       this.client = new AdBlockClient()
0138       this.client.parse('/pubads_\n@@||fastly.net/ad2/$image,script,xmlhttprequest\n.net/ad2/\n@@||fastly.net/ad2/$image,script,xmlhttprequest')
0139     })
0140     it('match', function () {
0141       const queryResult = this.client.findMatchingFilters('https://securepubads.g.doubleclick.net/gpt/pubads_impl_rendering_193.js?cb=194', FilterOptions.script, 'www.cnn.com')
0142       assert.strictEqual(queryResult.matches, true)
0143       assert.strictEqual(queryResult.matchingFilter, '/pubads_')
0144     })
0145     it('miss', function () {
0146       const queryResult = this.client.findMatchingFilters('https://cdn.cnn.com/cnn/.e1mo/img/4.0/logos/menu_entertainment.png', FilterOptions.image, 'www.cnn.com')
0147       assert.strictEqual(queryResult.matches, false)
0148     })
0149     it('whitelisted', function () {
0150       const queryResult = this.client.findMatchingFilters('https://0914.global.ssl.fastly.net/ad2/script/x.js?cb=1523383475084', FilterOptions.script, 'www.cnn.com')
0151       assert.strictEqual(queryResult.matches, false)
0152       assert.strictEqual(queryResult.matchingFilter, '.net/ad2/')
0153       assert.strictEqual(queryResult.matchingExceptionFilter, 'fastly.net/ad2/')
0154     })
0155   })
0156 
0157   describe('original filter rules', function () {
0158     describe('returning original filter rule', function () {
0159       before(function () {
0160         this.client = new AdBlockClient()
0161         const rules = [
0162           '-google-analytics.',
0163           '@@||www.scrumpoker.online^$~third-party',
0164           '.net/ad',
0165           '@@||fastly.net/ad2/$image,script,xmlhttprequest'
0166         ]
0167         this.client.parse(rules.join('\n'), true)
0168       })
0169       it('match rule returned', function () {
0170         const queryResult = this.client.findMatchingFilters('https://www.scrumpoker.online/js/angular-google-analytics.js', FilterOptions.script, 'www.scrumpoker.online')
0171         assert.strictEqual(queryResult.matchingOrigRule, '-google-analytics.')
0172       })
0173       it('exception rule returned', function () {
0174         const queryResult = this.client.findMatchingFilters('https://www.scrumpoker.online/js/angular-google-analytics.js', FilterOptions.script, 'www.scrumpoker.online')
0175         assert.strictEqual(queryResult.matchingExceptionOrigRule, '@@||www.scrumpoker.online^$~third-party')
0176       })
0177       it('rules with multiple options', function () {
0178         const queryResult = this.client.findMatchingFilters('https://0914.global.ssl.fastly.net/ad2/img/x.gif?cb=1523404173915', FilterOptions.image, 'www.cnn.com')
0179         assert.strictEqual(queryResult.matches, false)
0180         assert.strictEqual(queryResult.matchingOrigRule, '.net/ad')
0181         assert.strictEqual(queryResult.matchingExceptionOrigRule, '@@||fastly.net/ad2/$image,script,xmlhttprequest')
0182       })
0183     })
0184     describe('do not return original filter text when not needed / requested', function () {
0185       before(function () {
0186         this.client = new AdBlockClient()
0187         const rules = [
0188           '-google-analytics.',
0189           '@@||www.scrumpoker.online^$~third-party',
0190           '.net/ad',
0191           '@@||fastly.net/ad2/$image,script,xmlhttprequest'
0192         ]
0193         this.client.parse(rules.join('\n')) // <- since not "true", then no rule data should be preserved
0194       })
0195       it('match rule returned', function () {
0196         const queryResult = this.client.findMatchingFilters('https://www.scrumpoker.online/js/angular-google-analytics.js', FilterOptions.script, 'www.scrumpoker.online')
0197         assert.strictEqual(queryResult.matchingOrigRule, undefined)
0198       })
0199       it('exception rule returned', function () {
0200         const queryResult = this.client.findMatchingFilters('https://www.scrumpoker.online/js/angular-google-analytics.js', FilterOptions.script, 'www.brianbondy.com')
0201         assert.strictEqual(queryResult.matchingExceptionOrigRule, undefined)
0202       })
0203       it('rules with multiple options', function () {
0204         const queryResult = this.client.findMatchingFilters('https://0914.global.ssl.fastly.net/ad2/img/x.gif?cb=1523404173915', FilterOptions.image, 'www.cnn.com')
0205         assert.strictEqual(queryResult.matches, false)
0206         assert.strictEqual(queryResult.matchingOrigRule, undefined)
0207         assert.strictEqual(queryResult.matchingExceptionOrigRule, undefined)
0208       })
0209     })
0210   })
0211 
0212   describe('Filters with unknown options are ignored', function () {
0213     it('known unsupported options are not blocked', function () {
0214       const client = new AdBlockClient()
0215       client.parse('adv$ping')
0216       assert(!client.matches('https://brianbondy.com/adv', FilterOptions.noFilterOption, 'slashdot.org'))
0217     })
0218     it('CSPs are ignored', function () {
0219       const client = new AdBlockClient()
0220       client.parse('adv$csp=script-src \'self\' \'unsafe-inline\' \'unsafe-eval\' data: *.google.com *.gstatic.com *.google-analytics.com')
0221       assert(!client.matches('!https://brianbondy.com/adv', FilterOptions.noFilterOption, 'slashdot.org'))
0222     })
0223     it('unknown unsupported options are not blocked', function () {
0224       const client = new AdBlockClient()
0225       client.parse('adv$somethingnew=3')
0226       assert(!client.matches('https://brianbondy.com/adv', FilterOptions.noFilterOption, 'slashdot.org'))
0227     })
0228     it('redirects are still blocked', function () {
0229       const client = new AdBlockClient()
0230       client.parse('adv$image,redirect=1x1-transparent.gif&dd')
0231       assert(client.matches('https://brianbondy.com/adv', FilterOptions.image, 'slashdot.org'))
0232     })
0233   })
0234   describe('Type option matching', function () {
0235     describe('font', function () {
0236       it('option matches for no resource type filters', function () {
0237         const client = new AdBlockClient()
0238         client.parse('adv')
0239         assert(client.matches('https://brianbondy.com/adv', FilterOptions.font, 'slashdot.org'))
0240       })
0241       it('option matches for same resource type', function () {
0242         const client = new AdBlockClient()
0243         client.parse('adv$font')
0244         assert(client.matches('https://brianbondy.com/adv', FilterOptions.font, 'slashdot.org'))
0245       })
0246       it('doesn\'t matche when resource type differs', function () {
0247         const client = new AdBlockClient()
0248         client.parse('adv$font')
0249         assert(!client.matches('https://brianbondy.com/adv', FilterOptions.image, 'slashdot.org'))
0250       })
0251       it('option matches for same resource type for rule with multiple types', function () {
0252         const client = new AdBlockClient()
0253         client.parse('adv$font,image,script')
0254         assert(client.matches('https://brianbondy.com/adv', FilterOptions.font, 'slashdot.org'))
0255       })
0256       it('option matches for rule without options', function () {
0257         const client = new AdBlockClient()
0258         client.parse('adv')
0259         assert(client.matches('https://brianbondy.com/adv', FilterOptions.font, 'slashdot.org'))
0260       })
0261     })
0262     describe('other', function () {
0263       it('option matches for rule without options', function () {
0264         const client = new AdBlockClient()
0265         client.parse('adv')
0266         assert(client.matches('https://brianbondy.com/adv', FilterOptions.other, 'slashdot.org'))
0267       })
0268     })
0269     describe('document', function () {
0270       it('should not match when filter rule has no type', function () {
0271         const client = new AdBlockClient()
0272         client.parse('adv')
0273         assert(!client.matches('https://brianbondy.com/adv', FilterOptions.document, 'slashdot.org'))
0274       })
0275       it('should not match when filter rule is an image', function () {
0276         const client = new AdBlockClient()
0277         client.parse('adv$image')
0278         assert(!client.matches('https://brianbondy.com/adv', FilterOptions.document, 'slashdot.org'))
0279       })
0280       it('should match when filter rule is a document', function () {
0281         const client = new AdBlockClient()
0282         client.parse('adv$document')
0283         assert(client.matches('https://brianbondy.com/adv', FilterOptions.document, 'slashdot.org'))
0284       })
0285       it('filter rule that is for documents should not match other types', function () {
0286         const client = new AdBlockClient()
0287         client.parse('adv$document')
0288         assert(!client.matches('https://brianbondy.com/adv', FilterOptions.other, 'slashdot.org'))
0289       })
0290     })
0291     describe('noFilterOption', function () {
0292       it('should not match when filter rule has no resource type', function () {
0293         const client = new AdBlockClient()
0294         client.parse('adv')
0295         assert(client.matches('https://brianbondy.com/adv', FilterOptions.noFilterOption, 'slashdot.org'))
0296       })
0297       it('should not match when filter rule has a resource type', function () {
0298         const client = new AdBlockClient()
0299         client.parse('adv$image')
0300         assert(!client.matches('https://brianbondy.com/adv', FilterOptions.noFilterOption, 'slashdot.org'))
0301       })
0302     })
0303   })
0304   describe('left anchored exception filter', function () {
0305     describe('simple block match', function () {
0306       before(function () {
0307         this.client = new AdBlockClient()
0308         this.client.parse('|http://baddomain.example/')
0309       })
0310       it('matches exactly from the left', function () {
0311         assert(this.client.matches('http://baddomain.example/banner.gif', FilterOptions.image, 'http://baddomain.example/'))
0312       })
0313       it('does not match if scheme does not match', function () {
0314         assert(!this.client.matches('https://baddomain.example/banner.gif', FilterOptions.image, 'http://baddomain.example/'))
0315       })
0316       it('does not match not at start', function () {
0317         assert(!this.client.matches('http://gooddomain.example/analyze?http://baddomain.example', FilterOptions.image, 'http://baddomain.example/'))
0318       })
0319     })
0320   })
0321   describe('domain filtered rules', function () {
0322     describe('All exclude domain rules', function () {
0323       before(function () {
0324         this.client = new AdBlockClient()
0325         this.client.parse('wp-content/$domain=~aaaaa.com|~bbbbb.com|~ccccc.com')
0326       })
0327 
0328       it('filter has all anti domains but with different input domain should block', function () {
0329         assert(this.client.matches('https://www.sportsnet.ca/wp-content/plugins',
0330           FilterOptions.image, 'www.brianbondy.com'))
0331       })
0332       it('filter has all anti domains and with a same input domain should not block', function () {
0333         assert(!this.client.matches('https://www.sportsnet.ca/wp-content/plugins',
0334           FilterOptions.image, 'aaaaa.com'))
0335       })
0336     })
0337     describe('All include domain rules', function () {
0338       before(function () {
0339         this.client = new AdBlockClient()
0340         this.client.parse('wp-content/$domain=aaaaa.com|bbbbb.com|ccccc.com')
0341       })
0342       it('filter has all anti=false domains but with different input domain should not block', function () {
0343         assert(!this.client.matches('https://www.sportsnet.ca/wp-content/plugins',
0344           FilterOptions.image, 'www.brianbondy.com'))
0345       })
0346       it('filter has all anti=false domains and with a same domain should not block', function () {
0347         assert(this.client.matches('https://www.sportsnet.ca/wp-content/plugins',
0348           FilterOptions.image, 'aaaaa.com'))
0349       })
0350     })
0351     describe('Rule with blocking parent domain and subdomain which is allowed', function () {
0352       before(function () {
0353         this.client = new AdBlockClient()
0354         this.client.parse('wp-content/$domain=example.com|~foo.example.com|x.com|y.com|z.com')
0355       })
0356       it('for test URL of unrelated domain should not match', function () {
0357         assert(!this.client.matches('https://www.sportsnet.ca/wp-content/plugins',
0358           FilterOptions.image, 'brianbondy.com'))
0359       })
0360       it('for test URL of parent should block', function () {
0361         assert(this.client.matches('https://www.sportsnet.ca/wp-content/plugins',
0362           FilterOptions.image, 'example.com'))
0363       })
0364       it('for test URL of subdomain should allow', function () {
0365         assert(!this.client.matches('https://www.sportsnet.ca/wp-content/plugins',
0366           FilterOptions.image, 'foo.example.com'))
0367       })
0368       it('for test URL of deeper subdomain should allow', function () {
0369         assert(!this.client.matches('https://www.sportsnet.ca/wp-content/plugins',
0370           FilterOptions.image, 'boo.foo.example.com'))
0371       })
0372       it('for test URL of subdomain of top level rule should block', function () {
0373         assert(this.client.matches('https://www.sportsnet.ca/wp-content/plugins',
0374           FilterOptions.image, 'boo.example.com'))
0375       })
0376     })
0377     describe('Rule with anti-block parent domain and subdomain which is blocked', function () {
0378       before(function () {
0379         this.client = new AdBlockClient()
0380         this.client.parse('wp-content/$domain=~example.com|foo.example.com|x.com|z.com|y.com')
0381       })
0382       it('for test URL of unrelated domain should not match', function () {
0383         assert(!this.client.matches('https://www.sportsnet.ca/wp-content/plugins',
0384           FilterOptions.image, 'brianbondy.com'))
0385       })
0386       it('for test URL of parent should not block', function () {
0387         assert(!this.client.matches('https://www.sportsnet.ca/wp-content/plugins',
0388           FilterOptions.image, 'example.com'))
0389       })
0390       it('for test URL of subdomain should block', function () {
0391         assert(this.client.matches('https://www.sportsnet.ca/wp-content/plugins',
0392           FilterOptions.image, 'foo.example.com'))
0393       })
0394       it('for test URL of deeper subdomain should block', function () {
0395         assert(this.client.matches('https://www.sportsnet.ca/wp-content/plugins',
0396           FilterOptions.image, 'boo.foo.example.com'))
0397       })
0398       it('for test URL of subdomain of top level rule should allow', function () {
0399         assert(!this.client.matches('https://www.sportsnet.ca/wp-content/plugins',
0400           FilterOptions.image, 'boo.example.com'))
0401       })
0402     })
0403 
0404     describe('Three level deep rules', function () {
0405       before(function () {
0406         this.client = new AdBlockClient()
0407         this.client.parse('wp-content/$domain=example.com|~brave.example.com|foo.brave.example.com')
0408       })
0409       it('for test URL of unrelated domain should not match', function () {
0410         assert(!this.client.matches('https://www.sportsnet.ca/wp-content/plugins',
0411           FilterOptions.image, 'brianbondy.com'))
0412       })
0413       it('for test URL of parent should block', function () {
0414         assert(this.client.matches('https://www.sportsnet.ca/wp-content/plugins',
0415           FilterOptions.image, 'example.com'))
0416       })
0417       it('for test URL of exception subdomain should allow', function () {
0418         assert(!this.client.matches('https://www.sportsnet.ca/wp-content/plugins',
0419           FilterOptions.image, 'brave.example.com'))
0420       })
0421       it('for test URL of deeper subdomain should block', function () {
0422         assert(this.client.matches('https://www.sportsnet.ca/wp-content/plugins',
0423           FilterOptions.image, 'foo.brave.example.com'))
0424       })
0425     })
0426     describe('Three level deep rules reversed', function () {
0427       before(function () {
0428         this.client = new AdBlockClient()
0429         this.client.parse('wp-content/$domain=~example.com|brave.example.com|~foo.brave.example.com')
0430       })
0431       it('for test URL of unrelated domain should not match since there is a blocking domain', function () {
0432         assert(!this.client.matches('https://www.sportsnet.ca/wp-content/plugins',
0433           FilterOptions.image, 'brianbondy.com'))
0434       })
0435       it('for test URL of parent should allow', function () {
0436         assert(!this.client.matches('https://www.sportsnet.ca/wp-content/plugins',
0437           FilterOptions.image, 'example.com'))
0438       })
0439       it('for test URL of exception subdomain should block', function () {
0440         assert(this.client.matches('https://www.sportsnet.ca/wp-content/plugins',
0441           FilterOptions.image, 'brave.example.com'))
0442       })
0443       it('for test URL of deeper subdomain should allow', function () {
0444         assert(!this.client.matches('https://www.sportsnet.ca/wp-content/plugins',
0445           FilterOptions.image, 'foo.brave.example.com'))
0446       })
0447     })
0448 
0449     describe('first-party host', function () {
0450       before(function () {
0451         this.client = new AdBlockClient()
0452         this.client.parse('analytics.brave.com^\n@@https://analytics.*/piwik.$~third-party')
0453       })
0454       it('for same host finds exception', function () {
0455         assert(!this.client.matches('https://analytics.brave.com/piwik.js',
0456           FilterOptions.image, 'analytics.brave.com'))
0457       })
0458       it('for same diff host does not find exception', function () {
0459         assert(this.client.matches('https://analytics.brave.com/piwik.js',
0460           FilterOptions.image, 'batcommunity.org'))
0461       })
0462       it('findMatchingFilters for same host finds exception', function () {
0463         const queryResult = this.client.findMatchingFilters('https://analytics.brave.com/piwik.js', FilterOptions.script, 'analytics.brave.com')
0464         assert.strictEqual(queryResult.matches, false)
0465         assert.strictEqual(queryResult.matchingFilter, 'analytics.brave.com^')
0466         assert.strictEqual(queryResult.matchingExceptionFilter, 'https://analytics.*/piwik.')
0467       })
0468       it('findMatchingFilters for same diff host does not find exception', function () {
0469         const queryResult = this.client.findMatchingFilters('https://analytics.brave.com/piwik.js', FilterOptions.script, 'batcommunity.org')
0470         assert.strictEqual(queryResult.matches, true)
0471         assert.strictEqual(queryResult.matchingFilter, 'analytics.brave.com^')
0472       })
0473     })
0474 
0475     describe('CSP rules', function () {
0476       before(function () {
0477         this.client = new AdBlockClient()
0478         this.client.parse('||merriam-webster.com^$csp=script-src "self" * "unsafe-inline"')
0479       })
0480       it('do not match since they are unsupported', function () {
0481         assert(!this.client.matches('https://www.merriam-webster.com/assets/test.min.css',
0482           FilterOptions.image, 'www.merriam-webster.com'))
0483       })
0484     })
0485   })
0486 })