def setUp(self): self.app = Holocron( conf={ 'site': { 'title': 'MyTestSite', 'author': 'Tester', 'url': 'http://www.mytest.com/', }, 'encoding': { 'output': 'my-enc', }, 'paths': { 'output': 'path/to/output', }, 'ext': { 'enabled': [], 'feed': { 'save_as': 'myfeed.xml', 'posts_number': 3, }, }, }) self.feed = Feed(self.app) self.date_early = datetime(2012, 2, 2) self.date_moderate = datetime(2013, 4, 1) self.date_late = datetime(2014, 6, 12) self.date_early_updated = datetime(2012, 12, 6) self.date_moderate_updated = datetime(2013, 12, 6) self.date_late_updated = datetime(2014, 12, 6) self.post_early = mock.Mock(spec=Post, published=self.date_early, updated_local=self.date_early_updated, abs_url='http://www.post_early.com', title='MyEarlyPost') self.post_moderate = mock.Mock( spec=Post, published=self.date_moderate, updated_local=self.date_moderate_updated, abs_url='http://www.post_moderate.com') self.post_late = mock.Mock(spec=Post, published=self.date_late, updated_local=self.date_late_updated, url='www.post_late.com', abs_url='http://www.post_late.com', title='MyTestPost') self.late_id = '<id>http://www.post_late.com</id>' self.moderate_id = '<id>http://www.post_moderate.com</id>' self.early_id = '<id>http://www.post_early.com</id>' self.page = mock.Mock(spec=Page, url='www.page.com') self.static = mock.Mock(spec=Static, url='www.image.com') self.open_fn = 'holocron.ext.feed.open'
def setUp(self): self.app = Holocron(conf={ 'sitename': 'MyTestSite', 'siteurl': 'www.mytest.com', 'author': 'Tester', 'encoding': { 'output': 'my-enc', }, 'paths': { 'output': 'path/to/output', }, 'ext': { 'enabled': [], 'tags': { 'output': 'mypath/tags/{tag}', }, }, }) self.tags = Tags(self.app) self.date_early = datetime(2012, 2, 2) self.date_moderate = datetime(2013, 4, 1) self.date_late = datetime(2014, 6, 12) self.post_early = mock.Mock( spec=Post, published=self.date_early, tags=['testtag1', 'testtag2'], title='MyTestPost', url='www.post_early.com') self.post_moderate = mock.Mock( spec=Post, published=self.date_moderate, url='www.post_moderate.com', tags=['testtag2', 'testtag3']) self.post_late = mock.Mock( spec=Post, published=self.date_late, url='www.post_late.com', tags=['testtag2']) self.post_malformed = mock.Mock( spec=Post, short_source='test', tags='testtag') self.page = mock.Mock(spec=Page) self.static = mock.Mock(spec=Static) self.open_fn = 'holocron.ext.tags.open'
def setUp(self, getcwd, getctime, getmtime): """ Prepares a document instance with a fake config. """ filename = os.path.join(self._conf['paths.content'], self.document_filename) self.app = Holocron(self._conf) self.app.add_converter(FakeConverter()) self.doc = self.document_class(filename, self.app)
def setUp(self): self.conv = ReStructuredText( Holocron(conf={ 'ext': { 'enabled': [], }, }))
def setUp(self): """ Prepares a sitemap instance with a fake config. """ self.app = Holocron(conf={ 'encoding': { 'output': 'my-enc', }, 'paths': { 'output': 'path/to/output', }, 'ext': { 'enabled': [], }, }) self.sitemap = Sitemap(self.app) self.open_fn = 'holocron.ext.sitemap.open' self.post_url = 'http://example.com/post/' self.page_url = 'http://example.com/page/' self.page_date = datetime(2014, 12, 27) self.post_date = datetime(2013, 4, 1) self.post = mock.Mock( spec=Post, abs_url=self.post_url, updated_local=self.post_date) self.page = mock.Mock( spec=Page, abs_url=self.page_url, updated_local=self.page_date) self.static = mock.Mock(spec=Static)
def test_extra_tables(self): """ Converter has to support tables syntax. """ self.conv = Markdown(Holocron(conf={ 'ext': { 'enabled': [], 'markdown': { 'extensions': ['markdown.extensions.extra'], }, }, })) _, html = self.conv.to_html(textwrap.dedent('''\ column a | column b ---------|--------- foo | bar ''')) self.assertIn('table', html) self.assertIn('<th>column a</th>', html) self.assertIn('<th>column b</th>', html) self.assertIn('<td>foo</td>', html) self.assertIn('<td>bar</td>', html)
def setUp(self): self.conv = Markdown(Holocron(conf={ 'ext': { 'enabled': [], 'markdown': { 'extensions': [], }, }, }))
class DocumentTestCase(HolocronTestCase): """ A testcase helper that prepares a document instance. """ _getcwd = 'cwd' # fake current working dir, used by abspath _getctime = 662739000 # UTC: 1991/01/01 2:10pm _getmtime = 1420121400 # UTC: 2015/01/01 2:10pm _conf = Conf({ 'site': { 'url': 'http://example.com', }, 'encoding': { 'content': 'cont-enc', 'output': 'out-enc', }, 'paths': { 'content': './content', 'output': './_output', } }) document_class = None # a document constructor document_filename = None # a document filename, relative to the content @mock.patch('holocron.content.os.path.getmtime', return_value=_getmtime) @mock.patch('holocron.content.os.path.getctime', return_value=_getctime) @mock.patch('holocron.content.os.getcwd', return_value=_getcwd) def setUp(self, getcwd, getctime, getmtime): """ Prepares a document instance with a fake config. """ filename = os.path.join(self._conf['paths.content'], self.document_filename) self.app = Holocron(self._conf) self.app.add_converter(FakeConverter()) self.doc = self.document_class(filename, self.app)
def test_user_settings(self): """ Tests creating an instance with custom settings: check for settings overriding. """ app = Holocron({ 'sitename': 'Luke Skywalker', 'paths': { 'content': 'path/to/content', }, }) conf = copy.deepcopy(app.default_conf) conf['sitename'] = 'Luke Skywalker' conf['paths']['content'] = 'path/to/content' self.assertEqual(app.conf, conf)
def setUp(self): """ Creates generator object and number of posts which will be further used in test sets. """ self.app = Holocron( conf={ 'sitename': 'MyTestSite', 'siteurl': 'www.mytest.com', 'author': 'Tester', 'encoding': { 'output': 'my-enc', }, 'paths': { 'output': 'path/to/output', }, 'ext': { 'enabled': [], }, }) self.index = Index(self.app) self.open_fn = 'holocron.ext.index.open' self.date_early = datetime(2012, 2, 2) self.date_late = datetime(2014, 6, 12) self.date_moderate = datetime(2013, 4, 1) self.post_early = mock.Mock( spec=Post, published=self.date_early, url='www.post_early.com', ) self.post_moderate = mock.Mock(spec=Post, published=self.date_moderate, url='www.post_moderate.com') self.post_late = mock.Mock(spec=Post, published=self.date_late, url='www.post_late.com') self.page = mock.Mock(spec=Page) self.static = mock.Mock(spec=Static)
def test_codehilite_extension(self): """ Converter has to use Pygments to highlight code blocks. """ self.conv = Markdown(Holocron(conf={ 'ext': { 'enabled': [], 'markdown': { 'extensions': ['markdown.extensions.codehilite'], }, }, })) _, html = self.conv.to_html(textwrap.dedent('''\ test codeblock :::python lambda x: pass ''')) self.assertRegexpMatches(html, '.*codehilite.*<pre>[\s\S]+</pre>.*')
def test_code_macros_is_enabled(self): """ Converter has to use Pygments to highlight code blocks. """ self.conv = Creole( Holocron( conf={ 'ext': { 'enabled': ['creole'], 'creole': { 'syntax_highlight': True, } } })) _, html = self.conv.to_html( textwrap.dedent('''\ <<code ext=".py">> lambda x: pass <</code>> ''')) self.assertRegexpMatches(html, '.*pygments.*<pre>[\s\S]+</pre>.*')
def test_extra_code(self): """ Converter has to support GitHub's fence code syntax. """ self.conv = Markdown(Holocron(conf={ 'ext': { 'enabled': [], 'markdown': { 'extensions': [ 'markdown.extensions.codehilite', 'markdown.extensions.extra', ], }, }, })) _, html = self.conv.to_html(textwrap.dedent('''\ ```python lambda x: pass ``` ''')) self.assertRegexpMatches(html, '.*codehilite.*<pre>[\s\S]+</pre>.*')
def test_code_macros_is_disabled(self): """ Converter shouldn't support code macros if syntax highlighting is turned off. """ self.conv = Creole( Holocron( conf={ 'ext': { 'enabled': ['creole'], 'creole': { 'syntax_highlight': False, } } })) _, html = self.conv.to_html( textwrap.dedent('''\ <<code ext=".py">> lambda x: pass <</code>> ''')) self.assertEqual(html, "[Error: Macro 'code' doesn't exist]")
def setUp(self): self.conv = Creole(Holocron(conf={ 'ext': { 'enabled': ['creole'], }, }))
def setUp(self): self.app = Holocron({ 'ext': { 'enabled': [], }, })
class TestHolocron(HolocronTestCase): def setUp(self): self.app = Holocron({ 'ext': { 'enabled': [], }, }) def test_user_settings(self): """ Tests creating an instance with custom settings: check for settings overriding. """ app = Holocron({ 'sitename': 'Luke Skywalker', 'paths': { 'content': 'path/to/content', }, }) conf = copy.deepcopy(app.default_conf) conf['sitename'] = 'Luke Skywalker' conf['paths']['content'] = 'path/to/content' self.assertEqual(app.conf, conf) def test_add_converter(self): """ Tests converter registration process. """ class TestConverter(abc.Converter): extensions = ['.tst', '.test'] def to_html(self, text): return {}, text # test registration process converter = TestConverter() self.assertEqual(len(self.app._converters), 0) self.app.add_converter(converter) self.assertEqual(len(self.app._converters), 2) self.assertIn('.tst', self.app._converters) self.assertIn('.test', self.app._converters) self.assertIs(self.app._converters['.tst'], converter) self.assertIs(self.app._converters['.test'], converter) # test protection from double registration self.app.add_converter(TestConverter()) self.assertIs(self.app._converters['.tst'], converter) self.assertIs(self.app._converters['.test'], converter) # test force registration new_converter = TestConverter() self.app.add_converter(new_converter, _force=True) self.assertIs(self.app._converters['.tst'], new_converter) self.assertIs(self.app._converters['.test'], new_converter) def test_add_generator(self): """ Tests generator registration process. """ class TestGenerator(abc.Generator): def generate(self, text): pass # test registration process generator = TestGenerator() self.assertEqual(len(self.app._generators), 0) self.app.add_generator(generator) self.assertEqual(len(self.app._generators), 1) self.assertIn(generator, self.app._generators) # test double registration is allowed new_generator = TestGenerator() self.app.add_generator(new_generator) self.assertEqual(len(self.app._generators), 2) self.assertIn(new_generator, self.app._generators) @mock.patch('holocron.app.mkdir') @mock.patch('holocron.app.iterfiles') def test_run(self, iterfiles, mkdir): """ Tests build process. """ iterfiles.return_value = ['doc_a', 'doc_b', 'doc_c'] self.app.__class__.document_factory = mock.Mock() self.app._copy_theme = mock.Mock() self.app._generators = { mock.Mock(): mock.Mock(), mock.Mock(): mock.Mock(), } self.app.run() # check iterfiles call signature iterfiles.assert_called_with(self.app.conf['paths']['content'], '[!_.]*', True) # check mkdir create ourpur dir mkdir.assert_called_with(self.app.conf['paths.output']) # check that generators was used for generator in self.app._generators: self.assertEqual(generator.generate.call_count, 1) self.app.__class__.document_factory.assert_has_calls([ # check that document class was used to generate class instances mock.call('doc_a', self.app), mock.call('doc_b', self.app), mock.call('doc_c', self.app), # check that document instances were built mock.call().build(), mock.call().build(), mock.call().build(), ]) self.assertEqual(self.app.__class__.document_factory.call_count, 3) # check that _copy_theme was called self.app._copy_theme.assert_called_once_with() @mock.patch('holocron.app.copy_tree') def test_copy_base_theme(self, mcopytree): """ Tests that Holocron do copy default theme. """ output = os.path.join(self.app.conf['paths.output'], 'static') theme = os.path.join(os.path.dirname(holocron.__file__), 'theme', 'static') self.app._copy_theme() mcopytree.assert_called_with(theme, output) @mock.patch('holocron.app.os.path.exists', return_value=True) @mock.patch('holocron.app.copy_tree') def test_copy_user_themes(self, mcopytree, _): """ Tests that Holocron do copy user theme. """ output = os.path.join(self.app.conf['paths.output'], 'static') theme = os.path.join(os.path.dirname(holocron.__file__), 'theme', 'static') self.app.add_theme('theme1') self.app.add_theme('theme2') self.app._copy_theme() self.assertEqual(mcopytree.call_args_list, [ mock.call(theme, output), mock.call(os.path.join('theme1', 'static'), output), mock.call(os.path.join('theme2', 'static'), output), ]) @mock.patch('holocron.app.os.path.exists', side_effect=[True, False]) @mock.patch('holocron.app.copy_tree') def test_copy_user_themes_not_exist(self, mcopytree, _): """ Tests that Holocron doesn't copy static if it's not exist. """ output = os.path.join(self.app.conf['paths.output'], 'static') theme = os.path.join(os.path.dirname(holocron.__file__), 'theme', 'static') self.app.add_theme('theme1') self.app._copy_theme() self.assertEqual(mcopytree.call_args_list, [ mock.call(theme, output), ])
def setUp(self): self.app = Holocron()
def setUp(self): self.holocron = Holocron(conf={ 'ext': { 'enabled': ['creole'], }, })
class TestTagsGenerator(HolocronTestCase): """ Test tags generator. """ #: generate html headers with years that is used for grouping in templates h_year = '<span class="year">{0}</span>'.format def setUp(self): self.app = Holocron(conf={ 'sitename': 'MyTestSite', 'siteurl': 'www.mytest.com', 'author': 'Tester', 'encoding': { 'output': 'my-enc', }, 'paths': { 'output': 'path/to/output', }, 'ext': { 'enabled': [], 'tags': { 'output': 'mypath/tags/{tag}', }, }, }) self.tags = Tags(self.app) self.date_early = datetime(2012, 2, 2) self.date_moderate = datetime(2013, 4, 1) self.date_late = datetime(2014, 6, 12) self.post_early = mock.Mock( spec=Post, published=self.date_early, tags=['testtag1', 'testtag2'], title='MyTestPost', url='www.post_early.com') self.post_moderate = mock.Mock( spec=Post, published=self.date_moderate, url='www.post_moderate.com', tags=['testtag2', 'testtag3']) self.post_late = mock.Mock( spec=Post, published=self.date_late, url='www.post_late.com', tags=['testtag2']) self.post_malformed = mock.Mock( spec=Post, short_source='test', tags='testtag') self.page = mock.Mock(spec=Page) self.static = mock.Mock(spec=Static) self.open_fn = 'holocron.ext.tags.open' @mock.patch('holocron.ext.tags.mkdir', mock.Mock()) def _get_content(self, documents): """ This helper method mocks the open function and return the content passed as input to write function. """ with mock.patch(self.open_fn, mock.mock_open(), create=True) as mopen: self.tags.generate(documents) # extract what was generated and what was passed to f.write() content, = mopen().write.call_args[0] return content @mock.patch('holocron.ext.tags.mkdir') def _get_tags_content(self, documents, mock_mkdir): with mock.patch(self.open_fn, mock.mock_open(), create=True) as mopen: self.tags.generate(documents) open_calls = [c[0][0] for c in mopen.call_args_list if c != ''] write_calls = [c[0][0] for c in mopen().write.call_args_list] mkdir_calls = [c[0][0] for c in mock_mkdir.call_args_list] # form a tuple that contains corresponding open and write calls # and sort it aplhabetically, so the testtag1 comes first content = list(zip(open_calls, write_calls, mkdir_calls)) content.sort() return content def test_tag_template_building(self): """ Test that tags function writes a post to a tag template. """ posts = [self.post_early, self.post_moderate] content = self._get_tags_content(posts) # check that open, write and mkdir functions were called three times # according to the number of different tags in test documents for entry in content: self.assertEqual(len(entry), 3) # test that output html contains early_post with its unique tag self.assertEqual( 'path/to/output/mypath/tags/testtag1/index.html', content[0][0]) self.assertIn(self.h_year(2012), content[0][1]) self.assertIn('<a href="www.post_early.com">', content[0][1]) self.assertEqual('path/to/output/mypath/tags/testtag1', content[0][2]) # test that output html contains posts with common tag self.assertEqual( 'path/to/output/mypath/tags/testtag2/index.html', content[1][0]) self.assertIn(self.h_year(2012), content[1][1]) self.assertIn(self.h_year(2013), content[1][1]) self.assertIn('<a href="www.post_early.com">', content[1][1]) self.assertIn('<a href="www.post_moderate.com">', content[1][1]) self.assertEqual('path/to/output/mypath/tags/testtag2', content[1][2]) # test that output html contains moderate_post with its unique tag self.assertEqual( 'path/to/output/mypath/tags/testtag3/index.html', content[2][0]) self.assertIn(self.h_year(2013), content[2][1]) self.assertIn('<a href="www.post_moderate.com">', content[2][1]) self.assertEqual('path/to/output/mypath/tags/testtag3', content[2][2]) def test_sorting_out_mixed_documents(self): """ Test that Tags sorts out post documents from documents of other types. """ documents = [self.page, self.static, self.post_late] content = self._get_content(documents) self.assertIn(self.h_year(2014), content) self.assertIn('<a href="www.post_late.com">', content) def test_posts_patching_with_tag_objects(self): """ Test that Tags patches post's tags attribute. """ posts = [self.post_late] self._get_tags_content(posts) self.assertEquals(self.post_late.tags[0].name, 'testtag2') self.assertEquals(self.post_late.tags[0].url, '/mypath/tags/testtag2/') @mock.patch('holocron.content.os.mkdir', mock.Mock()) @mock.patch('holocron.content.os.path.getmtime') @mock.patch('holocron.content.os.path.getctime') def test_tags_are_shown_in_post(self, _, __): """ Test that tags are actually get to the output. """ # since we're interested in rendered page, let's register # a fake converter for that purpose self.app.add_converter(FakeConverter()) data = textwrap.dedent('''\ --- tags: [tag1, tag2] --- some text''') open_fn = 'holocron.content.open' with mock.patch(open_fn, mock.mock_open(read_data=data), create=True): post = Post('2015/05/23/filename.fake', self.app) self._get_content([post]) with mock.patch(open_fn, mock.mock_open(), create=True) as mopen: post.build() content = mopen().write.call_args[0][0] err = 'Could not find link for #tag1.' self.assertIn('<a href="/mypath/tags/tag1/">#tag1</a>', content, err) err = 'Could not find link for #tag2.' self.assertIn('<a href="/mypath/tags/tag2/">#tag2</a>', content, err) @mock.patch('holocron.ext.tags.mkdir') def test_malformed_tags_are_skipped(self, mock_mkdir): """ Test if tags formatting is correct. """ content = self._get_tags_content([self.post_malformed]) self.assertEqual(content, [])
def _create_document(self, filename, getcwd, getctime, getmtime, _): app = Holocron({'paths': { 'content': './content', }}) app.add_converter(FakeConverter()) return content.create_document(filename, app)
class TestFeedGenerator(HolocronTestCase): """ Test feed generator. """ def setUp(self): self.app = Holocron( conf={ 'site': { 'title': 'MyTestSite', 'author': 'Tester', 'url': 'http://www.mytest.com/', }, 'encoding': { 'output': 'my-enc', }, 'paths': { 'output': 'path/to/output', }, 'ext': { 'enabled': [], 'feed': { 'save_as': 'myfeed.xml', 'posts_number': 3, }, }, }) self.feed = Feed(self.app) self.date_early = datetime(2012, 2, 2) self.date_moderate = datetime(2013, 4, 1) self.date_late = datetime(2014, 6, 12) self.date_early_updated = datetime(2012, 12, 6) self.date_moderate_updated = datetime(2013, 12, 6) self.date_late_updated = datetime(2014, 12, 6) self.post_early = mock.Mock(spec=Post, published=self.date_early, updated_local=self.date_early_updated, abs_url='http://www.post_early.com', title='MyEarlyPost') self.post_moderate = mock.Mock( spec=Post, published=self.date_moderate, updated_local=self.date_moderate_updated, abs_url='http://www.post_moderate.com') self.post_late = mock.Mock(spec=Post, published=self.date_late, updated_local=self.date_late_updated, url='www.post_late.com', abs_url='http://www.post_late.com', title='MyTestPost') self.late_id = '<id>http://www.post_late.com</id>' self.moderate_id = '<id>http://www.post_moderate.com</id>' self.early_id = '<id>http://www.post_early.com</id>' self.page = mock.Mock(spec=Page, url='www.page.com') self.static = mock.Mock(spec=Static, url='www.image.com') self.open_fn = 'holocron.ext.feed.open' @mock.patch('holocron.ext.feed.mkdir', mock.Mock()) def _get_content(self, documents): """ This helper method mocks the open function and returns the content passed as input to write function. """ with mock.patch(self.open_fn, mock.mock_open(), create=True) as mopen: self.feed.generate(documents) content, = mopen().write.call_args[0] return content def _xml_to_dict(self, xml): """ Generates and returns python dict from an xml string passed as input. """ parsed = minidom.parseString(xml) root = parsed.documentElement #: use this to sort DOM Elements from DOM Text containing \n and spaces def is_element(n): return n.nodeType == n.ELEMENT_NODE #: use this to parse <link> which contain attributes instead of values def is_attribute(n): return len(n.attributes) != 0 #: use this to distinguish feed common elements (link, title) from post def has_child(n): return len(n.childNodes) < 2 urls = [url for url in filter(is_element, root.childNodes)] entries = {} url_data = {} #: use to store dictionnaries with post data posts = [] #: links in feed differ by attribute (rel or alt), use this attribute #: as a key to avoid dicts with same key key = '{link}.{fmt}'.format for url in urls: if has_child(url): if is_attribute(url): link = key(link=url.nodeName, fmt=url.getAttribute('rel')) entries[link] = url.getAttribute('href') else: entries[url.nodeName] = url.firstChild.nodeValue else: for attr in filter(is_element, url.childNodes): if is_attribute(attr): url_data[attr.nodeName] = attr.getAttribute('href') else: url_data[attr.nodeName] = attr.firstChild.nodeValue posts.append(url_data) entries[url.nodeName] = posts content = {root.nodeName: entries} return content @mock.patch('holocron.ext.feed.mkdir', mock.Mock()) def test_feed_filename_and_enc(self): """ Feed function has to save feed xml file to a proper location and with proper filename. All settings are fetched from the configuration file. """ with mock.patch(self.open_fn, mock.mock_open(), create=True) as mopen: self.feed.generate([]) self.assertEqual(mopen.call_args[0][0], 'path/to/output/myfeed.xml') self.assertEqual(mopen.call_args[1]['encoding'], 'my-enc') def test_feed_encoding_attr(self): """ The feed.xml has to have an XML tag with right encoding. """ output = self._get_content([]) self.assertIn('encoding="my-enc"', output) def test_feed_template(self): """ Test that feed writes correct values to an xml template. """ content = self._get_content([]) content = self._xml_to_dict(content) feed = content['feed'] self.assertEqual('MyTestSite', feed['title']) self.assertEqual('http://www.mytest.com/', feed['id']) self.assertEqual('http://www.mytest.com/myfeed.xml', feed['link.self']) self.assertEqual('http://www.mytest.com/', feed['link.alternate']) def test_feed_empty(self): """ Feed runned on an empty list of documents has to create an xml file, no posts should be listed there. """ content = self._get_content([]) content = self._xml_to_dict(content) self.assertNotIn('entry', content['feed']) def test_feed_with_posts(self): """ Feed function has to f*****g work. """ # here we require only one post to test its content correctness # we test posts in other test suites self.feed._conf['posts_number'] = 1 content = self._get_content([self.post_early, self.post_late]) content = self._xml_to_dict(content) self.assertIn('entry', content['feed']) self.assertEqual(len(content['feed']['entry']), 1) feed = content['feed']['entry'][0] self.assertEqual('http://www.post_late.com', feed['link']) self.assertEqual(self.date_late_updated.isoformat(), feed['updated']) self.assertEqual(self.date_late.isoformat(), feed['published']) self.assertEqual('http://www.post_late.com', feed['id']) self.assertEqual('MyTestPost', feed['title']) def test_posts_in_front_order(self): """ Tests posts ordering. Feed must display older posts first. """ posts = [self.post_early, self.post_moderate, self.post_late] content = self._get_content(posts) #: test that the latest post comes first self.assertIn(self.late_id, content) #: delete information about the latest post post_position = content.index(self.late_id) + len(self.late_id) content = content[post_position:] self.assertIn(self.moderate_id, content) #: another strim to delete next post post_position = content.index(self.moderate_id) + len(self.moderate_id) content = content[post_position:] self.assertIn(self.early_id, content) def test_posts_in_reverse_order(self): """ Tests posts ordering. Feed must display older posts first. """ posts = [self.post_late, self.post_moderate, self.post_early] content = self._get_content(posts) #: test that the latest post comes first self.assertIn(self.late_id, content) #: delete information about the latest post post_position = content.index(self.late_id) + len(self.late_id) content = content[post_position:] self.assertIn(self.moderate_id, content) #: another strim to delete next post post_position = content.index(self.moderate_id) + len(self.moderate_id) content = content[post_position:] self.assertIn(self.early_id, content) def test_mixed_documents(self): """ Test that feed generator sorts out post documents out of other types. """ documents = [self.page, self.post_late, self.static] content = self._get_content(documents) self.assertNotIn('www.page.com', content) self.assertNotIn('www.image.com', content) self.assertIn('www.post_late.com', content) @mock.patch('holocron.content.os.mkdir', mock.Mock()) @mock.patch('holocron.content.os.path.getmtime') @mock.patch('holocron.content.os.path.getctime') def test_feed_link_in_html_header(self, _, __): """ Test that html pages have the link to feed. """ # since we're interested in rendered page, let's register # a fake converter for that purpose self.app.add_converter(FakeConverter()) open_fn = 'holocron.content.open' with mock.patch(open_fn, mock.mock_open(read_data=''), create=True): page = Page('filename.fake', self.app) with mock.patch(open_fn, mock.mock_open(), create=True) as mopen: page.build() content = mopen().write.call_args[0][0] err = 'could not find link to feed in html header' self.assertIn( '<link rel="alternate" type="application/atom+xml" ' 'href="http://www.mytest.com/myfeed.xml" title="MyTestSite">', content, err)