1"""
2    test_ext_graphviz
3    ~~~~~~~~~~~~~~~~~
4
5    Test sphinx.ext.graphviz extension.
6
7    :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
8    :license: BSD, see LICENSE for details.
9"""
10
11import re
12
13import pytest
14
15from sphinx.ext.graphviz import ClickableMapDefinition
16
17
18@pytest.mark.sphinx('html', testroot='ext-graphviz')
19@pytest.mark.usefixtures('if_graphviz_found')
20def test_graphviz_png_html(app, status, warning):
21    app.builder.build_all()
22
23    content = (app.outdir / 'index.html').read_text()
24    html = (r'<div class="figure align-default" .*?>\s*'
25            r'<div class="graphviz"><img .*?/></div>\s*<p class="caption">'
26            r'<span class="caption-text">caption of graph</span>.*</p>\s*</div>')
27    assert re.search(html, content, re.S)
28
29    html = 'Hello <div class="graphviz"><img .*?/></div>\n graphviz world'
30    assert re.search(html, content, re.S)
31
32    html = ('<img src=".*?" alt="digraph foo {\nbaz -&gt; qux\n}" '
33            'class="graphviz neato-graph" />')
34    assert re.search(html, content, re.S)
35
36    html = (r'<div class="figure align-right" .*?>\s*'
37            r'<div class="graphviz"><img .*?/></div>\s*<p class="caption">'
38            r'<span class="caption-text">on <em>right</em></span>.*</p>\s*</div>')
39    assert re.search(html, content, re.S)
40
41    html = (r'<div align=\"center\" class=\"align-center\">'
42            r'<div class="graphviz"><img src=\".*\.png\" alt=\"digraph foo {\n'
43            r'centered\n'
44            r'}\" class="graphviz" /></div>\n</div>')
45    assert re.search(html, content, re.S)
46
47
48@pytest.mark.sphinx('html', testroot='ext-graphviz',
49                    confoverrides={'graphviz_output_format': 'svg'})
50@pytest.mark.usefixtures('if_graphviz_found')
51def test_graphviz_svg_html(app, status, warning):
52    app.builder.build_all()
53
54    content = (app.outdir / 'index.html').read_text()
55
56    html = (r'<div class=\"figure align-default\" .*?>\n'
57            r'<div class="graphviz"><object data=\".*\.svg\".*>\n'
58            r'\s*<p class=\"warning\">digraph foo {\n'
59            r'bar -&gt; baz\n'
60            r'}</p></object></div>\n'
61            r'<p class=\"caption\"><span class=\"caption-text\">'
62            r'caption of graph</span>.*</p>\n</div>')
63    assert re.search(html, content, re.S)
64
65    html = (r'Hello <div class="graphviz"><object.*>\n'
66            r'\s*<p class=\"warning\">graph</p></object></div>\n'
67            r' graphviz world')
68    assert re.search(html, content, re.S)
69
70    html = (r'<div class=\"figure align-right\" .*\>\n'
71            r'<div class="graphviz"><object data=\".*\.svg\".*>\n'
72            r'\s*<p class=\"warning\">digraph bar {\n'
73            r'foo -&gt; bar\n'
74            r'}</p></object></div>\n'
75            r'<p class=\"caption\"><span class=\"caption-text\">'
76            r'on <em>right</em></span>.*</p>\n'
77            r'</div>')
78    assert re.search(html, content, re.S)
79
80    html = (r'<div align=\"center\" class=\"align-center\">'
81            r'<div class="graphviz"><object data=\".*\.svg\".*>\n'
82            r'\s*<p class=\"warning\">digraph foo {\n'
83            r'centered\n'
84            r'}</p></object></div>\n'
85            r'</div>')
86    assert re.search(html, content, re.S)
87
88
89@pytest.mark.sphinx('latex', testroot='ext-graphviz')
90@pytest.mark.usefixtures('if_graphviz_found')
91def test_graphviz_latex(app, status, warning):
92    app.builder.build_all()
93
94    content = (app.outdir / 'python.tex').read_text()
95    macro = ('\\\\begin{figure}\\[htbp\\]\n\\\\centering\n\\\\capstart\n\n'
96             '\\\\sphinxincludegraphics\\[\\]{graphviz-\\w+.pdf}\n'
97             '\\\\caption{caption of graph}\\\\label{.*}\\\\end{figure}')
98    assert re.search(macro, content, re.S)
99
100    macro = 'Hello \\\\sphinxincludegraphics\\[\\]{graphviz-\\w+.pdf} graphviz world'
101    assert re.search(macro, content, re.S)
102
103    macro = ('\\\\begin{wrapfigure}{r}{0pt}\n\\\\centering\n'
104             '\\\\sphinxincludegraphics\\[\\]{graphviz-\\w+.pdf}\n'
105             '\\\\caption{on \\\\sphinxstyleemphasis{right}}'
106             '\\\\label{.*}\\\\end{wrapfigure}')
107    assert re.search(macro, content, re.S)
108
109    macro = (r'\{\\hfill'
110             r'\\sphinxincludegraphics\[\]{graphviz-.*}'
111             r'\\hspace\*{\\fill}}')
112    assert re.search(macro, content, re.S)
113
114
115@pytest.mark.sphinx('html', testroot='ext-graphviz', confoverrides={'language': 'xx'})
116@pytest.mark.usefixtures('if_graphviz_found')
117def test_graphviz_i18n(app, status, warning):
118    app.builder.build_all()
119
120    content = (app.outdir / 'index.html').read_text()
121    html = '<img src=".*?" alt="digraph {\n  BAR -&gt; BAZ\n}" class="graphviz" />'
122    assert re.search(html, content, re.M)
123
124
125def test_graphviz_parse_mapfile():
126    # empty graph
127    code = ('# digraph {\n'
128            '# }\n')
129    content = ('<map id="%3" name="%3">\n'
130               '</map>')
131    cmap = ClickableMapDefinition('dummy.map', content, code)
132    assert cmap.filename == 'dummy.map'
133    assert cmap.id == 'grapvizb08107169e'
134    assert len(cmap.clickable) == 0
135    assert cmap.generate_clickable_map() == ''
136
137    # normal graph
138    code = ('digraph {\n'
139            '  foo [href="http://www.google.com/"];\n'
140            '  foo -> bar;\n'
141            '}\n')
142    content = ('<map id="%3" name="%3">\n'
143               '<area shape="poly" id="node1" href="http://www.google.com/" title="foo" alt=""'
144               ' coords="77,29,76,22,70,15,62,10,52,7,41,5,30,7,20,10,12,15,7,22,5,29,7,37,12,'
145               '43,20,49,30,52,41,53,52,52,62,49,70,43,76,37"/>\n'
146               '</map>')
147    cmap = ClickableMapDefinition('dummy.map', content, code)
148    assert cmap.filename == 'dummy.map'
149    assert cmap.id == 'grapviza4ccdd48ce'
150    assert len(cmap.clickable) == 1
151    assert cmap.generate_clickable_map() == content.replace('%3', cmap.id)
152
153    # inheritance-diagram:: sphinx.builders.html
154    content = (
155        '<map id="inheritance66ff5471b9" name="inheritance66ff5471b9">\n'
156        '<area shape="rect" id="node1" title="Builds target formats from the reST sources."'
157        ' alt="" coords="26,95,125,110"/>\n'
158        '<area shape="rect" id="node5" title="Builds standalone HTML docs."'
159        ' alt="" coords="179,95,362,110"/>\n'
160        '<area shape="rect" id="node2" title="buildinfo file manipulator." '
161        ' alt="" coords="14,64,138,80"/>\n'
162        '<area shape="rect" id="node3" title="The container of stylesheets."'
163        ' alt="" coords="3,34,148,49"/>\n'
164        '<area shape="rect" id="node4" title="A StandaloneHTMLBuilder that creates all HTML'
165        ' pages as &quot;index.html&quot; in" alt="" coords="395,64,569,80"/>\n'
166        '<area shape="rect" id="node7" title="An abstract builder that serializes'
167        ' the generated HTML." alt="" coords="392,95,571,110"/>\n'
168        '<area shape="rect" id="node9" title="A StandaloneHTMLBuilder subclass that puts'
169        ' the whole document tree on one" alt="" coords="393,125,570,141"/>\n'
170        '<area shape="rect" id="node6" title="A builder that dumps the generated HTML'
171        ' into JSON files." alt="" coords="602,80,765,95"/>\n'
172        '<area shape="rect" id="node8" title="A Builder that dumps the generated HTML'
173        ' into pickle files." alt="" coords="602,110,765,125"/>\n'
174        '<area shape="rect" id="node10" title="The metadata of stylesheet."'
175        ' alt="" coords="11,3,141,19"/>\n'
176        '</map>'
177    )
178    cmap = ClickableMapDefinition('dummy.map', content, 'dummy_code')
179    assert cmap.filename == 'dummy.map'
180    assert cmap.id == 'inheritance66ff5471b9'
181    assert len(cmap.clickable) == 0
182    assert cmap.generate_clickable_map() == ''
183