This commit is contained in:
Claudio Maggioni 2023-12-18 15:13:31 +01:00
parent 8687b6f36a
commit a70deaf845
11 changed files with 118 additions and 175 deletions

View file

@ -18,7 +18,7 @@ CXPROB = 0.33
TOURNSIZE = 3 TOURNSIZE = 3
NPOP = 1000 NPOP = 1000
NGEN = 200 NGEN = 200
REPS = 1 REPS = 10
OUT_DIR = os.path.join(os.path.dirname(__file__), "tests") OUT_DIR = os.path.join(os.path.dirname(__file__), "tests")
@ -93,7 +93,6 @@ def generate(orig_name: str) -> set[instrument.Params]:
top_coverage = 0 top_coverage = 0
for i in range(REPS): for i in range(REPS):
archive.reset()
population = toolbox.population(n=NPOP) population = toolbox.population(n=NPOP)
# Create statistics object # Create statistics object
@ -103,10 +102,20 @@ def generate(orig_name: str) -> set[instrument.Params]:
population, logbook = algorithms.eaSimple(population, toolbox, CXPROB, MUPROB, NGEN, verbose=False, stats=stats) population, logbook = algorithms.eaSimple(population, toolbox, CXPROB, MUPROB, NGEN, verbose=False, stats=stats)
for gen, record in enumerate(logbook): print("population:\n" + "\n".join([str(p) for p in population]) + "\n")
print(f"Generation {gen}: min={record['min']} max={record['max']}")
print(population) for member in population:
m = frozendict.frozendict(member)
for branch in range(range_start, range_end):
if (branch in operators.distances_true and
operators.distances_true[branch] == 0 and branch not in archive.true_branches):
archive.true_branches[branch] = m
if (branch in operators.distances_false and
operators.distances_false[branch] == 0 and branch not in archive.false_branches):
archive.false_branches[branch] = m
# for gen, record in enumerate(logbook):
# print(f"Generation {gen}: min={record['min']} max={record['max']}")
tot_covered = archive.branches_covered() tot_covered = archive.branches_covered()
@ -114,6 +123,7 @@ def generate(orig_name: str) -> set[instrument.Params]:
branches = archive.branches_str() branches = archive.branches_str()
print(f"{orig_name}: rep #{i:02d}: Cov: {cov:02.02f}% ({tot_covered}/{total_branches} branches): {branches}") print(f"{orig_name}: rep #{i:02d}: Cov: {cov:02.02f}% ({tot_covered}/{total_branches} branches): {branches}")
print(archive.build_suite())
if cov > top_coverage: if cov > top_coverage:
top_result = archive.build_suite() top_result = archive.build_suite()
@ -132,8 +142,6 @@ def compute_fitness(f_name: str, archive: Archive, individual: list) -> tuple[fl
# Reset any distance values from previous executions # Reset any distance values from previous executions
operators.distances_true = {} operators.distances_true = {}
operators.distances_false = {} operators.distances_false = {}
# archive.true_branches = {}
# archive.false_branches = {}
# the archive_true_branches and archive_false_branches are reset after # the archive_true_branches and archive_false_branches are reset after
# each generation. This is intentional as they are used to archive branches that # each generation. This is intentional as they are used to archive branches that
@ -144,38 +152,29 @@ def compute_fitness(f_name: str, archive: Archive, individual: list) -> tuple[fl
try: try:
out = instrument.invoke(f_name, x) out = instrument.invoke(f_name, x)
except AssertionError: except AssertionError:
print(f_name, x, "=", "[FAILS] fitness = 100.0") # print(f_name, x, "=", "[FAILS] fitness = 100.0")
return 100.0, return 100.0,
fitness = 0.0 fitness = 0.0
branches = False #branches = False
# print(operators.distances_true, operators.distances_false)
# Sum up branch distances # Sum up branch distances
for branch in range(range_start, range_end): for branch in range(range_start, range_end):
if branch in operators.distances_true: if branch in operators.distances_true:
fitness += normalize(operators.distances_true[branch]) if branch not in archive.true_branches:
branches = True fitness += normalize(operators.distances_true[branch])
#branches = True
if operators.distances_true[branch] == 0: # if test is true for this branch
if branch not in archive.false_score or archive.false_score[branch] > operators.distances_false[branch]:
archive.true_branches[branch] = x
archive.false_score[branch] = operators.distances_false[branch]
for branch in range(range_start, range_end):
if branch in operators.distances_false: if branch in operators.distances_false:
fitness += normalize(operators.distances_false[branch]) if branch not in archive.false_branches:
branches = True fitness += normalize(operators.distances_false[branch])
#branches = True
if operators.distances_false[branch] == 0: # if test is true for this branch #if not branches:
if branch not in archive.true_score or archive.true_score[branch] > operators.distances_true[branch]: # return 100.0,
archive.false_branches[branch] = x
archive.true_score[branch] = operators.distances_true[branch]
if not branches: # print(f_name, x, "=", out, "fitness =", fitness)
return 100.0,
print(f_name, x, "=", out, "fitness =", fitness)
return fitness, return fitness,
@ -188,21 +187,27 @@ def build_suite(filename: str, f_names: list[str]):
f.write("\n\n".join([get_test_class(name, cases) for name, cases in suite])) f.write("\n\n".join([get_test_class(name, cases) for name, cases in suite]))
def main(): def run_genetic(files: list[str], seed: int):
random.seed(0) # init random seed instrument.load_benchmark(save_instrumented=False, files=files)
random.seed(seed) # init random seed
parser = argparse.ArgumentParser(prog='genetic.py',
description='Runs genetic algorithm for test case generation. Works on benchmark '
'files situated in the \'benchmark\' directory.')
parser.add_argument('file', type=str, help="File to test",
nargs="*")
instrument.load_benchmark(save_instrumented=False, files=parser.parse_args().file)
init_deap() init_deap()
for file_name, functions in tqdm.tqdm(instrument.get_benchmark().items(), desc="Generating tests"): for file_name, functions in tqdm.tqdm(instrument.get_benchmark().items(), desc="Generating tests"):
build_suite(file_name, functions) build_suite(file_name, functions)
def main():
parser = argparse.ArgumentParser(prog='genetic.py',
description='Runs genetic algorithm for test case generation. Works on benchmark '
'files situated in the \'benchmark\' directory.')
parser.add_argument('file', type=str, help="File to test",
nargs="*")
parser.add_argument('-s', '--seed', type=int, help="Random generator seed",
nargs="?", default=0)
args = parser.parse_args()
run_genetic(args.file, args.seed)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -119,9 +119,6 @@ def instrument(source_path: str, target_path: str, save_instrumented=True):
top_level_f_ast: list[ast.FunctionDef] = [f for f in node.body if isinstance(f, ast.FunctionDef)] top_level_f_ast: list[ast.FunctionDef] = [f for f in node.body if isinstance(f, ast.FunctionDef)]
for f in top_level_f_ast: for f in top_level_f_ast:
if f.name in functions:
raise ValueError(f"Function '{f.name}' already loaded from another file")
arg_types: list[Arg] = [] arg_types: list[Arg] = []
for arg in f.args.args: for arg in f.args.args:

View file

@ -1,9 +1,11 @@
import argparse import argparse
import os import os
import random
import re import re
import sys import sys
import instrument import instrument
from genetic import run_genetic
ROOT_DIR = os.path.dirname(__file__) ROOT_DIR = os.path.dirname(__file__)
IN_SOURCE_DIR = os.path.join(ROOT_DIR, "benchmark") IN_SOURCE_DIR = os.path.join(ROOT_DIR, "benchmark")
@ -12,6 +14,8 @@ OUT_DIR = os.path.join(ROOT_DIR, "tests")
def run_mutpy(test_path: str, source_path: str): def run_mutpy(test_path: str, source_path: str):
run_genetic([source_path], random.randint(0, 500))
stream = os.popen(f'mut.py --target \'{source_path}\' --unit-test \'{test_path}\' -m') stream = os.popen(f'mut.py --target \'{source_path}\' --unit-test \'{test_path}\' -m')
output = stream.read() output = stream.read()
score = re.search('Mutation score \\[.*\\]: (\d+\.\d+)\%', output).group(1) score = re.search('Mutation score \\[.*\\]: (\d+\.\d+)\%', output).group(1)
@ -27,14 +31,16 @@ def main():
files = parser.parse_args().file files = parser.parse_args().file
if len(files) == 0: if len(files) == 0:
to_test = instrument.get_benchmark().keys() files = [os.path.splitext(f) for f in os.listdir(IN_SOURCE_DIR)]
to_test = [file[0] for file in files if file[1] == ".py"]
else: else:
to_test = [os.path.splitext(os.path.basename(file))[0] for file in files] to_test = [os.path.splitext(os.path.basename(file))[0] for file in files]
for filename in to_test: for filename in to_test:
source_path = os.path.join(IN_SOURCE_DIR, f"{filename}.py") for i in range(10):
test_path = os.path.join(IN_TEST_DIR, f"test_{filename}.py") source_path = os.path.join(IN_SOURCE_DIR, f"{filename}.py")
run_mutpy(test_path, source_path) test_path = os.path.join(IN_TEST_DIR, f"test_{filename}.py")
run_mutpy(test_path, source_path)
if __name__ == "__main__": if __name__ == "__main__":

View file

@ -3,14 +3,17 @@ from benchmark.anagram_check import anagram_check
class Test_anagram_check(TestCase): class Test_anagram_check(TestCase):
# distances_true = {1: [0], 2: [1], 3: [0]}
# distances_false = {1: [1], 2: [0], 3: [1]}
def test_anagram_check_1(self): def test_anagram_check_1(self):
assert anagram_check(s1='@', s2='{') == False assert anagram_check(s1='Z', s2='') == False
# distances_true = {1: [0], 2: [0]}
# distances_false = {1: [1], 2: [1]}
def test_anagram_check_2(self): def test_anagram_check_2(self):
assert anagram_check(s1='', s2='X~|') == False assert anagram_check(s1='w', s2='t') == False
# distances_true = {1: [1], 3: [0]}
# distances_false = {1: [0], 3: [1]}
def test_anagram_check_3(self): def test_anagram_check_3(self):
assert anagram_check(s1='?kv|d', s2='43J!j') == False assert anagram_check(s1='', s2='f') == False
def test_anagram_check_4(self):
assert anagram_check(s1='U', s2='') == False

View file

@ -4,24 +4,14 @@ from benchmark.caesar_cipher import decrypt
class Test_encrypt(TestCase): class Test_encrypt(TestCase):
# distances_true = {1: [1]} # distances_true = {}
# distances_false = {1: [0]} # distances_false = {}
def test_encrypt_1(self): def test_encrypt_1(self):
assert encrypt(strng='U', key=41) == '~' assert encrypt(strng='', key=45) == ''
# distances_true = {1: [0]}
# distances_false = {1: [1]}
def test_encrypt_2(self):
assert encrypt(strng='h', key=23) == ' '
class Test_decrypt(TestCase): class Test_decrypt(TestCase):
# distances_true = {2: [1]} # distances_true = {2: [0, 211, 211, 0, 0, 196, 15, 221, 189]}
# distances_false = {2: [0]} # distances_false = {2: [13, 0, 0, 9, 24, 0, 0, 0, 0]}
def test_decrypt_1(self): def test_decrypt_1(self):
assert decrypt(strng='C', key=35) == ' ' assert decrypt(strng=']<<aR-xF&', key=74) == 'ròòvgã.üÜ'
# distances_true = {2: [0]}
# distances_false = {2: [1]}
def test_decrypt_2(self):
assert decrypt(strng='7', key=24) == '~'

View file

@ -3,27 +3,22 @@ from benchmark.check_armstrong import check_armstrong
class Test_check_armstrong(TestCase): class Test_check_armstrong(TestCase):
# distances_true = {1: [977], 2: [976], 3: [827], 4: [0, 0, 0, 1], 5: [438]}
# distances_false = {1: [0], 2: [0], 3: [0], 4: [977, 97, 9, 0], 5: [0]}
def test_check_armstrong_1(self):
assert check_armstrong(n=977) == False
# distances_true = {1: [0]} # distances_true = {1: [0]}
# distances_false = {1: [1]} # distances_false = {1: [1]}
def test_check_armstrong_1(self): def test_check_armstrong_2(self):
assert check_armstrong(n=0) == True assert check_armstrong(n=0) == True
# distances_true = {1: [2], 2: [1], 3: [0]} # distances_true = {1: [140], 2: [139], 3: [0]}
# distances_false = {1: [0], 2: [0], 3: [149]} # distances_false = {1: [0], 2: [0], 3: [11]}
def test_check_armstrong_2(self):
assert check_armstrong(n=2) == False
# distances_true = {1: [1], 2: [0]}
# distances_false = {1: [0], 2: [1]}
def test_check_armstrong_3(self): def test_check_armstrong_3(self):
assert check_armstrong(n=1) == True assert check_armstrong(n=140) == False
# distances_true = {1: [150], 2: [149], 3: [0]} # distances_true = {1: [3], 2: [2], 3: [0]}
# distances_false = {1: [0], 2: [0], 3: [1]} # distances_false = {1: [0], 2: [0], 3: [148]}
def test_check_armstrong_4(self): def test_check_armstrong_4(self):
assert check_armstrong(n=150) == False assert check_armstrong(n=3) == False
# distances_true = {1: [151], 2: [150], 3: [1], 4: [0], 5: [151]}
# distances_false = {1: [0], 2: [0], 3: [0], 4: [151], 5: [0]}
def test_check_armstrong_5(self):
assert check_armstrong(n=151) == False

View file

@ -3,17 +3,32 @@ from benchmark.common_divisor_count import cd_count
class Test_cd_count(TestCase): class Test_cd_count(TestCase):
# distances_true = {1: [7], 2: [561], 3: [8], 4: [0], 5: [0, 0, 1], 6: [0], 7: [0]}
# distances_false = {1: [0], 2: [0], 3: [0], 4: [561], 5: [7, 1, 0], 6: [1], 7: [1]}
def test_cd_count_1(self): def test_cd_count_1(self):
assert cd_count(a=-741, b=-457) == 2 assert cd_count(a=7, b=-561) == 1
# distances_true = {1: [496], 2: [9], 3: [0], 4: [10], 5: [0, 0, 0, 1], 6: [0], 7: [0]}
# distances_false = {1: [0], 2: [0], 3: [496], 4: [0], 5: [496, 9, 1, 0], 6: [1], 7: [1]}
def test_cd_count_2(self): def test_cd_count_2(self):
assert cd_count(a=111, b=99) == 6 assert cd_count(a=-496, b=9) == 1
# distances_true = {1: [1090], 2: [810], 3: [0], 4: [0], 5: [0, 0, 0, 0, 0, 0, 1], 6: [0, 0, 1], 7: [9, 3]}
# distances_false = {1: [0], 2: [0], 3: [1090], 4: [810], 5: [1090, 810, 280, 250, 30, 10, 0], 6: [1, 1, 0], 7: [0, 0]}
def test_cd_count_3(self): def test_cd_count_3(self):
assert cd_count(a=740, b=-169) == 3 assert cd_count(a=-1090, b=-810) == 4
# distances_true = {1: [771], 2: [0]}
# distances_false = {1: [0], 2: [1]}
def test_cd_count_4(self): def test_cd_count_4(self):
assert cd_count(a=0, b=449) == 2 assert cd_count(a=771, b=0) == 2
# distances_true = {1: [0]}
# distances_false = {1: [1]}
def test_cd_count_5(self): def test_cd_count_5(self):
assert cd_count(a=910, b=0) == 2 assert cd_count(a=0, b=-504) == 2
# distances_true = {1: [0]}
# distances_false = {1: [1]}
def test_cd_count_6(self):
assert cd_count(a=0, b=346) == 2

View file

@ -3,5 +3,7 @@ from benchmark.exponentiation import exponentiation
class Test_exponentiation(TestCase): class Test_exponentiation(TestCase):
# distances_true = {1: [0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 3: [0], 2: [1, 1, 1, 0, 1, 0, 1, 0, 0]}
# distances_false = {1: [554, 276, 137, 68, 33, 16, 7, 3, 1, 0], 3: [1], 2: [0, 0, 0, 1, 0, 1, 0, 1, 1]}
def test_exponentiation_1(self): def test_exponentiation_1(self):
assert exponentiation(baseNumber=771, power=474) == 2909210833489491293378842744086198556807698873805727913089141407566444307615874153703385291756938871584773318376082715282560979576003239005635105383696346203211241092618871232636438256963156478107480938401494345016352663544251711600300410294173581492138819773752393733341176714058194552308171277586141676868377612692878963273168698528314579277083563280084863520035365678210031287889772088909455822915896837639257753201805916075921630683337539958393092565260283310668864760181646358235718551645281913578630788801289878777658471432050952913833670208688658984707550985045490960816912971550665977523223101342154277056798749106996358053949918115208536589659714855628074010414625147806448539987417123348274550207168187859690445981358534944856355827734611140152400206513027687952209274470811281719393462377048863468859856738711318208410712979094433620095183415992926567580010288921145076938532560376641152027545404240780516247328096495417952049358953162107534093353491634575118361354594270772437236185212631466579892318815456992018956388226428774320211702200525700236584879799246396547556437518901096156284575576838239123951159155896959994089575333138430692507022983208229342846303747301555381846496103057947746652402219370385064952595644297390849057715440768800731610673913446165042850598544860086460108426470227274128434108967174102649421640276420078514555815576331215899881 assert exponentiation(baseNumber=46, power=555) == 67701233776950740204942019458828678585228142727678765936712535724840687550392116600906870144545698010222155411454260850560248023622100924992829889775933434061810832462573875369185421327277159309564167510534321885543792397713571903199824376891708112137193105827711458802486745550166352806857564334946534837344031123784629760780542963072605426968444846293162755227316493959098410341690649453984690766001914535282833132048115400743640541717271552222480474321128912084160330658824454957670614550610057315309451870771464295316404482951582420308563847120161312137794517827199490374669737373326830613443532865503190040204882188234457906737870995608971298860024320484356074519686361893084826607266908460838607722699711920001088429651680486816904830482100545984931012988682700360948582560942831753442007911350372119223160722859489509754277036741791779555164722595786304251143106041689420581326006007810981939096858483944366828158976

View file

@ -2,18 +2,3 @@ from unittest import TestCase
from benchmark.gcd import gcd from benchmark.gcd import gcd
class Test_gcd(TestCase):
def test_gcd_1(self):
assert gcd(a=1, b=292) == 1
def test_gcd_2(self):
assert gcd(a=706, b=706) == 706
def test_gcd_3(self):
assert gcd(a=506, b=1) == 1
def test_gcd_4(self):
assert gcd(a=695, b=765) == 765
def test_gcd_5(self):
assert gcd(a=140, b=29) == 140

File diff suppressed because one or more lines are too long

View file

@ -3,47 +3,17 @@ from benchmark.zellers_birthday import zeller
class Test_zeller(TestCase): class Test_zeller(TestCase):
# distances_true = {1: [0], 2: [0], 3: [0], 4: [27], 5: [0], 6: [0], 7: [0], 8: [6, 5, 4, 3, 2, 1, 0]} # distances_true = {1: [0], 2: [0], 3: [901], 5: [901], 7: [0], 8: [3, 2, 1, 0]}
# distances_false = {1: [607], 2: [301], 3: [51], 4: [0], 5: [51], 6: [0], 7: [1], 8: [0, 0, 0, 0, 0, 0, 1]} # distances_false = {1: [1], 2: [913], 3: [0], 5: [0], 7: [1], 8: [0, 0, 0, 1]}
def test_zeller_1(self): def test_zeller_1(self):
assert zeller(d=-638, m=313, y=49) == 'Saturday' assert zeller(d=32, m=-925, y=-1000) == 'Wednesday'
# distances_true = {1: [0], 2: [0], 3: [0], 4: [35], 5: [0], 6: [0], 7: [0], 8: [6, 5, 4, 3, 2, 1, 0]} # distances_true = {1: [0], 2: [0], 3: [0], 4: [0], 5: [1903], 7: [7], 8: [2, 1, 0]}
# distances_false = {1: [125], 2: [1], 3: [43], 4: [0], 5: [43], 6: [0], 7: [1], 8: [0, 0, 0, 0, 0, 0, 1]} # distances_false = {1: [691], 2: [536], 3: [98], 4: [21], 5: [0], 7: [0], 8: [0, 0, 1]}
def test_zeller_2(self): def test_zeller_2(self):
assert zeller(d=-156, m=13, y=-57) == 'Saturday' assert zeller(d=-722, m=548, y=-2) == 'Tuesday'
# distances_true = {1: [0], 2: [0], 3: [0], 4: [1], 5: [0], 6: [0], 7: [10], 8: [3, 2, 1, 0]} # distances_true = {1: [0], 2: [7], 3: [0], 4: [1], 5: [0], 6: [0], 7: [4], 8: [4, 3, 2, 1, 0]}
# distances_false = {1: [600], 2: [863], 3: [77], 4: [0], 5: [77], 6: [1], 7: [0], 8: [0, 0, 0, 1]} # distances_false = {1: [285], 2: [0], 3: [77], 4: [0], 5: [77], 6: [1], 7: [0], 8: [0, 0, 0, 0, 1]}
def test_zeller_3(self): def test_zeller_3(self):
assert zeller(d=-631, m=-875, y=23) == 'Wednesday' assert zeller(d=316, m=6, y=-23) == 'Thursday'
# distances_true = {1: [0], 2: [0], 3: [0], 4: [37], 5: [0], 6: [0], 7: [1], 8: [6, 5, 4, 3, 2, 1, 0]}
# distances_false = {1: [571], 2: [458], 3: [41], 4: [0], 5: [41], 6: [0], 7: [0], 8: [0, 0, 0, 0, 0, 0, 1]}
def test_zeller_4(self):
assert zeller(d=602, m=-470, y=59) == 'Saturday'
# distances_true = {1: [0], 2: [1], 3: [0], 4: [3], 5: [0], 6: [0], 7: [10], 8: [1, 0]}
# distances_false = {1: [392], 2: [0], 3: [75], 4: [0], 5: [75], 6: [0], 7: [0], 8: [0, 1]}
def test_zeller_5(self):
assert zeller(d=423, m=12, y=-25) == 'Monday'
# distances_true = {1: [0], 2: [0], 3: [0], 4: [0], 5: [1903], 7: [9], 8: [0]}
# distances_false = {1: [9], 2: [898], 3: [98], 4: [21], 5: [0], 7: [0], 8: [1]}
def test_zeller_6(self):
assert zeller(d=40, m=910, y=2) == 'Sunday'
# distances_true = {1: [0], 2: [0], 3: [0], 4: [77], 5: [0], 6: [0], 7: [3], 8: [4, 3, 2, 1, 0]}
# distances_false = {1: [584], 2: [652], 3: [1], 4: [0], 5: [1], 6: [0], 7: [0], 8: [0, 0, 0, 0, 1]}
def test_zeller_7(self):
assert zeller(d=-615, m=-664, y=-99) == 'Thursday'
# distances_true = {1: [0], 2: [0], 3: [0], 4: [0], 5: [1923], 7: [1], 8: [4, 3, 2, 1, 0]}
# distances_false = {1: [40], 2: [758], 3: [78], 4: [1], 5: [0], 7: [0], 8: [0, 0, 0, 0, 1]}
def test_zeller_8(self):
assert zeller(d=-71, m=-770, y=-22) == 'Thursday'
# distances_true = {1: [0], 2: [0], 3: [901], 5: [901], 7: [4], 8: [0]}
# distances_false = {1: [338], 2: [905], 3: [0], 5: [0], 7: [0], 8: [1]}
def test_zeller_9(self):
assert zeller(d=369, m=-917, y=-1000) == 'Sunday'