import unittest from app.tourism import compute_tourism_signal class TourismSignalTests(unittest.TestCase): def test_theme_surprise_is_mean_of_standardized_observations(self): snapshot = { "as_of": "2026-08-21", "source": { "source_id": "fixture.tourism", "source_url": "https://example.invalid/tourism", "published_at": "2026-08-21T08:00:00Z", "retrieved_at": "2026-08-21T08:05:00Z", "vintage_id": "fixture-1", }, "observations": [ {"metric_key": "arrivals_yoy", "value": 12, "expected": 8, "scale": 2, "unit": "percent"}, {"metric_key": "airport_passengers_yoy", "value": 8, "expected": 6, "scale": 2, "unit": "percent"}, ], "exposures": [], } result = compute_tourism_signal(snapshot) self.assertAlmostEqual(result["theme_surprise"], 1.5) self.assertEqual(result["data_quality"], "fixture") def test_exposure_score_and_rank_are_deterministic(self): snapshot = { "as_of": "2026-08-21", "source": { "source_id": "fixture.tourism", "source_url": "https://example.invalid/tourism", "published_at": "2026-08-21T08:00:00Z", "retrieved_at": "2026-08-21T08:05:00Z", "vintage_id": "fixture-1", }, "observations": [ {"metric_key": "arrivals_yoy", "value": 12, "expected": 8, "scale": 2, "unit": "percent"}, ], "exposures": [ {"symbol": "AOT", "coefficient": 1.0, "confidence": 0.95, "evidence": "airport"}, {"symbol": "MINT", "coefficient": 0.6, "confidence": 0.80, "evidence": "hotel"}, {"symbol": "PTT", "coefficient": -0.2, "confidence": 0.60, "evidence": "control"}, ], } result = compute_tourism_signal(snapshot) self.assertEqual([item["symbol"] for item in result["signals"]], ["AOT", "MINT", "PTT"]) self.assertEqual(result["signals"][0]["side"], "LONG") self.assertEqual(result["signals"][-1]["side"], "SHORT") self.assertGreater(result["signals"][0]["score"], result["signals"][1]["score"]) self.assertEqual(result["signals"][0]["reason_codes"], ["TOURISM_SURPRISE", "AIRPORT"]) def test_missing_scale_is_rejected(self): snapshot = { "as_of": "2026-08-21", "source": {}, "observations": [{"metric_key": "arrivals_yoy", "value": 10, "expected": 8}], "exposures": [], } with self.assertRaises(ValueError): compute_tourism_signal(snapshot) if __name__ == "__main__": unittest.main()