diff --git a/examples/basic_usage.py b/examples/basic_usage.py index 8c70521..d5ad2b0 100644 --- a/examples/basic_usage.py +++ b/examples/basic_usage.py @@ -1,13 +1,11 @@ from puzzle_generator.create_puzzle import create -_PUZZLE = { - "str": "What is 1+1?", - "pass": "2", - "rest": { - "str": "What is my name?", - "pass": "Piotr", - "rest": {"str": "Congratulations, you solved this quiz!"}, - }, -} +_PUZZLE = [ + "What is 1+1?", + "2", + "What is my name?", + "Piotr", + "Congratulations, you solved this quiz!", +] print(create(_PUZZLE)) diff --git a/puzzle_generator/create_puzzle.py b/puzzle_generator/create_puzzle.py index 4940e2b..a80676f 100644 --- a/puzzle_generator/create_puzzle.py +++ b/puzzle_generator/create_puzzle.py @@ -1,9 +1,22 @@ import inspect +import typing from .puzzle_data_encryption import encrypt_data from .configurators import configurators +def question_answer_list_to_dict(qa_list: typing.List[str]): + if len(qa_list) % 2 == 0: + raise ValueError("The question/answer list must have odd length.") + if len(qa_list) == 1: + return {"str": qa_list[0]} + return { + "str": qa_list[0], + "pass": qa_list[1], + "rest": question_answer_list_to_dict(qa_list[2:]), + } + + def _create_str(in_encrypted_puzzle, configurator) -> str: advertisement = """# generated with puzzle-generator # @@ -32,7 +45,8 @@ def _create_str(in_encrypted_puzzle, configurator) -> str: ) -def create(in_puzzle, **kwargs) -> str: +def create(qa_list: typing.List[str], **kwargs) -> str: + puzzle = question_answer_list_to_dict(qa_list) configurator = configurators.get_configurator(**kwargs) - encrypted_puzzle = encrypt_data(in_puzzle, configurator.get_encrypt()) + encrypted_puzzle = encrypt_data(puzzle, configurator.get_encrypt()) return _create_str(encrypted_puzzle, configurator) diff --git a/pyproject.toml b/pyproject.toml index 6ab04dc..043da91 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "puzzle-generator" -version = "0.5.3" +version = "0.6.0" description = "Generates python code representing a puzzle" authors = ["piotr.idzik "] readme = "./puzzle_generator/README.md" diff --git a/tests/test_create_puzzle.py b/tests/test_create_puzzle.py index ea938db..f33c0d5 100644 --- a/tests/test_create_puzzle.py +++ b/tests/test_create_puzzle.py @@ -17,7 +17,7 @@ _PuzzleTestCase = collections.namedtuple( "_PuzzleTestCase", [ - "puzzle", + "qa_list", "correct", "wrong", ], @@ -26,17 +26,15 @@ @pytest.fixture(name="puzzle_tc") def fixture_puzzle_tc(): - puzzle = { - "str": "Question 1?", - "pass": "Answer 1", - "rest": { - "str": "Question 2?", - "pass": "Is this the final answer?", - "rest": {"str": "Congratulations!"}, - }, - } + qa_list = [ + "Question 1?", + "Answer 1", + "Question 2?", + "Is this the final answer?", + "Congratulations!", + ] return _PuzzleTestCase( - puzzle=puzzle, + qa_list=qa_list, correct=_InputOutput( input=["Answer 1", "Is this the final answer?"], output="Question 1?\nQuestion 2?\nCongratulations!\n", @@ -111,7 +109,7 @@ def test_all_good_answers( puzzle_path: pathlib.Path, configuration, ) -> None: - puzzle: str = cp.create(puzzle_tc.puzzle, **configuration) + puzzle: str = cp.create(puzzle_tc.qa_list, **configuration) res = _run_puzzle_str(puzzle, puzzle_tc.correct.input, puzzle_path) assert res.returncode == 0 @@ -126,7 +124,7 @@ def test_wrong_answers( configuration, ) -> None: for cur_wrong in puzzle_tc.wrong: - puzzle: str = cp.create(puzzle_tc.puzzle, **configuration) + puzzle: str = cp.create(puzzle_tc.qa_list, **configuration) res = _run_puzzle_str(puzzle, cur_wrong.input, puzzle_path) assert res.returncode == 1 assert res.stdout == cur_wrong.output @@ -176,7 +174,9 @@ def _input_simulator() -> str: @pytest.mark.parametrize(("encrypt", "decrypt"), _ENCRYPT_DECRYPT_PAIRS) def test_run_puzzle_all_good_answers(capsys, puzzle_tc, encrypt, decrypt) -> None: - encrypted_puzzle = pde.encrypt_data(puzzle_tc.puzzle, encrypt) + encrypted_puzzle = pde.encrypt_data( + cp.question_answer_list_to_dict(puzzle_tc.qa_list), encrypt + ) rp.run_puzzle( encrypted_puzzle, decrypt, _get_input_simulator(puzzle_tc.correct.input) ) @@ -187,7 +187,9 @@ def test_run_puzzle_all_good_answers(capsys, puzzle_tc, encrypt, decrypt) -> Non @pytest.mark.parametrize(("encrypt", "decrypt"), _ENCRYPT_DECRYPT_PAIRS) def test_run_puzzle_wrong_answers(capsys, puzzle_tc, encrypt, decrypt) -> None: for cur_wrong in puzzle_tc.wrong: - encrypted_puzzle = pde.encrypt_data(puzzle_tc.puzzle, encrypt) + encrypted_puzzle = pde.encrypt_data( + cp.question_answer_list_to_dict(puzzle_tc.qa_list), encrypt + ) with pytest.raises(SystemExit) as exc_info: rp.run_puzzle( encrypted_puzzle, @@ -198,3 +200,62 @@ def test_run_puzzle_wrong_answers(capsys, puzzle_tc, encrypt, decrypt) -> None: assert captured.out == cur_wrong.output assert exc_info.type is SystemExit assert exc_info.value.code == 1 + + +@pytest.mark.parametrize( + ("qa_list", "expected"), + [ + (["Congratulations!"], {"str": "Congratulations!"}), + ( + ["Question 1?", "Answer 1", "Congratulations!"], + { + "str": "Question 1?", + "pass": "Answer 1", + "rest": {"str": "Congratulations!"}, + }, + ), + ( + [ + "What is 1+1?", + "2", + "What is 2+2?", + "4", + "What is 3+3?", + "6", + "Congratulations!", + ], + { + "str": "What is 1+1?", + "pass": "2", + "rest": { + "str": "What is 2+2?", + "pass": "4", + "rest": { + "str": "What is 3+3?", + "pass": "6", + "rest": {"str": "Congratulations!"}, + }, + }, + }, + ), + ], +) +def test_question_answer_list_to_dict(qa_list, expected): + assert cp.question_answer_list_to_dict(qa_list) == expected + + +@pytest.mark.parametrize( + "wrong_qa_list", + [ + [], + ["Question", "Answer"], + ["Question 1", "Answer 1", "Question 2", "Answer 2"], + ], +) +def test_question_answer_list_to_dict_raises_when_input_list_has_even_length( + wrong_qa_list, +): + with pytest.raises( + ValueError, match="The question/answer list must have odd length." + ): + cp.question_answer_list_to_dict(wrong_qa_list)