chiark / gitweb /
doxygen: new \m_examplenavigation command.
authorVladimír Vondruš <mosra@centrum.cz>
Thu, 18 Jan 2018 12:48:04 +0000 (13:48 +0100)
committerVladimír Vondruš <mosra@centrum.cz>
Thu, 18 Jan 2018 12:49:27 +0000 (13:49 +0100)
This tests the example page for the first time. So I took the
opportunity and also renamed the title suffix to "source" instead of
"example".

12 files changed:
doc/doxygen.rst
doxygen/dox2html5.py
doxygen/templates/example.html
doxygen/test/example/Doxyfile [new file with mode: 0644]
doxygen/test/example/input.dox [new file with mode: 0644]
doxygen/test/example/path-prefix/CMakeLists.txt [new file with mode: 0644]
doxygen/test/example/path-prefix/configure.h.cmake [new file with mode: 0644]
doxygen/test/example/path-prefix/main.cpp [new file with mode: 0644]
doxygen/test/example/path-prefix_2CMakeLists_8txt-example.html [new file with mode: 0644]
doxygen/test/example/path-prefix_2configure_8h_8cmake-example.html [new file with mode: 0644]
doxygen/test/example/path-prefix_2main_8cpp-example.html [new file with mode: 0644]
doxygen/test/test_example.py [new file with mode: 0644]

index 6e7bbc25ccf36338d5cdea9227abefe1dfffd173..ee6440a787610cfd32fe30d37c91668924b6bb1e 100644 (file)
@@ -615,7 +615,8 @@ following to your ``Doxyfile-mcss``:
         "m_span{1}=@xmlonly<mcss:span xmlns:mcss=\"http://mcss.mosra.cz/doxygen/\" mcss:class=\"\1\">@endxmlonly" \
         "m_endspan=@xmlonly</mcss:span>@endxmlonly" \
         "m_class{1}=@xmlonly<mcss:class xmlns:mcss=\"http://mcss.mosra.cz/doxygen/\" mcss:class=\"\1\" />@endxmlonly" \
-        "m_footernavigation=@xmlonly<mcss:footernavigation xmlns:mcss=\"http://mcss.mosra.cz/doxygen/\" />@endxmlonly"
+        "m_footernavigation=@xmlonly<mcss:footernavigation xmlns:mcss=\"http://mcss.mosra.cz/doxygen/\" />@endxmlonly" \
+        "m_examplenavigation{2}=@xmlonly<mcss:examplenavigation xmlns:mcss=\"http://mcss.mosra.cz/doxygen/\" mcss:page=\"\1\" mcss:prefix=\"\2\" />@endxmlonly"
 
 If you need backwards compatibility with stock Doxygen HTML output, just make
 the aliases empty in your original ``Doxyfile``. Note that you can rename the
@@ -629,7 +630,8 @@ aliases however you want to fit your naming scheme.
         "m_span{1}=" \
         "m_endspan=" \
         "m_class{1}=" \
-        "m_footernavigation="
+        "m_footernavigation=" \
+        "m_examplenavigation{2}"
 
 With ``@m_div`` and ``@m_span`` it's possible to wrap individual paragraphs or
 inline text in :html:`<div>` / :html:`<span>` and add CSS classes to them.
@@ -686,6 +688,28 @@ present in page detailed description, it will cause the footer of the rendered
 page to contain a link to previous, parent and next page according to defined
 page order.
 
+The ``@m_examplenavigation`` command is able to put breadcrumb navigation to
+parent page(s) of ``@example`` listings in order to make it easier for users to
+return back from example source code to a tutorial page, for example. When used
+in combination with ``@m_footernavigation``, navigation to parent page and to
+prev/next file of the same example is put at the bottom of the page. The
+``@m_examplenavigation`` command takes two arguments, first is the parent page
+for this example (used to build the breadcrumb and footer navigation), second
+is example path prefix (which is then stripped from page title and is also used
+to discover which example files belong together). Example usage --- the
+``@m_examplenavigation`` and ``@m_footernavigation`` commands are simply
+appended the an existing ``@example`` command.
+
+.. code-figure::
+
+    .. code:: c++
+
+        /**
+        @example helloworld/CMakeLists.txt @m_examplenavigation{example,helloworld/} @m_footernavigation
+        @example helloworld/configure.h.cmake @m_examplenavigation{example,helloworld/} @m_footernavigation
+        @example helloworld/main.cpp @m_examplenavigation{example,helloworld/} @m_footernavigation
+        */
+
 `Customizing the template`_
 ===========================
 
