Update test coverage

This commit is contained in:
Veronica Berglyd Olsen
2024-10-30 00:08:31 +01:00
parent 3749c9f21d
commit 3d935e29eb
13 changed files with 206 additions and 97 deletions
-1
View File
@@ -903,7 +903,6 @@ class ToDocX(Tokenizer):
"""Populate document.xml.""" """Populate document.xml."""
rId = self._nextRelId() rId = self._nextRelId()
xRoot = xmlElement(_wTag("document")) xRoot = xmlElement(_wTag("document"))
xRoot.set("xmlns:w14", "http://schemas.microsoft.com/office/word/2010/wordml")
xBody = xmlSubElem(xRoot, _wTag("body")) xBody = xmlSubElem(xRoot, _wTag("body"))
self._rels["document.xml"] = DocXXmlRel( self._rels["document.xml"] = DocXXmlRel(
rId=rId, rId=rId,
+2 -6
View File
@@ -2065,12 +2065,8 @@ class GuiDocEditor(QPlainTextEdit):
feature for French, Spanish, etc, so it doesn't insert a feature for French, Spanish, etc, so it doesn't insert a
space before colons in meta data lines. See issue #1090. space before colons in meta data lines. See issue #1090.
""" """
if char == ":" and len(text) > 1: if char == ":" and len(text) > 1 and text[0] == "@":
if text[0] == "@": return False
return False
if text[0] == "%":
if text[1:].lstrip()[:9].lower() == "synopsis:":
return False
return True return True
def _autoSelect(self) -> QTextCursor: def _autoSelect(self) -> QTextCursor:
@@ -1,13 +1,13 @@
<?xml version='1.0' encoding='utf-8'?> <?xml version='1.0' encoding='utf-8'?>
<office:document xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text"> <office:document xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text">
<office:meta> <office:meta>
<meta:creation-date>2024-10-29T09:33:22</meta:creation-date> <meta:creation-date>2024-10-29T23:24:19</meta:creation-date>
<meta:generator>novelWriter/2.6a3</meta:generator> <meta:generator>novelWriter/2.6a3</meta:generator>
<meta:initial-creator>Jane Smith</meta:initial-creator> <meta:initial-creator>Jane Smith</meta:initial-creator>
<meta:editing-cycles>1234</meta:editing-cycles> <meta:editing-cycles>1234</meta:editing-cycles>
<meta:editing-duration>P42DT12H34M56S</meta:editing-duration> <meta:editing-duration>P42DT12H34M56S</meta:editing-duration>
<dc:title>Test Project</dc:title> <dc:title>Test Project</dc:title>
<dc:date>2024-10-29T09:33:22</dc:date> <dc:date>2024-10-29T23:24:19</dc:date>
<dc:creator>Jane Smith</dc:creator> <dc:creator>Jane Smith</dc:creator>
</office:meta> </office:meta>
<office:font-face-decls> <office:font-face-decls>
@@ -82,6 +82,12 @@
<style:style style:name="P1" style:family="paragraph" style:parent-style-name="Heading_20_2"> <style:style style:name="P1" style:family="paragraph" style:parent-style-name="Heading_20_2">
<style:paragraph-properties fo:break-before="page" /> <style:paragraph-properties fo:break-before="page" />
</style:style> </style:style>
<style:style style:name="T1" style:family="text">
<style:text-properties fo:font-weight="bold" />
</style:style>
<style:style style:name="T2" style:family="text">
<style:text-properties fo:color="#4271ae" style:text-underline-style="solid" style:text-underline-width="auto" style:text-underline-color="font-color" />
</style:style>
</office:automatic-styles> </office:automatic-styles>
<office:master-styles> <office:master-styles>
<style:master-page style:name="Standard" style:page-layout-name="PM1"> <style:master-page style:name="Standard" style:page-layout-name="PM1">
@@ -95,10 +101,30 @@
</office:master-styles> </office:master-styles>
<office:body> <office:body>
<office:text> <office:text>
<text:h text:style-name="Heading_20_2" text:outline-level="2">Chapter One</text:h> <text:user-field-decls>
<text:p text:style-name="Text_20_body">Text</text:p> <text:user-field-decl office:value-type="float" office:value="3" text:name="ManuscriptTitleCount" />
<text:user-field-decl office:value-type="float" office:value="3" text:name="ManuscriptParagraphCount" />
<text:user-field-decl office:value-type="float" office:value="217" text:name="ManuscriptAllWords" />
<text:user-field-decl office:value-type="float" office:value="211" text:name="ManuscriptTextWords" />
<text:user-field-decl office:value-type="float" office:value="6" text:name="ManuscriptTitleWords" />
<text:user-field-decl office:value-type="float" office:value="1471" text:name="ManuscriptAllChars" />
<text:user-field-decl office:value-type="float" office:value="1441" text:name="ManuscriptTextChars" />
<text:user-field-decl office:value-type="float" office:value="30" text:name="ManuscriptTitleChars" />
<text:user-field-decl office:value-type="float" office:value="1258" text:name="ManuscriptAllWordChars" />
<text:user-field-decl office:value-type="float" office:value="1231" text:name="ManuscriptTextWordChars" />
<text:user-field-decl office:value-type="float" office:value="27" text:name="ManuscriptTitleWordChars" />
</text:user-field-decls>
<text:p text:style-name="Title">My Novel</text:p>
<text:p text:style-name="Text_20_body"><text:span text:style-name="T1">Word Count: </text:span><text:span text:style-name="T1"><text:user-field-get style:data-style-name="N0" text:name="ManuscriptAllWords">0</text:user-field-get></text:span><text:line-break /><text:user-field-get style:data-style-name="N0" text:name="ManuscriptParagraphCount">0</text:user-field-get> paragrphs<text:line-break />Web: <text:a xlink:type="simple" xlink:href="http://example.com" text:style-name="T2">http://example.com</text:a></text:p>
<text:h text:style-name="P1" text:outline-level="2">Chapter One</text:h>
<text:p text:style-name="Text_20_body">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc maximus justo non dictum commodo. Curabitur lacinia tempor orci vel luctus. Phasellus porta metus eu massa luctus, eget euismod risus rhoncus. Vestibulum sed arcu nisi. Maecenas pretium facilisis velit, vel semper lacus aliquam sit amet. Vestibulum vulputate neque ligula, rhoncus blandit turpis consequat id. Mauris sagittis vehicula imperdiet. Duis sed nunc pretium, ornare purus vel, sodales augue. Maecenas a suscipit risus. Quisque volutpat justo eleifend est ullamcorper fermentum. Donec ullamcorper et tortor a laoreet. Nam id risus nisi. Vivamus non imperdiet erat, sit amet imperdiet felis. Mauris vitae neque et est aliquam scelerisque non non ipsum.</text:p>
<text:h text:style-name="P1" text:outline-level="2">Chapter Two</text:h> <text:h text:style-name="P1" text:outline-level="2">Chapter Two</text:h>
<text:p text:style-name="Text_20_body">Text</text:p> <text:p text:style-name="Text_20_body">Nullam laoreet lorem nec malesuada vehicula. Vivamus tempus sodales lectus sed viverra. Aenean lacinia sollicitudin quam, quis tempus eros suscipit id. Duis sed rutrum nisi, ut pulvinar magna. Nam et cursus tortor. Phasellus ac odio tellus. Nullam in iaculis ipsum. Vivamus ante sem, ultricies sed varius quis, tristique nec tellus. Nullam eu urna vitae lacus hendrerit gravida. Quisque pulvinar erat ex, id efficitur velit sodales vitae. Proin vestibulum, sapien eget mattis euismod, tortor quam viverra risus, at congue mauris tortor eu nunc. Mauris pellentesque elit leo, quis eleifend sem placerat a. Vivamus iaculis dui eget tellus volutpat, ac varius nisi facilisis.<text:note text:id="ftn1" text:note-class="footnote">
<text:note-citation>1</text:note-citation>
<text:note-body>
<text:p text:style-name="Footnote">Lorem ipsum</text:p>
</text:note-body>
</text:note></text:p>
</office:text> </office:text>
</office:body> </office:body>
</office:document> </office:document>
+38 -4
View File
@@ -1,5 +1,5 @@
<?xml version='1.0' encoding='utf-8'?> <?xml version='1.0' encoding='utf-8'?>
<office:document-content xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" office:version="1.3"> <office:document-content xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" office:version="1.3">
<office:font-face-decls> <office:font-face-decls>
<style:font-face style:name="Liberation Serif" style:font-pitch="variable" /> <style:font-face style:name="Liberation Serif" style:font-pitch="variable" />
</office:font-face-decls> </office:font-face-decls>
@@ -7,13 +7,47 @@
<style:style style:name="P1" style:family="paragraph" style:parent-style-name="Heading_20_2"> <style:style style:name="P1" style:family="paragraph" style:parent-style-name="Heading_20_2">
<style:paragraph-properties fo:break-before="page" /> <style:paragraph-properties fo:break-before="page" />
</style:style> </style:style>
<style:style style:name="T1" style:family="text">
<style:text-properties fo:font-weight="bold" />
</style:style>
<style:style style:name="T2" style:family="text">
<style:text-properties fo:color="#4271ae" style:text-underline-style="solid" style:text-underline-width="auto" style:text-underline-color="font-color" />
</style:style>
</office:automatic-styles> </office:automatic-styles>
<office:body> <office:body>
<office:text> <office:text>
<text:h text:style-name="Heading_20_2" text:outline-level="2">Chapter One</text:h> <text:user-field-decls>
<text:p text:style-name="Text_20_body">Text</text:p> <text:user-field-decl office:value-type="float" office:value="3" text:name="ManuscriptTitleCount" />
<text:user-field-decl office:value-type="float" office:value="3" text:name="ManuscriptParagraphCount" />
<text:user-field-decl office:value-type="float" office:value="217" text:name="ManuscriptAllWords" />
<text:user-field-decl office:value-type="float" office:value="211" text:name="ManuscriptTextWords" />
<text:user-field-decl office:value-type="float" office:value="6" text:name="ManuscriptTitleWords" />
<text:user-field-decl office:value-type="float" office:value="1471" text:name="ManuscriptAllChars" />
<text:user-field-decl office:value-type="float" office:value="1441" text:name="ManuscriptTextChars" />
<text:user-field-decl office:value-type="float" office:value="30" text:name="ManuscriptTitleChars" />
<text:user-field-decl office:value-type="float" office:value="1258" text:name="ManuscriptAllWordChars" />
<text:user-field-decl office:value-type="float" office:value="1231" text:name="ManuscriptTextWordChars" />
<text:user-field-decl office:value-type="float" office:value="27" text:name="ManuscriptTitleWordChars" />
</text:user-field-decls>
<text:p text:style-name="Title">My Novel</text:p>
<text:p text:style-name="Text_20_body">
<text:span text:style-name="T1">Word Count: </text:span>
<text:span text:style-name="T1">
<text:user-field-get style:data-style-name="N0" text:name="ManuscriptAllWords">0</text:user-field-get>
</text:span>
<text:line-break />
<text:user-field-get style:data-style-name="N0" text:name="ManuscriptParagraphCount">0</text:user-field-get> paragrphs<text:line-break />Web: <text:a xlink:type="simple" xlink:href="http://example.com" text:style-name="T2">http://example.com</text:a>
</text:p>
<text:h text:style-name="P1" text:outline-level="2">Chapter One</text:h>
<text:p text:style-name="Text_20_body">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc maximus justo non dictum commodo. Curabitur lacinia tempor orci vel luctus. Phasellus porta metus eu massa luctus, eget euismod risus rhoncus. Vestibulum sed arcu nisi. Maecenas pretium facilisis velit, vel semper lacus aliquam sit amet. Vestibulum vulputate neque ligula, rhoncus blandit turpis consequat id. Mauris sagittis vehicula imperdiet. Duis sed nunc pretium, ornare purus vel, sodales augue. Maecenas a suscipit risus. Quisque volutpat justo eleifend est ullamcorper fermentum. Donec ullamcorper et tortor a laoreet. Nam id risus nisi. Vivamus non imperdiet erat, sit amet imperdiet felis. Mauris vitae neque et est aliquam scelerisque non non ipsum.</text:p>
<text:h text:style-name="P1" text:outline-level="2">Chapter Two</text:h> <text:h text:style-name="P1" text:outline-level="2">Chapter Two</text:h>
<text:p text:style-name="Text_20_body">Text</text:p> <text:p text:style-name="Text_20_body">Nullam laoreet lorem nec malesuada vehicula. Vivamus tempus sodales lectus sed viverra. Aenean lacinia sollicitudin quam, quis tempus eros suscipit id. Duis sed rutrum nisi, ut pulvinar magna. Nam et cursus tortor. Phasellus ac odio tellus. Nullam in iaculis ipsum. Vivamus ante sem, ultricies sed varius quis, tristique nec tellus. Nullam eu urna vitae lacus hendrerit gravida. Quisque pulvinar erat ex, id efficitur velit sodales vitae. Proin vestibulum, sapien eget mattis euismod, tortor quam viverra risus, at congue mauris tortor eu nunc. Mauris pellentesque elit leo, quis eleifend sem placerat a. Vivamus iaculis dui eget tellus volutpat, ac varius nisi facilisis.<text:note text:id="ftn1" text:note-class="footnote">
<text:note-citation>1</text:note-citation>
<text:note-body>
<text:p text:style-name="Footnote">Lorem ipsum</text:p>
</text:note-body>
</text:note>
</text:p>
</office:text> </office:text>
</office:body> </office:body>
</office:document-content> </office:document-content>
@@ -1,8 +1,8 @@
%%~name: New Scene %%~name: New Scene
%%~path: 000000000000d/000000000000f %%~path: 000000000000d/000000000000f
%%~kind: NOVEL/DOCUMENT %%~kind: NOVEL/DOCUMENT
%%~hash: 0566024662fb6ed7ed645717addd64dabf058915 %%~hash: 89b54ddaec2fddfd220e91dd438c84fb3aef9fc2
%%~date: 2024-10-27 13:03:13/2024-10-27 13:03:18 %%~date: 2024-10-30 00:07:21/2024-10-30 00:07:26
# Novel # Novel
## Chapter ## Chapter
@@ -40,7 +40,9 @@ Some “ double quoted text with spaces padded ”.
@object: NoSpaceAdded @object: NoSpaceAdded
% synopsis: No space before this colon. % synopsis : Space before this is OK.
%Footnote.abc : A simple footnote.
Add space before this colon : See? Add space before this colon : See?
@@ -1,6 +1,6 @@
<?xml version='1.0' encoding='utf-8'?> <?xml version='1.0' encoding='utf-8'?>
<novelWriterXML appVersion="2.6a3" hexVersion="0x020600a3" fileVersion="1.5" fileRevision="4" timeStamp="2024-10-27 13:01:24"> <novelWriterXML appVersion="2.6a3" hexVersion="0x020600a3" fileVersion="1.5" fileRevision="4" timeStamp="2024-10-30 00:06:45">
<project id="d0f3fe10-c6e6-4310-8bfd-181eb4224eed" saveCount="3" autoCount="2" editTime="6"> <project id="d0f3fe10-c6e6-4310-8bfd-181eb4224eed" saveCount="3" autoCount="2" editTime="5">
<name>New Project</name> <name>New Project</name>
<author>Jane Doe</author> <author>Jane Doe</author>
</project> </project>
@@ -46,7 +46,7 @@
<name status="s000000" import="i000004" active="yes">New Chapter</name> <name status="s000000" import="i000004" active="yes">New Chapter</name>
</item> </item>
<item handle="000000000000f" parent="000000000000d" root="0000000000008" order="1" type="FILE" class="NOVEL" layout="DOCUMENT"> <item handle="000000000000f" parent="000000000000d" root="0000000000008" order="1" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta expanded="no" heading="H1" charCount="918" wordCount="154" paraCount="17" cursorPos="1140" /> <meta expanded="no" heading="H1" charCount="918" wordCount="154" paraCount="17" cursorPos="1174" />
<name status="s000000" import="i000004" active="yes">New Scene</name> <name status="s000000" import="i000004" active="yes">New Scene</name>
</item> </item>
<item handle="0000000000009" parent="None" root="0000000000009" order="1" type="ROOT" class="PLOT"> <item handle="0000000000009" parent="None" root="0000000000009" order="1" type="ROOT" class="PLOT">
+1
View File
@@ -1490,5 +1490,6 @@ def testCoreIndex_processComment():
# Padding with term # Padding with term
assert processComment("%note.term: Hi") == (nwComment.NOTE, "term", "Hi", 6, 11) assert processComment("%note.term: Hi") == (nwComment.NOTE, "term", "Hi", 6, 11)
assert processComment("% note.term: Hi") == (nwComment.NOTE, "term", "Hi", 7, 12) assert processComment("% note.term: Hi") == (nwComment.NOTE, "term", "Hi", 7, 12)
assert processComment("% note.term : Hi") == (nwComment.NOTE, "term", "Hi", 7, 13)
assert processComment("% note. term : Hi") == (nwComment.PLAIN, "", "note. term : Hi", 0, 0) assert processComment("% note. term : Hi") == (nwComment.PLAIN, "", "note. term : Hi", 0, 0)
assert processComment("% note . term : Hi") == (nwComment.PLAIN, "", "note . term : Hi", 0, 0) assert processComment("% note . term : Hi") == (nwComment.PLAIN, "", "note . term : Hi", 0, 0)
+45 -21
View File
@@ -32,28 +32,9 @@ from novelwriter.core.docbuild import NWBuildDocument
from novelwriter.core.project import NWProject from novelwriter.core.project import NWProject
from novelwriter.enum import nwBuildFmt from novelwriter.enum import nwBuildFmt
from novelwriter.formats.shared import BlockFmt, BlockTyp from novelwriter.formats.shared import BlockFmt, BlockTyp
from novelwriter.formats.todocx import ToDocX, _mkTag, _wTag from novelwriter.formats.todocx import OOXML_SCM, ToDocX, _mkTag, _wTag
from tests.tools import DOCX_IGNORE, cmpFiles from tests.tools import DOCX_IGNORE, cmpFiles, xmlToText
OOXML_SCM = "http://schemas.openxmlformats.org"
XML_NS = [
f' xmlns:r="{OOXML_SCM}/officeDocument/2006/relationships"',
f' xmlns:w="{OOXML_SCM}/wordprocessingml/2006/main"',
f' xmlns:cp="{OOXML_SCM}/package/2006/metadata/core-properties"',
' xmlns:dc="http://purl.org/dc/elements/1.1/"',
' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"',
' xmlns:xml="http://www.w3.org/XML/1998/namespace"',
' xmlns:dcterms="http://purl.org/dc/terms/"',
]
def xmlToText(xElem):
"""Get the text content of an XML element."""
rTxt = ET.tostring(xElem, encoding="utf-8", xml_declaration=False).decode()
for ns in XML_NS:
rTxt = rTxt.replace(ns, "")
return rTxt
@pytest.mark.core @pytest.mark.core
@@ -610,6 +591,49 @@ def testFmtToDocX_Footnotes(mockGUI):
) )
@pytest.mark.core
def testFmtToDocX_Fields(mockGUI):
"""Test formatting of footnotes."""
project = NWProject()
doc = ToDocX(project)
doc.initDocument()
# Field Builder
xNode = doc._generateField("a:b", 0x00)
assert isinstance(xNode, ET.Element)
assert xmlToText(xNode) == "<w:r><w:rPr /><w:t>0</w:t></w:r>"
assert doc._usedFields == [(xNode.find(_wTag("t")), "b")]
assert doc._generateField("a", 0x00) is None
# Full Processing
doc._text = (
"Word Count: [field:allWords]\n"
"Character Count: [field:allChars]\n"
"Chicken Count: [field:allChickens]\n"
)
doc.tokenizeText()
doc.doConvert()
doc.countStats()
doc._documentXml(None, None)
assert xmlToText(doc._files["document.xml"].xml) == (
'<w:document><w:body><w:p><w:pPr><w:pStyle w:val="Normal" /></w:pPr>'
'<w:r><w:rPr /><w:t xml:space="preserve">Word Count: </w:t></w:r>'
'<w:r><w:rPr /><w:t>6</w:t></w:r>'
'<w:r><w:rPr /><w:br /><w:t xml:space="preserve">Character Count: </w:t></w:r>'
'<w:r><w:rPr /><w:t>46</w:t></w:r>'
'<w:r><w:rPr /><w:br /><w:t xml:space="preserve">Chicken Count: </w:t></w:r>'
'<w:r><w:rPr /><w:t>0</w:t></w:r>'
'</w:p><w:sectPr>'
'<w:footnotePr><w:numFmt w:val="decimal" /></w:footnotePr>'
'<w:pgSz w:w="11905" w:h="16837" w:orient="portrait" />'
'<w:pgMar w:top="1133" w:right="1133" w:bottom="1133" w:left="1133" '
'w:header="566" w:footer="0" w:gutter="0" />'
'<w:pgNumType w:start="1" w:fmt="decimal" /><w:titlePg />'
'</w:sectPr></w:body></w:document>'
)
@pytest.mark.core @pytest.mark.core
def testFmtToDocX_SaveDocument(mockGUI, prjLipsum, fncPath, tstPaths): def testFmtToDocX_SaveDocument(mockGUI, prjLipsum, fncPath, tstPaths):
"""Test document output.""" """Test document output."""
+4 -1
View File
@@ -45,7 +45,7 @@ class BareTokenizer(Tokenizer):
super().doConvert() # type: ignore (deliberate check) super().doConvert() # type: ignore (deliberate check)
def closeDocument(self): def closeDocument(self):
super().doConvert() # type: ignore (deliberate check) super().closeDocument() # type: ignore (deliberate check)
def saveDocument(self, path) -> None: def saveDocument(self, path) -> None:
super().saveDocument(path) # type: ignore (deliberate check) super().saveDocument(path) # type: ignore (deliberate check)
@@ -60,6 +60,9 @@ def testFmtToken_Abstracts(mockGUI, tstPaths):
with pytest.raises(NotImplementedError): with pytest.raises(NotImplementedError):
tokens.doConvert() tokens.doConvert()
with pytest.raises(NotImplementedError):
tokens.closeDocument()
with pytest.raises(NotImplementedError): with pytest.raises(NotImplementedError):
tokens.saveDocument(tstPaths) tokens.saveDocument(tstPaths)
+59 -26
View File
@@ -35,26 +35,7 @@ from novelwriter.core.project import NWProject
from novelwriter.formats.shared import BlockFmt, BlockTyp, TextFmt from novelwriter.formats.shared import BlockFmt, BlockTyp, TextFmt
from novelwriter.formats.toodt import ODTParagraphStyle, ODTTextStyle, ToOdt, XMLParagraph, _mkTag from novelwriter.formats.toodt import ODTParagraphStyle, ODTTextStyle, ToOdt, XMLParagraph, _mkTag
from tests.tools import ODT_IGNORE, cmpFiles from tests.tools import ODT_IGNORE, cmpFiles, xmlToText
XML_NS = [
' xmlns:dc="http://purl.org/dc/elements/1.1/"',
' xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0"',
' xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0"',
' xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0"',
' xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"',
' xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0"',
' xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"',
' xmlns:xlink="http://www.w3.org/1999/xlink"',
]
def xmlToText(xElem):
"""Get the text content of an XML element."""
rTxt = ET.tostring(xElem, encoding="utf-8", xml_declaration=False).decode()
for ns in XML_NS:
rTxt = rTxt.replace(ns, "")
return rTxt
@pytest.mark.core @pytest.mark.core
@@ -237,6 +218,46 @@ def testFmtToOdt_TextFormatting(mockGUI):
) )
@pytest.mark.core
def testFmtToOdt_Fields(mockGUI):
"""Test formatting of footnotes."""
project = NWProject()
odt = ToOdt(project, True)
odt.initDocument()
# Field Builder
xNode = odt._generateField("a:allWords", 0x00)
assert isinstance(xNode, ET.Element)
assert xmlToText(xNode) == (
'<text:user-field-getstyle:data-style-name="N0" text:name="ManuscriptAllWords">'
'0</text:user-field-get>'
)
# assert odt._usedFields == [(xNode.find(_wTag("t")), "b")]
assert odt._generateField("a", 0x00) is None
# Full Processing
odt._text = (
"Word Count: [field:allWords]\n"
"Character Count: [field:allChars]\n"
"Chicken Count: [field:allChickens]\n"
)
odt.tokenizeText()
odt.doConvert()
odt.countStats()
assert xmlToText(odt._xBody) == (
'<office:body><office:text>'
'<text:p text:style-name="Text_20_body">'
'Word Count: <text:user-field-get style:data-style-name="N0" '
'text:name="ManuscriptAllWords">0</text:user-field-get><text:line-break />'
'Character Count: <text:user-field-get style:data-style-name="N0" '
'text:name="ManuscriptAllChars">0</text:user-field-get><text:line-break />'
'Chicken Count: <text:user-field-get style:data-style-name="N0" '
'text:name="ManuscriptAllChickens">0</text:user-field-get></text:p>'
'</office:text></office:body>'
)
@pytest.mark.core @pytest.mark.core
def testFmtToOdt_DialogueFormatting(mockGUI): def testFmtToOdt_DialogueFormatting(mockGUI):
"""Test formatting of dialogue.""" """Test formatting of dialogue."""
@@ -770,7 +791,7 @@ def testFmtToOdt_ConvertDirect(mockGUI):
@pytest.mark.core @pytest.mark.core
def testFmtToOdt_SaveFlat(mockGUI, fncPath, tstPaths): def testFmtToOdt_SaveFlat(mockGUI, fncPath, tstPaths, ipsumText):
"""Test the document save functions.""" """Test the document save functions."""
project = NWProject() project = NWProject()
project.data.setAuthor("Jane Smith") project.data.setAuthor("Jane Smith")
@@ -796,14 +817,20 @@ def testFmtToOdt_SaveFlat(mockGUI, fncPath, tstPaths):
assert odt._mDocRight == "1.500cm" assert odt._mDocRight == "1.500cm"
odt._text = ( odt._text = (
"#! My Novel\n\n"
"**Word Count: [field:allWords]**\n"
"[field:paragraphCount] paragrphs\n"
"Web: http://example.com\n\n"
"## Chapter One\n\n" "## Chapter One\n\n"
"Text\n\n" f"{ipsumText[0]}\n\n"
"## Chapter Two\n\n" "## Chapter Two\n\n"
"Text\n\n" f"{ipsumText[1]}[footnote:abc]\n\n"
"%Footnote.abc: Lorem ipsum\n\n"
) )
odt.tokenizeText() odt.tokenizeText()
odt.initDocument() odt.initDocument()
odt.doConvert() odt.doConvert()
odt.countStats()
odt.closeDocument() odt.closeDocument()
flatFile = fncPath / "document.fodt" flatFile = fncPath / "document.fodt"
@@ -818,7 +845,7 @@ def testFmtToOdt_SaveFlat(mockGUI, fncPath, tstPaths):
@pytest.mark.core @pytest.mark.core
def testFmtToOdt_SaveFull(mockGUI, fncPath, tstPaths): def testFmtToOdt_SaveFull(mockGUI, fncPath, tstPaths, ipsumText):
"""Test the document save functions.""" """Test the document save functions."""
project = NWProject() project = NWProject()
project.data.setAuthor("Jane Smith") project.data.setAuthor("Jane Smith")
@@ -833,14 +860,20 @@ def testFmtToOdt_SaveFull(mockGUI, fncPath, tstPaths):
odt.setHeaderFormat(f"{nwHeadFmt.DOC_PROJECT} - {nwHeadFmt.DOC_AUTHOR}", 0) odt.setHeaderFormat(f"{nwHeadFmt.DOC_PROJECT} - {nwHeadFmt.DOC_AUTHOR}", 0)
odt._text = ( odt._text = (
"#! My Novel\n\n"
"**Word Count: [field:allWords]**\n"
"[field:paragraphCount] paragrphs\n"
"Web: http://example.com\n\n"
"## Chapter One\n\n" "## Chapter One\n\n"
"Text\n\n" f"{ipsumText[0]}\n\n"
"## Chapter Two\n\n" "## Chapter Two\n\n"
"Text\n\n" f"{ipsumText[1]}[footnote:abc]\n\n"
"%Footnote.abc: Lorem ipsum\n\n"
) )
odt.tokenizeText() odt.tokenizeText()
odt.initDocument() odt.initDocument()
odt.doConvert() odt.doConvert()
odt.countStats()
odt.closeDocument() odt.closeDocument()
fullFile = fncPath / "document.odt" fullFile = fncPath / "document.odt"
-24
View File
@@ -2184,27 +2184,3 @@ def testGuiEditor_Search(qtbot, monkeypatch, nwGUI, prjLipsum):
assert docEditor.textCursor().selectedText() == "" assert docEditor.textCursor().selectedText() == ""
# qtbot.stop() # qtbot.stop()
@pytest.mark.gui
def testGuiEditor_StaticMethods():
"""Test the document editor's static methods."""
# Check the method that decides if it is allowed to insert a space
# before a colon using the French, Spanish, etc language feature
assert GuiDocEditor._allowSpaceBeforeColon("", "") is True
assert GuiDocEditor._allowSpaceBeforeColon("", ":") is True
assert GuiDocEditor._allowSpaceBeforeColon("some text", ":") is True
assert GuiDocEditor._allowSpaceBeforeColon("@:", ":") is False
assert GuiDocEditor._allowSpaceBeforeColon("@>", ">") is True
assert GuiDocEditor._allowSpaceBeforeColon("%", ":") is True
assert GuiDocEditor._allowSpaceBeforeColon("%:", ":") is True
assert GuiDocEditor._allowSpaceBeforeColon("%synopsis:", ":") is False
assert GuiDocEditor._allowSpaceBeforeColon("%Synopsis:", ":") is False
assert GuiDocEditor._allowSpaceBeforeColon("% synopsis:", ":") is False
assert GuiDocEditor._allowSpaceBeforeColon("% Synopsis:", ":") is False
assert GuiDocEditor._allowSpaceBeforeColon("% synopsis:", ":") is False
assert GuiDocEditor._allowSpaceBeforeColon("% Synopsis:", ":") is False
assert GuiDocEditor._allowSpaceBeforeColon("%synopsis :", ":") is True
assert GuiDocEditor._allowSpaceBeforeColon("%Synopsis :", ":") is True
+7 -2
View File
@@ -474,7 +474,7 @@ def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, projPath, tstPaths, mockRnd):
# Special Formatting # Special Formatting
# ================== # ==================
# Insert spaces before colon, but ignore tags and synopsis # Insert spaces before colon, but ignore tags
docEditor._typPadBefore = ":" docEditor._typPadBefore = ":"
for c in "@object: NoSpaceAdded": for c in "@object: NoSpaceAdded":
@@ -482,7 +482,12 @@ def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, projPath, tstPaths, mockRnd):
qtbot.keyClick(docEditor, Qt.Key.Key_Return, delay=KEY_DELAY) qtbot.keyClick(docEditor, Qt.Key.Key_Return, delay=KEY_DELAY)
qtbot.keyClick(docEditor, Qt.Key.Key_Return, delay=KEY_DELAY) qtbot.keyClick(docEditor, Qt.Key.Key_Return, delay=KEY_DELAY)
for c in "% synopsis: No space before this colon.": for c in "% synopsis: Space before this is OK.":
qtbot.keyClick(docEditor, c, delay=KEY_DELAY)
qtbot.keyClick(docEditor, Qt.Key.Key_Return, delay=KEY_DELAY)
qtbot.keyClick(docEditor, Qt.Key.Key_Return, delay=KEY_DELAY)
for c in "%Footnote.abc: A simple footnote.":
qtbot.keyClick(docEditor, c, delay=KEY_DELAY) qtbot.keyClick(docEditor, c, delay=KEY_DELAY)
qtbot.keyClick(docEditor, Qt.Key.Key_Return, delay=KEY_DELAY) qtbot.keyClick(docEditor, Qt.Key.Key_Return, delay=KEY_DELAY)
qtbot.keyClick(docEditor, Qt.Key.Key_Return, delay=KEY_DELAY) qtbot.keyClick(docEditor, Qt.Key.Key_Return, delay=KEY_DELAY)
+10
View File
@@ -21,6 +21,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
from __future__ import annotations from __future__ import annotations
import shutil import shutil
import xml.etree.ElementTree as ET
from datetime import datetime from datetime import datetime
from pathlib import Path from pathlib import Path
@@ -110,6 +111,15 @@ def cmpFiles(
return not diffFound return not diffFound
def xmlToText(xElem):
"""Get the text content of an XML element."""
text = ET.tostring(xElem, encoding="utf-8", xml_declaration=False).decode()
bits = text.partition(">")
node = bits[0].partition(" ")
rest = " ".join(x for x in node[2].split() if not x.startswith("xmlns")).replace("/", " /")
return f"{node[0]}{rest}{bits[1]}{bits[2]}"
def readFile(fileName: str | Path): def readFile(fileName: str | Path):
"""Returns the content of a file as a string.""" """Returns the content of a file as a string."""
with open(fileName, mode="r", encoding="utf-8") as inFile: with open(fileName, mode="r", encoding="utf-8") as inFile: