Compare commits

...

10 Commits

Author SHA1 Message Date
Claudio Maggioni a660cb793a commit id in report 2023-12-28 12:13:40 +01:00
Claudio Maggioni 549b8859ff report work 2023-12-28 12:13:01 +01:00
Claudio Maggioni c1b91104a3 report 2023-12-28 12:10:06 +01:00
Claudio Maggioni 6d44303c57 report 2023-12-28 11:27:31 +01:00
Claudio Maggioni 9d6315152e report 2023-12-28 10:43:47 +01:00
Claudio Maggioni f77c297ca0 updated table in report 2023-12-27 16:18:52 +01:00
Claudio Maggioni 967209b852 reran muttest with regeneration 2023-12-27 16:07:31 +01:00
Claudio Maggioni f5f605c259 Done except report 2023-12-26 13:55:44 +01:00
Claudio Maggioni 1153d5138a works 2023-12-25 22:24:01 +01:00
Claudio Maggioni a622cc5e27 part 4 code done 2023-12-24 16:38:44 +01:00
37 changed files with 875 additions and 490 deletions

View File

@ -13,7 +13,7 @@ Note: Feel free to modify this file according to the project's necessities.
## Environment setup
To install the required dependencies the Python version manager `pyenv` must be installed and in `$PATH`.
To install the required dependencies the Python version manager `pyenv` must be installed and in `$PATH`.
To set up a Python 3.11 virtualenv to execute parts 1, 2, and 3 of the project run:
@ -24,7 +24,7 @@ pyenv shell 3.11
python3.11 -m venv env
source env/bin/activate
pip3.11 install -r requirements.txt
pip3.11 install -r requirements_3.11.txt
```
To set up Python 3.7 (last version supported by `mut.py`) to execute part 4 of the project run:
@ -34,18 +34,16 @@ deactivate || true # deactivate existing environment
pyenv install -s 3.7
pyenv shell 3.7
python3.7 -m venv env37
source env37/bin/activate
pip3.7 install MutPy==0.6.1
pip3.7 install -r requirements.txt
source env37/bin/activate
pip3.7 install -r requirements_3.7.txt
```
## Instrumentation (Part 1)
To generate the instrumented code for all the files in the benchmark run the command:
To generate the instrumented code for all the files in the benchmark run the commands:
```shell
# Reset Python to latest (system) version
deactivate || true
pyenv shell 3.11
source env/bin/activate
@ -56,12 +54,36 @@ python3.11 ./instrument.py
The generated files are created in the directory `instrumented`. Each file name matches the file name of the
corresponding source file in `benchmark`.
## Test case generation (Part 2 and Part 3)
## Test case generation using the fuzzer (Part 2)
To generate test cases for all files in the benchmark run the command:
To generate test cases for all files in the benchmark using the fuzzer run the commands:
```shell
deactivate || true
pyenv shell 3.11
source env/bin/activate
python3.11 ./fuzzer.py
```
The test suite is created in the directory `fuzzer_tests`. One test file is generated for each file present in the
`benchmark` directory. Run the command with the `-h` options for more details on partial generation.
The test suite can be then executed over the benchmark code with the commands:
```shell
deactivate || true
pyenv shell 3.11
source env/bin/activate
python3.11 -m unittest discover fuzzer_tests
```
## Test case generation using the genetic algorithm (Part 3)
To generate test cases for all files in the benchmark using the genetic algorithm run the commands:
```shell
# Reset Python to latest (system) version
deactivate || true
pyenv shell 3.11
source env/bin/activate
@ -69,13 +91,12 @@ source env/bin/activate
python3.11 ./genetic.py
```
The test suite is created in the directory `tests`. One test file is generated for each file present in the
The test suite is created in the directory `tests`. One test file is generated for each file present in the
`benchmark` directory. Run the command with the `-h` options for more details on partial generation.
The test suite can be then executed over the benchmark code with the command:
The test suite can be then executed over the benchmark code with the commands:
```shell
# Reset Python to latest (system) version
deactivate || true
pyenv shell 3.11
source env/bin/activate
@ -94,4 +115,27 @@ pyenv shell 3.7
source env37/bin/activate
python3.7 muttest.py
```
```
The script will consider the tests in `fuzzer_tests` and `tests` and run mutation testing on them, collecting the
mutation score for each run in `out/mutation_results_fuzzer.csv` and `out/mutation_results_genetic.csv` respectively.
If either or both file exist, the p run for the matching test suite will be skipped and the saved values will be
used.
The script additionally generates two plots for the distribution and average of mutation scores per kind of generation
and benchmark file. These two plots are saved in `out/mutation_scores.png` and `out/mutation_scores_mean.png`
respectively. `out/stats.csv` is also generated and will contain a statistical comparison between the mutation score
distribution for the fuzzer-generated and genetic-generated test of each benchmark file, including the average score for
both generations, the Wilcoxon paired test p-value, the Cohen's d effect size and its interpretation.
# Report
To compile the report run:
```shell
cd report
pdflatex -interaction=nonstopmode -output-directory=. main.tex
pdflatex -interaction=nonstopmode -output-directory=. main.tex
```
The report is then located in `report/main.pdf`.

View File

@ -9,8 +9,6 @@ import operators
class Archive:
true_branches: Dict[int, any]
false_branches: Dict[int, any]
false_score: Dict[int, any]
true_score: Dict[int, any]
f_name: str
def __init__(self, f_name: str) -> None:
@ -20,8 +18,6 @@ class Archive:
def reset(self):
self.true_branches = {}
self.false_branches = {}
self.true_score = {}
self.false_score = {}
def branches_covered(self) -> int:
return len(self.true_branches.keys()) + len(self.false_branches.keys())
@ -67,7 +63,4 @@ class Archive:
branch not in self.false_branches):
branches.append((branch, False))
if len(branches) > 0:
print(list(test_case.items()), branches)
return branches

View File

@ -1,6 +1,7 @@
import argparse
import os
from random import randrange, choice, random, sample, seed
from random import randrange, choice, random, seed
from typing import Tuple, Dict, List, Set, Callable
from frozendict import frozendict
from tqdm import tqdm
@ -10,7 +11,6 @@ import operators
from archive import Archive
from instrument import (Arg, Params, invoke, call_statement, BranchTransformer,
module_of, load_benchmark, get_benchmark, functions)
from typing import Tuple, Dict, List, Set, Callable
Range = Tuple[int, int]
@ -18,7 +18,7 @@ INT_RANGE: Range = (-1000, 1000)
STRING_LEN_RANGE: Range = (0, 10)
STRING_CHAR_RANGE: Range = (32, 127)
POOL_SIZE: int = 1000
FUZZER_REPS: int = 1000
FUZZER_REPS: int = 250
OUT_DIR = os.path.join(os.path.dirname(__file__), "fuzzer_tests")
@ -102,10 +102,11 @@ def add_to_pool(arguments: List[Arg], params: Params):
param_list: List[any] = [None] * len(arg_names)
for i, name in enumerate(arg_names):
param_list[i] = params[name]
pools[arg_types].add(tuple(param_list))
def get_pool(arguments: List[Arg]) -> List[Params]:
def extract_from_pool(arguments: List[Arg]) -> Params:
arg_types = tuple([arg_type for _, arg_type in arguments])
arg_names = [arg_name for arg_name, _ in arguments]
@ -124,13 +125,22 @@ def get_pool(arguments: List[Arg]) -> List[Params]:
pools[arg_types] = new_pool
return [frozendict({arg_names[i]: p for i, p in enumerate(param)}) for param in pools[arg_types]]
i = randrange(0, len(pools[arg_types]))
for e in pools[arg_types]:
if i == 0:
return frozendict({arg_names[i]: p for i, p in enumerate(e)})
i -= 1
raise RuntimeError("unreachable statement")
def mutate(test_case: Params, arguments: List[Arg]) -> Params:
arg_name = choice(list(test_case.keys())) # choose name to mutate
types: Dict[str, str] = {arg_name: arg_type for arg_name, arg_type in arguments}
return test_case.set(arg_name, random_mutate(types[arg_name], test_case[arg_name]))
mutated = test_case.set(arg_name, random_mutate(types[arg_name], test_case[arg_name]))
add_to_pool(arguments, mutated)
return mutated
def crossover(chosen_test: Params, other_chosen_test: Params, arguments: List[Arg]) -> Tuple[Params, Params]:
@ -149,31 +159,12 @@ def crossover(chosen_test: Params, other_chosen_test: Params, arguments: List[Ar
t1 = chosen_test.set(arg_name, i1)
t2 = other_chosen_test.set(arg_name, i2)
add_to_pool(arguments, t1)
add_to_pool(arguments, t2)
return t1, t2
def generate_test_case(f_name: str, arguments: List[Arg], archive: Archive, bias_unseen=True) -> Params:
pool: List[Params] = get_pool(arguments)
attempts = 20 # attempts to generate a random test that satisfies a new branch
while True:
test = sample(pool, 1)[0]
is_new = [] if not bias_unseen else archive.satisfies_unseen_branches(test)
attempts -= 1
if bias_unseen and len(is_new) == 0 and attempts > 0:
# print(f"Not new: {test}")
continue
try:
invoke(f_name, test)
return test # return only test cases that satisfy assertions
except AssertionError:
pass
def str_crossover(parent1: str, parent2: str):
if len(parent1) > 1 and len(parent2) > 1:
pos = randrange(1, len(parent1))
@ -218,13 +209,13 @@ def get_test_class(orig_f_name: str, cases: Set[Params]) -> str:
"\n")
def generate_tests(files: List[str], seed_num: int, generation_fn: Callable[[str], Set[Params]]):
load_benchmark(save_instrumented=False, files=files)
def generate_tests(files: List[str], seed_num: int, generation_fn: Callable[[str], Set[Params]], out_dir: str):
load_benchmark(save_instrumented=False, files_count=files)
seed(seed_num) # init random seed
for file_name, f_names in tqdm(get_benchmark().items(), desc="Generating tests"):
suite = [(name, generation_fn(name)) for name in f_names]
with open(os.path.join(OUT_DIR, f"test_{file_name}.py"), "w") as f:
with open(os.path.join(out_dir, f"test_{file_name}.py"), "w") as f:
f.write(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]))
@ -237,19 +228,17 @@ def fuzzer_generate(f_name: str) -> Set[Params]:
archive = Archive(instrumented)
for _ in tqdm(range(FUZZER_REPS), desc=f"fuzzer [{f_name}]"):
test = generate_test_case(instrumented, args, archive, bias_unseen=False)
test = extract_from_pool(args)
alteration_choice = randrange(3)
if alteration_choice == 1:
test = mutate(test, args)
elif alteration_choice == 2:
test2 = generate_test_case(instrumented, args, archive, bias_unseen=False)
test2 = extract_from_pool(args)
test, test2 = crossover(test, test2, args)
archive.consider_test(test2)
add_to_pool(args, test2)
archive.consider_test(test)
add_to_pool(args, test)
return archive.build_suite()
@ -264,7 +253,7 @@ def main():
nargs="?", default=0)
args = parser.parse_args()
generate_tests(args.file, args.seed, fuzzer_generate)
generate_tests(args.file, args.seed, fuzzer_generate, OUT_DIR)
if __name__ == "__main__":

View File

