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

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

11 Apr 2025 10:45PM UTC coverage: 97.443% (+0.2%) from 97.251%
429

push

travis-pro

divya603
Autoformat announcements app with Black and fix Flake8 style issues

4 of 5 new or added lines in 3 files covered. (80.0%)

18 existing lines in 5 files now uncovered.

1105 of 1134 relevant lines covered (97.44%)

0.97 hits per line

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

99.26
/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

10
class ErrorPageTests(TestCase):
1✔
11
    def test_trigger_400(self):
1✔
12
        response = self.client.get("/test400/")
1✔
13
        self.assertEqual(response.status_code, 400)
1✔
14

15
    def test_trigger_403(self):
1✔
16
        response = self.client.get("/test403/")
1✔
17
        self.assertEqual(response.status_code, 403)
1✔
18

19
    def test_trigger_404(self):
1✔
20
        response = self.client.get("/test404/")
1✔
21
        self.assertEqual(response.status_code, 404)
1✔
22

23
    def test_trigger_500(self):
1✔
24
        with self.assertRaises(Exception) as context:
1✔
25
            self.client.get("/test500/")
1✔
26
        self.assertIn("Intentional server error", str(context.exception))
1✔
27

28

29
class UniqueEmailTests(TestCase):
1✔
30
    def setUp(self):
1✔
31
        self.client = Client()
1✔
32
        User.objects.create_user(
1✔
33
            username="existinguser",
34
            email="duplicate@pawpark.com",
35
            password="SomeStrongPassword1",
36
        )
37
        self.register_url = reverse("register")
1✔
38

39
    def test_duplicate_email_registration(self):
1✔
40
        """
41
        Attempting to register a new user with an email that already exists should
42
        re-render the form with an error message.
43
        """
44
        response = self.client.post(
1✔
45
            self.register_url,
46
            {
47
                "username": "newuser",
48
                "email": "duplicate@pawpark.com",
49
                "password1": "StrongPass123",
50
                "password2": "StrongPass123",
51
                "role": "user",
52
                "admin_access_code": "",
53
            },
54
        )
55
        self.assertEqual(response.status_code, 200)
1✔
56
        self.assertContains(response, "A user with that email address already exists.")
1✔
57
        self.assertFalse(User.objects.filter(username="newuser").exists())
1✔
58

59

60
class WeakPasswordTests(TestCase):
1✔
61
    def setUp(self):
1✔
62
        self.client = Client()
1✔
63
        self.register_url = reverse("register")
1✔
64

65
    def test_too_short_password(self):
1✔
66
        response = self.client.post(
1✔
67
            self.register_url,
68
            {
69
                "username": "weakuser",
70
                "password1": "123",
71
                "password2": "123",
72
                "role": "user",
73
            },
74
        )
75
        self.assertEqual(response.status_code, 200)
1✔
76
        self.assertFalse(User.objects.filter(username="weakuser").exists())
1✔
77
        self.assertContains(response, "must contain at least 8 characters")
1✔
78

79
    def test_entirely_numeric_password(self):
1✔
80
        response = self.client.post(
1✔
81
            self.register_url,
82
            {
83
                "username": "numericuser",
84
                "password1": "12345678",
85
                "password2": "12345678",
86
                "role": "user",
87
            },
88
        )
89
        self.assertEqual(response.status_code, 200)
1✔
90
        self.assertFalse(User.objects.filter(username="numericuser").exists())
1✔
91
        self.assertContains(response, "can’t be entirely numeric")
1✔
92

93

94
class PasswordResetTests(TestCase):
1✔
95
    def setUp(self):
1✔
96
        self.client = Client()
1✔
97
        self.user = User.objects.create_user(
1✔
98
            "resetuser", "reset@pawpark.com", "Pass123456"
99
        )
100

101
    def test_password_reset_page_loads(self):
1✔
102
        url = reverse("password_reset")
1✔
103
        response = self.client.get(url)
1✔
104
        self.assertEqual(response.status_code, 200)
1✔
105
        self.assertTemplateUsed(response, "registration/password_reset_form.html")
1✔
106

107
    def test_password_reset_flow(self):
