• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

gcivil-nyu-org / team4-wed-spring25 / 451

15 Apr 2025 04:44PM UTC coverage: 94.434%. Remained the same
451

push

travis-pro

mr2447
Revert to commit 70a810d

2 of 3 new or added lines in 2 files covered. (66.67%)

24 existing lines in 2 files now uncovered.

1018 of 1078 relevant lines covered (94.43%)

0.94 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

99.37
/parks/tests.py
1
from django.test import TestCase, Client
1✔
2
from django.urls import reverse
1✔
3
from django.contrib.auth.models import User
1✔
4
from .models import DogRunNew, Review, ParkImage, ReviewReport, ImageReport
1✔
5
from parks.templatetags.display_rating import render_stars
1✔
6
from django.utils.text import slugify
1✔
7
from django.core import mail
1✔
8

9
from django.utils import timezone
1✔
10
from datetime import timedelta
1✔
11
from parks.models import ParkPresence
1✔
12

13
from unittest.mock import patch
1✔
14

15

16
class ErrorPageTests(TestCase):
1✔
17
    def test_trigger_400(self):
1✔
18
        response = self.client.get("/test400/")
1✔
19
        self.assertEqual(response.status_code, 400)
1✔
20
        self.assertTemplateUsed(response, "400.html")
1✔
21

22
    def test_trigger_403(self):
1✔
23
        response = self.client.get("/test403/")
1✔
24
        self.assertEqual(response.status_code, 403)
1✔
25
        self.assertTemplateUsed(response, "403.html")
1✔
26

27
    def test_trigger_404(self):
1✔
28
        response = self.client.get("/test404/")
1✔
29
        self.assertEqual(response.status_code, 404)
1✔
30
        self.assertTemplateUsed(response, "404.html")
1✔
31

32
    def test_trigger_500(self):
1✔
33
        response = self.client.get("/test500/")
1✔
34
        self.assertEqual(response.status_code, 500)
1✔
35
        self.assertTemplateUsed(response, "500.html")
1✔
36

37

38
class UniqueEmailTests(TestCase):
1✔
39
    def setUp(self):
1✔
40
        self.client = Client()
1✔
41
        User.objects.create_user(
1✔
42
            username="existinguser",
43
            email="duplicate@pawpark.com",
44
            password="SomeStrongPassword1",
45
        )
46
        self.register_url = reverse("register")
1✔
47

48
    def test_duplicate_email_registration(self):
1✔
49
        """
50
        Attempting to register a new user with an email that already exists should
51
        re-render the form with an error message.
52
        """
53
        response = self.client.post(
1✔
54
            self.register_url,
55
            {
56
                "username": "newuser",
57
                "email": "duplicate@pawpark.com",
58
                "password1": "StrongPass123",
59
                "password2": "StrongPass123",
60
                "role": "user",
61
                "admin_access_code": "",
62
            },
63
        )
64
        self.assertEqual(response.status_code, 200)
1✔
65
        self.assertContains(response, "A user with that email address already exists.")
1✔
66
        self.assertFalse(User.objects.filter(username="newuser").exists())
1✔
67

68

69
class WeakPasswordTests(TestCase):
1✔
70
    def setUp(self):
1✔
71
        self.client = Client()
1✔
72
        self.register_url = reverse("register")
1✔
73

74
    def test_too_short_password(self):
1✔
75
        response = self.client.post(
1✔
76
            self.register_url,
77
            {
78
                "username": "weakuser",
79
                "password1": "123",
80
                "password2": "123",
81
                "role": "user",
82
            },
83
        )
84
        self.assertEqual(response.status_code, 200)
1✔
85
        self.assertFalse(User.objects.filter(username="weakuser").exists())
1✔
86
        self.assertContains(response, "must contain at least 8 characters")
1✔
87

88
    def test_entirely_numeric_password(self):
1✔
89
        response = self.client.post(
1✔
90
            self.register_url,
91
            {
92
                "username": "numericuser",
93
                "password1": "12345678",
94
                "password2": "12345678",
95
                "role": "user",
96
            },
97
        )
98
        self.assertEqual(response.status_code, 200)
