Example #1
0
class TestNotes(TestCase):

    def setUp(self):
        # create base values to test db representations
        self.now = datetime.datetime.utcnow()

        # create a school to satisfy course requirements
        self.school = School()
        self.school.name = 'Marshall College'
        self.school.save()

        # create a course to test relationships
        self.course = Course()
        self.course.school = self.school
        self.course.name = u'Archaeology 101'
        self.course.save()
        # override Course.save() appending an ID to the slug
        self.course.slug = u'archaeology-101'
        self.course.save()

        # create a note to test against
        self.note = Note()
        self.note.course = self.course
        self.note.name = u"Lecture notes concerning the use of therefore ∴"
        self.note.uploaded_at = self.now
        self.note.text = "This is the plaintext version of a note. It's pretty cool. Alpaca."
        self.note.save()

    def test_course_fkey(self):
        self.assertEqual(self.course, self.note.course)

    def test_slug_natural(self):
        """ Test that the slug field is slugifying unicode Note.names """
        expected = u"lecture-notes-concerning-the-use-of-therefore"
        self.assertEqual(self.note.slug, expected)

    def test_remake_slug(self):
        """ Test the generation of a Note.slug field based on Note.
        Name collision is expected, so see if slug handles this."""
        expected = u"lecture-notes-concerning-the-use-of-therefore-{0}-{1}-{2}".format(
                    self.note.uploaded_at.month,
                    self.note.uploaded_at.day, self.note.uploaded_at.microsecond)

        self.note.slug = None
        self.note.save()
        self.assertEqual(self.note.slug, expected)

    expected_url_prefix = u'/marshall-college/archaeology-101/'
    expected_slug = u'lecture-notes-concerning-the-use-of-therefore'
    expected = expected_url_prefix + expected_slug

    def test_note_get_absolute_url_slug(self):
        """ Given a note with a slug, test that an expected url is generated """
        # check that Note.get_absolute_url() is generating the right url
        self.assertEqual(self.note.get_absolute_url(), self.expected)

    def test_note_get_absolute_url_id(self):
        self.note.slug = None
        url = self.expected_url_prefix + str(self.note.id)
        self.assertEqual(self.note.get_absolute_url(), url)
Example #2
0
    def setUp(self):
        # create base values to test db representations
        self.now = datetime.datetime.utcnow()

        # create a school to satisfy course requirements
        self.school = School()
        self.school.name = 'Marshall College'
        self.school.save()

        # create a course to test relationships
        self.course = Course()
        self.course.school = self.school
        self.course.name = u'Archaeology 101'
        self.course.save()
        # override Course.save() appending an ID to the slug
        self.course.slug = u'archaeology-101'
        self.course.save()

        # create a note to test against
        self.note = Note()
        self.note.course = self.course
        self.note.name = u"Lecture notes concerning the use of therefore ∴"
        self.note.category = Note.LECTURE_NOTES
        self.note.uploaded_at = self.now
        self.note.text = "This is the plaintext version of a note. It's pretty cool. Alpaca."
        self.note.save()
Example #3
0
    def setup(self):
        # create base values to test db representations
        self.now = datetime.datetime.utcnow()

        # create a school to satisfy course requirements
        self.school = School()
        self.school.name = 'Marshall College'
        self.school.save()

        # create a course to test relationships
        self.course = Course()
        self.course.school = self.school
        self.course.name = u'Archaeology 101'
        self.course.save()
        # override Course.save() appending an ID to the slug
        self.course.slug = u'archaeology-101'
        self.course.save()

        # create a note to test against
        self.note = Note()
        self.note.course = self.course
        self.note.name = u"Lecture notes concerning the use of therefore ∴"
        #self.note.slug := do not set for test_remake_slug() behavior
        self.note.file_type = 'doc'
        self.note.uploaded_at = self.now
        self.note.save()
Example #4
0
 def setUp(self):
     self.school = School(name='Northeastern University')
     self.school.save()
     self.course = Course(name='Intro to Advanced Study',
                          school=self.school)
     self.course.save()
     self.client = Client()
Example #5
0
class BaseNote(object):
    def setup(self):
        # create base values to test db representations
        self.now = datetime.datetime.utcnow()

        # create a school to satisfy course requirements
        self.school = School()
        self.school.name = 'Marshall College'
        self.school.save()

        # create a course to test relationships
        self.course = Course()
        self.course.school = self.school
        self.course.name = u'Archaeology 101'
        self.course.save()
        # override Course.save() appending an ID to the slug
        self.course.slug = u'archaeology-101'
        self.course.save()

        # create a note to test against
        self.note = Note()
        self.note.course = self.course
        self.note.name = u"Lecture notes concerning the use of therefore ∴"
        #self.note.slug := do not set for test_remake_slug() behavior
        self.note.file_type = 'doc'
        self.note.uploaded_at = self.now
        self.note.save()

    def teardown(self):
        """ erase anything we created """
        print "generating a note teardown"
        self.note.delete()
Example #6
0
    def setUp(self):
        # create base values to test db representations
        self.now = datetime.datetime.utcnow()

        # create a school to satisfy course requirements
        self.school = School()
        self.school.name = 'Marshall College'
        self.school.save()

        # create a course to test relationships
        self.course = Course()
        self.course.school = self.school
        self.course.name = u'Archaeology 101'
        self.course.save()
        # override Course.save() appending an ID to the slug
        self.course.slug = u'archaeology-101'
        self.course.save()

        # create a note to test against
        self.note = Note()
        self.note.course = self.course
        self.note.name = u"Lecture notes concerning the use of therefore ∴"
        self.note.uploaded_at = self.now
        self.note.text = "This is the plaintext version of a note. It's pretty cool. Alpaca."
        self.note.save()
Example #7
0
    def setUp(self):
        # create base values to test db representations
        self.now = datetime.datetime.utcnow()

        # create a school to satisfy course requirements
        self.school = School()
        self.school.name = 'Marshall College'
        self.school.save()

        # create a course to test relationships
        self.course = Course()
        self.course.school = self.school
        self.course.name = u'Archaeology 101'
        self.course.save()
        # override Course.save() appending an ID to the slug
        self.course.slug = u'archaeology-101'
        self.course.save()

        self.user1 = User(username='******')
        self.user1.save()

        self.user2 = User(username='******')
        self.user2.save()

        # create a note to test against
        self.note = Note()
        self.note.course = self.course
        self.note.name = u"Lecture notes concerning the use of therefore ∴"
        self.note.text = "This is the plaintext version of a note. It's pretty cool."
        self.note.user = self.user1
        self.note.save()

        self.request1 = HttpRequest()
        self.request1.user = self.user1
        self.request1.method = 'POST'
        self.request1.META = {'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'}
        self.request1.session = SessionStore()

        self.request2 = HttpRequest()
        self.request2.user = self.user2
        self.request2.method = 'POST'
        self.request2.META = {'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'}
        self.request2.session = SessionStore()
Example #8
0
    def handle(self, *args, **kwargs):

        if len(args) < 1:
            self.stdout.write('Provide a filename\n')
            return

        filename = args[0]

        school_dicts = self.parse_school_csv(filename)

        self.stdout.write('Importing from list of %d schools\n' %
                          len(school_dicts))

        count = 0

        for d in school_dicts:

            if 'institution_id' not in d or not d['institution_id']:
                print d
                raise Exception(
                    'Error: School does not have an institution_id!')

            try:
                school = School.objects.get(usde_id=d['institution_id'])

            except School.DoesNotExist:
                school = School()
                #print d['institution_id']
                #print d['institution_name']
                count += 1

            school.name = d['institution_name']
            school.location = d['institution_city'] + ', ' + d[
                'institution_state']
            school.url = d['institution_web_address']
            school.usde_id = d['institution_id']
            school.save()

        self.stdout.write('Imported %d NEW unique schools\n' % count)
Example #9
0
    def handle(self, *args, **kwargs):

        if len(args) < 1:
            self.stdout.write('Provide a filename\n')
            return

        filename = args[0]

        school_dicts = self.parse_school_csv(filename)

        self.stdout.write('Importing from list of %d schools\n' % len(school_dicts))

        count = 0

        for d in school_dicts:

            if 'institution_id' not in d or not d['institution_id']:
                print d
                raise Exception('Error: School does not have an institution_id!')

            try:
                school = School.objects.get(usde_id=d['institution_id'])

            except School.DoesNotExist:
                school = School()
                #print d['institution_id']
                #print d['institution_name']
                count += 1


            school.name = d['institution_name']
            school.location = d['institution_city'] + ', ' + d['institution_state']
            school.url = d['institution_web_address']
            school.usde_id = d['institution_id']
            school.save()

        self.stdout.write('Imported %d NEW unique schools\n' % count)