1✔
108
        """
109
        Ensure that posting an email to password_reset
110
        sends the user to password_reset_done,
111
        and optionally check that an email was
112
        "sent" (console backend or etc.)
113
        """
114
        url = reverse("password_reset")
1✔
115
        response = self.client.post(url, {"email": "reset@pawpark.com"})
1✔
116
        self.assertEqual(response.status_code, 302)
1✔
117
        self.assertRedirects(response, reverse("password_reset_done"))
1✔
118

119
        self.assertEqual(len(mail.outbox), 1)
1✔
120
        self.assertIn("resetuser", mail.outbox[0].body)
1✔
121

122

123
class AdminSignUpTests(TestCase):
1✔
124
    def setUp(self):
1✔
125
        self.client = Client()
1✔
126
        self.register_url = reverse("register")
1✔
127

128
    def test_admin_signup_with_correct_code(self):
1✔
129
        """
130
        Signing up as admin with correct access code should create a staff user.
131
        """
132
        response = self.client.post(
1✔
133
            self.register_url,
134
            {
135
                "username": "adminuser",
136
                "password1": "StrongAdminPass123",
137
                "password2": "StrongAdminPass123",
138
                "role": "admin",
139
                "admin_access_code": "SUPERDOG123",
140
            },
141
        )
142
        self.assertEqual(response.status_code, 302)
1✔
143
        self.assertTrue(User.objects.filter(username="adminuser").exists())
1✔
144
        user = User.objects.get(username="adminuser")
1✔
145
        self.assertTrue(user.is_staff)
1✔
146

147
    def test_admin_signup_with_wrong_code(self):
1✔
148
        """
149
        Signing up as admin with wrong code should fail and not create staff user.
150
        """
151
        response = self.client.post(
1✔
152
            self.register_url,
153
            {
154
                "username": "fakeadmin",
155
                "password1": "StrongAdminPass123",
156
                "password2": "StrongAdminPass123",
157
                "role": "admin",
158
                "admin_access_code": "WRONGCODE",
159
            },
160
        )
161
        self.assertEqual(response.status_code, 200)
1✔
162
        self.assertFalse(User.objects.filter(username="fakeadmin").exists())
1✔
163

164
    def test_signup_as_normal_user_ignores_access_code(self):
1✔
165
        """
166
        If someone chooses 'user' role, the admin_access_code is irrelevant.
167
        """
168
        response = self.client.post(
1✔
169
            self.register_url,
170
            {
171
                "username": "normaluser",
172
                "password1": "StrongPass456",
173
                "password2": "StrongPass456",
174
                "role": "user",
175
                "admin_access_code": "SUPERDOG123",
176
            },
177
        )
178
        self.assertEqual(response.status_code, 302)
1✔
179
        self.assertTrue(User.objects.filter(username="normaluser").exists())
1✔
180
        user = User.objects.get(username="normaluser")
1✔
181
        self.assertFalse(user.is_staff)
1✔
182

183

184
class LoginTests(TestCase):
1✔
185
    def setUp(self):
1✔
186
        self.client = Client()
1✔
187
        self.user = User.objects.create_user(
1✔
188
            username="testuser", password="StrongPass123"
189
        )
190

191
    def test_login_page_loads(self):
1✔
192
        """Ensure the login page loads properly."""
193
        response = self.client.get(reverse("login"))
1✔
194
        self.assertEqual(response.status_code, 200)
1✔
195
        self.assertTemplateUsed(response, "parks/login.html")
1✔
196

197
    def test_valid_login(self):
1✔
198
        """Ensure a valid user can log in."""
199
        response = self.client.post(
1✔
200
            reverse("login"), {"username": "testuser", "password": "StrongPass123"}
201
        )
202
        self.assertEqual(response.status_code, 302)
1✔
203

204

205
class AuthTests(TestCase):
1✔
206
    def setUp(self):
1✔
207
        self.client = Client()
1✔
208

209
    def test_register_page_loads(self):
1✔
210
        """Ensure the registration page loads properly."""
211
        response = self.client.get(reverse("register"))
1✔
212
        self.assertEqual(response.status_code, 200)