index 7d9d0a61c620e45a138b0491889637eeae81dc36..7fce3351f099f7305e563cb768e0928acf3d07f7 100755 (executable)
@@ -58,6 +58,7 @@ class State:
     def __init__(self):
         self.basedir = ''
         self.compounds: Dict[str, Any] = {}
+        self.examples: List[Any] = []
         self.doxyfile: Dict[str, str] = {}
         self.images: List[str] = []
         self.current = ''
@@ -144,6 +145,7 @@ def parse_desc_internal(state: State, element: ET.Element, immediate_parent: ET.
     out.return_value = None
     out.add_css_class = None
     out.footer_navigation = False
+    out.example_navigation = None
 
     # DOXYGEN <PARA> PATCHING 1/4
     #
@@ -415,8 +417,9 @@ def parse_desc_internal(state: State, element: ET.Element, immediate_parent: ET.
             # resetting here explicitly.
             add_css_class = parsed.add_css_class
 
-            # Bubble up also the footer navigation
+            # Bubble up also footer / example navigation
             if parsed.footer_navigation: out.footer_navigation = True
+            if parsed.example_navigation: out.example_navigation = parsed.example_navigation
 
             # Assert we didn't miss anything important
             assert not parsed.section
@@ -611,6 +614,11 @@ def parse_desc_internal(state: State, element: ET.Element, immediate_parent: ET.
         elif i.tag == '{http://mcss.mosra.cz/doxygen/}footernavigation':
             out.footer_navigation = True
 
+        # Enabling navigation for an example
+        elif i.tag == '{http://mcss.mosra.cz/doxygen/}examplenavigation':
+            out.example_navigation = (i.attrib['{http://mcss.mosra.cz/doxygen/}page'],
+                                      i.attrib['{http://mcss.mosra.cz/doxygen/}prefix'])
+
         # Either block or inline
         elif i.tag == 'programlisting':
             assert element.tag == 'para' # is inside a paragraph :/
@@ -868,7 +876,7 @@ def parse_toplevel_desc(state: State, element: ET.Element):
     assert not parsed.return_value
     if parsed.params:
         logging.warning("{}: use @tparam instead of @param for documenting class templates, @param is ignored".format(state.current))
-    return (parsed.parsed, parsed.templates, parsed.section[2] if parsed.section else '', parsed.footer_navigation)
+    return (parsed.parsed, parsed.templates, parsed.section[2] if parsed.section else '', parsed.footer_navigation, parsed.example_navigation)
 
 def parse_typedef_desc(state: State, element: ET.Element):
     # Verify that we didn't ignore any important info by accident
@@ -1129,15 +1137,24 @@ def parse_define(state: State, element: ET.Element):
     return define if define.brief or define.has_details else None
 
 def extract_metadata(state: State, xml):
-    # index.xml will be parsed later in parse_index_xml()
-    if os.path.basename(xml) == 'index.xml': return
-
     logging.debug("Extracting metadata from {}".format(os.path.basename(xml)))
 
     tree = ET.parse(xml)
     root = tree.getroot()
 
+    # We need just list of all example files in correct order, nothing else
+    if os.path.basename(xml) == 'index.xml':
+        for i in root:
+            if i.attrib['kind'] == 'example':
+                compound = Empty()
+                compound.id = i.attrib['refid']
+                compound.url = compound.id + '.html'
+                compound.name = i.find('name').text
+                state.examples += [compound]
+        return
+
     compounddef: ET.Element = root.find('compounddef')
+
     if compounddef.attrib['kind'] not in ['namespace', 'class', 'struct', 'union', 'dir', 'file', 'page']:
         logging.debug("No useful info in {}, skipping".format(os.path.basename(xml)))
         return
@@ -1274,7 +1291,8 @@ def parse_xml(state: State, xml: str):
     compound.has_template_details = False
     compound.templates = None
     compound.brief = parse_desc(state, compounddef.find('briefdescription'))
-    compound.description, templates, compound.sections, footer_navigation = parse_toplevel_desc(state, compounddef.find('detaileddescription'))
+    compound.description, templates, compound.sections, footer_navigation, example_navigation = parse_toplevel_desc(state, compounddef.find('detaileddescription'))
+    compound.example_navigation = None
     compound.footer_navigation = None
     compound.dirs = []
     compound.files = []
@@ -1305,7 +1323,8 @@ def parse_xml(state: State, xml: str):
     compound.has_var_details = False
     compound.has_define_details = False
 
-    # Build breadcrumb
+    # Build breadcrumb. Breadcrumb for example pages is built after everything
+    # is parsed.
     if compound.kind in ['namespace', 'struct', 'class', 'union', 'file', 'dir', 'page']:
         # Gather parent compounds
         path_reverse = [compound.id]
@@ -1326,7 +1345,7 @@ def parse_xml(state: State, xml: str):
         if footer_navigation:
             up = state.compounds[compound.id].parent
 
-            # Go through all parent children and
+            # Go through all parent children and find previous and next
             if up:
                 up = state.compounds[up]
 
@@ -1668,6 +1687,53 @@ def parse_xml(state: State, xml: str):
 
         compound.prefix_wbr += '::<wbr />'
 
+    # Example pages
+    if compound.kind == 'example':
+        # Build breadcrumb navigation
+        if example_navigation:
+            if not compound.name.startswith(example_navigation[1]):
+                logging.critical("{}: example filename is not prefixed with {}".format(state.current, example_navigation[1]))
+                assert False
+
+            prefix_length = len(example_navigation[1])
+
+            path_reverse = [example_navigation[0]]
+            while path_reverse[-1] in state.compounds and state.compounds[path_reverse[-1]].parent:
+                path_reverse += [state.compounds[path_reverse[-1]].parent]
+
+            # Fill breadcrumb with leaf names and URLs
+            compound.breadcrumb = []
+            for i in reversed(path_reverse):
+                compound.breadcrumb += [(state.compounds[i].leaf_name, state.compounds[i].url)]
+
+            # Add example filename as leaf item
+            compound.breadcrumb += [(compound.name[prefix_length:], compound.id + '.html')]
+
+            # Enable footer navigation, if requested
+            if footer_navigation:
+                up = state.compounds[example_navigation[0]]
+
+                prev = None
+                next = None
+                prev_child = None
+                for example in state.examples:
+                    if example.id == compound.id:
+                        if prev_child: prev = prev_child
+                    elif prev_child and prev_child.id == compound.id:
+                        if example.name.startswith(example_navigation[1]):
+                            next = example
+                        break
+
+                    if example.name.startswith(example_navigation[1]):
+                        prev_child = example
+
+                compound.footer_navigation = ((prev.url, prev.name[prefix_length:]) if prev else None,
+                                              (up.url, up.name),
+                                              (next.url, next.name[prefix_length:]) if next else None)
+
+        else:
+            compound.breadcrumb = [(compound.name, compound.id + '.html')]
+
     parsed = Empty()
     parsed.version = root.attrib['version']
 
index e594db258cd38746c2b6468d593f0d6b80cb5189..5392792903807762faffc5d9fc26cbec824a2286 100644 (file)
@@ -1,13 +1,30 @@
 {% extends 'base.html' %}
 
-{% block title %}{{ compound.name }} example | {{ super() }}{% endblock %}
+{% block title %}{% set j = joiner(' &raquo; ') %}{% for name, _ in compound.breadcrumb %}{{ j() }}{{ name }}{% endfor %} source | {{ super() }}{% endblock %}
+
+{% block header_links %}
+{% if compound.footer_navigation and compound.footer_navigation[0] %}
+  <link rel="prev" href="{{ compound.footer_navigation[0][0] }}" />
+{% endif %}
+{% if compound.footer_navigation and compound.footer_navigation[2] %}
+  <link rel="next" href="{{ compound.footer_navigation[2][0] }}" />
+{% endif %}
+{% endblock %}
 
 {% block main %}
-          <h1>{{ compound.name }} <span class="m-thin">example</span></h1>
-          {% if compound.brief %}
-          <p>{{ compound.brief }}</p>
-          {% endif %}
-{% if compound.description %}
+        <h1>
+          {% for name, target in compound.breadcrumb[:-1] %}
+          <span class="m-breadcrumb"><a href="{{ target }}">{{ name }}</a> &raquo;</span>
+          {% endfor %}
+          {{ compound.breadcrumb[-1][0] }} <span class="m-thin">source</span>
+        </h1>
+        {% if compound.brief %}
+        <p>{{ compound.brief }}</p>
+        {% endif %}
+        {% if compound.description %}
 {{ compound.description }}
-{% endif %}
+        {% endif %}
+        {% if compound.footer_navigation %}
+        <div class="m-note m-dim m-thin m-text-center">{% if compound.footer_navigation[0] %}<a href="{{ compound.footer_navigation[0][0] }}" class="m-dox">&laquo; {{ compound.footer_navigation[0][1] }}</a> | {% endif %}<a href="{{ compound.footer_navigation[1][0] }}" class="m-dox">{{ compound.footer_navigation[1][1] }}</a>{% if compound.footer_navigation[2] %} | <a href="{{ compound.footer_navigation[2][0] }}" class="m-dox">{{ compound.footer_navigation[2][1] }} &raquo;</a>{% endif %}</div>
+        {% endif %}
 {% endblock %}
diff --git a/doxygen/test/example/Doxyfile b/doxygen/test/example/Doxyfile
new file mode 100644 (file)
index 0000000..9bb6261
--- /dev/null
@@ -0,0 +1,14 @@
+INPUT                   = input.dox
+QUIET                   = YES
+GENERATE_HTML           = NO
+GENERATE_LATEX          = NO
+GENERATE_XML            = YES
+EXAMPLE_PATH            = .
+ALIASES                 = \
+    "m_footernavigation=@xmlonly<mcss:footernavigation xmlns:mcss=\"http://mcss.mosra.cz/doxygen/\" />@endxmlonly" \
+    "m_examplenavigation{2}=@xmlonly<mcss:examplenavigation xmlns:mcss=\"http://mcss.mosra.cz/doxygen/\" mcss:page=\"\1\" mcss:prefix=\"\2\" />@endxmlonly"
+
+M_PAGE_FINE_PRINT       =
+M_THEME_COLOR           =
+M_LINKS_NAVBAR1         =
+M_LINKS_NAVBAR2         =
diff --git a/doxygen/test/example/input.dox b/doxygen/test/example/input.dox
new file mode 100644 (file)
index 0000000..507035d
--- /dev/null
@@ -0,0 +1,17 @@
+/** @page page A page
+
+Go here: @subpage example
+*/
+
+/** @page example The Example
+
+See here:
+
+-   @ref path-prefix/CMakeLists.txt
+-   @ref path-prefix/configure.h.cmake
+-   @ref path-prefix/main.cpp
+
+@example path-prefix/CMakeLists.txt @m_examplenavigation{example,path-prefix/} @m_footernavigation
+@example path-prefix/configure.h.cmake @m_examplenavigation{example,path-prefix/} @m_footernavigation
+@example path-prefix/main.cpp @m_examplenavigation{example,path-prefix/} @m_footernavigation
+*/
diff --git a/doxygen/test/example/path-prefix/CMakeLists.txt b/doxygen/test/example/path-prefix/CMakeLists.txt
new file mode 100644 (file)
index 0000000..2828f30
--- /dev/null
@@ -0,0 +1,5 @@
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/configure.h.cmake
+               ${CMAKE_CURRENT_BINARY_DIR}/configure.h)
+
+add_executable(app main.cpp)
+target_include_directories(app ${CMAKE_CURRENT_BINARY_DIR})
diff --git a/doxygen/test/example/path-prefix/configure.h.cmake b/doxygen/test/example/path-prefix/configure.h.cmake
new file mode 100644 (file)
index 0000000..8f39964
--- /dev/null
@@ -0,0 +1 @@
+#cmakedefine SAY_HELLO
diff --git a/doxygen/test/example/path-prefix/main.cpp b/doxygen/test/example/path-prefix/main.cpp
new file mode 100644 (file)
index 0000000..7ff42a0
--- /dev/null
@@ -0,0 +1,9 @@
+#include <iostream>
+
+#include "configure.h"
+
+int main() {
+    #ifdef SAY_HELLO
+    std::cout << "hello?" << std::endl;
+    #endif
+}
diff --git a/doxygen/test/example/path-prefix_2CMakeLists_8txt-example.html b/doxygen/test/example/path-prefix_2CMakeLists_8txt-example.html
new file mode 100644 (file)
index 0000000..9fbf300
--- /dev/null
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8" />
+  <title>A page &raquo; The Example &raquo; CMakeLists.txt source | My Project</title>
+  <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400i,600,600i%7CSource+Code+Pro:400,400i,600" />
+  <link rel="stylesheet" href="m-dark+doxygen.compiled.css" />
+  <link rel="next" href="path-prefix_2configure_8h_8cmake-example.html" />
+  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+</head>
+<body>
+<header><nav id="navigation">
+  <div class="m-container">
+    <div class="m-row">
+      <a href="index.html" id="m-navbar-brand" class="m-col-t-9 m-col-m-none m-left-m">My Project</a>
+    </div>
+  </div>
+</nav></header>
+<main><article>
+  <div class="m-container m-container-inflatable">
+    <div class="m-row">
+      <div class="m-col-l-10 m-push-l-1">
+        <h1>
+          <span class="m-breadcrumb"><a href="page.html">A page</a> &raquo;</span>
+          <span class="m-breadcrumb"><a href="example.html">The Example</a> &raquo;</span>
+          CMakeLists.txt <span class="m-thin">source</span>
+        </h1>
+<pre class="m-code"><span class="nb">configure_file</span><span class="p">(</span><span class="o">${</span><span class="nv">CMAKE_CURRENT_SOURCE_DIR</span><span class="o">}</span><span class="s">/configure.h.cmake</span>
+               <span class="o">${</span><span class="nv">CMAKE_CURRENT_BINARY_DIR</span><span class="o">}</span><span class="s">/configure.h</span><span class="p">)</span>
+
+<span class="nb">add_executable</span><span class="p">(</span><span class="s">app</span> <span class="s">main.cpp</span><span class="p">)</span>
+<span class="nb">target_include_directories</span><span class="p">(</span><span class="s">app</span> <span class="o">${</span><span class="nv">CMAKE_CURRENT_BINARY_DIR</span><span class="o">}</span><span class="p">)</span></pre>
+        <div class="m-note m-dim m-thin m-text-center"><a href="example.html" class="m-dox">The Example</a> | <a href="path-prefix_2configure_8h_8cmake-example.html" class="m-dox">configure.h.cmake &raquo;</a></div>
+      </div>
+    </div>
+  </div>
+</article></main>
+</body>
+</html>
diff --git a/doxygen/test/example/path-prefix_2configure_8h_8cmake-example.html b/doxygen/test/example/path-prefix_2configure_8h_8cmake-example.html
new file mode 100644 (file)
index 0000000..59313c0
--- /dev/null
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8" />
+  <title>A page &raquo; The Example &raquo; configure.h.cmake source | My Project</title>
+  <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400i,600,600i%7CSource+Code+Pro:400,400i,600" />
+  <link rel="stylesheet" href="m-dark+doxygen.compiled.css" />
+  <link rel="prev" href="path-prefix_2CMakeLists_8txt-example.html" />
+  <link rel="next" href="path-prefix_2main_8cpp-example.html" />
+  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+</head>
+<body>
+<header><nav id="navigation">
+  <div class="m-container">
+    <div class="m-row">
+      <a href="index.html" id="m-navbar-brand" class="m-col-t-9 m-col-m-none m-left-m">My Project</a>
+    </div>
+  </div>
+</nav></header>
+<main><article>
+  <div class="m-container m-container-inflatable">
+    <div class="m-row">
+      <div class="m-col-l-10 m-push-l-1">
+        <h1>
+          <span class="m-breadcrumb"><a href="page.html">A page</a> &raquo;</span>
+          <span class="m-breadcrumb"><a href="example.html">The Example</a> &raquo;</span>
+          configure.h.cmake <span class="m-thin">source</span>
+        </h1>
+<pre class="m-code"><span class="cp">#cmakedefine SAY_HELLO</span></pre>
+        <div class="m-note m-dim m-thin m-text-center"><a href="path-prefix_2CMakeLists_8txt-example.html" class="m-dox">&laquo; CMakeLists.txt</a> | <a href="example.html" class="m-dox">The Example</a> | <a href="path-prefix_2main_8cpp-example.html" class="m-dox">main.cpp &raquo;</a></div>
+      </div>
+    </div>
+  </div>
+</article></main>
+</body>
+</html>
diff --git a/doxygen/test/example/path-prefix_2main_8cpp-example.html b/doxygen/test/example/path-prefix_2main_8cpp-example.html
new file mode 100644 (file)
index 0000000..6ff176b
--- /dev/null
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8" />
+  <title>A page &raquo; The Example &raquo; main.cpp source | My Project</title>
+  <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400i,600,600i%7CSource+Code+Pro:400,400i,600" />
+  <link rel="stylesheet" href="m-dark+doxygen.compiled.css" />
+  <link rel="prev" href="path-prefix_2configure_8h_8cmake-example.html" />
+  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+</head>
+<body>
+<header><nav id="navigation">
+  <div class="m-container">
+    <div class="m-row">
+      <a href="index.html" id="m-navbar-brand" class="m-col-t-9 m-col-m-none m-left-m">My Project</a>
+    </div>
+  </div>
+</nav></header>
+<main><article>
+  <div class="m-container m-container-inflatable">
+    <div class="m-row">
+      <div class="m-col-l-10 m-push-l-1">
+        <h1>
+          <span class="m-breadcrumb"><a href="page.html">A page</a> &raquo;</span>
+          <span class="m-breadcrumb"><a href="example.html">The Example</a> &raquo;</span>
+          main.cpp <span class="m-thin">source</span>
+        </h1>
+<pre class="m-code"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"></span>
+
+<span class="cp">#include</span> <span class="cpf">&quot;configure.h&quot;</span><span class="cp"></span>
+
+<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
+    <span class="cp">#ifdef SAY_HELLO</span>
+    <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&quot;hello?&quot;</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
+    <span class="cp">#endif</span>
+<span class="p">}</span></pre>
+        <div class="m-note m-dim m-thin m-text-center"><a href="path-prefix_2configure_8h_8cmake-example.html" class="m-dox">&laquo; configure.h.cmake</a> | <a href="example.html" class="m-dox">The Example</a></div>
+      </div>
+    </div>
+  </div>
+</article></main>
+</body>
+</html>
diff --git a/doxygen/test/test_example.py b/doxygen/test/test_example.py
new file mode 100644 (file)
index 0000000..3e8bfb0
--- /dev/null
@@ -0,0 +1,39 @@
+#
+#   This file is part of m.css.
+#
+#   Copyright © 2017, 2018 Vladimír Vondruš <mosra@centrum.cz>
+#
+#   Permission is hereby granted, free of charge, to any person obtaining a
+#   copy of this software and associated documentation files (the "Software"),
+#   to deal in the Software without restriction, including without limitation
+#   the rights to use, copy, modify, merge, publish, distribute, sublicense,
+#   and/or sell copies of the Software, and to permit persons to whom the
+#   Software is furnished to do so, subject to the following conditions:
+#
+#   The above copyright notice and this permission notice shall be included
+#   in all copies or substantial portions of the Software.
+#
+#   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+#   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+#   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+#   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+#   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+#   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+#   DEALINGS IN THE SOFTWARE.
+#
+
+import unittest
+
+from distutils.version import LooseVersion
+
+from test import IntegrationTestCase, doxygen_version
+
+class Example(IntegrationTestCase):
+    def __init__(self, *args, **kwargs):
+        super().__init__(__file__, '', *args, **kwargs)
+
+    def test(self):
+        self.run_dox2html5(index_pages=[], wildcard='*.xml')
+        self.assertEqual(*self.actual_expected_contents('path-prefix_2CMakeLists_8txt-example.html'))
+        self.assertEqual(*self.actual_expected_contents('path-prefix_2configure_8h_8cmake-example.html'))
+        self.assertEqual(*self.actual_expected_contents('path-prefix_2main_8cpp-example.html'))