Example #10
0
class TestNotes(TestCase):
    def setUp(self):
        # create base values to test db representations
        self.now = datetime.datetime.utcnow()

        # create a school to satisfy course requirements
        self.school = School()
        self.school.name = 'Marshall College'
        self.school.save()

        # create a course to test relationships
        self.course = Course()
        self.course.school = self.school
        self.course.name = u'Archaeology 101'
        self.course.save()
        # override Course.save() appending an ID to the slug
        self.course.slug = u'archaeology-101'
        self.course.save()

        # create a note to test against
        self.note = Note()
        self.note.course = self.course
        self.note.name = u"Lecture notes concerning the use of therefore ∴"
        self.note.category = Note.LECTURE_NOTES
        self.note.uploaded_at = self.now
        self.note.text = "This is the plaintext version of a note. It's pretty cool. Alpaca."
        self.note.save()

    def test_course_fkey(self):
        self.assertEqual(self.course, self.note.course)

    def test_slug_natural(self):
        """ Test that the slug field is slugifying unicode Note.names """
        expected = u"lecture-notes-concerning-the-use-of-therefore"
        self.assertEqual(self.note.slug, expected)

    def test_remake_slug(self):
        """ Test the generation of a Note.slug field based on Note.
        Name collision is expected, so see if slug handles this."""
        expected = u"lecture-notes-concerning-the-use-of-therefore-{0}-{1}-{2}".format(
            self.note.uploaded_at.month, self.note.uploaded_at.day,
            self.note.uploaded_at.microsecond)

        self.note.slug = None
        self.note.save()
        self.assertEqual(self.note.slug, expected)

    expected_url_prefix = u'/note/marshall-college/archaeology-101/'
    expected_slug = u'lecture-notes-concerning-the-use-of-therefore'
    expected = expected_url_prefix + expected_slug

    def test_note_get_absolute_url_slug(self):
        """ Given a note with a slug, test that an expected url is generated """
        # check that Note.get_absolute_url() is generating the right url
        self.assertEqual(self.note.get_absolute_url(), self.expected)

    def test_note_get_absolute_url_id(self):
        self.note.slug = None
        url = self.expected_url_prefix + str(self.note.id)
        self.assertEqual(self.note.get_absolute_url(), url)

    def test_note_markdown_rendering(self):
        rich = NoteMarkdown(
            note=self.note,
            markdown="""# This is fun\n[oh](http://yeah.com)""")
        rich.save()
        self.assertHTMLEqual(
            rich.html,
            """<h1>This is fun</h1>\n<p><a href="http://yeah.com" rel="nofollow" target="_blank">oh</a></p>"""
        )

    def test_note_rich_text_sanitization(self):
        rich = NoteMarkdown(note=self.note,
                            html="""
            <script>unsafe</script>
            <h1 class='obtrusive'>Something</h1>
            <h2>OK</h2>
            &amp;
            &rdquo;
            <a href='javascript:alert("Oh no")'>This stuff</a>
            <a href='http://google.com'>That guy</a>
        """)

        rich.save()
        self.assertHTMLEqual(
            rich.html, u"""
            <h1>Something</h1>
            <h2>OK</h2>
            &amp;
            \u201d
            <a target='_blank' rel='nofollow'>This stuff</a>
            <a href="http://google.com" target="_blank" rel="nofollow">That guy</a>
        """)
