Skip to content

Commit

Permalink
87% test coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
Peter Bengtsson committed Apr 7, 2011
1 parent 3351ecf commit c9b0f3f
Show file tree
Hide file tree
Showing 11 changed files with 411 additions and 107 deletions.
2 changes: 0 additions & 2 deletions TODO.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
* TESTS!

* commenting on lines of code

* Comments in HTML instead of AJAX (SEO)
Expand Down
15 changes: 10 additions & 5 deletions apps/gists/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ def on_gist_found(self, gist_id, response):
#files = iter(gist.files)
#self.fetch_files(gist, files)

def fetch_files(self, gist, files_iterator, response=None):
def fetch_files(self, gist, files_iterator, response=None): # pragma: no cover
# don't think we need this any more
# Might be good one day for full text indexing search or something
if response is not None:
gist.contents.append(unicode(response.body))
gist.save()
Expand All @@ -80,13 +82,16 @@ def get(self):
class GistHandler(BaseHandler):
def find_gist(self, gist_id):
try:
return self.db.Gist.one({'gist_id': int(gist_id)})
gist = self.db.Gist.one({'gist_id': int(gist_id)})
assert gist
return gist
except (ValueError, AssertionError):
raise tornado.web.HTTPError(404, "Gist not found")

def get(self, gist_id):
options = self.get_base_options()
gist = self.find_gist(gist_id)
assert gist.gist_id == int(gist_id)
options['gist'] = gist
options['edit'] = False
self.render("gist.html", **options)
Expand Down Expand Up @@ -147,7 +152,7 @@ def get(self, gist_id):
self.redirect('/?gist=deleted')


@route(r'/preview_markdown$')
@route(r'/preview_markdown$', name="preview_markdown")
class PreviewMarkdownHandler(BaseHandler):
def check_xsrf_cookie(self):
pass
Expand All @@ -158,7 +163,7 @@ def post(self):
self.write_json(dict(html=html))


@route(r'/(\d+)/comments', name="add_comment")
@route(r'/(\d+)/comments', name="comments")
class CommentsHandler(GistHandler):

def get(self, gist_id):
Expand Down Expand Up @@ -186,7 +191,7 @@ def get(self, gist_id):

self.write_json(dict(comments=comments))


@tornado.web.authenticated
def post(self, gist_id):
options = self.get_base_options()
gist = self.find_gist(gist_id)
Expand Down
2 changes: 2 additions & 0 deletions apps/gists/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from test_models import *
from test_handlers import *
77 changes: 77 additions & 0 deletions apps/gists/tests/test_handlers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import json
from apps.main.tests.test_handlers import HandlersTestCase
class GistsHandlersTestCase(HandlersTestCase):


def test_commenting_on_gist(self):
assert not self.db.Comment.find().count()
peter = self.db.User()
peter.login = u'peterbe'
peter.email = u''
peter.company = u''
peter.name = u'Peter'
peter.save()

gist1 = self.db.Gist()
gist1.user = peter
gist1.gist_id = 1234
gist1.created_at = u'yesterday'
gist1.files = [u'foo.py']
gist1.description = u'Testing the Atom feed'
gist1.discussion = u"""Full `markdown` description:
function foo():
return bar
[peterbe](http://www.peterbe.com)
"""
gist1.save()

comment_url = self.reverse_url('comments', 1234)
response = self.client.get(comment_url)
assert response.code == 200
struct = json.loads(response.body)
self.assertEqual(struct, {'comments':[]})

post_data = {
'comment':'I love `cheese`!',
'file': 'foo.py',
}
response = self.client.post(comment_url, post_data)
self.assertEqual(response.code, 403)

self.client.login('peterbe')

response = self.client.post(comment_url, post_data)
self.assertEqual(response.code, 302)
self.assertTrue(response.headers['Location'].startswith(
self.reverse_url('view_gist', 1234)))

