-
Notifications
You must be signed in to change notification settings - Fork 891
forums/tests => use model makers #558
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 6 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,155 +1,33 @@ | ||
| from datetime import datetime | ||
| import random | ||
| from string import letters | ||
|
|
||
| from django.conf import settings | ||
| from django.contrib.auth.models import User | ||
| from django.template.defaultfilters import slugify | ||
|
|
||
| from nose.tools import eq_ | ||
|
|
||
| from forums.models import Forum, Thread, Post, ThreadLockedError | ||
| from forums.views import sort_threads | ||
| from sumo.tests import get, LocalizingClient, TestCase, with_save | ||
| from forums.models import Forum, Thread, Post | ||
| from users.tests import user | ||
| from sumo.tests import LocalizingClient, TestCase, with_save | ||
|
|
||
|
|
||
| class ForumTestCase(TestCase): | ||
| fixtures = ['users.json', 'posts.json', 'forums_permissions.json'] | ||
| client_class = LocalizingClient | ||
|
|
||
|
|
||
| class PostTestCase(ForumTestCase): | ||
|
|
||
| def test_new_post_updates_thread(self): | ||
| """Saving a new post in a thread should update the last_post key in | ||
| that thread to point to the new post.""" | ||
| t = Thread.objects.get(pk=2) | ||
| post = t.new_post(author=t.creator, content='an update') | ||
| post.save() | ||
| eq_(post.id, t.last_post_id) | ||
|
|
||
| def test_new_post_updates_forum(self): | ||
| """Saving a new post should update the last_post key in the forum to | ||
| point to the new post.""" | ||
| t = Thread.objects.get(pk=2) | ||
| f = t.forum | ||
| post = t.new_post(author=t.creator, content='another update') | ||
| post.save() | ||
| eq_(post.id, f.last_post_id) | ||
|
|
||
| def test_update_post_does_not_update_thread(self): | ||
| """Updating/saving an old post in a thread should _not_ update the | ||
| last_post key in that thread.""" | ||
| p = Post.objects.get(pk=2) | ||
| old = p.thread.last_post_id | ||
| p.content = 'updated content' | ||
| p.save() | ||
| eq_(old, p.thread.last_post_id) | ||
|
|
||
| def test_update_forum_does_not_update_thread(self): | ||
| """Updating/saving an old post in a forum should _not_ update the | ||
| last_post key in that forum.""" | ||
| p = Post.objects.get(pk=2) | ||
| old = p.thread.forum.last_post_id | ||
| p.content = 'updated content' | ||
| p.save() | ||
| eq_(old, p.thread.forum.last_post_id) | ||
|
|
||
| def test_replies_count(self): | ||
| """The Thread.replies value should remain one less than the number of | ||
| posts in the thread.""" | ||
| t = Thread.objects.get(pk=2) | ||
| old = t.replies | ||
| t.new_post(author=t.creator, content='test').save() | ||
| eq_(old + 1, t.replies) | ||
|
|
||
| def test_sticky_threads_first(self): | ||
| """Sticky threads should come before non-sticky threads.""" | ||
| thread = Thread.objects.all()[0] | ||
| # Thread 2 is the only sticky thread. | ||
| eq_(2, thread.id) | ||
|
|
||
| def test_thread_sorting(self): | ||
| """After the sticky threads, threads should be sorted by the created | ||
| date of the last post.""" | ||
| threads = Thread.objects.filter(is_sticky=False) | ||
| self.assert_(threads[0].last_post.created > | ||
| threads[1].last_post.created) | ||
|
|
||
| def test_post_sorting(self): | ||
| """Posts should be sorted chronologically.""" | ||
| posts = Thread.objects.get(pk=1).post_set.all() | ||
| for i in range(len(posts) - 1): | ||
| self.assert_(posts[i].created <= posts[i + 1].created) | ||
|
|
||
| def test_sorting_creator(self): | ||
| """Sorting threads by creator.""" | ||
| threads = sort_threads(Thread.objects, 3, 1) | ||
| self.assert_(threads[0].creator.username >= | ||
| threads[1].creator.username) | ||
|
|
||
| def test_sorting_replies(self): | ||
| """Sorting threads by replies.""" | ||
| threads = sort_threads(Thread.objects, 4) | ||
| self.assert_(threads[0].replies <= threads[1].replies) | ||
|
|
||
| def test_sorting_last_post_desc(self): | ||
| """Sorting threads by last_post descendingly.""" | ||
| threads = sort_threads(Thread.objects, 5, 1) | ||
| self.assert_(threads[0].last_post.created >= | ||
| threads[1].last_post.created) | ||
|
|
||
| def test_thread_last_page(self): | ||
| """Thread's last_page property is accurate.""" | ||
| thread = Thread.objects.all()[0] | ||
| # Format: (# replies, # of pages to expect) | ||
| test_data = ((thread.replies, 1), # Test default | ||
| (50, 3), # Test a large number | ||
| (19, 1), # Test off-by-one error, low | ||
| (20, 2), # Test off-by-one error, high | ||
| ) | ||
| for replies, pages in test_data: | ||
| thread.replies = replies | ||
| eq_(thread.last_page, pages) | ||
|
|
||
| def test_locked_thread(self): | ||
| """Trying to reply to a locked thread should raise an exception.""" | ||
| locked = Thread.objects.get(pk=3) | ||
| open = Thread.objects.get(pk=2) | ||
| user1 = User.objects.get(pk=118533) | ||
| fn = lambda: locked.new_post(author=user1, content='empty') | ||
| self.assertRaises(ThreadLockedError, fn) | ||
|
|
||
| # This should not raise an exception. | ||
| open.new_post(author=user1, content='empty') | ||
|
|
||
| def test_post_no_session(self): | ||
| r = get(self.client, 'forums.new_thread', | ||
| kwargs={'forum_slug': 'test-forum'}) | ||
| assert(settings.LOGIN_URL in r.redirect_chain[0][0]) | ||
| eq_(302, r.redirect_chain[0][1]) | ||
|
|
||
|
|
||
| class ThreadTestCase(ForumTestCase): | ||
|
|
||
| def test_delete_no_session(self): | ||
| """Delete a thread while logged out redirects.""" | ||
| r = get(self.client, 'forums.delete_thread', | ||
| kwargs={'forum_slug': 'test-forum', 'thread_id': 1}) | ||
| assert(settings.LOGIN_URL in r.redirect_chain[0][0]) | ||
| eq_(302, r.redirect_chain[0][1]) | ||
|
|
||
|
|
||
| @with_save | ||
| def forum(**kwargs): | ||
| if 'name' not in kwargs: | ||
| kwargs['name'] = u'test forum' | ||
| kwargs['name'] = ''.join(random.choice(letters) | ||
| for x in xrange(15)) | ||
| if 'slug' not in kwargs: | ||
| kwargs['slug'] = u'testforum' | ||
| kwargs['slug'] = slugify(kwargs['name']) | ||
| return Forum(**kwargs) | ||
|
|
||
|
|
||
| @with_save | ||
| def thread(**kwargs): | ||
| defaults = dict(created=datetime.now()) | ||
| defaults = dict( | ||
| created=datetime.now(), | ||
| title=''.join(random.choice(letters) for x in xrange(15))) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One thing I was doing at one point, but don't think I'm doing any longer, is use uuids for these rather than random.choice. I'm not sure the result is that different, but it's shorter code:
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like short. Also, I like killing the possibility of two randoms coming back equal. |
||
| defaults.update(kwargs) | ||
| if 'creator' not in kwargs and 'creator_id' not in kwargs: | ||
| defaults['creator'] = user(save=True) | ||
|
|
@@ -164,4 +42,13 @@ def post(**kwargs): | |
| defaults.update(kwargs) | ||
| if 'author' not in kwargs and 'author_id' not in kwargs: | ||
| defaults['author'] = user(save=True) | ||
| if 'thread' not in kwargs and 'thread_id' not in kwargs: | ||
| # The thread creator should match the post author if the | ||
| # thread doesn't exist yet. | ||
| kw = {} | ||
| if 'author' in defaults: | ||
| kw['creator'] = defaults['author'] | ||
| else: | ||
| kw['creator_id'] = defaults['author_id'] | ||
| defaults['thread'] = thread(save=True, **kw) | ||
| return Post(**defaults) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,9 +1,10 @@ | ||
| from datetime import datetime, timedelta | ||
| from nose.tools import eq_ | ||
| from pyquery import PyQuery as pq | ||
|
|
||
| from forums.feeds import ThreadsFeed, PostsFeed | ||
| from forums.models import Forum, Thread | ||
| from forums.tests import ForumTestCase, get | ||
| from forums.tests import ForumTestCase, thread, post | ||
| from sumo.tests import get | ||
|
|
||
|
|
||
| class ForumTestFeedSorting(ForumTestCase): | ||
|
|
@@ -13,23 +14,29 @@ def setUp(self): | |
|
|
||
| def test_threads_sort(self): | ||
| """Ensure that threads are being sorted properly by date/time.""" | ||
| f = Forum.objects.get(pk=1) | ||
| given_ = ThreadsFeed().items(f)[0].id | ||
| exp_ = 4L | ||
| eq_(exp_, given_) | ||
| t = thread(save=True) | ||
| f = t.forum | ||
|
|
||
| eq_(f.id, ThreadsFeed().items(f)[0].id) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure this covers the test right. It seems like the test is checking to see if for a given forum, the threads are sorted by datetime. But if there is only one thread, then it's always sorted. Seems like we want to create a forum here. Then create a few threads with various datetimes (probably want to specify the datetimes since it's part of the test), then make sure the ThreadsFeed puts them in order correctly.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. definitely, should be more than one thread :-) |
||
|
|
||
| def test_posts_sort(self): | ||
| """Ensure that posts are being sorted properly by date/time.""" | ||
| t = Thread.objects.get(pk=1) | ||
| given_ = PostsFeed().items(t)[0].id | ||
| exp_ = 24L | ||
| eq_(exp_, given_) | ||
| t = thread(save=True) | ||
| yesterday = datetime.now() - timedelta(days=1) | ||
| post(thread=t, created=yesterday, save=True) | ||
| post(thread=t, created=yesterday, save=True) | ||
| p = post(thread=t, save=True) | ||
|
|
||
| # The newest post should be the first one listed. | ||
| eq_(p.id, PostsFeed().items(t)[0].id) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is soooo much more readable than the original version. |
||
|
|
||
| def test_multi_feed_titling(self): | ||
| """Ensure that titles are being applied properly to feeds.""" | ||
| forum = Forum.objects.filter()[0] | ||
| t = thread(save=True) | ||
| forum = t.forum | ||
| post(thread=t, save=True) | ||
|
|
||
| response = get(self.client, 'forums.threads', args=[forum.slug]) | ||
| doc = pq(response.content) | ||
| given_ = doc('link[type="application/atom+xml"]')[0].attrib['title'] | ||
| exp_ = ThreadsFeed().title(forum) | ||
| eq_(exp_, given_) | ||
| eq_(doc('link[type="application/atom+xml"]')[0].attrib['title'], | ||
| ThreadsFeed().title(forum)) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we have a convention for which should go first? I'm pretty sure you switched the given and expected order. If there's no convention, it's not a big deal, but figured I'd ask.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am pretty sure most of the tests have expected first. I'll keep it consistent. |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just moved these out of
__init__.pyto their own file