Example #11
0
class TestUsers(TestCase):

    def setUp(self):
        # create base values to test db representations
        self.now = datetime.datetime.utcnow()

        # create a school to satisfy course requirements
        self.school = School()
        self.school.name = 'Marshall College'
        self.school.save()

        # create a course to test relationships
        self.course = Course()
        self.course.school = self.school
        self.course.name = u'Archaeology 101'
        self.course.save()
        # override Course.save() appending an ID to the slug
        self.course.slug = u'archaeology-101'
        self.course.save()

        self.user1 = User(username='******')
        self.user1.save()

        self.user2 = User(username='******')
        self.user2.save()

        # create a note to test against
        self.note = Note()
        self.note.course = self.course
        self.note.name = u"Lecture notes concerning the use of therefore ∴"
        self.note.text = "This is the plaintext version of a note. It's pretty cool."
        self.note.user = self.user1
        self.note.save()

        self.request1 = HttpRequest()
        self.request1.user = self.user1
        self.request1.method = 'POST'
        self.request1.META = {'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'}
        self.request1.session = SessionStore()

        self.request2 = HttpRequest()
        self.request2.user = self.user2
        self.request2.method = 'POST'
        self.request2.META = {'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'}
        self.request2.session = SessionStore()

    def test_thank_own_note_karma(self):
        """Make sure you don't get karma for thanking your own note"""
        thank_note(self.request1, self.note.pk)
        try:
            NoteKarmaEvent.objects.get(note=self.note)
            self.fail("You can't thank your own note")
        except ObjectDoesNotExist:
            pass

    def test_thank_anothers_note_karma(self):
        """Get karma for having your note thanked"""
        thank_note(self.request2, self.note.pk)
        try:
            NoteKarmaEvent.objects.get(note=self.note)
        except ObjectDoesNotExist:
            self.fail("Karma event not created")

    def test_note_deleted_karma(self):
        """Lose karma if your note is deleted"""
        thank_note(self.request2, self.note.pk)
        self.note.delete()
        try:
            GenericKarmaEvent.objects.get(event_type=GenericKarmaEvent.NOTE_DELETED)
        except ObjectDoesNotExist:
            self.fail("Karma event not created")
        try:
            NoteKarmaEvent.objects.get(note=self.note)
            self.fail("Karma event not deleted")
        except ObjectDoesNotExist:
            pass

    def test_note_give_flag_karma(self):
        """Lose karma for flagging a note"""
        flag_note(self.request2, self.note.pk)
        try:
            NoteKarmaEvent.objects.get(event_type=NoteKarmaEvent.GIVE_FLAG, user=self.user2)
        except ObjectDoesNotExist:
            self.fail("Karma event not created")

    def test_course_give_flag_karma(self):
        """Lose karma for flagging a course"""
        flag_course(self.request2, self.course.pk)
        try:
            CourseKarmaEvent.objects.get(event_type=CourseKarmaEvent.GIVE_FLAG, user=self.user2)
        except ObjectDoesNotExist:
            self.fail("Karma event not created")

    def test_note_get_flagged_karma(self):
        """Lose karma for having your note flagged many times"""
        flag_note(self.request2, self.note.pk)
        flag_note(self.request2, self.note.pk)
        flag_note(self.request2, self.note.pk)
        flag_note(self.request2, self.note.pk)
        flag_note(self.request2, self.note.pk)
        flag_note(self.request2, self.note.pk)
        try:
            NoteKarmaEvent.objects.get(event_type=NoteKarmaEvent.GET_FLAGGED, user=self.user1)
        except ObjectDoesNotExist:
            self.fail("Karma event not created")

    def test_note_download_karma(self):
        """You lose karma for downloading a note, person who uploaded it gains karma"""
        downloaded_note(self.request2, self.note.pk)
        try:
            NoteKarmaEvent.objects.get(event_type=NoteKarmaEvent.DOWNLOADED_NOTE, user=self.user2)
        except ObjectDoesNotExist:
            self.fail("Karma event not created")
        try:
            NoteKarmaEvent.objects.get(event_type=NoteKarmaEvent.HAD_NOTE_DOWNLOADED, user=self.user1)
        except ObjectDoesNotExist:
            self.fail("Karma event not created")

    def test_download_own_note_karma(self):
        """No karma change for downloading your own note"""
        downloaded_note(self.request1, self.note.pk)
        try:
            NoteKarmaEvent.objects.get(event_type=NoteKarmaEvent.DOWNLOADED_NOTE, user=self.user1)
            self.fail("Karma debited for downloading own note, but shouldn't have been.")
        except ObjectDoesNotExist:
            pass
        try:
            NoteKarmaEvent.objects.get(event_type=NoteKarmaEvent.HAD_NOTE_DOWNLOADED, user=self.user1)
            self.fail("Karma given for downloading own note, but shouldn't have been.")
        except ObjectDoesNotExist:
            pass

    def test_email_confirm_karma(self):
        class FakeEmailAddress:
            user = self.user1
            email = self.user1.email

        give_email_confirm_karma(None, email_address=FakeEmailAddress())
        try:
            GenericKarmaEvent.objects.get(event_type=GenericKarmaEvent.EMAIL_CONFIRMED, user=self.user1)
        except ObjectDoesNotExist:
            self.fail("Karma event not created")