assert self.db.Comment.find().count()
comment = self.db.Comment.one()
self.assertEqual(comment.user.login, 'peterbe')
self.assertEqual(comment.comment, post_data['comment'])
self.assertEqual(comment.file, post_data['file'])

response = self.client.get(comment_url)
assert response.code == 200
struct = json.loads(response.body)
self.assertEqual(len(struct['comments']), 1)
first = struct['comments'][0]

self.assertTrue(first.get('ago'))
self.assertTrue('<code>cheese</code>' in first['comment'])
self.assertTrue(first.get('user'))
self.assertTrue(first.get('id'))

def test_preview_markdown(self):
url = self.reverse_url('preview_markdown')
post_data = {'text':
"Test\nfoo `and` <script>alert('xsss')</script>"}
response = self.client.post(url, post_data)
assert response.code == 200
struct = json.loads(response.body)
assert struct['html']
self.assertTrue('<code>and</code>' in struct['html'])
self.assertTrue(
"&lt;script&gt;alert('xsss')&lt;/script&gt;" \
in struct['html'])
49 changes: 49 additions & 0 deletions apps/gists/tests/test_models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
from mongokit import RequireFieldError, ValidationError
import datetime
#import sys; sys.path.insert(0, '..')
from apps.main.tests.base import BaseModelsTestCase
from apps.gists.models import Gist, Comment
#from apps.main.models import User

class ModelsTestCase(BaseModelsTestCase):

def setUp(self):
super(ModelsTestCase, self).setUp()
self.con.register([Gist, Comment])


def test_gist(self):
user = self.db.User()
user.login = u'peterbe'
user.save()

gist = self.db.Gist()
gist.user = user
gist.gist_id = 1
gist.description = u'Description'
gist.files = [u'foo.py', u'bar.js']
gist.save()

assert gist.no_comments == 0

def test_comment(self):
user = self.db.User()
user.login = u'peterbe'
user.save()

gist = self.db.Gist()
gist.user = user
gist.gist_id = 1
gist.description = u'Description'
gist.files = [u'foo.py', u'bar.js']
gist.save()

comment = self.db.Comment()
comment.gist = gist
comment.user = user
comment.comment = u"Works"
comment.comment_format = u"markdown"
comment.file = u'bar.js'
comment.save()

self.assertEqual(comment.file_index_number, 1)
100 changes: 16 additions & 84 deletions apps/main/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

try:
import pyatom
except ImportError:
except ImportError: # pragma: no cover
import warnings
warnings.warn("pyatom not installed (pip install pyatom)")
pyatom = None
Expand All @@ -39,26 +39,17 @@
from utils.decorators import login_required
import settings

class HTTPSMixin(object):

def is_secure(self):
# XXX is this really the best/only way?
return self.request.headers.get('X-Scheme') == 'https'

def httpify_url(self):
return self.request.full_url().replace('https://', 'http://')

def httpsify_url(self):
return self.request.full_url().replace('http://', 'https://')


class BaseHandler(tornado.web.RequestHandler, HTTPSMixin):
class BaseHandler(tornado.web.RequestHandler):

@property
def db(self):
return self.application.con[self.application.database_name]

def xxx_handle_request_exception(self, exception):
def is_secure(self):
return self.request.headers.get('X-Scheme') == 'https'

def xxx_handle_request_exception(self, exception): # pragma: no cover
if not isinstance(exception, tornado.web.HTTPError) and \
not self.application.settings['debug']:
# ie. a 500 error
Expand All @@ -74,20 +65,6 @@ def xxx_handle_request_exception(self, exception):
print exception
super(BaseHandler, self)._handle_request_exception(exception)

def xxx_log(self):
"""overwritten from tornado.web.RequestHandler because we want to put
all requests as logging.debug and keep all normal logging.info()"""
if self._status_code < 400:
#log_method = logging.info
log_method = logging.debug
elif self._status_code < 500:
log_method = logging.warning
else:
log_method = logging.error
request_time = 1000.0 * self.request.request_time()
log_method("%d %s %.2fms", self._status_code,
self._request_summary(), request_time)