1✔
213
        self.assertTemplateUsed(response, "parks/register.html")
1✔
214

215
    def test_user_registration(self):
1✔
216
        """Ensure a new user can register successfully."""
217
        response = self.client.post(
1✔
218
            reverse("register"),
219
            {
220
                "username": "testuser",
221
                "password1": "StrongPass123",
222
                "password2": "StrongPass123",
223
                "role": "user",  # Ensure this field is required
224
            },
225
        )
226
        self.assertEqual(response.status_code, 302)
1✔
227
        self.assertTrue(User.objects.filter(username="testuser").exists())
1✔
228

229

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

265
    def test_park_creation(self):
1✔
266
        self.assertEqual(self.park.name, "Central Park")
1✔
267
        self.assertEqual(self.park.address, "New York, NY")
1✔
268
        self.assertEqual(self.park.notes, "Test park notes")
1✔
269
        self.assertEqual(self.park.slug, "central-park-1234")
1✔
270

271

272
class ReviewModelTest(TestCase):
1✔
273
    def setUp(self):
1✔
274
        self.user = User.objects.create_user(username="testuser", password="123456abc")
1✔
275
        self.park = DogRunNew.objects.create(
1✔
276
            id="2",
277
            prop_id="5678",
278
            name="Brooklyn Park",
279
            address="Brooklyn, NY",
280
            dogruns_type="Large",
281
            accessible="No",
282
            notes="Another test park",
283
            display_name="Brooklyn Park",
284
            slug=slugify(f"{'Brooklyn Park'}-{'5678'}"),
285
        )
286
        self.review = Review.objects.create(
1✔
287
            park=self.park, text="Great park!", rating=5, user=self.user
288
        )
289

290
    def test_review_creation(self):
1✔
291
        self.assertEqual(self.review.text, "Great park!")
1✔
292
        self.assertEqual(self.review.rating, 5)
1✔
293
        self.assertEqual(self.review.park.name, "Brooklyn Park")
1✔
294

295
    def test_review_str_method(self):
1✔
296
        self.assertEqual(str(self.review), "Review for Brooklyn Park (5 stars)")
1✔
297

298

299
class CombinedViewTest(TestCase):
1✔
300
    def test_combined_view(self):
1✔
301
        response = self.client.get(reverse("park_and_map"))
1✔
302
        self.assertEqual(response.status_code, 200)
1✔
303

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

339
    def test_combined_view_filters_by_borough(self):
1✔
340
        response = self.client.get(reverse("park_and_map"), {"borough": "M"})
1✔
341
        self.assertEqual(response.status_code, 200)
1✔
342
        self.assertContains(response, "Central Park")
1✔
343
        self.assertNotContains(response, "Brooklyn Bridge Park")
1✔
344

345

346
class ParkDetailViewTest(TestCase):
1✔
347
    def setUp(self):
1✔
348
        """Set up the test client and create a test park."""
UNCOV
349
        self.client = Client()
×
350

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

381

382
class ReportFunctionalityTests(TestCase):
1✔
383
    def setUp(self):
1✔
384
        self.client = Client()
1✔
385
        self.user = User.objects.create_user(
1✔
386
            username="reporter", password="testpass123"
387
        )
388
        self.other_user = User.objects.create_user(
1✔
389
            username="uploader", password="testpass123"
390
        )
391

392
        self.park = DogRunNew.objects.create(
1✔
393
            id="10",
394
            prop_id="9999",
395
            name="Test Park",
396
            address="Test Address",
397
            dogruns_type="All",
398
            accessible="Yes",
399
            formatted_address="Test Address",
400
            latitude=40.0,
401
            longitude=-73.0,
402
        )
403

404
        self.image = ParkImage.objects.create(
1✔
405
            park=self.park,
406
            image="https://res.cloudinary.com/demo/image/upload/sample.jpg",
407
            user=self.other_user,
408
        )
409

410
        self.review = Review.objects.create(
1✔
411
            park=self.park, text="Nice place!", rating=4, user=self.other_user
412
        )
413

414
        self.client.login(username="reporter", password="testpass123")
1✔
415

