Skip to content
Closed
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion apps/access/tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,18 @@
import test_utils

import access
from authority.models import Permission
from forums.models import Forum, Thread
from sumo.tests import TestCase
from sumo.tests import TestCase, with_save
from sumo.urlresolvers import reverse


@with_save
def permission(**kwargs):
if 'approved' not in kwargs:
kwargs['approved'] = True
return Permission(**kwargs)

class AccessTests(TestCase):
"""Test stuff in access/__init__.py"""
fixtures = ['users.json', 'posts.json', 'forums_permissions.json']
Expand Down
153 changes: 20 additions & 133 deletions apps/forums/tests/__init__.py
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)

Copy link
Copy Markdown
Contributor Author

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__.py to their own file

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)))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The 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:

import uuid

faux_title = str(uuid.uuid4())

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The 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)
Expand All @@ -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)
16 changes: 7 additions & 9 deletions apps/forums/tests/test_activity.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
from django.contrib.auth.models import User

from nose.tools import eq_

from activity.models import Action
from forums.models import Forum, Post, Thread
from forums.tests import ForumTestCase
from forums.tests import ForumTestCase, thread, post
from users.tests import user


class ReplyLoggingTests(ForumTestCase):
Expand All @@ -14,13 +12,13 @@ def setUp(self):

def test_activity_logged(self):
assert not Action.uncached.exists(), 'Actions start empty.'
orig, replier = User.objects.all()[0:2]
f = Forum.objects.all()[0]
t = Thread.objects.create(creator=orig, title='foo', forum=f)
Post.objects.create(author=orig, content='foo', thread=t)
orig = user(save=True)
replier = user(save=True)
t = thread(creator=orig, title='foo', save=True)
post(author=orig, content='foo', thread=t, save=True)
assert not Action.uncached.exists(), 'No actions were logged.'

Post.objects.create(author=replier, content='foo2', thread=t)
post(author=replier, content='foo2', thread=t, save=True)
eq_(1, Action.uncached.count(), 'One action was logged.')

a = Action.uncached.all()[0]
Expand Down
35 changes: 21 additions & 14 deletions apps/forums/tests/test_feeds.py
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):
Expand All @@ -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)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The 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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The 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)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The 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))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The 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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The 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.

Loading