1✔
99
        self.assertFalse(User.objects.filter(username="numericuser").exists())
1✔
100
        self.assertContains(response, "can’t be entirely numeric")
1✔
101

102

103
class PasswordResetTests(TestCase):
1✔
104
    def setUp(self):
1✔
105
        self.client = Client()
1✔
106
        self.user = User.objects.create_user(
1✔
107
            "resetuser", "reset@pawpark.com", "Pass123456"
108
        )
109

110
    def test_password_reset_page_loads(self):
1✔
111
        url = reverse("password_reset")
1✔
112
        response = self.client.get(url)
1✔
113
        self.assertEqual(response.status_code, 200)
1✔
114
        self.assertTemplateUsed(response, "registration/password_reset_form.html")
1✔
115

116
    def test_password_reset_flow(self):
1✔
117
        """
118
        Ensure that posting an email to password_reset
119
        sends the user to password_reset_done,
120
        and optionally check that an email was
121
        "sent" (console backend or etc.)
122
        """
123
        url = reverse("password_reset")
1✔
124
        response = self.client.post(url, {"email": "reset@pawpark.com"})
1✔
125
        self.assertEqual(response.status_code, 302)
1✔
126
        self.assertRedirects(response, reverse("password_reset_done"))
1✔
127

128
        self.assertEqual(len(mail.outbox), 1)
1✔
129
        self.assertIn("resetuser", mail.outbox[0].body)
1✔
130

131

132
class AdminSignUpTests(TestCase):
1✔
133
    def setUp(self):
1✔
134
        self.client = Client()
1✔
135
        self.register_url = reverse("register")
1✔
136

137
    def test_admin_signup_with_correct_code(self):
1✔
138
        """
139
        Signing up as admin with correct access code should create a staff user.
140
        """
141
        response = self.client.post(
1✔
142
            self.register_url,
143
            {
144
                "username": "adminuser",
145
                "password1": "StrongAdminPass123",
146
                "password2": "StrongAdminPass123",
147
                "role": "admin",
148
                "admin_access_code": "SUPERDOG123",
149
            },
150
        )
151
        self.assertEqual(response.status_code, 302)
1✔
152
        self.assertTrue(User.objects.filter(username="adminuser").exists())
1✔
153
        user = User.objects.get(username="adminuser")
1✔
154
        self.assertTrue(user.is_staff)
1✔
155

156
    def test_admin_signup_with_wrong_code(self):
1✔
157
        """
158
        Signing up as admin with wrong code should fail and not create staff user.
159
        """
160
        response = self.client.post(
1✔
161
            self.register_url,
162
            {
163
                "username": "fakeadmin",
164
                "password1": "StrongAdminPass123",
165
                "password2": "StrongAdminPass123",
166
                "role": "admin",
167
                "admin_access_code": "WRONGCODE",
168
            },
169
        )
170
        self.assertEqual(response.status_code, 200)
1✔
171
        self.assertFalse(User.objects.filter(username="fakeadmin").exists())
1✔
172

173
    def test_signup_as_normal_user_ignores_access_code(self):
1✔
174
        """
175
        If someone chooses 'user' role, the admin_access_code is irrelevant.
176
        """
177
        response = self.client.post(
1✔
178
            self.register_url,
179
            {
180
                "username": "normaluser",
181
                "password1": "StrongPass456",
182
                "password2": "StrongPass456",
183
                "role": "user",
184
                "admin_access_code": "SUPERDOG123",
185
            },
186
        )
187
        self.assertEqual(response.status_code, 302)
1✔
188
        self.assertTrue(User.objects.filter(username="normaluser").exists())
1✔
189
        user = User.objects.get(username="normaluser")
1✔
190
        self.assertFalse(user.is_staff)
1✔
191

192

193
class LoginTests(TestCase):
1✔
194
    def setUp(self):
1✔
195
        self.client = Client()
1✔
196
        self.user = User.objects.create_user(
1✔
197
            username="testuser", password="StrongPass123"
198
        )
199

200
    def test_login_page_loads(self):
1✔
201
        """Ensure the login page loads properly."""
202
        response = self.client.get(reverse("login"))
