diff --git a/python/.tasks.txt b/python/.tasks.txt new file mode 100644 index 0000000..044cff1 --- /dev/null +++ b/python/.tasks.txt @@ -0,0 +1,6 @@ +Item 1 +Item 2 +Item 3 +Item 4 +Item 5 +Item 6 diff --git a/python/SEPwC_formative b/python/SEPwC_formative new file mode 100644 index 0000000..e69de29 diff --git a/python/__pycache__/test_todo.cpython-313-pytest-8.3.5.pyc b/python/__pycache__/test_todo.cpython-313-pytest-8.3.5.pyc new file mode 100644 index 0000000..fff03cf Binary files /dev/null and b/python/__pycache__/test_todo.cpython-313-pytest-8.3.5.pyc differ diff --git a/python/__pycache__/todo.cpython-313-pytest-8.3.5.pyc b/python/__pycache__/todo.cpython-313-pytest-8.3.5.pyc new file mode 100644 index 0000000..391fde2 Binary files /dev/null and b/python/__pycache__/todo.cpython-313-pytest-8.3.5.pyc differ diff --git a/python/__pycache__/todo.cpython-313.pyc b/python/__pycache__/todo.cpython-313.pyc new file mode 100644 index 0000000..269c6cb Binary files /dev/null and b/python/__pycache__/todo.cpython-313.pyc differ diff --git a/python/test/__pycache__/test_to-do.cpython-313-pytest-8.3.5.pyc b/python/test/__pycache__/test_to-do.cpython-313-pytest-8.3.5.pyc new file mode 100644 index 0000000..5ec17cb Binary files /dev/null and b/python/test/__pycache__/test_to-do.cpython-313-pytest-8.3.5.pyc differ diff --git a/python/test_todo.py b/python/test_todo.py new file mode 100644 index 0000000..1698246 --- /dev/null +++ b/python/test_todo.py @@ -0,0 +1,66 @@ +import os +import unittest +from unittest.mock import patch +from todo import add_task, list_tasks, remove_task, TASK_FILE + +class TestTodoFunctions(unittest.TestCase): + + def setUp(self): + """Ensure an empty task file before each test.""" + if os.path.exists(TASK_FILE): + os.remove(TASK_FILE) + + def tearDown(self): + """Clean up the task file after each test.""" + if os.path.exists(TASK_FILE): + os.remove(TASK_FILE) + + def test_add_task(self): + """Test that a task is added correctly.""" + add_task("First") + self.assertTrue(os.path.exists(TASK_FILE)) # Check if the file exists + + with open(TASK_FILE, "r") as file: + tasks = file.readlines() + + self.assertEqual(len(tasks), 1) # This checks that the numbers of tasks added is 1 (as only added one) + self.assertEqual(tasks[0].strip(), "First") # This checks that the task added is the same as the one that was added + + def test_list_tasks(self): + """Test printing all the tasks.""" + add_task("First") + add_task("Second") + + tasks = list_tasks() + + self.assertIn("1. First", tasks) # Check if the first task is in the list + self.assertIn("2. Second", tasks) # Check if the second task is in the list + + def test_remove_task(self): + """Test removing a task in the middle of the list.""" + add_task("First") + add_task("Second") + add_task("Third") + + remove_task(2) + + with open(TASK_FILE, "r") as file: + tasks = file.readlines() + + self.assertEqual(len(tasks), 2) + self.assertEqual(tasks[1].strip(), "Third") # Check that the second task is now the third task because the middle task was removed + + def test_remove_task_invalid_index(self): + """Test removing a task with an invalid index.""" + add_task("First") + with patch("builtins.print") as mock_print: + remove_task(5) # Invalid index out of range + mock_print.assert_called_with("Invalid task number. Please choose between 1 and 1.") + + with open(TASK_FILE, "r") as file: + tasks = file.readlines() + self.assertEqual(len(tasks), 1) + self.assertEqual(tasks[0].strip(), "First") + +if __name__ == "__main__": + unittest.main() diff --git a/python/todo.py b/python/todo.py index a04234e..7309b43 100644 --- a/python/todo.py +++ b/python/todo.py @@ -1,23 +1,67 @@ +"""A command-line to-do list application that supports adding, listing, and removing tasks""" + import argparse import os TASK_FILE = ".tasks.txt" +NO_TASKS_FOUND_MSG = "No tasks found. Please add a task using -a or --add option." def add_task(task): - """Function: add_task - - Input - a task to add to the list - Return - nothing - """ + """Add new task to task file""" + with open(TASK_FILE, "a", encoding="utf-8") as file: + file.write(task + "\n") def list_tasks(): - return + """Read tasks from task file and return them as a numbered list""" + if not os.path.exists(TASK_FILE): + return NO_TASKS_FOUND_MSG + + with open(TASK_FILE, "r", encoding="utf-8") as file: + lines = [line.strip() for line in file if line.strip()] + + if not lines: + return NO_TASKS_FOUND_MSG + numbered_tasks = [f"{idx + 1}. {line}" for idx, line in enumerate(lines)] + return "\n".join(numbered_tasks) def remove_task(index): - return + """Remove a task by its number from the task file""" + if not os.path.exists(TASK_FILE): + print(NO_TASKS_FOUND_MSG) + return + + # Read all non-empty lines from the file + # strip() to remove any leading/trailing whitespace + with open(TASK_FILE, "r", encoding="utf-8") as file: + tasks = [line.strip() for line in file if line.strip()] + + if not tasks: + print("No tasks to remove.") + return + + # Check for valid input from user + if index < 1 or index > len(tasks): + print(f"Invalid task number. Please choose between 1 and {len(tasks)}.") + return + + # Remove the specified task + removed = tasks.pop(index - 1) + + # Write remaining tasks back to the file + if tasks: + with open(TASK_FILE, "w", encoding="utf-8") as file: + file.write("\n".join(tasks) + "\n") + print(f"Task '{removed}' removed successfully.") + print("Remaining tasks:") + for i, task in enumerate(tasks, 1): + print(f"{i}. {task}") + else: + os.remove(TASK_FILE) + print(f"Task '{removed}' removed. No tasks left. File deleted.") def main(): + """Parse the command-line arguments and run the selected task operation""" parser = argparse.ArgumentParser(description="Command-line Todo List") parser.add_argument( "-a", @@ -38,6 +82,7 @@ def main(): if args.add: add_task(args.add) + print (f"Task '{args.add}' added successfully.") elif args.list: tasks = list_tasks() print(tasks)