@ -1,101 +0,0 @@
,file,score
0,anagram_check,23.1
1,anagram_check,23.1
2,anagram_check,23.1
3,anagram_check,23.1
4,anagram_check,23.1
5,anagram_check,23.1
6,anagram_check,23.1
7,anagram_check,23.1
8,anagram_check,23.1
9,anagram_check,23.1
10,caesar_cipher,58.8
11,caesar_cipher,58.8
12,caesar_cipher,58.8
13,caesar_cipher,58.8
14,caesar_cipher,58.8
15,caesar_cipher,58.8
16,caesar_cipher,58.8
17,caesar_cipher,58.8
18,caesar_cipher,58.8
19,caesar_cipher,58.8
20,check_armstrong,90.3
21,check_armstrong,90.3
22,check_armstrong,90.3
23,check_armstrong,90.3
24,check_armstrong,90.3
25,check_armstrong,90.3
26,check_armstrong,90.3
27,check_armstrong,90.3
28,check_armstrong,90.3
29,check_armstrong,90.3
30,common_divisor_count,72.3
31,common_divisor_count,72.3
32,common_divisor_count,72.3
33,common_divisor_count,72.3
34,common_divisor_count,72.3
35,common_divisor_count,72.3
36,common_divisor_count,72.3
37,common_divisor_count,72.3
38,common_divisor_count,72.3
39,common_divisor_count,72.3
40,exponentiation,71.4
41,exponentiation,71.4
42,exponentiation,71.4
43,exponentiation,71.4
44,exponentiation,71.4
45,exponentiation,71.4
46,exponentiation,71.4
47,exponentiation,71.4
48,exponentiation,71.4
49,exponentiation,71.4
50,gcd,47.8
51,gcd,47.8
52,gcd,47.8
53,gcd,47.8
54,gcd,47.8
55,gcd,47.8
56,gcd,47.8
57,gcd,47.8
58,gcd,47.8
59,gcd,47.8
60,longest_substring,82.6
61,longest_substring,82.6
62,longest_substring,82.6
63,longest_substring,82.6
64,longest_substring,82.6
65,longest_substring,82.6
66,longest_substring,82.6
67,longest_substring,82.6
68,longest_substring,82.6
69,longest_substring,82.6
70,rabin_karp,64.9
71,rabin_karp,64.9
72,rabin_karp,64.9
73,rabin_karp,64.9
74,rabin_karp,64.9
75,rabin_karp,64.9
76,rabin_karp,64.9
77,rabin_karp,64.9
78,rabin_karp,64.9
79,rabin_karp,64.9
80,railfence_cipher,89.4
81,railfence_cipher,89.4
82,railfence_cipher,89.4
83,railfence_cipher,89.4
84,railfence_cipher,89.4
85,railfence_cipher,89.4
86,railfence_cipher,89.4
87,railfence_cipher,89.4
88,railfence_cipher,89.4
89,railfence_cipher,89.4
90,zellers_birthday,68.3
91,zellers_birthday,68.3
92,zellers_birthday,68.3
93,zellers_birthday,68.3
94,zellers_birthday,68.3
95,zellers_birthday,68.3
96,zellers_birthday,68.3
97,zellers_birthday,68.3
98,zellers_birthday,68.3
99,zellers_birthday,68.3
1 file score
2 0 anagram_check 23.1
3 1 anagram_check 23.1
4 2 anagram_check 23.1
5 3 anagram_check 23.1
6 4 anagram_check 23.1
7 5 anagram_check 23.1
8 6 anagram_check 23.1
9 7 anagram_check 23.1
10 8 anagram_check 23.1
11 9 anagram_check 23.1
12 10 caesar_cipher 58.8
13 11 caesar_cipher 58.8
14 12 caesar_cipher 58.8
15 13 caesar_cipher 58.8
16 14 caesar_cipher 58.8
17 15 caesar_cipher 58.8
18 16 caesar_cipher 58.8
19 17 caesar_cipher 58.8
20 18 caesar_cipher 58.8
21 19 caesar_cipher 58.8
22 20 check_armstrong 90.3
23 21 check_armstrong 90.3
24 22 check_armstrong 90.3
25 23 check_armstrong 90.3
26 24 check_armstrong 90.3
27 25 check_armstrong 90.3
28 26 check_armstrong 90.3
29 27 check_armstrong 90.3
30 28 check_armstrong 90.3
31 29 check_armstrong 90.3
32 30 common_divisor_count 72.3
33 31 common_divisor_count 72.3
34 32 common_divisor_count 72.3
35 33 common_divisor_count 72.3
36 34 common_divisor_count 72.3
37 35 common_divisor_count 72.3
38 36 common_divisor_count 72.3
39 37 common_divisor_count 72.3
40 38 common_divisor_count 72.3
41 39 common_divisor_count 72.3
42 40 exponentiation 71.4
43 41 exponentiation 71.4
44 42 exponentiation 71.4
45 43 exponentiation 71.4
46 44 exponentiation 71.4
47 45 exponentiation 71.4
48 46 exponentiation 71.4
49 47 exponentiation 71.4
50 48 exponentiation 71.4
51 49 exponentiation 71.4
52 50 gcd 47.8
53 51 gcd 47.8
54 52 gcd 47.8
55 53 gcd 47.8
56 54 gcd 47.8
57 55 gcd 47.8
58 56 gcd 47.8
59 57 gcd 47.8
60 58 gcd 47.8
61 59 gcd 47.8
62 60 longest_substring 82.6
63 61 longest_substring 82.6
64 62 longest_substring 82.6
65 63 longest_substring 82.6
66 64 longest_substring 82.6
67 65 longest_substring 82.6
68 66 longest_substring 82.6
69 67 longest_substring 82.6
70 68 longest_substring 82.6
71 69 longest_substring 82.6
72 70 rabin_karp 64.9
73 71 rabin_karp 64.9
74 72 rabin_karp 64.9
75 73 rabin_karp 64.9
76 74 rabin_karp 64.9
77 75 rabin_karp 64.9
78 76 rabin_karp 64.9
79 77 rabin_karp 64.9
80 78 rabin_karp 64.9
81 79 rabin_karp 64.9
82 80 railfence_cipher 89.4
83 81 railfence_cipher 89.4
84 82 railfence_cipher 89.4
85 83 railfence_cipher 89.4
86 84 railfence_cipher 89.4
87 85 railfence_cipher 89.4
88 86 railfence_cipher 89.4
89 87 railfence_cipher 89.4
90 88 railfence_cipher 89.4
91 89 railfence_cipher 89.4
92 90 zellers_birthday 68.3
93 91 zellers_birthday 68.3
94 92 zellers_birthday 68.3
95 93 zellers_birthday 68.3
96 94 zellers_birthday 68.3
97 95 zellers_birthday 68.3
98 96 zellers_birthday 68.3
99 97 zellers_birthday 68.3
100 98 zellers_birthday 68.3
101 99 zellers_birthday 68.3

View File

@ -3,22 +3,17 @@ from benchmark.anagram_check import anagram_check
class Test_anagram_check(TestCase):
# distances_true = {1: [8], 3: [0]}
# distances_false = {1: [0], 3: [7]}
# distances_true = {1: [0], 2: [0]}
# distances_false = {1: [1], 2: [1]}
def test_anagram_check_1(self):
assert anagram_check(s1='gU(@sp?!<', s2='^$') == False
assert anagram_check(s1='2', s2='K') == False
# distances_true = {1: [1], 3: [0]}
# distances_false = {1: [0], 3: [1]}
def test_anagram_check_2(self):
assert anagram_check(s1='NW', s2='^') == False
# distances_true = {1: [2], 3: [1], 4: [3]}
# distances_false = {1: [0], 3: [0], 4: [0]}
def test_anagram_check_2(self):
assert anagram_check(s1='N9)', s2='%;r') == False
# distances_true = {1: [0], 2: [0]}
# distances_false = {1: [1], 2: [1]}
def test_anagram_check_3(self):
assert anagram_check(s1='j', s2='7') == False
# distances_true = {1: [0], 2: [2], 3: [0]}
# distances_false = {1: [1], 2: [0], 3: [2]}
def test_anagram_check_4(self):
assert anagram_check(s1='i', s2='E y') == False
assert anagram_check(s1='I@N', s2='}*9') == False

View File

@ -4,14 +4,14 @@ from benchmark.caesar_cipher import decrypt
class Test_encrypt(TestCase):
# distances_true = {1: [0, 6, 0, 10, 0, 0, 0, 0]}
# distances_false = {1: [48, 0, 60, 0, 57, 30, 25, 47]}
# distances_true = {1: [24, 61, 0, 0, 48, 5]}
# distances_false = {1: [0, 0, 12, 18, 0, 0]}
def test_encrypt_1(self):
assert encrypt(strng='_*k&hMH^', key=79) == 'Oy[uX=8N'
assert encrypt(strng='P+sy8c', key=23) == 'gB+1Oz'
class Test_decrypt(TestCase):
# distances_true = {2: [0, 0, 32, 0]}
# distances_false = {2: [1, 12, 0, 24]}
# distances_true = {2: [9, 0, 43, 25, 0, 8, 42]}
# distances_false = {2: [0, 8, 0, 0, 5, 0, 0]}
def test_decrypt_1(self):
assert decrypt(strng='\\Q|E', key=61) == '~s?g'
assert decrypt(strng='VFxfIUw', key=46) == "(wJ8z'I"

View File

@ -3,22 +3,17 @@ from benchmark.check_armstrong import check_armstrong
class Test_check_armstrong(TestCase):
# distances_true = {1: [583], 2: [582], 3: [433], 4: [0, 0, 0, 1], 5: [81]}
# distances_false = {1: [0], 2: [0], 3: [0], 4: [583, 58, 5, 0], 5: [0]}
# distances_true = {1: [1], 2: [0]}
# distances_false = {1: [0], 2: [1]}
def test_check_armstrong_1(self):
assert check_armstrong(n=583) == False
assert check_armstrong(n=1) == True
# distances_true = {1: [0]}
# distances_false = {1: [1]}
# distances_true = {1: [135], 2: [134], 3: [0]}
# distances_false = {1: [0], 2: [0], 3: [16]}
def test_check_armstrong_2(self):
assert check_armstrong(n=0) == True
assert check_armstrong(n=135) == False
# distances_true = {1: [153], 2: [152], 3: [3], 4: [0, 0, 0, 1], 5: [0]}
# distances_false = {1: [0], 2: [0], 3: [0], 4: [153, 15, 1, 0], 5: [1]}
# distances_true = {1: [307], 2: [306], 3: [157], 4: [0, 0, 0, 1], 5: [63]}
# distances_false = {1: [0], 2: [0], 3: [0], 4: [307, 30, 3, 0], 5: [0]}
def test_check_armstrong_3(self):
assert check_armstrong(n=153) == True
# distances_true = {1: [5], 2: [4], 3: [0]}
# distances_false = {1: [0], 2: [0], 3: [146]}
def test_check_armstrong_4(self):
assert check_armstrong(n=5) == False
assert check_armstrong(n=307) == False

View File

@ -3,17 +3,32 @@ from benchmark.common_divisor_count import cd_count
class Test_cd_count(TestCase):
# distances_true = {1: [180], 2: [450], 3: [0], 4: [451], 5: [0, 0, 1], 6: [0, 0, 0, 2, 0, 0, 6, 2, 0], 7: [89, 43, 27, 13, 9, 1]}
# distances_false = {1: [0], 2: [0], 3: [180], 4: [0], 5: [180, 90, 0], 6: [1, 1, 1, 0, 1, 1, 0, 0, 1], 7: [0, 0, 0, 0, 0, 0]}
# distances_true = {1: [301], 2: [0]}
# distances_false = {1: [0], 2: [1]}
def test_cd_count_1(self):
assert cd_count(a=-180, b=450) == 12
assert cd_count(a=301, b=0) == 2
# distances_true = {1: [524], 2: [858], 3: [525], 4: [0], 5: [0, 0, 0, 0, 0, 0, 0, 0, 1], 6: [0], 7: [1]}
# distances_false = {1: [0], 2: [0], 3: [0], 4: [858], 5: [524, 334, 190, 144, 46, 6, 4, 2, 0], 6: [1], 7: [0]}
# distances_true = {1: [28], 2: [7], 3: [29], 4: [8], 5: [0, 0, 1], 6: [0, 1], 7: [6]}
# distances_false = {1: [0], 2: [0], 3: [0], 4: [0], 5: [28, 7, 0], 6: [1, 0], 7: [0]}
def test_cd_count_2(self):
assert cd_count(a=524, b=-858) == 2
assert cd_count(a=28, b=7) == 2
# distances_true = {1: [171], 2: [880], 3: [0], 4: [881], 5: [0, 0, 0, 0, 0, 1], 6: [0], 7: [0]}
# distances_false = {1: [0], 2: [0], 3: [171], 4: [0], 5: [171, 25, 21, 4, 1, 0], 6: [1], 7: [1]}
# distances_true = {1: [153], 2: [2], 3: [154], 4: [3], 5: [0, 0, 0, 1], 6: [0], 7: [0]}
# distances_false = {1: [0], 2: [0], 3: [0], 4: [0], 5: [153, 2, 1, 0], 6: [1], 7: [1]}
def test_cd_count_3(self):
assert cd_count(a=-171, b=880) == 1
assert cd_count(a=153, b=2) == 1
# distances_true = {1: [502], 2: [178], 3: [503], 4: [179], 5: [0, 0, 0, 0, 0, 0, 0, 0, 1], 6: [0], 7: [1]}
# distances_false = {1: [0], 2: [0], 3: [0], 4: [0], 5: [502, 178, 146, 32, 18, 14, 4, 2, 0], 6: [1], 7: [0]}
def test_cd_count_4(self):
assert cd_count(a=502, b=178) == 2
# distances_true = {1: [0]}
# distances_false = {1: [1]}
def test_cd_count_5(self):
assert cd_count(a=0, b=904) == 2
# distances_true = {1: [443], 2: [6], 3: [0], 4: [0], 5: [0, 0, 0, 0, 1], 6: [0], 7: [0]}
# distances_false = {1: [0], 2: [0], 3: [443], 4: [6], 5: [443, 6, 5, 1, 0], 6: [1], 7: [1]}
def test_cd_count_6(self):
assert cd_count(a=-443, b=-6) == 1

View File

@ -3,7 +3,7 @@ from benchmark.exponentiation import exponentiation
class Test_exponentiation(TestCase):
# distances_true = {1: [0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 3: [0], 2: [1, 1, 0, 0, 0, 1, 0, 0, 0]}
# distances_false = {1: [630, 314, 156, 77, 38, 18, 8, 3, 1, 0], 3: [1], 2: [0, 0, 1, 1, 1, 0, 1, 1, 1]}
# distances_true = {1: [0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 3: [0], 2: [0, 1, 0, 1, 1, 1, 1, 1, 0]}
# distances_false = {1: [832, 415, 207, 103, 51, 25, 12, 5, 2, 0], 3: [1], 2: [1, 0, 1, 0, 0, 0, 0, 0, 1]}
def test_exponentiation_1(self):
assert exponentiation(baseNumber=229, power=631) == 11381234101445775753511392015341744682588570986102224039390720285077899169674568038197326342940064901244177560842841924371421802587044521315773772186187547659830685455568537528049212994980159679816838690878596437635556336390603217974843590523706585633093363478766247718669151124253597924271460074695331123030002477672470888683820892451691712794240150714666068396254837851712428304279437706402840278841022427798845642299620119122197582242489041676042030717852031723255821528213497142055551145575663634990077305256845727132894737670148720272258452398194448015830799903170149287684706972565823541486622411136605841318617521051177682587295876588617192583199512651351936677507861660939730278101046178558162552821556410557719089125378645170386340572632243077354907575845913647147461310394166725741203050654294205855227960718731811784697401084780988753863828019215023964034022075473428520603004040086437560944507735374937837026821029527152268670187574842115160681136501433596553090081291095916580753660680615454664168228698567169031280782756475821551196582762941080904807113833394318850338264484961526692224500757025151325286773628959521989541968478235125022809094655704670640668124923174654970259046198975073787375738402994461267901157313580710146722768111601235186132446805107849024669181014876768249128669364324993951100257739165644330717095953945583658926347402457474225454535689578418160695265405822296417373349554757877558059686302770208714142534097327460841575601330771335995265872402591629
assert exponentiation(baseNumber=-6, power=833) == -1584862427176646441032581448163502056522304714791688863077680763401594759422056202480618372145524894456151986289670118768654538337866053263611922000599918608949612484758034859452586327393651279190541552669586881048781584189639428134027926187502542805755360587303203758250141709609935145755270362171617090607605771330425353289800694836743426874185222171194524983577694492237864072603517346560417482797868100221342243559501229220749459182746246997902149679964895722044423357661248125544267360836746288616059898701793481334662209049986346281366837693465240393495058780389499730155312477987604559702499972667524745974854042821278371009362182850127855616