1✔
203
        self.assertEqual(response.status_code, 200)
1✔
204
        self.assertTemplateUsed(response, "parks/login.html")
1✔
205

206
    def test_valid_login(self):
1✔
207
        """Ensure a valid user can log in."""
208
        response = self.client.post(
1✔
209
            reverse("login"), {"username": "testuser", "password": "StrongPass123"}
210
        )
211
        self.assertEqual(response.status_code, 302)
1✔
212

213

214
class AuthTests(TestCase):
1✔
215
    def setUp(self):
1✔
216
        self.client = Client()
1✔
217

218
    def test_register_page_loads(self):
1✔
219
        """Ensure the registration page loads properly."""
220
        response = self.client.get(reverse("register"))
1✔
221
        self.assertEqual(response.status_code, 200)
1✔
222
        self.assertTemplateUsed(response, "parks/register.html")
1✔
223

224
    def test_user_registration(self):
1✔
225
        """Ensure a new user can register successfully."""
226
        response = self.client.post(
1✔
227
            reverse("register"),
228
            {
229
                "username": "testuser",
230
                "password1": "StrongPass123",
231
                "password2": "StrongPass123",
232
                "role": "user",  # Ensure this field is required
233
            },
234
        )
235
        self.assertEqual(response.status_code, 302)
1✔
236
        self.assertTrue(User.objects.filter(username="testuser").exists())
1✔
237

238

239
class ParkModelTest(TestCase):
1✔
240
    def setUp(self):
1✔
241
        self.client = Client()
1✔
242
        self.park = DogRunNew.objects.create(
1✔
243
            id="1",
244
            prop_id="1234",
245
            name="Central Park",
246
            address="New York, NY",
247
            dogruns_type="Small",
248
            accessible="Yes",
249
            notes="Test park notes",
250
            google_name="Central Park",
251
            borough="M",
252
            zip_code="United States",
253
            formatted_address="Central Pk N, New York, NY, USA",
254
            latitude=40.7987768,
255
            longitude=-73.9537196,
256
            additional={
257
                "geometry": {
258
                    "bounds": {
259
                        "northeast": {"lat": 40.8009264, "lng": -73.9495752},
260
                        "southwest": {"lat": 40.796948, "lng": -73.9580246},
261
                    },
262
                    "location": {"lat": 40.7987768, "lng": -73.9537196},
263
                    "location_type": "GEOMETRIC_CENTER",
264
                    "viewport": {
265
                        "northeast": {"lat": 40.8009264, "lng": -73.9495752},
266
                        "southwest": {"lat": 40.796948, "lng": -73.9580246},
267
                    },
268
                }
269
            },
270
            display_name="Central Park",
271
            slug=slugify(f"{'Central Park'}-{'1234'}"),
272
        )
273

274
    def test_park_creation(self):
1✔
275
        self.assertEqual(self.park.name, "Central Park")
1✔
276
        self.assertEqual(self.park.address, "New York, NY")
1✔
277
        self.assertEqual(self.park.notes, "Test park notes")
1✔
278
        self.assertEqual(self.park.slug, "central-park-1234")
1✔
279

280

281
class ReviewModelTest(TestCase):
1✔
282
    def setUp(self):
1✔
283
        self.user = User.objects.create_user(username="testuser", password="123456abc")
1✔
284
        self.park = DogRunNew.objects.create(
1✔
285
            id="2",
286
            prop_id="5678",
287
            name="Brooklyn Park",
288
            address="Brooklyn, NY",
289
            dogruns_type="Large",
290
            accessible="No",
291
            notes="Another test park",
292
            display_name="Brooklyn Park",
293
            slug=slugify(f"{'Brooklyn Park'}-{'5678'}"),
294
        )
295
        self.review = Review.objects.create(
1✔
296
            park=self.park, text="Great park!", rating=5, user=self.user
297
        )
298

299
    def test_review_creation(self):
1✔
300
        self.assertEqual(self.review.text, "Great park!")
1✔
301
        self.assertEqual(self.review.rating, 5)
1✔
302
        self.assertEqual(self.review.park.name, "Brooklyn Park")
