This commit is contained in:
Claudio Maggioni 2023-12-09 20:52:07 +01:00
parent eadbd8f14a
commit b9fcf68fdf
22 changed files with 201 additions and 166 deletions

View file

@ -166,10 +166,18 @@ def get_test_case_source(f_name: str, test_case: Params, i: int, indent: int):
{space}{single_indent}assert {call_statement(f_name_orig, test_case)} == {repr(output)}""" {space}{single_indent}assert {call_statement(f_name_orig, test_case)} == {repr(output)}"""
def get_test_class(f_name: str, cases: set[Params]) -> str: def get_test_import_stmt(names: list[str]):
f_name_orig = BranchTransformer.to_original_name(f_name) imports = ["from unittest import TestCase"]
test_class = (f"from unittest import TestCase\n\nfrom {module_of[f_name]} import {f_name_orig}\n\n\n" for orig_f_name in names:
f"class Test_{f_name_orig}(TestCase):\n") f_name = BranchTransformer.to_instrumented_name(orig_f_name)
test_class += "\n\n".join([get_test_case_source(f_name, case, i + 1, 1) for i, case in enumerate(cases)]) imports.append(f"from {'.'.join(module_of[f_name])} import {orig_f_name}")
return test_class
return "\n".join(imports) + "\n"
def get_test_class(orig_f_name: str, cases: set[Params]) -> str:
f_name = BranchTransformer.to_instrumented_name(orig_f_name)
return (f"class Test_{orig_f_name}(TestCase):\n" +
"\n\n".join([get_test_case_source(f_name, case, i + 1, 1) for i, case in enumerate(cases)]) +
"\n")

View file

