def test_open_existing_dictionary(temp_dir): # Create not existing language. with Dictionary.open("english", create=True, _database_path=temp_dir) as _: pass # Open newly created language with Dictionary.open("english", _database_path=temp_dir) as english_dictionary: assert english_dictionary._already_created()
def test_populate_database_histogram_from_text_file(temp_dir): text_file_pathname = "cifra/tests/resources/english_book.txt" with Dictionary.open("english", create=True, _database_path=temp_dir) as current_dictionary: current_dictionary.populate(text_file_pathname) with Dictionary.open("english", create=False, _database_path=temp_dir) as current_dictionary: assert current_dictionary.letter_histogram["e"] == 35127 assert current_dictionary.letter_histogram["t"] == 26406 assert current_dictionary.letter_histogram["a"] == 24684 assert current_dictionary.letter_histogram["o"] == 22983
def main(args=sys.argv[1:], _database_path=None) -> None: arguments: Dict[str, str] = parse_arguments(args) # DICTIONARY MANAGEMENT if arguments["mode"] == "dictionary": if arguments["action"] == "create": initial_words_file = arguments.get("initial_words_file", None) with Dictionary.open(arguments["dictionary_name"], create=True, _database_path=_database_path) as dictionary: if initial_words_file is not None: dictionary.populate(initial_words_file) elif arguments["action"] == "delete": Dictionary.remove_dictionary(arguments["dictionary_name"], _database_path=_database_path) elif arguments["action"] == "update": with Dictionary.open(arguments["dictionary_name"], create=False, _database_path=_database_path) as dictionary: dictionary.populate(arguments["words_file"]) elif arguments["action"] == "list": dictionaries = Dictionary.get_available_languages( _database_path=_database_path) for dictionary in dictionaries: print(dictionary) # CIPHERING MANAGEMENT elif arguments["mode"] == "cipher": ciphered_content = _process_file_with_key( arguments["file_to_cipher"], Algorithm.from_string(arguments["algorithm"]), arguments["key"], MessageOperation.from_string(arguments["mode"]), arguments["charset"] if "charset" in arguments else None) _output_result(ciphered_content, arguments) # DECIPHERING MANAGEMENT elif arguments["mode"] == "decipher": deciphered_content = _process_file_with_key( arguments["file_to_decipher"], Algorithm.from_string(arguments["algorithm"]), arguments["key"], MessageOperation.from_string(arguments["mode"]), arguments["charset"] if "charset" in arguments else None) _output_result(deciphered_content, arguments) # ATTACK MANAGEMENT elif arguments["mode"] == "attack": recovered_content = _attack_file( arguments["file_to_attack"], Algorithm.from_string(arguments["algorithm"]), arguments["charset"] if "charset" in arguments else None, _database_path=_database_path) _output_result(recovered_content, arguments)
def test_populate_words_from_text_files(temporary_text_file): text_file = temporary_text_file[0].name text_without_punctuation_marks = temporary_text_file[1] current_language = temporary_text_file[2] temp_dir = temporary_text_file[3] expected_set = set(text_without_punctuation_marks.lower().split()) with Dictionary.open(current_language, create=True, _database_path=temp_dir) as current_dictionary: current_dictionary.populate(text_file) with Dictionary.open(current_language, _database_path=temp_dir) as current_dictionary: for word in expected_set: assert current_dictionary.word_exists(word)
def test_get_all_words(loaded_dictionary_temp_dir): expected_words = ["yes", "no", "dog", "cat", "snake"] with Dictionary.open( "english", False, _database_path=loaded_dictionary_temp_dir) as dictionary: returned_words = dictionary.get_all_words() assert set(returned_words) == set(expected_words)
def loaded_dictionary_temp_dir(tmp_path): """Create a dictionary at a temp dir filled with only a handful of words. :return: Yields created temp_dir to host temporal dictionary database. """ # Load test data. for language, words in MICRO_DICTIONARIES.items(): with Dictionary.open(language, create=True, _database_path=tmp_path) as language_dictionary: _ = [language_dictionary.add_word(word) for word in words] # Check all words are stored at database: for language, words in MICRO_DICTIONARIES.items(): with Dictionary.open(language, _database_path=tmp_path) as language_dictionary: assert all(language_dictionary.word_exists(word) for word in words) yield tmp_path
def _dictionary_word_key_generator( _database_path: Optional[str] = None) -> Iterator[str]: """ Iterate through every word in our dictionaries. """ available_languages = Dictionary.get_available_languages(_database_path) for language in available_languages: with Dictionary.open(language, False, _database_path) as language_dictionary: words = language_dictionary.get_all_words() for word in words: yield word
def test_add_multiple_words(temp_dir): language = "english" with Dictionary.open(language, create=True, _database_path=temp_dir) as dictionary: assert all(not dictionary.word_exists(word) for word in MICRO_DICTIONARIES[language]) dictionary.add_multiple_words(MICRO_DICTIONARIES[language]) assert all( dictionary.word_exists(word) for word in MICRO_DICTIONARIES[language])
def test_cwd_word(temp_dir): """Test if we can check for word existence, write a new word and finally delete it.""" word = "test" with Dictionary.open("english", create=True, _database_path=temp_dir) as english_dictionary: assert not english_dictionary.word_exists(word) english_dictionary.add_word(word) assert english_dictionary.word_exists(word) english_dictionary.remove_word(word) assert not english_dictionary.word_exists(word)
def test_store_word_pattern(temp_dir): """Test word pattern is properly stored at database.""" word = "classification" with Dictionary.open("test", create=True, _database_path=temp_dir) as test_dictionary: assert not test_dictionary.word_exists(word) test_dictionary.add_word(word) assert test_dictionary.word_exists(word) words = test_dictionary.get_words_with_pattern( "0.1.2.3.3.4.5.4.0.2.6.4.7.8") assert word in words
def _generate_language_mapping(language: str, ciphered_words: Set[str], charset: str = DEFAULT_CHARSET, _database_path: Optional[str] = None) -> Mapping: """ Generate a mapping with all letter candidates in given language for every cipherletter. :param language: Language to look letter candidates into. :param ciphered_words: Every cipherword in message. :param charset: Charset used for substitution. Both ends, ciphering and deciphering, should use the same charset or original text won't be properly recovered. :param _database_path: Absolute pathname to database file. Usually you don't set this parameter, but it is useful for tests. :return: Mapping loaded with all candidates in given language. """ language_mapping = Mapping(charset) with Dictionary.open(language, False, _database_path=_database_path) as dictionary: for ciphered_word in ciphered_words: word_mapping = _get_word_mapping(charset, ciphered_word, dictionary) language_mapping.reduce_mapping(word_mapping) return language_mapping
def loaded_dictionaries() -> LoadedDictionaries: """Create a dictionaries database at a temp dir filled with four languages. Languages in database are: english, spanish, french and german. :return: Yields a LoadedDictionary fill info of temporal dictionaries database. """ with tempfile.TemporaryDirectory() as temp_dir: resources_path = os.path.join(temp_dir, "resources") os.mkdir(resources_path) copy_files([ f"cifra/tests/resources/{language}_book.txt" for language in LANGUAGES ], resources_path) for language in LANGUAGES: with Dictionary.open(language=language, create=True, _database_path=temp_dir) as dictionary: language_book = os.path.join(temp_dir, f"resources/{language}_book.txt") dictionary.populate(language_book) yield LoadedDictionaries(temp_dir=temp_dir, languages=LANGUAGES)
def frequency_key_generator( ciphered_text: str, maximum_key_length: int = 5, _database_path: Optional[str] = None) -> Iterator[str]: """ Assess statistically given ciphertext to return most likely keys. :param ciphered_text: Text to be deciphered. :param maximum_key_length: Give keys up to given maximum key length. :param _database_path: Absolute pathname to database file. Usually you don't set this parameter, but it is useful for tests. :return: An iterator through most likely keys below given length. """ likely_key_lengths = _get_likely_key_lengths(ciphered_text, maximum_key_length) keys_to_try: List[str] = [] for language in Dictionary.get_available_languages(_database_path): with Dictionary.open(language, False, _database_path) as language_dictionary: for key_length in likely_key_lengths: substrings = get_substrings(ciphered_text, key_length) likely_keys = _get_likely_keys(substrings, language_dictionary) keys_to_try.extend(likely_keys) for key in keys_to_try: yield key
def test_open_not_existing_dictionary(temp_dir): with pytest.raises(NotExistingLanguage): with Dictionary.open("english", _database_path=temp_dir) as _: pass