1✔
303

304
    def test_review_str_method(self):
1✔
305
        self.assertEqual(str(self.review), "Review for Brooklyn Park (5 stars)")
1✔
306

307

308
class CombinedViewTest(TestCase):
1✔
309
    def test_combined_view(self):
1✔
310
        response = self.client.get(reverse("park_and_map"))
1✔
311
        self.assertEqual(response.status_code, 200)
1✔
312

313
    def setUp(self):
1✔
314
        self.client = Client()
1✔
315
        # One park in Manhattan
316
        self.park_manhattan = DogRunNew.objects.create(
1✔
317
            id="1",
318
            prop_id="1234",
319
            name="Central Park",
320
            address="New York, NY",
321
            dogruns_type="Small",
322
            accessible="Yes",
323
            notes="Manhattan park",
324
            google_name="Central Park",
325
            borough="M",
326
            zip_code="10024",
327
            latitude=40.7987768,
328
            longitude=-73.9537196,
329
            display_name="Central Park",
330
        )
331
        # One park in Brooklyn
332
        self.park_brooklyn = DogRunNew.objects.create(
1✔
333
            id="2",
334
            prop_id="5678",
335
            name="Brooklyn Bridge Park",
336
            address="Brooklyn, NY",
337
            dogruns_type="Large",
338
            accessible="Yes",
339
            notes="Brooklyn park",
340
            google_name="Brooklyn Bridge Park",
341
            borough="B",
342
            zip_code="11201",
343
            latitude=40.700292,
344
            longitude=-73.996123,
345
            display_name="Brooklyn Bridge Park",
346
        )
347

348
    def test_combined_view_filters_by_borough(self):
1✔
349
        response = self.client.get(reverse("park_and_map"), {"borough": "M"})
1✔
350
        self.assertEqual(response.status_code, 200)
1✔
351
        self.assertContains(response, "Central Park")
1✔
352
        self.assertNotContains(response, "Brooklyn Bridge Park")
1✔
353

354

355
class ParkDetailViewTest(TestCase):
1✔
356
    def setUp(self):
1✔
357
        """Set up the test client and create a test park."""
UNCOV
358
        self.client = Client()
×
359

UNCOV
360
        self.park = DogRunNew.objects.create(
×
361
            id="1",
362
            prop_id="1234",
363
            name="Central Park",
364
            address="New York, NY",
365
            dogruns_type="Small",
366
            accessible="Yes",
367
            notes="Test park notes",
368
            google_name="Central Park",
369
            borough="M",
370
            zip_code="United States",
371
            formatted_address="Central Pk N, New York, NY, USA",
372
            latitude=40.7987768,
373
            longitude=-73.9537196,
374
            additional={
375
                "geometry": {
376
                    "bounds": {
377
                        "northeast": {"lat": 40.8009264, "lng": -73.9495752},
378
                        "southwest": {"lat": 40.796948, "lng": -73.9580246},
379
                    },
380
                    "location": {"lat": 40.7987768, "lng": -73.9537196},
381
                    "location_type": "GEOMETRIC_CENTER",
382
                    "viewport": {
383
                        "northeast": {"lat": 40.8009264, "lng": -73.9495752},
384
                        "southwest": {"lat": 40.796948, "lng": -73.9580246},
385
                    },
386
                }
387
            },
388
        )
389

390

391
class ReportFunctionalityTests(TestCase):
1✔
392
    def setUp(self):
1✔
393
        self.client = Client()
1✔
394
        self.user = User.objects.create_user(
1✔
395
            username="reporter", password="testpass123"
396
        )
397
        self.other_user = User.objects.create_user(
1✔
398
            username="uploader", password="testpass123"
399
        )
400

401
        self.park = DogRunNew.objects.create(
1✔
402
            id="10",
403
            prop_id="9999",
404
            name="Test Park",
405
            address="Test Address",
406
            dogruns_type="All",
407
            accessible="Yes",
408
            formatted_address="Test Address",
409
            latitude=40.0,
410
            longitude=-73.0,
411
        )
412