View File

@ -3,12 +3,27 @@ from benchmark.gcd import gcd
class Test_gcd(TestCase):
# distances_true = {1: [182], 2: [931], 3: [749], 4: [0], 5: [0, 0, 0, 0, 0, 1]}
# distances_false = {1: [0], 2: [0], 3: [0], 4: [749], 5: [183, 17, 13, 4, 1, 0]}
# distances_true = {1: [0]}
# distances_false = {1: [1]}
def test_gcd_1(self):
assert gcd(a=183, b=932) == 1
assert gcd(a=1, b=751) == 1
# distances_true = {1: [720], 2: [503], 3: [217], 4: [218], 5: [0, 0, 0, 0, 1]}
# distances_false = {1: [0], 2: [0], 3: [0], 4: [0], 5: [504, 217, 70, 7, 0]}
# distances_true = {1: [964], 2: [964], 3: [0]}
# distances_false = {1: [0], 2: [0], 3: [1]}
def test_gcd_2(self):
assert gcd(a=721, b=504) == 7
assert gcd(a=965, b=965) == 965
# distances_true = {1: [700], 2: [440], 3: [260], 4: [261], 5: [0, 0, 0, 0, 0, 0, 0, 0, 1]}
# distances_false = {1: [0], 2: [0], 3: [0], 4: [0], 5: [441, 260, 181, 79, 23, 10, 3, 1, 0]}
def test_gcd_3(self):
assert gcd(a=701, b=441) == 1
# distances_true = {1: [941], 2: [944], 3: [3], 4: [0], 5: [0, 0, 1]}
# distances_false = {1: [0], 2: [0], 3: [0], 4: [3], 5: [942, 3, 0]}
def test_gcd_4(self):
assert gcd(a=942, b=945) == 3
# distances_true = {1: [354], 2: [0]}
# distances_false = {1: [0], 2: [1]}
def test_gcd_5(self):
assert gcd(a=355, b=1) == 1

View File

@ -3,12 +3,7 @@ from benchmark.longest_substring import longest_sorted_substr
class Test_longest_sorted_substr(TestCase):
# distances_true = {1: [5, 0, 56, 0, 81, 0, 0], 2: [0, 1, 1, 0]}
# distances_false = {1: [0, 38, 0, 86, 0, 5, 57], 2: [1, 0, 0, 1]}
# distances_true = {1: [0, 17, 12, 17, 0, 47, 10, 0], 2: [0, 1, 1]}
# distances_false = {1: [12, 0, 0, 0, 42, 0, 0, 3], 2: [1, 0, 0]}
def test_longest_sorted_substr_1(self):
assert longest_sorted_substr(s='<7\\$y(,d') == '(,d'
# distances_true = {1: [29, 2, 0, 50], 2: [0]}
# distances_false = {1: [0, 0, 35, 0], 2: [1]}
def test_longest_sorted_substr_2(self):
assert longest_sorted_substr(s='Q42T"') == '2T'
assert longest_sorted_substr(s='\\gVJ9b3)+') == '\\g'

View File

@ -3,22 +3,12 @@ from benchmark.rabin_karp import rabin_karp_search
class Test_rabin_karp_search(TestCase):
# distances_true = {1: [0, 70, 54, 65, 28, 51, 66], 3: [1], 4: [0, 0, 0, 0, 0, 0, 1], 5: [71, 55, 66, 29, 52, 67]}
# distances_false = {1: [1, 0, 0, 0, 0, 0, 0], 3: [0], 4: [6, 5, 4, 3, 2, 1, 0], 5: [0, 0, 0, 0, 0, 0]}
# distances_true = {1: [69, 86], 4: [0, 1], 5: [15]}
# distances_false = {1: [0, 0], 4: [1, 0], 5: [0]}
def test_rabin_karp_search_1(self):
assert rabin_karp_search(pat='', txt=']vzK<k') == []
assert rabin_karp_search(pat='Hi', txt=';Wd') == []
# distances_true = {1: [43, 0, 35, 7, 61], 4: [0, 0, 0, 0, 1], 5: [62, 27, 69, 1], 2: [0], 3: [2]}
# distances_false = {1: [0, 1, 0, 0, 0], 4: [4, 3, 2, 1, 0], 5: [0, 0, 0, 0], 2: [53], 3: [0]}
# distances_true = {1: [53, 0], 4: [0, 1], 5: [94], 2: [0], 3: [1]}
# distances_false = {1: [0, 1], 4: [1, 0], 5: [0], 2: [47], 3: [0]}
def test_rabin_karp_search_2(self):
assert rabin_karp_search(pat='z+e', txt=':EQBa9M') == []
# distances_true = {1: [50, 61, 64, 66, 16, 14, 66], 4: [0, 0, 0, 0, 0, 0, 1], 5: [16, 13, 11, 93, 63, 11]}
# distances_false = {1: [0, 0, 0, 0, 0, 0, 0], 4: [6, 5, 4, 3, 2, 1, 0], 5: [0, 0, 0, 0, 0, 0]}
def test_rabin_karp_search_3(self):
assert rabin_karp_search(pat='f)', txt='^E}QhXq_') == []
# distances_true = {1: [14, 24, 0, 29, 5, 70, 55], 4: [0, 0, 0, 0, 0, 0, 1], 5: [65, 89, 60, 84, 19, 34], 2: [1], 3: [0]}
# distances_false = {1: [0, 0, 1, 0, 0, 0, 0], 4: [6, 5, 4, 3, 2, 1, 0], 5: [0, 0, 0, 0, 0, 0], 2: [0], 3: [1]}
def test_rabin_karp_search_4(self):
assert rabin_karp_search(pat='X', txt='J@X;Sw!') == [2]
assert rabin_karp_search(pat='+g', txt='rZJ') == []

View File

@ -4,34 +4,24 @@ from benchmark.railfence_cipher import raildecrypt
class Test_railencrypt(TestCase):
# distances_true = {1: [0], 2: [944], 4: [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]}
# distances_false = {1: [1], 2: [0], 4: [125, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]}
# distances_true = {1: [0, 0, 0, 0, 1, 1, 1, 0], 2: [3, 2, 1, 0, 2], 3: [2, 1, 0], 4: [0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1]}
# distances_false = {1: [1, 1, 1, 1, 0, 0, 0, 1], 2: [0, 0, 0, 1, 0], 3: [0, 0, 1], 4: [106, 0, 0, 0, 0, 0, 38, 0, 0, 57, 0, 0, 0, 77, 0, 32, 0, 0, 41, 0, 108, 0, 0, 0, 0, 0, 0, 119, 0, 0, 0, 0]}
def test_railencrypt_1(self):
assert railencrypt(st='}', k=945) == '}'
assert railencrypt(st='j9)wlM& ', k=4) == 'j&9M )lw'
# distances_true = {1: [0, 0, 0, 0, 1, 1, 1, 0, 0], 2: [3, 2, 1, 0, 2, 1], 3: [2, 1, 0], 4: [0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1]}
# distances_false = {1: [1, 1, 1, 1, 0, 0, 0, 1, 1], 2: [0, 0, 0, 1, 0, 0], 3: [0, 0, 1], 4: [45, 0, 0, 0, 0, 0, 71, 0, 0, 0, 66, 0, 0, 0, 104, 0, 70, 0, 0, 0, 61, 0, 54, 0, 0, 0, 36, 0, 0, 0, 57, 0, 0, 0, 0, 0]}
# distances_true = {1: [0, 0, 0, 0, 0, 0, 0, 0], 2: [61, 60, 59, 58, 57, 56, 55, 54], 4: [0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]}
# distances_false = {1: [1, 1, 1, 1, 1, 1, 1, 1], 2: [0, 0, 0, 0, 0, 0, 0, 0], 4: [34, 0, 0, 0, 0, 0, 0, 0, 0, 81, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 122, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0, 0, 119, 0, 0, 0, 0, 0, 0, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]}
def test_railencrypt_2(self):
assert railencrypt(st='-B=96hGF$', k=4) == '-GBhF=6$9'
# distances_true = {1: [0, 0, 0, 0, 0, 0, 0, 0, 1], 2: [7, 6, 5, 4, 3, 2, 1, 0], 3: [6], 4: [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1]}
# distances_false = {1: [1, 1, 1, 1, 1, 1, 1, 1, 0], 2: [0, 0, 0, 0, 0, 0, 0, 1], 3: [0], 4: [119, 0, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 107, 0, 122, 0, 0, 0, 0, 0, 0, 0, 72, 0]}
def test_railencrypt_3(self):
assert railencrypt(st='w[*]^=kHz', k=8) == 'w[*]^=kzH'
assert railencrypt(st='"Q z <wC', k=62) == '"Q z <wC'
class Test_raildecrypt(TestCase):
# distances_true = {5: [0, 0, 0, 0, 0, 0, 0, 0, 0], 6: [43, 42, 41, 40, 39, 38, 37, 36, 35], 8: [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], 9: [0, 0, 0, 0, 0, 0, 0, 0, 0], 10: [9, 0, 0, 0, 0, 0, 0, 0, 0], 12: [0], 11: [42, 41, 40, 39, 38, 37, 36, 35]}
# distances_false = {5: [1, 1, 1, 1, 1, 1, 1, 1, 1], 6: [0, 0, 0, 0, 0, 0, 0, 0, 0], 8: [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 9: [73, 68, 91, 120, 37, 34, 41, 61, 107], 10: [0, 1, 1, 1, 1, 1, 1, 1, 1], 12: [1], 11: [0, 0, 0, 0, 0, 0, 0, 0]}
# distances_true = {5: [0, 0, 0, 1, 1, 0, 0], 6: [2, 1, 0, 1, 0], 7: [1, 0], 8: [0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0], 9: [0, 0, 0, 0, 0, 0, 0], 10: [7, 0, 0, 1, 1, 0, 0], 12: [0, 1, 0], 11: [1, 0, 1, 0]}
# distances_false = {5: [1, 1, 1, 0, 0, 1, 1], 6: [0, 0, 1, 0, 1], 7: [0, 1], 8: [1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1], 9: [80, 119, 85, 119, 33, 102, 116], 10: [0, 1, 1, 0, 0, 1, 1], 12: [1, 0, 1], 11: [0, 1, 0, 1]}
def test_raildecrypt_1(self):
assert raildecrypt(st='ID[x%")=k', k=44) == 'ID[x%")=k'
assert raildecrypt(st='P!wwfUt', k=3) == 'PwUw!ft'
# distances_true = {5: [0, 0, 0, 0, 1, 1, 1, 0, 0], 6: [3, 2, 1, 0, 2, 1], 7: [2, 1, 0], 8: [0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1], 9: [0, 0, 0, 0, 0, 0, 0, 0, 0], 10: [9, 0, 0, 0, 1, 1, 1, 0, 0], 12: [0, 2, 1, 0], 11: [2, 1, 0, 2, 1]}
# distances_false = {5: [1, 1, 1, 1, 0, 0, 0, 1, 1], 6: [0, 0, 0, 1, 0, 0], 7: [0, 0, 1], 8: [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0], 9: [45, 61, 104, 36, 71, 57, 66, 54, 70], 10: [0, 1, 1, 1, 0, 0, 0, 1, 1], 12: [1, 0, 0, 1], 11: [0, 0, 1, 0, 0]}
# distances_true = {5: [0], 6: [365], 8: [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], 9: [0], 10: [1], 12: [0]}
# distances_false = {5: [1], 6: [0], 8: [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 9: [88], 10: [0], 12: [1]}
def test_raildecrypt_2(self):
assert raildecrypt(st='-B=96hGF$', k=4) == '-=h$G9B6F'
# distances_true = {5: [0, 0, 0, 0, 0, 0, 1, 1], 6: [5, 4, 3, 2, 1, 0], 7: [4, 3], 8: [0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1], 9: [0, 0, 0, 0, 0, 0, 0, 0], 10: [8, 0, 0, 0, 0, 0, 1, 1], 12: [0, 4, 3], 11: [4, 3, 2, 1, 0]}
# distances_false = {5: [1, 1, 1, 1, 1, 1, 0, 0], 6: [0, 0, 0, 0, 0, 1], 7: [0, 0], 8: [1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0], 9: [51, 99, 79, 96, 77, 65, 72, 104], 10: [0, 1, 1, 1, 1, 1, 0, 0], 12: [1, 0, 0], 11: [0, 0, 0, 0, 1]}
def test_raildecrypt_3(self):
assert raildecrypt(st='3cO`hMHA', k=6) == '3cO`MAHh'
assert raildecrypt(st='X', k=366) == 'X'

View File