Example #12
0
class ConversionTest(TestCase):
    def setUp(self):
        self.school = School(name='Northeastern University')
        self.school.save()
        self.course = Course(name='Intro to Advanced Study',
                             school=self.school)
        self.course.save()
        self.client = Client()

    def doConversionForPost(self, post, user=None, session=None):
        self.assertEqual(Note.objects.count(), 0)
        r_d_f = RawDocumentForm(post)
        self.assertTrue(r_d_f.is_valid())
        raw_document = r_d_f.save(commit=False)
        raw_document.fp_file = post['fp_file']
        convert_raw_document(raw_document, user=user)
        self.assertEqual(Note.objects.count(), 1)

    def testPlaintextConversion(self):
        """Test upload of a plain text file"""
        self.doConversionForPost({
            'fp_file':
            'https://www.filepicker.io/api/file/S2lhT3INSFCVFURR2RV7',
            'course': str(self.course.id),
            'name': 'graph3.txt',
            'tags': '',
            'mimetype': 'text/plain'
        })

    def testEvernoteConversion(self):
        """Test upload of an Evernote note"""
        self.doConversionForPost({
            'fp_file':
            'https://www.filepicker.io/api/file/vOtEo0FrSbu2WDbAOzLn',
            'course': str(self.course.id),
            'name': 'KarmaNotes test 3',
            'tags': '',
            'mimetype': 'text/enml'
        })

    def testPdfConversion(self):
        """Test upload of a PDF"""
        self.doConversionForPost({
            'fp_file':
            'https://www.filepicker.io/api/file/8l6mtMURnu1uXvcvJo9s',
            'course': str(self.course.id),
            'name': 'geneve_1564.pdf',
            'tags': '',
            'mimetype': 'application/pdf'
        })

    def testGarbage(self):
        """Test upload of a file with a bogus mimetype"""
        with self.assertRaises(ValueError):
            self.doConversionForPost({
                'fp_file':
                'https://www.filepicker.io/api/file/H85Xl8VURqiGusxhZKMl',
                'course': str(self.course.id),
                'name': 'random',
                'tags': '',
                'mimetype': 'application/octet-stream'
            })

    def testSessionUserAssociation1(self):
        """If the user is already logged in when they
        upload a note, it should set note.user correctly."""
        user = User(username=TEST_USERNAME)
        user.save()
        self.doConversionForPost(
            {
                'fp_file':
                'https://www.filepicker.io/api/file/S2lhT3INSFCVFURR2RV7',
                'course': str(self.course.id),
                'name': 'graph3.txt',
                'tags': '',
                'mimetype': 'text/plain'
            },
            user=user)
        note = Note.objects.all()[0]
        self.assertEqual(note.user, user)
        try:
            NoteKarmaEvent.objects.get(note=note,
                                       event_type=NoteKarmaEvent.UPLOAD)
        except ObjectDoesNotExist:
            self.fail("Karma event not created")

    def testSessionUserAssociation2(self):
        """If a user logs in after convert_raw_document has finished,
        we should associate them with the note they uploaded anonymously"""
        s = SessionStore()
        s[ANONYMOUS_UPLOAD_URLS] = [
            'https://www.filepicker.io/api/file/S2lhT3INSFCVFURR2RV7'
        ]
        s.save()
        self.doConversionForPost({
            'fp_file':
            'https://www.filepicker.io/api/file/S2lhT3INSFCVFURR2RV7',
            'course': str(self.course.id),
            'name': 'graph3.txt',
            'tags': '',
            'mimetype': 'text/plain'
        })
        user = User(username=TEST_USERNAME)
        user.save()
        request = HttpRequest()
        request.session = s
        find_orphan_notes(None, user=user, request=request)
        note = Note.objects.all()[0]
        self.assertEqual(note.user, user)
        try:
            NoteKarmaEvent.objects.get(note=note,
                                       event_type=NoteKarmaEvent.UPLOAD)
        except ObjectDoesNotExist:
            self.fail("Karma event not created")

    def testSessionUserAssociation3(self):
        """If a user logs in WHILE convert_raw_document is running,
        make sure they are associated with that note by the time it finishes."""
        s = SessionStore()
        s[ANONYMOUS_UPLOAD_URLS] = [
            'https://www.filepicker.io/api/file/S2lhT3INSFCVFURR2RV7'
        ]
        s.save()
        user = User(username=TEST_USERNAME)
        user.save()
        request = HttpRequest()
        request.session = s
        find_orphan_notes(None, user=user, request=request)
        self.doConversionForPost(
            {
                'fp_file':
                'https://www.filepicker.io/api/file/S2lhT3INSFCVFURR2RV7',
                'course': str(self.course.id),
                'name': 'graph3.txt',
                'tags': '',
                'mimetype': 'text/plain'
            },
            session=s)
        note = Note.objects.all()[0]
        self.assertEqual(note.user, user)
        try:
            NoteKarmaEvent.objects.get(note=note,
                                       event_type=NoteKarmaEvent.UPLOAD)
        except ObjectDoesNotExist:
            self.fail("Karma event not created")
