This commit is contained in:
Claudio Maggioni 2023-12-09 17:56:04 +01:00
parent 7ca85a871d
commit 6bb60c3323
17 changed files with 167 additions and 129 deletions

View file

@ -84,7 +84,7 @@ def random_params(arguments: list[Arg]) -> Params:
pools: dict[tuple, set[tuple]] = {} pools: dict[tuple, set[tuple]] = {}
def get_pool(arguments: list[Arg]) -> set[Params]: def get_pool(arguments: list[Arg]) -> list[Params]:
arg_types = tuple([arg_type for _, arg_type in arguments]) arg_types = tuple([arg_type for _, arg_type in arguments])
arg_names = [arg_name for arg_name, _ in arguments] arg_names = [arg_name for arg_name, _ in arguments]
@ -103,7 +103,7 @@ def get_pool(arguments: list[Arg]) -> set[Params]:
pools[arg_types] = new_pool pools[arg_types] = new_pool
return set([frozendict({arg_names[i]: p for i, p in enumerate(param)}) for param in pools[arg_types]]) return [frozendict({arg_names[i]: p for i, p in enumerate(param)}) for param in pools[arg_types]]
def mutate(test_case: Params, arguments: list[Arg]) -> Params: def mutate(test_case: Params, arguments: list[Arg]) -> Params:
@ -132,7 +132,7 @@ def crossover(chosen_test: Params, other_chosen_test: Params, arguments: list[Ar
def generate_test_case(f_name: str, arguments: list[Arg]) -> Params: def generate_test_case(f_name: str, arguments: list[Arg]) -> Params:
pool: set[Params] = get_pool(arguments) pool: list[Params] = get_pool(arguments)
while True: while True:
test = sample(pool, 1)[0] test = sample(pool, 1)[0]

View file

@ -1,6 +1,8 @@
import argparse
import os import os
import random import random
import sys import sys
from functools import partial
import frozendict import frozendict
import tqdm import tqdm
@ -8,6 +10,7 @@ from deap import creator, base, tools, algorithms
import fuzzer import fuzzer
import instrument import instrument
import operators
from fuzzer import generate_test_case, get_test_class from fuzzer import generate_test_case, get_test_class
INDMUPROB = 0.05 INDMUPROB = 0.05
@ -18,11 +21,32 @@ NPOP = 1000
NGEN = 200 NGEN = 200
REPS = 10 REPS = 10
to_test: str = ""
OUT_DIR = os.path.join(os.path.dirname(__file__), "tests") OUT_DIR = os.path.join(os.path.dirname(__file__), "tests")
class Archive:
true_branches: dict[int, any]
false_branches: dict[int, any]
def __init__(self):
self.reset()
def reset(self):
self.true_branches = {}
self.false_branches = {}
def branches_covered(self) -> int:
return len(self.true_branches.keys()) + len(self.false_branches.keys())
def branches_str(self) -> str:
branch_ids = sorted([f"{branch:2d}T" for branch in self.true_branches.keys()] +
[f"{branch:2d}F" for branch in self.false_branches.keys()])
return ' '.join([branch.strip() for branch in branch_ids])
def build_suite(self) -> set[instrument.Params]:
return set(list(self.true_branches.values()) + list(self.false_branches.values()))
def normalize(x): def normalize(x):
return x / (1.0 + x) return x / (1.0 + x)
@ -32,25 +56,19 @@ def init_deap():
creator.create("Individual", list, fitness=creator.Fitness) creator.create("Individual", list, fitness=creator.Fitness)
def taken_branches_descriptor() -> str:
branch_ids = sorted([f"{branch:2d}T" for branch in instrument.archive_true_branches.keys()] +
[f"{branch:2d}F" for branch in instrument.archive_false_branches.keys()])
return ' '.join([branch.strip() for branch in branch_ids])
def generate(f_name: str): def generate(f_name: str):
global to_test
to_test = f_name
orig_name = instrument.BranchTransformer.to_original_name(f_name) orig_name = instrument.BranchTransformer.to_original_name(f_name)
args = instrument.functions[f_name] args = instrument.functions[f_name]
range_start, range_end = instrument.n_of_branches[f_name]
total_branches = (range_end - range_start) * 2 # *2 because of True and False
archive = Archive()
toolbox = base.Toolbox() toolbox = base.Toolbox()
toolbox.register("attr_test_case", lambda: list(generate_test_case(f_name, args).items())) toolbox.register("attr_test_case", lambda: list(generate_test_case(f_name, args).items()))
toolbox.register("individual", tools.initIterate, creator.Individual, lambda: toolbox.attr_test_case()) toolbox.register("individual", tools.initIterate, creator.Individual, lambda: toolbox.attr_test_case())
toolbox.register("population", tools.initRepeat, list, toolbox.individual) toolbox.register("population", tools.initRepeat, list, toolbox.individual)
toolbox.register("evaluate", compute_fitness) toolbox.register("evaluate", partial(compute_fitness, f_name, archive))
def mate(tc1, tc2): def mate(tc1, tc2):
t1, t2 = frozendict.frozendict(tc1), frozendict.frozendict(tc2) t1, t2 = frozendict.frozendict(tc1), frozendict.frozendict(tc2)
@ -71,44 +89,33 @@ def generate(f_name: str):
top_result = set() top_result = set()
top_coverage = 0 top_coverage = 0
range_start, range_end = instrument.n_of_branches[to_test]
total_branches = (range_end - range_start) * 2 # *2 because of True and False
coverage = []
for i in range(REPS): for i in range(REPS):
instrument.archive_true_branches = {} archive.reset()
instrument.archive_false_branches = {}
population = toolbox.population(n=NPOP) population = toolbox.population(n=NPOP)
algorithms.eaSimple(population, toolbox, CXPROB, MUPROB, NGEN, verbose=False) algorithms.eaSimple(population, toolbox, CXPROB, MUPROB, NGEN, verbose=False)
true_covered = len(instrument.archive_true_branches.keys()) tot_covered = archive.branches_covered()
false_covered = len(instrument.archive_false_branches.keys())
tot_covered = true_covered + false_covered
cov: float = (tot_covered / total_branches) * 100 cov: float = (tot_covered / total_branches) * 100
coverage.append(cov)
branches = taken_branches_descriptor() 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}")
if cov > top_coverage: if cov > top_coverage:
top_result = set(list(instrument.archive_true_branches.values()) + top_result = archive.build_suite()
list(instrument.archive_false_branches.values()))
top_coverage = cov top_coverage = cov
print(coverage)
return top_result return top_result
def compute_fitness(individual: list) -> tuple[float]: def compute_fitness(f_name: str, archive: Archive, individual: list) -> tuple[float]:
x = frozendict.frozendict(individual) x = frozendict.frozendict(individual)
range_start, range_end = instrument.n_of_branches[to_test] range_start, range_end = instrument.n_of_branches[f_name]
# Reset any distance values from previous executions # Reset any distance values from previous executions
instrument.distances_true = {} operators.distances_true = {}
instrument.distances_false = {} operators.distances_false = {}
# 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
@ -117,7 +124,7 @@ def compute_fitness(individual: list) -> tuple[float]:
# Run the function under test # Run the function under test
try: try:
out = instrument.invoke(to_test, x) instrument.invoke(f_name, x)
except AssertionError: except AssertionError:
# print(to_test, x, "=", "[FAILS] fitness = 100.0") # print(to_test, x, "=", "[FAILS] fitness = 100.0")
return 100.0, return 100.0,
@ -126,18 +133,18 @@ def compute_fitness(individual: list) -> tuple[float]:
# 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 instrument.distances_true: if branch in operators.distances_true:
if instrument.distances_true[branch] == 0 and branch not in instrument.archive_true_branches: if operators.distances_true[branch] == 0 and branch not in archive.true_branches:
instrument.archive_true_branches[branch] = x archive.true_branches[branch] = x
if branch not in instrument.archive_true_branches: if branch not in archive.true_branches:
fitness += normalize(instrument.distances_true[branch]) fitness += normalize(operators.distances_true[branch])
for branch in range(range_start, range_end): for branch in range(range_start, range_end):
if branch in instrument.distances_false: if branch in operators.distances_false:
if instrument.distances_false[branch] == 0 and branch not in instrument.archive_false_branches: if operators.distances_false[branch] == 0 and branch not in archive.false_branches:
instrument.archive_false_branches[branch] = x archive.false_branches[branch] = x
if branch not in instrument.archive_false_branches: if branch not in archive.false_branches:
fitness += normalize(instrument.distances_false[branch]) fitness += normalize(operators.distances_false[branch])
# print(to_test, x, "=", out, "fitness =", fitness) # print(to_test, x, "=", out, "fitness =", fitness)
return fitness, return fitness,
@ -146,13 +153,20 @@ def compute_fitness(individual: list) -> tuple[float]:
def build_suite(f_name: str): def build_suite(f_name: str):
instr_name = instrument.BranchTransformer.to_instrumented_name(f_name) instr_name = instrument.BranchTransformer.to_instrumented_name(f_name)
cases = generate(instr_name) cases = generate(instr_name)
with open(os.path.join(OUT_DIR, f_name + ".py"), "w") as f: with open(os.path.join(OUT_DIR, "test_" + f_name + ".py"), "w") as f:
f.write(get_test_class(instr_name, cases)) f.write(get_test_class(instr_name, cases))
def main(): def main():
random.seed(0) # init random seed random.seed(0) # init random seed
instrument.load_benchmark(save_instrumented=False) # instrument all files in benchmark
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 instr_f in tqdm.tqdm(sorted(instrument.functions.keys()), desc="Generating tests"): for instr_f in tqdm.tqdm(sorted(instrument.functions.keys()), desc="Generating tests"):

View file

@ -1,28 +1,18 @@
from typing import Optional import ast
import os.path import os.path
import sys
from typing import Optional
import astunparse
import tqdm import tqdm
from frozendict import frozendict from frozendict import frozendict
from operators import evaluate_condition
import ast
import astunparse
import sys
import random
from operators import compute_distances
# hyperparameters
ROOT_DIR: str = os.path.dirname(__file__) ROOT_DIR: str = os.path.dirname(__file__)
IN_DIR: str = os.path.join(ROOT_DIR, 'benchmark') IN_DIR: str = os.path.join(ROOT_DIR, 'benchmark')
OUT_DIR: str = os.path.join(ROOT_DIR, 'instrumented') OUT_DIR: str = os.path.join(ROOT_DIR, 'instrumented')
SUFFIX: str = "_instrumented" SUFFIX: str = "_instrumented"
distances_true: dict[int, int] = {}
distances_false: dict[int, int] = {}
# Archive of solutions
archive_true_branches: dict[int, any] = {}
archive_false_branches: dict[int, any] = {}
class BranchTransformer(ast.NodeTransformer): class BranchTransformer(ast.NodeTransformer):
branches_range: dict[str, tuple[int, int]] branches_range: dict[str, tuple[int, int]]
@ -78,7 +68,7 @@ class BranchTransformer(ast.NodeTransformer):
return self.generic_visit(ast_node) return self.generic_visit(ast_node)
self.branch_num += 1 self.branch_num += 1
return ast.Call(func=ast.Name("evaluate_condition", ast.Load()), return ast.Call(func=ast.Name(evaluate_condition.__name__, ast.Load()),
args=[ast.Num(self.branch_num), args=[ast.Num(self.branch_num),
ast.Str(ast_node.ops[0].__class__.__name__), ast.Str(ast_node.ops[0].__class__.__name__),
ast_node.left, ast_node.left,
@ -88,41 +78,6 @@ class BranchTransformer(ast.NodeTransformer):
kwargs=None) kwargs=None)
def update_maps(condition_num, d_true, d_false):
global distances_true, distances_false
if condition_num in distances_true.keys():
distances_true[condition_num] = min(distances_true[condition_num], d_true)
else:
distances_true[condition_num] = d_true
if condition_num in distances_false.keys():
distances_false[condition_num] = min(distances_false[condition_num], d_false)
else:
distances_false[condition_num] = d_false
def evaluate_condition(num, op, lhs, rhs): # type: ignore
if op == "In":
if isinstance(lhs, str):
lhs = ord(lhs)
minimum = sys.maxsize
for elem in rhs.keys():
distance = abs(lhs - ord(elem))
if distance < minimum:
minimum = distance
distance_true, distance_false = minimum, 1 if minimum == 0 else 0
else:
distance_true, distance_false = compute_distances(op, lhs, rhs)
update_maps(num, distance_true, distance_false)
# distance == 0 equivalent to actual test by construction
return distance_true == 0
ArgType = str ArgType = str
Arg = tuple[str, ArgType] Arg = tuple[str, ArgType]
Params = frozendict[str, any] Params = frozendict[str, any]
@ -203,9 +158,14 @@ def find_py_files(search_dir: str):
yield os.path.join(cwd, file) yield os.path.join(cwd, file)
def load_benchmark(save_instrumented=True): def load_benchmark(save_instrumented=True, files: list[str] = ()):
to_load = set([os.path.splitext(os.path.basename(file))[0] + ".py" for file in files])
do_all = len(to_load) == 0
for file in tqdm.tqdm(find_py_files(IN_DIR), desc="Instrumenting"): for file in tqdm.tqdm(find_py_files(IN_DIR), desc="Instrumenting"):
instrument(file, os.path.join(OUT_DIR, os.path.basename(file)), save_instrumented=save_instrumented) filename = os.path.basename(file)
if do_all or filename in to_load:
instrument(file, os.path.join(OUT_DIR, filename), save_instrumented=save_instrumented)
def call_statement(f_name: str, f_args: Params) -> str: def call_statement(f_name: str, f_args: Params) -> str:

View file

@ -1,9 +1,13 @@
import sys
from dataclasses import dataclass from dataclasses import dataclass
from typing import TypeVar, Callable
from typing import Generic from typing import Generic
from typing import TypeVar, Callable
from nltk import edit_distance from nltk import edit_distance
distances_true: dict[int, int] = {}
distances_false: dict[int, int] = {}
T = TypeVar('T') T = TypeVar('T')
U = TypeVar('U') U = TypeVar('U')
@ -100,7 +104,7 @@ def str_check(a: any, b: any) -> bool:
return type(a) == str and type(b) == str return type(a) == str and type(b) == str
def compute_distances(name: str, lhs: any, rhs: any) -> tuple[int, int]: def compute_distances(name: str, lhs: any, rhs: any) -> tuple[int, int, bool]:
if int_str_check(lhs, rhs): if int_str_check(lhs, rhs):
lhs_int = int_str_convert(lhs) lhs_int = int_str_convert(lhs)
rhs_int = int_str_convert(rhs) rhs_int = int_str_convert(rhs)
@ -109,13 +113,50 @@ def compute_distances(name: str, lhs: any, rhs: any) -> tuple[int, int]:
raise ValueError(f"'{name}' is not a valid CmpOp name for 'int_str' operators") raise ValueError(f"'{name}' is not a valid CmpOp name for 'int_str' operators")
op = int_str_by_name[name] op = int_str_by_name[name]
return op.true_dist(lhs_int, rhs_int), op.false_dist(lhs_int, rhs_int) return op.true_dist(lhs_int, rhs_int), op.false_dist(lhs_int, rhs_int), op.test(lhs_int, rhs_int)
if str_check(lhs, rhs): if str_check(lhs, rhs):
if name not in str_by_name: if name not in str_by_name:
raise ValueError(f"'{name}' is not a valid CmpOp name for 'str' operators") raise ValueError(f"'{name}' is not a valid CmpOp name for 'str' operators")
op = str_by_name[name] op = str_by_name[name]
return op.true_dist(lhs, rhs), op.false_dist(lhs, rhs) return op.true_dist(lhs, rhs), op.false_dist(lhs, rhs), op.test(lhs, rhs)
raise ValueError(f"'{lhs}' and '{rhs}' are not suitable for both 'int_str' and 'str' operators") raise ValueError(f"'{lhs}' and '{rhs}' are not suitable for both 'int_str' and 'str' operators")
def update_map(the_map: dict[int, int], condition_num: int, distance: int):
if condition_num in the_map.keys():
the_map[condition_num] = min(the_map[condition_num], distance)
else:
the_map[condition_num] = distance
def update_maps(condition_num, d_true, d_false):
global distances_true, distances_false
update_map(distances_true, condition_num, d_true)
update_map(distances_false, condition_num, d_false)
def in_op(num, lhs, rhs):
if isinstance(lhs, str):
lhs = ord(lhs)
minimum = sys.maxsize
for elem in rhs.keys():
distance = abs(lhs - ord(elem))
if distance < minimum:
minimum = distance
distance_true, distance_false = minimum, 1 if minimum == 0 else 0
update_maps(num, distance_true, distance_false)
return distance_true == 0 # distance == 0 equivalent to actual test by construction
def evaluate_condition(num, op, lhs, rhs):
if op == "In":
return in_op(num, lhs, rhs)
distance_true, distance_false, test = compute_distances(op, lhs, rhs)
update_maps(num, distance_true, distance_false)
return test

View file

@ -1,6 +1,3 @@
/usr/local/bin/python3.10 /Volumes/Data/git/kse/project-02-python-test-generator-maggicl/genetic.py
Instrumenting: 10it [00:00, 722.61it/s]
Generating tests: 0%| | 0/12 [00:00<?, ?it/s]
anagram_check: rep #00: Cov: 87.50% (7/8 branches): 1F 1T 2F 2T 3F 3T 4F anagram_check: rep #00: Cov: 87.50% (7/8 branches): 1F 1T 2F 2T 3F 3T 4F
anagram_check: rep #01: Cov: 87.50% (7/8 branches): 1F 1T 2F 2T 3F 3T 4F anagram_check: rep #01: Cov: 87.50% (7/8 branches): 1F 1T 2F 2T 3F 3T 4F
anagram_check: rep #02: Cov: 100.00% (8/8 branches): 1F 1T 2F 2T 3F 3T 4F 4T anagram_check: rep #02: Cov: 100.00% (8/8 branches): 1F 1T 2F 2T 3F 3T 4F 4T
@ -11,8 +8,6 @@ anagram_check: rep #06: Cov: 100.00% (8/8 branches): 1F 1T 2F 2T 3F 3T 4F 4T
anagram_check: rep #07: Cov: 100.00% (8/8 branches): 1F 1T 2F 2T 3F 3T 4F 4T anagram_check: rep #07: Cov: 100.00% (8/8 branches): 1F 1T 2F 2T 3F 3T 4F 4T
anagram_check: rep #08: Cov: 87.50% (7/8 branches): 1F 1T 2F 2T 3F 3T 4F anagram_check: rep #08: Cov: 87.50% (7/8 branches): 1F 1T 2F 2T 3F 3T 4F
anagram_check: rep #09: Cov: 100.00% (8/8 branches): 1F 1T 2F 2T 3F 3T 4F 4T anagram_check: rep #09: Cov: 100.00% (8/8 branches): 1F 1T 2F 2T 3F 3T 4F 4T
[87.5, 87.5, 100.0, 87.5, 87.5, 87.5, 100.0, 100.0, 87.5, 100.0]
Generating tests: 8%|▊ | 1/12 [01:05<12:02, 65.64s/it]
cd_count: rep #00: Cov: 100.00% (14/14 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T 6F 6T 7F 7T cd_count: rep #00: Cov: 100.00% (14/14 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T 6F 6T 7F 7T
cd_count: rep #01: Cov: 100.00% (14/14 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T 6F 6T 7F 7T cd_count: rep #01: Cov: 100.00% (14/14 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T 6F 6T 7F 7T
cd_count: rep #02: Cov: 100.00% (14/14 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T 6F 6T 7F 7T cd_count: rep #02: Cov: 100.00% (14/14 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T 6F 6T 7F 7T
@ -23,8 +18,6 @@ cd_count: rep #06: Cov: 100.00% (14/14 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T
cd_count: rep #07: Cov: 100.00% (14/14 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T 6F 6T 7F 7T cd_count: rep #07: Cov: 100.00% (14/14 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T 6F 6T 7F 7T
cd_count: rep #08: Cov: 100.00% (14/14 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T 6F 6T 7F 7T cd_count: rep #08: Cov: 100.00% (14/14 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T 6F 6T 7F 7T
cd_count: rep #09: Cov: 100.00% (14/14 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T 6F 6T 7F 7T cd_count: rep #09: Cov: 100.00% (14/14 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T 6F 6T 7F 7T
[100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0]
Generating tests: 17%|█▋ | 2/12 [02:30<12:50, 77.04s/it]
check_armstrong: rep #00: Cov: 100.00% (10/10 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T check_armstrong: rep #00: Cov: 100.00% (10/10 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T
check_armstrong: rep #01: Cov: 100.00% (10/10 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T check_armstrong: rep #01: Cov: 100.00% (10/10 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T
check_armstrong: rep #02: Cov: 100.00% (10/10 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T check_armstrong: rep #02: Cov: 100.00% (10/10 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T
@ -35,8 +28,6 @@ check_armstrong: rep #06: Cov: 100.00% (10/10 branches): 1F 1T 2F 2T 3F 3T 4F 4T
check_armstrong: rep #07: Cov: 100.00% (10/10 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T check_armstrong: rep #07: Cov: 100.00% (10/10 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T
check_armstrong: rep #08: Cov: 100.00% (10/10 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T check_armstrong: rep #08: Cov: 100.00% (10/10 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T
check_armstrong: rep #09: Cov: 100.00% (10/10 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T check_armstrong: rep #09: Cov: 100.00% (10/10 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T
[100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0]
Generating tests: 25%|██▌ | 3/12 [03:36<10:45, 71.73s/it]
decrypt: rep #00: Cov: 100.00% (2/2 branches): 2F 2T decrypt: rep #00: Cov: 100.00% (2/2 branches): 2F 2T
decrypt: rep #01: Cov: 100.00% (2/2 branches): 2F 2T decrypt: rep #01: Cov: 100.00% (2/2 branches): 2F 2T
decrypt: rep #02: Cov: 100.00% (2/2 branches): 2F 2T decrypt: rep #02: Cov: 100.00% (2/2 branches): 2F 2T
@ -47,8 +38,6 @@ decrypt: rep #06: Cov: 100.00% (2/2 branches): 2F 2T
decrypt: rep #07: Cov: 100.00% (2/2 branches): 2F 2T decrypt: rep #07: Cov: 100.00% (2/2 branches): 2F 2T
decrypt: rep #08: Cov: 100.00% (2/2 branches): 2F 2T decrypt: rep #08: Cov: 100.00% (2/2 branches): 2F 2T
decrypt: rep #09: Cov: 100.00% (2/2 branches): 2F 2T decrypt: rep #09: Cov: 100.00% (2/2 branches): 2F 2T
[100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0]
Generating tests: 33%|███▎ | 4/12 [04:49<09:40, 72.50s/it]
encrypt: rep #00: Cov: 100.00% (2/2 branches): 1F 1T encrypt: rep #00: Cov: 100.00% (2/2 branches): 1F 1T
encrypt: rep #01: Cov: 100.00% (2/2 branches): 1F 1T encrypt: rep #01: Cov: 100.00% (2/2 branches): 1F 1T
encrypt: rep #02: Cov: 100.00% (2/2 branches): 1F 1T encrypt: rep #02: Cov: 100.00% (2/2 branches): 1F 1T
@ -59,8 +48,6 @@ encrypt: rep #06: Cov: 100.00% (2/2 branches): 1F 1T
encrypt: rep #07: Cov: 100.00% (2/2 branches): 1F 1T encrypt: rep #07: Cov: 100.00% (2/2 branches): 1F 1T
encrypt: rep #08: Cov: 100.00% (2/2 branches): 1F 1T encrypt: rep #08: Cov: 100.00% (2/2 branches): 1F 1T
encrypt: rep #09: Cov: 100.00% (2/2 branches): 1F 1T encrypt: rep #09: Cov: 100.00% (2/2 branches): 1F 1T
[100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0]
Generating tests: 42%|████▏ | 5/12 [06:04<08:31, 73.13s/it]
exponentiation: rep #00: Cov: 62.50% (5/8 branches): 1F 1T 2F 2T 3T exponentiation: rep #00: Cov: 62.50% (5/8 branches): 1F 1T 2F 2T 3T
exponentiation: rep #01: Cov: 62.50% (5/8 branches): 1F 1T 2F 2T 3T exponentiation: rep #01: Cov: 62.50% (5/8 branches): 1F 1T 2F 2T 3T
exponentiation: rep #02: Cov: 62.50% (5/8 branches): 1F 1T 2F 2T 3T exponentiation: rep #02: Cov: 62.50% (5/8 branches): 1F 1T 2F 2T 3T
@ -70,9 +57,6 @@ exponentiation: rep #05: Cov: 62.50% (5/8 branches): 1F 1T 2F 2T 3T
exponentiation: rep #06: Cov: 62.50% (5/8 branches): 1F 1T 2F 2T 3T exponentiation: rep #06: Cov: 62.50% (5/8 branches): 1F 1T 2F 2T 3T
exponentiation: rep #07: Cov: 62.50% (5/8 branches): 1F 1T 2F 2T 3T exponentiation: rep #07: Cov: 62.50% (5/8 branches): 1F 1T 2F 2T 3T
exponentiation: rep #08: Cov: 62.50% (5/8 branches): 1F 1T 2F 2T 3T exponentiation: rep #08: Cov: 62.50% (5/8 branches): 1F 1T 2F 2T 3T
Generating tests: 50%|█████ | 6/12 [07:50<08:26, 84.43s/it]
exponentiation: rep #09: Cov: 62.50% (5/8 branches): 1F 1T 2F 2T 3T
[62.5, 62.5, 62.5, 62.5, 62.5, 62.5, 62.5, 62.5, 62.5, 62.5]
gcd: rep #00: Cov: 100.00% (10/10 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T gcd: rep #00: Cov: 100.00% (10/10 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T
gcd: rep #01: Cov: 100.00% (10/10 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T gcd: rep #01: Cov: 100.00% (10/10 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T
gcd: rep #02: Cov: 100.00% (10/10 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T gcd: rep #02: Cov: 100.00% (10/10 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T
@ -83,8 +67,6 @@ gcd: rep #06: Cov: 100.00% (10/10 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T
gcd: rep #07: Cov: 100.00% (10/10 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T gcd: rep #07: Cov: 100.00% (10/10 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T
gcd: rep #08: Cov: 100.00% (10/10 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T gcd: rep #08: Cov: 100.00% (10/10 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T
gcd: rep #09: Cov: 100.00% (10/10 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T gcd: rep #09: Cov: 100.00% (10/10 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T
[100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0]
Generating tests: 58%|█████▊ | 7/12 [09:09<06:52, 82.57s/it]
longest_sorted_substr: rep #00: Cov: 100.00% (4/4 branches): 1F 1T 2F 2T longest_sorted_substr: rep #00: Cov: 100.00% (4/4 branches): 1F 1T 2F 2T
longest_sorted_substr: rep #01: Cov: 100.00% (4/4 branches): 1F 1T 2F 2T longest_sorted_substr: rep #01: Cov: 100.00% (4/4 branches): 1F 1T 2F 2T
longest_sorted_substr: rep #02: Cov: 100.00% (4/4 branches): 1F 1T 2F 2T longest_sorted_substr: rep #02: Cov: 100.00% (4/4 branches): 1F 1T 2F 2T
@ -94,9 +76,7 @@ longest_sorted_substr: rep #05: Cov: 100.00% (4/4 branches): 1F 1T 2F 2T
longest_sorted_substr: rep #06: Cov: 100.00% (4/4 branches): 1F 1T 2F 2T longest_sorted_substr: rep #06: Cov: 100.00% (4/4 branches): 1F 1T 2F 2T
longest_sorted_substr: rep #07: Cov: 100.00% (4/4 branches): 1F 1T 2F 2T longest_sorted_substr: rep #07: Cov: 100.00% (4/4 branches): 1F 1T 2F 2T
longest_sorted_substr: rep #08: Cov: 100.00% (4/4 branches): 1F 1T 2F 2T longest_sorted_substr: rep #08: Cov: 100.00% (4/4 branches): 1F 1T 2F 2T
Generating tests: 67%|██████▋ | 8/12 [10:19<05:15, 78.78s/it]
longest_sorted_substr: rep #09: Cov: 100.00% (4/4 branches): 1F 1T 2F 2T longest_sorted_substr: rep #09: Cov: 100.00% (4/4 branches): 1F 1T 2F 2T
[100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0]
rabin_karp_search: rep #00: Cov: 90.00% (9/10 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F rabin_karp_search: rep #00: Cov: 90.00% (9/10 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F
rabin_karp_search: rep #01: Cov: 90.00% (9/10 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F rabin_karp_search: rep #01: Cov: 90.00% (9/10 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F
rabin_karp_search: rep #02: Cov: 90.00% (9/10 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F rabin_karp_search: rep #02: Cov: 90.00% (9/10 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F
@ -107,8 +87,6 @@ rabin_karp_search: rep #06: Cov: 90.00% (9/10 branches): 1F 1T 2F 2T 3F 3T 4F 4T
rabin_karp_search: rep #07: Cov: 90.00% (9/10 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F rabin_karp_search: rep #07: Cov: 90.00% (9/10 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F
rabin_karp_search: rep #08: Cov: 90.00% (9/10 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F rabin_karp_search: rep #08: Cov: 90.00% (9/10 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F
rabin_karp_search: rep #09: Cov: 90.00% (9/10 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F rabin_karp_search: rep #09: Cov: 90.00% (9/10 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F
[90.0, 90.0, 90.0, 90.0, 90.0, 90.0, 90.0, 90.0, 90.0, 90.0]
Generating tests: 75%|███████▌ | 9/12 [11:32<03:50, 76.96s/it]
raildecrypt: rep #00: Cov: 87.50% (14/16 branches): 5F 5T 6F 6T 7F 8F 8T 9T 10F 10T 11F 11T 12F 12T raildecrypt: rep #00: Cov: 87.50% (14/16 branches): 5F 5T 6F 6T 7F 8F 8T 9T 10F 10T 11F 11T 12F 12T
raildecrypt: rep #01: Cov: 93.75% (15/16 branches): 5F 5T 6F 6T 7F 7T 8F 8T 9T 10F 10T 11F 11T 12F 12T raildecrypt: rep #01: Cov: 93.75% (15/16 branches): 5F 5T 6F 6T 7F 7T 8F 8T 9T 10F 10T 11F 11T 12F 12T
raildecrypt: rep #02: Cov: 93.75% (15/16 branches): 5F 5T 6F 6T 7F 7T 8F 8T 9T 10F 10T 11F 11T 12F 12T raildecrypt: rep #02: Cov: 93.75% (15/16 branches): 5F 5T 6F 6T 7F 7T 8F 8T 9T 10F 10T 11F 11T 12F 12T
@ -119,9 +97,17 @@ raildecrypt: rep #06: Cov: 93.75% (15/16 branches): 5F 5T 6F 6T 7F 7T 8F 8T 9T 1
raildecrypt: rep #07: Cov: 93.75% (15/16 branches): 5F 5T 6F 6T 7F 7T 8F 8T 9T 10F 10T 11F 11T 12F 12T raildecrypt: rep #07: Cov: 93.75% (15/16 branches): 5F 5T 6F 6T 7F 7T 8F 8T 9T 10F 10T 11F 11T 12F 12T
raildecrypt: rep #08: Cov: 93.75% (15/16 branches): 5F 5T 6F 6T 7F 7T 8F 8T 9T 10F 10T 11F 11T 12F 12T raildecrypt: rep #08: Cov: 93.75% (15/16 branches): 5F 5T 6F 6T 7F 7T 8F 8T 9T 10F 10T 11F 11T 12F 12T
raildecrypt: rep #09: Cov: 68.75% (11/16 branches): 5T 6F 6T 8F 8T 9T 10F 10T 11F 11T 12T raildecrypt: rep #09: Cov: 68.75% (11/16 branches): 5T 6F 6T 8F 8T 9T 10F 10T 11F 11T 12T
[87.5, 93.75, 93.75, 87.5, 87.5, 87.5, 93.75, 93.75, 93.75, 68.75]
Generating tests: 83%|████████▎ | 10/12 [17:25<05:24, 162.00s/it]
railencrypt: rep #00: Cov: 100.00% (8/8 branches): 1F 1T 2F 2T 3F 3T 4F 4T railencrypt: rep #00: Cov: 100.00% (8/8 branches): 1F 1T 2F 2T 3F 3T 4F 4T
railencrypt: rep #01: Cov: 100.00% (8/8 branches): 1F 1T 2F 2T 3F 3T 4F 4T railencrypt: rep #01: Cov: 100.00% (8/8 branches): 1F 1T 2F 2T 3F 3T 4F 4T
railencrypt: rep #02: Cov: 62.50% (5/8 branches): 1T 2F 2T 4F 4T railencrypt: rep #02: Cov: 62.50% (5/8 branches): 1T 2F 2T 4F 4T
railencrypt: rep #03: Cov: 100.00% (8/8 branches): 1F 1T 2F 2T 3F 3T 4F 4T railencrypt: rep #03: Cov: 100.00% (8/8 branches): 1F 1T 2F 2T 3F 3T 4F 4T
zeller: rep #00: Cov: 93.75% (15/16 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T 6T 7F 7T 8F 8T
zeller: rep #01: Cov: 93.75% (15/16 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T 6T 7F 7T 8F 8T
zeller: rep #02: Cov: 93.75% (15/16 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T 6T 7F 7T 8F 8T
zeller: rep #03: Cov: 93.75% (15/16 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T 6T 7F 7T 8F 8T
zeller: rep #04: Cov: 93.75% (15/16 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T 6T 7F 7T 8F 8T
zeller: rep #05: Cov: 93.75% (15/16 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T 6T 7F 7T 8F 8T
zeller: rep #06: Cov: 93.75% (15/16 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T 6T 7F 7T 8F 8T
zeller: rep #07: Cov: 93.75% (15/16 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T 6T 7F 7T 8F 8T
zeller: rep #08: Cov: 93.75% (15/16 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T 6T 7F 7T 8F 8T
zeller: rep #09: Cov: 93.75% (15/16 branches): 1F 1T 2F 2T 3F 3T 4F 4T 5F 5T 6T 7F 7T 8F 8T

14
tests/test_railencrypt.py Normal file
View file

@ -0,0 +1,14 @@
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'

23
tests/test_zeller.py Normal file
View file

@ -0,0 +1,23 @@
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'