@ -3,22 +3,32 @@ from benchmark.zellers_birthday import zeller
class Test_zeller(TestCase):
# distances_true = {1: [6], 2: [0], 3: [0], 4: [7], 5: [0], 6: [0], 7: [0], 8: [2, 1, 0]}
# distances_false = {1: [0], 2: [121], 3: [71], 4: [0], 5: [71], 6: [7], 7: [1], 8: [0, 0, 1]}
# distances_true = {1: [0], 2: [0], 3: [0], 4: [0], 5: [1923], 7: [0], 8: [2, 1, 0]}
# distances_false = {1: [214], 2: [49], 3: [78], 4: [1], 5: [0], 7: [1], 8: [0, 0, 1]}
def test_zeller_1(self):
assert zeller(d=-26, m=133, y=29) == 'Tuesday'
assert zeller(d=245, m=-61, y=-22) == 'Tuesday'
# distances_true = {1: [0], 2: [0], 3: [0], 4: [0], 5: [1904], 7: [3], 8: [6, 5, 4, 3, 2, 1, 0]}
# distances_false = {1: [929], 2: [304], 3: [97], 4: [20], 5: [0], 7: [0], 8: [0, 0, 0, 0, 0, 0, 1]}
# distances_true = {1: [0], 2: [0], 3: [0], 4: [0], 5: [1916], 7: [9], 8: [5, 4, 3, 2, 1, 0]}
# distances_false = {1: [601], 2: [838], 3: [85], 4: [8], 5: [0], 7: [0], 8: [0, 0, 0, 0, 0, 1]}
def test_zeller_2(self):
assert zeller(d=960, m=-316, y=-3) == 'Saturday'
assert zeller(d=-632, m=-850, y=15) == 'Friday'
# distances_true = {1: [0], 2: [0], 3: [0], 4: [74], 5: [0], 6: [0], 7: [0], 8: [3, 2, 1, 0]}
# distances_false = {1: [932], 2: [552], 3: [4], 4: [0], 5: [4], 6: [74], 7: [2], 8: [0, 0, 0, 1]}
# distances_true = {1: [5], 2: [0], 3: [0], 4: [9], 5: [0], 6: [0], 7: [10], 8: [0]}
# distances_false = {1: [0], 2: [47], 3: [69], 4: [0], 5: [69], 6: [9], 7: [0], 8: [1]}
def test_zeller_3(self):
assert zeller(d=963, m=-564, y=96) == 'Wednesday'
assert zeller(d=-27, m=-59, y=-31) == 'Sunday'
# distances_true = {1: [0], 2: [0], 3: [0], 4: [58], 5: [0], 6: [0], 7: [3], 8: [3, 2, 1, 0]}
# distances_false = {1: [492], 2: [988], 3: [20], 4: [0], 5: [20], 6: [58], 7: [0], 8: [0, 0, 0, 1]}
# distances_true = {1: [0], 2: [6], 3: [0], 4: [0], 5: [1915], 7: [5], 8: [5, 4, 3, 2, 1, 0]}
# distances_false = {1: [885], 2: [0], 3: [86], 4: [9], 5: [0], 7: [0], 8: [0, 0, 0, 0, 0, 1]}
def test_zeller_4(self):
assert zeller(d=-523, m=-1000, y=80) == 'Wednesday'
assert zeller(d=916, m=7, y=-14) == 'Friday'
# distances_true = {1: [0], 2: [0], 3: [0], 4: [0], 5: [1923], 7: [8], 8: [0]}
# distances_false = {1: [256], 2: [21], 3: [78], 4: [1], 5: [0], 7: [0], 8: [1]}
def test_zeller_5(self):
assert zeller(d=287, m=-33, y=-22) == 'Sunday'
# distances_true = {1: [0], 2: [0], 3: [0], 4: [5], 5: [0], 6: [0], 7: [4], 8: [0]}
# distances_false = {1: [18], 2: [41], 3: [73], 4: [0], 5: [73], 6: [5], 7: [0], 8: [1]}
def test_zeller_6(self):
assert zeller(d=-49, m=-53, y=-27) == 'Sunday'

View File

@ -1,25 +1,22 @@
import argparse
import math
import os
import random
from functools import partial
from typing import Tuple, List, Set
from typing import Tuple, Set
import frozendict
import tqdm
from deap import creator, base, tools, algorithms
import fuzzer
import instrument
import operators
from fuzzer import generate_test_case, get_test_class
from archive import Archive
INDMUPROB = 0.05
MUPROB = 0.33
CXPROB = 0.33
TOURNSIZE = 3
NPOP = 1000
NGEN = 200
NPOP = 200
NGEN = 20
REPS = 10
OUT_DIR = os.path.join(os.path.dirname(__file__), "tests")
@ -43,7 +40,7 @@ def generate(orig_name: str) -> Set[instrument.Params]:
archive = Archive(f_name)
toolbox = base.Toolbox()
toolbox.register("attr_test_case", lambda: list(generate_test_case(f_name, args, archive).items()))
toolbox.register("attr_test_case", lambda: list(fuzzer.extract_from_pool(args).items()))
toolbox.register("individual", tools.initIterate, creator.Individual, lambda: toolbox.attr_test_case())
toolbox.register("population", tools.initRepeat, list, toolbox.individual)
toolbox.register("evaluate", partial(compute_fitness, f_name, archive))
@ -52,12 +49,14 @@ def generate(orig_name: str) -> Set[instrument.Params]:
t1, t2 = frozendict.frozendict(tc1), frozendict.frozendict(tc2)
o1, o2 = fuzzer.crossover(t1, t2, args)
i1, i2 = creator.Individual(o1.items()), creator.Individual(o2.items())
# print("mate", tc1, tc2, i1, i2)
return i1, i2
def mutate(tc):
t = frozendict.frozendict(tc)
o = fuzzer.mutate(t, args)
i1 = creator.Individual(o.items())
# print("mutate", tc, i1)
return i1,
toolbox.register("mate", mate)
@ -102,10 +101,11 @@ def compute_fitness(f_name: str, archive: Archive, individual: list) -> Tuple[fl
try:
out = instrument.invoke(f_name, x)
except AssertionError:
# print(f_name, x, "=", "[FAILS] fitness = 100.0")
return 100.0,
# print(f_name, x, "=", "[FAILS] fitness = inf")
return math.inf,
fitness = 0.0
no_branches_hit = True
# Sum up branch distances
for branch in range(range_start, range_end):
@ -113,14 +113,19 @@ def compute_fitness(f_name: str, archive: Archive, individual: list) -> Tuple[fl
if branch not in archive.true_branches:
fitness += normalize(operators.distances_true[branch])
else:
fitness += 10
fitness += 2
no_branches_hit = False
for branch in range(range_start, range_end):
if branch in operators.distances_false:
if branch not in archive.false_branches:
fitness += normalize(operators.distances_false[branch])
else:
fitness += 10
fitness += 2
no_branches_hit = False
if no_branches_hit:
fitness = 1000000
# print(f_name, x, "=", out, "fitness =", fitness)
return fitness,
@ -137,7 +142,7 @@ def main():
args = parser.parse_args()
init_deap()
fuzzer.generate_tests(args.file, args.seed, generate)
fuzzer.generate_tests(args.file, args.seed, generate, OUT_DIR)
if __name__ == '__main__':

View File

@ -6,6 +6,7 @@ from typing import Optional, Dict, DefaultDict, Tuple, List
import astunparse
import frozendict
import pandas as pd
import tqdm
import operators
@ -23,6 +24,7 @@ class BranchTransformer(ast.NodeTransformer):
instrumented_name: Optional[str]
in_assert: bool
in_return: bool
function_nodes: int
def __init__(self):
self.branch_num = 0
@ -30,6 +32,7 @@ class BranchTransformer(ast.NodeTransformer):
self.in_assert = False
self.in_return = False
self.branches_range = {}
self.function_nodes = 0
@staticmethod
def to_instrumented_name(name: str):
@ -53,6 +56,7 @@ class BranchTransformer(ast.NodeTransformer):
return ast_node
def visit_FunctionDef(self, ast_node):
self.function_nodes += 1
self.instrumented_name = ast_node.name
b_start = self.branch_num
ast_node.name = BranchTransformer.to_instrumented_name(ast_node.name)
@ -83,7 +87,7 @@ class BranchTransformer(ast.NodeTransformer):
ArgType = str
Arg = Tuple[str, ArgType]
Params = frozendict.frozendict[str, any]
Params = 'frozendict.frozendict[str, any]'
SignatureDict = Dict[str, List[Arg]]
n_of_branches: Dict[str, Tuple[int, int]] = {}
@ -91,7 +95,7 @@ functions: SignatureDict = {}
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) -> Tuple[int, int]:
global functions, n_of_branches
with open(source_path, "r") as f:
@ -102,6 +106,9 @@ def instrument(source_path: str, target_path: str, save_instrumented=True):
b = BranchTransformer()
b.visit(node)
functions_found = b.function_nodes
conditions_found = b.branch_num - 1
for f_name, limits in b.branches_range.items():
n_of_branches[f_name] = limits
@ -132,6 +139,8 @@ def instrument(source_path: str, target_path: str, save_instrumented=True):
functions[f.name] = arg_types
module_of[f.name] = os.path.splitext(os.path.normpath(os.path.relpath(source_path, ROOT_DIR)))[0].split("/")
return functions_found, conditions_found
def invoke(f_name: str, f_args: Params) -> any:
global functions
@ -159,14 +168,24 @@ def find_py_files(search_dir: str):
yield os.path.join(cwd, file)
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])
def load_benchmark(save_instrumented=True, files_count: List[str] = ()) -> Tuple[int, int, int]:
to_load = set([os.path.splitext(os.path.basename(file))[0] + ".py" for file in files_count])
do_all = len(to_load) == 0
files_count = 0
functions_count = 0
conditions_count = 0
for file in tqdm.tqdm(find_py_files(IN_DIR), desc="Instrumenting"):
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)
fs, cs = instrument(file, os.path.join(OUT_DIR, filename), save_instrumented=save_instrumented)
files_count += 1
functions_count += fs
conditions_count += cs
return files_count, functions_count, conditions_count
def call_statement(f_name: str, f_args: Params) -> str:
@ -191,5 +210,15 @@ def get_benchmark() -> Dict[str, List[str]]:
return dict(names)
def main():
files_count, functions_count, conditions_count = load_benchmark(save_instrumented=True)
df = pd.DataFrame.from_records([
{'Type': 'Python Files', 'Number': files_count},
{'Type': 'Function Nodes', 'Number': functions_count},
{'Type': 'Comparison Nodes', 'Number': conditions_count},
])
print(df.to_latex(index=False))
if __name__ == '__main__':
load_benchmark(save_instrumented=True)
main()

View File

@ -1,52 +1,147 @@
import math
import os
import re
import subprocess
import sys
from typing import List, Dict
from math import sqrt
from statistics import mean, variance
from typing import List, Dict, Callable, Set
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
from scipy.stats import wilcoxon
from tqdm import tqdm
import genetic
from fuzzer import generate_tests, fuzzer_generate
from instrument import Params
ROOT_DIR = os.path.dirname(__file__)
IN_SOURCE_DIR = os.path.join(ROOT_DIR, "benchmark")
IN_TEST_DIR = os.path.join(ROOT_DIR, "tests")
IN_FUZZER_TEST_DIR = os.path.join(ROOT_DIR, "fuzzer_tests")
OUT_DIR = os.path.join(ROOT_DIR, "out")
MUT_PY_PATH = os.path.join(ROOT_DIR, 'env37', 'bin', 'mut.py')
REPS: int = 10
def cohen_d(d1: List[float], d2: List[float]) -> float:
pooled_sd = sqrt(((len(d1) - 1) * variance(d1) + (len(d2) - 1) * variance(d2)) /
(len(d1) + len(d2) - 2))
if pooled_sd == 0:
return math.inf
return (mean(d1) - mean(d2)) / pooled_sd
def effect_size(eff: float) -> str:
eff = abs(eff)
if eff <= 0.01:
return 'Very small'
elif eff <= 0.2:
return 'Small'
elif eff <= 0.5:
return 'Medium'
elif eff <= 0.8:
return 'Large'
elif eff <= 1.2:
return 'Very large'
else:
return 'Huge'
def compute_stats(df_gen: pd.DataFrame, df_fuz: pd.DataFrame, output_file: str, avg_output_file: str, stat_csv: str):
combined_df = pd.concat([df_gen, df_fuz], keys=["genetic", "fuzzer"]).reset_index()
combined_df.columns = ['source', *combined_df.columns[1:]]
del combined_df[combined_df.columns[1]]
combined_df = combined_df.sort_values(['source', 'file'])
plt.figure(figsize=(10, 6))
sns.set(style="whitegrid")
sns.boxplot(data=combined_df, x="file", y="score", hue="source")
plt.yticks(range(0, 101, 10))
plt.xticks(rotation=45)
plt.tight_layout()
plt.savefig(output_file)
plt.figure(figsize=(10, 6))
df_avg = combined_df.groupby(['file', 'source']).mean().reset_index().sort_values(['source', 'file'])
sns.set(style="whitegrid")
sns.barplot(data=df_avg, x="file", y="score", hue="source")
plt.yticks(range(0, 101, 10))
plt.xticks(rotation=45)
plt.tight_layout()
plt.savefig(avg_output_file)
df_avg = df_avg.pivot(index='file', columns='source', values='score').rename_axis(None, axis=1)
df_avg['cohen-d'] = [math.nan] * len(df_avg.index)
df_avg['interpretation'] = [math.nan] * len(df_avg.index)
df_avg['wilcoxon'] = [math.nan] * len(df_avg.index)
for f in combined_df['file'].drop_duplicates():
list_gen = df_gen.loc[(df_gen.file == f), 'score'].tolist()
list_fuz = df_fuz.loc[(df_fuz.file == f), 'score'].tolist()
df_avg.loc[f, 'cohen-d'] = cohen_d(list_gen, list_fuz)
df_avg.loc[f, 'interpretation'] = effect_size(df_avg.loc[f, 'cohen-d'])
df_avg.loc[f, 'wilcoxon'] = wilcoxon(list_gen, list_fuz, zero_method='zsplit').pvalue
df_avg.round(4).to_csv(stat_csv)
def run_mutpy(test_path: str, source_path: str) -> float:
output = subprocess.check_output(
[sys.executable, MUT_PY_PATH, '-t', source_path, '-u', test_path]).decode('utf-8')
[sys.executable,
MUT_PY_PATH,
'-t', source_path,
'-u', test_path]).decode('utf-8')
score = re.search('Mutation score \\[.*]: (\\d+\\.\\d+)%', output).group(1)
return float(score)
def mutate_suite(out_file: str, in_test_dir: str, to_test: List[str]):
def mutate_suite(out_file: str, in_test_dir: str, to_test: List[str], seeds: List[int],
generation_fn: Callable[[str], Set[Params]]):
scores: List[Dict[str, any]] = []
if os.path.isfile(out_file): # do not re-generate if file exists
return
return pd.read_csv(out_file, index_col=0)
for filename in tqdm(to_test, desc=f"mut.py [{os.path.basename(out_file)}]"):
source_path = os.path.join(IN_SOURCE_DIR, f"{filename}.py")
test_path = os.path.join(in_test_dir, f"test_{filename}.py")
scores.append({
'file': filename,
'score': run_mutpy(test_path, source_path)
})
for seed in tqdm(seeds, desc=f"generating with seeds"):
generate_tests([], seed, generation_fn, in_test_dir)
for filename in tqdm(to_test, desc=f"mut.py [{os.path.basename(out_file)}]"):
source_path = os.path.join(IN_SOURCE_DIR, f"{filename}.py")
test_path = os.path.join(in_test_dir, f"test_{filename}.py")
scores.append({
'file': filename,
'score': run_mutpy(test_path, source_path)
})
df = pd.DataFrame.from_records(scores)
df.to_csv(out_file)
return df
def main():
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"]
to_test = [e for t in to_test for e in ([t] * REPS)]
mutate_suite(os.path.join(IN_TEST_DIR, 'mutation_results_genetic.csv'), IN_TEST_DIR, to_test)
mutate_suite(os.path.join(IN_FUZZER_TEST_DIR, 'mutation_results_fuzzer.csv'), IN_FUZZER_TEST_DIR, to_test)
seeds = [182, 81, 95, 16, 124, 166, 178, 22, 20, 54]
genetic.init_deap()
df_gen = mutate_suite(os.path.join(OUT_DIR, 'mutation_results_genetic.csv'), IN_TEST_DIR, to_test, seeds,
genetic.generate)
df_fuz = mutate_suite(os.path.join(OUT_DIR, 'mutation_results_fuzzer.csv'), IN_FUZZER_TEST_DIR, to_test, seeds,
fuzzer_generate)
compute_stats(df_gen, df_fuz,
os.path.join(OUT_DIR, "mutation_scores.png"),
os.path.join(OUT_DIR, "mutation_scores_mean.png"),
os.path.join(OUT_DIR, "stats.csv"))
if __name__ == "__main__":

