def test_indented_toc(self): md = dedent(""" # Heading 1 ## Heading 2 ### Heading 3 """) expected = dedent(""" Heading 1 - #heading-1 Heading 2 - #heading-2 Heading 3 - #heading-3 """) toc = get_toc(get_markdown_toc(md)) self.assertEqual(str(toc).strip(), expected) self.assertEqual(len(toc), 1)
def test_entityref(self): md = dedent(""" # Heading & 1 ## Heading > 2 ### Heading < 3 """) expected = dedent(""" Heading & 1 - #heading-1 Heading > 2 - #heading-2 Heading < 3 - #heading-3 """) toc = get_toc(get_markdown_toc(md)) self.assertEqual(str(toc).strip(), expected) self.assertEqual(len(toc), 1)
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('mkdocs', level='DEBUG') as cm: site_navigation = get_navigation(files, cfg) self.assertEqual(cm.output, [ "DEBUG:mkdocs.structure.nav:An absolute path to '/local.html' is included in the " "'nav' configuration, which presumably points to an external resource.", "DEBUG:mkdocs.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_nested_ungrouped_nav(self): nav_cfg = [ { 'Home': 'index.md' }, { 'Contact': 'about/contact.md' }, { 'License Title': 'about/sub/license.md' }, ] expected = dedent(""" Page(title='Home', url='/') Page(title='Contact', url='/about/contact/') Page(title='License Title', url='/about/sub/license/') """) cfg = load_config(nav=nav_cfg, site_url='http://example.com/') files = Files([ File( list(item.values())[0], cfg['docs_dir'], cfg['site_dir'], cfg['use_directory_urls']) for item in nav_cfg ]) 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), 3)
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('mkdocs', level='WARNING') as cm: site_navigation = get_navigation(files, cfg) self.assertEqual(cm.output, [ "WARNING:mkdocs.structure.nav:A relative path to 'missing.html' is included " "in the 'nav' configuration, which is not found in the documentation files", "WARNING:mkdocs.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_config_option(self): """ Users can explicitly set the config file using the '--config' option. Allows users to specify a config other than the default `mkdocutils.yml`. """ expected_result = { 'site_name': 'Example', 'pages': [{ 'Introduction': 'index.md' }], } file_contents = dedent(""" site_name: Example pages: - 'Introduction': 'index.md' """) with TemporaryDirectory() as temp_path: os.mkdir(os.path.join(temp_path, 'docs')) config_path = os.path.join(temp_path, 'mkdocutils.yml') config_file = open(config_path, 'w') config_file.write(file_contents) config_file.flush() config_file.close() result = config.load_config(config_file=config_file.name) self.assertEqual(result['site_name'], expected_result['site_name']) self.assertEqual(result['pages'], expected_result['pages'])
def test_find_toc_by_id(self): """ Test finding the relevant TOC item by the tag ID. """ index = search_index.SearchIndex() md = dedent(""" # Heading 1 ## Heading 2 ### Heading 3 """) toc = get_toc(get_markdown_toc(md)) toc_item = index._find_toc_by_id(toc, "heading-1") self.assertEqual(toc_item.url, "#heading-1") self.assertEqual(toc_item.title, "Heading 1") toc_item2 = index._find_toc_by_id(toc, "heading-2") self.assertEqual(toc_item2.url, "#heading-2") self.assertEqual(toc_item2.title, "Heading 2") toc_item3 = index._find_toc_by_id(toc, "heading-3") self.assertEqual(toc_item3.url, "#heading-3") self.assertEqual(toc_item3.title, "Heading 3")
def test_yaml_meta_data_not_dict(self): doc = dedent(""" --- - List item --- Doc body """) self.assertEqual(utils.meta.get_data(doc), (doc, {}))
def test_yaml_meta_data_invalid(self): doc = dedent(""" --- foo: bar: baz --- Doc body """) self.assertEqual(utils.meta.get_data(doc), (doc, {}))
def test_mixed_html(self): md = dedent(""" # Heading 1 ## Heading 2 # Heading 3 ### Heading 4 ### <a>Heading 5</a> """) expected = dedent(""" Heading 1 - #heading-1 Heading 2 - #heading-2 Heading 3 - #heading-3 Heading 4 - #heading-4 Heading 5 - #heading-5 """) toc = get_toc(get_markdown_toc(md)) self.assertEqual(str(toc).strip(), expected) self.assertEqual(len(toc), 2)
def test_unicode_yaml(self): yaml_src = dedent(''' key: value key2: - value ''') config = utils.yaml_load(yaml_src) self.assertTrue(isinstance(config['key'], str)) self.assertTrue(isinstance(config['key2'][0], str))
def test_level(self): md = dedent(""" # Heading 1 ## Heading 1.1 ### Heading 1.1.1 ### Heading 1.1.2 ## Heading 1.2 """) toc = get_toc(get_markdown_toc(md)) def get_level_sequence(items): for item in items: yield item.level yield from get_level_sequence(item.children) self.assertEqual(tuple(get_level_sequence(toc)), (1, 2, 3, 3, 2))
def test_nav_no_title(self): nav_cfg = ['index.md', {'About': 'about.md'}] expected = dedent(""" Page(title=[blank], url='/') Page(title='About', url='/about/') """) cfg = load_config(nav=nav_cfg, site_url='http://example.com/') files = Files([ File(nav_cfg[0], cfg['docs_dir'], cfg['site_dir'], cfg['use_directory_urls']), File(nav_cfg[1]['About'], 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), 2) self.assertEqual(len(site_navigation.pages), 2)
def test_invalid_config(self): file_contents = dedent(""" - ['index.md', 'Introduction'] - ['index.md', 'Introduction'] - ['index.md', 'Introduction'] """) config_file = tempfile.NamedTemporaryFile('w', delete=False) try: config_file.write(file_contents) config_file.flush() config_file.close() self.assertRaises(ConfigurationError, config.load_config, config_file=open(config_file.name, 'rb')) finally: os.remove(config_file.name)
def test_mm_meta_data(self): doc = dedent(""" Title: Foo Bar Date: 2018-07-10 Summary: Line one Line two Tags: foo Tags: bar Doc body """) self.assertEqual(utils.meta.get_data(doc), ("Doc body", { 'title': 'Foo Bar', 'date': '2018-07-10', 'summary': 'Line one Line two', 'tags': 'foo bar' }))
def test_nav_from_files(self): expected = dedent(""" Page(title=[blank], url='/') Page(title=[blank], url='/about/') """) 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.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), 2) self.assertEqual(len(site_navigation.pages), 2) self.assertEqual(repr(site_navigation.homepage), "Page(title=[blank], url='/')")
def test_env_var_in_yaml(self): yaml_src = dedent(''' key1: !ENV VARNAME key2: !ENV UNDEFINED key3: !ENV [UNDEFINED, default] key4: !ENV [UNDEFINED, VARNAME, default] key5: !ENV BOOLVAR ''') config = utils.yaml_load(yaml_src) self.assertIsInstance(config['key1'], str) self.assertEqual(config['key1'], 'Hello, World!') self.assertIsNone(config['key2']) self.assertIsInstance(config['key3'], str) self.assertEqual(config['key3'], 'default') self.assertIsInstance(config['key4'], str) self.assertEqual(config['key4'], 'Hello, World!') self.assertIs(config['key5'], False)
def test_nav_no_directory_urls(self): nav_cfg = [{'Home': 'index.md'}, {'About': 'about.md'}] expected = dedent(""" Page(title='Home', url='/index.html') Page(title='About', url='/about.html') """) cfg = load_config(nav=nav_cfg, use_directory_urls=False, site_url='http://example.com/') files = Files([ File( list(item.values())[0], cfg['docs_dir'], cfg['site_dir'], cfg['use_directory_urls']) for item in nav_cfg ]) site_navigation = get_navigation(files, cfg) self.assertEqual(str(site_navigation).strip(), expected) self.assertEqual(len(site_navigation.items), 2) self.assertEqual(len(site_navigation.pages), 2)
def test_nav_missing_page(self): nav_cfg = [{'Home': 'index.md'}] expected = dedent(""" Page(title='Home', url='/') """) 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']), File('page_not_in_nav.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), 1) self.assertEqual(len(site_navigation.pages), 1) for file in files: self.assertIsInstance(file.page, Page)
def test_nested_ungrouped_nav_no_titles(self): nav_cfg = ['index.md', 'about/contact.md', 'about/sub/license.md'] expected = dedent(""" Page(title=[blank], url='/') Page(title=[blank], url='/about/contact/') Page(title=[blank], url='/about/sub/license/') """) cfg = load_config(nav=nav_cfg, site_url='http://example.com/') files = Files([ File(item, cfg['docs_dir'], cfg['site_dir'], cfg['use_directory_urls']) for item in nav_cfg ]) 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), 3) self.assertEqual(repr(site_navigation.homepage), "Page(title=[blank], url='/')")
def test_page_render(self): cfg = load_config() fl = File('testing.md', cfg['docs_dir'], cfg['site_dir'], cfg['use_directory_urls']) pg = Page('Foo', fl, cfg) pg.read_source(cfg) self.assertEqual(pg.content, None) self.assertEqual(pg.toc, []) pg.render(cfg, [fl]) self.assertTrue( pg.content.startswith( '<h1 id="welcome-to-mkdocs">Welcome to MkDocs</h1>\n')) self.assertEqual( str(pg.toc).strip(), dedent(""" Welcome to MkDocs - #welcome-to-mkdocs Commands - #commands Project layout - #project-layout """))
def test_yaml_meta_data(self): doc = dedent(""" --- Title: Foo Bar Date: 2018-07-10 Summary: Line one Line two Tags: - foo - bar --- Doc body """) self.assertEqual(utils.meta.get_data(doc), ("Doc body", { 'Title': 'Foo Bar', 'Date': datetime.date(2018, 7, 10), 'Summary': 'Line one Line two', 'Tags': ['foo', 'bar'] }))
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_no_meta_data(self): doc = dedent(""" Doc body """) self.assertEqual(utils.meta.get_data(doc), (doc, {}))
def test_indented_nav(self): nav_cfg = [{ 'Home': 'index.md' }, { 'API Guide': [ { 'Running': 'api-guide/running.md' }, { 'Testing': 'api-guide/testing.md' }, { 'Debugging': 'api-guide/debugging.md' }, { 'Advanced': [ { 'Part 1': 'api-guide/advanced/part-1.md' }, ] }, ] }, { 'About': [{ 'Release notes': 'about/release-notes.md' }, { 'License': '/license.html' }] }, { 'External': 'https://example.com/' }] expected = dedent(""" Page(title='Home', url='/') Section(title='API Guide') Page(title='Running', url='/api-guide/running/') Page(title='Testing', url='/api-guide/testing/') Page(title='Debugging', url='/api-guide/debugging/') Section(title='Advanced') Page(title='Part 1', url='/api-guide/advanced/part-1/') Section(title='About') Page(title='Release notes', url='/about/release-notes/') Link(title='License', url='/license.html') Link(title='External', url='https://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']), 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/debugging.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']), File('about/release-notes.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), 4) self.assertEqual(len(site_navigation.pages), 6) self.assertEqual(repr(site_navigation.homepage), "Page(title='Home', url='/')") self.assertIsNone(site_navigation.items[0].parent) self.assertEqual(site_navigation.items[0].ancestors, []) self.assertIsNone(site_navigation.items[1].parent) self.assertEqual(site_navigation.items[1].ancestors, []) self.assertEqual(len(site_navigation.items[1].children), 4) self.assertEqual(repr(site_navigation.items[1].children[0].parent), "Section(title='API Guide')") self.assertEqual(site_navigation.items[1].children[0].ancestors, [site_navigation.items[1]]) self.assertEqual(repr(site_navigation.items[1].children[1].parent), "Section(title='API Guide')") self.assertEqual(site_navigation.items[1].children[1].ancestors, [site_navigation.items[1]]) self.assertEqual(repr(site_navigation.items[1].children[2].parent), "Section(title='API Guide')") self.assertEqual(site_navigation.items[1].children[2].ancestors, [site_navigation.items[1]]) self.assertEqual(repr(site_navigation.items[1].children[3].parent), "Section(title='API Guide')") self.assertEqual(site_navigation.items[1].children[3].ancestors, [site_navigation.items[1]]) self.assertEqual(len(site_navigation.items[1].children[3].children), 1) self.assertEqual( repr(site_navigation.items[1].children[3].children[0].parent), "Section(title='Advanced')") self.assertEqual( site_navigation.items[1].children[3].children[0].ancestors, [site_navigation.items[1].children[3], site_navigation.items[1]]) self.assertIsNone(site_navigation.items[2].parent) self.assertEqual(len(site_navigation.items[2].children), 2) self.assertEqual(repr(site_navigation.items[2].children[0].parent), "Section(title='About')") self.assertEqual(site_navigation.items[2].children[0].ancestors, [site_navigation.items[2]]) self.assertEqual(repr(site_navigation.items[2].children[1].parent), "Section(title='About')") self.assertEqual(site_navigation.items[2].children[1].ancestors, [site_navigation.items[2]]) self.assertIsNone(site_navigation.items[3].parent) self.assertEqual(site_navigation.items[3].ancestors, []) self.assertIsNone(site_navigation.items[3].children)
def test_create_search_index(self): html_content = """ <h1 id="heading-1">Heading 1</h1> <p>Content 1</p> <h2 id="heading-2">Heading 2</h1> <p>Content 2</p> <h3 id="heading-3">Heading 3</h1> <p>Content 3</p> """ cfg = load_config() 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, ), ] md = dedent(""" # Heading 1 ## Heading 2 ### Heading 3 """) toc = get_toc(get_markdown_toc(md)) full_content = ''.join("""Heading{0}Content{0}""".format(i) for i in range(1, 4)) for page in pages: # Fake page.read_source() and page.render() page.source = md page.toc = toc page.content = html_content index = search_index.SearchIndex() index.add_entry_from_context(page) self.assertEqual(len(index._entries), 4) loc = page.url self.assertEqual(index._entries[0]['title'], page.title) self.assertEqual( strip_whitespace(index._entries[0]['text'], ), full_content, ) self.assertEqual(index._entries[0]['location'], loc) self.assertEqual(index._entries[1]['title'], "Heading 1") self.assertEqual(index._entries[1]['text'], "Content 1") self.assertEqual( index._entries[1]['location'], "{}#heading-1".format(loc), ) self.assertEqual(index._entries[2]['title'], "Heading 2") self.assertEqual( strip_whitespace(index._entries[2]['text'], ), "Content2", ) self.assertEqual( index._entries[2]['location'], "{}#heading-2".format(loc), ) self.assertEqual(index._entries[3]['title'], "Heading 3") self.assertEqual( strip_whitespace(index._entries[3]['text'], ), "Content3", ) self.assertEqual( index._entries[3]['location'], "{}#heading-3".format(loc), )