aboutsummaryrefslogtreecommitdiffstats
path: root/python/servo/mutation/test.py
diff options
context:
space:
mode:
authorbors-servo <lbergstrom+bors@mozilla.com>2017-11-16 11:51:01 -0600
committerGitHub <noreply@github.com>2017-11-16 11:51:01 -0600
commit50f11e3584c9c0255098bdd438b11a84c093b197 (patch)
treea3265535f53a6354a72bc260a27c871fc4e240f2 /python/servo/mutation/test.py
parent5c7e79e91c12d19830fdb4c6c17be2a551f88aa2 (diff)
parentb8c6d144f3445bc969a3bc46a6117226d1097cc1 (diff)
downloadservo-50f11e3584c9c0255098bdd438b11a84c093b197.tar.gz
servo-50f11e3584c9c0255098bdd438b11a84c093b197.zip
Auto merge of #18984 - dsandeephegde:master, r=jdm
Initial steps of Mutation testing <!-- Please describe your changes on the following line: --> - Added one strategy of mutation which is replacing occurrences && to ||. - Added test mapping framework for running mutation tests corresponding to a mutant. - Added one test_mapping.json to map source file in a folder to WPT test. - Added README mentioning about Mutation testing. - Added CI script to invoke mutation test. --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [x] These changes #18529 (github issue number if applicable). - [x] These changes do not require tests because it is a python script to run mutation test and does not change any behavior. <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/18984) <!-- Reviewable:end -->
Diffstat (limited to 'python/servo/mutation/test.py')
-rw-r--r--python/servo/mutation/test.py78
1 files changed, 78 insertions, 0 deletions
diff --git a/python/servo/mutation/test.py b/python/servo/mutation/test.py
new file mode 100644
index 00000000000..2248f81ccd3
--- /dev/null
+++ b/python/servo/mutation/test.py
@@ -0,0 +1,78 @@
+# Copyright 2013 The Servo Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+import fileinput
+import re
+import subprocess
+import sys
+import os
+import random
+from enum import Enum
+DEVNULL = open(os.devnull, 'wb')
+
+
+class Status(Enum):
+ KILLED = 0
+ SURVIVED = 1
+ SKIPPED = 2
+ UNEXPECTED = 3
+
+
+def mutate_random_line(file_name, strategy):
+ line_numbers = []
+ for line in fileinput.input(file_name):
+ if re.search(strategy['regex'], line):
+ line_numbers.append(fileinput.lineno())
+ if len(line_numbers) == 0:
+ return -1
+ else:
+ mutation_line_number = line_numbers[random.randint(0, len(line_numbers) - 1)]
+ for line in fileinput.input(file_name, inplace=True):
+ if fileinput.lineno() == mutation_line_number:
+ line = re.sub(strategy['regex'], strategy['replaceString'], line)
+ print line.rstrip()
+ return mutation_line_number
+
+
+def mutation_test(file_name, tests):
+ status = Status.UNEXPECTED
+ local_changes_present = subprocess.call('git diff --quiet {0}'.format(file_name), shell=True)
+ if local_changes_present == 1:
+ status = Status.SKIPPED
+ print "{0} has local changes, please commit/remove changes before running the test".format(file_name)
+ else:
+ strategy = {'regex': r'\s&&\s', 'replaceString': ' || '}
+ mutated_line = mutate_random_line(file_name, strategy)
+ if mutated_line != -1:
+ print "Mutating {0} at line {1}".format(file_name, mutated_line)
+ print "compiling mutant {0}:{1}".format(file_name, mutated_line)
+ sys.stdout.flush()
+ subprocess.call('python mach build --release', shell=True, stdout=DEVNULL)
+ for test in tests:
+ test_command = "python mach test-wpt {0} --release".format(test.encode('utf-8'))
+ print "running `{0}` test for mutant {1}:{2}".format(test, file_name, mutated_line)
+ sys.stdout.flush()
+ test_status = subprocess.call(test_command, shell=True, stdout=DEVNULL)
+ if test_status != 0:
+ print("Failed: while running `{0}`".format(test_command))
+ print "mutated file {0} diff".format(file_name)
+ sys.stdout.flush()
+ subprocess.call('git --no-pager diff {0}'.format(file_name), shell=True)
+ status = Status.SURVIVED
+ else:
+ print("Success: Mutation killed by {0}".format(test.encode('utf-8')))
+ status = Status.KILLED
+ break
+ print "reverting mutant {0}:{1}".format(file_name, mutated_line)
+ sys.stdout.flush()
+ subprocess.call('git checkout {0}'.format(file_name), shell=True)
+ else:
+ print "Cannot mutate {0}".format(file_name)
+ print "-" * 80 + "\n"
+ return status