class OutlinerTest(unittest.TestCase): def setUp(self): self.t = TocGenerator('') def test_no_headings(self): actual = self.t._generate_outline([]) expected = [] self.assertEqual(expected, actual) def test_single_level(self): actual = self.t._generate_outline([ [1, u'T1'], [1, u'T2'], ]) expected = [ [u'T1', []], [u'T2', []], ] self.assertEqual(expected, actual) def test_multi_level_case_1(self): actual = self.t._generate_outline([ [1, u'T1'], [1, u'T2'], [2, u'T2-1'], [2, u'T2-2'], [1, u'T3'], ]) expected = [ [u'T1', []], [u'T2', [ [u'T2-1', []], [u'T2-2', []], ]], [u'T3', []], ] self.assertEqual(expected, actual) def test_multi_level_case_2(self): actual = self.t._generate_outline([ [1, u'T1'], [2, u'T1-1'], [3, u'T1-1-1'], [3, u'T1-1-2'], [1, u'T2'], ]) expected = [ [u'T1', [ [u'T1-1', [ [u'T1-1-1', []], [u'T1-1-2', []], ]], ]], [u'T2', []], ] self.assertEqual(expected, actual) def test_invalid_level(self): self.assertRaises(ValueError, self.t._generate_outline, [[1, u'T1'], [3, u'T2']]) self.assertRaises(ValueError, self.t._generate_outline, [[2, u'T1'], [3, u'T2']])
class OutlinerTest(unittest.TestCase): def setUp(self): self.t = TocGenerator("") def test_no_headings(self): actual = self.t.generate_outline([]) expected = [] self.assertEqual(expected, actual) def test_single_level(self): actual = self.t.generate_outline([[1, u"T1"], [1, u"T2"]]) expected = [[u"T1", []], [u"T2", []]] self.assertEqual(expected, actual) def test_multi_level_case_1(self): actual = self.t.generate_outline([[1, u"T1"], [1, u"T2"], [2, u"T2-1"], [2, u"T2-2"], [1, u"T3"]]) expected = [[u"T1", []], [u"T2", [[u"T2-1", []], [u"T2-2", []]]], [u"T3", []]] self.assertEqual(expected, actual) def test_multi_level_case_2(self): actual = self.t.generate_outline([[1, u"T1"], [2, u"T1-1"], [3, u"T1-1-1"], [3, u"T1-1-2"], [1, u"T2"]]) expected = [[u"T1", [[u"T1-1", [[u"T1-1-1", []], [u"T1-1-2", []]]]]], [u"T2", []]] self.assertEqual(expected, actual) def test_invalid_level(self): self.assertRaises(ValueError, self.t.generate_outline, [[1, u"T1"], [3, u"T2"]]) self.assertRaises(ValueError, self.t.generate_outline, [[2, u"T1"], [3, u"T2"]])
def test_heading_not_startig_from_h1_should_mention_reason(self): html = ''' <h2>two</h2> <h3>three</h3> ''' reason = TocGenerator(html).is_invalid() self.assertIn('<h2>two</h2>', reason.lower())
def test_invalid_level_of_headings_should_mention_reason(self): html = ''' <h1>one</h1> <h1>two</h1> <h3>three</h3> ''' reason = TocGenerator(html).is_invalid() self.assertIn('<h3>three</h3>', reason.lower())
def test_strip_html_in_headings(self): html = """ <h1><a href="Blah">Hello 1</a></h1> <h1>Hello 2</h1> <h1>Hello 3</h1> <h1>Hello 4</h1> """ t = TocGenerator(html) self.assertEqual(1, len(re.findall(ur'Blah', t.add_toc())))
def test_strip_html_in_headings(self): html = """ <h1><a href="Blah">Hello 1</a></h1> <h1>Hello 2</h1> <h1>Hello 3</h1> <h1>Hello 4</h1> """ t = TocGenerator(html) self.assertEqual(1, len(re.findall(ur"Blah", t.add_toc())))
def test_header_with_attributes(self): html = ''' <h1>a one</h1> <h1 id="user-defined-id">a two</h1> <h1>a three</h1> ''' headings = TocGenerator.extract_headings(html) self.assertEqual(len(headings), 3)
class PathTest(unittest.TestCase): def setUp(self): self.t = TocGenerator("") def test_single_level(self): actual = self.t.generate_path([[u"제목1", []], [u"제목2", []]]) expected = [u"제목1", u"제목2"] self.assertEqual(expected, actual) def test_multi_level(self): actual = self.t.generate_path( [[u"T1", []], [u"제목2", [[u"제목2-1", []], [u"제목2-2", [[u"제목2-2-1", []]]]]], [u"T3", []]] ) expected = [u"T1", u"제목2", u"제목2\t제목2-1", u"제목2\t제목2-2", u"제목2\t제목2-2\t제목2-2-1", u"T3"] self.assertEqual(expected, actual) def test_duplicated_path(self): self.assertRaises(ValueError, self.t.generate_path, [[u"T1", []], [u"T1", []]])
def test_duplicate_path_name_should_mention_reason(self): html = ''' <h1>a one</h1> <h1>a two</h1> <h1>a one</h1> <h1>two</h1> <h1>three</h1> ''' reason = TocGenerator(html).is_invalid() self.assertIn('a one', reason)
class PathTest(unittest.TestCase): def setUp(self): self.t = TocGenerator('') def test_single_level(self): actual = self.t._generate_path([ [u'제목1', []], [u'제목2', []], ]) expected = [ u'제목1', u'제목2', ] self.assertEqual(expected, actual) def test_multi_level(self): actual = self.t._generate_path([ [u'T1', []], [u'제목2', [ [u'제목2-1', []], [u'제목2-2', [ [u'제목2-2-1', []], ]], ]], [u'T3', []], ]) expected = [ u'T1', u'제목2', u'제목2\t제목2-1', u'제목2\t제목2-2', u'제목2\t제목2-2\t제목2-2-1', u'T3', ] self.assertEqual(expected, actual) def test_duplicated_path(self): self.assertRaises(ValueError, self.t._generate_path, [[u'T1', []], [u'T1', []]])
def render_body(cls, title, body, rendered_data='', inlinks={}, related_links_by_score={}, older_title=None, newer_title=None): # body body_parts = [cls.remove_metadata(body)] # incoming links if len(inlinks) > 0: lines = [u'# Incoming Links'] for i, (rel, links) in enumerate(inlinks.items()): itemtype, rel = rel.split('/') lines.append(u'## %s <span class="hidden">(%s %d)</span>' % (schema.humane_property(itemtype, rel, True), itemtype, i)) # remove dups and sort links = list(set(links)) links.sort() lines += [u'* [[%s]]' % t for t in links] body_parts.append(u'\n'.join(lines)) # related links related_links = related_links_by_score if len(related_links) > 0: lines = [u'# Suggested Pages'] lines += [u'* {{.score::%.3f}} [[%s]]\n{.noli}' % (score, t) for t, score in related_links.items()[:10]] body_parts.append(u'\n'.join(lines)) body_parts.append(u'* [More suggestions...](/+%s)\n{.more-suggestions}' % (cls.title_to_path(title))) # other posts if older_title or newer_title: lines = [u'# Other Posts'] if newer_title: lines.append(u'* {{.newer::newer}} [[%s]]\n{.noli}' % newer_title) if older_title: lines.append(u'* {{.older::older}} [[%s]]\n{.noli}' % older_title) body_parts.append(u'\n'.join(lines)) # remove yaml/schema block joined = u'\n'.join(body_parts) joined = re.sub(PageOperationMixin.re_yaml_schema, u'\n', joined) # render to html rendered = md.convert(joined) # add table of contents rendered = TocGenerator(rendered).add_toc() # add class for embedded image rendered = PageOperationMixin.re_img.sub(ur'<\1 class="img-container"><img\2/></\3>', rendered) # add structured data block rendered = rendered_data + rendered return cls.sanitize_html(rendered)
def validate_new_content(self, base_revision, new_body, user): # check metadata new_md = PageOperationMixin.parse_metadata(new_body) ## prevent self-revoke acl_r = new_md.get('read', '') acl_r = acl_r.split(',') if acl_r else [] acl_w = new_md.get('write', '') acl_w = acl_w.split(',') if acl_w else [] if not self.can_read(user, acl_r=acl_r, acl_w=acl_w): raise ValueError('Cannot restrict your permission') if not self.can_write(user, acl_r=acl_r, acl_w=acl_w): raise ValueError('Cannot restrict your permission') ## prevent circular-redirection try: WikiPage._follow_redirect(self, new_md.get(u'redirect')) except ValueError as e: raise e # check data new_data = PageOperationMixin.parse_data(self.title, new_body, new_md['schema']) if any( type(value) == schema.InvalidProperty for value in new_data.values()): invalid_keys = [ key for key, value in new_data.iteritems() if type(value) == schema.InvalidProperty ] raise ValueError('Invalid schema data: %s' % ', '.join(invalid_keys)) # check revision if self.revision < base_revision: raise ValueError('Invalid revision number: %d' % base_revision) # check headings invalid_reason = TocGenerator(md.convert(new_body)).is_invalid() if invalid_reason: raise ValueError(invalid_reason) return new_data, new_md
def setUp(self): self.t = TocGenerator('')