Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions confluence_markdown_exporter/utils/table_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,16 +77,18 @@ def convert_table(self, el: BeautifulSoup, text: str, parent_tags: list[str]) ->

def convert_th(self, el: BeautifulSoup, text: str, parent_tags: list[str]) -> str:
"""This method is empty because we want a No-Op for the <th> tag."""
# return the html as is
return text
# return the html as is, but escape pipe characters
return text.replace("|", "\\|")

def convert_tr(self, el: BeautifulSoup, text: str, parent_tags: list[str]) -> str:
"""This method is empty because we want a No-Op for the <tr> tag."""
return text

def convert_td(self, el: BeautifulSoup, text: str, parent_tags: list[str]) -> str:
"""This method is empty because we want a No-Op for the <td> tag."""
return text.replace("\n", "<br/>").removesuffix("<br/>").removeprefix("<br/>")
# Escape pipe characters to prevent them from being interpreted as column separators
return (text.replace("|", "\\|").replace("\n", "<br/>").removesuffix("<br/>")
.removeprefix("<br/>"))

def convert_thead(self, el: BeautifulSoup, text: str, parent_tags: list[str]) -> str:
"""This method is empty because we want a No-Op for the <thead> tag."""
Expand Down
109 changes: 109 additions & 0 deletions tests/unit/utils/test_table_converter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
"""Tests for the table_converter module."""

from bs4 import BeautifulSoup

from confluence_markdown_exporter.utils.table_converter import TableConverter


class TestTableConverter:
"""Test TableConverter class."""

def test_pipe_character_in_cell(self) -> None:
"""Test that pipe characters are escaped in table cells."""
html = """
<table>
<tr>
<th>Column 1</th>
<th>Column 2</th>
</tr>
<tr>
<td>Value with | pipe</td>
<td>Normal value</td>
</tr>
</table>
"""
BeautifulSoup(html, "html.parser")
converter = TableConverter()
result = converter.convert(html)

# The pipe character should be escaped
assert "\\|" in result
# The result should still have proper table structure
assert "Column 1" in result
assert "Column 2" in result
assert "Value with" in result
assert "pipe" in result

def test_multiple_pipes_in_cell(self) -> None:
"""Test that multiple pipe characters are escaped in table cells."""
html = """
<table>
<tr>
<th>Header</th>
</tr>
<tr>
<td>Value | with | multiple | pipes</td>
</tr>
</table>
"""
BeautifulSoup(html, "html.parser")
converter = TableConverter()
result = converter.convert(html)

# All pipe characters should be escaped (3 pipes in the content)
assert result.count("\\|") == 3
assert "Value" in result
assert "with" in result
assert "multiple" in result
assert "pipes" in result

def test_pipe_character_in_header(self) -> None:
"""Test that pipe characters are escaped in table header cells."""
html = """
<table>
<tr>
<th>Column | 1</th>
<th>Column | 2</th>
</tr>
<tr>
<td>Value 1</td>
<td>Value 2</td>
</tr>
</table>
"""
converter = TableConverter()
result = converter.convert(html)

# The pipe characters in headers should be escaped (2 pipes)
assert result.count("\\|") == 2
assert "Column" in result
assert "Value 1" in result
assert "Value 2" in result

def test_table_without_pipes(self) -> None:
"""Test normal table conversion without pipe characters."""
html = """
<table>
<tr>
<th>Name</th>
<th>Age</th>
</tr>
<tr>
<td>John</td>
<td>30</td>
</tr>
</table>
"""
converter = TableConverter()
result = converter.convert(html)

assert "Name" in result
assert "Age" in result
assert "John" in result
assert "30" in result
# Should have proper table structure
assert "|" in result
assert "---" in result
# Should have no escaped pipes
assert "\\|" not in result