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)}"""
def get_test_class(f_name: str, cases: set[Params]) -> str:
f_name_orig = BranchTransformer.to_original_name(f_name)
def get_test_import_stmt(names: list[str]):
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"
f"class Test_{f_name_orig}(TestCase):\n")
test_class += "\n\n".join([get_test_case_source(f_name, case, i + 1, 1) for i, case in enumerate(cases)])
return test_class
for orig_f_name in names:
f_name = BranchTransformer.to_instrumented_name(orig_f_name)
imports.append(f"from {'.'.join(module_of[f_name])} import {orig_f_name}")
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 os
import random
import sys
from functools import partial
import frozendict
@ -56,8 +55,8 @@ def init_deap():
creator.create("Individual", list, fitness=creator.Fitness)
def generate(f_name: str):
orig_name = instrument.BranchTransformer.to_original_name(f_name)
def generate(orig_name: str) -> set[instrument.Params]:
f_name = instrument.BranchTransformer.to_instrumented_name(orig_name)
args = instrument.functions[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_coverage = cov
if tot_covered == total_branches:
break
return top_result
@ -150,11 +152,13 @@ def compute_fitness(f_name: str, archive: Archive, individual: list) -> tuple[fl
return fitness,
def build_suite(f_name: str):
instr_name = instrument.BranchTransformer.to_instrumented_name(f_name)
cases = generate(instr_name)
with open(os.path.join(OUT_DIR, "test_" + f_name + ".py"), "w") as f:
f.write(get_test_class(instr_name, cases))
def build_suite(filename: str, f_names: list[str]):
suite = [(name, generate(name)) for name in f_names]
with open(os.path.join(OUT_DIR, f"test_{filename}.py"), "w") as f:
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():
@ -169,9 +173,8 @@ def main():
instrument.load_benchmark(save_instrumented=False, files=parser.parse_args().file)
init_deap()
for instr_f in tqdm.tqdm(sorted(instrument.functions.keys()), desc="Generating tests"):
print("", file=sys.stderr)
build_suite(instrument.BranchTransformer.to_original_name(instr_f))
for file_name, functions in tqdm.tqdm(instrument.get_benchmark().items(), desc="Generating tests"):
build_suite(file_name, functions)
if __name__ == '__main__':

View file

@ -1,11 +1,13 @@
import ast
import os.path
import sys
from collections import defaultdict
from typing import Optional
import astunparse
import tqdm
from frozendict import frozendict
from operators import evaluate_condition
ROOT_DIR: str = os.path.dirname(__file__)
@ -85,7 +87,7 @@ SignatureDict = dict[str, list[Arg]]
n_of_branches: dict[str, tuple[int, int]] = {}
functions: SignatureDict = {}
module_of: dict[str, str] = {}
module_of: dict[str, list[str]] = {}
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))
functions[f.name] = arg_types
module_of[f.name] = os.path.normpath(os.path.relpath(source_path, ROOT_DIR)) \
.replace(".py", "") \
.replace("/", ".")
module_of[f.name] = os.path.splitext(os.path.normpath(os.path.relpath(source_path, ROOT_DIR)))[0].split("/")
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)})"
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__':
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
frozendict==2.3.8
tqdm==4.66.1
MutPy==0.6.1

View file

@ -1,20 +1,16 @@
from unittest import TestCase
from benchmark.anagram_check import anagram_check
class Test_anagram_check(TestCase):
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):
assert anagram_check(s1=' ', s2='u') == False
assert anagram_check(s1='', s2='X~|') == False
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):
assert anagram_check(s1='?8H', s2='') == False
def test_anagram_check_5(self):
assert anagram_check(s1='@m', s2='Pj') == False
assert anagram_check(s1='U', s2='') == 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 benchmark.check_armstrong import check_armstrong
class Test_check_armstrong(TestCase):
def test_check_armstrong_1(self):
assert check_armstrong(n=370) == True
assert check_armstrong(n=220) == False
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
def test_check_armstrong_5(self):
assert check_armstrong(n=346) == False
def test_check_armstrong_3(self):
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 benchmark.exponentiation import exponentiation
class Test_exponentiation(TestCase):
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 benchmark.gcd import gcd
class Test_gcd(TestCase):
def test_gcd_1(self):
assert gcd(a=531, b=338) == 1
assert gcd(a=1, b=292) == 1
def test_gcd_2(self):
assert gcd(a=1, b=395) == 1
assert gcd(a=706, b=706) == 706
def test_gcd_3(self):
assert gcd(a=71, b=496) == 1
assert gcd(a=506, b=1) == 1
def test_gcd_4(self):
assert gcd(a=644, b=644) == 644
assert gcd(a=695, b=765) == 765
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 benchmark.longest_substring import longest_sorted_substr
class Test_longest_sorted_substr(TestCase):
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'