416
    def test_report_image_creates_record(self):
1✔
417
        response = self.client.post(
1✔
418
            reverse("report_image", args=[self.image.id]),
419
            {"reason": "Inappropriate image"},
420
        )
421
        self.assertEqual(response.status_code, 302)
1✔
422
        self.assertEqual(self.image.reports.count(), 1)
1✔
423
        report = self.image.reports.first()
1✔
424
        self.assertEqual(report.reason, "Inappropriate image")
1✔
425
        self.assertEqual(report.user, self.user)
1✔
426

427
    def test_report_review_creates_record(self):
1✔
428
        response = self.client.post(
1✔
429
            reverse("park_detail", args=[self.park.slug, self.park.id]),
430
            {
431
                "form_type": "report_review",
432
                "review_id": self.review.id,
433
                "reason": "Offensive content",
434
            },
435
        )
436
        self.assertEqual(response.status_code, 302)
1✔
437
        self.assertEqual(self.review.reports.count(), 1)
1✔
438
        report = self.review.reports.first()
1✔
439
        self.assertEqual(report.reason, "Offensive content")
1✔
440
        self.assertEqual(report.reported_by, self.user)
1✔
441

442
    def test_submit_review(self):
1✔
443
        response = self.client.post(
1✔
444
            reverse("park_detail", args=[self.park.slug, self.park.id]),
445
            {"form_type": "submit_review", "text": "Another review!", "rating": "5"},
446
        )
447
        self.assertEqual(response.status_code, 302)
1✔
448
        self.assertEqual(Review.objects.filter(park=self.park).count(), 2)
1✔
449

450
    def test_review_report_str(self):
1✔
451
        report = ReviewReport.objects.create(
1✔
452
            review=self.review, reported_by=self.user, reason="Inappropriate content"
453
        )
454
        self.assertIn("Reported by", str(report))
1✔
455
        self.assertIn(str(self.review.id), str(report))
1✔
456

457
    def test_image_report_str(self):
1✔
458
        report = ImageReport.objects.create(
1✔
459
            image=self.image, user=self.user, reason="Offensive image"
460
        )
461
        self.assertIn("Report by", str(report))
1✔
462
        self.assertIn(str(self.image.id), str(report))
1✔
463

464
    def test_missing_reason_does_not_create_report(self):
1✔
465
        self.client.login(username="user2", password="testpass")
1✔
466
        response = self.client.post(
1✔
467
            reverse("report_image", args=[self.image.id]),
468
            {"reason": ""},
469
        )
470
        self.assertEqual(ImageReport.objects.count(), 0)
1✔
471
        self.assertEqual(response.status_code, 302)
1✔
472

473

474
class DeleteTests(TestCase):
1✔
475
    def setUp(self):
1✔
476
        self.client = Client()
1✔
477
        self.user = User.objects.create_user(username="deleter", password="123pass")
1✔
478
        self.client.login(username="deleter", password="123pass")
1✔
479

480
        self.park = DogRunNew.objects.create(
1✔
481
            id="22",
482
            prop_id="9988",
483
            name="Del Park",
484
            address="Somewhere",
485
            dogruns_type="All",
486
            accessible="Yes",
487
            formatted_address="Addr",
488
            latitude=40.0,
489
            longitude=-73.0,
490
        )
491
        self.review = Review.objects.create(
1✔
492
            park=self.park, text="Review", rating=4, user=self.user
493
        )
494
        self.image = ParkImage.objects.create(
1✔
495
            park=self.park,
496
            image="https://res.cloudinary.com/demo/image/upload/sample.jpg",
497
            user=self.user,
498
        )
499

500
    def test_delete_review(self):
1✔
501
        response = self.client.post(reverse("delete_review", args=[self.review.id]))
1✔
502
        self.assertEqual(response.status_code, 302)
1✔
503
        self.assertFalse(Review.objects.filter(id=self.review.id).exists())
1✔
504

505
    def test_delete_image(self):
1✔
506
        response = self.client.post(reverse("delete_image", args=[self.image.id]))
1✔
507
        self.assertEqual(response.status_code, 302)
