""" Integration tests for GET /api/windows/ — the reverse ephemeris lookup (Set the Game Clock narrowing, EarthmanRPG roadmap step 21). The endpoint folds `placements` (Planet:Sign pairs) into the intersected date windows where every placement holds simultaneously, bounded by the game window (settings GAME_WINDOW_START/END — defaults span the precomputed snapshot range, 1781-03-13 → 2100-12-31), and reports which signs the `next` planet can reach within them. Tests override the game window to a tight decade so the real ephemeris scan stays fast + deterministic. Run: pyswiss/.venv/Scripts/python pyswiss/manage.py test apps.charts """ from django.test import SimpleTestCase, override_settings @override_settings(GAME_WINDOW_START='1990-01-01', GAME_WINDOW_END='2000-01-01') class WindowsApiTest(SimpleTestCase): def test_empty_placements_returns_the_full_game_window(self): response = self.client.get('/api/windows/') self.assertEqual(response.status_code, 200) data = response.json() self.assertEqual(len(data['windows']), 1) self.assertTrue(data['windows'][0]['start'].startswith('1990-01-01')) self.assertTrue(data['windows'][0]['end'].startswith('2000-01-01')) self.assertAlmostEqual(data['days'], 3652, delta=2) def test_placements_narrow_the_windows(self): response = self.client.get( '/api/windows/', {'placements': 'Uranus:Aquarius,Saturn:Pisces'}, ) self.assertEqual(response.status_code, 200) data = response.json() self.assertGreaterEqual(len(data['windows']), 1) self.assertLess(data['days'], 500) for w in data['windows']: self.assertLess(w['start'], w['end']) def test_next_reports_reachable_signs(self): response = self.client.get( '/api/windows/', {'placements': 'Saturn:Pisces', 'next': 'Jupiter'}, ) self.assertEqual(response.status_code, 200) nxt = response.json()['next'] self.assertEqual(nxt['planet'], 'Jupiter') self.assertEqual(len(nxt['signs']), 12) reachable = [s for s, ok in nxt['signs'].items() if ok] # Jupiter (1-year residence) reaches SOME but not ALL signs inside # Saturn's ~3-year Pisces windows. self.assertGreater(len(reachable), 0) self.assertLess(len(reachable), 12) def test_unreachable_placement_yields_empty_windows(self): response = self.client.get( '/api/windows/', {'placements': 'Saturn:Leo', 'next': 'Jupiter'}) self.assertEqual(response.status_code, 200) data = response.json() self.assertEqual(data['windows'], []) self.assertEqual(data['days'], 0) self.assertEqual( [s for s, ok in data['next']['signs'].items() if ok], []) def test_invalid_planet_400(self): self.assertEqual(self.client.get( '/api/windows/', {'placements': 'Vulcan:Aries'}).status_code, 400) def test_invalid_sign_400(self): self.assertEqual(self.client.get( '/api/windows/', {'placements': 'Saturn:Notasign'}).status_code, 400) def test_invalid_next_400(self): self.assertEqual(self.client.get( '/api/windows/', {'next': 'Vulcan'}).status_code, 400) def test_malformed_placements_400(self): self.assertEqual(self.client.get( '/api/windows/', {'placements': 'SaturnPisces'}).status_code, 400)