From bfa82f6bb3bebb13e961ac79e6e6ae19cbde3273 Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Wed, 23 Oct 2024 21:12:25 +0200
Subject: [PATCH] Add test coverage of title line breaks, and don't break
markdown titles
---
novelwriter/formats/tomarkdown.py | 10 +-
tests/test_formats/test_fmt_todocx.py | 228 ++++++++++++++--------
tests/test_formats/test_fmt_tohtml.py | 20 +-
tests/test_formats/test_fmt_tomarkdown.py | 16 +-
tests/test_formats/test_fmt_toodt.py | 20 +-
5 files changed, 185 insertions(+), 109 deletions(-)
diff --git a/novelwriter/formats/tomarkdown.py b/novelwriter/formats/tomarkdown.py
index 198b7e7a..db1627be 100644
--- a/novelwriter/formats/tomarkdown.py
+++ b/novelwriter/formats/tomarkdown.py
@@ -113,23 +113,23 @@ class ToMarkdown(Tokenizer):
lines.append(f"{tTemp}\n\n")
elif tType == BlockTyp.TITLE:
- tHead = tText.replace(nwHeadFmt.BR, "\n")
+ tHead = tText.replace(nwHeadFmt.BR, " - ")
lines.append(f"# {tHead}\n\n")
elif tType == BlockTyp.HEAD1:
- tHead = tText.replace(nwHeadFmt.BR, "\n")
+ tHead = tText.replace(nwHeadFmt.BR, " - ")
lines.append(f"# {tHead}\n\n")
elif tType == BlockTyp.HEAD2:
- tHead = tText.replace(nwHeadFmt.BR, "\n")
+ tHead = tText.replace(nwHeadFmt.BR, " - ")
lines.append(f"## {tHead}\n\n")
elif tType == BlockTyp.HEAD3:
- tHead = tText.replace(nwHeadFmt.BR, "\n")
+ tHead = tText.replace(nwHeadFmt.BR, " - ")
lines.append(f"### {tHead}\n\n")
elif tType == BlockTyp.HEAD4:
- tHead = tText.replace(nwHeadFmt.BR, "\n")
+ tHead = tText.replace(nwHeadFmt.BR, " - ")
lines.append(f"#### {tHead}\n\n")
elif tType == BlockTyp.SEP:
diff --git a/tests/test_formats/test_fmt_todocx.py b/tests/test_formats/test_fmt_todocx.py
index a9214db9..d395eaee 100644
--- a/tests/test_formats/test_fmt_todocx.py
+++ b/tests/test_formats/test_fmt_todocx.py
@@ -32,10 +32,7 @@ from novelwriter.core.docbuild import NWBuildDocument
from novelwriter.core.project import NWProject
from novelwriter.enum import nwBuildFmt
from novelwriter.formats.shared import BlockFmt, BlockTyp
-from novelwriter.formats.todocx import (
- S_FNOTE, S_HEAD1, S_HEAD2, S_HEAD3, S_HEAD4, S_META, S_NORM, S_SEP,
- S_TITLE, ToDocX, _mkTag, _wTag
-)
+from novelwriter.formats.todocx import ToDocX, _mkTag, _wTag
from tests.tools import DOCX_IGNORE, cmpFiles
@@ -59,6 +56,120 @@ def xmlToText(xElem):
return rTxt
+@pytest.mark.core
+def testFmtToDocX_HeadingStyles(mockGUI):
+ """Test formatting of headings."""
+ project = NWProject()
+ doc = ToDocX(project)
+ doc._isNovel = True
+ doc.initDocument()
+
+ # Title
+ # =====
+
+ xTest = ET.Element(_wTag("body"))
+ doc._text = "#! Hello World"
+ doc.tokenizeText()
+ doc.doConvert()
+ doc._pars[-1].toXml(xTest)
+ assert xmlToText(xTest) == (
+ ''
+ 'Hello World'
+ )
+
+ # Heading Level 1
+ # ===============
+ doc._text = "# Hello World"
+
+ # Plain
+ xTest = ET.Element(_wTag("body"))
+ doc.tokenizeText()
+ doc.doConvert()
+ doc._pars[-1].toXml(xTest)
+ assert xmlToText(xTest) == (
+ ''
+ ''
+ 'Hello World'
+ )
+
+ # Formatted
+ xTest = ET.Element(_wTag("body"))
+ doc.setPartitionFormat(f"Part{nwHeadFmt.BR}{nwHeadFmt.TITLE}")
+ doc.tokenizeText()
+ doc.doConvert()
+ doc._pars[-1].toXml(xTest)
+ assert xmlToText(xTest) == (
+ ''
+ ''
+ 'PartHello World'
+ )
+
+ # Heading Level 2
+ # ===============
+ doc._text = "## Hello World"
+
+ # Plain
+ xTest = ET.Element(_wTag("body"))
+ doc.tokenizeText()
+ doc.doConvert()
+ doc._pars[-1].toXml(xTest)
+ assert xmlToText(xTest) == (
+ ''
+ ''
+ 'Hello World'
+ )
+
+ # Formatted
+ xTest = ET.Element(_wTag("body"))
+ doc.setChapterFormat(f"Chapter {nwHeadFmt.CH_NUM}{nwHeadFmt.BR}{nwHeadFmt.TITLE}")
+ doc.tokenizeText()
+ doc.doConvert()
+ doc._pars[-1].toXml(xTest)
+ assert xmlToText(xTest) == (
+ ''
+ ''
+ 'Chapter 2Hello World'
+ )
+
+ # Heading Level 3
+ # ===============
+ doc._text = "### Hello World"
+
+ # Plain
+ xTest = ET.Element(_wTag("body"))
+ doc.tokenizeText()
+ doc.doConvert()
+ doc._pars[-1].toXml(xTest)
+ assert xmlToText(xTest) == (
+ ''
+ 'Hello World'
+ )
+
+ # Formatted
+ xTest = ET.Element(_wTag("body"))
+ doc.setSceneFormat(f"Scene {nwHeadFmt.SC_ABS}{nwHeadFmt.BR}{nwHeadFmt.TITLE}")
+ doc.tokenizeText()
+ doc.doConvert()
+ doc._pars[-1].toXml(xTest)
+ assert xmlToText(xTest) == (
+ ''
+ 'Scene 2Hello World'
+ )
+
+ # Heading Level 4
+ # ===============
+ doc._text = "#### Hello World"
+
+ xTest = ET.Element(_wTag("body"))
+ doc.tokenizeText()
+ doc.doConvert()
+ doc._pars[-1].toXml(xTest)
+ assert xmlToText(xTest) == (
+ ''
+ 'Hello World'
+ )
+
+
@pytest.mark.core
def testFmtToDocX_ParagraphStyles(mockGUI):
"""Test formatting of paragraphs."""
@@ -71,61 +182,12 @@ def testFmtToDocX_ParagraphStyles(mockGUI):
# Normal Text
xTest = ET.Element(_wTag("body"))
- doc._blocks = [(BlockTyp.TEXT, "", "Hello World", [], BlockFmt.NONE)]
+ doc._text = "Hello World"
+ doc.tokenizeText()
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
- f''
- 'Hello World'
- )
-
- # Title
- xTest = ET.Element(_wTag("body"))
- doc._blocks = [(BlockTyp.TITLE, "", "Hello World", [], BlockFmt.NONE)]
- doc.doConvert()
- doc._pars[-1].toXml(xTest)
- assert xmlToText(xTest) == (
- f''
- 'Hello World'
- )
-
- # Heading Level 1
- xTest = ET.Element(_wTag("body"))
- doc._blocks = [(BlockTyp.HEAD1, "", "Hello World", [], BlockFmt.NONE)]
- doc.doConvert()
- doc._pars[-1].toXml(xTest)
- assert xmlToText(xTest) == (
- f''
- 'Hello World'
- )
-
- # Heading Level 2
- xTest = ET.Element(_wTag("body"))
- doc._blocks = [(BlockTyp.HEAD2, "", "Hello World", [], BlockFmt.NONE)]
- doc.doConvert()
- doc._pars[-1].toXml(xTest)
- assert xmlToText(xTest) == (
- f''
- 'Hello World'
- )
-
- # Heading Level 3
- xTest = ET.Element(_wTag("body"))
- doc._blocks = [(BlockTyp.HEAD3, "", "Hello World", [], BlockFmt.NONE)]
- doc.doConvert()
- doc._pars[-1].toXml(xTest)
- assert xmlToText(xTest) == (
- f''
- 'Hello World'
- )
-
- # Heading Level 4
- xTest = ET.Element(_wTag("body"))
- doc._blocks = [(BlockTyp.HEAD4, "", "Hello World", [], BlockFmt.NONE)]
- doc.doConvert()
- doc._pars[-1].toXml(xTest)
- assert xmlToText(xTest) == (
- f''
+ ''
'Hello World'
)
@@ -135,7 +197,7 @@ def testFmtToDocX_ParagraphStyles(mockGUI):
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
- f''
+ ''
'* * *'
)
@@ -145,7 +207,7 @@ def testFmtToDocX_ParagraphStyles(mockGUI):
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
- f''
+ ''
)
# Synopsis
@@ -155,7 +217,7 @@ def testFmtToDocX_ParagraphStyles(mockGUI):
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
- f''
+ ''
'Synopsis:'
' '
'Hello World'
@@ -169,7 +231,7 @@ def testFmtToDocX_ParagraphStyles(mockGUI):
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
- f''
+ ''
'Short Description:'
' '
'Hello World'
@@ -183,7 +245,7 @@ def testFmtToDocX_ParagraphStyles(mockGUI):
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
- f''
+ ''
'Comment:'
' '
'Hello World'
@@ -197,7 +259,7 @@ def testFmtToDocX_ParagraphStyles(mockGUI):
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
- f''
+ ''
'Tag:'
' '
'Stuff'
@@ -211,7 +273,7 @@ def testFmtToDocX_ParagraphStyles(mockGUI):
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
- f''
+ ''
'Characters:'
' '
'Jane'
@@ -245,7 +307,7 @@ def testFmtToDocX_ParagraphFormatting(mockGUI):
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
- f''
+ ''
'Hello World'
)
@@ -255,7 +317,7 @@ def testFmtToDocX_ParagraphFormatting(mockGUI):
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
- f''
+ ''
'Hello World'
)
@@ -265,7 +327,7 @@ def testFmtToDocX_ParagraphFormatting(mockGUI):
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
- f''
+ ''
'Hello World'
)
@@ -275,7 +337,7 @@ def testFmtToDocX_ParagraphFormatting(mockGUI):
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
- f''
+ ''
'Hello World'
)
@@ -285,7 +347,7 @@ def testFmtToDocX_ParagraphFormatting(mockGUI):
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
- f''
+ ''
''
'Hello World'
''
@@ -297,7 +359,7 @@ def testFmtToDocX_ParagraphFormatting(mockGUI):
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
- f''
+ ''
'Hello World'
''
''
@@ -309,7 +371,7 @@ def testFmtToDocX_ParagraphFormatting(mockGUI):
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
- f''
+ ''
''
'Hello World'
)
@@ -320,7 +382,7 @@ def testFmtToDocX_ParagraphFormatting(mockGUI):
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
- f''
+ ''
''
'Hello World'
)
@@ -331,7 +393,7 @@ def testFmtToDocX_ParagraphFormatting(mockGUI):
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
- f''
+ ''
''
'Hello World'
)
@@ -351,7 +413,7 @@ def testFmtToDocX_TextFormatting(mockGUI):
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
- f''
+ ''
'Text '
'bold'
', '
@@ -369,7 +431,7 @@ def testFmtToDocX_TextFormatting(mockGUI):
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
- f''
+ ''
'Some '
'nested '
'bold'
@@ -389,7 +451,7 @@ def testFmtToDocX_TextFormatting(mockGUI):
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
- f''
+ ''
'Some super'
'script'
' and sub'
@@ -405,7 +467,7 @@ def testFmtToDocX_TextFormatting(mockGUI):
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
- f''
+ ''
'Some '
''
'underlined and '
@@ -422,7 +484,7 @@ def testFmtToDocX_TextFormatting(mockGUI):
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
- f''
+ ''
'Some text.Next line'
''
)
@@ -434,7 +496,7 @@ def testFmtToDocX_TextFormatting(mockGUI):
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
- f''
+ ''
'Item 1Item 2'
''
)
@@ -446,7 +508,7 @@ def testFmtToDocX_TextFormatting(mockGUI):
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
- f''
+ ''
'Some '
'boldtext'
''
@@ -474,7 +536,7 @@ def testFmtToDocX_Footnotes(mockGUI):
doc.doConvert()
doc._pars[-1].toXml(xTest)
assert xmlToText(xTest) == (
- f''
+ ''
'Text with one'
''
''
@@ -493,11 +555,11 @@ def testFmtToDocX_Footnotes(mockGUI):
doc._footnotesXml()
assert xmlToText(doc._files["footnotes.xml"].xml) == (
''
- f''
+ ''
'Footnote text A.'
- f''
+ ''
'Another footnote.'
- f''
+ ''
'Again?'
''
)
diff --git a/tests/test_formats/test_fmt_tohtml.py b/tests/test_formats/test_fmt_tohtml.py
index 68db421c..ac5abbec 100644
--- a/tests/test_formats/test_fmt_tohtml.py
+++ b/tests/test_formats/test_fmt_tohtml.py
@@ -25,6 +25,7 @@ import json
import pytest
from novelwriter import CONFIG
+from novelwriter.constants import nwHeadFmt
from novelwriter.core.project import NWProject
from novelwriter.formats.shared import BlockFmt, BlockTyp
from novelwriter.formats.tohtml import ToHtml
@@ -44,32 +45,35 @@ def testFmtToHtml_ConvertHeaders(mockGUI):
html._isFirst = True
# Header 1
- html._text = "# Partition\n"
+ html._text = "# Title\n"
+ html.setPartitionFormat(f"Part{nwHeadFmt.BR}{nwHeadFmt.TITLE}")
html.tokenizeText()
html.doConvert()
assert html._pages[-1] == (
- "Partition
\n"
+ "Part
Title
\n"
)
# Header 2
- html._text = "## Chapter Title\n"
+ html._text = "## Title\n"
+ html.setChapterFormat(f"Chapter {nwHeadFmt.CH_NUM}{nwHeadFmt.BR}{nwHeadFmt.TITLE}")
html.tokenizeText()
html.doConvert()
assert html._pages[-1] == (
- "Chapter Title
\n"
+ "Chapter 1
Title
\n"
)
# Header 3
- html._text = "### Scene Title\n"
+ html._text = "### Title\n"
+ html.setSceneFormat(f"Scene {nwHeadFmt.SC_ABS}{nwHeadFmt.BR}{nwHeadFmt.TITLE}")
html.tokenizeText()
html.doConvert()
- assert html._pages[-1] == "Scene Title
\n"
+ assert html._pages[-1] == "Scene 1
Title
\n"
# Header 4
- html._text = "#### Section Title\n"
+ html._text = "#### Title\n"
html.tokenizeText()
html.doConvert()
- assert html._pages[-1] == "Section Title
\n"
+ assert html._pages[-1] == "Title
\n"
# Title
html._text = "#! Title\n"
diff --git a/tests/test_formats/test_fmt_tomarkdown.py b/tests/test_formats/test_fmt_tomarkdown.py
index ad0633ae..e94f4b72 100644
--- a/tests/test_formats/test_fmt_tomarkdown.py
+++ b/tests/test_formats/test_fmt_tomarkdown.py
@@ -22,6 +22,7 @@ from __future__ import annotations
import pytest
+from novelwriter.constants import nwHeadFmt
from novelwriter.core.project import NWProject
from novelwriter.formats.shared import BlockFmt, BlockTyp
from novelwriter.formats.tomarkdown import ToMarkdown
@@ -37,22 +38,25 @@ def testFmtToMarkdown_ConvertHeaders(mockGUI):
md._isFirst = True
# Header 1
- md._text = "# Partition\n"
+ md._text = "# Title\n"
+ md.setPartitionFormat(f"Part{nwHeadFmt.BR}{nwHeadFmt.TITLE}")
md.tokenizeText()
md.doConvert()
- assert md._pages[-1] == "# Partition\n\n"
+ assert md._pages[-1] == "# Part - Title\n\n"
# Header 2
- md._text = "## Chapter Title\n"
+ md._text = "## Title\n"
+ md.setChapterFormat(f"Chapter {nwHeadFmt.CH_NUM}{nwHeadFmt.BR}{nwHeadFmt.TITLE}")
md.tokenizeText()
md.doConvert()
- assert md._pages[-1] == "## Chapter Title\n\n"
+ assert md._pages[-1] == "## Chapter 1 - Title\n\n"
# Header 3
- md._text = "### Scene Title\n"
+ md._text = "### Title\n"
+ md.setSceneFormat(f"Scene {nwHeadFmt.SC_ABS}{nwHeadFmt.BR}{nwHeadFmt.TITLE}")
md.tokenizeText()
md.doConvert()
- assert md._pages[-1] == "### Scene Title\n\n"
+ assert md._pages[-1] == "### Scene 1 - Title\n\n"
# Header 4
md._text = "#### Section Title\n"
diff --git a/tests/test_formats/test_fmt_toodt.py b/tests/test_formats/test_fmt_toodt.py
index 0da42138..fedb5f2a 100644
--- a/tests/test_formats/test_fmt_toodt.py
+++ b/tests/test_formats/test_fmt_toodt.py
@@ -281,6 +281,7 @@ def testFmtToOdt_ConvertHeaders(mockGUI):
# Header 1
odt._text = "# Title\n"
+ odt.setPartitionFormat(f"Part{nwHeadFmt.BR}{nwHeadFmt.TITLE}")
odt.tokenizeText()
odt.initDocument()
odt.doConvert()
@@ -288,12 +289,14 @@ def testFmtToOdt_ConvertHeaders(mockGUI):
assert odt.errData == []
assert xmlToText(odt._xText) == (
''
- 'Title'
+ 'Part'
+ 'Title'
''
)
# Header 2
- odt._text = "## Chapter\n"
+ odt._text = "## Title\n"
+ odt.setChapterFormat(f"Chapter {nwHeadFmt.CH_NUM}{nwHeadFmt.BR}{nwHeadFmt.TITLE}")
odt.tokenizeText()
odt.initDocument()
odt.doConvert()
@@ -301,12 +304,14 @@ def testFmtToOdt_ConvertHeaders(mockGUI):
assert odt.errData == []
assert xmlToText(odt._xText) == (
''
- 'Chapter'
+ 'Chapter 1'
+ 'Title'
''
)
# Header 3
- odt._text = "### Scene\n"
+ odt._text = "### Title\n"
+ odt.setSceneFormat(f"Scene {nwHeadFmt.SC_ABS}{nwHeadFmt.BR}{nwHeadFmt.TITLE}")
odt.tokenizeText()
odt.initDocument()
odt.doConvert()
@@ -314,12 +319,13 @@ def testFmtToOdt_ConvertHeaders(mockGUI):
assert odt.errData == []
assert xmlToText(odt._xText) == (
''
- 'Scene'
+ 'Scene 1'
+ 'Title'
''
)
# Header 4
- odt._text = "#### Section\n"
+ odt._text = "#### Title\n"
odt.tokenizeText()
odt.initDocument()
odt.doConvert()
@@ -327,7 +333,7 @@ def testFmtToOdt_ConvertHeaders(mockGUI):
assert odt.errData == []
assert xmlToText(odt._xText) == (
''
- 'Section'
+ 'Title'
''
)