View File

@ -0,0 +1,101 @@
,file,score
0,anagram_check,23.1
1,caesar_cipher,61.8
2,check_armstrong,83.9
3,common_divisor_count,74.5
4,exponentiation,71.4
5,gcd,60.9
6,longest_substring,69.6
7,rabin_karp,28.1
8,railfence_cipher,88.3
9,zellers_birthday,68.3
10,anagram_check,23.1
11,caesar_cipher,61.8
12,check_armstrong,77.4
13,common_divisor_count,78.7
14,exponentiation,68.6
15,gcd,65.2
16,longest_substring,73.9
17,rabin_karp,26.3
18,railfence_cipher,89.4
19,zellers_birthday,72.5
20,anagram_check,23.1
21,caesar_cipher,61.8
22,check_armstrong,25.8
23,common_divisor_count,76.6
24,exponentiation,68.6
25,gcd,56.5
26,longest_substring,78.3
27,rabin_karp,26.3
28,railfence_cipher,88.3
29,zellers_birthday,72.5
30,anagram_check,23.1
31,caesar_cipher,58.8
32,check_armstrong,38.7
33,common_divisor_count,76.6
34,exponentiation,68.6
35,gcd,60.9
36,longest_substring,78.3
37,rabin_karp,50.9
38,railfence_cipher,87.2
39,zellers_birthday,70.0
40,anagram_check,23.1
41,caesar_cipher,58.8
42,check_armstrong,45.2
43,common_divisor_count,74.5
44,exponentiation,71.4
45,gcd,60.9
46,longest_substring,82.6
47,rabin_karp,24.6
48,railfence_cipher,89.4
49,zellers_birthday,62.5
50,anagram_check,23.1
51,caesar_cipher,58.8
52,check_armstrong,83.9
53,common_divisor_count,78.7
54,exponentiation,68.6
55,gcd,43.5
56,longest_substring,78.3
57,rabin_karp,15.8
58,railfence_cipher,87.2
59,zellers_birthday,67.5
60,anagram_check,23.1
61,caesar_cipher,58.8
62,check_armstrong,25.8
63,common_divisor_count,74.5
64,exponentiation,68.6
65,gcd,60.9
66,longest_substring,82.6
67,rabin_karp,26.3
68,railfence_cipher,89.4
69,zellers_birthday,69.2
70,anagram_check,23.1
71,caesar_cipher,61.8
72,check_armstrong,77.4
73,common_divisor_count,78.7
74,exponentiation,71.4
75,gcd,60.9
76,longest_substring,78.3
77,rabin_karp,29.8
78,railfence_cipher,89.4
79,zellers_birthday,66.7
80,anagram_check,23.1
81,caesar_cipher,64.7
82,check_armstrong,77.4
83,common_divisor_count,72.3
84,exponentiation,68.6
85,gcd,60.9
86,longest_substring,69.6
87,rabin_karp,24.6
88,railfence_cipher,87.2
89,zellers_birthday,64.2
90,anagram_check,23.1
91,caesar_cipher,58.8
92,check_armstrong,45.2
93,common_divisor_count,76.6
94,exponentiation,68.6
95,gcd,60.9
96,longest_substring,82.6
97,rabin_karp,26.3
98,railfence_cipher,88.3
99,zellers_birthday,67.5
1 file score
2 0 anagram_check 23.1
3 1 caesar_cipher 61.8
4 2 check_armstrong 83.9
5 3 common_divisor_count 74.5
6 4 exponentiation 71.4
7 5 gcd 60.9
8 6 longest_substring 69.6
9 7 rabin_karp 28.1
10 8 railfence_cipher 88.3
11 9 zellers_birthday 68.3
12 10 anagram_check 23.1
13 11 caesar_cipher 61.8
14 12 check_armstrong 77.4
15 13 common_divisor_count 78.7
16 14 exponentiation 68.6
17 15 gcd 65.2
18 16 longest_substring 73.9
19 17 rabin_karp 26.3
20 18 railfence_cipher 89.4
21 19 zellers_birthday 72.5
22 20 anagram_check 23.1
23 21 caesar_cipher 61.8
24 22 check_armstrong 25.8
25 23 common_divisor_count 76.6
26 24 exponentiation 68.6
27 25 gcd 56.5
28 26 longest_substring 78.3
29 27 rabin_karp 26.3
30 28 railfence_cipher 88.3
31 29 zellers_birthday 72.5
32 30 anagram_check 23.1
33 31 caesar_cipher 58.8
34 32 check_armstrong 38.7
35 33 common_divisor_count 76.6
36 34 exponentiation 68.6
37 35 gcd 60.9
38 36 longest_substring 78.3
39 37 rabin_karp 50.9
40 38 railfence_cipher 87.2
41 39 zellers_birthday 70.0
42 40 anagram_check 23.1
43 41 caesar_cipher 58.8
44 42 check_armstrong 45.2
45 43 common_divisor_count 74.5
46 44 exponentiation 71.4
47 45 gcd 60.9
48 46 longest_substring 82.6
49 47 rabin_karp 24.6
50 48 railfence_cipher 89.4
51 49 zellers_birthday 62.5
52 50 anagram_check 23.1
53 51 caesar_cipher 58.8
54 52 check_armstrong 83.9
55 53 common_divisor_count 78.7
56 54 exponentiation 68.6
57 55 gcd 43.5
58 56 longest_substring 78.3
59 57 rabin_karp 15.8
60 58 railfence_cipher 87.2
61 59 zellers_birthday 67.5
62 60 anagram_check 23.1
63 61 caesar_cipher 58.8
64 62 check_armstrong 25.8
65 63 common_divisor_count 74.5
66 64 exponentiation 68.6
67 65 gcd 60.9
68 66 longest_substring 82.6
69 67 rabin_karp 26.3
70 68 railfence_cipher 89.4
71 69 zellers_birthday 69.2
72 70 anagram_check 23.1
73 71 caesar_cipher 61.8
74 72 check_armstrong 77.4
75 73 common_divisor_count 78.7
76 74 exponentiation 71.4
77 75 gcd 60.9
78 76 longest_substring 78.3
79 77 rabin_karp 29.8
80 78 railfence_cipher 89.4
81 79 zellers_birthday 66.7
82 80 anagram_check 23.1
83 81 caesar_cipher 64.7
84 82 check_armstrong 77.4
85 83 common_divisor_count 72.3
86 84 exponentiation 68.6
87 85 gcd 60.9
88 86 longest_substring 69.6
89 87 rabin_karp 24.6
90 88 railfence_cipher 87.2
91 89 zellers_birthday 64.2
92 90 anagram_check 23.1
93 91 caesar_cipher 58.8
94 92 check_armstrong 45.2
95 93 common_divisor_count 76.6
96 94 exponentiation 68.6
97 95 gcd 60.9
98 96 longest_substring 82.6
99 97 rabin_karp 26.3
100 98 railfence_cipher 88.3
101 99 zellers_birthday 67.5

View File

@ -0,0 +1,101 @@
,file,score
0,anagram_check,7.7
1,caesar_cipher,61.8
2,check_armstrong,93.5
3,common_divisor_count,66.0
4,exponentiation,71.4
5,gcd,47.8
6,longest_substring,78.3
7,rabin_karp,45.6
8,railfence_cipher,87.2
9,zellers_birthday,70.0
10,anagram_check,7.7
11,caesar_cipher,61.8
12,check_armstrong,93.5
13,common_divisor_count,68.1
14,exponentiation,71.4
15,gcd,60.9
16,longest_substring,78.3
17,rabin_karp,50.9
18,railfence_cipher,88.3
19,zellers_birthday,71.7
20,anagram_check,7.7
21,caesar_cipher,61.8
22,check_armstrong,93.5
23,common_divisor_count,61.7
24,exponentiation,68.6
25,gcd,47.8
26,longest_substring,69.6
27,rabin_karp,50.9
28,railfence_cipher,87.2
29,zellers_birthday,75.0
30,anagram_check,7.7
31,caesar_cipher,61.8
32,check_armstrong,93.5
33,common_divisor_count,72.3
34,exponentiation,68.6
35,gcd,60.9
36,longest_substring,82.6
37,rabin_karp,50.9
38,railfence_cipher,88.3
39,zellers_birthday,73.3
40,anagram_check,7.7
41,caesar_cipher,61.8
42,check_armstrong,93.5
43,common_divisor_count,70.2
44,exponentiation,71.4
45,gcd,47.8
46,longest_substring,78.3
47,rabin_karp,50.9
48,railfence_cipher,87.2
49,zellers_birthday,71.7
50,anagram_check,7.7
51,caesar_cipher,58.8
52,check_armstrong,93.5
53,common_divisor_count,76.6
54,exponentiation,68.6
55,gcd,43.5
56,longest_substring,69.6
57,rabin_karp,50.9
58,railfence_cipher,87.2
59,zellers_birthday,70.8
60,anagram_check,7.7
61,caesar_cipher,58.8
62,check_armstrong,93.5
63,common_divisor_count,78.7
64,exponentiation,68.6
65,gcd,60.9
66,longest_substring,69.6
67,rabin_karp,50.9
68,railfence_cipher,88.3
69,zellers_birthday,70.8
70,anagram_check,7.7
71,caesar_cipher,61.8
72,check_armstrong,93.5
73,common_divisor_count,78.7
74,exponentiation,71.4
75,gcd,60.9
76,longest_substring,73.9
77,rabin_karp,49.1
78,railfence_cipher,85.1
79,zellers_birthday,71.7
80,anagram_check,7.7
81,caesar_cipher,61.8
82,check_armstrong,93.5
83,common_divisor_count,78.7
84,exponentiation,71.4
85,gcd,60.9
86,longest_substring,87.0
87,rabin_karp,49.1
88,railfence_cipher,86.2
89,zellers_birthday,70.8
90,anagram_check,7.7
91,caesar_cipher,61.8
92,check_armstrong,93.5
93,common_divisor_count,76.6
94,exponentiation,40.0
95,gcd,65.2
96,longest_substring,82.6
97,rabin_karp,26.3
98,railfence_cipher,89.4
99,zellers_birthday,71.7
1 file score
2 0 anagram_check 7.7
3 1 caesar_cipher 61.8
4 2 check_armstrong 93.5
5 3 common_divisor_count 66.0
6 4 exponentiation 71.4
7 5 gcd 47.8
8 6 longest_substring 78.3
9 7 rabin_karp 45.6
10 8 railfence_cipher 87.2
11 9 zellers_birthday 70.0
12 10 anagram_check 7.7
13 11 caesar_cipher 61.8
14 12 check_armstrong 93.5
15 13 common_divisor_count 68.1
16 14 exponentiation 71.4
17 15 gcd 60.9
18 16 longest_substring 78.3
19 17 rabin_karp 50.9
20 18 railfence_cipher 88.3
21 19 zellers_birthday 71.7
22 20 anagram_check 7.7
23 21 caesar_cipher 61.8
24 22 check_armstrong 93.5
25 23 common_divisor_count 61.7
26 24 exponentiation 68.6
27 25 gcd 47.8
28 26 longest_substring 69.6
29 27 rabin_karp 50.9
30 28 railfence_cipher 87.2
31 29 zellers_birthday 75.0
32 30 anagram_check 7.7
33 31 caesar_cipher 61.8
34 32 check_armstrong 93.5
35 33 common_divisor_count 72.3
36 34 exponentiation 68.6
37 35 gcd 60.9
38 36 longest_substring 82.6
39 37 rabin_karp 50.9
40 38 railfence_cipher 88.3
41 39 zellers_birthday 73.3
42 40 anagram_check 7.7
43 41 caesar_cipher 61.8
44 42 check_armstrong 93.5
45 43 common_divisor_count 70.2
46 44 exponentiation 71.4
47 45 gcd 47.8
48 46 longest_substring 78.3
49 47 rabin_karp 50.9
50 48 railfence_cipher 87.2
51 49 zellers_birthday 71.7
52 50 anagram_check 7.7
53 51 caesar_cipher 58.8
54 52 check_armstrong 93.5
55 53 common_divisor_count 76.6
56 54 exponentiation 68.6
57 55 gcd 43.5
58 56 longest_substring 69.6
59 57 rabin_karp 50.9
60 58 railfence_cipher 87.2
61 59 zellers_birthday 70.8
62 60 anagram_check 7.7
63 61 caesar_cipher 58.8
64 62 check_armstrong 93.5
65 63 common_divisor_count 78.7
66 64 exponentiation 68.6
67 65 gcd 60.9
68 66 longest_substring 69.6
69 67 rabin_karp 50.9
70 68 railfence_cipher 88.3
71 69 zellers_birthday 70.8
72 70 anagram_check 7.7
73 71 caesar_cipher 61.8
74 72 check_armstrong 93.5
75 73 common_divisor_count 78.7
76 74 exponentiation 71.4
77 75 gcd 60.9
78 76 longest_substring 73.9
79 77 rabin_karp 49.1
80 78 railfence_cipher 85.1
81 79 zellers_birthday 71.7
82 80 anagram_check 7.7
83 81 caesar_cipher 61.8
84 82 check_armstrong 93.5
85 83 common_divisor_count 78.7
86 84 exponentiation 71.4
87 85 gcd 60.9
88 86 longest_substring 87.0
89 87 rabin_karp 49.1
90 88 railfence_cipher 86.2
91 89 zellers_birthday 70.8
92 90 anagram_check 7.7
93 91 caesar_cipher 61.8
94 92 check_armstrong 93.5
95 93 common_divisor_count 76.6
96 94 exponentiation 40.0
97 95 gcd 65.2
98 96 longest_substring 82.6
99 97 rabin_karp 26.3
100 98 railfence_cipher 89.4
101 99 zellers_birthday 71.7

