]> Nutra Git (v2) - gamesguru/getmyancestors.git/commitdiff
less mocks in tests
authorShane Jaroch <chown_tee@proton.me>
Sat, 27 Dec 2025 12:04:15 +0000 (07:04 -0500)
committerShane Jaroch <chown_tee@proton.me>
Sat, 27 Dec 2025 12:04:35 +0000 (07:04 -0500)
tests/conftest.py
tests/test_cli.py
tests/test_parsing.py [new file with mode: 0644]

index f6ae9a23fb8881c1bf92711c0396baf863aa5eda..fe6c097c2655b94e7cd5bf423f126a1a10444845 100644 (file)
@@ -1,39 +1,69 @@
+import pytest
 from unittest.mock import MagicMock
+import sys
+import os
 
-import pytest
+# Ensure we can import the module from the root directory
+sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
 
+from getmyancestors.classes.session import Session
 
 @pytest.fixture
-def mock_user_data():
-    return {
-        "users": [
-            {
-                "personId": "KW7V-Y32",
-                "preferredLanguage": "en",
-                "displayName": "Test User",
-            }
-        ]
-    }
+def mock_session():
+    """
+    Creates a Session object where the network layer is mocked out.
+    """
+    # Create the session but suppress the automatic login() call in __init__
+    # We do this by mocking the login method *before* instantiation
+    with pytest.helpers.patch_method(Session, 'login'):
+        session = Session("test_user", "test_pass", verbose=False)
+
+        # Manually set logged status to True so checks pass
+        # We need to mock the cookies since 'logged' property checks for 'fssessionid'
+        session.cookies = {"fssessionid": "mock_session_id"}
 
+        # Mock the request methods
+        session.get = MagicMock()
+        session.post = MagicMock()
+
+        # Mock the internal translation method to just return the string
+        session._ = lambda s: s
+
+        return session
 
 @pytest.fixture
-def mock_person_data():
+def sample_person_json():
+    """Returns a raw JSON response representing a Person from FamilySearch"""
     return {
-        "persons": [
-            {
-                "id": "KW7V-Y32",
-                "display": {
-                    "name": "John Doe",
-                    "gender": "Male",
-                    "lifespan": "1900-1980",
-                },
-                "facts": [
-                    {
-                        "type": "http://gedcomx.org/Birth",
-                        "date": {"original": "1 Jan 1900"},
-                    }
-                ],
-                "names": [{"nameForms": [{"fullText": "John Doe"}]}],
-            }
-        ]
+        "persons": [{
+            "id": "KW7V-Y32",
+            "display": {
+                "name": "John Doe",
+                "gender": "Male",
+                "lifespan": "1900-1980"
+            },
+            "facts": [
+                {
+                    "type": "http://gedcomx.org/Birth",
+                    "date": {"original": "1 Jan 1900"},
+                    "place": {"original": "New York"}
+                }
+            ],
+            "names": [
+                {
+                    "nameForms": [{"fullText": "John Doe"}]
+                }
+            ]
+        }]
     }
+
+# Helper to patch methods cleanly in fixtures
+class Helpers:
+    @staticmethod
+    def patch_method(cls, method_name):
+        from unittest.mock import patch
+        return patch.object(cls, method_name)
+
+@pytest.fixture
+def helpers():
+    return Helpers
index bbea8b94fa69e5ea344db9f4f2bc461c8552da7f..f2b086a4ad92041b76daaf0003a4f1a24179085e 100644 (file)
@@ -1,59 +1,49 @@
+import pytest
 import sys
-from unittest.mock import MagicMock, patch
+from unittest.mock import patch, MagicMock
+from getmyancestors.getmyancestors import main
 
-import pytest
+class TestCLI:
 
-from getmyancestors.getmyancestors import main
+    @patch('getmyancestors.getmyancestors.Session')
+    @patch('getmyancestors.getmyancestors.Tree')
+    def test_basic_args(self, MockTree, MockSession):
+        """Test that arguments are parsed and passed to classes correctly"""
 
+        # Mock sys.argv to simulate command line execution
+        test_args = [
+            "getmyancestors",
+            "-u", "myuser",
+            "-p", "mypass",
+            "-i", "KW7V-Y32",
+            "--verbose"
+        ]
 
-class TestCLI:
+        # Setup the session to appear logged in
+        MockSession.return_value.logged = True
+
+        with patch.object(sys, 'argv', test_args):
+            main()
 
