indexden is now optional
[oweals/karmaworld.git] / karmaworld / apps / notes / tests.py
1 #!/usr/bin/env python
2 # -*- coding:utf8 -*-
3 # Copyright (C) 2012  FinalsClub Foundation
4 import re
5 import datetime
6 from django.test import TestCase
7 from bs4 import BeautifulSoup
8 from karmaworld.apps.notes.search import SearchIndex
9
10 from karmaworld.apps.notes.models import Note, NoteMarkdown
11 from karmaworld.apps.notes import sanitizer
12 from karmaworld.apps.courses.models import Course
13 from karmaworld.apps.courses.models import School
14
15 class TestNotes(TestCase):
16
17     def setUp(self):
18         # create base values to test db representations
19         self.now = datetime.datetime.utcnow()
20
21         # create a school to satisfy course requirements
22         self.school = School()
23         self.school.name = 'Marshall College'
24         self.school.save()
25
26         # create a course to test relationships
27         self.course = Course()
28         self.course.school = self.school
29         self.course.name = u'Archaeology 101'
30         self.course.save()
31         # override Course.save() appending an ID to the slug
32         self.course.slug = u'archaeology-101'
33         self.course.save()
34
35         # create a note to test against
36         self.note = Note()
37         self.note.course = self.course
38         self.note.name = u"Lecture notes concerning the use of therefore ∴"
39         self.note.category = Note.LECTURE_NOTES
40         self.note.uploaded_at = self.now
41         self.note.text = "This is the plaintext version of a note. It's pretty cool. Alpaca."
42         self.note.save()
43
44     def test_course_fkey(self):
45         self.assertEqual(self.course, self.note.course)
46
47     def test_slug_natural(self):
48         """ Test that the slug field is slugifying unicode Note.names """
49         expected = u"lecture-notes-concerning-the-use-of-therefore"
50         self.assertEqual(self.note.slug, expected)
51
52     def test_remake_slug(self):
53         """ Test the generation of a Note.slug field based on Note.
54         Name collision is expected, so see if slug handles this."""
55         expected = u"lecture-notes-concerning-the-use-of-therefore-{0}-{1}-{2}".format(
56                     self.note.uploaded_at.month,
57                     self.note.uploaded_at.day, self.note.uploaded_at.microsecond)
58
59         self.note.slug = None
60         self.note.save()
61         self.assertEqual(self.note.slug, expected)
62
63     expected_url_prefix = u'/note/marshall-college/archaeology-101/'
64     expected_slug = u'lecture-notes-concerning-the-use-of-therefore'
65     expected = expected_url_prefix + expected_slug
66
67     def test_note_get_absolute_url_slug(self):
68         """ Given a note with a slug, test that an expected url is generated """
69         # check that Note.get_absolute_url() is generating the right url
70         self.assertEqual(self.note.get_absolute_url(), self.expected)
71
72     def test_note_get_absolute_url_id(self):
73         self.note.slug = None
74         url = self.expected_url_prefix + str(self.note.id)
75         self.assertEqual(self.note.get_absolute_url(), url)
76
77     def test_note_markdown_rendering(self):
78         rich = NoteMarkdown(note=self.note,
79             markdown="""# This is fun\n[oh](http://yeah.com)""")
80         rich.save()
81         self.assertHTMLEqual(rich.html,
82                 """<h1>This is fun</h1>\n<p><a href="http://yeah.com" rel="nofollow" target="_blank">oh</a></p>""")
83
84     def test_note_rich_text_sanitization(self):
85         rich = NoteMarkdown(note=self.note, html="""
86             <script>unsafe</script>
87             <h1 class='obtrusive'>Something</h1>
88             <h2>OK</h2>
89             &amp;
90             &rdquo;
91             <a href='javascript:alert("Oh no")'>This stuff</a>
92             <a href='http://google.com'>That guy</a>
93         """)
94
95         rich.save()
96         self.assertHTMLEqual(rich.html, u"""
97             <h1>Something</h1>
98             <h2>OK</h2>
99             &amp;
100             \u201d
101             <a target='_blank' rel='nofollow'>This stuff</a>
102             <a href="http://google.com" target="_blank" rel="nofollow">That guy</a>
103         """)
104
105 class TestSanitizeToEditable(TestCase):
106     def test_clean(self):
107         dirty = """
108             <script>unsafe</script>
109             <style>html {background-color: pink !important;}</style>
110             <h1 class='obtrusive'>Something</h1>
111             <h2>OK</h2>
112             &amp;
113             &rdquo;
114             <a href='javascript:alert("Oh no")'>This stuff</a>
115             <a href='http://google.com'>That guy</a>
116             <section>
117               <h3>This should show up</h3>
118             </section>
119         """
120
121         self.assertHTMLEqual(sanitizer.sanitize_html_to_editable(dirty), u"""
122             <h1>Something</h1>
123             <h2>OK</h2>
124             &amp;
125             \u201d
126             <a target="_blank" rel="nofollow">This stuff</a>
127             <a href="http://google.com" target="_blank" rel="nofollow">That guy</a>
128             <h3>This should show up</h3>
129         """)
130
131     def test_canonical_rel(self):
132         html = """<h1>Hey there!</h1>"""
133         canonicalized = sanitizer.set_canonical_rel(html, "http://example.com")
134         self.assertHTMLEqual(canonicalized, """<html><head><link rel='canonical' href='http://example.com'></head><body><h1>Hey there!</h1></body></html>""")
135
136     def test_data_uri(self):
137         # Strip out all data URIs.
138         html = '<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==">'
139         self.assertHTMLEqual(sanitizer.sanitize_html_to_editable(html), "<img/>")
140
141         # Strip out non-image data URI's
142         html = '<img src="data:application/pdf;base64,blergh">'
143         self.assertHTMLEqual(sanitizer.sanitize_html_to_editable(html), "<img/>")
144
145 class TestDataUriToS3(TestCase):
146     def test_image_data_uri(self):
147         html = '<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==">'
148         s3ified = sanitizer.data_uris_to_s3(html)
149         soup = BeautifulSoup(s3ified)
150         regex = r'^https?://.*$'
151         self.assertTrue(bool(re.match(regex, soup.img['src'])),
152                 "{} does not match {}".format(s3ified, regex))
153
154         resanitize = sanitizer.data_uris_to_s3(s3ified)
155         self.assertHTMLEqual(s3ified, resanitize)
156
157     def test_font_face_data_uri(self):
158         # Note: this data-uri is not a valid font (it's the red dot).
159         html = '''<style>@font-face { src: url('data:application/font-woff;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=='); }</style>'''
160
161         s3ified = sanitizer.data_uris_to_s3(html)
162         self.assertFalse(re.search(r"url\('data:application", s3ified),
163                 "data URL not removed: {}".format(s3ified))
164         self.assertTrue(re.search(r"url\('https?://[^\)]+\)", s3ified),
165                 "URL not inserted: {}".format(s3ified))
166
167         # Ensure that cleaning is idempotent.
168         self.assertHTMLEqual(s3ified,
169                 sanitizer.sanitize_html_preserve_formatting(s3ified))