def test_nav_bad_links(self): nav_cfg = [ {'Home': 'index.md'}, {'Missing': 'missing.html'}, {'Bad External': 'example.com'} ] expected = dedent(""" Page(title='Home', url='/') Link(title='Missing', url='missing.html') Link(title='Bad External', url='example.com') """) cfg = load_config(nav=nav_cfg, site_url='http://example.com/') files = Files([File('index.md', cfg['docs_dir'], cfg['site_dir'], cfg['use_directory_urls'])]) with self.assertLogs('elstir', level='WARNING') as cm: site_navigation = get_navigation(files, cfg) self.assertEqual( cm.output, [ "WARNING:elstir.structure.nav:A relative path to 'missing.html' is included " "in the 'nav' configuration, which is not found in the documentation files", "WARNING:elstir.structure.nav:A relative path to 'example.com' is included " "in the 'nav' configuration, which is not found in the documentation files" ] ) self.assertEqual(str(site_navigation).strip(), expected) self.assertEqual(len(site_navigation.items), 3) self.assertEqual(len(site_navigation.pages), 1)
def test_context_base_url__absolute_no_page_use_directory_urls(self): cfg = load_config() context = build.get_context(mock.Mock(), mock.Mock(), cfg, base_url='/') self.assertEqual(context['base_url'], '/')
def test_build_theme_template(self, mock_build_template, mock_write_file): cfg = load_config() env = cfg['theme'].get_env() build._build_theme_template('main.html', env, mock.Mock(), cfg, mock.Mock()) self.assert_mock_called_once(mock_write_file) self.assert_mock_called_once(mock_build_template)
def test_context_base_url_absolute_nested_no_page(self): cfg = load_config(use_directory_urls=False) context = build.get_context(mock.Mock(), mock.Mock(), cfg, base_url='/foo/') self.assertEqual(context['base_url'], '/foo/')
def test_get_files_exclude_readme_with_index(self, tdir): config = load_config(docs_dir=tdir) files = get_files(config) expected = ['index.md', 'foo.md'] self.assertIsInstance(files, Files) self.assertEqual(len(files), len(expected)) self.assertEqual([f.src_path for f in files], expected)
def test_build_extra_template(self): cfg = load_config() files = Files([ File('foo.html', cfg['docs_dir'], cfg['site_dir'], cfg['use_directory_urls']), ]) build._build_extra_template('foo.html', files, cfg, mock.Mock())
def test_populate_page(self, docs_dir): cfg = load_config(docs_dir=docs_dir) file = File('index.md', cfg['docs_dir'], cfg['site_dir'], cfg['use_directory_urls']) page = Page('Foo', file, cfg) build._populate_page(page, cfg, Files([file])) self.assertEqual(page.content, '<p>page content</p>')
def test_nav_from_nested_files(self): expected = dedent(""" Page(title=[blank], url='/') Section(title='About') Page(title=[blank], url='/about/license/') Page(title=[blank], url='/about/release-notes/') Section(title='Api guide') Page(title=[blank], url='/api-guide/debugging/') Page(title=[blank], url='/api-guide/running/') Page(title=[blank], url='/api-guide/testing/') Section(title='Advanced') Page(title=[blank], url='/api-guide/advanced/part-1/') """) cfg = load_config(site_url='http://example.com/') files = Files([ File('index.md', cfg['docs_dir'], cfg['site_dir'], cfg['use_directory_urls']), File('about/license.md', cfg['docs_dir'], cfg['site_dir'], cfg['use_directory_urls']), File('about/release-notes.md', cfg['docs_dir'], cfg['site_dir'], cfg['use_directory_urls']), File('api-guide/debugging.md', cfg['docs_dir'], cfg['site_dir'], cfg['use_directory_urls']), File('api-guide/running.md', cfg['docs_dir'], cfg['site_dir'], cfg['use_directory_urls']), File('api-guide/testing.md', cfg['docs_dir'], cfg['site_dir'], cfg['use_directory_urls']), File('api-guide/advanced/part-1.md', cfg['docs_dir'], cfg['site_dir'], cfg['use_directory_urls']), ]) site_navigation = get_navigation(files, cfg) self.assertEqual(str(site_navigation).strip(), expected) self.assertEqual(len(site_navigation.items), 3) self.assertEqual(len(site_navigation.pages), 7) self.assertEqual(repr(site_navigation.homepage), "Page(title=[blank], url='/')")
def test_context_base_url_relative_no_page(self): cfg = load_config(use_directory_urls=False) context = build.get_context(mock.Mock(), mock.Mock(), cfg, base_url='..') self.assertEqual(context['base_url'], '..')
def test_nav_external_links(self): nav_cfg = [ {'Home': 'index.md'}, {'Local': '/local.html'}, {'External': 'http://example.com/external.html'} ] expected = dedent(""" Page(title='Home', url='/') Link(title='Local', url='/local.html') Link(title='External', url='http://example.com/external.html') """) cfg = load_config(nav=nav_cfg, site_url='http://example.com/') files = Files([File('index.md', cfg['docs_dir'], cfg['site_dir'], cfg['use_directory_urls'])]) with self.assertLogs('elstir', level='DEBUG') as cm: site_navigation = get_navigation(files, cfg) self.assertEqual( cm.output, [ "DEBUG:elstir.structure.nav:An absolute path to '/local.html' is included in the " "'nav' configuration, which presumably points to an external resource.", "DEBUG:elstir.structure.nav:An external link to 'http://example.com/external.html' " "is included in the 'nav' configuration." ] ) self.assertEqual(str(site_navigation).strip(), expected) self.assertEqual(len(site_navigation.items), 3) self.assertEqual(len(site_navigation.pages), 1)
def test_populate_page_dirty_not_modified(self, site_dir, docs_dir): cfg = load_config(docs_dir=docs_dir, site_dir=site_dir) file = File('index.md', cfg['docs_dir'], cfg['site_dir'], cfg['use_directory_urls']) page = Page('Foo', file, cfg) build._populate_page(page, cfg, Files([file]), dirty=True) # Content is empty as file read was skipped self.assertEqual(page.markdown, None) self.assertEqual(page.content, None)
def test_event_on_post_build_multi_lang(self, mock_copy_file, mock_write_file): plugin = search.SearchPlugin() plugin.load_config({'lang': ['es', 'fr']}) config = load_config(theme='elstir') plugin.on_pre_build(config) plugin.on_post_build(config) self.assertEqual(mock_copy_file.call_count, 4) self.assertEqual(mock_write_file.call_count, 1)
def test_context_extra_css_js_no_page(self): cfg = load_config(extra_css=['style.css'], extra_javascript=['script.js']) context = build.get_context(mock.Mock(), mock.Mock(), cfg, base_url='..') self.assertEqual(context['extra_css'], ['../style.css']) self.assertEqual(context['extra_javascript'], ['../script.js'])
def test_event_on_post_build_defaults(self, mock_copy_file, mock_write_file): plugin = search.SearchPlugin() plugin.load_config({}) config = load_config(theme='elstir') plugin.on_pre_build(config) plugin.on_post_build(config) self.assertEqual(mock_copy_file.call_count, 0) self.assertEqual(mock_write_file.call_count, 1)
def test_create_media_urls_use_directory_urls(self): expected_results = { 'https://media.cdn.org/jq.js': [ 'https://media.cdn.org/jq.js', 'https://media.cdn.org/jq.js', 'https://media.cdn.org/jq.js' ], 'http://media.cdn.org/jquery.js': [ 'http://media.cdn.org/jquery.js', 'http://media.cdn.org/jquery.js', 'http://media.cdn.org/jquery.js' ], '//media.cdn.org/jquery.js': [ '//media.cdn.org/jquery.js', '//media.cdn.org/jquery.js', '//media.cdn.org/jquery.js' ], 'media.cdn.org/jquery.js': [ 'media.cdn.org/jquery.js', '../media.cdn.org/jquery.js', '../../media.cdn.org/jquery.js' ], 'local/file/jquery.js': [ 'local/file/jquery.js', '../local/file/jquery.js', '../../local/file/jquery.js' ], 'local\\windows\\file\\jquery.js': [ 'local/windows/file/jquery.js', '../local/windows/file/jquery.js', '../../local/windows/file/jquery.js' ], 'image.png': ['image.png', '../image.png', '../../image.png'], 'style.css?v=20180308c': [ 'style.css?v=20180308c', '../style.css?v=20180308c', '../../style.css?v=20180308c' ], '#some_id': ['#some_id', '#some_id', '#some_id'] } cfg = load_config(use_directory_urls=True) pages = [ Page( 'Home', File('index.md', cfg['docs_dir'], cfg['site_dir'], cfg['use_directory_urls']), cfg), Page( 'About', File('about.md', cfg['docs_dir'], cfg['site_dir'], cfg['use_directory_urls']), cfg), Page( 'FooBar', File('foo/bar.md', cfg['docs_dir'], cfg['site_dir'], cfg['use_directory_urls']), cfg) ] for i, page in enumerate(pages): urls = utils.create_media_urls(expected_results.keys(), page) self.assertEqual([v[i] for v in expected_results.values()], urls)
def test_populate_page_dirty_modified(self, site_dir): cfg = load_config(site_dir=site_dir) file = File('testing.md', cfg['docs_dir'], cfg['site_dir'], cfg['use_directory_urls']) page = Page('Foo', file, cfg) build._populate_page(page, cfg, Files([file]), dirty=True) self.assertTrue(page.markdown.startswith('# Welcome to elstir')) self.assertTrue( page.content.startswith( '<h1 id="welcome-to-elstir">Welcome to elstir</h1>'))
def test_context_base_url_homepage_use_directory_urls(self): nav_cfg = [{'Home': 'index.md'}] cfg = load_config(nav=nav_cfg) files = Files([ File('index.md', cfg['docs_dir'], cfg['site_dir'], cfg['use_directory_urls']), ]) nav = get_navigation(files, cfg) context = build.get_context(nav, files, cfg, nav.pages[0]) self.assertEqual(context['base_url'], '.')
def test_get_files(self, tdir): config = load_config(docs_dir=tdir, extra_css=['bar.css'], extra_javascript=['bar.js']) files = get_files(config) expected = [ 'index.md', 'bar.css', 'bar.html', 'bar.jpg', 'bar.js', 'bar.md' ] self.assertIsInstance(files, Files) self.assertEqual(len(files), len(expected)) self.assertEqual([f.src_path for f in files], expected)
def test_skip_extra_template_empty_output(self): cfg = load_config() files = Files([ File('foo.html', cfg['docs_dir'], cfg['site_dir'], cfg['use_directory_urls']), ]) with self.assertLogs('elstir', level='INFO') as cm: build._build_extra_template('foo.html', files, cfg, mock.Mock()) self.assertEqual(cm.output, [ "INFO:elstir.commands.build:Template skipped: 'foo.html' generated empty output." ])
def test_skip_ioerror_extra_template(self, mock_open): cfg = load_config() files = Files([ File('foo.html', cfg['docs_dir'], cfg['site_dir'], cfg['use_directory_urls']), ]) with self.assertLogs('elstir', level='INFO') as cm: build._build_extra_template('foo.html', files, cfg, mock.Mock()) self.assertEqual(cm.output, [ "WARNING:elstir.commands.build:Error reading template 'foo.html': Error message." ])
def test_event_on_config_defaults(self): plugin = search.SearchPlugin() plugin.load_config({}) result = plugin.on_config( load_config(theme='elstir', extra_javascript=[])) self.assertFalse(result['theme']['search_index_only']) self.assertFalse(result['theme']['include_search_page']) self.assertEqual(result['theme'].static_templates, {'404.html', 'sitemap.xml'}) self.assertEqual(len(result['theme'].dirs), 3) self.assertEqual(result['extra_javascript'], ['search/main.js'])
def test_copying_media(self, site_dir, docs_dir): cfg = load_config(docs_dir=docs_dir, site_dir=site_dir) build.build(cfg) # Verify that only non-empty md file (coverted to html), static HTML file and image are copied. self.assertPathIsFile(site_dir, 'index.html') self.assertPathIsFile(site_dir, 'img.jpg') self.assertPathIsFile(site_dir, 'static.html') self.assertPathNotExists(site_dir, 'empty.md') self.assertPathNotExists(site_dir, '.hidden') self.assertPathNotExists(site_dir, '.git/hidden')
def test_event_on_post_build_search_index_only(self, mock_copy_file, mock_write_file): plugin = search.SearchPlugin() plugin.load_config({'lang': ['es']}) config = load_config(theme={ 'name': 'elstir', 'search_index_only': True }) plugin.on_pre_build(config) plugin.on_post_build(config) self.assertEqual(mock_copy_file.call_count, 0) self.assertEqual(mock_write_file.call_count, 1)
def test_skip_missing_theme_template(self, mock_build_template, mock_write_file): cfg = load_config() env = cfg['theme'].get_env() with self.assertLogs('elstir', level='WARN') as cm: build._build_theme_template('missing.html', env, mock.Mock(), cfg, mock.Mock()) self.assertEqual(cm.output, [ "WARNING:elstir.commands.build:Template skipped: 'missing.html' not found in theme directories." ]) mock_write_file.assert_not_called() mock_build_template.assert_not_called()
def test_skip_theme_template_empty_output(self, mock_build_template, mock_write_file): cfg = load_config() env = cfg['theme'].get_env() with self.assertLogs('elstir', level='INFO') as cm: build._build_theme_template('main.html', env, mock.Mock(), cfg, mock.Mock()) self.assertEqual(cm.output, [ "INFO:elstir.commands.build:Template skipped: 'main.html' generated empty output." ]) mock_write_file.assert_not_called() self.assert_mock_called_once(mock_build_template)
def test_context_base_url_nested_page(self): nav_cfg = [{'Home': 'index.md'}, {'Nested': 'foo/bar.md'}] cfg = load_config(nav=nav_cfg, use_directory_urls=False) files = Files([ File('index.md', cfg['docs_dir'], cfg['site_dir'], cfg['use_directory_urls']), File('foo/bar.md', cfg['docs_dir'], cfg['site_dir'], cfg['use_directory_urls']) ]) nav = get_navigation(files, cfg) context = build.get_context(nav, files, cfg, nav.pages[1]) self.assertEqual(context['base_url'], '..')
def test_skip_missing_extra_template(self): cfg = load_config() files = Files([ File('foo.html', cfg['docs_dir'], cfg['site_dir'], cfg['use_directory_urls']), ]) with self.assertLogs('elstir', level='INFO') as cm: build._build_extra_template('missing.html', files, cfg, mock.Mock()) self.assertEqual(cm.output, [ "WARNING:elstir.commands.build:Template skipped: 'missing.html' not found in docs_dir." ])
def test_populate_page_read_plugin_error(self, docs_dir, mock_open): cfg = load_config(docs_dir=docs_dir) file = File('index.md', cfg['docs_dir'], cfg['site_dir'], cfg['use_directory_urls']) page = Page('Foo', file, cfg) with self.assertLogs('mkdocs', level='ERROR') as cm: self.assertRaises(PluginError, build._populate_page, page, cfg, Files([file])) self.assertEqual( cm.output, ["ERROR:mkdocs.commands.build:Error reading page 'index.md':"]) self.assert_mock_called_once(mock_open)
def test_populate_page_read_error(self, docs_dir, mock_open): cfg = load_config(docs_dir=docs_dir) file = File('missing.md', cfg['docs_dir'], cfg['site_dir'], cfg['use_directory_urls']) page = Page('Foo', file, cfg) with self.assertLogs('elstir', level='ERROR') as cm: self.assertRaises(OSError, build._populate_page, page, cfg, Files([file])) self.assertEqual(cm.output, [ 'ERROR:elstir.structure.pages:File not found: missing.md', "ERROR:elstir.commands.build:Error reading page 'missing.md': Error message." ]) self.assert_mock_called_once(mock_open)
def test_get_by_type_nested_sections(self): nav_cfg = [ {'Section 1': [ {'Section 2': [ {'Page': 'page.md'} ]} ]} ] cfg = load_config(nav=nav_cfg, site_url='http://example.com/') files = Files([ File('page.md', cfg['docs_dir'], cfg['site_dir'], cfg['use_directory_urls']) ]) site_navigation = get_navigation(files, cfg) self.assertEqual(len(_get_by_type(site_navigation, Section)), 2)