BIN
out/mutation_scores.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

11
out/stats.csv Normal file
View File

@ -0,0 +1,11 @@
file,fuzzer,genetic,cohen-d,interpretation,wilcoxon
anagram_check,23.1,7.7,inf,Huge,0.002
caesar_cipher,60.59,61.2,0.3549,Medium,0.2955
check_armstrong,58.07,93.5,2.0757,Huge,0.002
common_divisor_count,76.17,72.76,-0.7471,Large,0.1258
exponentiation,69.44,67.14,-0.3342,Medium,0.7108
gcd,59.15,55.66,-0.5016,Large,0.1627
longest_substring,77.41,76.98,-0.0771,Small,0.7589
rabin_karp,27.9,47.55,2.3688,Huge,0.0078
railfence_cipher,88.41,87.44,-0.8844,Very large,0.1011
zellers_birthday,68.09,71.75,1.4701,Huge,0.0039
1 file fuzzer genetic cohen-d interpretation wilcoxon
2 anagram_check 23.1 7.7 inf Huge 0.002
3 caesar_cipher 60.59 61.2 0.3549 Medium 0.2955
4 check_armstrong 58.07 93.5 2.0757 Huge 0.002
5 common_divisor_count 76.17 72.76 -0.7471 Large 0.1258
6 exponentiation 69.44 67.14 -0.3342 Medium 0.7108
7 gcd 59.15 55.66 -0.5016 Large 0.1627
8 longest_substring 77.41 76.98 -0.0771 Small 0.7589
9 rabin_karp 27.9 47.55 2.3688 Huge 0.0078
10 railfence_cipher 88.41 87.44 -0.8844 Very large 0.1011
11 zellers_birthday 68.09 71.75 1.4701 Huge 0.0039

BIN
report/main.pdf Normal file

Binary file not shown.

196
report/main.tex Normal file
View File