413
        self.image = ParkImage.objects.create(
1✔
414
            park=self.park,
415
            image="https://res.cloudinary.com/demo/image/upload/sample.jpg",
416
            user=self.other_user,
417
        )
418

419
        self.review = Review.objects.create(
1✔
420
            park=self.park, text="Nice place!", rating=4, user=self.other_user
421
        )
422

423
        self.client.login(username="reporter", password="testpass123")
1✔
424

425
    def test_report_image_creates_record(self):
1✔
426
        response = self.client.post(
1✔
427
            reverse("report_image", args=[self.image.id]),
428
            {"reason": "Inappropriate image"},
429
        )
430
        self.assertEqual(response.status_code, 302)
1✔
431
        self.assertEqual(self.image.reports.count(), 1)
1✔
432
        report = self.image.reports.first()
1✔
433
        self.assertEqual(report.reason, "Inappropriate image")
1✔
434
        self.assertEqual(report.user, self.user)
1✔
435

436
    def test_report_review_creates_record(self):
1✔
437
        response = self.client.post(
1✔
438
            reverse("park_detail", args=[self.park.slug, self.park.id]),
439
            {
440
                "form_type": "report_review",
441
                "review_id": self.review.id,
442
                "reason": "Offensive content",
443
            },
444
        )
445
        self.assertEqual(response.status_code, 302)
1✔
446
        self.assertEqual(self.review.reports.count(), 1)
1✔
447
        report = self.review.reports.first()
1✔
448
        self.assertEqual(report.reason, "Offensive content")
1✔
449
        self.assertEqual(report.reported_by, self.user)
1✔
450

451
    def test_submit_review(self):
1✔
452
        response = self.client.post(
1✔
453
            reverse("park_detail", args=[self.park.slug, self.park.id]),
454
            {"form_type": "submit_review", "text": "Another review!", "rating": "5"},
455
        )
456
        self.assertEqual(response.status_code, 302)
1✔
457
        self.assertEqual(Review.objects.filter(park=self.park).count(), 2)
1✔
458

459
    def test_review_report_str(self):
1✔
460
        report = ReviewReport.objects.create(
1✔
461
            review=self.review, reported_by=self.user, reason="Inappropriate content"
462
        )
463
        self.assertIn("Reported by", str(report))
1✔
464
        self.assertIn(str(self.review.id), str(report))
1✔
465

466
    def test_image_report_str(self):
1✔
467
        report = ImageReport.objects.create(
1✔
468
            image=self.image, user=self.user, reason="Offensive image"
469
        )
470
        self.assertIn("Report by", str(report))
1✔
471
        self.assertIn(str(self.image.id), str(report))
1✔
472

473
    def test_missing_reason_does_not_create_report(self):
1✔
474
        self.client.login(username="user2", password="testpass")
1✔
475
        response = self.client.post(
1✔
476
            reverse("report_image", args=[self.image.id]),
477
            {"reason": ""},
478
        )
479
        self.assertEqual(ImageReport.objects.count(), 0)
1✔
480
        self.assertEqual(response.status_code, 302)
1✔
481

482

483
class DeleteTests(TestCase):
1✔
484
    def setUp(self):
1✔
485
        self.client = Client()
1✔
486
        self.user = User.objects.create_user(username="deleter", password="123pass")
1✔
487
        self.client.login(username="deleter", password="123pass")
1✔
488

489
        self.park = DogRunNew.objects.create(
1✔
490
            id="22",
491
            prop_id="9988",
492
            name="Del Park",
493
            address="Somewhere",
494
            dogruns_type="All",
495
            accessible="Yes",
496
            formatted_address="Addr",
497
            latitude=40.0,
498
            longitude=-73.0,
499
        )
500
        self.review = Review.objects.create(
1✔
501
            park=self.park, text="Review", rating=4, user=self.user
502
        )
503
        self.image = ParkImage.objects.create(
1✔
504
            park=self.park,
505
            image="https://res.cloudinary.com/demo/image/upload/sample.jpg",
506
            user=self.user,
507
        )
508

509
    def test_delete_review(self):
1✔
510
        response = self.client.post(reverse("delete_review", args=[self.review.id]))
1✔
511
        self.assertEqual(response.status_code, 302)
