Skip to content

Commit 950c212

Browse files
committed
Add tests against non-match groups being used in replacements (resolves EFForg#4327)
1 parent 2fdd1d2 commit 950c212

File tree

3 files changed

+48
-12
lines changed

3 files changed

+48
-12
lines changed

test/rules/coverage.checker.config

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
[rulesets]
55
rulesdir = src/chrome/content/rules
66
check_coverage = true
7+
check_nonmatch_groups = true
78
include_default_off = false
89
skiplist = utils/ruleset-coverage-whitelist.txt
910

test/rules/src/https_everywhere_checker/check_rules.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,9 @@ def cli():
279279
checkCoverage = False
280280
if config.has_option("rulesets", "check_coverage"):
281281
checkCoverage = config.getboolean("rulesets", "check_coverage")
282+
checkNonmatchGroups = False
283+
if config.has_option("rulesets", "check_nonmatch_groups"):
284+
checkNonmatchGroups = config.getboolean("rulesets", "check_nonmatch_groups")
282285
certdir = config.get("certificates", "basedir")
283286
if config.has_option("rulesets", "check_coverage"):
284287
checkCoverage = config.getboolean("rulesets", "check_coverage")
@@ -322,6 +325,7 @@ def cli():
322325

323326
rulesets = []
324327
coverageProblemsExist = False
328+
nonmatchGroupProblemsExist = False
325329
for xmlFname in xmlFnames:
326330
logging.debug("Parsing %s", xmlFname)
327331
if skipFile(xmlFname):
@@ -342,6 +346,12 @@ def cli():
342346
for problem in problems:
343347
coverageProblemsExist = True
344348
logging.error(problem)
349+
if checkNonmatchGroups:
350+
logging.debug("Checking non-match groups for '%s'." % ruleset.name)
351+
problems = ruleset.getNonmatchGroupProblems()
352+
for problem in problems:
353+
nonmatchGroupProblemsExist = True
354+
logging.error(problem)
345355
trie.addRuleset(ruleset)
346356
rulesets.append(ruleset)
347357

@@ -411,8 +421,10 @@ def cli():
411421
if checkCoverage:
412422
if coverageProblemsExist:
413423
return 1 # exit with error code
414-
else:
415-
return 0 # exit with success
424+
if checkNonmatchGroups:
425+
if nonmatchGroupProblemsExist:
426+
return 1 # exit with error code
427+
return 0 # exit with success
416428

417429
if __name__ == '__main__':
418430
sys.exit(cli())

test/rules/src/https_everywhere_checker/rules.py

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ def __init__(self, xmlTree, filename):
122122
self.exclusions = []
123123
self.filename = filename
124124
self.tests = []
125+
self.determine_test_application_run = False
125126

126127
for (attrName, xpath, conversion) in self._attrConvert:
127128
elems = root.xpath(xpath)
@@ -161,6 +162,21 @@ def _addTests(self):
161162
continue
162163
self.tests.append(Test("http://%s/" % target))
163164

165+
def _determineTestApplication(self):
166+
"""Match each test against a rule or exclusion if possible, and hang them
167+
off that rule or exclusion. Return any coverage problems."""
168+
if not self.determine_test_application_run:
169+
self.test_application_problems = []
170+
for test in self.tests:
171+
applies = self.whatApplies(test.url)
172+
if applies:
173+
applies.tests.append(test)
174+
else:
175+
self.test_application_problems.append("%s: No rule or exclusion applies to test URL %s" % (
176+
self.filename, test.url))
177+
self.determine_test_application_run = True
178+
return self.test_application_problems
179+
164180
def getCoverageProblems(self):
165181
"""Verify that each rule and each exclusion has the right number of tests
166182
that applies to it. TODO: Also check that each target has the right
@@ -170,16 +186,7 @@ def getCoverageProblems(self):
170186
Returns an array of strings reporting any coverage problems if they exist,
171187
or empty list if coverage is sufficient.
172188
"""
173-
# First, match each test against a rule or exclusion if possible, and hang
174-
# them off that rule or exclusion.
175-
problems = []
176-
for test in self.tests:
177-
applies = self.whatApplies(test.url)
178-
if applies:
179-
applies.tests.append(test)
180-
else:
181-
problems.append("%s: No rule or exclusion applies to test URL %s" % (
182-
self.filename, test.url))
189+
problems = self._determineTestApplication()
183190
# Next, make sure each rule or exclusion has sufficient tests.
184191
for rule in self.rules:
185192
needed_count = 1 + len(regex.findall("[+*?|]", rule.fromPattern))
@@ -206,6 +213,22 @@ def getCoverageProblems(self):
206213
self.filename, actual_count, needed_count, exclusion))
207214
return problems
208215

216+
def getNonmatchGroupProblems(self):
217+
"""Verify that when rules are actually applied, no non-match groups (e.g.
218+
'$1', '$2' etc.) will exist in the rewritten url"""
219+
self._determineTestApplication()
220+
problems = []
221+
for rule in self.rules:
222+
test_urls = map(lambda test: test.url, rule.tests)
223+
for test in rule.tests:
224+
try:
225+
replacement_url = rule.apply(test.url)
226+
except Exception, e:
227+
if ~e.message.index("invalid group reference"):
228+
problems.append("%s: Rules include non-matched groups in replacement for url: %s" % (
229+
self.filename, test.url))
230+
return problems
231+
209232
def whatApplies(self, url):
210233
for exclusion in self.exclusions:
211234
if exclusion.matches(url):

0 commit comments

Comments
 (0)