@ -0,0 +1,196 @@
%!TEX TS-program = pdflatexmk
\documentclass{scrartcl}
\usepackage{algorithm}
\usepackage{textcomp}
\usepackage{xcolor}
\usepackage{booktabs}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{microtype}
\usepackage{rotating}
\usepackage{graphicx}
\usepackage{paralist}
\usepackage{tabularx}
\usepackage{multicol}
\usepackage{multirow}
\usepackage{pbox}
\usepackage{enumitem}
\usepackage{colortbl}
\usepackage{pifont}
\usepackage{xspace}
\usepackage{url}
\usepackage{tikz}
\usepackage{fontawesome}
\usepackage{lscape}
\usepackage{listings}
\usepackage{color}
\usepackage{anyfontsize}
\usepackage{comment}
\usepackage{soul}
\usepackage{multibib}
\usepackage{float}
\usepackage{caption}
\usepackage{subcaption}
\usepackage{amssymb}
\usepackage{amsmath}
\usepackage{hyperref}
\usepackage[margin=2.5cm]{geometry}
\usepackage{changepage}
\title{Knowledge Search \& Extraction \\ Project 02: Python Test Generator}
\author{Claudio Maggioni}
\date{}
\begin{document}
\maketitle
\begin{adjustwidth}{-4cm}{-4cm}
\centering
\begin{tabular}{cc}
\toprule
Repository URL & \url{https://github.com/kamclassroom2022/project-02-python-test-generator-maggicl} \\
Commit ID & \texttt{549b8859ffaad5391da362ed9bbe9db82b2c5c0b} \\ \bottomrule
\end{tabular}
\end{adjustwidth}
\vspace{1cm}
\subsection*{Section 1 - Instrumentation}
The script \textit{instrument.py} in the main directory of the project performs instrumentation to replace each
condition node in the Python files present benchmark suite with a call to \texttt{evaluate\_condition}, which will
preserve program behaviour but as a side effect will compute and store condition distance for each traversed branch.
Table~\ref{tab:count1} summarizes the number of Python files, function definition (\textit{FunctionDef}) nodes,
and comparison nodes (\textit{Compare} nodes not in an \texttt{assert} or \texttt{return} statement) found by the
instrumentation script.
\begin{table} [H]
\centering
\begin{tabular}{lr}
\toprule
\textbf{Type} & \textbf{Number} \\
\midrule
Python Files & 10 \\
Function Nodes & 12 \\
Comparison Nodes & 44 \\
\bottomrule
\end{tabular}
\caption{Count of files and nodes found.}
\label{tab:count1}
\end{table}
\subsection*{Section 2: Fuzzer test generator}
The script \textit{fuzzer.py} loads the instrumented benchmark suite and generates tests at random to maximize branch
coverage.
The implementation submitted with this report slightly improves on the specification required as it is
able to deal with an arbitrary number of function parameters, which must be type-hinted as either \texttt{str} or
\texttt{int}. The fuzzing process generates a pool of 1000 test case inputs according to the function signature,
using randomly generated integers $\in [-1000, 1000]$, and randomly generated string of length $\in [0, 10]$ with
ASCII characters with code $\in [32, 127]$. Note that test cases generated in the pool may not satisfy the
preconditions (i.e.\ the \texttt{assert} statements on the inputs) for the given function.
250 test cases are extracted from the pool following this procedure. With equal probabilities (each with $p=1/3$):
\begin{itemize}
\item The extracted test case may be kept as-is;
\item The extracted test case may be randomly mutated using the \textit{mutate} function. An argument will be
chosen at random, and if of type \texttt{str} a random position in the string will be replaced with a
random character. If the argument is of type \texttt{int}, a random value $\in [-10, 10]$ will be added to
the argument. If the resulting test case is not present in the pool, it will be added to the pool;
\item The extracted test case may be randomly combined with another randomly extracted test using the
\textit{crossover} function. The function will choose at random an argument, and if of type \texttt{int} it will
swap the values assigned to the two tests. If the argument is of type \texttt{str}, the strings from the two test
cases will be split in two substrings at random and they will be joined by combining the ``head'' substring from
one test case with the ``tail'' substring from the other. If the two resulting test cases are new, they will be
added to the pool.
\end{itemize}
If the resulting test case (or test cases) satisfy the function precondition, and if their execution covers branches
that have not been covered by other test cases, they will be added to the test suite. The resulting test suite is
then saved as a \textit{unittest} file, comprising of one test class per function present in the benchmark test file.
\subsection*{Section 3: Genetic Algorithm test generator}
The script \textit{genetic.py} loads the instrumented benchmark suite and generates tests using a genetic algorithm
to maximize branch coverage and minimize distance to condition boundary values.
The genetic algorithm is implemented via the library \textit{deap} using the \textit{eaSimple} procedure.
The algorithm is initialized with 200 individuals extracted from a pool generated in the same way as the previous
section. The algorithm runs for 20 generations, and it implements the \textit{mate} and \textit{mutate} operators
using the \textit{crossover} and \textit{mutate} functions respectively as described in the previous section.
The fitness function used returns a value of $\infty$ if the test case does not satisfy the function precondition,
a value of $1000000$ if the test case does not cover any new branches,
or the sum of normalized ($1 / (x + 1)$) sum of distances for branches that are not yet covered by other test cases.
A penalty of $2$ is summed to the fitness value for every branch that is already covered. The fitness function is
minimized by the genetic algorithm.
The genetic algorithm is ran 10 times. At the end of each execution the best individuals (sorted by increasing
fitness) are selected if they cover at least one branch that has not been covered. This is the only point in the
procedure where the set of covered branches is updated\footnote{This differs from the reference implementation of
\texttt{sb\_cgi\_decode.py}, which performs the update directly in the fitness function.}.
\subsection*{Section 4: Statistical comparison of test generators}
To compare the performance of the fuzzer and the genetic algorithm, the mutation testing tool \textit{mut.py} has
been used to measure how robust the generated test suites hard. Both implementations have been executed for 10 times
using different RNG seeds each time, and a statistical comparison of the resulting mutation score distributions has
been performed to determine when one generation method is statistically more performant than the other.
\begin{figure}[t]
\begin{center}
\includegraphics[width=\linewidth]{../out/mutation_scores}
\caption{Distributions of \textit{mut.py} mutation scores over the generated benchmark tests suites
using the fuzzer and the genetic algorithm.}\label{fig:mutation-scores}
\end{center}
\end{figure}
\begin{figure}[t]
\begin{center}
\includegraphics[width=\linewidth]{../out/mutation_scores_mean}
\caption{\textit{mut.py} Mutation score average over the generated benchmark tests suites
using the fuzzer and the genetic algorithm.}\label{fig:mutation-scores-mean}
\end{center}
\end{figure}
Figure~\ref{fig:mutation-scores} shows a boxplot of the mutation score distributions for each file in the benchmark
suite, while figure~\ref{fig:mutation-scores-mean} shows the mean mutation scores.
\begin{table}[t]
\centering
\begin{tabular}{lrrp{3.5cm}r}
\toprule
\textbf{File} & \textbf{$E(\text{Fuzzer})$} & \textbf{$E(\text{Genetic})$} & \textbf{Cohen's $|d|$} & \textbf{Wilcoxon $p$} \\
\midrule
check\_armstrong & 58.07 & 93.50 & 2.0757 \hfill Huge & 0.0020 \\
railfence\_cipher & 88.41 & 87.44 & 0.8844 \hfill Very large & 0.1011 \\
longest\_substring & 77.41 & 76.98 & 0.0771 \hfill Small & 0.7589 \\
common\_divisor\_count & 76.17 & 72.76 & 0.7471 \hfill Large & 0.1258 \\
zellers\_birthday & 68.09 & 71.75 & 1.4701 \hfill Huge & 0.0039 \\
exponentiation & 69.44 & 67.14 & 0.3342 \hfill Medium & 0.7108 \\
caesar\_cipher & 60.59 & 61.20 & 0.3549 \hfill Medium & 0.2955 \\
gcd & 59.15 & 55.66 & 0.5016 \hfill Large & 0.1627 \\
rabin\_karp & 27.90 & 47.55 & 2.3688 \hfill Huge & 0.0078 \\
anagram\_check & 23.10 & 7.70 & $\infty$ \hfill Huge & 0.0020 \\
\bottomrule
\end{tabular}
\caption{Statistical comparison between fuzzer and genetic algorithm test case generation in terms of mutation
score as reported by \textit{mut.py} over 10 runs, sorted by genetic mutation score. The table reports run
means, the wilcoxon paired test p-value and the Cohen's $d$ effect size for each file in the
benchmark.}\label{tab:stats}
\end{table}
To perform a statistical comparison, the Wilcoxon paired test has been used with a p-value threshold of 0.05 has been
used to check if there is there is a statistical difference between the distributions. Moreover, the Cohen's d
effect-size has been used to measure the significance of the difference. Results of the statistical analysis are
shown in table~\ref{tab:stats}.
Only 4 benchmark files out of 10 make the two script have statistical different performance. They are namely
\textit{check\_armstrong}, \textit{zeller\_birthday}, \textit{rabin\_karp} and \textit{anagram\_check}.
The first three show that the genetic algorithm performs significantly better than the fuzzer,
while the last file shows the opposite.
\end{document}

View File

@ -3,4 +3,7 @@ deap==1.4.1
astunparse==1.6.3
frozendict==2.3.8
tqdm==4.66.1
pandas==1.3.5
pandas==1.3.5
matplotlib==3.8.2
seaborn==0.12.2
scipy==1.11.4

10
requirements_3.7.txt Normal file
View File

@ -0,0 +1,10 @@
nltk==3.8.1
deap==1.4.1
astunparse==1.6.3
frozendict==2.3.8
tqdm==4.66.1
pandas==1.3.5
matplotlib==3.5.3
seaborn==0.12.2
scipy==1.7.3
MutPy==0.6.1

View File

@ -1,101 +0,0 @@
,file,score
0,anagram_check,38.5
1,anagram_check,38.5
2,anagram_check,38.5
3,anagram_check,38.5
4,anagram_check,38.5
5,anagram_check,38.5
6,anagram_check,38.5
7,anagram_check,38.5
8,anagram_check,38.5
9,anagram_check,38.5
10,caesar_cipher,64.7
11,caesar_cipher,64.7
12,caesar_cipher,64.7
13,caesar_cipher,64.7
14,caesar_cipher,64.7
15,caesar_cipher,64.7
16,caesar_cipher,64.7
17,caesar_cipher,64.7
18,caesar_cipher,64.7
19,caesar_cipher,64.7
20,check_armstrong,93.5
21,check_armstrong,93.5
22,check_armstrong,93.5
23,check_armstrong,93.5
24,check_armstrong,93.5
25,check_armstrong,93.5
26,check_armstrong,93.5
27,check_armstrong,93.5
28,check_armstrong,93.5
29,check_armstrong,93.5
30,common_divisor_count,80.9
31,common_divisor_count,80.9
32,common_divisor_count,80.9
33,common_divisor_count,80.9
34,common_divisor_count,80.9
35,common_divisor_count,80.9
36,common_divisor_count,80.9
37,common_divisor_count,80.9
38,common_divisor_count,80.9
39,common_divisor_count,80.9
40,exponentiation,71.4
41,exponentiation,71.4
42,exponentiation,71.4
43,exponentiation,71.4
44,exponentiation,71.4
45,exponentiation,71.4
46,exponentiation,71.4
47,exponentiation,71.4
48,exponentiation,71.4
49,exponentiation,71.4
50,gcd,60.9
51,gcd,60.9
52,gcd,60.9
53,gcd,60.9
54,gcd,60.9
55,gcd,60.9
56,gcd,60.9
57,gcd,60.9
58,gcd,60.9
59,gcd,60.9
60,longest_substring,69.6
61,longest_substring,69.6
62,longest_substring,69.6
63,longest_substring,69.6
64,longest_substring,69.6
65,longest_substring,69.6
66,longest_substring,69.6
67,longest_substring,69.6
68,longest_substring,69.6
69,longest_substring,69.6
70,rabin_karp,50.9
71,rabin_karp,50.9
72,rabin_karp,50.9
73,rabin_karp,50.9
74,rabin_karp,50.9
75,rabin_karp,50.9
76,rabin_karp,50.9
77,rabin_karp,50.9
78,rabin_karp,50.9
79,rabin_karp,50.9
80,railfence_cipher,86.2
81,railfence_cipher,86.2
82,railfence_cipher,86.2
83,railfence_cipher,86.2
84,railfence_cipher,86.2
85,railfence_cipher,86.2
86,railfence_cipher,86.2
87,railfence_cipher,86.2
88,railfence_cipher,86.2
89,railfence_cipher,86.2
90,zellers_birthday,65.0
91,zellers_birthday,65.0
92,zellers_birthday,65.0
93,zellers_birthday,65.0
94,zellers_birthday,65.0
95,zellers_birthday,65.0
96,zellers_birthday,65.0
97,zellers_birthday,65.0
98,zellers_birthday,65.0
99,zellers_birthday,65.0
1 file score
2 0 anagram_check 38.5
3 1 anagram_check 38.5
4 2 anagram_check 38.5
5 3 anagram_check 38.5
6 4 anagram_check 38.5
7 5 anagram_check 38.5
8 6 anagram_check 38.5
9 7 anagram_check 38.5
10 8 anagram_check 38.5
11 9 anagram_check 38.5
12 10 caesar_cipher 64.7
13 11 caesar_cipher 64.7
14 12 caesar_cipher 64.7
15 13 caesar_cipher 64.7
16 14 caesar_cipher 64.7
17 15 caesar_cipher 64.7
18 16 caesar_cipher 64.7
19 17 caesar_cipher 64.7
20 18 caesar_cipher 64.7
21 19 caesar_cipher 64.7
22 20 check_armstrong 93.5
23 21 check_armstrong 93.5
24 22 check_armstrong 93.5
25 23 check_armstrong 93.5
26 24 check_armstrong 93.5
27 25 check_armstrong 93.5
28 26 check_armstrong 93.5
29 27 check_armstrong 93.5
30 28 check_armstrong 93.5
31 29 check_armstrong 93.5
32 30 common_divisor_count 80.9
33 31 common_divisor_count 80.9
34 32 common_divisor_count 80.9
35 33 common_divisor_count 80.9
36 34 common_divisor_count 80.9
37 35 common_divisor_count 80.9
38 36 common_divisor_count 80.9
39 37 common_divisor_count 80.9
40 38 common_divisor_count 80.9
41 39 common_divisor_count 80.9
42 40 exponentiation 71.4
43 41 exponentiation 71.4
44 42 exponentiation 71.4
45 43 exponentiation 71.4
46 44 exponentiation 71.4
47 45 exponentiation 71.4
48 46 exponentiation 71.4
49 47 exponentiation 71.4
50 48 exponentiation 71.4
51 49 exponentiation 71.4
52 50 gcd 60.9
53 51 gcd 60.9
54 52 gcd 60.9
55 53 gcd 60.9
56 54 gcd 60.9
57 55 gcd 60.9
58 56 gcd 60.9
59 57 gcd 60.9
60 58 gcd 60.9
61 59 gcd 60.9
62 60 longest_substring 69.6
63 61 longest_substring 69.6
64 62 longest_substring 69.6
65 63 longest_substring 69.6
66 64 longest_substring 69.6
67 65 longest_substring 69.6
68 66 longest_substring 69.6
69 67 longest_substring 69.6
70 68 longest_substring 69.6
71 69 longest_substring 69.6
72 70 rabin_karp 50.9
73 71 rabin_karp 50.9
74 72 rabin_karp 50.9
75 73 rabin_karp 50.9
76 74 rabin_karp 50.9
77 75 rabin_karp 50.9
78 76 rabin_karp 50.9
79 77 rabin_karp 50.9
80 78 rabin_karp 50.9
81 79 rabin_karp 50.9
82 80 railfence_cipher 86.2
83 81 railfence_cipher 86.2
84 82 railfence_cipher 86.2
85 83 railfence_cipher 86.2
86 84 railfence_cipher 86.2
87 85 railfence_cipher 86.2
88 86 railfence_cipher 86.2
89 87 railfence_cipher 86.2
90 88 railfence_cipher 86.2
91 89 railfence_cipher 86.2
92 90 zellers_birthday 65.0
93 91 zellers_birthday 65.0
94 92 zellers_birthday 65.0
95 93 zellers_birthday 65.0
96 94 zellers_birthday 65.0
97 95 zellers_birthday 65.0
98 96 zellers_birthday 65.0
99 97 zellers_birthday 65.0
100 98 zellers_birthday 65.0
101 99 zellers_birthday 65.0

View File

@ -3,17 +3,12 @@ from benchmark.anagram_check import anagram_check
class Test_anagram_check(TestCase):
# distances_true = {1: [0], 2: [0]}
# distances_false = {1: [1], 2: [1]}
def test_anagram_check_1(self):
assert anagram_check(s1='/', s2='6') == False
# distances_true = {1: [1], 3: [1], 4: [0]}
# distances_false = {1: [0], 3: [0], 4: [1]}
def test_anagram_check_2(self):
assert anagram_check(s1='', s2='') == True
# distances_true = {1: [1], 3: [0]}
# distances_false = {1: [0], 3: [1]}
def test_anagram_check_3(self):
assert anagram_check(s1='md', s2='p') == False
def test_anagram_check_1(self):
assert anagram_check(s1='Oi', s2='p') == False
# distances_true = {1: [0], 2: [0]}
# distances_false = {1: [1], 2: [1]}
def test_anagram_check_2(self):
assert anagram_check(s1='_', s2='T') == False

View File

@ -4,14 +4,14 @@ from benchmark.caesar_cipher import decrypt
class Test_encrypt(TestCase):
# distances_true = {1: [0, 0, 0, 0, 40, 0, 31, 22]}
# distances_false = {1: [33, 14, 23, 29, 0, 28, 0, 0]}
# distances_true = {1: [3, 47, 0, 0, 46, 0, 22]}
# distances_false = {1: [0, 0, 31, 19, 0, 8, 0]}
def test_encrypt_1(self):
assert encrypt(strng='vclr.q7@', key=41) == '@-6<W;`i'
assert encrypt(strng='V*wk+`C', key=38) == "|P>2Q'i"
class Test_decrypt(TestCase):
# distances_true = {2: [0, 0, 1, 0, 0, 3, 1, 18, 48]}
# distances_false = {2: [1, 3, 0, 15, 6, 0, 0, 0, 0]}
# distances_true = {2: [0, 215, 203, 206, 217, 13]}
# distances_false = {2: [21, 0, 0, 0, 0, 0]}
def test_decrypt_1(self):
assert decrypt(strng='203$-53Db', key=19) == '~| py" 1O'
assert decrypt(strng='C."%0d', key=56) == 'jöêíø,'

View File

@ -3,27 +3,27 @@ from benchmark.check_armstrong import check_armstrong
class Test_check_armstrong(TestCase):
# distances_true = {1: [2], 2: [1], 3: [0]}
# distances_false = {1: [0], 2: [0], 3: [149]}
# distances_true = {1: [1], 2: [0]}
# distances_false = {1: [0], 2: [1]}
def test_check_armstrong_1(self):
assert check_armstrong(n=2) == False
assert check_armstrong(n=1) == True
# distances_true = {1: [0]}
# distances_false = {1: [1]}
def test_check_armstrong_2(self):
assert check_armstrong(n=0) == True
# distances_true = {1: [380], 2: [379], 3: [230], 4: [0, 0, 0, 1], 5: [159]}
# distances_false = {1: [0], 2: [0], 3: [0], 4: [380, 38, 3, 0], 5: [0]}
# distances_true = {1: [161], 2: [160], 3: [11], 4: [0, 0, 0, 1], 5: [57]}
# distances_false = {1: [0], 2: [0], 3: [0], 4: [161, 16, 1, 0], 5: [0]}
def test_check_armstrong_3(self):
assert check_armstrong(n=380) == False
assert check_armstrong(n=161) == False
# distances_true = {1: [153], 2: [152], 3: [3], 4: [0, 0, 0, 1], 5: [0]}
# distances_false = {1: [0], 2: [0], 3: [0], 4: [153, 15, 1, 0], 5: [1]}
def test_check_armstrong_4(self):
assert check_armstrong(n=153) == True
# distances_true = {1: [1], 2: [0]}
# distances_false = {1: [0], 2: [1]}
# distances_true = {1: [3], 2: [2], 3: [0]}
# distances_false = {1: [0], 2: [0], 3: [148]}
def test_check_armstrong_5(self):
assert check_armstrong(n=1) == True
assert check_armstrong(n=3) == False

View File

@ -3,32 +3,32 @@ from benchmark.common_divisor_count import cd_count
class Test_cd_count(TestCase):
# distances_true = {1: [5], 2: [618], 3: [6], 4: [619], 5: [0, 0, 0, 0, 1], 6: [0], 7: [0]}
# distances_false = {1: [0], 2: [0], 3: [0], 4: [0], 5: [5, 3, 2, 1, 0], 6: [1], 7: [1]}
# distances_true = {1: [5], 2: [621], 3: [0], 4: [622], 5: [0, 0, 1], 6: [0], 7: [0]}
# distances_false = {1: [0], 2: [0], 3: [5], 4: [0], 5: [5, 1, 0], 6: [1], 7: [1]}
def test_cd_count_1(self):
assert cd_count(a=5, b=618) == 1
assert cd_count(a=-5, b=621) == 1
# distances_true = {1: [0]}
# distances_false = {1: [1]}
def test_cd_count_2(self):
assert cd_count(a=0, b=-49) == 2
assert cd_count(a=0, b=621) == 2
# distances_true = {1: [4], 2: [101], 3: [5], 4: [0], 5: [0, 0, 1], 6: [0], 7: [0]}
# distances_false = {1: [0], 2: [0], 3: [0], 4: [101], 5: [4, 1, 0], 6: [1], 7: [1]}
# distances_true = {1: [2], 2: [616], 3: [3], 4: [617], 5: [0, 1], 6: [0], 7: [1]}
# distances_false = {1: [0], 2: [0], 3: [0], 4: [0], 5: [2, 0], 6: [1], 7: [0]}
def test_cd_count_3(self):
assert cd_count(a=4, b=-101) == 1
assert cd_count(a=2, b=616) == 2
# distances_true = {1: [10], 2: [52], 3: [0], 4: [0], 5: [0, 0, 1], 6: [0], 7: [1]}
# distances_false = {1: [0], 2: [0], 3: [10], 4: [52], 5: [10, 2, 0], 6: [1], 7: [0]}
# distances_true = {1: [7], 2: [630], 3: [0], 4: [631], 5: [0, 1], 6: [0, 1], 7: [6]}
# distances_false = {1: [0], 2: [0], 3: [7], 4: [0], 5: [7, 0], 6: [1, 0], 7: [0]}
def test_cd_count_4(self):
assert cd_count(a=-10, b=-52) == 2
assert cd_count(a=-7, b=630) == 2
# distances_true = {1: [9], 2: [0]}
# distances_true = {1: [624], 2: [0]}
# distances_false = {1: [0], 2: [1]}
def test_cd_count_5(self):
assert cd_count(a=9, b=0) == 2
assert cd_count(a=-624, b=0) == 2
# distances_true = {1: [10], 2: [150], 3: [0], 4: [0], 5: [0, 1], 6: [0, 0, 1], 7: [9, 3]}
# distances_false = {1: [0], 2: [0], 3: [10], 4: [150], 5: [10, 0], 6: [1, 1, 0], 7: [0, 0]}
# distances_true = {1: [637], 2: [6], 3: [0], 4: [0], 5: [0, 0, 0, 1], 6: [0], 7: [0]}
# distances_false = {1: [0], 2: [0], 3: [637], 4: [6], 5: [637, 6, 1, 0], 6: [1], 7: [1]}
def test_cd_count_6(self):
assert cd_count(a=-10, b=-150) == 4
assert cd_count(a=-637, b=-6) == 1

View File

@ -3,7 +3,7 @@ from benchmark.exponentiation import exponentiation
class Test_exponentiation(TestCase):
# distances_true = {1: [0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 3: [0], 2: [1, 1, 0, 1, 0, 1, 1, 1, 1]}
# distances_false = {1: [591, 295, 147, 73, 36, 17, 8, 3, 1, 0], 3: [1], 2: [0, 0, 1, 0, 1, 0, 0, 0, 0]}
# distances_true = {1: [0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 3: [0], 2: [0, 1, 1, 1, 1, 1, 0, 0, 1]}
# distances_false = {1: [773, 386, 192, 95, 47, 23, 11, 5, 2, 0], 3: [1], 2: [1, 0, 0, 0, 0, 0, 1, 1, 0]}
def test_exponentiation_1(self):
assert exponentiation(baseNumber=748, power=592) == 2237411859567305228712820969577177889399507688925863669623492970046756800811752671771192642266754818786206883016528099952656873068236573570940727536208482507787576742117892529716174302439216500172363521344994812494798736599216689085381729125165667408413134378577619291662064250215391547791138001022452137862778730264821893010999654434708983063321061487758219131875157534566833176981850918287964729665626846138477133321680757074668758491790945198601054224199588300081988215907925870651530562786845054260705838873377721118111382749970684115994163428904242940249188932413043444079730697574946438556722431973692672316117631662669780447322962255376036216266360170992797300680863608151678208837497803629559832285706122751678247068182933676547879825690946817522731921058001762116141626296741021042361970731691972888241818460142317141771780073548156492405406490981515425290002128649234461825789947573119368985161153262332388808724131879060867880473096842000650483632521058294479344879944564436266652927131107918428149402925778007533423162302903655859402260228366219008304205413113994847339399353552421491921433679173463981507810853240889014970942564956030433528528976883729747234323037570498652835167034147294039927751837932259353682824119565000780453933743514380393121666554146174425347788804096581718436380869076273595714279596282320033858652789005508958162362572551844879419089353500606113442189427958545044465106509994666028492893004614086892576645413919934301813479926994631172622364458500761310743512340332065554689760340750349754142540650730287762939301975905339162897423087384712675419496189151357961520127467940210297313531487397450555066413386239184330770939775155310643870407646031104489325011664896
assert exponentiation(baseNumber=-1, power=774) == 1

View File

@ -3,22 +3,27 @@ from benchmark.gcd import gcd
class Test_gcd(TestCase):
# distances_true = {1: [97], 2: [0]}
# distances_false = {1: [0], 2: [1]}
def test_gcd_1(self):
assert gcd(a=98, b=1) == 1
# distances_true = {1: [97], 2: [1], 3: [96], 4: [97], 5: [0, 1]}
# distances_false = {1: [0], 2: [0], 3: [0], 4: [0], 5: [2, 0]}
def test_gcd_2(self):
assert gcd(a=98, b=2) == 2
# distances_true = {1: [9], 2: [9], 3: [0]}
# distances_false = {1: [0], 2: [0], 3: [1]}
def test_gcd_3(self):
assert gcd(a=10, b=10) == 10
# distances_true = {1: [7], 2: [943], 3: [936], 4: [0], 5: [0, 1]}
# distances_false = {1: [0], 2: [0], 3: [0], 4: [936], 5: [8, 0]}
def test_gcd_4(self):
assert gcd(a=8, b=944) == 8
# distances_true = {1: [0]}
# distances_false = {1: [1]}
def test_gcd_1(self):
assert gcd(a=1, b=376) == 1
# distances_true = {1: [3], 2: [309], 3: [306], 4: [0], 5: [0, 0, 1]}
# distances_false = {1: [0], 2: [0], 3: [0], 4: [306], 5: [4, 2, 0]}
def test_gcd_2(self):
assert gcd(a=4, b=310) == 2
# distances_true = {1: [930], 2: [8], 3: [922], 4: [923], 5: [0, 0, 0, 1]}
# distances_false = {1: [0], 2: [0], 3: [0], 4: [0], 5: [9, 4, 1, 0]}
def test_gcd_3(self):
assert gcd(a=931, b=9) == 1
# distances_true = {1: [698], 2: [0]}
# distances_false = {1: [0], 2: [1]}
def test_gcd_4(self):
assert gcd(a=699, b=1) == 1
def test_gcd_5(self):
assert gcd(a=1, b=933) == 1

View File

@ -3,7 +3,7 @@ from benchmark.longest_substring import longest_sorted_substr
class Test_longest_sorted_substr(TestCase):
# distances_true = {1: [45, 0, 14, 0, 15, 0, 0], 2: [0, 1, 1, 0]}
# distances_false = {1: [0, 43, 0, 13, 0, 30, 3], 2: [1, 0, 0, 1]}
# distances_true = {1: [0, 8, 0, 27, 53, 0, 11], 2: [0, 1, 1]}
# distances_false = {1: [11, 0, 82, 0, 0, 71, 0], 2: [1, 0, 0]}
def test_longest_sorted_substr_1(self):
assert longest_sorted_substr(s='b5_Q]Nkm') == 'Nkm'
assert longest_sorted_substr(s="$.&w\\'mb") == '$.'

View File

@ -3,17 +3,17 @@ from benchmark.rabin_karp import rabin_karp_search
class Test_rabin_karp_search(TestCase):
# distances_true = {1: [0], 2: [1], 3: [0], 4: [1]}
# distances_false = {1: [1], 2: [0], 3: [1], 4: [0]}
# distances_true = {1: [0], 2: [1, 0], 3: [1], 4: [1]}
# distances_false = {1: [1], 2: [0, 4], 3: [0], 4: [0]}
def test_rabin_karp_search_1(self):
assert rabin_karp_search(pat='z', txt='z') == [0]
assert rabin_karp_search(pat='A@@', txt='A<g') == []
# distances_true = {1: [0], 2: [0], 3: [3], 4: [1]}
# distances_false = {1: [1], 2: [23], 3: [0], 4: [0]}
# distances_true = {1: [28], 4: [1]}
# distances_false = {1: [0], 4: [0]}
def test_rabin_karp_search_2(self):
assert rabin_karp_search(pat='b&k<', txt='K@qO') == []
assert rabin_karp_search(pat='RC)', txt='][`') == []
# distances_true = {1: [0, 0, 61, 51, 81, 82, 87, 98], 3: [1, 2], 4: [0, 0, 0, 0, 0, 0, 0, 1], 5: [1, 62, 52, 82, 83, 88, 99]}
# distances_false = {1: [1, 1, 0, 0, 0, 0, 0, 0], 3: [0, 0], 4: [7, 6, 5, 4, 3, 2, 1, 0], 5: [0, 0, 0, 0, 0, 0, 0]}
# distances_true = {1: [0], 2: [0], 3: [2], 4: [1]}
# distances_false = {1: [1], 2: [25], 3: [0], 4: [0]}
def test_rabin_karp_search_3(self):
assert rabin_karp_search(pat='', txt='ex[>NC6') == []
assert rabin_karp_search(pat='*3~', txt='C9`') == []

View File

@ -4,14 +4,14 @@ from benchmark.railfence_cipher import raildecrypt
class Test_railencrypt(TestCase):
# distances_true = {1: [0, 0, 0, 0, 1, 1, 1, 0, 0], 2: [3, 2, 1, 0, 2, 1], 3: [2, 1, 0], 4: [0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1]}
# distances_false = {1: [1, 1, 1, 1, 0, 0, 0, 1, 1], 2: [0, 0, 0, 1, 0, 0], 3: [0, 0, 1], 4: [102, 0, 0, 0, 0, 0, 112, 0, 0, 0, 110, 0, 0, 0, 122, 0, 52, 0, 0, 0, 124, 0, 50, 0, 0, 0, 48, 0, 0, 0, 38, 0, 0, 0, 0, 0]}
# distances_true = {1: [0, 0, 0, 1, 1, 0, 0, 1], 2: [2, 1, 0, 1, 0], 3: [1, 0, 1], 4: [0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1]}
# distances_false = {1: [1, 1, 1, 0, 0, 1, 1, 0], 2: [0, 0, 1, 0, 1], 3: [0, 1, 0], 4: [126, 0, 0, 0, 110, 0, 0, 0, 0, 117, 0, 52, 0, 50, 0, 67, 0, 0, 32, 0, 0, 0, 104, 0]}
def test_railencrypt_1(self):
assert railencrypt(st='fn|&2zp40', k=4) == 'fpnz4|20&'
assert railencrypt(st='~u 4n2hC', k=3) == '~nu42C h'
class Test_raildecrypt(TestCase):
# distances_true = {5: [0, 0, 0, 0, 1, 1, 1], 6: [3, 2, 1, 0], 7: [2, 1, 0], 8: [0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1], 9: [0, 0, 0, 0, 0, 0, 0], 10: [7, 0, 0, 0, 1, 1, 1], 12: [0, 2, 1, 0], 11: [2, 1, 0]}
# distances_false = {5: [1, 1, 1, 1, 0, 0, 0], 6: [0, 0, 0, 1], 7: [0, 0, 1], 8: [1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0], 9: [125, 79, 95, 32, 85, 109, 46], 10: [0, 1, 1, 1, 0, 0, 0], 12: [1, 0, 0, 1], 11: [0, 0, 1]}
# distances_true = {5: [0, 0, 0, 1, 1, 0, 0, 1], 6: [2, 1, 0, 1, 0], 7: [1, 0, 1], 8: [0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1], 9: [0, 0, 0, 0, 0, 0, 0, 0], 10: [8, 0, 0, 1, 1, 0, 0, 1], 12: [0, 1, 0, 1], 11: [1, 0, 1, 0]}
# distances_false = {5: [1, 1, 1, 0, 0, 1, 1, 0], 6: [0, 0, 1, 0, 1], 7: [0, 1, 0], 8: [1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0], 9: [58, 96, 58, 124, 48, 73, 82, 79], 10: [0, 1, 1, 0, 0, 1, 1, 0], 12: [1, 0, 1, 0], 11: [0, 1, 0, 1]}
def test_raildecrypt_1(self):
assert raildecrypt(st='}.Om_U ', k=4) == '}O_ Um.'
assert raildecrypt(st=':0`|IO:R', k=3) == ':`:|0IRO'

View File

@ -6,14 +6,19 @@ class Test_zeller(TestCase):
# distances_true = {1: [1], 2: [6], 3: [0], 4: [0], 5: [1923], 7: [5], 8: [0]}
# distances_false = {1: [0], 2: [0], 3: [78], 4: [1], 5: [0], 7: [0], 8: [1]}
def test_zeller_1(self):
assert zeller(d=31, m=7, y=-22) == 'Sunday'
assert zeller(d=-31, m=-7, y=-22) == 'Sunday'
# distances_true = {1: [0], 2: [0], 3: [0], 4: [0], 5: [1923], 7: [0], 8: [3, 2, 1, 0]}
# distances_false = {1: [1], 2: [1], 3: [78], 4: [1], 5: [0], 7: [1], 8: [0, 0, 0, 1]}
# distances_true = {1: [0], 2: [0], 3: [0], 4: [0], 5: [1923], 7: [0], 8: [6, 5, 4, 3, 2, 1, 0]}
# distances_false = {1: [4], 2: [1], 3: [78], 4: [1], 5: [0], 7: [1], 8: [0, 0, 0, 0, 0, 0, 1]}
def test_zeller_2(self):
assert zeller(d=32, m=13, y=-22) == 'Wednesday'
assert zeller(d=-35, m=-13, y=-22) == 'Saturday'
# distances_true = {1: [1], 2: [0], 3: [0], 4: [8], 5: [0], 6: [0], 7: [0], 8: [1, 0]}
# distances_false = {1: [0], 2: [1], 3: [70], 4: [0], 5: [70], 6: [8], 7: [1], 8: [0, 1]}
# distances_true = {1: [1], 2: [0], 3: [0], 4: [7], 5: [0], 6: [0], 7: [0], 8: [0]}
# distances_false = {1: [0], 2: [1], 3: [71], 4: [0], 5: [71], 6: [7], 7: [1], 8: [1]}
def test_zeller_3(self):
assert zeller(d=31, m=13, y=-30) == 'Monday'
assert zeller(d=-31, m=-13, y=-29) == 'Sunday'
# distances_true = {1: [1], 2: [0], 3: [0], 4: [0], 5: [1923], 7: [1], 8: [4, 3, 2, 1, 0]}
# distances_false = {1: [0], 2: [2], 3: [78], 4: [1], 5: [0], 7: [0], 8: [0, 0, 0, 0, 1]}
def test_zeller_4(self):
assert zeller(d=-31, m=-14, y=-22) == 'Thursday'