Example #13
0
class TestNotes(TestCase):

    def setUp(self):
        # create base values to test db representations
        self.now = datetime.datetime.utcnow()

        # create a school to satisfy course requirements
        self.school = School()
        self.school.name = 'Marshall College'
        self.school.save()

        # create a course to test relationships
        self.course = Course()
        self.course.school = self.school
        self.course.name = u'Archaeology 101'
        self.course.save()
        # override Course.save() appending an ID to the slug
        self.course.slug = u'archaeology-101'
        self.course.save()

        # create a note to test against
        self.note = Note()
        self.note.course = self.course
        self.note.name = u"Lecture notes concerning the use of therefore ∴"
        self.note.category = Note.LECTURE_NOTES
        self.note.uploaded_at = self.now
        self.note.text = "This is the plaintext version of a note. It's pretty cool. Alpaca."
        self.note.save()

    def test_course_fkey(self):
        self.assertEqual(self.course, self.note.course)

    def test_slug_natural(self):
        """ Test that the slug field is slugifying unicode Note.names """
        expected = u"lecture-notes-concerning-the-use-of-therefore"
        self.assertEqual(self.note.slug, expected)

    def test_remake_slug(self):
        """ Test the generation of a Note.slug field based on Note.
        Name collision is expected, so see if slug handles this."""
        expected = u"lecture-notes-concerning-the-use-of-therefore-{0}-{1}-{2}".format(
                    self.note.uploaded_at.month,
                    self.note.uploaded_at.day, self.note.uploaded_at.microsecond)

        self.note.slug = None
        self.note.save()
        self.assertEqual(self.note.slug, expected)

    expected_url_prefix = u'/note/marshall-college/archaeology-101/'
    expected_slug = u'lecture-notes-concerning-the-use-of-therefore'
    expected = expected_url_prefix + expected_slug

    def test_note_get_absolute_url_slug(self):
        """ Given a note with a slug, test that an expected url is generated """
        # check that Note.get_absolute_url() is generating the right url
        self.assertEqual(self.note.get_absolute_url(), self.expected)

    def test_note_get_absolute_url_id(self):
        self.note.slug = None
        url = self.expected_url_prefix + str(self.note.id)
        self.assertEqual(self.note.get_absolute_url(), url)

    def test_note_markdown_rendering(self):
        rich = NoteMarkdown(note=self.note,
            markdown="""# This is fun\n[oh](http://yeah.com)""")
        rich.save()
        self.assertHTMLEqual(rich.html,
                """<h1>This is fun</h1>\n<p><a href="http://yeah.com" rel="nofollow" target="_blank">oh</a></p>""")

    def test_note_rich_text_sanitization(self):
        rich = NoteMarkdown(note=self.note, html="""
            <script>unsafe</script>
            <h1 class='obtrusive'>Something</h1>
            <h2>OK</h2>
            &amp;
            &rdquo;
            <a href='javascript:alert("Oh no")'>This stuff</a>
            <a href='http://google.com'>That guy</a>
        """)

        rich.save()
        self.assertHTMLEqual(rich.html, u"""
            <h1>Something</h1>
            <h2>OK</h2>
            &amp;
            \u201d
            <a target='_blank' rel='nofollow'>This stuff</a>
            <a href="http://google.com" target="_blank" rel="nofollow">That guy</a>
        """)