from django.core.exceptions import ValidationError from django.template import Context, Template from django.test import RequestFactory, TestCase from apps.pages.maps import resolve_city from apps.pages.models import MapMembership, MapPerson, MapPlacement, PeopleMap class PeopleMapTests(TestCase): def setUp(self): self.world = PeopleMap.objects.create(title='Our global network') self.person = MapPerson.objects.create(name='', institution='Institute') def test_offline_city_and_country_resolution(self): lat, lon = resolve_city('CA', 'Vancouver') self.assertAlmostEqual(lat, 49.24966, places=2) self.assertAlmostEqual(lon, -123.11934, places=2) self.assertEqual(resolve_city('Canada', 'Vancouver'), (lat, lon)) def test_invalid_or_ambiguous_city_is_rejected(self): for country, city in [('Canada', 'Not a real city'), ('Unknown country', 'Paris'), ('US', 'Springfield')]: with self.subTest(country=country, city=city), self.assertRaises(ValidationError): resolve_city(country, city) def test_membership_saves_resolved_coordinates(self): member = MapMembership.objects.create(people_map=self.world, person=self.person, country='CA', city='Vancouver') self.assertLess(member.longitude, -120) member.city = 'Toronto' member.save() member.refresh_from_db() self.assertGreater(member.longitude, -80) def test_explicit_coordinates_and_invalid_ranges(self): member = MapMembership(people_map=self.world, person=self.person, location_method='coordinates', latitude=0, longitude=0) member.full_clean() for latitude, longitude in [(91, 0), (0, -181), (None, 0), (float('nan'), 0), (0, float('inf'))]: member.latitude, member.longitude = latitude, longitude with self.subTest(latitude=latitude, longitude=longitude), self.assertRaises(ValidationError): member.full_clean() def test_different_maps_can_have_different_members(self): second = PeopleMap.objects.create(title='Other map') MapMembership.objects.create(people_map=self.world, person=self.person, location_method='coordinates', latitude=0, longitude=0) self.assertEqual(second.memberships.count(), 0) with self.assertRaises(ValidationError): MapMembership.objects.create(people_map=self.world, person=self.person, location_method='coordinates', latitude=1, longitude=1) def test_placement_path_validation(self): for path in ['https://example.com/', '//example.com/', '/about/?a=1', '/about/#x']: with self.subTest(path=path), self.assertRaises(ValidationError): MapPlacement(people_map=self.world, page_path=path).full_clean() def render_maps(self, path, position='bottom'): request = RequestFactory().get(path) return Template('{% load people_maps %}{% people_maps position %}').render(Context({'request': request, 'position': position})) def test_placement_filters_and_escaped_person_data(self): MapPlacement.objects.create(people_map=self.world, page_path='/about/') MapMembership.objects.create(people_map=self.world, person=self.person, location_method='coordinates', latitude=0, longitude=0) html = self.render_maps('/about/') self.assertIn('Our global network', html) self.assertIn('<script>', html) self.assertNotIn('