diff options
| author | Georg Brandl <georg@python.org> | 2009-12-28 19:49:57 +0100 |
|---|---|---|
| committer | Georg Brandl <georg@python.org> | 2009-12-28 19:49:57 +0100 |
| commit | 6b954328bea16abf763a2d829471d6565747f1a4 (patch) | |
| tree | 17299e304c5608d335c88e2eb26780ba14fafecc /tests | |
| parent | 2637a7b44ad5b68412d14da5ff64b0f8ee88512f (diff) | |
| parent | a3cd1ee676757c69ae30f401b62b7a055f1e3f1a (diff) | |
| download | sphinx-6b954328bea16abf763a2d829471d6565747f1a4.tar.gz | |
merge with trunk
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/root/_templates/layout.html | 7 | ||||
| -rw-r--r-- | tests/root/conf.py | 22 | ||||
| -rw-r--r-- | tests/root/contents.txt | 3 | ||||
| -rw-r--r-- | tests/root/extapi.txt | 10 | ||||
| -rw-r--r-- | tests/root/markup.txt | 113 | ||||
| -rw-r--r-- | tests/root/objects.txt (renamed from tests/root/desc.txt) | 38 | ||||
| -rw-r--r-- | tests/test_autodoc.py | 35 | ||||
| -rw-r--r-- | tests/test_build.py | 159 | ||||
| -rw-r--r-- | tests/test_build_html.py | 245 | ||||
| -rw-r--r-- | tests/test_config.py | 2 | ||||
| -rw-r--r-- | tests/test_coverage.py | 1 | ||||
| -rw-r--r-- | tests/test_env.py | 19 | ||||
| -rw-r--r-- | tests/test_intersphinx.py | 112 | ||||
| -rw-r--r-- | tests/test_markup.py | 3 | ||||
| -rw-r--r-- | tests/util.py | 4 |
15 files changed, 549 insertions, 224 deletions
diff --git a/tests/root/_templates/layout.html b/tests/root/_templates/layout.html index e8920025..d312238f 100644 --- a/tests/root/_templates/layout.html +++ b/tests/root/_templates/layout.html @@ -1,5 +1,12 @@ {% extends "!layout.html" %} + {% block extrahead %} <meta name="hc" content="{{ hckey }}" /> {{ super() }} {% endblock %} + +{% block sidebartoc %} +{# display global TOC in addition to local TOC #} +{{ super() }} +{{ toctree(collapse=False, maxdepth=-1) }} +{% endblock %}
\ No newline at end of file diff --git a/tests/root/conf.py b/tests/root/conf.py index fd82be7d..13b26799 100644 --- a/tests/root/conf.py +++ b/tests/root/conf.py @@ -25,6 +25,7 @@ today_fmt = '%B %d, %Y' exclude_trees = ['_build'] keep_warnings = True pygments_style = 'sphinx' +show_authors = True rst_epilog = '.. |subst| replace:: global substitution' @@ -49,6 +50,7 @@ latex_additional_files = ['svgimg.svg'] value_from_conf_py = 84 coverage_c_path = ['special/*.h'] +# XXX cfunction? coverage_c_regexes = {'cfunction': r'^PyAPI_FUNC\(.*\)\s+([^_][\w_]+)'} autosummary_generate = ['autosummary'] @@ -56,7 +58,12 @@ autosummary_generate = ['autosummary'] # modify tags from conf.py tags.add('confpytag') + +# -- extension API + +from docutils import nodes from sphinx import addnodes +from sphinx.util.compat import Directive def userdesc_parse(env, sig, signode): x, y = sig.split(':') @@ -65,7 +72,18 @@ def userdesc_parse(env, sig, signode): signode[-1] += addnodes.desc_parameter(y, y) return x +def functional_directive(name, arguments, options, content, lineno, + content_offset, block_text, state, state_machine): + return [nodes.strong(text='from function: %s' % options['opt'])] + +class ClassDirective(Directive): + option_spec = {'opt': lambda x: x} + def run(self): + return [nodes.strong(text='from class: %s' % self.options['opt'])] + def setup(app): app.add_config_value('value_from_conf_py', 42, False) - app.add_description_unit('userdesc', 'userdescrole', '%s (userdesc)', - userdesc_parse) + app.add_directive('funcdir', functional_directive, opt=lambda x: x) + app.add_directive('clsdir', ClassDirective) + app.add_object_type('userdesc', 'userdescrole', '%s (userdesc)', + userdesc_parse, objname='user desc') diff --git a/tests/root/contents.txt b/tests/root/contents.txt index 6133f887..6955ec62 100644 --- a/tests/root/contents.txt +++ b/tests/root/contents.txt @@ -11,12 +11,13 @@ Contents: :maxdepth: 2 :numbered: + extapi images subdir/images subdir/includes includes markup - desc + objects bom math autodoc diff --git a/tests/root/extapi.txt b/tests/root/extapi.txt new file mode 100644 index 00000000..4728e3de --- /dev/null +++ b/tests/root/extapi.txt @@ -0,0 +1,10 @@ +Extension API tests +=================== + +Testing directives: + +.. funcdir:: + :opt: Foo + +.. clsdir:: + :opt: Bar diff --git a/tests/root/markup.txt b/tests/root/markup.txt index 32b037ee..c5022b32 100644 --- a/tests/root/markup.txt +++ b/tests/root/markup.txt @@ -5,7 +5,11 @@ Testing various markup ====================== +Meta markup +----------- + .. sectionauthor:: Georg Brandl +.. moduleauthor:: Georg Brandl .. contents:: TOC @@ -13,7 +17,11 @@ Testing various markup :author: Me :keywords: docs, sphinx -A |subst|. + +Generic reST +------------ + +A |subst| (the definition is in rst_epilog). .. _label: @@ -21,22 +29,14 @@ A |subst|. some code -Admonitions ------------ - -.. note:: Note - Note text. - -.. warning:: Warning - - Warning text. +Option list: -.. tip:: - Tip text. +-h help +--help also help Body directives ---------------- +^^^^^^^^^^^^^^^ .. topic:: Title @@ -69,7 +69,67 @@ Body directives b - + +Admonitions +^^^^^^^^^^^ + +.. admonition:: My Admonition + + Admonition text. + +.. note:: + Note text. + +.. warning:: + + Warning text. + +.. tip:: + Tip text. + + +Inline markup +------------- + +*Generic inline markup* + +* :command:`command` +* :dfn:`dfn` +* :guilabel:`guilabel` +* :kbd:`kbd` +* :mailheader:`mailheader` +* :makevar:`makevar` +* :manpage:`manpage` +* :mimetype:`mimetype` +* :newsgroup:`newsgroup` +* :program:`program` +* :regexp:`regexp` +* :menuselection:`File --> Close` +* :file:`a/{varpart}/b` +* :samp:`print {i}` + +*Linking inline markup* + +* :pep:`8` +* :rfc:`1` +* :envvar:`HOME` +* :keyword:`with` +* :token:`try statement <try_stmt>` +* :doc:`subdir/includes` +* ``:download:`` is tested in includes.txt +* :option:`Python -c option <python -c>` + +Test :abbr:`abbr (abbreviation)` and another :abbr:`abbr (abbreviation)`. + + +.. _with: + +With +---- + +(Empty section.) + + Tables ------ @@ -96,6 +156,17 @@ Version markup Boring stuff. +Code blocks +----------- + +.. code-block:: ruby + :linenos: + + def ruby? + false + end + + Misc stuff ---------- @@ -124,11 +195,6 @@ This is a side note. This tests :CLASS:`role names in uppercase`. -Option list: - --h help ---help also help - .. centered:: LICENSE AGREEMENT .. acks:: @@ -146,7 +212,7 @@ Option list: Particle with half-integer spin. .. productionlist:: - try_stmt: try1_stmt | try2_stmt + try_stmt: `try1_stmt` | `try2_stmt` try1_stmt: "try" ":" `suite` : ("except" [`expression` ["," `target`]] ":" `suite`)+ : ["else" ":" `suite`] @@ -154,7 +220,6 @@ Option list: try2_stmt: "try" ":" `suite` : "finally" ":" `suite` -Test :abbr:`abbr (abbreviation)` and another :abbr:`abbr (abbreviation)`. Index markup ------------ @@ -179,11 +244,6 @@ Invalid index markup... Testing öäü... -Object markup -------------- - -:cfunc:`CFunction`. - Only directive -------------- @@ -207,3 +267,4 @@ Only directive .. rubric:: Footnotes .. [#] Like footnotes. + diff --git a/tests/root/desc.txt b/tests/root/objects.txt index d6915dc2..fd33a6cc 100644 --- a/tests/root/desc.txt +++ b/tests/root/objects.txt @@ -1,5 +1,5 @@ -Testing description units -========================= +Testing object descriptions +=========================== .. function:: func_without_module(a, b, *c[, d]) @@ -43,22 +43,42 @@ Testing description units C items ======= -.. cfunction:: Sphinx_DoSomething() +.. c:function:: Sphinx_DoSomething() -.. cmember:: SphinxStruct.member +.. c:member:: SphinxStruct.member -.. cmacro:: SPHINX_USE_PYTHON +.. c:macro:: SPHINX_USE_PYTHON -.. ctype:: SphinxType +.. c:type:: SphinxType -.. cvar:: sphinx_global +.. c:var:: sphinx_global -Testing references -================== +References +========== Referencing :class:`mod.Cls` or :Class:`mod.Cls` should be the same. +With target: :c:func:`Sphinx_DoSomething()` (parentheses are handled), +:c:member:`SphinxStruct.member`, :c:macro:`SPHINX_USE_PYTHON`, +:c:type:`SphinxType *` (pointer is handled), :c:data:`sphinx_global`. + +Without target: :c:func:`CFunction`. :c:func:`!malloc`. + + +Others +====== + +.. envvar:: HOME + +.. program:: python + +.. cmdoption:: -c command + +.. program:: perl + +.. cmdoption:: -c + User markup =========== diff --git a/tests/test_autodoc.py b/tests/test_autodoc.py index 687fbd0d..9f1e2bd9 100644 --- a/tests/test_autodoc.py +++ b/tests/test_autodoc.py @@ -97,28 +97,28 @@ def test_parse_name(): verify('function', 'util.raises', ('util', ['raises'], None, None)) verify('function', 'util.raises(exc) -> None', ('util', ['raises'], 'exc', 'None')) - directive.env.autodoc_current_module = 'util' + directive.env.doc_read_data['autodoc_module'] = 'util' verify('function', 'raises', ('util', ['raises'], None, None)) - directive.env.autodoc_current_module = None - directive.env.currmodule = 'util' + del directive.env.doc_read_data['autodoc_module'] + directive.env.doc_read_data['py_module'] = 'util' verify('function', 'raises', ('util', ['raises'], None, None)) verify('class', 'TestApp', ('util', ['TestApp'], None, None)) # for members - directive.env.currmodule = 'foo' + directive.env.doc_read_data['py_module'] = 'foo' verify('method', 'util.TestApp.cleanup', ('util', ['TestApp', 'cleanup'], None, None)) - directive.env.currmodule = 'util' - directive.env.currclass = 'Foo' - directive.env.autodoc_current_class = 'TestApp' + directive.env.doc_read_data['py_module'] = 'util' + directive.env.doc_read_data['py_class'] = 'Foo' + directive.env.doc_read_data['autodoc_class'] = 'TestApp' verify('method', 'cleanup', ('util', ['TestApp', 'cleanup'], None, None)) verify('method', 'TestApp.cleanup', ('util', ['TestApp', 'cleanup'], None, None)) # and clean up - directive.env.currmodule = None - directive.env.currclass = None - directive.env.autodoc_current_class = None + del directive.env.doc_read_data['py_module'] + del directive.env.doc_read_data['py_class'] + del directive.env.doc_read_data['autodoc_class'] def test_format_signature(): @@ -306,7 +306,7 @@ def test_new_documenter(): del directive.result[:] options.members = ['integer'] - assert_result_contains('.. data:: integer', 'module', 'test_autodoc') + assert_result_contains('.. py:data:: integer', 'module', 'test_autodoc') def test_generate(): @@ -353,7 +353,7 @@ def test_generate(): 'function', 'util.foobar', more_content=None) # test auto and given content mixing - directive.env.currmodule = 'test_autodoc' + directive.env.doc_read_data['py_module'] = 'test_autodoc' assert_result_contains(' Function.', 'method', 'Class.meth') add_content = ViewList() add_content.append('Content.', '', 0) @@ -394,7 +394,8 @@ def test_generate(): options.members = [] # test module flags - assert_result_contains('.. module:: test_autodoc', 'module', 'test_autodoc') + assert_result_contains('.. py:module:: test_autodoc', + 'module', 'test_autodoc') options.synopsis = 'Synopsis' assert_result_contains(' :synopsis: Synopsis', 'module', 'test_autodoc') options.deprecated = True @@ -403,9 +404,9 @@ def test_generate(): assert_result_contains(' :platform: Platform', 'module', 'test_autodoc') # test if __all__ is respected for modules options.members = ALL - assert_result_contains('.. class:: Class', 'module', 'test_autodoc') + assert_result_contains('.. py:class:: Class', 'module', 'test_autodoc') try: - assert_result_contains('.. exception:: CustomEx', + assert_result_contains('.. py:exception:: CustomEx', 'module', 'test_autodoc') except AssertionError: pass @@ -419,7 +420,7 @@ def test_generate(): assert_result_contains(' :noindex:', 'class', 'Base') # okay, now let's get serious about mixing Python and C signature stuff - assert_result_contains('.. class:: CustomDict', 'class', 'CustomDict', + assert_result_contains('.. py:class:: CustomDict', 'class', 'CustomDict', all_members=True) # test inner class handling @@ -433,7 +434,7 @@ def test_generate(): 'attribute', 'test_autodoc.Class.descr') # test generation for C modules (which have no source file) - directive.env.currmodule = 'time' + directive.env.doc_read_data['py_module'] = 'time' assert_processes([('function', 'time.asctime')], 'function', 'asctime') assert_processes([('function', 'time.asctime')], 'function', 'asctime') diff --git a/tests/test_build.py b/tests/test_build.py index 47311f27..9d3210e7 100644 --- a/tests/test_build.py +++ b/tests/test_build.py @@ -13,28 +13,19 @@ import os import re import sys import difflib -import htmlentitydefs from StringIO import StringIO from subprocess import Popen, PIPE -from util import * -from etree13 import ElementTree as ET - -try: - import pygments -except ImportError: - pygments = None - -from sphinx.builders.html import StandaloneHTMLBuilder from sphinx.builders.latex import LaTeXBuilder from sphinx.writers.latex import LaTeXTranslator +from util import * + def teardown_module(): (test_root / '_build').rmtree(True) -html_warnfile = StringIO() latex_warnfile = StringIO() ENV_WARNINGS = """\ @@ -46,157 +37,11 @@ included file u'wrongenc.inc' seems to be wrong, try giving an :encoding: option %(root)s/includes.txt:4: WARNING: download file not readable: nonexisting.png """ -HTML_WARNINGS = ENV_WARNINGS + """\ -%(root)s/images.txt:20: WARNING: no matching candidate for image URI u'foo.*' -%(root)s/markup.txt:: WARNING: invalid index entry u'' -%(root)s/markup.txt:: WARNING: invalid pair index entry u'' -%(root)s/markup.txt:: WARNING: invalid pair index entry u'keyword; ' -""" - LATEX_WARNINGS = ENV_WARNINGS + """\ None:None: WARNING: no matching candidate for image URI u'foo.*' WARNING: invalid pair index entry u'' """ -HTML_XPATH = { - 'images.html': { - ".//img[@src='_images/img.png']": '', - ".//img[@src='_images/img1.png']": '', - ".//img[@src='_images/simg.png']": '', - ".//object[@data='_images/svgimg.svg']": '', - ".//embed[@src='_images/svgimg.svg']": '', - }, - 'subdir/images.html': { - ".//img[@src='../_images/img1.png']": '', - ".//img[@src='../_images/rimg.png']": '', - }, - 'subdir/includes.html': { - ".//a[@href='../_downloads/img.png']": '', - }, - 'includes.html': { - ".//pre": u'Max Strauß', - ".//a[@href='_downloads/img.png']": '', - ".//a[@href='_downloads/img1.png']": '', - ".//pre": u'"quotes"', - ".//pre": u"'included'", - }, - 'autodoc.html': { - ".//dt[@id='test_autodoc.Class']": '', - ".//dt[@id='test_autodoc.function']/em": r'\*\*kwds', - ".//dd": r'Return spam\.', - }, - 'markup.html': { - ".//meta[@name='author'][@content='Me']": '', - ".//meta[@name='keywords'][@content='docs, sphinx']": '', - ".//a[@href='contents.html#ref1']": '', - ".//div[@id='label']": '', - ".//span[@class='option']": '--help', - ".//p": 'A global substitution.', - ".//p": 'In HTML.', - ".//p": 'In both.', - ".//p": 'Always present', - ".//title": 'set by title directive', - ".//span[@class='pre']": 'CFunction()', - }, - 'desc.html': { - ".//dt[@id='mod.Cls.meth1']": '', - ".//dt[@id='errmod.Error']": '', - ".//a[@href='#mod.Cls']": '', - ".//dl[@class='userdesc']": '', - ".//dt[@id='userdescrole-myobj']": '', - ".//a[@href='#userdescrole-myobj']": '', - }, - 'contents.html': { - ".//meta[@name='hc'][@content='hcval']": '', - ".//meta[@name='testopt'][@content='testoverride']": '', - #".//td[@class='label']": r'\[Ref1\]', # docutils 0.5 only - ".//td[@class='label']": '', - ".//li[@class='toctree-l1']/a": 'Testing various markup', - ".//li[@class='toctree-l2']/a": 'Admonitions', - ".//title": 'Sphinx <Tests>', - ".//div[@class='footer']": 'Georg Brandl & Team', - ".//a[@href='http://python.org/']": '', - }, - 'bom.html': { - ".//title": " File with UTF-8 BOM", - }, - '_static/statictmpl.html': { - ".//project": 'Sphinx <Tests>', - }, -} - -if pygments: - HTML_XPATH['includes.html'].update({ - ".//pre/span[@class='s']": u'üöä', - ".//div[@class='inc-pyobj1 highlight-text']/div/pre": - r'^class Foo:\n pass\n\s*$', - ".//div[@class='inc-pyobj2 highlight-text']/div/pre": - r'^ def baz\(\):\n pass\n\s*$', - ".//div[@class='inc-lines highlight-text']/div/pre": - r'^class Foo:\n pass\nclass Bar:\n$', - ".//div[@class='inc-startend highlight-text']/div/pre": - ur'^foo = u"Including Unicode characters: üöä"\n$', - ".//div[@class='inc-preappend highlight-text']/div/pre": - r'(?m)^START CODE$', - ".//div[@class='inc-pyobj-dedent highlight-python']/div/pre/span": - r'def', - }) - HTML_XPATH['subdir/includes.html'].update({ - ".//pre/span": 'line 1', - ".//pre/span": 'line 2', - }) - -class NslessParser(ET.XMLParser): - """XMLParser that throws away namespaces in tag names.""" - - def _fixname(self, key): - try: - return self._names[key] - except KeyError: - name = key - br = name.find('}') - if br > 0: - name = name[br+1:] - self._names[key] = name = self._fixtext(name) - return name - - -def check_xpath(etree, fname, path, check): - nodes = list(etree.findall(path)) - assert nodes != [], ('did not find any node matching xpath ' - '%r in file %s' % (path, fname)) - if hasattr(check, '__call__'): - check(nodes) - elif not check: - # only check for node presence - pass - else: - rex = re.compile(check) - for node in nodes: - if node.text and rex.search(node.text): - break - else: - assert False, ('%r not found in any node matching ' - 'path %s in %s: %r' % (check, path, fname, - [node.text for node in nodes])) - -@gen_with_app(buildername='html', warning=html_warnfile, cleanenv=True, - tags=['testtag']) -def test_html(app): - app.builder.build_all() - html_warnings = html_warnfile.getvalue().replace(os.sep, '/') - html_warnings_exp = HTML_WARNINGS % {'root': app.srcdir} - assert html_warnings == html_warnings_exp, 'Warnings don\'t match:\n' + \ - '\n'.join(difflib.ndiff(html_warnings_exp.splitlines(), - html_warnings.splitlines())) - - for fname, paths in HTML_XPATH.iteritems(): - parser = NslessParser() - parser.entity.update(htmlentitydefs.entitydefs) - etree = ET.parse(os.path.join(app.outdir, fname), parser) - for path, check in paths.iteritems(): - yield check_xpath, etree, fname, path, check - @with_app(buildername='latex', warning=latex_warnfile, cleanenv=True) def test_latex(app): diff --git a/tests/test_build_html.py b/tests/test_build_html.py new file mode 100644 index 00000000..7079971c --- /dev/null +++ b/tests/test_build_html.py @@ -0,0 +1,245 @@ +# -*- coding: utf-8 -*- +""" + test_build_html + ~~~~~~~~~~~~~~~ + + Test the HTML builder and check output against XPath. + + :copyright: Copyright 2007-2009 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" + +import os +import re +import sys +import difflib +import htmlentitydefs +from StringIO import StringIO + +try: + import pygments +except ImportError: + pygments = None + +from sphinx.builders.html import StandaloneHTMLBuilder + +from util import * +from test_build import ENV_WARNINGS +from etree13 import ElementTree as ET + + +def teardown_module(): + (test_root / '_build').rmtree(True) + + +html_warnfile = StringIO() + +HTML_WARNINGS = ENV_WARNINGS + """\ +%(root)s/images.txt:20: WARNING: no matching candidate for image URI u'foo.*' +%(root)s/markup.txt:: WARNING: invalid index entry u'' +%(root)s/markup.txt:: WARNING: invalid pair index entry u'' +%(root)s/markup.txt:: WARNING: invalid pair index entry u'keyword; ' +""" + +HTML_XPATH = { + 'images.html': { + ".//img[@src='_images/img.png']": '', + ".//img[@src='_images/img1.png']": '', + ".//img[@src='_images/simg.png']": '', + ".//object[@data='_images/svgimg.svg']": '', + ".//embed[@src='_images/svgimg.svg']": '', + }, + 'subdir/images.html': { + ".//img[@src='../_images/img1.png']": '', + ".//img[@src='../_images/rimg.png']": '', + }, + 'subdir/includes.html': { + ".//a[@href='../_downloads/img.png']": '', + }, + 'includes.html': { + ".//pre": u'Max Strauß', + ".//a[@href='_downloads/img.png']": '', + ".//a[@href='_downloads/img1.png']": '', + ".//pre": u'"quotes"', + ".//pre": u"'included'", + }, + 'autodoc.html': { + ".//dt[@id='test_autodoc.Class']": '', + ".//dt[@id='test_autodoc.function']/em": r'\*\*kwds', + ".//dd": r'Return spam\.', + }, + 'extapi.html': { + ".//strong": 'from function: Foo', + ".//strong": 'from class: Bar', + }, + 'markup.html': { + ".//title": 'set by title directive', + ".//p/em": 'Section author: Georg Brandl', + ".//p/em": 'Module author: Georg Brandl', + # created by the meta directive + ".//meta[@name='author'][@content='Me']": '', + ".//meta[@name='keywords'][@content='docs, sphinx']": '', + # a label created by ``.. _label:`` + ".//div[@id='label']": '', + # code with standard code blocks + ".//pre": '^some code$', + # an option list + ".//span[@class='option']": '--help', + # admonitions + ".//p[@class='first admonition-title']": 'My Admonition', + ".//p[@class='last']": 'Note text.', + ".//p[@class='last']": 'Warning text.', + # inline markup + ".//li/strong": '^command$', + ".//li/strong": '^program$', + ".//li/em": '^dfn$', + ".//li/tt/span[@class='pre']": '^kbd$', + ".//li/em": u'File \N{TRIANGULAR BULLET} Close', + ".//li/tt/span[@class='pre']": '^a/$', + ".//li/tt/em/span[@class='pre']": '^varpart$', + ".//li/tt/em/span[@class='pre']": '^i$', + ".//a[@href='http://www.python.org/dev/peps/pep-0008']/strong": 'PEP 8', + ".//a[@href='http://tools.ietf.org/html/rfc1.html']/strong": 'RFC 1', + ".//a[@href='objects.html#envvar-HOME']/tt/span[@class='pre']": 'HOME', + ".//a[@href='#with']/tt/span[@class='pre']": '^with$', + ".//a[@href='#grammar-token-try_stmt']/tt/span": '^statement$', + ".//a[@href='subdir/includes.html']/em": 'Including in subdir', + ".//a[@href='objects.html#cmdoption-python-c']/em": 'Python -c option', + # abbreviations + ".//abbr[@title='abbreviation']": '^abbr$', + # version stuff + ".//span[@class='versionmodified']": 'New in version 0.6', + # footnote reference + ".//a[@class='footnote-reference']": r'\[1\]', + # created by reference lookup + ".//a[@href='contents.html#ref1']": '', + # ``seealso`` directive + ".//div/p[@class='first admonition-title']": 'See also', + # a ``hlist`` directive + ".//table[@class='hlist']/tr/td/ul/li": '^This$', + # a ``centered`` directive + ".//p[@class='centered']/strong": 'LICENSE', + # a glossary + ".//dl/dt[@id='term-boson']": 'boson', + # a production list + ".//pre/strong": 'try_stmt', + ".//pre/a[@href='#grammar-token-try1_stmt']/tt/span": 'try1_stmt', + # tests for ``only`` directive + ".//p": 'A global substitution.', + ".//p": 'In HTML.', + ".//p": 'In both.', + ".//p": 'Always present', + }, + 'objects.html': { + ".//dt[@id='mod.Cls.meth1']": '', + ".//dt[@id='errmod.Error']": '', + ".//a[@href='#mod.Cls']": '', + ".//dl[@class='userdesc']": '', + ".//dt[@id='userdesc-myobj']": '', + ".//a[@href='#userdesc-myobj']": '', + # C references + ".//span[@class='pre']": 'CFunction()', + ".//a[@href='#Sphinx_DoSomething']": '', + ".//a[@href='#SphinxStruct.member']": '', + ".//a[@href='#SPHINX_USE_PYTHON']": '', + ".//a[@href='#SphinxType']": '', + ".//a[@href='#sphinx_global']": '', + # test global TOC created by toctree() + ".//ul[@class='current']/li[@class='toctree-l1 current']/a[@href='']": + 'Testing object descriptions', + ".//li[@class='toctree-l1']/a[@href='markup.html']": + 'Testing various markup', + }, + 'contents.html': { + ".//meta[@name='hc'][@content='hcval']": '', + ".//meta[@name='testopt'][@content='testoverride']": '', + #".//td[@class='label']": r'\[Ref1\]', # docutils 0.5 only + ".//td[@class='label']": '', + ".//li[@class='toctree-l1']/a": 'Testing various markup', + ".//li[@class='toctree-l2']/a": 'Inline markup', + ".//title": 'Sphinx <Tests>', + ".//div[@class='footer']": 'Georg Brandl & Team', + ".//a[@href='http://python.org/']": '', + ".//li/a[@href='genindex.html']/em": 'Index', + ".//li/a[@href='modindex.html']/em": 'Module Index', + ".//li/a[@href='search.html']/em": 'Search Page', + }, + 'bom.html': { + ".//title": " File with UTF-8 BOM", + }, + '_static/statictmpl.html': { + ".//project": 'Sphinx <Tests>', + }, +} + +if pygments: + HTML_XPATH['includes.html'].update({ + ".//pre/span[@class='s']": u'üöä', + ".//div[@class='inc-pyobj1 highlight-text']/div/pre": + r'^class Foo:\n pass\n\s*$', + ".//div[@class='inc-pyobj2 highlight-text']/div/pre": + r'^ def baz\(\):\n pass\n\s*$', + ".//div[@class='inc-lines highlight-text']/div/pre": + r'^class Foo:\n pass\nclass Bar:\n$', + ".//div[@class='inc-startend highlight-text']/div/pre": + ur'^foo = u"Including Unicode characters: üöä"\n$', + ".//div[@class='inc-preappend highlight-text']/div/pre": + r'(?m)^START CODE$', + ".//div[@class='inc-pyobj-dedent highlight-python']/div/pre/span": + r'def', + }) + HTML_XPATH['subdir/includes.html'].update({ + ".//pre/span": 'line 1', + ".//pre/span": 'line 2', + }) + +class NslessParser(ET.XMLParser): + """XMLParser that throws away namespaces in tag names.""" + + def _fixname(self, key): + try: + return self._names[key] + except KeyError: + name = key + br = name.find('}') + if br > 0: + name = name[br+1:] + self._names[key] = name = self._fixtext(name) + return name + + +def check_xpath(etree, fname, path, check): + nodes = list(etree.findall(path)) + assert nodes != [], ('did not find any node matching xpath ' + '%r in file %s' % (path, fname)) + if hasattr(check, '__call__'): + check(nodes) + elif not check: + # only check for node presence + pass + else: + rex = re.compile(check) + for node in nodes: + if node.text and rex.search(node.text): + break + else: + assert False, ('%r not found in any node matching ' + 'path %s in %s: %r' % (check, path, fname, + [node.text for node in nodes])) + +@gen_with_app(buildername='html', warning=html_warnfile, cleanenv=True, + tags=['testtag']) +def test_html(app): + app.builder.build_all() + html_warnings = html_warnfile.getvalue().replace(os.sep, '/') + html_warnings_exp = HTML_WARNINGS % {'root': app.srcdir} + assert html_warnings == html_warnings_exp, 'Warnings don\'t match:\n' + \ + '\n'.join(difflib.ndiff(html_warnings_exp.splitlines(), + html_warnings.splitlines())) + + for fname, paths in HTML_XPATH.iteritems(): + parser = NslessParser() + parser.entity.update(htmlentitydefs.entitydefs) + etree = ET.parse(os.path.join(app.outdir, fname), parser) + for path, check in paths.iteritems(): + yield check_xpath, etree, fname, path, check diff --git a/tests/test_config.py b/tests/test_config.py index b3aa4eea..1560c257 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -32,7 +32,7 @@ def test_core_config(app): # simple default values assert 'exclude_dirs' not in cfg.__dict__ assert cfg.exclude_dirs == [] - assert cfg.show_authors == False + assert cfg.trim_footnote_reference_space == False # complex default values assert 'html_title' not in cfg.__dict__ diff --git a/tests/test_coverage.py b/tests/test_coverage.py index 369788a1..bc59a815 100644 --- a/tests/test_coverage.py +++ b/tests/test_coverage.py @@ -36,6 +36,7 @@ def test_build(app): undoc_py, undoc_c = pickle.loads((app.outdir / 'undoc.pickle').text()) assert len(undoc_c) == 1 # the key is the full path to the header file, which isn't testable + # XXX this should fail right now assert undoc_c.values()[0] == [('cfunction', 'Py_SphinxTest')] assert 'test_autodoc' in undoc_py diff --git a/tests/test_env.py b/tests/test_env.py index a06656d6..660d0e3b 100644 --- a/tests/test_env.py +++ b/tests/test_env.py @@ -20,8 +20,8 @@ warnings = [] def setup_module(): global app, env - app = TestApp(srcdir='(temp)') - env = BuildEnvironment(app.srcdir, app.doctreedir, app.config) + app = TestApp(srcdir='(temp)', freshenv=True) + env = app.env env.set_warnfunc(lambda *args: warnings.append(args)) def teardown_module(): @@ -51,7 +51,7 @@ def test_images(): tree = env.get_doctree('images') app._warning.reset() - htmlbuilder = StandaloneHTMLBuilder(app, env) + htmlbuilder = StandaloneHTMLBuilder(app) htmlbuilder.post_process_images(tree) assert "no matching candidate for image URI u'foo.*'" in \ app._warning.content[-1] @@ -61,7 +61,7 @@ def test_images(): set(['img.png', 'img1.png', 'simg.png', 'svgimg.svg']) app._warning.reset() - latexbuilder = LaTeXBuilder(app, env) + latexbuilder = LaTeXBuilder(app) latexbuilder.post_process_images(tree) assert "no matching candidate for image URI u'foo.*'" in \ app._warning.content[-1] @@ -92,10 +92,10 @@ def test_second_update(): assert 'autodoc' not in env.found_docs def test_object_inventory(): - refs = env.descrefs + refs = env.domaindata['py']['objects'] assert 'func_without_module' in refs - assert refs['func_without_module'] == ('desc', 'function') + assert refs['func_without_module'] == ('objects', 'function') assert 'func_without_module2' in refs assert 'mod.func_in_module' in refs assert 'mod.Cls' in refs @@ -109,5 +109,8 @@ def test_object_inventory(): assert 'func_in_module' not in refs assert 'func_noindex' not in refs - assert 'mod' in env.modules - assert env.modules['mod'] == ('desc', 'Module synopsis.', 'UNIX', False) + assert env.domaindata['py']['modules']['mod'] == \ + ('objects', 'Module synopsis.', 'UNIX', False) + + assert env.domains['py'].data is env.domaindata['py'] + assert env.domains['c'].data is env.domaindata['c'] diff --git a/tests/test_intersphinx.py b/tests/test_intersphinx.py new file mode 100644 index 00000000..2d521914 --- /dev/null +++ b/tests/test_intersphinx.py @@ -0,0 +1,112 @@ +# -*- coding: utf-8 -*- +""" + test_intersphinx + ~~~~~~~~~~~~~~~~ + + Test the intersphinx extension. + + :copyright: Copyright 2007-2009 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" + +import zlib +import posixpath +from cStringIO import StringIO + +from docutils import nodes + +from sphinx import addnodes +from sphinx.ext.intersphinx import read_inventory_v1, read_inventory_v2, \ + fetch_inventory, load_mappings, missing_reference + +from util import * + + +inventory_v1 = '''\ +# Sphinx inventory version 1 +# Project: foo +# Version: 1.0 +module mod foo.html +module.cls class foo.html +''' + +inventory_v2 = '''\ +# Sphinx inventory version 2 +# Project: foo +# Version: 2.0 +# The remainder of this file is compressed with zlib. +''' + zlib.compress('''\ +module1 py:module 0 foo.html#module-module1 +module2 py:module 0 foo.html#module-$ +module1.func py:function 1 sub/foo.html#$ +CFunc c:function 2 cfunc.html#CFunc +''') + + +def test_read_inventory_v1(): + f = StringIO(inventory_v1) + f.readline() + invdata = read_inventory_v1(f, '/util', posixpath.join) + assert invdata['py:module']['module'] == \ + ('foo', '1.0', '/util/foo.html#module-module') + assert invdata['py:class']['module.cls'] == \ + ('foo', '1.0', '/util/foo.html#module.cls') + + +def test_read_inventory_v2(): + f = StringIO(inventory_v2) + f.readline() + invdata1 = read_inventory_v2(f, '/util', posixpath.join) + + # try again with a small buffer size to test the chunking algorithm + f = StringIO(inventory_v2) + f.readline() + invdata2 = read_inventory_v2(f, '/util', posixpath.join, bufsize=5) + + assert invdata1 == invdata2 + + assert len(invdata1['py:module']) == 2 + assert invdata1['py:module']['module1'] == \ + ('foo', '2.0', '/util/foo.html#module-module1') + assert invdata1['py:module']['module2'] == \ + ('foo', '2.0', '/util/foo.html#module-module2') + assert invdata1['py:function']['module1.func'][2] == \ + '/util/sub/foo.html#module1.func' + assert invdata1['c:function']['CFunc'][2] == '/util/cfunc.html#CFunc' + + +@with_app(confoverrides={'extensions': 'sphinx.ext.intersphinx'}) +@with_tempdir +def test_missing_reference(tempdir, app): + inv_file = tempdir / 'inventory' + write_file(inv_file, inventory_v2) + app.config.intersphinx_mapping = {'http://docs.python.org/': inv_file} + app.config.intersphinx_cache_limit = 0 + + # load the inventory and check if it's done correctly + load_mappings(app) + inv = app.env.intersphinx_inventory + + assert inv['py:module']['module2'] == \ + ('foo', '2.0', 'http://docs.python.org/foo.html#module-module2') + + # create fake nodes and check referencing + contnode = nodes.emphasis('foo') + refnode = addnodes.pending_xref('') + refnode['reftarget'] = 'module1.func' + refnode['reftype'] = 'func' + refnode['refdomain'] = 'py' + + rn = missing_reference(app, app.env, refnode, contnode) + assert isinstance(rn, nodes.reference) + assert rn['refuri'] == 'http://docs.python.org/sub/foo.html#module1.func' + assert rn['reftitle'] == '(in foo v2.0)' + assert rn[0] is contnode + + # create unresolvable nodes and check None return value + refnode['reftype'] = 'foo' + assert missing_reference(app, app.env, refnode, contnode) is None + + refnode['reftype'] = 'function' + refnode['reftarget'] = 'foo.func' + assert missing_reference(app, app.env, refnode, contnode) is None diff --git a/tests/test_markup.py b/tests/test_markup.py index 03c421a1..22481953 100644 --- a/tests/test_markup.py +++ b/tests/test_markup.py @@ -29,6 +29,7 @@ def setup_module(): components=(rst.Parser, HTMLWriter, LaTeXWriter)) settings = optparser.get_default_values() settings.env = app.builder.env + settings.env.patch_lookup_functions() parser = rst.Parser() def teardown_module(): @@ -60,7 +61,7 @@ def verify_re(rst, html_expected, latex_expected): html_translator = ForgivingHTMLTranslator(app.builder, document) document.walkabout(html_translator) html_translated = ''.join(html_translator.fragment).strip() - assert re.match(html_expected, html_translated), 'from' + rst + assert re.match(html_expected, html_translated), 'from ' + rst if latex_expected: latex_translator = ForgivingLaTeXTranslator(document, app.builder) diff --git a/tests/util.py b/tests/util.py index 4bb6a653..ad0f6d7e 100644 --- a/tests/util.py +++ b/tests/util.py @@ -184,9 +184,9 @@ def gen_with_app(*args, **kwargs): def with_tempdir(func): - def new_func(): + def new_func(*args, **kwds): tempdir = path(tempfile.mkdtemp()) - func(tempdir) + func(tempdir, *args, **kwds) tempdir.rmtree() new_func.__name__ = func.__name__ return new_func |
