Update project builder tests
This commit is contained in:
@@ -327,22 +327,17 @@ class ProjectBuilder:
|
|||||||
|
|
||||||
def buildProject(self, data: dict) -> bool:
|
def buildProject(self, data: dict) -> bool:
|
||||||
"""Build or copy a project from a data dictionary."""
|
"""Build or copy a project from a data dictionary."""
|
||||||
if not isinstance(data, dict):
|
if isinstance(data, dict):
|
||||||
logger.error("Invalid call to buildProject function")
|
path = data.get("path", None) or None
|
||||||
return False
|
if isinstance(path, (str, Path)):
|
||||||
|
self._path = Path(path).resolve()
|
||||||
path = data.get("path", None) or None
|
if data.get("sample", False):
|
||||||
if isinstance(path, (str, Path)):
|
return self._extractSampleProject(self._path)
|
||||||
self._path = Path(path).resolve()
|
elif data.get("template"):
|
||||||
if data.get("sample", False):
|
return True
|
||||||
return self._extractSampleProject(self._path)
|
else:
|
||||||
elif data.get("template"):
|
return self._buildAndPopulate(self._path, data)
|
||||||
return True
|
SHARED.error("A project path is required.")
|
||||||
else:
|
|
||||||
return self._buildAndPopulate(self._path, data)
|
|
||||||
|
|
||||||
SHARED.error("A project path is required.")
|
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
##
|
##
|
||||||
@@ -361,7 +356,7 @@ class ProjectBuilder:
|
|||||||
return False
|
return False
|
||||||
elif status == NWStorageCreate.OS_ERROR:
|
elif status == NWStorageCreate.OS_ERROR:
|
||||||
SHARED.error(self.tr(
|
SHARED.error(self.tr(
|
||||||
"An error occured while trying to create the project."
|
"An error occurred while trying to create the project."
|
||||||
), exc=project.storage.exc)
|
), exc=project.storage.exc)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -378,6 +373,7 @@ class ProjectBuilder:
|
|||||||
|
|
||||||
project.data.setUuid(None)
|
project.data.setUuid(None)
|
||||||
project.data.setName(projName)
|
project.data.setName(projName)
|
||||||
|
project.data.setTitle(projName)
|
||||||
project.data.setAuthor(projAuthor)
|
project.data.setAuthor(projAuthor)
|
||||||
project.data.setLanguage(projLang)
|
project.data.setLanguage(projLang)
|
||||||
project.setDefaultStatusImport()
|
project.setDefaultStatusImport()
|
||||||
|
|||||||
@@ -1,66 +0,0 @@
|
|||||||
<?xml version='1.0' encoding='utf-8'?>
|
|
||||||
<novelWriterXML appVersion="2.0.7" hexVersion="0x020007f0" fileVersion="1.5" fileRevision="1" timeStamp="2023-06-03 18:18:22">
|
|
||||||
<project id="d0f3fe10-c6e6-4310-8bfd-181eb4224eed" saveCount="1" autoCount="0" editTime="0">
|
|
||||||
<name>New Project</name>
|
|
||||||
<title>New Project</title>
|
|
||||||
<author />
|
|
||||||
</project>
|
|
||||||
<settings>
|
|
||||||
<doBackup>yes</doBackup>
|
|
||||||
<language>en_GB</language>
|
|
||||||
<spellChecking auto="no">None</spellChecking>
|
|
||||||
<lastHandle>
|
|
||||||
<entry key="editor">None</entry>
|
|
||||||
<entry key="viewer">None</entry>
|
|
||||||
<entry key="novelTree">None</entry>
|
|
||||||
<entry key="outline">None</entry>
|
|
||||||
</lastHandle>
|
|
||||||
<autoReplace />
|
|
||||||
<status>
|
|
||||||
<entry key="s000000" count="5" red="100" green="100" blue="100">New</entry>
|
|
||||||
<entry key="s000001" count="0" red="200" green="50" blue="0">Note</entry>
|
|
||||||
<entry key="s000002" count="0" red="200" green="150" blue="0">Draft</entry>
|
|
||||||
<entry key="s000003" count="0" red="50" green="200" blue="0">Finished</entry>
|
|
||||||
</status>
|
|
||||||
<importance>
|
|
||||||
<entry key="i000004" count="3" red="100" green="100" blue="100">New</entry>
|
|
||||||
<entry key="i000005" count="0" red="200" green="50" blue="0">Minor</entry>
|
|
||||||
<entry key="i000006" count="0" red="200" green="150" blue="0">Major</entry>
|
|
||||||
<entry key="i000007" count="0" red="50" green="200" blue="0">Main</entry>
|
|
||||||
</importance>
|
|
||||||
</settings>
|
|
||||||
<content items="8" novelWords="0" notesWords="0">
|
|
||||||
<item handle="0000000000008" parent="None" root="0000000000008" order="0" type="ROOT" class="NOVEL">
|
|
||||||
<meta expanded="no" />
|
|
||||||
<name status="s000000" import="i000004">Novel</name>
|
|
||||||
</item>
|
|
||||||
<item handle="0000000000009" parent="0000000000008" root="0000000000008" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
|
|
||||||
<meta expanded="no" heading="H0" charCount="0" wordCount="0" paraCount="0" cursorPos="0" />
|
|
||||||
<name status="s000000" import="i000004" active="yes">Title Page</name>
|
|
||||||
</item>
|
|
||||||
<item handle="000000000000a" parent="0000000000008" root="0000000000008" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
|
|
||||||
<meta expanded="no" heading="H0" charCount="0" wordCount="0" paraCount="0" cursorPos="0" />
|
|
||||||
<name status="s000000" import="i000004" active="yes">New Chapter</name>
|
|
||||||
</item>
|
|
||||||
<item handle="000000000000b" parent="000000000000a" root="0000000000008" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
|
|
||||||
<meta expanded="no" heading="H0" charCount="0" wordCount="0" paraCount="0" cursorPos="0" />
|
|
||||||
<name status="s000000" import="i000004" active="yes">New Scene</name>
|
|
||||||
</item>
|
|
||||||
<item handle="000000000000c" parent="None" root="000000000000c" order="0" type="ROOT" class="PLOT">
|
|
||||||
<meta expanded="no" />
|
|
||||||
<name status="s000000" import="i000004">Plot</name>
|
|
||||||
</item>
|
|
||||||
<item handle="000000000000d" parent="None" root="000000000000d" order="0" type="ROOT" class="CHARACTER">
|
|
||||||
<meta expanded="no" />
|
|
||||||
<name status="s000000" import="i000004">Characters</name>
|
|
||||||
</item>
|
|
||||||
<item handle="000000000000e" parent="None" root="000000000000e" order="0" type="ROOT" class="WORLD">
|
|
||||||
<meta expanded="no" />
|
|
||||||
<name status="s000000" import="i000004">Locations</name>
|
|
||||||
</item>
|
|
||||||
<item handle="000000000000f" parent="None" root="000000000000f" order="0" type="ROOT" class="ARCHIVE">
|
|
||||||
<meta expanded="no" />
|
|
||||||
<name status="s000000" import="i000004">Archive</name>
|
|
||||||
</item>
|
|
||||||
</content>
|
|
||||||
</novelWriterXML>
|
|
||||||
+3
-3
@@ -1,8 +1,8 @@
|
|||||||
<?xml version='1.0' encoding='utf-8'?>
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
<novelWriterXML appVersion="2.0.7" hexVersion="0x020007f0" fileVersion="1.5" fileRevision="1" timeStamp="2023-06-03 18:18:22">
|
<novelWriterXML appVersion="2.3-alpha1" hexVersion="0x020300a1" fileVersion="1.5" fileRevision="1" timeStamp="2023-12-29 14:34:07">
|
||||||
<project id="d0f3fe10-c6e6-4310-8bfd-181eb4224eed" saveCount="1" autoCount="0" editTime="0">
|
<project id="d0f3fe10-c6e6-4310-8bfd-181eb4224eed" saveCount="1" autoCount="0" editTime="0">
|
||||||
<name>Test Custom</name>
|
<name>Test Project A</name>
|
||||||
<title>Test Novel</title>
|
<title>Test Project A</title>
|
||||||
<author>Jane Doe</author>
|
<author>Jane Doe</author>
|
||||||
</project>
|
</project>
|
||||||
<settings>
|
<settings>
|
||||||
+3
-3
@@ -1,8 +1,8 @@
|
|||||||
<?xml version='1.0' encoding='utf-8'?>
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
<novelWriterXML appVersion="2.0.7" hexVersion="0x020007f0" fileVersion="1.5" fileRevision="1" timeStamp="2023-06-03 18:18:22">
|
<novelWriterXML appVersion="2.3-alpha1" hexVersion="0x020300a1" fileVersion="1.5" fileRevision="1" timeStamp="2023-12-29 14:36:07">
|
||||||
<project id="d0f3fe10-c6e6-4310-8bfd-181eb4224eed" saveCount="1" autoCount="0" editTime="0">
|
<project id="d0f3fe10-c6e6-4310-8bfd-181eb4224eed" saveCount="1" autoCount="0" editTime="0">
|
||||||
<name>Test Custom</name>
|
<name>Test Project B</name>
|
||||||
<title>Test Novel</title>
|
<title>Test Project B</title>
|
||||||
<author>Jane Doe</author>
|
<author>Jane Doe</author>
|
||||||
</project>
|
</project>
|
||||||
<settings>
|
<settings>
|
||||||
@@ -39,32 +39,32 @@ from novelwriter.core.coretools import DocDuplicator, DocMerger, DocSplitter, Pr
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreTools_DocMerger(monkeypatch, mockGUI, fncPath, tstPaths, mockRnd, ipsumText):
|
def testCoreTools_DocMerger(monkeypatch, mockGUI, fncPath, tstPaths, mockRnd, ipsumText):
|
||||||
"""Test the DocMerger utility."""
|
"""Test the DocMerger utility."""
|
||||||
theProject = NWProject()
|
project = NWProject()
|
||||||
mockRnd.reset()
|
mockRnd.reset()
|
||||||
buildTestProject(theProject, fncPath)
|
buildTestProject(project, fncPath)
|
||||||
|
|
||||||
# Create Files to Merge
|
# Create Files to Merge
|
||||||
# =====================
|
# =====================
|
||||||
|
|
||||||
hChapter1 = theProject.newFile("Chapter 1", C.hNovelRoot)
|
hChapter1 = project.newFile("Chapter 1", C.hNovelRoot)
|
||||||
hSceneOne11 = theProject.newFile("Scene 1.1", hChapter1) # type: ignore
|
hSceneOne11 = project.newFile("Scene 1.1", hChapter1) # type: ignore
|
||||||
hSceneOne12 = theProject.newFile("Scene 1.2", hChapter1) # type: ignore
|
hSceneOne12 = project.newFile("Scene 1.2", hChapter1) # type: ignore
|
||||||
hSceneOne13 = theProject.newFile("Scene 1.3", hChapter1) # type: ignore
|
hSceneOne13 = project.newFile("Scene 1.3", hChapter1) # type: ignore
|
||||||
|
|
||||||
docText1 = "\n\n".join(ipsumText[0:2]) + "\n\n"
|
docText1 = "\n\n".join(ipsumText[0:2]) + "\n\n"
|
||||||
docText2 = "\n\n".join(ipsumText[1:3]) + "\n\n"
|
docText2 = "\n\n".join(ipsumText[1:3]) + "\n\n"
|
||||||
docText3 = "\n\n".join(ipsumText[2:4]) + "\n\n"
|
docText3 = "\n\n".join(ipsumText[2:4]) + "\n\n"
|
||||||
docText4 = "\n\n".join(ipsumText[3:5]) + "\n\n"
|
docText4 = "\n\n".join(ipsumText[3:5]) + "\n\n"
|
||||||
|
|
||||||
theProject.writeNewFile(hChapter1, 2, True, docText1) # type: ignore
|
project.writeNewFile(hChapter1, 2, True, docText1) # type: ignore
|
||||||
theProject.writeNewFile(hSceneOne11, 3, True, docText2) # type: ignore
|
project.writeNewFile(hSceneOne11, 3, True, docText2) # type: ignore
|
||||||
theProject.writeNewFile(hSceneOne12, 3, True, docText3) # type: ignore
|
project.writeNewFile(hSceneOne12, 3, True, docText3) # type: ignore
|
||||||
theProject.writeNewFile(hSceneOne13, 3, True, docText4) # type: ignore
|
project.writeNewFile(hSceneOne13, 3, True, docText4) # type: ignore
|
||||||
|
|
||||||
# Basic Checks
|
# Basic Checks
|
||||||
# ============
|
# ============
|
||||||
|
|
||||||
docMerger = DocMerger(theProject)
|
docMerger = DocMerger(project)
|
||||||
|
|
||||||
# No writing without a target set
|
# No writing without a target set
|
||||||
assert docMerger.writeTargetDoc() is False
|
assert docMerger.writeTargetDoc() is False
|
||||||
@@ -127,14 +127,14 @@ def testCoreTools_DocMerger(monkeypatch, mockGUI, fncPath, tstPaths, mockRnd, ip
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreTools_DocSplitter(monkeypatch, mockGUI, fncPath, mockRnd, ipsumText):
|
def testCoreTools_DocSplitter(monkeypatch, mockGUI, fncPath, mockRnd, ipsumText):
|
||||||
"""Test the DocSplitter utility."""
|
"""Test the DocSplitter utility."""
|
||||||
theProject = NWProject()
|
project = NWProject()
|
||||||
mockRnd.reset()
|
mockRnd.reset()
|
||||||
buildTestProject(theProject, fncPath)
|
buildTestProject(project, fncPath)
|
||||||
|
|
||||||
# Create File to Split
|
# Create File to Split
|
||||||
# ====================
|
# ====================
|
||||||
|
|
||||||
hSplitDoc = theProject.newFile("Split Doc", C.hNovelRoot)
|
hSplitDoc = project.newFile("Split Doc", C.hNovelRoot)
|
||||||
|
|
||||||
docData = [
|
docData = [
|
||||||
"# Part One", ipsumText[0],
|
"# Part One", ipsumText[0],
|
||||||
@@ -163,16 +163,16 @@ def testCoreTools_DocSplitter(monkeypatch, mockGUI, fncPath, mockRnd, ipsumText)
|
|||||||
|
|
||||||
docText = "\n\n".join(docData)
|
docText = "\n\n".join(docData)
|
||||||
docRaw = docText.splitlines()
|
docRaw = docText.splitlines()
|
||||||
assert theProject.storage.getDocument(hSplitDoc).writeDocument(docText) is True
|
assert project.storage.getDocument(hSplitDoc).writeDocument(docText) is True
|
||||||
theProject.tree[hSplitDoc].setStatus(C.sFinished) # type: ignore
|
project.tree[hSplitDoc].setStatus(C.sFinished) # type: ignore
|
||||||
theProject.tree[hSplitDoc].setImport(C.iMain) # type: ignore
|
project.tree[hSplitDoc].setImport(C.iMain) # type: ignore
|
||||||
|
|
||||||
docSplitter = DocSplitter(theProject, hSplitDoc) # type: ignore
|
docSplitter = DocSplitter(project, hSplitDoc) # type: ignore
|
||||||
assert docSplitter._srcItem.isFileType() # type: ignore
|
assert docSplitter._srcItem.isFileType() # type: ignore
|
||||||
assert docSplitter.getError() == ""
|
assert docSplitter.getError() == ""
|
||||||
|
|
||||||
# Run the split algorithm
|
# Run the split algorithm
|
||||||
docSplitter.splitDocument(splitData, docRaw)
|
docSplitter.splitDocument(splitData, docRaw) # type: ignore
|
||||||
for i, (lineNo, hLevel, hLabel) in enumerate(splitData):
|
for i, (lineNo, hLevel, hLabel) in enumerate(splitData):
|
||||||
assert docSplitter._rawData[i] == (docRaw[lineNo:lineNo+4], hLevel, hLabel)
|
assert docSplitter._rawData[i] == (docRaw[lineNo:lineNo+4], hLevel, hLabel)
|
||||||
|
|
||||||
@@ -248,17 +248,17 @@ def testCoreTools_DocSplitter(monkeypatch, mockGUI, fncPath, mockRnd, ipsumText)
|
|||||||
|
|
||||||
# Check that status and importance has been preserved
|
# Check that status and importance has been preserved
|
||||||
for rHandle in resDocHandle:
|
for rHandle in resDocHandle:
|
||||||
assert theProject.tree[rHandle].itemStatus == C.sFinished # type: ignore
|
assert project.tree[rHandle].itemStatus == C.sFinished # type: ignore
|
||||||
assert theProject.tree[rHandle].itemImport == C.iMain # type: ignore
|
assert project.tree[rHandle].itemImport == C.iMain # type: ignore
|
||||||
|
|
||||||
# Check handling of improper initialisation
|
# Check handling of improper initialisation
|
||||||
docSplitter = DocSplitter(theProject, C.hInvalid)
|
docSplitter = DocSplitter(project, C.hInvalid)
|
||||||
assert docSplitter._srcHandle is None
|
assert docSplitter._srcHandle is None
|
||||||
assert docSplitter._srcItem is None
|
assert docSplitter._srcItem is None
|
||||||
assert docSplitter.newParentFolder(C.hNovelRoot, "Split Folder") is None
|
assert docSplitter.newParentFolder(C.hNovelRoot, "Split Folder") is None
|
||||||
assert list(docSplitter.writeDocuments(False)) == []
|
assert list(docSplitter.writeDocuments(False)) == []
|
||||||
|
|
||||||
theProject.saveProject()
|
project.saveProject()
|
||||||
|
|
||||||
# END Test testCoreTools_DocSplitter
|
# END Test testCoreTools_DocSplitter
|
||||||
|
|
||||||
@@ -266,20 +266,20 @@ def testCoreTools_DocSplitter(monkeypatch, mockGUI, fncPath, mockRnd, ipsumText)
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreTools_DocDuplicator(mockGUI, fncPath, tstPaths, mockRnd):
|
def testCoreTools_DocDuplicator(mockGUI, fncPath, tstPaths, mockRnd):
|
||||||
"""Test the DocDuplicator utility."""
|
"""Test the DocDuplicator utility."""
|
||||||
theProject = NWProject()
|
project = NWProject()
|
||||||
mockRnd.reset()
|
mockRnd.reset()
|
||||||
buildTestProject(theProject, fncPath)
|
buildTestProject(project, fncPath)
|
||||||
|
|
||||||
dup = DocDuplicator(theProject)
|
dup = DocDuplicator(project)
|
||||||
|
|
||||||
ttText = "#! New Novel\n\n>> By Jane Doe <<\n"
|
ttText = "#! New Novel\n\n>> By Jane Doe <<\n"
|
||||||
chText = "## New Chapter\n\n"
|
chText = "## New Chapter\n\n"
|
||||||
scText = "### New Scene\n\n"
|
scText = "### New Scene\n\n"
|
||||||
|
|
||||||
# Check document content
|
# Check document content
|
||||||
assert theProject.storage.getDocument(C.hTitlePage).readDocument() == ttText
|
assert project.storage.getDocument(C.hTitlePage).readDocument() == ttText
|
||||||
assert theProject.storage.getDocument(C.hChapterDoc).readDocument() == chText
|
assert project.storage.getDocument(C.hChapterDoc).readDocument() == chText
|
||||||
assert theProject.storage.getDocument(C.hSceneDoc).readDocument() == scText
|
assert project.storage.getDocument(C.hSceneDoc).readDocument() == scText
|
||||||
|
|
||||||
# Nothing to do
|
# Nothing to do
|
||||||
assert list(dup.duplicate([])) == []
|
assert list(dup.duplicate([])) == []
|
||||||
@@ -291,17 +291,17 @@ def testCoreTools_DocDuplicator(mockGUI, fncPath, tstPaths, mockRnd):
|
|||||||
assert list(dup.duplicate([C.hSceneDoc])) == [
|
assert list(dup.duplicate([C.hSceneDoc])) == [
|
||||||
("0000000000010", C.hSceneDoc), # The Scene
|
("0000000000010", C.hSceneDoc), # The Scene
|
||||||
]
|
]
|
||||||
assert theProject.tree._order == [
|
assert project.tree._order == [
|
||||||
C.hNovelRoot, C.hPlotRoot, C.hCharRoot, C.hWorldRoot,
|
C.hNovelRoot, C.hPlotRoot, C.hCharRoot, C.hWorldRoot,
|
||||||
C.hTitlePage, C.hChapterDir, C.hChapterDoc, C.hSceneDoc,
|
C.hTitlePage, C.hChapterDir, C.hChapterDoc, C.hSceneDoc,
|
||||||
"0000000000010",
|
"0000000000010",
|
||||||
]
|
]
|
||||||
|
|
||||||
# With the same content
|
# With the same content
|
||||||
assert theProject.storage.getDocument("0000000000010").readDocument() == scText
|
assert project.storage.getDocument("0000000000010").readDocument() == scText
|
||||||
|
|
||||||
# They should have the same parent
|
# They should have the same parent
|
||||||
assert theProject.tree["0000000000010"].itemParent == C.hChapterDir # type: ignore
|
assert project.tree["0000000000010"].itemParent == C.hChapterDir # type: ignore
|
||||||
|
|
||||||
# Folder w/Two Files
|
# Folder w/Two Files
|
||||||
# ==================
|
# ==================
|
||||||
@@ -312,7 +312,7 @@ def testCoreTools_DocDuplicator(mockGUI, fncPath, tstPaths, mockRnd):
|
|||||||
("0000000000012", None), # The Chapter
|
("0000000000012", None), # The Chapter
|
||||||
("0000000000013", None), # The Scene
|
("0000000000013", None), # The Scene
|
||||||
]
|
]
|
||||||
assert theProject.tree._order == [
|
assert project.tree._order == [
|
||||||
C.hNovelRoot, C.hPlotRoot, C.hCharRoot, C.hWorldRoot,
|
C.hNovelRoot, C.hPlotRoot, C.hCharRoot, C.hWorldRoot,
|
||||||
C.hTitlePage, C.hChapterDir, C.hChapterDoc, C.hSceneDoc,
|
C.hTitlePage, C.hChapterDir, C.hChapterDoc, C.hSceneDoc,
|
||||||
"0000000000010",
|
"0000000000010",
|
||||||
@@ -320,15 +320,15 @@ def testCoreTools_DocDuplicator(mockGUI, fncPath, tstPaths, mockRnd):
|
|||||||
]
|
]
|
||||||
|
|
||||||
# With the same content
|
# With the same content
|
||||||
assert theProject.storage.getDocument("0000000000012").readDocument() == chText
|
assert project.storage.getDocument("0000000000012").readDocument() == chText
|
||||||
assert theProject.storage.getDocument("0000000000013").readDocument() == scText
|
assert project.storage.getDocument("0000000000013").readDocument() == scText
|
||||||
|
|
||||||
# The chapter dirs should have the same parent
|
# The chapter dirs should have the same parent
|
||||||
assert theProject.tree["0000000000011"].itemParent == C.hNovelRoot # type: ignore
|
assert project.tree["0000000000011"].itemParent == C.hNovelRoot # type: ignore
|
||||||
|
|
||||||
# The new files should have the new folder as parent
|
# The new files should have the new folder as parent
|
||||||
assert theProject.tree["0000000000012"].itemParent == "0000000000011" # type: ignore
|
assert project.tree["0000000000012"].itemParent == "0000000000011" # type: ignore
|
||||||
assert theProject.tree["0000000000013"].itemParent == "0000000000011" # type: ignore
|
assert project.tree["0000000000013"].itemParent == "0000000000011" # type: ignore
|
||||||
|
|
||||||
# Full Root Folder
|
# Full Root Folder
|
||||||
# ================
|
# ================
|
||||||
@@ -343,7 +343,7 @@ def testCoreTools_DocDuplicator(mockGUI, fncPath, tstPaths, mockRnd):
|
|||||||
("0000000000017", None), # The Chapter
|
("0000000000017", None), # The Chapter
|
||||||
("0000000000018", None), # The Scene
|
("0000000000018", None), # The Scene
|
||||||
]
|
]
|
||||||
assert theProject.tree._order == [
|
assert project.tree._order == [
|
||||||
C.hNovelRoot, C.hPlotRoot, C.hCharRoot, C.hWorldRoot,
|
C.hNovelRoot, C.hPlotRoot, C.hCharRoot, C.hWorldRoot,
|
||||||
C.hTitlePage, C.hChapterDir, C.hChapterDoc, C.hSceneDoc,
|
C.hTitlePage, C.hChapterDir, C.hChapterDoc, C.hSceneDoc,
|
||||||
"0000000000010",
|
"0000000000010",
|
||||||
@@ -352,24 +352,24 @@ def testCoreTools_DocDuplicator(mockGUI, fncPath, tstPaths, mockRnd):
|
|||||||
]
|
]
|
||||||
|
|
||||||
# With the same content
|
# With the same content
|
||||||
assert theProject.storage.getDocument("0000000000015").readDocument() == ttText
|
assert project.storage.getDocument("0000000000015").readDocument() == ttText
|
||||||
assert theProject.storage.getDocument("0000000000017").readDocument() == chText
|
assert project.storage.getDocument("0000000000017").readDocument() == chText
|
||||||
assert theProject.storage.getDocument("0000000000018").readDocument() == scText
|
assert project.storage.getDocument("0000000000018").readDocument() == scText
|
||||||
|
|
||||||
# The root folder should have no parent
|
# The root folder should have no parent
|
||||||
assert theProject.tree["0000000000014"].itemParent is None # type: ignore
|
assert project.tree["0000000000014"].itemParent is None # type: ignore
|
||||||
|
|
||||||
# The folder and files should have the new root
|
# The folder and files should have the new root
|
||||||
assert theProject.tree["0000000000015"].itemRoot == "0000000000014" # type: ignore
|
assert project.tree["0000000000015"].itemRoot == "0000000000014" # type: ignore
|
||||||
assert theProject.tree["0000000000016"].itemRoot == "0000000000014" # type: ignore
|
assert project.tree["0000000000016"].itemRoot == "0000000000014" # type: ignore
|
||||||
assert theProject.tree["0000000000017"].itemRoot == "0000000000014" # type: ignore
|
assert project.tree["0000000000017"].itemRoot == "0000000000014" # type: ignore
|
||||||
assert theProject.tree["0000000000018"].itemRoot == "0000000000014" # type: ignore
|
assert project.tree["0000000000018"].itemRoot == "0000000000014" # type: ignore
|
||||||
|
|
||||||
# And they should have new parents
|
# And they should have new parents
|
||||||
assert theProject.tree["0000000000015"].itemParent == "0000000000014" # type: ignore
|
assert project.tree["0000000000015"].itemParent == "0000000000014" # type: ignore
|
||||||
assert theProject.tree["0000000000016"].itemParent == "0000000000014" # type: ignore
|
assert project.tree["0000000000016"].itemParent == "0000000000014" # type: ignore
|
||||||
assert theProject.tree["0000000000017"].itemParent == "0000000000016" # type: ignore
|
assert project.tree["0000000000017"].itemParent == "0000000000016" # type: ignore
|
||||||
assert theProject.tree["0000000000018"].itemParent == "0000000000016" # type: ignore
|
assert project.tree["0000000000018"].itemParent == "0000000000016" # type: ignore
|
||||||
|
|
||||||
# Exceptions
|
# Exceptions
|
||||||
# ==========
|
# ==========
|
||||||
@@ -381,14 +381,14 @@ def testCoreTools_DocDuplicator(mockGUI, fncPath, tstPaths, mockRnd):
|
|||||||
assert list(dup.duplicate([C.hInvalid, C.hSceneDoc])) == []
|
assert list(dup.duplicate([C.hInvalid, C.hSceneDoc])) == []
|
||||||
|
|
||||||
# Don't overwrite existing files
|
# Don't overwrite existing files
|
||||||
content = theProject.storage.contentPath
|
content = project.storage.contentPath
|
||||||
assert isinstance(content, Path)
|
assert isinstance(content, Path)
|
||||||
(content / "0000000000019.nwd").touch()
|
(content / "0000000000019.nwd").touch()
|
||||||
assert (content / "0000000000019.nwd").exists()
|
assert (content / "0000000000019.nwd").exists()
|
||||||
assert list(dup.duplicate([C.hChapterDoc, C.hSceneDoc])) == []
|
assert list(dup.duplicate([C.hChapterDoc, C.hSceneDoc])) == []
|
||||||
|
|
||||||
# Save and Close
|
# Save and Close
|
||||||
theProject.saveProject()
|
project.saveProject()
|
||||||
|
|
||||||
projFile = fncPath / "nwProject.nwx"
|
projFile = fncPath / "nwProject.nwx"
|
||||||
testFile = tstPaths.outDir / "coreTools_DocDuplicator_nwProject.nwx"
|
testFile = tstPaths.outDir / "coreTools_DocDuplicator_nwProject.nwx"
|
||||||
@@ -401,134 +401,121 @@ def testCoreTools_DocDuplicator(mockGUI, fncPath, tstPaths, mockRnd):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreTools_NewMinimal(monkeypatch, fncPath, tstPaths, mockGUI, mockRnd):
|
def testCoreTools_ProjectBuilderWrapper(monkeypatch, caplog, fncPath, mockGUI):
|
||||||
"""Create a new project from a project wizard dictionary. With
|
"""Test the wrapper function of the project builder."""
|
||||||
default setting, creating a Minimal project.
|
builder = ProjectBuilder()
|
||||||
"""
|
|
||||||
monkeypatch.setattr("uuid.uuid4", lambda *a: uuid.UUID("d0f3fe10-c6e6-4310-8bfd-181eb4224eed"))
|
|
||||||
|
|
||||||
projFile = fncPath / "nwProject.nwx"
|
|
||||||
testFile = tstPaths.outDir / "coreTools_NewMinimal_nwProject.nwx"
|
|
||||||
compFile = tstPaths.refDir / "coreTools_NewMinimal_nwProject.nwx"
|
|
||||||
|
|
||||||
projBuild = ProjectBuilder()
|
|
||||||
|
|
||||||
# Setting no data should fail
|
# Setting no data should fail
|
||||||
assert projBuild.buildProject({}) is False
|
assert builder.buildProject({}) is False
|
||||||
|
|
||||||
# Wrong type should also fail
|
# Wrong type should also fail
|
||||||
assert projBuild.buildProject("stuff") is False # type: ignore
|
assert builder.buildProject("stuff") is False # type: ignore
|
||||||
|
|
||||||
|
# Folder not writable
|
||||||
|
caplog.clear()
|
||||||
|
with monkeypatch.context() as mp:
|
||||||
|
mp.setattr("pathlib.Path.mkdir", causeOSError)
|
||||||
|
assert builder.buildProject({"path": fncPath}) is False
|
||||||
|
assert "An error occurred" in caplog.text
|
||||||
|
|
||||||
# Try again with a proper path
|
# Try again with a proper path
|
||||||
assert projBuild.buildProject({"projPath": fncPath}) is True
|
assert builder.buildProject({"path": fncPath}) is True
|
||||||
|
assert builder.projPath == fncPath
|
||||||
|
|
||||||
# Creating the project once more should fail
|
# Creating the project once more should fail
|
||||||
assert projBuild.buildProject({"projPath": fncPath}) is False
|
caplog.clear()
|
||||||
|
assert builder.buildProject({"path": fncPath}) is False
|
||||||
|
assert "A project already exists" in caplog.text
|
||||||
|
|
||||||
# Save and close
|
# END Test testCoreTools_ProjectBuilderWrapper
|
||||||
copyfile(projFile, testFile)
|
|
||||||
assert cmpFiles(testFile, compFile, ignoreStart=XML_IGNORE)
|
|
||||||
|
|
||||||
# END Test testCoreTools_NewMinimal
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreTools_NewCustomA(monkeypatch, fncPath, tstPaths, mockRnd):
|
def testCoreTools_ProjectBuilderA(monkeypatch, fncPath, tstPaths, mockRnd):
|
||||||
"""Create a new project from a project wizard dictionary.
|
"""Create a new project from a project dictionary, with chapters."""
|
||||||
Custom type with chapters and scenes.
|
|
||||||
"""
|
|
||||||
monkeypatch.setattr("uuid.uuid4", lambda *a: uuid.UUID("d0f3fe10-c6e6-4310-8bfd-181eb4224eed"))
|
monkeypatch.setattr("uuid.uuid4", lambda *a: uuid.UUID("d0f3fe10-c6e6-4310-8bfd-181eb4224eed"))
|
||||||
|
|
||||||
projFile = fncPath / "nwProject.nwx"
|
projFile = fncPath / "nwProject.nwx"
|
||||||
testFile = tstPaths.outDir / "coreTools_NewCustomA_nwProject.nwx"
|
testFile = tstPaths.outDir / "coreTools_ProjectBuilderA_nwProject.nwx"
|
||||||
compFile = tstPaths.refDir / "coreTools_NewCustomA_nwProject.nwx"
|
compFile = tstPaths.refDir / "coreTools_ProjectBuilderA_nwProject.nwx"
|
||||||
|
|
||||||
projData = {
|
data = {
|
||||||
"projName": "Test Custom",
|
"name": "Test Project A",
|
||||||
"projTitle": "Test Novel",
|
"author": "Jane Doe",
|
||||||
"projAuthor": "Jane Doe",
|
"language": -1,
|
||||||
"projLang": -1,
|
"path": fncPath,
|
||||||
"projPath": fncPath,
|
"sample": False,
|
||||||
"popSample": False,
|
"template": None,
|
||||||
"popMinimal": False,
|
"chapters": 3,
|
||||||
"popCustom": True,
|
"scenes": 3,
|
||||||
"addRoots": [
|
"roots": [
|
||||||
nwItemClass.PLOT,
|
nwItemClass.PLOT,
|
||||||
nwItemClass.CHARACTER,
|
nwItemClass.CHARACTER,
|
||||||
nwItemClass.WORLD,
|
nwItemClass.WORLD,
|
||||||
],
|
],
|
||||||
"addNotes": True,
|
"notes": True,
|
||||||
"numChapters": 3,
|
|
||||||
"numScenes": 3,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
projBuild = ProjectBuilder()
|
builder = ProjectBuilder()
|
||||||
assert projBuild.buildProject(projData) is True
|
assert builder.buildProject(data) is True
|
||||||
|
|
||||||
copyfile(projFile, testFile)
|
copyfile(projFile, testFile)
|
||||||
assert cmpFiles(testFile, compFile, ignoreStart=XML_IGNORE)
|
assert cmpFiles(testFile, compFile, ignoreStart=XML_IGNORE)
|
||||||
|
|
||||||
# END Test testCoreTools_NewCustomA
|
# END Test testCoreTools_ProjectBuilderA
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreTools_NewCustomB(monkeypatch, fncPath, tstPaths, mockRnd):
|
def testCoreTools_ProjectBuilderB(monkeypatch, fncPath, tstPaths, mockRnd):
|
||||||
"""Create a new project from a project wizard dictionary.
|
"""Create a new project from a project dictionary, without chapters."""
|
||||||
Custom type without chapters, but with scenes.
|
|
||||||
"""
|
|
||||||
monkeypatch.setattr("uuid.uuid4", lambda *a: uuid.UUID("d0f3fe10-c6e6-4310-8bfd-181eb4224eed"))
|
monkeypatch.setattr("uuid.uuid4", lambda *a: uuid.UUID("d0f3fe10-c6e6-4310-8bfd-181eb4224eed"))
|
||||||
|
|
||||||
projFile = fncPath / "nwProject.nwx"
|
projFile = fncPath / "nwProject.nwx"
|
||||||
testFile = tstPaths.outDir / "coreTools_NewCustomB_nwProject.nwx"
|
testFile = tstPaths.outDir / "coreTools_ProjectBuilderB_nwProject.nwx"
|
||||||
compFile = tstPaths.refDir / "coreTools_NewCustomB_nwProject.nwx"
|
compFile = tstPaths.refDir / "coreTools_ProjectBuilderB_nwProject.nwx"
|
||||||
|
|
||||||
projData = {
|
data = {
|
||||||
"projName": "Test Custom",
|
"name": "Test Project B",
|
||||||
"projTitle": "Test Novel",
|
"author": "Jane Doe",
|
||||||
"projAuthor": "Jane Doe",
|
"language": -1,
|
||||||
"projLang": -1,
|
"path": fncPath,
|
||||||
"projPath": fncPath,
|
"sample": False,
|
||||||
"popSample": False,
|
"template": None,
|
||||||
"popMinimal": False,
|
"chapters": 0,
|
||||||
"popCustom": True,
|
"scenes": 6,
|
||||||
"addRoots": [
|
"roots": [
|
||||||
nwItemClass.PLOT,
|
nwItemClass.PLOT,
|
||||||
nwItemClass.CHARACTER,
|
nwItemClass.CHARACTER,
|
||||||
nwItemClass.WORLD,
|
nwItemClass.WORLD,
|
||||||
],
|
],
|
||||||
"addNotes": True,
|
"notes": True,
|
||||||
"numChapters": 0,
|
|
||||||
"numScenes": 6,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
projBuild = ProjectBuilder()
|
builder = ProjectBuilder()
|
||||||
assert projBuild.buildProject(projData) is True
|
assert builder.buildProject(data) is True
|
||||||
|
|
||||||
copyfile(projFile, testFile)
|
copyfile(projFile, testFile)
|
||||||
assert cmpFiles(testFile, compFile, ignoreStart=XML_IGNORE)
|
assert cmpFiles(testFile, compFile, ignoreStart=XML_IGNORE)
|
||||||
|
|
||||||
# END Test testCoreTools_NewCustomB
|
# END Test testCoreTools_ProjectBuilderB
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreTools_NewSample(monkeypatch, mockGUI, fncPath, tstPaths):
|
def testCoreTools_ProjectBuilderSample(monkeypatch, mockGUI, fncPath, tstPaths):
|
||||||
"""Check that we can create a new project can be created from the
|
"""Check that we can create a new project can be created from the
|
||||||
provided sample project via a zip file.
|
provided sample project via a zip file.
|
||||||
"""
|
"""
|
||||||
projData = {
|
data = {
|
||||||
"projName": "Test Sample",
|
"name": "Test Sample",
|
||||||
"projTitle": "Test Novel",
|
"author": "Jane Doe",
|
||||||
"projAuthor": "Jane Doe",
|
"path": fncPath,
|
||||||
"projPath": fncPath,
|
"sample": True,
|
||||||
"popSample": True,
|
|
||||||
"popMinimal": False,
|
|
||||||
"popCustom": False,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
projBuild = ProjectBuilder()
|
builder = ProjectBuilder()
|
||||||
|
|
||||||
# No path set
|
# No path set
|
||||||
assert projBuild.buildProject({"popSample": True}) is False
|
assert builder.buildProject({"popSample": True}) is False
|
||||||
|
|
||||||
# Force the lookup path for assets to our temp folder
|
# Force the lookup path for assets to our temp folder
|
||||||
srcSample = CONFIG._appRoot / "sample"
|
srcSample = CONFIG._appRoot / "sample"
|
||||||
@@ -538,13 +525,13 @@ def testCoreTools_NewSample(monkeypatch, mockGUI, fncPath, tstPaths):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Cannot extract when the zip does not exist
|
# Cannot extract when the zip does not exist
|
||||||
assert projBuild.buildProject(projData) is False
|
assert builder.buildProject(data) is False
|
||||||
|
|
||||||
# Create and open a defective zip file
|
# Create and open a defective zip file
|
||||||
with open(dstSample, mode="w+") as outFile:
|
with open(dstSample, mode="w+") as outFile:
|
||||||
outFile.write("foo")
|
outFile.write("foo")
|
||||||
|
|
||||||
assert projBuild.buildProject(projData) is False
|
assert builder.buildProject(data) is False
|
||||||
dstSample.unlink()
|
dstSample.unlink()
|
||||||
|
|
||||||
# Create a real zip file, and unpack it
|
# Create a real zip file, and unpack it
|
||||||
@@ -553,7 +540,7 @@ def testCoreTools_NewSample(monkeypatch, mockGUI, fncPath, tstPaths):
|
|||||||
for docFile in (srcSample / "content").iterdir():
|
for docFile in (srcSample / "content").iterdir():
|
||||||
zipObj.write(docFile, f"content/{docFile.name}")
|
zipObj.write(docFile, f"content/{docFile.name}")
|
||||||
|
|
||||||
assert projBuild.buildProject(projData) is True
|
assert builder.buildProject(data) is True
|
||||||
dstSample.unlink()
|
dstSample.unlink()
|
||||||
|
|
||||||
# END Test testCoreTools_NewSample
|
# END Test testCoreTools_ProjectBuilderSample
|
||||||
|
|||||||
Reference in New Issue
Block a user