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

rafalp / Misago / 9487666026

12 Jun 2024 06:16PM UTC coverage: 97.699% (-1.0%) from 98.716%
9487666026

push

github

web-flow
Replace forum options with account settings (#1742)

1947 of 1979 new or added lines in 68 files covered. (98.38%)

661 existing lines in 143 files now uncovered.

52601 of 53840 relevant lines covered (97.7%)

0.98 hits per line

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

99.39
/misago/threads/tests/test_threadview.py
1
from unittest.mock import Mock, patch
1✔
2

3
from .. import test
1✔
4
from ...acl import useracl
1✔
5
from ...acl.test import patch_user_acl
1✔
6
from ...categories.models import Category
1✔
7
from ...conf.test import override_dynamic_settings
1✔
8
from ...conftest import get_cache_versions
1✔
9
from ...users.test import AuthenticatedUserTestCase
1✔
10
from ..checksums import update_post_checksum
1✔
11
from ..events import record_event
1✔
12
from ..moderation import hide_post
1✔
13
from ..moderation import threads as threads_moderation
1✔
14

15
cache_versions = get_cache_versions()
1✔
16

17

18
def patch_category_acl(new_acl=None):
1✔
19
    def patch_acl(_, user_acl):
1✔
20
        category = Category.objects.get(slug="first-category")
1✔
21
        category_acl = user_acl["categories"][category.id]
1✔
22

23
        # reset category ACL to single predictable state
24
        category_acl.update(
1✔
25
            {
26
                "can_see": 1,
27
                "can_browse": 1,
28
                "can_see_all_threads": 1,
29
                "can_see_own_threads": 0,
30
                "can_hide_threads": 0,
31
                "can_approve_content": 0,
32
                "can_edit_posts": 0,
33
                "can_hide_posts": 0,
34
                "can_hide_own_posts": 0,
35
                "can_close_threads": 0,
36
                "post_edit_time": 0,
37
                "can_hide_events": 0,
38
            }
39
        )
40

41
        if new_acl:
1✔
42
            category_acl.update(new_acl)
1✔
43

44
    return patch_user_acl(patch_acl)
1✔
45

46

47
class ThreadViewTestCase(AuthenticatedUserTestCase):
1✔
48
    def setUp(self):
1✔
49
        super().setUp()
1✔
50

51
        self.category = Category.objects.get(slug="first-category")
1✔
52
        self.thread = test.post_thread(category=self.category)
1✔
53

54

55
class ThreadVisibilityTests(ThreadViewTestCase):
1✔
56
    def test_thread_displays(self):
1✔
57
        """thread view has no showstoppers"""
58
        response = self.client.get(self.thread.get_absolute_url())
1✔
59
        self.assertContains(response, self.thread.title)
1✔
60

61
    def test_view_shows_owner_thread(self):
1✔
62
        """view handles "owned threads" only"""
63
        with patch_category_acl({"can_see_all_threads": 0}):
1✔
64
            response = self.client.get(self.thread.get_absolute_url())
1✔
65
            self.assertEqual(response.status_code, 404)
1✔
66

67
            self.thread.starter = self.user
1✔
68
            self.thread.save()
1✔
69

70
            response = self.client.get(self.thread.get_absolute_url())
1✔
71
            self.assertContains(response, self.thread.title)
1✔
72

73
    def test_view_validates_category_permissions(self):
1✔
74
        """view validates category visiblity"""
75
        with patch_category_acl({"can_see": 0}):
1✔
76
            response = self.client.get(self.thread.get_absolute_url())
1✔
77
            self.assertEqual(response.status_code, 404)
1✔
78

79
        with patch_category_acl({"can_browse": 0}):
1✔
80
            response = self.client.get(self.thread.get_absolute_url())
1✔
81
            self.assertEqual(response.status_code, 404)
1✔
82

83
    def test_view_shows_unapproved_thread(self):
1✔
84
        """view handles unapproved thread"""
85
        with patch_category_acl({"can_approve_content": 0}):
1✔
86
            self.thread.is_unapproved = True
1✔
87
            self.thread.save()
1✔
88

89
            response = self.client.get(self.thread.get_absolute_url())
1✔
90
            self.assertEqual(response.status_code, 404)
1✔
91

92
        # grant permission to see unapproved content
93
        with patch_category_acl({"can_approve_content": 1}):
1✔
94
            response = self.client.get(self.thread.get_absolute_url())
1✔
95
            self.assertContains(response, self.thread.title)
1✔
96

97
            # make test user thread's owner and remove permission to see unapproved
98
            # user should be able to see thread as its author anyway
99
            self.thread.starter = self.user
1✔
100
            self.thread.save()
1✔
101

102
        with patch_category_acl({"can_approve_content": 0}):
1✔
103
            response = self.client.get(self.thread.get_absolute_url())
1✔
104
            self.assertContains(response, self.thread.title)
1✔
105

106
    def test_view_shows_hidden_thread(self):
1✔
107
        """view handles hidden thread"""
108
        with patch_category_acl({"can_hide_threads": 0}):
1✔
109
            self.thread.is_hidden = True
1✔
110
            self.thread.save()
1✔
111

112
            response = self.client.get(self.thread.get_absolute_url())
1✔
113
            self.assertEqual(response.status_code, 404)
1✔
114

115
        # threads owners are not extempt from hidden threads check
116
        self.thread.starter = self.user
1✔
117
        self.thread.save()
1✔
118

119
        response = self.client.get(self.thread.get_absolute_url())
1✔
120
        self.assertEqual(response.status_code, 404)
1✔
121

122
        # grant permission to see hidden content
123
        with patch_category_acl({"can_hide_threads": 1}):
1✔
124
            response = self.client.get(self.thread.get_absolute_url())
1✔
125
            self.assertContains(response, self.thread.title)
1✔
126

127

128
class ThreadPostsVisibilityTests(ThreadViewTestCase):
1✔
129
    def test_post_renders(self):
1✔
130
        """post renders"""
131
        post = test.reply_thread(self.thread, poster=self.user)
1✔
132

133
        response = self.client.get(self.thread.get_absolute_url())
1✔
134
        self.assertContains(response, post.get_absolute_url())
1✔
135

136
    def test_invalid_post_renders(self):
1✔
137
        """invalid post renders"""
138
        post = test.reply_thread(self.thread, poster=self.user)
1✔
139

140
        post.parsed = "fiddled post content"
1✔
141
        post.save()
1✔
142

143
        response = self.client.get(self.thread.get_absolute_url())
1✔
144
        self.assertContains(response, post.get_absolute_url())
1✔
145
        self.assertContains(response, "This post's contents cannot be displayed.")
1✔
146
        self.assertNotContains(response, post.parsed)
1✔
147

148
    def test_hidden_post_visibility(self):
1✔
149
        """hidden post renders correctly"""
150
        post = test.reply_thread(self.thread, message="Hello, I'm hidden post!")
1✔
151
        hide_post(self.user, post)
1✔
152

153
        response = self.client.get(self.thread.get_absolute_url())
1✔
154
        self.assertContains(response, post.get_absolute_url())
1✔
155
        self.assertContains(
1✔
156
            response, "This post is hidden. You cannot see its contents."
157
        )
158
        self.assertNotContains(response, post.parsed)
1✔
159

160
        # posts authors are not extempt from seeing hidden posts content
161
        post.posted_by = self.user
1✔
162
        post.save()
1✔
163

164
        response = self.client.get(self.thread.get_absolute_url())
1✔
165
        self.assertContains(response, post.get_absolute_url())
1✔
166
        self.assertContains(
1✔
167
            response, "This post is hidden. You cannot see its contents."
168
        )
169
        self.assertNotContains(response, post.parsed)
1✔
170

171
        # permission to hide own posts isn't enought to see post content
172
        with patch_category_acl({"can_hide_own_posts": 1}):
1✔
173
            response = self.client.get(self.thread.get_absolute_url())
1✔
174
            self.assertContains(response, post.get_absolute_url())
1✔
175
            self.assertContains(
1✔
176
                response, "This post is hidden. You cannot see its contents."
177
            )
178
            self.assertNotContains(response, post.parsed)
1✔
179

180
        # post's content is displayed after permission to see posts is granted
181
        with patch_category_acl({"can_hide_posts": 1}):
1✔
182
            response = self.client.get(self.thread.get_absolute_url())
1✔
183
            self.assertContains(response, post.get_absolute_url())
1✔
184
            self.assertContains(
1✔
185
                response,
186
                "This post is hidden. Only users with permission may see its contents.",
187
            )
188
            self.assertNotContains(
1✔
189
                response, "This post is hidden. You cannot see its contents."
190
            )
191
            self.assertContains(response, post.parsed)
1✔
192

193
    def test_unapproved_post_visibility(self):
1✔
194
        """
195
        unapproved post renders for its author and users with perm to approve content
196
        """
197
        post = test.reply_thread(self.thread, is_unapproved=True)
1✔
198

199
        # post is hdden because we aren't its author nor user with permission to approve
200
        response = self.client.get(self.thread.get_absolute_url())
1✔
201
        self.assertNotContains(response, post.get_absolute_url())
1✔
202

203
        # post displays because we have permission to approve unapproved content
204
        with patch_category_acl({"can_approve_content": 1}):
1✔
205
            response = self.client.get(self.thread.get_absolute_url())
1✔
206
            self.assertContains(response, post.get_absolute_url())
1✔
207
            self.assertContains(response, "This post is unapproved.")
1✔
208
            self.assertContains(response, post.parsed)
1✔
209

210
        # post displays because we are its author
211
        with patch_category_acl({"can_approve_content": 0}):
1✔
212
            post.poster = self.user
1✔
213
            post.save()
1✔
214

215
            response = self.client.get(self.thread.get_absolute_url())
1✔
216
            self.assertContains(response, post.get_absolute_url())
1✔
217
            self.assertContains(response, "This post is unapproved.")
1✔
218
            self.assertContains(response, post.parsed)
1✔
219

220

221
class ThreadEventVisibilityTests(ThreadViewTestCase):
1✔
222
    def test_thread_events_render(self):
1✔
223
        """different thread events render"""
224
        TEST_ACTIONS = [
1✔
225
            (
226
                threads_moderation.pin_thread_globally,
227
                "Thread has been pinned globally.",
228
            ),
229
            (
230
                threads_moderation.pin_thread_locally,
231
                "Thread has been pinned in category.",
232
            ),
233
            (threads_moderation.unpin_thread, "Thread has been unpinned."),
234
            (threads_moderation.approve_thread, "Thread has been approved."),
235
            (threads_moderation.close_thread, "Thread has been closed."),
236
            (threads_moderation.open_thread, "Thread has been opened."),
237
            (threads_moderation.hide_thread, "Thread has been made hidden."),
238
            (threads_moderation.unhide_thread, "Thread has been revealed."),
239
        ]
240

241
        self.thread.is_unapproved = True
1✔
242
        self.thread.save()
1✔
243

244
        for action, message in TEST_ACTIONS:
1✔
245
            self.thread.post_set.filter(is_event=True).delete()
1✔
246

247
            with patch_category_acl({"can_approve_content": 1, "can_hide_threads": 1}):
1✔
248
                user_acl = useracl.get_user_acl(self.user, cache_versions)
1✔
249
                request = Mock(user=self.user, user_acl=user_acl, user_ip="127.0.0.1")
1✔
250
                action(request, self.thread)
1✔
251

252
                event = self.thread.post_set.filter(is_event=True)[0]
1✔
253

254
                # event renders
255
                response = self.client.get(self.thread.get_absolute_url())
1✔
256
                self.assertContains(response, event.get_absolute_url())
1✔
257
                self.assertContains(response, message)
1✔
258

259
            # hidden events don't render without permission
260
            with patch_category_acl({"can_approve_content": 1, "can_hide_threads": 1}):
1✔
261
                hide_post(self.user, event)
1✔
262
                response = self.client.get(self.thread.get_absolute_url())
1✔
263
                self.assertNotContains(response, event.get_absolute_url())
1✔
264
                self.assertNotContains(response, message)
1✔
265

266
            # hidden event renders with permission
267
            with patch_category_acl(
1✔
268
                {"can_approve_content": 1, "can_hide_threads": 1, "can_hide_events": 1}
269
            ):
270
                hide_post(self.user, event)
1✔
271
                response = self.client.get(self.thread.get_absolute_url())
1✔
272
                self.assertContains(response, event.get_absolute_url())
1✔
273
                self.assertContains(response, message)
1✔
274
                self.assertContains(response, "Hidden by")
1✔
275

276
            # Event is only loaded if thread has events flag
277
            with patch_category_acl(
1✔
278
                {"can_approve_content": 1, "can_hide_threads": 1, "can_hide_events": 1}
279
            ):
280
                self.thread.has_events = False
1✔
281
                self.thread.save()
1✔
282

283
                response = self.client.get(self.thread.get_absolute_url())
1✔
284
                self.assertNotContains(response, event.get_absolute_url())
1✔
285

286
    @override_dynamic_settings(events_per_page=4)
1✔
287
    def test_events_limit(self):
1✔
288
        """forum will trim oldest events if theres more than allowed by config"""
289
        events = []
1✔
290
        for _ in range(5):
1✔
291
            request = Mock(user=self.user, user_ip="127.0.0.1")
1✔
292
            event = record_event(request, self.thread, "closed")
1✔
293
            events.append(event)
1✔
294

295
        # test that only events within limits were rendered
296
        response = self.client.get(self.thread.get_absolute_url())
1✔
297

298
        for event in events[4:]:
1✔
299
            self.assertContains(response, event.get_absolute_url())
1✔
300
        self.assertNotContains(response, events[0].get_absolute_url())
1✔
301

302
    @override_dynamic_settings(posts_per_page=10, events_per_page=4)
1✔
303
    def test_events_dont_take_space(self):
1✔
304
        """events dont take space away from posts"""
305
        posts_limit = 10
1✔
306
        events_limit = 4
1✔
307
        events = []
1✔
308

309
        for _ in range(events_limit + 5):
1✔
310
            request = Mock(user=self.user, user_ip="127.0.0.1")
1✔
311
            event = record_event(request, self.thread, "closed")
1✔
312
            events.append(event)
1✔
313

314
        posts = []
1✔
315
        for _ in range(posts_limit - 1):
1✔
316
            post = test.reply_thread(self.thread)
1✔
317
            posts.append(post)
1✔
318

319
        # test that all events and posts within limits were rendered
320
        response = self.client.get(self.thread.get_absolute_url())
1✔
321

322
        for event in events[5:]:
1✔
323
            self.assertContains(response, event.get_absolute_url())
1✔
324
        for post in posts:
1✔
325
            self.assertContains(response, post.get_absolute_url())
1✔
326

327
        # add second page to thread with more events
328
        for _ in range(posts_limit):
1✔
329
            post = test.reply_thread(self.thread)
1✔
330
        for _ in range(events_limit):
1✔
331
            request = Mock(user=self.user, user_ip="127.0.0.1")
1✔
332
            event = record_event(request, self.thread, "closed")
1✔
333
            events.append(event)
1✔
334

335
        # see first page
336
        response = self.client.get(self.thread.get_absolute_url())
1✔
337

338
        for event in events[5:events_limit]:
1✔
UNCOV
339
            self.assertContains(response, event.get_absolute_url())
×
340
        for post in posts[: posts_limit - 1]:
1✔
341
            self.assertContains(response, post.get_absolute_url())
1✔
342

343
        # see second page
344
        response = self.client.get("%s2/" % self.thread.get_absolute_url())
1✔
345
        for event in events[5 + events_limit :]:
1✔
346
            self.assertContains(response, event.get_absolute_url())
1✔
347
        for post in posts[posts_limit - 1 :]:
1✔
UNCOV
348
            self.assertContains(response, post.get_absolute_url())
×
349

350
    def test_changed_thread_title_event_renders(self):
1✔
351
        """changed thread title event renders"""
352
        request = Mock(user=self.user, user_ip="127.0.0.1")
1✔
353
        threads_moderation.change_thread_title(
1✔
354
            request, self.thread, "Lorem renamed ipsum!"
355
        )
356

357
        event = self.thread.post_set.filter(is_event=True)[0]
1✔
358
        self.assertEqual(event.event_type, "changed_title")
1✔
359

360
        # event renders
361
        response = self.client.get(self.thread.get_absolute_url())
1✔
362
        self.assertContains(response, event.get_absolute_url())
1✔
363
        self.assertContains(response, "title has been changed from")
1✔
364
        self.assertContains(response, self.thread.title)
1✔
365

366
    def test_thread_move_event_renders(self):
1✔
367
        """moved thread event renders"""
368
        self.thread.category = self.thread.category.parent
1✔
369
        self.thread.save()
1✔
370

371
        request = Mock(user=self.user, user_ip="127.0.0.1")
1✔
372
        threads_moderation.move_thread(request, self.thread, self.category)
1✔
373

374
        event = self.thread.post_set.filter(is_event=True)[0]
1✔
375
        self.assertEqual(event.event_type, "moved")
1✔
376

377
        # event renders
378
        response = self.client.get(self.thread.get_absolute_url())
1✔
379
        self.assertContains(response, event.get_absolute_url())
1✔
380
        self.assertContains(response, "Thread has been moved from")
1✔
381

382
    @patch("misago.threads.moderation.threads.delete_duplicate_watched_threads")
1✔
383
    def test_thread_merged_event_renders(self, delete_duplicate_watched_threads_mock):
1✔
384
        """merged thread event renders"""
385
        request = Mock(user=self.user, user_ip="127.0.0.1")
1✔
386
        other_thread = test.post_thread(category=self.category)
1✔
387
        threads_moderation.merge_thread(request, self.thread, other_thread)
1✔
388

389
        event = self.thread.post_set.filter(is_event=True)[0]
1✔
390
        self.assertEqual(event.event_type, "merged")
1✔
391

392
        # event renders
393
        response = self.client.get(self.thread.get_absolute_url())
1✔
394
        self.assertContains(response, event.get_absolute_url())
1✔
395
        self.assertContains(response, "thread has been merged into this thread")
1✔
396

397

398
class ThreadAttachmentsViewTests(ThreadViewTestCase):
1✔
399
    def mock_attachment_cache(self, data):
1✔
400
        json = {
1✔
401
            "url": {},
402
            "size": 16914,
403
            "filename": "Archiwum.zip",
404
            "filetype": "ZIP",
405
            "is_image": False,
406
            "uploaded_on": "2016-10-22T21:17:40.408710Z",
407
            "uploader_name": "User",
408
        }
409

410
        json.update(data)
1✔
411
        return json
1✔
412

413
    def test_attachments_display(self):
1✔
414
        """thread posts show list of attachments below them"""
415
        post = self.thread.first_post
1✔
416

417
        post.attachments_cache = [
1✔
418
            self.mock_attachment_cache(
419
                {
420
                    "url": {
421
                        "index": "/attachment/loremipsum-123/",
422
                        "thumb": None,
423
                        "uploader": "/user/user-123/",
424
                    },
425
                    "filename": "Archiwum-1.zip",
426
                }
427
            ),
428
            self.mock_attachment_cache(
429
                {
430
                    "url": {
431
                        "index": "/attachment/loremipsum-223/",
432
                        "thumb": "/attachment/thumb/loremipsum-223/",
433
                        "uploader": "/user/user-223/",
434
                    },
435
                    "is_image": True,
436
                    "filename": "Archiwum-2.zip",
437
                }
438
            ),
439
            self.mock_attachment_cache(
440
                {
441
                    "url": {
442
                        "index": "/attachment/loremipsum-323/",
443
                        "thumb": None,
444
                        "uploader": "/user/user-323/",
445
                    },
446
                    "filename": "Archiwum-3.zip",
447
                }
448
            ),
449
        ]
450
        post.save()
1✔
451

452
        # attachments render
453
        response = self.client.get(self.thread.get_absolute_url())
1✔
454

455
        for attachment in post.attachments_cache:
1✔
456
            self.assertContains(response, attachment["filename"])
1✔
457
            self.assertContains(response, attachment["uploader_name"])
1✔
458
            self.assertContains(response, attachment["url"]["index"])
1✔
459
            self.assertContains(response, attachment["url"]["uploader"])
1✔
460

461
            if attachment["url"]["thumb"]:
1✔
462
                self.assertContains(response, attachment["url"]["thumb"])
1✔
463

464

465
class ThreadPollViewTests(ThreadViewTestCase):
1✔
466
    def test_poll_voted_display(self):
1✔
467
        """view has no showstoppers when displaying voted poll"""
468
        poll = test.post_poll(self.thread, self.user)
1✔
469

470
        response = self.client.get(self.thread.get_absolute_url())
1✔
471
        self.assertContains(response, poll.question)
1✔
472
        self.assertContains(response, "4 votes")
1✔
473
        self.assertNotContains(response, "Save your vote")
1✔
474

475
    def test_poll_unvoted_display(self):
1✔
476
        """view has no showstoppers when displaying poll vote form"""
477
        poll = test.post_poll(self.thread, self.user)
1✔
478
        poll.pollvote_set.all().delete()
1✔
479

480
        response = self.client.get(self.thread.get_absolute_url())
1✔
481
        self.assertContains(response, poll.question)
1✔
482
        self.assertContains(response, "Save your vote")
1✔
483

484
    def test_poll_anonymous_view(self):
1✔
485
        """view has no showstoppers when displaying poll to anon user"""
486
        poll = test.post_poll(self.thread, self.user)
1✔
487

488
        self.logout_user()
1✔
489

490
        response = self.client.get(self.thread.get_absolute_url())
1✔
491
        self.assertContains(response, poll.question)
1✔
492
        self.assertContains(response, "4 votes")
1✔
493
        self.assertNotContains(response, "Save your vote")
1✔
494

495

496
class ThreadLikedPostsViewTests(ThreadViewTestCase):
1✔
497
    def test_liked_posts_display(self):
1✔
498
        """view has no showstoppers on displaying posts with likes"""
499
        test.like_post(self.thread.first_post, self.user)
1✔
500

501
        response = self.client.get(self.thread.get_absolute_url())
1✔
502
        self.assertContains(response, '"is_liked": true')
1✔
503

504
    def test_liked_posts_no_permission(self):
1✔
505
        """
506
        view has no showstoppers on displaying posts with likes without perm
507
        """
508
        test.like_post(self.thread.first_post, self.user)
1✔
509

510
        with patch_category_acl({"can_see_posts_likes": 0}):
1✔
511
            response = self.client.get(self.thread.get_absolute_url())
1✔
512
            self.assertNotContains(response, '"is_liked": true')
1✔
513
            self.assertNotContains(response, '"is_liked": false')
1✔
514
            self.assertContains(response, '"is_liked": null')
1✔
515

516

517
class ThreadAnonViewTests(ThreadViewTestCase):
1✔
518
    def test_anonymous_user_view_no_showstoppers_display(self):
1✔
519
        """kitchensink thread view has no showstoppers for anons"""
520
        request = Mock(user=self.user, user_ip="127.0.0.1")
1✔
521

522
        poll = test.post_poll(self.thread, self.user)
1✔
523
        event = record_event(request, self.thread, "closed")
1✔
524

525
        hidden_event = record_event(request, self.thread, "opened")
1✔
526
        hide_post(self.user, hidden_event)
1✔
527

528
        unapproved_post = test.reply_thread(self.thread, is_unapproved=True)
1✔
529
        post = test.reply_thread(self.thread)
1✔
530

531
        self.logout_user()
1✔
532

533
        response = self.client.get(self.thread.get_absolute_url())
1✔
534
        self.assertContains(response, poll.question)
1✔
535
        self.assertContains(response, event.get_absolute_url())
1✔
536
        self.assertContains(response, post.get_absolute_url())
1✔
537
        self.assertNotContains(response, hidden_event.get_absolute_url())
1✔
538
        self.assertNotContains(response, unapproved_post.get_absolute_url())
1✔
539

540

541
class ThreadUnicodeSupportTests(ThreadViewTestCase):
1✔
542
    def test_category_name(self):
1✔
543
        """unicode in category name causes no showstopper"""
544
        self.category.name = "Łódź"
1✔
545
        self.category.save()
1✔
546

547
        with patch_category_acl():
1✔
548
            response = self.client.get(self.thread.get_absolute_url())
1✔
549
            self.assertEqual(response.status_code, 200)
1✔
550

551
    def test_thread_title(self):
1✔
552
        """unicode in thread title causes no showstopper"""
553
        self.thread.title = "Łódź"
1✔
554
        self.thread.slug = "Lodz"
1✔
555
        self.thread.save()
1✔
556

557
        with patch_category_acl():
1✔
558
            response = self.client.get(self.thread.get_absolute_url())
1✔
559
            self.assertEqual(response.status_code, 200)
1✔
560

561
    def test_post_content(self):
1✔
562
        """unicode in thread title causes no showstopper"""
563
        self.thread.first_post.original = "Łódź"
1✔
564
        self.thread.first_post.parsed = "<p>Łódź</p>"
1✔
565

566
        update_post_checksum(self.thread.first_post)
1✔
567
        self.thread.first_post.save()
1✔
568

569
        with patch_category_acl():
1✔
570
            response = self.client.get(self.thread.get_absolute_url())
1✔
571
            self.assertEqual(response.status_code, 200)
1✔
572

573
    def test_user_rank(self):
1✔
574
        """unicode in user rank causes no showstopper"""
575
        self.user.title = "Łódź"
1✔
576
        self.user.rank.name = "Łódź"
1✔
577
        self.user.rank.title = "Łódź"
1✔
578
        self.user.rank.save()
1✔
579
        self.user.save()
1✔
580

581
        with patch_category_acl():
1✔
582
            response = self.client.get(self.thread.get_absolute_url())
1✔
583
            self.assertEqual(response.status_code, 200)
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