| """Runtime validation for data contracts.""" |
|
|
| from datetime import datetime, timezone |
|
|
| import pandas as pd |
| import pytest |
|
|
| from TerraFin.data.contracts import ( |
| CalendarEvent, |
| EventList, |
| FilingDocument, |
| FinancialStatementFrame, |
| IndicatorSnapshot, |
| TOCEntry, |
| ) |
|
|
|
|
| def test_toc_entry_valid(): |
| e = TOCEntry(id="a", title="Item 1", level=0, anchor="item-1") |
| assert e.level == 0 |
|
|
|
|
| def test_toc_entry_negative_level_rejected(): |
| with pytest.raises(ValueError): |
| TOCEntry(id="a", title="x", level=-1, anchor="x") |
|
|
|
|
| def test_filing_document_valid(): |
| doc = FilingDocument( |
| ticker="AAPL", |
| filing_type="10-K", |
| accession="0000320193-24-000123", |
| filing_date="2024-01-15", |
| markdown="# hello", |
| toc=[], |
| ) |
| assert doc.ticker == "AAPL" |
|
|
|
|
| def test_filing_document_invalid_filing_type(): |
| with pytest.raises(ValueError): |
| FilingDocument( |
| ticker="AAPL", |
| filing_type="invalid", |
| accession="x", |
| filing_date="2024-01-15", |
| markdown="", |
| toc=[], |
| ) |
|
|
|
|
| def test_filing_document_invalid_filing_date(): |
| with pytest.raises(ValueError): |
| FilingDocument( |
| ticker="AAPL", |
| filing_type="10-K", |
| accession="x", |
| filing_date="not-a-date", |
| markdown="", |
| toc=[], |
| ) |
|
|
|
|
| def test_filing_document_empty_accession_rejected(): |
| with pytest.raises(ValueError): |
| FilingDocument( |
| ticker="AAPL", |
| filing_type="10-K", |
| accession="", |
| filing_date="2024-01-15", |
| markdown="", |
| toc=[], |
| ) |
|
|
|
|
| def test_filing_document_make_empty(): |
| doc = FilingDocument.make_empty("AAPL", "10-K") |
| assert doc.ticker == "AAPL" |
| assert doc.accession == "" |
|
|
|
|
| def test_calendar_event_valid(): |
| ev = CalendarEvent( |
| id="1", |
| title="x", |
| start=datetime(2026, 1, 1, tzinfo=timezone.utc), |
| category="macro", |
| importance="low", |
| display_time="", |
| ) |
| assert ev.id == "1" |
|
|
|
|
| def test_calendar_event_naive_datetime_rejected(): |
| with pytest.raises(ValueError): |
| CalendarEvent( |
| id="1", |
| title="x", |
| start=datetime(2026, 1, 1), |
| category="macro", |
| importance="low", |
| display_time="", |
| ) |
|
|
|
|
| def test_calendar_event_invalid_category(): |
| with pytest.raises(ValueError): |
| CalendarEvent( |
| id="1", |
| title="x", |
| start=datetime(2026, 1, 1, tzinfo=timezone.utc), |
| category="invalid", |
| importance="low", |
| display_time="", |
| ) |
|
|
|
|
| def test_calendar_event_invalid_importance(): |
| with pytest.raises(ValueError): |
| CalendarEvent( |
| id="1", |
| title="x", |
| start=datetime(2026, 1, 1, tzinfo=timezone.utc), |
| category="macro", |
| importance="invalid", |
| display_time="", |
| ) |
|
|
|
|
| def test_event_list_make_empty(): |
| el = EventList.make_empty() |
| assert len(el) == 0 |
|
|
|
|
| def test_event_list_non_list_rejected(): |
| with pytest.raises(ValueError): |
| EventList(events="not a list") |
|
|
|
|
| def test_financial_statement_frame_valid_dates(): |
| df = pd.DataFrame({"2024-01-01": [1.0], "2023-01-01": [2.0]}, index=["revenue"]) |
| fsf = FinancialStatementFrame(df, statement_type="income", period="annual", ticker="AAPL") |
| assert fsf.ticker == "AAPL" |
|
|
|
|
| def test_financial_statement_frame_non_date_columns_rejected(): |
| df = pd.DataFrame({"not_a_date": [1.0]}, index=["revenue"]) |
| with pytest.raises(ValueError): |
| FinancialStatementFrame(df, statement_type="income", period="annual", ticker="AAPL") |
|
|
|
|
| def test_indicator_snapshot_make_empty(): |
| snap = IndicatorSnapshot.make_empty() |
| assert snap.name == "" |
| assert snap.as_of == "" |
|
|