diff --git a/scripts/test_date_uniqueness.py b/scripts/test_date_uniqueness.py new file mode 100644 index 0000000..2e5d92d --- /dev/null +++ b/scripts/test_date_uniqueness.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python3 +""" +Test script to verify date uniqueness functionality in TheChart app. +""" + +import logging +import os +import sys + +# Add the src directory to the Python path +sys.path.insert(0, os.path.join(os.path.dirname(__file__), "src")) + +from data_manager import DataManager + +# Set up simple logging +logging.basicConfig(level=logging.DEBUG) +logger = logging.getLogger("test") + + +def test_date_uniqueness(): + """Test the date uniqueness validation.""" + print("Testing date uniqueness functionality...") + + # Create a test data manager with a test file + test_filename = "test_data.csv" + dm = DataManager(test_filename, logger) + + # Test 1: Add first entry (should succeed) + print("\n1. Adding first entry...") + entry1 = ["2025-07-28", 5, 5, 5, 5, 0, 0, 0, 0, "First entry"] + result1 = dm.add_entry(entry1) + print(f"Result: {result1} (Expected: True)") + + # Test 2: Try to add duplicate date (should fail) + print("\n2. Trying to add duplicate date...") + entry2 = ["2025-07-28", 3, 3, 3, 3, 1, 1, 1, 1, "Duplicate entry"] + result2 = dm.add_entry(entry2) + print(f"Result: {result2} (Expected: False)") + + # Test 3: Add different date (should succeed) + print("\n3. Adding different date...") + entry3 = ["2025-07-29", 4, 4, 4, 4, 0, 0, 0, 0, "Second entry"] + result3 = dm.add_entry(entry3) + print(f"Result: {result3} (Expected: True)") + + # Test 4: Update entry with same date (should succeed) + print("\n4. Updating entry with same date...") + updated_entry = ["2025-07-28", 6, 6, 6, 6, 1, 1, 1, 1, "Updated entry"] + result4 = dm.update_entry("2025-07-28", updated_entry) + print(f"Result: {result4} (Expected: True)") + + # Test 5: Try to update entry to existing date (should fail) + print("\n5. Trying to update entry to existing date...") + conflicting_entry = ["2025-07-29", 7, 7, 7, 7, 1, 1, 1, 1, "Conflicting entry"] + result5 = dm.update_entry("2025-07-28", conflicting_entry) + print(f"Result: {result5} (Expected: False)") + + # Test 6: Update entry to new date (should succeed) + print("\n6. Updating entry to new date...") + new_date_entry = ["2025-07-30", 8, 8, 8, 8, 1, 1, 1, 1, "New date entry"] + result6 = dm.update_entry("2025-07-28", new_date_entry) + print(f"Result: {result6} (Expected: True)") + + # Cleanup + if os.path.exists(test_filename): + os.remove(test_filename) + + # Summary + expected_results = [True, False, True, True, False, True] + actual_results = [result1, result2, result3, result4, result5, result6] + + print("\n" + "=" * 50) + print("TEST SUMMARY:") + print("=" * 50) + + all_passed = True + for i, (expected, actual) in enumerate( + zip(expected_results, actual_results, strict=True), 1 + ): + status = "PASS" if expected == actual else "FAIL" + if expected != actual: + all_passed = False + print(f"Test {i}: {status} (Expected: {expected}, Got: {actual})") + + overall_result = "ALL TESTS PASSED" if all_passed else "SOME TESTS FAILED" + print(f"\nOverall result: {overall_result}") + return all_passed + + +if __name__ == "__main__": + test_date_uniqueness() diff --git a/src/data_manager.py b/src/data_manager.py index 0c91970..6b7eb66 100644 --- a/src/data_manager.py +++ b/src/data_manager.py @@ -66,6 +66,14 @@ class DataManager: def add_entry(self, entry_data: list[str | int]) -> bool: """Add a new entry to the CSV file.""" try: + # Check if date already exists + df: pd.DataFrame = self.load_data() + date_to_add: str = str(entry_data[0]) + + if not df.empty and date_to_add in df["date"].values: + self.logger.warning(f"Entry with date {date_to_add} already exists.") + return False + with open(self.filename, mode="a", newline="") as file: writer = csv.writer(file) writer.writerow(entry_data) @@ -74,13 +82,22 @@ class DataManager: self.logger.error(f"Error adding entry: {str(e)}") return False - def update_entry(self, date: str, values: list[str | int]) -> bool: - """Update an existing entry identified by date.""" + def update_entry(self, original_date: str, values: list[str | int]) -> bool: + """Update an existing entry identified by original_date.""" try: df: pd.DataFrame = self.load_data() - # Find the row to update using date as a unique identifier + new_date: str = str(values[0]) + + # If the date is being changed, check if the new date already exists + if original_date != new_date and new_date in df["date"].values: + self.logger.warning( + f"Cannot update: entry with date {new_date} already exists." + ) + return False + + # Find the row to update using original_date as a unique identifier df.loc[ - df["date"] == date, + df["date"] == original_date, [ "date", "depression", diff --git a/src/main.py b/src/main.py index 0fc2e80..3a2f75d 100644 --- a/src/main.py +++ b/src/main.py @@ -119,9 +119,11 @@ class MedTrackerApp: def _create_edit_window(self, item_id: str, values: tuple[str, ...]) -> None: """Create a new Toplevel window for editing an entry.""" + original_date = values[0] # Store the original date + # Define callbacks for edit window buttons callbacks: dict[str, Callable] = { - "save": self._save_edit, + "save": lambda win, *args: self._save_edit(win, original_date, *args), "delete": lambda win: self._delete_entry(win, item_id), } @@ -131,6 +133,7 @@ class MedTrackerApp: def _save_edit( self, edit_win: tk.Toplevel, + original_date: str, date: str, dep: int, anx: int, @@ -156,7 +159,7 @@ class MedTrackerApp: note, ] - if self.data_manager.update_entry(date, values): + if self.data_manager.update_entry(original_date, values): edit_win.destroy() messagebox.showinfo( "Success", "Entry updated successfully!", parent=self.root @@ -164,7 +167,17 @@ class MedTrackerApp: self._clear_entries() self.load_data() else: - messagebox.showerror("Error", "Failed to save changes", parent=edit_win) + # Check if it's a duplicate date issue + df = self.data_manager.load_data() + if original_date != date and not df.empty and date in df["date"].values: + messagebox.showerror( + "Error", + f"An entry for date '{date}' already exists. " + "Please use a different date.", + parent=edit_win, + ) + else: + messagebox.showerror("Error", "Failed to save changes", parent=edit_win) def on_closing(self) -> None: if messagebox.askokcancel( @@ -189,6 +202,11 @@ class MedTrackerApp: ] logger.debug(f"Adding entry: {entry}") + # Check if date is empty + if not self.date_var.get().strip(): + messagebox.showerror("Error", "Please enter a date.", parent=self.root) + return + if self.data_manager.add_entry(entry): messagebox.showinfo( "Success", "Entry added successfully!", parent=self.root @@ -196,7 +214,17 @@ class MedTrackerApp: self._clear_entries() self.load_data() else: - messagebox.showerror("Error", "Failed to add entry", parent=self.root) + # Check if it's a duplicate date by trying to load existing data + df = self.data_manager.load_data() + if not df.empty and self.date_var.get() in df["date"].values: + messagebox.showerror( + "Error", + f"An entry for date '{self.date_var.get()}' already exists. " + "Please use a different date or edit the existing entry.", + parent=self.root, + ) + else: + messagebox.showerror("Error", "Failed to add entry", parent=self.root) def _delete_entry(self, edit_win: tk.Toplevel, item_id: str) -> None: """Delete the selected entry from the CSV file."""