163 lines
4.9 KiB
Python
163 lines
4.9 KiB
Python
"""
|
|
©AngelaMos | 2026
|
|
test_cli.py
|
|
|
|
Integration tests for the encrypt, decrypt, and crack CLI commands
|
|
|
|
Tests each command's exit codes, output content, key validation, and
|
|
file-based I/O using Typer's CliRunner without spawning a subprocess.
|
|
|
|
Tests:
|
|
encrypt command: basic output, spaces, invalid key rejection
|
|
decrypt command: basic output, spaces, invalid key rejection
|
|
crack command: output format, --top option, --all option
|
|
file I/O: reading from and writing to temp files
|
|
|
|
Connects to:
|
|
main.py - invokes the Typer app under test
|
|
"""
|
|
|
|
from pathlib import Path
|
|
|
|
from typer.testing import CliRunner
|
|
|
|
from caesar_cipher.main import app
|
|
|
|
|
|
runner = CliRunner()
|
|
|
|
|
|
class TestEncryptCommand:
|
|
def test_encrypt_basic(self) -> None:
|
|
"""
|
|
Runs the encrypt command with key 3 and checks KHOOR appears in output
|
|
"""
|
|
result = runner.invoke(app, ["encrypt", "HELLO", "--key", "3"])
|
|
assert result.exit_code == 0
|
|
assert "KHOOR" in result.stdout
|
|
|
|
def test_encrypt_with_spaces(self) -> None:
|
|
"""
|
|
Runs encrypt on a two-word phrase and checks both words shift correctly
|
|
"""
|
|
result = runner.invoke(app, ["encrypt", "HELLO WORLD", "--key", "3"])
|
|
assert result.exit_code == 0
|
|
assert "KHOOR ZRUOG" in result.stdout
|
|
|
|
def test_encrypt_invalid_key(self) -> None:
|
|
"""
|
|
Runs encrypt with key 30 and confirms exit code 1 and an error message
|
|
"""
|
|
result = runner.invoke(app, ["encrypt", "HELLO", "--key", "30"])
|
|
assert result.exit_code == 1
|
|
assert "Error" in result.stdout
|
|
|
|
|
|
class TestDecryptCommand:
|
|
def test_decrypt_basic(self) -> None:
|
|
"""
|
|
Runs the decrypt command with key 3 and checks HELLO appears in output
|
|
"""
|
|
result = runner.invoke(app, ["decrypt", "KHOOR", "--key", "3"])
|
|
assert result.exit_code == 0
|
|
assert "HELLO" in result.stdout
|
|
|
|
def test_decrypt_with_spaces(self) -> None:
|
|
"""
|
|
Runs decrypt on a two-word ciphertext and checks the full plaintext is recovered
|
|
"""
|
|
result = runner.invoke(app, ["decrypt", "KHOOR ZRUOG", "--key", "3"])
|
|
assert result.exit_code == 0
|
|
assert "HELLO WORLD" in result.stdout
|
|
|
|
def test_decrypt_invalid_key(self) -> None:
|
|
"""
|
|
Runs decrypt with an out-of-range key and confirms exit code 1 and an error message
|
|
"""
|
|
result = runner.invoke(app, ["decrypt", "KHOOR", "--key", "30"])
|
|
assert result.exit_code == 1
|
|
assert "Error" in result.stdout
|
|
|
|
|
|
class TestCrackCommand:
|
|
def test_crack_basic(self) -> None:
|
|
"""
|
|
Runs the crack command and confirms HELLO is recovered and best match is shown
|
|
"""
|
|
result = runner.invoke(app, ["crack", "KHOOR"])
|
|
assert result.exit_code == 0
|
|
assert "HELLO" in result.stdout
|
|
assert "Best match" in result.stdout
|
|
|
|
def test_crack_with_top_option(self) -> None:
|
|
"""
|
|
Runs crack with --top 3 and confirms the command completes successfully
|
|
"""
|
|
result = runner.invoke(app, ["crack", "KHOOR", "--top", "3"])
|
|
assert result.exit_code == 0
|
|
|
|
def test_crack_show_all(self) -> None:
|
|
"""
|
|
Runs crack with --all and confirms all 26 shifts are displayed without error
|
|
"""
|
|
result = runner.invoke(app, ["crack", "KHOOR", "--all"])
|
|
assert result.exit_code == 0
|
|
|
|
|
|
class TestFileIO:
|
|
def test_encrypt_from_file(self, tmp_path: Path) -> None:
|
|
"""
|
|
Encrypts text read from a temp input file and checks the ciphertext in output
|
|
"""
|
|
input_file = tmp_path / "input.txt"
|
|
input_file.write_text("HELLO WORLD")
|
|
|
|
result = runner.invoke(
|
|
app,
|
|
["encrypt",
|
|
"--input-file",
|
|
str(input_file),
|
|
"--key",
|
|
"3"]
|
|
)
|
|
assert result.exit_code == 0
|
|
assert "KHOOR ZRUOG" in result.stdout
|
|
|
|
def test_encrypt_to_file(self, tmp_path: Path) -> None:
|
|
"""
|
|
Encrypts text and writes to a temp file, then reads it back to verify contents
|
|
"""
|
|
output_file = tmp_path / "output.txt"
|
|
|
|
result = runner.invoke(
|
|
app,
|
|
[
|
|
"encrypt",
|
|
"HELLO",
|
|
"--key",
|
|
"3",
|
|
"--output-file",
|
|
str(output_file),
|
|
],
|
|
)
|
|
assert result.exit_code == 0
|
|
assert output_file.read_text() == "KHOOR"
|
|
|
|
def test_decrypt_from_file(self, tmp_path: Path) -> None:
|
|
"""
|
|
Decrypts text read from a temp input file and checks the plaintext in output
|
|
"""
|
|
input_file = tmp_path / "input.txt"
|
|
input_file.write_text("KHOOR")
|
|
|
|
result = runner.invoke(
|
|
app,
|
|
["decrypt",
|
|
"--input-file",
|
|
str(input_file),
|
|
"--key",
|
|
"3"]
|
|
)
|
|
assert result.exit_code == 0
|
|
assert "HELLO" in result.stdout
|