From abbdcf0afc822fbce96f3b4ba152ceb9d0063740 Mon Sep 17 00:00:00 2001 From: Sandeep Hegde Date: Thu, 19 Oct 2017 01:15:03 -0400 Subject: [PATCH 01/24] XMLHTTPRequest Mutator - Initial step Mutation testing --- python/servo/mutation/test.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 python/servo/mutation/test.py diff --git a/python/servo/mutation/test.py b/python/servo/mutation/test.py new file mode 100644 index 00000000000..f62045c0398 --- /dev/null +++ b/python/servo/mutation/test.py @@ -0,0 +1,35 @@ +import fileinput +import re +import subprocess +import sys + +def mutate_line(file_name, line_number): + lines = open(file_name, 'r').readlines() + lines[line_number - 1] = re.sub(r'\s&&\s', ' || ', lines[line_number - 1]) + out = open(file_name, 'w') + out.writelines(lines) + out.close() + +def mutation_test(file_name): + lineNumbers = [] + for line in fileinput.input(file_name): + if re.search(r'\s&&\s', line): + lineNumbers.append(fileinput.lineno()) + + for lineToMutate in lineNumbers: + print "Mutating {0} at line {1}".format(file_name, lineToMutate) + mutate_line(file_name, lineToMutate) + print "compling mutant {0}-{1}".format(file_name, lineToMutate) + sys.stdout.flush() + subprocess.call('python mach build --release', shell=True) + print "running tests for mutant {0}-{1}".format(file_name, lineToMutate) + sys.stdout.flush() + subprocess.call('python mach test-wpt XMLHttpRequest --release', shell=True) + print "mutated file {0} diff".format(file_name) + sys.stdout.flush() + subprocess.call('git --no-pager diff {0}'.format(file_name), shell=True) + print "reverting mutant {0}-{1}".format(file_name, lineToMutate) + sys.stdout.flush() + subprocess.call('git checkout {0}'.format(file_name), shell=True) + +mutation_test('components/script/dom/xmlhttprequest.rs') From 0d2ad9a5beebfb2ac19e99139dd6ddb747bb4bbb Mon Sep 17 00:00:00 2001 From: Sandeep Hegde Date: Tue, 24 Oct 2017 22:11:48 -0400 Subject: [PATCH 02/24] Checking the wpt test failures/success. --- python/servo/mutation/test.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/python/servo/mutation/test.py b/python/servo/mutation/test.py index f62045c0398..790789f3fdd 100644 --- a/python/servo/mutation/test.py +++ b/python/servo/mutation/test.py @@ -24,10 +24,12 @@ def mutation_test(file_name): subprocess.call('python mach build --release', shell=True) print "running tests for mutant {0}-{1}".format(file_name, lineToMutate) sys.stdout.flush() - subprocess.call('python mach test-wpt XMLHttpRequest --release', shell=True) - print "mutated file {0} diff".format(file_name) - sys.stdout.flush() - subprocess.call('git --no-pager diff {0}'.format(file_name), shell=True) + testStatus = subprocess.call('python mach test-wpt XMLHttpRequest --release', shell=True) + if testStatus != 0: + print('Failed in while running `python mach test-wpt XMLHttpRequest --release`') + print "mutated file {0} diff".format(file_name) + sys.stdout.flush() + subprocess.call('git --no-pager diff {0}'.format(file_name), shell=True) print "reverting mutant {0}-{1}".format(file_name, lineToMutate) sys.stdout.flush() subprocess.call('git checkout {0}'.format(file_name), shell=True) From ba2152900cc0aa82e62905033e943fb3e4320945 Mon Sep 17 00:00:00 2001 From: Sandeep Hegde Date: Tue, 24 Oct 2017 22:16:48 -0400 Subject: [PATCH 03/24] Added Test Mapping framework and running through a path. --- components/script/dom/Test_mapping.json | 10 +++++++++ python/servo/mutation/init.py | 29 +++++++++++++++++++++++++ python/servo/mutation/test.py | 19 ++++++++-------- 3 files changed, 48 insertions(+), 10 deletions(-) create mode 100644 components/script/dom/Test_mapping.json create mode 100644 python/servo/mutation/init.py diff --git a/components/script/dom/Test_mapping.json b/components/script/dom/Test_mapping.json new file mode 100644 index 00000000000..6ea27ad36ae --- /dev/null +++ b/components/script/dom/Test_mapping.json @@ -0,0 +1,10 @@ +{ + "xmlhttprequest.rs": + [ + "XMLHttpRequest" + ], + "range.rs": + [ + "dom/ranges" + ] +} diff --git a/python/servo/mutation/init.py b/python/servo/mutation/init.py new file mode 100644 index 00000000000..e3d4aea9bcd --- /dev/null +++ b/python/servo/mutation/init.py @@ -0,0 +1,29 @@ +from os import listdir +from os.path import isfile, isdir, join +import json +import sys +import test + +def get_folders_list(path): + folder_list = [] + for filename in listdir(path): + if (isdir(join(path, filename))): + folder_name = join(path,filename) + folder_list.append(folder_name) + return(folder_list) + +def mutation_test_for(mutation_path): + test_mapping_file = join(mutation_path, 'Test_mapping.json') + if(isfile(test_mapping_file)): + json_data = open(test_mapping_file).read() + test_mapping = json.loads(json_data) + + for src_file in test_mapping.keys(): + test.mutation_test(join(mutation_path,src_file.encode('utf-8')), test_mapping[src_file]) + + for folder in get_folders_list(mutation_path): + mutation_test_for(folder) + else: + print ("This folder %s has no test mapping file." %(mutation_path)) + +mutation_test_for(sys.argv[1]) diff --git a/python/servo/mutation/test.py b/python/servo/mutation/test.py index 790789f3fdd..533e7cffe4b 100644 --- a/python/servo/mutation/test.py +++ b/python/servo/mutation/test.py @@ -10,7 +10,7 @@ def mutate_line(file_name, line_number): out.writelines(lines) out.close() -def mutation_test(file_name): +def mutation_test(file_name, tests): lineNumbers = [] for line in fileinput.input(file_name): if re.search(r'\s&&\s', line): @@ -21,17 +21,16 @@ def mutation_test(file_name): mutate_line(file_name, lineToMutate) print "compling mutant {0}-{1}".format(file_name, lineToMutate) sys.stdout.flush() - subprocess.call('python mach build --release', shell=True) + #subprocess.call('python mach build --release', shell=True) print "running tests for mutant {0}-{1}".format(file_name, lineToMutate) sys.stdout.flush() - testStatus = subprocess.call('python mach test-wpt XMLHttpRequest --release', shell=True) - if testStatus != 0: - print('Failed in while running `python mach test-wpt XMLHttpRequest --release`') - print "mutated file {0} diff".format(file_name) - sys.stdout.flush() - subprocess.call('git --no-pager diff {0}'.format(file_name), shell=True) + for test in tests: + testStatus = subprocess.call("python mach test-wpt {0} --release".format(test.encode('utf-8')), shell=True) + if testStatus != 0: + print('Failed in while running `python mach test-wpt {0} --release`'.format(test.encode('utf-8'))) + print "mutated file {0} diff".format(file_name) + sys.stdout.flush() + subprocess.call('git --no-pager diff {0}'.format(file_name), shell=True) print "reverting mutant {0}-{1}".format(file_name, lineToMutate) sys.stdout.flush() subprocess.call('git checkout {0}'.format(file_name), shell=True) - -mutation_test('components/script/dom/xmlhttprequest.rs') From af605a6e099253bdf7d0f269f896247a82c97862 Mon Sep 17 00:00:00 2001 From: Sandeep Hegde Date: Tue, 24 Oct 2017 23:55:47 -0400 Subject: [PATCH 04/24] Added Mutation Test to CI --- etc/ci/buildbot_steps.yml | 1 + etc/ci/mutation_test.py | 4 ++++ 2 files changed, 5 insertions(+) create mode 100644 etc/ci/mutation_test.py diff --git a/etc/ci/buildbot_steps.yml b/etc/ci/buildbot_steps.yml index 497ba972762..a25235c503f 100644 --- a/etc/ci/buildbot_steps.yml +++ b/etc/ci/buildbot_steps.yml @@ -68,6 +68,7 @@ linux-rel-nogate: - ./mach clean-nightlies --keep 3 --force - ./mach build --release - python ./etc/ci/chaos_monkey_test.py + - python ./etc/ci/mutation_test.py mac-rel-intermittent: - ./mach clean-nightlies --keep 3 --force diff --git a/etc/ci/mutation_test.py b/etc/ci/mutation_test.py new file mode 100644 index 00000000000..22504fea045 --- /dev/null +++ b/etc/ci/mutation_test.py @@ -0,0 +1,4 @@ +import sys +import subprocess + +subprocess.call('python python/servo/mutation/init.py components/script/dom', shell=True) From 445ab9ae8dce1fa841f5fed19c749af82015a08b Mon Sep 17 00:00:00 2001 From: Sandeep Hegde Date: Wed, 25 Oct 2017 00:43:01 -0400 Subject: [PATCH 05/24] Reverting wrong comment. --- python/servo/mutation/test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/servo/mutation/test.py b/python/servo/mutation/test.py index 533e7cffe4b..76f88af36f3 100644 --- a/python/servo/mutation/test.py +++ b/python/servo/mutation/test.py @@ -21,7 +21,7 @@ def mutation_test(file_name, tests): mutate_line(file_name, lineToMutate) print "compling mutant {0}-{1}".format(file_name, lineToMutate) sys.stdout.flush() - #subprocess.call('python mach build --release', shell=True) + subprocess.call('python mach build --release', shell=True) print "running tests for mutant {0}-{1}".format(file_name, lineToMutate) sys.stdout.flush() for test in tests: From 58ab11cf9b42c5040bbdd3a57e4f38332e93b26f Mon Sep 17 00:00:00 2001 From: Sandeep Hegde Date: Wed, 25 Oct 2017 11:27:26 -0400 Subject: [PATCH 06/24] Fixed few tidy errors --- components/script/dom/Test_mapping.json | 10 ++++------ etc/ci/mutation_test.py | 10 +++++++++- python/servo/mutation/init.py | 23 +++++++++++++++++------ python/servo/mutation/test.py | 11 +++++++++++ 4 files changed, 41 insertions(+), 13 deletions(-) diff --git a/components/script/dom/Test_mapping.json b/components/script/dom/Test_mapping.json index 6ea27ad36ae..fea1022609b 100644 --- a/components/script/dom/Test_mapping.json +++ b/components/script/dom/Test_mapping.json @@ -1,10 +1,8 @@ { - "xmlhttprequest.rs": - [ - "XMLHttpRequest" + "xmlhttprequest.rs": [ + "XMLHttpRequest" ], - "range.rs": - [ - "dom/ranges" + "range.rs": [ + "dom/ranges" ] } diff --git a/etc/ci/mutation_test.py b/etc/ci/mutation_test.py index 22504fea045..a8a5603228d 100644 --- a/etc/ci/mutation_test.py +++ b/etc/ci/mutation_test.py @@ -1,4 +1,12 @@ -import sys +# 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 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + import subprocess subprocess.call('python python/servo/mutation/init.py components/script/dom', shell=True) diff --git a/python/servo/mutation/init.py b/python/servo/mutation/init.py index e3d4aea9bcd..5cf7c1fce48 100644 --- a/python/servo/mutation/init.py +++ b/python/servo/mutation/init.py @@ -1,16 +1,27 @@ +# 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 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + from os import listdir from os.path import isfile, isdir, join import json import sys import test + def get_folders_list(path): folder_list = [] for filename in listdir(path): - if (isdir(join(path, filename))): - folder_name = join(path,filename) - folder_list.append(folder_name) - return(folder_list) + if (isdir(join(path, filename))): + folder_name = join(path, filename) + folder_list.append(folder_name) + return(folder_list) + def mutation_test_for(mutation_path): test_mapping_file = join(mutation_path, 'Test_mapping.json') @@ -19,11 +30,11 @@ def mutation_test_for(mutation_path): test_mapping = json.loads(json_data) for src_file in test_mapping.keys(): - test.mutation_test(join(mutation_path,src_file.encode('utf-8')), test_mapping[src_file]) + test.mutation_test(join(mutation_path, src_file.encode('utf-8')), test_mapping[src_file]) for folder in get_folders_list(mutation_path): mutation_test_for(folder) else: - print ("This folder %s has no test mapping file." %(mutation_path)) + print("This folder {0} has no test mapping file.".format(mutation_path)) mutation_test_for(sys.argv[1]) diff --git a/python/servo/mutation/test.py b/python/servo/mutation/test.py index 76f88af36f3..dd06871e65b 100644 --- a/python/servo/mutation/test.py +++ b/python/servo/mutation/test.py @@ -1,8 +1,18 @@ +# 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 or the MIT license +# , 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 + def mutate_line(file_name, line_number): lines = open(file_name, 'r').readlines() lines[line_number - 1] = re.sub(r'\s&&\s', ' || ', lines[line_number - 1]) @@ -10,6 +20,7 @@ def mutate_line(file_name, line_number): out.writelines(lines) out.close() + def mutation_test(file_name, tests): lineNumbers = [] for line in fileinput.input(file_name): From c2d46c3b90264105bfa20ff6084f1fc9e054013b Mon Sep 17 00:00:00 2001 From: Sandeep Hegde Date: Wed, 25 Oct 2017 14:03:37 -0400 Subject: [PATCH 07/24] Fixed json tidy error --- components/script/dom/Test_mapping.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/components/script/dom/Test_mapping.json b/components/script/dom/Test_mapping.json index fea1022609b..3a66bae87ac 100644 --- a/components/script/dom/Test_mapping.json +++ b/components/script/dom/Test_mapping.json @@ -1,8 +1,8 @@ -{ - "xmlhttprequest.rs": [ - "XMLHttpRequest" - ], - "range.rs": [ - "dom/ranges" - ] -} +{ + "xmlhttprequest.rs": [ + "XMLHttpRequest" + ], + "range.rs": [ + "dom/ranges" + ] +} From 6688b8a146cbc4ade65c7c021aef4acf0b36bee6 Mon Sep 17 00:00:00 2001 From: Sandeep Hegde Date: Wed, 25 Oct 2017 16:18:21 -0400 Subject: [PATCH 08/24] Changed method to mutate a line of code --- python/servo/mutation/test.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/python/servo/mutation/test.py b/python/servo/mutation/test.py index dd06871e65b..d3f4dd60ecb 100644 --- a/python/servo/mutation/test.py +++ b/python/servo/mutation/test.py @@ -14,11 +14,10 @@ import sys def mutate_line(file_name, line_number): - lines = open(file_name, 'r').readlines() - lines[line_number - 1] = re.sub(r'\s&&\s', ' || ', lines[line_number - 1]) - out = open(file_name, 'w') - out.writelines(lines) - out.close() + for line in fileinput.input(file_name, inplace=True): + if(fileinput.lineno() == line_number): + line = re.sub(r'\s&&\s', ' || ', line) + print line.rstrip() def mutation_test(file_name, tests): From 2b8b98d3a669461775fc30bff88237a9d9055311 Mon Sep 17 00:00:00 2001 From: Sandeep Hegde Date: Wed, 25 Oct 2017 19:56:26 -0400 Subject: [PATCH 09/24] Removed build and wpt-test output from mutation test log and refactored code. --- python/servo/mutation/init.py | 12 ++++++------ python/servo/mutation/test.py | 29 ++++++++++++++++------------- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/python/servo/mutation/init.py b/python/servo/mutation/init.py index 5cf7c1fce48..6087dc2500d 100644 --- a/python/servo/mutation/init.py +++ b/python/servo/mutation/init.py @@ -17,21 +17,21 @@ import test def get_folders_list(path): folder_list = [] for filename in listdir(path): - if (isdir(join(path, filename))): + if isdir(join(path, filename)): folder_name = join(path, filename) folder_list.append(folder_name) - return(folder_list) + return folder_list def mutation_test_for(mutation_path): - test_mapping_file = join(mutation_path, 'Test_mapping.json') - if(isfile(test_mapping_file)): + test_mapping_file = join(mutation_path, 'test_mapping.json') + if isfile(test_mapping_file): json_data = open(test_mapping_file).read() test_mapping = json.loads(json_data) - + # Run mutation test for all source files in mapping file. for src_file in test_mapping.keys(): test.mutation_test(join(mutation_path, src_file.encode('utf-8')), test_mapping[src_file]) - + # Run mutation test in all folder in the path. for folder in get_folders_list(mutation_path): mutation_test_for(folder) else: diff --git a/python/servo/mutation/test.py b/python/servo/mutation/test.py index d3f4dd60ecb..e86d237351d 100644 --- a/python/servo/mutation/test.py +++ b/python/servo/mutation/test.py @@ -11,36 +11,39 @@ import fileinput import re import subprocess import sys +import os +DEVNULL = open(os.devnull, 'wb') def mutate_line(file_name, line_number): for line in fileinput.input(file_name, inplace=True): - if(fileinput.lineno() == line_number): + if fileinput.lineno() == line_number: line = re.sub(r'\s&&\s', ' || ', line) print line.rstrip() def mutation_test(file_name, tests): - lineNumbers = [] + line_numbers = [] for line in fileinput.input(file_name): if re.search(r'\s&&\s', line): - lineNumbers.append(fileinput.lineno()) + line_numbers.append(fileinput.lineno()) - for lineToMutate in lineNumbers: - print "Mutating {0} at line {1}".format(file_name, lineToMutate) - mutate_line(file_name, lineToMutate) - print "compling mutant {0}-{1}".format(file_name, lineToMutate) + for line_to_mutate in line_numbers: + print "Mutating {0} at line {1}".format(file_name, line_to_mutate) + mutate_line(file_name, line_to_mutate) + print "compling mutant {0}:{1}".format(file_name, line_to_mutate) sys.stdout.flush() - subprocess.call('python mach build --release', shell=True) - print "running tests for mutant {0}-{1}".format(file_name, lineToMutate) + subprocess.call('python mach build --release', shell=True, stdout=DEVNULL) + print "running tests for mutant {0}:{1}".format(file_name, line_to_mutate) sys.stdout.flush() for test in tests: - testStatus = subprocess.call("python mach test-wpt {0} --release".format(test.encode('utf-8')), shell=True) - if testStatus != 0: - print('Failed in while running `python mach test-wpt {0} --release`'.format(test.encode('utf-8'))) + test_command = "python mach test-wpt {0} --release".format(test.encode('utf-8')) + test_status = subprocess.call(test_command, shell=True, stdout=DEVNULL) + if test_status != 0: + print("Failed in 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) - print "reverting mutant {0}-{1}".format(file_name, lineToMutate) + print "reverting mutant {0}:{1}".format(file_name, line_to_mutate) sys.stdout.flush() subprocess.call('git checkout {0}'.format(file_name), shell=True) From 5366264494a2a41ba9e3ed097c6c66abcfea5fde Mon Sep 17 00:00:00 2001 From: panup21091993 <32853219+panup21091993@users.noreply.github.com> Date: Thu, 26 Oct 2017 17:36:31 -0400 Subject: [PATCH 10/24] Added Readme.md file for mutation testing --- python/servo/mutation/README.md | 55 +++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 python/servo/mutation/README.md diff --git a/python/servo/mutation/README.md b/python/servo/mutation/README.md new file mode 100644 index 00000000000..c52953c363c --- /dev/null +++ b/python/servo/mutation/README.md @@ -0,0 +1,55 @@ +## Implement Mutation Testing on Servo Parallel Browsing Project + + +The motivation for mutation testing is to test the breadth coverage of tests for source code. Faults (or mutations) are automatically seeded into the code, then tests are run. If tests fail then the mutation is killed, if the tests pass then the mutation lived. The quality of tests can be gauged from the percentage of mutations killed. + +For more info refer [Wiki page](https://en.wikipedia.org/wiki/Mutation_testing). + +In this project, mutation testing is used to test the coverage of WPT for Servo's browsing engine. + +### Mutation Strategy +This version of mutation testing consists of a Python script that finds random uses of && in Servo's code base and replaces them by ||. The expectation from the WPT tests is to catch this mutation and result in failures when executed on the corresponding code base. + +### Test Run Strategy +The mutation test aims to run only tests which are concerned with the mutant. Therefore part of WPT test is related to the source code under mutation is invoked. For this it requires a test mapping in source folders. + +#### test_mapping.json +The file test_mapping.json is used to map the source code to their corresponding WPT tests. The user must maintain a updated version of this file in the path where mutation testing needs to be performed. Additionally, the test_mapping.json will only consist of maps of source codes that are present in the current directory. Hence, each folder will have a unique test_mapping.json file. Any source code files that may be present in a path but are not mapped to a WPT in test_mapping.json will not be covered for mutation testing. + +### Sample test_mapping.json format +A sample of test_mapping.json is as shown below: + +``` +{ + "xmlhttprequest.rs": [ + "XMLHttpRequest" + ], + "range.rs": [ + "dom/ranges" + ] +} +``` + +Please ensure that each folder that requires a mutant to be generated consists of test_mapping.json file so that the script can function as expected. + +### Basic Execution Flow +The implementation of mutation testing is as follows: +1. The script is called from the command line, it searches through the path entered by user for test_mapping.json. +2. If found, it reads the json file and parses one componenent of source file to generate mutants. +3. The corresponding WPT tests are run for each mutant and the test results are logged. +4. Once all WPT are run for the first source file, the mutation continues for other source files mentioned in the json file and runs their corresponding WPT tests. +5. Once it has completed executing mutation testing for the entered path, it repeats the above procedure for sub-paths present inside the entered path. + + +### Running Mutation test +The mutation tests can be run by running the below command from the servo directory on the command line interface: + +`python python/servo/mutation/init.py ` + +Eg. `python python/servo/mutation/init.py components/script/dom` + +### Running Mutation Test from CI + +The CI script for running mutation testing is present in /etc/ci folder. It can be called by executing the below command from the CLI: + +`python /etc/ci/mutation_test.py` \ No newline at end of file From 5cc498dba22326be6bd88e37261284d2e201a6cb Mon Sep 17 00:00:00 2001 From: Sandeep Hegde Date: Fri, 27 Oct 2017 17:06:25 -0400 Subject: [PATCH 11/24] Loging success message on mutation test success --- python/servo/mutation/test.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python/servo/mutation/test.py b/python/servo/mutation/test.py index e86d237351d..5e1772e0a28 100644 --- a/python/servo/mutation/test.py +++ b/python/servo/mutation/test.py @@ -40,10 +40,13 @@ def mutation_test(file_name, tests): test_command = "python mach test-wpt {0} --release".format(test.encode('utf-8')) test_status = subprocess.call(test_command, shell=True, stdout=DEVNULL) if test_status != 0: - print("Failed in while running `{0}`".format(test_command)) + 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) + else: + print("Success: Mutation killed by {0}".format(test.encode('utf-8'))) + break print "reverting mutant {0}:{1}".format(file_name, line_to_mutate) sys.stdout.flush() subprocess.call('git checkout {0}'.format(file_name), shell=True) From ffbabf4a4c0dbc3e89590162e8ef9d4a0ea852bb Mon Sep 17 00:00:00 2001 From: Sandeep Hegde Date: Tue, 31 Oct 2017 01:54:59 -0400 Subject: [PATCH 12/24] Added randomness to the mutation strategy - now running only maximum one mutation per file. - Beautified the output --- .../{Test_mapping.json => test_mapping.json} | 0 python/servo/mutation/test.py | 38 +++++++++++-------- 2 files changed, 23 insertions(+), 15 deletions(-) rename components/script/dom/{Test_mapping.json => test_mapping.json} (100%) diff --git a/components/script/dom/Test_mapping.json b/components/script/dom/test_mapping.json similarity index 100% rename from components/script/dom/Test_mapping.json rename to components/script/dom/test_mapping.json diff --git a/python/servo/mutation/test.py b/python/servo/mutation/test.py index 5e1772e0a28..39c5c84903a 100644 --- a/python/servo/mutation/test.py +++ b/python/servo/mutation/test.py @@ -12,32 +12,37 @@ import re import subprocess import sys import os +import random DEVNULL = open(os.devnull, 'wb') -def mutate_line(file_name, line_number): - for line in fileinput.input(file_name, inplace=True): - if fileinput.lineno() == line_number: - line = re.sub(r'\s&&\s', ' || ', line) - print line.rstrip() - - -def mutation_test(file_name, tests): +def mutate_random_line(file_name): line_numbers = [] for line in fileinput.input(file_name): if re.search(r'\s&&\s', 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(r'\s&&\s', ' || ', line) + print line.rstrip() + return mutation_line_number - for line_to_mutate in line_numbers: - print "Mutating {0} at line {1}".format(file_name, line_to_mutate) - mutate_line(file_name, line_to_mutate) - print "compling mutant {0}:{1}".format(file_name, line_to_mutate) + +def mutation_test(file_name, tests): + mutated_line = mutate_random_line(file_name) + if mutated_line != -1: + print "Mutating {0} at line {1}".format(file_name, mutated_line) + print "compling mutant {0}:{1}".format(file_name, mutated_line) sys.stdout.flush() subprocess.call('python mach build --release', shell=True, stdout=DEVNULL) - print "running tests for mutant {0}:{1}".format(file_name, line_to_mutate) - sys.stdout.flush() 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)) @@ -47,6 +52,9 @@ def mutation_test(file_name, tests): else: print("Success: Mutation killed by {0}".format(test.encode('utf-8'))) break - print "reverting mutant {0}:{1}".format(file_name, line_to_mutate) + 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 "-----------------------------------------------------------------\n" From d24d6ac8ef1dcd0dde4637099d97d93e75ce181c Mon Sep 17 00:00:00 2001 From: Sandeep Hegde Date: Mon, 6 Nov 2017 12:57:00 -0500 Subject: [PATCH 13/24] Skipping mutation test for file with local changes --- python/servo/mutation/test.py | 52 +++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/python/servo/mutation/test.py b/python/servo/mutation/test.py index 39c5c84903a..242d545a305 100644 --- a/python/servo/mutation/test.py +++ b/python/servo/mutation/test.py @@ -33,28 +33,32 @@ def mutate_random_line(file_name): def mutation_test(file_name, tests): - mutated_line = mutate_random_line(file_name) - if mutated_line != -1: - print "Mutating {0} at line {1}".format(file_name, mutated_line) - print "compling 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) - else: - print("Success: Mutation killed by {0}".format(test.encode('utf-8'))) - break - print "reverting mutant {0}:{1}".format(file_name, mutated_line) - sys.stdout.flush() - subprocess.call('git checkout {0}'.format(file_name), shell=True) + local_changes_present = subprocess.call('git diff --quiet {0}'.format(file_name), shell=True) + if local_changes_present == 1: + print "{0} has local changes, please commit/remove changes before running the test".format(file_name) else: - print "Cannot mutate {0}".format(file_name) - print "-----------------------------------------------------------------\n" + mutated_line = mutate_random_line(file_name) + if mutated_line != -1: + print "Mutating {0} at line {1}".format(file_name, mutated_line) + print "compling 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) + else: + print("Success: Mutation killed by {0}".format(test.encode('utf-8'))) + 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 "-----------------------------------------------------------------\n" From 84f694dc9331dc5ccefbe5cbf66770a9e31e5ec1 Mon Sep 17 00:00:00 2001 From: Sandeep Hegde Date: Wed, 8 Nov 2017 12:58:46 -0500 Subject: [PATCH 14/24] Added more information in Mutation Test Readme --- python/servo/mutation/README.md | 28 ++++++++++++++++++---------- python/servo/mutation/test.py | 2 +- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/python/servo/mutation/README.md b/python/servo/mutation/README.md index c52953c363c..bc9c5f2eea6 100644 --- a/python/servo/mutation/README.md +++ b/python/servo/mutation/README.md @@ -5,7 +5,7 @@ The motivation for mutation testing is to test the breadth coverage of tests for For more info refer [Wiki page](https://en.wikipedia.org/wiki/Mutation_testing). -In this project, mutation testing is used to test the coverage of WPT for Servo's browsing engine. +Here Mutation testing is used to test the coverage of WPT for Servo's browsing engine. ### Mutation Strategy This version of mutation testing consists of a Python script that finds random uses of && in Servo's code base and replaces them by ||. The expectation from the WPT tests is to catch this mutation and result in failures when executed on the corresponding code base. @@ -16,7 +16,7 @@ The mutation test aims to run only tests which are concerned with the mutant. Th #### test_mapping.json The file test_mapping.json is used to map the source code to their corresponding WPT tests. The user must maintain a updated version of this file in the path where mutation testing needs to be performed. Additionally, the test_mapping.json will only consist of maps of source codes that are present in the current directory. Hence, each folder will have a unique test_mapping.json file. Any source code files that may be present in a path but are not mapped to a WPT in test_mapping.json will not be covered for mutation testing. -### Sample test_mapping.json format +#### Sample test_mapping.json format A sample of test_mapping.json is as shown below: ``` @@ -32,14 +32,14 @@ A sample of test_mapping.json is as shown below: Please ensure that each folder that requires a mutant to be generated consists of test_mapping.json file so that the script can function as expected. -### Basic Execution Flow -The implementation of mutation testing is as follows: -1. The script is called from the command line, it searches through the path entered by user for test_mapping.json. -2. If found, it reads the json file and parses one componenent of source file to generate mutants. -3. The corresponding WPT tests are run for each mutant and the test results are logged. -4. Once all WPT are run for the first source file, the mutation continues for other source files mentioned in the json file and runs their corresponding WPT tests. -5. Once it has completed executing mutation testing for the entered path, it repeats the above procedure for sub-paths present inside the entered path. +If we want to run mutation test for a source path then there should be test_mapping.json in that path and all the subdirectories which has source files. +Eg: There should be test mapping in following folders if we run mutation test on 'components/script' path. +* components/script/test_mapping.json +* components/script/dom/test_mapping.json +* components/script/task_source/test_mapping.json +* components/script/dom/bindings/test_mapping.json +* ... ### Running Mutation test The mutation tests can be run by running the below command from the servo directory on the command line interface: @@ -52,4 +52,12 @@ Eg. `python python/servo/mutation/init.py components/script/dom` The CI script for running mutation testing is present in /etc/ci folder. It can be called by executing the below command from the CLI: -`python /etc/ci/mutation_test.py` \ No newline at end of file +`python /etc/ci/mutation_test.py` + +### Execution Flow +1. The script is called from the command line, it searches for test_mapping.json in the path entered by user. +2. If found, it reads the json file and parses it, gets source file to tests mapping. +3. If the source file does not have any local changes then it is mutated at a random line. +4. The corresponding WPT tests are run for this mutant and the test results are logged. +5. Once all WPT are run for the first source file, the mutation continues for other source files mentioned in the json file and runs their corresponding WPT tests. +6. Once it has completed executing mutation testing for the entered path, it repeats the above procedure for sub-paths present inside the entered path. diff --git a/python/servo/mutation/test.py b/python/servo/mutation/test.py index 242d545a305..1d5a6f48d2a 100644 --- a/python/servo/mutation/test.py +++ b/python/servo/mutation/test.py @@ -61,4 +61,4 @@ def mutation_test(file_name, tests): subprocess.call('git checkout {0}'.format(file_name), shell=True) else: print "Cannot mutate {0}".format(file_name) - print "-----------------------------------------------------------------\n" + print "-"*80 + "\n" From f6f454505e29485bd9af879b7eed52f745b92a0e Mon Sep 17 00:00:00 2001 From: Sandeep Hegde Date: Wed, 8 Nov 2017 13:00:14 -0500 Subject: [PATCH 15/24] fixed tidy error --- python/servo/mutation/test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/servo/mutation/test.py b/python/servo/mutation/test.py index 1d5a6f48d2a..b004dc3fcd9 100644 --- a/python/servo/mutation/test.py +++ b/python/servo/mutation/test.py @@ -61,4 +61,4 @@ def mutation_test(file_name, tests): subprocess.call('git checkout {0}'.format(file_name), shell=True) else: print "Cannot mutate {0}".format(file_name) - print "-"*80 + "\n" + print "-" * 80 + "\n" From 6e66c0d1ef9a98c03d8b7af6d5a641e7e49e593e Mon Sep 17 00:00:00 2001 From: Sandeep Hegde Date: Fri, 10 Nov 2017 20:22:12 -0500 Subject: [PATCH 16/24] Corrected typo in Readme --- python/servo/mutation/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/servo/mutation/README.md b/python/servo/mutation/README.md index bc9c5f2eea6..46dd3287605 100644 --- a/python/servo/mutation/README.md +++ b/python/servo/mutation/README.md @@ -5,7 +5,7 @@ The motivation for mutation testing is to test the breadth coverage of tests for For more info refer [Wiki page](https://en.wikipedia.org/wiki/Mutation_testing). -Here Mutation testing is used to test the coverage of WPT for Servo's browsing engine. +Here Mutation testing is used to test the coverage of WPT for Servo's browser engine. ### Mutation Strategy This version of mutation testing consists of a Python script that finds random uses of && in Servo's code base and replaces them by ||. The expectation from the WPT tests is to catch this mutation and result in failures when executed on the corresponding code base. From b8199e11e018d1e4fa35d3ebbe3dbf934cd258d2 Mon Sep 17 00:00:00 2001 From: Sandeep Hegde Date: Fri, 10 Nov 2017 20:48:47 -0500 Subject: [PATCH 17/24] Changed readme saying wildcard not allowed in test_mapping.josn --- python/servo/mutation/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/servo/mutation/README.md b/python/servo/mutation/README.md index 46dd3287605..1db063ca365 100644 --- a/python/servo/mutation/README.md +++ b/python/servo/mutation/README.md @@ -30,7 +30,7 @@ A sample of test_mapping.json is as shown below: } ``` -Please ensure that each folder that requires a mutant to be generated consists of test_mapping.json file so that the script can function as expected. +Please ensure that each folder that requires a mutant to be generated consists of test_mapping.json file so that the script can function as expected. Wildcards are not allowed in test_mapping.json. If we want to run mutation test for a source path then there should be test_mapping.json in that path and all the subdirectories which has source files. From cc6c2eea6ede64280684b5c98795a207c4b78192 Mon Sep 17 00:00:00 2001 From: Sandeep Hegde Date: Sun, 12 Nov 2017 01:18:29 -0500 Subject: [PATCH 18/24] Added mutation test summary and made it exit with relevant exit code --- etc/ci/mutation_test.py | 5 ++++- python/servo/mutation/init.py | 15 ++++++++++++++- python/servo/mutation/test.py | 13 +++++++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/etc/ci/mutation_test.py b/etc/ci/mutation_test.py index a8a5603228d..e2957499b8a 100644 --- a/etc/ci/mutation_test.py +++ b/etc/ci/mutation_test.py @@ -8,5 +8,8 @@ # except according to those terms. import subprocess +import sys -subprocess.call('python python/servo/mutation/init.py components/script/dom', shell=True) +mutation_path = 'components/script/dom' +status = subprocess.call('python python/servo/mutation/init.py %s' % mutation_path, shell=True) +sys.exit(status) diff --git a/python/servo/mutation/init.py b/python/servo/mutation/init.py index 6087dc2500d..aa7b86c5f00 100644 --- a/python/servo/mutation/init.py +++ b/python/servo/mutation/init.py @@ -12,6 +12,12 @@ from os.path import isfile, isdir, join import json import sys import test +test_summary = { + test.Status.PASSED: 0, + test.Status.FAILED: 0, + test.Status.SKIPPED: 0, + test.Status.UNEXPECTED: 0 +} def get_folders_list(path): @@ -30,11 +36,18 @@ def mutation_test_for(mutation_path): test_mapping = json.loads(json_data) # Run mutation test for all source files in mapping file. for src_file in test_mapping.keys(): - test.mutation_test(join(mutation_path, src_file.encode('utf-8')), test_mapping[src_file]) + status = test.mutation_test(join(mutation_path, src_file.encode('utf-8')), test_mapping[src_file]) + test_summary[status] += 1 # Run mutation test in all folder in the path. for folder in get_folders_list(mutation_path): mutation_test_for(folder) else: print("This folder {0} has no test mapping file.".format(mutation_path)) + mutation_test_for(sys.argv[1]) +print "\nTest Summary:" +for test_status in test_summary: + print "{0} : {1}".format(test_status.name, test_summary[test_status]) +if test_summary[test.Status.FAILED] or test_summary[test.Status.UNEXPECTED]: + sys.exit(1) diff --git a/python/servo/mutation/test.py b/python/servo/mutation/test.py index b004dc3fcd9..46bd3950778 100644 --- a/python/servo/mutation/test.py +++ b/python/servo/mutation/test.py @@ -13,9 +13,17 @@ import subprocess import sys import os import random +from enum import Enum DEVNULL = open(os.devnull, 'wb') +class Status(Enum): + PASSED = 0 + FAILED = 1 + SKIPPED = 2 + UNEXPECTED = 3 + + def mutate_random_line(file_name): line_numbers = [] for line in fileinput.input(file_name): @@ -33,8 +41,10 @@ def mutate_random_line(file_name): 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: mutated_line = mutate_random_line(file_name) @@ -53,8 +63,10 @@ def mutation_test(file_name, tests): 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.FAILED else: print("Success: Mutation killed by {0}".format(test.encode('utf-8'))) + status = Status.PASSED break print "reverting mutant {0}:{1}".format(file_name, mutated_line) sys.stdout.flush() @@ -62,3 +74,4 @@ def mutation_test(file_name, tests): else: print "Cannot mutate {0}".format(file_name) print "-" * 80 + "\n" + return status From ed47f89e79c79aa2f69652c7302c64d8bf0880ad Mon Sep 17 00:00:00 2001 From: Sandeep Hegde Date: Mon, 13 Nov 2017 01:01:09 -0500 Subject: [PATCH 19/24] Changed invocation of muatation test in CI to bash script to use virtualenv --- etc/ci/buildbot_steps.yml | 2 +- etc/ci/mutation_test.py | 15 --------------- etc/ci/mutation_test.sh | 12 ++++++++++++ 3 files changed, 13 insertions(+), 16 deletions(-) delete mode 100644 etc/ci/mutation_test.py create mode 100755 etc/ci/mutation_test.sh diff --git a/etc/ci/buildbot_steps.yml b/etc/ci/buildbot_steps.yml index a25235c503f..8da9728ccd6 100644 --- a/etc/ci/buildbot_steps.yml +++ b/etc/ci/buildbot_steps.yml @@ -68,7 +68,7 @@ linux-rel-nogate: - ./mach clean-nightlies --keep 3 --force - ./mach build --release - python ./etc/ci/chaos_monkey_test.py - - python ./etc/ci/mutation_test.py + - bash ./etc/ci/mutation_test.sh mac-rel-intermittent: - ./mach clean-nightlies --keep 3 --force diff --git a/etc/ci/mutation_test.py b/etc/ci/mutation_test.py deleted file mode 100644 index e2957499b8a..00000000000 --- a/etc/ci/mutation_test.py +++ /dev/null @@ -1,15 +0,0 @@ -# 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 or the MIT license -# , at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - -import subprocess -import sys - -mutation_path = 'components/script/dom' -status = subprocess.call('python python/servo/mutation/init.py %s' % mutation_path, shell=True) -sys.exit(status) diff --git a/etc/ci/mutation_test.sh b/etc/ci/mutation_test.sh new file mode 100755 index 00000000000..a501b408796 --- /dev/null +++ b/etc/ci/mutation_test.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +set -o errexit +set -o nounset +set -o pipefail + +source python/_virtualenv/bin/activate +python python/servo/mutation/init.py components/script/dom From 2f900a0427052786751894dc44db21ae0b92b5e9 Mon Sep 17 00:00:00 2001 From: Sandeep Hegde Date: Mon, 13 Nov 2017 08:05:34 -0500 Subject: [PATCH 20/24] Added PS1 variable before activating virtualenv --- etc/ci/mutation_test.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/etc/ci/mutation_test.sh b/etc/ci/mutation_test.sh index a501b408796..f2fc3c994fb 100755 --- a/etc/ci/mutation_test.sh +++ b/etc/ci/mutation_test.sh @@ -8,5 +8,6 @@ set -o errexit set -o nounset set -o pipefail -source python/_virtualenv/bin/activate +PS1="" source python/_virtualenv/bin/activate +# `PS1` must be defined before activating virtualenv python python/servo/mutation/init.py components/script/dom From 61794f8bbd3bd5c7adbf11c7ce007e7b6f41e2a6 Mon Sep 17 00:00:00 2001 From: Sandeep Hegde Date: Mon, 13 Nov 2017 20:40:16 -0500 Subject: [PATCH 21/24] Made test summary more descriptive and Updated Readme --- components/script/dom/xmlhttprequest.rs | 2 +- python/servo/mutation/README.md | 16 ++++++++++++++++ python/servo/mutation/init.py | 12 +++++++----- python/servo/mutation/test.py | 8 ++++---- 4 files changed, 28 insertions(+), 10 deletions(-) diff --git a/components/script/dom/xmlhttprequest.rs b/components/script/dom/xmlhttprequest.rs index 81133ea6bc9..3fd293a5f39 100644 --- a/components/script/dom/xmlhttprequest.rs +++ b/components/script/dom/xmlhttprequest.rs @@ -213,7 +213,7 @@ impl XMLHttpRequest { } fn sync_in_window(&self) -> bool { - self.sync.get() && self.global().is::() + self.sync.get() || self.global().is::() } fn initiate_async_xhr(context: Arc>, diff --git a/python/servo/mutation/README.md b/python/servo/mutation/README.md index 1db063ca365..fe051642703 100644 --- a/python/servo/mutation/README.md +++ b/python/servo/mutation/README.md @@ -61,3 +61,19 @@ The CI script for running mutation testing is present in /etc/ci folder. It can 4. The corresponding WPT tests are run for this mutant and the test results are logged. 5. Once all WPT are run for the first source file, the mutation continues for other source files mentioned in the json file and runs their corresponding WPT tests. 6. Once it has completed executing mutation testing for the entered path, it repeats the above procedure for sub-paths present inside the entered path. + +### Test Summary + +At the end of the test run the test summary displayed which looks like this: +``` +Test Summary: +Mutant Killed (Success) 25 +Mutant Survived (Failure) 10 +Mutation Skipped 1 +Unexpected error in mutation 0 +``` + +* Mutant Killed (Success): The mutant was successfully killed by WPT test suite. +* Mutant Survived (Failure): The mutation has survived the WPT Test Suite, tests in WPT could not catch this mutation. +* Mutation Skipped: Files is skipped for mutation test due to the local changes in that file. +* Unexpected error in mutation: Mutation test could not run due to unexpected failures. (example: if no && preset in the file to replace) diff --git a/python/servo/mutation/init.py b/python/servo/mutation/init.py index aa7b86c5f00..a3461779bbb 100644 --- a/python/servo/mutation/init.py +++ b/python/servo/mutation/init.py @@ -13,8 +13,8 @@ import json import sys import test test_summary = { - test.Status.PASSED: 0, - test.Status.FAILED: 0, + test.Status.KILLED: 0, + test.Status.SURVIVED: 0, test.Status.SKIPPED: 0, test.Status.UNEXPECTED: 0 } @@ -47,7 +47,9 @@ def mutation_test_for(mutation_path): mutation_test_for(sys.argv[1]) print "\nTest Summary:" -for test_status in test_summary: - print "{0} : {1}".format(test_status.name, test_summary[test_status]) -if test_summary[test.Status.FAILED] or test_summary[test.Status.UNEXPECTED]: +print "Mutant Killed (Success) \t{0}".format(test_summary[test.Status.KILLED]) +print "Mutant Survived (Failure) \t{0}".format(test_summary[test.Status.SURVIVED]) +print "Mutation Skipped \t\t{0}".format(test_summary[test.Status.SKIPPED]) +print "Unexpected error in mutation \t{0}".format(test_summary[test.Status.UNEXPECTED]) +if test_summary[test.Status.SURVIVED]: sys.exit(1) diff --git a/python/servo/mutation/test.py b/python/servo/mutation/test.py index 46bd3950778..585a0b1a82c 100644 --- a/python/servo/mutation/test.py +++ b/python/servo/mutation/test.py @@ -18,8 +18,8 @@ DEVNULL = open(os.devnull, 'wb') class Status(Enum): - PASSED = 0 - FAILED = 1 + KILLED = 0 + SURVIVED = 1 SKIPPED = 2 UNEXPECTED = 3 @@ -63,10 +63,10 @@ def mutation_test(file_name, tests): 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.FAILED + status = Status.SURVIVED else: print("Success: Mutation killed by {0}".format(test.encode('utf-8'))) - status = Status.PASSED + status = Status.KILLED break print "reverting mutant {0}:{1}".format(file_name, mutated_line) sys.stdout.flush() From f817a9c37146ddbb24207af1b54dac0ed08d208a Mon Sep 17 00:00:00 2001 From: Sandeep Hegde Date: Mon, 13 Nov 2017 20:47:06 -0500 Subject: [PATCH 22/24] Refactored mutate random line method --- python/servo/mutation/test.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/python/servo/mutation/test.py b/python/servo/mutation/test.py index 585a0b1a82c..7ecc383f682 100644 --- a/python/servo/mutation/test.py +++ b/python/servo/mutation/test.py @@ -24,10 +24,10 @@ class Status(Enum): UNEXPECTED = 3 -def mutate_random_line(file_name): +def mutate_random_line(file_name, strategy): line_numbers = [] for line in fileinput.input(file_name): - if re.search(r'\s&&\s', line): + if re.search(strategy['regex'], line): line_numbers.append(fileinput.lineno()) if len(line_numbers) == 0: return -1 @@ -35,7 +35,7 @@ def mutate_random_line(file_name): 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(r'\s&&\s', ' || ', line) + line = re.sub(strategy['regex'], strategy['replaceString'], line) print line.rstrip() return mutation_line_number @@ -47,7 +47,8 @@ def mutation_test(file_name, tests): status = Status.SKIPPED print "{0} has local changes, please commit/remove changes before running the test".format(file_name) else: - mutated_line = mutate_random_line(file_name) + 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 "compling mutant {0}:{1}".format(file_name, mutated_line) From a9493d08874d3a9f8c4f61d9bb83a21dd2a94575 Mon Sep 17 00:00:00 2001 From: Sandeep Hegde Date: Mon, 13 Nov 2017 21:12:53 -0500 Subject: [PATCH 23/24] Corrected a typo --- python/servo/mutation/test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/servo/mutation/test.py b/python/servo/mutation/test.py index 7ecc383f682..2248f81ccd3 100644 --- a/python/servo/mutation/test.py +++ b/python/servo/mutation/test.py @@ -51,7 +51,7 @@ def mutation_test(file_name, tests): mutated_line = mutate_random_line(file_name, strategy) if mutated_line != -1: print "Mutating {0} at line {1}".format(file_name, mutated_line) - print "compling mutant {0}:{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: From b8c6d144f3445bc969a3bc46a6117226d1097cc1 Mon Sep 17 00:00:00 2001 From: Sandeep Hegde Date: Thu, 16 Nov 2017 10:54:01 -0500 Subject: [PATCH 24/24] Reveting accidental mutant commit --- components/script/dom/xmlhttprequest.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/script/dom/xmlhttprequest.rs b/components/script/dom/xmlhttprequest.rs index 3fd293a5f39..81133ea6bc9 100644 --- a/components/script/dom/xmlhttprequest.rs +++ b/components/script/dom/xmlhttprequest.rs @@ -213,7 +213,7 @@ impl XMLHttpRequest { } fn sync_in_window(&self) -> bool { - self.sync.get() || self.global().is::() + self.sync.get() && self.global().is::() } fn initiate_async_xhr(context: Arc>,