Skip to content

Commit 2994e6c

Browse files
committed
Add tests for DocAST.to_markdown/1 functionality
1 parent 512fac1 commit 2994e6c

File tree

2 files changed

+444
-6
lines changed

2 files changed

+444
-6
lines changed

test/ex_doc/doc_ast_test.exs

Lines changed: 173 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,179 @@ defmodule ExDoc.DocASTTest do
4747
end
4848
end
4949

50+
describe "to_markdown/1" do
51+
test "converts simple text" do
52+
assert DocAST.to_markdown("hello world") == "hello world"
53+
end
54+
55+
test "escapes HTML entities in text" do
56+
assert DocAST.to_markdown("<script>alert('xss')</script>") ==
57+
"&lt;script&gt;alert('xss')&lt;/script&gt;"
58+
59+
assert DocAST.to_markdown("Tom & Jerry") == "Tom &amp; Jerry"
60+
end
61+
62+
test "converts lists of elements" do
63+
ast = ["Hello ", "world", "!"]
64+
assert DocAST.to_markdown(ast) == "Hello world!"
65+
end
66+
67+
test "converts paragraphs" do
68+
ast = {:p, [], ["Hello world"], %{}}
69+
assert DocAST.to_markdown(ast) == "Hello world\n\n"
70+
end
71+
72+
test "converts multiple paragraphs" do
73+
ast = [
74+
{:p, [], ["First paragraph"], %{}},
75+
{:p, [], ["Second paragraph"], %{}}
76+
]
77+
78+
assert DocAST.to_markdown(ast) == "First paragraph\n\nSecond paragraph\n\n"
79+
end
80+
81+
test "converts code blocks with language" do
82+
ast = {:code, [class: "elixir"], "defmodule Test do\n def hello, do: :world\nend", %{}}
83+
expected = "```elixir\ndefmodule Test do\n def hello, do: :world\nend\n```\n"
84+
assert DocAST.to_markdown(ast) == expected
85+
end
86+
87+
test "converts code blocks without language" do
88+
ast = {:code, [], "some code", %{}}
89+
assert DocAST.to_markdown(ast) == "```\nsome code\n```\n"
90+
end
91+
92+
test "converts inline code with class attribute" do
93+
ast = {:code, [class: "language-elixir"], "IO.puts", %{}}
94+
expected = "```language-elixir\nIO.puts\n```\n"
95+
assert DocAST.to_markdown(ast) == expected
96+
end
97+
98+
test "converts links" do
99+
ast = {:a, [href: "https://example.com"], ["Example"], %{}}
100+
assert DocAST.to_markdown(ast) == "[Example](https://example.com)"
101+
end
102+
103+
test "converts links with nested content" do
104+
ast = {:a, [href: "/docs"], [{:code, [], ["API"], %{}}], %{}}
105+
assert DocAST.to_markdown(ast) == "[```\nAPI\n```\n](/docs)"
106+
end
107+
108+
test "converts images with alt and title" do
109+
ast = {:img, [src: "image.png", alt: "Alt text", title: "Title"], [], %{}}
110+
assert DocAST.to_markdown(ast) == "![Alt text](image.png \"Title\")"
111+
end
112+
113+
test "converts images with missing attributes" do
114+
ast = {:img, [src: "image.png"], [], %{}}
115+
assert DocAST.to_markdown(ast) == "![](image.png \"\")"
116+
end
117+
118+
test "converts horizontal rules" do
119+
ast = {:hr, [], [], %{}}
120+
assert DocAST.to_markdown(ast) == "\n\n---\n\n"
121+
end
122+
123+
test "converts line breaks" do
124+
ast = {:br, [], [], %{}}
125+
assert DocAST.to_markdown(ast) == "\n\n"
126+
end
127+
128+
test "converts comments" do
129+
ast = {:comment, [], [" This is a comment "], %{}}
130+
assert DocAST.to_markdown(ast) == "<!-- This is a comment -->"
131+
end
132+
133+
test "handles void elements" do
134+
void_elements = [
135+
:area,
136+
:base,
137+
:col,
138+
:embed,
139+
:input,
140+
:link,
141+
:meta,
142+
:param,
143+
:source,
144+
:track,
145+
:wbr
146+
]
147+
148+
for element <- void_elements do
149+
ast = {element, [], [], %{}}
150+
assert DocAST.to_markdown(ast) == ""
151+
end
152+
end
153+
154+
test "handles verbatim content" do
155+
ast = {:pre, [], [" verbatim \n content "], %{verbatim: true}}
156+
assert DocAST.to_markdown(ast) == " verbatim \n content "
157+
end
158+
159+
test "converts nested structures" do
160+
ast = {:p, [], ["Hello ", {:strong, [], ["world"], %{}}, "!"], %{}}
161+
162+
result = DocAST.to_markdown(ast)
163+
assert result =~ "Hello"
164+
assert result =~ "world"
165+
assert result =~ "!"
166+
assert String.ends_with?(result, "\n\n")
167+
end
168+
169+
test "handles unknown elements by extracting content" do
170+
ast = {:custom_element, [class: "special"], ["Content"], %{}}
171+
assert DocAST.to_markdown(ast) == "Content"
172+
end
173+
174+
test "handles complex nested document" do
175+
ast = [
176+
{:h1, [], ["Main Title"], %{}},
177+
{:p, [], ["Introduction paragraph with ", {:a, [href: "/link"], ["a link"], %{}}], %{}},
178+
{:code, [class: "elixir"], "IO.puts \"Hello\"", %{}},
179+
{:hr, [], [], %{}},
180+
{:p, [], ["Final paragraph"], %{}}
181+
]
182+
183+
result = DocAST.to_markdown(ast)
184+
185+
assert result =~ "Main Title"
186+
assert result =~ "Introduction paragraph with [a link](/link)"
187+
assert result =~ "```elixir\nIO.puts \"Hello\"\n```\n"
188+
assert result =~ "\n\n---\n\n"
189+
assert result =~ "Final paragraph\n\n"
190+
end
191+
192+
test "handles empty content gracefully" do
193+
assert DocAST.to_markdown([]) == ""
194+
assert DocAST.to_markdown({:p, [], [], %{}}) == "\n\n"
195+
end
196+
197+
test "preserves whitespace in code blocks" do
198+
code_content = " def hello do\n :world\n end"
199+
ast = {:code, [class: "elixir"], code_content, %{}}
200+
result = DocAST.to_markdown(ast)
201+
202+
assert result =~ "```elixir"
203+
assert String.contains?(result, code_content)
204+
assert result =~ "```"
205+
end
206+
207+
test "handles mixed content types" do
208+
ast = [
209+
"Plain text",
210+
{:p, [], ["Paragraph text"], %{}},
211+
{:code, [], "code", %{}},
212+
"More plain text"
213+
]
214+
215+
result = DocAST.to_markdown(ast)
216+
assert result =~ "Plain text"
217+
assert result =~ "Paragraph text\n\n"
218+
assert result =~ "```\ncode\n```\n"
219+
assert result =~ "More plain text"
220+
end
221+
end
222+
50223
describe "to_string/2" do
51224
test "simple" do
52225
markdown = """
@@ -161,21 +334,18 @@ defmodule ExDoc.DocASTTest do
161334

162335
describe "highlight" do
163336
test "with default class" do
164-
# Four spaces
165337
assert highlight("""
166338
mix run --no-halt path/to/file.exs
167339
""") =~
168340
~r{<pre><code class=\"makeup elixir\" translate="no">.*}
169341

170-
# Code block without language
171342
assert highlight("""
172343
```
173344
mix run --no-halt path/to/file.exs</code></pre>
174345
```
175346
""") =~
176347
~r{<pre><code class=\"makeup elixir\" translate="no">.*}
177348

178-
# Pre IAL
179349
assert highlight("""
180350
```
181351
mix run --no-halt path/to/file.exs</code></pre>
@@ -184,23 +354,20 @@ defmodule ExDoc.DocASTTest do
184354
""") =~
185355
~r{<pre class="wrap"><code class=\"makeup elixir\" translate="no">.*}
186356

187-
# Code with language
188357
assert highlight("""
189358
```html
190359
<foo />
191360
```
192361
""") =~
193362
~r{<pre><code class=\"makeup html\" translate="no">.*}
194363

195-
# Code with shell detection
196364
assert highlight("""
197365
```
198366
$ hello
199367
```
200368
""") =~
201369
~r{<pre><code class=\"makeup shell\" translate="no"><span class="gp unselectable">\$.*}
202370

203-
# Nested in another element
204371
assert highlight("""
205372
> ```elixir
206373
> hello

0 commit comments

Comments
 (0)