1✔
512
        self.assertFalse(Review.objects.filter(id=self.review.id).exists())
1✔
513

514
    def test_delete_image(self):
1✔
515
        response = self.client.post(reverse("delete_image", args=[self.image.id]))
1✔
516
        self.assertEqual(response.status_code, 302)
1✔
517
        self.assertFalse(ParkImage.objects.filter(id=self.image.id).exists())
1✔
518

519

520
class ParkImageModelTest(TestCase):
1✔
521
    def setUp(self):
1✔
522
        """Set up a test park and associated images."""
523
        self.park = DogRunNew.objects.create(
1✔
524
            id="1",
525
            prop_id="1234",
526
            name="Central Park",
527
            address="New York, NY",
528
            dogruns_type="Small",
529
            accessible="Yes",
530
            notes="Test park notes",
531
            google_name="Central Park",
532
            borough="M",
533
            zip_code="United States",
534
            formatted_address="Central Pk N, New York, NY, USA",
535
            latitude=40.7987768,
536
            longitude=-73.9537196,
537
            additional={
538
                "geometry": {
539
                    "bounds": {
540
                        "northeast": {"lat": 40.8009264, "lng": -73.9495752},
541
                        "southwest": {"lat": 40.796948, "lng": -73.9580246},
542
                    },
543
                    "location": {"lat": 40.7987768, "lng": -73.9537196},
544
                    "location_type": "GEOMETRIC_CENTER",
545
                    "viewport": {
546
                        "northeast": {"lat": 40.8009264, "lng": -73.9495752},
547
                        "southwest": {"lat": 40.796948, "lng": -73.9580246},
548
                    },
549
                }
550
            },
551
        )
552
        self.image = ParkImage.objects.create(
1✔
553
            park=self.park,
554
            image="https://res.cloudinary.com/demo/image/upload/sample.jpg",
555
        )
556

557
    def test_park_image_creation(self):
1✔
558
        """Test that a ParkImage object is created successfully."""
559
        self.assertEqual(self.image.park, self.park)
1✔
560
        self.assertEqual(
1✔
561
            self.image.image, "https://res.cloudinary.com/demo/image/upload/sample.jpg"
562
        )
563

564
    def test_park_image_str(self):
1✔
565
        """Test the string representation of a ParkImage object."""
566
        self.assertEqual(str(self.image), f"Image for {self.park.name}")
1✔
567

568

569
class ParkDetailViewImageTest(TestCase):
1✔
570
    def setUp(self):
1✔
571
        """Set up a test park and associated images."""
572
        self.client = Client()
1✔
573
        self.park = DogRunNew.objects.create(
1✔
574
            id="1",
575
            prop_id="1234",
576
            name="Central Park",
577
            address="New York, NY",
578
            dogruns_type="Small",
579
            accessible="Yes",
580
            notes="Test park notes",
581
            google_name="Central Park",
582
            borough="M",
583
            zip_code="United States",
584
            formatted_address="Central Pk N, New York, NY, USA",
585
            latitude=40.7987768,
586
            longitude=-73.9537196,
587
            additional={
588
                "geometry": {
589
                    "bounds": {
590
                        "northeast": {"lat": 40.8009264, "lng": -73.9495752},
591
                        "southwest": {"lat": 40.796948, "lng": -73.9580246},
592
                    },
593
                    "location": {"lat": 40.7987768, "lng": -73.9537196},
594
                    "location_type": "GEOMETRIC_CENTER",
595
                    "viewport": {
596
                        "northeast": {"lat": 40.8009264, "lng": -73.9495752},
597
                        "southwest": {"lat": 40.796948, "lng": -73.9580246},
598
                    },
599
                }
600
            },
601
        )
602
        self.image = ParkImage.objects.create(
1✔
603
            park=self.park,
604
            image="https://res.cloudinary.com/demo/image/upload/sample.jpg",
605
        )
606

607
    def test_park_detail_view_with_images(self):
1✔
608
        """Test that the park detail view displays associated images."""
609
        response = self.client.get(
1✔
610
            reverse("park_detail", args=[self.park.slug, self.park.id])
611
        )