def _email_exception(self, exception): # pragma: no cover
import sys
Expand Down Expand Up @@ -142,30 +119,6 @@ def get_current_user(self):
if user_id:
return self.db.User.one({'_id': ObjectId(user_id)})

# shortcut where the user parameter is not optional
def get_user_settings(self, user, fast=False):
return self.get_current_user_settings(user=user, fast=fast)

def get_current_user_settings(self, user=None, fast=False):
if user is None:
user = self.get_current_user()

if not user:
raise ValueError("Can't get settings when there is no user")
_search = {'user.$id': user['_id']}
if fast:
return self.db[UserSettings.__collection__].one(_search) # skip mongokit
else:
return self.db.UserSettings.one(_search)

def create_user_settings(self, user, **default_settings):
user_settings = self.db.UserSettings()
user_settings.user = user
for key in default_settings:
setattr(user_settings, key, default_settings[key])
user_settings.save()
return user_settings

def get_cdn_prefix(self):
"""return something that can be put in front of the static filename
E.g. if filename is '/static/image.png' and you return '//cloudfront.com'
Expand All @@ -175,30 +128,9 @@ def get_cdn_prefix(self):
return self.application.settings.get('cdn_prefix')

def write_json(self, struct, javascript=False):
if javascript:
self.set_header("Content-Type", "text/javascript; charset=UTF-8")
else:
self.set_header("Content-Type", "application/json; charset=UTF-8")
self.set_header("Content-Type", "application/json; charset=UTF-8")
self.write(tornado.escape.json_encode(struct))


def serialize_dict(self, data):
for key, value in data.items():
if isinstance(value, (datetime.datetime, datetime.date)):
data[key] = mktime(value.timetuple())
return data

def find_user(self, username):
return self.db.User.one(dict(username=\
re.compile('^%s$' % re.escape(username), re.I)))

def find_user_by_email(self, email):
return self.db.User.one(dict(email=\
re.compile('^%s$' % re.escape(email), re.I)))

def has_user(self, username):
return bool(self.find_user(username))

def is_admin_user(self, user):
return user.email in settings.ADMIN_EMAILS

Expand Down Expand Up @@ -228,9 +160,6 @@ def get_base_options(self):
user_name = "stranger"
options['user_name'] = user_name

# override possible settings
user_settings = self.get_current_user_settings(user)

options['settings'] = settings
options['git_revision'] = self.application.settings['git_revision']
options['debug'] = self.application.settings['debug']
Expand Down Expand Up @@ -441,7 +370,7 @@ def _on_github_request(self, callback, response):
callback(tornado.escape.json_decode(response.body))


@route('/auth/github/')
@route('/auth/github/', name="github_login")
class GithubLoginHandler(BaseAuthHandler, GithubMixin):

@tornado.web.asynchronous
Expand All @@ -462,24 +391,27 @@ def get(self):
extra_params={})#"scope": "read_stream,offline_access"})

def _on_login(self, github_user):
user = self.db.User.one({'login':github_user['login']})
if not github_user.get('login'):
return self.redirect('/?login_failed=true')

#pprint(github_user)
user = self.db.User.one({'login':unicode(github_user['login'])})
if user is None:
user = self.db.User()
user.login = github_user['login']
print "CREATE NEW USER"
user.login = unicode(github_user['login'])
#print "CREATE NEW USER"
for key in ('email','name','company','gravatar_id','access_token'):
if key in github_user:
setattr(user, key, unicode(github_user[key]))
user.save()
print repr(user)
self.set_secure_cookie("user", str(user._id), expires_days=100)

self.redirect('/')
#logging.error(user)



@route(r'/auth/logout/')
@route(r'/auth/logout/', name="logout")
class AuthLogoutHandler(BaseAuthHandler):
def get(self):
self.clear_all_cookies()
Expand Down
Loading

0 comments on commit c9b0f3f

Please sign in to comment.