diff --git a/final_automate.py b/final_automate.py new file mode 100644 index 00000000..5a9d2821 --- /dev/null +++ b/final_automate.py @@ -0,0 +1,92 @@ +import ast +import os +import re + +PLACEHOLDER = '"""TODO: Add docstring."""' + +def get_meaningful_docstring(node, filepath): + if isinstance(node, ast.Module): + if os.path.basename(filepath) == '__init__.py': + return '"""Test package initialization."""' + name = os.path.basename(filepath).replace('.py', '').replace('test_', '').replace('_', ' ') + return f'"""Unit tests for {name}."""' + + if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)): + if node.name == '__init__': + return '"""Initialize the test object."""' + if node.name.startswith('test_'): + name = node.name[5:].replace('_', ' ') + suffix = " asynchronously" if isinstance(node, ast.AsyncFunctionDef) else "" + return f'"""Test that {name}{suffix}."""' + else: + name = node.name.replace('_', ' ') + return f'"""Helper function to {name}."""' + + if isinstance(node, ast.ClassDef): + name = node.name.replace('Test', '').replace('_', ' ') + return f'"""Test suite for {name}."""' + + return PLACEHOLDER + +def process_file(filepath): + with open(filepath, 'r') as f: + content = f.read() + + if PLACEHOLDER not in content: + return + + try: + tree = ast.parse(content) + except SyntaxError: + return + + modifications = [] + + for node in ast.walk(tree): + if isinstance(node, (ast.Module, ast.ClassDef, ast.FunctionDef, ast.AsyncFunctionDef)): + # Check for docstring + docstring = ast.get_docstring(node, clean=False) + if docstring == "TODO: Add docstring.": + # Find the line number of the docstring. + for body_node in node.body: + if isinstance(body_node, ast.Expr) and isinstance(body_node.value, (ast.Constant, ast.Str)): + val = body_node.value.value if isinstance(body_node.value, ast.Constant) else body_node.value.s + if val == "TODO: Add docstring.": + new_doc = get_meaningful_docstring(node, filepath) + modifications.append((body_node.lineno, new_doc)) + break + + if not modifications: + # Sometimes there's a TODO at the very top of the file that ast doesn't pick up if it's not a proper docstring? + # No, ast.Module should pick it up. + # But let's check for any remaining placeholders manually if needed. + pass + + lines = content.splitlines() + for lineno, new_doc in sorted(modifications, reverse=True): + idx = lineno - 1 + if idx < len(lines) and PLACEHOLDER in lines[idx]: + lines[idx] = lines[idx].replace(PLACEHOLDER, new_doc) + else: + found = False + for i in range(max(0, idx-5), min(len(lines), idx+6)): + if PLACEHOLDER in lines[i]: + lines[i] = lines[i].replace(PLACEHOLDER, new_doc) + found = True + break + + new_content = '\n'.join(lines) + if not new_content.endswith('\n') and content.endswith('\n'): + new_content += '\n' + + with open(filepath, 'w') as f: + f.write(new_content) + +def main(): + for root, dirs, files in os.walk('tests'): + for file in files: + if file.endswith('.py'): + process_file(os.path.join(root, file)) + +if __name__ == '__main__': + main() diff --git a/tests/conftest.py b/tests/conftest.py index fe65a54f..f14de6d4 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,6 +1,10 @@ # ruff: noqa: E402 -"""TODO: Add docstring.""" +"""Global test configuration and shared fixtures for the iMedNet SDK test suite. + +This module provides common fixtures for mocking network requests, managing study context, +and simulating API responses across unit and integration tests. +""" import sys from pathlib import Path @@ -39,7 +43,14 @@ def block_external_requests(request: pytest.FixtureRequest): def _is_live_test(node: object) -> bool: - """TODO: Add docstring.""" + """Check if a test node is marked as a live test or resides in the live tests directory. + + Args: + node: The pytest node to check. + + Returns: + True if the test is a live test, False otherwise. + """ if not hasattr(node, "get_closest_marker"): return False @@ -55,7 +66,7 @@ def _is_live_test(node: object) -> bool: @pytest.fixture(autouse=True) def reset_study_context_between_tests(): - """TODO: Add docstring.""" + """Reset the global study context before and after each test to ensure isolation.""" clear_study_context() yield clear_study_context() @@ -63,7 +74,7 @@ def reset_study_context_between_tests(): @pytest.fixture(autouse=True) def reset_circuit_breaker_between_tests(): - """TODO: Add docstring.""" + """Reset the global circuit breaker before and after each test to ensure state isolation.""" from imednet.core.operations.circuit_breaker import get_global_circuit_breaker get_global_circuit_breaker().reset() @@ -72,35 +83,43 @@ def reset_circuit_breaker_between_tests(): class DummyResponse: - """TODO: Add docstring.""" + """A simple mock response object that mimics the httpx.Response JSON interface.""" def __init__(self, data): - """TODO: Add docstring.""" + """Initialize the dummy response with data. + + Args: + data: The data to be returned by the json() method. + """ self._data = data def json(self): - """TODO: Add docstring.""" + """Return the stored data as JSON. + + Returns: + The data provided during initialization. + """ return self._data @pytest.fixture def context(): - """TODO: Add docstring.""" + """Provide a fresh Context instance for each test.""" return Context() @pytest.fixture def dummy_client(): - """TODO: Add docstring.""" + """Provide a MagicMock to simulate an iMedNet client.""" return MagicMock() @pytest.fixture def response_factory(): - """TODO: Add docstring.""" + """Provide a factory function to create DummyResponse instances.""" def factory(data): - """TODO: Add docstring.""" + """Create a DummyResponse with the given data.""" return DummyResponse(data) return factory @@ -108,19 +127,31 @@ def factory(data): @pytest.fixture def paginator_factory(monkeypatch): - """TODO: Add docstring.""" + """Provide a factory to mock synchronous pagination for iMedNet endpoints. + + This fixture patches the endpoint classes to use a dummy paginator and + captures the arguments passed to it. + """ from imednet.core.endpoint.operations.list import ListOperation from tests.utils.streaming import StreamingMockWrapper def factory(module, items): - """TODO: Add docstring.""" + """Create a dummy paginator and patch the specified module. + + Args: + module: The module containing endpoint classes to patch. + items: The list of items the dummy paginator should return. + + Returns: + A dictionary containing captured arguments from the paginator initialization. + """ captured = {"count": 0} class DummyPaginator: - """TODO: Add docstring.""" + """A mock paginator for synchronous list operations.""" def __init__(self, client, path, params=None, page_size=100, **kwargs): - """TODO: Add docstring.""" + """Initialize the dummy paginator and capture arguments.""" captured["client"] = client captured["path"] = path captured["params"] = params or {} @@ -129,7 +160,7 @@ def __init__(self, client, path, params=None, page_size=100, **kwargs): self._items = items def __iter__(self): - """TODO: Add docstring.""" + """Iterate over the provided items.""" yield from self._items from imednet.core.endpoint.base import SyncListGetEndpoint @@ -139,7 +170,7 @@ def __iter__(self): monkeypatch.setattr(obj, "PAGINATOR_CLS", DummyPaginator, raising=False) def fake_execute_sync(self, client, paginator_cls): - """TODO: Add docstring.""" + """Fake implementation of the synchronous list operation execution.""" paginator = paginator_cls( client, self.path, params=self.params, page_size=self.page_size ) @@ -154,19 +185,31 @@ def fake_execute_sync(self, client, paginator_cls): @pytest.fixture def async_paginator_factory(monkeypatch): - """TODO: Add docstring.""" + """Provide a factory to mock asynchronous pagination for iMedNet endpoints. + + This fixture patches the endpoint classes to use an async dummy paginator + and captures the arguments passed to it. + """ from imednet.core.endpoint.operations.list import ListOperation from tests.utils.streaming import StreamingMockWrapper def factory(module, items): - """TODO: Add docstring.""" + """Create an async dummy paginator and patch the specified module. + + Args: + module: The module containing endpoint classes to patch. + items: The list of items the dummy paginator should return. + + Returns: + A dictionary containing captured arguments from the paginator initialization. + """ captured = {"count": 0} class DummyPaginator: - """TODO: Add docstring.""" + """A mock paginator for asynchronous list operations.""" def __init__(self, client, path, params=None, page_size=100, **kwargs): - """TODO: Add docstring.""" + """Initialize the dummy paginator and capture arguments.""" captured["client"] = client captured["path"] = path captured["params"] = params or {} @@ -175,7 +218,7 @@ def __init__(self, client, path, params=None, page_size=100, **kwargs): self._items = items async def __aiter__(self): - """TODO: Add docstring.""" + """Asynchronously iterate over the provided items.""" for item in self._items: yield item @@ -186,7 +229,7 @@ async def __aiter__(self): monkeypatch.setattr(obj, "ASYNC_PAGINATOR_CLS", DummyPaginator, raising=False) def fake_execute_async(self, client, paginator_cls): - """TODO: Add docstring.""" + """Fake implementation of the asynchronous list operation execution.""" paginator = paginator_cls( client, self.path, params=self.params, page_size=self.page_size ) @@ -202,14 +245,21 @@ def fake_execute_async(self, client, paginator_cls): @pytest.fixture def patch_build_filter(monkeypatch): - """TODO: Add docstring.""" + """Provide a helper to mock the filter string builder and capture input filters.""" def patch(module): - """TODO: Add docstring.""" + """Patch the filter builder in the specified module. + + Args: + module: The module where the filter builder should be patched. + + Returns: + A dictionary that will contain the captured filters. + """ captured = {} def fake(filters): - """TODO: Add docstring.""" + """Fake filter builder that captures filters and returns a constant.""" captured["filters"] = filters return "FILTERED" @@ -226,13 +276,16 @@ def fake(filters): @pytest.fixture def http_client(): - """TODO: Add docstring.""" + """Provide a synchronous Client instance configured for testing.""" return Client("key", "secret", base_url="https://api.test") @pytest_asyncio.fixture async def async_http_client(): - """TODO: Add docstring.""" + """Provide an asynchronous AsyncClient instance configured for testing. + + This fixture ensures the client is properly closed after use. + """ client = AsyncClient("key", "secret", base_url="https://api.test") try: yield client @@ -242,19 +295,19 @@ async def async_http_client(): @pytest.fixture def respx_mock_client(http_client, respx_mock): - """TODO: Add docstring.""" + """Configure respx_mock with the base URL of the synchronous test client.""" respx_mock.base_url = http_client.base_url return respx_mock @pytest_asyncio.fixture async def respx_mock_async_client(async_http_client, respx_mock): - """TODO: Add docstring.""" + """Configure respx_mock with the base URL of the asynchronous test client.""" respx_mock.base_url = async_http_client.base_url return respx_mock @pytest.fixture def sample_data(): - """TODO: Add docstring.""" + """Provide a simple dictionary for testing data handling.""" return {"data": [1]} diff --git a/tests/core/__init__.py b/tests/core/__init__.py index a9cca0f7..fae6326f 100644 --- a/tests/core/__init__.py +++ b/tests/core/__init__.py @@ -1 +1 @@ -"""TODO: Add docstring.""" +"""Test package initialization.""" diff --git a/tests/core/test_requester.py b/tests/core/test_requester.py index 19347499..bdcf8fde 100644 --- a/tests/core/test_requester.py +++ b/tests/core/test_requester.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for requester.""" import httpx import pytest @@ -11,12 +11,12 @@ @respx.mock def test_sync_executor_retries_success(): - """TODO: Add docstring.""" + """Test that sync executor retries success.""" client = httpx.Client(base_url="https://api.test") calls = {"count": 0} def handler(request: httpx.Request) -> httpx.Response: - """TODO: Add docstring.""" + """Helper function to handler.""" calls["count"] += 1 if calls["count"] == 1: raise httpx.RequestError("boom", request=request) @@ -34,7 +34,7 @@ def handler(request: httpx.Request) -> httpx.Response: @respx.mock @pytest.mark.asyncio async def test_async_executor_error_mapping(): - """TODO: Add docstring.""" + """Test that async executor error mapping asynchronously.""" async_client = httpx.AsyncClient(base_url="https://api.test") respx.get("https://api.test/bad").respond(status_code=404, json={"msg": "x"}) @@ -49,12 +49,12 @@ async def test_async_executor_error_mapping(): @respx.mock def test_sync_executor_retries_exhausted(): - """TODO: Add docstring.""" + """Test that sync executor retries exhausted.""" client = httpx.Client(base_url="https://api.test") calls = {"count": 0} def handler(request: httpx.Request) -> httpx.Response: - """TODO: Add docstring.""" + """Helper function to handler.""" calls["count"] += 1 raise httpx.RequestError("boom", request=request) @@ -71,12 +71,12 @@ def handler(request: httpx.Request) -> httpx.Response: @respx.mock def test_sync_executor_retries_exhausted_with_error_response(): - """TODO: Add docstring.""" + """Test that sync executor retries exhausted with error response.""" client = httpx.Client(base_url="https://api.test") calls = {"count": 0} def handler(request: httpx.Request) -> httpx.Response: - """TODO: Add docstring.""" + """Helper function to handler.""" calls["count"] += 1 return httpx.Response(500, json={"error": "server error"}) @@ -94,12 +94,12 @@ def handler(request: httpx.Request) -> httpx.Response: @respx.mock @pytest.mark.asyncio async def test_async_executor_retries_exhausted(): - """TODO: Add docstring.""" + """Test that async executor retries exhausted asynchronously.""" async_client = httpx.AsyncClient(base_url="https://api.test") calls = {"count": 0} def handler(request: httpx.Request) -> httpx.Response: - """TODO: Add docstring.""" + """Helper function to handler.""" calls["count"] += 1 raise httpx.RequestError("boom", request=request) @@ -118,11 +118,11 @@ def handler(request: httpx.Request) -> httpx.Response: @respx.mock def test_sync_executor_null_response(monkeypatch): - """TODO: Add docstring.""" + """Test that sync executor null response.""" client = httpx.Client(base_url="https://api.test") def mock_retryer(*args, **kwargs): - """TODO: Add docstring.""" + """Helper function to mock retryer.""" return None monkeypatch.setattr("tenacity.Retrying.__call__", mock_retryer) @@ -138,11 +138,11 @@ def mock_retryer(*args, **kwargs): @respx.mock @pytest.mark.asyncio async def test_async_executor_null_response(monkeypatch): - """TODO: Add docstring.""" + """Test that async executor null response asynchronously.""" async_client = httpx.AsyncClient(base_url="https://api.test") async def mock_retryer(*args, **kwargs): - """TODO: Add docstring.""" + """Helper function to mock retryer.""" return None monkeypatch.setattr("tenacity.AsyncRetrying.__call__", mock_retryer) @@ -159,12 +159,12 @@ async def mock_retryer(*args, **kwargs): @respx.mock @pytest.mark.asyncio async def test_async_executor_retries_exhausted_with_error_response(): - """TODO: Add docstring.""" + """Test that async executor retries exhausted with error response asynchronously.""" async_client = httpx.AsyncClient(base_url="https://api.test") calls = {"count": 0} def handler(request: httpx.Request) -> httpx.Response: - """TODO: Add docstring.""" + """Helper function to handler.""" calls["count"] += 1 return httpx.Response(500, json={"error": "server error"}) @@ -182,36 +182,36 @@ def handler(request: httpx.Request) -> httpx.Response: class FakeAttempt: - """TODO: Add docstring.""" + """Test suite for FakeAttempt.""" def __init__(self, failed): - """TODO: Add docstring.""" + """Initialize the test object.""" self.failed = failed def exception(self): - """TODO: Add docstring.""" + """Helper function to exception.""" return RuntimeError("Fake error") def result(self): - """TODO: Add docstring.""" + """Helper function to result.""" return httpx.Response(200, json={"ok": True}) class FakeRetryError(RetryError): - """TODO: Add docstring.""" + """Test suite for FakeRetryError.""" def __init__(self, failed): - """TODO: Add docstring.""" + """Initialize the test object.""" self.last_attempt = FakeAttempt(failed) super().__init__(self.last_attempt) def test_sync_executor_unreachable_branch(monkeypatch): - """TODO: Add docstring.""" + """Test that sync executor unreachable branch.""" client = httpx.Client(base_url="https://api.test") def mock_retryer(*args, **kwargs): - """TODO: Add docstring.""" + """Helper function to mock retryer.""" raise FakeRetryError(False) monkeypatch.setattr("tenacity.Retrying.__call__", mock_retryer) @@ -226,11 +226,11 @@ def mock_retryer(*args, **kwargs): @pytest.mark.asyncio async def test_async_executor_unreachable_branch(monkeypatch): - """TODO: Add docstring.""" + """Test that async executor unreachable branch asynchronously.""" async_client = httpx.AsyncClient(base_url="https://api.test") async def mock_retryer(*args, **kwargs): - """TODO: Add docstring.""" + """Helper function to mock retryer.""" raise FakeRetryError(False) monkeypatch.setattr("tenacity.AsyncRetrying.__call__", mock_retryer) diff --git a/tests/core/test_retry_policy.py b/tests/core/test_retry_policy.py index bdbee37e..afdc5a13 100644 --- a/tests/core/test_retry_policy.py +++ b/tests/core/test_retry_policy.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for retry policy.""" import httpx import pytest @@ -9,7 +9,7 @@ def test_default_policy_request_error(): - """TODO: Add docstring.""" + """Test that default policy request error.""" policy = DefaultRetryPolicy() state = RetryState( 1, @@ -21,7 +21,7 @@ def test_default_policy_request_error(): def test_default_policy_retry_behavior(): - """TODO: Add docstring.""" + """Test that default policy retry behavior.""" policy = DefaultRetryPolicy() # Retryable responses for idempotent methods (Server Errors & Rate Limits) @@ -45,12 +45,12 @@ def test_default_policy_retry_behavior(): def test_default_policy_non_request_exception(monkeypatch): - """TODO: Add docstring.""" + """Test that default policy non request exception.""" client = Client("k", "s", base_url="https://api.test", retries=3) calls = {"count": 0} def request(method: str, url: str, **kwargs: object) -> httpx.Response: - """TODO: Add docstring.""" + """Helper function to request.""" calls["count"] += 1 raise RuntimeError("boom") @@ -63,20 +63,20 @@ def request(method: str, url: str, **kwargs: object) -> httpx.Response: def test_custom_policy(monkeypatch): - """TODO: Add docstring.""" + """Test that custom policy.""" class ServerPolicy: - """TODO: Add docstring.""" + """Test suite for ServerPolicy.""" def should_retry(self, state: RetryState) -> bool: - """TODO: Add docstring.""" + """Helper function to should retry.""" return isinstance(state.exception, ServerError) client = Client("k", "s", base_url="https://api.test", retries=3, retry_policy=ServerPolicy()) calls = {"count": 0} def request(method: str, url: str, **kwargs: object) -> httpx.Response: - """TODO: Add docstring.""" + """Helper function to request.""" calls["count"] += 1 if calls["count"] < 3: raise ServerError({}, status_code=500) @@ -91,13 +91,13 @@ def request(method: str, url: str, **kwargs: object) -> httpx.Response: def test_custom_policy_based_on_result(monkeypatch): - """TODO: Add docstring.""" + """Test that custom policy based on result.""" class ResponsePolicy: - """TODO: Add docstring.""" + """Test suite for ResponsePolicy.""" def should_retry(self, state: RetryState) -> bool: - """TODO: Add docstring.""" + """Helper function to should retry.""" resp = state.result return isinstance(resp, httpx.Response) and resp.status_code >= 500 @@ -105,7 +105,7 @@ def should_retry(self, state: RetryState) -> bool: calls = {"count": 0} def request(method: str, url: str, **kwargs: object) -> httpx.Response: - """TODO: Add docstring.""" + """Helper function to request.""" calls["count"] += 1 if calls["count"] < 3: return httpx.Response(500) diff --git a/tests/integration/__init__.py b/tests/integration/__init__.py index a9cca0f7..fae6326f 100644 --- a/tests/integration/__init__.py +++ b/tests/integration/__init__.py @@ -1 +1 @@ -"""TODO: Add docstring.""" +"""Test package initialization.""" diff --git a/tests/integration/test_airflow_dag.py b/tests/integration/test_airflow_dag.py index 1c1c638e..6d31ecf6 100644 --- a/tests/integration/test_airflow_dag.py +++ b/tests/integration/test_airflow_dag.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for airflow dag.""" from datetime import datetime from types import SimpleNamespace @@ -8,7 +8,7 @@ def test_dag_runs(monkeypatch, tmp_path): - """TODO: Add docstring.""" + """Test that dag runs.""" pytest.importorskip("airflow") out_csv = tmp_path / "out.csv" from airflow.models import DAG, TaskInstance # noqa: E402, I001 diff --git a/tests/integration/test_cli_integration.py b/tests/integration/test_cli_integration.py index 7d4ef878..1150622b 100644 --- a/tests/integration/test_cli_integration.py +++ b/tests/integration/test_cli_integration.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for cli integration.""" from pathlib import Path from unittest.mock import MagicMock @@ -41,7 +41,7 @@ def invoke(self, app, args): def test_cli_rejects_missing_credentials(monkeypatch: pytest.MonkeyPatch) -> None: - """TODO: Add docstring.""" + """Test that cli rejects missing credentials.""" runner = CliRunner() monkeypatch.delenv("IMEDNET_API_KEY", raising=False) monkeypatch.delenv("IMEDNET_SECURITY_KEY", raising=False) @@ -53,7 +53,7 @@ def test_cli_rejects_missing_credentials(monkeypatch: pytest.MonkeyPatch) -> Non def test_studies_list_success(monkeypatch: pytest.MonkeyPatch) -> None: - """TODO: Add docstring.""" + """Test that studies list success.""" runner = CliRunner() monkeypatch.setenv("IMEDNET_API_KEY", "k") monkeypatch.setenv("IMEDNET_SECURITY_KEY", "s") @@ -75,7 +75,7 @@ def test_studies_list_success(monkeypatch: pytest.MonkeyPatch) -> None: def test_records_list_output_csv(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None: - """TODO: Add docstring.""" + """Test that records list output csv.""" runner = CliRunner() monkeypatch.setenv("IMEDNET_API_KEY", "k") monkeypatch.setenv("IMEDNET_SECURITY_KEY", "s") @@ -94,7 +94,7 @@ def test_records_list_output_csv(monkeypatch: pytest.MonkeyPatch, tmp_path: Path def test_extract_records_cli_parses_filters(monkeypatch: pytest.MonkeyPatch) -> None: - """TODO: Add docstring.""" + """Test that extract records cli parses filters.""" runner = CliRunner() monkeypatch.setenv("IMEDNET_API_KEY", "k") monkeypatch.setenv("IMEDNET_SECURITY_KEY", "s") @@ -131,7 +131,7 @@ def test_extract_records_cli_parses_filters(monkeypatch: pytest.MonkeyPatch) -> def test_invalid_filter_string(monkeypatch: pytest.MonkeyPatch) -> None: - """TODO: Add docstring.""" + """Test that invalid filter string.""" runner = CliRunner() monkeypatch.setenv("IMEDNET_API_KEY", "k") monkeypatch.setenv("IMEDNET_SECURITY_KEY", "s") diff --git a/tests/integration/test_core_client_integration.py b/tests/integration/test_core_client_integration.py index 4bb3bb9e..c468c73d 100644 --- a/tests/integration/test_core_client_integration.py +++ b/tests/integration/test_core_client_integration.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for core client integration.""" import contextlib @@ -12,7 +12,7 @@ @respx.mock def test_successful_get_sync_client(): - """TODO: Add docstring.""" + """Test that successful get sync client.""" client = Client("k", "s", base_url="https://api.test") respx.get("https://api.test/api/v1/edc/studies").respond(status_code=200, json={"data": [1]}) @@ -24,20 +24,20 @@ def test_successful_get_sync_client(): @respx.mock(assert_all_mocked=False) def test_retry_on_transient_500(monkeypatch: pytest.MonkeyPatch) -> None: - """TODO: Add docstring.""" + """Test that retry on transient 500.""" class Policy: - """TODO: Add docstring.""" + """Test suite for Policy.""" def should_retry(self, state) -> bool: - """TODO: Add docstring.""" + """Helper function to should retry.""" return isinstance(state.exception, errors.ServerError) client = Client("k", "s", base_url="https://api.test", retries=3, retry_policy=Policy()) calls = {"count": 0} def request(method: str, url: str, **kwargs: object) -> httpx.Response: - """TODO: Add docstring.""" + """Helper function to request.""" calls["count"] += 1 if calls["count"] < 3: raise errors.ServerError({}, status_code=500) @@ -53,7 +53,7 @@ def request(method: str, url: str, **kwargs: object) -> httpx.Response: @respx.mock def test_authentication_error(): - """TODO: Add docstring.""" + """Test that authentication error.""" client = Client("k", "s", base_url="https://api.test") respx.get("https://api.test/protected").respond(status_code=401, json={}) @@ -63,11 +63,11 @@ def test_authentication_error(): @respx.mock def test_timeout_handling(): - """TODO: Add docstring.""" + """Test that timeout handling.""" client = Client("k", "s", base_url="https://api.test", timeout=1, retries=1) def slow(request): - """TODO: Add docstring.""" + """Helper function to slow.""" raise httpx.ReadTimeout("timeout", request=request) respx.get("https://api.test/slow").mock(side_effect=slow) @@ -79,17 +79,17 @@ def slow(request): @respx.mock def test_tracer_records_span(): - """TODO: Add docstring.""" + """Test that tracer records span.""" class DummyTracer: - """TODO: Add docstring.""" + """Test suite for DummyTracer.""" def __init__(self): - """TODO: Add docstring.""" + """Initialize the test object.""" self.called = False def start_as_current_span(self, name, attributes=None): - """TODO: Add docstring.""" + """Helper function to start as current span.""" self.called = True return contextlib.nullcontext() diff --git a/tests/integration/test_endpoints_integration.py b/tests/integration/test_endpoints_integration.py index de8eee02..698172d1 100644 --- a/tests/integration/test_endpoints_integration.py +++ b/tests/integration/test_endpoints_integration.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for endpoints integration.""" import httpx import pytest @@ -9,12 +9,12 @@ @respx.mock def test_studies_list_pagination(): - """TODO: Add docstring.""" + """Test that studies list pagination.""" sdk = ImednetSDK(api_key="k", security_key="s", base_url="https://api.test") calls = [] def responder(request): - """TODO: Add docstring.""" + """Helper function to responder.""" calls.append(dict(request.url.params)) if len(calls) == 1: return httpx.Response( @@ -43,7 +43,7 @@ def responder(request): @respx.mock def test_records_list_filter_param(): - """TODO: Add docstring.""" + """Test that records list filter param.""" sdk = ImednetSDK(api_key="k", security_key="s", base_url="https://api.test") route = respx.get("https://api.test/api/v1/edc/studies/ST/records").respond( @@ -60,7 +60,7 @@ def test_records_list_filter_param(): @respx.mock @pytest.mark.asyncio async def test_async_endpoint_mirror(): - """TODO: Add docstring.""" + """Test that async endpoint mirror asynchronously.""" sync_sdk = ImednetSDK(api_key="k", security_key="s", base_url="https://api.test") async_sdk = AsyncImednetSDK(api_key="k", security_key="s", base_url="https://api.test") diff --git a/tests/integration/test_sqlite_export_modes.py b/tests/integration/test_sqlite_export_modes.py index a9cf857d..248fd9ff 100644 --- a/tests/integration/test_sqlite_export_modes.py +++ b/tests/integration/test_sqlite_export_modes.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for sqlite export modes.""" import importlib.util import sys @@ -47,7 +47,7 @@ def invoke(self, app, args): @pytest.fixture def sqlite_env(monkeypatch: pytest.MonkeyPatch) -> None: - """TODO: Add docstring.""" + """Helper function to sqlite env.""" monkeypatch.setenv("IMEDNET_API_KEY", "k") monkeypatch.setenv("IMEDNET_SECURITY_KEY", "s") monkeypatch.setattr(importlib.util, "find_spec", lambda name: object()) @@ -59,7 +59,7 @@ def sqlite_env(monkeypatch: pytest.MonkeyPatch) -> None: def _setup_per_form_mapper(monkeypatch: pytest.MonkeyPatch) -> None: - """TODO: Add docstring.""" + """Helper function to setup per form mapper.""" form1_vars = [MagicMock(variable_name=f"v{i}", label=f"v{i}") for i in range(1500)] form2_vars = [MagicMock(variable_name=f"w{i}", label=f"w{i}") for i in range(600)] sdk = MagicMock() @@ -84,7 +84,7 @@ def _setup_per_form_mapper(monkeypatch: pytest.MonkeyPatch) -> None: def _setup_single_table_mapper(monkeypatch: pytest.MonkeyPatch) -> MagicMock: - """TODO: Add docstring.""" + """Helper function to setup single table mapper.""" columns = [f"c{i}" for i in range(2100)] df = pd.DataFrame([range(2100)], columns=columns) mapper_inst = MagicMock(dataframe=MagicMock(return_value=df)) @@ -100,7 +100,7 @@ def _setup_single_table_mapper(monkeypatch: pytest.MonkeyPatch) -> MagicMock: def test_default_sqlite_mode_splits_by_form( sqlite_env, monkeypatch: pytest.MonkeyPatch, tmp_path: Path ) -> None: - """TODO: Add docstring.""" + """Test that default sqlite mode splits by form.""" _setup_per_form_mapper(monkeypatch) runner = CliRunner() monkeypatch.chdir(tmp_path) @@ -114,7 +114,7 @@ def test_default_sqlite_mode_splits_by_form( def test_single_table_mode_chunks( sqlite_env, monkeypatch: pytest.MonkeyPatch, tmp_path: Path ) -> None: - """TODO: Add docstring.""" + """Test that single table mode chunks.""" mock_to_sql = _setup_single_table_mapper(monkeypatch) runner = CliRunner() monkeypatch.chdir(tmp_path) diff --git a/tests/integration/test_sync_worker_integration.py b/tests/integration/test_sync_worker_integration.py index 157af631..4a5a7cad 100644 --- a/tests/integration/test_sync_worker_integration.py +++ b/tests/integration/test_sync_worker_integration.py @@ -21,7 +21,7 @@ def _make_record(record_id: int, study_key: str = "PROT-01") -> Record: - """TODO: Add docstring.""" + """Helper function to make record.""" return Record( study_key=study_key, form_id=1, @@ -46,7 +46,7 @@ class _ReaderLoop(threading.Thread): """Continuously reads cached records until ``stop_event`` is set.""" def __init__(self, loader: CachedRecordsLoader, stop_event: threading.Event) -> None: - """TODO: Add docstring.""" + """Initialize the test object.""" super().__init__(daemon=True) self.loader = loader self.stop_event = stop_event @@ -54,7 +54,7 @@ def __init__(self, loader: CachedRecordsLoader, stop_event: threading.Event) -> self.read_count = 0 def run(self) -> None: - """TODO: Add docstring.""" + """Helper function to run.""" while not self.stop_event.is_set(): try: self.loader.get_cached_records("PROT-01") @@ -110,7 +110,7 @@ def test_parallel_sync_workers_no_deadlock(tmp_path: Path) -> None: barrier = threading.Barrier(3) def _run_worker(worker_id: int) -> None: - """TODO: Add docstring.""" + """Helper function to run worker.""" sdk = _make_sdk(records) loader = CachedRecordsLoader(sdk, cache_dir=tmp_path) worker = SyncWorker( diff --git a/tests/integration/test_workflows_integration.py b/tests/integration/test_workflows_integration.py index 6d62f2ce..a87b759a 100644 --- a/tests/integration/test_workflows_integration.py +++ b/tests/integration/test_workflows_integration.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for workflows integration.""" import re import time @@ -16,7 +16,7 @@ @respx.mock def test_data_extraction_filters(): - """TODO: Add docstring.""" + """Test that data extraction filters.""" sdk = ImednetSDK(api_key="k", security_key="s", base_url="https://api.test") respx.get("https://api.test/api/v1/edc/studies/ST/variables").respond(json={"data": []}) respx.get("https://api.test/api/v1/edc/studies/ST/subjects").respond( @@ -47,7 +47,7 @@ def test_data_extraction_filters(): @respx.mock def test_record_update_submit_and_wait(monkeypatch: pytest.MonkeyPatch): - """TODO: Add docstring.""" + """Test that record update submit and wait.""" sdk = ImednetSDK(api_key="k", security_key="s", base_url="https://api.test") respx.get(re.compile("https://api.test/api/v1/edc/studies/ST/variables.*")).respond( json={ @@ -76,7 +76,7 @@ def test_record_update_submit_and_wait(monkeypatch: pytest.MonkeyPatch): @respx.mock def test_subject_data_aggregation(): - """TODO: Add docstring.""" + """Test that subject data aggregation.""" sdk = ImednetSDK(api_key="k", security_key="s", base_url="https://api.test") respx.get("https://api.test/api/v1/edc/studies/ST/subjects").respond( json={"data": [{"subjectKey": "SUB1"}]} @@ -102,7 +102,7 @@ def test_subject_data_aggregation(): @respx.mock def test_query_management_counts(): - """TODO: Add docstring.""" + """Test that query management counts.""" sdk = ImednetSDK(api_key="k", security_key="s", base_url="https://api.test") respx.get("https://api.test/api/v1/edc/studies/ST/queries").respond( json={ @@ -122,7 +122,7 @@ def test_query_management_counts(): @respx.mock def test_data_extraction_no_matching_subjects() -> None: - """TODO: Add docstring.""" + """Test that data extraction no matching subjects.""" sdk = ImednetSDK(api_key="k", security_key="s", base_url="https://api.test") subjects_route = respx.get("https://api.test/api/v1/edc/studies/ST/subjects").respond( json={"data": []} @@ -145,7 +145,7 @@ def test_data_extraction_no_matching_subjects() -> None: @respx.mock def test_record_update_timeout(monkeypatch: pytest.MonkeyPatch) -> None: - """TODO: Add docstring.""" + """Test that record update timeout.""" sdk = ImednetSDK(api_key="k", security_key="s", base_url="https://api.test") respx.get(re.compile("https://api.test/api/v1/edc/studies/ST/variables.*")).respond( json={ @@ -162,7 +162,7 @@ def test_record_update_timeout(monkeypatch: pytest.MonkeyPatch) -> None: counter = {"v": 0} def monotonic() -> int: - """TODO: Add docstring.""" + """Helper function to monotonic.""" counter["v"] += 1 return counter["v"] @@ -182,7 +182,7 @@ def monotonic() -> int: @respx.mock def test_get_open_queries() -> None: - """TODO: Add docstring.""" + """Test that get open queries.""" sdk = ImednetSDK(api_key="k", security_key="s", base_url="https://api.test") respx.get("https://api.test/api/v1/edc/studies/ST/queries").respond( json={ diff --git a/tests/live/__init__.py b/tests/live/__init__.py index a9cca0f7..fae6326f 100644 --- a/tests/live/__init__.py +++ b/tests/live/__init__.py @@ -1 +1 @@ -"""TODO: Add docstring.""" +"""Test package initialization.""" diff --git a/tests/live/conftest.py b/tests/live/conftest.py index 1a3bfc83..c2fee377 100644 --- a/tests/live/conftest.py +++ b/tests/live/conftest.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for conftest.""" import asyncio import logging @@ -52,7 +52,7 @@ def _print_startup_context() -> None: @pytest.fixture(scope="session", autouse=True) def _check_live_env() -> None: - """TODO: Add docstring.""" + """Helper function to check live env.""" _print_startup_context() if not RUN_E2E or not (API_KEY and SECURITY_KEY): pytest.skip( @@ -70,7 +70,7 @@ def allow_mutation() -> bool: @pytest.fixture(scope="session") def sdk() -> Iterator[ImednetSDK]: - """TODO: Add docstring.""" + """Helper function to sdk.""" with ImednetSDK(api_key=API_KEY, security_key=SECURITY_KEY, base_url=BASE_URL) as client: yield client @@ -91,19 +91,19 @@ async def async_sdk(event_loop: asyncio.AbstractEventLoop) -> AsyncIterator[Asyn @pytest.fixture(scope="session") def study_key(sdk: ImednetSDK) -> str: - """TODO: Add docstring.""" + """Helper function to study key.""" return get_study_key(sdk) @pytest.fixture(scope="session") def first_form_key(sdk: ImednetSDK, study_key: str) -> str: - """TODO: Add docstring.""" + """Helper function to first form key.""" return get_form_key(sdk, study_key) @pytest.fixture(scope="session") def first_site_name(sdk: ImednetSDK, study_key: str) -> str: - """TODO: Add docstring.""" + """Helper function to first site name.""" try: return discover_site_name(sdk, study_key) except NoLiveDataError as exc: @@ -112,7 +112,7 @@ def first_site_name(sdk: ImednetSDK, study_key: str) -> str: @pytest.fixture(scope="session") def first_subject_key(sdk: ImednetSDK, study_key: str) -> str: - """TODO: Add docstring.""" + """Helper function to first subject key.""" try: return discover_subject_key(sdk, study_key) except NoLiveDataError as exc: @@ -121,7 +121,7 @@ def first_subject_key(sdk: ImednetSDK, study_key: str) -> str: @pytest.fixture(scope="session") def first_interval_name(sdk: ImednetSDK, study_key: str) -> str: - """TODO: Add docstring.""" + """Helper function to first interval name.""" try: return discover_interval_name(sdk, study_key) except NoLiveDataError as exc: @@ -168,7 +168,7 @@ def typed_record( study_key: str, first_form_key: str, ) -> Callable[..., dict[str, Any]]: - """TODO: Add docstring.""" + """Helper function to typed record.""" variables = list(sdk.variables.list(study_key=study_key, formKey=first_form_key)) if not variables: pytest.skip(f"No variables available for form {first_form_key}") @@ -189,7 +189,7 @@ def build( subject_key: str | None = None, interval_name: str | None = None, ) -> dict[str, Any]: - """TODO: Add docstring.""" + """Helper function to build.""" record: dict[str, Any] = {"formKey": first_form_key, "data": data} if site_name is not None: record["siteName"] = site_name @@ -210,7 +210,7 @@ def record_payload( first_subject_key: str, first_interval_name: str, ) -> dict[str, Any]: - """TODO: Add docstring.""" + """Helper function to record payload.""" scenario = request.param if scenario == "register": return typed_record(site_name=first_site_name) diff --git a/tests/live/helpers.py b/tests/live/helpers.py index 74e28e9e..0fcf742c 100644 --- a/tests/live/helpers.py +++ b/tests/live/helpers.py @@ -15,7 +15,7 @@ def _skip(msg: str) -> NoReturn: - """TODO: Add docstring.""" + """Helper function to skip.""" pytest.skip(msg) raise AssertionError("unreachable") diff --git a/tests/live/test_cli_live.py b/tests/live/test_cli_live.py index a6ac2c2e..e3025b0d 100644 --- a/tests/live/test_cli_live.py +++ b/tests/live/test_cli_live.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for cli live.""" import pandas as pd import pytest @@ -41,36 +41,36 @@ def invoke(self, app, args): @pytest.fixture(scope="session") def runner() -> CliRunner: - """TODO: Add docstring.""" + """Helper function to runner.""" return CliRunner() def test_cli_studies_list(runner: CliRunner) -> None: - """TODO: Add docstring.""" + """Test that cli studies list.""" result = runner.invoke(cli.app, ["studies", "list"]) assert result.exit_code == 0 def test_cli_sites_list(runner: CliRunner, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that cli sites list.""" result = runner.invoke(cli.app, ["sites", "list", study_key]) assert result.exit_code == 0 def test_cli_subjects_list(runner: CliRunner, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that cli subjects list.""" result = runner.invoke(cli.app, ["subjects", "list", study_key]) assert result.exit_code == 0 def test_cli_records_list(runner: CliRunner, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that cli records list.""" result = runner.invoke(cli.app, ["records", "list", study_key]) assert result.exit_code == 0 def test_cli_jobs_status(runner: CliRunner, study_key: str, generated_batch_id: str) -> None: - """TODO: Add docstring.""" + """Test that cli jobs status.""" result = runner.invoke( cli.app, ["jobs", "status", study_key, generated_batch_id], @@ -79,7 +79,7 @@ def test_cli_jobs_status(runner: CliRunner, study_key: str, generated_batch_id: def test_cli_jobs_wait(runner: CliRunner, study_key: str, generated_batch_id: str) -> None: - """TODO: Add docstring.""" + """Test that cli jobs wait.""" result = runner.invoke( cli.app, ["jobs", "wait", study_key, generated_batch_id, "--interval", "1", "--timeout", "60"], @@ -88,7 +88,7 @@ def test_cli_jobs_wait(runner: CliRunner, study_key: str, generated_batch_id: st def test_cli_export_parquet(runner: CliRunner, study_key: str, tmp_path) -> None: - """TODO: Add docstring.""" + """Test that cli export parquet.""" pytest.importorskip("pyarrow") out = tmp_path / "data.parquet" result = runner.invoke(cli.app, ["export", "parquet", study_key, str(out)]) @@ -97,7 +97,7 @@ def test_cli_export_parquet(runner: CliRunner, study_key: str, tmp_path) -> None def test_cli_export_csv(runner: CliRunner, study_key: str, tmp_path) -> None: - """TODO: Add docstring.""" + """Test that cli export csv.""" out = tmp_path / "data.csv" result = runner.invoke(cli.app, ["export", "csv", study_key, str(out)]) assert result.exit_code == 0 @@ -105,7 +105,7 @@ def test_cli_export_csv(runner: CliRunner, study_key: str, tmp_path) -> None: def test_cli_export_excel(runner: CliRunner, study_key: str, tmp_path) -> None: - """TODO: Add docstring.""" + """Test that cli export excel.""" pytest.importorskip("openpyxl") out = tmp_path / "data.xlsx" result = runner.invoke(cli.app, ["export", "excel", study_key, str(out)]) @@ -114,7 +114,7 @@ def test_cli_export_excel(runner: CliRunner, study_key: str, tmp_path) -> None: def test_cli_export_json(runner: CliRunner, study_key: str, tmp_path) -> None: - """TODO: Add docstring.""" + """Test that cli export json.""" out = tmp_path / "data.json" result = runner.invoke(cli.app, ["export", "json", study_key, str(out)]) assert result.exit_code == 0 @@ -124,7 +124,7 @@ def test_cli_export_json(runner: CliRunner, study_key: str, tmp_path) -> None: def test_cli_export_sql_chunks_tables( runner: CliRunner, study_key: str, tmp_path, monkeypatch: pytest.MonkeyPatch ) -> None: - """TODO: Add docstring.""" + """Test that cli export sql chunks tables.""" pytest.importorskip("sqlalchemy") from sqlalchemy import create_engine, inspect, text @@ -156,6 +156,6 @@ def test_cli_export_sql_chunks_tables( def test_cli_workflows_extract(runner: CliRunner, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that cli workflows extract.""" result = runner.invoke(cli.app, ["workflows", "extract-records", study_key]) assert result.exit_code == 0 diff --git a/tests/live/test_drift_postman.py b/tests/live/test_drift_postman.py index a4342ddc..b9b7a93e 100644 --- a/tests/live/test_drift_postman.py +++ b/tests/live/test_drift_postman.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for drift postman.""" import json import logging @@ -56,7 +56,7 @@ def test_postman_collection_drift(sdk: ImednetSDK, study_key: str): endpoints_to_test = set() def walk(items): - """TODO: Add docstring.""" + """Helper function to walk.""" for item in items: if "item" in item: walk(item["item"]) diff --git a/tests/live/test_endpoints_async_live.py b/tests/live/test_endpoints_async_live.py index f9e6610d..27bd2f98 100644 --- a/tests/live/test_endpoints_async_live.py +++ b/tests/live/test_endpoints_async_live.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for endpoints async live.""" from typing import Any @@ -10,7 +10,7 @@ @pytest.mark.asyncio(scope="session") async def test_async_sites(async_sdk: AsyncImednetSDK, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that async sites asynchronously.""" sites = [item async for item in async_sdk.sites.async_list(study_key)] assert isinstance(sites, list) if sites: @@ -20,7 +20,7 @@ async def test_async_sites(async_sdk: AsyncImednetSDK, study_key: str) -> None: @pytest.mark.asyncio(scope="session") async def test_async_subjects(async_sdk: AsyncImednetSDK, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that async subjects asynchronously.""" subjects = [item async for item in async_sdk.subjects.async_list(study_key)] assert isinstance(subjects, list) if subjects: @@ -30,7 +30,7 @@ async def test_async_subjects(async_sdk: AsyncImednetSDK, study_key: str) -> Non @pytest.mark.asyncio(scope="session") async def test_async_records(async_sdk: AsyncImednetSDK, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that async records asynchronously.""" records = [item async for item in async_sdk.records.async_list(study_key)] assert isinstance(records, list) if records: @@ -40,7 +40,7 @@ async def test_async_records(async_sdk: AsyncImednetSDK, study_key: str) -> None @pytest.mark.asyncio(scope="session") async def test_async_intervals(async_sdk: AsyncImednetSDK, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that async intervals asynchronously.""" intervals = [item async for item in async_sdk.intervals.async_list(study_key)] assert isinstance(intervals, list) if intervals: @@ -50,7 +50,7 @@ async def test_async_intervals(async_sdk: AsyncImednetSDK, study_key: str) -> No @pytest.mark.asyncio(scope="session") async def test_async_visits(async_sdk: AsyncImednetSDK, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that async visits asynchronously.""" visits = [item async for item in async_sdk.visits.async_list(study_key)] assert isinstance(visits, list) if visits: @@ -60,7 +60,7 @@ async def test_async_visits(async_sdk: AsyncImednetSDK, study_key: str) -> None: @pytest.mark.asyncio(scope="session") async def test_async_variables(async_sdk: AsyncImednetSDK, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that async variables asynchronously.""" variables = [item async for item in async_sdk.variables.async_list(study_key)] assert isinstance(variables, list) if variables: @@ -70,7 +70,7 @@ async def test_async_variables(async_sdk: AsyncImednetSDK, study_key: str) -> No @pytest.mark.asyncio(scope="session") async def test_async_forms(async_sdk: AsyncImednetSDK, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that async forms asynchronously.""" forms = [item async for item in async_sdk.forms.async_list(study_key)] assert isinstance(forms, list) if forms: @@ -80,7 +80,7 @@ async def test_async_forms(async_sdk: AsyncImednetSDK, study_key: str) -> None: @pytest.mark.asyncio(scope="session") async def test_async_queries(async_sdk: AsyncImednetSDK, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that async queries asynchronously.""" queries = [item async for item in async_sdk.queries.async_list(study_key)] assert isinstance(queries, list) if queries: @@ -90,7 +90,7 @@ async def test_async_queries(async_sdk: AsyncImednetSDK, study_key: str) -> None @pytest.mark.asyncio(scope="session") async def test_async_record_revisions(async_sdk: AsyncImednetSDK, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that async record revisions asynchronously.""" revisions = [item async for item in async_sdk.record_revisions.async_list(study_key)] assert isinstance(revisions, list) if revisions: @@ -100,7 +100,7 @@ async def test_async_record_revisions(async_sdk: AsyncImednetSDK, study_key: str @pytest.mark.asyncio(scope="session") async def test_async_users(async_sdk: AsyncImednetSDK, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that async users asynchronously.""" users = [item async for item in async_sdk.users.async_list(study_key)] assert isinstance(users, list) if users: @@ -110,7 +110,7 @@ async def test_async_users(async_sdk: AsyncImednetSDK, study_key: str) -> None: @pytest.mark.asyncio(scope="session") async def test_async_codings(async_sdk: AsyncImednetSDK, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that async codings asynchronously.""" codings = [item async for item in async_sdk.codings.async_list(study_key)] assert isinstance(codings, list) if codings: @@ -129,7 +129,7 @@ async def test_async_create_and_poll( study_key: str, record_payload: dict[str, Any], ) -> None: - """TODO: Add docstring.""" + """Test that async create and poll asynchronously.""" require_mutation() job = await async_sdk.records.async_create(study_key, [record_payload]) if not job.batch_id: diff --git a/tests/live/test_endpoints_sync_live.py b/tests/live/test_endpoints_sync_live.py index d203967b..ed1f0512 100644 --- a/tests/live/test_endpoints_sync_live.py +++ b/tests/live/test_endpoints_sync_live.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for endpoints sync live.""" from typing import Any @@ -22,7 +22,7 @@ def test_list_studies(sdk: ImednetSDK) -> None: - """TODO: Add docstring.""" + """Test that list studies.""" studies = list(sdk.studies.list()) assert isinstance(studies, list) assert studies, "No studies returned from server" @@ -32,7 +32,7 @@ def test_list_studies(sdk: ImednetSDK) -> None: def test_list_sites(sdk: ImednetSDK, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that list sites.""" sites = list(sdk.sites.list(study_key=study_key)) assert isinstance(sites, list) if sites: @@ -42,7 +42,7 @@ def test_list_sites(sdk: ImednetSDK, study_key: str) -> None: def test_get_study(sdk: ImednetSDK, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that get study.""" try: study = sdk.studies.get(None, study_key) except ServerError as exc: @@ -52,7 +52,7 @@ def test_get_study(sdk: ImednetSDK, study_key: str) -> None: def test_list_forms(sdk: ImednetSDK, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that list forms.""" forms = list(sdk.forms.list(study_key=study_key)) assert isinstance(forms, list) if forms: @@ -62,7 +62,7 @@ def test_list_forms(sdk: ImednetSDK, study_key: str) -> None: def test_list_subjects(sdk: ImednetSDK, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that list subjects.""" subjects = list(sdk.subjects.list(study_key=study_key)) assert isinstance(subjects, list) if subjects: @@ -72,7 +72,7 @@ def test_list_subjects(sdk: ImednetSDK, study_key: str) -> None: def test_list_records(sdk: ImednetSDK, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that list records.""" records = list(sdk.records.list(study_key=study_key)) assert isinstance(records, list) if records: @@ -82,7 +82,7 @@ def test_list_records(sdk: ImednetSDK, study_key: str) -> None: def test_list_intervals(sdk: ImednetSDK, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that list intervals.""" intervals = list(sdk.intervals.list(study_key=study_key)) assert isinstance(intervals, list) if intervals: @@ -92,7 +92,7 @@ def test_list_intervals(sdk: ImednetSDK, study_key: str) -> None: def test_list_visits(sdk: ImednetSDK, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that list visits.""" visits = list(sdk.visits.list(study_key=study_key)) assert isinstance(visits, list) if visits: @@ -102,7 +102,7 @@ def test_list_visits(sdk: ImednetSDK, study_key: str) -> None: def test_list_variables(sdk: ImednetSDK, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that list variables.""" variables = list(sdk.variables.list(study_key=study_key)) assert isinstance(variables, list) if variables: @@ -112,7 +112,7 @@ def test_list_variables(sdk: ImednetSDK, study_key: str) -> None: def test_list_users(sdk: ImednetSDK, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that list users.""" users = list(sdk.users.list(study_key=study_key)) assert isinstance(users, list) if users: @@ -122,7 +122,7 @@ def test_list_users(sdk: ImednetSDK, study_key: str) -> None: def test_list_queries(sdk: ImednetSDK, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that list queries.""" queries = list(sdk.queries.list(study_key=study_key)) assert isinstance(queries, list) if queries: @@ -132,7 +132,7 @@ def test_list_queries(sdk: ImednetSDK, study_key: str) -> None: def test_list_record_revisions(sdk: ImednetSDK, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that list record revisions.""" revisions = list(sdk.record_revisions.list(study_key=study_key)) assert isinstance(revisions, list) if revisions: @@ -142,7 +142,7 @@ def test_list_record_revisions(sdk: ImednetSDK, study_key: str) -> None: def test_job_get_known_batch(sdk: ImednetSDK, study_key: str, generated_batch_id: str) -> None: - """TODO: Add docstring.""" + """Test that job get known batch.""" job = sdk.jobs.get(study_key, generated_batch_id) assert job.batch_id == generated_batch_id @@ -157,7 +157,7 @@ def test_create_record_and_poll_job( study_key: str, record_payload: dict[str, Any], ) -> None: - """TODO: Add docstring.""" + """Test that create record and poll job.""" require_mutation() job = sdk.records.create(study_key, [record_payload]) if not job.batch_id: @@ -167,7 +167,7 @@ def test_create_record_and_poll_job( def test_list_codings(sdk: ImednetSDK, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that list codings.""" codings = list(sdk.codings.list(study_key=study_key)) assert isinstance(codings, list) if codings: diff --git a/tests/live/test_integrations_live.py b/tests/live/test_integrations_live.py index 4d5a5d5d..87b00fda 100644 --- a/tests/live/test_integrations_live.py +++ b/tests/live/test_integrations_live.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for integrations live.""" import pandas as pd import pytest @@ -8,14 +8,14 @@ def test_export_to_csv(sdk: ImednetSDK, study_key: str, tmp_path) -> None: - """TODO: Add docstring.""" + """Test that export to csv.""" p = tmp_path / "out.csv" export.export_to_csv(sdk, study_key, str(p)) assert p.exists() def test_export_to_excel(sdk: ImednetSDK, study_key: str, tmp_path) -> None: - """TODO: Add docstring.""" + """Test that export to excel.""" pytest.importorskip("openpyxl") p = tmp_path / "out.xlsx" export.export_to_excel(sdk, study_key, str(p)) @@ -23,14 +23,14 @@ def test_export_to_excel(sdk: ImednetSDK, study_key: str, tmp_path) -> None: def test_export_to_json(sdk: ImednetSDK, study_key: str, tmp_path) -> None: - """TODO: Add docstring.""" + """Test that export to json.""" p = tmp_path / "out.json" export.export_to_json(sdk, study_key, str(p)) assert p.exists() def test_export_to_parquet(sdk: ImednetSDK, study_key: str, tmp_path) -> None: - """TODO: Add docstring.""" + """Test that export to parquet.""" pytest.importorskip("pyarrow") p = tmp_path / "out.parquet" export.export_to_parquet(sdk, study_key, str(p)) @@ -40,7 +40,7 @@ def test_export_to_parquet(sdk: ImednetSDK, study_key: str, tmp_path) -> None: def test_export_to_sql_handles_column_limit( sdk: ImednetSDK, study_key: str, tmp_path, monkeypatch: pytest.MonkeyPatch ) -> None: - """TODO: Add docstring.""" + """Test that export to sql handles column limit.""" pytest.importorskip("sqlalchemy") from sqlalchemy import create_engine, inspect, text @@ -62,7 +62,7 @@ def test_export_to_sql_handles_column_limit( def test_imednet_hook() -> None: - """TODO: Add docstring.""" + """Test that imednet hook.""" pytest.importorskip("airflow") from apache_airflow_providers_imednet import ImednetHook @@ -72,7 +72,7 @@ def test_imednet_hook() -> None: def test_imednet_export_operator(study_key: str, tmp_path) -> None: - """TODO: Add docstring.""" + """Test that imednet export operator.""" pytest.importorskip("airflow") from apache_airflow_providers_imednet import ImednetExportOperator # type: ignore[attr-defined] @@ -81,7 +81,7 @@ def test_imednet_export_operator(study_key: str, tmp_path) -> None: def test_imednet_job_sensor(study_key: str) -> None: - """TODO: Add docstring.""" + """Test that imednet job sensor.""" pytest.importorskip("airflow") from apache_airflow_providers_imednet import ImednetJobSensor # type: ignore[attr-defined] diff --git a/tests/live/test_schema_validator_live.py b/tests/live/test_schema_validator_live.py index 1fb07e8b..12805d7a 100644 --- a/tests/live/test_schema_validator_live.py +++ b/tests/live/test_schema_validator_live.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for schema validator live.""" import pytest @@ -8,7 +8,7 @@ def _get_first_variable(sdk: ImednetSDK, study_key: str): - """TODO: Add docstring.""" + """Helper function to get first variable.""" variables = list(sdk.variables.list(study_key=study_key)) if not variables: pytest.skip("No variables available for live tests") @@ -16,7 +16,7 @@ def _get_first_variable(sdk: ImednetSDK, study_key: str): def _wrong_value(var_type: str): - """TODO: Add docstring.""" + """Helper function to wrong value.""" t = (var_type or "").lower() if t in {"text", "string"}: return 1 @@ -24,7 +24,7 @@ def _wrong_value(var_type: str): def test_validator_unknown_variable(sdk: ImednetSDK, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that validator unknown variable.""" var = _get_first_variable(sdk, study_key) validator = SchemaValidator(sdk) validator.refresh(study_key) @@ -40,7 +40,7 @@ def test_validator_unknown_variable(sdk: ImednetSDK, study_key: str) -> None: def test_validator_wrong_type(sdk: ImednetSDK, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that validator wrong type.""" var = _get_first_variable(sdk, study_key) validator = SchemaValidator(sdk) validator.refresh(study_key) diff --git a/tests/live/test_sdk_utilities_live.py b/tests/live/test_sdk_utilities_live.py index 49f6fd39..07468f2b 100644 --- a/tests/live/test_sdk_utilities_live.py +++ b/tests/live/test_sdk_utilities_live.py @@ -1,86 +1,86 @@ -"""TODO: Add docstring.""" +"""Unit tests for sdk utilities live.""" from imednet.sdk import ImednetSDK def test_get_studies(sdk: ImednetSDK) -> None: - """TODO: Add docstring.""" + """Test that get studies.""" assert sdk.get_studies() def test_get_records(sdk: ImednetSDK, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that get records.""" records = sdk.get_records(study_key) assert isinstance(records, list) def test_get_sites(sdk: ImednetSDK, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that get sites.""" sites = sdk.get_sites(study_key) assert isinstance(sites, list) def test_get_subjects(sdk: ImednetSDK, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that get subjects.""" subjects = sdk.get_subjects(study_key) assert isinstance(subjects, list) def test_get_forms(sdk: ImednetSDK, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that get forms.""" forms = sdk.get_forms(study_key) assert isinstance(forms, list) def test_get_intervals(sdk: ImednetSDK, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that get intervals.""" intervals = sdk.get_intervals(study_key) assert isinstance(intervals, list) def test_get_variables(sdk: ImednetSDK, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that get variables.""" vars_ = sdk.get_variables(study_key) assert isinstance(vars_, list) def test_get_visits(sdk: ImednetSDK, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that get visits.""" visits = sdk.get_visits(study_key) assert isinstance(visits, list) def test_get_codings(sdk: ImednetSDK, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that get codings.""" codings = sdk.get_codings(study_key) assert isinstance(codings, list) def test_get_queries(sdk: ImednetSDK, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that get queries.""" queries = sdk.get_queries(study_key) assert isinstance(queries, list) def test_get_record_revisions(sdk: ImednetSDK, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that get record revisions.""" revs = sdk.get_record_revisions(study_key) assert isinstance(revs, list) def test_get_users(sdk: ImednetSDK, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that get users.""" users = sdk.get_users(study_key) assert isinstance(users, list) def test_get_job(sdk: ImednetSDK, study_key: str, generated_batch_id: str) -> None: - """TODO: Add docstring.""" + """Test that get job.""" job = sdk.get_job(study_key, generated_batch_id) assert job.batch_id == generated_batch_id def test_poll_job(sdk: ImednetSDK, study_key: str, generated_batch_id: str) -> None: - """TODO: Add docstring.""" + """Test that poll job.""" job = sdk.poll_job(study_key, generated_batch_id, interval=1, timeout=60) assert job.batch_id == generated_batch_id diff --git a/tests/live/test_workflows_live.py b/tests/live/test_workflows_live.py index 70ce2dcf..b0e4cc9b 100644 --- a/tests/live/test_workflows_live.py +++ b/tests/live/test_workflows_live.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for workflows live.""" import pytest @@ -13,14 +13,14 @@ def test_get_study_structure(sdk: ImednetSDK, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that get study structure.""" structure = get_study_structure(sdk, study_key) assert structure.study_key == study_key @pytest.mark.asyncio(scope="session") async def test_async_get_study_structure(async_sdk: AsyncImednetSDK, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that async get study structure asynchronously.""" struct = await async_get_study_structure(async_sdk, study_key) assert struct.study_key == study_key @@ -28,7 +28,7 @@ async def test_async_get_study_structure(async_sdk: AsyncImednetSDK, study_key: def test_register_subjects_workflow( sdk: ImednetSDK, study_key: str, first_subject_key: str ) -> None: - """TODO: Add docstring.""" + """Test that register subjects workflow.""" require_mutation() forms = sdk.get_forms(study_key) sites = sdk.get_sites(study_key) @@ -44,27 +44,27 @@ def test_register_subjects_workflow( def test_extract_records_by_criteria(sdk: ImednetSDK, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that extract records by criteria.""" wf = sdk.workflows.data_extraction records = wf.extract_records_by_criteria(study_key) assert isinstance(records, list) def test_extract_audit_trail(sdk: ImednetSDK, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that extract audit trail.""" wf = sdk.workflows.data_extraction trail = wf.extract_audit_trail(study_key) assert isinstance(trail, list) def test_subject_data_workflow(sdk: ImednetSDK, study_key: str, first_subject_key: str) -> None: - """TODO: Add docstring.""" + """Test that subject data workflow.""" data = sdk.workflows.subject_data.get_all_subject_data(study_key, first_subject_key) assert data.subject_details is not None def test_query_management_open_queries(sdk: ImednetSDK, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that query management open queries.""" wf = sdk.workflows.query_management assert isinstance(wf.get_open_queries(study_key), list) @@ -72,14 +72,14 @@ def test_query_management_open_queries(sdk: ImednetSDK, study_key: str) -> None: def test_query_management_for_subject( sdk: ImednetSDK, study_key: str, first_subject_key: str ) -> None: - """TODO: Add docstring.""" + """Test that query management for subject.""" wf = sdk.workflows.query_management queries = wf.get_queries_for_subject(study_key, first_subject_key) assert isinstance(queries, list) def test_query_management_by_site(sdk: ImednetSDK, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that query management by site.""" wf = sdk.workflows.query_management sites = sdk.get_sites(study_key) if not sites: @@ -88,27 +88,27 @@ def test_query_management_by_site(sdk: ImednetSDK, study_key: str) -> None: def test_query_management_state_counts(sdk: ImednetSDK, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that query management state counts.""" wf = sdk.workflows.query_management counts = wf.get_query_state_counts(study_key) assert isinstance(counts, dict) def test_record_mapper_dataframe(sdk: ImednetSDK, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that record mapper dataframe.""" df = sdk.workflows.record_mapper.dataframe(study_key) assert hasattr(df, "columns") def test_record_update_submit_batch(sdk: ImednetSDK, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that record update submit batch.""" require_mutation() job = sdk.workflows.record_update.create_or_update_records(study_key, []) assert job.batch_id or not job.state or job.state.upper() in ("COMPLETED", "SUCCESS") def test_record_update_register_subject(sdk: ImednetSDK, study_key: str) -> None: - """TODO: Add docstring.""" + """Test that record update register subject.""" require_mutation() job = sdk.workflows.record_update.register_subject( study_key, @@ -123,7 +123,7 @@ def test_record_update_register_subject(sdk: ImednetSDK, study_key: str) -> None def test_record_update_update_scheduled( sdk: ImednetSDK, study_key: str, first_subject_key: str ) -> None: - """TODO: Add docstring.""" + """Test that record update update scheduled.""" require_mutation() job = sdk.workflows.record_update.update_scheduled_record( study_key, @@ -137,7 +137,7 @@ def test_record_update_update_scheduled( def test_record_update_create_new(sdk: ImednetSDK, study_key: str, first_subject_key: str) -> None: - """TODO: Add docstring.""" + """Test that record update create new.""" require_mutation() job = sdk.workflows.record_update.create_new_record( study_key, diff --git a/tests/test_mermaid_diagrams.py b/tests/test_mermaid_diagrams.py index c4badab1..7573377f 100644 --- a/tests/test_mermaid_diagrams.py +++ b/tests/test_mermaid_diagrams.py @@ -1,11 +1,11 @@ -"""TODO: Add docstring.""" +"""Unit tests for mermaid diagrams.""" import re from pathlib import Path def get_mermaid_lines(path: Path): - """TODO: Add docstring.""" + """Helper function to get mermaid lines.""" lines = [] inside = False skip_blank = False @@ -30,7 +30,7 @@ def get_mermaid_lines(path: Path): def test_no_unquoted_parentheses_in_mermaid_blocks(): - """TODO: Add docstring.""" + """Test that no unquoted parentheses in mermaid blocks.""" errors = [] for path in Path("docs").rglob("*.rst"): if "_build" in path.parts: diff --git a/tests/unit/architecture/test_architecture.py b/tests/unit/architecture/test_architecture.py index 1d67ae18..874457c6 100644 --- a/tests/unit/architecture/test_architecture.py +++ b/tests/unit/architecture/test_architecture.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for architecture.""" import ast from pathlib import Path @@ -16,12 +16,12 @@ def get_all_python_files(package_path: Path) -> list[Path]: - """TODO: Add docstring.""" + """Helper function to get all python files.""" return list(package_path.rglob("*.py")) def get_imports_from_file(file_path: Path) -> set[str]: - """TODO: Add docstring.""" + """Helper function to get imports from file.""" with open(file_path, "r", encoding="utf-8") as f: # We want SyntaxError to be raised if a file cannot be parsed, rather than silently ignored. tree = ast.parse(f.read(), filename=str(file_path)) @@ -59,7 +59,7 @@ def test_core_does_not_import_cli(): def test_core_does_not_import_workflows(): - """TODO: Add docstring.""" + """Test that core does not import workflows.""" core_dir = Path(imednet.__file__).parent files = get_all_python_files(core_dir) assert len(files) > 0, f"No files found to test in {core_dir}" @@ -74,7 +74,7 @@ def test_core_does_not_import_workflows(): def test_workflows_does_not_import_providers(): - """TODO: Add docstring.""" + """Test that workflows does not import providers.""" if imednet_workflows is None: pytest.skip("imednet_workflows not installed") @@ -122,7 +122,7 @@ def test_extensions_use_spi(): def test_endpoint_no_shared_mutable_state(): - """TODO: Add docstring.""" + """Test that endpoint no shared mutable state.""" sdk = ImednetSDK(api_key="1", security_key="2", base_url="http://x") assert sdk.records is not sdk.forms @@ -137,12 +137,12 @@ def test_endpoint_no_shared_mutable_state(): def test_sync_sdk_no_async_client(monkeypatch): - """TODO: Add docstring.""" + """Test that sync sdk no async client.""" instantiated = False original_init = AsyncClient.__init__ def mock_init(self, *args, **kwargs): - """TODO: Add docstring.""" + """Helper function to mock init.""" nonlocal instantiated instantiated = True original_init(self, *args, **kwargs) @@ -155,12 +155,12 @@ def mock_init(self, *args, **kwargs): def test_async_sdk_no_sync_client(monkeypatch): - """TODO: Add docstring.""" + """Test that async sdk no sync client.""" instantiated = False original_init = Client.__init__ def mock_init(self, *args, **kwargs): - """TODO: Add docstring.""" + """Helper function to mock init.""" nonlocal instantiated instantiated = True original_init(self, *args, **kwargs) @@ -172,7 +172,7 @@ def mock_init(self, *args, **kwargs): def test_plugin_discovery_failure(monkeypatch): - """TODO: Add docstring.""" + """Test that plugin discovery failure.""" monkeypatch.setattr("imednet.sdk.entry_points", lambda *, group, name: []) sdk = ImednetSDK(api_key="1", security_key="2", base_url="http://x") diff --git a/tests/unit/architecture/test_public_interface.py b/tests/unit/architecture/test_public_interface.py index bdc96721..fa2f4548 100644 --- a/tests/unit/architecture/test_public_interface.py +++ b/tests/unit/architecture/test_public_interface.py @@ -177,10 +177,10 @@ def test_sdk_convenience_mixin_uses_filter_value() -> None: from imednet.sdk_convenience import SDKConvenienceMixin class DummySDK(SDKConvenienceMixin): - """TODO: Add docstring.""" + """Test suite for DummySDK.""" def __init__(self): - """TODO: Add docstring.""" + """Initialize the test object.""" from unittest.mock import MagicMock self.records = MagicMock() diff --git a/tests/unit/async/test_async_client.py b/tests/unit/async/test_async_client.py index d6a4c9d2..d196f8b5 100644 --- a/tests/unit/async/test_async_client.py +++ b/tests/unit/async/test_async_client.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for async client.""" import httpx import pytest @@ -8,7 +8,7 @@ @pytest.mark.asyncio async def test_get_request(respx_mock): - """TODO: Add docstring.""" + """Test that get request asynchronously.""" client = AsyncClient("key", "secret", base_url="https://api.test") respx_mock.base_url = client.base_url respx_mock.get("/ping").mock(return_value=httpx.Response(200, json={"ok": True})) diff --git a/tests/unit/async/test_async_paginator.py b/tests/unit/async/test_async_paginator.py index 5e0230d0..5e64273c 100644 --- a/tests/unit/async/test_async_paginator.py +++ b/tests/unit/async/test_async_paginator.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for async paginator.""" import pytest @@ -6,15 +6,15 @@ class DummyAsyncClient: - """TODO: Add docstring.""" + """Test suite for DummyAsyncClient.""" def __init__(self, responses): - """TODO: Add docstring.""" + """Initialize the test object.""" self.responses = responses self.calls = [] async def get(self, path, params=None): - """TODO: Add docstring.""" + """Helper function to get.""" self.calls.append({"path": path, "params": params}) data = self.responses.pop(0) return type("Resp", (), {"json": lambda self, d=data: d})() @@ -22,7 +22,7 @@ async def get(self, path, params=None): @pytest.mark.asyncio async def test_iterates_pages(): - """TODO: Add docstring.""" + """Test that iterates pages asynchronously.""" client = DummyAsyncClient( [ {"data": [1], "pagination": {"totalPages": 2}}, diff --git a/tests/unit/cli/test_cli.py b/tests/unit/cli/test_cli.py index af36c4b0..961b3927 100644 --- a/tests/unit/cli/test_cli.py +++ b/tests/unit/cli/test_cli.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for cli.""" import importlib import importlib.util @@ -65,7 +65,7 @@ def env(monkeypatch: pytest.MonkeyPatch) -> None: @pytest.fixture() def runner() -> CliRunner: - """TODO: Add docstring.""" + """Helper function to runner.""" return CliRunner() @@ -79,7 +79,7 @@ def sdk(monkeypatch: pytest.MonkeyPatch) -> MagicMock: def test_missing_env_vars(runner: CliRunner, monkeypatch: pytest.MonkeyPatch) -> None: - """TODO: Add docstring.""" + """Test that missing env vars.""" monkeypatch.delenv("IMEDNET_API_KEY", raising=False) monkeypatch.delenv("IMEDNET_SECURITY_KEY", raising=False) result = runner.invoke(cli.app, ["studies", "list"]) @@ -88,7 +88,7 @@ def test_missing_env_vars(runner: CliRunner, monkeypatch: pytest.MonkeyPatch) -> def test_studies_list_success(runner: CliRunner, sdk: MagicMock) -> None: - """TODO: Add docstring.""" + """Test that studies list success.""" obj = MagicMock() obj.study_key = "study1" obj.study_name = "Study One" @@ -102,7 +102,7 @@ def test_studies_list_success(runner: CliRunner, sdk: MagicMock) -> None: def test_studies_list_api_error(runner: CliRunner, sdk: MagicMock) -> None: - """TODO: Add docstring.""" + """Test that studies list api error.""" sdk.studies.list.side_effect = ApiError("boom") result = runner.invoke(cli.app, ["studies", "list"]) assert result.exit_code == 1 @@ -110,7 +110,7 @@ def test_studies_list_api_error(runner: CliRunner, sdk: MagicMock) -> None: def test_sdk_closed_after_command(runner: CliRunner, sdk: MagicMock) -> None: - """TODO: Add docstring.""" + """Test that sdk closed after command.""" sdk.studies.list.return_value = [] result = runner.invoke(cli.app, ["studies", "list"]) assert result.exit_code == 0 @@ -118,7 +118,7 @@ def test_sdk_closed_after_command(runner: CliRunner, sdk: MagicMock) -> None: def test_multiple_invocations_close_sdk(runner: CliRunner, sdk: MagicMock) -> None: - """TODO: Add docstring.""" + """Test that multiple invocations close sdk.""" sdk.studies.list.return_value = [] first = runner.invoke(cli.app, ["studies", "list"]) second = runner.invoke(cli.app, ["studies", "list"]) @@ -127,7 +127,7 @@ def test_multiple_invocations_close_sdk(runner: CliRunner, sdk: MagicMock) -> No def test_sites_list_success(runner: CliRunner, sdk: MagicMock) -> None: - """TODO: Add docstring.""" + """Test that sites list success.""" obj = MagicMock() obj.site_id = "site1" obj.site_name = "Site One" @@ -140,13 +140,13 @@ def test_sites_list_success(runner: CliRunner, sdk: MagicMock) -> None: def test_sites_list_missing_argument(runner: CliRunner) -> None: - """TODO: Add docstring.""" + """Test that sites list missing argument.""" result = runner.invoke(cli.app, ["sites", "list"]) assert result.exit_code != 0 def test_sites_list_api_error(runner: CliRunner, sdk: MagicMock) -> None: - """TODO: Add docstring.""" + """Test that sites list api error.""" sdk.sites.list.side_effect = ApiError("fail") result = runner.invoke(cli.app, ["sites", "list", "STUDY"]) assert result.exit_code == 1 @@ -154,7 +154,7 @@ def test_sites_list_api_error(runner: CliRunner, sdk: MagicMock) -> None: def test_subjects_list_success(runner: CliRunner, sdk: MagicMock) -> None: - """TODO: Add docstring.""" + """Test that subjects list success.""" mock_subject = MagicMock() mock_subject.subject_key = "S1" mock_subject.subject_status = "Screened" @@ -174,7 +174,7 @@ def test_subjects_list_success(runner: CliRunner, sdk: MagicMock) -> None: def test_subjects_list_invalid_filter(runner: CliRunner, sdk: MagicMock) -> None: - """TODO: Add docstring.""" + """Test that subjects list invalid filter.""" result = runner.invoke(cli.app, ["subjects", "list", "STUDY", "--filter", "badfilter"]) assert result.exit_code == 1 assert "Invalid filter format" in result.stdout @@ -182,7 +182,7 @@ def test_subjects_list_invalid_filter(runner: CliRunner, sdk: MagicMock) -> None def test_subjects_list_api_error(runner: CliRunner, sdk: MagicMock) -> None: - """TODO: Add docstring.""" + """Test that subjects list api error.""" sdk.subjects.list.side_effect = ApiError("boom") result = runner.invoke(cli.app, ["subjects", "list", "STUDY"]) assert result.exit_code == 1 @@ -192,7 +192,7 @@ def test_subjects_list_api_error(runner: CliRunner, sdk: MagicMock) -> None: def test_extract_records_calls_workflow( runner: CliRunner, sdk: MagicMock, monkeypatch: pytest.MonkeyPatch ) -> None: - """TODO: Add docstring.""" + """Test that extract records calls workflow.""" workflow = MagicMock() monkeypatch.setattr( "imednet_workflows.cli.DataExtractionWorkflow", MagicMock(return_value=workflow) @@ -226,7 +226,7 @@ def test_extract_records_api_error( def test_records_list_success(runner: CliRunner, sdk: MagicMock) -> None: - """TODO: Add docstring.""" + """Test that records list success.""" rec = MagicMock() rec.record_id = 1 rec.subject_key = "S1" @@ -243,7 +243,7 @@ def test_records_list_success(runner: CliRunner, sdk: MagicMock) -> None: def test_records_list_output_csv( runner: CliRunner, sdk: MagicMock, monkeypatch: pytest.MonkeyPatch, tmp_path: Path ) -> None: - """TODO: Add docstring.""" + """Test that records list output csv.""" rec = MagicMock() rec.model_dump.return_value = {"recordId": 1} sdk.records.list.return_value = [rec] @@ -257,7 +257,7 @@ def test_records_list_output_csv( def test_records_list_output_json( runner: CliRunner, sdk: MagicMock, monkeypatch: pytest.MonkeyPatch, tmp_path: Path ) -> None: - """TODO: Add docstring.""" + """Test that records list output json.""" rec = MagicMock() rec.model_dump.return_value = {"recordId": 1} sdk.records.list.return_value = [rec] @@ -269,7 +269,7 @@ def test_records_list_output_json( def test_records_list_no_records(runner: CliRunner, sdk: MagicMock) -> None: - """TODO: Add docstring.""" + """Test that records list no records.""" sdk.records.list.return_value = [] result = runner.invoke(cli.app, ["records", "list", "STUDY"]) assert result.exit_code == 0 @@ -278,7 +278,7 @@ def test_records_list_no_records(runner: CliRunner, sdk: MagicMock) -> None: def test_records_list_invalid_output(runner: CliRunner, sdk: MagicMock) -> None: - """TODO: Add docstring.""" + """Test that records list invalid output.""" result = runner.invoke(cli.app, ["records", "list", "STUDY", "--output", "txt"]) assert result.exit_code == 1 assert "Invalid output format" in result.stdout @@ -286,7 +286,7 @@ def test_records_list_invalid_output(runner: CliRunner, sdk: MagicMock) -> None: def test_records_list_api_error(runner: CliRunner, sdk: MagicMock) -> None: - """TODO: Add docstring.""" + """Test that records list api error.""" sdk.records.list.side_effect = ApiError("oops") result = runner.invoke(cli.app, ["records", "list", "STUDY"]) assert result.exit_code == 1 @@ -296,7 +296,7 @@ def test_records_list_api_error(runner: CliRunner, sdk: MagicMock) -> None: def test_export_parquet_calls_helper( runner: CliRunner, sdk: MagicMock, monkeypatch: pytest.MonkeyPatch ) -> None: - """TODO: Add docstring.""" + """Test that export parquet calls helper.""" func = MagicMock() monkeypatch.setattr(export_mod, "export_to_parquet", func) monkeypatch.setattr(cli, "export_to_parquet", export_mod.export_to_parquet) @@ -309,7 +309,7 @@ def test_export_parquet_calls_helper( def test_export_csv_calls_helper( runner: CliRunner, sdk: MagicMock, monkeypatch: pytest.MonkeyPatch ) -> None: - """TODO: Add docstring.""" + """Test that export csv calls helper.""" func = MagicMock() monkeypatch.setattr(export_mod, "export_to_csv", func) monkeypatch.setattr(cli, "export_to_csv", export_mod.export_to_csv) @@ -321,7 +321,7 @@ def test_export_csv_calls_helper( def test_export_excel_calls_helper( runner: CliRunner, sdk: MagicMock, monkeypatch: pytest.MonkeyPatch ) -> None: - """TODO: Add docstring.""" + """Test that export excel calls helper.""" func = MagicMock() monkeypatch.setattr(export_mod, "export_to_excel", func) monkeypatch.setattr(cli, "export_to_excel", export_mod.export_to_excel) @@ -333,7 +333,7 @@ def test_export_excel_calls_helper( def test_export_json_calls_helper( runner: CliRunner, sdk: MagicMock, monkeypatch: pytest.MonkeyPatch ) -> None: - """TODO: Add docstring.""" + """Test that export json calls helper.""" func = MagicMock() monkeypatch.setattr(export_mod, "export_to_json", func) monkeypatch.setattr(cli, "export_to_json", export_mod.export_to_json) @@ -345,7 +345,7 @@ def test_export_json_calls_helper( def test_export_duckdb_calls_helper( runner: CliRunner, sdk: MagicMock, monkeypatch: pytest.MonkeyPatch ) -> None: - """TODO: Add docstring.""" + """Test that export duckdb calls helper.""" func = MagicMock() monkeypatch.setattr(export_mod, "export_to_duckdb", func) monkeypatch.setattr(cli, "export_to_duckdb", export_mod.export_to_duckdb) @@ -378,7 +378,7 @@ def test_export_duckdb_calls_helper( def test_export_duckdb_help(runner: CliRunner) -> None: - """TODO: Add docstring.""" + """Test that export duckdb help.""" result = runner.invoke(cli.app, ["export", "duckdb", "--help"]) assert result.exit_code == 0 assert "The key identifying the study" in result.stdout @@ -392,7 +392,7 @@ def test_export_duckdb_help(runner: CliRunner) -> None: def test_export_sql_calls_helper_non_sqlite( runner: CliRunner, sdk: MagicMock, monkeypatch: pytest.MonkeyPatch ) -> None: - """TODO: Add docstring.""" + """Test that export sql calls helper non sqlite.""" func = MagicMock() form_func = MagicMock() monkeypatch.setattr(export_mod, "export_to_sql", func) @@ -433,7 +433,7 @@ def test_export_sql_calls_helper_non_sqlite( def test_export_sql_sqlite_uses_by_form( runner: CliRunner, sdk: MagicMock, monkeypatch: pytest.MonkeyPatch ) -> None: - """TODO: Add docstring.""" + """Test that export sql sqlite uses by form.""" form_func = MagicMock() sql_func = MagicMock() monkeypatch.setattr(export_mod, "export_to_sql_by_form", form_func) @@ -473,7 +473,7 @@ def test_export_sql_sqlite_uses_by_form( def test_export_sql_sqlite_single_table( runner: CliRunner, sdk: MagicMock, monkeypatch: pytest.MonkeyPatch ) -> None: - """TODO: Add docstring.""" + """Test that export sql sqlite single table.""" form_func = MagicMock() single = ["--single-table"] sql_func = MagicMock() @@ -517,7 +517,7 @@ def test_export_sql_sqlite_single_table( def test_export_sql_long_format( runner: CliRunner, sdk: MagicMock, monkeypatch: pytest.MonkeyPatch ) -> None: - """TODO: Add docstring.""" + """Test that export sql long format.""" long_func = MagicMock() form_func = MagicMock() sql_func = MagicMock() @@ -546,7 +546,7 @@ def test_export_sql_long_format( def test_export_sql_long_format_overrides_single( runner: CliRunner, sdk: MagicMock, monkeypatch: pytest.MonkeyPatch ) -> None: - """TODO: Add docstring.""" + """Test that export sql long format overrides single.""" long_func = MagicMock() form_func = MagicMock() sql_func = MagicMock() @@ -581,11 +581,11 @@ def test_export_sql_long_format_overrides_single( def test_export_parquet_missing_pyarrow(runner: CliRunner, monkeypatch: pytest.MonkeyPatch) -> None: - """TODO: Add docstring.""" + """Test that export parquet missing pyarrow.""" original_find_spec = importlib.util.find_spec def fake_find_spec(name: str) -> object | None: - """TODO: Add docstring.""" + """Helper function to fake find spec.""" if name == "pyarrow": return None return original_find_spec(name) @@ -597,11 +597,11 @@ def fake_find_spec(name: str) -> object | None: def test_export_sql_missing_sqlalchemy(runner: CliRunner, monkeypatch: pytest.MonkeyPatch) -> None: - """TODO: Add docstring.""" + """Test that export sql missing sqlalchemy.""" original_find_spec = importlib.util.find_spec def fake_find_spec(name: str) -> object | None: - """TODO: Add docstring.""" + """Helper function to fake find spec.""" if name == "sqlalchemy": return None return original_find_spec(name) @@ -618,11 +618,11 @@ def fake_find_spec(name: str) -> object | None: def test_export_duckdb_missing_dependency( runner: CliRunner, monkeypatch: pytest.MonkeyPatch ) -> None: - """TODO: Add docstring.""" + """Test that export duckdb missing dependency.""" original_find_spec = importlib.util.find_spec def fake_find_spec(name: str) -> object | None: - """TODO: Add docstring.""" + """Helper function to fake find spec.""" if name == "duckdb": return None return original_find_spec(name) @@ -639,7 +639,7 @@ def fake_find_spec(name: str) -> object | None: def test_subject_data_calls_workflow( runner: CliRunner, sdk: MagicMock, monkeypatch: pytest.MonkeyPatch ) -> None: - """TODO: Add docstring.""" + """Test that subject data calls workflow.""" workflow = MagicMock() monkeypatch.setattr( "imednet_workflows.cli.SubjectDataWorkflow", MagicMock(return_value=workflow) @@ -653,7 +653,7 @@ def test_subject_data_calls_workflow( def test_sync_worker_once_command( runner: CliRunner, sdk: MagicMock, monkeypatch: pytest.MonkeyPatch ) -> None: - """TODO: Add docstring.""" + """Test that sync worker once command.""" worker = MagicMock() worker.run_once.return_value = 42 loader_cls = MagicMock() @@ -671,7 +671,7 @@ def test_sync_worker_once_command( def test_sync_worker_command_handles_keyboard_interrupt( runner: CliRunner, sdk: MagicMock, monkeypatch: pytest.MonkeyPatch ) -> None: - """TODO: Add docstring.""" + """Test that sync worker command handles keyboard interrupt.""" worker = MagicMock() worker.run_forever.side_effect = KeyboardInterrupt() loader_cls = MagicMock() @@ -687,7 +687,7 @@ def test_sync_worker_command_handles_keyboard_interrupt( def test_queries_list_success(runner: CliRunner, sdk: MagicMock) -> None: - """TODO: Add docstring.""" + """Test that queries list success.""" obj = MagicMock() obj.description = "Q1" obj.annotation_type = "Query" @@ -703,7 +703,7 @@ def test_queries_list_success(runner: CliRunner, sdk: MagicMock) -> None: def test_queries_list_empty(runner: CliRunner, sdk: MagicMock) -> None: - """TODO: Add docstring.""" + """Test that queries list empty.""" sdk.queries.list.return_value = [] result = runner.invoke(cli.app, ["queries", "list", "STUDY"]) assert result.exit_code == 0 @@ -711,7 +711,7 @@ def test_queries_list_empty(runner: CliRunner, sdk: MagicMock) -> None: def test_variables_list_success(runner: CliRunner, sdk: MagicMock) -> None: - """TODO: Add docstring.""" + """Test that variables list success.""" obj = MagicMock() obj.variable_name = "V1" obj.label = "Var 1" @@ -727,7 +727,7 @@ def test_variables_list_success(runner: CliRunner, sdk: MagicMock) -> None: def test_variables_list_empty(runner: CliRunner, sdk: MagicMock) -> None: - """TODO: Add docstring.""" + """Test that variables list empty.""" sdk.variables.list.return_value = [] result = runner.invoke(cli.app, ["variables", "list", "STUDY"]) assert result.exit_code == 0 @@ -735,7 +735,7 @@ def test_variables_list_empty(runner: CliRunner, sdk: MagicMock) -> None: def test_record_revisions_list_success(runner: CliRunner, sdk: MagicMock) -> None: - """TODO: Add docstring.""" + """Test that record revisions list success.""" sdk.record_revisions.list.return_value = ["R1"] result = runner.invoke(cli.app, ["record-revisions", "list", "STUDY"]) assert result.exit_code == 0 @@ -745,7 +745,7 @@ def test_record_revisions_list_success(runner: CliRunner, sdk: MagicMock) -> Non def test_record_revisions_list_empty(runner: CliRunner, sdk: MagicMock) -> None: - """TODO: Add docstring.""" + """Test that record revisions list empty.""" sdk.record_revisions.list.return_value = [] result = runner.invoke(cli.app, ["record-revisions", "list", "STUDY"]) assert result.exit_code == 0 @@ -753,21 +753,21 @@ def test_record_revisions_list_empty(runner: CliRunner, sdk: MagicMock) -> None: def test_jobs_status_success(runner: CliRunner, sdk: MagicMock) -> None: - """TODO: Add docstring.""" + """Test that jobs status success.""" result = runner.invoke(cli.app, ["jobs", "status", "STUDY", "BATCH"]) assert result.exit_code == 0 sdk.get_job.assert_called_once_with("STUDY", "BATCH") def test_jobs_wait_success(runner: CliRunner, sdk: MagicMock) -> None: - """TODO: Add docstring.""" + """Test that jobs wait success.""" result = runner.invoke(cli.app, ["jobs", "wait", "STUDY", "BATCH"]) assert result.exit_code == 0 sdk.poll_job.assert_called_once_with("STUDY", "BATCH", interval=5, timeout=300) def test_intervals_list_success(runner: CliRunner, sdk: MagicMock) -> None: - """TODO: Add docstring.""" + """Test that intervals list success.""" obj = MagicMock() obj.interval_id = 1 obj.interval_name = "Baseline" @@ -781,7 +781,7 @@ def test_intervals_list_success(runner: CliRunner, sdk: MagicMock) -> None: def test_intervals_list_empty(runner: CliRunner, sdk: MagicMock) -> None: - """TODO: Add docstring.""" + """Test that intervals list empty.""" sdk.intervals.list.return_value = [] result = runner.invoke(cli.app, ["intervals", "list", "STUDY"]) assert result.exit_code == 0 diff --git a/tests/unit/cli/test_cli_export.py b/tests/unit/cli/test_cli_export.py index f3fb9429..cff6fba7 100644 --- a/tests/unit/cli/test_cli_export.py +++ b/tests/unit/cli/test_cli_export.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for cli export.""" import importlib.util from unittest.mock import ANY, MagicMock @@ -46,20 +46,20 @@ def invoke(self, app, args): @pytest.fixture(autouse=True) def env(monkeypatch: pytest.MonkeyPatch) -> None: - """TODO: Add docstring.""" + """Helper function to env.""" monkeypatch.setenv("IMEDNET_API_KEY", "key") monkeypatch.setenv("IMEDNET_SECURITY_KEY", "secret") @pytest.fixture() def runner() -> CliRunner: - """TODO: Add docstring.""" + """Helper function to runner.""" return CliRunner() @pytest.fixture() def sdk(monkeypatch: pytest.MonkeyPatch) -> MagicMock: - """TODO: Add docstring.""" + """Helper function to sdk.""" mock_sdk = MagicMock() monkeypatch.setattr("imednet.cli.utils.context.get_sdk", MagicMock(return_value=mock_sdk)) return mock_sdk @@ -68,7 +68,7 @@ def sdk(monkeypatch: pytest.MonkeyPatch) -> MagicMock: def test_cli_export_duckdb_happy_path( runner: CliRunner, sdk: MagicMock, monkeypatch: pytest.MonkeyPatch ) -> None: - """TODO: Add docstring.""" + """Test that cli export duckdb happy path.""" func = MagicMock() monkeypatch.setattr(export_mod, "export_to_duckdb", func) monkeypatch.setattr(cli, "export_to_duckdb", export_mod.export_to_duckdb) @@ -94,11 +94,11 @@ def test_cli_export_duckdb_happy_path( def test_cli_export_duckdb_missing_dependency( runner: CliRunner, monkeypatch: pytest.MonkeyPatch ) -> None: - """TODO: Add docstring.""" + """Test that cli export duckdb missing dependency.""" original_find_spec = importlib.util.find_spec def fake_find_spec(name: str) -> object | None: - """TODO: Add docstring.""" + """Helper function to fake find spec.""" if name == "duckdb": return None return original_find_spec(name) @@ -117,7 +117,7 @@ def fake_find_spec(name: str) -> object | None: def test_cli_export_duckdb_vars_forms_passthrough( runner: CliRunner, sdk: MagicMock, monkeypatch: pytest.MonkeyPatch ) -> None: - """TODO: Add docstring.""" + """Test that cli export duckdb vars forms passthrough.""" func = MagicMock() monkeypatch.setattr(export_mod, "export_to_duckdb", func) monkeypatch.setattr(cli, "export_to_duckdb", export_mod.export_to_duckdb) @@ -153,7 +153,7 @@ def test_cli_export_duckdb_vars_forms_passthrough( def test_cli_export_mongodb_happy_path( runner: CliRunner, sdk: MagicMock, monkeypatch: pytest.MonkeyPatch ) -> None: - """TODO: Add docstring.""" + """Test that cli export mongodb happy path.""" monkeypatch.setattr(importlib.util, "find_spec", lambda _name: object()) result = runner.invoke( @@ -185,11 +185,11 @@ def test_cli_export_mongodb_happy_path( def test_cli_export_mongodb_missing_dependency( runner: CliRunner, monkeypatch: pytest.MonkeyPatch ) -> None: - """TODO: Add docstring.""" + """Test that cli export mongodb missing dependency.""" original_find_spec = importlib.util.find_spec def fake_find_spec(name: str) -> object | None: - """TODO: Add docstring.""" + """Helper function to fake find spec.""" if name == "pymongo": return None return original_find_spec(name) @@ -207,7 +207,7 @@ def fake_find_spec(name: str) -> object | None: def test_cli_export_neo4j_happy_path( runner: CliRunner, sdk: MagicMock, monkeypatch: pytest.MonkeyPatch ) -> None: - """TODO: Add docstring.""" + """Test that cli export neo4j happy path.""" sdk.sinks.Neo4jSinkConfig = Neo4jSinkConfig monkeypatch.setattr(importlib.util, "find_spec", lambda _name: object()) @@ -241,11 +241,11 @@ def test_cli_export_neo4j_happy_path( def test_cli_export_neo4j_missing_dependency( runner: CliRunner, monkeypatch: pytest.MonkeyPatch ) -> None: - """TODO: Add docstring.""" + """Test that cli export neo4j missing dependency.""" original_find_spec = importlib.util.find_spec def fake_find_spec(name: str) -> object | None: - """TODO: Add docstring.""" + """Helper function to fake find spec.""" if name == "neo4j": return None return original_find_spec(name) @@ -263,7 +263,7 @@ def fake_find_spec(name: str) -> object | None: def test_cli_export_snowflake_happy_path( runner: CliRunner, sdk: MagicMock, monkeypatch: pytest.MonkeyPatch ) -> None: - """TODO: Add docstring.""" + """Test that cli export snowflake happy path.""" sdk.sinks.SnowflakeSinkConfig = SnowflakeSinkConfig monkeypatch.setattr(importlib.util, "find_spec", lambda _name: object()) @@ -312,11 +312,11 @@ def test_cli_export_snowflake_happy_path( def test_cli_export_snowflake_missing_dependency( runner: CliRunner, monkeypatch: pytest.MonkeyPatch ) -> None: - """TODO: Add docstring.""" + """Test that cli export snowflake missing dependency.""" original_find_spec = importlib.util.find_spec def fake_find_spec(name: str) -> object | None: - """TODO: Add docstring.""" + """Helper function to fake find spec.""" if name == "snowflake.connector": return None return original_find_spec(name) diff --git a/tests/unit/cli/test_csv_injection.py b/tests/unit/cli/test_csv_injection.py index 5c523eb7..d483f934 100644 --- a/tests/unit/cli/test_csv_injection.py +++ b/tests/unit/cli/test_csv_injection.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for csv injection.""" from pathlib import Path from unittest.mock import MagicMock @@ -42,13 +42,13 @@ def invoke(self, app, args): @pytest.fixture() def runner() -> CliRunner: - """TODO: Add docstring.""" + """Helper function to runner.""" return CliRunner() @pytest.fixture() def sdk(monkeypatch: pytest.MonkeyPatch) -> MagicMock: - """TODO: Add docstring.""" + """Helper function to sdk.""" mock_sdk = MagicMock() monkeypatch.setattr("imednet.cli.utils.context.get_sdk", MagicMock(return_value=mock_sdk)) return mock_sdk @@ -57,7 +57,7 @@ def sdk(monkeypatch: pytest.MonkeyPatch) -> MagicMock: def test_records_list_output_csv_injection_prevention( runner: CliRunner, sdk: MagicMock, monkeypatch: pytest.MonkeyPatch, tmp_path: Path ) -> None: - """TODO: Add docstring.""" + """Test that records list output csv injection prevention.""" rec = MagicMock() # Malicious payload and normal payload rec.model_dump.return_value = {"recordId": 1, "note": "=cmd|' /C calc'!A0", "normal": "hello"} diff --git a/tests/unit/cli/test_dashboard_command.py b/tests/unit/cli/test_dashboard_command.py index 22dbfedc..6f41f638 100644 --- a/tests/unit/cli/test_dashboard_command.py +++ b/tests/unit/cli/test_dashboard_command.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for dashboard command.""" from __future__ import annotations @@ -46,13 +46,13 @@ def invoke(self, app, args): @pytest.fixture() def runner() -> CliRunner: - """TODO: Add docstring.""" + """Helper function to runner.""" return CliRunner() @pytest.fixture() def cli_module() -> ModuleType: - """TODO: Add docstring.""" + """Helper function to cli module.""" import imednet.cli as cli importlib.reload(cli) @@ -63,11 +63,11 @@ def cli_module() -> ModuleType: def test_dashboard_command_falls_back_when_plugin_missing( runner: CliRunner, cli_module: ModuleType, monkeypatch: pytest.MonkeyPatch ) -> None: - """TODO: Add docstring.""" + """Test that dashboard command falls back when plugin missing.""" real_find_spec = importlib.util.find_spec def fake_find_spec(name: str, package: str | None = None) -> object | None: - """TODO: Add docstring.""" + """Helper function to fake find spec.""" if name in ("imednet_streamlit.app", "imednet_streamlit"): return None return real_find_spec(name, package) @@ -87,12 +87,12 @@ def fake_find_spec(name: str, package: str | None = None) -> object | None: def test_dashboard_command_runs_streamlit_when_plugin_present( runner: CliRunner, cli_module: ModuleType, monkeypatch: pytest.MonkeyPatch ) -> None: - """TODO: Add docstring.""" + """Test that dashboard command runs streamlit when plugin present.""" real_find_spec = importlib.util.find_spec dashboard_spec = MagicMock(origin=FAKE_DASHBOARD_PATH) def fake_find_spec(name: str, package: str | None = None) -> object | None: - """TODO: Add docstring.""" + """Helper function to fake find spec.""" if name in ("imednet_streamlit.app", "imednet_streamlit"): return dashboard_spec return real_find_spec(name, package) @@ -130,12 +130,12 @@ def fake_find_spec(name: str, package: str | None = None) -> object | None: def test_dashboard_command_uses_default_options( runner: CliRunner, cli_module: ModuleType, monkeypatch: pytest.MonkeyPatch ) -> None: - """TODO: Add docstring.""" + """Test that dashboard command uses default options.""" real_find_spec = importlib.util.find_spec dashboard_spec = MagicMock(origin=FAKE_DASHBOARD_PATH) def fake_find_spec(name: str, package: str | None = None) -> object | None: - """TODO: Add docstring.""" + """Helper function to fake find spec.""" if name in ("imednet_streamlit.app", "imednet_streamlit"): return dashboard_spec return real_find_spec(name, package) @@ -165,12 +165,12 @@ def fake_find_spec(name: str, package: str | None = None) -> object | None: def test_dashboard_command_fails_when_app_path_missing( runner: CliRunner, cli_module: ModuleType, monkeypatch: pytest.MonkeyPatch ) -> None: - """TODO: Add docstring.""" + """Test that dashboard command fails when app path missing.""" real_find_spec = importlib.util.find_spec dashboard_spec = MagicMock(origin=None) def fake_find_spec(name: str, package: str | None = None) -> object | None: - """TODO: Add docstring.""" + """Helper function to fake find spec.""" if name in ("imednet_streamlit.app", "imednet_streamlit"): return dashboard_spec return real_find_spec(name, package) @@ -186,12 +186,12 @@ def fake_find_spec(name: str, package: str | None = None) -> object | None: def test_dashboard_command_propagates_streamlit_failure( runner: CliRunner, cli_module: ModuleType, monkeypatch: pytest.MonkeyPatch ) -> None: - """TODO: Add docstring.""" + """Test that dashboard command propagates streamlit failure.""" real_find_spec = importlib.util.find_spec dashboard_spec = MagicMock(origin=FAKE_DASHBOARD_PATH) def fake_find_spec(name: str, package: str | None = None) -> object | None: - """TODO: Add docstring.""" + """Helper function to fake find spec.""" if name in ("imednet_streamlit.app", "imednet_streamlit"): return dashboard_spec return real_find_spec(name, package) @@ -210,12 +210,12 @@ def fake_find_spec(name: str, package: str | None = None) -> object | None: def test_dashboard_command_handles_subprocess_oserror( runner: CliRunner, cli_module: ModuleType, monkeypatch: pytest.MonkeyPatch ) -> None: - """TODO: Add docstring.""" + """Test that dashboard command handles subprocess oserror.""" real_find_spec = importlib.util.find_spec dashboard_spec = MagicMock(origin=FAKE_DASHBOARD_PATH) def fake_find_spec(name: str, package: str | None = None) -> object | None: - """TODO: Add docstring.""" + """Helper function to fake find spec.""" if name in ("imednet_streamlit.app", "imednet_streamlit"): return dashboard_spec return real_find_spec(name, package) diff --git a/tests/unit/cli/test_decorators.py b/tests/unit/cli/test_decorators.py index cd76eb8a..6b5ef2fb 100644 --- a/tests/unit/cli/test_decorators.py +++ b/tests/unit/cli/test_decorators.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for decorators.""" from unittest.mock import MagicMock @@ -40,7 +40,7 @@ def invoke(self, app, args): def test_decorator_handles_unexpected_error(monkeypatch: pytest.MonkeyPatch) -> None: - """TODO: Add docstring.""" + """Test that decorator handles unexpected error.""" runner = CliRunner() monkeypatch.setenv("IMEDNET_API_KEY", "k") monkeypatch.setenv("IMEDNET_SECURITY_KEY", "s") diff --git a/tests/unit/cli/test_parse_filters.py b/tests/unit/cli/test_parse_filters.py index 90296d39..67d5e1cc 100644 --- a/tests/unit/cli/test_parse_filters.py +++ b/tests/unit/cli/test_parse_filters.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for parse filters.""" import pytest import typer @@ -7,25 +7,25 @@ def test_parse_filter_args_none(): - """TODO: Add docstring.""" + """Test that parse filter args none.""" assert parse_filter_args(None) is None def test_parse_filter_args_types(): - """TODO: Add docstring.""" + """Test that parse filter args types.""" result = parse_filter_args(["a=1", "b=true", "c=no", "d=text"]) assert result == {"a": 1, "b": True, "c": "no", "d": "text"} def test_parse_filter_args_invalid(): - """TODO: Add docstring.""" + """Test that parse filter args invalid.""" with pytest.raises(SystemExit) as exc_info: parse_filter_args(["bad"]) assert exc_info.value.code == 1 def test_parse_filter_args_invalid_escaped(capfd: pytest.CaptureFixture[str]): - """TODO: Add docstring.""" + """Test that parse filter args invalid escaped.""" with pytest.raises(SystemExit) as exc_info: parse_filter_args(["[red]bad[/red]"]) assert exc_info.value.code == 1 diff --git a/tests/unit/cli/test_utils_output.py b/tests/unit/cli/test_utils_output.py index c5e3f573..8256699d 100644 --- a/tests/unit/cli/test_utils_output.py +++ b/tests/unit/cli/test_utils_output.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for utils output.""" from unittest.mock import MagicMock, patch diff --git a/tests/unit/cli/test_workflows_state_cli.py b/tests/unit/cli/test_workflows_state_cli.py index f90f474a..5341e896 100644 --- a/tests/unit/cli/test_workflows_state_cli.py +++ b/tests/unit/cli/test_workflows_state_cli.py @@ -45,12 +45,12 @@ def invoke(self, app, args): @pytest.fixture() def runner() -> CliRunner: - """TODO: Add docstring.""" + """Helper function to runner.""" return CliRunner() def _make_ledger_state(study_key: str, stream_name: str) -> LedgerState: - """TODO: Add docstring.""" + """Helper function to make ledger state.""" ts = datetime(2026, 5, 22, 12, 0, 0, tzinfo=timezone.utc) return LedgerState( studies={ @@ -68,10 +68,10 @@ def _make_ledger_state(study_key: str, stream_name: str) -> LedgerState: class TestShowState: - """TODO: Add docstring.""" + """Test suite for ShowState.""" def test_show_all_entries(self, runner: CliRunner, tmp_path) -> None: - """TODO: Add docstring.""" + """Test that show all entries.""" ledger_path = str(tmp_path / "ledger.json") state = _make_ledger_state("STUDY-01", "records") with patch("imednet_workflows.cli.ExtractionStateLedger") as mock_ledger: @@ -81,7 +81,7 @@ def test_show_all_entries(self, runner: CliRunner, tmp_path) -> None: assert result.exit_code == 0 def test_show_filters_by_study_key(self, runner: CliRunner, tmp_path) -> None: - """TODO: Add docstring.""" + """Test that show filters by study key.""" ledger_path = str(tmp_path / "ledger.json") state = _make_ledger_state("STUDY-01", "records") with patch("imednet_workflows.cli.ExtractionStateLedger") as mock_ledger: @@ -94,7 +94,7 @@ def test_show_filters_by_study_key(self, runner: CliRunner, tmp_path) -> None: assert result.exit_code == 0 def test_show_no_matching_entries_prints_warning(self, runner: CliRunner, tmp_path) -> None: - """TODO: Add docstring.""" + """Test that show no matching entries prints warning.""" ledger_path = str(tmp_path / "ledger.json") with patch("imednet_workflows.cli.ExtractionStateLedger") as mock_ledger: mock_ledger.return_value.read_state.return_value = LedgerState() @@ -104,7 +104,7 @@ def test_show_no_matching_entries_prints_warning(self, runner: CliRunner, tmp_pa assert "No ledger entries" in result.output def test_show_error_on_read_failure(self, runner: CliRunner, tmp_path) -> None: - """TODO: Add docstring.""" + """Test that show error on read failure.""" ledger_path = str(tmp_path / "ledger.json") with patch("imednet_workflows.cli.ExtractionStateLedger") as mock_ledger: mock_ledger.return_value.read_state.side_effect = OSError("cannot read") @@ -114,10 +114,10 @@ def test_show_error_on_read_failure(self, runner: CliRunner, tmp_path) -> None: class TestSetState: - """TODO: Add docstring.""" + """Test suite for SetState.""" def test_set_valid_utc_timestamp(self, runner: CliRunner, tmp_path) -> None: - """TODO: Add docstring.""" + """Test that set valid utc timestamp.""" ledger_path = str(tmp_path / "ledger.json") with patch("imednet_workflows.cli.ExtractionStateLedger") as mock_ledger: result = runner.invoke( @@ -140,7 +140,7 @@ def test_set_valid_utc_timestamp(self, runner: CliRunner, tmp_path) -> None: assert "Successfully set" in result.output def test_set_with_records_processed(self, runner: CliRunner, tmp_path) -> None: - """TODO: Add docstring.""" + """Test that set with records processed.""" ledger_path = str(tmp_path / "ledger.json") with patch("imednet_workflows.cli.ExtractionStateLedger") as mock_ledger: result = runner.invoke( @@ -167,7 +167,7 @@ def test_set_with_records_processed(self, runner: CliRunner, tmp_path) -> None: assert result.exit_code == 0 def test_set_invalid_timestamp_exits_with_error(self, runner: CliRunner, tmp_path) -> None: - """TODO: Add docstring.""" + """Test that set invalid timestamp exits with error.""" ledger_path = str(tmp_path / "ledger.json") result = runner.invoke( state_app, @@ -187,7 +187,7 @@ def test_set_invalid_timestamp_exits_with_error(self, runner: CliRunner, tmp_pat assert "Invalid ISO timestamp" in result.output def test_set_write_failure_exits_with_error(self, runner: CliRunner, tmp_path) -> None: - """TODO: Add docstring.""" + """Test that set write failure exits with error.""" ledger_path = str(tmp_path / "ledger.json") with patch("imednet_workflows.cli.ExtractionStateLedger") as mock_ledger: mock_ledger.return_value.set_last_timestamp.side_effect = OSError("disk full") @@ -211,10 +211,10 @@ def test_set_write_failure_exits_with_error(self, runner: CliRunner, tmp_path) - class TestResetState: - """TODO: Add docstring.""" + """Test suite for ResetState.""" def test_reset_whole_study_when_found(self, runner: CliRunner, tmp_path) -> None: - """TODO: Add docstring.""" + """Test that reset whole study when found.""" ledger_path = str(tmp_path / "ledger.json") with patch("imednet_workflows.cli.ExtractionStateLedger") as mock_ledger: mock_ledger.return_value.delete_entry.return_value = True @@ -228,7 +228,7 @@ def test_reset_whole_study_when_found(self, runner: CliRunner, tmp_path) -> None assert "Successfully reset all streams" in result.output def test_reset_specific_stream_when_found(self, runner: CliRunner, tmp_path) -> None: - """TODO: Add docstring.""" + """Test that reset specific stream when found.""" ledger_path = str(tmp_path / "ledger.json") with patch("imednet_workflows.cli.ExtractionStateLedger") as mock_ledger: mock_ledger.return_value.delete_entry.return_value = True @@ -250,7 +250,7 @@ def test_reset_specific_stream_when_found(self, runner: CliRunner, tmp_path) -> assert "Successfully reset stream" in result.output def test_reset_study_not_found_prints_warning(self, runner: CliRunner, tmp_path) -> None: - """TODO: Add docstring.""" + """Test that reset study not found prints warning.""" ledger_path = str(tmp_path / "ledger.json") with patch("imednet_workflows.cli.ExtractionStateLedger") as mock_ledger: mock_ledger.return_value.delete_entry.return_value = False @@ -263,7 +263,7 @@ def test_reset_study_not_found_prints_warning(self, runner: CliRunner, tmp_path) assert "No state found" in result.output def test_reset_stream_not_found_prints_warning(self, runner: CliRunner, tmp_path) -> None: - """TODO: Add docstring.""" + """Test that reset stream not found prints warning.""" ledger_path = str(tmp_path / "ledger.json") with patch("imednet_workflows.cli.ExtractionStateLedger") as mock_ledger: mock_ledger.return_value.delete_entry.return_value = False @@ -284,7 +284,7 @@ def test_reset_stream_not_found_prints_warning(self, runner: CliRunner, tmp_path assert "No stream" in result.output def test_reset_exception_exits_with_error(self, runner: CliRunner, tmp_path) -> None: - """TODO: Add docstring.""" + """Test that reset exception exits with error.""" ledger_path = str(tmp_path / "ledger.json") with patch("imednet_workflows.cli.ExtractionStateLedger") as mock_ledger: mock_ledger.return_value.delete_entry.side_effect = OSError("locked") diff --git a/tests/unit/core/http/test_retry.py b/tests/unit/core/http/test_retry.py index 59edef22..85bdf212 100644 --- a/tests/unit/core/http/test_retry.py +++ b/tests/unit/core/http/test_retry.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for retry.""" from unittest.mock import AsyncMock, Mock diff --git a/tests/unit/core/operations/__init__.py b/tests/unit/core/operations/__init__.py index a9cca0f7..fae6326f 100644 --- a/tests/unit/core/operations/__init__.py +++ b/tests/unit/core/operations/__init__.py @@ -1 +1 @@ -"""TODO: Add docstring.""" +"""Test package initialization.""" diff --git a/tests/unit/core/operations/test_executor.py b/tests/unit/core/operations/test_executor.py index ecb3ace1..2266c723 100644 --- a/tests/unit/core/operations/test_executor.py +++ b/tests/unit/core/operations/test_executor.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for executor.""" import pytest @@ -8,15 +8,15 @@ class RESTTask(OperationProtocol[str]): - """TODO: Add docstring.""" + """Test suite for RESTTask.""" def __init__(self, fail_times=0): - """TODO: Add docstring.""" + """Initialize the test object.""" self.fail_times = fail_times self.attempts = 0 def execute(self) -> str: - """TODO: Add docstring.""" + """Helper function to execute.""" self.attempts += 1 if self.attempts <= self.fail_times: raise ValueError("HTTP Error") @@ -24,15 +24,15 @@ def execute(self) -> str: class NonRESTTask(OperationProtocol[str]): - """TODO: Add docstring.""" + """Test suite for NonRESTTask.""" def __init__(self, fail_times=0): - """TODO: Add docstring.""" + """Initialize the test object.""" self.fail_times = fail_times self.attempts = 0 def execute(self) -> str: - """TODO: Add docstring.""" + """Helper function to execute.""" self.attempts += 1 if self.attempts <= self.fail_times: raise RuntimeError("DB Error") @@ -40,7 +40,7 @@ def execute(self) -> str: def test_universal_executor_supports_rest_and_non_rest(): - """TODO: Add docstring.""" + """Test that universal executor supports rest and non rest.""" get_global_circuit_breaker().reset() executor = UniversalExecutor(retries=2, backoff_factor=0.01) @@ -56,7 +56,7 @@ def test_universal_executor_supports_rest_and_non_rest(): def test_universal_executor_fails_after_retries(): - """TODO: Add docstring.""" + """Test that universal executor fails after retries.""" get_global_circuit_breaker().reset() executor = UniversalExecutor(retries=1, backoff_factor=0.01) @@ -68,21 +68,21 @@ def test_universal_executor_fails_after_retries(): @pytest.mark.asyncio async def test_universal_executor_async(): - """TODO: Add docstring.""" + """Test that universal executor async asynchronously.""" get_global_circuit_breaker().reset() executor = UniversalExecutor(retries=1, backoff_factor=0.01) attempts = 0 async def failing_task(): - """TODO: Add docstring.""" + """Helper function to failing task.""" nonlocal attempts attempts += 1 raise ValueError("Async Error") # Use a regular function returning a coroutine, to match Callable[[], Awaitable[T]] def task_factory(): - """TODO: Add docstring.""" + """Helper function to task factory.""" return failing_task() with pytest.raises(ValueError, match="Async Error"): diff --git a/tests/unit/core/test_abc.py b/tests/unit/core/test_abc.py index 3ebbab9f..785b1e48 100644 --- a/tests/unit/core/test_abc.py +++ b/tests/unit/core/test_abc.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for abc.""" from typing import Any, Dict, Type @@ -9,41 +9,41 @@ class MockModel(JsonModel): - """TODO: Add docstring.""" + """Test suite for MockModel.""" id: int class ConcreteEndpoint(EndpointABC[MockModel]): - """TODO: Add docstring.""" + """Test suite for ConcreteEndpoint.""" @property def PATH(self) -> str: # noqa: N802 - """TODO: Add docstring.""" + """Helper function to PATH.""" return "mock" @property def MODEL(self) -> Type[MockModel]: # noqa: N802 - """TODO: Add docstring.""" + """Helper function to MODEL.""" return MockModel def _build_path(self, *segments: Any) -> str: - """TODO: Add docstring.""" + """Helper function to build path.""" return "/".join(["mock", *(str(s) for s in segments)]) def _auto_filter(self, filters: Dict[str, Any]) -> Dict[str, Any]: - """TODO: Add docstring.""" + """Helper function to auto filter.""" return {"auto": True, **filters} class UnimplementedEndpoint(EndpointABC[MockModel]): - """TODO: Add docstring.""" + """Test suite for UnimplementedEndpoint.""" pass def test_endpoint_abc_properties(): - """TODO: Add docstring.""" + """Test that endpoint abc properties.""" endpoint = ConcreteEndpoint() assert endpoint.PATH == "mock" assert endpoint.MODEL == MockModel @@ -52,21 +52,21 @@ def test_endpoint_abc_properties(): def test_endpoint_abc_methods(): - """TODO: Add docstring.""" + """Test that endpoint abc methods.""" endpoint = ConcreteEndpoint() assert endpoint._build_path(1, "test") == "mock/1/test" assert endpoint._auto_filter({"test": "value"}) == {"auto": True, "test": "value"} def test_endpoint_abc_abstract_instantiation_fails(): - """TODO: Add docstring.""" + """Test that endpoint abc abstract instantiation fails.""" with pytest.raises(TypeError) as exc_info: UnimplementedEndpoint() # type: ignore[abstract] assert "Can't instantiate abstract class" in str(exc_info.value) def test_endpoint_abc_pass_coverage(): - """TODO: Add docstring.""" + """Test that endpoint abc pass coverage.""" # Hit the `pass` statements in abstract properties/methods to ensure 100% coverage assert EndpointABC.PATH.fget(None) is None assert EndpointABC.MODEL.fget(None) is None diff --git a/tests/unit/core/test_context_safety.py b/tests/unit/core/test_context_safety.py index 9edc1bd2..0b68f5d6 100644 --- a/tests/unit/core/test_context_safety.py +++ b/tests/unit/core/test_context_safety.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for context safety.""" import asyncio import threading @@ -16,7 +16,7 @@ async def async_worker(study_key: str, delay: float) -> str: - """TODO: Add docstring.""" + """Helper function to async worker.""" token = set_study_context(study_key) try: await asyncio.sleep(delay) @@ -27,7 +27,7 @@ async def async_worker(study_key: str, delay: float) -> str: @pytest.mark.asyncio async def test_contextvars_prevents_race_conditions() -> None: - """TODO: Add docstring.""" + """Test that contextvars prevents race conditions asynchronously.""" results = await asyncio.gather( async_worker("STUDY-A", 0.2), async_worker("STUDY-B", 0.1), @@ -41,7 +41,7 @@ def test_study_context_is_visible_inside_worker_thread() -> None: result: list[str | None] = [] def worker() -> None: - """TODO: Add docstring.""" + """Helper function to worker.""" with study_context("THREAD-A"): result.append(get_current_study()) @@ -57,7 +57,7 @@ def test_study_context_is_isolated_between_threads() -> None: results: dict[str, str] = {} def worker(key: str) -> None: - """TODO: Add docstring.""" + """Helper function to worker.""" with study_context(key): time.sleep(0.05) results[key] = get_current_study() @@ -76,7 +76,7 @@ def test_study_context_is_reset_after_worker_thread_completes() -> None: sentinel: list[str | Exception] = [] def worker() -> None: - """TODO: Add docstring.""" + """Helper function to worker.""" with study_context("TRANSIENT"): pass # context manager exits before thread ends diff --git a/tests/unit/core/test_parsing.py b/tests/unit/core/test_parsing.py index e8885b9b..8ce56aff 100644 --- a/tests/unit/core/test_parsing.py +++ b/tests/unit/core/test_parsing.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for parsing.""" from typing import Any, Dict @@ -8,26 +8,26 @@ class BasicModel(BaseModel): - """TODO: Add docstring.""" + """Test suite for BasicModel.""" id: int name: str class CustomModel(BaseModel): - """TODO: Add docstring.""" + """Test suite for CustomModel.""" id: int name: str @classmethod def from_json(cls, data: Dict[str, Any]) -> "CustomModel": - """TODO: Add docstring.""" + """Helper function to from json.""" return cls(id=data["id"], name=data["name"] + " (parsed)") def test_get_model_parser_pydantic_fallback(): - """TODO: Add docstring.""" + """Test that get model parser pydantic fallback.""" parser = get_model_parser(BasicModel) data = {"id": 1, "name": "Test"} model = parser(data) @@ -37,7 +37,7 @@ def test_get_model_parser_pydantic_fallback(): def test_get_model_parser_custom_method(): - """TODO: Add docstring.""" + """Test that get model parser custom method.""" parser = get_model_parser(CustomModel) data = {"id": 1, "name": "Test"} model = parser(data) @@ -47,7 +47,7 @@ def test_get_model_parser_custom_method(): def test_model_parser_parse(): - """TODO: Add docstring.""" + """Test that model parser parse.""" parser = ModelParser(BasicModel) data = {"id": 1, "name": "Test"} model = parser.parse(data) @@ -57,7 +57,7 @@ def test_model_parser_parse(): def test_model_parser_parse_many(): - """TODO: Add docstring.""" + """Test that model parser parse many.""" parser = ModelParser(CustomModel) data = [{"id": 1, "name": "Test1"}, {"id": 2, "name": "Test2"}] models = parser.parse_many(data) diff --git a/tests/unit/core/test_parsing_mixin.py b/tests/unit/core/test_parsing_mixin.py index 037f63f7..d66334ce 100644 --- a/tests/unit/core/test_parsing_mixin.py +++ b/tests/unit/core/test_parsing_mixin.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for parsing mixin.""" from unittest.mock import MagicMock @@ -8,24 +8,24 @@ class MockModel(JsonModel): - """TODO: Add docstring.""" + """Test suite for MockModel.""" id: int class EndpointWithParsing(GenericListGetEndpoint[MockModel]): - """TODO: Add docstring.""" + """Test suite for EndpointWithParsing.""" PATH = "items" MODEL = MockModel def _auto_filter(self, filters): - """TODO: Add docstring.""" + """Helper function to auto filter.""" return filters def test_parsing_mixin_parse_item(): - """TODO: Add docstring.""" + """Test that parsing mixin parse item.""" endpoint = EndpointWithParsing(client=MagicMock(), ctx=Context()) result = endpoint._parse_item({"id": 1}) assert isinstance(result, MockModel) diff --git a/tests/unit/core/test_triage_models.py b/tests/unit/core/test_triage_models.py index f15fe154..73de2f07 100644 --- a/tests/unit/core/test_triage_models.py +++ b/tests/unit/core/test_triage_models.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for triage models.""" from __future__ import annotations @@ -16,7 +16,7 @@ def test_triage_models_parse_and_strip_whitespace() -> None: - """TODO: Add docstring.""" + """Test that triage models parse and strip whitespace.""" item = TriageItem.model_validate( { "item_id": " AE-1001 ", @@ -55,7 +55,7 @@ def test_triage_models_parse_and_strip_whitespace() -> None: def test_triage_history_blank_comment_normalizes_to_none() -> None: - """TODO: Add docstring.""" + """Test that triage history blank comment normalizes to none.""" entry = TriageHistoryEntry.model_validate( { "transition_id": "h-2", @@ -71,7 +71,7 @@ def test_triage_history_blank_comment_normalizes_to_none() -> None: def test_triage_json_roundtrip_keeps_enum_values() -> None: - """TODO: Add docstring.""" + """Test that triage json roundtrip keeps enum values.""" annotation = TriageAnnotation( annotation_id="a-2", user_id="reviewer", @@ -95,7 +95,7 @@ def test_triage_json_roundtrip_keeps_enum_values() -> None: def test_triage_models_enforce_schema_constraints() -> None: - """TODO: Add docstring.""" + """Test that triage models enforce schema constraints.""" with pytest.raises(ValidationError) as blank_id_error: TriageAnnotation.model_validate( { diff --git a/tests/unit/endpoints/test_base_endpoint.py b/tests/unit/endpoints/test_base_endpoint.py index 5474fba7..183fae16 100644 --- a/tests/unit/endpoints/test_base_endpoint.py +++ b/tests/unit/endpoints/test_base_endpoint.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for base endpoint.""" import inspect from unittest.mock import MagicMock @@ -13,24 +13,24 @@ class MockModel(JsonModel): - """TODO: Add docstring.""" + """Test suite for MockModel.""" pass class MockEndpointImpl(EdcEndpointMixin, GenericEndpoint[MockModel]): - """TODO: Add docstring.""" + """Test suite for MockEndpointImpl.""" PATH = "/test" MODEL = MockModel def __init__(self, client, ctx, async_client=None): - """TODO: Add docstring.""" + """Initialize the test object.""" super().__init__(client, ctx, async_client) class MockListGetEndpoint(EdcEndpointMixin, GenericListGetEndpoint[MockModel]): - """TODO: Add docstring.""" + """Test suite for MockListGetEndpoint.""" PATH = "/items" MODEL = MockModel @@ -38,26 +38,26 @@ class MockListGetEndpoint(EdcEndpointMixin, GenericListGetEndpoint[MockModel]): class TestBaseEndpoint: - """TODO: Add docstring.""" + """Test suite for BaseEndpoint.""" @pytest.fixture def client(self): - """TODO: Add docstring.""" + """Helper function to client.""" return MagicMock(spec=Client) @pytest.fixture def context(self): - """TODO: Add docstring.""" + """Helper function to context.""" return Context() def test_require_async_client_raises(self, client, context): - """TODO: Add docstring.""" + """Test that require async client raises.""" ep = MockEndpointImpl(client, context, async_client=None) with pytest.raises(RuntimeError, match="Async client not configured"): ep._require_async_client() def test_auto_filter_injects_study_key(self, client, context): - """TODO: Add docstring.""" + """Test that auto filter injects study key.""" context.set_default_study_key("DEFAULT") ep = MockEndpointImpl(client, context) @@ -67,7 +67,7 @@ def test_auto_filter_injects_study_key(self, client, context): assert result["foo"] == "bar" def test_auto_filter_preserves_existing_study_key(self, client, context): - """TODO: Add docstring.""" + """Test that auto filter preserves existing study key.""" context.set_default_study_key("DEFAULT") ep = MockEndpointImpl(client, context) @@ -76,14 +76,14 @@ def test_auto_filter_preserves_existing_study_key(self, client, context): assert result["studyKey"] == "EXPLICIT" def test_get_signature_is_explicit(self, client, context): - """TODO: Add docstring.""" + """Test that get signature is explicit.""" ep = MockListGetEndpoint(client, context) signature = inspect.signature(ep.get) assert list(signature.parameters.keys()) == ["study_key", "item_id"] def test_get_requires_item_id(self, client, context): - """TODO: Add docstring.""" + """Test that get requires item id.""" ep = MockListGetEndpoint(client, context) with pytest.raises(TypeError, match="Missing required argument: item_id"): diff --git a/tests/unit/endpoints/test_codings_endpoint.py b/tests/unit/endpoints/test_codings_endpoint.py index a1ea6119..86c9b801 100644 --- a/tests/unit/endpoints/test_codings_endpoint.py +++ b/tests/unit/endpoints/test_codings_endpoint.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for codings endpoint.""" import pytest @@ -9,7 +9,7 @@ def test_list_requires_study_key(dummy_client, context, paginator_factory, patch_build_filter): - """TODO: Add docstring.""" + """Test that list requires study key.""" ep = codings.CodingsEndpoint(dummy_client, context) capture = paginator_factory(codings, [{"codingId": 1}]) patch = patch_build_filter(codings) @@ -26,11 +26,11 @@ def test_list_requires_study_key(dummy_client, context, paginator_factory, patch def test_get_not_found(monkeypatch, dummy_client, context): - """TODO: Add docstring.""" + """Test that get not found.""" ep = codings.CodingsEndpoint(dummy_client, context) def fake_impl(self, client, paginator, *, study_key=None, refresh=False, **filters): - """TODO: Add docstring.""" + """Helper function to fake impl.""" return [] monkeypatch.setattr(codings.CodingsEndpoint, "_list_sync", fake_impl) diff --git a/tests/unit/endpoints/test_endpoint_composition.py b/tests/unit/endpoints/test_endpoint_composition.py index 18dd240d..d69e6803 100644 --- a/tests/unit/endpoints/test_endpoint_composition.py +++ b/tests/unit/endpoints/test_endpoint_composition.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for endpoint composition.""" import imednet.endpoints.records as records_module from imednet.endpoints.codings import AsyncCodingsEndpoint, CodingsEndpoint @@ -49,7 +49,7 @@ def test_records_endpoint_keeps_public_read_api(dummy_client, context, paginator_factory): - """TODO: Add docstring.""" + """Test that records endpoint keeps public read api.""" endpoint = RecordsEndpoint(dummy_client, context) capture = paginator_factory(records_module, [{"recordId": 1}]) @@ -64,7 +64,7 @@ def test_records_endpoint_keeps_public_read_api(dummy_client, context, paginator def test_jobs_endpoint_keeps_public_read_api(dummy_client, context, response_factory): - """TODO: Add docstring.""" + """Test that jobs endpoint keeps public read api.""" endpoint = JobsEndpoint(dummy_client, context) dummy_client.get.return_value = response_factory({"jobId": "1"}) diff --git a/tests/unit/endpoints/test_endpoints_async.py b/tests/unit/endpoints/test_endpoints_async.py index aca12569..709ac849 100644 --- a/tests/unit/endpoints/test_endpoints_async.py +++ b/tests/unit/endpoints/test_endpoints_async.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for endpoints async.""" from unittest.mock import AsyncMock @@ -35,7 +35,7 @@ async def test_async_list_records( dummy_client, context, async_paginator_factory, patch_build_filter ): - """TODO: Add docstring.""" + """Test that async list records asynchronously.""" ep = records.AsyncRecordsEndpoint(dummy_client, context) captured = async_paginator_factory(records, [{"recordId": 1}]) filter_capture = patch_build_filter(records) @@ -48,7 +48,7 @@ async def test_async_list_records( @pytest.mark.asyncio async def test_async_list_codings(dummy_client, context, async_paginator_factory): - """TODO: Add docstring.""" + """Test that async list codings asynchronously.""" ep = codings.AsyncCodingsEndpoint(dummy_client, context) captured = async_paginator_factory(codings, [{"codingId": 1}]) result = await ep.async_list(study_key="S1") @@ -58,7 +58,7 @@ async def test_async_list_codings(dummy_client, context, async_paginator_factory @pytest.mark.asyncio async def test_async_list_forms(dummy_client, context, async_paginator_factory): - """TODO: Add docstring.""" + """Test that async list forms asynchronously.""" context.set_default_study_key("S1") ep = forms.AsyncFormsEndpoint(dummy_client, context) captured = async_paginator_factory(forms, [{"formId": 1}]) @@ -69,7 +69,7 @@ async def test_async_list_forms(dummy_client, context, async_paginator_factory): @pytest.mark.asyncio async def test_async_list_intervals(dummy_client, context, async_paginator_factory): - """TODO: Add docstring.""" + """Test that async list intervals asynchronously.""" context.set_default_study_key("S1") ep = intervals.AsyncIntervalsEndpoint(dummy_client, context) captured = async_paginator_factory(intervals, [{"intervalId": 1}]) @@ -80,7 +80,7 @@ async def test_async_list_intervals(dummy_client, context, async_paginator_facto @pytest.mark.asyncio async def test_async_list_queries(dummy_client, context, async_paginator_factory): - """TODO: Add docstring.""" + """Test that async list queries asynchronously.""" context.set_default_study_key("S1") ep = queries.AsyncQueriesEndpoint(dummy_client, context) captured = async_paginator_factory(queries, [{"annotationId": 1}]) @@ -91,7 +91,7 @@ async def test_async_list_queries(dummy_client, context, async_paginator_factory @pytest.mark.asyncio async def test_async_list_record_revisions(dummy_client, context, async_paginator_factory): - """TODO: Add docstring.""" + """Test that async list record revisions asynchronously.""" context.set_default_study_key("S1") ep = record_revisions.AsyncRecordRevisionsEndpoint(dummy_client, context) captured = async_paginator_factory(record_revisions, [{"recordRevisionId": 1}]) @@ -102,7 +102,7 @@ async def test_async_list_record_revisions(dummy_client, context, async_paginato @pytest.mark.asyncio async def test_async_list_sites(dummy_client, context, async_paginator_factory): - """TODO: Add docstring.""" + """Test that async list sites asynchronously.""" ep = sites.AsyncSitesEndpoint(dummy_client, context) captured = async_paginator_factory(sites, [{"siteId": 1}]) result = await ep.async_list(study_key="S1") @@ -112,7 +112,7 @@ async def test_async_list_sites(dummy_client, context, async_paginator_factory): @pytest.mark.asyncio async def test_async_list_subjects(dummy_client, context, async_paginator_factory): - """TODO: Add docstring.""" + """Test that async list subjects asynchronously.""" context.set_default_study_key("S1") ep = subjects.AsyncSubjectsEndpoint(dummy_client, context) captured = async_paginator_factory(subjects, [{"subjectKey": "x"}]) @@ -123,7 +123,7 @@ async def test_async_list_subjects(dummy_client, context, async_paginator_factor @pytest.mark.asyncio async def test_async_list_users(dummy_client, context, async_paginator_factory): - """TODO: Add docstring.""" + """Test that async list users asynchronously.""" ep = users.AsyncUsersEndpoint(dummy_client, context) captured = async_paginator_factory(users, [{"userId": 1}]) result = await ep.async_list(study_key="S1", include_inactive=True) @@ -134,7 +134,7 @@ async def test_async_list_users(dummy_client, context, async_paginator_factory): @pytest.mark.asyncio async def test_async_list_variables(dummy_client, context, async_paginator_factory): - """TODO: Add docstring.""" + """Test that async list variables asynchronously.""" ep = variables.AsyncVariablesEndpoint(dummy_client, context) captured = async_paginator_factory(variables, [{"variableId": 1}]) result = await ep.async_list(study_key="S1") @@ -144,7 +144,7 @@ async def test_async_list_variables(dummy_client, context, async_paginator_facto @pytest.mark.asyncio async def test_async_list_visits(dummy_client, context, async_paginator_factory): - """TODO: Add docstring.""" + """Test that async list visits asynchronously.""" context.set_default_study_key("S1") ep = visits.AsyncVisitsEndpoint(dummy_client, context) captured = async_paginator_factory(visits, [{"visitId": 1}]) @@ -155,11 +155,11 @@ async def test_async_list_visits(dummy_client, context, async_paginator_factory) @pytest.mark.asyncio async def test_async_get_job(dummy_client, context, response_factory): - """TODO: Add docstring.""" + """Test that async get job asynchronously.""" ep = jobs.AsyncJobsEndpoint(dummy_client, context) async def fake_get(path): - """TODO: Add docstring.""" + """Helper function to fake get.""" assert path == "/api/v1/edc/studies/S1/jobs/B1" return response_factory({"jobId": "1"}) @@ -170,12 +170,12 @@ async def fake_get(path): @pytest.mark.asyncio async def test_async_get_record(monkeypatch, dummy_client, context, response_factory): - """TODO: Add docstring.""" + """Test that async get record asynchronously.""" ep = records.AsyncRecordsEndpoint(dummy_client, context) called = {} async def fake_impl(self, client, paginator, *, study_key=None, **filters): - """TODO: Add docstring.""" + """Helper function to fake impl.""" called["study_key"] = study_key called["filters"] = filters yield Record(record_id=1) @@ -190,11 +190,11 @@ async def fake_impl(self, client, paginator, *, study_key=None, **filters): @pytest.mark.asyncio async def test_async_get_record_not_found(monkeypatch, dummy_client, context, response_factory): - """TODO: Add docstring.""" + """Test that async get record not found asynchronously.""" ep = records.AsyncRecordsEndpoint(dummy_client, context) async def fake_impl(self, client, paginator, *, study_key=None, **filters): - """TODO: Add docstring.""" + """Helper function to fake impl.""" if False: yield @@ -206,7 +206,7 @@ async def fake_impl(self, client, paginator, *, study_key=None, **filters): @pytest.mark.asyncio async def test_async_create_record(dummy_client, context, response_factory, monkeypatch): - """TODO: Add docstring.""" + """Test that async create record asynchronously.""" ep = records.AsyncRecordsEndpoint(dummy_client, context) dummy_client.post = AsyncMock(return_value=response_factory({"jobId": "1"})) diff --git a/tests/unit/endpoints/test_forms_endpoint.py b/tests/unit/endpoints/test_forms_endpoint.py index f878fdbe..0d0b64f8 100644 --- a/tests/unit/endpoints/test_forms_endpoint.py +++ b/tests/unit/endpoints/test_forms_endpoint.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for forms endpoint.""" import pytest @@ -11,7 +11,7 @@ def test_list_requires_study_key_and_page_size( monkeypatch, dummy_client, context, paginator_factory, patch_build_filter ): - """TODO: Add docstring.""" + """Test that list requires study key and page size.""" ep = forms.FormsEndpoint(dummy_client, context) captured = paginator_factory(forms, [{"formId": 1}]) filter_capture = patch_build_filter(forms) @@ -30,12 +30,12 @@ def test_list_requires_study_key_and_page_size( def test_get_success(monkeypatch, dummy_client, context): - """TODO: Add docstring.""" + """Test that get success.""" ep = forms.FormsEndpoint(dummy_client, context) called = {} def fake_impl(self, client, paginator, *, study_key=None, **filters): - """TODO: Add docstring.""" + """Helper function to fake impl.""" called["study_key"] = study_key called["filters"] = filters return [Form(form_id=1)] @@ -49,11 +49,11 @@ def fake_impl(self, client, paginator, *, study_key=None, **filters): def test_get_not_found(monkeypatch, dummy_client, context): - """TODO: Add docstring.""" + """Test that get not found.""" ep = forms.FormsEndpoint(dummy_client, context) def fake_impl(self, client, paginator, *, study_key=None, **filters): - """TODO: Add docstring.""" + """Helper function to fake impl.""" return [] monkeypatch.setattr(forms.FormsEndpoint, "_list_sync", fake_impl) @@ -63,7 +63,7 @@ def fake_impl(self, client, paginator, *, study_key=None, **filters): def test_list_makes_request_per_call(dummy_client, context, paginator_factory): - """TODO: Add docstring.""" + """Test that list makes request per call.""" ep = forms.FormsEndpoint(dummy_client, context) capture = paginator_factory(forms, [{"formId": 1}]) @@ -74,7 +74,7 @@ def test_list_makes_request_per_call(dummy_client, context, paginator_factory): def test_list_different_study_keys_make_separate_requests(dummy_client, context, paginator_factory): - """TODO: Add docstring.""" + """Test that list different study keys make separate requests.""" ep = forms.FormsEndpoint(dummy_client, context) capture = paginator_factory(forms, [{"formId": 1}]) diff --git a/tests/unit/endpoints/test_intervals_endpoint.py b/tests/unit/endpoints/test_intervals_endpoint.py index 78ec7db6..c26369eb 100644 --- a/tests/unit/endpoints/test_intervals_endpoint.py +++ b/tests/unit/endpoints/test_intervals_endpoint.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for intervals endpoint.""" import pytest @@ -10,7 +10,7 @@ def test_list_uses_default_study_and_page_size( dummy_client, context, paginator_factory, patch_build_filter ): - """TODO: Add docstring.""" + """Test that list uses default study and page size.""" context.set_default_study_key("S1") ep = intervals.IntervalsEndpoint(dummy_client, context) captured = paginator_factory(intervals, [{"intervalId": 1}]) @@ -26,11 +26,11 @@ def test_list_uses_default_study_and_page_size( def test_get_not_found(monkeypatch, dummy_client, context): - """TODO: Add docstring.""" + """Test that get not found.""" ep = intervals.IntervalsEndpoint(dummy_client, context) def fake_impl(self, client, paginator, *, study_key=None, **filters): - """TODO: Add docstring.""" + """Helper function to fake impl.""" return [] monkeypatch.setattr(intervals.IntervalsEndpoint, "_list_sync", fake_impl) @@ -40,7 +40,7 @@ def fake_impl(self, client, paginator, *, study_key=None, **filters): def test_list_makes_request_per_call(dummy_client, context, paginator_factory): - """TODO: Add docstring.""" + """Test that list makes request per call.""" ep = intervals.IntervalsEndpoint(dummy_client, context) capture = paginator_factory(intervals, [{"intervalId": 1}]) @@ -51,7 +51,7 @@ def test_list_makes_request_per_call(dummy_client, context, paginator_factory): def test_list_different_study_keys_make_separate_requests(dummy_client, context, paginator_factory): - """TODO: Add docstring.""" + """Test that list different study keys make separate requests.""" ep = intervals.IntervalsEndpoint(dummy_client, context) capture = paginator_factory(intervals, [{"intervalId": 1}]) diff --git a/tests/unit/endpoints/test_jobs_async.py b/tests/unit/endpoints/test_jobs_async.py index 4f337b12..0dd5cb9e 100644 --- a/tests/unit/endpoints/test_jobs_async.py +++ b/tests/unit/endpoints/test_jobs_async.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for jobs async.""" from unittest.mock import AsyncMock @@ -11,7 +11,7 @@ @pytest.mark.asyncio async def test_async_get_success(dummy_client, context, response_factory): - """TODO: Add docstring.""" + """Test that async get success asynchronously.""" # Setup async mock async_client = AsyncMock() async_client.get.return_value = response_factory({"jobId": "1"}) @@ -26,7 +26,7 @@ async def test_async_get_success(dummy_client, context, response_factory): @pytest.mark.asyncio async def test_async_get_not_found(dummy_client, context, response_factory): - """TODO: Add docstring.""" + """Test that async get not found asynchronously.""" async_client = AsyncMock() async_client.get.return_value = response_factory({}) diff --git a/tests/unit/endpoints/test_jobs_endpoint.py b/tests/unit/endpoints/test_jobs_endpoint.py index d77248ef..d857ffed 100644 --- a/tests/unit/endpoints/test_jobs_endpoint.py +++ b/tests/unit/endpoints/test_jobs_endpoint.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for jobs endpoint.""" import pytest @@ -8,7 +8,7 @@ def test_get_success(dummy_client, context, response_factory): - """TODO: Add docstring.""" + """Test that get success.""" ep = jobs.JobsEndpoint(dummy_client, context) dummy_client.get.return_value = response_factory({"jobId": "1"}) @@ -19,7 +19,7 @@ def test_get_success(dummy_client, context, response_factory): def test_get_not_found(dummy_client, context, response_factory): - """TODO: Add docstring.""" + """Test that get not found.""" ep = jobs.JobsEndpoint(dummy_client, context) dummy_client.get.return_value = response_factory({}) with pytest.raises(NotFoundError): diff --git a/tests/unit/endpoints/test_list_get.py b/tests/unit/endpoints/test_list_get.py index e481839e..17c7523f 100644 --- a/tests/unit/endpoints/test_list_get.py +++ b/tests/unit/endpoints/test_list_get.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for list get.""" import pytest @@ -60,7 +60,7 @@ @pytest.mark.parametrize("cls,module,model,item_id", CASES) def test_list_and_get(dummy_client, context, paginator_factory, cls, module, model, item_id): - """TODO: Add docstring.""" + """Test that list and get.""" ep = cls(dummy_client, context) capture = paginator_factory(module, [{cls._id_param: item_id}]) @@ -91,7 +91,7 @@ async def test_async_list_and_get( model, item_id, ): - """TODO: Add docstring.""" + """Test that async list and get asynchronously.""" ep = cls(dummy_client, context) capture = async_paginator_factory(module, [{cls._id_param: item_id}]) diff --git a/tests/unit/endpoints/test_queries_endpoint.py b/tests/unit/endpoints/test_queries_endpoint.py index dde74139..0ac77471 100644 --- a/tests/unit/endpoints/test_queries_endpoint.py +++ b/tests/unit/endpoints/test_queries_endpoint.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for queries endpoint.""" import pytest @@ -8,7 +8,7 @@ def test_list_builds_path_and_filters(dummy_client, context, paginator_factory, patch_build_filter): - """TODO: Add docstring.""" + """Test that list builds path and filters.""" context.set_default_study_key("S1") ep = queries.QueriesEndpoint(dummy_client, context) capture = paginator_factory(queries, [{"annotationId": 1}]) @@ -23,11 +23,11 @@ def test_list_builds_path_and_filters(dummy_client, context, paginator_factory, def test_get_not_found(monkeypatch, dummy_client, context): - """TODO: Add docstring.""" + """Test that get not found.""" ep = queries.QueriesEndpoint(dummy_client, context) def fake_impl(self, client, paginator, *, study_key=None, refresh=False, **filters): - """TODO: Add docstring.""" + """Helper function to fake impl.""" return [] monkeypatch.setattr(queries.QueriesEndpoint, "_list_sync", fake_impl) diff --git a/tests/unit/endpoints/test_record_revisions_endpoint.py b/tests/unit/endpoints/test_record_revisions_endpoint.py index 2370d1fc..96b5da0e 100644 --- a/tests/unit/endpoints/test_record_revisions_endpoint.py +++ b/tests/unit/endpoints/test_record_revisions_endpoint.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for record revisions endpoint.""" import pytest @@ -8,7 +8,7 @@ def test_list_uses_filters(dummy_client, context, paginator_factory, patch_build_filter): - """TODO: Add docstring.""" + """Test that list uses filters.""" context.set_default_study_key("S1") ep = record_revisions.RecordRevisionsEndpoint(dummy_client, context) capture = paginator_factory(record_revisions, [{"recordRevisionId": 1}]) @@ -23,11 +23,11 @@ def test_list_uses_filters(dummy_client, context, paginator_factory, patch_build def test_get_not_found(monkeypatch, dummy_client, context): - """TODO: Add docstring.""" + """Test that get not found.""" ep = record_revisions.RecordRevisionsEndpoint(dummy_client, context) def fake_impl(self, client, paginator, *, study_key=None, refresh=False, **filters): - """TODO: Add docstring.""" + """Helper function to fake impl.""" return [] monkeypatch.setattr(record_revisions.RecordRevisionsEndpoint, "_list_sync", fake_impl) diff --git a/tests/unit/endpoints/test_records_async.py b/tests/unit/endpoints/test_records_async.py index bf625a74..41a745ce 100644 --- a/tests/unit/endpoints/test_records_async.py +++ b/tests/unit/endpoints/test_records_async.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for records async.""" from unittest.mock import AsyncMock @@ -12,7 +12,7 @@ @pytest.fixture def schema(): - """TODO: Add docstring.""" + """Helper function to schema.""" s = SchemaCache() var = Variable(variable_name="age", variable_type="integer", form_id=1, form_key="F1") s._form_variables = {"F1": {"age": var}} @@ -22,7 +22,7 @@ def schema(): @pytest.mark.asyncio async def test_async_create_validates_data(dummy_client, context, response_factory, schema): - """TODO: Add docstring.""" + """Test that async create validates data asynchronously.""" ep = records.AsyncRecordsEndpoint(dummy_client, context) dummy_client.post = AsyncMock(return_value=response_factory({"jobId": "1"})) @@ -45,7 +45,7 @@ async def test_async_create_validates_data(dummy_client, context, response_facto async def test_async_create_validates_data_with_snake_case_keys( dummy_client, context, response_factory, schema ): - """TODO: Add docstring.""" + """Test that async create validates data with snake case keys asynchronously.""" ep = records.AsyncRecordsEndpoint(dummy_client, context) dummy_client.post = AsyncMock(return_value=response_factory({"jobId": "1"})) @@ -57,7 +57,7 @@ async def test_async_create_validates_data_with_snake_case_keys( @pytest.mark.asyncio async def test_async_create_resolves_form_id(dummy_client, context, response_factory, schema): - """TODO: Add docstring.""" + """Test that async create resolves form id asynchronously.""" ep = records.AsyncRecordsEndpoint(dummy_client, context) dummy_client.post = AsyncMock(return_value=response_factory({"jobId": "1"})) diff --git a/tests/unit/endpoints/test_records_endpoint.py b/tests/unit/endpoints/test_records_endpoint.py index cb7d174c..a86881a8 100644 --- a/tests/unit/endpoints/test_records_endpoint.py +++ b/tests/unit/endpoints/test_records_endpoint.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for records endpoint.""" import pytest @@ -12,7 +12,7 @@ def test_list_builds_path_filters_and_data_filter( dummy_client, context, paginator_factory, patch_build_filter ): - """TODO: Add docstring.""" + """Test that list builds path filters and data filter.""" ep = records.RecordsEndpoint(dummy_client, context) captured = paginator_factory(records, [{"recordId": 1}]) filter_capture = patch_build_filter(records) @@ -30,12 +30,12 @@ def test_list_builds_path_filters_and_data_filter( def test_get_success(monkeypatch, dummy_client, context): - """TODO: Add docstring.""" + """Test that get success.""" ep = records.RecordsEndpoint(dummy_client, context) called = {} def fake_impl(self, client, paginator, *, study_key=None, **filters): - """TODO: Add docstring.""" + """Helper function to fake impl.""" called["study_key"] = study_key called["filters"] = filters return [Record(record_id=1)] @@ -49,7 +49,7 @@ def fake_impl(self, client, paginator, *, study_key=None, **filters): def test_get_rejects_unknown_keyword(monkeypatch, dummy_client, context): - """TODO: Add docstring.""" + """Test that get rejects unknown keyword.""" context.set_default_study_key("S1") ep = records.RecordsEndpoint(dummy_client, context) monkeypatch.setattr( @@ -61,11 +61,11 @@ def test_get_rejects_unknown_keyword(monkeypatch, dummy_client, context): def test_get_not_found(monkeypatch, dummy_client, context): - """TODO: Add docstring.""" + """Test that get not found.""" ep = records.RecordsEndpoint(dummy_client, context) def fake_impl(self, client, paginator, *, study_key=None, refresh=False, **filters): - """TODO: Add docstring.""" + """Helper function to fake impl.""" return [] monkeypatch.setattr(records.RecordsEndpoint, "_list_sync", fake_impl) @@ -75,13 +75,13 @@ def fake_impl(self, client, paginator, *, study_key=None, refresh=False, **filte def test_create_sends_headers_and_parses_job(dummy_client, context, response_factory, monkeypatch): - """TODO: Add docstring.""" + """Test that create sends headers and parses job.""" ep = records.RecordsEndpoint(dummy_client, context) dummy_client.post.return_value = response_factory({"jobId": "1"}) called = {} def fake_from_json(data): - """TODO: Add docstring.""" + """Helper function to fake from json.""" called["data"] = data return "JOB" @@ -99,7 +99,7 @@ def fake_from_json(data): def test_create_validates_data(dummy_client, context, response_factory): - """TODO: Add docstring.""" + """Test that create validates data.""" ep = records.RecordsEndpoint(dummy_client, context) schema = SchemaCache() var = Variable(variable_name="age", variable_type="integer", form_id=1, form_key="F1") @@ -123,7 +123,7 @@ def test_create_validates_data(dummy_client, context, response_factory): def test_create_validates_data_with_snake_case_keys(dummy_client, context, response_factory): - """TODO: Add docstring.""" + """Test that create validates data with snake case keys.""" ep = records.RecordsEndpoint(dummy_client, context) schema = SchemaCache() var = Variable(variable_name="age", variable_type="integer", form_id=1, form_key="F1") @@ -139,7 +139,7 @@ def test_create_validates_data_with_snake_case_keys(dummy_client, context, respo def test_create_raises_on_header_injection(dummy_client, context): - """TODO: Add docstring.""" + """Test that create raises on header injection.""" ep = records.RecordsEndpoint(dummy_client, context) with pytest.raises(ClientError, match="Header value must not contain newlines"): ep.create("S1", [{"data": {}}], email_notify="test\n@example.com") diff --git a/tests/unit/endpoints/test_sites_endpoint.py b/tests/unit/endpoints/test_sites_endpoint.py index 938a96cd..56bf643f 100644 --- a/tests/unit/endpoints/test_sites_endpoint.py +++ b/tests/unit/endpoints/test_sites_endpoint.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for sites endpoint.""" import pytest @@ -9,7 +9,7 @@ def test_list_requires_study_key(dummy_client, context, paginator_factory, patch_build_filter): - """TODO: Add docstring.""" + """Test that list requires study key.""" ep = sites.SitesEndpoint(dummy_client, context) paginator_capture = paginator_factory(sites, [{"siteId": 1}]) patch = patch_build_filter(sites) @@ -26,11 +26,11 @@ def test_list_requires_study_key(dummy_client, context, paginator_factory, patch def test_get_not_found(monkeypatch, dummy_client, context): - """TODO: Add docstring.""" + """Test that get not found.""" ep = sites.SitesEndpoint(dummy_client, context) def fake_impl(self, client, paginator, *, study_key=None, refresh=False, **filters): - """TODO: Add docstring.""" + """Helper function to fake impl.""" return [] monkeypatch.setattr(sites.SitesEndpoint, "_list_sync", fake_impl) diff --git a/tests/unit/endpoints/test_studies_endpoint.py b/tests/unit/endpoints/test_studies_endpoint.py index 423b9c7e..b4379207 100644 --- a/tests/unit/endpoints/test_studies_endpoint.py +++ b/tests/unit/endpoints/test_studies_endpoint.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for studies endpoint.""" import pytest @@ -10,7 +10,7 @@ def test_list_builds_path_and_filters( monkeypatch, dummy_client, context, paginator_factory, patch_build_filter ): - """TODO: Add docstring.""" + """Test that list builds path and filters.""" ep = studies.StudiesEndpoint(dummy_client, context) captured = paginator_factory(studies, [{"studyKey": "S1"}]) filter_capture = patch_build_filter(studies) @@ -24,7 +24,7 @@ def test_list_builds_path_and_filters( def test_get_success(monkeypatch, dummy_client, context, paginator_factory, patch_build_filter): - """TODO: Add docstring.""" + """Test that get success.""" ep = studies.StudiesEndpoint(dummy_client, context) captured = paginator_factory(studies, [{"studyKey": "S1"}]) filter_capture = patch_build_filter(studies) @@ -38,7 +38,7 @@ def test_get_success(monkeypatch, dummy_client, context, paginator_factory, patc def test_get_not_found(monkeypatch, dummy_client, context, paginator_factory): - """TODO: Add docstring.""" + """Test that get not found.""" ep = studies.StudiesEndpoint(dummy_client, context) paginator_factory(studies, []) with pytest.raises(NotFoundError): @@ -46,7 +46,7 @@ def test_get_not_found(monkeypatch, dummy_client, context, paginator_factory): def test_list_each_call_makes_request(dummy_client, context, paginator_factory): - """TODO: Add docstring.""" + """Test that list each call makes request.""" ep = studies.StudiesEndpoint(dummy_client, context) captured = paginator_factory(studies, [{"studyKey": "S1"}]) diff --git a/tests/unit/endpoints/test_studies_endpoint_async.py b/tests/unit/endpoints/test_studies_endpoint_async.py index 9a949944..c669ea8d 100644 --- a/tests/unit/endpoints/test_studies_endpoint_async.py +++ b/tests/unit/endpoints/test_studies_endpoint_async.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for studies endpoint async.""" import pytest @@ -14,7 +14,7 @@ async def test_async_list_builds_path_and_filters( async_paginator_factory, patch_build_filter, ): - """TODO: Add docstring.""" + """Test that async list builds path and filters asynchronously.""" ep = studies.AsyncStudiesEndpoint(dummy_client, context) captured = async_paginator_factory(studies, [{"studyKey": "S1"}]) filter_capture = patch_build_filter(studies) diff --git a/tests/unit/endpoints/test_subjects_endpoint.py b/tests/unit/endpoints/test_subjects_endpoint.py index d27fcaf0..6ff710cd 100644 --- a/tests/unit/endpoints/test_subjects_endpoint.py +++ b/tests/unit/endpoints/test_subjects_endpoint.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for subjects endpoint.""" import pytest @@ -10,7 +10,7 @@ def test_list_builds_path_with_default( dummy_client, context, paginator_factory, patch_build_filter ): - """TODO: Add docstring.""" + """Test that list builds path with default.""" context.set_default_study_key("S1") ep = subjects.SubjectsEndpoint(dummy_client, context) capture = paginator_factory(subjects, [{"subjectKey": "x"}]) @@ -25,11 +25,11 @@ def test_list_builds_path_with_default( def test_get_not_found(monkeypatch, dummy_client, context): - """TODO: Add docstring.""" + """Test that get not found.""" ep = subjects.SubjectsEndpoint(dummy_client, context) def fake_impl(self, client, paginator, *, study_key=None, refresh=False, **filters): - """TODO: Add docstring.""" + """Helper function to fake impl.""" return [] monkeypatch.setattr(subjects.SubjectsEndpoint, "_list_sync", fake_impl) diff --git a/tests/unit/endpoints/test_subjects_filtering.py b/tests/unit/endpoints/test_subjects_filtering.py index 5e520500..1d73f25f 100644 --- a/tests/unit/endpoints/test_subjects_filtering.py +++ b/tests/unit/endpoints/test_subjects_filtering.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for subjects filtering.""" from unittest.mock import AsyncMock, Mock @@ -8,7 +8,7 @@ def test_list_by_site_filtering(): - """TODO: Add docstring.""" + """Test that list by site filtering.""" mock_client = Mock() mock_ctx = Mock() @@ -24,14 +24,14 @@ def test_list_by_site_filtering(): @pytest.mark.asyncio async def test_async_list_by_site_filtering(): - """TODO: Add docstring.""" + """Test that async list by site filtering asynchronously.""" mock_client = Mock() mock_ctx = Mock() endpoint = AsyncSubjectsEndpoint(mock_client, mock_ctx) async def fake_async_list(*args, **kwargs): - """TODO: Add docstring.""" + """Helper function to fake async list.""" if False: yield diff --git a/tests/unit/endpoints/test_users_endpoint.py b/tests/unit/endpoints/test_users_endpoint.py index 0efeeb0d..03c2f5db 100644 --- a/tests/unit/endpoints/test_users_endpoint.py +++ b/tests/unit/endpoints/test_users_endpoint.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for users endpoint.""" import pytest @@ -9,7 +9,7 @@ def test_list_requires_study_key_and_include_inactive(dummy_client, context, paginator_factory): - """TODO: Add docstring.""" + """Test that list requires study key and include inactive.""" ep = users.UsersEndpoint(dummy_client, context) capture = paginator_factory(users, [{"userId": 1}]) @@ -24,11 +24,11 @@ def test_list_requires_study_key_and_include_inactive(dummy_client, context, pag def test_get_not_found(monkeypatch, dummy_client, context): - """TODO: Add docstring.""" + """Test that get not found.""" ep = users.UsersEndpoint(dummy_client, context) def fake_impl(self, client, paginator, *, study_key=None, refresh=False, **filters): - """TODO: Add docstring.""" + """Helper function to fake impl.""" return [] monkeypatch.setattr(users.UsersEndpoint, "_list_sync", fake_impl) diff --git a/tests/unit/endpoints/test_variables_endpoint.py b/tests/unit/endpoints/test_variables_endpoint.py index 0f7cca3d..58d503bc 100644 --- a/tests/unit/endpoints/test_variables_endpoint.py +++ b/tests/unit/endpoints/test_variables_endpoint.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for variables endpoint.""" import pytest @@ -11,7 +11,7 @@ def test_list_requires_study_key_page_size( dummy_client, context, paginator_factory, patch_build_filter ): - """TODO: Add docstring.""" + """Test that list requires study key page size.""" ep = variables.VariablesEndpoint(dummy_client, context) capture = paginator_factory(variables, [{"variableId": 1}]) patch = patch_build_filter(variables) @@ -29,11 +29,11 @@ def test_list_requires_study_key_page_size( def test_get_not_found(monkeypatch, dummy_client, context): - """TODO: Add docstring.""" + """Test that get not found.""" ep = variables.VariablesEndpoint(dummy_client, context) def fake_impl(self, client, paginator, *, study_key=None, **filters): - """TODO: Add docstring.""" + """Helper function to fake impl.""" return [] monkeypatch.setattr(variables.VariablesEndpoint, "_list_sync", fake_impl) @@ -43,7 +43,7 @@ def fake_impl(self, client, paginator, *, study_key=None, **filters): def test_list_makes_request_per_call(dummy_client, context, paginator_factory): - """TODO: Add docstring.""" + """Test that list makes request per call.""" ep = variables.VariablesEndpoint(dummy_client, context) capture = paginator_factory(variables, [{"variableId": 1}]) @@ -54,7 +54,7 @@ def test_list_makes_request_per_call(dummy_client, context, paginator_factory): def test_list_different_study_keys_make_separate_requests(dummy_client, context, paginator_factory): - """TODO: Add docstring.""" + """Test that list different study keys make separate requests.""" ep = variables.VariablesEndpoint(dummy_client, context) capture = paginator_factory(variables, [{"variableId": 1}]) diff --git a/tests/unit/endpoints/test_visits_endpoint.py b/tests/unit/endpoints/test_visits_endpoint.py index 26a4206a..cd4b151b 100644 --- a/tests/unit/endpoints/test_visits_endpoint.py +++ b/tests/unit/endpoints/test_visits_endpoint.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for visits endpoint.""" import pytest @@ -8,7 +8,7 @@ def test_list_filters_and_path(dummy_client, context, paginator_factory, patch_build_filter): - """TODO: Add docstring.""" + """Test that list filters and path.""" context.set_default_study_key("S1") ep = visits.VisitsEndpoint(dummy_client, context) capture = paginator_factory(visits, [{"visitId": 1}]) @@ -23,11 +23,11 @@ def test_list_filters_and_path(dummy_client, context, paginator_factory, patch_b def test_get_not_found(monkeypatch, dummy_client, context): - """TODO: Add docstring.""" + """Test that get not found.""" ep = visits.VisitsEndpoint(dummy_client, context) def fake_impl(self, client, paginator, *, study_key=None, refresh=False, **filters): - """TODO: Add docstring.""" + """Helper function to fake impl.""" return [] monkeypatch.setattr(visits.VisitsEndpoint, "_list_sync", fake_impl) diff --git a/tests/unit/errors/test_api_error.py b/tests/unit/errors/test_api_error.py index 430d7634..6faa211b 100644 --- a/tests/unit/errors/test_api_error.py +++ b/tests/unit/errors/test_api_error.py @@ -1,10 +1,10 @@ -"""TODO: Add docstring.""" +"""Unit tests for api error.""" from imednet.errors.api import ApiError def test_api_error_str_representation(): - """TODO: Add docstring.""" + """Test that api error str representation.""" # Test basic instantiation with string err = ApiError("Something went wrong") assert str(err) == "Something went wrong (Response: Something went wrong)" @@ -21,7 +21,7 @@ def test_api_error_str_representation(): def test_api_error_empty_response(): - """TODO: Add docstring.""" + """Test that api error empty response.""" # Test instantiation with empty response string err = ApiError("", status_code=500) assert str(err) == " (Status Code: 500)" @@ -32,6 +32,6 @@ def test_api_error_empty_response(): def test_api_error_base_str_only(): - """TODO: Add docstring.""" + """Test that api error base str only.""" err = ApiError(None) assert str(err) == "None" diff --git a/tests/unit/form_designer/test_builder.py b/tests/unit/form_designer/test_builder.py index 3ab6679e..7cf0bbd8 100644 --- a/tests/unit/form_designer/test_builder.py +++ b/tests/unit/form_designer/test_builder.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for builder.""" import pytest @@ -6,21 +6,21 @@ def test_form_builder_initialization(): - """TODO: Add docstring.""" + """Test that form builder initialization.""" builder = FormBuilder() assert len(builder.pages) == 1 assert builder.current_page is not None def test_form_builder_add_page(): - """TODO: Add docstring.""" + """Test that form builder add page.""" builder = FormBuilder() builder.add_page() assert len(builder.pages) == 2 def test_form_builder_add_field_text(): - """TODO: Add docstring.""" + """Test that form builder add field text.""" builder = FormBuilder() builder.add_field(type="text", label="My Text", question_name="my_text") @@ -43,14 +43,14 @@ def test_form_builder_add_field_text(): def test_form_builder_add_field_invalid_type(): - """TODO: Add docstring.""" + """Test that form builder add field invalid type.""" builder = FormBuilder() with pytest.raises(ValueError, match="Unsupported field type: invalid"): builder.add_field(type="invalid", label="Invalid", question_name="inv") # type: ignore def test_form_builder_add_all_field_types(): - """TODO: Add docstring.""" + """Test that form builder add all field types.""" builder = FormBuilder() types = ["text", "number", "radio", "dropdown", "datetime", "upload", "checkbox", "memo"] @@ -73,7 +73,7 @@ def test_form_builder_add_all_field_types(): def test_form_builder_add_section_header(): - """TODO: Add docstring.""" + """Test that form builder add section header.""" builder = FormBuilder() builder.add_section_header("My Section") @@ -84,7 +84,7 @@ def test_form_builder_add_section_header(): def test_form_builder_add_group_header(): - """TODO: Add docstring.""" + """Test that form builder add group header.""" builder = FormBuilder() builder.add_group_header("My Group") @@ -101,7 +101,7 @@ def test_form_builder_add_group_header(): def test_form_builder_build(): - """TODO: Add docstring.""" + """Test that form builder build.""" builder = FormBuilder() builder.add_section_header("My Section") layout = builder.build() @@ -109,7 +109,7 @@ def test_form_builder_build(): def test_form_builder_none_rows_initialization(): - """TODO: Add docstring.""" + """Test that form builder none rows initialization.""" builder = FormBuilder() # We need to manually inject a table with no rows to hit lines 92 and 133 diff --git a/tests/unit/form_designer/test_fd_client.py b/tests/unit/form_designer/test_fd_client.py index 8936912e..cded5500 100644 --- a/tests/unit/form_designer/test_fd_client.py +++ b/tests/unit/form_designer/test_fd_client.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for fd client.""" import httpx import pytest @@ -10,12 +10,12 @@ @pytest.fixture def mock_layout(): - """TODO: Add docstring.""" + """Helper function to mock layout.""" return Layout(pages=[Page(entities=[])]) def test_save_form_success(mock_layout, respx_mock): - """TODO: Add docstring.""" + """Test that save form success.""" base_url = "https://test.imednet.com" client = FormDesignerClient(base_url, "fake_sessid") @@ -34,7 +34,7 @@ def test_save_form_success(mock_layout, respx_mock): def test_save_form_server_error(mock_layout, respx_mock): - """TODO: Add docstring.""" + """Test that save form server error.""" base_url = "https://test.imednet.com" client = FormDesignerClient(base_url, "fake_sessid") @@ -47,7 +47,7 @@ def test_save_form_server_error(mock_layout, respx_mock): def test_save_form_http_error(mock_layout, respx_mock): - """TODO: Add docstring.""" + """Test that save form http error.""" base_url = "https://test.imednet.com" client = FormDesignerClient(base_url, "fake_sessid") @@ -92,7 +92,7 @@ def test_save_form_invalid_json_fallback(mock_layout, respx_mock): ], ) def test_save_form_validation_sad_paths(mock_layout, csrf, form_id, comm_id, rev, expected_error): - """TODO: Add docstring.""" + """Test that save form validation sad paths.""" base_url = "https://test.imednet.com" client = FormDesignerClient(base_url, "fake_sessid") diff --git a/tests/unit/form_designer/test_presets.py b/tests/unit/form_designer/test_presets.py index 9fff4af2..c2648b75 100644 --- a/tests/unit/form_designer/test_presets.py +++ b/tests/unit/form_designer/test_presets.py @@ -1,11 +1,11 @@ -"""TODO: Add docstring.""" +"""Unit tests for presets.""" from imednet.form_designer.builder import FormBuilder from imednet.form_designer.presets import PRESETS def test_demo_form_preset(): - """TODO: Add docstring.""" + """Test that demo form preset.""" builder = FormBuilder() PRESETS["Demo Form"](builder) layout = builder.build() @@ -31,7 +31,7 @@ def test_demo_form_preset(): def test_cv_pathology_preset(): - """TODO: Add docstring.""" + """Test that cv pathology preset.""" builder = FormBuilder() PRESETS["CV Pathology"](builder) layout = builder.build() diff --git a/tests/unit/orchestration/conftest.py b/tests/unit/orchestration/conftest.py index 32016470..e936ee0d 100644 --- a/tests/unit/orchestration/conftest.py +++ b/tests/unit/orchestration/conftest.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for conftest.""" from __future__ import annotations @@ -15,7 +15,7 @@ def mock_study() -> Callable[[str], MagicMock]: """Factory fixture: create a mock Study-like object with a study_key.""" def _make(study_key: str) -> MagicMock: - """TODO: Add docstring.""" + """Helper function to make.""" study = MagicMock() study.study_key = study_key return study @@ -34,5 +34,5 @@ def mock_sdk(request: pytest.FixtureRequest) -> MagicMock: @pytest.fixture def orchestrator(mock_sdk: MagicMock) -> MultiStudyOrchestrator: - """TODO: Add docstring.""" + """Helper function to orchestrator.""" return MultiStudyOrchestrator(mock_sdk, max_workers=3) diff --git a/tests/unit/orchestration/test_execute_pipeline.py b/tests/unit/orchestration/test_execute_pipeline.py index 64e06590..11886983 100644 --- a/tests/unit/orchestration/test_execute_pipeline.py +++ b/tests/unit/orchestration/test_execute_pipeline.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for execute pipeline.""" from __future__ import annotations @@ -19,7 +19,7 @@ def test_isolation_study_a_failure_does_not_affect_b_and_c( """STUDY-A raises RuntimeError; STUDY-B and STUDY-C must succeed.""" def pipeline(study_key: str, sdk: object, logger: logging.LoggerAdapter, **kwargs: Any) -> str: - """TODO: Add docstring.""" + """Helper function to pipeline.""" if study_key == "STUDY-A": raise RuntimeError("Simulated failure") return f"processed:{study_key}" @@ -38,7 +38,7 @@ def test_sdk_immutability_across_threads(mock_sdk: MagicMock) -> None: original_id = id(mock_sdk) def pipeline(study_key: str, sdk: object, logger: logging.LoggerAdapter) -> bool: - """TODO: Add docstring.""" + """Helper function to pipeline.""" assert id(sdk) == original_id return True @@ -55,7 +55,7 @@ def test_logger_study_key_propagated_to_worker( """Log records emitted inside workers must carry the correct study_key.""" def pipeline(study_key: str, sdk: object, logger: logging.LoggerAdapter) -> str: - """TODO: Add docstring.""" + """Helper function to pipeline.""" logger.info("Processing %s", study_key) return study_key @@ -72,10 +72,10 @@ def pipeline(study_key: str, sdk: object, logger: logging.LoggerAdapter) -> str: def test_result_contains_duration_seconds(orchestrator: MultiStudyOrchestrator) -> None: - """TODO: Add docstring.""" + """Test that result contains duration seconds.""" def pipeline(study_key: str, sdk: object, logger: logging.LoggerAdapter) -> str: - """TODO: Add docstring.""" + """Helper function to pipeline.""" sleep(0.02) return study_key @@ -85,10 +85,10 @@ def pipeline(study_key: str, sdk: object, logger: logging.LoggerAdapter) -> str: def test_successful_result_error_is_none(orchestrator: MultiStudyOrchestrator) -> None: - """TODO: Add docstring.""" + """Test that successful result error is none.""" def pipeline(study_key: str, sdk: object, logger: logging.LoggerAdapter) -> str: - """TODO: Add docstring.""" + """Helper function to pipeline.""" return study_key results = orchestrator.execute_pipeline(pipeline) @@ -98,10 +98,10 @@ def pipeline(study_key: str, sdk: object, logger: logging.LoggerAdapter) -> str: def test_failed_result_data_is_none(orchestrator: MultiStudyOrchestrator) -> None: - """TODO: Add docstring.""" + """Test that failed result data is none.""" def pipeline(study_key: str, sdk: object, logger: logging.LoggerAdapter) -> str: - """TODO: Add docstring.""" + """Helper function to pipeline.""" raise RuntimeError(f"Boom:{study_key}") results = orchestrator.execute_pipeline(pipeline) @@ -112,10 +112,10 @@ def pipeline(study_key: str, sdk: object, logger: logging.LoggerAdapter) -> str: def test_execute_pipeline_respects_whitelist(orchestrator: MultiStudyOrchestrator) -> None: - """TODO: Add docstring.""" + """Test that execute pipeline respects whitelist.""" def pipeline(study_key: str, sdk: object, logger: logging.LoggerAdapter) -> str: - """TODO: Add docstring.""" + """Helper function to pipeline.""" return study_key results = orchestrator.execute_pipeline(pipeline, whitelist={"STUDY-A"}) @@ -124,10 +124,10 @@ def pipeline(study_key: str, sdk: object, logger: logging.LoggerAdapter) -> str: def test_execute_pipeline_context_propagation(orchestrator: MultiStudyOrchestrator) -> None: - """TODO: Add docstring.""" + """Test that execute pipeline context propagation.""" def pipeline(study_key: str, sdk: object, logger: logging.LoggerAdapter) -> str: - """TODO: Add docstring.""" + """Helper function to pipeline.""" return get_current_study() results = orchestrator.execute_pipeline(pipeline) @@ -139,7 +139,7 @@ def pipeline(study_key: str, sdk: object, logger: logging.LoggerAdapter) -> str: @pytest.mark.parametrize("mock_sdk", [[]], indirect=True) def test_empty_study_list_returns_empty_dict(mock_sdk: MagicMock) -> None: - """TODO: Add docstring.""" + """Test that empty study list returns empty dict.""" orchestrator = MultiStudyOrchestrator(mock_sdk, max_workers=3) results = orchestrator.execute_pipeline(lambda *_args, **_kwargs: True) diff --git a/tests/unit/orchestration/test_log_adapter.py b/tests/unit/orchestration/test_log_adapter.py index 2eaacd38..95dae051 100644 --- a/tests/unit/orchestration/test_log_adapter.py +++ b/tests/unit/orchestration/test_log_adapter.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for log adapter.""" from __future__ import annotations @@ -11,7 +11,7 @@ def test_process_injects_study_key() -> None: - """TODO: Add docstring.""" + """Test that process injects study key.""" adapter = StudyContextLogAdapter(logging.getLogger("tests.orchestration"), "PROT-01") _, kwargs = adapter.process("msg", {}) @@ -21,7 +21,7 @@ def test_process_injects_study_key() -> None: def test_process_preserves_caller_extra() -> None: - """TODO: Add docstring.""" + """Test that process preserves caller extra.""" adapter = StudyContextLogAdapter(logging.getLogger("tests.orchestration"), "PROT-01") input_kwargs: dict[str, Any] = {"extra": {"custom": "value"}} @@ -33,19 +33,19 @@ def test_process_preserves_caller_extra() -> None: def test_study_key_property() -> None: - """TODO: Add docstring.""" + """Test that study key property.""" adapter = StudyContextLogAdapter(logging.getLogger("tests.orchestration"), "PROT-01") assert adapter.study_key == "PROT-01" def test_make_study_logger_returns_adapter() -> None: - """TODO: Add docstring.""" + """Test that make study logger returns adapter.""" assert isinstance(make_study_logger("X"), StudyContextLogAdapter) def test_log_emission_includes_study_key(caplog: pytest.LogCaptureFixture) -> None: - """TODO: Add docstring.""" + """Test that log emission includes study key.""" adapter = make_study_logger("PROT-01") with caplog.at_level(logging.INFO, logger="imednet.orchestration"): diff --git a/tests/unit/orchestration/test_resolve_studies.py b/tests/unit/orchestration/test_resolve_studies.py index d1ae04f5..bf5584c4 100644 --- a/tests/unit/orchestration/test_resolve_studies.py +++ b/tests/unit/orchestration/test_resolve_studies.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for resolve studies.""" from __future__ import annotations @@ -11,38 +11,38 @@ def test_resolve_all_studies(orchestrator: MultiStudyOrchestrator) -> None: - """TODO: Add docstring.""" + """Test that resolve all studies.""" assert orchestrator.resolve_active_studies() == ["STUDY-A", "STUDY-B", "STUDY-C"] def test_whitelist_filter(orchestrator: MultiStudyOrchestrator) -> None: - """TODO: Add docstring.""" + """Test that whitelist filter.""" assert orchestrator.resolve_active_studies(whitelist={"STUDY-A"}) == ["STUDY-A"] def test_blacklist_filter(orchestrator: MultiStudyOrchestrator) -> None: - """TODO: Add docstring.""" + """Test that blacklist filter.""" assert orchestrator.resolve_active_studies(blacklist={"STUDY-A"}) == ["STUDY-B", "STUDY-C"] def test_whitelist_with_nonexistent_key(orchestrator: MultiStudyOrchestrator) -> None: - """TODO: Add docstring.""" + """Test that whitelist with nonexistent key.""" assert orchestrator.resolve_active_studies(whitelist={"NONEXISTENT"}) == [] def test_blacklist_excludes_all(orchestrator: MultiStudyOrchestrator) -> None: - """TODO: Add docstring.""" + """Test that blacklist excludes all.""" assert orchestrator.resolve_active_studies(blacklist={"STUDY-A", "STUDY-B", "STUDY-C"}) == [] def test_filter_conflict_raises(orchestrator: MultiStudyOrchestrator) -> None: - """TODO: Add docstring.""" + """Test that filter conflict raises.""" with pytest.raises(FilterConflictError): orchestrator.resolve_active_studies(whitelist={"STUDY-A"}, blacklist={"STUDY-B"}) def test_filter_conflict_error_attributes(orchestrator: MultiStudyOrchestrator) -> None: - """TODO: Add docstring.""" + """Test that filter conflict error attributes.""" whitelist = {"STUDY-A"} blacklist = {"STUDY-B"} @@ -54,7 +54,7 @@ def test_filter_conflict_error_attributes(orchestrator: MultiStudyOrchestrator) def test_filter_conflict_raised_before_api_call(mock_sdk: MagicMock) -> None: - """TODO: Add docstring.""" + """Test that filter conflict raised before api call.""" orchestrator = MultiStudyOrchestrator(mock_sdk) with pytest.raises(FilterConflictError): @@ -64,11 +64,11 @@ def test_filter_conflict_raised_before_api_call(mock_sdk: MagicMock) -> None: def test_max_workers_validation(mock_sdk: MagicMock) -> None: - """TODO: Add docstring.""" + """Test that max workers validation.""" with pytest.raises(ValueError, match="max_workers must be >= 1"): MultiStudyOrchestrator(mock_sdk, max_workers=0) def test_sdk_stored_as_reference(mock_sdk: MagicMock, orchestrator: MultiStudyOrchestrator) -> None: - """TODO: Add docstring.""" + """Test that sdk stored as reference.""" assert orchestrator.sdk is mock_sdk diff --git a/tests/unit/reporting/test_reporting_models.py b/tests/unit/reporting/test_reporting_models.py index c45faf93..0456a57c 100644 --- a/tests/unit/reporting/test_reporting_models.py +++ b/tests/unit/reporting/test_reporting_models.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for reporting models.""" from datetime import datetime, timezone @@ -9,7 +9,7 @@ def test_adverse_event_parses_alias_input_and_coerces_types() -> None: - """TODO: Add docstring.""" + """Test that adverse event parses alias input and coerces types.""" model = AdverseEvent.model_validate( { "subjectKey": 101, @@ -29,7 +29,7 @@ def test_adverse_event_parses_alias_input_and_coerces_types() -> None: def test_protocol_deviation_applies_defaults_and_parses_datetime_timestamp() -> None: - """TODO: Add docstring.""" + """Test that protocol deviation applies defaults and parses datetime timestamp.""" model = ProtocolDeviation.model_validate( { "subjectKey": 77, @@ -46,7 +46,7 @@ def test_protocol_deviation_applies_defaults_and_parses_datetime_timestamp() -> def test_device_deficiency_parses_valid_input() -> None: - """TODO: Add docstring.""" + """Test that device deficiency parses valid input.""" model = DeviceDeficiency.model_validate( { "subjectKey": "SUBJ-001", @@ -85,13 +85,13 @@ def test_device_deficiency_parses_valid_input() -> None: ], ) def test_reporting_models_reject_missing_required_fields(model_cls: type, payload: dict) -> None: - """TODO: Add docstring.""" + """Test that reporting models reject missing required fields.""" with pytest.raises(ValidationError): model_cls.model_validate(payload) def test_protocol_deviation_rejects_invalid_datetime() -> None: - """TODO: Add docstring.""" + """Test that protocol deviation rejects invalid datetime.""" with pytest.raises(ValidationError): ProtocolDeviation.model_validate( { diff --git a/tests/unit/reporting/test_standards.py b/tests/unit/reporting/test_standards.py index eac156cd..098dd7ff 100644 --- a/tests/unit/reporting/test_standards.py +++ b/tests/unit/reporting/test_standards.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for standards.""" from imednet.models.standards import ( PROFILE_REGISTRY, @@ -9,12 +9,12 @@ def test_profile_registry_contains_general_drug_and_device_profiles() -> None: - """TODO: Add docstring.""" + """Test that profile registry contains general drug and device profiles.""" assert PROFILE_REGISTRY.list_profiles() == ["device", "drug", "general"] def test_drug_profile_enforces_ae_decod_relationship_and_ctcae_grades() -> None: - """TODO: Add docstring.""" + """Test that drug profile enforces ae decod relationship and ctcae grades.""" profile = DrugSafetyProfile() violations = profile.validate( domain="AE", @@ -35,7 +35,7 @@ def test_drug_profile_enforces_ae_decod_relationship_and_ctcae_grades() -> None: def test_general_profile_only_warns_for_missing_recommended_ae_fields() -> None: - """TODO: Add docstring.""" + """Test that general profile only warns for missing recommended ae fields.""" profile = GeneralClinicalProfile() violations = profile.validate( domain="AE", @@ -53,7 +53,7 @@ def test_general_profile_only_warns_for_missing_recommended_ae_fields() -> None: def test_device_profile_requires_boolean_dd_serious() -> None: - """TODO: Add docstring.""" + """Test that device profile requires boolean dd serious.""" profile = DeviceSafetyProfile() violations = profile.validate( domain="DD", diff --git a/tests/unit/reporting/test_study_config.py b/tests/unit/reporting/test_study_config.py index 245b71b6..6f50eaba 100644 --- a/tests/unit/reporting/test_study_config.py +++ b/tests/unit/reporting/test_study_config.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for study config.""" import pytest from pydantic import ValidationError @@ -7,7 +7,7 @@ def test_study_configuration_roundtrip_json_with_aliases() -> None: - """TODO: Add docstring.""" + """Test that study configuration roundtrip json with aliases.""" config = StudyConfiguration.model_validate( { "studyKey": " STUDY-001 ", @@ -49,7 +49,7 @@ def test_study_configuration_roundtrip_json_with_aliases() -> None: def test_study_configuration_accepts_snake_case_field_names() -> None: - """TODO: Add docstring.""" + """Test that study configuration accepts snake case field names.""" config = StudyConfiguration( study_key="STUDY-002", mappings=[ @@ -73,7 +73,7 @@ def test_study_configuration_accepts_snake_case_field_names() -> None: def test_study_configuration_rejects_unknown_reporting_profile() -> None: - """TODO: Add docstring.""" + """Test that study configuration rejects unknown reporting profile.""" with pytest.raises(ValidationError, match="reportingProfile must be one of"): StudyConfiguration.model_validate( { diff --git a/tests/unit/streamlit/test_app.py b/tests/unit/streamlit/test_app.py index a47dcd65..ff698afe 100644 --- a/tests/unit/streamlit/test_app.py +++ b/tests/unit/streamlit/test_app.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for app.""" from __future__ import annotations @@ -12,7 +12,7 @@ def test_dashboard_login_requires_all_fields() -> None: - """TODO: Add docstring.""" + """Test that dashboard login requires all fields.""" # We mock studies so the form renders, but mock credentials so it fails. with ( patch("imednet_streamlit.auth.get_provisioned_studies", return_value=["PROT-100"]), @@ -30,7 +30,7 @@ def test_dashboard_login_requires_all_fields() -> None: def test_dashboard_shows_auth_prompt_when_not_connected() -> None: - """TODO: Add docstring.""" + """Test that dashboard shows auth prompt when not connected.""" at = AppTest.from_file(str(APP_PATH)) at.run() diff --git a/tests/unit/streamlit/test_components_paginated_grid.py b/tests/unit/streamlit/test_components_paginated_grid.py index e7a85713..ef0fd114 100644 --- a/tests/unit/streamlit/test_components_paginated_grid.py +++ b/tests/unit/streamlit/test_components_paginated_grid.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for components paginated grid.""" from __future__ import annotations @@ -11,16 +11,16 @@ class _FakeColumn: - """TODO: Add docstring.""" + """Test suite for FakeColumn.""" def __init__(self, *, next_click: bool = False, prev_click: bool = False) -> None: - """TODO: Add docstring.""" + """Initialize the test object.""" self._next_click = next_click self._prev_click = prev_click self.captions: list[str] = [] def button(self, label: str, **kwargs: Any) -> bool: - """TODO: Add docstring.""" + """Helper function to button.""" if label == "Next": return self._next_click if label == "Previous": @@ -28,12 +28,12 @@ def button(self, label: str, **kwargs: Any) -> bool: return False def caption(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to caption.""" self.captions.append(value) def test_paginated_slice_limits_rows_to_active_page(monkeypatch: pytest.MonkeyPatch) -> None: - """TODO: Add docstring.""" + """Test that paginated slice limits rows to active page.""" session_state: dict[str, Any] = {} prev_col = _FakeColumn() info_col = _FakeColumn() @@ -57,7 +57,7 @@ def test_paginated_slice_limits_rows_to_active_page(monkeypatch: pytest.MonkeyPa def test_paginated_slice_moves_to_next_page(monkeypatch: pytest.MonkeyPatch) -> None: - """TODO: Add docstring.""" + """Test that paginated slice moves to next page.""" session_state: dict[str, Any] = {"records_page": 1} prev_col = _FakeColumn() info_col = _FakeColumn() @@ -81,7 +81,7 @@ def test_paginated_slice_moves_to_next_page(monkeypatch: pytest.MonkeyPatch) -> def test_top_n_with_other_adds_remainder_bucket() -> None: - """TODO: Add docstring.""" + """Test that top n with other adds remainder bucket.""" df = pd.DataFrame({"label": ["A", "B", "C", "D"], "count": [10, 8, 3, 2]}) result = paginated_grid.top_n_with_other( diff --git a/tests/unit/streamlit/test_pages_data_lineage.py b/tests/unit/streamlit/test_pages_data_lineage.py index c030d7f3..7d2f4b8b 100644 --- a/tests/unit/streamlit/test_pages_data_lineage.py +++ b/tests/unit/streamlit/test_pages_data_lineage.py @@ -20,43 +20,43 @@ class _FakeContextManager: - """TODO: Add docstring.""" + """Test suite for FakeContextManager.""" def __enter__(self) -> "_FakeContextManager": - """TODO: Add docstring.""" + """Helper function to enter .""" return self def __exit__(self, *args: Any) -> None: - """TODO: Add docstring.""" + """Helper function to exit .""" pass # Make it usable as a column mock with common widget methods def metric(self, label: str, value: Any, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to metric.""" pass def button(self, label: str, **kwargs: Any) -> bool: - """TODO: Add docstring.""" + """Helper function to button.""" return False def text_input(self, label: str, **kwargs: Any) -> str: - """TODO: Add docstring.""" + """Helper function to text input.""" return str(kwargs.get("value", "")) def selectbox(self, label: str, options: list[Any], index: int = 0, **kwargs: Any) -> Any: - """TODO: Add docstring.""" + """Helper function to selectbox.""" return options[index] def dataframe(self, df: Any, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to dataframe.""" pass class _FakeStreamlit: - """TODO: Add docstring.""" + """Test suite for FakeStreamlit.""" def __init__(self) -> None: - """TODO: Add docstring.""" + """Initialize the test object.""" self.session_state: dict[str, Any] = {"_imednet_connected": True} self.success_calls: list[str] = [] self.warning_calls: list[str] = [] @@ -69,58 +69,58 @@ def __init__(self) -> None: self.text_input_values: dict[str, str] = {} def title(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to title.""" pass def subheader(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to subheader.""" pass def markdown(self, value: str, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to markdown.""" pass def info(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to info.""" self.info_calls.append(value) def success(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to success.""" self.success_calls.append(value) def warning(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to warning.""" self.warning_calls.append(value) def error(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to error.""" self.error_calls.append(value) def divider(self) -> None: - """TODO: Add docstring.""" + """Helper function to divider.""" pass def json(self, value: Any) -> None: - """TODO: Add docstring.""" + """Helper function to json.""" self.json_calls.append(value) def dataframe(self, df: Any, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to dataframe.""" self.dataframe_calls.append(df) def metric(self, label: str, value: Any, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to metric.""" self.metric_calls.append({"label": label, "value": value}) def button(self, label: str, **kwargs: Any) -> bool: - """TODO: Add docstring.""" + """Helper function to button.""" key = str(kwargs.get("key") or label) if kwargs.get("disabled", False): return False return key in self.button_presses def columns(self, spec: Any) -> list[_FakeContextManager]: - """TODO: Add docstring.""" + """Helper function to columns.""" count = spec if isinstance(spec, int) else len(spec) cols = [] for _ in range(count): @@ -134,35 +134,35 @@ def columns(self, spec: Any) -> list[_FakeContextManager]: return cols def selectbox(self, label: str, options: list[Any], index: int = 0, **kwargs: Any) -> Any: - """TODO: Add docstring.""" + """Helper function to selectbox.""" return options[index] def text_input(self, label: str, **kwargs: Any) -> str: - """TODO: Add docstring.""" + """Helper function to text input.""" key = str(kwargs.get("key") or label) if key in self.text_input_values: return self.text_input_values[key] return str(kwargs.get("value", "")) def text_area(self, label: str, **kwargs: Any) -> str: - """TODO: Add docstring.""" + """Helper function to text area.""" return str(kwargs.get("value", "")) def expander(self, label: str, **kwargs: Any) -> _FakeContextManager: - """TODO: Add docstring.""" + """Helper function to expander.""" return _FakeContextManager() def caption(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to caption.""" pass def progress(self, value: float) -> None: - """TODO: Add docstring.""" + """Helper function to progress.""" pass def _make_fake_records() -> list[Any]: - """TODO: Add docstring.""" + """Helper function to make fake records.""" return [ SimpleNamespace( record_id=1, @@ -180,7 +180,7 @@ def _make_fake_records() -> list[Any]: def _make_extraction() -> ExtractionResult: - """TODO: Add docstring.""" + """Helper function to make extraction.""" ae1 = AdverseEvent( subjectKey="SUBJ-001", aeTerm="headache", @@ -199,7 +199,7 @@ def _run_data_lineage( *, study_key: str = "STUDY-01", ) -> None: - """TODO: Add docstring.""" + """Helper function to run data lineage.""" fake_streamlit_module = ModuleType("streamlit") fake_streamlit_module.session_state = fake_st.session_state # type: ignore[attr-defined] for attr in ( @@ -234,14 +234,14 @@ def _run_data_lineage( fake_extraction = _make_extraction() class _FakeLoader: - """TODO: Add docstring.""" + """Test suite for FakeLoader.""" def __init__(self, sdk: object) -> None: - """TODO: Add docstring.""" + """Initialize the test object.""" pass def load_records(self, sk: str) -> list[Any]: - """TODO: Add docstring.""" + """Helper function to load records.""" return fake_records fake_workflows_module = ModuleType("imednet_workflows") diff --git a/tests/unit/streamlit/test_pages_publisher_wizard.py b/tests/unit/streamlit/test_pages_publisher_wizard.py index 7547723b..88ab6596 100644 --- a/tests/unit/streamlit/test_pages_publisher_wizard.py +++ b/tests/unit/streamlit/test_pages_publisher_wizard.py @@ -18,7 +18,7 @@ def _make_committed_store(tmp_path: Path, study_key: str = "STUDY-01") -> ConfigVersionStore: - """TODO: Add docstring.""" + """Helper function to make committed store.""" store = ConfigVersionStore(db_path=tmp_path / "versions.sqlite3") config = StudyConfiguration( version="1.0.0", @@ -41,22 +41,22 @@ def _make_committed_store(tmp_path: Path, study_key: str = "STUDY-01") -> Config class _FakeContextManager: - """TODO: Add docstring.""" + """Test suite for FakeContextManager.""" def __enter__(self) -> "_FakeContextManager": - """TODO: Add docstring.""" + """Helper function to enter .""" return self def __exit__(self, *args: Any) -> None: - """TODO: Add docstring.""" + """Helper function to exit .""" pass class _FakeStreamlit: - """TODO: Add docstring.""" + """Test suite for FakeStreamlit.""" def __init__(self) -> None: - """TODO: Add docstring.""" + """Initialize the test object.""" self.session_state: dict[str, Any] = {"_imednet_connected": True} self.success_calls: list[str] = [] self.warning_calls: list[str] = [] @@ -67,54 +67,54 @@ def __init__(self) -> None: self.text_input_values: dict[str, str] = {} def title(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to title.""" pass def subheader(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to subheader.""" pass def markdown(self, value: str, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to markdown.""" pass def info(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to info.""" self.info_calls.append(value) def success(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to success.""" self.success_calls.append(value) def warning(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to warning.""" self.warning_calls.append(value) def error(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to error.""" self.error_calls.append(value) def divider(self) -> None: - """TODO: Add docstring.""" + """Helper function to divider.""" pass def json(self, value: Any) -> None: - """TODO: Add docstring.""" + """Helper function to json.""" pass def dataframe(self, df: Any, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to dataframe.""" pass def button(self, label: str, **kwargs: Any) -> bool: - """TODO: Add docstring.""" + """Helper function to button.""" key = str(kwargs.get("key") or label) if kwargs.get("disabled", False): return False return key in self.button_presses def columns(self, spec: Any) -> list[_FakeContextManager]: - """TODO: Add docstring.""" + """Helper function to columns.""" count = spec if isinstance(spec, int) else len(spec) cols = [_FakeContextManager() for _ in range(count)] # Attach button and other widget methods to each column @@ -126,37 +126,37 @@ def columns(self, spec: Any) -> list[_FakeContextManager]: return cols def selectbox(self, label: str, options: list[Any], index: int = 0, **kwargs: Any) -> Any: - """TODO: Add docstring.""" + """Helper function to selectbox.""" key = str(kwargs.get("key") or label) if key in self.selectbox_values and self.selectbox_values[key] in options: return self.selectbox_values[key] return options[index] def text_input(self, label: str, **kwargs: Any) -> str: - """TODO: Add docstring.""" + """Helper function to text input.""" key = str(kwargs.get("key") or label) if key in self.text_input_values: return self.text_input_values[key] return str(kwargs.get("value", "")) def text_area(self, label: str, **kwargs: Any) -> str: - """TODO: Add docstring.""" + """Helper function to text area.""" return str(kwargs.get("value", "")) def expander(self, label: str, **kwargs: Any) -> _FakeContextManager: - """TODO: Add docstring.""" + """Helper function to expander.""" return _FakeContextManager() def metric(self, label: str, value: Any, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to metric.""" pass def caption(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to caption.""" pass def progress(self, value: float) -> None: - """TODO: Add docstring.""" + """Helper function to progress.""" pass @@ -166,7 +166,7 @@ def _run_publisher_wizard( *, study_key: str = "STUDY-01", ) -> None: - """TODO: Add docstring.""" + """Helper function to run publisher wizard.""" fake_streamlit_module = ModuleType("streamlit") fake_streamlit_module.session_state = fake_st.session_state # type: ignore[attr-defined] for attr in ( @@ -196,19 +196,19 @@ def _run_publisher_wizard( fake_auth_module.get_study_key = lambda: study_key # type: ignore[attr-defined] class FakeAuth: - """TODO: Add docstring.""" + """Test suite for FakeAuth.""" def get_user_roles(self): - """TODO: Add docstring.""" + """Helper function to get user roles.""" # Read from session state simulator instead of UI return [fake_st.selectbox_values.get("_publisher_role", "viewer")] def get_user_id(self): - """TODO: Add docstring.""" + """Helper function to get user id.""" return fake_st.text_input_values.get("_publisher_user", "") class FakeSDK: - """TODO: Add docstring.""" + """Test suite for FakeSDK.""" auth = FakeAuth() diff --git a/tests/unit/streamlit/test_pages_reporting_dashboard.py b/tests/unit/streamlit/test_pages_reporting_dashboard.py index ce7e58dc..55271f9a 100644 --- a/tests/unit/streamlit/test_pages_reporting_dashboard.py +++ b/tests/unit/streamlit/test_pages_reporting_dashboard.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for pages reporting dashboard.""" from __future__ import annotations @@ -24,36 +24,36 @@ class _FakeContextManager: - """TODO: Add docstring.""" + """Test suite for FakeContextManager.""" def __enter__(self) -> "_FakeContextManager": - """TODO: Add docstring.""" + """Helper function to enter .""" return self def __exit__(self, *args: Any) -> None: - """TODO: Add docstring.""" + """Helper function to exit .""" pass class _FakeCacheDataDecorator: - """TODO: Add docstring.""" + """Test suite for FakeCacheDataDecorator.""" def __call__(self, func: Any = None, **kwargs: Any) -> Any: - """TODO: Add docstring.""" + """Helper function to call .""" if func is not None: return func return lambda f: f def clear(self) -> None: - """TODO: Add docstring.""" + """Helper function to clear.""" pass class _FakeStreamlit: - """TODO: Add docstring.""" + """Test suite for FakeStreamlit.""" def __init__(self, *, multiselect_values: dict[str, list[Any]] | None = None) -> None: - """TODO: Add docstring.""" + """Initialize the test object.""" self.session_state: dict[str, Any] = {"_imednet_connected": True} self.cache_data = _FakeCacheDataDecorator() self.sidebar = _FakeContextManager() @@ -66,96 +66,96 @@ def __init__(self, *, multiselect_values: dict[str, list[Any]] | None = None) -> self.successes: list[str] = [] def title(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to title.""" pass def subheader(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to subheader.""" pass def info(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to info.""" self.infos.append(value) def success(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to success.""" self.successes.append(value) def warning(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to warning.""" pass def markdown(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to markdown.""" pass def button(self, label: str, **kwargs: Any) -> bool: - """TODO: Add docstring.""" + """Helper function to button.""" return False def text_input(self, label: str, **kwargs: Any) -> str: - """TODO: Add docstring.""" + """Helper function to text input.""" return "" def selectbox(self, label: str, options: list[Any], index: int = 0, **kwargs: Any) -> Any: - """TODO: Add docstring.""" + """Helper function to selectbox.""" if label in self.selectbox_values: return self.selectbox_values[label] return options[index] def multiselect(self, label: str, options: list[Any], **kwargs: Any) -> list[Any]: - """TODO: Add docstring.""" + """Helper function to multiselect.""" if label in self.multiselect_values: return self.multiselect_values[label] return list(kwargs.get("default", [])) def date_input(self, label: str, *, value: Any, **kwargs: Any) -> list[Any]: - """TODO: Add docstring.""" + """Helper function to date input.""" if isinstance(value, (list, tuple)): return list(value) return [value] def columns(self, spec: Any) -> list[Any]: - """TODO: Add docstring.""" + """Helper function to columns.""" count = spec if isinstance(spec, int) else len(spec) return [_FakeContextManager() for _ in range(count)] def tabs(self, names: list[str]) -> list[Any]: - """TODO: Add docstring.""" + """Helper function to tabs.""" return [_FakeContextManager() for _ in names] def dataframe(self, df: Any, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to dataframe.""" self.dataframes.append(df) def altair_chart(self, chart: Any, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to altair chart.""" pass def rerun(self) -> None: - """TODO: Add docstring.""" + """Helper function to rerun.""" pass def _make_fake_components_module(fake_st: _FakeStreamlit) -> ModuleType: - """TODO: Add docstring.""" + """Helper function to make fake components module.""" module = ModuleType("imednet_streamlit.components") module.PALETTE = ["#1f77b4", "#ff7f0e", "#2ca02c"] # type: ignore[attr-defined] def _kpi_row(metrics: list[dict[str, Any]]) -> None: - """TODO: Add docstring.""" + """Helper function to kpi row.""" fake_st.kpi_rows.append(metrics) def _bar_chart(*args: Any, **kwargs: Any) -> MagicMock: - """TODO: Add docstring.""" + """Helper function to bar chart.""" return MagicMock() def _line_chart(*args: Any, **kwargs: Any) -> MagicMock: - """TODO: Add docstring.""" + """Helper function to line chart.""" return MagicMock() def _filterable_dataframe(df: Any, *, key: str, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to filterable dataframe.""" fake_st.tables[key] = df module.kpi_row = _kpi_row # type: ignore[attr-defined] @@ -166,7 +166,7 @@ def _filterable_dataframe(df: Any, *, key: str, **kwargs: Any) -> None: def _run_page(*, multiselect_values: dict[str, list[Any]] | None = None) -> _FakeStreamlit: - """TODO: Add docstring.""" + """Helper function to run page.""" fake_st = _FakeStreamlit(multiselect_values=multiselect_values) for key in list(sys.modules): @@ -240,10 +240,10 @@ def _run_page(*, multiselect_values: dict[str, list[Any]] | None = None) -> _Fak fake_components_module = _make_fake_components_module(fake_st) class _ExtractionResult: - """TODO: Add docstring.""" + """Test suite for ExtractionResult.""" def __init__(self) -> None: - """TODO: Add docstring.""" + """Initialize the test object.""" self.adverse_events = [ AdverseEvent.model_validate( { @@ -337,12 +337,12 @@ def __init__(self) -> None: def _kpi_dict(metrics: list[dict[str, Any]]) -> dict[str, Any]: - """TODO: Add docstring.""" + """Helper function to kpi dict.""" return {entry["label"]: entry["value"] for entry in metrics} def test_reporting_dashboard_renders_expected_kpis_and_site_aggregation() -> None: - """TODO: Add docstring.""" + """Test that reporting dashboard renders expected kpis and site aggregation.""" fake_st = _run_page() kpi_maps = [_kpi_dict(row) for row in fake_st.kpi_rows] @@ -364,7 +364,7 @@ def test_reporting_dashboard_renders_expected_kpis_and_site_aggregation() -> Non def test_reporting_dashboard_filters_cascade_to_adverse_event_table() -> None: - """TODO: Add docstring.""" + """Test that reporting dashboard filters cascade to adverse event table.""" fake_st = _run_page( multiselect_values={ "Site": ["Site A"], @@ -391,7 +391,7 @@ def __init__( protocol_deviations: list[Any] | None = None, device_deficiencies: list[Any] | None = None, ) -> None: - """TODO: Add docstring.""" + """Initialize the test object.""" self.adverse_events = adverse_events or [] self.protocol_deviations = protocol_deviations or [] self.device_deficiencies = device_deficiencies or [] @@ -424,7 +424,7 @@ def _run_page_extended( _button_overrides["⭐ Set as Default"] = True def _patched_button(label: str, **kwargs: Any) -> bool: - """TODO: Add docstring.""" + """Helper function to patched button.""" return _button_overrides.get(label, False) fake_st.button = _patched_button # type: ignore[method-assign] @@ -433,7 +433,7 @@ def _patched_button(label: str, **kwargs: Any) -> bool: if save_view_name: def _patched_text_input(label: str, **kwargs: Any) -> str: - """TODO: Add docstring.""" + """Helper function to patched text input.""" return save_view_name if label == "Save Current View As" else "" fake_st.text_input = _patched_text_input # type: ignore[method-assign] diff --git a/tests/unit/streamlit/test_pages_setup_wizard.py b/tests/unit/streamlit/test_pages_setup_wizard.py index 3da177be..03a5fc30 100644 --- a/tests/unit/streamlit/test_pages_setup_wizard.py +++ b/tests/unit/streamlit/test_pages_setup_wizard.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for pages setup wizard.""" from __future__ import annotations @@ -15,46 +15,46 @@ class _FakeColumn: - """TODO: Add docstring.""" + """Test suite for FakeColumn.""" def __init__(self, parent: "_FakeStreamlit") -> None: - """TODO: Add docstring.""" + """Initialize the test object.""" self._parent = parent def button(self, label: str, **kwargs: Any) -> bool: - """TODO: Add docstring.""" + """Helper function to button.""" return self._parent.button(label, **kwargs) def selectbox(self, label: str, options: list[str], **kwargs: Any) -> str: - """TODO: Add docstring.""" + """Helper function to selectbox.""" return self._parent.selectbox(label, options, **kwargs) def text_input(self, label: str, **kwargs: Any) -> str: - """TODO: Add docstring.""" + """Helper function to text input.""" return self._parent.text_input(label, **kwargs) def metric(self, label: str, value: Any, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to metric.""" self._parent.metric(label, value, **kwargs) class _FakeContextManager: - """TODO: Add docstring.""" + """Test suite for FakeContextManager.""" def __enter__(self) -> "_FakeContextManager": - """TODO: Add docstring.""" + """Helper function to enter .""" return self def __exit__(self, exc_type: Any, exc: Any, tb: Any) -> None: - """TODO: Add docstring.""" + """Helper function to exit .""" return None class _FakeStreamlit: - """TODO: Add docstring.""" + """Test suite for FakeStreamlit.""" def __init__(self) -> None: - """TODO: Add docstring.""" + """Initialize the test object.""" self.session_state: dict[str, Any] = { "_imednet_connected": True, "_imednet_study_key": "STUDY", @@ -76,71 +76,71 @@ def __init__(self) -> None: self.expander_calls: list[tuple[str, bool]] = [] def title(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to title.""" self.titles.append(value) def subheader(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to subheader.""" return None def markdown(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to markdown.""" self.markdown_calls.append(value) def caption(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to caption.""" return None def expander(self, label: str, *, expanded: bool = False) -> _FakeContextManager: - """TODO: Add docstring.""" + """Helper function to expander.""" self.expander_calls.append((label, expanded)) return _FakeContextManager() def code(self, body: str, *, language: str = "") -> None: - """TODO: Add docstring.""" + """Helper function to code.""" self.code_calls.append(body) def progress(self, value: float) -> None: - """TODO: Add docstring.""" + """Helper function to progress.""" return None def success(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to success.""" self.success_calls.append(value) def warning(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to warning.""" self.warning_calls.append(value) def info(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to info.""" self.info_calls.append(value) def error(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to error.""" self.error_calls.append(value) def button(self, label: str, **kwargs: Any) -> bool: - """TODO: Add docstring.""" + """Helper function to button.""" key = str(kwargs.get("key") or label) if kwargs.get("disabled", False): return False return key in self.button_presses def columns(self, spec: int | list[Any]) -> list[_FakeColumn]: - """TODO: Add docstring.""" + """Helper function to columns.""" count = spec if isinstance(spec, int) else len(spec) return [_FakeColumn(self) for _ in range(count)] def selectbox(self, label: str, options: list[str], **kwargs: Any) -> str: - """TODO: Add docstring.""" + """Helper function to selectbox.""" key = str(kwargs.get("key") or label) if key in self.selectbox_values and self.selectbox_values[key] in options: return self.selectbox_values[key] return str(options[0]) if options else "" def text_input(self, label: str, **kwargs: Any) -> str: - """TODO: Add docstring.""" + """Helper function to text input.""" key = str(kwargs.get("key") or label) if key in self.text_input_values: return self.text_input_values[key] @@ -148,7 +148,7 @@ def text_input(self, label: str, **kwargs: Any) -> str: return str(value) if value is not None else "" def multiselect(self, label: str, options: list[str], **kwargs: Any) -> list[str]: - """TODO: Add docstring.""" + """Helper function to multiselect.""" key = str(kwargs.get("key") or label) if key in self.multiselect_values: return self.multiselect_values[key] @@ -159,57 +159,57 @@ def multiselect(self, label: str, options: list[str], **kwargs: Any) -> list[str return [str(value) for value in default] def slider(self, label: str, **kwargs: Any) -> int: - """TODO: Add docstring.""" + """Helper function to slider.""" if self.slider_value is not None: return self.slider_value return int(kwargs.get("value", kwargs.get("min_value", 0))) def dataframe(self, df: Any, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to dataframe.""" return None def metric(self, label: str, value: Any, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to metric.""" self.metric_calls.append({"label": label, "value": value}) def json(self, value: Any) -> None: - """TODO: Add docstring.""" + """Helper function to json.""" return None def download_button(self, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to download button.""" self.download_calls.append(kwargs) class _WidgetOwnedSessionState(dict[str, Any]): - """TODO: Add docstring.""" + """Test suite for WidgetOwnedSessionState.""" def __init__(self, initial_state: dict[str, Any]) -> None: - """TODO: Add docstring.""" + """Initialize the test object.""" super().__init__(initial_state) self._widget_owned_keys: set[str] = set() def lock_widget_key(self, key: str) -> None: - """TODO: Add docstring.""" + """Helper function to lock widget key.""" self._widget_owned_keys.add(key) def __setitem__(self, key: str, value: Any) -> None: - """TODO: Add docstring.""" + """Helper function to setitem .""" if key in self._widget_owned_keys: raise RuntimeError(f"session_state key '{key}' is widget-owned") super().__setitem__(key, value) class _StrictWidgetStateFakeStreamlit(_FakeStreamlit): - """TODO: Add docstring.""" + """Test suite for StrictWidgetStateFakeStreamlit.""" def __init__(self) -> None: - """TODO: Add docstring.""" + """Initialize the test object.""" super().__init__() self.session_state = _WidgetOwnedSessionState(dict(self.session_state)) def selectbox(self, label: str, options: list[str], **kwargs: Any) -> str: - """TODO: Add docstring.""" + """Helper function to selectbox.""" value = super().selectbox(label, options, **kwargs) key = str(kwargs.get("key") or label) dict.__setitem__(self.session_state, key, value) @@ -223,7 +223,7 @@ def _run_setup_wizard( get_sdk: Any | None = None, get_study_key: Any | None = None, ) -> None: - """TODO: Add docstring.""" + """Helper function to run setup wizard.""" page_path = PACKAGE_ROOT / "pages" / "setup_wizard.py" module_name = "imednet_streamlit.pages.setup_wizard" @@ -289,28 +289,28 @@ def _run_setup_wizard( } class _FakeLoader: - """TODO: Add docstring.""" + """Test suite for FakeLoader.""" def __init__(self, sdk: object) -> None: - """TODO: Add docstring.""" + """Initialize the test object.""" self.sdk = sdk def load_records(self, study_key: str) -> list[Any]: - """TODO: Add docstring.""" + """Helper function to load records.""" return records class _FakeProfiler: - """TODO: Add docstring.""" + """Test suite for FakeProfiler.""" def __init__(self, sdk: object, loader: object) -> None: - """TODO: Add docstring.""" + """Initialize the test object.""" self.sdk = sdk self.loader = loader def profile_records( self, study_key: str, *, records: list[Any] | None = None ) -> dict[str, Any]: - """TODO: Add docstring.""" + """Helper function to profile records.""" return profiles fake_auth_module = ModuleType("imednet_streamlit.auth") @@ -350,7 +350,7 @@ def profile_records( def test_setup_wizard_scan_and_next_step() -> None: - """TODO: Add docstring.""" + """Test that setup wizard scan and next step.""" fake_st = _FakeStreamlit() fake_st.button_presses = {"wizard_scan"} _run_setup_wizard(fake_st) @@ -365,7 +365,7 @@ def test_setup_wizard_scan_and_next_step() -> None: def test_setup_wizard_scan_post_scan_rerender_respects_widget_owned_state() -> None: - """TODO: Add docstring.""" + """Test that setup wizard scan post scan rerender respects widget owned state.""" fake_st = _StrictWidgetStateFakeStreamlit() fake_st.button_presses = {"wizard_scan"} @@ -377,7 +377,7 @@ def test_setup_wizard_scan_post_scan_rerender_respects_widget_owned_state() -> N def test_setup_wizard_renders_design_specification_sections() -> None: - """TODO: Add docstring.""" + """Test that setup wizard renders design specification sections.""" fake_st = _FakeStreamlit() _run_setup_wizard(fake_st) @@ -390,7 +390,7 @@ def test_setup_wizard_renders_design_specification_sections() -> None: def test_setup_wizard_mapping_normalization_preview_and_export() -> None: - """TODO: Add docstring.""" + """Test that setup wizard mapping normalization preview and export.""" fake_st = _FakeStreamlit() fake_st.session_state["wizard_step"] = 2 fake_st.session_state["mapping_config"] = StudyConfiguration(study_key="STUDY") @@ -454,7 +454,7 @@ def test_setup_wizard_mapping_normalization_preview_and_export() -> None: def test_setup_wizard_mapping_falls_back_when_saved_form_is_missing() -> None: - """TODO: Add docstring.""" + """Test that setup wizard mapping falls back when saved form is missing.""" fake_st = _FakeStreamlit() fake_st.session_state["wizard_step"] = 2 fake_st.session_state["mapping_config"] = StudyConfiguration.from_json( @@ -491,7 +491,7 @@ def test_setup_wizard_mapping_falls_back_when_saved_form_is_missing() -> None: def test_setup_wizard_preview_filters_invalid_saved_widget_types() -> None: - """TODO: Add docstring.""" + """Test that setup wizard preview filters invalid saved widget types.""" fake_st = _FakeStreamlit() fake_st.session_state["wizard_step"] = 4 fake_st.session_state["mapping_config"] = StudyConfiguration.from_json( @@ -532,7 +532,7 @@ def test_setup_wizard_preview_filters_invalid_saved_widget_types() -> None: def test_setup_wizard_save_managed_database(monkeypatch: Any) -> None: - """TODO: Add docstring.""" + """Test that setup wizard save managed database.""" fake_st = _FakeStreamlit() fake_st.session_state["wizard_step"] = 5 fake_st.session_state["_imednet_study_key"] = "STUDY-123" @@ -540,10 +540,10 @@ def test_setup_wizard_save_managed_database(monkeypatch: Any) -> None: fake_st.button_presses = {"wizard_save_managed"} class MockStore: - """TODO: Add docstring.""" + """Test suite for MockStore.""" def commit_config(self, study_key, config, user, desc): - """TODO: Add docstring.""" + """Helper function to commit config.""" self.study_key = study_key self.user = user @@ -559,17 +559,17 @@ def commit_config(self, study_key, config, user, desc): def test_setup_wizard_save_managed_reports_error(monkeypatch: Any) -> None: - """TODO: Add docstring.""" + """Test that setup wizard save managed reports error.""" fake_st = _FakeStreamlit() fake_st.session_state["wizard_step"] = 5 fake_st.session_state["mapping_config"] = StudyConfiguration(study_key="STUDY") fake_st.button_presses = {"wizard_save_managed"} class MockStore: - """TODO: Add docstring.""" + """Test suite for MockStore.""" def commit_config(self, study_key, config, user, desc): - """TODO: Add docstring.""" + """Helper function to commit config.""" raise OSError("boom") monkeypatch.setattr( @@ -582,7 +582,7 @@ def commit_config(self, study_key, config, user, desc): def test_setup_wizard_shows_prerequisite_info_messages() -> None: - """TODO: Add docstring.""" + """Test that setup wizard shows prerequisite info messages.""" step_one = _FakeStreamlit() _run_setup_wizard(step_one) assert step_one.info_calls[-1] == "Run scan to discover forms and field candidates." @@ -607,7 +607,7 @@ def test_setup_wizard_shows_prerequisite_info_messages() -> None: def test_setup_wizard_handles_connection_and_auth_failures() -> None: - """TODO: Add docstring.""" + """Test that setup wizard handles connection and auth failures.""" disconnected = _FakeStreamlit() disconnected.session_state["_imednet_connected"] = False _run_setup_wizard(disconnected) @@ -618,7 +618,7 @@ def test_setup_wizard_handles_connection_and_auth_failures() -> None: auth_failure = _FakeStreamlit() def _raise_runtime_error() -> object: - """TODO: Add docstring.""" + """Helper function to raise runtime error.""" raise RuntimeError("missing credentials") _run_setup_wizard(auth_failure, get_sdk=_raise_runtime_error) @@ -626,7 +626,7 @@ def _raise_runtime_error() -> object: def test_setup_wizard_snapshot_controls_and_navigation_work() -> None: - """TODO: Add docstring.""" + """Test that setup wizard snapshot controls and navigation work.""" fake_st = _FakeStreamlit() fake_st.session_state["wizard_step"] = 3 fake_st.session_state["mapping_config"] = StudyConfiguration.from_json( @@ -684,7 +684,7 @@ def test_setup_wizard_snapshot_controls_and_navigation_work() -> None: def test_setup_wizard_undo_without_snapshot_and_nav_button_paths() -> None: - """TODO: Add docstring.""" + """Test that setup wizard undo without snapshot and nav button paths.""" fake_st = _FakeStreamlit() fake_st.session_state["wizard_step"] = 3 fake_st.session_state["mapping_config"] = StudyConfiguration.from_json( @@ -732,7 +732,7 @@ def test_setup_wizard_undo_without_snapshot_and_nav_button_paths() -> None: def test_setup_wizard_preview_handles_empty_records() -> None: - """TODO: Add docstring.""" + """Test that setup wizard preview handles empty records.""" fake_st = _FakeStreamlit() fake_st.session_state["wizard_step"] = 4 fake_st.session_state["mapping_config"] = StudyConfiguration.from_json( diff --git a/tests/unit/streamlit/test_review_workbench.py b/tests/unit/streamlit/test_review_workbench.py index d40827a7..f8c57b3f 100644 --- a/tests/unit/streamlit/test_review_workbench.py +++ b/tests/unit/streamlit/test_review_workbench.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for review workbench.""" from __future__ import annotations @@ -34,32 +34,32 @@ class _FakeContextManager: - """TODO: Add docstring.""" + """Test suite for FakeContextManager.""" def __init__(self, streamlit_client: "_FakeStreamlit | None" = None) -> None: - """TODO: Add docstring.""" + """Initialize the test object.""" self._streamlit_client = streamlit_client def __enter__(self) -> "_FakeContextManager": - """TODO: Add docstring.""" + """Helper function to enter .""" return self def __exit__(self, *args: Any) -> None: - """TODO: Add docstring.""" + """Helper function to exit .""" pass def button(self, label: str, **kwargs: Any) -> bool: - """TODO: Add docstring.""" + """Helper function to button.""" if self._streamlit_client is None: return False return self._streamlit_client.button(label, **kwargs) class _FakeStreamlit: - """TODO: Add docstring.""" + """Test suite for FakeStreamlit.""" def __init__(self) -> None: - """TODO: Add docstring.""" + """Initialize the test object.""" self.session_state: dict[str, Any] = {} self.metrics: dict[str, Any] = {} self.frames: list[Any] = [] @@ -69,74 +69,74 @@ def __init__(self) -> None: self.button_presses: set[str] = set() def title(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to title.""" pass def markdown(self, value: str, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to markdown.""" pass def info(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to info.""" pass def columns(self, spec: int | list[Any], **kwargs: Any) -> list[_FakeContextManager]: - """TODO: Add docstring.""" + """Helper function to columns.""" count = spec if isinstance(spec, int) else len(spec) return [_FakeContextManager(self) for _ in range(count)] def metric(self, label: str, value: Any, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to metric.""" self.metrics[label] = value def multiselect(self, label: str, options: list[str], **kwargs: Any) -> list[str]: - """TODO: Add docstring.""" + """Helper function to multiselect.""" return self.multiselect_values.get(label, list(kwargs.get("default", []))) def text_input(self, label: str, **kwargs: Any) -> str: - """TODO: Add docstring.""" + """Helper function to text input.""" return self.text_values.get(label, "") def dataframe(self, df: Any, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to dataframe.""" self.frames.append(df) def selectbox(self, label: str, options: list[str], index: int = 0, **kwargs: Any) -> str: - """TODO: Add docstring.""" + """Helper function to selectbox.""" return self.selectbox_values.get(label, options[index]) def subheader(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to subheader.""" pass def caption(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to caption.""" pass def write(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to write.""" pass def button(self, label: str, **kwargs: Any) -> bool: - """TODO: Add docstring.""" + """Helper function to button.""" key = kwargs.get("key") return label in self.button_presses or (isinstance(key, str) and key in self.button_presses) def text_area(self, label: str, **kwargs: Any) -> str: - """TODO: Add docstring.""" + """Helper function to text area.""" return "" def success(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to success.""" pass def warning(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to warning.""" pass def _sample_items() -> list[TriageItem]: - """TODO: Add docstring.""" + """Helper function to sample items.""" old_ts = datetime.now(timezone.utc) - timedelta(hours=96) recent_ts = datetime.now(timezone.utc) - timedelta(hours=2) return [ @@ -178,7 +178,7 @@ def _sample_items() -> list[TriageItem]: def test_review_workbench_renders_kpis_and_filters_queue() -> None: - """TODO: Add docstring.""" + """Test that review workbench renders kpis and filters queue.""" fake_st = _FakeStreamlit() fake_st.multiselect_values = { "Severity": ["Critical/Severe"], @@ -265,7 +265,7 @@ def test_review_workbench_renders_kpis_and_filters_queue() -> None: def test_triage_drawer_submits_assignment_annotation_and_status() -> None: - """TODO: Add docstring.""" + """Test that triage drawer submits assignment annotation and status.""" fake_st = _FakeStreamlit() fake_st.text_area = lambda label, **kwargs: "follow-up" # type: ignore[assignment] fake_st.selectbox_values = { diff --git a/tests/unit/streamlit/test_triage_drawer_apptest.py b/tests/unit/streamlit/test_triage_drawer_apptest.py index f06148f5..332a4f38 100644 --- a/tests/unit/streamlit/test_triage_drawer_apptest.py +++ b/tests/unit/streamlit/test_triage_drawer_apptest.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for triage drawer apptest.""" from __future__ import annotations @@ -12,7 +12,7 @@ def _triage_drawer_app() -> None: - """TODO: Add docstring.""" + """Helper function to triage drawer app.""" import tempfile import uuid from datetime import datetime, timezone @@ -63,7 +63,7 @@ def _triage_drawer_app() -> None: def test_triage_drawer_submission_updates_session_state_and_persistence() -> None: - """TODO: Add docstring.""" + """Test that triage drawer submission updates session state and persistence.""" from imednet.models.triage import TriageStatus from imednet_workflows.triage_store import TriageStore diff --git a/tests/unit/streamlit_plugin/__init__.py b/tests/unit/streamlit_plugin/__init__.py index 621f1807..a1b38363 100644 --- a/tests/unit/streamlit_plugin/__init__.py +++ b/tests/unit/streamlit_plugin/__init__.py @@ -1,3 +1,3 @@ -"""TODO: Add docstring.""" +"""Test package initialization.""" from __future__ import annotations diff --git a/tests/unit/streamlit_plugin/test_app.py b/tests/unit/streamlit_plugin/test_app.py index ce9e6908..814093f3 100644 --- a/tests/unit/streamlit_plugin/test_app.py +++ b/tests/unit/streamlit_plugin/test_app.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for app.""" from __future__ import annotations @@ -13,28 +13,28 @@ class _FakeNavigation: - """TODO: Add docstring.""" + """Test suite for FakeNavigation.""" def __init__(self, pages: list[dict[str, Any]]) -> None: - """TODO: Add docstring.""" + """Initialize the test object.""" self.pages = pages self.ran = False def run(self) -> None: - """TODO: Add docstring.""" + """Helper function to run.""" self.ran = True class _FakeStreamlit: - """TODO: Add docstring.""" + """Test suite for FakeStreamlit.""" def __init__(self) -> None: - """TODO: Add docstring.""" + """Initialize the test object.""" self.page_config: dict[str, Any] | None = None self.navigation_calls: list[_FakeNavigation] = [] def set_page_config(self, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to set page config.""" self.page_config = kwargs def page( @@ -45,7 +45,7 @@ def page( icon: str, default: bool = False, ) -> dict[str, Any]: - """TODO: Add docstring.""" + """Helper function to page.""" return { "path": path, "title": title, @@ -54,14 +54,14 @@ def page( } def navigation(self, pages: list[dict[str, Any]]) -> _FakeNavigation: - """TODO: Add docstring.""" + """Helper function to navigation.""" nav = _FakeNavigation(pages) self.navigation_calls.append(nav) return nav def _run_app(is_connected: bool) -> _FakeStreamlit: - """TODO: Add docstring.""" + """Helper function to run app.""" app_path = PACKAGE_ROOT / "app.py" module_name = "imednet_streamlit.app" fake_st = _FakeStreamlit() @@ -75,22 +75,22 @@ def _run_app(is_connected: bool) -> _FakeStreamlit: fake_streamlit_module.query_params = {} class FakeSidebar: - """TODO: Add docstring.""" + """Test suite for FakeSidebar.""" def toggle(self, *args, **kwargs): - """TODO: Add docstring.""" + """Helper function to toggle.""" pass fake_streamlit_module.sidebar = FakeSidebar() def fake_markdown(*args, **kwargs): - """TODO: Add docstring.""" + """Helper function to fake markdown.""" pass fake_streamlit_module.markdown = fake_markdown def fake_altair_chart(*args, **kwargs): - """TODO: Add docstring.""" + """Helper function to fake altair chart.""" pass fake_streamlit_module.altair_chart = fake_altair_chart @@ -103,7 +103,7 @@ def fake_altair_chart(*args, **kwargs): fake_auth_module: Any = ModuleType("imednet_streamlit.auth") def _render_auth_sidebar() -> bool: - """TODO: Add docstring.""" + """Helper function to render auth sidebar.""" return is_connected fake_auth_module.render_auth_sidebar = _render_auth_sidebar @@ -139,7 +139,7 @@ def _render_auth_sidebar() -> bool: def test_streamlit_app_navigation_is_home_only_before_auth() -> None: - """TODO: Add docstring.""" + """Test that streamlit app navigation is home only before auth.""" fake_st = _run_app(is_connected=False) assert fake_st.page_config == { @@ -159,7 +159,7 @@ def test_streamlit_app_navigation_is_home_only_before_auth() -> None: def test_streamlit_app_navigation_includes_all_pages_after_auth() -> None: - """TODO: Add docstring.""" + """Test that streamlit app navigation includes all pages after auth.""" fake_st = _run_app(is_connected=True) assert len(fake_st.navigation_calls) == 1 diff --git a/tests/unit/streamlit_plugin/test_app_redaction.py b/tests/unit/streamlit_plugin/test_app_redaction.py index 088d67f6..f14ea4df 100644 --- a/tests/unit/streamlit_plugin/test_app_redaction.py +++ b/tests/unit/streamlit_plugin/test_app_redaction.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for app redaction.""" from __future__ import annotations @@ -7,7 +7,7 @@ def test_sanitize_body_string(): - """TODO: Add docstring.""" + """Test that sanitize body string.""" from imednet_streamlit.app import _sanitize_body res = _sanitize_body("mongodb://user:password123@host:27017") @@ -15,7 +15,7 @@ def test_sanitize_body_string(): def test_sanitize_body_exception(): - """TODO: Add docstring.""" + """Test that sanitize body exception.""" from imednet_streamlit.app import _sanitize_body ex = ValueError("mongodb://user:password123@host:27017") @@ -25,18 +25,18 @@ def test_sanitize_body_exception(): def test_sanitize_body_unprintable_exception(): - """TODO: Add docstring.""" + """Test that sanitize body unprintable exception.""" from imednet_streamlit.app import _sanitize_body class BadError(Exception): - """TODO: Add docstring.""" + """Test suite for BadError.""" def __str__(self): - """TODO: Add docstring.""" + """Helper function to str .""" raise RuntimeError("Cannot print") def __init__(self, msg=None): - """TODO: Add docstring.""" + """Initialize the test object.""" if msg == "": raise RuntimeError("Failed init") super().__init__(msg) @@ -49,7 +49,7 @@ def __init__(self, msg=None): def test_sanitize_body_non_string(): - """TODO: Add docstring.""" + """Test that sanitize body non string.""" from imednet_streamlit.app import _sanitize_body res = _sanitize_body(123) @@ -57,7 +57,7 @@ def test_sanitize_body_non_string(): def test_secure_st_methods(monkeypatch): - """TODO: Add docstring.""" + """Test that secure st methods.""" from imednet_streamlit.app import ( secure_st_error, secure_st_exception, @@ -68,19 +68,19 @@ def test_secure_st_methods(monkeypatch): calls = {} def mock_error(msg, *args, **kwargs): - """TODO: Add docstring.""" + """Helper function to mock error.""" calls["error"] = msg def mock_exception(msg, *args, **kwargs): - """TODO: Add docstring.""" + """Helper function to mock exception.""" calls["exception"] = msg def mock_warning(msg, *args, **kwargs): - """TODO: Add docstring.""" + """Helper function to mock warning.""" calls["warning"] = msg def mock_info(msg, *args, **kwargs): - """TODO: Add docstring.""" + """Helper function to mock info.""" calls["info"] = msg import imednet_streamlit.app as app @@ -105,28 +105,28 @@ def mock_info(msg, *args, **kwargs): class _FakeChart: - """TODO: Add docstring.""" + """Test suite for FakeChart.""" def __init__(self, title="Test Chart"): - """TODO: Add docstring.""" + """Initialize the test object.""" self.title = title self.data = "dummy_data" def properties(self, description=None): - """TODO: Add docstring.""" + """Helper function to properties.""" self.description = description return self def test_accessible_altair_chart(monkeypatch): - """TODO: Add docstring.""" + """Test that accessible altair chart.""" import imednet_streamlit.app as app from imednet_streamlit.app import accessible_altair_chart calls = [] def mock_original_altair_chart(chart, use_container_width, theme, **kwargs): - """TODO: Add docstring.""" + """Helper function to mock original altair chart.""" calls.append((chart, use_container_width, theme)) monkeypatch.setattr(app, "original_altair_chart", mock_original_altair_chart) @@ -141,14 +141,14 @@ def mock_original_altair_chart(chart, use_container_width, theme, **kwargs): def test_accessible_altair_chart_dict_title(monkeypatch): - """TODO: Add docstring.""" + """Test that accessible altair chart dict title.""" import imednet_streamlit.app as app from imednet_streamlit.app import accessible_altair_chart calls = [] def mock_original_altair_chart(chart, use_container_width, theme, **kwargs): - """TODO: Add docstring.""" + """Helper function to mock original altair chart.""" calls.append(chart) monkeypatch.setattr(app, "original_altair_chart", mock_original_altair_chart) @@ -161,7 +161,7 @@ def mock_original_altair_chart(chart, use_container_width, theme, **kwargs): def test_accessible_altair_chart_non_str_title(monkeypatch): - """TODO: Add docstring.""" + """Test that accessible altair chart non str title.""" import imednet_streamlit.app as app from imednet_streamlit.app import accessible_altair_chart @@ -171,7 +171,7 @@ def test_accessible_altair_chart_non_str_title(monkeypatch): def test_accessible_altair_chart_with_dataframe(monkeypatch): - """TODO: Add docstring.""" + """Test that accessible altair chart with dataframe.""" import pandas as pd import imednet_streamlit.app as app @@ -180,28 +180,28 @@ def test_accessible_altair_chart_with_dataframe(monkeypatch): calls = [] def mock_original_altair_chart(*args, **kwargs): - """TODO: Add docstring.""" + """Helper function to mock original altair chart.""" pass monkeypatch.setattr(app, "original_altair_chart", mock_original_altair_chart) class FakeExpander: - """TODO: Add docstring.""" + """Test suite for FakeExpander.""" def __init__(self, label, expanded): - """TODO: Add docstring.""" + """Initialize the test object.""" calls.append(("expander", label, expanded)) def __enter__(self): - """TODO: Add docstring.""" + """Helper function to enter .""" return self def __exit__(self, *args): - """TODO: Add docstring.""" + """Helper function to exit .""" pass def mock_dataframe(df, use_container_width): - """TODO: Add docstring.""" + """Helper function to mock dataframe.""" calls.append(("dataframe", df, use_container_width)) monkeypatch.setattr(st, "expander", FakeExpander) @@ -216,7 +216,7 @@ def mock_dataframe(df, use_container_width): def test_toggle_high_contrast(): - """TODO: Add docstring.""" + """Test that toggle high contrast.""" import imednet_streamlit.app as app # Set up session state and query params diff --git a/tests/unit/streamlit_plugin/test_auth.py b/tests/unit/streamlit_plugin/test_auth.py index 85dbe37a..44cfd072 100644 --- a/tests/unit/streamlit_plugin/test_auth.py +++ b/tests/unit/streamlit_plugin/test_auth.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for auth.""" from __future__ import annotations @@ -10,27 +10,27 @@ class _SidebarContext: - """TODO: Add docstring.""" + """Test suite for SidebarContext.""" def __enter__(self) -> None: - """TODO: Add docstring.""" + """Helper function to enter .""" return None def __exit__(self, exc_type, exc_val, exc_tb) -> None: - """TODO: Add docstring.""" + """Helper function to exit .""" return None class _FakeCacheData: - """TODO: Add docstring.""" + """Test suite for FakeCacheData.""" def clear(self) -> None: - """TODO: Add docstring.""" + """Helper function to clear.""" pass class _FakeStreamlit: - """TODO: Add docstring.""" + """Test suite for FakeStreamlit.""" def __init__( self, @@ -39,7 +39,7 @@ def __init__( connect_clicked: bool = False, selected_study: str = "STUDY", ) -> None: - """TODO: Add docstring.""" + """Initialize the test object.""" self.session_state: dict[str, object] = {} self.sidebar = _SidebarContext() self._connect_clicked = connect_clicked @@ -54,51 +54,51 @@ def __init__( self._selected_study = selected_study def header(self, _: str) -> None: - """TODO: Add docstring.""" + """Helper function to header.""" pass def text_input(self, label: str, **kwargs: object) -> str: - """TODO: Add docstring.""" + """Helper function to text input.""" key = kwargs["key"] self.session_state[key] = "" return "" def selectbox(self, label: str, options: list[str], key: str, **kwargs: object) -> str: - """TODO: Add docstring.""" + """Helper function to selectbox.""" self.session_state[key] = self._selected_study return self._selected_study def button(self, _: str, **kwargs: object) -> bool: - """TODO: Add docstring.""" + """Helper function to button.""" return self._connect_clicked def rerun(self) -> None: - """TODO: Add docstring.""" + """Helper function to rerun.""" pass def success(self, message: str) -> None: - """TODO: Add docstring.""" + """Helper function to success.""" self.success_messages.append(message) def error(self, message: str) -> None: - """TODO: Add docstring.""" + """Helper function to error.""" self.error_messages.append(message) def warning(self, message: str) -> None: - """TODO: Add docstring.""" + """Helper function to warning.""" self.warning_messages.append(message) def info(self, message: str) -> None: - """TODO: Add docstring.""" + """Helper function to info.""" self.info_messages.append(message) def login(self) -> None: - """TODO: Add docstring.""" + """Helper function to login.""" self.login_called = True def test_render_auth_sidebar_not_connected_returns_false(monkeypatch: pytest.MonkeyPatch) -> None: - """TODO: Add docstring.""" + """Test that render auth sidebar not connected returns false.""" fake_st = _FakeStreamlit(logged_in=False, connect_clicked=False) monkeypatch.setattr(auth, "st", fake_st) @@ -109,7 +109,7 @@ def test_render_auth_sidebar_not_connected_returns_false(monkeypatch: pytest.Mon def test_render_auth_sidebar_connects_and_clears_secret_keys( monkeypatch: pytest.MonkeyPatch, ) -> None: - """TODO: Add docstring.""" + """Test that render auth sidebar connects and clears secret keys.""" fake_st = _FakeStreamlit(logged_in=True, connect_clicked=True, selected_study="STUDY") monkeypatch.setattr(auth, "st", fake_st) monkeypatch.setattr(auth, "get_provisioned_studies", lambda: ["STUDY"]) @@ -117,7 +117,7 @@ def test_render_auth_sidebar_connects_and_clears_secret_keys( sentinel_sdk = SimpleNamespace(name="sdk") def _fake_store_sdk(**_: object) -> None: - """TODO: Add docstring.""" + """Helper function to fake store sdk.""" fake_st.session_state[auth._KEY_SDK] = sentinel_sdk monkeypatch.setattr( @@ -132,7 +132,7 @@ def _fake_store_sdk(**_: object) -> None: def test_get_sdk_before_connect_raises_runtime_error(monkeypatch: pytest.MonkeyPatch) -> None: - """TODO: Add docstring.""" + """Test that get sdk before connect raises runtime error.""" fake_st = _FakeStreamlit(logged_in=False, connect_clicked=False) monkeypatch.setattr(auth, "st", fake_st) @@ -141,7 +141,7 @@ def test_get_sdk_before_connect_raises_runtime_error(monkeypatch: pytest.MonkeyP def test_clear_credentials_removes_all_session_keys(monkeypatch: pytest.MonkeyPatch) -> None: - """TODO: Add docstring.""" + """Test that clear credentials removes all session keys.""" fake_st = _FakeStreamlit(logged_in=False, connect_clicked=False) fake_st.session_state.update( { @@ -162,14 +162,14 @@ def test_clear_credentials_removes_all_session_keys(monkeypatch: pytest.MonkeyPa def test_render_auth_sidebar_build_failure_clears_secret_keys( monkeypatch: pytest.MonkeyPatch, ) -> None: - """TODO: Add docstring.""" + """Test that render auth sidebar build failure clears secret keys.""" fake_st = _FakeStreamlit(logged_in=True, connect_clicked=True) monkeypatch.setattr(auth, "st", fake_st) monkeypatch.setattr(auth, "get_provisioned_studies", lambda: ["STUDY"]) monkeypatch.setattr(auth, "get_tenant_credentials", lambda x: ("api", "sec")) def _raise_build_error(**_: object) -> None: - """TODO: Add docstring.""" + """Helper function to raise build error.""" raise RuntimeError("boom") monkeypatch.setattr(auth, "_build_sdk", _raise_build_error) @@ -181,7 +181,7 @@ def _raise_build_error(**_: object) -> None: def test_render_auth_sidebar_missing_fields_marks_disconnected_and_clears_secrets( monkeypatch: pytest.MonkeyPatch, ) -> None: - """TODO: Add docstring.""" + """Test that render auth sidebar missing fields marks disconnected and clears secrets.""" fake_st = _FakeStreamlit(logged_in=True, connect_clicked=True) monkeypatch.setattr(auth, "st", fake_st) monkeypatch.setattr(auth, "get_provisioned_studies", lambda: ["STUDY"]) @@ -197,17 +197,17 @@ def test_render_auth_sidebar_missing_fields_marks_disconnected_and_clears_secret def test_build_sdk_calls_sdk_init(monkeypatch: pytest.MonkeyPatch) -> None: - """TODO: Add docstring.""" + """Test that build sdk calls sdk init.""" fake_st = _FakeStreamlit(logged_in=False, connect_clicked=False) monkeypatch.setattr(auth, "st", fake_st) sdk_args = {} class FakeSDK: - """TODO: Add docstring.""" + """Test suite for FakeSDK.""" def __init__(self, api_key: str, security_key: str) -> None: - """TODO: Add docstring.""" + """Initialize the test object.""" sdk_args["api_key"] = api_key sdk_args["security_key"] = security_key @@ -219,7 +219,7 @@ def __init__(self, api_key: str, security_key: str) -> None: def test_get_study_key_raises_when_missing(monkeypatch: pytest.MonkeyPatch) -> None: - """TODO: Add docstring.""" + """Test that get study key raises when missing.""" fake_st = _FakeStreamlit(logged_in=False, connect_clicked=False) monkeypatch.setattr(auth, "st", fake_st) diff --git a/tests/unit/streamlit_plugin/test_cli_dashboard.py b/tests/unit/streamlit_plugin/test_cli_dashboard.py index 7c718d32..37e4bdd6 100644 --- a/tests/unit/streamlit_plugin/test_cli_dashboard.py +++ b/tests/unit/streamlit_plugin/test_cli_dashboard.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for cli dashboard.""" from __future__ import annotations @@ -42,7 +42,7 @@ def test_dashboard_missing_plugin() -> None: original_find_spec = find_spec def mock_find_spec(name: str, package: str | None = None) -> Any: - """TODO: Add docstring.""" + """Helper function to mock find spec.""" if name == "imednet_streamlit.app": return None return original_find_spec(name, package) @@ -71,7 +71,7 @@ def test_dashboard_launches_subprocess() -> None: original_find_spec = find_spec def mock_find_spec(name: str, package: str | None = None) -> Any: - """TODO: Add docstring.""" + """Helper function to mock find spec.""" if name == "imednet_streamlit.app": return dashboard_spec return original_find_spec(name, package) diff --git a/tests/unit/streamlit_plugin/test_components_charts.py b/tests/unit/streamlit_plugin/test_components_charts.py index 1d9cee55..835705e6 100644 --- a/tests/unit/streamlit_plugin/test_components_charts.py +++ b/tests/unit/streamlit_plugin/test_components_charts.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for components charts.""" from __future__ import annotations @@ -9,7 +9,7 @@ def test_bar_chart_returns_altair_chart_with_defaults() -> None: - """TODO: Add docstring.""" + """Test that bar chart returns altair chart with defaults.""" df = pd.DataFrame({"category": ["A", "B"], "value": [1, 2]}) chart = bar_chart(df, x="value", y="category", title="Example") @@ -20,7 +20,7 @@ def test_bar_chart_returns_altair_chart_with_defaults() -> None: def test_bar_chart_returns_altair_chart_with_color_encoding() -> None: - """TODO: Add docstring.""" + """Test that bar chart returns altair chart with color encoding.""" df = pd.DataFrame({"category": ["A", "B"], "value": [1, 2], "group": ["X", "Y"]}) chart = bar_chart(df, x="value", y="category", color="group", title="Example") @@ -34,7 +34,7 @@ def test_bar_chart_returns_altair_chart_with_color_encoding() -> None: def test_line_chart_returns_altair_chart_with_defaults() -> None: - """TODO: Add docstring.""" + """Test that line chart returns altair chart with defaults.""" df = pd.DataFrame( { "date": pd.to_datetime(["2026-01-01", "2026-01-02"]), @@ -50,7 +50,7 @@ def test_line_chart_returns_altair_chart_with_defaults() -> None: def test_line_chart_returns_altair_chart_with_color_encoding() -> None: - """TODO: Add docstring.""" + """Test that line chart returns altair chart with color encoding.""" df = pd.DataFrame( { "date": pd.to_datetime(["2026-01-01", "2026-01-02"]), @@ -69,7 +69,7 @@ def test_line_chart_returns_altair_chart_with_color_encoding() -> None: def test_pie_chart_returns_altair_chart() -> None: - """TODO: Add docstring.""" + """Test that pie chart returns altair chart.""" df = pd.DataFrame({"status": ["Open", "Closed"], "count": [4, 6]}) chart = pie_chart(df, theta="count", color="status") diff --git a/tests/unit/streamlit_plugin/test_components_export.py b/tests/unit/streamlit_plugin/test_components_export.py index baad18bb..02dccc5a 100644 --- a/tests/unit/streamlit_plugin/test_components_export.py +++ b/tests/unit/streamlit_plugin/test_components_export.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for components export.""" from __future__ import annotations @@ -12,10 +12,10 @@ class _FakeExportStreamlit: - """TODO: Add docstring.""" + """Test suite for FakeExportStreamlit.""" def __init__(self) -> None: - """TODO: Add docstring.""" + """Initialize the test object.""" self.download_calls: list[dict[str, object]] = [] def download_button( @@ -26,14 +26,14 @@ def download_button( file_name: str, mime: str, ) -> None: - """TODO: Add docstring.""" + """Helper function to download button.""" self.download_calls.append( {"label": label, "data": data, "file_name": file_name, "mime": mime} ) def test_csv_download_button_exports_utf8_csv(monkeypatch: pytest.MonkeyPatch) -> None: - """TODO: Add docstring.""" + """Test that csv download button exports utf8 csv.""" fake_st = _FakeExportStreamlit() monkeypatch.setattr(export_components, "st", fake_st) df = pd.DataFrame({"name": ["José"], "count": [1]}) @@ -52,7 +52,7 @@ def test_csv_download_button_exports_utf8_csv(monkeypatch: pytest.MonkeyPatch) - def test_excel_download_button_exports_valid_xlsx(monkeypatch: pytest.MonkeyPatch) -> None: - """TODO: Add docstring.""" + """Test that excel download button exports valid xlsx.""" fake_st = _FakeExportStreamlit() monkeypatch.setattr(export_components, "st", fake_st) df = pd.DataFrame({"name": ["Site A"], "count": [3]}) diff --git a/tests/unit/streamlit_plugin/test_components_metrics.py b/tests/unit/streamlit_plugin/test_components_metrics.py index 696b20f9..6917c165 100644 --- a/tests/unit/streamlit_plugin/test_components_metrics.py +++ b/tests/unit/streamlit_plugin/test_components_metrics.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for components metrics.""" from __future__ import annotations @@ -8,27 +8,27 @@ class _ColumnContext: - """TODO: Add docstring.""" + """Test suite for ColumnContext.""" def __enter__(self) -> None: - """TODO: Add docstring.""" + """Helper function to enter .""" return None def __exit__(self, exc_type, exc_val, exc_tb) -> None: - """TODO: Add docstring.""" + """Helper function to exit .""" return None class _FakeMetricStreamlit: - """TODO: Add docstring.""" + """Test suite for FakeMetricStreamlit.""" def __init__(self) -> None: - """TODO: Add docstring.""" + """Initialize the test object.""" self.columns_calls: list[int] = [] self.metrics: list[dict[str, object]] = [] def columns(self, count: int) -> list[_ColumnContext]: - """TODO: Add docstring.""" + """Helper function to columns.""" self.columns_calls.append(count) return [_ColumnContext() for _ in range(count)] @@ -40,7 +40,7 @@ def metric( delta: str | None = None, help: str | None = None, ) -> None: - """TODO: Add docstring.""" + """Helper function to metric.""" self.metrics.append( { "label": label, @@ -52,7 +52,7 @@ def metric( def test_kpi_row_uses_column_count_and_renders_metrics(monkeypatch: pytest.MonkeyPatch) -> None: - """TODO: Add docstring.""" + """Test that kpi row uses column count and renders metrics.""" fake_st = _FakeMetricStreamlit() monkeypatch.setattr(metrics, "st", fake_st) @@ -71,7 +71,7 @@ def test_kpi_row_uses_column_count_and_renders_metrics(monkeypatch: pytest.Monke def test_kpi_card_calls_streamlit_metric(monkeypatch: pytest.MonkeyPatch) -> None: - """TODO: Add docstring.""" + """Test that kpi card calls streamlit metric.""" fake_st = _FakeMetricStreamlit() monkeypatch.setattr(metrics, "st", fake_st) diff --git a/tests/unit/streamlit_plugin/test_components_paginated_grid.py b/tests/unit/streamlit_plugin/test_components_paginated_grid.py index e35d293b..c00124e4 100644 --- a/tests/unit/streamlit_plugin/test_components_paginated_grid.py +++ b/tests/unit/streamlit_plugin/test_components_paginated_grid.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for components paginated grid.""" from __future__ import annotations @@ -12,16 +12,16 @@ class _FakeColumn: - """TODO: Add docstring.""" + """Test suite for FakeColumn.""" def __init__(self, *, next_click: bool = False, prev_click: bool = False) -> None: - """TODO: Add docstring.""" + """Initialize the test object.""" self._next_click = next_click self._prev_click = prev_click self.captions: list[str] = [] def button(self, label: str, **kwargs: Any) -> bool: - """TODO: Add docstring.""" + """Helper function to button.""" if label == "Next": return self._next_click if label == "Previous": @@ -29,12 +29,12 @@ def button(self, label: str, **kwargs: Any) -> bool: return False def caption(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to caption.""" self.captions.append(value) def test_top_n_with_other_adds_remainder_bucket() -> None: - """TODO: Add docstring.""" + """Test that top n with other adds remainder bucket.""" df = pd.DataFrame( { "label": ["A", "B", "C", "D"], @@ -49,7 +49,7 @@ def test_top_n_with_other_adds_remainder_bucket() -> None: def test_top_n_with_other_empty_dataframe_returns_empty() -> None: - """TODO: Add docstring.""" + """Test that top n with other empty dataframe returns empty.""" df = pd.DataFrame({"label": [], "count": []}) result = top_n_with_other(df, label_column="label", value_column="count") @@ -58,7 +58,7 @@ def test_top_n_with_other_empty_dataframe_returns_empty() -> None: def test_top_n_with_other_all_rows_fit_in_top_n_returns_no_other() -> None: - """TODO: Add docstring.""" + """Test that top n with other all rows fit in top n returns no other.""" df = pd.DataFrame({"label": ["A", "B"], "count": [5, 3]}) result = top_n_with_other(df, label_column="label", value_column="count", top_n=10) @@ -68,7 +68,7 @@ def test_top_n_with_other_all_rows_fit_in_top_n_returns_no_other() -> None: def test_top_n_with_other_zero_remainder_omits_other_row() -> None: - """TODO: Add docstring.""" + """Test that top n with other zero remainder omits other row.""" df = pd.DataFrame({"label": ["A", "B", "C"], "count": [5, 3, 0]}) result = top_n_with_other(df, label_column="label", value_column="count", top_n=2) @@ -78,7 +78,7 @@ def test_top_n_with_other_zero_remainder_omits_other_row() -> None: def test_paginated_slice_limits_rows_to_active_page(monkeypatch: pytest.MonkeyPatch) -> None: - """TODO: Add docstring.""" + """Test that paginated slice limits rows to active page.""" session_state: dict[str, Any] = {} prev_col = _FakeColumn() info_col = _FakeColumn() @@ -98,7 +98,7 @@ def test_paginated_slice_limits_rows_to_active_page(monkeypatch: pytest.MonkeyPa def test_paginated_slice_prev_button_decrements_page(monkeypatch: pytest.MonkeyPatch) -> None: - """TODO: Add docstring.""" + """Test that paginated slice prev button decrements page.""" session_state: dict[str, Any] = {"grid_page": 3} prev_col = _FakeColumn(prev_click=True) info_col = _FakeColumn() @@ -117,7 +117,7 @@ def test_paginated_slice_prev_button_decrements_page(monkeypatch: pytest.MonkeyP def test_paginated_slice_clamps_page_above_total_pages(monkeypatch: pytest.MonkeyPatch) -> None: - """TODO: Add docstring.""" + """Test that paginated slice clamps page above total pages.""" session_state: dict[str, Any] = {"grid_page": 999} prev_col = _FakeColumn() info_col = _FakeColumn() @@ -137,7 +137,7 @@ def test_paginated_slice_clamps_page_above_total_pages(monkeypatch: pytest.Monke def test_paginated_slice_custom_page_size_not_in_options( monkeypatch: pytest.MonkeyPatch, ) -> None: - """TODO: Add docstring.""" + """Test that paginated slice custom page size not in options.""" session_state: dict[str, Any] = {} prev_col = _FakeColumn() info_col = _FakeColumn() diff --git a/tests/unit/streamlit_plugin/test_components_tables.py b/tests/unit/streamlit_plugin/test_components_tables.py index d1b56fdd..5f86ed48 100644 --- a/tests/unit/streamlit_plugin/test_components_tables.py +++ b/tests/unit/streamlit_plugin/test_components_tables.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for components tables.""" from __future__ import annotations @@ -9,43 +9,43 @@ class _FakeColumn: - """TODO: Add docstring.""" + """Test suite for FakeColumn.""" def button(self, *_: object, **__: object) -> bool: - """TODO: Add docstring.""" + """Helper function to button.""" return False def caption(self, *_: object, **__: object) -> None: - """TODO: Add docstring.""" + """Helper function to caption.""" return None class _FakeTableStreamlit: - """TODO: Add docstring.""" + """Test suite for FakeTableStreamlit.""" def __init__(self, *, query: str) -> None: - """TODO: Add docstring.""" + """Initialize the test object.""" self._query = query self.dataframe_calls: list[pd.DataFrame] = [] self.text_input_keys: list[str] = [] self.session_state: dict[str, object] = {} def text_input(self, _: str, *, key: str) -> str: - """TODO: Add docstring.""" + """Helper function to text input.""" self.text_input_keys.append(key) return self._query def selectbox(self, _: str, *, options: tuple[object, ...], key: str, index: int = 0) -> int: - """TODO: Add docstring.""" + """Helper function to selectbox.""" self.session_state[key] = options[index] return int(options[index]) def columns(self, _: list[int]) -> tuple[_FakeColumn, _FakeColumn, _FakeColumn]: - """TODO: Add docstring.""" + """Helper function to columns.""" return (_FakeColumn(), _FakeColumn(), _FakeColumn()) def dataframe(self, df: pd.DataFrame, *, use_container_width: bool, height: int) -> None: - """TODO: Add docstring.""" + """Helper function to dataframe.""" assert use_container_width is True assert height == 400 self.dataframe_calls.append(df.copy()) @@ -54,7 +54,7 @@ def dataframe(self, df: pd.DataFrame, *, use_container_width: bool, height: int) def test_filterable_dataframe_applies_case_insensitive_row_filter( monkeypatch: pytest.MonkeyPatch, ) -> None: - """TODO: Add docstring.""" + """Test that filterable dataframe applies case insensitive row filter.""" fake_st = _FakeTableStreamlit(query="site b") monkeypatch.setattr(tables, "st", fake_st) monkeypatch.setattr(paginated_grid, "st", fake_st) @@ -76,7 +76,7 @@ def test_filterable_dataframe_applies_case_insensitive_row_filter( def test_filterable_dataframe_empty_query_returns_original( monkeypatch: pytest.MonkeyPatch, ) -> None: - """TODO: Add docstring.""" + """Test that filterable dataframe empty query returns original.""" fake_st = _FakeTableStreamlit(query="") monkeypatch.setattr(tables, "st", fake_st) monkeypatch.setattr(paginated_grid, "st", fake_st) diff --git a/tests/unit/streamlit_plugin/test_pages_admin.py b/tests/unit/streamlit_plugin/test_pages_admin.py index 562d7b40..125e7931 100644 --- a/tests/unit/streamlit_plugin/test_pages_admin.py +++ b/tests/unit/streamlit_plugin/test_pages_admin.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for pages admin.""" import importlib.util import sys @@ -12,7 +12,7 @@ def test_admin_page_renders(): - """TODO: Add docstring.""" + """Test that admin page renders.""" page_path = PACKAGE_ROOT / "pages" / "admin.py" fake_st = MagicMock() diff --git a/tests/unit/streamlit_plugin/test_pages_conformance.py b/tests/unit/streamlit_plugin/test_pages_conformance.py index 3290afb5..8b228d12 100644 --- a/tests/unit/streamlit_plugin/test_pages_conformance.py +++ b/tests/unit/streamlit_plugin/test_pages_conformance.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for pages conformance.""" import importlib.util import sys @@ -12,7 +12,7 @@ def test_conformance_page_renders(): - """TODO: Add docstring.""" + """Test that conformance page renders.""" page_path = PACKAGE_ROOT / "pages" / "conformance.py" fake_st = MagicMock() diff --git a/tests/unit/streamlit_plugin/test_pages_enrollment.py b/tests/unit/streamlit_plugin/test_pages_enrollment.py index 0c4dc81e..bdc9d5b9 100644 --- a/tests/unit/streamlit_plugin/test_pages_enrollment.py +++ b/tests/unit/streamlit_plugin/test_pages_enrollment.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for pages enrollment.""" from __future__ import annotations @@ -15,36 +15,36 @@ class _FakeContextManager: - """TODO: Add docstring.""" + """Test suite for FakeContextManager.""" def __enter__(self) -> "_FakeContextManager": - """TODO: Add docstring.""" + """Helper function to enter .""" return self def __exit__(self, *args: Any) -> None: - """TODO: Add docstring.""" + """Helper function to exit .""" pass class _FakeCacheDataDecorator: - """TODO: Add docstring.""" + """Test suite for FakeCacheDataDecorator.""" def __call__(self, func: Any = None, **kwargs: Any) -> Any: - """TODO: Add docstring.""" + """Helper function to call .""" if func is not None: return func return lambda f: f def clear(self) -> None: - """TODO: Add docstring.""" + """Helper function to clear.""" pass class _FakeEnrollmentStreamlit: - """TODO: Add docstring.""" + """Test suite for FakeEnrollmentStreamlit.""" def __init__(self) -> None: - """TODO: Add docstring.""" + """Initialize the test object.""" self.session_state: dict[str, Any] = {"_imednet_connected": True} self.titles: list[str] = [] self.infos: list[str] = [] @@ -54,100 +54,100 @@ def __init__(self) -> None: self.sidebar = _FakeContextManager() def title(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to title.""" self.titles.append(value) def info(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to info.""" self.infos.append(value) def success(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to success.""" self.successes.append(value) def markdown(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to markdown.""" self.markdowns.append(value) def button(self, label: str, **kwargs: Any) -> bool: - """TODO: Add docstring.""" + """Helper function to button.""" return False def subheader(self, value: str, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to subheader.""" pass def altair_chart(self, chart: Any, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to altair chart.""" pass def columns(self, spec: Any) -> list[Any]: - """TODO: Add docstring.""" + """Helper function to columns.""" count = spec if isinstance(spec, int) else len(spec) return [_FakeContextManager() for _ in range(count)] def multiselect(self, label: str, options: Any, **kwargs: Any) -> list[Any]: - """TODO: Add docstring.""" + """Helper function to multiselect.""" return list(kwargs.get("default", [])) def date_input(self, label: str, **kwargs: Any) -> list[Any]: - """TODO: Add docstring.""" + """Helper function to date input.""" val = kwargs.get("value", []) return list(val) if hasattr(val, "__iter__") else [] def rerun(self) -> None: - """TODO: Add docstring.""" + """Helper function to rerun.""" pass def text_input(self, label: str, **kwargs: Any) -> str: - """TODO: Add docstring.""" + """Helper function to text input.""" return "" def dataframe(self, df: Any, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to dataframe.""" pass def download_button(self, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to download button.""" pass def metric(self, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to metric.""" pass def _make_fake_components_module() -> ModuleType: - """TODO: Add docstring.""" + """Helper function to make fake components module.""" import pandas as pd mod = ModuleType("imednet_streamlit.components") def _noop_kpi_row(metrics: list[dict[str, Any]]) -> None: - """TODO: Add docstring.""" + """Helper function to noop kpi row.""" pass def _noop_bar_chart(df: pd.DataFrame, **kwargs: Any) -> MagicMock: - """TODO: Add docstring.""" + """Helper function to noop bar chart.""" return MagicMock() def _noop_line_chart(df: pd.DataFrame, **kwargs: Any) -> MagicMock: - """TODO: Add docstring.""" + """Helper function to noop line chart.""" return MagicMock() def _noop_pie_chart(df: pd.DataFrame, **kwargs: Any) -> MagicMock: - """TODO: Add docstring.""" + """Helper function to noop pie chart.""" return MagicMock() def _noop_filterable_dataframe(df: pd.DataFrame, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to noop filterable dataframe.""" pass def _noop_csv_download_button(df: pd.DataFrame, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to noop csv download button.""" pass def _noop_excel_download_button(df: pd.DataFrame, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to noop excel download button.""" pass mod.kpi_row = _noop_kpi_row # type: ignore[attr-defined] @@ -161,7 +161,7 @@ def _noop_excel_download_button(df: pd.DataFrame, **kwargs: Any) -> None: def test_enrollment_page_renders_with_mock_sdk() -> None: - """TODO: Add docstring.""" + """Test that enrollment page renders with mock sdk.""" page_path = PACKAGE_ROOT / "pages" / "enrollment.py" fake_st = _FakeEnrollmentStreamlit() @@ -201,7 +201,7 @@ def _make_subject( site_name: str, enrollment_start_date: datetime.datetime | None = None, ) -> MagicMock: - """TODO: Add docstring.""" + """Helper function to make subject.""" s = MagicMock() s.subject_id = subject_id s.subject_key = f"S{subject_id:03d}" @@ -266,19 +266,19 @@ def _make_subject( def test_enrollment_page_empty_and_filters_and_refresh() -> None: - """TODO: Add docstring.""" + """Test that enrollment page empty and filters and refresh.""" page_path = PACKAGE_ROOT / "pages" / "enrollment.py" fake_st = _FakeEnrollmentStreamlit() # Stub the button to return True for refresh, and multiselect to return filters def _button(label: str, **kwargs: Any) -> bool: - """TODO: Add docstring.""" + """Helper function to button.""" if label == "🔄 Refresh Data": return True return False def _multiselect(label: str, options: Any, **kwargs: Any) -> list[Any]: - """TODO: Add docstring.""" + """Helper function to multiselect.""" if label == "Site": return ["Site A"] if label == "Subject Status": diff --git a/tests/unit/streamlit_plugin/test_pages_home.py b/tests/unit/streamlit_plugin/test_pages_home.py index ddaf4778..4f8de388 100644 --- a/tests/unit/streamlit_plugin/test_pages_home.py +++ b/tests/unit/streamlit_plugin/test_pages_home.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for pages home.""" from __future__ import annotations @@ -15,10 +15,10 @@ class _FakePageStreamlit: - """TODO: Add docstring.""" + """Test suite for FakePageStreamlit.""" def __init__(self, *, connected: bool) -> None: - """TODO: Add docstring.""" + """Initialize the test object.""" self.session_state: dict[str, Any] = {"_imednet_connected": connected} self.titles: list[str] = [] self.infos: list[str] = [] @@ -26,24 +26,24 @@ def __init__(self, *, connected: bool) -> None: self.markdowns: list[str] = [] def title(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to title.""" self.titles.append(value) def info(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to info.""" self.infos.append(value) def success(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to success.""" self.successes.append(value) def markdown(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to markdown.""" self.markdowns.append(value) def _run_page(page_name: str, *, connected: bool) -> _FakePageStreamlit: - """TODO: Add docstring.""" + """Helper function to run page.""" page_path = PACKAGE_ROOT / "pages" / page_name fake_st = _FakePageStreamlit(connected=connected) fake_streamlit_module = ModuleType("streamlit") @@ -84,13 +84,13 @@ def _run_page(page_name: str, *, connected: bool) -> _FakePageStreamlit: def test_home_page_renders_disconnected() -> None: - """TODO: Add docstring.""" + """Test that home page renders disconnected.""" home_disconnected = _run_page("home.py", connected=False) assert "🏥 iMednet EDC Dashboard" in home_disconnected.titles assert any("authenticate" in info.lower() for info in home_disconnected.infos) def test_home_page_renders_connected() -> None: - """TODO: Add docstring.""" + """Test that home page renders connected.""" home_connected = _run_page("home.py", connected=True) assert any("connected" in success.lower() for success in home_connected.successes) diff --git a/tests/unit/streamlit_plugin/test_pages_queries.py b/tests/unit/streamlit_plugin/test_pages_queries.py index 1d83ceeb..3d0bdd75 100644 --- a/tests/unit/streamlit_plugin/test_pages_queries.py +++ b/tests/unit/streamlit_plugin/test_pages_queries.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for pages queries.""" from __future__ import annotations @@ -14,36 +14,36 @@ class _FakeContextManager: - """TODO: Add docstring.""" + """Test suite for FakeContextManager.""" def __enter__(self) -> "_FakeContextManager": - """TODO: Add docstring.""" + """Helper function to enter .""" return self def __exit__(self, *args: Any) -> None: - """TODO: Add docstring.""" + """Helper function to exit .""" pass class _FakeCacheDataDecorator: - """TODO: Add docstring.""" + """Test suite for FakeCacheDataDecorator.""" def __call__(self, func: Any = None, **kwargs: Any) -> Any: - """TODO: Add docstring.""" + """Helper function to call .""" if func is not None: return func return lambda f: f def clear(self) -> None: - """TODO: Add docstring.""" + """Helper function to clear.""" pass class _FakeQueriesStreamlit: - """TODO: Add docstring.""" + """Test suite for FakeQueriesStreamlit.""" def __init__(self) -> None: - """TODO: Add docstring.""" + """Initialize the test object.""" self.session_state: dict[str, Any] = {"_imednet_connected": True} self.titles: list[str] = [] self.infos: list[str] = [] @@ -53,100 +53,100 @@ def __init__(self) -> None: self.sidebar = _FakeContextManager() def title(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to title.""" self.titles.append(value) def info(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to info.""" self.infos.append(value) def success(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to success.""" self.successes.append(value) def markdown(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to markdown.""" self.markdowns.append(value) def button(self, label: str, **kwargs: Any) -> bool: - """TODO: Add docstring.""" + """Helper function to button.""" return False def subheader(self, value: str, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to subheader.""" pass def altair_chart(self, chart: Any, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to altair chart.""" pass def columns(self, spec: Any) -> list[Any]: - """TODO: Add docstring.""" + """Helper function to columns.""" count = spec if isinstance(spec, int) else len(spec) return [_FakeContextManager() for _ in range(count)] def multiselect(self, label: str, options: Any, **kwargs: Any) -> list[Any]: - """TODO: Add docstring.""" + """Helper function to multiselect.""" return list(kwargs.get("default", [])) def date_input(self, label: str, **kwargs: Any) -> list[Any]: - """TODO: Add docstring.""" + """Helper function to date input.""" val = kwargs.get("value", []) return list(val) if hasattr(val, "__iter__") else [] def rerun(self) -> None: - """TODO: Add docstring.""" + """Helper function to rerun.""" pass def text_input(self, label: str, **kwargs: Any) -> str: - """TODO: Add docstring.""" + """Helper function to text input.""" return "" def dataframe(self, df: Any, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to dataframe.""" pass def download_button(self, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to download button.""" pass def metric(self, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to metric.""" pass def _make_fake_components_module() -> ModuleType: - """TODO: Add docstring.""" + """Helper function to make fake components module.""" import pandas as pd mod = ModuleType("imednet_streamlit.components") def _noop_kpi_row(metrics: list[dict[str, Any]]) -> None: - """TODO: Add docstring.""" + """Helper function to noop kpi row.""" pass def _noop_bar_chart(df: pd.DataFrame, **kwargs: Any) -> MagicMock: - """TODO: Add docstring.""" + """Helper function to noop bar chart.""" return MagicMock() def _noop_line_chart(df: pd.DataFrame, **kwargs: Any) -> MagicMock: - """TODO: Add docstring.""" + """Helper function to noop line chart.""" return MagicMock() def _noop_filterable_dataframe(df: pd.DataFrame, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to noop filterable dataframe.""" pass def _noop_csv_download_button(df: pd.DataFrame, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to noop csv download button.""" pass def _noop_excel_download_button(df: pd.DataFrame, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to noop excel download button.""" pass def _noop_top_n_with_other(df: pd.DataFrame, **kwargs: Any) -> pd.DataFrame: - """TODO: Add docstring.""" + """Helper function to noop top n with other.""" return df mod.kpi_row = _noop_kpi_row # type: ignore[attr-defined] @@ -160,7 +160,7 @@ def _noop_top_n_with_other(df: pd.DataFrame, **kwargs: Any) -> pd.DataFrame: def test_queries_page_renders_with_mock_sdk() -> None: - """TODO: Add docstring.""" + """Test that queries page renders with mock sdk.""" page_path = PACKAGE_ROOT / "pages" / "queries.py" fake_st = _FakeQueriesStreamlit() @@ -248,19 +248,19 @@ def test_queries_page_renders_with_mock_sdk() -> None: def test_queries_page_populated_and_filters_and_refresh() -> None: - """TODO: Add docstring.""" + """Test that queries page populated and filters and refresh.""" page_path = PACKAGE_ROOT / "pages" / "queries.py" fake_st = _FakeQueriesStreamlit() # Stub button and multiselect def _button(label: str, **kwargs: Any) -> bool: - """TODO: Add docstring.""" + """Helper function to button.""" if label == "🔄 Refresh Data": return True return False def _multiselect(label: str, options: Any, **kwargs: Any) -> list[Any]: - """TODO: Add docstring.""" + """Helper function to multiselect.""" if label == "Annotation Type": return ["Missing"] return list(kwargs.get("default", [])) diff --git a/tests/unit/streamlit_plugin/test_pages_sites.py b/tests/unit/streamlit_plugin/test_pages_sites.py index 49dd27e2..7afa6e31 100644 --- a/tests/unit/streamlit_plugin/test_pages_sites.py +++ b/tests/unit/streamlit_plugin/test_pages_sites.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for pages sites.""" from __future__ import annotations @@ -14,36 +14,36 @@ class _FakeContextManager: - """TODO: Add docstring.""" + """Test suite for FakeContextManager.""" def __enter__(self) -> "_FakeContextManager": - """TODO: Add docstring.""" + """Helper function to enter .""" return self def __exit__(self, *args: Any) -> None: - """TODO: Add docstring.""" + """Helper function to exit .""" pass class _FakeCacheDataDecorator: - """TODO: Add docstring.""" + """Test suite for FakeCacheDataDecorator.""" def __call__(self, func: Any = None, **kwargs: Any) -> Any: - """TODO: Add docstring.""" + """Helper function to call .""" if func is not None: return func return lambda f: f def clear(self) -> None: - """TODO: Add docstring.""" + """Helper function to clear.""" pass class _FakeSitesStreamlit: - """TODO: Add docstring.""" + """Test suite for FakeSitesStreamlit.""" def __init__(self) -> None: - """TODO: Add docstring.""" + """Initialize the test object.""" self.session_state: dict[str, Any] = {"_imednet_connected": True} self.titles: list[str] = [] self.infos: list[str] = [] @@ -53,100 +53,100 @@ def __init__(self) -> None: self.sidebar = _FakeContextManager() def title(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to title.""" self.titles.append(value) def info(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to info.""" self.infos.append(value) def success(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to success.""" self.successes.append(value) def markdown(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to markdown.""" self.markdowns.append(value) def button(self, label: str, **kwargs: Any) -> bool: - """TODO: Add docstring.""" + """Helper function to button.""" return False def subheader(self, value: str, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to subheader.""" pass def altair_chart(self, chart: Any, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to altair chart.""" pass def columns(self, spec: Any) -> list[Any]: - """TODO: Add docstring.""" + """Helper function to columns.""" count = spec if isinstance(spec, int) else len(spec) return [_FakeContextManager() for _ in range(count)] def multiselect(self, label: str, options: Any, **kwargs: Any) -> list[Any]: - """TODO: Add docstring.""" + """Helper function to multiselect.""" return list(kwargs.get("default", [])) def date_input(self, label: str, **kwargs: Any) -> list[Any]: - """TODO: Add docstring.""" + """Helper function to date input.""" val = kwargs.get("value", []) return list(val) if hasattr(val, "__iter__") else [] def rerun(self) -> None: - """TODO: Add docstring.""" + """Helper function to rerun.""" pass def text_input(self, label: str, **kwargs: Any) -> str: - """TODO: Add docstring.""" + """Helper function to text input.""" return "" def dataframe(self, df: Any, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to dataframe.""" pass def download_button(self, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to download button.""" pass def metric(self, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to metric.""" pass def _make_fake_components_module() -> ModuleType: - """TODO: Add docstring.""" + """Helper function to make fake components module.""" import pandas as pd mod = ModuleType("imednet_streamlit.components") def _noop_kpi_row(metrics: list[dict[str, Any]]) -> None: - """TODO: Add docstring.""" + """Helper function to noop kpi row.""" pass def _noop_bar_chart(df: pd.DataFrame, **kwargs: Any) -> MagicMock: - """TODO: Add docstring.""" + """Helper function to noop bar chart.""" return MagicMock() def _noop_line_chart(df: pd.DataFrame, **kwargs: Any) -> MagicMock: - """TODO: Add docstring.""" + """Helper function to noop line chart.""" return MagicMock() def _noop_filterable_dataframe(df: pd.DataFrame, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to noop filterable dataframe.""" pass def _noop_csv_download_button(df: pd.DataFrame, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to noop csv download button.""" pass def _noop_excel_download_button(df: pd.DataFrame, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to noop excel download button.""" pass def _noop_paginated_slice(df: pd.DataFrame, **kwargs: Any) -> pd.DataFrame: - """TODO: Add docstring.""" + """Helper function to noop paginated slice.""" return df mod.kpi_row = _noop_kpi_row # type: ignore[attr-defined] @@ -160,7 +160,7 @@ def _noop_paginated_slice(df: pd.DataFrame, **kwargs: Any) -> pd.DataFrame: def test_sites_page_renders_with_mock_sdk() -> None: - """TODO: Add docstring.""" + """Test that sites page renders with mock sdk.""" page_path = PACKAGE_ROOT / "pages" / "sites.py" fake_st = _FakeSitesStreamlit() @@ -248,13 +248,13 @@ def test_sites_page_renders_with_mock_sdk() -> None: def test_sites_page_populated_and_refresh() -> None: - """TODO: Add docstring.""" + """Test that sites page populated and refresh.""" page_path = PACKAGE_ROOT / "pages" / "sites.py" fake_st = _FakeSitesStreamlit() # Stub button to return True for refresh def _button(label: str, **kwargs: Any) -> bool: - """TODO: Add docstring.""" + """Helper function to button.""" if label == "🔄 Refresh Data": return True return False diff --git a/tests/unit/test_airflow_deprecation.py b/tests/unit/test_airflow_deprecation.py index f59762a4..f2a0e2a3 100644 --- a/tests/unit/test_airflow_deprecation.py +++ b/tests/unit/test_airflow_deprecation.py @@ -1,11 +1,11 @@ -"""TODO: Add docstring.""" +"""Unit tests for airflow deprecation.""" import sys from types import ModuleType def _setup_airflow(monkeypatch): - """TODO: Add docstring.""" + """Helper function to setup airflow.""" airflow_mod = ModuleType("airflow") hooks_pkg = ModuleType("airflow.hooks") hooks_mod = ModuleType("airflow.sdk.bases.hook") @@ -16,20 +16,20 @@ def _setup_airflow(monkeypatch): models_mod = ModuleType("airflow.models") class DummyBaseHook: - """TODO: Add docstring.""" + """Test suite for DummyBaseHook.""" @classmethod def get_connection(cls, conn_id): # pragma: no cover - """TODO: Add docstring.""" + """Helper function to get connection.""" raise NotImplementedError class DummyBaseOperator: - """TODO: Add docstring.""" + """Test suite for DummyBaseOperator.""" template_fields = () def __init__(self, **kwargs): # pragma: no cover - """TODO: Add docstring.""" + """Initialize the test object.""" pass hooks_mod.BaseHook = DummyBaseHook @@ -54,7 +54,7 @@ def __init__(self, **kwargs): # pragma: no cover def test_airflow_provider_exports_public_api(monkeypatch): - """TODO: Add docstring.""" + """Test that airflow provider exports public api.""" _setup_airflow(monkeypatch) for mod in [ "apache_airflow_providers_imednet", diff --git a/tests/unit/test_airflow_export.py b/tests/unit/test_airflow_export.py index bc593f9e..d2d26558 100644 --- a/tests/unit/test_airflow_export.py +++ b/tests/unit/test_airflow_export.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for airflow export.""" import sys from types import ModuleType @@ -9,7 +9,7 @@ # Setup dummy airflow modules to prevent import errors if airflow is not installed def _setup_airflow(monkeypatch): - """TODO: Add docstring.""" + """Helper function to setup airflow.""" airflow_mod = ModuleType("airflow") hooks_pkg = ModuleType("airflow.hooks") hooks_mod = ModuleType("airflow.sdk.bases.hook") @@ -20,20 +20,20 @@ def _setup_airflow(monkeypatch): models_mod = ModuleType("airflow.models") class DummyBaseHook: - """TODO: Add docstring.""" + """Test suite for DummyBaseHook.""" @classmethod def get_connection(cls, conn_id): - """TODO: Add docstring.""" + """Helper function to get connection.""" raise NotImplementedError class DummyBaseOperator: - """TODO: Add docstring.""" + """Test suite for DummyBaseOperator.""" template_fields = () def __init__(self, **kwargs): - """TODO: Add docstring.""" + """Initialize the test object.""" pass hooks_mod.BaseHook = DummyBaseHook @@ -69,7 +69,7 @@ def __init__(self, **kwargs): @pytest.fixture(autouse=True) def setup_airflow_mock(monkeypatch): - """TODO: Add docstring.""" + """Helper function to setup airflow mock.""" _setup_airflow(monkeypatch) diff --git a/tests/unit/test_airflow_integration.py b/tests/unit/test_airflow_integration.py index a37a8e6a..67a6139c 100644 --- a/tests/unit/test_airflow_integration.py +++ b/tests/unit/test_airflow_integration.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for airflow integration.""" import importlib.util import sys @@ -13,7 +13,7 @@ def _setup_airflow(monkeypatch): - """TODO: Add docstring.""" + """Helper function to setup airflow.""" airflow_mod = ModuleType("airflow") hooks_pkg = ModuleType("airflow.hooks") hooks_mod = ModuleType("airflow.sdk.bases.hook") @@ -24,20 +24,20 @@ def _setup_airflow(monkeypatch): models_mod = ModuleType("airflow.models") class DummyBaseHook: - """TODO: Add docstring.""" + """Test suite for DummyBaseHook.""" @classmethod def get_connection(cls, conn_id): - """TODO: Add docstring.""" + """Helper function to get connection.""" raise NotImplementedError class DummyBaseOperator: - """TODO: Add docstring.""" + """Test suite for DummyBaseOperator.""" template_fields = () def __init__(self, **kwargs): - """TODO: Add docstring.""" + """Initialize the test object.""" pass hooks_mod.BaseHook = DummyBaseHook @@ -62,7 +62,7 @@ def __init__(self, **kwargs): def test_imednet_hook_returns_sdk(monkeypatch): - """TODO: Add docstring.""" + """Test that imednet hook returns sdk.""" _setup_airflow(monkeypatch) conn = MagicMock() @@ -90,7 +90,7 @@ def test_imednet_hook_returns_sdk(monkeypatch): def test_export_operator_calls_helper(monkeypatch): - """TODO: Add docstring.""" + """Test that export operator calls helper.""" if "apache_airflow_providers_imednet" in sys.modules: del sys.modules["apache_airflow_providers_imednet"] @@ -129,7 +129,7 @@ def test_export_operator_calls_helper(monkeypatch): def test_export_operator_exposes_mapped_runtime_fields(monkeypatch): - """TODO: Add docstring.""" + """Test that export operator exposes mapped runtime fields.""" if "apache_airflow_providers_imednet" in sys.modules: del sys.modules["apache_airflow_providers_imednet"] @@ -147,7 +147,7 @@ def test_export_operator_exposes_mapped_runtime_fields(monkeypatch): def test_export_operator_copies_runtime_kwargs_and_resolves_sdk_at_execute(monkeypatch): - """TODO: Add docstring.""" + """Test that export operator copies runtime kwargs and resolves sdk at execute.""" if "apache_airflow_providers_imednet" in sys.modules: del sys.modules["apache_airflow_providers_imednet"] @@ -192,7 +192,7 @@ def test_export_operator_copies_runtime_kwargs_and_resolves_sdk_at_execute(monke def test_export_operator_rejects_unknown_export_callable(monkeypatch): - """TODO: Add docstring.""" + """Test that export operator rejects unknown export callable.""" if "apache_airflow_providers_imednet" in sys.modules: del sys.modules["apache_airflow_providers_imednet"] @@ -222,7 +222,7 @@ def test_export_operator_rejects_unknown_export_callable(monkeypatch): def test_imednet_hook_non_dict_extras(monkeypatch): - """TODO: Add docstring.""" + """Test that imednet hook non dict extras.""" _setup_airflow(monkeypatch) conn = MagicMock() @@ -248,7 +248,7 @@ def test_imednet_hook_non_dict_extras(monkeypatch): def test_imednet_hook_get_extra_json_fallback(monkeypatch): - """TODO: Add docstring.""" + """Test that imednet hook get extra json fallback.""" _setup_airflow(monkeypatch) conn = MagicMock() @@ -281,7 +281,7 @@ def test_imednet_hook_get_extra_json_fallback(monkeypatch): def test_imednet_hook_extra_json_string_fallback(monkeypatch): - """TODO: Add docstring.""" + """Test that imednet hook extra json string fallback.""" _setup_airflow(monkeypatch) conn = MagicMock() @@ -313,7 +313,7 @@ def test_imednet_hook_extra_json_string_fallback(monkeypatch): def test_imednet_hook_non_string_login(monkeypatch): - """TODO: Add docstring.""" + """Test that imednet hook non string login.""" _setup_airflow(monkeypatch) conn = MagicMock() @@ -338,7 +338,7 @@ def test_imednet_hook_non_string_login(monkeypatch): def test_imednet_hook_non_string_password(monkeypatch): - """TODO: Add docstring.""" + """Test that imednet hook non string password.""" _setup_airflow(monkeypatch) conn = MagicMock() @@ -366,7 +366,7 @@ def test_imednet_hook_non_string_password(monkeypatch): def test_imednet_hook_environment_fallback(monkeypatch): - """TODO: Add docstring.""" + """Test that imednet hook environment fallback.""" _setup_airflow(monkeypatch) monkeypatch.setenv("IMEDNET_API_KEY", "ENV_KEY") monkeypatch.setenv("IMEDNET_SECURITY_KEY", "ENV_SEC") @@ -395,7 +395,7 @@ def test_imednet_hook_environment_fallback(monkeypatch): def test_imednet_hook_describe_connection_redacts_credentials(monkeypatch): - """TODO: Add docstring.""" + """Test that imednet hook describe connection redacts credentials.""" _setup_airflow(monkeypatch) conn = MagicMock() @@ -427,7 +427,7 @@ def test_imednet_hook_describe_connection_redacts_credentials(monkeypatch): def test_imednet_hook_prefers_extras_over_environment(monkeypatch): - """TODO: Add docstring.""" + """Test that imednet hook prefers extras over environment.""" _setup_airflow(monkeypatch) monkeypatch.setenv("IMEDNET_API_KEY", "ENV_KEY") monkeypatch.setenv("IMEDNET_SECURITY_KEY", "ENV_SEC") @@ -454,16 +454,16 @@ def test_imednet_hook_prefers_extras_over_environment(monkeypatch): def test_imednet_hook_study_discovery_serialization_safe(monkeypatch): - """TODO: Add docstring.""" + """Test that imednet hook study discovery serialization safe.""" _setup_airflow(monkeypatch) from apache_airflow_providers_imednet.hooks import ImednetHook class _StudyModel: - """TODO: Add docstring.""" + """Test suite for StudyModel.""" def model_dump(self, mode="json", by_alias=True): - """TODO: Add docstring.""" + """Helper function to model dump.""" assert mode == "json" assert by_alias is True return { @@ -508,32 +508,32 @@ def _setup_airflow_for_dag(monkeypatch): airflow_mod = sys.modules["airflow"] class _DummyDAG: - """TODO: Add docstring.""" + """Test suite for DummyDAG.""" def __init__(self, *args, **kwargs): - """TODO: Add docstring.""" + """Initialize the test object.""" pass def __enter__(self): - """TODO: Add docstring.""" + """Helper function to enter .""" return self def __exit__(self, *args): - """TODO: Add docstring.""" + """Helper function to exit .""" pass class _DummyTaskDecorator: """Thin shim for ``@task`` and ``@task(...)``.""" def __call__(self, *args, **kwargs): - """TODO: Add docstring.""" + """Helper function to call .""" if len(args) == 1 and callable(args[0]): # bare @task usage return args[0] # @task(...) — return a no-op decorator def _decorator(fn): - """TODO: Add docstring.""" + """Helper function to decorator.""" return fn return _decorator @@ -545,7 +545,7 @@ def _decorator(fn): monkeypatch.setitem(sys.modules, "airflow.decorators", decorators_mod) class _DummyOperator: - """TODO: Add docstring.""" + """Test suite for DummyOperator.""" template_fields = () # Mirrors ImednetExportOperator.mapped_runtime_fields: these are the fields @@ -554,31 +554,31 @@ class _DummyOperator: mapped_runtime_fields = ("study_key", "output_path", "export_kwargs") def __init__(self, **kwargs): - """TODO: Add docstring.""" + """Initialize the test object.""" pass @classmethod def partial(cls, **kwargs): - """TODO: Add docstring.""" + """Helper function to partial.""" class _PartialOp: - """TODO: Add docstring.""" + """Test suite for PartialOp.""" def expand_kwargs(self, targets): - """TODO: Add docstring.""" + """Helper function to expand kwargs.""" pass return _PartialOp() class _DummyHook: - """TODO: Add docstring.""" + """Test suite for DummyHook.""" def __init__(self, conn_id: str = "imednet_default") -> None: - """TODO: Add docstring.""" + """Initialize the test object.""" pass def list_study_keys(self): - """TODO: Add docstring.""" + """Helper function to list study keys.""" return [] provider_mod = ModuleType("apache_airflow_providers_imednet") @@ -593,10 +593,10 @@ def test_to_primitive_unknown_object_type_falls_back_to_str(monkeypatch): from apache_airflow_providers_imednet.hooks import ImednetHook class _Opaque: - """TODO: Add docstring.""" + """Test suite for Opaque.""" def __str__(self): - """TODO: Add docstring.""" + """Helper function to str .""" return "opaque-repr" result = ImednetHook._to_primitive(_Opaque()) @@ -721,7 +721,7 @@ def test_list_study_keys_skips_entries_without_recognized_key(monkeypatch): def test_export_operator_resolves_snowflake_sink(monkeypatch): - """TODO: Add docstring.""" + """Test that export operator resolves snowflake sink.""" if "apache_airflow_providers_imednet" in sys.modules: del sys.modules["apache_airflow_providers_imednet"] diff --git a/tests/unit/test_airflow_operators.py b/tests/unit/test_airflow_operators.py index 01406a86..6c821b51 100644 --- a/tests/unit/test_airflow_operators.py +++ b/tests/unit/test_airflow_operators.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for airflow operators.""" import importlib import sys @@ -9,7 +9,7 @@ def _setup_airflow(monkeypatch): - """TODO: Add docstring.""" + """Helper function to setup airflow.""" airflow = ModuleType("airflow") hooks_pkg = ModuleType("airflow.hooks") hooks_base = ModuleType("airflow.sdk.bases.hook") @@ -23,29 +23,29 @@ def _setup_airflow(monkeypatch): s3_mod = ModuleType("airflow.providers.amazon.aws.hooks.s3") class DummyBaseHook: - """TODO: Add docstring.""" + """Test suite for DummyBaseHook.""" @classmethod def get_connection(cls, conn_id): - """TODO: Add docstring.""" + """Helper function to get connection.""" raise NotImplementedError class DummyBaseOperator: - """TODO: Add docstring.""" + """Test suite for DummyBaseOperator.""" template_fields = () def __init__(self, *a, **kw): - """TODO: Add docstring.""" + """Initialize the test object.""" pass class DummySensorOperator: - """TODO: Add docstring.""" + """Test suite for DummySensorOperator.""" template_fields = () def __init__(self, *a, **kw): - """TODO: Add docstring.""" + """Initialize the test object.""" pass hooks_base.BaseHook = DummyBaseHook @@ -53,7 +53,7 @@ def __init__(self, *a, **kw): sensors_base.BaseSensorOperator = DummySensorOperator class DummyAirflowError(Exception): - """TODO: Add docstring.""" + """Test suite for DummyAirflowError.""" pass @@ -98,7 +98,7 @@ class DummyAirflowError(Exception): def _import_operators(monkeypatch): - """TODO: Add docstring.""" + """Helper function to import operators.""" _setup_airflow(monkeypatch) import apache_airflow_providers_imednet.operators as ops @@ -106,7 +106,7 @@ def _import_operators(monkeypatch): def _import_sensors(monkeypatch): - """TODO: Add docstring.""" + """Helper function to import sensors.""" _setup_airflow(monkeypatch) import apache_airflow_providers_imednet.sensors as sensors @@ -114,7 +114,7 @@ def _import_sensors(monkeypatch): def _patch_basehook(monkeypatch, extras=None): - """TODO: Add docstring.""" + """Helper function to patch basehook.""" conn = SimpleNamespace(login=None, password=None, extra_dejson=extras or {}) import apache_airflow_providers_imednet.hooks as hook_mod @@ -127,7 +127,7 @@ def _patch_basehook(monkeypatch, extras=None): def test_job_sensor(monkeypatch): - """TODO: Add docstring.""" + """Test that job sensor.""" _setup_airflow(monkeypatch) import apache_airflow_providers_imednet.operators as ops import apache_airflow_providers_imednet.sensors as sensors diff --git a/tests/unit/test_async_sdk_deprecation.py b/tests/unit/test_async_sdk_deprecation.py index 26fccc6d..0541cbb8 100644 --- a/tests/unit/test_async_sdk_deprecation.py +++ b/tests/unit/test_async_sdk_deprecation.py @@ -1,10 +1,10 @@ -"""TODO: Add docstring.""" +"""Unit tests for async sdk deprecation.""" import pytest def test_async_sdk_deprecation_warning(): - """TODO: Add docstring.""" + """Test that async sdk deprecation warning.""" import sys if "imednet.async_sdk" in sys.modules: diff --git a/tests/unit/test_base_client.py b/tests/unit/test_base_client.py index 8cec1453..ddfe2f09 100644 --- a/tests/unit/test_base_client.py +++ b/tests/unit/test_base_client.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for base client.""" from unittest.mock import MagicMock @@ -11,16 +11,16 @@ class DummyClient(BaseClient): - """TODO: Add docstring.""" + """Test suite for DummyClient.""" def _create_client(self, auth: AuthStrategy) -> httpx.Client: - """TODO: Add docstring.""" + """Helper function to create client.""" headers = auth.get_headers() return httpx.Client(headers=headers) def test_initialization_from_env(monkeypatch) -> None: - """TODO: Add docstring.""" + """Test that initialization from env.""" monkeypatch.setenv("IMEDNET_API_KEY", "env_key") monkeypatch.setenv("IMEDNET_SECURITY_KEY", "env_secret") monkeypatch.setenv("IMEDNET_BASE_URL", "https://env.example.com") diff --git a/tests/unit/test_base_url_normalization.py b/tests/unit/test_base_url_normalization.py index 62070fa4..dc35a115 100644 --- a/tests/unit/test_base_url_normalization.py +++ b/tests/unit/test_base_url_normalization.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for base url normalization.""" from unittest.mock import MagicMock @@ -13,20 +13,20 @@ class MockModel(JsonModel): - """TODO: Add docstring.""" + """Test suite for MockModel.""" pass class MockEndpoint(EdcEndpointMixin, GenericEndpoint[MockModel]): - """TODO: Add docstring.""" + """Test suite for MockEndpoint.""" MODEL = MockModel PATH = "/test" def test_client_strips_api_suffix() -> None: - """TODO: Add docstring.""" + """Test that client strips api suffix.""" client = Client(api_key="k", security_key="s", base_url="https://x/api") assert client.base_url == "https://x" assert client._client.base_url == httpx.URL("https://x") @@ -34,7 +34,7 @@ def test_client_strips_api_suffix() -> None: @pytest.mark.asyncio async def test_async_client_strips_api_suffix() -> None: - """TODO: Add docstring.""" + """Test that async client strips api suffix asynchronously.""" async with AsyncClient( api_key="k", security_key="s", @@ -45,7 +45,7 @@ async def test_async_client_strips_api_suffix() -> None: def test_build_safe_path_handles_special_characters() -> None: - """TODO: Add docstring.""" + """Test that build safe path handles special characters.""" client = MagicMock(spec=Client) endpoint = MockEndpoint(client) @@ -56,7 +56,7 @@ def test_build_safe_path_handles_special_characters() -> None: def test_build_safe_path_prevents_double_slashes() -> None: - """TODO: Add docstring.""" + """Test that build safe path prevents double slashes.""" client = MagicMock(spec=Client) endpoint = MockEndpoint(client) diff --git a/tests/unit/test_cached_records_loader.py b/tests/unit/test_cached_records_loader.py index d0f4b66e..4920e867 100644 --- a/tests/unit/test_cached_records_loader.py +++ b/tests/unit/test_cached_records_loader.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for cached records loader.""" from __future__ import annotations @@ -13,7 +13,7 @@ def _record(record_id: int, modified_at: str) -> Record: - """TODO: Add docstring.""" + """Helper function to record.""" return Record( study_key="STUDY", form_id=10, @@ -26,7 +26,7 @@ def _record(record_id: int, modified_at: str) -> Record: def test_get_cache_connection_enables_wal_mode(tmp_path: Path) -> None: - """TODO: Add docstring.""" + """Test that get cache connection enables wal mode.""" conn = get_cache_connection(tmp_path / "cache" / "records.sqlite3") try: journal_mode = conn.execute("PRAGMA journal_mode").fetchone()[0] @@ -36,7 +36,7 @@ def test_get_cache_connection_enables_wal_mode(tmp_path: Path) -> None: def test_cached_loader_applies_delta_sync_and_reconciliation(tmp_path: Path) -> None: - """TODO: Add docstring.""" + """Test that cached loader applies delta sync and reconciliation.""" sdk = MagicMock() first_batch = [ _record(1, "2024-01-01 00:00:00+00:00"), @@ -76,7 +76,7 @@ def test_cached_loader_applies_delta_sync_and_reconciliation(tmp_path: Path) -> def test_cached_loader_retries_record_fetches(tmp_path: Path) -> None: - """TODO: Add docstring.""" + """Test that cached loader retries record fetches.""" sdk = MagicMock() record = _record(1, "2024-01-01 00:00:00+00:00") sdk.get_records.side_effect = [RuntimeError("temporary"), [record], [record]] @@ -90,7 +90,7 @@ def test_cached_loader_retries_record_fetches(tmp_path: Path) -> None: def test_iter_cached_records_yields_chunked_rows(tmp_path: Path) -> None: - """TODO: Add docstring.""" + """Test that iter cached records yields chunked rows.""" sdk = MagicMock() sdk.get_records.side_effect = [ [_record(1, "2024-01-01 00:00:00+00:00"), _record(2, "2024-01-02 00:00:00+00:00")], @@ -105,7 +105,7 @@ def test_iter_cached_records_yields_chunked_rows(tmp_path: Path) -> None: def test_iter_cached_records_rejects_non_positive_chunk_size(tmp_path: Path) -> None: - """TODO: Add docstring.""" + """Test that iter cached records rejects non positive chunk size.""" loader = CachedRecordsLoader(MagicMock(), cache_dir=tmp_path) with pytest.raises(ValueError, match="chunk_size must be greater than zero"): @@ -113,7 +113,7 @@ def test_iter_cached_records_rejects_non_positive_chunk_size(tmp_path: Path) -> def test_sync_records_updates_cache_without_loading_rows(tmp_path: Path) -> None: - """TODO: Add docstring.""" + """Test that sync records updates cache without loading rows.""" sdk = MagicMock() sdk.get_records.side_effect = [ [_record(1, "2024-01-01 00:00:00+00:00")], @@ -134,7 +134,7 @@ def test_sync_records_updates_cache_without_loading_rows(tmp_path: Path) -> None def test_sync_records_handles_empty_delta_without_reconciliation(tmp_path: Path) -> None: - """TODO: Add docstring.""" + """Test that sync records handles empty delta without reconciliation.""" sdk = MagicMock() sdk.get_records.side_effect = [ [_record(1, "2024-01-01 00:00:00+00:00")], diff --git a/tests/unit/test_chunked_pipeline.py b/tests/unit/test_chunked_pipeline.py index 68de81ef..ac1de353 100644 --- a/tests/unit/test_chunked_pipeline.py +++ b/tests/unit/test_chunked_pipeline.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for chunked pipeline.""" from __future__ import annotations @@ -8,19 +8,19 @@ def test_iter_chunks_splits_batches() -> None: - """TODO: Add docstring.""" + """Test that iter chunks splits batches.""" chunks = list(iter_chunks(range(5), chunk_size=2)) assert chunks == [[0, 1], [2, 3], [4]] def test_iter_chunks_rejects_invalid_chunk_size() -> None: - """TODO: Add docstring.""" + """Test that iter chunks rejects invalid chunk size.""" with pytest.raises(ValueError, match="chunk_size must be greater than zero"): list(iter_chunks([1, 2], chunk_size=0)) def test_chunked_record_pipeline_maps_in_chunks() -> None: - """TODO: Add docstring.""" + """Test that chunked record pipeline maps in chunks.""" pipeline = ChunkedRecordPipeline(chunk_size=2) mapped = list(pipeline.map_chunks([1, 2, 3], lambda value: value * 10)) assert mapped == [[10, 20], [30]] diff --git a/tests/unit/test_client.py b/tests/unit/test_client.py index 66ebd496..bc0a57f9 100644 --- a/tests/unit/test_client.py +++ b/tests/unit/test_client.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for client.""" import httpx import pytest @@ -15,7 +15,7 @@ def test_get_success(http_client, respx_mock_client, sample_data): - """TODO: Add docstring.""" + """Test that get success.""" respx_mock_client.get("/items").mock(return_value=httpx.Response(200, json=sample_data)) response = http_client.get("/items") @@ -37,7 +37,7 @@ def test_get_success(http_client, respx_mock_client, sample_data): ], ) def test_request_error_mapping(http_client, respx_mock_client, status, exc): - """TODO: Add docstring.""" + """Test that request error mapping.""" respx_mock_client.get("/path").mock(return_value=httpx.Response(status, json={"err": "x"})) with pytest.raises(exc): @@ -45,7 +45,7 @@ def test_request_error_mapping(http_client, respx_mock_client, status, exc): def test_client_sends_auth_headers(http_client, respx_mock_client): - """TODO: Add docstring.""" + """Test that client sends auth headers.""" route = respx_mock_client.get("/headers").mock(return_value=httpx.Response(200, json={})) http_client.get("/headers") diff --git a/tests/unit/test_config.py b/tests/unit/test_config.py index 7e6be929..4691e7dd 100644 --- a/tests/unit/test_config.py +++ b/tests/unit/test_config.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for config.""" import pytest @@ -6,7 +6,7 @@ def test_load_config_from_env(monkeypatch): - """TODO: Add docstring.""" + """Test that load config from env.""" monkeypatch.setenv("IMEDNET_API_KEY", "env_key") monkeypatch.setenv("IMEDNET_SECURITY_KEY", "env_secret") monkeypatch.setenv("IMEDNET_BASE_URL", " https://example.com ") @@ -18,7 +18,7 @@ def test_load_config_from_env(monkeypatch): def test_load_config_overrides_env(monkeypatch): - """TODO: Add docstring.""" + """Test that load config overrides env.""" monkeypatch.setenv("IMEDNET_API_KEY", "env_key") monkeypatch.setenv("IMEDNET_SECURITY_KEY", "env_secret") cfg = load_config(api_key="arg_key", security_key="arg_sec", base_url="https://override") @@ -26,7 +26,7 @@ def test_load_config_overrides_env(monkeypatch): def test_load_config_missing(monkeypatch): - """TODO: Add docstring.""" + """Test that load config missing.""" monkeypatch.delenv("IMEDNET_API_KEY", raising=False) monkeypatch.delenv("IMEDNET_SECURITY_KEY", raising=False) with pytest.raises(ValueError, match="API key and security key are required"): diff --git a/tests/unit/test_config_version_control.py b/tests/unit/test_config_version_control.py index 9562db78..9934643c 100644 --- a/tests/unit/test_config_version_control.py +++ b/tests/unit/test_config_version_control.py @@ -23,7 +23,7 @@ def _make_config( *, extra_mapping: bool = False, ) -> StudyConfiguration: - """TODO: Add docstring.""" + """Helper function to make config.""" mappings = [ MappingRule( domain="AE", @@ -60,7 +60,7 @@ def _make_config( @pytest.fixture() def store(tmp_path: Path) -> ConfigVersionStore: - """TODO: Add docstring.""" + """Helper function to store.""" return ConfigVersionStore(db_path=tmp_path / "test_versions.sqlite3") @@ -70,13 +70,13 @@ def store(tmp_path: Path) -> ConfigVersionStore: def test_sha256_deterministic() -> None: - """TODO: Add docstring.""" + """Test that sha256 deterministic.""" assert _sha256_of("hello") == _sha256_of("hello") assert _sha256_of("hello") != _sha256_of("world") def test_sha256_length() -> None: - """TODO: Add docstring.""" + """Test that sha256 length.""" digest = _sha256_of("any string") assert len(digest) == 64 @@ -87,28 +87,28 @@ def test_sha256_length() -> None: def test_flatten_flat_dict() -> None: - """TODO: Add docstring.""" + """Test that flatten flat dict.""" data = {"a": 1, "b": "two"} result = _flatten(data) assert result == {"a": 1, "b": "two"} def test_flatten_nested_dict() -> None: - """TODO: Add docstring.""" + """Test that flatten nested dict.""" data = {"outer": {"inner": 42}} result = _flatten(data) assert result == {"outer.inner": 42} def test_flatten_list() -> None: - """TODO: Add docstring.""" + """Test that flatten list.""" data = {"items": [10, 20]} result = _flatten(data) assert result == {"items[0]": 10, "items[1]": 20} def test_flatten_mixed() -> None: - """TODO: Add docstring.""" + """Test that flatten mixed.""" data = {"a": {"b": [1, {"c": 3}]}} result = _flatten(data) assert "a.b[0]" in result @@ -121,7 +121,7 @@ def test_flatten_mixed() -> None: def test_commit_config_returns_sha256(store: ConfigVersionStore) -> None: - """TODO: Add docstring.""" + """Test that commit config returns sha256.""" config = _make_config() commit_id = store.commit_config("STUDY-01", config, user="alice", desc="Initial commit") assert len(commit_id) == 64 @@ -129,7 +129,7 @@ def test_commit_config_returns_sha256(store: ConfigVersionStore) -> None: def test_commit_config_duplicate_raises(store: ConfigVersionStore) -> None: - """TODO: Add docstring.""" + """Test that commit config duplicate raises.""" config = _make_config() store.commit_config("STUDY-01", config, user="alice", desc="First") with pytest.raises(ValueError, match="already exists"): @@ -137,7 +137,7 @@ def test_commit_config_duplicate_raises(store: ConfigVersionStore) -> None: def test_commit_config_different_content_succeeds(store: ConfigVersionStore) -> None: - """TODO: Add docstring.""" + """Test that commit config different content succeeds.""" config_a = _make_config(version="1.0.0") config_b = _make_config(version="1.1.0") id_a = store.commit_config("STUDY-01", config_a, user="alice", desc="v1.0.0") @@ -146,7 +146,7 @@ def test_commit_config_different_content_succeeds(store: ConfigVersionStore) -> def test_commit_config_persists_metadata(store: ConfigVersionStore, tmp_path: Path) -> None: - """TODO: Add docstring.""" + """Test that commit config persists metadata.""" config = _make_config() commit_id = store.commit_config("STUDY-01", config, user="bob", desc="Test commit") history = store.get_history("STUDY-01") @@ -166,12 +166,12 @@ def test_commit_config_persists_metadata(store: ConfigVersionStore, tmp_path: Pa def test_get_history_empty(store: ConfigVersionStore) -> None: - """TODO: Add docstring.""" + """Test that get history empty.""" assert store.get_history("UNKNOWN") == [] def test_get_history_ordered(store: ConfigVersionStore) -> None: - """TODO: Add docstring.""" + """Test that get history ordered.""" c1 = _make_config(version="1.0.0") c2 = _make_config(version="1.1.0") c3 = _make_config(version="1.2.0", extra_mapping=True) @@ -188,7 +188,7 @@ def test_get_history_ordered(store: ConfigVersionStore) -> None: def test_get_history_isolated_by_study(store: ConfigVersionStore) -> None: - """TODO: Add docstring.""" + """Test that get history isolated by study.""" c1 = _make_config(study_key="STUDY-01") c2 = _make_config(study_key="STUDY-02") store.commit_config("STUDY-01", c1, user="alice", desc="first") @@ -200,7 +200,7 @@ def test_get_history_isolated_by_study(store: ConfigVersionStore) -> None: def test_get_history_excludes_config_data(store: ConfigVersionStore) -> None: - """TODO: Add docstring.""" + """Test that get history excludes config data.""" config = _make_config() store.commit_config("STUDY-01", config, user="alice", desc="first") history = store.get_history("STUDY-01") @@ -213,7 +213,7 @@ def test_get_history_excludes_config_data(store: ConfigVersionStore) -> None: def test_diff_configs_no_changes(store: ConfigVersionStore) -> None: - """TODO: Add docstring.""" + """Test that diff configs no changes.""" # Verify self-diff of a flattened config produces no differences. c1 = _make_config(version="1.0.0") config_json = json.dumps(c1.model_dump(mode="json", by_alias=True), sort_keys=True) @@ -233,7 +233,7 @@ def test_diff_configs_no_changes(store: ConfigVersionStore) -> None: def test_diff_configs_detects_changes(store: ConfigVersionStore) -> None: - """TODO: Add docstring.""" + """Test that diff configs detects changes.""" c1 = _make_config(version="1.0.0") c2 = _make_config(version="1.1.0") id_a = store.commit_config("STUDY-01", c1, user="alice", desc="v1.0.0") @@ -246,7 +246,7 @@ def test_diff_configs_detects_changes(store: ConfigVersionStore) -> None: def test_diff_configs_detects_added_keys(store: ConfigVersionStore) -> None: - """TODO: Add docstring.""" + """Test that diff configs detects added keys.""" c1 = _make_config(version="1.0.0", extra_mapping=False) c2 = _make_config(version="1.1.0", extra_mapping=True) id_a = store.commit_config("STUDY-01", c1, user="alice", desc="base") @@ -257,7 +257,7 @@ def test_diff_configs_detects_added_keys(store: ConfigVersionStore) -> None: def test_diff_configs_missing_commit_raises(store: ConfigVersionStore) -> None: - """TODO: Add docstring.""" + """Test that diff configs missing commit raises.""" c1 = _make_config() id_a = store.commit_config("STUDY-01", c1, user="alice", desc="base") with pytest.raises(KeyError): @@ -270,7 +270,7 @@ def test_diff_configs_missing_commit_raises(store: ConfigVersionStore) -> None: def test_rollback_config_restores_original(store: ConfigVersionStore) -> None: - """TODO: Add docstring.""" + """Test that rollback config restores original.""" original = _make_config(version="1.0.0") commit_id = store.commit_config("STUDY-01", original, user="alice", desc="base") @@ -286,7 +286,7 @@ def test_rollback_config_restores_original(store: ConfigVersionStore) -> None: def test_rollback_config_is_non_destructive(store: ConfigVersionStore) -> None: - """TODO: Add docstring.""" + """Test that rollback config is non destructive.""" c1 = _make_config(version="1.0.0") c2 = _make_config(version="1.1.0") id1 = store.commit_config("STUDY-01", c1, user="alice", desc="v1") @@ -300,7 +300,7 @@ def test_rollback_config_is_non_destructive(store: ConfigVersionStore) -> None: def test_rollback_config_wrong_study_raises(store: ConfigVersionStore) -> None: - """TODO: Add docstring.""" + """Test that rollback config wrong study raises.""" config = _make_config(study_key="STUDY-01") commit_id = store.commit_config("STUDY-01", config, user="alice", desc="base") with pytest.raises(KeyError, match="not found for study"): @@ -308,7 +308,7 @@ def test_rollback_config_wrong_study_raises(store: ConfigVersionStore) -> None: def test_rollback_config_unknown_commit_raises(store: ConfigVersionStore) -> None: - """TODO: Add docstring.""" + """Test that rollback config unknown commit raises.""" with pytest.raises(KeyError): store.rollback_config("STUDY-01", "deadbeef" * 8) @@ -346,7 +346,7 @@ def test_multiple_studies_independent(store: ConfigVersionStore) -> None: def test_get_history_detects_invalid_signature(store: ConfigVersionStore) -> None: - """TODO: Add docstring.""" + """Test that get history detects invalid signature.""" config_json = json.dumps( _make_config(version="9.9.9").model_dump(mode="json", by_alias=True), sort_keys=True, @@ -376,7 +376,7 @@ def test_get_history_detects_invalid_signature(store: ConfigVersionStore) -> Non def test_rollback_config_detects_invalid_signature(store: ConfigVersionStore) -> None: - """TODO: Add docstring.""" + """Test that rollback config detects invalid signature.""" config_json = json.dumps( _make_config(version="9.9.9").model_dump(mode="json", by_alias=True), sort_keys=True, @@ -407,7 +407,7 @@ def test_rollback_config_detects_invalid_signature(store: ConfigVersionStore) -> def test_diff_configs_detects_invalid_signature(store: ConfigVersionStore) -> None: - """TODO: Add docstring.""" + """Test that diff configs detects invalid signature.""" valid = _make_config(version="1.0.0") valid_commit = store.commit_config("STUDY-01", valid, user="alice", desc="valid") forged_json = json.dumps( @@ -440,7 +440,7 @@ def test_diff_configs_detects_invalid_signature(store: ConfigVersionStore) -> No def test_history_rows_cannot_be_updated(store: ConfigVersionStore) -> None: - """TODO: Add docstring.""" + """Test that history rows cannot be updated.""" config = _make_config(version="1.0.0") commit_id = store.commit_config("STUDY-01", config, user="alice", desc="base") @@ -455,7 +455,7 @@ def test_history_rows_cannot_be_updated(store: ConfigVersionStore) -> None: def test_history_rows_cannot_be_deleted(store: ConfigVersionStore) -> None: - """TODO: Add docstring.""" + """Test that history rows cannot be deleted.""" config = _make_config(version="1.0.0") commit_id = store.commit_config("STUDY-01", config, user="alice", desc="base") diff --git a/tests/unit/test_core_async_client.py b/tests/unit/test_core_async_client.py index f8dc1433..f8068ed2 100644 --- a/tests/unit/test_core_async_client.py +++ b/tests/unit/test_core_async_client.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for core async client.""" import httpx import pytest @@ -6,7 +6,7 @@ @pytest.mark.asyncio async def test_async_get_success(async_http_client, respx_mock_async_client, sample_data): - """TODO: Add docstring.""" + """Test that async get success asynchronously.""" respx_mock_async_client.get("/items").mock(return_value=httpx.Response(200, json=sample_data)) response = await async_http_client.get("/items") diff --git a/tests/unit/test_core_async_client_extended.py b/tests/unit/test_core_async_client_extended.py index b3542c39..02c557d1 100644 --- a/tests/unit/test_core_async_client_extended.py +++ b/tests/unit/test_core_async_client_extended.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for core async client extended.""" from unittest.mock import AsyncMock, MagicMock @@ -12,12 +12,12 @@ @pytest.mark.asyncio async def test_async_request_retries(): - """TODO: Add docstring.""" + """Test that async request retries asynchronously.""" async with AsyncClient("k", "s", base_url="https://api.test", retries=2) as client: calls = {"count": 0} async def request(request: httpx.Request) -> httpx.Response: - """TODO: Add docstring.""" + """Helper function to request.""" calls["count"] += 1 if calls["count"] == 1: raise httpx.RequestError("boom", request=request) @@ -45,7 +45,7 @@ async def request(request: httpx.Request) -> httpx.Response: ], ) async def test_async_request_error_mapping(status, exc): - """TODO: Add docstring.""" + """Test that async request error mapping asynchronously.""" async with AsyncClient("k", "s", base_url="https://api.test") as client: with respx.mock(assert_all_called=True, assert_all_mocked=True) as respx_mock: respx_mock.get("https://api.test/some").respond( @@ -58,7 +58,7 @@ async def test_async_request_error_mapping(status, exc): @pytest.mark.asyncio async def test_tracing(): - """TODO: Add docstring.""" + """Test that tracing asynchronously.""" tracer = MagicMock() span_cm = AsyncMock() span = MagicMock() diff --git a/tests/unit/test_core_client.py b/tests/unit/test_core_client.py index f22e5be5..c7550245 100644 --- a/tests/unit/test_core_client.py +++ b/tests/unit/test_core_client.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for core client.""" from unittest.mock import MagicMock @@ -13,7 +13,7 @@ def test_initialization_sets_defaults() -> None: - """TODO: Add docstring.""" + """Test that initialization sets defaults.""" client = Client(api_key="A", security_key="B") assert client.base_url == DEFAULT_BASE_URL assert client._client.headers["x-api-key"] == "A" @@ -21,12 +21,12 @@ def test_initialization_sets_defaults() -> None: def test_retry_logic_retries_request_errors() -> None: - """TODO: Add docstring.""" + """Test that retry logic retries request errors.""" client = Client(api_key="A", security_key="B", base_url="https://api.test", retries=2) call_count = {"count": 0} def side_effect(request: httpx.Request) -> httpx.Response: - """TODO: Add docstring.""" + """Helper function to side effect.""" call_count["count"] += 1 if call_count["count"] == 1: raise httpx.RequestError("boom", request=request) @@ -54,7 +54,7 @@ def side_effect(request: httpx.Request) -> httpx.Response: ], ) def test_request_error_mapping(status, exc) -> None: - """TODO: Add docstring.""" + """Test that request error mapping.""" client = Client(api_key="A", security_key="B", base_url="https://api.test") with respx.mock(assert_all_called=True, assert_all_mocked=True) as respx_mock: @@ -65,7 +65,7 @@ def test_request_error_mapping(status, exc) -> None: def test_tracer_records_span() -> None: - """TODO: Add docstring.""" + """Test that tracer records span.""" tracer = MagicMock() span_cm = MagicMock() span = MagicMock() @@ -85,13 +85,13 @@ def test_tracer_records_span() -> None: def test_base_url_sanitized() -> None: - """TODO: Add docstring.""" + """Test that base url sanitized.""" client = Client(api_key="A", security_key="B", base_url="https://host/api/") assert client.base_url == "https://host" def test_retry_policy_accessor_updates_executor() -> None: - """TODO: Add docstring.""" + """Test that retry policy accessor updates executor.""" client = Client(api_key="A", security_key="B") policy = MagicMock(spec=RetryPolicy) diff --git a/tests/unit/test_core_context.py b/tests/unit/test_core_context.py index 9aee21d4..5e7e2125 100644 --- a/tests/unit/test_core_context.py +++ b/tests/unit/test_core_context.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for core context.""" import pytest @@ -13,7 +13,7 @@ def test_set_and_reset_study_context() -> None: - """TODO: Add docstring.""" + """Test that set and reset study context.""" token = set_study_context("S1") assert get_current_study() == "S1" reset_study_context(token) @@ -22,7 +22,7 @@ def test_set_and_reset_study_context() -> None: def test_study_context_manager_resets_to_none() -> None: - """TODO: Add docstring.""" + """Test that study context manager resets to none.""" with study_context("S1"): assert get_current_study() == "S1" assert get_study_context() == "S1" @@ -31,7 +31,7 @@ def test_study_context_manager_resets_to_none() -> None: def test_study_context_manager_restores_previous_context() -> None: - """TODO: Add docstring.""" + """Test that study context manager restores previous context.""" with study_context("OUTER"): with study_context("INNER"): assert get_current_study() == "INNER" diff --git a/tests/unit/test_core_endpoint_operations.py b/tests/unit/test_core_endpoint_operations.py index 21bf25ea..7cdbcc26 100644 --- a/tests/unit/test_core_endpoint_operations.py +++ b/tests/unit/test_core_endpoint_operations.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for core endpoint operations.""" from unittest.mock import AsyncMock, MagicMock @@ -13,12 +13,12 @@ def dummy_parse_func(data): - """TODO: Add docstring.""" + """Helper function to dummy parse func.""" return data def test_path_get_operation_execute_sync(): - """TODO: Add docstring.""" + """Test that path get operation execute sync.""" client = MagicMock() response = MagicMock() response.json.return_value = {"id": 1, "name": "Test"} @@ -38,7 +38,7 @@ def test_path_get_operation_execute_sync(): def test_path_get_operation_execute_sync_not_found(): - """TODO: Add docstring.""" + """Test that path get operation execute sync not found.""" client = MagicMock() response = MagicMock() response.json.return_value = None @@ -59,7 +59,7 @@ def test_path_get_operation_execute_sync_not_found(): @pytest.mark.asyncio async def test_path_get_operation_execute_async(): - """TODO: Add docstring.""" + """Test that path get operation execute async asynchronously.""" client = AsyncMock() response = MagicMock() response.json.return_value = {"id": 1, "name": "Test"} @@ -80,7 +80,7 @@ async def test_path_get_operation_execute_async(): @pytest.mark.asyncio async def test_path_get_operation_execute_async_not_found(): - """TODO: Add docstring.""" + """Test that path get operation execute async not found asynchronously.""" client = AsyncMock() response = MagicMock() response.json.return_value = None @@ -100,7 +100,7 @@ async def test_path_get_operation_execute_async_not_found(): def test_list_operation_sync(): - """TODO: Add docstring.""" + """Test that list operation sync.""" client = MagicMock() paginator_cls = MagicMock() paginator_instance = [{"id": 1}, {"id": 2}] @@ -117,19 +117,19 @@ def test_list_operation_sync(): @pytest.mark.asyncio async def test_list_operation_async(): - """TODO: Add docstring.""" + """Test that list operation async asynchronously.""" client = AsyncMock() paginator_cls = MagicMock() class AsyncIteratorMock: - """TODO: Add docstring.""" + """Test suite for AsyncIteratorMock.""" def __init__(self, items): - """TODO: Add docstring.""" + """Initialize the test object.""" self.items = items async def __aiter__(self): - """TODO: Add docstring.""" + """Helper function to aiter .""" for item in self.items: yield item @@ -145,7 +145,7 @@ async def __aiter__(self): def test_filter_get_operation_sync(): - """TODO: Add docstring.""" + """Test that filter get operation sync.""" list_sync_func = MagicMock(return_value=[{"id": 1}]) validate_func = MagicMock(return_value={"id": 1}) client = MagicMock() @@ -167,7 +167,7 @@ def test_filter_get_operation_sync(): def test_filter_get_operation_sync_missing_list_func(): - """TODO: Add docstring.""" + """Test that filter get operation sync missing list func.""" client = MagicMock() paginator_cls = MagicMock() @@ -184,7 +184,7 @@ def test_filter_get_operation_sync_missing_list_func(): @pytest.mark.asyncio async def test_filter_get_operation_async(): - """TODO: Add docstring.""" + """Test that filter get operation async asynchronously.""" list_async_func = AsyncMock(return_value=[{"id": 1}]) validate_func = MagicMock(return_value={"id": 1}) client = AsyncMock() @@ -207,7 +207,7 @@ async def test_filter_get_operation_async(): @pytest.mark.asyncio async def test_filter_get_operation_async_missing_list_func(): - """TODO: Add docstring.""" + """Test that filter get operation async missing list func asynchronously.""" client = AsyncMock() paginator_cls = MagicMock() @@ -223,7 +223,7 @@ async def test_filter_get_operation_async_missing_list_func(): def test_record_create_operation_sync(): - """TODO: Add docstring.""" + """Test that record create operation sync.""" client = MagicMock() response = MagicMock() response.json.return_value = {"status": "created"} @@ -244,7 +244,7 @@ def test_record_create_operation_sync(): def test_record_create_operation_header_validation_failure(): - """TODO: Add docstring.""" + """Test that record create operation header validation failure.""" with pytest.raises(ClientError, match="Header value must not contain newlines"): RecordCreateOperation( path="/create", @@ -254,7 +254,7 @@ def test_record_create_operation_header_validation_failure(): def test_record_create_operation_schema_validation_failure(): - """TODO: Add docstring.""" + """Test that record create operation schema validation failure.""" schema_mock = MagicMock() with pytest.MonkeyPatch.context() as m: @@ -271,7 +271,7 @@ def test_record_create_operation_schema_validation_failure(): @pytest.mark.asyncio async def test_record_create_operation_async(): - """TODO: Add docstring.""" + """Test that record create operation async asynchronously.""" client = AsyncMock() response = MagicMock() response.json.return_value = {"status": "created"} diff --git a/tests/unit/test_core_exceptions.py b/tests/unit/test_core_exceptions.py index 90bd2db0..8839e5da 100644 --- a/tests/unit/test_core_exceptions.py +++ b/tests/unit/test_core_exceptions.py @@ -1,10 +1,10 @@ -"""TODO: Add docstring.""" +"""Unit tests for core exceptions.""" from imednet import errors def test_api_error_str_includes_details() -> None: - """TODO: Add docstring.""" + """Test that api error str includes details.""" err = errors.ApiError({"msg": "bad"}, status_code=400) text = str(err) assert "Status Code: 400" in text @@ -12,7 +12,7 @@ def test_api_error_str_includes_details() -> None: def test_exception_hierarchy() -> None: - """TODO: Add docstring.""" + """Test that exception hierarchy.""" assert issubclass(errors.AuthenticationError, errors.ApiError) assert issubclass(errors.AuthorizationError, errors.ApiError) assert issubclass(errors.NotFoundError, errors.ApiError) @@ -28,7 +28,7 @@ def test_exception_hierarchy() -> None: def test_filter_conflict_error_keeps_conflicting_filters() -> None: - """TODO: Add docstring.""" + """Test that filter conflict error keeps conflicting filters.""" whitelist = {"STUDY-A"} blacklist = {"STUDY-B"} diff --git a/tests/unit/test_core_paginator.py b/tests/unit/test_core_paginator.py index 8eba8195..616d4a66 100644 --- a/tests/unit/test_core_paginator.py +++ b/tests/unit/test_core_paginator.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for core paginator.""" from typing import Any, Dict, List @@ -13,37 +13,37 @@ class DummyClient: - """TODO: Add docstring.""" + """Test suite for DummyClient.""" def __init__(self, responses: List[Dict[str, Any]]): - """TODO: Add docstring.""" + """Initialize the test object.""" self.responses = responses self.calls: List[Dict[str, Any]] = [] def get(self, path: str, params: Dict[str, Any] | None = None): - """TODO: Add docstring.""" + """Helper function to get.""" self.calls.append({"path": path, "params": params}) data = self.responses.pop(0) return type("Resp", (), {"json": lambda self: data})() class AsyncDummyClient: - """TODO: Add docstring.""" + """Test suite for AsyncDummyClient.""" def __init__(self, responses: List[Dict[str, Any]]): - """TODO: Add docstring.""" + """Initialize the test object.""" self.responses = responses self.calls: List[Dict[str, Any]] = [] async def get(self, path: str, params: Dict[str, Any] | None = None): - """TODO: Add docstring.""" + """Helper function to get.""" self.calls.append({"path": path, "params": params}) data = self.responses.pop(0) return type("Resp", (), {"json": lambda self: data})() def test_single_page_iteration() -> None: - """TODO: Add docstring.""" + """Test that single page iteration.""" client = DummyClient([{"data": [1, 2]}]) paginator = Paginator(client, "/p") assert list(paginator) == [1, 2] @@ -51,7 +51,7 @@ def test_single_page_iteration() -> None: def test_multiple_page_iteration() -> None: - """TODO: Add docstring.""" + """Test that multiple page iteration.""" client = DummyClient( [ {"data": [1], "pagination": {"totalPages": 2}}, diff --git a/tests/unit/test_core_parsing.py b/tests/unit/test_core_parsing.py index a14d96a2..f6cc1440 100644 --- a/tests/unit/test_core_parsing.py +++ b/tests/unit/test_core_parsing.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for core parsing.""" from typing import Any @@ -8,26 +8,26 @@ class SimpleModel(BaseModel): - """TODO: Add docstring.""" + """Test suite for SimpleModel.""" id: int name: str class CustomParseModel(BaseModel): - """TODO: Add docstring.""" + """Test suite for CustomParseModel.""" id: int name: str @classmethod def from_json(cls, data: dict[str, Any]) -> "CustomParseModel": - """TODO: Add docstring.""" + """Helper function to from json.""" return cls(id=data["identifier"], name=data["full_name"]) def test_get_model_parser_uses_model_validate_by_default() -> None: - """TODO: Add docstring.""" + """Test that get model parser uses model validate by default.""" parser = get_model_parser(SimpleModel) assert parser == SimpleModel.model_validate @@ -39,7 +39,7 @@ def test_get_model_parser_uses_model_validate_by_default() -> None: def test_get_model_parser_uses_custom_from_json() -> None: - """TODO: Add docstring.""" + """Test that get model parser uses custom from json.""" parser = get_model_parser(CustomParseModel) assert parser == CustomParseModel.from_json @@ -51,7 +51,7 @@ def test_get_model_parser_uses_custom_from_json() -> None: def test_model_parser_class_parse() -> None: - """TODO: Add docstring.""" + """Test that model parser class parse.""" parser = ModelParser(SimpleModel) data = {"id": 3, "name": "Class Test"} @@ -62,7 +62,7 @@ def test_model_parser_class_parse() -> None: def test_model_parser_class_parse_many() -> None: - """TODO: Add docstring.""" + """Test that model parser class parse many.""" parser = ModelParser(CustomParseModel) data_list = [ {"identifier": 10, "full_name": "Alice"}, diff --git a/tests/unit/test_core_retry.py b/tests/unit/test_core_retry.py index 87c6e9d7..6d5b35c4 100644 --- a/tests/unit/test_core_retry.py +++ b/tests/unit/test_core_retry.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for core retry.""" import httpx import pytest @@ -7,7 +7,7 @@ def test_default_retry_policy_retries_on_network_errors(): - """TODO: Add docstring.""" + """Test that default retry policy retries on network errors.""" policy = DefaultRetryPolicy() # Simulate a network request error for an idempotent method (GET) @@ -19,7 +19,7 @@ def test_default_retry_policy_retries_on_network_errors(): def test_default_retry_policy_retries_on_rate_limits(): - """TODO: Add docstring.""" + """Test that default retry policy retries on rate limits.""" policy = DefaultRetryPolicy() # Simulate a 429 Too Many Requests response — retried regardless of method @@ -31,7 +31,7 @@ def test_default_retry_policy_retries_on_rate_limits(): def test_default_retry_policy_retries_on_server_errors(): - """TODO: Add docstring.""" + """Test that default retry policy retries on server errors.""" policy = DefaultRetryPolicy() # Simulate 500-599 Server Error responses for an idempotent method (GET) @@ -44,7 +44,7 @@ def test_default_retry_policy_retries_on_server_errors(): def test_default_retry_policy_does_not_retry_on_client_errors(): - """TODO: Add docstring.""" + """Test that default retry policy does not retry on client errors.""" policy = DefaultRetryPolicy() # Simulate 400-499 Client Error responses (excluding 429) @@ -57,7 +57,7 @@ def test_default_retry_policy_does_not_retry_on_client_errors(): def test_default_retry_policy_does_not_retry_on_success(): - """TODO: Add docstring.""" + """Test that default retry policy does not retry on success.""" policy = DefaultRetryPolicy() # Simulate 200-299 Success responses @@ -70,7 +70,7 @@ def test_default_retry_policy_does_not_retry_on_success(): def test_default_retry_policy_does_not_retry_on_unrelated_exceptions(): - """TODO: Add docstring.""" + """Test that default retry policy does not retry on unrelated exceptions.""" policy = DefaultRetryPolicy() # Simulate an exception that is not a RequestError @@ -81,7 +81,7 @@ def test_default_retry_policy_does_not_retry_on_unrelated_exceptions(): def test_default_retry_policy_with_no_result_or_exception(): - """TODO: Add docstring.""" + """Test that default retry policy with no result or exception.""" policy = DefaultRetryPolicy() # Simulate an empty state @@ -92,7 +92,7 @@ def test_default_retry_policy_with_no_result_or_exception(): @pytest.mark.parametrize("method", ["POST", "PATCH"]) def test_default_retry_policy_does_not_retry_non_idempotent_on_network_error(method: str): - """TODO: Add docstring.""" + """Test that default retry policy does not retry non idempotent on network error.""" policy = DefaultRetryPolicy() request = httpx.Request(method, "https://example.com") @@ -105,7 +105,7 @@ def test_default_retry_policy_does_not_retry_non_idempotent_on_network_error(met @pytest.mark.parametrize("method", ["POST", "PATCH"]) def test_default_retry_policy_does_not_retry_non_idempotent_on_server_error(method: str): - """TODO: Add docstring.""" + """Test that default retry policy does not retry non idempotent on server error.""" policy = DefaultRetryPolicy() request = httpx.Request(method, "https://example.com") @@ -117,7 +117,7 @@ def test_default_retry_policy_does_not_retry_non_idempotent_on_server_error(meth def test_default_retry_policy_retries_post_on_rate_limit(): - """TODO: Add docstring.""" + """Test that default retry policy retries post on rate limit.""" policy = DefaultRetryPolicy() # 429 means the server rejected the request before processing it, so @@ -130,7 +130,7 @@ def test_default_retry_policy_retries_post_on_rate_limit(): def test_default_retry_policy_does_not_retry_unknown_method_on_network_error(): - """TODO: Add docstring.""" + """Test that default retry policy does not retry unknown method on network error.""" policy = DefaultRetryPolicy() # Unknown / missing method → fail-safe: do not retry @@ -142,7 +142,7 @@ def test_default_retry_policy_does_not_retry_unknown_method_on_network_error(): def test_default_retry_policy_does_not_retry_unknown_method_on_server_error(): - """TODO: Add docstring.""" + """Test that default retry policy does not retry unknown method on server error.""" policy = DefaultRetryPolicy() # Unknown / missing method → fail-safe: do not retry diff --git a/tests/unit/test_credential_redaction.py b/tests/unit/test_credential_redaction.py index 04f7f45b..c7c76a35 100644 --- a/tests/unit/test_credential_redaction.py +++ b/tests/unit/test_credential_redaction.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for credential redaction.""" import logging from unittest.mock import MagicMock @@ -44,7 +44,7 @@ def invoke(self, app, args): def test_api_key_auth_repr_and_str_mask_secrets() -> None: - """TODO: Add docstring.""" + """Test that api key auth repr and str mask secrets.""" auth = ApiKeyAuth(api_key="plain-api-key", security_key="plain-security-key") assert "plain-api-key" not in repr(auth) @@ -56,7 +56,7 @@ def test_api_key_auth_repr_and_str_mask_secrets() -> None: @pytest.mark.parametrize("error_cls", [AuthenticationError, RateLimitError]) def test_api_errors_mask_sensitive_values(error_cls: type[ApiError]) -> None: - """TODO: Add docstring.""" + """Test that api errors mask sensitive values.""" secret_api_key = "very-secret-api-key" secret_token = "very-secret-token" secret_auth = "Bearer very-secret-authorization" @@ -82,7 +82,7 @@ def test_api_errors_mask_sensitive_values(error_cls: type[ApiError]) -> None: def test_http_client_never_logs_authorization_header( caplog: pytest.LogCaptureFixture, monkeypatch: pytest.MonkeyPatch ) -> None: - """TODO: Add docstring.""" + """Test that http client never logs authorization header.""" monkeypatch.setenv("IMEDNET_API_KEY", "api") monkeypatch.setenv("IMEDNET_SECURITY_KEY", "security") caplog.set_level("DEBUG") @@ -106,7 +106,7 @@ def test_http_client_never_logs_authorization_header( def test_cli_surfaces_redacted_authentication_errors(monkeypatch: pytest.MonkeyPatch) -> None: - """TODO: Add docstring.""" + """Test that cli surfaces redacted authentication errors.""" from importlib import import_module runner = CliRunner() diff --git a/tests/unit/test_data_dictionary.py b/tests/unit/test_data_dictionary.py index a65144a1..c86ce348 100644 --- a/tests/unit/test_data_dictionary.py +++ b/tests/unit/test_data_dictionary.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for data dictionary.""" from __future__ import annotations @@ -12,12 +12,12 @@ def _expected() -> DataDictionary: - """TODO: Add docstring.""" + """Helper function to expected.""" return DataDictionaryLoader.from_directory(FIXTURES) def test_from_directory() -> None: - """TODO: Add docstring.""" + """Test that from directory.""" dd = DataDictionaryLoader.from_directory(FIXTURES) assert isinstance(dd, DataDictionary) assert len(dd.forms) == 3 @@ -25,7 +25,7 @@ def test_from_directory() -> None: def test_from_zip() -> None: - """TODO: Add docstring.""" + """Test that from zip.""" buffer = io.BytesIO() with zipfile.ZipFile(buffer, "w") as zf: for name in DataDictionaryLoader.REQUIRED_FILES: diff --git a/tests/unit/test_discovery.py b/tests/unit/test_discovery.py index b76b466f..611b2636 100644 --- a/tests/unit/test_discovery.py +++ b/tests/unit/test_discovery.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for discovery.""" from unittest.mock import Mock @@ -26,28 +26,28 @@ def test_is_site_eligible_accepts_enrollment_open() -> None: - """TODO: Add docstring.""" + """Test that is site eligible accepts enrollment open.""" assert is_site_eligible("ENROLLMENT_OPEN") is True def test_is_site_eligible_accepts_active_case_insensitive() -> None: - """TODO: Add docstring.""" + """Test that is site eligible accepts active case insensitive.""" assert is_site_eligible("Active") is True assert is_site_eligible("ACTIVE") is True def test_is_site_eligible_rejects_read_only() -> None: - """TODO: Add docstring.""" + """Test that is site eligible rejects read only.""" assert is_site_eligible("READ_ONLY") is False def test_is_site_eligible_rejects_closed() -> None: - """TODO: Add docstring.""" + """Test that is site eligible rejects closed.""" assert is_site_eligible("Closed") is False def test_eligible_site_statuses_contains_expected_values() -> None: - """TODO: Add docstring.""" + """Test that eligible site statuses contains expected values.""" assert "enrollment_open" in ELIGIBLE_SITE_STATUSES assert "active" in ELIGIBLE_SITE_STATUSES @@ -58,33 +58,33 @@ def test_eligible_site_statuses_contains_expected_values() -> None: def test_is_subject_eligible_accepts_registered() -> None: - """TODO: Add docstring.""" + """Test that is subject eligible accepts registered.""" assert is_subject_eligible("Registered") is True def test_is_subject_eligible_accepts_baseline() -> None: - """TODO: Add docstring.""" + """Test that is subject eligible accepts baseline.""" assert is_subject_eligible("Baseline") is True def test_is_subject_eligible_accepts_enrolled() -> None: - """TODO: Add docstring.""" + """Test that is subject eligible accepts enrolled.""" assert is_subject_eligible("Enrolled") is True def test_is_subject_eligible_accepts_active_case_insensitive() -> None: - """TODO: Add docstring.""" + """Test that is subject eligible accepts active case insensitive.""" assert is_subject_eligible("Active") is True assert is_subject_eligible("ACTIVE") is True def test_is_subject_eligible_rejects_closed() -> None: - """TODO: Add docstring.""" + """Test that is subject eligible rejects closed.""" assert is_subject_eligible("Closed") is False def test_eligible_subject_statuses_contains_expected_values() -> None: - """TODO: Add docstring.""" + """Test that eligible subject statuses contains expected values.""" assert "registered" in ELIGIBLE_SUBJECT_STATUSES assert "baseline" in ELIGIBLE_SUBJECT_STATUSES assert "enrolled" in ELIGIBLE_SUBJECT_STATUSES @@ -97,7 +97,7 @@ def test_eligible_subject_statuses_contains_expected_values() -> None: def test_discover_form_key_chooses_subject_form() -> None: - """TODO: Add docstring.""" + """Test that discover form key chooses subject form.""" sdk = Mock() sdk.forms.list.return_value = [ Form(study_key="S", form_key="SS", subject_record_report=False), @@ -110,7 +110,7 @@ def test_discover_form_key_chooses_subject_form() -> None: def test_discover_form_key_raises_when_no_valid_forms() -> None: - """TODO: Add docstring.""" + """Test that discover form key raises when no valid forms.""" sdk = Mock() sdk.forms.list.return_value = [Form(study_key="S", form_key="SS", subject_record_report=False)] sdk.variables.list.return_value = [Mock()] @@ -125,7 +125,7 @@ def test_discover_form_key_raises_when_no_valid_forms() -> None: def test_discover_site_name_returns_active_site() -> None: - """TODO: Add docstring.""" + """Test that discover site name returns active site.""" sdk = Mock() sdk.sites.list.return_value = [ Site(study_key="S", site_name="Closed", site_enrollment_status="Closed"), @@ -148,7 +148,7 @@ def test_discover_site_name_returns_enrollment_open_site() -> None: def test_discover_site_name_raises_when_no_active() -> None: - """TODO: Add docstring.""" + """Test that discover site name raises when no active.""" sdk = Mock() sdk.sites.list.return_value = [ Site(study_key="S", site_name="X", site_enrollment_status="Closed") @@ -171,7 +171,7 @@ def test_discover_site_name_error_includes_encountered_statuses() -> None: def test_discover_site_name_raises_when_no_sites() -> None: - """TODO: Add docstring.""" + """Test that discover site name raises when no sites.""" sdk = Mock() sdk.sites.list.return_value = [] @@ -185,7 +185,7 @@ def test_discover_site_name_raises_when_no_sites() -> None: def test_discover_subject_key_returns_active_subject() -> None: - """TODO: Add docstring.""" + """Test that discover subject key returns active subject.""" sdk = Mock() sdk.subjects.list.return_value = [ Subject(study_key="S", subject_key="S1", subject_status="Closed"), @@ -227,7 +227,7 @@ def test_discover_subject_key_returns_enrolled_subject() -> None: def test_discover_subject_key_raises_when_no_active() -> None: - """TODO: Add docstring.""" + """Test that discover subject key raises when no active.""" sdk = Mock() sdk.subjects.list.return_value = [ Subject(study_key="S", subject_key="S1", subject_status="Closed") @@ -250,7 +250,7 @@ def test_discover_subject_key_error_includes_encountered_statuses() -> None: def test_discover_subject_key_raises_when_no_subjects() -> None: - """TODO: Add docstring.""" + """Test that discover subject key raises when no subjects.""" sdk = Mock() sdk.subjects.list.return_value = [] @@ -264,7 +264,7 @@ def test_discover_subject_key_raises_when_no_subjects() -> None: def test_discover_interval_name_returns_active_interval() -> None: - """TODO: Add docstring.""" + """Test that discover interval name returns active interval.""" sdk = Mock() sdk.intervals.list.return_value = [ Interval(study_key="S", interval_name="I1", disabled=True), @@ -276,7 +276,7 @@ def test_discover_interval_name_returns_active_interval() -> None: def test_discover_interval_name_raises_when_all_disabled() -> None: - """TODO: Add docstring.""" + """Test that discover interval name raises when all disabled.""" sdk = Mock() sdk.intervals.list.return_value = [Interval(study_key="S", interval_name="I1", disabled=True)] diff --git a/tests/unit/test_discovery_helpers.py b/tests/unit/test_discovery_helpers.py index 23193a5d..c0f9cbdc 100644 --- a/tests/unit/test_discovery_helpers.py +++ b/tests/unit/test_discovery_helpers.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for discovery helpers.""" from unittest.mock import MagicMock @@ -15,7 +15,7 @@ def test_discover_study_key_returns_first() -> None: - """TODO: Add docstring.""" + """Test that discover study key returns first.""" sdk = MagicMock() sdk.studies.list.return_value = [ MagicMock(study_key="S1"), @@ -27,7 +27,7 @@ def test_discover_study_key_returns_first() -> None: def test_discover_study_key_raises_when_empty() -> None: - """TODO: Add docstring.""" + """Test that discover study key raises when empty.""" sdk = MagicMock() sdk.studies.list.return_value = [] @@ -36,7 +36,7 @@ def test_discover_study_key_raises_when_empty() -> None: def test_discover_form_key_returns_first_matching() -> None: - """TODO: Add docstring.""" + """Test that discover form key returns first matching.""" sdk = MagicMock() sdk.forms.list.return_value = [ MagicMock(subject_record_report=False), @@ -50,7 +50,7 @@ def test_discover_form_key_returns_first_matching() -> None: def test_discover_form_key_raises_when_empty() -> None: - """TODO: Add docstring.""" + """Test that discover form key raises when empty.""" sdk = MagicMock() sdk.forms.list.return_value = [] sdk.variables.list.return_value = [MagicMock()] @@ -60,7 +60,7 @@ def test_discover_form_key_raises_when_empty() -> None: def test_discover_site_name_returns_first_active() -> None: - """TODO: Add docstring.""" + """Test that discover site name returns first active.""" sdk = MagicMock() sdk.sites.list.return_value = [ MagicMock(site_enrollment_status="Closed"), @@ -82,7 +82,7 @@ def test_discover_site_name_returns_enrollment_open() -> None: def test_discover_site_name_raises_when_empty() -> None: - """TODO: Add docstring.""" + """Test that discover site name raises when empty.""" sdk = MagicMock() sdk.sites.list.return_value = [] @@ -102,7 +102,7 @@ def test_discover_site_name_raises_with_read_only_sites() -> None: def test_discover_subject_key_returns_first_active() -> None: - """TODO: Add docstring.""" + """Test that discover subject key returns first active.""" sdk = MagicMock() sdk.subjects.list.return_value = [ MagicMock(subject_status="Closed"), @@ -144,7 +144,7 @@ def test_discover_subject_key_returns_enrolled() -> None: def test_discover_subject_key_raises_when_empty() -> None: - """TODO: Add docstring.""" + """Test that discover subject key raises when empty.""" sdk = MagicMock() sdk.subjects.list.return_value = [] @@ -165,7 +165,7 @@ def test_discover_subject_key_raises_with_encountered_statuses() -> None: def test_discover_interval_name_returns_first_enabled() -> None: - """TODO: Add docstring.""" + """Test that discover interval name returns first enabled.""" sdk = MagicMock() sdk.intervals.list.return_value = [ MagicMock(disabled=True), @@ -177,7 +177,7 @@ def test_discover_interval_name_returns_first_enabled() -> None: def test_discover_interval_name_raises_when_empty() -> None: - """TODO: Add docstring.""" + """Test that discover interval name raises when empty.""" sdk = MagicMock() sdk.intervals.list.return_value = [] diff --git a/tests/unit/test_duckdb_export.py b/tests/unit/test_duckdb_export.py index c75df7a3..81d20c30 100644 --- a/tests/unit/test_duckdb_export.py +++ b/tests/unit/test_duckdb_export.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for duckdb export.""" import sys from builtins import __import__ as builtin_import @@ -14,7 +14,7 @@ def test_export_to_duckdb_happy_path(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: - """TODO: Add docstring.""" + """Test that export to duckdb happy path.""" duckdb = pytest.importorskip("duckdb") sdk = MagicMock() @@ -36,7 +36,7 @@ def test_export_to_duckdb_happy_path(tmp_path: Path, monkeypatch: pytest.MonkeyP def test_export_to_duckdb_wide_dataframe(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: - """TODO: Add docstring.""" + """Test that export to duckdb wide dataframe.""" duckdb = pytest.importorskip("duckdb") sdk = MagicMock() @@ -61,7 +61,7 @@ def test_export_to_duckdb_wide_dataframe(tmp_path: Path, monkeypatch: pytest.Mon def test_export_to_duckdb_by_form_creates_per_form_tables( tmp_path: Path, monkeypatch: pytest.MonkeyPatch ) -> None: - """TODO: Add docstring.""" + """Test that export to duckdb by form creates per form tables.""" duckdb = pytest.importorskip("duckdb") sdk = MagicMock() @@ -96,7 +96,7 @@ def test_export_to_duckdb_by_form_creates_per_form_tables( def test_export_to_duckdb_import_error(monkeypatch: pytest.MonkeyPatch) -> None: - """TODO: Add docstring.""" + """Test that export to duckdb import error.""" def fake_import( name: str, @@ -105,7 +105,7 @@ def fake_import( fromlist: tuple[str, ...] = (), level: int = 0, ) -> Any: - """TODO: Add docstring.""" + """Helper function to fake import.""" if name == "duckdb": raise ImportError("No module named duckdb") return builtin_import(name, globals_arg, locals_arg, fromlist, level) @@ -121,7 +121,7 @@ def fake_import( def test_export_to_duckdb_type_handling(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: - """TODO: Add docstring.""" + """Test that export to duckdb type handling.""" duckdb = pytest.importorskip("duckdb") sdk = MagicMock() @@ -161,7 +161,7 @@ def test_export_to_duckdb_type_handling(tmp_path: Path, monkeypatch: pytest.Monk def test_export_to_duckdb_connection_closed_on_error( tmp_path: Path, monkeypatch: pytest.MonkeyPatch ) -> None: - """TODO: Add docstring.""" + """Test that export to duckdb connection closed on error.""" sdk = MagicMock() df = pd.DataFrame({"a": [1]}) monkeypatch.setattr(export_mod, "_prepare_export_df", MagicMock(return_value=df)) diff --git a/tests/unit/test_duckdb_ingestion_workflow.py b/tests/unit/test_duckdb_ingestion_workflow.py index 934242a6..8dd14851 100644 --- a/tests/unit/test_duckdb_ingestion_workflow.py +++ b/tests/unit/test_duckdb_ingestion_workflow.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for duckdb ingestion workflow.""" from __future__ import annotations @@ -16,7 +16,7 @@ def test_ingest_revisions_append_mode() -> None: - """TODO: Add docstring.""" + """Test that ingest revisions append mode.""" pytest.importorskip("duckdb") workflow = DuckDBIngestionWorkflow(MagicMock(), ":memory:") @@ -52,7 +52,7 @@ def test_ingest_revisions_append_mode() -> None: def test_ingest_revisions_replace_mode() -> None: - """TODO: Add docstring.""" + """Test that ingest revisions replace mode.""" pytest.importorskip("duckdb") workflow = DuckDBIngestionWorkflow(MagicMock(), ":memory:") @@ -94,7 +94,7 @@ def test_ingest_revisions_replace_mode() -> None: def test_build_silver_view_deduplication() -> None: - """TODO: Add docstring.""" + """Test that build silver view deduplication.""" pytest.importorskip("duckdb") workflow = DuckDBIngestionWorkflow(MagicMock(), ":memory:") @@ -131,7 +131,7 @@ def test_build_silver_view_deduplication() -> None: def test_ingest_revisions_returns_row_count() -> None: - """TODO: Add docstring.""" + """Test that ingest revisions returns row count.""" pytest.importorskip("duckdb") workflow = DuckDBIngestionWorkflow(MagicMock(), ":memory:") @@ -170,7 +170,7 @@ def test_ingest_revisions_returns_row_count() -> None: def test_duckdb_workflow_import_error(monkeypatch: pytest.MonkeyPatch) -> None: - """TODO: Add docstring.""" + """Test that duckdb workflow import error.""" def fake_import( name: str, @@ -179,7 +179,7 @@ def fake_import( fromlist: tuple[str, ...] = (), level: int = 0, ) -> Any: - """TODO: Add docstring.""" + """Helper function to fake import.""" if name == "duckdb": raise ImportError("No module named duckdb") return builtin_import(name, globals_arg, locals_arg, fromlist, level) diff --git a/tests/unit/test_export_sanitization.py b/tests/unit/test_export_sanitization.py index 2b700e5e..93e2d99f 100644 --- a/tests/unit/test_export_sanitization.py +++ b/tests/unit/test_export_sanitization.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for export sanitization.""" import warnings from unittest.mock import MagicMock @@ -15,7 +15,7 @@ def mock_record_mapper(monkeypatch): mapper_inst = MagicMock() def _setup(df: pd.DataFrame): - """TODO: Add docstring.""" + """Helper function to setup.""" mapper_inst.dataframe.return_value = df monkeypatch.setattr( export_mod, @@ -72,7 +72,7 @@ def test_export_to_excel_sanitization(tmp_path, mock_record_mapper, monkeypatch) captured_df = None def mock_to_excel(self, excel_writer, index=False, **kwargs): - """TODO: Add docstring.""" + """Helper function to mock to excel.""" nonlocal captured_df captured_df = self.copy() # Call original to generate file if needed, but we can skip file generation diff --git a/tests/unit/test_export_sink_base.py b/tests/unit/test_export_sink_base.py index 794f9748..425accb2 100644 --- a/tests/unit/test_export_sink_base.py +++ b/tests/unit/test_export_sink_base.py @@ -25,24 +25,24 @@ class TestRedactUri: - """TODO: Add docstring.""" + """Test suite for RedactUri.""" def test_redacts_user_and_password(self): - """TODO: Add docstring.""" + """Test that redacts user and password.""" userpass_uri = "mongodb://" + "user:pass" + "@localhost:27017/db" assert _redact_uri(userpass_uri) == "mongodb://***@localhost:27017/db" def test_redacts_user_only(self): - """TODO: Add docstring.""" + """Test that redacts user only.""" assert _redact_uri("bolt://neo4j@localhost:7687") == "bolt://***@localhost:7687" def test_leaves_uri_without_userinfo_unchanged(self): - """TODO: Add docstring.""" + """Test that leaves uri without userinfo unchanged.""" uri = "neo4j+s://bolt.example.com" assert _redact_uri(uri) == uri def test_handles_empty_string(self): - """TODO: Add docstring.""" + """Test that handles empty string.""" assert _redact_uri("") == "" @@ -52,18 +52,18 @@ def test_handles_empty_string(self): class TestRequireOptionalDep: - """TODO: Add docstring.""" + """Test suite for RequireOptionalDep.""" def test_returns_module_when_installed(self): - """TODO: Add docstring.""" + """Test that returns module when installed.""" mod = _require_optional_dep("sys", "dummy") assert mod is sys def test_raises_import_error_when_missing(self, monkeypatch): - """TODO: Add docstring.""" + """Test that raises import error when missing.""" def fake_import(name): - """TODO: Add docstring.""" + """Helper function to fake import.""" raise ModuleNotFoundError(name=name) monkeypatch.setattr(sink_base_mod, "import_module", fake_import) @@ -71,10 +71,10 @@ def fake_import(name): _require_optional_dep("mypkg", "mypkg") def test_reraises_unrelated_module_not_found_error(self, monkeypatch): - """TODO: Add docstring.""" + """Test that reraises unrelated module not found error.""" def fake_import(name): - """TODO: Add docstring.""" + """Helper function to fake import.""" raise ModuleNotFoundError(name="some_other_missing_lib") monkeypatch.setattr(sink_base_mod, "import_module", fake_import) @@ -88,10 +88,10 @@ def fake_import(name): class TestSinkConfig: - """TODO: Add docstring.""" + """Test suite for SinkConfig.""" def test_defaults(self): - """TODO: Add docstring.""" + """Test that defaults.""" cfg = SinkConfig() assert cfg.batch_size == 500 assert cfg.max_retries == 3 @@ -100,7 +100,7 @@ def test_defaults(self): assert cfg.extra == {} def test_custom_values(self): - """TODO: Add docstring.""" + """Test that custom values.""" cfg = SinkConfig(batch_size=100, max_retries=0, idempotent=False) assert cfg.batch_size == 100 assert cfg.max_retries == 0 @@ -108,15 +108,15 @@ def test_custom_values(self): class TestIterBatches: - """TODO: Add docstring.""" + """Test suite for IterBatches.""" def test_splits_sequence_by_batch_size(self): - """TODO: Add docstring.""" + """Test that splits sequence by batch size.""" batches = list(iter_batches([1, 2, 3, 4, 5], 2)) assert batches == [[1, 2], [3, 4], [5]] def test_rejects_non_positive_batch_size(self): - """TODO: Add docstring.""" + """Test that rejects non positive batch size.""" with pytest.raises(ValueError, match="batch_size"): list(iter_batches([1, 2], 0)) @@ -130,31 +130,31 @@ class _StubSink(ExportSink): """Minimal concrete sink for testing the base class.""" def __init__(self, config=None): - """TODO: Add docstring.""" + """Initialize the test object.""" super().__init__(config) self.batches: list[tuple[list, str]] = [] self.flushed = False self.closed = False def write_batch(self, records, *, batch_id: str) -> int: - """TODO: Add docstring.""" + """Helper function to write batch.""" self.batches.append((list(records), batch_id)) return len(records) def flush(self) -> None: - """TODO: Add docstring.""" + """Helper function to flush.""" self.flushed = True def close(self) -> None: - """TODO: Add docstring.""" + """Helper function to close.""" self.closed = True class TestExportSinkContextManager: - """TODO: Add docstring.""" + """Test suite for ExportSinkContextManager.""" def test_flush_and_close_called_on_clean_exit(self): - """TODO: Add docstring.""" + """Test that flush and close called on clean exit.""" sink = _StubSink() with sink as s: s.write_batch([1, 2, 3], batch_id="b1") @@ -162,7 +162,7 @@ def test_flush_and_close_called_on_clean_exit(self): assert sink.closed def test_close_called_on_exception(self): - """TODO: Add docstring.""" + """Test that close called on exception.""" sink = _StubSink() with pytest.raises(ValueError): with sink: @@ -172,7 +172,7 @@ def test_close_called_on_exception(self): assert sink.closed def test_write_batch_records_returned(self): - """TODO: Add docstring.""" + """Test that write batch records returned.""" sink = _StubSink() result = sink.write_batch([10, 20], batch_id="b2") assert result == 2 @@ -185,26 +185,26 @@ def test_write_batch_records_returned(self): class TestExportErrors: - """TODO: Add docstring.""" + """Test suite for ExportErrors.""" def test_export_error_is_imednet_error(self): - """TODO: Add docstring.""" + """Test that export error is imednet error.""" from imednet.errors import ImednetError assert issubclass(ExportError, ImednetError) def test_export_batch_error_carries_batch_id(self): - """TODO: Add docstring.""" + """Test that export batch error carries batch id.""" err = ExportBatchError("failed", batch_id="STUDY/FORM/0") assert err.batch_id == "STUDY/FORM/0" assert "failed" in str(err) def test_export_configuration_error_is_export_error(self): - """TODO: Add docstring.""" + """Test that export configuration error is export error.""" assert issubclass(ExportConfigurationError, ExportError) def test_export_batch_error_is_export_error(self): - """TODO: Add docstring.""" + """Test that export batch error is export error.""" assert issubclass(ExportBatchError, ExportError) @@ -214,7 +214,7 @@ def test_export_batch_error_is_export_error(self): def _fake_neo4j_module(fail_connect: bool = False) -> ModuleType: - """TODO: Add docstring.""" + """Helper function to fake neo4j module.""" neo4j = ModuleType("neo4j") driver = MagicMock() if fail_connect: diff --git a/tests/unit/test_form_designer_client.py b/tests/unit/test_form_designer_client.py index ffaadb43..e9d9bc73 100644 --- a/tests/unit/test_form_designer_client.py +++ b/tests/unit/test_form_designer_client.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for form designer client.""" import json @@ -12,13 +12,13 @@ @pytest.fixture def form_designer_client(): - """TODO: Add docstring.""" + """Helper function to form designer client.""" return FormDesignerClient(base_url="https://test.imednet.com", phpsessid="test_session") @pytest.fixture def empty_layout(): - """TODO: Add docstring.""" + """Helper function to empty layout.""" return Layout(pages=[]) diff --git a/tests/unit/test_hive_parquet_export.py b/tests/unit/test_hive_parquet_export.py index 82a43579..1efea771 100644 --- a/tests/unit/test_hive_parquet_export.py +++ b/tests/unit/test_hive_parquet_export.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for hive parquet export.""" from pathlib import Path from types import SimpleNamespace @@ -12,7 +12,7 @@ def _read_partition_dataframe(path: Path) -> pd.DataFrame: - """TODO: Add docstring.""" + """Helper function to read partition dataframe.""" parquet_files = sorted(path.glob("**/*.parquet")) assert parquet_files return pd.read_parquet(parquet_files[0], engine="pyarrow") @@ -21,7 +21,7 @@ def _read_partition_dataframe(path: Path) -> pd.DataFrame: def test_export_to_hive_parquet_directory_structure( tmp_path: Path, monkeypatch: pytest.MonkeyPatch ) -> None: - """TODO: Add docstring.""" + """Test that export to hive parquet directory structure.""" pytest.importorskip("pyarrow") sdk = MagicMock() @@ -29,20 +29,20 @@ def test_export_to_hive_parquet_directory_structure( sdk.variables.list.return_value = [SimpleNamespace(form_id=1, variable_name="age", label="Age")] class FakeMapper: - """TODO: Add docstring.""" + """Test suite for FakeMapper.""" def __init__(self, sdk: MagicMock) -> None: - """TODO: Add docstring.""" + """Initialize the test object.""" self._sdk = sdk def _build_record_model( self, variable_keys: list[str], label_map: dict[str, str] ) -> tuple[list[str], dict[str, str]]: - """TODO: Add docstring.""" + """Helper function to build record model.""" return (variable_keys, label_map) def _fetch_records(self, _study_key: str, extra_filters: dict[str, Any]) -> list[int]: - """TODO: Add docstring.""" + """Helper function to fetch records.""" return [extra_filters["formId"]] def _parse_records( @@ -50,7 +50,7 @@ def _parse_records( records: list[int], _record_model: tuple[list[str], dict[str, str]], ) -> tuple[list[int], int]: - """TODO: Add docstring.""" + """Helper function to parse records.""" return records, len(records) def _build_dataframe( @@ -60,7 +60,7 @@ def _build_dataframe( _label_map: dict[str, str], _use_labels_as_columns: bool, ) -> pd.DataFrame: - """TODO: Add docstring.""" + """Helper function to build dataframe.""" return pd.DataFrame([{"age": rows[0]}]) monkeypatch.setattr(parquet_mod, "_record_mapper", lambda: FakeMapper) @@ -73,7 +73,7 @@ def _build_dataframe( def test_export_to_hive_parquet_concurrent_studies_no_conflict( tmp_path: Path, monkeypatch: pytest.MonkeyPatch ) -> None: - """TODO: Add docstring.""" + """Test that export to hive parquet concurrent studies no conflict.""" pytest.importorskip("pyarrow") sdk = MagicMock() @@ -83,22 +83,22 @@ def test_export_to_hive_parquet_concurrent_studies_no_conflict( ] class FakeMapper: - """TODO: Add docstring.""" + """Test suite for FakeMapper.""" def __init__(self, sdk: MagicMock) -> None: - """TODO: Add docstring.""" + """Initialize the test object.""" self._sdk = sdk def _build_record_model( self, variable_keys: list[str], label_map: dict[str, str] ) -> tuple[list[str], dict[str, str]]: - """TODO: Add docstring.""" + """Helper function to build record model.""" return (variable_keys, label_map) def _fetch_records( self, study_key: str, extra_filters: dict[str, Any] | None = None ) -> list[str]: - """TODO: Add docstring.""" + """Helper function to fetch records.""" assert extra_filters is not None assert "formId" in extra_filters return [study_key] @@ -108,7 +108,7 @@ def _parse_records( records: list[str], _record_model: tuple[list[str], dict[str, str]], ) -> tuple[list[str], int]: - """TODO: Add docstring.""" + """Helper function to parse records.""" return records, len(records) def _build_dataframe( @@ -118,7 +118,7 @@ def _build_dataframe( _label_map: dict[str, str], _use_labels_as_columns: bool, ) -> pd.DataFrame: - """TODO: Add docstring.""" + """Helper function to build dataframe.""" return pd.DataFrame([{"study": rows[0]}]) monkeypatch.setattr(parquet_mod, "_record_mapper", lambda: FakeMapper) @@ -134,7 +134,7 @@ def _build_dataframe( def test_hive_parquet_query_returns_correct_string() -> None: - """TODO: Add docstring.""" + """Test that hive parquet query returns correct string.""" assert ( parquet_mod.hive_parquet_query("/tmp/lake") == "SELECT * FROM read_parquet('/tmp/lake/**/*.parquet', " @@ -143,10 +143,10 @@ def test_hive_parquet_query_returns_correct_string() -> None: def test_export_to_hive_parquet_import_error(monkeypatch: pytest.MonkeyPatch) -> None: - """TODO: Add docstring.""" + """Test that export to hive parquet import error.""" def _raise_import_error(module_name: str): - """TODO: Add docstring.""" + """Helper function to raise import error.""" if module_name == "pyarrow": raise ImportError("missing pyarrow") return __import__(module_name) diff --git a/tests/unit/test_integrations_export.py b/tests/unit/test_integrations_export.py index 3977cd05..01d72ddd 100644 --- a/tests/unit/test_integrations_export.py +++ b/tests/unit/test_integrations_export.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for integrations export.""" import sys from builtins import __import__ as builtin_import @@ -13,7 +13,7 @@ def _setup_mapper(monkeypatch): - """TODO: Add docstring.""" + """Helper function to setup mapper.""" df = MagicMock() mapper_inst = MagicMock() mapper_inst.dataframe.return_value = df @@ -23,7 +23,7 @@ def _setup_mapper(monkeypatch): def _setup_real_mapper(monkeypatch): - """TODO: Add docstring.""" + """Helper function to setup real mapper.""" df = pd.DataFrame({"A": [1]}) mapper_inst = MagicMock() mapper_inst.dataframe.return_value = df @@ -33,7 +33,7 @@ def _setup_real_mapper(monkeypatch): def test_export_to_csv(monkeypatch): - """TODO: Add docstring.""" + """Test that export to csv.""" df, mapper_cls, mapper_inst = _setup_mapper(monkeypatch) sdk = MagicMock() @@ -50,7 +50,7 @@ def test_export_to_csv(monkeypatch): def test_export_to_excel(monkeypatch): - """TODO: Add docstring.""" + """Test that export to excel.""" df, mapper_cls, mapper_inst = _setup_mapper(monkeypatch) sdk = MagicMock() @@ -67,7 +67,7 @@ def test_export_to_excel(monkeypatch): def test_export_to_json(monkeypatch): - """TODO: Add docstring.""" + """Test that export to json.""" df, mapper_cls, mapper_inst = _setup_mapper(monkeypatch) df.where.return_value.to_dict.return_value = [{"A": 1}] sdk = MagicMock() @@ -84,7 +84,7 @@ def test_export_to_json(monkeypatch): def test_export_to_parquet(monkeypatch): - """TODO: Add docstring.""" + """Test that export to parquet.""" df, mapper_cls, mapper_inst = _setup_mapper(monkeypatch) sdk = MagicMock() @@ -101,7 +101,7 @@ def test_export_to_parquet(monkeypatch): def test_export_to_sql(monkeypatch): - """TODO: Add docstring.""" + """Test that export to sql.""" df, mapper_cls, mapper_inst = _setup_mapper(monkeypatch) sdk = MagicMock() @@ -126,7 +126,7 @@ def test_export_to_sql(monkeypatch): def test_export_to_duckdb(monkeypatch): - """TODO: Add docstring.""" + """Test that export to duckdb.""" sdk = MagicMock() df = pd.DataFrame({"A": [1]}) monkeypatch.setattr(export_mod, "_prepare_export_df", MagicMock(return_value=df)) @@ -146,7 +146,7 @@ def test_export_to_duckdb(monkeypatch): def test_export_to_duckdb_handles_wide_dataframe(monkeypatch): - """TODO: Add docstring.""" + """Test that export to duckdb handles wide dataframe.""" sdk = MagicMock() wide_df = pd.DataFrame([range(export_mod.MAX_SQLITE_COLUMNS + 50)]) monkeypatch.setattr(export_mod, "_prepare_export_df", MagicMock(return_value=wide_df)) @@ -165,10 +165,10 @@ def test_export_to_duckdb_handles_wide_dataframe(monkeypatch): def test_export_to_duckdb_import_error(monkeypatch): - """TODO: Add docstring.""" + """Test that export to duckdb import error.""" def fake_import(name, globals=None, locals=None, fromlist=(), level=0): - """TODO: Add docstring.""" + """Helper function to fake import.""" if name == "duckdb": raise ImportError("No module named duckdb") return builtin_import(name, globals, locals, fromlist, level) @@ -187,7 +187,7 @@ def fake_import(name, globals=None, locals=None, fromlist=(), level=0): def test_export_functions_handle_duplicate_columns(tmp_path, monkeypatch): - """TODO: Add docstring.""" + """Test that export functions handle duplicate columns.""" df = pd.DataFrame([[1, 2]], columns=["A", "A"]) monkeypatch.setattr( pd.DataFrame, @@ -212,7 +212,7 @@ def test_export_functions_handle_duplicate_columns(tmp_path, monkeypatch): def test_export_functions_handle_case_insensitive_duplicates(tmp_path, monkeypatch): - """TODO: Add docstring.""" + """Test that export functions handle case insensitive duplicates.""" df = pd.DataFrame([[1, 2]], columns=["A", "a"]) monkeypatch.setattr( pd.DataFrame, @@ -237,7 +237,7 @@ def test_export_functions_handle_case_insensitive_duplicates(tmp_path, monkeypat def test_export_sql_too_many_columns(monkeypatch): - """TODO: Add docstring.""" + """Test that export sql too many columns.""" columns = [f"c{i}" for i in range(export_mod.MAX_SQLITE_COLUMNS + 1)] df = pd.DataFrame( [range(export_mod.MAX_SQLITE_COLUMNS + 1)], @@ -262,7 +262,7 @@ def test_export_sql_too_many_columns(monkeypatch): def test_export_to_sql_by_form(monkeypatch): - """TODO: Add docstring.""" + """Test that export to sql by form.""" sdk = MagicMock() form1 = MagicMock(form_id=1, form_key="F1") form2 = MagicMock(form_id=2, form_key="F2") @@ -298,7 +298,7 @@ def test_export_to_sql_by_form(monkeypatch): def test_export_to_duckdb_by_form(monkeypatch): - """TODO: Add docstring.""" + """Test that export to duckdb by form.""" sdk = MagicMock() form1 = MagicMock(form_id=1, form_key="F1") form2 = MagicMock(form_id=2, form_key="F2") @@ -348,10 +348,10 @@ def test_export_to_duckdb_by_form(monkeypatch): def test_export_to_duckdb_by_form_import_error(monkeypatch): - """TODO: Add docstring.""" + """Test that export to duckdb by form import error.""" def fake_import(name, globals=None, locals=None, fromlist=(), level=0): - """TODO: Add docstring.""" + """Helper function to fake import.""" if name == "duckdb": raise ImportError("No module named duckdb") return builtin_import(name, globals, locals, fromlist, level) @@ -370,7 +370,7 @@ def fake_import(name, globals=None, locals=None, fromlist=(), level=0): def test_export_to_long_sql(monkeypatch): - """TODO: Add docstring.""" + """Test that export to long sql.""" sdk = MagicMock() dt1 = datetime(2023, 1, 1) dt2 = datetime(2023, 1, 2) @@ -392,7 +392,7 @@ def test_export_to_long_sql(monkeypatch): captured = [] def fake_to_sql(self, table, engine_arg, if_exists, index=False): - """TODO: Add docstring.""" + """Helper function to fake to sql.""" captured.append((self.copy(), if_exists)) monkeypatch.setattr(pd.DataFrame, "to_sql", fake_to_sql) @@ -413,7 +413,7 @@ def fake_to_sql(self, table, engine_arg, if_exists, index=False): def test_records_df_missing_pandas(monkeypatch): - """TODO: Add docstring.""" + """Test that records df missing pandas.""" monkeypatch.setattr(export_mod, "pd", None) with pytest.raises( ImportError, @@ -423,7 +423,7 @@ def test_records_df_missing_pandas(monkeypatch): def test_export_to_long_sql_missing_pandas(monkeypatch): - """TODO: Add docstring.""" + """Test that export to long sql missing pandas.""" monkeypatch.setattr(export_mod, "pd", None) with pytest.raises( ImportError, diff --git a/tests/unit/test_integrations_parquet.py b/tests/unit/test_integrations_parquet.py index 366df923..3a742b8d 100644 --- a/tests/unit/test_integrations_parquet.py +++ b/tests/unit/test_integrations_parquet.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for integrations parquet.""" from pathlib import Path from types import SimpleNamespace @@ -12,14 +12,14 @@ def _read_partition_dataframe(path: Path) -> pd.DataFrame: - """TODO: Add docstring.""" + """Helper function to read partition dataframe.""" parquet_files = sorted(path.glob("**/*.parquet")) assert parquet_files return pd.read_parquet(parquet_files[0], engine="pyarrow") def test_export_creates_hive_layout_and_contents(tmp_path, monkeypatch) -> None: - """TODO: Add docstring.""" + """Test that export creates hive layout and contents.""" pytest.importorskip("pyarrow") sdk = MagicMock() @@ -33,26 +33,26 @@ def test_export_creates_hive_layout_and_contents(tmp_path, monkeypatch) -> None: ] class FakeMapper: - """TODO: Add docstring.""" + """Test suite for FakeMapper.""" def __init__(self, _sdk) -> None: - """TODO: Add docstring.""" + """Initialize the test object.""" self._sdk = _sdk def _build_record_model(self, variable_keys, label_map): - """TODO: Add docstring.""" + """Helper function to build record model.""" return (variable_keys, label_map) def _fetch_records(self, _study_key, extra_filters): - """TODO: Add docstring.""" + """Helper function to fetch records.""" return [extra_filters["formId"]] def _parse_records(self, records, _record_model): - """TODO: Add docstring.""" + """Helper function to parse records.""" return records, len(records) def _build_dataframe(self, rows, _variable_keys, _label_map, _use_labels_as_columns): - """TODO: Add docstring.""" + """Helper function to build dataframe.""" form_id = rows[0] if form_id == 1: return pd.DataFrame([{"age": 42}]) @@ -74,7 +74,7 @@ def _build_dataframe(self, rows, _variable_keys, _label_map, _use_labels_as_colu def test_export_isolates_studies(tmp_path, monkeypatch) -> None: - """TODO: Add docstring.""" + """Test that export isolates studies.""" pytest.importorskip("pyarrow") sdk = MagicMock() @@ -82,26 +82,26 @@ def test_export_isolates_studies(tmp_path, monkeypatch) -> None: sdk.variables.list.return_value = [SimpleNamespace(form_id=1, variable_name="age", label="Age")] class FakeMapper: - """TODO: Add docstring.""" + """Test suite for FakeMapper.""" def __init__(self, _sdk) -> None: - """TODO: Add docstring.""" + """Initialize the test object.""" self._sdk = _sdk def _build_record_model(self, variable_keys, label_map): - """TODO: Add docstring.""" + """Helper function to build record model.""" return (variable_keys, label_map) def _fetch_records(self, study_key, extra_filters): - """TODO: Add docstring.""" + """Helper function to fetch records.""" return [(study_key, extra_filters["formId"])] def _parse_records(self, records, _record_model): - """TODO: Add docstring.""" + """Helper function to parse records.""" return records, len(records) def _build_dataframe(self, rows, _variable_keys, _label_map, _use_labels_as_columns): - """TODO: Add docstring.""" + """Helper function to build dataframe.""" study_key, _form_id = rows[0] return pd.DataFrame([{"study": study_key}]) @@ -120,7 +120,7 @@ def _build_dataframe(self, rows, _variable_keys, _label_map, _use_labels_as_colu def test_hive_parquet_query() -> None: - """TODO: Add docstring.""" + """Test that hive parquet query.""" assert ( parquet_mod.hive_parquet_query("/tmp/lake") == "SELECT * FROM read_parquet('/tmp/lake/**/*.parquet', " @@ -129,10 +129,10 @@ def test_hive_parquet_query() -> None: def test_export_to_hive_parquet_missing_pyarrow(monkeypatch) -> None: - """TODO: Add docstring.""" + """Test that export to hive parquet missing pyarrow.""" def _raise_import_error(module_name: str): - """TODO: Add docstring.""" + """Helper function to raise import error.""" if module_name == "pyarrow": raise ImportError("missing pyarrow") return __import__(module_name) @@ -144,7 +144,7 @@ def _raise_import_error(module_name: str): def test_export_to_hive_parquet_rejects_malicious_study_key(monkeypatch) -> None: - """TODO: Add docstring.""" + """Test that export to hive parquet rejects malicious study key.""" monkeypatch.setattr(parquet_mod, "_ensure_pyarrow", lambda: None) sdk = MagicMock() @@ -156,7 +156,7 @@ def test_export_to_hive_parquet_rejects_malicious_study_key(monkeypatch) -> None def test_export_to_hive_parquet_rejects_malicious_form_key(monkeypatch) -> None: - """TODO: Add docstring.""" + """Test that export to hive parquet rejects malicious form key.""" monkeypatch.setattr(parquet_mod, "_ensure_pyarrow", lambda: None) sdk = MagicMock() @@ -173,44 +173,44 @@ def test_export_to_hive_parquet_rejects_malicious_form_key(monkeypatch) -> None: def test_export_to_hive_parquet_flushes_form_batches(monkeypatch, tmp_path) -> None: - """TODO: Add docstring.""" + """Test that export to hive parquet flushes form batches.""" sdk = MagicMock() sdk.forms.list.return_value = [SimpleNamespace(form_id=1, form_key="DEMOGRAPHICS")] sdk.variables.list.return_value = [SimpleNamespace(form_id=1, variable_name="age", label="Age")] class FakeMapper: - """TODO: Add docstring.""" + """Test suite for FakeMapper.""" def __init__(self, _sdk) -> None: - """TODO: Add docstring.""" + """Initialize the test object.""" self._sdk = _sdk def _build_record_model(self, variable_keys, label_map): - """TODO: Add docstring.""" + """Helper function to build record model.""" return (variable_keys, label_map) def _iter_records(self, _study_key, extra_filters): - """TODO: Add docstring.""" + """Helper function to iter records.""" assert extra_filters == {"formIds": [1]} return iter([1, 2, 3]) def _iter_parsed_rows(self, records, _record_model): - """TODO: Add docstring.""" + """Helper function to iter parsed rows.""" values = list(records) yield values[:2], 0 yield values[2:], 0 def _build_dataframe(self, rows, _variable_keys, _label_map, _use_labels_as_columns): - """TODO: Add docstring.""" + """Helper function to build dataframe.""" return pd.DataFrame([{"age": value} for value in rows]) writes: list[list[dict[str, int]]] = [] class FakeEngine: - """TODO: Add docstring.""" + """Test suite for FakeEngine.""" def write_form_table(self, table, **kwargs) -> None: - """TODO: Add docstring.""" + """Helper function to write form table.""" assert kwargs == { "base_dir": str(tmp_path), "study_key": "STUDY_A", @@ -219,11 +219,11 @@ def write_form_table(self, table, **kwargs) -> None: writes.append(table.to_dict("records")) class _FakeTable: - """TODO: Add docstring.""" + """Test suite for FakeTable.""" @staticmethod def from_pandas(df: pd.DataFrame, preserve_index: bool = False) -> pd.DataFrame: - """TODO: Add docstring.""" + """Helper function to from pandas.""" assert preserve_index is False return df diff --git a/tests/unit/test_json_list_paginator_robustness.py b/tests/unit/test_json_list_paginator_robustness.py index c09252d9..5688ea44 100644 --- a/tests/unit/test_json_list_paginator_robustness.py +++ b/tests/unit/test_json_list_paginator_robustness.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for json list paginator robustness.""" from unittest.mock import Mock @@ -8,28 +8,28 @@ class MockClient: - """TODO: Add docstring.""" + """Test suite for MockClient.""" def __init__(self, response_data): - """TODO: Add docstring.""" + """Initialize the test object.""" self.response_data = response_data def get(self, path, params=None): - """TODO: Add docstring.""" + """Helper function to get.""" response = Mock() response.json.return_value = self.response_data return response class MockAsyncClient: - """TODO: Add docstring.""" + """Test suite for MockAsyncClient.""" def __init__(self, response_data): - """TODO: Add docstring.""" + """Initialize the test object.""" self.response_data = response_data async def get(self, path, params=None): - """TODO: Add docstring.""" + """Helper function to get.""" response = Mock() response.json.return_value = self.response_data return response diff --git a/tests/unit/test_json_model_normalization.py b/tests/unit/test_json_model_normalization.py index 9dbd5672..f01726b3 100644 --- a/tests/unit/test_json_model_normalization.py +++ b/tests/unit/test_json_model_normalization.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for json model normalization.""" from datetime import datetime, timezone from typing import Any, Optional, Union @@ -7,7 +7,7 @@ class SampleModel(JsonModel): - """TODO: Add docstring.""" + """Test suite for SampleModel.""" flag: bool count: int @@ -17,7 +17,7 @@ class SampleModel(JsonModel): def test_json_model_normalization() -> None: - """TODO: Add docstring.""" + """Test that json model normalization.""" model = SampleModel( flag="true", count="5", @@ -34,7 +34,7 @@ def test_json_model_normalization() -> None: class SampleOptionalModel(JsonModel): - """TODO: Add docstring.""" + """Test suite for SampleOptionalModel.""" opt_str: Optional[str] = None opt_int: Optional[int] = None @@ -43,7 +43,7 @@ class SampleOptionalModel(JsonModel): def test_json_model_normalization_optional_fields() -> None: - """TODO: Add docstring.""" + """Test that json model normalization optional fields.""" # Test with None values model_none = SampleOptionalModel(opt_str=None, opt_int=None, opt_bool=None, opt_datetime=None) assert model_none.opt_str is None @@ -62,10 +62,10 @@ def test_json_model_normalization_optional_fields() -> None: def test_json_model_normalization_union_field() -> None: - """TODO: Add docstring.""" + """Test that json model normalization union field.""" class SampleUnionModel(JsonModel): - """TODO: Add docstring.""" + """Test suite for SampleUnionModel.""" union_field: Union[int, str] @@ -74,10 +74,10 @@ class SampleUnionModel(JsonModel): def test_json_model_identity_normalizer() -> None: - """TODO: Add docstring.""" + """Test that json model identity normalizer.""" class SampleIdentityModel(JsonModel): - """TODO: Add docstring.""" + """Test suite for SampleIdentityModel.""" identity_field: Any @@ -86,10 +86,10 @@ class SampleIdentityModel(JsonModel): def test_json_model_normalization_missing_field() -> None: - """TODO: Add docstring.""" + """Test that json model normalization missing field.""" class SampleModelMissing(JsonModel): - """TODO: Add docstring.""" + """Test suite for SampleModelMissing.""" opt_str: Optional[str] = None @@ -98,7 +98,7 @@ class SampleModelMissing(JsonModel): def test_json_model_from_json_method() -> None: - """TODO: Add docstring.""" + """Test that json model from json method.""" data = { "flag": "true", "count": "5", @@ -112,16 +112,16 @@ def test_json_model_from_json_method() -> None: def test_json_model_structural_shift(caplog): - """TODO: Add docstring.""" + """Test that json model structural shift.""" import logging class NestedModel(JsonModel): - """TODO: Add docstring.""" + """Test suite for NestedModel.""" id: int class TestModel(JsonModel): - """TODO: Add docstring.""" + """Test suite for Model.""" nested: NestedModel items: list[NestedModel] diff --git a/tests/unit/test_json_roundtrip.py b/tests/unit/test_json_roundtrip.py index 461c58b1..6f866085 100644 --- a/tests/unit/test_json_roundtrip.py +++ b/tests/unit/test_json_roundtrip.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for json roundtrip.""" import pytest @@ -39,7 +39,7 @@ ], ) def test_json_roundtrip(cls, payload_func): - """TODO: Add docstring.""" + """Test that json roundtrip.""" payload = payload_func() model = cls.from_json(payload) dumped = model.model_dump(by_alias=True) @@ -47,7 +47,7 @@ def test_json_roundtrip(cls, payload_func): def test_fake_forms_for_cache(): - """TODO: Add docstring.""" + """Test that fake forms for cache.""" forms = fake_data.fake_forms_for_cache(num_forms=2, study_key="TEST-1") assert len(forms) == 2 for form in forms: @@ -56,7 +56,7 @@ def test_fake_forms_for_cache(): def test_fake_variables_for_cache(): - """TODO: Add docstring.""" + """Test that fake variables for cache.""" forms = fake_data.fake_forms_for_cache(num_forms=1) variables = fake_data.fake_variables_for_cache(forms, vars_per_form=2, study_key="TEST-1") assert len(variables) == 2 diff --git a/tests/unit/test_live_network_guard.py b/tests/unit/test_live_network_guard.py index 10957721..869b46c9 100644 --- a/tests/unit/test_live_network_guard.py +++ b/tests/unit/test_live_network_guard.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for live network guard.""" import importlib from pathlib import Path @@ -9,30 +9,30 @@ class _DummyNode: - """TODO: Add docstring.""" + """Test suite for DummyNode.""" def __init__(self, *, path: Path, has_live_marker: bool = False): - """TODO: Add docstring.""" + """Initialize the test object.""" self.path = path self._has_live_marker = has_live_marker def get_closest_marker(self, name: str) -> object | None: - """TODO: Add docstring.""" + """Helper function to get closest marker.""" if name == "live" and self._has_live_marker: return object() return None class _DummyRequest: - """TODO: Add docstring.""" + """Test suite for DummyRequest.""" def __init__(self, node: _DummyNode): - """TODO: Add docstring.""" + """Initialize the test object.""" self.node = node self.fixture_calls: list[str] = [] def getfixturevalue(self, fixture_name: str) -> None: - """TODO: Add docstring.""" + """Helper function to getfixturevalue.""" self.fixture_calls.append(fixture_name) @@ -46,7 +46,7 @@ def _run_guard(request: _DummyRequest) -> None: def test_live_path_bypasses_respx_guard() -> None: - """TODO: Add docstring.""" + """Test that live path bypasses respx guard.""" request = _DummyRequest( node=_DummyNode(path=test_conftest.ROOT / "tests" / "live" / "test_a.py") ) @@ -57,7 +57,7 @@ def test_live_path_bypasses_respx_guard() -> None: def test_non_live_path_activates_respx_guard() -> None: - """TODO: Add docstring.""" + """Test that non live path activates respx guard.""" request = _DummyRequest( node=_DummyNode(path=test_conftest.ROOT / "tests" / "unit" / "test_a.py") ) @@ -68,7 +68,7 @@ def test_non_live_path_activates_respx_guard() -> None: def test_live_marker_bypasses_guard_outside_live_directory() -> None: - """TODO: Add docstring.""" + """Test that live marker bypasses guard outside live directory.""" request = _DummyRequest( node=_DummyNode( path=test_conftest.ROOT / "tests" / "unit" / "test_a.py", diff --git a/tests/unit/test_models.py b/tests/unit/test_models.py index c7d9f119..4c7f171f 100644 --- a/tests/unit/test_models.py +++ b/tests/unit/test_models.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for models.""" from datetime import datetime from enum import Enum @@ -11,7 +11,7 @@ def _build_value(annotation: Any) -> Any: - """TODO: Add docstring.""" + """Helper function to build value.""" origin = get_origin(annotation) if origin is list: sub = get_args(annotation)[0] @@ -45,7 +45,7 @@ def _build_value(annotation: Any) -> Any: def _build_sample_data(cls: type[BaseModel]) -> Any: - """TODO: Add docstring.""" + """Helper function to build sample data.""" if getattr(cls, "__pydantic_root_model__", False): return {"foo": "bar"} data = {} @@ -65,7 +65,7 @@ def _build_sample_data(cls: type[BaseModel]) -> Any: @pytest.mark.parametrize("model_cls", MODEL_CLASSES) def test_model_instantiation_and_dump(model_cls: type[BaseModel]) -> None: - """TODO: Add docstring.""" + """Test that model instantiation and dump.""" sample = _build_sample_data(model_cls) model = model_cls.model_validate(sample) dumped = model.model_dump(by_alias=True) @@ -79,7 +79,7 @@ def test_model_instantiation_and_dump(model_cls: type[BaseModel]) -> None: @pytest.mark.parametrize("model_cls", MODEL_CLASSES) def test_missing_required_fields(model_cls: type[BaseModel]) -> None: - """TODO: Add docstring.""" + """Test that missing required fields.""" if getattr(model_cls, "__pydantic_root_model__", False): model_cls.model_validate({}) return @@ -94,7 +94,7 @@ def test_missing_required_fields(model_cls: type[BaseModel]) -> None: @pytest.mark.parametrize("model_cls", MODEL_CLASSES) def test_invalid_int_defaults(model_cls: type[BaseModel]) -> None: - """TODO: Add docstring.""" + """Test that invalid int defaults.""" if getattr(model_cls, "__pydantic_root_model__", False): pytest.skip("root model") int_field_item = next( @@ -115,7 +115,7 @@ def test_invalid_int_defaults(model_cls: type[BaseModel]) -> None: def test_job_properties() -> None: - """TODO: Add docstring.""" + """Test that job properties.""" from imednet.models.jobs import Job job_completed = Job(batchId="1", state="COMPLETED") @@ -145,7 +145,7 @@ def test_job_properties() -> None: def test_job_status_progress_parsing() -> None: - """TODO: Add docstring.""" + """Test that job status progress parsing.""" from imednet.models.jobs import JobStatus js_valid = JobStatus(batchId="1", state="PROCESSING", progress="50") @@ -159,7 +159,7 @@ def test_job_status_progress_parsing() -> None: def test_study_structure_methods() -> None: - """TODO: Add docstring.""" + """Test that study structure methods.""" from datetime import datetime from imednet.models.forms import Form @@ -204,7 +204,7 @@ def test_study_structure_methods() -> None: def test_visit_clean_empty_dates() -> None: - """TODO: Add docstring.""" + """Test that visit clean empty dates.""" from imednet.models.visits import Visit # Valid date @@ -221,7 +221,7 @@ def test_visit_clean_empty_dates() -> None: def test_study_structure_study() -> None: - """TODO: Add docstring.""" + """Test that study structure study.""" from imednet.models.study_structure import StudyStructure study = StudyStructure(studyKey="ST1", intervals=[]) diff --git a/tests/unit/test_models_base_extra.py b/tests/unit/test_models_base_extra.py index a31c880b..86f62d14 100644 --- a/tests/unit/test_models_base_extra.py +++ b/tests/unit/test_models_base_extra.py @@ -22,14 +22,14 @@ def test_sort_field_defaults(): - """TODO: Add docstring.""" + """Test that sort field defaults.""" model = SortField.model_validate({"property": None, "direction": None}) assert model.property == "" assert model.direction == "" def test_pagination_aliases_and_defaults(): - """TODO: Add docstring.""" + """Test that pagination aliases and defaults.""" data = { "currentPage": "2", "size": "5", @@ -46,7 +46,7 @@ def test_pagination_aliases_and_defaults(): def test_error_and_metadata_parsing(): - """TODO: Add docstring.""" + """Test that error and metadata parsing.""" err = Error.model_validate({"details": {"foo": "bar"}}) assert err.code == "" assert err.message == "" @@ -64,7 +64,7 @@ def test_error_and_metadata_parsing(): def test_api_response_generic(): - """TODO: Add docstring.""" + """Test that api response generic.""" resp = ApiResponse[int].model_validate( { "metadata": {"timestamp": "2023-01-01T00:00:00Z"}, diff --git a/tests/unit/test_models_validators.py b/tests/unit/test_models_validators.py index 5edc2e09..2a1c46eb 100644 --- a/tests/unit/test_models_validators.py +++ b/tests/unit/test_models_validators.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for models validators.""" import datetime @@ -51,12 +51,12 @@ ], ) def test_parse_bool_comprehensive(input_val, expected): - """TODO: Add docstring.""" + """Test that parse bool comprehensive.""" assert validators.parse_bool(input_val) is expected def test_parse_int_or_default_and_str_default(): - """TODO: Add docstring.""" + """Test that parse int or default and str default.""" assert validators.parse_int_or_default("5") == 5 assert validators.parse_int_or_default(None, default=2) == 2 assert validators.parse_int_or_default("bad") == 0 @@ -76,7 +76,7 @@ def test_parse_int_or_default_and_str_default(): def test_parse_list_and_dict_helpers(): - """TODO: Add docstring.""" + """Test that parse list and dict helpers.""" assert validators.parse_list_or_default(None) == [] assert validators.parse_list_or_default("a") == ["a"] assert validators.parse_list_or_default([1, 2]) == [1, 2] @@ -86,7 +86,7 @@ def test_parse_list_and_dict_helpers(): def test_parse_datetime_wrapper(): - """TODO: Add docstring.""" + """Test that parse datetime wrapper.""" dt = datetime.datetime(2024, 1, 1) assert validators.parse_datetime(dt) == dt iso = "2024-01-01T00:00:00Z" @@ -110,7 +110,7 @@ def test_parse_datetime_parses_strings() -> None: def test_parse_datetime_numeric(): - """TODO: Add docstring.""" + """Test that parse datetime numeric.""" timestamp = 1704067200 # 2024-01-01 00:00:00 UTC dt = validators.parse_datetime(timestamp) assert dt == datetime.datetime(2024, 1, 1, 0, 0, tzinfo=datetime.timezone.utc) @@ -120,7 +120,7 @@ def test_parse_datetime_numeric(): def test_parse_bool_string_float(): - """TODO: Add docstring.""" + """Test that parse bool string float.""" assert validators.parse_bool("1.0") is True assert validators.parse_bool("0.0") is False assert validators.parse_bool("-1") is True @@ -134,7 +134,7 @@ def test_parse_bool_string_float(): def test_parse_dict_or_default_structural_shift(caplog): - """TODO: Add docstring.""" + """Test that parse dict or default structural shift.""" import logging with caplog.at_level(logging.WARNING): @@ -150,7 +150,7 @@ def test_parse_dict_or_default_structural_shift(caplog): def test_parse_list_or_default_structural_shift(caplog): - """TODO: Add docstring.""" + """Test that parse list or default structural shift.""" import logging with caplog.at_level(logging.WARNING): @@ -163,6 +163,6 @@ def test_parse_list_or_default_structural_shift(caplog): def test_parse_bool_invalid_float(): - """TODO: Add docstring.""" + """Test that parse bool invalid float.""" # To cover the 'except (ValueError, TypeError)' block in parse_bool float fallback assert validators.parse_bool("1invalid") is False diff --git a/tests/unit/test_operation_get.py b/tests/unit/test_operation_get.py index a255aa1d..26b80300 100644 --- a/tests/unit/test_operation_get.py +++ b/tests/unit/test_operation_get.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for operation get.""" from unittest.mock import AsyncMock, MagicMock @@ -10,7 +10,7 @@ def test_filter_get_operation_returns_first_result(): - """TODO: Add docstring.""" + """Test that filter get operation returns first result.""" validate = MagicMock(return_value={"id": 123}) list_sync = MagicMock(return_value=[{"id": 123}]) @@ -31,7 +31,7 @@ def test_filter_get_operation_returns_first_result(): @pytest.mark.asyncio async def test_filter_get_operation_async_missing_callable(): - """TODO: Add docstring.""" + """Test that filter get operation async missing callable asynchronously.""" operation = FilterGetOperation( study_key="STUDY", item_id=123, @@ -44,14 +44,14 @@ async def test_filter_get_operation_async_missing_callable(): def test_path_get_operation_not_found_callback(): - """TODO: Add docstring.""" + """Test that path get operation not found callback.""" client = MagicMock() response = MagicMock() response.json.return_value = None client.get.return_value = response def raise_not_found() -> None: - """TODO: Add docstring.""" + """Helper function to raise not found.""" raise NotFoundError("missing") operation = PathGetOperation( @@ -65,7 +65,7 @@ def raise_not_found() -> None: def test_path_get_operation_calls_parse_func(): - """TODO: Add docstring.""" + """Test that path get operation calls parse func.""" client = MagicMock() response = MagicMock() response.json.return_value = {"jobId": "1"} diff --git a/tests/unit/test_operation_list.py b/tests/unit/test_operation_list.py index 482b418e..69a85c39 100644 --- a/tests/unit/test_operation_list.py +++ b/tests/unit/test_operation_list.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for operation list.""" from unittest.mock import AsyncMock, MagicMock @@ -8,7 +8,7 @@ def test_list_operation_sync_uses_paginator(): - """TODO: Add docstring.""" + """Test that list operation sync uses paginator.""" client = MagicMock() paginator_cls = MagicMock(return_value=[{"id": 1}, {"id": 2}]) @@ -23,17 +23,17 @@ def test_list_operation_sync_uses_paginator(): @pytest.mark.asyncio async def test_list_operation_async_uses_paginator(): - """TODO: Add docstring.""" + """Test that list operation async uses paginator asynchronously.""" class _AsyncPaginator: - """TODO: Add docstring.""" + """Test suite for AsyncPaginator.""" def __init__(self, *_args, **_kwargs): - """TODO: Add docstring.""" + """Initialize the test object.""" pass async def __aiter__(self): - """TODO: Add docstring.""" + """Helper function to aiter .""" for item in [{"id": 1}, {"id": 2}]: yield item diff --git a/tests/unit/test_orchestration_logging.py b/tests/unit/test_orchestration_logging.py index e16fafd5..23aa29f8 100644 --- a/tests/unit/test_orchestration_logging.py +++ b/tests/unit/test_orchestration_logging.py @@ -9,13 +9,13 @@ def test_study_context_log_adapter_exposes_study_key() -> None: - """TODO: Add docstring.""" + """Test that study context log adapter exposes study key.""" adapter = StudyContextLogAdapter(logging.getLogger("tests"), study_key="PROT-01") assert adapter.study_key == "PROT-01" def test_study_context_log_adapter_process_injects_study_key() -> None: - """TODO: Add docstring.""" + """Test that study context log adapter process injects study key.""" adapter = StudyContextLogAdapter(logging.getLogger("tests"), study_key="PROT-01") msg, kwargs = adapter.process("msg", {}) @@ -25,7 +25,7 @@ def test_study_context_log_adapter_process_injects_study_key() -> None: def test_study_context_log_adapter_process_overrides_extra_study_key() -> None: - """TODO: Add docstring.""" + """Test that study context log adapter process overrides extra study key.""" adapter = StudyContextLogAdapter(logging.getLogger("tests"), study_key="PROT-01") kwargs: dict[str, Any] = {"extra": {"study_key": "OTHER", "x": 1}} @@ -37,7 +37,7 @@ def test_study_context_log_adapter_process_overrides_extra_study_key() -> None: def test_make_study_logger_uses_orchestration_logger() -> None: - """TODO: Add docstring.""" + """Test that make study logger uses orchestration logger.""" adapter = make_study_logger("PROT-01") assert isinstance(adapter, StudyContextLogAdapter) assert adapter.study_key == "PROT-01" diff --git a/tests/unit/test_orchestration_types.py b/tests/unit/test_orchestration_types.py index 912ce79f..a0f68eb9 100644 --- a/tests/unit/test_orchestration_types.py +++ b/tests/unit/test_orchestration_types.py @@ -8,23 +8,23 @@ def _worker(study_key: str, sdk_client: Any, logger: Any, *args: Any, **kwargs: Any) -> int: - """TODO: Add docstring.""" + """Helper function to worker.""" _ = (study_key, sdk_client, logger, args, kwargs) return 1 def test_study_worker_callable_runtime_check() -> None: - """TODO: Add docstring.""" + """Test that study worker callable runtime check.""" assert isinstance(_worker, StudyWorkerCallable) def test_non_callable_does_not_satisfy_study_worker_callable() -> None: - """TODO: Add docstring.""" + """Test that non callable does not satisfy study worker callable.""" assert not isinstance("not-a-worker", StudyWorkerCallable) def test_orchestrator_result_allows_partial_keys() -> None: - """TODO: Add docstring.""" + """Test that orchestrator result allows partial keys.""" result: OrchestratorResult = {"status": "SUCCESS", "duration_seconds": 0.5} assert result["status"] == "SUCCESS" assert result["duration_seconds"] == 0.5 diff --git a/tests/unit/test_orchestrator.py b/tests/unit/test_orchestrator.py index 49a58d8f..4cde0a9f 100644 --- a/tests/unit/test_orchestrator.py +++ b/tests/unit/test_orchestrator.py @@ -14,15 +14,15 @@ def _make_study(study_key: str) -> Study: - """TODO: Add docstring.""" + """Helper function to make study.""" return Study(study_key=study_key) def _mock_monotonic(monkeypatch: pytest.MonkeyPatch, values: list[float]) -> None: - """TODO: Add docstring.""" + """Helper function to mock monotonic.""" def infinite_clock(): - """TODO: Add docstring.""" + """Helper function to infinite clock.""" for v in values: yield v last_v = values[-1] if values else 0.0 @@ -38,7 +38,7 @@ def infinite_clock(): def test_orchestrator_is_instantiable_with_default_max_workers() -> None: - """TODO: Add docstring.""" + """Test that orchestrator is instantiable with default max workers.""" sdk = MagicMock() orchestrator = MultiStudyOrchestrator(sdk) @@ -48,7 +48,7 @@ def test_orchestrator_is_instantiable_with_default_max_workers() -> None: def test_orchestrator_raises_for_invalid_max_workers() -> None: - """TODO: Add docstring.""" + """Test that orchestrator raises for invalid max workers.""" sdk = MagicMock() with pytest.raises(ValueError, match="max_workers must be >= 1"): @@ -56,7 +56,7 @@ def test_orchestrator_raises_for_invalid_max_workers() -> None: def test_resolve_active_studies_returns_all_study_keys() -> None: - """TODO: Add docstring.""" + """Test that resolve active studies returns all study keys.""" sdk = MagicMock() sdk.studies.list.return_value = [_make_study("A"), _make_study("B")] orchestrator = MultiStudyOrchestrator(sdk) @@ -68,7 +68,7 @@ def test_resolve_active_studies_returns_all_study_keys() -> None: def test_resolve_active_studies_applies_whitelist() -> None: - """TODO: Add docstring.""" + """Test that resolve active studies applies whitelist.""" sdk = MagicMock() sdk.studies.list.return_value = [_make_study("A"), _make_study("B")] orchestrator = MultiStudyOrchestrator(sdk) @@ -79,7 +79,7 @@ def test_resolve_active_studies_applies_whitelist() -> None: def test_resolve_active_studies_applies_blacklist() -> None: - """TODO: Add docstring.""" + """Test that resolve active studies applies blacklist.""" sdk = MagicMock() sdk.studies.list.return_value = [_make_study("A"), _make_study("B")] orchestrator = MultiStudyOrchestrator(sdk) @@ -90,7 +90,7 @@ def test_resolve_active_studies_applies_blacklist() -> None: def test_resolve_active_studies_raises_on_conflicting_filters_before_network_call() -> None: - """TODO: Add docstring.""" + """Test that resolve active studies raises on conflicting filters before network call.""" sdk = MagicMock() orchestrator = MultiStudyOrchestrator(sdk) @@ -103,7 +103,7 @@ def test_resolve_active_studies_raises_on_conflicting_filters_before_network_cal def test_resolve_active_studies_with_empty_filter_sets_returns_all_studies() -> None: - """TODO: Add docstring.""" + """Test that resolve active studies with empty filter sets returns all studies.""" sdk = MagicMock() sdk.studies.list.return_value = [_make_study("A"), _make_study("B")] orchestrator = MultiStudyOrchestrator(sdk) @@ -116,7 +116,7 @@ def test_resolve_active_studies_with_empty_filter_sets_returns_all_studies() -> def test_execute_pipeline_returns_success_results_and_forwards_worker_arguments( monkeypatch: pytest.MonkeyPatch, ) -> None: - """TODO: Add docstring.""" + """Test that execute pipeline returns success results and forwards worker arguments.""" sdk = MagicMock() sdk.studies.list.return_value = [_make_study("A"), _make_study("B")] orchestrator = MultiStudyOrchestrator(sdk, max_workers=2) @@ -130,7 +130,7 @@ def worker( *, scale: int, ) -> str: - """TODO: Add docstring.""" + """Helper function to worker.""" assert sdk_client is sdk assert study_logger.study_key == study_key return f"{study_key}-{suffix}-{scale}" @@ -148,7 +148,7 @@ def worker( def test_execute_pipeline_isolates_per_study_failures( monkeypatch: pytest.MonkeyPatch, ) -> None: - """TODO: Add docstring.""" + """Test that execute pipeline isolates per study failures.""" sdk = MagicMock() sdk.studies.list.return_value = [_make_study("A"), _make_study("B"), _make_study("C")] orchestrator = MultiStudyOrchestrator(sdk, max_workers=3) @@ -157,7 +157,7 @@ def test_execute_pipeline_isolates_per_study_failures( def worker( study_key: str, _sdk_client: MagicMock, _study_logger: StudyContextLogAdapter ) -> str: - """TODO: Add docstring.""" + """Helper function to worker.""" if study_key == "B": raise RuntimeError("boom") return f"ok-{study_key}" @@ -191,7 +191,7 @@ def worker( sdk_client: MagicMock, study_logger: StudyContextLogAdapter, ) -> str: - """TODO: Add docstring.""" + """Helper function to worker.""" # get_current_study() must resolve to the same key passed explicitly. return get_current_study() @@ -204,14 +204,14 @@ def worker( def test_sdk_property_returns_original_sdk() -> None: - """TODO: Add docstring.""" + """Test that sdk property returns original sdk.""" sdk = MagicMock() orchestrator = MultiStudyOrchestrator(sdk) assert orchestrator.sdk is sdk def test_max_workers_property_returns_configured_value() -> None: - """TODO: Add docstring.""" + """Test that max workers property returns configured value.""" sdk = MagicMock() orchestrator = MultiStudyOrchestrator(sdk, max_workers=7) assert orchestrator.max_workers == 7 @@ -220,7 +220,7 @@ def test_max_workers_property_returns_configured_value() -> None: def test_resolve_active_studies_logs_and_returns_all_when_no_filters( caplog: pytest.LogCaptureFixture, ) -> None: - """TODO: Add docstring.""" + """Test that resolve active studies logs and returns all when no filters.""" sdk = MagicMock() sdk.studies.list.return_value = [_make_study("A"), _make_study("B")] orchestrator = MultiStudyOrchestrator(sdk) @@ -235,7 +235,7 @@ def test_resolve_active_studies_logs_and_returns_all_when_no_filters( def test_resolve_active_studies_logs_whitelist_selection( caplog: pytest.LogCaptureFixture, ) -> None: - """TODO: Add docstring.""" + """Test that resolve active studies logs whitelist selection.""" sdk = MagicMock() sdk.studies.list.return_value = [_make_study("A"), _make_study("B"), _make_study("C")] orchestrator = MultiStudyOrchestrator(sdk) @@ -250,7 +250,7 @@ def test_resolve_active_studies_logs_whitelist_selection( def test_resolve_active_studies_logs_blacklist_selection( caplog: pytest.LogCaptureFixture, ) -> None: - """TODO: Add docstring.""" + """Test that resolve active studies logs blacklist selection.""" sdk = MagicMock() sdk.studies.list.return_value = [_make_study("A"), _make_study("B"), _make_study("C")] orchestrator = MultiStudyOrchestrator(sdk) diff --git a/tests/unit/test_pagination_guarantees.py b/tests/unit/test_pagination_guarantees.py index aedc261a..df32b079 100644 --- a/tests/unit/test_pagination_guarantees.py +++ b/tests/unit/test_pagination_guarantees.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for pagination guarantees.""" import itertools @@ -12,7 +12,7 @@ @respx.mock def test_empty_result_set_stops_immediately() -> None: - """TODO: Add docstring.""" + """Test that empty result set stops immediately.""" respx.get("https://api.test/items").mock( return_value=httpx.Response(200, json={"data": [], "pagination": {"totalPages": 0}}) ) @@ -24,7 +24,7 @@ def test_empty_result_set_stops_immediately() -> None: @respx.mock def test_single_page_iteration() -> None: - """TODO: Add docstring.""" + """Test that single page iteration.""" respx.get("https://api.test/items").mock( return_value=httpx.Response(200, json={"data": [1, 2], "pagination": {"totalPages": 1}}) ) @@ -38,11 +38,11 @@ def test_single_page_iteration() -> None: @respx.mock def test_last_page_partial_results() -> None: - """TODO: Add docstring.""" + """Test that last page partial results.""" calls: list[int] = [] def responder(request: httpx.Request) -> httpx.Response: - """TODO: Add docstring.""" + """Helper function to responder.""" page = int(request.url.params["page"]) calls.append(page) if page == 0: @@ -58,7 +58,7 @@ def responder(request: httpx.Request) -> httpx.Response: @respx.mock def test_missing_cursor_raises_typed_error() -> None: - """TODO: Add docstring.""" + """Test that missing cursor raises typed error.""" respx.get("https://api.test/items").mock( return_value=httpx.Response(200, json={"data": [1, 2], "pagination": {}}) ) @@ -70,7 +70,7 @@ def test_missing_cursor_raises_typed_error() -> None: @respx.mock def test_malformed_cursor_raises_typed_error() -> None: - """TODO: Add docstring.""" + """Test that malformed cursor raises typed error.""" respx.get("https://api.test/items").mock( return_value=httpx.Response( 200, json={"data": [1], "pagination": {"totalPages": "not-an-integer"}} @@ -84,12 +84,12 @@ def test_malformed_cursor_raises_typed_error() -> None: @respx.mock def test_large_result_set_iteration_is_lazy_and_bounded() -> None: - """TODO: Add docstring.""" + """Test that large result set iteration is lazy and bounded.""" calls: list[int] = [] total_pages = 100_000 def responder(request: httpx.Request) -> httpx.Response: - """TODO: Add docstring.""" + """Helper function to responder.""" page = int(request.url.params["page"]) calls.append(page) return httpx.Response( @@ -107,11 +107,11 @@ def responder(request: httpx.Request) -> httpx.Response: @respx.mock def test_iteration_can_be_interrupted_and_resumed() -> None: - """TODO: Add docstring.""" + """Test that iteration can be interrupted and resumed.""" calls: list[int] = [] def responder(request: httpx.Request) -> httpx.Response: - """TODO: Add docstring.""" + """Helper function to responder.""" page = int(request.url.params["page"]) calls.append(page) if page == 0: diff --git a/tests/unit/test_paginator_robustness.py b/tests/unit/test_paginator_robustness.py index 5a3d0205..2fcefca1 100644 --- a/tests/unit/test_paginator_robustness.py +++ b/tests/unit/test_paginator_robustness.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for paginator robustness.""" from unittest.mock import Mock @@ -9,14 +9,14 @@ class MockClient: - """TODO: Add docstring.""" + """Test suite for MockClient.""" def __init__(self, response_data): - """TODO: Add docstring.""" + """Initialize the test object.""" self.response_data = response_data def get(self, path, params=None): - """TODO: Add docstring.""" + """Helper function to get.""" response = Mock() response.json.return_value = self.response_data return response diff --git a/tests/unit/test_parquet_engine.py b/tests/unit/test_parquet_engine.py index 8f091bcc..2c7ca590 100644 --- a/tests/unit/test_parquet_engine.py +++ b/tests/unit/test_parquet_engine.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for parquet engine.""" from pathlib import Path from typing import Any @@ -9,20 +9,20 @@ class _FakeTable: - """TODO: Add docstring.""" + """Test suite for FakeTable.""" def __init__(self) -> None: - """TODO: Add docstring.""" + """Initialize the test object.""" self.num_rows = 2 self.columns: list[tuple[str, list[str]]] = [] def append_column(self, name: str, values: list[str]) -> "_FakeTable": - """TODO: Add docstring.""" + """Helper function to append column.""" self.columns.append((name, values)) return self def value_for_column(self, name: str) -> Any: - """TODO: Add docstring.""" + """Helper function to value for column.""" for column_name, values in self.columns: if column_name == name: return values[0] @@ -30,39 +30,39 @@ def value_for_column(self, name: str) -> Any: class _FakeParquetFormat: - """TODO: Add docstring.""" + """Test suite for FakeParquetFormat.""" def __init__(self) -> None: - """TODO: Add docstring.""" + """Initialize the test object.""" self.options: dict[str, Any] | None = None def make_write_options(self, **kwargs: Any) -> dict[str, Any]: - """TODO: Add docstring.""" + """Helper function to make write options.""" self.options = kwargs return kwargs class _FakeDatasetModule: - """TODO: Add docstring.""" + """Test suite for FakeDatasetModule.""" def __init__(self) -> None: - """TODO: Add docstring.""" + """Initialize the test object.""" self.partitioning_args: dict[str, Any] | None = None self.write_call: dict[str, Any] | None = None self.format = _FakeParquetFormat() self.should_fail = False def ParquetFileFormat(self) -> _FakeParquetFormat: # noqa: N802 - """TODO: Add docstring.""" + """Helper function to ParquetFileFormat.""" return self.format def partitioning(self, **kwargs: Any) -> dict[str, Any]: - """TODO: Add docstring.""" + """Helper function to partitioning.""" self.partitioning_args = kwargs return kwargs def write_dataset(self, table: _FakeTable, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to write dataset.""" if self.should_fail: raise RuntimeError("boom") base_dir = Path(kwargs["base_dir"]) @@ -75,24 +75,24 @@ def write_dataset(self, table: _FakeTable, **kwargs: Any) -> None: class _FakePyArrowModule: - """TODO: Add docstring.""" + """Test suite for FakePyArrowModule.""" def string(self) -> str: - """TODO: Add docstring.""" + """Helper function to string.""" return "string" def schema(self, fields: list[tuple[str, str]]) -> list[tuple[str, str]]: - """TODO: Add docstring.""" + """Helper function to schema.""" return fields def array(self, values: list[str], **kwargs: Any) -> list[str]: - """TODO: Add docstring.""" + """Helper function to array.""" assert kwargs["type"] == "string" return values def _raise_replace_failure(*_args: Any) -> None: - """TODO: Add docstring.""" + """Helper function to raise replace failure.""" raise OSError("rename failed") @@ -100,7 +100,7 @@ def test_pyarrow_dataset_partitioned_storage_engine_defaults( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: - """TODO: Add docstring.""" + """Test that pyarrow dataset partitioned storage engine defaults.""" fake_pa = _FakePyArrowModule() fake_ds = _FakeDatasetModule() monkeypatch.setattr( @@ -137,7 +137,7 @@ def test_pyarrow_dataset_partitioned_storage_engine_cleans_staging_on_failure( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: - """TODO: Add docstring.""" + """Test that pyarrow dataset partitioned storage engine cleans staging on failure.""" fake_pa = _FakePyArrowModule() fake_ds = _FakeDatasetModule() fake_ds.should_fail = True @@ -162,7 +162,7 @@ def test_pyarrow_dataset_partitioned_storage_engine_cleans_visible_dirs_on_commi tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: - """TODO: Add docstring.""" + """Test that pyarrow dataset partitioned storage engine cleans visible dirs on commit failure.""" fake_pa = _FakePyArrowModule() fake_ds = _FakeDatasetModule() monkeypatch.setattr( @@ -189,7 +189,7 @@ def test_pyarrow_dataset_partitioned_storage_engine_cleans_visible_dirs_on_commi def test_pyarrow_dataset_partitioned_storage_engine_schema_drift_duckdb( tmp_path: Path, ) -> None: - """TODO: Add docstring.""" + """Test that pyarrow dataset partitioned storage engine schema drift duckdb.""" duckdb = pytest.importorskip("duckdb") pyarrow = pytest.importorskip("pyarrow") parquet_module = pytest.importorskip("pyarrow.parquet") diff --git a/tests/unit/test_parse_bool_float_str.py b/tests/unit/test_parse_bool_float_str.py index 797693c5..ef57c32d 100644 --- a/tests/unit/test_parse_bool_float_str.py +++ b/tests/unit/test_parse_bool_float_str.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for parse bool float str.""" import pytest diff --git a/tests/unit/test_parse_datetime_robustness.py b/tests/unit/test_parse_datetime_robustness.py index f8eaa242..b11ea399 100644 --- a/tests/unit/test_parse_datetime_robustness.py +++ b/tests/unit/test_parse_datetime_robustness.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for parse datetime robustness.""" from datetime import datetime, timezone diff --git a/tests/unit/test_plugin_contract.py b/tests/unit/test_plugin_contract.py index 363fe30f..b48103f9 100644 --- a/tests/unit/test_plugin_contract.py +++ b/tests/unit/test_plugin_contract.py @@ -28,7 +28,7 @@ class _ValidNamespace: def _valid_factory(sdk_instance: Any) -> _ValidNamespace: # noqa: ANN401 - """TODO: Add docstring.""" + """Helper function to valid factory.""" return _ValidNamespace() @@ -38,15 +38,15 @@ def _valid_factory(sdk_instance: Any) -> _ValidNamespace: # noqa: ANN401 def test_valid_namespace_satisfies_protocol() -> None: - """TODO: Add docstring.""" + """Test that valid namespace satisfies protocol.""" assert isinstance(_ValidNamespace(), WorkflowsNamespaceProtocol) def test_object_missing_attributes_does_not_satisfy_namespace_protocol() -> None: - """TODO: Add docstring.""" + """Test that object missing attributes does not satisfy namespace protocol.""" class _Incomplete: - """TODO: Add docstring.""" + """Test suite for Incomplete.""" data_extraction: Any = None # missing: query_management, record_mapper, record_update, subject_data @@ -60,12 +60,12 @@ class _Incomplete: def test_callable_factory_satisfies_plugin_protocol() -> None: - """TODO: Add docstring.""" + """Test that callable factory satisfies plugin protocol.""" assert isinstance(_valid_factory, PluginProtocol) def test_non_callable_does_not_satisfy_plugin_protocol() -> None: - """TODO: Add docstring.""" + """Test that non callable does not satisfy plugin protocol.""" assert not isinstance("not-a-callable", PluginProtocol) @@ -75,7 +75,7 @@ def test_non_callable_does_not_satisfy_plugin_protocol() -> None: def test_plugin_load_error_is_imednet_error() -> None: - """TODO: Add docstring.""" + """Test that plugin load error is imednet error.""" from imednet.errors import ImednetError err = PluginLoadError("boom") @@ -95,7 +95,7 @@ def _make_sdk() -> _BaseSDK: def test_get_workflow_entry_point_returns_none_when_no_plugins_installed() -> None: - """TODO: Add docstring.""" + """Test that get workflow entry point returns none when no plugins installed.""" sdk = _make_sdk() with patch("imednet.sdk.entry_points", return_value=[]): result = sdk._get_workflow_entry_point() @@ -103,7 +103,7 @@ def test_get_workflow_entry_point_returns_none_when_no_plugins_installed() -> No def test_get_workflow_entry_point_raises_plugin_load_error_on_multiple_plugins() -> None: - """TODO: Add docstring.""" + """Test that get workflow entry point raises plugin load error on multiple plugins.""" ep1 = MagicMock(spec=EntryPoint) ep1.value = "plugin_a.ns:factory" ep2 = MagicMock(spec=EntryPoint) @@ -116,7 +116,7 @@ def test_get_workflow_entry_point_raises_plugin_load_error_on_multiple_plugins() def test_get_workflow_entry_point_returns_single_entry_point() -> None: - """TODO: Add docstring.""" + """Test that get workflow entry point returns single entry point.""" ep = MagicMock(spec=EntryPoint) ep.value = "myplugin.ns:factory" @@ -132,7 +132,7 @@ def test_get_workflow_entry_point_returns_single_entry_point() -> None: def test_init_workflows_returns_missing_workflows_when_no_plugin() -> None: - """TODO: Add docstring.""" + """Test that init workflows returns missing workflows when no plugin.""" sdk = _make_sdk() with patch("imednet.sdk.entry_points", return_value=[]): ns = sdk._init_workflows() @@ -148,7 +148,7 @@ def test_init_workflows_returns_missing_workflows_when_no_plugin() -> None: def test_init_workflows_raises_plugin_load_error_on_broken_entry_point() -> None: - """TODO: Add docstring.""" + """Test that init workflows raises plugin load error on broken entry point.""" ep = MagicMock(spec=EntryPoint) ep.value = "broken.module:factory" ep.load.side_effect = ModuleNotFoundError("No module named 'broken'") @@ -165,7 +165,7 @@ def test_init_workflows_raises_plugin_load_error_on_broken_entry_point() -> None def test_init_workflows_raises_plugin_load_error_when_entry_point_not_callable() -> None: - """TODO: Add docstring.""" + """Test that init workflows raises plugin load error when entry point not callable.""" ep = MagicMock(spec=EntryPoint) ep.value = "myplugin.ns:NOT_A_CALLABLE" ep.load.return_value = "I am a string, not a callable" # type: ignore[assignment] @@ -182,7 +182,7 @@ def test_init_workflows_raises_plugin_load_error_when_entry_point_not_callable() def test_init_workflows_returns_namespace_from_valid_plugin() -> None: - """TODO: Add docstring.""" + """Test that init workflows returns namespace from valid plugin.""" ep = MagicMock(spec=EntryPoint) ep.value = "myplugin.ns:factory" ep.load.return_value = _valid_factory @@ -200,10 +200,10 @@ def test_init_workflows_returns_namespace_from_valid_plugin() -> None: def test_init_workflows_raises_plugin_load_error_when_factory_raises_type_error() -> None: - """TODO: Add docstring.""" + """Test that init workflows raises plugin load error when factory raises type error.""" def _bad_factory(*args: Any, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to bad factory.""" raise TypeError("unexpected argument") ep = MagicMock(spec=EntryPoint) diff --git a/tests/unit/test_poll_job.py b/tests/unit/test_poll_job.py index 1a6a1687..c8e7ba96 100644 --- a/tests/unit/test_poll_job.py +++ b/tests/unit/test_poll_job.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for poll job.""" import asyncio from unittest.mock import AsyncMock @@ -10,14 +10,14 @@ def _create_sdk(async_mode: bool) -> sdk_mod.ImednetSDK: - """TODO: Add docstring.""" + """Helper function to create sdk.""" cls = sdk_mod.AsyncImednetSDK if async_mode else sdk_mod.ImednetSDK return cls(api_key="key", security_key="secret", base_url="https://example.com") @pytest.mark.parametrize("async_mode", [False, True]) def test_poll_job_success(async_mode: bool, monkeypatch: pytest.MonkeyPatch) -> None: - """TODO: Add docstring.""" + """Test that poll job success.""" sdk = _create_sdk(async_mode) states = [ JobStatus(batch_id="1", state="PROCESSING", progress=10), @@ -40,7 +40,7 @@ def test_poll_job_success(async_mode: bool, monkeypatch: pytest.MonkeyPatch) -> @pytest.mark.parametrize("async_mode", [False, True]) def test_poll_job_timeout(async_mode: bool, monkeypatch: pytest.MonkeyPatch) -> None: - """TODO: Add docstring.""" + """Test that poll job timeout.""" sdk = _create_sdk(async_mode) job = JobStatus(batch_id="1", state="PROCESSING") if async_mode: @@ -56,7 +56,7 @@ def test_poll_job_timeout(async_mode: bool, monkeypatch: pytest.MonkeyPatch) -> tick = {"v": 0} def monotonic() -> int: - """TODO: Add docstring.""" + """Helper function to monotonic.""" tick["v"] += 1 return tick["v"] @@ -70,7 +70,7 @@ def monotonic() -> int: @pytest.mark.parametrize("async_mode", [False, True]) def test_poll_job_failed(async_mode: bool, monkeypatch: pytest.MonkeyPatch) -> None: - """TODO: Add docstring.""" + """Test that poll job failed.""" sdk = _create_sdk(async_mode) states = [ JobStatus(batch_id="1", state="PROCESSING"), diff --git a/tests/unit/test_post_smoke_record.py b/tests/unit/test_post_smoke_record.py index 8909f8c3..a17d4936 100644 --- a/tests/unit/test_post_smoke_record.py +++ b/tests/unit/test_post_smoke_record.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for post smoke record.""" import logging from unittest.mock import Mock @@ -14,7 +14,7 @@ def test_submit_record_uses_configured_timeout() -> None: - """TODO: Add docstring.""" + """Test that submit record uses configured timeout.""" sdk = Mock() sdk.records.create.return_value = Mock(batch_id="B1") sdk.poll_job.return_value = Mock(state="COMPLETED", batch_id="B1") @@ -26,7 +26,7 @@ def test_submit_record_uses_configured_timeout() -> None: def test_submit_record_reports_failure_details() -> None: - """TODO: Add docstring.""" + """Test that submit record reports failure details.""" sdk = Mock() sdk.records.create.return_value = Mock(batch_id="B1") sdk.poll_job.return_value = Mock( @@ -41,12 +41,12 @@ def test_submit_record_reports_failure_details() -> None: def _var(name: str, var_type: str) -> Variable: - """TODO: Add docstring.""" + """Helper function to var.""" return Variable(variable_name=name, variable_type=var_type, form_id=1, form_key="F1") def test_build_record_returns_typed_values() -> None: - """TODO: Add docstring.""" + """Test that build record returns typed values.""" sdk = Mock() sdk.variables.list.return_value = [ _var("text", "text"), @@ -98,7 +98,7 @@ def test_build_record_returns_typed_values() -> None: ], ) def test_build_record_optional_identifiers(kwargs: dict[str, str], extra: dict[str, str]) -> None: - """TODO: Add docstring.""" + """Test that build record optional identifiers.""" sdk = Mock() sdk.variables.list.return_value = [] @@ -109,7 +109,7 @@ def test_build_record_optional_identifiers(kwargs: dict[str, str], extra: dict[s def test_discover_identifiers_returns_all() -> None: - """TODO: Add docstring.""" + """Test that discover identifiers returns all.""" sdk = Mock() sdk.sites.list.return_value = [ Site(study_key="S", site_name="SITE", site_enrollment_status="Active") @@ -128,7 +128,7 @@ def test_discover_identifiers_returns_all() -> None: def test_discover_identifiers_reports_missing(monkeypatch, capsys) -> None: - """TODO: Add docstring.""" + """Test that discover identifiers reports missing.""" monkeypatch.setattr(smoke, "discover_site_name", Mock(side_effect=Exception("no site"))) monkeypatch.setattr(smoke, "discover_subject_key", Mock(side_effect=Exception("no subject"))) monkeypatch.setattr(smoke, "discover_interval_name", Mock(side_effect=Exception("no int"))) @@ -143,7 +143,7 @@ def test_discover_identifiers_reports_missing(monkeypatch, capsys) -> None: def test_main_verbose_logs(monkeypatch, caplog) -> None: - """TODO: Add docstring.""" + """Test that main verbose logs.""" sdk = Mock() sdk.__enter__ = Mock(return_value=sdk) sdk.__exit__ = Mock(return_value=False) @@ -169,7 +169,7 @@ def test_main_verbose_logs(monkeypatch, caplog) -> None: def test_main_returns_skip_when_identifiers_missing(monkeypatch, capsys) -> None: - """TODO: Add docstring.""" + """Test that main returns skip when identifiers missing.""" sdk = Mock() sdk.__enter__ = Mock(return_value=sdk) sdk.__exit__ = Mock(return_value=False) @@ -185,7 +185,7 @@ def test_main_returns_skip_when_identifiers_missing(monkeypatch, capsys) -> None def test_main_returns_skip_on_discovery_failure(monkeypatch, capsys) -> None: - """TODO: Add docstring.""" + """Test that main returns skip on discovery failure.""" sdk = Mock() sdk.__enter__ = Mock(return_value=sdk) sdk.__exit__ = Mock(return_value=False) diff --git a/tests/unit/test_pyproject_metadata.py b/tests/unit/test_pyproject_metadata.py index 6bb0c8da..dbf97dd6 100644 --- a/tests/unit/test_pyproject_metadata.py +++ b/tests/unit/test_pyproject_metadata.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for pyproject metadata.""" import re from pathlib import Path @@ -7,7 +7,7 @@ def test_project_version_is_single_source_of_truth() -> None: - """TODO: Add docstring.""" + """Test that project version is single source of truth.""" pyproject_path = Path(__file__).resolve().parents[2] / "packages" / "core" / "pyproject.toml" content = pyproject_path.read_text(encoding="utf-8") diff --git a/tests/unit/test_record_mapper.py b/tests/unit/test_record_mapper.py index 77aa26a0..fd4c908c 100644 --- a/tests/unit/test_record_mapper.py +++ b/tests/unit/test_record_mapper.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for record mapper.""" import tracemalloc from datetime import datetime @@ -20,7 +20,7 @@ def test_dataframe_builds_expected_structure() -> None: - """TODO: Add docstring.""" + """Test that dataframe builds expected structure.""" sdk = MagicMock() variables = [ Variable(variable_name="VAR1", label="Label1", form_id=10), @@ -28,7 +28,7 @@ def test_dataframe_builds_expected_structure() -> None: ] def var_list(**kwargs): - """TODO: Add docstring.""" + """Helper function to var list.""" if kwargs.get("variableNames"): assert kwargs == { "study_key": "STUDY", @@ -79,7 +79,7 @@ def var_list(**kwargs): def test_dataframe_whitelists_variables_and_forms() -> None: - """TODO: Add docstring.""" + """Test that dataframe whitelists variables and forms.""" sdk = MagicMock() variables = [ Variable(variable_name="VAR1", label="Label1", form_id=10), @@ -87,7 +87,7 @@ def test_dataframe_whitelists_variables_and_forms() -> None: ] def var_list(**kwargs): - """TODO: Add docstring.""" + """Helper function to var list.""" assert kwargs == { "study_key": "STUDY", "variableNames": ["VAR1"], @@ -107,7 +107,7 @@ def var_list(**kwargs): ) def rec_list(**kwargs): - """TODO: Add docstring.""" + """Helper function to rec list.""" if kwargs.get("variableNames"): assert kwargs == { "study_key": "STUDY", @@ -150,7 +150,7 @@ def rec_list(**kwargs): def test_dataframe_empty_when_no_variables() -> None: - """TODO: Add docstring.""" + """Test that dataframe empty when no variables.""" sdk = MagicMock() sdk.get_variables.return_value = [] mapper = RecordMapper(sdk) @@ -159,7 +159,7 @@ def test_dataframe_empty_when_no_variables() -> None: def test_invalid_visit_key_logs_warning(caplog) -> None: - """TODO: Add docstring.""" + """Test that invalid visit key logs warning.""" sdk = MagicMock() sdk.get_variables.return_value = [Variable(variable_name="VAR", label="L", form_id=1)] sdk.get_records.return_value = [] @@ -174,7 +174,7 @@ def test_invalid_visit_key_logs_warning(caplog) -> None: def test_records_fetch_error_returns_empty(caplog) -> None: - """TODO: Add docstring.""" + """Test that records fetch error returns empty.""" sdk = MagicMock() sdk.get_variables.return_value = [Variable(variable_name="VAR", label="L", form_id=1)] sdk.get_records.side_effect = Exception("boom") @@ -188,7 +188,7 @@ def test_records_fetch_error_returns_empty(caplog) -> None: def test_parsing_error_logs_warning(monkeypatch, caplog) -> None: - """TODO: Add docstring.""" + """Test that parsing error logs warning.""" sdk = MagicMock() sdk.get_variables.return_value = [Variable(variable_name="V", label="L", form_id=1)] record = Record( @@ -203,10 +203,10 @@ def test_parsing_error_logs_warning(monkeypatch, caplog) -> None: sdk.get_records.return_value = [record] class DummyModel(BaseModel): - """TODO: Add docstring.""" + """Test suite for DummyModel.""" def __init__(self, **kwargs): - """TODO: Add docstring.""" + """Initialize the test object.""" raise ValidationError([], DummyModel) monkeypatch.setattr("imednet_workflows.record_mapper.create_model", lambda *a, **k: DummyModel) @@ -220,7 +220,7 @@ def __init__(self, **kwargs): def test_parse_records_counts_errors() -> None: - """TODO: Add docstring.""" + """Test that parse records counts errors.""" mapper = RecordMapper(MagicMock()) records = [ Record( @@ -244,7 +244,7 @@ def test_parse_records_counts_errors() -> None: ] class Dummy(BaseModel): - """TODO: Add docstring.""" + """Test suite for Dummy.""" def __init__(self, **_: Any) -> None: # noqa: D401 - simple """Always fail.""" @@ -257,7 +257,7 @@ def __init__(self, **_: Any) -> None: # noqa: D401 - simple def test_dataframe_raises_importerror_when_pandas_missing(monkeypatch) -> None: - """TODO: Add docstring.""" + """Test that dataframe raises importerror when pandas missing.""" monkeypatch.setattr("imednet_workflows.record_mapper.pd", None) mapper = RecordMapper(MagicMock()) with pytest.raises(ImportError, match="pandas is required for RecordMapper.dataframe"): @@ -265,18 +265,18 @@ def test_dataframe_raises_importerror_when_pandas_missing(monkeypatch) -> None: def test_iter_dataframes_streams_large_study_with_bounded_memory() -> None: - """TODO: Add docstring.""" + """Test that iter dataframes streams large study with bounded memory.""" fake = Faker() class _StreamingLoader: - """TODO: Add docstring.""" + """Test suite for StreamingLoader.""" def __init__(self) -> None: - """TODO: Add docstring.""" + """Initialize the test object.""" self.sync_records = MagicMock() def iter_cached_records(self, study_key: str, *, chunk_size: int = 5_000): - """TODO: Add docstring.""" + """Helper function to iter cached records.""" assert study_key == "STUDY" assert chunk_size == 5_000 for record_id in range(50_000): diff --git a/tests/unit/test_record_mapper_hierarchy.py b/tests/unit/test_record_mapper_hierarchy.py index 0c2acd15..3cb4a7d8 100644 --- a/tests/unit/test_record_mapper_hierarchy.py +++ b/tests/unit/test_record_mapper_hierarchy.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for record mapper hierarchy.""" from datetime import datetime from unittest.mock import MagicMock, patch @@ -10,7 +10,7 @@ @patch("imednet_workflows.study_structure.get_study_structure") def test_build_hierarchy(mock_get_study_structure): - """TODO: Add docstring.""" + """Test that build hierarchy.""" sdk = MagicMock() mock_study_struct = MagicMock() diff --git a/tests/unit/test_schema_validator.py b/tests/unit/test_schema_validator.py index 90f7a039..bd8a4115 100644 --- a/tests/unit/test_schema_validator.py +++ b/tests/unit/test_schema_validator.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for schema validator.""" import asyncio from unittest.mock import AsyncMock, MagicMock @@ -11,7 +11,7 @@ def _build_sdk(variable: Variable, async_mode: bool) -> MagicMock: - """TODO: Add docstring.""" + """Helper function to build sdk.""" sdk = MagicMock() if async_mode: sdk.async_get_variables = AsyncMock(return_value=[variable]) @@ -22,7 +22,7 @@ def _build_sdk(variable: Variable, async_mode: bool) -> MagicMock: @pytest.mark.parametrize("async_mode", [False, True]) def test_validate_record_unknown_variable(async_mode: bool) -> None: - """TODO: Add docstring.""" + """Test that validate record unknown variable.""" var = Variable(variable_name="age", variable_type="integer", form_id=1, form_key="F1") sdk = _build_sdk(var, async_mode) if async_mode: @@ -44,7 +44,7 @@ def test_validate_record_unknown_variable(async_mode: bool) -> None: @pytest.mark.parametrize("async_mode", [False, True]) def test_validate_record_wrong_type(async_mode: bool) -> None: - """TODO: Add docstring.""" + """Test that validate record wrong type.""" var = Variable(variable_name="age", variable_type="integer", form_id=1, form_key="F1") sdk = _build_sdk(var, async_mode) if async_mode: @@ -66,7 +66,7 @@ def test_validate_record_wrong_type(async_mode: bool) -> None: @pytest.mark.parametrize("async_mode", [False, True]) def test_validate_record_unknown_form(async_mode: bool) -> None: - """TODO: Add docstring.""" + """Test that validate record unknown form.""" var = Variable(variable_name="age", variable_type="integer", form_id=1, form_key="F1") sdk = _build_sdk(var, async_mode) if async_mode: @@ -88,7 +88,7 @@ def test_validate_record_unknown_form(async_mode: bool) -> None: @pytest.mark.parametrize("async_mode", [False, True]) def test_refresh_called_when_form_not_cached(async_mode: bool) -> None: - """TODO: Add docstring.""" + """Test that refresh called when form not cached.""" var = Variable(variable_name="age", variable_type="integer", form_id=1, form_key="F1") sdk = _build_sdk(var, async_mode) if async_mode: @@ -107,7 +107,7 @@ def test_refresh_called_when_form_not_cached(async_mode: bool) -> None: @pytest.mark.parametrize("async_mode", [False, True]) def test_validate_record_cached(async_mode: bool) -> None: - """TODO: Add docstring.""" + """Test that validate record cached.""" var = Variable(variable_name="age", variable_type="integer", form_id=1, form_key="F1") sdk = _build_sdk(var, async_mode) if async_mode: @@ -127,7 +127,7 @@ def test_validate_record_cached(async_mode: bool) -> None: @pytest.mark.parametrize("async_mode", [False, True]) def test_validate_record_with_form_id_fallback(async_mode: bool) -> None: - """TODO: Add docstring.""" + """Test that validate record with form id fallback.""" var = Variable(variable_name="age", variable_type="integer", form_id=123, form_key="F1") sdk = _build_sdk(var, async_mode) if async_mode: @@ -148,7 +148,7 @@ def test_validate_record_with_form_id_fallback(async_mode: bool) -> None: @pytest.mark.parametrize("async_mode", [False, True]) def test_validate_record_missing_form_identifier(async_mode: bool) -> None: - """TODO: Add docstring.""" + """Test that validate record missing form identifier.""" var = Variable(variable_name="age", variable_type="integer", form_id=1, form_key="F1") sdk = _build_sdk(var, async_mode) if async_mode: @@ -168,7 +168,7 @@ def test_validate_record_missing_form_identifier(async_mode: bool) -> None: def test_schema_validator_is_async_deprecation_warning() -> None: - """TODO: Add docstring.""" + """Test that schema validator is async deprecation warning.""" sdk = MagicMock() with pytest.warns( DeprecationWarning, match="Passing `is_async=True` to SchemaValidator is deprecated" @@ -179,7 +179,7 @@ def test_schema_validator_is_async_deprecation_warning() -> None: def test_schema_validator_is_async_positional_deprecation_warning() -> None: - """TODO: Add docstring.""" + """Test that schema validator is async positional deprecation warning.""" sdk = MagicMock() with pytest.warns( DeprecationWarning, match="Passing `is_async=True` to SchemaValidator is deprecated" @@ -190,7 +190,7 @@ def test_schema_validator_is_async_positional_deprecation_warning() -> None: def test_validate_record_with_none_value_does_not_raise() -> None: - """TODO: Add docstring.""" + """Test that validate record with none value does not raise.""" var = Variable(variable_name="age", variable_type="integer", form_id=1, form_key="F1") sdk = _build_sdk(var, async_mode=False) validator = SchemaValidator(sdk) @@ -201,7 +201,7 @@ def test_validate_record_with_none_value_does_not_raise() -> None: def test_check_type_unknown_variable_type() -> None: - """TODO: Add docstring.""" + """Test that check type unknown variable type.""" var = Variable(variable_name="age", variable_type="unknown_type", form_id=1, form_key="F1") sdk = _build_sdk(var, async_mode=False) validator = SchemaValidator(sdk) @@ -214,7 +214,7 @@ def test_check_type_unknown_variable_type() -> None: def test_check_type_case_insensitive_type() -> None: - """TODO: Add docstring.""" + """Test that check type case insensitive type.""" var = Variable(variable_name="age", variable_type="InTeGeR", form_id=1, form_key="F1") sdk = _build_sdk(var, async_mode=False) validator = SchemaValidator(sdk) @@ -225,7 +225,7 @@ def test_check_type_case_insensitive_type() -> None: def test_validate_record_entry_with_form_key() -> None: - """TODO: Add docstring.""" + """Test that validate record entry with form key.""" from imednet.validation.cache import SchemaCache, validate_record_entry var = Variable(variable_name="age", variable_type="integer", form_id=1, form_key="F1") @@ -237,7 +237,7 @@ def test_validate_record_entry_with_form_key() -> None: def test_validate_record_entry_with_form_id() -> None: - """TODO: Add docstring.""" + """Test that validate record entry with form id.""" from imednet.validation.cache import SchemaCache, validate_record_entry var = Variable(variable_name="age", variable_type="integer", form_id=1, form_key="F1") @@ -249,7 +249,7 @@ def test_validate_record_entry_with_form_id() -> None: def test_validate_record_entry_missing_both() -> None: - """TODO: Add docstring.""" + """Test that validate record entry missing both.""" from imednet.validation.cache import SchemaCache, validate_record_entry var = Variable(variable_name="age", variable_type="integer", form_id=1, form_key="F1") @@ -261,7 +261,7 @@ def test_validate_record_entry_missing_both() -> None: def test_type_validators_coverage() -> None: - """TODO: Add docstring.""" + """Test that type validators coverage.""" from imednet.validation.cache import ( ValidationError, _validate_bool, @@ -281,7 +281,7 @@ def test_type_validators_coverage() -> None: def test_validate_batch_coverage() -> None: - """TODO: Add docstring.""" + """Test that validate batch coverage.""" var = Variable(variable_name="age", variable_type="integer", form_id=1, form_key="F1") sdk = _build_sdk(var, async_mode=False) validator = SchemaValidator(sdk) @@ -294,7 +294,7 @@ def test_validate_batch_coverage() -> None: def test_async_validate_batch_coverage() -> None: - """TODO: Add docstring.""" + """Test that async validate batch coverage.""" var = Variable(variable_name="age", variable_type="integer", form_id=1, form_key="F1") sdk = _build_sdk(var, async_mode=True) validator = AsyncSchemaValidator(sdk) @@ -309,7 +309,7 @@ def test_async_validate_batch_coverage() -> None: def test_schema_cache_forms_property() -> None: - """TODO: Add docstring.""" + """Test that schema cache forms property.""" from imednet.validation.cache import SchemaCache var = Variable(variable_name="age", variable_type="integer", form_id=1, form_key="F1") @@ -321,7 +321,7 @@ def test_schema_cache_forms_property() -> None: def test_base_schema_cache_refresh() -> None: - """TODO: Add docstring.""" + """Test that base schema cache refresh.""" from unittest.mock import MagicMock from imednet.validation.cache import SchemaCache @@ -340,7 +340,7 @@ def test_base_schema_cache_refresh() -> None: @pytest.mark.asyncio async def test_base_schema_cache_async_refresh() -> None: - """TODO: Add docstring.""" + """Test that base schema cache async refresh asynchronously.""" from unittest.mock import AsyncMock, MagicMock from imednet.validation.cache import AsyncSchemaCache @@ -352,7 +352,7 @@ async def test_base_schema_cache_async_refresh() -> None: variables = MagicMock() async def mock_async_list(*args, **kwargs): - """TODO: Add docstring.""" + """Helper function to mock async list.""" yield var variables.async_list = MagicMock(side_effect=mock_async_list) diff --git a/tests/unit/test_sdk_async.py b/tests/unit/test_sdk_async.py index df95e42a..6a0c5df0 100644 --- a/tests/unit/test_sdk_async.py +++ b/tests/unit/test_sdk_async.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for sdk async.""" import pytest @@ -7,7 +7,7 @@ def _create_async_sdk() -> sdk_mod.AsyncImednetSDK: - """TODO: Add docstring.""" + """Helper function to create async sdk.""" return sdk_mod.AsyncImednetSDK( api_key="key", security_key="secret", @@ -16,18 +16,18 @@ def _create_async_sdk() -> sdk_mod.AsyncImednetSDK: def test_async_sdk_initializes_async_client() -> None: - """TODO: Add docstring.""" + """Test that async sdk initializes async client.""" sdk = _create_async_sdk() assert isinstance(sdk._async_client, AsyncClient) def test_async_sdk_is_not_subclass_of_sync_sdk() -> None: - """TODO: Add docstring.""" + """Test that async sdk is not subclass of sync sdk.""" assert not issubclass(sdk_mod.AsyncImednetSDK, sdk_mod.ImednetSDK) def test_sync_and_async_endpoints_expose_strict_method_surfaces() -> None: - """TODO: Add docstring.""" + """Test that sync and async endpoints expose strict method surfaces.""" sync_sdk = sdk_mod.ImednetSDK( api_key="key", security_key="secret", @@ -48,11 +48,11 @@ def test_sync_and_async_endpoints_expose_strict_method_surfaces() -> None: @pytest.mark.asyncio async def test_async_context_management(monkeypatch) -> None: - """TODO: Add docstring.""" + """Test that async context management asynchronously.""" called = {"close": False} async def fake_aclose(self) -> None: - """TODO: Add docstring.""" + """Helper function to fake aclose.""" called["close"] = True monkeypatch.setattr(AsyncClient, "aclose", fake_aclose) @@ -65,12 +65,12 @@ async def fake_aclose(self) -> None: @pytest.mark.asyncio async def test_convenience_methods_delegate_to_endpoints_async(monkeypatch) -> None: - """TODO: Add docstring.""" + """Test that convenience methods delegate to endpoints async asynchronously.""" sdk = _create_async_sdk() calls = {} async def fake_async_studies_list(**kw): - """TODO: Add docstring.""" + """Helper function to fake async studies list.""" calls["studies"] = kw return ["STUDY"] diff --git a/tests/unit/test_sdk_context.py b/tests/unit/test_sdk_context.py index 5d1d83f1..4ddf7c9d 100644 --- a/tests/unit/test_sdk_context.py +++ b/tests/unit/test_sdk_context.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for sdk context.""" import asyncio from unittest.mock import AsyncMock, MagicMock, patch @@ -15,13 +15,13 @@ # Mock environment variables to avoid API key requirement issues @pytest.fixture(autouse=True) def mock_env(monkeypatch): - """TODO: Add docstring.""" + """Helper function to mock env.""" monkeypatch.setenv("IMEDNET_API_KEY", "test_api_key") monkeypatch.setenv("IMEDNET_SECURITY_KEY", "test_sec_key") def test_sync_context_manager(): - """TODO: Add docstring.""" + """Test that sync context manager.""" client_mock = MagicMock(spec=Client) with ImednetSDK(client=client_mock) as sdk: @@ -32,7 +32,7 @@ def test_sync_context_manager(): @pytest.mark.asyncio async def test_async_context_manager(): - """TODO: Add docstring.""" + """Test that async context manager asynchronously.""" async_client_mock = MagicMock(spec=AsyncClient) async_client_mock.aclose = AsyncMock() @@ -44,7 +44,7 @@ async def test_async_context_manager(): def test_close_without_async_client(): - """TODO: Add docstring.""" + """Test that close without async client.""" client_mock = MagicMock(spec=Client) sdk = ImednetSDK(client=client_mock) sdk.close() @@ -52,7 +52,7 @@ def test_close_without_async_client(): def test_sync_sdk_does_not_create_async_client(): - """TODO: Add docstring.""" + """Test that sync sdk does not create async client.""" client_mock = MagicMock(spec=Client) sdk = ImednetSDK(client=client_mock) assert not hasattr(sdk, "_async_client") @@ -72,7 +72,7 @@ def test_async_sdk_close_raises_type_error(): def test_async_sdk_sync_context_manager_raises_type_error(): - """TODO: Add docstring.""" + """Test that async sdk sync context manager raises type error.""" with patch("imednet.sdk.load_config"): with patch("imednet.sdk.ClientFactory.create_client", return_value=MagicMock(spec=Client)): with patch( @@ -100,7 +100,7 @@ def test_async_sdk_exit_raises_type_error(): @pytest.mark.asyncio async def test_aclose(): - """TODO: Add docstring.""" + """Test that aclose asynchronously.""" async_client_mock = MagicMock(spec=AsyncClient) async_client_mock.aclose = AsyncMock() @@ -113,7 +113,7 @@ async def test_aclose(): @pytest.mark.asyncio async def test_aclose_without_async_client(): - """TODO: Add docstring.""" + """Test that aclose without async client asynchronously.""" client_mock = MagicMock(spec=Client) sdk = ImednetSDK(client=client_mock) @@ -125,7 +125,7 @@ async def test_aclose_without_async_client(): def test_study_context_manager_sets_and_resets_context(): - """TODO: Add docstring.""" + """Test that study context manager sets and resets context.""" client_mock = MagicMock(spec=Client) sdk = ImednetSDK(client=client_mock) @@ -137,7 +137,7 @@ def test_study_context_manager_sets_and_resets_context(): def test_study_context_manager_resets_on_exception(): - """TODO: Add docstring.""" + """Test that study context manager resets on exception.""" client_mock = MagicMock(spec=Client) sdk = ImednetSDK(client=client_mock) @@ -150,7 +150,7 @@ def test_study_context_manager_resets_on_exception(): def test_default_study_mutation_methods_removed(): - """TODO: Add docstring.""" + """Test that default study mutation methods removed.""" client_mock = MagicMock(spec=Client) sdk = ImednetSDK(client=client_mock) assert not hasattr(sdk, "set_default_study") @@ -158,7 +158,7 @@ def test_default_study_mutation_methods_removed(): def test_retry_policy_property(): - """TODO: Add docstring.""" + """Test that retry policy property.""" async_client_mock = MagicMock(spec=AsyncClient) sdk = AsyncImednetSDK(async_client=async_client_mock) @@ -175,7 +175,7 @@ def test_retry_policy_property(): def test_retry_policy_property_without_async_client(): - """TODO: Add docstring.""" + """Test that retry policy property without async client.""" client_mock = MagicMock(spec=Client) sdk = ImednetSDK(client=client_mock) @@ -188,11 +188,11 @@ def test_retry_policy_property_without_async_client(): @pytest.mark.asyncio async def test_study_context_isolation_on_shared_sdk_instance(): - """TODO: Add docstring.""" + """Test that study context isolation on shared sdk instance asynchronously.""" shared_sdk = ImednetSDK(client=MagicMock(spec=Client)) async def worker(study_key: str, delay: float) -> str: - """TODO: Add docstring.""" + """Helper function to worker.""" with shared_sdk.study_context(study_key): await asyncio.sleep(delay) return get_current_study() @@ -208,7 +208,7 @@ async def worker(study_key: str, delay: float) -> str: @pytest.mark.asyncio async def test_async_sdk_aenter_aexit(): - """TODO: Add docstring.""" + """Test that async sdk aenter aexit asynchronously.""" async_client_mock = MagicMock(spec=AsyncClient) async_client_mock.aclose = AsyncMock() @@ -221,7 +221,7 @@ async def test_async_sdk_aenter_aexit(): def test_async_sdk_sync_init(): - """TODO: Add docstring.""" + """Test that async sdk sync init.""" async_client_mock = MagicMock(spec=AsyncClient) with patch("imednet.sdk.load_config"): diff --git a/tests/unit/test_sdk_convenience_async.py b/tests/unit/test_sdk_convenience_async.py index ef786f91..452e00d9 100644 --- a/tests/unit/test_sdk_convenience_async.py +++ b/tests/unit/test_sdk_convenience_async.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for sdk convenience async.""" import pytest @@ -7,74 +7,74 @@ @pytest.mark.asyncio async def test_async_convenience_methods_delegate_to_endpoints(monkeypatch) -> None: - """TODO: Add docstring.""" + """Test that async convenience methods delegate to endpoints asynchronously.""" sdk = sdk_mod.AsyncImednetSDK( api_key="key", security_key="secret", base_url="https://example.com" ) calls = {} async def fake_studies_async_list(study_key=None, **kw): - """TODO: Add docstring.""" + """Helper function to fake studies async list.""" calls["studies"] = kw return ["STUDY"] async def fake_records_async_list(study_key, record_data_filter=None, **kw): - """TODO: Add docstring.""" + """Helper function to fake records async list.""" calls["records"] = (study_key, record_data_filter, kw) return ["REC"] async def fake_sites_async_list(study_key, **kw): - """TODO: Add docstring.""" + """Helper function to fake sites async list.""" calls["sites"] = (study_key, kw) return ["SITE"] async def fake_subjects_async_list(study_key, **kw): - """TODO: Add docstring.""" + """Helper function to fake subjects async list.""" calls["subjects"] = (study_key, kw) return ["SUB"] async def fake_forms_async_list(study_key, **kw): - """TODO: Add docstring.""" + """Helper function to fake forms async list.""" calls["forms"] = (study_key, kw) return ["FORM"] async def fake_intervals_async_list(study_key, **kw): - """TODO: Add docstring.""" + """Helper function to fake intervals async list.""" calls["intervals"] = (study_key, kw) return ["INT"] async def fake_variables_async_list(study_key, **kw): - """TODO: Add docstring.""" + """Helper function to fake variables async list.""" calls["variables"] = (study_key, kw) return ["VAR"] async def fake_visits_async_list(study_key, **kw): - """TODO: Add docstring.""" + """Helper function to fake visits async list.""" calls["visits"] = (study_key, kw) return ["VIS"] async def fake_codings_async_list(study_key, **kw): - """TODO: Add docstring.""" + """Helper function to fake codings async list.""" calls["codings"] = (study_key, kw) return ["COD"] async def fake_queries_async_list(study_key, **kw): - """TODO: Add docstring.""" + """Helper function to fake queries async list.""" calls["queries"] = (study_key, kw) return ["QUERY"] async def fake_record_revisions_async_list(study_key, **kw): - """TODO: Add docstring.""" + """Helper function to fake record revisions async list.""" calls["record_revisions"] = (study_key, kw) return ["REV"] async def fake_users_async_list(study_key, include_inactive=False): - """TODO: Add docstring.""" + """Helper function to fake users async list.""" calls["users"] = (study_key, include_inactive) return ["USER"] async def fake_async_get_job(study_key, batch_id): - """TODO: Add docstring.""" + """Helper function to fake async get job.""" calls["job"] = (study_key, batch_id) return "JOBOBJ" @@ -123,21 +123,21 @@ async def fake_async_get_job(study_key, batch_id): @pytest.mark.asyncio async def test_async_poll_job_convenience(monkeypatch) -> None: - """TODO: Add docstring.""" + """Test that async poll job convenience asynchronously.""" sdk = sdk_mod.AsyncImednetSDK( api_key="key", security_key="secret", base_url="https://example.com" ) calls = {} class FakePoller: - """TODO: Add docstring.""" + """Test suite for FakePoller.""" def __init__(self, get_func, **kwargs): - """TODO: Add docstring.""" + """Initialize the test object.""" calls["init"] = get_func async def run(self, study_key, batch_id, interval, timeout): - """TODO: Add docstring.""" + """Helper function to run.""" calls["run"] = (study_key, batch_id, interval, timeout) return "JOBOBJ" diff --git a/tests/unit/test_sdk_credentials.py b/tests/unit/test_sdk_credentials.py index 12980302..d1c2b262 100644 --- a/tests/unit/test_sdk_credentials.py +++ b/tests/unit/test_sdk_credentials.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for sdk credentials.""" import pytest @@ -7,7 +7,7 @@ def test_missing_both_keys(monkeypatch) -> None: - """TODO: Add docstring.""" + """Test that missing both keys.""" monkeypatch.setattr( "imednet.sdk.load_config", lambda **_: Config(api_key="", security_key="", base_url=None), @@ -17,7 +17,7 @@ def test_missing_both_keys(monkeypatch) -> None: def test_missing_security_key(monkeypatch) -> None: - """TODO: Add docstring.""" + """Test that missing security key.""" monkeypatch.setattr( "imednet.sdk.load_config", lambda **_: Config(api_key="key", security_key="", base_url=None), @@ -27,7 +27,7 @@ def test_missing_security_key(monkeypatch) -> None: def test_missing_api_key(monkeypatch) -> None: - """TODO: Add docstring.""" + """Test that missing api key.""" monkeypatch.setattr( "imednet.sdk.load_config", lambda **_: Config(api_key="", security_key="sec", base_url=None), @@ -37,7 +37,7 @@ def test_missing_api_key(monkeypatch) -> None: def test_initialization_succeeds(monkeypatch) -> None: - """TODO: Add docstring.""" + """Test that initialization succeeds.""" monkeypatch.setattr( "imednet.sdk.load_config", lambda **_: Config(api_key="key", security_key="sec", base_url=None), diff --git a/tests/unit/test_sdk_entrypoint.py b/tests/unit/test_sdk_entrypoint.py index b6edcb8a..c8ae39ba 100644 --- a/tests/unit/test_sdk_entrypoint.py +++ b/tests/unit/test_sdk_entrypoint.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for sdk entrypoint.""" from typing import Any, Callable @@ -36,17 +36,17 @@ class _FakeEntryPoint: def __init__( self, loader: Callable[[], Any], value: str = "tests.fake_plugin:Workflows" ) -> None: - """TODO: Add docstring.""" + """Initialize the test object.""" self._loader = loader self.value = value def load(self): - """TODO: Add docstring.""" + """Helper function to load.""" return self._loader() def test_top_level_orchestration_exports() -> None: - """TODO: Add docstring.""" + """Test that top level orchestration exports.""" from imednet import FilterConflictError as TopLevelFilterConflictError from imednet import MultiStudyOrchestrator as TopLevelMultiStudyOrchestrator from imednet import OrchestratorError as TopLevelOrchestratorError @@ -61,18 +61,18 @@ def test_top_level_orchestration_exports() -> None: def test_sdk_workflows_uses_entry_point_discovery(monkeypatch) -> None: - """TODO: Add docstring.""" + """Test that sdk workflows uses entry point discovery.""" loaded = {"called": False} def load_workflows(): - """TODO: Add docstring.""" + """Helper function to load workflows.""" loaded["called"] = True class FakeWorkflows: - """TODO: Add docstring.""" + """Test suite for FakeWorkflows.""" def __init__(self, sdk_instance): - """TODO: Add docstring.""" + """Initialize the test object.""" self.sdk_instance = sdk_instance return FakeWorkflows @@ -97,10 +97,10 @@ def __init__(self, sdk_instance): def test_sdk_workflows_invalid_entry_point_load_raises_import_error( monkeypatch, exception_class ) -> None: - """TODO: Add docstring.""" + """Test that sdk workflows invalid entry point load raises import error.""" def failing_loader(): - """TODO: Add docstring.""" + """Helper function to failing loader.""" raise exception_class("boom") monkeypatch.setattr( @@ -118,7 +118,7 @@ def failing_loader(): def test_sdk_workflows_entry_point_must_be_callable(monkeypatch) -> None: - """TODO: Add docstring.""" + """Test that sdk workflows entry point must be callable.""" monkeypatch.setattr( sdk_mod, "entry_points", @@ -134,7 +134,7 @@ def test_sdk_workflows_entry_point_must_be_callable(monkeypatch) -> None: def test_sdk_workflows_multiple_plugins_raises_import_error(monkeypatch) -> None: - """TODO: Add docstring.""" + """Test that sdk workflows multiple plugins raises import error.""" monkeypatch.setattr( sdk_mod, "entry_points", @@ -150,13 +150,13 @@ def test_sdk_workflows_multiple_plugins_raises_import_error(monkeypatch) -> None def test_sdk_workflows_instantiation_failure_raises_import_error(monkeypatch) -> None: - """TODO: Add docstring.""" + """Test that sdk workflows instantiation failure raises import error.""" class BrokenWorkflows: - """TODO: Add docstring.""" + """Test suite for BrokenWorkflows.""" def __init__(self, sdk_instance): - """TODO: Add docstring.""" + """Initialize the test object.""" raise TypeError("broken") monkeypatch.setattr( @@ -174,7 +174,7 @@ def __init__(self, sdk_instance): def _create_sdk() -> sdk_mod.ImednetSDK: - """TODO: Add docstring.""" + """Helper function to create sdk.""" return sdk_mod.ImednetSDK( api_key="key", security_key="secret", @@ -183,7 +183,7 @@ def _create_sdk() -> sdk_mod.ImednetSDK: def test_env_var_credentials(monkeypatch) -> None: - """TODO: Add docstring.""" + """Test that env var credentials.""" monkeypatch.setenv("IMEDNET_API_KEY", "env_key") monkeypatch.setenv("IMEDNET_SECURITY_KEY", "env_secret") @@ -193,7 +193,7 @@ def test_env_var_credentials(monkeypatch) -> None: def test_sdk_initialization_wires_endpoints_and_workflows() -> None: - """TODO: Add docstring.""" + """Test that sdk initialization wires endpoints and workflows.""" sdk = _create_sdk() assert isinstance(sdk._client, Client) @@ -225,11 +225,11 @@ def test_sdk_initialization_wires_endpoints_and_workflows() -> None: def test_context_management_closes_client(monkeypatch) -> None: - """TODO: Add docstring.""" + """Test that context management closes client.""" called = {"close": False} def fake_close(self) -> None: - """TODO: Add docstring.""" + """Helper function to fake close.""" called["close"] = True monkeypatch.setattr(Client, "close", fake_close) @@ -241,77 +241,77 @@ def fake_close(self) -> None: def test_convenience_methods_delegate_to_endpoints(monkeypatch) -> None: - """TODO: Add docstring.""" + """Test that convenience methods delegate to endpoints.""" sdk = _create_sdk() calls = {} def fake_studies_list(study_key=None, **kw): - """TODO: Add docstring.""" + """Helper function to fake studies list.""" calls["studies"] = kw return ["STUDY"] def fake_records_list(study_key, record_data_filter=None, **kw): - """TODO: Add docstring.""" + """Helper function to fake records list.""" calls["records"] = (study_key, record_data_filter, kw) return ["REC"] def fake_sites_list(study_key, **kw): - """TODO: Add docstring.""" + """Helper function to fake sites list.""" calls["sites"] = (study_key, kw) return ["SITE"] def fake_subjects_list(study_key, **kw): - """TODO: Add docstring.""" + """Helper function to fake subjects list.""" calls["subjects"] = (study_key, kw) return ["SUB"] def fake_create(study_key, records_data, email_notify=None, schema=None): - """TODO: Add docstring.""" + """Helper function to fake create.""" calls["create"] = (study_key, records_data, email_notify) return "JOB" def fake_forms_list(study_key, **kw): - """TODO: Add docstring.""" + """Helper function to fake forms list.""" calls["forms"] = (study_key, kw) return ["FORM"] def fake_intervals_list(study_key, **kw): - """TODO: Add docstring.""" + """Helper function to fake intervals list.""" calls["intervals"] = (study_key, kw) return ["INT"] def fake_variables_list(study_key, **kw): - """TODO: Add docstring.""" + """Helper function to fake variables list.""" calls["variables"] = (study_key, kw) return ["VAR"] def fake_visits_list(study_key, **kw): - """TODO: Add docstring.""" + """Helper function to fake visits list.""" calls["visits"] = (study_key, kw) return ["VIS"] def fake_codings_list(study_key, **kw): - """TODO: Add docstring.""" + """Helper function to fake codings list.""" calls["codings"] = (study_key, kw) return ["COD"] def fake_queries_list(study_key, **kw): - """TODO: Add docstring.""" + """Helper function to fake queries list.""" calls["queries"] = (study_key, kw) return ["QUERY"] def fake_record_revisions_list(study_key, **kw): - """TODO: Add docstring.""" + """Helper function to fake record revisions list.""" calls["record_revisions"] = (study_key, kw) return ["REV"] def fake_users_list(study_key, include_inactive=False): - """TODO: Add docstring.""" + """Helper function to fake users list.""" calls["users"] = (study_key, include_inactive) return ["USER"] def fake_get_job(study_key, batch_id): - """TODO: Add docstring.""" + """Helper function to fake get job.""" calls["job"] = (study_key, batch_id) return "JOBOBJ" @@ -362,19 +362,19 @@ def fake_get_job(study_key, batch_id): def test_poll_job_convenience_sync(monkeypatch) -> None: - """TODO: Add docstring.""" + """Test that poll job convenience sync.""" sdk = _create_sdk() calls = {} class FakePoller: - """TODO: Add docstring.""" + """Test suite for FakePoller.""" def __init__(self, get_func, **kwargs): - """TODO: Add docstring.""" + """Initialize the test object.""" calls["init"] = get_func def run(self, study_key, batch_id, interval, timeout): - """TODO: Add docstring.""" + """Helper function to run.""" calls["run"] = (study_key, batch_id, interval, timeout) return "JOBOBJ" diff --git a/tests/unit/test_sdk_retry_policy.py b/tests/unit/test_sdk_retry_policy.py index d8f89ef0..27efa154 100644 --- a/tests/unit/test_sdk_retry_policy.py +++ b/tests/unit/test_sdk_retry_policy.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for sdk retry policy.""" import httpx import pytest @@ -10,20 +10,20 @@ class NamedPolicy(RetryPolicy): - """TODO: Add docstring.""" + """Test suite for NamedPolicy.""" def __init__(self, name: str) -> None: - """TODO: Add docstring.""" + """Initialize the test object.""" self.name = name def should_retry(self, state: RetryState) -> bool: # pragma: no cover - simple - """TODO: Add docstring.""" + """Helper function to should retry.""" return False @pytest.fixture() def async_sdk() -> AsyncImednetSDK: - """TODO: Add docstring.""" + """Helper function to async sdk.""" return AsyncImednetSDK( api_key="key", security_key="secret", @@ -33,13 +33,13 @@ def async_sdk() -> AsyncImednetSDK: @pytest.fixture def respx_mock_external(): - """TODO: Add docstring.""" + """Helper function to respx mock external.""" with respx.mock(base_url="https://example.com") as mock: yield mock def test_initial_retry_policy_propagates_to_async_client() -> None: - """TODO: Add docstring.""" + """Test that initial retry policy propagates to async client.""" policy = NamedPolicy("init") sdk = AsyncImednetSDK( api_key="key", @@ -52,7 +52,7 @@ def test_initial_retry_policy_propagates_to_async_client() -> None: def test_retry_policy_propagates_to_async_client(async_sdk: AsyncImednetSDK) -> None: - """TODO: Add docstring.""" + """Test that retry policy propagates to async client.""" async_policy = NamedPolicy("async") async_sdk._async_client.retry_policy = async_policy diff --git a/tests/unit/test_security_config.py b/tests/unit/test_security_config.py index 74d96416..5a7f6135 100644 --- a/tests/unit/test_security_config.py +++ b/tests/unit/test_security_config.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for security config.""" from imednet.config import Config diff --git a/tests/unit/test_security_path_traversal.py b/tests/unit/test_security_path_traversal.py index 2d06652c..10b5d3a0 100644 --- a/tests/unit/test_security_path_traversal.py +++ b/tests/unit/test_security_path_traversal.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for security path traversal.""" from unittest.mock import MagicMock @@ -10,20 +10,20 @@ class MockModel(JsonModel): - """TODO: Add docstring.""" + """Test suite for MockModel.""" pass class MockEndpoint(EdcEndpointMixin, GenericEndpoint[MockModel]): - """TODO: Add docstring.""" + """Test suite for MockEndpoint.""" MODEL = MockModel PATH = "/test" def test_build_path_security(): - """TODO: Add docstring.""" + """Test that build path security.""" client = MagicMock(spec=Client) ctx = Context() endpoint = MockEndpoint(client, ctx) diff --git a/tests/unit/test_smoke.py b/tests/unit/test_smoke.py index 87b376b8..717252fb 100644 --- a/tests/unit/test_smoke.py +++ b/tests/unit/test_smoke.py @@ -1,15 +1,15 @@ -"""TODO: Add docstring.""" +"""Unit tests for smoke.""" def test_smoke_import() -> None: - """TODO: Add docstring.""" + """Test that smoke import.""" import imednet assert hasattr(imednet, "ImednetSDK") def test_orchestration_exports() -> None: - """TODO: Add docstring.""" + """Test that orchestration exports.""" from imednet import ( FilterConflictError, MultiStudyOrchestrator, @@ -26,7 +26,7 @@ def test_orchestration_exports() -> None: def test_role_import() -> None: - """TODO: Add docstring.""" + """Test that role import.""" from imednet.models import Role assert Role.__name__ == "Role" diff --git a/tests/unit/test_state_ledger.py b/tests/unit/test_state_ledger.py index 3f0f1e8f..66c8c55a 100644 --- a/tests/unit/test_state_ledger.py +++ b/tests/unit/test_state_ledger.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for state ledger.""" from __future__ import annotations @@ -14,7 +14,7 @@ def test_state_ledger_read_write(tmp_path) -> None: - """TODO: Add docstring.""" + """Test that state ledger read write.""" ledger_file = tmp_path / "ledger.json" ledger = ExtractionStateLedger(str(ledger_file)) @@ -53,7 +53,7 @@ def test_state_ledger_read_write(tmp_path) -> None: def test_state_ledger_transaction_success(tmp_path) -> None: - """TODO: Add docstring.""" + """Test that state ledger transaction success.""" ledger_file = tmp_path / "ledger.json" ledger = ExtractionStateLedger(str(ledger_file)) fallback_ts = datetime(2026, 5, 22, 10, 0, 0, tzinfo=timezone.utc) @@ -78,7 +78,7 @@ def test_state_ledger_transaction_success(tmp_path) -> None: def test_state_ledger_transaction_failure(tmp_path) -> None: - """TODO: Add docstring.""" + """Test that state ledger transaction failure.""" ledger_file = tmp_path / "ledger.json" ledger = ExtractionStateLedger(str(ledger_file)) fallback_ts = datetime(2026, 5, 22, 10, 0, 0, tzinfo=timezone.utc) @@ -99,7 +99,7 @@ def test_state_ledger_transaction_failure(tmp_path) -> None: def test_state_ledger_atomic_write_failure(tmp_path, monkeypatch) -> None: - """TODO: Add docstring.""" + """Test that state ledger atomic write failure.""" ledger_file = tmp_path / "ledger.json" ledger = ExtractionStateLedger(str(ledger_file)) @@ -109,7 +109,7 @@ def test_state_ledger_atomic_write_failure(tmp_path, monkeypatch) -> None: # Mock os.replace to raise an error def mock_replace(src, dst): - """TODO: Add docstring.""" + """Helper function to mock replace.""" raise OSError("Disk full") monkeypatch.setattr(os, "replace", mock_replace) @@ -129,7 +129,7 @@ def mock_replace(src, dst): reason="flock not available on this platform (no fcntl)", ) def test_state_ledger_flock_concurrency(tmp_path) -> None: - """TODO: Add docstring.""" + """Test that state ledger flock concurrency.""" ledger_file = tmp_path / "ledger.json" ledger = ExtractionStateLedger(str(ledger_file)) @@ -142,7 +142,7 @@ def test_state_ledger_flock_concurrency(tmp_path) -> None: thread_done = threading.Event() def locking_thread(): - """TODO: Add docstring.""" + """Helper function to locking thread.""" with ledger._lock(): lock_acquired.set() release_lock.wait() @@ -163,7 +163,7 @@ def locking_thread(): lock_acquired_in_t2 = threading.Event() def second_thread(): - """TODO: Add docstring.""" + """Helper function to second thread.""" with ledger._lock(): lock_acquired_in_t2.set() @@ -184,7 +184,7 @@ def second_thread(): def test_delete_entry_removes_whole_study(tmp_path) -> None: - """TODO: Add docstring.""" + """Test that delete entry removes whole study.""" ledger_file = tmp_path / "ledger.json" ledger = ExtractionStateLedger(str(ledger_file)) ts = datetime(2026, 5, 22, 12, 0, 0, tzinfo=timezone.utc) @@ -200,7 +200,7 @@ def test_delete_entry_removes_whole_study(tmp_path) -> None: def test_delete_entry_removes_specific_stream(tmp_path) -> None: - """TODO: Add docstring.""" + """Test that delete entry removes specific stream.""" ledger_file = tmp_path / "ledger.json" ledger = ExtractionStateLedger(str(ledger_file)) ts = datetime(2026, 5, 22, 12, 0, 0, tzinfo=timezone.utc) @@ -217,7 +217,7 @@ def test_delete_entry_removes_specific_stream(tmp_path) -> None: def test_delete_entry_returns_false_when_study_not_found(tmp_path) -> None: - """TODO: Add docstring.""" + """Test that delete entry returns false when study not found.""" ledger_file = tmp_path / "ledger.json" ledger = ExtractionStateLedger(str(ledger_file)) @@ -227,7 +227,7 @@ def test_delete_entry_returns_false_when_study_not_found(tmp_path) -> None: def test_delete_entry_returns_false_when_stream_not_found(tmp_path) -> None: - """TODO: Add docstring.""" + """Test that delete entry returns false when stream not found.""" ledger_file = tmp_path / "ledger.json" ledger = ExtractionStateLedger(str(ledger_file)) ts = datetime(2026, 5, 22, 12, 0, 0, tzinfo=timezone.utc) @@ -241,7 +241,7 @@ def test_delete_entry_returns_false_when_stream_not_found(tmp_path) -> None: def test_corrupted_ledger_recovery(tmp_path) -> None: - """TODO: Add docstring.""" + """Test that corrupted ledger recovery.""" ledger_file = tmp_path / "ledger.json" # Write garbage content to file with open(ledger_file, "w") as f: diff --git a/tests/unit/test_streamlit_plugin_scaffold.py b/tests/unit/test_streamlit_plugin_scaffold.py index 5fd4d0e9..c2204870 100644 --- a/tests/unit/test_streamlit_plugin_scaffold.py +++ b/tests/unit/test_streamlit_plugin_scaffold.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for streamlit plugin scaffold.""" from __future__ import annotations @@ -20,36 +20,36 @@ def _component_palette() -> list[str]: - """TODO: Add docstring.""" + """Helper function to component palette.""" return runpy.run_path(str(PACKAGE_ROOT / "components" / "charts.py"))["PALETTE"] class _FakeNavigation: - """TODO: Add docstring.""" + """Test suite for FakeNavigation.""" def __init__(self, pages: list[dict[str, Any]]) -> None: - """TODO: Add docstring.""" + """Initialize the test object.""" self.pages = pages self.ran = False def run(self) -> None: - """TODO: Add docstring.""" + """Helper function to run.""" self.ran = True class _FakeSidebar: - """TODO: Add docstring.""" + """Test suite for FakeSidebar.""" def toggle(self, label: str, value: bool = False, on_change: Any = None, **kwargs: Any) -> bool: - """TODO: Add docstring.""" + """Helper function to toggle.""" return value class _FakeStreamlit: - """TODO: Add docstring.""" + """Test suite for FakeStreamlit.""" def __init__(self) -> None: - """TODO: Add docstring.""" + """Initialize the test object.""" self.page_config: dict[str, Any] | None = None self.navigation_calls: list[_FakeNavigation] = [] self.session_state: dict[str, Any] = {} @@ -57,7 +57,7 @@ def __init__(self) -> None: self.sidebar = _FakeSidebar() def set_page_config(self, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to set page config.""" self.page_config = kwargs def page( @@ -68,7 +68,7 @@ def page( icon: str, default: bool = False, ) -> dict[str, Any]: - """TODO: Add docstring.""" + """Helper function to page.""" return { "path": path, "title": title, @@ -77,49 +77,49 @@ def page( } def navigation(self, pages: list[dict[str, Any]]) -> _FakeNavigation: - """TODO: Add docstring.""" + """Helper function to navigation.""" nav = _FakeNavigation(pages) self.navigation_calls.append(nav) return nav def markdown(self, body: str, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to markdown.""" pass def altair_chart(self, chart: Any, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to altair chart.""" pass def error(self, body: Any, *args: Any, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to error.""" pass def exception(self, exception: Any, *args: Any, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to exception.""" pass def warning(self, body: Any, *args: Any, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to warning.""" pass def info(self, body: Any, *args: Any, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to info.""" pass def expander(self, label: str, **kwargs: Any) -> _FakeContextManager: - """TODO: Add docstring.""" + """Helper function to expander.""" return _FakeContextManager() def dataframe(self, data: Any, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to dataframe.""" pass class _FakePageStreamlit: - """TODO: Add docstring.""" + """Test suite for FakePageStreamlit.""" def __init__(self, *, connected: bool) -> None: - """TODO: Add docstring.""" + """Initialize the test object.""" self.session_state: dict[str, Any] = {"_imednet_connected": connected} self.titles: list[str] = [] self.infos: list[str] = [] @@ -127,19 +127,19 @@ def __init__(self, *, connected: bool) -> None: self.markdowns: list[str] = [] def title(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to title.""" self.titles.append(value) def info(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to info.""" self.infos.append(value) def success(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to success.""" self.successes.append(value) def markdown(self, value: str) -> None: - """TODO: Add docstring.""" + """Helper function to markdown.""" self.markdowns.append(value) @@ -147,11 +147,11 @@ class _FakeContextManager: """A no-op context manager (used for st.sidebar and column objects).""" def __enter__(self) -> "_FakeContextManager": - """TODO: Add docstring.""" + """Helper function to enter .""" return self def __exit__(self, *args: Any) -> None: - """TODO: Add docstring.""" + """Helper function to exit .""" pass @@ -159,13 +159,13 @@ class _FakeCacheDataDecorator: """Fake st.cache_data — identity decorator, clear() is a no-op.""" def __call__(self, func: Any = None, **kwargs: Any) -> Any: - """TODO: Add docstring.""" + """Helper function to call .""" if func is not None: return func return lambda f: f def clear(self) -> None: - """TODO: Add docstring.""" + """Helper function to clear.""" pass @@ -173,7 +173,7 @@ class _FakeDashboardStreamlit(_FakePageStreamlit): """Extended fake Streamlit for dashboard pages with charts, filters, and exports.""" def __init__(self, *, connected: bool) -> None: - """TODO: Add docstring.""" + """Initialize the test object.""" super().__init__(connected=connected) self.cache_data = _FakeCacheDataDecorator() self.sidebar = _FakeContextManager() @@ -187,55 +187,55 @@ def __init__(self, *, connected: bool) -> None: # stubs that return sensible defaults so the page runs end-to-end def button(self, label: str, **kwargs: Any) -> bool: - """TODO: Add docstring.""" + """Helper function to button.""" return False def warning(self, value: str, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to warning.""" self.warnings.append(value) def subheader(self, value: str, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to subheader.""" self.subheaders.append(value) def altair_chart(self, chart: Any, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to altair chart.""" self.altair_charts.append(chart) def columns(self, spec: Any) -> list[Any]: - """TODO: Add docstring.""" + """Helper function to columns.""" count = spec if isinstance(spec, int) else len(spec) return [_FakeContextManager() for _ in range(count)] def multiselect(self, label: str, options: Any, **kwargs: Any) -> list[Any]: - """TODO: Add docstring.""" + """Helper function to multiselect.""" if label in self.multiselect_values: return self.multiselect_values[label] return list(kwargs.get("default", [])) def date_input(self, label: str, **kwargs: Any) -> list[Any]: - """TODO: Add docstring.""" + """Helper function to date input.""" val = kwargs.get("value", []) return list(val) if hasattr(val, "__iter__") else [] def rerun(self) -> None: - """TODO: Add docstring.""" + """Helper function to rerun.""" pass def text_input(self, label: str, **kwargs: Any) -> str: - """TODO: Add docstring.""" + """Helper function to text input.""" return "" def dataframe(self, df: Any, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to dataframe.""" self.dataframes.append(df) def download_button(self, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to download button.""" self.download_calls.append(kwargs) def metric(self, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to metric.""" self.metric_calls.append(kwargs) @@ -245,35 +245,35 @@ def _make_fake_components_module(fake_st: _FakeDashboardStreamlit) -> ModuleType mod.PALETTE = _component_palette() # type: ignore[attr-defined] def _noop_kpi_row(metrics: list[dict[str, Any]]) -> None: - """TODO: Add docstring.""" + """Helper function to noop kpi row.""" fake_st.metric_calls.extend(metrics) def _noop_bar_chart(df: pd.DataFrame, **kwargs: Any) -> SimpleNamespace: - """TODO: Add docstring.""" + """Helper function to noop bar chart.""" return SimpleNamespace(data=df.copy(), kwargs=kwargs) def _noop_line_chart(df: pd.DataFrame, **kwargs: Any) -> SimpleNamespace: - """TODO: Add docstring.""" + """Helper function to noop line chart.""" return SimpleNamespace(data=df.copy(), kwargs=kwargs) def _noop_filterable_dataframe(df: pd.DataFrame, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to noop filterable dataframe.""" fake_st.dataframes.append(df.copy()) def _noop_csv_download_button(df: pd.DataFrame, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to noop csv download button.""" fake_st.download_calls.append({"kind": "csv", "df": df.copy(), **kwargs}) def _noop_excel_download_button(df: pd.DataFrame, **kwargs: Any) -> None: - """TODO: Add docstring.""" + """Helper function to noop excel download button.""" fake_st.download_calls.append({"kind": "excel", "df": df.copy(), **kwargs}) def _noop_top_n_with_other(df: pd.DataFrame, **kwargs: Any) -> pd.DataFrame: - """TODO: Add docstring.""" + """Helper function to noop top n with other.""" return df def _noop_paginated_slice(df: pd.DataFrame, **kwargs: Any) -> pd.DataFrame: - """TODO: Add docstring.""" + """Helper function to noop paginated slice.""" return df mod.kpi_row = _noop_kpi_row # type: ignore[attr-defined] @@ -581,7 +581,7 @@ def _run_records_page( def _expected_version() -> str: - """TODO: Add docstring.""" + """Helper function to expected version.""" pyproject_text = (PLUGIN_ROOT / "pyproject.toml").read_text(encoding="utf-8") version_match = re.search(r'^version\s*=\s*"([^"]+)"', pyproject_text, re.MULTILINE) assert version_match is not None @@ -589,7 +589,7 @@ def _expected_version() -> str: def _run_app(is_connected: bool) -> _FakeStreamlit: - """TODO: Add docstring.""" + """Helper function to run app.""" app_path = PACKAGE_ROOT / "app.py" fake_st = _FakeStreamlit() fake_streamlit_module = ModuleType("streamlit") @@ -611,7 +611,7 @@ def _run_app(is_connected: bool) -> _FakeStreamlit: fake_auth_module = ModuleType("imednet_streamlit.auth") def _render_auth_sidebar() -> bool: - """TODO: Add docstring.""" + """Helper function to render auth sidebar.""" return is_connected fake_auth_module.render_auth_sidebar = _render_auth_sidebar @@ -645,7 +645,7 @@ def _render_auth_sidebar() -> bool: def _run_page(page_name: str, *, connected: bool) -> _FakePageStreamlit: - """TODO: Add docstring.""" + """Helper function to run page.""" page_path = PACKAGE_ROOT / "pages" / page_name fake_st = _FakePageStreamlit(connected=connected) fake_streamlit_module = ModuleType("streamlit") @@ -687,7 +687,7 @@ def _run_page(page_name: str, *, connected: bool) -> _FakePageStreamlit: def test_streamlit_plugin_version() -> None: - """TODO: Add docstring.""" + """Test that streamlit plugin version.""" init_path = PACKAGE_ROOT / "__init__.py" package_spec = importlib.util.spec_from_file_location( "imednet_streamlit", init_path, submodule_search_locations=[str(PACKAGE_ROOT)] @@ -700,7 +700,7 @@ def test_streamlit_plugin_version() -> None: def test_streamlit_app_navigation_is_home_only_before_auth() -> None: - """TODO: Add docstring.""" + """Test that streamlit app navigation is home only before auth.""" fake_st = _run_app(is_connected=False) assert fake_st.page_config == { @@ -720,7 +720,7 @@ def test_streamlit_app_navigation_is_home_only_before_auth() -> None: def test_streamlit_app_navigation_includes_all_pages_after_auth() -> None: - """TODO: Add docstring.""" + """Test that streamlit app navigation includes all pages after auth.""" fake_st = _run_app(is_connected=True) assert len(fake_st.navigation_calls) == 1 @@ -743,7 +743,7 @@ def test_streamlit_app_navigation_includes_all_pages_after_auth() -> None: def test_streamlit_pages_scaffold_exists() -> None: - """TODO: Add docstring.""" + """Test that streamlit pages scaffold exists.""" pages_root = PACKAGE_ROOT / "pages" assert (pages_root / "__init__.py").is_file() @@ -759,7 +759,7 @@ def test_streamlit_pages_scaffold_exists() -> None: def test_streamlit_pages_execute_without_exceptions() -> None: - """TODO: Add docstring.""" + """Test that streamlit pages execute without exceptions.""" home_disconnected = _run_page("home.py", connected=False) assert "🏥 iMednet EDC Dashboard" in home_disconnected.titles assert home_disconnected.infos @@ -811,7 +811,7 @@ def test_sites_page_renders() -> None: def test_records_page_renders_with_filtered_metrics_and_downloads() -> None: - """TODO: Add docstring.""" + """Test that records page renders with filtered metrics and downloads.""" records = [ SimpleNamespace( record_id=1, @@ -890,7 +890,7 @@ def test_records_page_renders_with_filtered_metrics_and_downloads() -> None: def test_records_fetch_and_heatmap_helpers_handle_deleted_records_and_caps() -> None: - """TODO: Add docstring.""" + """Test that records fetch and heatmap helpers handle deleted records and caps.""" _, records_globals = _run_records_page() fetch_records = records_globals["_fetch_records"] build_heatmap_source = records_globals["_build_heatmap_source"] @@ -960,7 +960,7 @@ def test_records_fetch_and_heatmap_helpers_handle_deleted_records_and_caps() -> def test_records_page_warns_for_large_datasets() -> None: - """TODO: Add docstring.""" + """Test that records page warns for large datasets.""" large_records = [ SimpleNamespace( record_id=index, @@ -1019,7 +1019,7 @@ def _make_subject( site_name: str, enrollment_start_date: datetime.datetime | None = None, ) -> MagicMock: - """TODO: Add docstring.""" + """Helper function to make subject.""" s = MagicMock() s.subject_id = subject_id s.subject_key = f"S{subject_id:03d}" @@ -1109,6 +1109,6 @@ def test_enrollment_page_renders() -> None: def test_streamlit_plugin_has_py_typed_marker() -> None: - """TODO: Add docstring.""" + """Test that streamlit plugin has py typed marker.""" py_typed = PACKAGE_ROOT / "py.typed" assert py_typed.is_file() diff --git a/tests/unit/test_study_key_strategies.py b/tests/unit/test_study_key_strategies.py index b3304085..67585f3f 100644 --- a/tests/unit/test_study_key_strategies.py +++ b/tests/unit/test_study_key_strategies.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for study key strategies.""" from imednet.core.endpoint.strategies import ( KeepStudyKeyStrategy, @@ -8,10 +8,10 @@ class TestKeepStudyKeyStrategy: - """TODO: Add docstring.""" + """Test suite for KeepStudyKeyStrategy.""" def test_process_with_valid_key(self): - """TODO: Add docstring.""" + """Test that process with valid key.""" strategy = KeepStudyKeyStrategy() filters = {"studyKey": "study-123", "other": "val"} key, new_filters = strategy.process(filters) @@ -19,7 +19,7 @@ def test_process_with_valid_key(self): assert new_filters == filters def test_process_missing_key(self): - """TODO: Add docstring.""" + """Test that process missing key.""" strategy = KeepStudyKeyStrategy() filters = {"other": "val"} key, new_filters = strategy.process(filters) @@ -28,10 +28,10 @@ def test_process_missing_key(self): class TestPopStudyKeyStrategy: - """TODO: Add docstring.""" + """Test suite for PopStudyKeyStrategy.""" def test_process_with_valid_key(self): - """TODO: Add docstring.""" + """Test that process with valid key.""" strategy = PopStudyKeyStrategy() filters = {"studyKey": "study-123", "other": "val"} key, new_filters = strategy.process(filters) @@ -39,7 +39,7 @@ def test_process_with_valid_key(self): assert new_filters == {"other": "val"} def test_process_missing_key(self): - """TODO: Add docstring.""" + """Test that process missing key.""" strategy = PopStudyKeyStrategy() filters = {"other": "val"} key, new_filters = strategy.process(filters) @@ -48,10 +48,10 @@ def test_process_missing_key(self): class TestOptionalStudyKeyStrategy: - """TODO: Add docstring.""" + """Test suite for OptionalStudyKeyStrategy.""" def test_process_with_key(self): - """TODO: Add docstring.""" + """Test that process with key.""" strategy = OptionalStudyKeyStrategy() filters = {"studyKey": "study-123", "other": "val"} key, new_filters = strategy.process(filters) @@ -59,7 +59,7 @@ def test_process_with_key(self): assert new_filters == filters def test_process_without_key(self): - """TODO: Add docstring.""" + """Test that process without key.""" strategy = OptionalStudyKeyStrategy() filters = {"other": "val"} key, new_filters = strategy.process(filters) diff --git a/tests/unit/test_study_structure.py b/tests/unit/test_study_structure.py index f0e5b105..e7008863 100644 --- a/tests/unit/test_study_structure.py +++ b/tests/unit/test_study_structure.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for study structure.""" import asyncio from unittest.mock import AsyncMock, MagicMock @@ -13,7 +13,7 @@ @pytest.mark.parametrize("async_mode", [False, True]) def test_get_study_structure_aggregates_related_data(async_mode: bool) -> None: - """TODO: Add docstring.""" + """Test that get study structure aggregates related data.""" sdk = MagicMock() interval = Interval( interval_id=1, @@ -37,7 +37,7 @@ def test_get_study_structure_aggregates_related_data(async_mode: bool) -> None: if async_mode: async def async_mock_return(items): - """TODO: Add docstring.""" + """Helper function to async mock return.""" return items sdk.async_get_intervals = MagicMock(return_value=async_mock_return([interval])) diff --git a/tests/unit/test_sync_worker.py b/tests/unit/test_sync_worker.py index 67ac3541..41c32210 100644 --- a/tests/unit/test_sync_worker.py +++ b/tests/unit/test_sync_worker.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for sync worker.""" from __future__ import annotations @@ -9,7 +9,7 @@ def test_sync_worker_run_once_syncs_with_lock(tmp_path) -> None: - """TODO: Add docstring.""" + """Test that sync worker run once syncs with lock.""" loader = MagicMock() loader.db_path = tmp_path / "records_cache.sqlite3" loader.load_records.return_value = [MagicMock(), MagicMock()] @@ -23,7 +23,7 @@ def test_sync_worker_run_once_syncs_with_lock(tmp_path) -> None: def test_sync_worker_run_forever_stops_gracefully(tmp_path) -> None: - """TODO: Add docstring.""" + """Test that sync worker run forever stops gracefully.""" loader = MagicMock() loader.db_path = tmp_path / "records_cache.sqlite3" stop_event = Event() @@ -34,7 +34,7 @@ def test_sync_worker_run_forever_stops_gracefully(tmp_path) -> None: ) def _stop_after_first_cycle(*args, **kwargs) -> list[MagicMock]: - """TODO: Add docstring.""" + """Helper function to stop after first cycle.""" stop_event.set() return [] diff --git a/tests/unit/test_transport_contract.py b/tests/unit/test_transport_contract.py index 29edc08e..ba1a7266 100644 --- a/tests/unit/test_transport_contract.py +++ b/tests/unit/test_transport_contract.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for transport contract.""" from __future__ import annotations @@ -16,7 +16,7 @@ @respx.mock(base_url="https://example.com") def test_retry_contract_by_method_class() -> None: - """TODO: Add docstring.""" + """Test that retry contract by method class.""" sdk = ImednetSDK(api_key="k", security_key="s", base_url="https://example.com", retries=3) get_route = respx.get("/retry-get").mock(return_value=httpx.Response(503)) @@ -38,7 +38,7 @@ def test_retry_contract_by_method_class() -> None: @pytest.mark.asyncio @respx.mock(base_url="https://example.com") async def test_transport_clients_use_base_url_for_relative_paths() -> None: - """TODO: Add docstring.""" + """Test that transport clients use base url for relative paths asynchronously.""" sync_client = Client(api_key="k", security_key="s", base_url="https://example.com") assert str(sync_client._client.base_url) == "https://example.com" @@ -85,14 +85,14 @@ async def test_transport_clients_use_base_url_for_relative_paths() -> None: @respx.mock(base_url="https://example.com") def test_retry_after_header_is_respected(monkeypatch: pytest.MonkeyPatch) -> None: - """TODO: Add docstring.""" + """Test that retry after header is respected.""" import imednet.core.http.executor as executor_module sleeps: list[float] = [] original_retrying = executor_module.Retrying def retrying_with_captured_sleep(*args, **kwargs): - """TODO: Add docstring.""" + """Helper function to retrying with captured sleep.""" kwargs["sleep"] = lambda seconds: sleeps.append(seconds) return original_retrying(*args, **kwargs) @@ -115,7 +115,7 @@ def retrying_with_captured_sleep(*args, **kwargs): @pytest.mark.asyncio async def test_timeout_propagates_to_httpx_clients() -> None: - """TODO: Add docstring.""" + """Test that timeout propagates to httpx clients asynchronously.""" timeout = httpx.Timeout(connect=1.0, read=2.0, write=3.0, pool=4.0) sync_client = Client( @@ -168,7 +168,7 @@ async def test_timeout_propagates_to_httpx_clients() -> None: def test_status_code_error_mapping_contract( status_code: int, exception_type: type[Exception] ) -> None: - """TODO: Add docstring.""" + """Test that status code error mapping contract.""" sdk = ImednetSDK(api_key="k", security_key="s", base_url="https://example.com") respx.get("/error-map").mock(return_value=httpx.Response(status_code, json={"error": "x"})) @@ -180,7 +180,7 @@ def test_status_code_error_mapping_contract( def test_credentials_are_redacted_from_transport_logs_and_exceptions( caplog: pytest.LogCaptureFixture, ) -> None: - """TODO: Add docstring.""" + """Test that credentials are redacted from transport logs and exceptions.""" api_key = "very-secret-api-key" security_key = "very-secret-security-key" token = "very-secret-token" @@ -207,7 +207,7 @@ def test_credentials_are_redacted_from_transport_logs_and_exceptions( assert "token=***" in success_record.url def connect_error(request: httpx.Request) -> httpx.Response: - """TODO: Add docstring.""" + """Helper function to connect error.""" raise httpx.ConnectError("connection failed", request=request) respx.get("/network-failure").mock(side_effect=connect_error) diff --git a/tests/unit/test_tui_migration.py b/tests/unit/test_tui_migration.py index 016a3dc3..ae64bc1b 100644 --- a/tests/unit/test_tui_migration.py +++ b/tests/unit/test_tui_migration.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for tui migration.""" import pytest diff --git a/tests/unit/test_type_signatures.py b/tests/unit/test_type_signatures.py index 7334fea2..28e78b0f 100644 --- a/tests/unit/test_type_signatures.py +++ b/tests/unit/test_type_signatures.py @@ -7,14 +7,14 @@ def sync_record_signature() -> None: - """TODO: Add docstring.""" + """Helper function to sync record signature.""" sdk = cast(ImednetSDK, object()) record: Record = sdk.records.get(study_key="STUDY", item_id="123") _ = record async def async_record_signature() -> None: - """TODO: Add docstring.""" + """Helper function to async record signature.""" sdk = cast(AsyncImednetSDK, object()) record: Record = await sdk.records.async_get(study_key="STUDY", item_id="123") _ = record diff --git a/tests/unit/test_typed_values.py b/tests/unit/test_typed_values.py index 2f02106c..f1e8fe6c 100644 --- a/tests/unit/test_typed_values.py +++ b/tests/unit/test_typed_values.py @@ -1,10 +1,10 @@ -"""TODO: Add docstring.""" +"""Unit tests for typed values.""" from imednet.testing import typed_values def test_value_for_each_type() -> None: - """TODO: Add docstring.""" + """Test that value for each type.""" assert typed_values.value_for("text") == "example" assert typed_values.value_for("date") == "2024-01-01" assert typed_values.value_for("integer") == 1 @@ -15,6 +15,6 @@ def test_value_for_each_type() -> None: def test_canonical_type_synonyms() -> None: - """TODO: Add docstring.""" + """Test that canonical type synonyms.""" assert typed_values.canonical_type("Text") == "string" assert typed_values.canonical_type("int") == "number" diff --git a/tests/unit/test_utils_dates_and_filters.py b/tests/unit/test_utils_dates_and_filters.py index 382f4580..6f34a0e5 100644 --- a/tests/unit/test_utils_dates_and_filters.py +++ b/tests/unit/test_utils_dates_and_filters.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for utils dates and filters.""" from datetime import datetime, timedelta, timezone @@ -9,13 +9,13 @@ def test_parse_iso_datetime_with_z() -> None: - """TODO: Add docstring.""" + """Test that parse iso datetime with z.""" dt = parse_iso_datetime("2024-01-01T12:30:00Z") assert dt == datetime(2024, 1, 1, 12, 30, 0, tzinfo=timezone.utc) def test_parse_iso_datetime_with_offset() -> None: - """TODO: Add docstring.""" + """Test that parse iso datetime with offset.""" dt = parse_iso_datetime("2024-01-01T12:30:00+02:00") assert dt.hour == 12 assert dt.tzinfo is not None @@ -23,106 +23,106 @@ def test_parse_iso_datetime_with_offset() -> None: def test_parse_iso_datetime_naive() -> None: - """TODO: Add docstring.""" + """Test that parse iso datetime naive.""" dt = parse_iso_datetime("2024-01-01T12:30:00") assert dt.tzinfo is None assert dt.year == 2024 def test_parse_iso_datetime_millis_padding() -> None: - """TODO: Add docstring.""" + """Test that parse iso datetime millis padding.""" dt = parse_iso_datetime("2021-12-09T08:23:21.99") assert dt.microsecond == 990000 assert dt.tzinfo is None def test_parse_iso_datetime_micro_padding() -> None: - """TODO: Add docstring.""" + """Test that parse iso datetime micro padding.""" dt = parse_iso_datetime("2025-06-30T21:40:44.98268") assert dt.microsecond == 982680 def test_parse_iso_datetime_invalid() -> None: - """TODO: Add docstring.""" + """Test that parse iso datetime invalid.""" with pytest.raises(ValueError): parse_iso_datetime("not-a-date") def test_parse_iso_datetime_none() -> None: - """TODO: Add docstring.""" + """Test that parse iso datetime none.""" with pytest.raises((AttributeError, TypeError)): parse_iso_datetime(None) # type: ignore[arg-type] def test_format_iso_datetime_aware() -> None: - """TODO: Add docstring.""" + """Test that format iso datetime aware.""" dt = datetime(2024, 1, 1, 12, 30, 0, tzinfo=timezone(timedelta(hours=2))) result = format_iso_datetime(dt) assert result == "2024-01-01T10:30:00Z" def test_format_iso_datetime_naive() -> None: - """TODO: Add docstring.""" + """Test that format iso datetime naive.""" dt = datetime(2024, 1, 1, 12, 30, 0) result = format_iso_datetime(dt) assert result == "2024-01-01T12:30:00Z" def test_build_filter_string_simple() -> None: - """TODO: Add docstring.""" + """Test that build filter string simple.""" result = build_filter_string({"name": "Alice"}) assert result == "name==Alice" def test_build_filter_string_multiple() -> None: - """TODO: Add docstring.""" + """Test that build filter string multiple.""" result = build_filter_string({"name": "A", "age": 30}) assert result == "name==A;age==30" def test_build_filter_string_tuple_and_list() -> None: - """TODO: Add docstring.""" + """Test that build filter string tuple and list.""" result = build_filter_string({"age": (">", 20), "type": ["A", "B"]}) assert result == "age>20;type==A,type==B" def test_build_filter_string_bool_and_none() -> None: - """TODO: Add docstring.""" + """Test that build filter string bool and none.""" result = build_filter_string({"active": True, "missing": None}) assert result == "active==True;missing==None" def test_build_filter_string_empty() -> None: - """TODO: Add docstring.""" + """Test that build filter string empty.""" assert build_filter_string({}) == "" def test_build_filter_string_snake_to_camel() -> None: - """TODO: Add docstring.""" + """Test that build filter string snake to camel.""" result = build_filter_string({"form_name": "Demo", "visit_date": (">=", "2024")}) assert result == "formName==Demo;visitDate>=2024" def test_build_filter_string_snake_list() -> None: - """TODO: Add docstring.""" + """Test that build filter string snake list.""" result = build_filter_string({"field_name": ["A", "B"]}) assert result == "fieldName==A,fieldName==B" def test_build_filter_string_quotes() -> None: - """TODO: Add docstring.""" + """Test that build filter string quotes.""" result = build_filter_string({"site_name": "My Site"}) assert result == 'siteName=="My Site"' def test_build_filter_string_quote_spaces() -> None: - """TODO: Add docstring.""" + """Test that build filter string quote spaces.""" result = build_filter_string({"site_name": "A B"}) assert result == 'siteName=="A B"' def test_build_filter_string_backslashes() -> None: - """TODO: Add docstring.""" + """Test that build filter string backslashes.""" result = build_filter_string({"path": r"C:\Temp", "quote": r"A\"B"}) # path: C:\Temp -> "C:\\Temp" # quote: A\"B -> "A\\\"B" diff --git a/tests/unit/test_utils_init.py b/tests/unit/test_utils_init.py index 2e20952c..fb8cb143 100644 --- a/tests/unit/test_utils_init.py +++ b/tests/unit/test_utils_init.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for utils init.""" import pytest @@ -6,7 +6,7 @@ def test_lazy_load_pandas_functions() -> None: - """TODO: Add docstring.""" + """Test that lazy load pandas functions.""" func = utils.records_to_dataframe from imednet.utils.pandas import records_to_dataframe as expected_rtodf @@ -18,7 +18,7 @@ def test_lazy_load_pandas_functions() -> None: def test_lazy_load_arrow_function() -> None: - """TODO: Add docstring.""" + """Test that lazy load arrow function.""" func = utils.to_arrow_table from imednet.utils.arrow import to_arrow_table as expected_to_arrow_table @@ -26,7 +26,7 @@ def test_lazy_load_arrow_function() -> None: def test_schema_objects_not_in_utils() -> None: - """TODO: Add docstring.""" + """Test that schema objects not in utils.""" with pytest.raises(AttributeError): getattr(utils, "SchemaCache") with pytest.raises(AttributeError): @@ -36,6 +36,6 @@ def test_schema_objects_not_in_utils() -> None: def test_getattr_unknown() -> None: - """TODO: Add docstring.""" + """Test that getattr unknown.""" with pytest.raises(AttributeError): getattr(utils, "does_not_exist") diff --git a/tests/unit/test_utils_pandas.py b/tests/unit/test_utils_pandas.py index f2a82871..3ce1b25e 100644 --- a/tests/unit/test_utils_pandas.py +++ b/tests/unit/test_utils_pandas.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for utils pandas.""" import ast from unittest.mock import MagicMock @@ -11,7 +11,7 @@ def _sample_record() -> Record: - """TODO: Add docstring.""" + """Helper function to sample record.""" return Record( record_id=1, subject_key="S1", @@ -23,7 +23,7 @@ def _sample_record() -> Record: def test_records_to_dataframe_flatten() -> None: - """TODO: Add docstring.""" + """Test that records to dataframe flatten.""" rec = _sample_record() df = records_to_dataframe([rec], flatten=True) assert "record_data" not in df.columns @@ -31,7 +31,7 @@ def test_records_to_dataframe_flatten() -> None: def test_records_to_dataframe_no_flatten() -> None: - """TODO: Add docstring.""" + """Test that records to dataframe no flatten.""" rec = _sample_record() df = records_to_dataframe([rec], flatten=False) assert "record_data" in df.columns @@ -39,13 +39,13 @@ def test_records_to_dataframe_no_flatten() -> None: def test_records_to_dataframe_empty() -> None: - """TODO: Add docstring.""" + """Test that records to dataframe empty.""" df = records_to_dataframe([], flatten=False) assert df.empty def test_export_records_csv(tmp_path) -> None: - """TODO: Add docstring.""" + """Test that export records csv.""" sdk = MagicMock() sdk.records.list.return_value = [_sample_record()] out_path = tmp_path / "records.csv" @@ -59,7 +59,7 @@ def test_export_records_csv(tmp_path) -> None: def test_export_records_csv_no_flatten(tmp_path) -> None: - """TODO: Add docstring.""" + """Test that export records csv no flatten.""" sdk = MagicMock() sdk.records.list.return_value = [_sample_record()] out_path = tmp_path / "records.csv" @@ -74,14 +74,14 @@ def test_export_records_csv_no_flatten(tmp_path) -> None: def test_records_to_dataframe_raises_importerror_when_pandas_missing(monkeypatch): - """TODO: Add docstring.""" + """Test that records to dataframe raises importerror when pandas missing.""" monkeypatch.setattr("imednet.utils.pandas.pd", None) with pytest.raises(ImportError, match="pandas is required for records_to_dataframe"): records_to_dataframe([]) def test_export_records_csv_raises_importerror_when_pandas_missing(monkeypatch): - """TODO: Add docstring.""" + """Test that export records csv raises importerror when pandas missing.""" monkeypatch.setattr("imednet.utils.pandas.pd", None) with pytest.raises(ImportError, match="pandas is required for export_records_csv"): export_records_csv(None, "STUDY", "path.csv") diff --git a/tests/unit/test_utils_schema.py b/tests/unit/test_utils_schema.py index c5402c81..d70448fe 100644 --- a/tests/unit/test_utils_schema.py +++ b/tests/unit/test_utils_schema.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for utils schema.""" from unittest.mock import MagicMock @@ -10,12 +10,12 @@ def _make_var(name: str, var_type: str = "integer") -> Variable: - """TODO: Add docstring.""" + """Helper function to make var.""" return Variable(variable_name=name, variable_type=var_type, form_id=1, form_key="F1") def test_schema_cache_refresh() -> None: - """TODO: Add docstring.""" + """Test that schema cache refresh.""" forms = MagicMock() variables = MagicMock() var = _make_var("age") @@ -31,7 +31,7 @@ def test_schema_cache_refresh() -> None: def test_check_type_int() -> None: - """TODO: Add docstring.""" + """Test that check type int.""" var = _make_var("age") _check_type(var.variable_type, 5) with pytest.raises(ValidationError): @@ -39,7 +39,7 @@ def test_check_type_int() -> None: def test_check_type_other_types() -> None: - """TODO: Add docstring.""" + """Test that check type other types.""" bool_var = _make_var("flag", "boolean") float_var = _make_var("score", "float") str_var = _make_var("name", "string") @@ -57,13 +57,13 @@ def test_check_type_other_types() -> None: def test_check_type_unknown_type() -> None: - """TODO: Add docstring.""" + """Test that check type unknown type.""" with pytest.raises(UnknownVariableTypeError): _check_type("weird", "x") def test_validate_record_data_errors() -> None: - """TODO: Add docstring.""" + """Test that validate record data errors.""" cache = SchemaCache() var = _make_var("age") # Bolt: Removed 'required' attribute injection as support was removed @@ -80,14 +80,14 @@ def test_validate_record_data_errors() -> None: def test_validate_record_data_unknown_form() -> None: - """TODO: Add docstring.""" + """Test that validate record data unknown form.""" cache = SchemaCache() with pytest.raises(ValidationError, match="Unknown form BAD"): validate_record_data(cache, "BAD", {}) def test_schema_validator_batch_calls_validate_record() -> None: - """TODO: Add docstring.""" + """Test that schema validator batch calls validate record.""" sdk = MagicMock() validator = SchemaValidator(sdk) validator.validate_record = MagicMock() # type: ignore[assignment] diff --git a/tests/unit/test_utils_schema_async.py b/tests/unit/test_utils_schema_async.py index f3bb18cf..ebfdfcbe 100644 --- a/tests/unit/test_utils_schema_async.py +++ b/tests/unit/test_utils_schema_async.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for utils schema async.""" from unittest.mock import AsyncMock, MagicMock @@ -11,20 +11,20 @@ def _make_var(name: str, form_id: int = 1, form_key: str = "F1") -> Variable: - """TODO: Add docstring.""" + """Helper function to make var.""" return Variable(variable_name=name, variable_type="integer", form_id=form_id, form_key=form_key) @pytest.mark.asyncio async def test_async_schema_cache_refresh() -> None: - """TODO: Add docstring.""" + """Test that async schema cache refresh asynchronously.""" forms = MagicMock() forms.list.return_value = [Form(form_id=1, form_key="F1")] variables = MagicMock() var = _make_var("age") async def mock_async_list(*args, **kwargs): - """TODO: Add docstring.""" + """Helper function to mock async list.""" yield var variables.async_list = MagicMock(side_effect=mock_async_list) @@ -43,7 +43,7 @@ async def mock_async_list(*args, **kwargs): @pytest.mark.asyncio async def test_validate_record_and_batch_async() -> None: - """TODO: Add docstring.""" + """Test that validate record and batch async asynchronously.""" var = _make_var("age") sdk = MagicMock() sdk.async_get_variables = AsyncMock(return_value=[var]) @@ -60,7 +60,7 @@ async def test_validate_record_and_batch_async() -> None: @pytest.mark.asyncio async def test_unknown_form_refreshes_and_raises() -> None: - """TODO: Add docstring.""" + """Test that unknown form refreshes and raises asynchronously.""" var = _make_var("age") sdk = MagicMock() sdk.async_get_variables = AsyncMock(return_value=[var]) diff --git a/tests/unit/test_utils_typing.py b/tests/unit/test_utils_typing.py index 6b3517d9..c289aa99 100644 --- a/tests/unit/test_utils_typing.py +++ b/tests/unit/test_utils_typing.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for utils typing.""" import importlib import sys @@ -10,12 +10,12 @@ def test_dataframe_alias() -> None: - """TODO: Add docstring.""" + """Test that dataframe alias.""" assert DataFrame is pd.DataFrame def test_dataframe_alias_without_pandas(monkeypatch): - """TODO: Add docstring.""" + """Test that dataframe alias without pandas.""" monkeypatch.setitem(sys.modules, "pandas", None) mod = importlib.reload(importlib.import_module("imednet.utils.typing")) assert mod.DataFrame is Any diff --git a/tests/unit/test_validation_schema.py b/tests/unit/test_validation_schema.py index 652015bf..11a8b3f1 100644 --- a/tests/unit/test_validation_schema.py +++ b/tests/unit/test_validation_schema.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for validation schema.""" import importlib @@ -6,7 +6,7 @@ def test_schema_module_exports_and_deprecation_warning() -> None: - """TODO: Add docstring.""" + """Test that schema module exports and deprecation warning.""" # First ensure we import it, and catch the warning so it doesn't fail strict CI with pytest.warns( DeprecationWarning, diff --git a/tests/unit/test_workflows_data_extraction.py b/tests/unit/test_workflows_data_extraction.py index be00884f..0285ce8d 100644 --- a/tests/unit/test_workflows_data_extraction.py +++ b/tests/unit/test_workflows_data_extraction.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for workflows data extraction.""" from unittest.mock import MagicMock @@ -10,7 +10,7 @@ def test_extract_records_by_criteria_filters_subject_and_visit() -> None: - """TODO: Add docstring.""" + """Test that extract records by criteria filters subject and visit.""" sdk = MagicMock() sdk.get_subjects.return_value = [Subject(subject_key="S1"), Subject(subject_key="S2")] sdk.get_visits.return_value = [ @@ -42,7 +42,7 @@ def test_extract_records_by_criteria_filters_subject_and_visit() -> None: def test_extract_audit_trail_builds_filters_and_dates() -> None: - """TODO: Add docstring.""" + """Test that extract audit trail builds filters and dates.""" sdk = MagicMock() revisions = [RecordRevision(record_revision_id=1)] sdk.get_record_revisions.return_value = revisions diff --git a/tests/unit/test_workflows_duckdb_centralizer.py b/tests/unit/test_workflows_duckdb_centralizer.py index c2af0e40..a8277657 100644 --- a/tests/unit/test_workflows_duckdb_centralizer.py +++ b/tests/unit/test_workflows_duckdb_centralizer.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for workflows duckdb centralizer.""" from __future__ import annotations @@ -14,11 +14,11 @@ def test_duckdb_ingestion_import_error(monkeypatch) -> None: - """TODO: Add docstring.""" + """Test that duckdb ingestion import error.""" builtin_import = __import__ def fake_import(name, globals=None, locals=None, fromlist=(), level=0): # type: ignore[no-untyped-def] - """TODO: Add docstring.""" + """Helper function to fake import.""" if name == "duckdb": raise ImportError("No module named duckdb") return builtin_import(name, globals, locals, fromlist, level) @@ -37,7 +37,7 @@ def fake_import(name, globals=None, locals=None, fromlist=(), level=0): # type: def test_ingest_revisions_and_build_silver_view() -> None: - """TODO: Add docstring.""" + """Test that ingest revisions and build silver view.""" pytest.importorskip("duckdb") sdk = MagicMock() workflow = DuckDBIngestionWorkflow(sdk, ":memory:") @@ -129,7 +129,7 @@ def test_ingest_revisions_and_build_silver_view() -> None: def test_ingest_revisions_invalid_mode() -> None: - """TODO: Add docstring.""" + """Test that ingest revisions invalid mode.""" pytest.importorskip("duckdb") workflow = DuckDBIngestionWorkflow(MagicMock(), ":memory:") diff --git a/tests/unit/test_workflows_query_management.py b/tests/unit/test_workflows_query_management.py index fa86443c..8695ec91 100644 --- a/tests/unit/test_workflows_query_management.py +++ b/tests/unit/test_workflows_query_management.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for workflows query management.""" from unittest.mock import MagicMock @@ -8,13 +8,13 @@ def make_query(sequence_closed: list[tuple[int, bool]]) -> Query: - """TODO: Add docstring.""" + """Helper function to make query.""" comments = [QueryComment(sequence=seq, closed=closed) for seq, closed in sequence_closed] return Query(query_comments=comments) def test_get_open_queries_filters_latest_comment() -> None: - """TODO: Add docstring.""" + """Test that get open queries filters latest comment.""" sdk = MagicMock() query_closed = make_query([(1, False), (2, True)]) query_open = make_query([(1, False)]) @@ -30,7 +30,7 @@ def test_get_open_queries_filters_latest_comment() -> None: def test_get_queries_for_subject_builds_combined_filter() -> None: - """TODO: Add docstring.""" + """Test that get queries for subject builds combined filter.""" sdk = MagicMock() wf = QueryManagementWorkflow(sdk) wf.get_queries_for_subject("STUDY", "SUBJ1", additional_filter={"type": "x"}) @@ -40,7 +40,7 @@ def test_get_queries_for_subject_builds_combined_filter() -> None: def test_get_query_state_counts_aggregates_states() -> None: - """TODO: Add docstring.""" + """Test that get query state counts aggregates states.""" sdk = MagicMock() open_query = make_query([(1, False)]) closed_query = make_query([(1, True)]) @@ -56,7 +56,7 @@ def test_get_query_state_counts_aggregates_states() -> None: def test_get_queries_by_site_filters_using_subjects() -> None: - """TODO: Add docstring.""" + """Test that get queries by site filters using subjects.""" sdk = MagicMock() sdk.get_subjects.return_value = [Subject(subject_key="S1"), Subject(subject_key="S2")] wf = QueryManagementWorkflow(sdk) @@ -69,7 +69,7 @@ def test_get_queries_by_site_filters_using_subjects() -> None: def test_get_queries_by_site_returns_empty_if_no_subjects() -> None: - """TODO: Add docstring.""" + """Test that get queries by site returns empty if no subjects.""" sdk = MagicMock() sdk.get_subjects.return_value = [] wf = QueryManagementWorkflow(sdk) @@ -82,7 +82,7 @@ def test_get_queries_by_site_returns_empty_if_no_subjects() -> None: def test_get_queries_by_site_with_space_in_name() -> None: - """TODO: Add docstring.""" + """Test that get queries by site with space in name.""" sdk = MagicMock() sdk.get_subjects.return_value = [Subject(subject_key="S1")] wf = QueryManagementWorkflow(sdk) diff --git a/tests/unit/test_workflows_record_update.py b/tests/unit/test_workflows_record_update.py index 1457aa16..b9840205 100644 --- a/tests/unit/test_workflows_record_update.py +++ b/tests/unit/test_workflows_record_update.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for workflows record update.""" import sys from unittest.mock import AsyncMock, MagicMock @@ -13,7 +13,7 @@ def test_create_or_update_records_no_wait() -> None: - """TODO: Add docstring.""" + """Test that create or update records no wait.""" sdk = MagicMock() del sdk.async_create_record job = Job(jobId="1", batchId="1", state="PROCESSING") @@ -27,7 +27,7 @@ def test_create_or_update_records_no_wait() -> None: def test_create_or_update_records_wait_for_completion(monkeypatch) -> None: - """TODO: Add docstring.""" + """Test that create or update records wait for completion.""" sdk = MagicMock() del sdk.async_create_record initial_job = Job(jobId="1", batchId="1", state="PROCESSING") @@ -52,7 +52,7 @@ def test_create_or_update_records_wait_for_completion(monkeypatch) -> None: def test_update_scheduled_record_builds_payload() -> None: - """TODO: Add docstring.""" + """Test that update scheduled record builds payload.""" sdk = MagicMock() del sdk.async_create_record wf = RecordUpdateWorkflow(sdk) @@ -81,7 +81,7 @@ def test_update_scheduled_record_builds_payload() -> None: def test_create_or_update_records_validation() -> None: - """TODO: Add docstring.""" + """Test that create or update records validation.""" sdk = MagicMock() del sdk.async_create_record var = Variable( @@ -116,7 +116,7 @@ def test_create_or_update_records_validation() -> None: def test_register_subject_builds_payload() -> None: - """TODO: Add docstring.""" + """Test that register subject builds payload.""" sdk = MagicMock() # Mock _async_client to prevent SchemaValidator from being async if not intended del sdk.async_create_record @@ -145,7 +145,7 @@ def test_register_subject_builds_payload() -> None: def test_register_subject_with_site_id() -> None: - """TODO: Add docstring.""" + """Test that register subject with site id.""" sdk = MagicMock() del sdk.async_create_record wf = RecordUpdateWorkflow(sdk) @@ -172,7 +172,7 @@ def test_register_subject_with_site_id() -> None: def test_create_new_record_builds_payload() -> None: - """TODO: Add docstring.""" + """Test that create new record builds payload.""" sdk = MagicMock() del sdk.async_create_record wf = RecordUpdateWorkflow(sdk) @@ -199,7 +199,7 @@ def test_create_new_record_builds_payload() -> None: def test_create_new_record_with_subject_oid() -> None: - """TODO: Add docstring.""" + """Test that create new record with subject oid.""" sdk = MagicMock() del sdk.async_create_record wf = RecordUpdateWorkflow(sdk) @@ -226,7 +226,7 @@ def test_create_new_record_with_subject_oid() -> None: def test_invalid_subject_identifier_type_raises_keyerror() -> None: - """TODO: Add docstring.""" + """Test that invalid subject identifier type raises keyerror.""" sdk = MagicMock() del sdk.async_create_record wf = RecordUpdateWorkflow(sdk) @@ -242,7 +242,7 @@ def test_invalid_subject_identifier_type_raises_keyerror() -> None: def test_invalid_site_identifier_type_raises_keyerror() -> None: - """TODO: Add docstring.""" + """Test that invalid site identifier type raises keyerror.""" sdk = MagicMock() del sdk.async_create_record wf = RecordUpdateWorkflow(sdk) @@ -258,7 +258,7 @@ def test_invalid_site_identifier_type_raises_keyerror() -> None: def test_update_scheduled_record_invalid_interval_identifier_type() -> None: - """TODO: Add docstring.""" + """Test that update scheduled record invalid interval identifier type.""" sdk = MagicMock() del sdk.async_create_record wf = RecordUpdateWorkflow(sdk) @@ -275,7 +275,7 @@ def test_update_scheduled_record_invalid_interval_identifier_type() -> None: def test_create_or_update_records_wait_for_completion_no_batch_id() -> None: - """TODO: Add docstring.""" + """Test that create or update records wait for completion no batch id.""" sdk = MagicMock() del sdk.async_create_record @@ -313,7 +313,7 @@ def test_create_or_update_records_wait_for_completion_no_batch_id() -> None: def test_create_or_update_records_form_key_not_found() -> None: - """TODO: Add docstring.""" + """Test that create or update records form key not found.""" sdk = MagicMock() del sdk.async_create_record @@ -331,7 +331,7 @@ def test_create_or_update_records_form_key_not_found() -> None: @pytest.mark.asyncio async def test_async_create_or_update_records_no_wait() -> None: - """TODO: Add docstring.""" + """Test that async create or update records no wait asynchronously.""" sdk = MagicMock() sdk._async_client = True job = Job(jobId="1", batchId="1", state="PROCESSING") @@ -346,7 +346,7 @@ async def test_async_create_or_update_records_no_wait() -> None: @pytest.mark.asyncio async def test_async_create_or_update_records_wait_for_completion(monkeypatch) -> None: - """TODO: Add docstring.""" + """Test that async create or update records wait for completion asynchronously.""" sdk = MagicMock() sdk._async_client = True initial_job = Job(jobId="1", batchId="1", state="PROCESSING") @@ -373,7 +373,7 @@ async def test_async_create_or_update_records_wait_for_completion(monkeypatch) - @pytest.mark.asyncio async def test_async_create_or_update_records_validation() -> None: - """TODO: Add docstring.""" + """Test that async create or update records validation asynchronously.""" sdk = MagicMock() sdk._async_client = True var = Variable( @@ -413,7 +413,7 @@ async def test_async_create_or_update_records_validation() -> None: @pytest.mark.asyncio async def test_async_create_or_update_records_wait_for_completion_no_batch_id() -> None: - """TODO: Add docstring.""" + """Test that async create or update records wait for completion no batch id asynchronously.""" sdk = MagicMock() sdk._async_client = True job = Job(jobId="1", batchId="", state="PROCESSING") @@ -448,7 +448,7 @@ async def test_async_create_or_update_records_wait_for_completion_no_batch_id() @pytest.mark.asyncio async def test_async_create_or_update_records_form_key_not_found() -> None: - """TODO: Add docstring.""" + """Test that async create or update records form key not found asynchronously.""" sdk = MagicMock() sdk._async_client = True sdk.async_get_variables = AsyncMock(return_value=[]) diff --git a/tests/unit/test_workflows_register_subjects.py b/tests/unit/test_workflows_register_subjects.py index d545e2de..75e1b537 100644 --- a/tests/unit/test_workflows_register_subjects.py +++ b/tests/unit/test_workflows_register_subjects.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for workflows register subjects.""" from unittest.mock import MagicMock @@ -11,7 +11,7 @@ def test_register_subjects_passes_records_correctly() -> None: - """TODO: Add docstring.""" + """Test that register subjects passes records correctly.""" sdk = MagicMock() job = Job(jobId="1", batchId="1", state="PROCESSING") sdk.create_record.return_value = job @@ -34,7 +34,7 @@ def test_register_subjects_passes_records_correctly() -> None: def test_register_subjects_with_polling() -> None: - """TODO: Add docstring.""" + """Test that register subjects with polling.""" sdk = MagicMock() job = Job(jobId="1", batchId="BATCH", state="PROCESSING") completed_job = Job(jobId="1", batchId="BATCH", state="COMPLETED") @@ -56,7 +56,7 @@ def test_register_subjects_with_polling() -> None: def test_register_subjects_missing_site() -> None: - """TODO: Add docstring.""" + """Test that register subjects missing site.""" sdk = MagicMock() sdk.get_sites.return_value = [] wf = RegisterSubjectsWorkflow(sdk) @@ -67,7 +67,7 @@ def test_register_subjects_missing_site() -> None: def test_register_subjects_missing_site_name() -> None: - """TODO: Add docstring.""" + """Test that register subjects missing site name.""" sdk = MagicMock() sdk.get_sites.return_value = [ Site(studyKey="S", siteId=1, siteName="SITE", siteEnrollmentStatus="Active") diff --git a/tests/unit/test_workflows_subject_data.py b/tests/unit/test_workflows_subject_data.py index 671ad60c..072c6428 100644 --- a/tests/unit/test_workflows_subject_data.py +++ b/tests/unit/test_workflows_subject_data.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for workflows subject data.""" from unittest.mock import MagicMock @@ -10,7 +10,7 @@ def test_get_all_subject_data_aggregates_across_endpoints() -> None: - """TODO: Add docstring.""" + """Test that get all subject data aggregates across endpoints.""" sdk = MagicMock() subject = Subject(subject_key="S1") visit = Visit(visit_id=1, subject_key="S1") diff --git a/tests/unit/utils/test_arrow.py b/tests/unit/utils/test_arrow.py index e3e173b0..7a677d06 100644 --- a/tests/unit/utils/test_arrow.py +++ b/tests/unit/utils/test_arrow.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for arrow.""" from datetime import datetime, timezone @@ -9,7 +9,7 @@ def test_to_arrow_table_empty_records_returns_empty_table() -> None: - """TODO: Add docstring.""" + """Test that to arrow table empty records returns empty table.""" table = to_arrow_table([]) assert table.num_rows == 0 @@ -17,7 +17,7 @@ def test_to_arrow_table_empty_records_returns_empty_table() -> None: def test_to_arrow_table_handles_key_variations_with_nulls() -> None: - """TODO: Add docstring.""" + """Test that to arrow table handles key variations with nulls.""" table = to_arrow_table([{"subject_key": "S1", "weight": 73.5}, {"subject_key": "S2"}]) assert table.column("subject_key").to_pylist() == ["S1", "S2"] @@ -26,7 +26,7 @@ def test_to_arrow_table_handles_key_variations_with_nulls() -> None: def test_to_arrow_table_preserves_datetime_bool_and_float_types() -> None: - """TODO: Add docstring.""" + """Test that to arrow table preserves datetime bool and float types.""" recorded_at = datetime(2025, 1, 1, 8, 30, tzinfo=timezone.utc) table = to_arrow_table( [ @@ -41,10 +41,10 @@ def test_to_arrow_table_preserves_datetime_bool_and_float_types() -> None: def test_to_arrow_table_accepts_pydantic_like_records() -> None: - """TODO: Add docstring.""" + """Test that to arrow table accepts pydantic like records.""" class Visit(BaseModel): - """TODO: Add docstring.""" + """Test suite for Visit.""" subject_key: str completed: bool diff --git a/tests/unit/utils/test_dates_legacy.py b/tests/unit/utils/test_dates_legacy.py index dc2056e0..8a846bde 100644 --- a/tests/unit/utils/test_dates_legacy.py +++ b/tests/unit/utils/test_dates_legacy.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for dates legacy.""" from datetime import datetime, timedelta, timezone from unittest.mock import patch diff --git a/tests/unit/utils/test_json_logging.py b/tests/unit/utils/test_json_logging.py index 61472226..356a84af 100644 --- a/tests/unit/utils/test_json_logging.py +++ b/tests/unit/utils/test_json_logging.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for json logging.""" import importlib import json @@ -27,10 +27,10 @@ def _install_formatter(monkeypatch: pytest.MonkeyPatch, submodule: str) -> type[ module = types.ModuleType(f"pythonjsonlogger.{submodule}") class DummyFormatter(logging.Formatter): - """TODO: Add docstring.""" + """Test suite for DummyFormatter.""" def format(self, record: logging.LogRecord) -> str: # type: ignore[override] - """TODO: Add docstring.""" + """Helper function to format.""" return json.dumps({"message": record.getMessage(), "levelname": record.levelname}) module.JsonFormatter = DummyFormatter # type: ignore[attr-defined] @@ -39,7 +39,7 @@ def format(self, record: logging.LogRecord) -> str: # type: ignore[override] def _configure_and_log(json_logging, caplog: pytest.LogCaptureFixture) -> logging.Handler: - """TODO: Add docstring.""" + """Helper function to configure and log.""" root = logging.getLogger() old_handlers, old_level = root.handlers[:], root.level with caplog.at_level(logging.INFO, logger=""): @@ -57,7 +57,7 @@ def _configure_and_log(json_logging, caplog: pytest.LogCaptureFixture) -> loggin def test_configure_json_logging_uses_json_import(monkeypatch, caplog): - """TODO: Add docstring.""" + """Test that configure json logging uses json import.""" formatter_cls = _install_formatter(monkeypatch, "json") monkeypatch.delitem(sys.modules, MODULE_PATH, raising=False) json_logging = importlib.import_module(MODULE_PATH) @@ -66,7 +66,7 @@ def test_configure_json_logging_uses_json_import(monkeypatch, caplog): def test_configure_json_logging_uses_jsonlogger_import(monkeypatch, caplog): - """TODO: Add docstring.""" + """Test that configure json logging uses jsonlogger import.""" formatter_cls = _install_formatter(monkeypatch, "jsonlogger") monkeypatch.delitem(sys.modules, MODULE_PATH, raising=False) json_logging = importlib.import_module(MODULE_PATH) diff --git a/tests/unit/utils/test_pandas_security.py b/tests/unit/utils/test_pandas_security.py index 63bc59a0..7c7d9adb 100644 --- a/tests/unit/utils/test_pandas_security.py +++ b/tests/unit/utils/test_pandas_security.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for pandas security.""" from unittest.mock import MagicMock @@ -10,7 +10,7 @@ @pytest.fixture def mock_sdk(): - """TODO: Add docstring.""" + """Helper function to mock sdk.""" sdk = MagicMock() # Create a record with malicious data record_data = { diff --git a/tests/unit/utils/test_security.py b/tests/unit/utils/test_security.py index 7e80cf7c..547cabf5 100644 --- a/tests/unit/utils/test_security.py +++ b/tests/unit/utils/test_security.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for security.""" import pytest @@ -36,7 +36,7 @@ ], ) def test_sanitize_csv_formula(input_val, expected): - """TODO: Add docstring.""" + """Test that sanitize csv formula.""" assert sanitize_csv_formula(input_val) == expected @@ -52,7 +52,7 @@ def test_sanitize_csv_formula(input_val, expected): ], ) def test_validate_header_value_valid(input_val): - """TODO: Add docstring.""" + """Test that validate header value valid.""" validate_header_value(input_val) @@ -69,7 +69,7 @@ def test_validate_header_value_valid(input_val): ], ) def test_validate_header_value_invalid(input_val): - """TODO: Add docstring.""" + """Test that validate header value invalid.""" with pytest.raises(ClientError, match="Header value must not contain newlines"): validate_header_value(input_val) @@ -83,13 +83,13 @@ def test_validate_header_value_invalid(input_val): ], ) def test_sanitize_csv_formula_collections(input_val, expected): - """TODO: Add docstring.""" + """Test that sanitize csv formula collections.""" assert sanitize_csv_formula(input_val) == expected @pytest.mark.parametrize("key", ["STUDY_A", "study-001", "visit 1"]) def test_validate_partition_key_valid(key: str) -> None: - """TODO: Add docstring.""" + """Test that validate partition key valid.""" validate_partition_key(key) @@ -109,6 +109,6 @@ def test_validate_partition_key_valid(key: str) -> None: ], ) def test_validate_partition_key_invalid(key: str) -> None: - """TODO: Add docstring.""" + """Test that validate partition key invalid.""" with pytest.raises(PathTraversalValidationError): validate_partition_key(key) diff --git a/tests/unit/utils/test_url.py b/tests/unit/utils/test_url.py index 0311772e..68ef964b 100644 --- a/tests/unit/utils/test_url.py +++ b/tests/unit/utils/test_url.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for url.""" import pytest @@ -15,7 +15,7 @@ ], ) def test_sanitize_base_url(url: str, expected: str) -> None: - """TODO: Add docstring.""" + """Test that sanitize base url.""" assert sanitize_base_url(url) == expected @@ -48,5 +48,5 @@ def test_redact_url_query() -> None: ], ) def test_build_safe_path(base_path: str, segments: tuple[object, ...], expected: str) -> None: - """TODO: Add docstring.""" + """Test that build safe path.""" assert build_safe_path(base_path, *segments) == expected diff --git a/tests/unit/utils/test_validators.py b/tests/unit/utils/test_validators.py index a7f83b61..8637d7bc 100644 --- a/tests/unit/utils/test_validators.py +++ b/tests/unit/utils/test_validators.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for validators.""" from datetime import datetime, timezone @@ -15,14 +15,14 @@ def test_parse_datetime_handles_empty_values(): - """TODO: Add docstring.""" + """Test that parse datetime handles empty values.""" sentinel = datetime(1969, 4, 20, 16, 20) assert parse_datetime("") == sentinel assert parse_datetime(None) == sentinel def test_parse_datetime_handles_numeric_timestamps(): - """TODO: Add docstring.""" + """Test that parse datetime handles numeric timestamps.""" dt = datetime(2024, 1, 1, 12, 0, tzinfo=timezone.utc) ts = dt.timestamp() assert parse_datetime(ts) == dt @@ -30,14 +30,14 @@ def test_parse_datetime_handles_numeric_timestamps(): def test_parse_datetime_handles_zero_timestamps(): - """TODO: Add docstring.""" + """Test that parse datetime handles zero timestamps.""" dt = datetime(1970, 1, 1, 0, 0, tzinfo=timezone.utc) assert parse_datetime(0) == dt assert parse_datetime(0.0) == dt def test_parse_bool_handles_various_representations(): - """TODO: Add docstring.""" + """Test that parse bool handles various representations.""" assert parse_bool(True) is True assert parse_bool("true") is True assert parse_bool("1") is True @@ -56,7 +56,7 @@ def test_parse_bool_handles_various_representations(): def test_parse_bool_handles_floats(): - """TODO: Add docstring.""" + """Test that parse bool handles floats.""" assert parse_bool("1.0") is True assert parse_bool(1.0) is True assert parse_bool("0.0") is False @@ -64,82 +64,82 @@ def test_parse_bool_handles_floats(): def test_parse_bool_handles_irregular_casing(): - """TODO: Add docstring.""" + """Test that parse bool handles irregular casing.""" assert parse_bool(" TrUe ") is True assert parse_bool(" fAlSe ") is False def test_parse_bool_returns_false_for_invalid_strings(): - """TODO: Add docstring.""" + """Test that parse bool returns false for invalid strings.""" assert parse_bool("invalid") is False assert parse_bool("apple") is False assert parse_bool("") is False def test_parse_int_or_default_handles_valid_ints(): - """TODO: Add docstring.""" + """Test that parse int or default handles valid ints.""" assert parse_int_or_default(42) == 42 assert parse_int_or_default("42") == 42 def test_parse_int_or_default_handles_floats(): - """TODO: Add docstring.""" + """Test that parse int or default handles floats.""" assert parse_int_or_default(42.0) == 42 assert parse_int_or_default("42.0") == 42 def test_parse_int_or_default_uses_default_for_empty(): - """TODO: Add docstring.""" + """Test that parse int or default uses default for empty.""" assert parse_int_or_default(None, default=10) == 10 assert parse_int_or_default("", default=10) == 10 def test_parse_int_or_default_strict_raises_on_invalid(): - """TODO: Add docstring.""" + """Test that parse int or default strict raises on invalid.""" with pytest.raises(ValueError): parse_int_or_default("invalid", strict=True) def test_parse_int_or_default_returns_default_on_invalid_when_not_strict(): - """TODO: Add docstring.""" + """Test that parse int or default returns default on invalid when not strict.""" assert parse_int_or_default("invalid", default=10) == 10 def test_parse_str_or_default(): - """TODO: Add docstring.""" + """Test that parse str or default.""" assert parse_str_or_default("hello") == "hello" assert parse_str_or_default(42) == "42" assert parse_str_or_default(None, default="default") == "default" def test_parse_list_or_default(): - """TODO: Add docstring.""" + """Test that parse list or default.""" assert parse_list_or_default([1, 2]) == [1, 2] assert parse_list_or_default(42) == [42] assert parse_list_or_default(None) == [] def test_parse_dict_or_default(): - """TODO: Add docstring.""" + """Test that parse dict or default.""" assert parse_dict_or_default({"a": 1}) == {"a": 1} assert parse_dict_or_default(None) == {} assert parse_dict_or_default("invalid") == {} def test_parse_datetime_handles_datetime_objects(): - """TODO: Add docstring.""" + """Test that parse datetime handles datetime objects.""" dt = datetime(2024, 1, 1, 12, 0, tzinfo=timezone.utc) assert parse_datetime(dt) == dt def test_parse_datetime_handles_string_timestamps(): - """TODO: Add docstring.""" + """Test that parse datetime handles string timestamps.""" dt = datetime(2024, 1, 1, 12, 0, tzinfo=timezone.utc) assert parse_datetime("2024-01-01T12:00:00Z") == dt def test_parse_bool_handles_unusual_strings(): - """TODO: Add docstring.""" + """Test that parse bool handles unusual strings.""" # Test cases that trigger the float fallback assert parse_bool("inf") is True assert parse_bool("nan") is True @@ -155,7 +155,7 @@ def test_parse_bool_handles_unusual_strings(): def test_parse_bool_handles_non_string_types(): - """TODO: Add docstring.""" + """Test that parse bool handles non string types.""" # Non-truthy values according to rationale should return False assert parse_bool(None) is False assert parse_bool([]) is False @@ -164,7 +164,7 @@ def test_parse_bool_handles_non_string_types(): def test_parse_bool_handles_extra_numeric_values(): - """TODO: Add docstring.""" + """Test that parse bool handles extra numeric values.""" # Numeric types are truthy if non-zero assert parse_bool(float("inf")) is True assert parse_bool(float("nan")) is True diff --git a/tests/unit/workflows/test_extraction_engine.py b/tests/unit/workflows/test_extraction_engine.py index 5719555c..47644849 100644 --- a/tests/unit/workflows/test_extraction_engine.py +++ b/tests/unit/workflows/test_extraction_engine.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for extraction engine.""" from __future__ import annotations @@ -10,7 +10,7 @@ def test_extract_canonical_records_maps_ae_pd_dd_and_collects_row_errors() -> None: - """TODO: Add docstring.""" + """Test that extract canonical records maps ae pd dd and collects row errors.""" config = StudyConfiguration( study_key="STUDY-1", mappings=[ @@ -154,7 +154,7 @@ def test_extract_canonical_records_maps_ae_pd_dd_and_collects_row_errors() -> No def test_extract_canonical_records_uses_fallback_values() -> None: - """TODO: Add docstring.""" + """Test that extract canonical records uses fallback values.""" config = StudyConfiguration( study_key="STUDY-1", mappings=[ @@ -198,7 +198,7 @@ def test_extract_canonical_records_uses_fallback_values() -> None: def test_extract_subject_centric_analysis_datasets() -> None: - """TODO: Add docstring.""" + """Test that extract subject centric analysis datasets.""" config = StudyConfiguration( study_key="STUDY-2", mappings=[ diff --git a/tests/unit/workflows/test_schema_profiler.py b/tests/unit/workflows/test_schema_profiler.py index 8f3863c4..7f773c73 100644 --- a/tests/unit/workflows/test_schema_profiler.py +++ b/tests/unit/workflows/test_schema_profiler.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for schema profiler.""" from __future__ import annotations @@ -12,7 +12,7 @@ def test_schema_profiler_builds_form_and_field_profiles() -> None: - """TODO: Add docstring.""" + """Test that schema profiler builds form and field profiles.""" sdk = MagicMock() sdk.get_forms.return_value = [Form(form_key="AE", form_name="Adverse Events", form_id=10)] sdk.get_variables.return_value = [ @@ -97,7 +97,7 @@ def test_schema_profiler_builds_form_and_field_profiles() -> None: def test_schema_profiler_uses_loader_when_records_are_not_supplied() -> None: - """TODO: Add docstring.""" + """Test that schema profiler uses loader when records are not supplied.""" sdk = MagicMock() loader = MagicMock() loader.load_records.return_value = [ @@ -130,20 +130,20 @@ def test_schema_profiler_uses_loader_when_records_are_not_supplied() -> None: def test_schema_profiler_streams_chunked_loader_records() -> None: - """TODO: Add docstring.""" + """Test that schema profiler streams chunked loader records.""" sdk = MagicMock() class _ChunkedLoader: - """TODO: Add docstring.""" + """Test suite for ChunkedLoader.""" def __init__(self) -> None: - """TODO: Add docstring.""" + """Initialize the test object.""" self.load_records = MagicMock() self.sync_records = MagicMock() self._iter_mock = MagicMock() def iter_cached_records(self, study_key: str): - """TODO: Add docstring.""" + """Helper function to iter cached records.""" self._iter_mock(study_key) return iter( [ diff --git a/tests/unit/workflows/test_standards_validation.py b/tests/unit/workflows/test_standards_validation.py index d62aea56..732d079f 100644 --- a/tests/unit/workflows/test_standards_validation.py +++ b/tests/unit/workflows/test_standards_validation.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for standards validation.""" import pytest @@ -10,7 +10,7 @@ def test_categorical_normalizer_translates_lookup_values_and_yes_no_booleans() -> None: - """TODO: Add docstring.""" + """Test that categorical normalizer translates lookup values and yes no booleans.""" normalizer = CategoricalNormalizer() result = normalizer.normalize_record( { @@ -27,7 +27,7 @@ def test_categorical_normalizer_translates_lookup_values_and_yes_no_booleans() - def test_standards_readiness_validator_scores_records() -> None: - """TODO: Add docstring.""" + """Test that standards readiness validator scores records.""" validator = StandardsReadinessValidator(profile=DrugSafetyProfile()) report = validator.score_records( records_by_domain={ diff --git a/tests/unit/workflows/test_triage_store.py b/tests/unit/workflows/test_triage_store.py index e93f44b7..7a66436d 100644 --- a/tests/unit/workflows/test_triage_store.py +++ b/tests/unit/workflows/test_triage_store.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for triage store.""" from __future__ import annotations @@ -16,7 +16,7 @@ def _seed_item(item_id: str = "AE-1") -> TriageItem: - """TODO: Add docstring.""" + """Helper function to seed item.""" return TriageItem( item_id=item_id, study_key="STUDY-A", @@ -45,13 +45,13 @@ def _seed_item(item_id: str = "AE-1") -> TriageItem: def test_triage_store_enables_wal_mode(tmp_path: Path) -> None: - """TODO: Add docstring.""" + """Test that triage store enables wal mode.""" store = TriageStore(tmp_path / "triage.sqlite3") assert store.get_journal_mode().lower() == "wal" def test_triage_store_crud_and_queue_filters(tmp_path: Path) -> None: - """TODO: Add docstring.""" + """Test that triage store crud and queue filters.""" store = TriageStore(tmp_path / "triage.sqlite3") store.upsert_item(_seed_item("AE-1")) store.upsert_item(_seed_item("PD-2")) @@ -75,16 +75,16 @@ def test_triage_store_crud_and_queue_filters(tmp_path: Path) -> None: def test_triage_store_handles_parallel_reads_and_writes(tmp_path: Path) -> None: - """TODO: Add docstring.""" + """Test that triage store handles parallel reads and writes.""" store = TriageStore(tmp_path / "triage.sqlite3") store.upsert_item(_seed_item("AE-99")) def _writer(idx: int) -> None: - """TODO: Add docstring.""" + """Helper function to writer.""" store.add_annotation("AE-99", f"user-{idx}", f"comment {idx}") def _reader() -> int: - """TODO: Add docstring.""" + """Helper function to reader.""" item = store.get_triage_item("AE-99") assert item is not None return len(item.annotations) @@ -103,7 +103,7 @@ def _reader() -> int: def test_triage_store_rejects_empty_annotation_comment(tmp_path: Path) -> None: - """TODO: Add docstring.""" + """Test that triage store rejects empty annotation comment.""" store = TriageStore(tmp_path / "triage.sqlite3") store.upsert_item(_seed_item("DD-4")) @@ -112,7 +112,7 @@ def test_triage_store_rejects_empty_annotation_comment(tmp_path: Path) -> None: def test_triage_store_migrates_legacy_schema(tmp_path: Path) -> None: - """TODO: Add docstring.""" + """Test that triage store migrates legacy schema.""" db_path = tmp_path / "triage.sqlite3" with sqlite3.connect(db_path) as conn: conn.execute(""" @@ -151,12 +151,12 @@ def test_triage_store_migrates_legacy_schema(tmp_path: Path) -> None: def test_triage_store_masks_sensitive_operational_errors( tmp_path: Path, monkeypatch: pytest.MonkeyPatch ) -> None: - """TODO: Add docstring.""" + """Test that triage store masks sensitive operational errors.""" store = TriageStore(tmp_path / "triage.sqlite3", retry_attempts=1) @contextmanager def _memory_connection() -> Iterator[sqlite3.Connection]: - """TODO: Add docstring.""" + """Helper function to memory connection.""" conn = sqlite3.connect(":memory:") try: yield conn @@ -166,7 +166,7 @@ def _memory_connection() -> Iterator[sqlite3.Connection]: monkeypatch.setattr(store, "_connection", _memory_connection) def _failing_write(_conn: sqlite3.Connection) -> None: - """TODO: Add docstring.""" + """Helper function to failing write.""" raise sqlite3.OperationalError("unable to open database file: token=supersecret") with pytest.raises(sqlite3.OperationalError) as exc_info: diff --git a/tests/unit/workflows/test_uat_engine.py b/tests/unit/workflows/test_uat_engine.py index 1da5b49c..721fd5cb 100644 --- a/tests/unit/workflows/test_uat_engine.py +++ b/tests/unit/workflows/test_uat_engine.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for uat engine.""" from unittest.mock import Mock @@ -10,7 +10,7 @@ def test_uat_engine_parses_rules(): - """TODO: Add docstring.""" + """Test that uat engine parses rules.""" dd = DataDictionary( business_logic=[ { @@ -33,7 +33,7 @@ def test_uat_engine_parses_rules(): def test_uat_engine_negative_generation(): - """TODO: Add docstring.""" + """Test that uat engine negative generation.""" dd = DataDictionary( business_logic=[ { @@ -55,7 +55,7 @@ def test_uat_engine_negative_generation(): def test_uat_engine_run_verification(): - """TODO: Add docstring.""" + """Test that uat engine run verification.""" sdk = Mock() sdk.create_record.side_effect = ValidationError("Invalid value") @@ -83,7 +83,7 @@ def test_uat_engine_run_verification(): def test_uat_engine_subject_limit(): - """TODO: Add docstring.""" + """Test that uat engine subject limit.""" sdk = Mock() sdk.create_record.side_effect = ValidationError("Invalid value") diff --git a/tests/unit/workflows/test_uat_inspector.py b/tests/unit/workflows/test_uat_inspector.py index 36e3f591..fb5f1db5 100644 --- a/tests/unit/workflows/test_uat_inspector.py +++ b/tests/unit/workflows/test_uat_inspector.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for uat inspector.""" from __future__ import annotations @@ -19,7 +19,7 @@ def test_study_snapshot_builds_indexes_and_filters() -> None: - """TODO: Add docstring.""" + """Test that study snapshot builds indexes and filters.""" enrollment = Form(form_key="ENR", form_type="Enrollment", form_name="Enroll") scheduled = Form(form_key="LABS", form_type="CRF", form_name="Labs") unscheduled = Form( @@ -52,7 +52,7 @@ def test_study_snapshot_builds_indexes_and_filters() -> None: def test_inspect_uses_cache_and_force_refresh() -> None: - """TODO: Add docstring.""" + """Test that inspect uses cache and force refresh.""" sdk = MagicMock() sdk.get_forms.return_value = [Form(form_key="F1", form_name="Form 1")] sdk.get_variables.return_value = [Variable(variable_name="V1", form_key="F1")] @@ -78,7 +78,7 @@ def test_inspect_uses_cache_and_force_refresh() -> None: def test_clear_cache_for_single_key_and_all_keys() -> None: - """TODO: Add docstring.""" + """Test that clear cache for single key and all keys.""" sdk = MagicMock() sdk.get_forms.return_value = [] sdk.get_variables.return_value = [] @@ -101,14 +101,14 @@ def test_clear_cache_for_single_key_and_all_keys() -> None: @pytest.mark.asyncio async def test_async_inspect_fetches_all_endpoints_concurrently() -> None: - """TODO: Add docstring.""" + """Test that async inspect fetches all endpoints concurrently asynchronously.""" sdk = MagicMock() calls = {"forms": 0, "variables": 0, "intervals": 0, "sites": 0} started = 0 release = asyncio.Event() async def delayed_result(name: str, payload: list[Any]) -> list[Any]: - """TODO: Add docstring.""" + """Helper function to delayed result.""" nonlocal started calls[name] += 1 started += 1 @@ -138,11 +138,11 @@ async def delayed_result(name: str, payload: list[Any]) -> list[Any]: @pytest.mark.asyncio async def test_async_inspect_force_refresh_bypasses_cache() -> None: - """TODO: Add docstring.""" + """Test that async inspect force refresh bypasses cache asynchronously.""" sdk = MagicMock() async def empty_async_gen(*args, **kwargs) -> list[Any]: - """TODO: Add docstring.""" + """Helper function to empty async gen.""" return [] sdk.async_get_forms = MagicMock(side_effect=empty_async_gen) @@ -161,7 +161,7 @@ async def empty_async_gen(*args, **kwargs) -> list[Any]: def test_inspect_with_async_sdk_raises_type_error() -> None: - """TODO: Add docstring.""" + """Test that inspect with async sdk raises type error.""" sdk = AsyncImednetSDK(api_key="k", security_key="s", base_url="https://api.test") inspector = StudySchemaInspector(sdk) try: @@ -173,7 +173,7 @@ def test_inspect_with_async_sdk_raises_type_error() -> None: @pytest.mark.asyncio async def test_async_inspect_with_sync_sdk_raises_type_error() -> None: - """TODO: Add docstring.""" + """Test that async inspect with sync sdk raises type error asynchronously.""" sdk = ImednetSDK(api_key="k", security_key="s", base_url="https://api.test") inspector = StudySchemaInspector(sdk) with pytest.raises(AttributeError): @@ -181,7 +181,7 @@ async def test_async_inspect_with_sync_sdk_raises_type_error() -> None: def _form_payload(form_id: int) -> dict[str, object]: - """TODO: Add docstring.""" + """Helper function to form payload.""" return { "studyKey": "ST", "formId": form_id, @@ -192,7 +192,7 @@ def _form_payload(form_id: int) -> dict[str, object]: def _variable_payload(variable_id: int) -> dict[str, object]: - """TODO: Add docstring.""" + """Helper function to variable payload.""" return { "studyKey": "ST", "variableId": variable_id, @@ -207,7 +207,7 @@ def _variable_payload(variable_id: int) -> dict[str, object]: @respx.mock def test_inspect_consumes_paginated_forms_and_variables() -> None: - """TODO: Add docstring.""" + """Test that inspect consumes paginated forms and variables.""" sdk = ImednetSDK(api_key="k", security_key="s", base_url="https://api.test") forms_route = respx.get("https://api.test/api/v1/edc/studies/ST/forms").mock( side_effect=[ diff --git a/tests/unit/workflows/test_uat_models.py b/tests/unit/workflows/test_uat_models.py index 798c9577..578dea73 100644 --- a/tests/unit/workflows/test_uat_models.py +++ b/tests/unit/workflows/test_uat_models.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for uat models.""" from __future__ import annotations @@ -23,7 +23,7 @@ def _build_valid_spec() -> UATSpecification: - """TODO: Add docstring.""" + """Helper function to build valid spec.""" variable = UATVariableSpec( variable_name="SYSTOLIC", variable_key="VAR-1", @@ -49,7 +49,7 @@ def _build_valid_spec() -> UATSpecification: def test_json_round_trip_serialization() -> None: - """TODO: Add docstring.""" + """Test that json round trip serialization.""" spec = _build_valid_spec() payload = spec.model_dump_json() parsed = UATSpecification.model_validate_json(payload) @@ -57,7 +57,7 @@ def test_json_round_trip_serialization() -> None: def test_alias_dump_uses_camel_case() -> None: - """TODO: Add docstring.""" + """Test that alias dump uses camel case.""" spec = _build_valid_spec() payload = spec.model_dump(by_alias=True) assert "studyKey" in payload @@ -67,7 +67,7 @@ def test_alias_dump_uses_camel_case() -> None: def test_fixed_strategy_requires_fixed_value() -> None: - """TODO: Add docstring.""" + """Test that fixed strategy requires fixed value.""" with pytest.raises(ValidationError, match="fixed_value must be provided"): UATVariableSpec( variable_name="AGE", @@ -80,7 +80,7 @@ def test_fixed_strategy_requires_fixed_value() -> None: @pytest.mark.parametrize("count", [0, 101]) def test_subject_count_bounds(count: int) -> None: - """TODO: Add docstring.""" + """Test that subject count bounds.""" with pytest.raises(ValidationError, match="subject_count must be between 1 and 100"): UATFormSpec( form_key="DEMOG", @@ -94,7 +94,7 @@ def test_subject_count_bounds(count: int) -> None: def test_spec_version_is_pinned() -> None: - """TODO: Add docstring.""" + """Test that spec version is pinned.""" with pytest.raises(ValidationError, match="spec_version must be '1.0'"): UATSpecification( spec_version="2.0", @@ -104,7 +104,7 @@ def test_spec_version_is_pinned() -> None: def test_variables_must_have_unique_names() -> None: - """TODO: Add docstring.""" + """Test that variables must have unique names.""" with pytest.raises(ValidationError, match="duplicate variable_name"): UATFormSpec( form_key="LABS", @@ -129,7 +129,7 @@ def test_variables_must_have_unique_names() -> None: def test_enabled_forms_and_forms_by_type_filters_correctly() -> None: - """TODO: Add docstring.""" + """Test that enabled forms and forms by type filters correctly.""" enabled_register = UATFormSpec( form_key="SUBJECT", form_name="Subject Registration", @@ -159,14 +159,14 @@ def test_enabled_forms_and_forms_by_type_filters_correctly() -> None: def test_from_yaml_raises_when_pyyaml_unavailable(monkeypatch: pytest.MonkeyPatch) -> None: - """TODO: Add docstring.""" + """Test that from yaml raises when pyyaml unavailable.""" monkeypatch.setattr(uat_models, "find_spec", lambda _: None) with pytest.raises(ImportError, match="PyYAML is required"): UATSpecification.from_yaml("studyKey: S1\nstudyName: Study") def test_from_yaml_loads_when_available(tmp_path: Path) -> None: - """TODO: Add docstring.""" + """Test that from yaml loads when available.""" if uat_models.find_spec("yaml") is None: pytest.skip("PyYAML not installed in test environment") diff --git a/tests/utils/streaming.py b/tests/utils/streaming.py index c55ab082..7d4ccec0 100644 --- a/tests/utils/streaming.py +++ b/tests/utils/streaming.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for streaming.""" import asyncio from typing import Any, AsyncIterator, Generic, Iterable, Iterator, List, TypeVar, Union, overload @@ -10,7 +10,7 @@ class StreamingMockWrapper(Generic[T]): """A robust test wrapper that mimics both a list and an async/sync iterator.""" def __init__(self, data: Iterable[T], max_buffer_size: int = 10000): - """TODO: Add docstring.""" + """Initialize the test object.""" self._max_buffer_size = max_buffer_size self._buffer: List[T] = [] self._fully_buffered = False @@ -23,7 +23,7 @@ def __init__(self, data: Iterable[T], max_buffer_size: int = 10000): self._sync_iter = iter(data) def _fill_buffer(self, target_index: Union[int, slice, None] = None) -> None: - """TODO: Add docstring.""" + """Helper function to fill buffer.""" if self._fully_buffered: return @@ -39,7 +39,7 @@ def _fill_buffer(self, target_index: Union[int, slice, None] = None) -> None: self._fully_buffered = True def __getitem__(self, index: Union[int, slice]) -> Union[T, List[T]]: - """TODO: Add docstring.""" + """Helper function to getitem .""" if isinstance(index, slice): if index.stop is None or index.stop < 0: self._fill_buffer() @@ -52,12 +52,12 @@ def __getitem__(self, index: Union[int, slice]) -> Union[T, List[T]]: return self._buffer[index] def __len__(self) -> int: - """TODO: Add docstring.""" + """Helper function to len .""" self._fill_buffer() return len(self._buffer) def __iter__(self) -> Iterator[T]: - """TODO: Add docstring.""" + """Helper function to iter .""" # Yield from buffer first yield from self._buffer # Then from source, adding to buffer @@ -73,7 +73,7 @@ def __iter__(self) -> Iterator[T]: self._fully_buffered = True async def __aiter__(self) -> AsyncIterator[T]: - """TODO: Add docstring.""" + """Helper function to aiter .""" # Yield from buffer first for item in self._buffer: yield item @@ -91,32 +91,32 @@ async def __aiter__(self) -> AsyncIterator[T]: self._fully_buffered = True def __eq__(self, other: Any) -> bool: - """TODO: Add docstring.""" + """Helper function to eq .""" self._fill_buffer() if isinstance(other, list): return self._buffer == other return super().__eq__(other) def __await__(self): - """TODO: Add docstring.""" + """Helper function to await .""" # Handle incorrect awaiting by gracefully returning self so test assertions can pass. async def _mock_coroutine(): - """TODO: Add docstring.""" + """Helper function to mock coroutine.""" return self return _mock_coroutine().__await__() def unified_paginator_factory(monkeypatch, module, items, is_async=False): - """TODO: Add docstring.""" + """Helper function to unified paginator factory.""" captured = {"count": 0} class DummyPaginator(StreamingMockWrapper): - """TODO: Add docstring.""" + """Test suite for DummyPaginator.""" def __init__(self, client, path, params=None, page_size=100, **kwargs): - """TODO: Add docstring.""" + """Initialize the test object.""" super().__init__(items) captured["client"] = client captured["path"] = path diff --git a/tests/utils/test_fake_data.py b/tests/utils/test_fake_data.py index e1937d92..87e79109 100644 --- a/tests/utils/test_fake_data.py +++ b/tests/utils/test_fake_data.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for fake data.""" from types import SimpleNamespace from typing import Any, cast @@ -23,42 +23,42 @@ def test_fake_subject_parses() -> None: - """TODO: Add docstring.""" + """Test that fake subject parses.""" data = fake_data.fake_subject() obj = Subject.from_json(data) assert isinstance(obj, Subject) def test_fake_site_parses() -> None: - """TODO: Add docstring.""" + """Test that fake site parses.""" data = fake_data.fake_site() obj = Site.from_json(data) assert isinstance(obj, Site) def test_fake_interval_parses() -> None: - """TODO: Add docstring.""" + """Test that fake interval parses.""" data = fake_data.fake_interval() obj = Interval.from_json(data) assert isinstance(obj, Interval) def test_fake_query_parses() -> None: - """TODO: Add docstring.""" + """Test that fake query parses.""" data = fake_data.fake_query() obj = Query.from_json(data) assert isinstance(obj, Query) def test_fake_record_parses() -> None: - """TODO: Add docstring.""" + """Test that fake record parses.""" data = fake_data.fake_record() obj = Record.from_json(data) assert isinstance(obj, Record) def test_fake_record_with_schema() -> None: - """TODO: Add docstring.""" + """Test that fake record with schema.""" cache = SchemaCache() var = Variable(variable_name="age", variable_type="integer", form_id=1, form_key="F1") object.__setattr__(var, "required", True) @@ -72,63 +72,63 @@ def test_fake_record_with_schema() -> None: def test_fake_form_parses() -> None: - """TODO: Add docstring.""" + """Test that fake form parses.""" data = fake_data.fake_form() obj = Form.from_json(data) assert isinstance(obj, Form) def test_fake_variable_parses() -> None: - """TODO: Add docstring.""" + """Test that fake variable parses.""" data = fake_data.fake_variable() obj = Variable.from_json(data) assert isinstance(obj, Variable) def test_fake_visit_parses() -> None: - """TODO: Add docstring.""" + """Test that fake visit parses.""" data = fake_data.fake_visit() obj = Visit.from_json(data) assert isinstance(obj, Visit) def test_fake_coding_parses() -> None: - """TODO: Add docstring.""" + """Test that fake coding parses.""" data = fake_data.fake_coding() obj = Coding.from_json(data) assert isinstance(obj, Coding) def test_fake_record_revision_parses() -> None: - """TODO: Add docstring.""" + """Test that fake record revision parses.""" data = fake_data.fake_record_revision() obj = RecordRevision.from_json(data) assert isinstance(obj, RecordRevision) def test_fake_study_parses() -> None: - """TODO: Add docstring.""" + """Test that fake study parses.""" data = fake_data.fake_study() obj = Study.model_validate(data) assert isinstance(obj, Study) def test_fake_job_parses() -> None: - """TODO: Add docstring.""" + """Test that fake job parses.""" data = fake_data.fake_job() obj = Job.from_json(data) assert isinstance(obj, Job) def test_fake_user_parses() -> None: - """TODO: Add docstring.""" + """Test that fake user parses.""" data = fake_data.fake_user() obj = User.from_json(data) assert isinstance(obj, User) def test_fake_forms_for_cache_returns_forms() -> None: - """TODO: Add docstring.""" + """Test that fake forms for cache returns forms.""" forms = fake_data.fake_forms_for_cache(2, study_key="S") assert len(forms) == 2 assert all(isinstance(f, Form) for f in forms) @@ -136,14 +136,14 @@ def test_fake_forms_for_cache_returns_forms() -> None: def test_fake_variables_for_cache_and_schema_refresh() -> None: - """TODO: Add docstring.""" + """Test that fake variables for cache and schema refresh.""" forms = fake_data.fake_forms_for_cache(1) variables = fake_data.fake_variables_for_cache(forms, vars_per_form=1) forms_ep = SimpleNamespace(list=lambda **_: forms) def list_vars(*_, form_id=None, **__): - """TODO: Add docstring.""" + """Helper function to list vars.""" return [v for v in variables if form_id is None or v.form_id == form_id] vars_ep = SimpleNamespace(list=list_vars) @@ -159,7 +159,7 @@ def list_vars(*_, form_id=None, **__): def test_fake_forms_for_cache_from_json() -> None: - """TODO: Add docstring.""" + """Test that fake forms for cache from json.""" forms = fake_data.fake_forms_for_cache(2) for form in forms: parsed = Form.from_json(form.model_dump(by_alias=True)) @@ -167,7 +167,7 @@ def test_fake_forms_for_cache_from_json() -> None: def test_fake_variables_for_cache_from_json() -> None: - """TODO: Add docstring.""" + """Test that fake variables for cache from json.""" forms = fake_data.fake_forms_for_cache(1) variables = fake_data.fake_variables_for_cache(forms, vars_per_form=2) for var in variables: @@ -176,7 +176,7 @@ def test_fake_variables_for_cache_from_json() -> None: def test_validate_record_data_with_cached_schema() -> None: - """TODO: Add docstring.""" + """Test that validate record data with cached schema.""" forms = fake_data.fake_forms_for_cache(1) variables = fake_data.fake_variables_for_cache(forms, vars_per_form=1) variables[0].variable_type = "integer" @@ -184,7 +184,7 @@ def test_validate_record_data_with_cached_schema() -> None: forms_ep = SimpleNamespace(list=lambda **_: forms) def list_vars(*_, form_id=None, **__): - """TODO: Add docstring.""" + """Helper function to list vars.""" return [v for v in variables if form_id is None or v.form_id == form_id] vars_ep = SimpleNamespace(list=list_vars) diff --git a/tests/utils/test_lazy_attrs.py b/tests/utils/test_lazy_attrs.py index c39bce4a..634ab427 100644 --- a/tests/utils/test_lazy_attrs.py +++ b/tests/utils/test_lazy_attrs.py @@ -1,10 +1,10 @@ -"""TODO: Add docstring.""" +"""Unit tests for lazy attrs.""" from imednet.utils import records_to_dataframe from imednet.validation.cache import SchemaCache def test_lazy_attrs_available() -> None: - """TODO: Add docstring.""" + """Test that lazy attrs available.""" assert callable(records_to_dataframe) assert isinstance(SchemaCache, type) diff --git a/tests/workflows/__init__.py b/tests/workflows/__init__.py index a9cca0f7..fae6326f 100644 --- a/tests/workflows/__init__.py +++ b/tests/workflows/__init__.py @@ -1 +1 @@ -"""TODO: Add docstring.""" +"""Test package initialization.""" diff --git a/tests/workflows/conftest.py b/tests/workflows/conftest.py index 37e65de3..8cecc438 100644 --- a/tests/workflows/conftest.py +++ b/tests/workflows/conftest.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for conftest.""" import types @@ -10,13 +10,13 @@ @pytest.fixture def schema() -> SchemaCache: - """TODO: Add docstring.""" + """Helper function to schema.""" forms = fake_data.fake_forms_for_cache(1, study_key="S") variables = fake_data.fake_variables_for_cache(forms, vars_per_form=1, study_key="S") forms_ep = types.SimpleNamespace(list=lambda **_: forms) def list_vars(*_, form_id=None, **__): - """TODO: Add docstring.""" + """Helper function to list vars.""" return [v for v in variables if form_id is None or v.form_id == form_id] vars_ep = types.SimpleNamespace(list=list_vars) diff --git a/tests/workflows/test_data_extraction.py b/tests/workflows/test_data_extraction.py index 0db66385..f9c6c96d 100644 --- a/tests/workflows/test_data_extraction.py +++ b/tests/workflows/test_data_extraction.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for data extraction.""" from unittest.mock import MagicMock @@ -11,7 +11,7 @@ def test_extract_records_by_criteria_filters_subject_and_visit(schema) -> None: - """TODO: Add docstring.""" + """Test that extract records by criteria filters subject and visit.""" sdk = MagicMock() s1 = Subject.from_json(fake_data.fake_subject()) s2 = Subject.from_json(fake_data.fake_subject()) @@ -59,7 +59,7 @@ def test_extract_records_by_criteria_filters_subject_and_visit(schema) -> None: def test_extract_audit_trail_builds_filters_and_dates() -> None: - """TODO: Add docstring.""" + """Test that extract audit trail builds filters and dates.""" sdk = MagicMock() revision = RecordRevision.from_json(fake_data.fake_record_revision()) sdk.get_record_revisions.return_value = [revision] diff --git a/tests/workflows/test_query_management.py b/tests/workflows/test_query_management.py index e83b24ea..b45e69f7 100644 --- a/tests/workflows/test_query_management.py +++ b/tests/workflows/test_query_management.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for query management.""" from unittest.mock import MagicMock @@ -9,13 +9,13 @@ def make_query(sequence_closed: list[tuple[int, bool]]) -> Query: - """TODO: Add docstring.""" + """Helper function to make query.""" comments = [QueryComment(sequence=seq, closed=closed) for seq, closed in sequence_closed] return Query(query_comments=comments) def test_get_open_queries_filters_latest_comment() -> None: - """TODO: Add docstring.""" + """Test that get open queries filters latest comment.""" sdk = MagicMock() query_closed = make_query([(1, False), (2, True)]) query_open = make_query([(1, False)]) @@ -31,7 +31,7 @@ def test_get_open_queries_filters_latest_comment() -> None: def test_get_queries_for_subject_builds_combined_filter() -> None: - """TODO: Add docstring.""" + """Test that get queries for subject builds combined filter.""" sdk = MagicMock() wf = QueryManagementWorkflow(sdk) wf.get_queries_for_subject("STUDY", "SUBJ1", additional_filter={"type": "x"}) @@ -41,7 +41,7 @@ def test_get_queries_for_subject_builds_combined_filter() -> None: def test_get_query_state_counts_aggregates_states() -> None: - """TODO: Add docstring.""" + """Test that get query state counts aggregates states.""" sdk = MagicMock() open_query = make_query([(1, False)]) closed_query = make_query([(1, True)]) @@ -57,7 +57,7 @@ def test_get_query_state_counts_aggregates_states() -> None: def test_get_queries_by_site_filters_using_subjects() -> None: - """TODO: Add docstring.""" + """Test that get queries by site filters using subjects.""" sdk = MagicMock() s1 = Subject.from_json(fake_data.fake_subject()) s2 = Subject.from_json(fake_data.fake_subject()) @@ -74,7 +74,7 @@ def test_get_queries_by_site_filters_using_subjects() -> None: def test_get_queries_by_site_returns_empty_if_no_subjects() -> None: - """TODO: Add docstring.""" + """Test that get queries by site returns empty if no subjects.""" sdk = MagicMock() sdk.get_subjects.return_value = [] wf = QueryManagementWorkflow(sdk) @@ -87,7 +87,7 @@ def test_get_queries_by_site_returns_empty_if_no_subjects() -> None: def test_get_queries_by_site_with_space_in_name() -> None: - """TODO: Add docstring.""" + """Test that get queries by site with space in name.""" sdk = MagicMock() s = Subject.from_json(fake_data.fake_subject()) s.subject_key = "S1" diff --git a/tests/workflows/test_record_update.py b/tests/workflows/test_record_update.py index ac2cb41d..a915615c 100644 --- a/tests/workflows/test_record_update.py +++ b/tests/workflows/test_record_update.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for record update.""" import asyncio import types @@ -15,7 +15,7 @@ def _build_schema() -> tuple[SchemaCache, Variable]: - """TODO: Add docstring.""" + """Helper function to build schema.""" forms = fake_data.fake_forms_for_cache(1, study_key="S") variables = fake_data.fake_variables_for_cache(forms, vars_per_form=1, study_key="S") var = variables[0] @@ -24,7 +24,7 @@ def _build_schema() -> tuple[SchemaCache, Variable]: forms_ep = types.SimpleNamespace(list=lambda **_: forms) def list_vars(*_, form_id=None, **__): - """TODO: Add docstring.""" + """Helper function to list vars.""" return [v for v in variables if form_id is None or v.form_id == form_id] vars_ep = types.SimpleNamespace(list=list_vars) @@ -37,7 +37,7 @@ def list_vars(*_, form_id=None, **__): @pytest.mark.parametrize("async_mode", [False, True]) def test_create_or_update_records_no_wait(schema: SchemaCache, async_mode: bool) -> None: - """TODO: Add docstring.""" + """Test that create or update records no wait.""" sdk = MagicMock() job = Job(batch_id="1", state="PROCESSING") if not async_mode: @@ -64,7 +64,7 @@ def test_create_or_update_records_no_wait(schema: SchemaCache, async_mode: bool) @pytest.mark.parametrize("async_mode", [False, True]) def test_create_or_update_records_validation(async_mode: bool) -> None: - """TODO: Add docstring.""" + """Test that create or update records validation.""" schema, var = _build_schema() sdk = MagicMock() if async_mode: @@ -122,7 +122,7 @@ def test_create_or_update_records_validation(async_mode: bool) -> None: @pytest.mark.parametrize("async_mode", [False, True]) def test_create_or_update_records_unknown_form_key(async_mode: bool) -> None: - """TODO: Add docstring.""" + """Test that create or update records unknown form key.""" sdk = MagicMock() if async_mode: sdk._async_client = object() @@ -160,7 +160,7 @@ def test_create_or_update_records_unknown_form_key(async_mode: bool) -> None: @pytest.mark.parametrize("async_mode", [False, True]) def test_create_or_update_records_refresh_and_validate(async_mode: bool) -> None: - """TODO: Add docstring.""" + """Test that create or update records refresh and validate.""" sdk = MagicMock() job = Job(batch_id="1", state="PROCESSING") if not async_mode: @@ -226,7 +226,7 @@ def test_create_or_update_records_refresh_and_validate(async_mode: bool) -> None def test_create_or_update_records_wait_for_completion( async_mode: bool, monkeypatch: pytest.MonkeyPatch ) -> None: - """TODO: Add docstring.""" + """Test that create or update records wait for completion.""" sdk = MagicMock() initial_job = Job(batch_id="1", state="PROCESSING") completed_job = Job(batch_id="1", state="COMPLETED") diff --git a/tests/workflows/test_register_subjects.py b/tests/workflows/test_register_subjects.py index c77ffdd5..2ad99c44 100644 --- a/tests/workflows/test_register_subjects.py +++ b/tests/workflows/test_register_subjects.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for register subjects.""" from unittest.mock import MagicMock @@ -12,7 +12,7 @@ def test_register_subjects_passes_records_correctly(schema) -> None: - """TODO: Add docstring.""" + """Test that register subjects passes records correctly.""" sdk = MagicMock() job = Job(jobId="1", batchId="1", state="PROCESSING") sdk.create_record.return_value = job @@ -38,7 +38,7 @@ def test_register_subjects_passes_records_correctly(schema) -> None: def test_register_subjects_validation_errors() -> None: - """TODO: Add docstring.""" + """Test that register subjects validation errors.""" sdk = MagicMock() sdk.get_sites.return_value = [ Site(studyKey="S", siteId=1, siteName="VALID_SITE", siteEnrollmentStatus="Active") diff --git a/tests/workflows/test_subject_data.py b/tests/workflows/test_subject_data.py index d953a294..7a7eb08d 100644 --- a/tests/workflows/test_subject_data.py +++ b/tests/workflows/test_subject_data.py @@ -1,4 +1,4 @@ -"""TODO: Add docstring.""" +"""Unit tests for subject data.""" from unittest.mock import MagicMock @@ -11,7 +11,7 @@ def test_get_all_subject_data_aggregates_across_endpoints(schema) -> None: - """TODO: Add docstring.""" + """Test that get all subject data aggregates across endpoints.""" sdk = MagicMock() subject = Subject.from_json(fake_data.fake_subject()) visit = Visit.from_json(fake_data.fake_visit()) @@ -49,7 +49,7 @@ def test_get_all_subject_data_aggregates_across_endpoints(schema) -> None: def test_get_all_subject_data_returns_empty_results() -> None: - """TODO: Add docstring.""" + """Test that get all subject data returns empty results.""" sdk = MagicMock() sdk.get_subjects.return_value = [] sdk.get_visits.return_value = []