612
        self.assertEqual(response.status_code, 200)
1✔
613
        self.assertContains(response, self.park.name)
1✔
614
        # self.assertIn(self.image.image, response.content.decode())
615

616

617
class RenderStarsTests(TestCase):
1✔
618
    def test_int_stars(self):
1✔
619
        size = 20
1✔
620
        result = render_stars(4, size)
1✔
621
        self.assertEqual(result["filled_stars"], 4)
1✔
622
        self.assertEqual(result["half_stars"], 0)
1✔
623
        self.assertEqual(result["empty_stars"], 1)
1✔
624
        self.assertEqual(result["size"], size)
1✔
625

626
    def test_full_stars(self):
1✔
627
        size = 15
1✔
628
        result = render_stars(5, size)
1✔
629
        self.assertEqual(result["filled_stars"], 5)
1✔
630
        self.assertEqual(result["half_stars"], 0)
1✔
631
        self.assertEqual(result["empty_stars"], 0)
1✔
632
        self.assertEqual(result["size"], size)
1✔
633

634
    def test_no_stars(self):
1✔
635
        size = 10
1✔
636
        result = render_stars(0, size)
1✔
637
        self.assertEqual(result["filled_stars"], 0)
1✔
638
        self.assertEqual(result["half_stars"], 0)
1✔
639
        self.assertEqual(result["empty_stars"], 5)
1✔
640
        self.assertEqual(result["size"], size)
1✔
641

642
    def test_half_stars(self):
1✔
643
        size = 20
1✔
644
        result = render_stars(2.5, size)
1✔
645
        self.assertEqual(result["filled_stars"], 2)
1✔
646
        self.assertEqual(result["half_stars"], 1)
1✔
647
        self.assertEqual(result["empty_stars"], 2)
1✔
648
        self.assertEqual(result["size"], size)
1✔
649

650
    # >= X.25 -> one half star
651
    def test_round_up_to_half(self):
1✔
652
        size = 20
1✔
653
        result = render_stars(4.25, size)
1✔
654
        self.assertEqual(result["filled_stars"], 4)
1✔
655
        self.assertEqual(result["half_stars"], 1)
1✔
656
        self.assertEqual(result["empty_stars"], 0)
1✔
657
        self.assertEqual(result["size"], size)
1✔
658

659
    # < X.25 -> round down to whole
660
    def test_round_down_to_whole(self):
1✔
661
        size = 20
1✔
662
        result = render_stars(3.24, size)
1✔
663
        self.assertEqual(result["filled_stars"], 3)
1✔
664
        self.assertEqual(result["half_stars"], 0)
1✔
665
        self.assertEqual(result["empty_stars"], 2)
1✔
666
        self.assertEqual(result["size"], size)
1✔
667

668
    # < X.75 -> one half star
669
    def test_round_down_to_half(self):
1✔
670
        size = 20
1✔
671
        result = render_stars(2.74, size)
1✔
672
        self.assertEqual(result["filled_stars"], 2)
1✔
673
        self.assertEqual(result["half_stars"], 1)
1✔
674
        self.assertEqual(result["empty_stars"], 2)
1✔
675
        self.assertEqual(result["size"], size)
1✔
676

677
    # >= X.75 -> round up to next whole
678
    def test_round_up_to_whole(self):
1✔
679
        size = 20
1✔
680
        result = render_stars(4.75, size)
1✔
681
        self.assertEqual(result["filled_stars"], 5)
1✔
682
        self.assertEqual(result["half_stars"], 0)
1✔
683
        self.assertEqual(result["empty_stars"], 0)
1✔
684
        self.assertEqual(result["size"], size)
1✔
685

686

687
class ParkPresenceTests(TestCase):
1✔
688
    def setUp(self):
1✔
689
        self.client = Client()
1✔
690
        self.user = User.objects.create_user(username="tester", password="testpass")
1✔
691
        self.park = DogRunNew.objects.create(
1✔
692
            id="5",
693
            prop_id="5566",
694
            name="Test Dog Park",
695
            address="Test Location",
696
            dogruns_type="All",
697
            accessible="Yes",
698
            formatted_address="Test Address",
699
            latitude=40.0,
700
            longitude=-73.0,
701
            display_name="Test Dog Park",
702
            slug="test-dog-park-5566",
703
        )