-    @patch("getmyancestors.getmyancestors.Session")
-    @patch("getmyancestors.getmyancestors.Tree")
-    @patch(
-        "sys.argv",
-        ["getmyancestors", "-u", "testuser", "-p", "testpass", "-i", "KW7V-Y32"],
-    )
-    def test_main_execution(self, mock_tree, mock_session):
-        """Test that main runs with basic arguments."""
-        mock_fs = mock_session.return_value
-        mock_fs.logged = True
-
-        # Run main
-        main()
-
-        # Verify Session initialized with args
-        mock_session.assert_called_with(
-            username="testuser",
-            password="testpass",
-            client_id=None,
-            redirect_uri=None,
-            verbose=False,
-            logfile=False,
-            timeout=60,
+        # Verify Session was initialized with CLI args
+        MockSession.assert_called_with(
+            "myuser",
+            "mypass",
+            None, # client_id (default)
+            None, # redirect_uri (default)
+            True, # verbose
+            False, # logfile
+            60 # timeout
         )
 
-        # Verify Tree operations
-        mock_tree.return_value.add_indis.assert_called()
-        mock_tree.return_value.print.assert_called()
-
-    @patch("getmyancestors.getmyancestors.Session")
-    @patch(
-        "sys.argv",
-        ["getmyancestors", "-u", "testuser", "-p", "testpass", "--descend", "2"],
-    )
-    def test_descend_argument(self, mock_session):
-        """Test that the descend argument is passed to logic."""
-        mock_fs = mock_session.return_value
-        mock_fs.logged = True
-
-        # We need to mock Tree because main interacts with it deeply
-        with patch("getmyancestors.getmyancestors.Tree") as mock_tree:
-            mock_tree_instance = mock_tree.return_value
-            # Return empty sets to stop loops
-            mock_tree_instance.add_children.return_value = set()
+        # Verify Tree started
+        MockTree.return_value.add_indis.assert_called_with(["KW7V-Y32"])
 
-            main()
+    def test_arg_validation(self):
+        """Test that invalid ID formats cause an exit"""
+        test_args = ["getmyancestors", "-u", "u", "-p", "p", "-i", "BAD_ID"]
 
-            # Verify add_children was called (logic inside main triggers this based on args.descend)
-            assert mock_tree_instance.add_children.called
+        with patch.object(sys, 'argv', test_args):
+            with pytest.raises(SystemExit):
+                # This should trigger sys.exit("Invalid FamilySearch ID...")
+                main()
diff --git a/tests/test_parsing.py b/tests/test_parsing.py
new file mode 100644 (file)
index 0000000..98c450a
--- /dev/null
@@ -0,0 +1,57 @@
+import pytest
+from unittest.mock import MagicMock
+from getmyancestors.classes.tree import Tree, Indi, Fam
+
+class TestDataParsing:
+
+    def test_individual_parsing(self, mock_session, sample_person_json):
+        """
+        Verify that raw JSON from FamilySearch is correctly parsed into an Indi object.
+        """
+        # Setup the mock to return our sample JSON when get_url is called
+        mock_session.get_url = MagicMock(return_value=sample_person_json)
+
+        tree = Tree(mock_session)
+
+        # Act: Add the individual
+        tree.add_indis(["KW7V-Y32"])
+
+        # Assert: Check if the individual exists in the tree
+        assert "KW7V-Y32" in tree.indi
+        person = tree.indi["KW7V-Y32"]
+
+        # Assert: Check attributes
+        assert person.name == "John Doe"
+        assert person.sex == "M"
+        assert person.fid == "KW7V-Y32"
+
+        # Check if Birth fact was parsed (this tests your Fact class logic implicitly)
+        birth_fact = next((f for f in person.facts if f.tag == "BIRT"), None)
+        assert birth_fact is not None
+        assert birth_fact.date == "1 Jan 1900"
+        assert birth_fact.place == "New York"
+
+    def test_family_linking(self, mock_session):
+        """
+        Verify that ensure_family links husband and wife correctly.
+        """
+        tree = Tree(mock_session)
+
+        # Create dummy individuals
+        husb = Indi("HUSB01", tree)
+        wife = Indi("WIFE01", tree)
+
+        # Create family
+        fam = tree.ensure_family(husb, wife)
+
+        # Assertions
+        assert fam.husband == husb
+        assert fam.wife == wife
+
+        # Check that the individuals know about the family
+        assert fam in husb.fams
+        assert fam in wife.fams
+
+        # Ensure creating the same family again returns the same object
+        fam2 = tree.ensure_family(husb, wife)
+        assert fam is fam2