1✔
508
        self.assertFalse(ParkImage.objects.filter(id=self.image.id).exists())
1✔
509

510

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

548
    def test_park_image_creation(self):
1✔
549
        """Test that a ParkImage object is created successfully."""
550
        self.assertEqual(self.image.park, self.park)
1✔
551
        self.assertEqual(
1✔
552
            self.image.image, "https://res.cloudinary.com/demo/image/upload/sample.jpg"
553
        )
554

555
    def test_park_image_str(self):
1✔
556
        """Test the string representation of a ParkImage object."""
557
        self.assertEqual(str(self.image), f"Image for {self.park.name}")
1✔
558

559

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

598
    def test_park_detail_view_with_images(self):
1✔
599
        """Test that the park detail view displays associated images."""
600
        response = self.client.get(
1✔
601
            reverse("park_detail", args=[self.park.slug, self.park.id])
602
        )
603
        self.assertEqual(response.status_code, 200)
1✔
604
        self.assertContains(response, self.park.name)
1✔
605
        # self.assertIn(self.image.image, response.content.decode())
606

607

608
class RenderStarsTests(TestCase):
1✔
609
    def test_int_stars(self):
1✔
610
        size = 20
1✔
611
        result = render_stars(4, size)
1✔
612
        self.assertEqual(result["filled_stars"], 4)
1✔
613
        self.assertEqual(result["half_stars"], 0)
1✔
614
        self.assertEqual(result["empty_stars"], 1)
1✔
615
        self.assertEqual(result["size"], size)
1✔
616

617
    def test_full_stars(self):
1✔
618
        size = 15
1✔
619
        result = render_stars(5, size)
1✔
620
        self.assertEqual(result["filled_stars"], 5)
1✔
621
        self.assertEqual(result["half_stars"], 0)
1✔
622
        self.assertEqual(result["empty_stars"], 0)
1✔
623
        self.assertEqual(result["size"], size)
1✔
624

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

633
    def test_half_stars(self):
1✔
634
        size = 20
1✔
635
        result = render_stars(2.5, size)
1✔
636
        self.assertEqual(result["filled_stars"], 2)
1✔
637
        self.assertEqual(result["half_stars"], 1)
1✔
638
        self.assertEqual(result["empty_stars"], 2)
1✔
639
        self.assertEqual(result["size"], size)
1✔
640

641
    # >= X.25 -> one half star
642
    def test_round_up_to_half(self):
1✔
643
        size = 20
1✔
644
        result = render_stars(4.25, size)
1✔
645
        self.assertEqual(result["filled_stars"], 4)
1✔
646
        self.assertEqual(result["half_stars"], 1)
1✔
647
        self.assertEqual(result["empty_stars"], 0)
1✔
648
        self.assertEqual(result["size"], size)
1✔
649

650
    # < X.25 -> round down to whole
651
    def test_round_down_to_whole(self):
1✔
652
        size = 20
1✔
653
        result = render_stars(3.24, size)
1✔
654
        self.assertEqual(result["filled_stars"], 3)
1✔
655
        self.assertEqual(result["half_stars"], 0)
1✔
656
        self.assertEqual(result["empty_stars"], 2)
1✔
657
        self.assertEqual(result["size"], size)
1✔
658

659
    # < X.75 -> one half star
660
    def test_round_down_to_half(self):
1✔
661
        size = 20
1✔
662
        result = render_stars(2.74, size)
1✔
663
        self.assertEqual(result["filled_stars"], 2)
1✔
664
        self.assertEqual(result["half_stars"], 1)
1✔
665
        self.assertEqual(result["empty_stars"], 2)
1✔
666
        self.assertEqual(result["size"], size)
1✔
667

668
    # >= X.75 -> round up to next whole
669
    def test_round_up_to_whole(self):
1✔
670
        size = 20
1✔
671
        result = render_stars(4.75, size)
1✔
672
        self.assertEqual(result["filled_stars"], 5)
1✔
673
        self.assertEqual(result["half_stars"], 0)
1✔
674
        self.assertEqual(result["empty_stars"], 0)
1✔
675
        self.assertEqual(result["size"], size)
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