704
        self.client.login(username="tester", password="testpass")
1✔
705

706
    def test_user_check_in_creates_presence(self):
1✔
707
        self.client.post(
1✔
708
            reverse("park_detail", args=[self.park.slug, self.park.id]),
709
            {"form_type": "check_in"},
710
        )
711
        presences = ParkPresence.objects.filter(user=self.user, park=self.park)
1✔
712
        self.assertEqual(presences.count(), 1)
1✔
713
        self.assertEqual(presences.first().status, "current")
1✔
714

715
    def test_user_be_there_at_creates_presence(self):
1✔
716
        future_time = (timezone.now() + timedelta(minutes=20)).strftime("%H:%M")
1✔
717
        self.client.post(
1✔
718
            reverse("park_detail", args=[self.park.slug, self.park.id]),
719
            {"form_type": "be_there_at", "time": future_time},
720
        )
721
        presences = ParkPresence.objects.filter(user=self.user, park=self.park)
1✔
722
        self.assertEqual(presences.count(), 1)
1✔
723
        self.assertEqual(presences.first().status, "on_the_way")
1✔
724

725

726
@patch(
1✔
727
    "cloudinary.uploader.upload",
728
    return_value={
729
        "asset_id": "dummy_asset_id",
730
        "public_id": "dummy_id",
731
        "version": "1234567890",
732
        "signature": "dummy_signature",
733
        "width": 800,
734
        "height": 600,
735
        "format": "jpg",
736
        "resource_type": "image",
737
        "type": "upload",
738
        "secure_url": "https://dummy.cloudinary.com/image.jpg",
739
        "url": "http://dummy.cloudinary.com/image.jpg",
740
    },
741
)
742
class ImageUploadTests(TestCase):
1✔
743
    def setUp(self):
1✔
744
        self.client = Client()
1✔
745
        self.user = User.objects.create_user(username="uploader", password="pass123")
1✔
746
        self.client.login(username="uploader", password="pass123")
1✔
747
        self.park = DogRunNew.objects.create(
1✔
748
            id="20",
749
            prop_id="8888",
750
            name="Mock Park",
751
            address="123",
752
            dogruns_type="All",
753
            accessible="Yes",
754
            formatted_address="123",
755
            latitude=40.0,
756
            longitude=-73.0,
757
            slug="mock-park-8888",
758
            display_name="Mock Park",
759
        )
760

761
    def test_upload_image_with_review(self, mock_upload):
1✔
762
        from django.core.files.uploadedfile import SimpleUploadedFile
1✔
763

764
        image = SimpleUploadedFile(
1✔
765
            "test.jpg", b"file_content", content_type="image/jpeg"
766
        )
767
        response = self.client.post(
1✔
768
            reverse("park_detail", args=[self.park.slug, self.park.id]),
769
            {
770
                "form_type": "submit_review",
771
                "text": "Nice park!",
772
                "rating": "5",
773
                "images": image,
774
            },
775
        )
776
        self.assertEqual(response.status_code, 302)
1✔
777
        self.assertEqual(ParkImage.objects.count(), 1)
1✔
778

779

780
class ModalInteractionTests(TestCase):
1✔
781
    def test_modal_js_is_present(self):
1✔
782
        client = Client()
1✔
783
        park = DogRunNew.objects.create(
1✔
784
            id="7",
785
            prop_id="3344",
786
            name="Modal Park",
787
            address="JSville",
788
            dogruns_type="Small",
789
            accessible="Yes",
790
            formatted_address="JS Road",
791
            latitude=42.0,
792
            longitude=-75.0,
793
            display_name="Modal Park",
794
            slug="modal-park-3344",
795
        )
796
        response = client.get(reverse("park_detail", args=[park.slug, park.id]))
1✔
797
        self.assertContains(response, "function openCarouselImageModal")
1✔
798
        self.assertContains(response, "imagePreviewModal")
1✔
799
        self.assertContains(response, "modalImage")
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc