diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..019f533 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,61 @@ +name: CI / CD - Morse Code + +on: + pull_request: + branches: [pipfile-experiment] + push: + tags: ["v*"] + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + timeout-minutes: 5 + strategy: + matrix: + python-version: ["3.10", "3.11"] + + steps: + - uses: actions/checkout@v4 + + - name: Install Python and Pipenv + uses: kojoru/prepare-pipenv@v1 + with: + python-version: ${{ matrix.python-version }} + + + - name: Turn on 'editable' mode + run: | + pipenv install -e . + + - name: Run pytest + run: | + pipenv install pytest + pipenv --venv + pipenv run python -m pytest + + deliver: + if: github.event_name != 'pull_request' + needs: [build] + runs-on: ubuntu-latest + timeout-minutes: 5 + + steps: + - uses: actions/checkout@v4 + + - name: Install Python, pipenv and Pipfile packages + uses: kojoru/prepare-pipenv@v1 + with: + python-version: "3.10" + + - name: Build package + run: | + pipenv install build + pipenv run python -m build . + + # publish to PyPI Test server + # - name: Publish to TestPyPI + # uses: pypa/gh-action-pypi-publish@release/v1 + # with: + # password: ${{ secrets.TEST_PYPI_API_TOKEN }} + # repository-url: https://test.pypi.org/legacy/ diff --git a/Pipfile b/Pipfile new file mode 100644 index 0000000..7e1d224 --- /dev/null +++ b/Pipfile @@ -0,0 +1,13 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +pytest = "*" +morse-code = {file = ".", editable = true} + +[dev-packages] + +[requires] +python_version = "3.10" diff --git a/Pipfile.lock b/Pipfile.lock new file mode 100644 index 0000000..7c5eb6e --- /dev/null +++ b/Pipfile.lock @@ -0,0 +1,66 @@ +{ + "_meta": { + "hash": { + "sha256": "8d4fce0340a506ab07fcfec2c61ecc8853335394bbda7148e9f28d01a844aded" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.10" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "iniconfig": { + "hashes": [ + "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", + "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12" + ], + "markers": "python_version >= '3.10'", + "version": "==2.3.0" + }, + "morse-code": { + "editable": true, + "file": "." + }, + "packaging": { + "hashes": [ + "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", + "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f" + ], + "markers": "python_version >= '3.8'", + "version": "==25.0" + }, + "pluggy": { + "hashes": [ + "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", + "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746" + ], + "markers": "python_version >= '3.9'", + "version": "==1.6.0" + }, + "pygments": { + "hashes": [ + "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", + "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b" + ], + "markers": "python_version >= '3.8'", + "version": "==2.19.2" + }, + "pytest": { + "hashes": [ + "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01", + "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79" + ], + "index": "pypi", + "markers": "python_version >= '3.9'", + "version": "==8.4.2" + } + }, + "develop": {} +} diff --git a/README.md b/README.md index 6022e0e..2272b65 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,21 @@ # Python Package Exercise An exercise to create a Python package, build it, test it, distribute it, and use it. See [instructions](./instructions.md) for details. + +## morseify - Overview +morseify is a lightweight Python package that brings the world of Morse code to anyone curious about how digital communication began. It offers intuitive encode and decode functionality to translate between English text and Morse code, along with built-in tools for text normalization and message validation. + +For a more interactive experience, morseify also includes a quiz mode that generates random Morse code challenges for users to decode, making it both an educational and entertaining way to explore the fundamentals of encoded communication. + +## Features +- Encode English text to Morse code +- Decode Morse code to English text +- Normalize text and Morse sequences +- Validate Morse message formats +- Explain message steps +- Quiz mode to test Morse knowledge + +## Installation / Setup + + diff --git a/examples/demo.py b/examples/demo.py new file mode 100644 index 0000000..e69de29 diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..6413373 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,31 @@ +[build-system] +requires = ["setuptools>=68", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "morse_code" +version = "0.1.0" +description = "A Python package for encoding and decoding Morse code." +readme = "README.md" +requires-python = ">=3.10" +license = { file = "LICENSE" } +authors = [{ name = "Team Lumen" }] +keywords = ["python", "morse code", "encoder", "decoder"] +classifiers = [ + "Programming Language :: Python :: 3", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent" +] + +[project.urls] +Homepage = "https://github.com/swe-students-fall2025/3-python-package-team_lumen" +Issues = "https://github.com/swe-students-fall2025/3-python-package-team_lumen/issues" + +[tool.setuptools] +package-dir = {"" = "src"} + +[tool.setuptools.packages.find] +where = ["src"] + +[project.scripts] +morseify = "morseify.cli:cli" diff --git a/src/morseify/__init__.py b/src/morseify/__init__.py new file mode 100644 index 0000000..7b188a8 --- /dev/null +++ b/src/morseify/__init__.py @@ -0,0 +1,27 @@ +""" +Morse Code Package +A Python package for encoding and decoding Morse code with additional utilities. +""" + +from morseify.core import ( + encode, + decode, + is_valid +) +from morseify.normalize import ( + normalize_text, + normalize_code +) +from morseify.explain import explain +from morseify.quiz import quiz + +__all__ = [ + 'encode', + 'decode', + 'is_valid', + 'normalize_text', + 'normalize_code', + 'explain', + 'quiz' +] + diff --git a/src/morseify/__main__.py b/src/morseify/__main__.py new file mode 100644 index 0000000..e974edb --- /dev/null +++ b/src/morseify/__main__.py @@ -0,0 +1,41 @@ +from .core import encode, decode, is_valid +from .explain import explain +from .quiz import quiz + + +def main(): + print("Morse Code Encode/Decode Test") + # Test cases + test_cases = [ + "HELLO", + "HELLO WORLD", + "SOS", + "PYTHON", + "123", + "A1B2C3" + ] + + for text in test_cases: + encoded = encode(text) + decoded = decode(encoded) + + print(f"\nOriginal: '{text}'") + print(f"Encoded : '{encoded}'") + print(f"Decoded : '{decoded}'") + + # Check if round-trip works + if decoded == text: + print("✓ Round-trip successful!") + else: + print(f"✗ Round-trip failed! Expected: '{text}'") + + # Uncomment for interactive mode + # print("\nInteractive mode:") + # text = input("Enter text to encode: ") + # encoded = encode(text) + # print(f"Encoded: {encoded}") + # decoded = decode(encoded) + # print(f"Decoded: {decoded}") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/src/morseify/cli.py b/src/morseify/cli.py new file mode 100644 index 0000000..296591b --- /dev/null +++ b/src/morseify/cli.py @@ -0,0 +1,41 @@ +""" +Command-line interface for morseify. +""" + +import sys +from morseify.core import encode, decode, is_valid + + +def cli(): + """ + Command-line interface for morseify. + Auto-detects whether input is text (encode) or morse code (decode). + + Usage: + morseify "HELLO" # Encodes text to morse code + morseify ".... . .-.. .-.. ---" # Decodes morse code to text + """ + if len(sys.argv) < 2: + print("Usage: morseify ") + print("Examples:") + print(' morseify "HELLO"') + print(' morseify ".... . .-.. .-.. ---"') + sys.exit(1) + + # Join all arguments in case user passes multiple words + input_text = ' '.join(sys.argv[1:]) + + # Auto-detect: if input contains only morse characters (., -, /, space), decode it + # Otherwise, encode it + valid_morse_chars = {'.', '-', '/', ' '} + is_morse = all(char in valid_morse_chars for char in input_text) and input_text.strip() + + if is_morse and is_valid(input_text): + # It's valid morse code, decode it + result = decode(input_text) + print(result) + else: + # It's text, encode it + result = encode(input_text) + print(result) + diff --git a/src/morseify/core.py b/src/morseify/core.py new file mode 100644 index 0000000..04c9343 --- /dev/null +++ b/src/morseify/core.py @@ -0,0 +1,112 @@ +from morseify.mapping import LETTER_TO_MORSE +from morseify.mapping import MORSE_TO_LETTER +from morseify.normalize import normalize_text +from morseify.normalize import normalize_code + +def encode(text): + """ + Convert English text to morse code. + + Args: + text: English text string to encode + + Returns: + Morse code string + """ + + # Normalize the text first(delete after normalize function is implemented) + # if text is None: + # return None + # normalized = text.upper().strip() + + normalized = normalize_text(text) + + # Convert each character to morse code + result = [] + for char in normalized: + if char == ' ': + # Space between words becomes ' / ' + result.append('/') + else: + # Get morse code for character + morse_char = LETTER_TO_MORSE.get(char, '') + if morse_char: + result.append(morse_char) + + # Join with spaces between letters + return ' '.join(result) + + +def decode(morse_code): + """ + Convert morse code to English text. + + Args: + morse_code: Morse code string to decode + + Returns: + English text string, or error message if morse code is invalid + """ + # Check if the morse code is valid + if not is_valid(morse_code): + return "Morse code is not valid" + + # If valid: normalize and decode + normalized = normalize_code(morse_code) + + # Split morse code by spaces to get individual morse sequences + morse_words = normalized.split(' ') + + result = [] + for i in morse_words: + if i == '': + # Skip empty sequences (multiple spaces) + continue + elif i == '/': + # Word separator + result.append(' ') + else: + # Look up the morse sequence in the dictionary + letter = MORSE_TO_LETTER.get(i, '') + result.append(letter) + + return ''.join(result) + + + + + + +def is_valid(morse_code): + """ + Check if morse code is valid. + + Args: + morse_code: Morse code string to check if valid + + Returns: + Boolean: True if valid, False otherwise + """ + + # check if morse_code is str or empty + try: + morse_code = morse_code.strip() + except AttributeError: + return False + + if not morse_code: + return False + + #check if valid chars or sequence + validchars = {'.', '-', '/', ' '} + if any(ch not in validchars for ch in morse_code): + return False + + for seq in morse_code.split(' '): + if not seq or seq == '/': + continue + if seq not in MORSE_TO_LETTER: + return False + return True + + diff --git a/src/morseify/explain.py b/src/morseify/explain.py new file mode 100644 index 0000000..d17e65a --- /dev/null +++ b/src/morseify/explain.py @@ -0,0 +1,3 @@ +def explain(morse_message): + # TODO: Implement explanation logic + pass \ No newline at end of file diff --git a/src/morseify/mapping.py b/src/morseify/mapping.py new file mode 100644 index 0000000..78e2a87 --- /dev/null +++ b/src/morseify/mapping.py @@ -0,0 +1,13 @@ +LETTER_TO_MORSE = { + "A": ".-", "B": "-...", "C": "-.-.", "D": "-..", "E": ".", + "F": "..-.", "G": "--.", "H": "....", "I": "..", "J": ".---", + "K": "-.-", "L": ".-..", "M": "--", "N": "-.", "O": "---", + "P": ".--.", "Q": "--.-", "R": ".-.", "S": "...", "T": "-", + "U": "..-", "V": "...-", "W": ".--", "X": "-..-", "Y": "-.--", + "Z": "--..", + "0": "-----", "1": ".----", "2": "..---", "3": "...--", "4": "....-", + "5": ".....", "6": "-....", "7": "--...", "8": "---..", "9": "----.", + ".": ".-.-.-", ",": "--..--", "?": "..--..", "/": "-..-.", "-": "-....-", + "(": "-.--.", ")": "-.--.-" +} +MORSE_TO_LETTER = {v: k for k, v in LETTER_TO_MORSE.items()} diff --git a/src/morseify/normalize.py b/src/morseify/normalize.py new file mode 100644 index 0000000..38d3392 --- /dev/null +++ b/src/morseify/normalize.py @@ -0,0 +1,56 @@ +import re +import string + +def normalize_text(text): + """ + Clean and standardize English text before encoding to Morse. + + Args: + text (str): Input text string + + Returns: + str: Normalized text ready for encoding + """ + if not isinstance(text, str): + return "" + # convert to uppercase + text = text.upper() + + # keep only supporting text + morse_punct = ".,?/-()" + allowed_chars = string.ascii_uppercase + string.digits + ' ' + morse_punct + cleaned = ''.join(ch for ch in text if ch in allowed_chars) + + # clean multiple or leading/trailing spaces + cleaned = re.sub(r'\s+', ' ', cleaned) + cleaned = cleaned.strip() + + return cleaned + + +def normalize_code(morse_code): + """ + Clean and standardize Morse code text before decoding. + + Args: + morse_code (str): Raw Morse code string + + Returns: + str: Normalized Morse code ready for decoding + """ + if not isinstance(morse_code, str): + return "" + + # replace any tabs with a space + morse_code = morse_code.replace('\t', ' ') + + # clean multiple spaces + morse_code = re.sub(r'\s+', ' ', morse_code) + + # clean multiple slashes + morse_code = re.sub(r'/+', '/', morse_code) + + # clean any leading/trailing space or slashes + morse_code = morse_code.strip(' /') + + return morse_code diff --git a/src/morseify/quiz.py b/src/morseify/quiz.py new file mode 100644 index 0000000..da116b5 --- /dev/null +++ b/src/morseify/quiz.py @@ -0,0 +1,132 @@ +import random +import sys +from pathlib import Path + +# Add parent directory to path if running as script +if __name__ == "__main__": + sys.path.insert(0, str(Path(__file__).parent.parent)) + +try: + from morseify.core import encode, decode, is_valid +except ModuleNotFoundError: + from .core import encode, decode, is_valid + +# List of sentences for the quiz +QUIZ_SENTENCES = [ + "HELLO WORLD", + "LET US TRY", + "MORSE CODE IS FUN", + "PYTHON ROCKS", + "LEARNING TAKES TIME", + "FORZA ROMA", + "SWE IS USEFUL", + "RUNNING OUT OF IDEAS", + "THIS SHOULD BE ENOUGH", + "I AM NOT VERY CREATIVE" +] + + +def quiz(sentence=None, mode=None): + """ + Interactive morse code quiz. + + Args: + sentence: Optional - specific sentence to use, or None for random + mode: Optional - 'reading' or 'writing', or None to ask + """ + if sentence is None: + selected_sentence = random.choice(QUIZ_SENTENCES) + else: + selected_sentence = sentence.upper().strip() + + + # Ask for mode if not provided + if mode is None: + print("\n" + "=" * 60) + print("MORSE CODE QUIZ") + print("=" * 60) + print("Choose your mode:") + print("'reading' - Decode morse code → text") + print("'writing' - Encode text → morse code") + print() + mode = input("Enter the mode ('reading' or 'writing'): ").strip().lower() + + while mode not in ['reading', 'writing']: + print("\nInvalid mode!") + print("Please enter 'reading' or 'writing'") + mode = input("\nEnter the mode: ").strip().lower() + + print("\n" + "=" * 60) + if mode == 'reading': + print("READING MODE: Decode morse code → text") + print("=" * 60) + morse_to_decode = encode(selected_sentence) + print(f"\nMorse code: {morse_to_decode}") + print() + + # Loop until correct or user gives up + while True: + answer = input("Your answer: ").upper().strip() + + if answer == selected_sentence: + print("\nCorrect! Well done!") + break + else: + print("\nIncorrect!") + retry = input("Try again? (yes/no): ").strip().lower() + + if retry == 'yes': + continue # Try again + else: # 'no' or anything else means give up + print("\n" + "-" * 60) + print("ANSWER REVEALED") + print("-" * 60) + print(f"Your answer: {answer}") + print(f"Correct answer: {selected_sentence}") + print(f"\nThe morse code '{morse_to_decode}' translates to '{selected_sentence}'") + print("-" * 60) + break + + else: # writing mode + print("WRITING MODE: Encode text → morse code") + print("=" * 60) + print(f"\nText to encode: {selected_sentence}") + print() + correct_morse = encode(selected_sentence) + + # Loop until correct or user gives up + while True: + answer = input("Your answer: ").strip() + + # Validate morse code format first + while not is_valid(answer): + print("\nInvalid morse code format!") + print("Please use only dots (.), dashes (-), spaces, and slashes (/)") + print("Example: ... --- ... (for SOS)") + answer = input("\nYour answer: ").strip() + + # Check if correct + if answer == correct_morse: + print("\nCorrect! Well done!") + break + else: + print("\nIncorrect!") + retry = input("Try again? (yes/no): ").strip().lower() + + if retry == 'yes': + continue # Try again + else: # 'no' or anything else means give up + print("\n" + "-" * 60) + print("ANSWER REVEALED") + print("-" * 60) + print(f"Your answer: {answer}") + print(f"Correct answer: {correct_morse}") + print(f"\n'{selected_sentence}' in morse code is: {correct_morse}") + print("-" * 60) + break + + print("=" * 60) + + +if __name__ == "__main__": + quiz() \ No newline at end of file diff --git a/tests/test_decode.py b/tests/test_decode.py new file mode 100644 index 0000000..7a5d4cb --- /dev/null +++ b/tests/test_decode.py @@ -0,0 +1,96 @@ +from morseify.core import decode + + +def test_decode_single_letter(): + """Test decoding a single letter.""" + assert decode(".-") == "A" + assert decode("-...") == "B" + assert decode("-.-.") == "C" + assert decode("-..") == "D" + assert decode(".") == "E" + assert decode("..-.") == "F" + assert decode("--.") == "G" + assert decode("....") == "H" + assert decode("..") == "I" + assert decode(".---") == "J" + assert decode("-.-") == "K" + assert decode(".-..") == "L" + assert decode("--") == "M" + assert decode("-.") == "N" + assert decode("---") == "O" + assert decode(".--.") == "P" + assert decode("--.-") == "Q" + assert decode(".-.") == "R" + assert decode("...") == "S" + assert decode("-") == "T" + assert decode("..-") == "U" + assert decode("...-") == "V" + assert decode(".--") == "W" + assert decode("-..-") == "X" + assert decode("-.--") == "Y" + assert decode("--..") == "Z" + + +def test_decode_word(): + """Test decoding a word.""" + assert decode(".... . .-.. .-.. ---") == "HELLO" + assert decode("... --- ...") == "SOS" + + +def test_decode_multiple_words(): + """Test decoding multiple words with separator.""" + assert decode(".... . .-.. .-.. --- / .-- --- .-. .-.. -..") == "HELLO WORLD" + assert decode("... --- ... / .... . .-.. .--.") == "SOS HELP" + + +def test_decode_numbers(): + """Test decoding numbers.""" + assert decode(".---- ..--- ...--") == "123" + assert decode("-----") == "0" + +def test_decode_extra_spaces(): + """Test decoding morse code with extra spaces.""" + assert decode(" ... --- ... ") == "SOS" + +def test_decode_invalid_morse_code(): + """Test decoding invalid morse code returns error message.""" + assert decode("---.") == "Morse code is not valid" # Invalid sequence not in mapping + assert decode("ABC") == "Morse code is not valid" # Contains invalid characters + assert decode("....X") == "Morse code is not valid" # Contains invalid character + assert decode("") == "Morse code is not valid" # Empty string + assert decode(" ") == "Morse code is not valid" # Only spaces + + +def test_decode_mixed_valid_invalid(): + """Test decoding morse code with invalid sequences.""" + assert decode(".... . .-.. .-.. --- ---.") == "Morse code is not valid" # Has invalid sequence + + +def test_decode_with_punctuation(): + """Test decoding morse code with punctuation.""" + assert decode(".... . .-.. .-.. --- .-.-.-") == "HELLO." + assert decode("-- ..- .-.. - .. .--. .-.. .") == "MULTIPLE" + + +def test_decode_normalized_input(): + """Test decoding already normalized morse code.""" + # decode should handle normalization internally + assert decode(" .... . .-.. .-.. --- ") == "HELLO" # Extra spaces + + + +def test_decode_punctuation_only(): + """Test decoding morse code with only punctuation.""" + assert decode(".-.-.-") == "." # period + assert decode("--..--") == "," # comma + assert decode("..--..") == "?" # question mark + assert decode("-..-.") == "/" # slash + assert decode("-....-") == "-" # hyphen + + +def test_decode_with_parentheses(): + """Test decoding morse code with parentheses.""" + assert decode("-.--. -.--.-") == "()" + assert decode(".... . .-.. .-.. --- -.--.") == "HELLO(" + assert decode("-.--.- .-- --- .-. .-.. -..") == ")WORLD" + diff --git a/tests/test_encode.py b/tests/test_encode.py new file mode 100644 index 0000000..be6716b --- /dev/null +++ b/tests/test_encode.py @@ -0,0 +1,141 @@ +from morseify.core import encode, decode + + +def test_encode_single_letter(): + """Test encoding a single letter.""" + assert encode("A") == ".-" + assert encode("B") == "-..." + assert encode("C") == "-.-." + assert encode("D") == "-.." + assert encode("E") == "." + assert encode("F") == "..-." + assert encode("G") == "--." + assert encode("H") == "...." + assert encode("I") == ".." + assert encode("J") == ".---" + assert encode("K") == "-.-" + assert encode("L") == ".-.." + assert encode("M") == "--" + assert encode("N") == "-." + assert encode("O") == "---" + assert encode("P") == ".--." + assert encode("Q") == "--.-" + assert encode("R") == ".-." + assert encode("S") == "..." + assert encode("T") == "-" + assert encode("U") == "..-" + assert encode("V") == "...-" + assert encode("W") == ".--" + assert encode("X") == "-..-" + assert encode("Y") == "-.--" + assert encode("Z") == "--.." + + +def test_encode_lowercase(): + """Test encoding lowercase letters (should convert to uppercase first).""" + assert encode("a") == ".-" + assert encode("hello") == ".... . .-.. .-.. ---" + assert encode("sos") == "... --- ..." + + +def test_encode_word(): + """Test encoding an uppercase word.""" + assert encode("HELLO") == ".... . .-.. .-.. ---" + assert encode("SOS") == "... --- ..." + +def test_encode_mixed_case(): + """Test encoding text with mixed case.""" + assert encode("Hello") == ".... . .-.. .-.. ---" + assert encode("World") == ".-- --- .-. .-.. -.." + assert encode("SoS") == "... --- ..." + + +def test_encode_multiple_words(): + """Test encoding multiple words with separator.""" + assert encode("HELLO WORLD") == ".... . .-.. .-.. --- / .-- --- .-. .-.. -.." + assert encode("SOS HELP") == "... --- ... / .... . .-.. .--." + + +def test_encode_numbers(): + """Test encoding numbers.""" + assert encode("123") == ".---- ..--- ...--" + assert encode("0") == "-----" + assert encode("0123456789") == "----- .---- ..--- ...-- ....- ..... -.... --... ---.. ----." + + +def test_encode_with_punctuation(): + """Test encoding text with punctuation.""" + assert encode("HELLO.") == ".... . .-.. .-.. --- .-.-.-" + assert encode("SOS?") == "... --- ... ..--.." + assert encode("A,B") == ".- --..-- -..." + + +def test_encode_with_parentheses(): + """Test encoding text with parentheses.""" + assert encode("()") == "-.--. -.--.-" + assert encode("HELLO(WORLD)") == ".... . .-.. .-.. --- -.--. .-- --- .-. .-.. -.. -.--.-" + assert encode("(A)") == "-.--. .- -.--.-" + + +def test_encode_with_extra_spaces(): + """Test encoding text with extra spaces.""" + assert encode(" HELLO ") == ".... . .-.. .-.. ---" + assert encode("A B") == ".- / -..." + assert encode(" SOS ") == "... --- ..." + + +def test_encode_only_spaces(): + """Test encoding only spaces.""" + assert encode(" ") == "" + assert encode(" ") == "" + assert encode(" ") == "" + + +def test_encode_empty_string(): + """Test encoding empty string.""" + assert encode("") == "" + + +def test_encode_decode_roundtrip(): + """Test that encoding then decoding returns the original text.""" + texts = [ + "A", + "HELLO", + "HELLO WORLD", + "123", + "SOS", + "HELLO.", + "SOS?", + "()", + "HELLO(WORLD)", + "0123456789" + ] + + for text in texts: + encoded = encode(text) + decoded = decode(encoded) + assert decoded == text, f"Round trip failed for '{text}': {encoded} -> {decoded}" + + +def test_decode_encode_roundtrip(): + """Test that decoding then encoding returns the original morse code.""" + morse_codes = [ + ".-", + "-", + "...", + ".... . .-.. .-.. ---", + "... --- ...", + ".... . .-.. .-.. --- / .-- --- .-. .-.. -..", + ".---- ..--- ...--", + "-----", + ".... . .-.. .-.. --- .-.-.-", + "... --- ... ..--..", + "-.--. -.--.-", + ".- .-.-.- -..." + ] + + for morse_code in morse_codes: + decoded = decode(morse_code) + encoded = encode(decoded) + assert encoded == morse_code, f"Round trip failed for '{morse_code}': {decoded} -> {encoded}" + \ No newline at end of file diff --git a/tests/test_is_valid.py b/tests/test_is_valid.py new file mode 100644 index 0000000..32a6635 --- /dev/null +++ b/tests/test_is_valid.py @@ -0,0 +1,2 @@ +def test_is_valid(): + assert True \ No newline at end of file diff --git a/tests/test_normalize_code.py b/tests/test_normalize_code.py new file mode 100644 index 0000000..abcd8d4 --- /dev/null +++ b/tests/test_normalize_code.py @@ -0,0 +1,2 @@ +def test_normalize_code(): + assert True \ No newline at end of file diff --git a/tests/test_normalize_text.py b/tests/test_normalize_text.py new file mode 100644 index 0000000..14519ca --- /dev/null +++ b/tests/test_normalize_text.py @@ -0,0 +1,2 @@ +def test_normalize_text(): + assert True \ No newline at end of file