tests.py 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. import json
  2. import warnings
  3. from django.core import mail
  4. from django.contrib.auth.models import User
  5. from django.test import TestCase, Client, override_settings
  6. from contribmap.models import Contrib
  7. from contribmap.forms import PublicContribForm
  8. class APITestClient(Client):
  9. def json_get(self, *args, **kwargs):
  10. """ Annotate the response with a .data containing parsed JSON
  11. """
  12. response = super().get(*args, **kwargs)
  13. response.data = json.loads(response.content.decode('utf-8'))
  14. return response
  15. class APITestCase(TestCase):
  16. def setUp(self):
  17. super().setUp()
  18. self.client = APITestClient()
  19. class TestContrib(TestCase):
  20. def test_comma_separatedcharfield(self):
  21. co = Contrib(name='foo', orientations=['SO', 'NE'],
  22. contrib_type=Contrib.CONTRIB_CONNECT,
  23. latitude=0.5, longitude=0.5,
  24. )
  25. co.save()
  26. self.assertEqual(
  27. Contrib.objects.get(name='foo').orientations,
  28. ['SO', 'NE'])
  29. co.orientations = ['S']
  30. co.save()
  31. class TestContribPrivacy(TestCase):
  32. def test_always_private_field(self):
  33. c = Contrib.objects.create(
  34. name='John',
  35. phone='010101010101',
  36. contrib_type=Contrib.CONTRIB_CONNECT,
  37. latitude=0.5,
  38. longitude=0.5,
  39. )
  40. self.assertEqual(c.get_public_field('phone'), None)
  41. def test_public_field(self):
  42. c = Contrib.objects.create(
  43. name='John',
  44. phone='010101010101',
  45. contrib_type=Contrib.CONTRIB_CONNECT,
  46. privacy_name=True,
  47. latitude=0.5,
  48. longitude=0.5,
  49. )
  50. self.assertEqual(c.get_public_field('name'), 'John')
  51. def test_public_callable_field(self):
  52. c = Contrib.objects.create(
  53. name='John',
  54. phone='010101010101',
  55. orientations=['N'],
  56. contrib_type=Contrib.CONTRIB_CONNECT,
  57. privacy_name=True,
  58. latitude=0.5,
  59. longitude=0.5,
  60. )
  61. self.assertEqual(c.get_public_field('angles'), [[-23, 22]])
  62. def test_private_field(self):
  63. c = Contrib.objects.create(
  64. name='John',
  65. phone='010101010101',
  66. contrib_type=Contrib.CONTRIB_CONNECT,
  67. latitude=0.5,
  68. longitude=0.5,
  69. )
  70. self.assertEqual(c.privacy_name, False)
  71. self.assertEqual(c.get_public_field('name'), None)
  72. class TestViews(APITestCase):
  73. def mk_contrib_post_data(self, *args, **kwargs):
  74. post_data = {
  75. 'roof': True,
  76. 'privacy_place_details': True,
  77. 'privacy_coordinates': True,
  78. 'phone': '0202020202',
  79. 'orientations': ('N', 'NO', 'O', 'SO', 'S', 'SE', 'E', 'NE'),
  80. 'orientation': 'all',
  81. 'name': 'JohnCleese',
  82. 'longitude': -1.553621,
  83. 'latitude': 47.218371,
  84. 'floor_total': '2',
  85. 'floor': 1,
  86. 'email': 'coucou@example.com',
  87. 'contrib_type': 'connect',
  88. 'connect_local': 'on',
  89. }
  90. post_data.update(kwargs)
  91. return post_data
  92. def test_public_json(self):
  93. response = self.client.json_get('/map/public.json')
  94. self.assertEqual(response.status_code, 200)
  95. self.assertEqual(len(response.data['features']), 0)
  96. Contrib.objects.create(
  97. name='John',
  98. phone='010101010101',
  99. contrib_type=Contrib.CONTRIB_CONNECT,
  100. privacy_coordinates=True,
  101. latitude=0.5,
  102. longitude=0.5,
  103. )
  104. response = self.client.json_get('/map/public.json')
  105. self.assertEqual(response.status_code, 200)
  106. self.assertEqual(len(response.data['features']), 1)
  107. def test_private_json(self):
  108. self.client.force_login(
  109. User.objects.create(username='foo', is_staff=False))
  110. response = self.client.get('/map/private.json')
  111. self.assertEqual(response.status_code, 403)
  112. def test_private_json_staff(self):
  113. self.client.force_login(
  114. User.objects.create(username='foo', is_staff=True))
  115. response = self.client.get('/map/private.json')
  116. self.assertEqual(response.status_code, 200)
  117. @override_settings(NOTIFICATION_EMAILS=['foo@example.com'])
  118. def test_add_contrib_sends_moderator_email(self):
  119. post_data = self.mk_contrib_post_data({'name': 'JohnCleese'})
  120. del post_data['email']
  121. response = self.client.post('/map/contribute', post_data)
  122. self.assertEqual(response.status_code, 302)
  123. self.assertEqual(len(mail.outbox), 1)
  124. self.assertIn('JohnCleese', mail.outbox[0].subject)
  125. self.assertIn('JohnCleese', mail.outbox[0].body)
  126. class TestForms(TestCase):
  127. valid_data = {
  128. 'roof': True,
  129. 'privacy_place_details': True,
  130. 'privacy_coordinates': True,
  131. 'orientations': ['N'],
  132. 'orientation': 'all',
  133. 'name': 'JohnCleese',
  134. 'longitude': -1.553621,
  135. 'email': 'foo@example.com',
  136. 'phone': '0202020202',
  137. 'latitude': 47.218371,
  138. 'floor_total': '2',
  139. 'floor': 1,
  140. 'contrib_type': 'connect',
  141. 'connect_local': 'on',
  142. }
  143. def test_contact_validation(self):
  144. no_contact, phone_contact, email_contact, both_contact = [
  145. self.valid_data.copy() for i in range(4)]
  146. del phone_contact['email']
  147. del email_contact['phone']
  148. del no_contact['phone']
  149. del no_contact['email']
  150. both_contact.update(phone_contact)
  151. both_contact.update(email_contact)
  152. self.assertFalse(PublicContribForm(no_contact).is_valid())
  153. self.assertTrue(PublicContribForm(phone_contact).is_valid())
  154. self.assertTrue(PublicContribForm(email_contact).is_valid())
  155. self.assertTrue(PublicContribForm(both_contact).is_valid())
  156. def test_floors_validation(self):
  157. invalid_floors = self.valid_data.copy()
  158. invalid_floors['floor'] = 2
  159. invalid_floors['floor_total'] = 1
  160. self.assertFalse(PublicContribForm(invalid_floors).is_valid())
  161. self.assertTrue(PublicContribForm(self.valid_data).is_valid())
  162. invalid_floors['floor'] = None
  163. invalid_floors['floor_total'] = None
  164. self.assertTrue(PublicContribForm(invalid_floors).is_valid())
  165. def test_share_fields_validation(self):
  166. data = self.valid_data.copy()
  167. data['contrib_type'] = 'share'
  168. self.assertFalse(PublicContribForm(data).is_valid())
  169. data['access_type'] = 'cable'
  170. self.assertTrue(PublicContribForm(data).is_valid())
  171. @override_settings(NOTIFICATION_EMAILS=['foo@example.com'])
  172. def test_add_contrib_like_a_robot(self):
  173. response = self.client.post('/map/contribute', {
  174. 'roof': True,
  175. 'human_field': 'should not have no value',
  176. 'privacy_place_details': True,
  177. 'privacy_coordinates': True,
  178. 'phone': '0202020202',
  179. 'orientations': 'N',
  180. 'orientations': 'NO',
  181. 'orientations': 'O',
  182. 'orientations': 'SO',
  183. 'orientations': 'S',
  184. 'orientations': 'SE',
  185. 'orientations': 'E',
  186. 'orientations': 'NE',
  187. 'orientation': 'all',
  188. 'name': 'JohnCleese',
  189. 'longitude': -1.553621,
  190. 'latitude': 47.218371,
  191. 'floor_total': '2',
  192. 'floor': 1,
  193. 'email': 'coucou@example.com',
  194. 'contrib_type': 'connect',
  195. 'connect_local': 'on',
  196. })
  197. self.assertEqual(response.status_code, 403)
  198. self.assertEqual(len(mail.outbox), 0)
  199. class TestDataImport(TestCase):
  200. fixtures = ['bottle_data.yaml']
  201. @classmethod
  202. def setUpClass(cls, *args, **kwargs):
  203. # Silence the warnings about naive datetimes contained in the yaml.
  204. with warnings.catch_warnings(): # Scope warn catch to this block
  205. warnings.simplefilter('ignore', RuntimeWarning)
  206. return super().setUpClass(*args, **kwargs)
  207. def test_re_save(self):
  208. for contrib in Contrib.objects.all():
  209. contrib.full_clean()
  210. contrib.save()