@ -1,7 +1,6 @@
import argparse import argparse
import os import os
import random import random
import sys
from functools import partial from functools import partial
import frozendict import frozendict
@ -56,8 +55,8 @@ def init_deap():
creator.create("Individual", list, fitness=creator.Fitness) creator.create("Individual", list, fitness=creator.Fitness)
def generate(f_name: str): def generate(orig_name: str) -> set[instrument.Params]:
orig_name = instrument.BranchTransformer.to_original_name(f_name) f_name = instrument.BranchTransformer.to_instrumented_name(orig_name)
args = instrument.functions[f_name] args = instrument.functions[f_name]
range_start, range_end = instrument.n_of_branches[f_name] range_start, range_end = instrument.n_of_branches[f_name]
@ -106,6 +105,9 @@ def generate(f_name: str):
top_result = archive.build_suite() top_result = archive.build_suite()
top_coverage = cov top_coverage = cov
if tot_covered == total_branches:
break
return top_result return top_result
@ -150,11 +152,13 @@ def compute_fitness(f_name: str, archive: Archive, individual: list) -> tuple[fl
return fitness, return fitness,
def build_suite(f_name: str): def build_suite(filename: str, f_names: list[str]):
instr_name = instrument.BranchTransformer.to_instrumented_name(f_name) suite = [(name, generate(name)) for name in f_names]
cases = generate(instr_name)
with open(os.path.join(OUT_DIR, "test_" + f_name + ".py"), "w") as f: with open(os.path.join(OUT_DIR, f"test_{filename}.py"), "w") as f:
f.write(get_test_class(instr_name, cases)) f.write(fuzzer.get_test_import_stmt(f_names))
f.write("\n\n")
f.write("\n\n".join([get_test_class(name, cases) for name, cases in suite]))
def main(): def main():
@ -169,9 +173,8 @@ def main():
instrument.load_benchmark(save_instrumented=False, files=parser.parse_args().file) instrument.load_benchmark(save_instrumented=False, files=parser.parse_args().file)
init_deap() init_deap()
for instr_f in tqdm.tqdm(sorted(instrument.functions.keys()), desc="Generating tests"): for file_name, functions in tqdm.tqdm(instrument.get_benchmark().items(), desc="Generating tests"):
print("", file=sys.stderr) build_suite(file_name, functions)
build_suite(instrument.BranchTransformer.to_original_name(instr_f))
if __name__ == '__main__': if __name__ == '__main__':

View file

@ -1,11 +1,13 @@
import ast import ast
import os.path import os.path
import sys import sys
from collections import defaultdict
from typing import Optional from typing import Optional
import astunparse import astunparse
import tqdm import tqdm
from frozendict import frozendict from frozendict import frozendict
from operators import evaluate_condition from operators import evaluate_condition
ROOT_DIR: str = os.path.dirname(__file__) ROOT_DIR: str = os.path.dirname(__file__)
@ -85,7 +87,7 @@ SignatureDict = dict[str, list[Arg]]
n_of_branches: dict[str, tuple[int, int]] = {} n_of_branches: dict[str, tuple[int, int]] = {}
functions: SignatureDict = {} functions: SignatureDict = {}
module_of: dict[str, str] = {} module_of: dict[str, list[str]] = {}
def instrument(source_path: str, target_path: str, save_instrumented=True): def instrument(source_path: str, target_path: str, save_instrumented=True):
@ -130,9 +132,7 @@ def instrument(source_path: str, target_path: str, save_instrumented=True):
arg_types.append((arg.arg, arg_type)) arg_types.append((arg.arg, arg_type))
functions[f.name] = arg_types functions[f.name] = arg_types
module_of[f.name] = os.path.normpath(os.path.relpath(source_path, ROOT_DIR)) \ module_of[f.name] = os.path.splitext(os.path.normpath(os.path.relpath(source_path, ROOT_DIR)))[0].split("/")
.replace(".py", "") \
.replace("/", ".")
def invoke(f_name: str, f_args: Params) -> any: def invoke(f_name: str, f_args: Params) -> any:
@ -176,5 +176,19 @@ def call_statement(f_name: str, f_args: Params) -> str:
return f"{f_name}({', '.join(arg_list)})" return f"{f_name}({', '.join(arg_list)})"
def get_benchmark() -> dict[str, list[str]]:
"""
Returns a dictionary associated each source code file name loaded (without extension) with the list of
(non-instrumented) function names defined within it
"""
names: defaultdict[str, list[str]] = defaultdict(list)
for f in functions:
names[module_of[f][-1]].append(BranchTransformer.to_original_name(f))
return dict(names)
if __name__ == '__main__': if __name__ == '__main__':
load_benchmark(save_instrumented=True) load_benchmark(save_instrumented=True)

41
muttest.py Normal file
View file

@ -0,0 +1,41 @@
import argparse
import os
import re
import sys
import instrument
ROOT_DIR = os.path.dirname(__file__)
IN_SOURCE_DIR = os.path.join(ROOT_DIR, "benchmark")
IN_TEST_DIR = os.path.join(ROOT_DIR, "tests")
OUT_DIR = os.path.join(ROOT_DIR, "tests")
def run_mutpy(test_path: str, source_path: str):
stream = os.popen(f'mut.py --target \'{source_path}\' --unit-test \'{test_path}\'')
output = stream.read()
score = re.search('Mutation score \[.*\]: (\d+\.\d+)\%', output).group(1)
print(output, file=sys.stderr)
print(f"Score is: {score}")
def main():
parser = argparse.ArgumentParser(prog='muttest.py',
description='Runs MutPy over generated test suite.')
parser.add_argument('file', type=str, help="Source file to test",
nargs="*")
files = parser.parse_args().file
if len(files) == 0:
to_test = instrument.get_benchmark().keys()
else:
to_test = [os.path.splitext(os.path.basename(file))[0] for file in files]
for filename in to_test:
source_path = os.path.join(IN_SOURCE_DIR, f"{filename}.py")
test_path = os.path.join(IN_TEST_DIR, f"test_{filename}.py")
run_mutpy(test_path, source_path)
if __name__ == "__main__":
main()

View file

@ -3,3 +3,4 @@ deap==1.4.1
astunparse==1.6.3 astunparse==1.6.3
frozendict==2.3.8 frozendict==2.3.8
tqdm==4.66.1 tqdm==4.66.1
MutPy==0.6.1

View file

@ -1,20 +1,16 @@
from unittest import TestCase from unittest import TestCase
from benchmark.anagram_check import anagram_check from benchmark.anagram_check import anagram_check
class Test_anagram_check(TestCase): class Test_anagram_check(TestCase):
def test_anagram_check_1(self): def test_anagram_check_1(self):
assert anagram_check(s1='B', s2='o8') == False assert anagram_check(s1='@', s2='{') == False
def test_anagram_check_2(self): def test_anagram_check_2(self):
assert anagram_check(s1=' ', s2='u') == False assert anagram_check(s1='', s2='X~|') == False
def test_anagram_check_3(self): def test_anagram_check_3(self):
assert anagram_check(s1='', s2='') == True assert anagram_check(s1='?kv|d', s2='43J!j') == False
def test_anagram_check_4(self): def test_anagram_check_4(self):
assert anagram_check(s1='?8H', s2='') == False assert anagram_check(s1='U', s2='') == False
def test_anagram_check_5(self):
assert anagram_check(s1='@m', s2='Pj') == False

View file

@ -0,0 +1,19 @@
from unittest import TestCase
from benchmark.caesar_cipher import encrypt
from benchmark.caesar_cipher import decrypt
class Test_encrypt(TestCase):
def test_encrypt_1(self):
assert encrypt(strng='(B{6M K', key=90) == '#=v1HzF'
def test_encrypt_2(self):
assert encrypt(strng='t3Cv', key=84) == 'i(8k'
class Test_decrypt(TestCase):
def test_decrypt_1(self):
assert decrypt(strng='4.J<IH{', key=11) == ')#?1>=p'
def test_decrypt_2(self):
assert decrypt(strng='5v8K', key=32) == 'tVw+'

View file

@ -1,23 +0,0 @@
from unittest import TestCase
from benchmark.common_divisor_count import cd_count
class Test_cd_count(TestCase):
def test_cd_count_1(self):
assert cd_count(a=-946, b=0) == 2
def test_cd_count_2(self):
assert cd_count(a=873, b=164) == 1
def test_cd_count_3(self):
assert cd_count(a=0, b=-90) == 2
def test_cd_count_4(self):
assert cd_count(a=783, b=-749) == 1
def test_cd_count_5(self):
assert cd_count(a=621, b=-23) == 2
def test_cd_count_6(self):
assert cd_count(a=-635, b=444) == 1

View file

@ -1,20 +1,16 @@
from unittest import TestCase from unittest import TestCase
from benchmark.check_armstrong import check_armstrong from benchmark.check_armstrong import check_armstrong
class Test_check_armstrong(TestCase): class Test_check_armstrong(TestCase):
def test_check_armstrong_1(self): def test_check_armstrong_1(self):
assert check_armstrong(n=370) == True assert check_armstrong(n=220) == False
def test_check_armstrong_2(self): def test_check_armstrong_2(self):
assert check_armstrong(n=5) == False
def test_check_armstrong_3(self):
assert check_armstrong(n=1) == True
def test_check_armstrong_4(self):
assert check_armstrong(n=0) == True assert check_armstrong(n=0) == True
def test_check_armstrong_5(self): def test_check_armstrong_3(self):
assert check_armstrong(n=346) == False assert check_armstrong(n=35) == False
def test_check_armstrong_4(self):
assert check_armstrong(n=1) == True

View file

@ -0,0 +1,19 @@
from unittest import TestCase
from benchmark.common_divisor_count import cd_count
class Test_cd_count(TestCase):
def test_cd_count_1(self):
assert cd_count(a=-741, b=-457) == 2
def test_cd_count_2(self):
assert cd_count(a=111, b=99) == 6
def test_cd_count_3(self):
assert cd_count(a=740, b=-169) == 3
def test_cd_count_4(self):
assert cd_count(a=0, b=449) == 2
def test_cd_count_5(self):
assert cd_count(a=910, b=0) == 2

View file

@ -1,8 +0,0 @@
from unittest import TestCase
from benchmark.caesar_cipher import decrypt
class Test_decrypt(TestCase):
def test_decrypt_1(self):
assert decrypt(strng='\\nEGQ&', key=41) == '3E{}'

View file

@ -1,11 +0,0 @@
from unittest import TestCase
from benchmark.caesar_cipher import encrypt
class Test_encrypt(TestCase):
def test_encrypt_1(self):
assert encrypt(strng='ToU}[G4}', key=70) == ';V<dB.zd'
def test_encrypt_2(self):
assert encrypt(strng='Ja%b7$x?S', key=91) == 'F]!^3 t;O'

View file

@ -1,8 +1,7 @@
from unittest import TestCase from unittest import TestCase
from benchmark.exponentiation import exponentiation from benchmark.exponentiation import exponentiation
class Test_exponentiation(TestCase): class Test_exponentiation(TestCase):
def test_exponentiation_1(self): def test_exponentiation_1(self):
assert exponentiation(baseNumber=-963, power=53) == -135579247021508037271506970896774862890401757444424074712158036994660498207857413507120369768136011010001454548485109484383268428282840962739680900835831388403 assert exponentiation(baseNumber=771, power=474) == 2909210833489491293378842744086198556807698873805727913089141407566444307615874153703385291756938871584773318376082715282560979576003239005635105383696346203211241092618871232636438256963156478107480938401494345016352663544251711600300410294173581492138819773752393733341176714058194552308171277586141676868377612692878963273168698528314579277083563280084863520035365678210031287889772088909455822915896837639257753201805916075921630683337539958393092565260283310668864760181646358235718551645281913578630788801289878777658471432050952913833670208688658984707550985045490960816912971550665977523223101342154277056798749106996358053949918115208536589659714855628074010414625147806448539987417123348274550207168187859690445981358534944856355827734611140152400206513027687952209274470811281719393462377048863468859856738711318208410712979094433620095183415992926567580010288921145076938532560376641152027545404240780516247328096495417952049358953162107534093353491634575118361354594270772437236185212631466579892318815456992018956388226428774320211702200525700236584879799246396547556437518901096156284575576838239123951159155896959994089575333138430692507022983208229342846303747301555381846496103057947746652402219370385064952595644297390849057715440768800731610673913446165042850598544860086460108426470227274128434108967174102649421640276420078514555815576331215899881

View file

@ -1,20 +1,19 @@
from unittest import TestCase from unittest import TestCase
from benchmark.gcd import gcd from benchmark.gcd import gcd
class Test_gcd(TestCase): class Test_gcd(TestCase):
def test_gcd_1(self): def test_gcd_1(self):
assert gcd(a=531, b=338) == 1 assert gcd(a=1, b=292) == 1
def test_gcd_2(self): def test_gcd_2(self):
assert gcd(a=1, b=395) == 1 assert gcd(a=706, b=706) == 706
def test_gcd_3(self): def test_gcd_3(self):
assert gcd(a=71, b=496) == 1 assert gcd(a=506, b=1) == 1
def test_gcd_4(self): def test_gcd_4(self):
assert gcd(a=644, b=644) == 644 assert gcd(a=695, b=765) == 765
def test_gcd_5(self): def test_gcd_5(self):
assert gcd(a=581, b=1) == 1 assert gcd(a=140, b=29) == 140

View file

@ -1,8 +1,7 @@
from unittest import TestCase from unittest import TestCase
from benchmark.longest_substring import longest_sorted_substr from benchmark.longest_substring import longest_sorted_substr
class Test_longest_sorted_substr(TestCase): class Test_longest_sorted_substr(TestCase):
def test_longest_sorted_substr_1(self): def test_longest_sorted_substr_1(self):
assert longest_sorted_substr(s='YW|jsXG,u') == 'W|' assert longest_sorted_substr(s='sixBa') == 'ix'

16
tests/test_rabin_karp.py Normal file
View file

@ -0,0 +1,16 @@
from unittest import TestCase
from benchmark.rabin_karp import rabin_karp_search
class Test_rabin_karp_search(TestCase):
def test_rabin_karp_search_1(self):
assert rabin_karp_search(pat='3gx!', txt='~*J~%eC') == [0]
def test_rabin_karp_search_2(self):
assert rabin_karp_search(pat='`gO7Vq!kU', txt='=DLaH\\p~[') == []
def test_rabin_karp_search_3(self):
assert rabin_karp_search(pat='', txt='%gxypQ7L') == []
def test_rabin_karp_search_4(self):
assert rabin_karp_search(pat='@', txt='H@@|DPma"') == [1, 2]

View file

@ -1,20 +0,0 @@
from unittest import TestCase
from benchmark.rabin_karp import rabin_karp_search
class Test_rabin_karp_search(TestCase):
def test_rabin_karp_search_1(self):
assert rabin_karp_search(pat='', txt='m 2') == []
def test_rabin_karp_search_2(self):
assert rabin_karp_search(pat='.w5', txt='55[Ax5X') == []
def test_rabin_karp_search_3(self):
assert rabin_karp_search(pat='h@=y', txt='JcEC') == []
def test_rabin_karp_search_4(self):
assert rabin_karp_search(pat='X', txt='J@X"') == [2]
def test_rabin_karp_search_5(self):
assert rabin_karp_search(pat='>0OPQ', txt='Dzxu8:(P') == []

View file

@ -1,17 +0,0 @@
from unittest import TestCase
from benchmark.railfence_cipher import raildecrypt
class Test_raildecrypt(TestCase):
def test_raildecrypt_1(self):
assert raildecrypt(st='q338K a{.', k=9) == 'q338K a{.'
def test_raildecrypt_2(self):
assert raildecrypt(st='q338K a{.', k=3) == 'q8{K3 .a3'
def test_raildecrypt_3(self):
assert raildecrypt(st='Hi=BC/', k=557) == 'Hi=BC/'
def test_raildecrypt_4(self):
assert raildecrypt(st='X61*8p', k=5) == 'X61*p8'

View file

@ -1,14 +0,0 @@
from unittest import TestCase
from benchmark.railfence_cipher import railencrypt
class Test_railencrypt(TestCase):
def test_railencrypt_1(self):
assert railencrypt(st=')x8ro;BVm', k=865) == ')x8ro;BVm'
def test_railencrypt_2(self):
assert railencrypt(st='q338K a{.', k=4) == 'qa3 {3K.8'
def test_railencrypt_3(self):
assert railencrypt(st='X61*8p', k=5) == 'X61*p8'

View file

@ -0,0 +1,25 @@
from unittest import TestCase
from benchmark.railfence_cipher import railencrypt
from benchmark.railfence_cipher import raildecrypt
class Test_railencrypt(TestCase):
def test_railencrypt_1(self):
assert railencrypt(st='78l%K2', k=3) == '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
def test_railencrypt_2(self):
assert railencrypt(st='f', k=25) == '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
def test_railencrypt_3(self):
assert railencrypt(st='(la_UD^', k=2) == '\x00\x00\x00\x00\x00\x00\x00'
class Test_raildecrypt(TestCase):
def test_raildecrypt_1(self):
assert raildecrypt(st='(la_UD^', k=2) == ''
def test_raildecrypt_2(self):
assert raildecrypt(st="ZZ.B/8M'M", k=3) == ''
def test_raildecrypt_3(self):
assert raildecrypt(st='9[HS4', k=960) == ''

View file

@ -1,23 +0,0 @@
from unittest import TestCase
from benchmark.zellers_birthday import zeller
class Test_zeller(TestCase):
def test_zeller_1(self):
assert zeller(d=-134, m=797, y=67) == 'Sunday'
def test_zeller_2(self):
assert zeller(d=-156, m=10, y=-57) == 'Wednesday'
def test_zeller_3(self):
assert zeller(d=715, m=444, y=74) == 'Thursday'
def test_zeller_4(self):
assert zeller(d=-726, m=864, y=-16) == 'Thursday'
def test_zeller_5(self):
assert zeller(d=31, m=910, y=2) == 'Sunday'
def test_zeller_6(self):
assert zeller(d=369, m=-917, y=-1000) == 'Sunday'

View file

@ -0,0 +1,16 @@
from unittest import TestCase
from benchmark.zellers_birthday import zeller
class Test_zeller(TestCase):
def test_zeller_1(self):
assert zeller(d=-466, m=3, y=76) == 'Tuesday'
def test_zeller_2(self):
assert zeller(d=626, m=-928, y=27) == 'Saturday'
def test_zeller_3(self):
assert zeller(d=19, m=108, y=68) == 'Friday'
def test_zeller_4(self):
assert zeller(d=284, m=255, y=-6) == 'Thursday'