Clean up variables and formatting

This commit is contained in:
Veronica Berglyd Olsen
2024-01-28 00:28:01 +01:00
parent 97b791511f
commit 8e4e6903b1
41 changed files with 1241 additions and 1248 deletions
+16 -16
View File
@@ -213,17 +213,17 @@ def formatInt(value: int) -> str:
if not isinstance(value, int):
return "ERR"
theVal = float(value)
if theVal > 1000.0:
fVal = float(value)
if fVal > 1000.0:
for pF in ["k", "M", "G", "T", "P", "E"]:
theVal /= 1000.0
if theVal < 1000.0:
if theVal < 10.0:
return f"{theVal:4.2f}{nwUnicode.U_THSP}{pF}"
elif theVal < 100.0:
return f"{theVal:4.1f}{nwUnicode.U_THSP}{pF}"
fVal /= 1000.0
if fVal < 1000.0:
if fVal < 10.0:
return f"{fVal:4.2f}{nwUnicode.U_THSP}{pF}"
elif fVal < 100.0:
return f"{fVal:4.1f}{nwUnicode.U_THSP}{pF}"
else:
return f"{theVal:3.0f}{nwUnicode.U_THSP}{pF}"
return f"{fVal:3.0f}{nwUnicode.U_THSP}{pF}"
return str(value)
@@ -275,22 +275,22 @@ def transferCase(source: str, target: str) -> str:
"""Transfers the case of the source word to the target word. This
will consider all upper or lower, and first char capitalisation.
"""
theResult = target
result = target
if not isinstance(source, str) or not isinstance(target, str):
return theResult
return result
if len(target) < 1 or len(source) < 1:
return theResult
return result
if source.istitle():
theResult = target.title()
result = target.title()
if source.isupper():
theResult = target.upper()
result = target.upper()
elif source.islower():
theResult = target.lower()
result = target.lower()
return theResult
return result
def fuzzyTime(seconds: int) -> str:
+2 -6
View File
@@ -235,16 +235,12 @@ class BuildSettings:
def getInt(self, key: str) -> int:
"""Type safe value access for integers."""
value = self._settings.get(key, SETTINGS_TEMPLATE.get(key, (None, None))[1])
if isinstance(value, (int, float)):
return int(value)
return 0
return int(value) if isinstance(value, (int, float)) else 0
def getFloat(self, key: str) -> float:
"""Type safe value access for floats."""
value = self._settings.get(key, SETTINGS_TEMPLATE.get(key, (None, None))[1])
if isinstance(value, (int, float)):
return float(value)
return 0.0
return float(value) if isinstance(value, (int, float)) else 0.0
##
# Setters
+19 -22
View File
@@ -279,28 +279,25 @@ class DocDuplicator:
"""Run through a list of items, duplicate them, and copy the
text content if they are documents.
"""
if not items:
return
nHandle = items[0]
hMap: dict[str, str | None] = {t: None for t in items}
for tHandle in items:
newItem = self._project.tree.duplicate(tHandle)
if newItem is None:
return
hMap[tHandle] = newItem.itemHandle
if newItem.itemParent in hMap:
newItem.setParent(hMap[newItem.itemParent])
self._project.tree.updateItemData(newItem.itemHandle)
if newItem.isFileType():
oldDoc = self._project.storage.getDocument(tHandle)
newDoc = self._project.storage.getDocument(newItem.itemHandle)
if newDoc.fileExists():
if items:
nHandle = items[0]
hMap: dict[str, str | None] = {t: None for t in items}
for tHandle in items:
newItem = self._project.tree.duplicate(tHandle)
if newItem is None:
return
newDoc.writeDocument(oldDoc.readDocument() or "")
yield newItem.itemHandle, nHandle
nHandle = None
hMap[tHandle] = newItem.itemHandle
if newItem.itemParent in hMap:
newItem.setParent(hMap[newItem.itemParent])
self._project.tree.updateItemData(newItem.itemHandle)
if newItem.isFileType():
oldDoc = self._project.storage.getDocument(tHandle)
newDoc = self._project.storage.getDocument(newItem.itemHandle)
if newDoc.fileExists():
return
newDoc.writeDocument(oldDoc.readDocument() or "")
yield newItem.itemHandle, nHandle
nHandle = None
return
# END Class DocDuplicator
@@ -313,7 +310,7 @@ class ProjectBuilder:
def __init__(self) -> None:
self._path = None
self.tr = partial(QCoreApplication.translate, "NWProject")
self.tr = partial(QCoreApplication.translate, "ProjectBuilder")
return
@property
+2 -2
View File
@@ -248,8 +248,8 @@ class NWBuildDocument:
def _setupBuild(self, bldObj: Tokenizer) -> dict:
"""Configure the build object."""
# Get Settings
textFont = self._build.getStr("format.textFont")
textSize = self._build.getInt("format.textSize")
textFont = self._build.getStr("format.textFont")
textSize = self._build.getInt("format.textSize")
fontFamily = textFont or CONFIG.textFont
bldFont = QFont(fontFamily, textSize)
+6 -6
View File
@@ -52,7 +52,7 @@ class NWDocument:
def __init__(self, project: NWProject, tHandle: str | None) -> None:
self._project = project
self._project = project
self._item = None # The currently open item
self._handle = None # The handle of the currently open item
@@ -284,12 +284,12 @@ class NWDocument:
"""Parse the document meta tag and return the name, parent,
class and layout meta values.
"""
theName = self._docMeta.get("name", "")
theParent = self._docMeta.get("parent", None)
theClass = self._docMeta.get("class", None)
theLayout = self._docMeta.get("layout", None)
name = self._docMeta.get("name", "")
parent = self._docMeta.get("parent", None)
itemClass = self._docMeta.get("class", None)
itemLayout = self._docMeta.get("layout", None)
return theName, theParent, theClass, theLayout
return name, parent, itemClass, itemLayout
def getError(self) -> str:
"""Return the last recorded exception."""
+4 -4
View File
@@ -122,8 +122,8 @@ class NWIndex:
for nwItem in self._project.tree:
if nwItem.isFileType():
tHandle = nwItem.itemHandle
theDoc = self._project.storage.getDocument(tHandle)
self.scanText(tHandle, theDoc.readDocument() or "", blockSignal=True)
doc = self._project.storage.getDocument(tHandle)
self.scanText(tHandle, doc.readDocument() or "", blockSignal=True)
self._indexBroken = False
SHARED.indexSignalProxy({"event": "buildIndex"})
return
@@ -148,8 +148,8 @@ class NWIndex:
"""
if tHandle and self._project.tree.checkType(tHandle, nwItemType.FILE):
logger.debug("Re-indexing item '%s'", tHandle)
theDoc = self._project.storage.getDocument(tHandle)
self.scanText(tHandle, theDoc.readDocument() or "")
doc = self._project.storage.getDocument(tHandle)
self.scanText(tHandle, doc.readDocument() or "")
return True
return False
+4 -4
View File
@@ -194,12 +194,12 @@ class Tokenizer(ABC):
##
@property
def theResult(self) -> str:
def result(self) -> str:
"""The result of the build process."""
return self._result
@property
def theMarkdown(self) -> list:
def allMarkdown(self) -> list:
"""The combined novelWriter Markdown text."""
return self._allMarkdown
@@ -358,8 +358,8 @@ class Tokenizer(ABC):
return True
def setText(self, tHandle: str, text: str | None = None) -> bool:
"""Set the text for the tokenizer from a handle. If theText is
not set, load it from the file.
"""Set the text for the tokenizer from a handle. If text is not
set, load it from the file.
"""
self._nwItem = self._project.tree[tHandle]
if self._nwItem is None:
+4 -4
View File
@@ -682,12 +682,12 @@ class ToOdt(Tokenizer):
return parName
oStyle.setParentStyleName(parName)
theID = oStyle.getID()
if theID in self._autoPara:
return self._autoPara[theID][0]
pID = oStyle.getID()
if pID in self._autoPara:
return self._autoPara[pID][0]
newName = "P%d" % (len(self._autoPara) + 1)
self._autoPara[theID] = (newName, oStyle)
self._autoPara[pID] = (newName, oStyle)
return newName
+1 -1
View File
@@ -500,7 +500,7 @@ class NWTree:
##
def _setTreeChanged(self, state: bool) -> None:
"""Set the changed flag to theState, and if being set to True,
"""Set the changed flag to state, and if being set to True,
propagate that state change to the parent NWProject class.
"""
self._changed = state
+3 -3
View File
@@ -77,9 +77,9 @@ class GuiQuoteSelect(QDialog):
minSize = 100
for sKey, sLabel in nwQuotes.SYMBOLS.items():
theText = "[ %s ] %s" % (sKey, trConst(sLabel))
minSize = max(minSize, qMetrics.boundingRect(theText).width())
qtItem = QListWidgetItem(theText)
text = "[ %s ] %s" % (sKey, trConst(sLabel))
minSize = max(minSize, qMetrics.boundingRect(text).width())
qtItem = QListWidgetItem(text)
qtItem.setData(self.D_KEY, sKey)
self.listBox.addItem(qtItem)
if sKey == current:
+3 -3
View File
@@ -256,9 +256,9 @@ class GuiDocHighlighter(QSyntaxHighlighter):
nBlocks = qDoc.blockCount()
tStart = time()
for i in range(nBlocks):
theBlock = qDoc.findBlockByNumber(i)
if theBlock.userState() & cType > 0:
self.rehighlightBlock(theBlock)
block = qDoc.findBlockByNumber(i)
if block.userState() & cType > 0:
self.rehighlightBlock(block)
logger.debug("Document highlighted in %.3f ms" % (1000*(time() - tStart)))
return
+4 -4
View File
@@ -229,7 +229,7 @@ class GuiDocViewer(QTextBrowser):
self.setDocumentTitle(tHandle)
# Replace tabs before setting the HTML, and then put them back in
self.setHtml(aDoc.theResult.replace("\t", "!!tab!!"))
self.setHtml(aDoc.result.replace("\t", "!!tab!!"))
while self.find("!!tab!!"):
self.textCursor().insertText("\t")
@@ -367,9 +367,9 @@ class GuiDocViewer(QTextBrowser):
link = url.url()
logger.debug("Clicked link: '%s'", link)
if len(link) > 0:
theBits = link.split("=")
if len(theBits) == 2:
self.loadDocumentTagRequest.emit(theBits[1], nwDocMode.VIEW)
bits = link.split("=")
if len(bits) == 2:
self.loadDocumentTagRequest.emit(bits[1], nwDocMode.VIEW)
return
@pyqtSlot("QPoint")
+7 -7
View File
@@ -239,9 +239,9 @@ class GuiItemDetails(QWidget):
# Label
# =====
theLabel = nwItem.itemName
if len(theLabel) > 100:
theLabel = theLabel[:96].rstrip()+" ..."
label = nwItem.itemName
if len(label) > 100:
label = label[:96].rstrip()+" ..."
if nwItem.isFileType():
if nwItem.isActive:
@@ -251,14 +251,14 @@ class GuiItemDetails(QWidget):
else:
self.labelIcon.setPixmap(SHARED.theme.getPixmap("noncheckable", (iPx, iPx)))
self.labelData.setText(theLabel)
self.labelData.setText(label)
# Status
# ======
theStatus, theIcon = nwItem.getImportStatus(incIcon=True)
self.statusIcon.setPixmap(theIcon.pixmap(iPx, iPx))
self.statusData.setText(theStatus)
status, icon = nwItem.getImportStatus(incIcon=True)
self.statusIcon.setPixmap(icon.pixmap(iPx, iPx))
self.statusData.setText(status)
# Class
# =====
+4 -4
View File
@@ -726,17 +726,17 @@ class GuiNovelTree(QTreeWidget):
refData = []
refName = ""
theRefs = SHARED.project.index.getReferences(tHandle, sTitle)
refs = SHARED.project.index.getReferences(tHandle, sTitle)
if self._lastCol == NovelTreeColumn.POV:
refData = theRefs[nwKeyWords.POV_KEY]
refData = refs[nwKeyWords.POV_KEY]
refName = self._povLabel
elif self._lastCol == NovelTreeColumn.FOCUS:
refData = theRefs[nwKeyWords.FOCUS_KEY]
refData = refs[nwKeyWords.FOCUS_KEY]
refName = self._focLabel
elif self._lastCol == NovelTreeColumn.PLOT:
refData = theRefs[nwKeyWords.PLOT_KEY]
refData = refs[nwKeyWords.PLOT_KEY]
refName = self._pltLabel
if refData:
+13 -13
View File
@@ -625,12 +625,12 @@ class GuiOutlineTree(QTreeWidget):
self.clear()
if self._firstView:
theLabels = []
labels = []
for i, hItem in enumerate(self._treeOrder):
theLabels.append(trConst(nwLabels.OUTLINE_COLS[hItem]))
labels.append(trConst(nwLabels.OUTLINE_COLS[hItem]))
self._colIdx[hItem] = i
self.setHeaderLabels(theLabels)
self.setHeaderLabels(labels)
for hItem in self._treeOrder:
self.setColumnWidth(self._colIdx[hItem], self._colWidth[hItem])
self.setColumnHidden(self._colIdx[hItem], self._colHidden[hItem])
@@ -990,7 +990,7 @@ class GuiOutlineDetails(QScrollArea):
pIndex = SHARED.project.index
nwItem = SHARED.project.tree[tHandle]
novIdx = pIndex.getItemHeader(tHandle, sTitle)
theRefs = pIndex.getReferences(tHandle, sTitle)
novRefs = pIndex.getReferences(tHandle, sTitle)
if nwItem is None or novIdx is None:
return False
@@ -1015,15 +1015,15 @@ class GuiOutlineDetails(QScrollArea):
self.synopValue.setText(novIdx.synopsis)
self.povKeyValue.setText(self._formatTags(theRefs, nwKeyWords.POV_KEY))
self.focKeyValue.setText(self._formatTags(theRefs, nwKeyWords.FOCUS_KEY))
self.chrKeyValue.setText(self._formatTags(theRefs, nwKeyWords.CHAR_KEY))
self.pltKeyValue.setText(self._formatTags(theRefs, nwKeyWords.PLOT_KEY))
self.timKeyValue.setText(self._formatTags(theRefs, nwKeyWords.TIME_KEY))
self.wldKeyValue.setText(self._formatTags(theRefs, nwKeyWords.WORLD_KEY))
self.objKeyValue.setText(self._formatTags(theRefs, nwKeyWords.OBJECT_KEY))
self.entKeyValue.setText(self._formatTags(theRefs, nwKeyWords.ENTITY_KEY))
self.cstKeyValue.setText(self._formatTags(theRefs, nwKeyWords.CUSTOM_KEY))
self.povKeyValue.setText(self._formatTags(novRefs, nwKeyWords.POV_KEY))
self.focKeyValue.setText(self._formatTags(novRefs, nwKeyWords.FOCUS_KEY))
self.chrKeyValue.setText(self._formatTags(novRefs, nwKeyWords.CHAR_KEY))
self.pltKeyValue.setText(self._formatTags(novRefs, nwKeyWords.PLOT_KEY))
self.timKeyValue.setText(self._formatTags(novRefs, nwKeyWords.TIME_KEY))
self.wldKeyValue.setText(self._formatTags(novRefs, nwKeyWords.WORLD_KEY))
self.objKeyValue.setText(self._formatTags(novRefs, nwKeyWords.OBJECT_KEY))
self.entKeyValue.setText(self._formatTags(novRefs, nwKeyWords.ENTITY_KEY))
self.cstKeyValue.setText(self._formatTags(novRefs, nwKeyWords.CUSTOM_KEY))
return True
+12 -12
View File
@@ -785,24 +785,24 @@ class GuiProjectTree(QTreeWidget):
project structure, and must be called before any code that
depends on this order to be up to date.
"""
theList = []
items = []
for i in range(self.topLevelItemCount()):
item = self.topLevelItem(i)
if isinstance(item, QTreeWidgetItem):
theList = self._scanChildren(theList, item, i)
items = self._scanChildren(items, item, i)
logger.debug("Saving project tree item order")
SHARED.project.setTreeOrder(theList)
SHARED.project.setTreeOrder(items)
return
def getTreeFromHandle(self, tHandle: str) -> list[str]:
"""Recursively return all the child items starting from a given
item handle.
"""
theList = []
theItem = self._getTreeItem(tHandle)
if theItem is not None:
theList = self._scanChildren(theList, theItem, 0)
return theList
result = []
tIten = self._getTreeItem(tHandle)
if tIten is not None:
result = self._scanChildren(result, tIten, 0)
return result
def requestDeleteItem(self, tHandle: str | None = None) -> bool:
"""Request an item deleted from the project tree. This function
@@ -857,11 +857,11 @@ class GuiProjectTree(QTreeWidget):
SHARED.info(self.tr("There is currently no Trash folder in this project."))
return False
theTrash = self.getTreeFromHandle(trashHandle)
if trashHandle in theTrash:
theTrash.remove(trashHandle)
trashItems = self.getTreeFromHandle(trashHandle)
if trashHandle in trashItems:
trashItems.remove(trashHandle)
nTrash = len(theTrash)
nTrash = len(trashItems)
if nTrash == 0:
SHARED.info(self.tr("The Trash folder is already empty."))
return False
+9 -9
View File
@@ -368,22 +368,22 @@ class GuiTheme:
def _setGuiFont(self) -> None:
"""Update the GUI's font style from settings."""
theFont = QFont()
font = QFont()
fontDB = QFontDatabase()
if CONFIG.guiFont not in fontDB.families():
if CONFIG.osWindows and "Arial" in fontDB.families():
# On Windows we default to Arial if possible
theFont.setFamily("Arial")
theFont.setPointSize(10)
font.setFamily("Arial")
font.setPointSize(10)
else:
theFont = fontDB.systemFont(QFontDatabase.GeneralFont)
CONFIG.guiFont = theFont.family()
CONFIG.guiFontSize = theFont.pointSize()
font = fontDB.systemFont(QFontDatabase.GeneralFont)
CONFIG.guiFont = font.family()
CONFIG.guiFontSize = font.pointSize()
else:
theFont.setFamily(CONFIG.guiFont)
theFont.setPointSize(CONFIG.guiFontSize)
font.setFamily(CONFIG.guiFont)
font.setPointSize(CONFIG.guiFontSize)
qApp.setFont(theFont)
qApp.setFont(font)
return
+3 -3
View File
@@ -679,10 +679,10 @@ class GuiMain(QMainWindow):
if loadFile.strip() == "":
return False
theText = None
text = None
try:
with open(loadFile, mode="rt", encoding="utf-8") as inFile:
theText = inFile.read()
text = inFile.read()
CONFIG.setLastPath(loadFile)
except Exception as exc:
SHARED.error(self.tr(
@@ -704,7 +704,7 @@ class GuiMain(QMainWindow):
if not msgYes:
return False
self.docEditor.replaceText(theText)
self.docEditor.replaceText(text)
return True
+5 -5
View File
@@ -375,9 +375,9 @@ class GuiManuscript(QDialog):
@pyqtSlot()
def _printDocument(self) -> None:
"""Open the print preview dialog."""
thePreview = QPrintPreviewDialog(self)
thePreview.paintRequested.connect(self.docPreview.printPreview)
thePreview.exec_()
preview = QPrintPreviewDialog(self)
preview.paintRequested.connect(self.docPreview.printPreview)
preview.exec_()
return
##
@@ -771,8 +771,8 @@ class _PreviewWidget(QTextBrowser):
self.setHtml(html)
qApp.processEvents()
while self.find("!!tab!!"):
theCursor = self.textCursor()
theCursor.insertText("\t")
cursor = self.textCursor()
cursor.insertText("\t")
self.verticalScrollBar().setValue(sPos)
self._docTime = checkInt(data.get("time"), 0)
+4 -4
View File
@@ -1112,10 +1112,10 @@ class _FormatTab(NScrollableForm):
currFont = QFont()
currFont.setFamily(self.textFont.text())
currFont.setPointSize(self.textSize.value())
theFont, theStatus = QFontDialog.getFont(currFont, self)
if theStatus:
self.textFont.setText(theFont.family())
self.textSize.setValue(theFont.pointSize())
newFont, status = QFontDialog.getFont(currFont, self)
if status:
self.textFont.setText(newFont.family())
self.textSize.setValue(newFont.pointSize())
return
@pyqtSlot(int)
+3 -3
View File
@@ -455,19 +455,19 @@ class _ContentsPage(NFixedPage):
pTotal = 0
tPages = 1
theList = []
entries = []
for _, tLevel, tTitle, wCount in self._data:
pCount = math.ceil(wCount/wpPage)
if dblPages:
pCount += pCount%2
pTotal += pCount
theList.append((tLevel, tTitle, wCount, pCount))
entries.append((tLevel, tTitle, wCount, pCount))
pMax = pTotal - fstPage
self.tocTree.clear()
for tLevel, tTitle, wCount, pCount in theList:
for tLevel, tTitle, wCount, pCount in entries:
newItem = QTreeWidgetItem()
if tPages <= fstPage:
+2 -2
View File
@@ -585,13 +585,13 @@ class GuiWritingStats(QDialog):
newItem.setText(self.C_COUNT, f"{nWords:n}")
if nWords > 0 and listMax > 0:
theBar = self.barImage.scaled(
wBar = self.barImage.scaled(
int(200*min(nWords, histMax)/listMax),
self.barHeight,
Qt.IgnoreAspectRatio,
Qt.FastTransformation
)
newItem.setData(self.C_BAR, Qt.DecorationRole, theBar)
newItem.setData(self.C_BAR, Qt.DecorationRole, wBar)
newItem.setTextAlignment(self.C_LENGTH, Qt.AlignRight)
newItem.setTextAlignment(self.C_IDLE, Qt.AlignRight)
+5 -5
View File
@@ -47,9 +47,9 @@ def extractVersion(beQuiet: bool = False) -> tuple[str, str, str]:
"""Extract the novelWriter version number without having to import
anything else from the main package.
"""
def getValue(theString):
theBits = theString.partition("=")
return theBits[2].strip().strip('"')
def getValue(text):
bits = text.partition("=")
return bits[2].strip().strip('"')
numVers = "0"
hexVers = "0x0"
@@ -1744,7 +1744,7 @@ def winUninstall() -> None:
print("")
print("Removing registry keys ...")
theKeys = [
keys = [
r"Software\Classes\novelWriterProject.nwx\shell\open\command",
r"Software\Classes\novelWriterProject.nwx\shell\open",
r"Software\Classes\novelWriterProject.nwx\shell",
@@ -1756,7 +1756,7 @@ def winUninstall() -> None:
r"Software\Classes\Applications\novelWriter.pyw",
]
for aKey in theKeys:
for aKey in keys:
try:
winreg.DeleteKey(winreg.HKEY_CURRENT_USER, aKey)
print("Deleted: HKEY_CURRENT_USER\\%s" % aKey)
+4 -4
View File
@@ -39,7 +39,7 @@ class MockGuiMain(QWidget):
def postLaunchTasks(self, cmdOpen):
return
def setStatus(self, theMessage):
def setStatus(self, message):
return
def openProject(self, projPath):
@@ -63,10 +63,10 @@ class MockStatusBar:
def __init__(self):
return
def setStatus(self, theText):
def setStatus(self, text):
return
def updateProjectStatus(self, theStatus):
def updateProjectStatus(self, status):
return
# END Class MockStatusBar
@@ -89,7 +89,7 @@ class MockApp:
def __init__(self):
return
def installTranslator(self, theLang):
def installTranslator(self, language):
return
# END Class MockApp
+8 -8
View File
@@ -177,19 +177,19 @@ def testBaseConfig_Localisation(fncPath, tstPaths):
tstConf.initLocalisation(tstApp) # type: ignore
# Check Lists
theList = tstConf.listLanguages(tstConf.LANG_NW)
assert theList == [("en_GB", "British English")]
theList = tstConf.listLanguages(tstConf.LANG_PROJ)
assert theList == [("en_GB", "British English")]
theList = tstConf.listLanguages(None) # type: ignore
assert theList == []
languages = tstConf.listLanguages(tstConf.LANG_NW)
assert languages == [("en_GB", "British English")]
languages = tstConf.listLanguages(tstConf.LANG_PROJ)
assert languages == [("en_GB", "British English")]
languages = tstConf.listLanguages(None) # type: ignore
assert languages == []
# Add Language
copyfile(tstPaths.filesDir / "nw_en_GB.qm", i18nDir / "nw_fr.qm")
writeFile(i18nDir / "nw_fr.ts", "")
theList = tstConf.listLanguages(tstConf.LANG_NW)
assert theList == [("en_GB", "British English"), ("fr", "Français")]
languages = tstConf.listLanguages(tstConf.LANG_NW)
assert languages == [("en_GB", "British English"), ("fr", "Français")]
# END Test testBaseConfig_Localisation
+8 -8
View File
@@ -43,19 +43,19 @@ def testBaseError_Dialog(qtbot, monkeypatch, nwGUI):
with monkeypatch.context() as mp:
mp.setattr("PyQt5.QtCore.QSysInfo.kernelVersion", lambda: "1.2.3")
nwErr.setMessage(Exception, "Fine Error", None)
theMessage = nwErr.msgBody.toPlainText()
assert theMessage != ""
assert "Fine Error" in theMessage
assert "Exception" in theMessage
assert "(1.2.3)" in theMessage
message = nwErr.msgBody.toPlainText()
assert message != ""
assert "Fine Error" in message
assert "Exception" in message
assert "(1.2.3)" in message
# No kernel version retrieved
with monkeypatch.context() as mp:
mp.setattr("PyQt5.QtCore.QSysInfo.kernelVersion", causeException)
nwErr.setMessage(Exception, "Almost Fine Error", None)
theMessage = nwErr.msgBody.toPlainText()
assert theMessage != ""
assert "(Unknown)" in theMessage
message = nwErr.msgBody.toPlainText()
assert message != ""
assert "(Unknown)" in message
nwErr._doClose()
nwErr.close()
+70 -70
View File
@@ -35,51 +35,51 @@ def testCoreDocument_LoadSave(monkeypatch, mockGUI, fncPath, mockRnd):
"""Test loading and saving a document with the NWDocument class."""
monkeypatch.setattr("novelwriter.core.document.time", lambda: MOCK_TIME)
theProject = NWProject()
project = NWProject()
mockRnd.reset()
buildTestProject(theProject, fncPath)
buildTestProject(project, fncPath)
# Read Document
# =============
# Not a valid handle
theDoc = NWDocument(theProject, "stuff")
assert bool(theDoc) is False
assert theDoc.readDocument() is None
assert theDoc.fileExists() is False
doc = NWDocument(project, "stuff")
assert bool(doc) is False
assert doc.readDocument() is None
assert doc.fileExists() is False
# Non-existent handle
theDoc = NWDocument(theProject, C.hInvalid)
assert theDoc.readDocument() is None
assert theDoc._lastHash == ""
assert theDoc.fileExists() is False
doc = NWDocument(project, C.hInvalid)
assert doc.readDocument() is None
assert doc._lastHash == ""
assert doc.fileExists() is False
# No content path
with monkeypatch.context() as mp:
mp.setattr("novelwriter.core.storage.NWStorage.contentPath", property(lambda *a: None))
theDoc = NWDocument(theProject, C.hSceneDoc)
assert theDoc.readDocument() is None
assert theDoc.fileExists() is False
doc = NWDocument(project, C.hSceneDoc)
assert doc.readDocument() is None
assert doc.fileExists() is False
# Cause open() to fail while loading
with monkeypatch.context() as mp:
mp.setattr("builtins.open", causeOSError)
theDoc = NWDocument(theProject, C.hSceneDoc)
assert theDoc.fileExists() is True
assert theDoc.readDocument() is None
assert theDoc.getError() == "OSError: Mock OSError"
doc = NWDocument(project, C.hSceneDoc)
assert doc.fileExists() is True
assert doc.readDocument() is None
assert doc.getError() == "OSError: Mock OSError"
# Load the text
theDoc = NWDocument(theProject, C.hSceneDoc)
assert theDoc.fileExists() is True
assert theDoc.readDocument() == "### New Scene\n\n"
doc = NWDocument(project, C.hSceneDoc)
assert doc.fileExists() is True
assert doc.readDocument() == "### New Scene\n\n"
# Try to open a new (non-existent) file
xHandle = theProject.newFile("New File", C.hNovelRoot)
theDoc = NWDocument(theProject, xHandle)
assert bool(theDoc) is True
assert repr(theDoc) == f"<NWDocument handle={xHandle}>"
assert theDoc.readDocument() == ""
xHandle = project.newFile("New File", C.hNovelRoot)
doc = NWDocument(project, xHandle)
assert bool(doc) is True
assert repr(doc) == f"<NWDocument handle={xHandle}>"
assert doc.readDocument() == ""
# Write Document
# ==============
@@ -87,17 +87,17 @@ def testCoreDocument_LoadSave(monkeypatch, mockGUI, fncPath, mockRnd):
# No content path
with monkeypatch.context() as mp:
mp.setattr("novelwriter.core.storage.NWStorage.contentPath", property(lambda *a: None))
theDoc = NWDocument(theProject, xHandle)
assert theDoc.writeDocument("") is False
doc = NWDocument(project, xHandle)
assert doc.writeDocument("") is False
# Set handle and save
theText = "### Test File\n\nText ...\n\n"
theDoc = NWDocument(theProject, xHandle)
assert theDoc.readDocument(xHandle) == "" # type: ignore
assert theDoc.writeDocument(theText) is True
text = "### Test File\n\nText ...\n\n"
doc = NWDocument(project, xHandle)
assert doc.readDocument(xHandle) == "" # type: ignore
assert doc.writeDocument(text) is True
# Save again to ensure temp file and previous file is handled
assert theDoc.writeDocument(theText) is True
assert doc.writeDocument(text) is True
# Check file content
docPath = fncPath / "content" / f"{xHandle}.nwd"
@@ -113,62 +113,62 @@ def testCoreDocument_LoadSave(monkeypatch, mockGUI, fncPath, mockRnd):
# Alter the document on disk and save again
writeFile(docPath, "blablabla")
assert theDoc.writeDocument(theText) is False
assert doc.writeDocument(text) is False
# Force the overwrite
assert theDoc.writeDocument(theText, forceWrite=True) is True
assert doc.writeDocument(text, forceWrite=True) is True
# Force no meta data
theDoc._item = None
assert theDoc.writeDocument(theText) is True
assert readFile(docPath) == theText
doc._item = None
assert doc.writeDocument(text) is True
assert readFile(docPath) == text
# Cause open() to fail while saving
with monkeypatch.context() as mp:
mp.setattr("builtins.open", causeOSError)
assert theDoc.writeDocument(theText) is False
assert theDoc.getError() == "OSError: Mock OSError"
assert doc.writeDocument(text) is False
assert doc.getError() == "OSError: Mock OSError"
theDoc._docError = ""
assert theDoc.getError() == ""
doc._docError = ""
assert doc.getError() == ""
# Cause os.replace() to fail while saving
with monkeypatch.context() as mp:
mp.setattr("pathlib.Path.replace", causeOSError)
assert theDoc.writeDocument(theText) is False
assert theDoc.getError() == "OSError: Mock OSError"
assert doc.writeDocument(text) is False
assert doc.getError() == "OSError: Mock OSError"
theDoc._docError = ""
assert theDoc.getError() == ""
doc._docError = ""
assert doc.getError() == ""
# Saving with no handle
theDoc._handle = None
assert theDoc.writeDocument(theText) is False
doc._handle = None
assert doc.writeDocument(text) is False
# Delete Document
# ===============
# Delete a non-existing document
theDoc = NWDocument(theProject, "stuff")
assert theDoc.deleteDocument() is False
doc = NWDocument(project, "stuff")
assert doc.deleteDocument() is False
assert docPath.exists()
# No content path
with monkeypatch.context() as mp:
mp.setattr("novelwriter.core.storage.NWStorage.contentPath", property(lambda *a: None))
theDoc = NWDocument(theProject, xHandle)
assert theDoc.deleteDocument() is False
doc = NWDocument(project, xHandle)
assert doc.deleteDocument() is False
# Cause the delete to fail
with monkeypatch.context() as mp:
mp.setattr("pathlib.Path.unlink", causeOSError)
theDoc = NWDocument(theProject, xHandle)
assert theDoc.deleteDocument() is False
assert theDoc.getError() == "OSError: Mock OSError"
doc = NWDocument(project, xHandle)
assert doc.deleteDocument() is False
assert doc.getError() == "OSError: Mock OSError"
# Make the delete pass
theDoc = NWDocument(theProject, xHandle)
assert theDoc.deleteDocument() is True
doc = NWDocument(project, xHandle)
assert doc.deleteDocument() is True
assert not docPath.exists()
# END Test testCoreDocument_Load
@@ -179,31 +179,31 @@ def testCoreDocument_Methods(monkeypatch, mockGUI, fncPath, mockRnd):
"""Test other methods of the NWDocument class."""
monkeypatch.setattr("novelwriter.core.document.time", lambda: MOCK_TIME)
theProject = NWProject()
project = NWProject()
mockRnd.reset()
buildTestProject(theProject, fncPath)
buildTestProject(project, fncPath)
theDoc = NWDocument(theProject, C.hSceneDoc)
doc = NWDocument(project, C.hSceneDoc)
docPath = fncPath / "content" / f"{C.hSceneDoc}.nwd"
assert theDoc.readDocument() == "### New Scene\n\n"
assert doc.readDocument() == "### New Scene\n\n"
# Check location
assert theDoc.fileLocation == str(docPath)
assert doc.fileLocation == str(docPath)
# Check the item
assert theDoc.nwItem is not None
assert theDoc.nwItem.itemHandle == C.hSceneDoc # type: ignore
assert doc.nwItem is not None
assert doc.nwItem.itemHandle == C.hSceneDoc # type: ignore
# Check the meta
theName, theParent, theClass, theLayout = theDoc.getMeta()
assert theName == "New Scene"
assert theParent == C.hChapterDir
assert theClass == nwItemClass.NOVEL
assert theLayout == nwItemLayout.DOCUMENT
name, parent, itemClass, itemLayout = doc.getMeta()
assert name == "New Scene"
assert parent == C.hChapterDir
assert itemClass == nwItemClass.NOVEL
assert itemLayout == nwItemLayout.DOCUMENT
# Add meta data garbage
assert theDoc.writeDocument("%%~ stuff\n### Test File\n\nText ...\n\n")
assert doc.writeDocument("%%~ stuff\n### Test File\n\nText ...\n\n")
assert readFile(docPath) == (
"%%~name: New Scene\n"
f"%%~path: {C.hChapterDir}/{C.hSceneDoc}\n"
@@ -215,6 +215,6 @@ def testCoreDocument_Methods(monkeypatch, mockGUI, fncPath, mockRnd):
"Text ...\n\n"
)
assert theDoc.readDocument() == "### Test File\n\nText ...\n\n"
assert doc.readDocument() == "### Test File\n\nText ...\n\n"
# END Test testCoreDocument_Methods
+25 -25
View File
@@ -160,52 +160,52 @@ def testCoreIndex_ScanThis(mockGUI):
project = NWProject()
index = project.index
isValid, theBits, thePos = index.scanThis("tag: this, and this")
isValid, bits, pos = index.scanThis("tag: this, and this")
assert isValid is False
isValid, theBits, thePos = index.scanThis("@")
isValid, bits, pos = index.scanThis("@")
assert isValid is False
isValid, theBits, thePos = index.scanThis("@:")
isValid, bits, pos = index.scanThis("@:")
assert isValid is False
isValid, theBits, thePos = index.scanThis(" @a: b")
isValid, bits, pos = index.scanThis(" @a: b")
assert isValid is False
isValid, theBits, thePos = index.scanThis("@a:")
isValid, bits, pos = index.scanThis("@a:")
assert isValid is True
assert theBits == ["@a"]
assert thePos == [0]
assert bits == ["@a"]
assert pos == [0]
isValid, theBits, thePos = index.scanThis("@a:b")
isValid, bits, pos = index.scanThis("@a:b")
assert isValid is True
assert theBits == ["@a", "b"]
assert thePos == [0, 3]
assert bits == ["@a", "b"]
assert pos == [0, 3]
isValid, theBits, thePos = index.scanThis("@a:b,c,d")
isValid, bits, pos = index.scanThis("@a:b,c,d")
assert isValid is True
assert theBits == ["@a", "b", "c", "d"]
assert thePos == [0, 3, 5, 7]
assert bits == ["@a", "b", "c", "d"]
assert pos == [0, 3, 5, 7]
isValid, theBits, thePos = index.scanThis("@a : b , c , d")
isValid, bits, pos = index.scanThis("@a : b , c , d")
assert isValid is True
assert theBits == ["@a", "b", "c", "d"]
assert thePos == [0, 5, 9, 13]
assert bits == ["@a", "b", "c", "d"]
assert pos == [0, 5, 9, 13]
isValid, theBits, thePos = index.scanThis("@tag: this, and this")
isValid, bits, pos = index.scanThis("@tag: this, and this")
assert isValid is True
assert theBits == ["@tag", "this", "and this"]
assert thePos == [0, 6, 12]
assert bits == ["@tag", "this", "and this"]
assert pos == [0, 6, 12]
isValid, theBits, thePos = index.scanThis("@tag: this,, and this")
isValid, bits, pos = index.scanThis("@tag: this,, and this")
assert isValid is True
assert theBits == ["@tag", "this", "", "and this"]
assert thePos == [0, 6, 11, 13]
assert bits == ["@tag", "this", "", "and this"]
assert pos == [0, 6, 11, 13]
isValid, theBits, thePos = index.scanThis("@tag: this, , and this")
isValid, bits, pos = index.scanThis("@tag: this, , and this")
assert isValid is True
assert theBits == ["@tag", "this", "", "and this"]
assert thePos == [0, 6, 12, 14]
assert bits == ["@tag", "this", "", "and this"]
assert pos == [0, 6, 12, 14]
project.closeProject()
+349 -349
View File
@@ -35,150 +35,150 @@ from novelwriter.core.project import NWProject
@pytest.mark.core
def testCoreItem_Setters(mockGUI, mockRnd, fncPath):
"""Test all the simple setters for the NWItem class."""
theProject = NWProject()
project = NWProject()
mockRnd.reset()
buildTestProject(theProject, fncPath)
theItem = NWItem(theProject, "0000000000000")
assert theItem.itemHandle == "0000000000000"
buildTestProject(project, fncPath)
item = NWItem(project, "0000000000000")
assert item.itemHandle == "0000000000000"
statusKeys = ["s000000", "s000001", "s000002", "s000003"]
importKeys = ["i000004", "i000005", "i000006", "i000007"]
# Name
theItem.setName("A Name")
assert theItem.itemName == "A Name"
theItem.setName("\t A Name ")
assert theItem.itemName == "A Name"
theItem.setName("\t A\t\u2009\u202f\u2002\u2003\u2028\u2029Name ")
assert theItem.itemName == "A Name"
theItem.setName(123)
assert theItem.itemName == ""
item.setName("A Name")
assert item.itemName == "A Name"
item.setName("\t A Name ")
assert item.itemName == "A Name"
item.setName("\t A\t\u2009\u202f\u2002\u2003\u2028\u2029Name ")
assert item.itemName == "A Name"
item.setName(123)
assert item.itemName == ""
# Parent
theItem.setParent(None)
assert theItem.itemParent is None
theItem.setParent(123)
assert theItem.itemParent is None
theItem.setParent("0123456789abcdef")
assert theItem.itemParent is None
theItem.setParent("0123456789abg")
assert theItem.itemParent is None
theItem.setParent("0123456789abc")
assert theItem.itemParent == "0123456789abc"
item.setParent(None)
assert item.itemParent is None
item.setParent(123)
assert item.itemParent is None
item.setParent("0123456789abcdef")
assert item.itemParent is None
item.setParent("0123456789abg")
assert item.itemParent is None
item.setParent("0123456789abc")
assert item.itemParent == "0123456789abc"
# Root
theItem.setRoot(None)
assert theItem.itemRoot is None
theItem.setRoot(123)
assert theItem.itemRoot is None
theItem.setRoot("0123456789abcdef")
assert theItem.itemRoot is None
theItem.setRoot("0123456789abg")
assert theItem.itemRoot is None
theItem.setRoot("0123456789abc")
assert theItem.itemRoot == "0123456789abc"
item.setRoot(None)
assert item.itemRoot is None
item.setRoot(123)
assert item.itemRoot is None
item.setRoot("0123456789abcdef")
assert item.itemRoot is None
item.setRoot("0123456789abg")
assert item.itemRoot is None
item.setRoot("0123456789abc")
assert item.itemRoot == "0123456789abc"
# Order
theItem.setOrder(None)
assert theItem.itemOrder == 0
theItem.setOrder("1")
assert theItem.itemOrder == 1
theItem.setOrder(1)
assert theItem.itemOrder == 1
item.setOrder(None)
assert item.itemOrder == 0
item.setOrder("1")
assert item.itemOrder == 1
item.setOrder(1)
assert item.itemOrder == 1
# Importance
theItem._class = nwItemClass.CHARACTER
theItem.setImport("Word")
assert theItem.itemImport == importKeys[0] # Default
item._class = nwItemClass.CHARACTER
item.setImport("Word")
assert item.itemImport == importKeys[0] # Default
for key in importKeys:
theItem.setImport(key)
assert theItem.itemImport == key
item.setImport(key)
assert item.itemImport == key
# Status
theItem._class = nwItemClass.NOVEL
theItem.setStatus("Word")
assert theItem.itemStatus == statusKeys[0] # Default
item._class = nwItemClass.NOVEL
item.setStatus("Word")
assert item.itemStatus == statusKeys[0] # Default
for key in statusKeys:
theItem.setStatus(key)
assert theItem.itemStatus == key
item.setStatus(key)
assert item.itemStatus == key
# Status/Importance Wrapper
theItem._class = nwItemClass.CHARACTER
item._class = nwItemClass.CHARACTER
for key in importKeys:
theItem.setImport(key)
assert theItem.itemImport == key
assert theItem.itemStatus == statusKeys[3] # Should not change
item.setImport(key)
assert item.itemImport == key
assert item.itemStatus == statusKeys[3] # Should not change
theItem._class = nwItemClass.NOVEL
item._class = nwItemClass.NOVEL
for key in statusKeys:
theItem.setStatus(key)
assert theItem.itemImport == importKeys[3] # Should not change
assert theItem.itemStatus == key
item.setStatus(key)
assert item.itemImport == importKeys[3] # Should not change
assert item.itemStatus == key
# Expanded
theItem.setExpanded(8)
assert theItem.isExpanded is False
theItem.setExpanded(None)
assert theItem.isExpanded is False
theItem.setExpanded("None")
assert theItem.isExpanded is False
theItem.setExpanded("What?")
assert theItem.isExpanded is False
theItem.setExpanded("True")
assert theItem.isExpanded is False
theItem.setExpanded(True)
assert theItem.isExpanded is True
item.setExpanded(8)
assert item.isExpanded is False
item.setExpanded(None)
assert item.isExpanded is False
item.setExpanded("None")
assert item.isExpanded is False
item.setExpanded("What?")
assert item.isExpanded is False
item.setExpanded("True")
assert item.isExpanded is False
item.setExpanded(True)
assert item.isExpanded is True
# Active
theItem.setActive(8)
assert theItem.isActive is False
theItem.setActive(None)
assert theItem.isActive is False
theItem.setActive("None")
assert theItem.isActive is False
theItem.setActive("What?")
assert theItem.isActive is False
theItem.setActive("True")
assert theItem.isActive is False
theItem.setActive(True)
assert theItem.isActive is True
item.setActive(8)
assert item.isActive is False
item.setActive(None)
assert item.isActive is False
item.setActive("None")
assert item.isActive is False
item.setActive("What?")
assert item.isActive is False
item.setActive("True")
assert item.isActive is False
item.setActive(True)
assert item.isActive is True
# CharCount
theItem.setCharCount(None)
assert theItem.charCount == 0
theItem.setCharCount("1")
assert theItem.charCount == 0
theItem.setCharCount(1)
assert theItem.charCount == 1
item.setCharCount(None)
assert item.charCount == 0
item.setCharCount("1")
assert item.charCount == 0
item.setCharCount(1)
assert item.charCount == 1
# WordCount
theItem.setWordCount(None)
assert theItem.wordCount == 0
theItem.setWordCount("1")
assert theItem.wordCount == 0
theItem.setWordCount(1)
assert theItem.wordCount == 1
item.setWordCount(None)
assert item.wordCount == 0
item.setWordCount("1")
assert item.wordCount == 0
item.setWordCount(1)
assert item.wordCount == 1
# ParaCount
theItem.setParaCount(None)
assert theItem.paraCount == 0
theItem.setParaCount("1")
assert theItem.paraCount == 0
theItem.setParaCount(1)
assert theItem.paraCount == 1
item.setParaCount(None)
assert item.paraCount == 0
item.setParaCount("1")
assert item.paraCount == 0
item.setParaCount(1)
assert item.paraCount == 1
# CursorPos
theItem.setCursorPos(None)
assert theItem.cursorPos == 0
theItem.setCursorPos("1")
assert theItem.cursorPos == 0
theItem.setCursorPos(1)
assert theItem.cursorPos == 1
item.setCursorPos(None)
assert item.cursorPos == 0
item.setCursorPos("1")
assert item.cursorPos == 0
item.setCursorPos(1)
assert item.cursorPos == 1
# Initial Count
theItem.setWordCount(234)
theItem.saveInitialCount()
assert theItem.initCount == 234
item.setWordCount(234)
item.saveInitialCount()
assert item.initCount == 234
# END Test testCoreItem_Setters
@@ -186,91 +186,91 @@ def testCoreItem_Setters(mockGUI, mockRnd, fncPath):
@pytest.mark.core
def testCoreItem_Methods(mockGUI, mockRnd, fncPath):
"""Test the simple methods of the NWItem class."""
theProject = NWProject()
project = NWProject()
mockRnd.reset()
buildTestProject(theProject, fncPath)
theItem = NWItem(theProject, "0000000000000")
buildTestProject(project, fncPath)
item = NWItem(project, "0000000000000")
# Describe Me
# ===========
assert theItem.describeMe() == "None"
assert item.describeMe() == "None"
theItem.setType("ROOT")
assert theItem.describeMe() == "Root Folder"
assert theItem.isRootType() is True
item.setType("ROOT")
assert item.describeMe() == "Root Folder"
assert item.isRootType() is True
theItem.setType("FOLDER")
assert theItem.describeMe() == "Folder"
assert theItem.isFolderType() is True
item.setType("FOLDER")
assert item.describeMe() == "Folder"
assert item.isFolderType() is True
theItem.setType("FILE")
theItem.setLayout("DOCUMENT")
assert theItem.isFileType() is True
assert theItem.isDocumentLayout() is True
item.setType("FILE")
item.setLayout("DOCUMENT")
assert item.isFileType() is True
assert item.isDocumentLayout() is True
theItem.setMainHeading("HH")
assert theItem.mainHeading == "H0"
assert theItem.describeMe() == "Novel Document"
item.setMainHeading("HH")
assert item.mainHeading == "H0"
assert item.describeMe() == "Novel Document"
theItem.setMainHeading("H0")
assert theItem.mainHeading == "H0"
assert theItem.describeMe() == "Novel Document"
item.setMainHeading("H0")
assert item.mainHeading == "H0"
assert item.describeMe() == "Novel Document"
theItem.setMainHeading("H1")
assert theItem.mainHeading == "H1"
assert theItem.describeMe() == "Novel Title Page"
item.setMainHeading("H1")
assert item.mainHeading == "H1"
assert item.describeMe() == "Novel Title Page"
theItem.setMainHeading("H2")
assert theItem.mainHeading == "H2"
assert theItem.describeMe() == "Novel Chapter"
item.setMainHeading("H2")
assert item.mainHeading == "H2"
assert item.describeMe() == "Novel Chapter"
theItem.setMainHeading("H3")
assert theItem.mainHeading == "H3"
assert theItem.describeMe() == "Novel Scene"
item.setMainHeading("H3")
assert item.mainHeading == "H3"
assert item.describeMe() == "Novel Scene"
theItem.setMainHeading("H4")
assert theItem.mainHeading == "H4"
assert theItem.describeMe() == "Novel Section"
item.setMainHeading("H4")
assert item.mainHeading == "H4"
assert item.describeMe() == "Novel Section"
theItem.setMainHeading("H5")
assert theItem.mainHeading == "H4"
assert theItem.describeMe() == "Novel Section"
item.setMainHeading("H5")
assert item.mainHeading == "H4"
assert item.describeMe() == "Novel Section"
theItem.setLayout("NOTE")
assert theItem.isNoteLayout() is True
assert theItem.describeMe() == "Project Note"
item.setLayout("NOTE")
assert item.isNoteLayout() is True
assert item.describeMe() == "Project Note"
# Status + Icon
# =============
theItem.setType("FILE")
theItem.setStatus(C.sNote)
theItem.setImport(C.iMinor)
item.setType("FILE")
item.setStatus(C.sNote)
item.setImport(C.iMinor)
theItem.setClass("NOVEL")
stT, stI = theItem.getImportStatus()
item.setClass("NOVEL")
stT, stI = item.getImportStatus()
assert stT == "Note"
assert isinstance(stI, QIcon)
theItem.setClass("CHARACTER")
stT, stI = theItem.getImportStatus()
item.setClass("CHARACTER")
stT, stI = item.getImportStatus()
assert stT == "Minor"
assert isinstance(stI, QIcon)
# Representation
# ==============
theItem.setName("New Item")
theItem.setParent("1111111111111")
assert repr(theItem) == "<NWItem handle=0000000000000, parent=1111111111111, name='New Item'>"
item.setName("New Item")
item.setParent("1111111111111")
assert repr(item) == "<NWItem handle=0000000000000, parent=1111111111111, name='New Item'>"
# Truthiness
# ==========
# Is True if the handle evaluates to True
assert bool(NWItem(theProject, "0000000000000")) is True
assert bool(NWItem(theProject, "")) is False
assert bool(NWItem(project, "0000000000000")) is True
assert bool(NWItem(project, "")) is False
# Copy an Item
# ============
@@ -302,11 +302,11 @@ def testCoreItem_Methods(mockGUI, mockRnd, fncPath):
}
# Get the scene item
scItem = theProject.tree[C.hSceneDoc]
scItem = project.tree[C.hSceneDoc]
assert isinstance(scItem, NWItem)
# Duplicate and update the expected content with a new handle
cpHandle = theProject.tree._makeHandle()
cpHandle = project.tree._makeHandle()
cpData = copy.deepcopy(scData)
cpData["itemAttr"]["handle"] = cpHandle
@@ -334,26 +334,26 @@ def testCoreItem_TypeSetter(mockGUI):
"""Test the setter for all the nwItemType values for the NWItem
class.
"""
theProject = NWProject()
theItem = NWItem(theProject, "0000000000000")
project = NWProject()
item = NWItem(project, "0000000000000")
# Type
theItem.setType(None)
assert theItem.itemType == nwItemType.NO_TYPE
theItem.setType("NONSENSE")
assert theItem.itemType == nwItemType.NO_TYPE
theItem.setType("NO_TYPE")
assert theItem.itemType == nwItemType.NO_TYPE
theItem.setType("ROOT")
assert theItem.itemType == nwItemType.ROOT
theItem.setType("FOLDER")
assert theItem.itemType == nwItemType.FOLDER
theItem.setType("FILE")
assert theItem.itemType == nwItemType.FILE
item.setType(None)
assert item.itemType == nwItemType.NO_TYPE
item.setType("NONSENSE")
assert item.itemType == nwItemType.NO_TYPE
item.setType("NO_TYPE")
assert item.itemType == nwItemType.NO_TYPE
item.setType("ROOT")
assert item.itemType == nwItemType.ROOT
item.setType("FOLDER")
assert item.itemType == nwItemType.FOLDER
item.setType("FILE")
assert item.itemType == nwItemType.FILE
# Alternative
theItem.setType(nwItemType.ROOT)
assert theItem.itemType == nwItemType.ROOT
item.setType(nwItemType.ROOT)
assert item.itemType == nwItemType.ROOT
# END Test testCoreItem_TypeSetter
@@ -363,84 +363,84 @@ def testCoreItem_ClassSetter(mockGUI):
"""Test the setter for all the nwItemClass values for the NWItem
class.
"""
theProject = NWProject()
theItem = NWItem(theProject, "0000000000000")
project = NWProject()
item = NWItem(project, "0000000000000")
# Class
theItem.setClass(None)
assert theItem.itemClass == nwItemClass.NO_CLASS
theItem.setClass("NONSENSE")
assert theItem.itemClass == nwItemClass.NO_CLASS
item.setClass(None)
assert item.itemClass == nwItemClass.NO_CLASS
item.setClass("NONSENSE")
assert item.itemClass == nwItemClass.NO_CLASS
theItem.setClass("NO_CLASS")
assert theItem.itemClass == nwItemClass.NO_CLASS
assert theItem.isNovelLike() is False
assert theItem.documentAllowed() is False
assert theItem.isInactiveClass() is True
item.setClass("NO_CLASS")
assert item.itemClass == nwItemClass.NO_CLASS
assert item.isNovelLike() is False
assert item.documentAllowed() is False
assert item.isInactiveClass() is True
theItem.setClass("NOVEL")
assert theItem.itemClass == nwItemClass.NOVEL
assert theItem.isNovelLike() is True
assert theItem.documentAllowed() is True
assert theItem.isInactiveClass() is False
item.setClass("NOVEL")
assert item.itemClass == nwItemClass.NOVEL
assert item.isNovelLike() is True
assert item.documentAllowed() is True
assert item.isInactiveClass() is False
theItem.setClass("PLOT")
assert theItem.itemClass == nwItemClass.PLOT
assert theItem.isNovelLike() is False
assert theItem.documentAllowed() is False
assert theItem.isInactiveClass() is False
item.setClass("PLOT")
assert item.itemClass == nwItemClass.PLOT
assert item.isNovelLike() is False
assert item.documentAllowed() is False
assert item.isInactiveClass() is False
theItem.setClass("CHARACTER")
assert theItem.itemClass == nwItemClass.CHARACTER
assert theItem.isNovelLike() is False
assert theItem.documentAllowed() is False
assert theItem.isInactiveClass() is False
item.setClass("CHARACTER")
assert item.itemClass == nwItemClass.CHARACTER
assert item.isNovelLike() is False
assert item.documentAllowed() is False
assert item.isInactiveClass() is False
theItem.setClass("WORLD")
assert theItem.itemClass == nwItemClass.WORLD
assert theItem.isNovelLike() is False
assert theItem.documentAllowed() is False
assert theItem.isInactiveClass() is False
item.setClass("WORLD")
assert item.itemClass == nwItemClass.WORLD
assert item.isNovelLike() is False
assert item.documentAllowed() is False
assert item.isInactiveClass() is False
theItem.setClass("TIMELINE")
assert theItem.itemClass == nwItemClass.TIMELINE
assert theItem.isNovelLike() is False
assert theItem.documentAllowed() is False
assert theItem.isInactiveClass() is False
item.setClass("TIMELINE")
assert item.itemClass == nwItemClass.TIMELINE
assert item.isNovelLike() is False
assert item.documentAllowed() is False
assert item.isInactiveClass() is False
theItem.setClass("OBJECT")
assert theItem.itemClass == nwItemClass.OBJECT
assert theItem.isNovelLike() is False
assert theItem.documentAllowed() is False
assert theItem.isInactiveClass() is False
item.setClass("OBJECT")
assert item.itemClass == nwItemClass.OBJECT
assert item.isNovelLike() is False
assert item.documentAllowed() is False
assert item.isInactiveClass() is False
theItem.setClass("ENTITY")
assert theItem.itemClass == nwItemClass.ENTITY
assert theItem.isNovelLike() is False
assert theItem.documentAllowed() is False
assert theItem.isInactiveClass() is False
item.setClass("ENTITY")
assert item.itemClass == nwItemClass.ENTITY
assert item.isNovelLike() is False
assert item.documentAllowed() is False
assert item.isInactiveClass() is False
theItem.setClass("CUSTOM")
assert theItem.itemClass == nwItemClass.CUSTOM
assert theItem.isNovelLike() is False
assert theItem.documentAllowed() is False
assert theItem.isInactiveClass() is False
item.setClass("CUSTOM")
assert item.itemClass == nwItemClass.CUSTOM
assert item.isNovelLike() is False
assert item.documentAllowed() is False
assert item.isInactiveClass() is False
theItem.setClass("ARCHIVE")
assert theItem.itemClass == nwItemClass.ARCHIVE
assert theItem.isNovelLike() is True
assert theItem.documentAllowed() is True
assert theItem.isInactiveClass() is True
item.setClass("ARCHIVE")
assert item.itemClass == nwItemClass.ARCHIVE
assert item.isNovelLike() is True
assert item.documentAllowed() is True
assert item.isInactiveClass() is True
theItem.setClass("TRASH")
assert theItem.itemClass == nwItemClass.TRASH
assert theItem.isNovelLike() is False
assert theItem.documentAllowed() is True
assert theItem.isInactiveClass() is True
item.setClass("TRASH")
assert item.itemClass == nwItemClass.TRASH
assert item.isNovelLike() is False
assert item.documentAllowed() is True
assert item.isInactiveClass() is True
# Alternative
theItem.setClass(nwItemClass.NOVEL)
assert theItem.itemClass == nwItemClass.NOVEL
item.setClass(nwItemClass.NOVEL)
assert item.itemClass == nwItemClass.NOVEL
# END Test testCoreItem_ClassSetter
@@ -450,26 +450,26 @@ def testCoreItem_LayoutSetter(mockGUI):
"""Test the setter for all the nwItemLayout values for the NWItem
class.
"""
theProject = NWProject()
theItem = NWItem(theProject, "0000000000000")
project = NWProject()
item = NWItem(project, "0000000000000")
# Faulty Layouts
theItem.setLayout(None)
assert theItem.itemLayout == nwItemLayout.NO_LAYOUT
theItem.setLayout("NONSENSE")
assert theItem.itemLayout == nwItemLayout.NO_LAYOUT
item.setLayout(None)
assert item.itemLayout == nwItemLayout.NO_LAYOUT
item.setLayout("NONSENSE")
assert item.itemLayout == nwItemLayout.NO_LAYOUT
# Current Layouts
theItem.setLayout("NO_LAYOUT")
assert theItem.itemLayout == nwItemLayout.NO_LAYOUT
theItem.setLayout("DOCUMENT")
assert theItem.itemLayout == nwItemLayout.DOCUMENT
theItem.setLayout("NOTE")
assert theItem.itemLayout == nwItemLayout.NOTE
item.setLayout("NO_LAYOUT")
assert item.itemLayout == nwItemLayout.NO_LAYOUT
item.setLayout("DOCUMENT")
assert item.itemLayout == nwItemLayout.DOCUMENT
item.setLayout("NOTE")
assert item.itemLayout == nwItemLayout.NOTE
# Alternative
theItem.setLayout(nwItemLayout.NOTE)
assert theItem.itemLayout == nwItemLayout.NOTE
item.setLayout(nwItemLayout.NOTE)
assert item.itemLayout == nwItemLayout.NOTE
# END Test testCoreItem_LayoutSetter
@@ -478,54 +478,54 @@ def testCoreItem_LayoutSetter(mockGUI):
def testCoreItem_ClassDefaults(mockGUI):
"""Test the setter for the default values.
"""
theProject = NWProject()
theItem = NWItem(theProject, "0000000000000")
project = NWProject()
item = NWItem(project, "0000000000000")
# Root items should not have their class updated
theItem.setParent(None)
theItem.setClass(nwItemClass.NO_CLASS)
assert theItem.itemClass == nwItemClass.NO_CLASS
item.setParent(None)
item.setClass(nwItemClass.NO_CLASS)
assert item.itemClass == nwItemClass.NO_CLASS
theItem.setClassDefaults(nwItemClass.NOVEL)
assert theItem.itemClass == nwItemClass.NO_CLASS
item.setClassDefaults(nwItemClass.NOVEL)
assert item.itemClass == nwItemClass.NO_CLASS
# Non-root items should have their class updated
theItem.setParent("0123456789abc")
theItem.setClass(nwItemClass.NO_CLASS)
assert theItem.itemClass == nwItemClass.NO_CLASS
item.setParent("0123456789abc")
item.setClass(nwItemClass.NO_CLASS)
assert item.itemClass == nwItemClass.NO_CLASS
theItem.setClassDefaults(nwItemClass.NOVEL)
assert theItem.itemClass == nwItemClass.NOVEL
item.setClassDefaults(nwItemClass.NOVEL)
assert item.itemClass == nwItemClass.NOVEL
# Non-layout items should have their layout set based on class
theItem.setParent("0123456789abc")
theItem.setClass(nwItemClass.NO_CLASS)
theItem.setLayout(nwItemLayout.NO_LAYOUT)
assert theItem.itemLayout == nwItemLayout.NO_LAYOUT
item.setParent("0123456789abc")
item.setClass(nwItemClass.NO_CLASS)
item.setLayout(nwItemLayout.NO_LAYOUT)
assert item.itemLayout == nwItemLayout.NO_LAYOUT
theItem.setClassDefaults(nwItemClass.NOVEL)
assert theItem.itemLayout == nwItemLayout.DOCUMENT
item.setClassDefaults(nwItemClass.NOVEL)
assert item.itemLayout == nwItemLayout.DOCUMENT
theItem.setParent("0123456789abc")
theItem.setClass(nwItemClass.NO_CLASS)
theItem.setLayout(nwItemLayout.NO_LAYOUT)
assert theItem.itemLayout == nwItemLayout.NO_LAYOUT
item.setParent("0123456789abc")
item.setClass(nwItemClass.NO_CLASS)
item.setLayout(nwItemLayout.NO_LAYOUT)
assert item.itemLayout == nwItemLayout.NO_LAYOUT
theItem.setClassDefaults(nwItemClass.PLOT)
assert theItem.itemLayout == nwItemLayout.NOTE
item.setClassDefaults(nwItemClass.PLOT)
assert item.itemLayout == nwItemLayout.NOTE
# If documents are not allowed in that class, the layout should be changed
theItem.setParent("0123456789abc")
theItem.setClass(nwItemClass.NO_CLASS)
theItem.setLayout(nwItemLayout.DOCUMENT)
assert theItem.itemLayout == nwItemLayout.DOCUMENT
item.setParent("0123456789abc")
item.setClass(nwItemClass.NO_CLASS)
item.setLayout(nwItemLayout.DOCUMENT)
assert item.itemLayout == nwItemLayout.DOCUMENT
theItem.setClassDefaults(nwItemClass.PLOT)
assert theItem.itemLayout == nwItemLayout.NOTE
item.setClassDefaults(nwItemClass.PLOT)
assert item.itemLayout == nwItemLayout.NOTE
# In all cases, status and importance should no longer be None
assert theItem.itemStatus is not None
assert theItem.itemImport is not None
assert item.itemStatus is not None
assert item.itemImport is not None
# END Test testCoreItem_ClassDefaults
@@ -533,17 +533,17 @@ def testCoreItem_ClassDefaults(mockGUI):
@pytest.mark.core
def testCoreItem_PackUnpack(mockGUI, caplog, mockRnd):
"""Test packing and unpacking entries for the NWItem class."""
theProject = NWProject()
theProject.data.itemStatus.write(None, "New", (100, 100, 100))
theProject.data.itemImport.write(None, "New", (100, 100, 100))
project = NWProject()
project.data.itemStatus.write(None, "New", (100, 100, 100))
project.data.itemImport.write(None, "New", (100, 100, 100))
# Invalid
theItem = NWItem(theProject, "0000000000000")
assert theItem.unpack({}) is False
item = NWItem(project, "0000000000000")
assert item.unpack({}) is False
# File
theItem = NWItem(theProject, "")
assert theItem.unpack({
item = NWItem(project, "")
assert item.unpack({
"name": "A File",
"itemAttr": {
"handle": "0000000000003",
@@ -569,25 +569,25 @@ def testCoreItem_PackUnpack(mockGUI, caplog, mockRnd):
},
}) is True
assert theItem.itemName == "A File"
assert theItem.itemHandle == "0000000000003"
assert theItem.itemParent == "0000000000002"
assert theItem.itemRoot == "0000000000001"
assert theItem.itemOrder == 1
assert theItem.itemType == nwItemType.FILE
assert theItem.itemClass == nwItemClass.NOVEL
assert theItem.itemLayout == nwItemLayout.DOCUMENT
assert theItem.itemStatus == "s000000"
assert theItem.itemImport == "i000001"
assert theItem.isActive is False
assert theItem.isExpanded is True
assert theItem.mainHeading == "H1"
assert theItem.charCount == 100
assert theItem.wordCount == 20
assert theItem.paraCount == 2
assert theItem.cursorPos == 50
assert item.itemName == "A File"
assert item.itemHandle == "0000000000003"
assert item.itemParent == "0000000000002"
assert item.itemRoot == "0000000000001"
assert item.itemOrder == 1
assert item.itemType == nwItemType.FILE
assert item.itemClass == nwItemClass.NOVEL
assert item.itemLayout == nwItemLayout.DOCUMENT
assert item.itemStatus == "s000000"
assert item.itemImport == "i000001"
assert item.isActive is False
assert item.isExpanded is True
assert item.mainHeading == "H1"
assert item.charCount == 100
assert item.wordCount == 20
assert item.paraCount == 2
assert item.cursorPos == 50
assert theItem.pack() == {
assert item.pack() == {
"name": "A File",
"itemAttr": {
"handle": "0000000000003",
@@ -614,8 +614,8 @@ def testCoreItem_PackUnpack(mockGUI, caplog, mockRnd):
}
# Folder
theItem = NWItem(theProject, "")
assert theItem.unpack({
item = NWItem(project, "")
assert item.unpack({
"name": "A Folder",
"itemAttr": {
"handle": "0000000000003",
@@ -641,25 +641,25 @@ def testCoreItem_PackUnpack(mockGUI, caplog, mockRnd):
}
}) is True
assert theItem.itemName == "A Folder"
assert theItem.itemHandle == "0000000000003"
assert theItem.itemParent == "0000000000002"
assert theItem.itemRoot == "0000000000001"
assert theItem.itemOrder == 1
assert theItem.itemType == nwItemType.FOLDER
assert theItem.itemClass == nwItemClass.NOVEL
assert theItem.itemLayout == nwItemLayout.NO_LAYOUT
assert theItem.itemStatus == "s000000"
assert theItem.itemImport == "i000001"
assert theItem.isActive is False
assert theItem.isExpanded is True
assert theItem.mainHeading == "H0"
assert theItem.charCount == 0
assert theItem.wordCount == 0
assert theItem.paraCount == 0
assert theItem.cursorPos == 0
assert item.itemName == "A Folder"
assert item.itemHandle == "0000000000003"
assert item.itemParent == "0000000000002"
assert item.itemRoot == "0000000000001"
assert item.itemOrder == 1
assert item.itemType == nwItemType.FOLDER
assert item.itemClass == nwItemClass.NOVEL
assert item.itemLayout == nwItemLayout.NO_LAYOUT
assert item.itemStatus == "s000000"
assert item.itemImport == "i000001"
assert item.isActive is False
assert item.isExpanded is True
assert item.mainHeading == "H0"
assert item.charCount == 0
assert item.wordCount == 0
assert item.paraCount == 0
assert item.cursorPos == 0
assert theItem.pack() == {
assert item.pack() == {
"name": "A Folder",
"itemAttr": {
"handle": "0000000000003",
@@ -679,8 +679,8 @@ def testCoreItem_PackUnpack(mockGUI, caplog, mockRnd):
}
# Root
theItem = NWItem(theProject, "")
assert theItem.unpack({
item = NWItem(project, "")
assert item.unpack({
"name": "A Novel",
"itemAttr": {
"handle": "0000000000003",
@@ -706,25 +706,25 @@ def testCoreItem_PackUnpack(mockGUI, caplog, mockRnd):
},
}) is True
assert theItem.itemName == "A Novel"
assert theItem.itemHandle == "0000000000003"
assert theItem.itemParent is None
assert theItem.itemRoot == "0000000000003"
assert theItem.itemOrder == 1
assert theItem.itemType == nwItemType.ROOT
assert theItem.itemClass == nwItemClass.NOVEL
assert theItem.itemLayout == nwItemLayout.NO_LAYOUT
assert theItem.itemStatus == "s000000"
assert theItem.itemImport == "i000001"
assert theItem.isActive is False
assert theItem.isExpanded is True
assert theItem.mainHeading == "H0"
assert theItem.charCount == 0
assert theItem.wordCount == 0
assert theItem.paraCount == 0
assert theItem.cursorPos == 0
assert item.itemName == "A Novel"
assert item.itemHandle == "0000000000003"
assert item.itemParent is None
assert item.itemRoot == "0000000000003"
assert item.itemOrder == 1
assert item.itemType == nwItemType.ROOT
assert item.itemClass == nwItemClass.NOVEL
assert item.itemLayout == nwItemLayout.NO_LAYOUT
assert item.itemStatus == "s000000"
assert item.itemImport == "i000001"
assert item.isActive is False
assert item.isExpanded is True
assert item.mainHeading == "H0"
assert item.charCount == 0
assert item.wordCount == 0
assert item.paraCount == 0
assert item.cursorPos == 0
assert theItem.pack() == {
assert item.pack() == {
"name": "A Novel",
"itemAttr": {
"handle": "0000000000003",
+6 -6
View File
@@ -622,15 +622,15 @@ def testCoreProject_Backup(monkeypatch, mockGUI, fncPath, tstPaths):
# Test correct settings
assert project.backupProject(doNotify=True) is True
theFiles = sorted((tstPaths.tmpDir / "Test Minimal").iterdir())
assert len(theFiles) in (1, 2) # Sometimes 2 due to clock tick
files = sorted((tstPaths.tmpDir / "Test Minimal").iterdir())
assert len(files) in (1, 2) # Sometimes 2 due to clock tick
theZip = theFiles[0]
assert theZip.name.startswith("Test Minimal")
assert theZip.suffix == ".zip"
zipFile = files[0]
assert zipFile.name.startswith("Test Minimal")
assert zipFile.suffix == ".zip"
# Extract the archive
with ZipFile(tstPaths.tmpDir / "Test Minimal" / theZip.name, mode="r") as inZip:
with ZipFile(tstPaths.tmpDir / "Test Minimal" / zipFile.name, mode="r") as inZip:
inZip.extractall(tstPaths.tmpDir / "extract")
# Check that the main project file was restored
+136 -136
View File
@@ -36,8 +36,8 @@ importKeys = [C.iNew, C.iMinor, C.iMajor, C.iMain]
def testCoreStatus_Internal(mockRnd):
"""Test all the internal functions of the NWStatus class.
"""
theStatus = NWStatus(NWStatus.STATUS)
theImport = NWStatus(NWStatus.IMPORT)
nStatus = NWStatus(NWStatus.STATUS)
nImport = NWStatus(NWStatus.IMPORT)
with pytest.raises(Exception):
NWStatus(999)
@@ -45,42 +45,42 @@ def testCoreStatus_Internal(mockRnd):
# Generate Key
# ============
assert theStatus._newKey() == statusKeys[0]
assert theStatus._newKey() == statusKeys[1]
assert nStatus._newKey() == statusKeys[0]
assert nStatus._newKey() == statusKeys[1]
# Key collision, should move to key 3
theStatus.write(statusKeys[2], "Crash", (0, 0, 0))
assert theStatus._newKey() == statusKeys[3]
nStatus.write(statusKeys[2], "Crash", (0, 0, 0))
assert nStatus._newKey() == statusKeys[3]
assert theImport._newKey() == importKeys[0]
assert theImport._newKey() == importKeys[1]
assert nImport._newKey() == importKeys[0]
assert nImport._newKey() == importKeys[1]
# Key collision, should move to key 3
theImport.write(importKeys[2], "Crash", (0, 0, 0))
assert theImport._newKey() == importKeys[3]
nImport.write(importKeys[2], "Crash", (0, 0, 0))
assert nImport._newKey() == importKeys[3]
# Check Key
# =========
assert theStatus._isKey(None) is False # Not a string
assert theStatus._isKey("s00000") is False # Too short
assert theStatus._isKey("s000000") is True # Correct length
assert theStatus._isKey("s0000000") is False # Too long
assert theStatus._isKey("i000000") is False # Wrong type
assert theStatus._isKey("q000000") is False # Wrong type
assert theStatus._isKey("s12345H") is False # Not a hex value
assert theStatus._isKey("s12345F") is False # Not a lower case hex value
assert theStatus._isKey("s12345f") is True # Valid hex value
assert nStatus._isKey(None) is False # Not a string
assert nStatus._isKey("s00000") is False # Too short
assert nStatus._isKey("s000000") is True # Correct length
assert nStatus._isKey("s0000000") is False # Too long
assert nStatus._isKey("i000000") is False # Wrong type
assert nStatus._isKey("q000000") is False # Wrong type
assert nStatus._isKey("s12345H") is False # Not a hex value
assert nStatus._isKey("s12345F") is False # Not a lower case hex value
assert nStatus._isKey("s12345f") is True # Valid hex value
assert theImport._isKey(None) is False # Not a string
assert theImport._isKey("i00000") is False # Too short
assert theImport._isKey("i000000") is True # Correct length
assert theImport._isKey("i0000000") is False # Too long
assert theImport._isKey("s000000") is False # Wrong type
assert theImport._isKey("q000000") is False # Wrong type
assert theImport._isKey("i12345H") is False # Not a hex value
assert theImport._isKey("i12345F") is False # Not a lower case hex value
assert theImport._isKey("i12345f") is True # Valid hex value
assert nImport._isKey(None) is False # Not a string
assert nImport._isKey("i00000") is False # Too short
assert nImport._isKey("i000000") is True # Correct length
assert nImport._isKey("i0000000") is False # Too long
assert nImport._isKey("s000000") is False # Wrong type
assert nImport._isKey("q000000") is False # Wrong type
assert nImport._isKey("i12345H") is False # Not a hex value
assert nImport._isKey("i12345F") is False # Not a lower case hex value
assert nImport._isKey("i12345f") is True # Valid hex value
# END Test testCoreStatus_Internal
@@ -89,30 +89,30 @@ def testCoreStatus_Internal(mockRnd):
def testCoreStatus_Iterator(mockRnd):
"""Test the iterator functions of the NWStatus class.
"""
theStatus = NWStatus(NWStatus.STATUS)
nStatus = NWStatus(NWStatus.STATUS)
theStatus.write(None, "New", (100, 100, 100))
theStatus.write(None, "Note", (200, 50, 0))
theStatus.write(None, "Draft", (200, 150, 0))
theStatus.write(None, "Finished", (50, 200, 0))
nStatus.write(None, "New", (100, 100, 100))
nStatus.write(None, "Note", (200, 50, 0))
nStatus.write(None, "Draft", (200, 150, 0))
nStatus.write(None, "Finished", (50, 200, 0))
# Direct access
entry = theStatus[statusKeys[0]]
entry = nStatus[statusKeys[0]]
assert entry["cols"] == (100, 100, 100)
assert entry["name"] == "New"
assert entry["count"] == 0
assert isinstance(entry["icon"], QIcon)
# Iterate
entries = list(theStatus)
entries = list(nStatus)
assert len(entries) == 4
assert len(theStatus) == 4
assert len(nStatus) == 4
# Keys
assert list(theStatus.keys()) == statusKeys
assert list(nStatus.keys()) == statusKeys
# Items
for index, (key, entry) in enumerate(theStatus.items()):
for index, (key, entry) in enumerate(nStatus.items()):
assert key == statusKeys[index]
assert "cols" in entry
assert "name" in entry
@@ -120,7 +120,7 @@ def testCoreStatus_Iterator(mockRnd):
assert "icon" in entry
# Valuse
for entry in theStatus.values():
for entry in nStatus.values():
assert "cols" in entry
assert "name" in entry
assert "count" in entry
@@ -133,67 +133,67 @@ def testCoreStatus_Iterator(mockRnd):
def testCoreStatus_Entries(mockRnd):
"""Test all the simple setters for the NWStatus class.
"""
theStatus = NWStatus(NWStatus.STATUS)
nStatus = NWStatus(NWStatus.STATUS)
# Write
# =====
# Have a key
theStatus.write(statusKeys[0], "Entry 1", (200, 100, 50))
assert theStatus[statusKeys[0]]["name"] == "Entry 1"
assert theStatus[statusKeys[0]]["cols"] == (200, 100, 50)
nStatus.write(statusKeys[0], "Entry 1", (200, 100, 50))
assert nStatus[statusKeys[0]]["name"] == "Entry 1"
assert nStatus[statusKeys[0]]["cols"] == (200, 100, 50)
# Don't have a key
theStatus.write(None, "Entry 2", (210, 110, 60))
assert theStatus[statusKeys[1]]["name"] == "Entry 2"
assert theStatus[statusKeys[1]]["cols"] == (210, 110, 60)
nStatus.write(None, "Entry 2", (210, 110, 60))
assert nStatus[statusKeys[1]]["name"] == "Entry 2"
assert nStatus[statusKeys[1]]["cols"] == (210, 110, 60)
# Wrong colour spec
theStatus.write(None, "Entry 3", "what?")
assert theStatus[statusKeys[2]]["name"] == "Entry 3"
assert theStatus[statusKeys[2]]["cols"] == (100, 100, 100)
nStatus.write(None, "Entry 3", "what?")
assert nStatus[statusKeys[2]]["name"] == "Entry 3"
assert nStatus[statusKeys[2]]["cols"] == (100, 100, 100)
# Wrong colour count
theStatus.write(None, "Entry 4", (10, 20))
assert theStatus[statusKeys[3]]["name"] == "Entry 4"
assert theStatus[statusKeys[3]]["cols"] == (100, 100, 100)
nStatus.write(None, "Entry 4", (10, 20))
assert nStatus[statusKeys[3]]["name"] == "Entry 4"
assert nStatus[statusKeys[3]]["cols"] == (100, 100, 100)
# Check
# =====
# Normal lookup
for key in statusKeys:
assert theStatus.check(key) == key
assert nStatus.check(key) == key
# Non-existing name
assert theStatus.check("s987654") == statusKeys[0]
assert nStatus.check("s987654") == statusKeys[0]
# Name Access
# ===========
assert theStatus.name(statusKeys[0]) == "Entry 1"
assert theStatus.name(statusKeys[1]) == "Entry 2"
assert theStatus.name(statusKeys[2]) == "Entry 3"
assert theStatus.name(statusKeys[3]) == "Entry 4"
assert theStatus.name("blablabla") == "Entry 1"
assert nStatus.name(statusKeys[0]) == "Entry 1"
assert nStatus.name(statusKeys[1]) == "Entry 2"
assert nStatus.name(statusKeys[2]) == "Entry 3"
assert nStatus.name(statusKeys[3]) == "Entry 4"
assert nStatus.name("blablabla") == "Entry 1"
# Colour Access
# =============
assert theStatus.cols(statusKeys[0]) == (200, 100, 50)
assert theStatus.cols(statusKeys[1]) == (210, 110, 60)
assert theStatus.cols(statusKeys[2]) == (100, 100, 100)
assert theStatus.cols(statusKeys[3]) == (100, 100, 100)
assert theStatus.cols("blablabla") == (200, 100, 50)
assert nStatus.cols(statusKeys[0]) == (200, 100, 50)
assert nStatus.cols(statusKeys[1]) == (210, 110, 60)
assert nStatus.cols(statusKeys[2]) == (100, 100, 100)
assert nStatus.cols(statusKeys[3]) == (100, 100, 100)
assert nStatus.cols("blablabla") == (200, 100, 50)
# Icon Access
# ===========
assert isinstance(theStatus.icon(statusKeys[0]), QIcon)
assert isinstance(theStatus.icon(statusKeys[1]), QIcon)
assert isinstance(theStatus.icon(statusKeys[2]), QIcon)
assert isinstance(theStatus.icon(statusKeys[3]), QIcon)
assert isinstance(theStatus.icon("blablabla"), QIcon)
assert isinstance(nStatus.icon(statusKeys[0]), QIcon)
assert isinstance(nStatus.icon(statusKeys[1]), QIcon)
assert isinstance(nStatus.icon(statusKeys[2]), QIcon)
assert isinstance(nStatus.icon(statusKeys[3]), QIcon)
assert isinstance(nStatus.icon("blablabla"), QIcon)
# Increment and Count Access
# ==========================
@@ -201,32 +201,32 @@ def testCoreStatus_Entries(mockRnd):
countTo = [3, 5, 7, 9]
for i, n in enumerate(countTo):
for _ in range(n):
theStatus.increment(statusKeys[i])
nStatus.increment(statusKeys[i])
assert theStatus.count(statusKeys[0]) == countTo[0]
assert theStatus.count(statusKeys[1]) == countTo[1]
assert theStatus.count(statusKeys[2]) == countTo[2]
assert theStatus.count(statusKeys[3]) == countTo[3]
assert theStatus.count("blablabla") == countTo[0]
assert nStatus.count(statusKeys[0]) == countTo[0]
assert nStatus.count(statusKeys[1]) == countTo[1]
assert nStatus.count(statusKeys[2]) == countTo[2]
assert nStatus.count(statusKeys[3]) == countTo[3]
assert nStatus.count("blablabla") == countTo[0]
theStatus.resetCounts()
nStatus.resetCounts()
assert theStatus.count(statusKeys[0]) == 0
assert theStatus.count(statusKeys[1]) == 0
assert theStatus.count(statusKeys[2]) == 0
assert theStatus.count(statusKeys[3]) == 0
assert nStatus.count(statusKeys[0]) == 0
assert nStatus.count(statusKeys[1]) == 0
assert nStatus.count(statusKeys[2]) == 0
assert nStatus.count(statusKeys[3]) == 0
# Reorder
# =======
cOrder = list(theStatus.keys())
cOrder = list(nStatus.keys())
assert cOrder == statusKeys
# Wrong length
assert theStatus.reorder([]) is False
assert nStatus.reorder([]) is False
# No change
assert theStatus.reorder(cOrder) is False
assert nStatus.reorder(cOrder) is False
# Actual reaorder
nOrder = [
@@ -235,63 +235,63 @@ def testCoreStatus_Entries(mockRnd):
statusKeys[1],
statusKeys[3],
]
assert theStatus.reorder(nOrder) is True
assert list(theStatus.keys()) == nOrder
assert nStatus.reorder(nOrder) is True
assert list(nStatus.keys()) == nOrder
# Add an unknown key
wOrder = nOrder.copy()
wOrder[3] = theStatus._newKey()
assert theStatus.reorder(wOrder) is False
assert list(theStatus.keys()) == nOrder
wOrder[3] = nStatus._newKey()
assert nStatus.reorder(wOrder) is False
assert list(nStatus.keys()) == nOrder
# Put it back
assert theStatus.reorder(cOrder) is True
assert list(theStatus.keys()) == cOrder
assert nStatus.reorder(cOrder) is True
assert list(nStatus.keys()) == cOrder
# Default
# =======
default = theStatus._default
theStatus._default = None
default = nStatus._default
nStatus._default = None
assert theStatus.check("Entry 5") == ""
assert theStatus.name("blablabla") == ""
assert theStatus.cols("blablabla") == (100, 100, 100)
assert theStatus.count("blablabla") == 0
assert isinstance(theStatus.icon("blablabla"), QIcon)
assert nStatus.check("Entry 5") == ""
assert nStatus.name("blablabla") == ""
assert nStatus.cols("blablabla") == (100, 100, 100)
assert nStatus.count("blablabla") == 0
assert isinstance(nStatus.icon("blablabla"), QIcon)
theStatus._default = default
nStatus._default = default
# Remove
# ======
# Non-existing entry
assert theStatus.remove("blablabla") is False
assert nStatus.remove("blablabla") is False
# Non-zero entry
theStatus.increment(statusKeys[3])
assert theStatus.remove(statusKeys[3]) is False
nStatus.increment(statusKeys[3])
assert nStatus.remove(statusKeys[3]) is False
# Delete last entry
theStatus.resetCounts()
lastName = theStatus.name(statusKeys[3])
nStatus.resetCounts()
lastName = nStatus.name(statusKeys[3])
assert lastName == "Entry 4"
assert theStatus.remove(statusKeys[3]) is True
assert theStatus.check(statusKeys[3]) == theStatus._default
assert theStatus.check(lastName) == theStatus._default
assert nStatus.remove(statusKeys[3]) is True
assert nStatus.check(statusKeys[3]) == nStatus._default
assert nStatus.check(lastName) == nStatus._default
# Delete default entry, Entry 2 is new default
firstName = theStatus.name(theStatus._default)
firstName = nStatus.name(nStatus._default)
assert firstName == "Entry 1"
assert theStatus.remove(theStatus._default) is True
assert theStatus.name(firstName) == "Entry 2"
assert nStatus.remove(nStatus._default) is True
assert nStatus.name(firstName) == "Entry 2"
# Remove remaining entries
assert theStatus.remove(statusKeys[1]) is True
assert theStatus.remove(statusKeys[2]) is True
assert nStatus.remove(statusKeys[1]) is True
assert nStatus.remove(statusKeys[2]) is True
assert len(theStatus) == 0
assert theStatus._default is None
assert len(nStatus) == 0
assert nStatus._default is None
# END Test testCoreStatus_Entries
@@ -300,19 +300,19 @@ def testCoreStatus_Entries(mockRnd):
def testCoreStatus_PackUnpack(mockRnd):
"""Test all the pack/unpack of the NWStatus class.
"""
theStatus = NWStatus(NWStatus.STATUS)
theStatus.write(None, "New", (100, 100, 100))
theStatus.write(None, "Note", (200, 50, 0))
theStatus.write(None, "Draft", (200, 150, 0))
theStatus.write(None, "Finished", (50, 200, 0))
nStatus = NWStatus(NWStatus.STATUS)
nStatus.write(None, "New", (100, 100, 100))
nStatus.write(None, "Note", (200, 50, 0))
nStatus.write(None, "Draft", (200, 150, 0))
nStatus.write(None, "Finished", (50, 200, 0))
countTo = [3, 5, 7, 9]
for i, n in enumerate(countTo):
for _ in range(n):
theStatus.increment(statusKeys[i])
nStatus.increment(statusKeys[i])
# Pack
assert list(theStatus.pack()) == [
assert list(nStatus.pack()) == [
("New", {
"key": statusKeys[0],
"count": "3",
@@ -344,26 +344,26 @@ def testCoreStatus_PackUnpack(mockRnd):
]
# Unpack
theStatus = NWStatus(NWStatus.STATUS)
theStatus.unpack({
nStatus = NWStatus(NWStatus.STATUS)
nStatus.unpack({
statusKeys[0]: {"label": "New0", "colour": (100, 100, 100), "count": countTo[0]},
statusKeys[1]: {"label": "New1", "colour": (150, 150, 150), "count": countTo[1]},
statusKeys[2]: {"label": "New2", "colour": (200, 200, 200), "count": countTo[2]},
statusKeys[3]: {"label": "New3", "colour": (250, 250, 250), "count": countTo[3]},
})
assert len(theStatus._store) == 4
assert list(theStatus._store.keys()) == statusKeys
assert theStatus._store[statusKeys[0]]["name"] == "New0"
assert theStatus._store[statusKeys[1]]["name"] == "New1"
assert theStatus._store[statusKeys[2]]["name"] == "New2"
assert theStatus._store[statusKeys[3]]["name"] == "New3"
assert theStatus._store[statusKeys[0]]["cols"] == (100, 100, 100)
assert theStatus._store[statusKeys[1]]["cols"] == (150, 150, 150)
assert theStatus._store[statusKeys[2]]["cols"] == (200, 200, 200)
assert theStatus._store[statusKeys[3]]["cols"] == (250, 250, 250)
assert theStatus._store[statusKeys[0]]["count"] == countTo[0]
assert theStatus._store[statusKeys[1]]["count"] == countTo[1]
assert theStatus._store[statusKeys[2]]["count"] == countTo[2]
assert theStatus._store[statusKeys[3]]["count"] == countTo[3]
assert len(nStatus._store) == 4
assert list(nStatus._store.keys()) == statusKeys
assert nStatus._store[statusKeys[0]]["name"] == "New0"
assert nStatus._store[statusKeys[1]]["name"] == "New1"
assert nStatus._store[statusKeys[2]]["name"] == "New2"
assert nStatus._store[statusKeys[3]]["name"] == "New3"
assert nStatus._store[statusKeys[0]]["cols"] == (100, 100, 100)
assert nStatus._store[statusKeys[1]]["cols"] == (150, 150, 150)
assert nStatus._store[statusKeys[2]]["cols"] == (200, 200, 200)
assert nStatus._store[statusKeys[3]]["cols"] == (250, 250, 250)
assert nStatus._store[statusKeys[0]]["count"] == countTo[0]
assert nStatus._store[statusKeys[1]]["count"] == countTo[1]
assert nStatus._store[statusKeys[2]]["count"] == countTo[2]
assert nStatus._store[statusKeys[3]]["count"] == countTo[3]
# END Test testCoreStatus_PackUnpack
+4 -4
View File
@@ -266,13 +266,13 @@ def testCoreStorage_ZipIt(monkeypatch, mockGUI, fncPath, tstPaths, mockRnd):
"""Test making a zip archive of a project."""
zipFile = tstPaths.tmpDir / "project.zip"
theProject = NWProject()
storage = theProject.storage
project = NWProject()
storage = project.storage
assert storage.zipIt(zipFile) is False
# Make a project
mockRnd.reset()
buildTestProject(theProject, fncPath)
buildTestProject(project, fncPath)
# Fail to create archive
with monkeypatch.context() as mp:
@@ -292,7 +292,7 @@ def testCoreStorage_ZipIt(monkeypatch, mockGUI, fncPath, tstPaths, mockRnd):
assert f"content/{C.hChapterDoc}.nwd" in names
assert f"content/{C.hSceneDoc}.nwd" in names
theProject.closeProject()
project.closeProject()
# END Test testCoreStorage_ZipIt
+48 -48
View File
@@ -45,7 +45,7 @@ def testCoreToHtml_ConvertFormat(mockGUI):
html._text = "# Partition\n"
html.tokenizeText()
html.doConvert()
assert html.theResult == (
assert html.result == (
"<h1 class='title' style='text-align: center;'>Partition</h1>\n"
)
@@ -53,7 +53,7 @@ def testCoreToHtml_ConvertFormat(mockGUI):
html._text = "## Chapter Title\n"
html.tokenizeText()
html.doConvert()
assert html.theResult == (
assert html.result == (
"<h1 style='page-break-before: always;'>Chapter Title</h1>\n"
)
@@ -61,19 +61,19 @@ def testCoreToHtml_ConvertFormat(mockGUI):
html._text = "### Scene Title\n"
html.tokenizeText()
html.doConvert()
assert html.theResult == "<h2>Scene Title</h2>\n"
assert html.result == "<h2>Scene Title</h2>\n"
# Header 4
html._text = "#### Section Title\n"
html.tokenizeText()
html.doConvert()
assert html.theResult == "<h3>Section Title</h3>\n"
assert html.result == "<h3>Section Title</h3>\n"
# Title
html._text = "#! Title\n"
html.tokenizeText()
html.doConvert()
assert html.theResult == (
assert html.result == (
"<h1 class='title' style='text-align: center;'>Title</h1>\n"
)
@@ -81,7 +81,7 @@ def testCoreToHtml_ConvertFormat(mockGUI):
html._text = "##! Prologue\n"
html.tokenizeText()
html.doConvert()
assert html.theResult == "<h1 style='page-break-before: always;'>Prologue</h1>\n"
assert html.result == "<h1 style='page-break-before: always;'>Prologue</h1>\n"
# Note Files Headers
# ==================
@@ -95,31 +95,31 @@ def testCoreToHtml_ConvertFormat(mockGUI):
html._text = "# Heading One\n"
html.tokenizeText()
html.doConvert()
assert html.theResult == "<h1><a name='T0001'></a>Heading One</h1>\n"
assert html.result == "<h1><a name='T0001'></a>Heading One</h1>\n"
# Header 2
html._text = "## Heading Two\n"
html.tokenizeText()
html.doConvert()
assert html.theResult == "<h2><a name='T0001'></a>Heading Two</h2>\n"
assert html.result == "<h2><a name='T0001'></a>Heading Two</h2>\n"
# Header 3
html._text = "### Heading Three\n"
html.tokenizeText()
html.doConvert()
assert html.theResult == "<h3><a name='T0001'></a>Heading Three</h3>\n"
assert html.result == "<h3><a name='T0001'></a>Heading Three</h3>\n"
# Header 4
html._text = "#### Heading Four\n"
html.tokenizeText()
html.doConvert()
assert html.theResult == "<h4><a name='T0001'></a>Heading Four</h4>\n"
assert html.result == "<h4><a name='T0001'></a>Heading Four</h4>\n"
# Title
html._text = "#! Heading One\n"
html.tokenizeText()
html.doConvert()
assert html.theResult == (
assert html.result == (
"<h1 style='text-align: center;'><a name='T0001'></a>Heading One</h1>\n"
)
@@ -127,7 +127,7 @@ def testCoreToHtml_ConvertFormat(mockGUI):
html._text = "##! Heading Two\n"
html.tokenizeText()
html.doConvert()
assert html.theResult == "<h2><a name='T0001'></a>Heading Two</h2>\n"
assert html.result == "<h2><a name='T0001'></a>Heading Two</h2>\n"
# Paragraphs
# ==========
@@ -136,7 +136,7 @@ def testCoreToHtml_ConvertFormat(mockGUI):
html._text = "Some **nested bold and _italic_ and ~~strikethrough~~ text** here\n"
html.tokenizeText()
html.doConvert()
assert html.theResult == (
assert html.result == (
"<p>Some <strong>nested bold and <em>italic</em> and "
"<del>strikethrough</del> text</strong> here</p>\n"
)
@@ -145,7 +145,7 @@ def testCoreToHtml_ConvertFormat(mockGUI):
html._text = "Line one \nLine two \nLine three\n"
html.tokenizeText()
html.doConvert()
assert html.theResult == (
assert html.result == (
"<p class='break'>Line one<br/>Line two<br/>Line three</p>\n"
)
@@ -153,13 +153,13 @@ def testCoreToHtml_ConvertFormat(mockGUI):
html._text = "%synopsis: The synopsis ...\n"
html.tokenizeText()
html.doConvert()
assert html.theResult == ""
assert html.result == ""
html.setSynopsis(True)
html._text = "%synopsis: The synopsis ...\n"
html.tokenizeText()
html.doConvert()
assert html.theResult == (
assert html.result == (
"<p class='synopsis'><strong>Synopsis:</strong> The synopsis ...</p>\n"
)
@@ -167,7 +167,7 @@ def testCoreToHtml_ConvertFormat(mockGUI):
html._text = "%short: A short description ...\n"
html.tokenizeText()
html.doConvert()
assert html.theResult == (
assert html.result == (
"<p class='synopsis'><strong>Short Description:</strong> A short description ...</p>\n"
)
@@ -175,13 +175,13 @@ def testCoreToHtml_ConvertFormat(mockGUI):
html._text = "% A comment ...\n"
html.tokenizeText()
html.doConvert()
assert html.theResult == ""
assert html.result == ""
html.setComments(True)
html._text = "% A comment ...\n"
html.tokenizeText()
html.doConvert()
assert html.theResult == (
assert html.result == (
"<p class='comment'><strong>Comment:</strong> A comment ...</p>\n"
)
@@ -189,13 +189,13 @@ def testCoreToHtml_ConvertFormat(mockGUI):
html._text = "@char: Bod, Jane\n"
html.tokenizeText()
html.doConvert()
assert html.theResult == ""
assert html.result == ""
html.setKeywords(True)
html._text = "@char: Bod, Jane\n"
html.tokenizeText()
html.doConvert()
assert html.theResult == (
assert html.result == (
"<p><span class='tags'>Characters:</span> "
"<a href='#tag_Bod'>Bod</a>, <a href='#tag_Jane'>Jane</a></p>\n"
)
@@ -205,7 +205,7 @@ def testCoreToHtml_ConvertFormat(mockGUI):
html._text = "## Chapter\n\n@pov: Bod\n@plot: Main\n@location: Europe\n\n"
html.tokenizeText()
html.doConvert()
assert html.theResult == (
assert html.result == (
"<h2>"
"<a name='T0001'></a>Chapter</h2>\n"
"<p style='margin-bottom: 0;'>"
@@ -228,7 +228,7 @@ def testCoreToHtml_ConvertFormat(mockGUI):
html._text = "Some **nested bold and _italic_ and ~~strikethrough~~ text** here\n"
html.tokenizeText()
html.doConvert()
assert html.theResult == (
assert html.result == (
"<p>Some <b>nested bold and <i>italic</i> and "
"<span style='text-decoration: line-through;'>strikethrough</span> "
"text</b> here</p>\n"
@@ -256,7 +256,7 @@ def testCoreToHtml_ConvertDirect(mockGUI):
(html.T_EMPTY, 1, "", None, html.A_NONE),
]
html.doConvert()
assert html.theResult == (
assert html.result == (
"<h1 class='title' style='text-align: center; page-break-before: always;'>"
"<a name='T0001'></a>A Title</h1>\n"
)
@@ -267,7 +267,7 @@ def testCoreToHtml_ConvertDirect(mockGUI):
(html.T_EMPTY, 1, "", None, html.A_NONE),
]
html.doConvert()
assert html.theResult == (
assert html.result == (
"<h1 style='page-break-before: always;'>"
"<a name='T0001'></a>Prologue</h1>\n"
)
@@ -281,7 +281,7 @@ def testCoreToHtml_ConvertDirect(mockGUI):
(html.T_EMPTY, 1, "", None, html.A_NONE),
]
html.doConvert()
assert html.theResult == "<p class='sep' style='text-align: center;'>* * *</p>\n"
assert html.result == "<p class='sep' style='text-align: center;'>* * *</p>\n"
# Skip
html._tokens = [
@@ -289,7 +289,7 @@ def testCoreToHtml_ConvertDirect(mockGUI):
(html.T_EMPTY, 1, "", None, html.A_NONE),
]
html.doConvert()
assert html.theResult == "<p class='skip'>&nbsp;</p>\n"
assert html.result == "<p class='skip'>&nbsp;</p>\n"
# Alignment
# =========
@@ -302,7 +302,7 @@ def testCoreToHtml_ConvertDirect(mockGUI):
(html.T_HEAD1, 1, "A Title", None, html.A_LEFT),
]
html.doConvert()
assert html.theResult == (
assert html.result == (
"<h1 class='title'>A Title</h1>\n"
)
@@ -313,7 +313,7 @@ def testCoreToHtml_ConvertDirect(mockGUI):
(html.T_HEAD1, 1, "A Title", None, html.A_LEFT),
]
html.doConvert()
assert html.theResult == (
assert html.result == (
"<h1 class='title' style='text-align: left;'>A Title</h1>\n"
)
@@ -322,7 +322,7 @@ def testCoreToHtml_ConvertDirect(mockGUI):
(html.T_HEAD1, 1, "A Title", None, html.A_RIGHT),
]
html.doConvert()
assert html.theResult == (
assert html.result == (
"<h1 class='title' style='text-align: right;'>A Title</h1>\n"
)
@@ -331,7 +331,7 @@ def testCoreToHtml_ConvertDirect(mockGUI):
(html.T_HEAD1, 1, "A Title", None, html.A_CENTRE),
]
html.doConvert()
assert html.theResult == (
assert html.result == (
"<h1 class='title' style='text-align: center;'>A Title</h1>\n"
)
@@ -340,7 +340,7 @@ def testCoreToHtml_ConvertDirect(mockGUI):
(html.T_HEAD1, 1, "A Title", None, html.A_JUSTIFY),
]
html.doConvert()
assert html.theResult == (
assert html.result == (
"<h1 class='title' style='text-align: justify;'>A Title</h1>\n"
)
@@ -352,7 +352,7 @@ def testCoreToHtml_ConvertDirect(mockGUI):
(html.T_HEAD1, 1, "A Title", None, html.A_PBB | html.A_PBA),
]
html.doConvert()
assert html.theResult == (
assert html.result == (
"<h1 class='title' "
"style='page-break-before: always; page-break-after: always;'>A Title</h1>\n"
)
@@ -366,7 +366,7 @@ def testCoreToHtml_ConvertDirect(mockGUI):
(html.T_EMPTY, 2, "", None, html.A_NONE),
]
html.doConvert()
assert html.theResult == (
assert html.result == (
"<p style='margin-left: 40px;'>Some text ...</p>\n"
)
@@ -376,7 +376,7 @@ def testCoreToHtml_ConvertDirect(mockGUI):
(html.T_EMPTY, 2, "", None, html.A_NONE),
]
html.doConvert()
assert html.theResult == (
assert html.result == (
"<p style='margin-right: 40px;'>Some text ...</p>\n"
)
@@ -396,28 +396,28 @@ def testCoreToHtml_SpecialCases(mockGUI):
html._text = "Text with > and < with some **bold text** in it.\n"
html.tokenizeText()
html.doConvert()
assert html.theResult == (
assert html.result == (
"<p>Text with &gt; and &lt; with some <strong>bold text</strong> in it.</p>\n"
)
html._text = "Text with some <**bold text**> in it.\n"
html.tokenizeText()
html.doConvert()
assert html.theResult == (
assert html.result == (
"<p>Text with some &lt;<strong>bold text</strong>&gt; in it.</p>\n"
)
html._text = "Let's > be > _difficult **shall** > we_?\n"
html.tokenizeText()
html.doConvert()
assert html.theResult == (
assert html.result == (
"<p>Let's &gt; be &gt; <em>difficult <strong>shall</strong> &gt; we</em>?</p>\n"
)
html._text = "Test > text _<**bold**>_ and more.\n"
html.tokenizeText()
html.doConvert()
assert html.theResult == (
assert html.result == (
"<p>Test &gt; text <em>&lt;<strong>bold</strong>&gt;</em> and more.</p>\n"
)
@@ -429,7 +429,7 @@ def testCoreToHtml_SpecialCases(mockGUI):
html._text = "% Test > text _<**bold**>_ and more.\n"
html.tokenizeText()
html.doConvert()
assert html.theResult == (
assert html.result == (
"<p class='comment'>"
"<strong>Comment:</strong> Test &gt; text _&lt;**bold**&gt;_ and more."
"</p>\n"
@@ -438,7 +438,7 @@ def testCoreToHtml_SpecialCases(mockGUI):
html._text = "## Heading <1>\n"
html.tokenizeText()
html.doConvert()
assert html.theResult == (
assert html.result == (
"<h1 style='page-break-before: always;'>Heading &lt;1&gt;</h1>\n"
)
@@ -449,7 +449,7 @@ def testCoreToHtml_SpecialCases(mockGUI):
html._text = "Test text \\**_bold_** and more.\n"
html.tokenizeText()
html.doConvert()
assert html.theResult == (
assert html.result == (
"<p>Test text **<em>bold</em>** and more.</p>\n"
)
@@ -511,7 +511,7 @@ def testCoreToHtml_Complex(mockGUI, fncPath):
html.doPreProcessing()
html.tokenizeText()
html.doConvert()
assert html.theResult == resText[i]
assert html.result == resText[i]
assert html.fullHTML == resText
@@ -521,7 +521,7 @@ def testCoreToHtml_Complex(mockGUI, fncPath):
# Check File
# ==========
theStyle = html.getStyleSheet()
hStyle = html.getStyleSheet()
htmlDoc = (
"<!DOCTYPE html>\n"
"<html>\n"
@@ -539,7 +539,7 @@ def testCoreToHtml_Complex(mockGUI, fncPath):
"</body>\n"
"</html>\n"
).format(
htmlStyle="\n".join(theStyle),
htmlStyle="\n".join(hStyle),
bodyText="".join(resText).rstrip()
)
@@ -564,7 +564,7 @@ def testCoreToHtml_Methods(mockGUI):
html.doPreProcessing()
html.tokenizeText()
html.doConvert()
assert html.theResult == (
assert html.result == (
"<p>Text with &lt;brackets&gt; &amp; shortdash, long—dash …</p>\n"
)
@@ -575,7 +575,7 @@ def testCoreToHtml_Methods(mockGUI):
html.doPreProcessing()
html.tokenizeText()
html.doConvert()
assert html.theResult == (
assert html.result == (
"<p>Text with &lt;brackets&gt; &amp; short&ndash;dash, long&mdash;dash &hellip;</p>\n"
)
@@ -585,7 +585,7 @@ def testCoreToHtml_Methods(mockGUI):
html.doPreProcessing()
html.tokenizeText()
html.doConvert()
assert html.theMarkdown[-1] == (
assert html.allMarkdown[-1] == (
"Text with <brackets> &amp; short&ndash;dash, long&mdash;dash &hellip;\n\n"
)
+33 -33
View File
@@ -168,14 +168,14 @@ def testCoreToken_TextOps(monkeypatch, mockGUI, mockRnd, fncPath):
# First Page
assert tokens.addRootHeading(C.hPlotRoot) is True
assert tokens.theMarkdown[-1] == "# Notes: Plot\n\n"
assert tokens.allMarkdown[-1] == "# Notes: Plot\n\n"
assert tokens._tokens[-1] == (
Tokenizer.T_TITLE, 0, "Notes: Plot", None, Tokenizer.A_CENTRE
)
# Not First Page
assert tokens.addRootHeading(C.hPlotRoot) is True
assert tokens.theMarkdown[-1] == "# Notes: Plot\n\n"
assert tokens.allMarkdown[-1] == "# Notes: Plot\n\n"
assert tokens._tokens[-1] == (
Tokenizer.T_TITLE, 0, "Notes: Plot", None, Tokenizer.A_CENTRE | Tokenizer.A_PBB
)
@@ -250,7 +250,7 @@ def testCoreToken_HeaderFormat(mockGUI):
(Tokenizer.T_TITLE, 1, "Novel Title", None, Tokenizer.A_CENTRE),
(Tokenizer.T_EMPTY, 1, "", None, Tokenizer.A_NONE),
]
assert tokens.theMarkdown[-1] == "#! Novel Title\n\n"
assert tokens.allMarkdown[-1] == "#! Novel Title\n\n"
# Note File
tokens._isNovel = False
@@ -263,7 +263,7 @@ def testCoreToken_HeaderFormat(mockGUI):
(Tokenizer.T_HEAD1, 1, "Note Title", None, Tokenizer.A_CENTRE),
(Tokenizer.T_EMPTY, 1, "", None, Tokenizer.A_NONE),
]
assert tokens.theMarkdown[-1] == "#! Note Title\n\n"
assert tokens.allMarkdown[-1] == "#! Note Title\n\n"
# Header 1
# ========
@@ -279,7 +279,7 @@ def testCoreToken_HeaderFormat(mockGUI):
(Tokenizer.T_HEAD1, 1, "Novel Title", None, Tokenizer.A_CENTRE),
(Tokenizer.T_EMPTY, 1, "", None, Tokenizer.A_NONE),
]
assert tokens.theMarkdown[-1] == "# Novel Title\n\n"
assert tokens.allMarkdown[-1] == "# Novel Title\n\n"
# Note File
tokens._isNovel = False
@@ -292,7 +292,7 @@ def testCoreToken_HeaderFormat(mockGUI):
(Tokenizer.T_HEAD1, 1, "Note Title", None, Tokenizer.A_NONE),
(Tokenizer.T_EMPTY, 1, "", None, Tokenizer.A_NONE),
]
assert tokens.theMarkdown[-1] == "# Note Title\n\n"
assert tokens.allMarkdown[-1] == "# Note Title\n\n"
# Header 2
# ========
@@ -307,7 +307,7 @@ def testCoreToken_HeaderFormat(mockGUI):
(Tokenizer.T_HEAD2, 1, "Chapter One", None, Tokenizer.A_PBB),
(Tokenizer.T_EMPTY, 1, "", None, Tokenizer.A_NONE),
]
assert tokens.theMarkdown[-1] == "## Chapter One\n\n"
assert tokens.allMarkdown[-1] == "## Chapter One\n\n"
# Note File
tokens._isNovel = False
@@ -319,7 +319,7 @@ def testCoreToken_HeaderFormat(mockGUI):
(Tokenizer.T_HEAD2, 1, "Heading 2", None, Tokenizer.A_NONE),
(Tokenizer.T_EMPTY, 1, "", None, Tokenizer.A_NONE),
]
assert tokens.theMarkdown[-1] == "## Heading 2\n\n"
assert tokens.allMarkdown[-1] == "## Heading 2\n\n"
# Header 3
# ========
@@ -334,7 +334,7 @@ def testCoreToken_HeaderFormat(mockGUI):
(Tokenizer.T_HEAD3, 1, "Scene One", None, Tokenizer.A_NONE),
(Tokenizer.T_EMPTY, 1, "", None, Tokenizer.A_NONE),
]
assert tokens.theMarkdown[-1] == "### Scene One\n\n"
assert tokens.allMarkdown[-1] == "### Scene One\n\n"
# Note File
tokens._isNovel = False
@@ -346,7 +346,7 @@ def testCoreToken_HeaderFormat(mockGUI):
(Tokenizer.T_HEAD3, 1, "Heading 3", None, Tokenizer.A_NONE),
(Tokenizer.T_EMPTY, 1, "", None, Tokenizer.A_NONE),
]
assert tokens.theMarkdown[-1] == "### Heading 3\n\n"
assert tokens.allMarkdown[-1] == "### Heading 3\n\n"
# Header 4
# ========
@@ -361,7 +361,7 @@ def testCoreToken_HeaderFormat(mockGUI):
(Tokenizer.T_HEAD4, 1, "A Section", None, Tokenizer.A_NONE),
(Tokenizer.T_EMPTY, 1, "", None, Tokenizer.A_NONE),
]
assert tokens.theMarkdown[-1] == "#### A Section\n\n"
assert tokens.allMarkdown[-1] == "#### A Section\n\n"
# Note File
tokens._isNovel = False
@@ -373,7 +373,7 @@ def testCoreToken_HeaderFormat(mockGUI):
(Tokenizer.T_HEAD4, 1, "Heading 4", None, Tokenizer.A_NONE),
(Tokenizer.T_EMPTY, 1, "", None, Tokenizer.A_NONE),
]
assert tokens.theMarkdown[-1] == "#### Heading 4\n\n"
assert tokens.allMarkdown[-1] == "#### Heading 4\n\n"
# Title
# =====
@@ -388,7 +388,7 @@ def testCoreToken_HeaderFormat(mockGUI):
(Tokenizer.T_TITLE, 1, "Title", None, Tokenizer.A_CENTRE),
(Tokenizer.T_EMPTY, 1, "", None, Tokenizer.A_NONE),
]
assert tokens.theMarkdown[-1] == "#! Title\n\n"
assert tokens.allMarkdown[-1] == "#! Title\n\n"
# Note File
tokens._isNovel = False
@@ -400,7 +400,7 @@ def testCoreToken_HeaderFormat(mockGUI):
(Tokenizer.T_HEAD1, 1, "Title", None, Tokenizer.A_CENTRE),
(Tokenizer.T_EMPTY, 1, "", None, Tokenizer.A_NONE),
]
assert tokens.theMarkdown[-1] == "#! Title\n\n"
assert tokens.allMarkdown[-1] == "#! Title\n\n"
# Unnumbered
# ==========
@@ -415,7 +415,7 @@ def testCoreToken_HeaderFormat(mockGUI):
(Tokenizer.T_UNNUM, 1, "Prologue", None, Tokenizer.A_PBB),
(Tokenizer.T_EMPTY, 1, "", None, Tokenizer.A_NONE),
]
assert tokens.theMarkdown[-1] == "##! Prologue\n\n"
assert tokens.allMarkdown[-1] == "##! Prologue\n\n"
# Note File
tokens._isNovel = False
@@ -427,7 +427,7 @@ def testCoreToken_HeaderFormat(mockGUI):
(Tokenizer.T_HEAD2, 1, "Prologue", None, Tokenizer.A_NONE),
(Tokenizer.T_EMPTY, 1, "", None, Tokenizer.A_NONE),
]
assert tokens.theMarkdown[-1] == "##! Prologue\n\n"
assert tokens.allMarkdown[-1] == "##! Prologue\n\n"
# END Test testCoreToken_HeaderFormat
@@ -446,11 +446,11 @@ def testCoreToken_MetaFormat(mockGUI):
(Tokenizer.T_COMMENT, 0, "A comment", None, Tokenizer.A_NONE),
(Tokenizer.T_EMPTY, 0, "", None, Tokenizer.A_NONE),
]
assert tokens.theMarkdown[-1] == "\n"
assert tokens.allMarkdown[-1] == "\n"
tokens.setComments(True)
tokens.tokenizeText()
assert tokens.theMarkdown[-1] == "% A comment\n\n"
assert tokens.allMarkdown[-1] == "% A comment\n\n"
# Synopsis
tokens._text = "%synopsis: The synopsis\n"
@@ -465,11 +465,11 @@ def testCoreToken_MetaFormat(mockGUI):
(Tokenizer.T_SYNOPSIS, 0, "The synopsis", None, Tokenizer.A_NONE),
(Tokenizer.T_EMPTY, 0, "", None, Tokenizer.A_NONE),
]
assert tokens.theMarkdown[-1] == "\n"
assert tokens.allMarkdown[-1] == "\n"
tokens.setSynopsis(True)
tokens.tokenizeText()
assert tokens.theMarkdown[-1] == "% synopsis: The synopsis\n\n"
assert tokens.allMarkdown[-1] == "% synopsis: The synopsis\n\n"
# Short
tokens.setSynopsis(False)
@@ -479,11 +479,11 @@ def testCoreToken_MetaFormat(mockGUI):
(Tokenizer.T_SHORT, 0, "A short description", None, Tokenizer.A_NONE),
(Tokenizer.T_EMPTY, 0, "", None, Tokenizer.A_NONE),
]
assert tokens.theMarkdown[-1] == "\n"
assert tokens.allMarkdown[-1] == "\n"
tokens.setSynopsis(True)
tokens.tokenizeText()
assert tokens.theMarkdown[-1] == "% short: A short description\n\n"
assert tokens.allMarkdown[-1] == "% short: A short description\n\n"
# Keyword
tokens._text = "@char: Bod\n"
@@ -492,11 +492,11 @@ def testCoreToken_MetaFormat(mockGUI):
(Tokenizer.T_KEYWORD, 0, "char: Bod", None, Tokenizer.A_NONE),
(Tokenizer.T_EMPTY, 0, "", None, Tokenizer.A_NONE),
]
assert tokens.theMarkdown[-1] == "\n"
assert tokens.allMarkdown[-1] == "\n"
tokens.setKeywords(True)
tokens.tokenizeText()
assert tokens.theMarkdown[-1] == "@char: Bod\n\n"
assert tokens.allMarkdown[-1] == "@char: Bod\n\n"
tokens._text = "@pov: Bod\n@plot: Main\n@location: Europe\n"
tokens.tokenizeText()
@@ -509,7 +509,7 @@ def testCoreToken_MetaFormat(mockGUI):
(Tokenizer.T_KEYWORD, 0, "location: Europe", None, styBtm),
(Tokenizer.T_EMPTY, 0, "", None, Tokenizer.A_NONE),
]
assert tokens.theMarkdown[-1] == "@pov: Bod\n@plot: Main\n@location: Europe\n\n"
assert tokens.allMarkdown[-1] == "@pov: Bod\n@plot: Main\n@location: Europe\n\n"
# END Test testCoreToken_MetaFormat
@@ -554,7 +554,7 @@ def testCoreToken_MarginFormat(mockGUI):
(Tokenizer.T_EMPTY, 0, "", None, Tokenizer.A_NONE),
(Tokenizer.T_EMPTY, 0, "", None, Tokenizer.A_NONE),
]
assert tokens.theMarkdown[-1] == (
assert tokens.allMarkdown[-1] == (
"Some regular text\n\n"
"Some left-aligned text\n\n"
"Some right-aligned text\n\n"
@@ -676,7 +676,7 @@ def testCoreToken_TextFormat(mockGUI):
(Tokenizer.T_EMPTY, 0, "", None, Tokenizer.A_NONE),
(Tokenizer.T_EMPTY, 0, "", None, Tokenizer.A_NONE),
]
assert tokens.theMarkdown[-1] == "Some plain text\non two lines\n\n\n\n"
assert tokens.allMarkdown[-1] == "Some plain text\non two lines\n\n\n\n"
tokens.setBodyText(False)
tokens.tokenizeText()
@@ -685,7 +685,7 @@ def testCoreToken_TextFormat(mockGUI):
(Tokenizer.T_EMPTY, 0, "", None, Tokenizer.A_NONE),
(Tokenizer.T_EMPTY, 0, "", None, Tokenizer.A_NONE),
]
assert tokens.theMarkdown[-1] == "\n\n\n"
assert tokens.allMarkdown[-1] == "\n\n\n"
tokens.setBodyText(True)
# Text Emphasis
@@ -703,7 +703,7 @@ def testCoreToken_TextFormat(mockGUI):
),
(Tokenizer.T_EMPTY, 0, "", None, Tokenizer.A_NONE),
]
assert tokens.theMarkdown[-1] == "Some **bolded text** on this lines\n\n"
assert tokens.allMarkdown[-1] == "Some **bolded text** on this lines\n\n"
tokens._text = "Some _italic text_ on this lines\n"
tokens.tokenizeText()
@@ -719,7 +719,7 @@ def testCoreToken_TextFormat(mockGUI):
),
(Tokenizer.T_EMPTY, 0, "", None, Tokenizer.A_NONE),
]
assert tokens.theMarkdown[-1] == "Some _italic text_ on this lines\n\n"
assert tokens.allMarkdown[-1] == "Some _italic text_ on this lines\n\n"
tokens._text = "Some **_bold italic text_** on this lines\n"
tokens.tokenizeText()
@@ -737,7 +737,7 @@ def testCoreToken_TextFormat(mockGUI):
),
(Tokenizer.T_EMPTY, 0, "", None, Tokenizer.A_NONE),
]
assert tokens.theMarkdown[-1] == "Some **_bold italic text_** on this lines\n\n"
assert tokens.allMarkdown[-1] == "Some **_bold italic text_** on this lines\n\n"
tokens._text = "Some ~~strikethrough text~~ on this lines\n"
tokens.tokenizeText()
@@ -753,7 +753,7 @@ def testCoreToken_TextFormat(mockGUI):
),
(Tokenizer.T_EMPTY, 0, "", None, Tokenizer.A_NONE),
]
assert tokens.theMarkdown[-1] == "Some ~~strikethrough text~~ on this lines\n\n"
assert tokens.allMarkdown[-1] == "Some ~~strikethrough text~~ on this lines\n\n"
tokens._text = "Some **nested bold and _italic_ and ~~strikethrough~~ text** here\n"
tokens.tokenizeText()
@@ -773,7 +773,7 @@ def testCoreToken_TextFormat(mockGUI):
),
(Tokenizer.T_EMPTY, 0, "", None, Tokenizer.A_NONE),
]
assert tokens.theMarkdown[-1] == (
assert tokens.allMarkdown[-1] == (
"Some **nested bold and _italic_ and ~~strikethrough~~ text** here\n\n"
)
+122 -122
View File
@@ -33,127 +33,127 @@ def testCoreToMarkdown_ConvertFormat(mockGUI):
"""Test the tokenizer and converter chain using the ToMarkdown
class.
"""
theProject = NWProject()
theMD = ToMarkdown(theProject)
project = NWProject()
toMD = ToMarkdown(project)
# Headers
# =======
theMD._isNovel = True
theMD._isNote = False
theMD._isFirst = True
toMD._isNovel = True
toMD._isNote = False
toMD._isFirst = True
# Header 1
theMD._text = "# Partition\n"
theMD.tokenizeText()
theMD.doConvert()
assert theMD.theResult == "# Partition\n\n"
toMD._text = "# Partition\n"
toMD.tokenizeText()
toMD.doConvert()
assert toMD.result == "# Partition\n\n"
# Header 2
theMD._text = "## Chapter Title\n"
theMD.tokenizeText()
theMD.doConvert()
assert theMD.theResult == "## Chapter Title\n\n"
toMD._text = "## Chapter Title\n"
toMD.tokenizeText()
toMD.doConvert()
assert toMD.result == "## Chapter Title\n\n"
# Header 3
theMD._text = "### Scene Title\n"
theMD.tokenizeText()
theMD.doConvert()
assert theMD.theResult == "### Scene Title\n\n"
toMD._text = "### Scene Title\n"
toMD.tokenizeText()
toMD.doConvert()
assert toMD.result == "### Scene Title\n\n"
# Header 4
theMD._text = "#### Section Title\n"
theMD.tokenizeText()
theMD.doConvert()
assert theMD.theResult == "#### Section Title\n\n"
toMD._text = "#### Section Title\n"
toMD.tokenizeText()
toMD.doConvert()
assert toMD.result == "#### Section Title\n\n"
# Title
theMD._text = "#! Title\n"
theMD.tokenizeText()
theMD.doConvert()
assert theMD.theResult == "# Title\n\n"
toMD._text = "#! Title\n"
toMD.tokenizeText()
toMD.doConvert()
assert toMD.result == "# Title\n\n"
# Unnumbered
theMD._text = "##! Prologue\n"
theMD.tokenizeText()
theMD.doConvert()
assert theMD.theResult == "## Prologue\n\n"
toMD._text = "##! Prologue\n"
toMD.tokenizeText()
toMD.doConvert()
assert toMD.result == "## Prologue\n\n"
# Paragraphs
# ==========
# Text for Extended Markdown
theMD.setExtendedMarkdown()
theMD._text = "Some **nested bold and _italic_ and ~~strikethrough~~ text** here\n"
theMD.tokenizeText()
theMD.doConvert()
assert theMD.theResult == (
toMD.setExtendedMarkdown()
toMD._text = "Some **nested bold and _italic_ and ~~strikethrough~~ text** here\n"
toMD.tokenizeText()
toMD.doConvert()
assert toMD.result == (
"Some **nested bold and _italic_ and ~~strikethrough~~ text** here\n\n"
)
# Text for Standard Markdown
theMD.setStandardMarkdown()
theMD._text = "Some **nested bold and _italic_ and ~~strikethrough~~ text** here\n"
theMD.tokenizeText()
theMD.doConvert()
assert theMD.theResult == (
toMD.setStandardMarkdown()
toMD._text = "Some **nested bold and _italic_ and ~~strikethrough~~ text** here\n"
toMD.tokenizeText()
toMD.doConvert()
assert toMD.result == (
"Some **nested bold and _italic_ and strikethrough text** here\n\n"
)
# Text w/Hard Break
theMD._text = "Line one \nLine two \nLine three\n"
theMD.tokenizeText()
theMD.doConvert()
assert theMD.theResult == "Line one \nLine two \nLine three\n\n"
toMD._text = "Line one \nLine two \nLine three\n"
toMD.tokenizeText()
toMD.doConvert()
assert toMD.result == "Line one \nLine two \nLine three\n\n"
# Synopsis, Short
theMD._text = "%synopsis: The synopsis ...\n"
theMD.tokenizeText()
theMD.doConvert()
assert theMD.theResult == ""
toMD._text = "%synopsis: The synopsis ...\n"
toMD.tokenizeText()
toMD.doConvert()
assert toMD.result == ""
theMD.setSynopsis(True)
theMD._text = "%synopsis: The synopsis ...\n"
theMD.tokenizeText()
theMD.doConvert()
assert theMD.theResult == "**Synopsis:** The synopsis ...\n\n"
toMD.setSynopsis(True)
toMD._text = "%synopsis: The synopsis ...\n"
toMD.tokenizeText()
toMD.doConvert()
assert toMD.result == "**Synopsis:** The synopsis ...\n\n"
theMD.setSynopsis(True)
theMD._text = "%short: A description ...\n"
theMD.tokenizeText()
theMD.doConvert()
assert theMD.theResult == "**Short Description:** A description ...\n\n"
toMD.setSynopsis(True)
toMD._text = "%short: A description ...\n"
toMD.tokenizeText()
toMD.doConvert()
assert toMD.result == "**Short Description:** A description ...\n\n"
# Comment
theMD._text = "% A comment ...\n"
theMD.tokenizeText()
theMD.doConvert()
assert theMD.theResult == ""
toMD._text = "% A comment ...\n"
toMD.tokenizeText()
toMD.doConvert()
assert toMD.result == ""
theMD.setComments(True)
theMD._text = "% A comment ...\n"
theMD.tokenizeText()
theMD.doConvert()
assert theMD.theResult == "**Comment:** A comment ...\n\n"
toMD.setComments(True)
toMD._text = "% A comment ...\n"
toMD.tokenizeText()
toMD.doConvert()
assert toMD.result == "**Comment:** A comment ...\n\n"
# Keywords
theMD._text = "@char: Bod, Jane\n"
theMD.tokenizeText()
theMD.doConvert()
assert theMD.theResult == ""
toMD._text = "@char: Bod, Jane\n"
toMD.tokenizeText()
toMD.doConvert()
assert toMD.result == ""
theMD.setKeywords(True)
theMD._text = "@char: Bod, Jane\n"
theMD.tokenizeText()
theMD.doConvert()
assert theMD.theResult == "**Characters:** Bod, Jane\n\n"
toMD.setKeywords(True)
toMD._text = "@char: Bod, Jane\n"
toMD.tokenizeText()
toMD.doConvert()
assert toMD.result == "**Characters:** Bod, Jane\n\n"
# Multiple Keywords
theMD.setKeywords(True)
theMD._text = "## Chapter\n\n@pov: Bod\n@plot: Main\n@location: Europe\n\n"
theMD.tokenizeText()
theMD.doConvert()
assert theMD.theResult == (
toMD.setKeywords(True)
toMD._text = "## Chapter\n\n@pov: Bod\n@plot: Main\n@location: Europe\n\n"
toMD.tokenizeText()
toMD.doConvert()
assert toMD.result == (
"## Chapter\n\n"
"**Point of View:** Bod \n"
"**Plot:** Main \n"
@@ -166,49 +166,49 @@ def testCoreToMarkdown_ConvertFormat(mockGUI):
@pytest.mark.core
def testCoreToMarkdown_ConvertDirect(mockGUI):
"""Test the converter directly using the ToMarkdown class."""
theProject = NWProject()
theMD = ToMarkdown(theProject)
project = NWProject()
toMD = ToMarkdown(project)
theMD._isNovel = True
theMD._isNote = False
toMD._isNovel = True
toMD._isNote = False
# Special Titles
# ==============
# Title
theMD._tokens = [
(theMD.T_TITLE, 1, "A Title", None, theMD.A_PBB | theMD.A_CENTRE),
(theMD.T_EMPTY, 1, "", None, theMD.A_NONE),
toMD._tokens = [
(toMD.T_TITLE, 1, "A Title", None, toMD.A_PBB | toMD.A_CENTRE),
(toMD.T_EMPTY, 1, "", None, toMD.A_NONE),
]
theMD.doConvert()
assert theMD.theResult == "# A Title\n\n"
toMD.doConvert()
assert toMD.result == "# A Title\n\n"
# Unnumbered
theMD._tokens = [
(theMD.T_UNNUM, 1, "Prologue", None, theMD.A_PBB),
(theMD.T_EMPTY, 1, "", None, theMD.A_NONE),
toMD._tokens = [
(toMD.T_UNNUM, 1, "Prologue", None, toMD.A_PBB),
(toMD.T_EMPTY, 1, "", None, toMD.A_NONE),
]
theMD.doConvert()
assert theMD.theResult == "## Prologue\n\n"
toMD.doConvert()
assert toMD.result == "## Prologue\n\n"
# Separators
# ==========
# Separator
theMD._tokens = [
(theMD.T_SEP, 1, "* * *", None, theMD.A_CENTRE),
(theMD.T_EMPTY, 1, "", None, theMD.A_NONE),
toMD._tokens = [
(toMD.T_SEP, 1, "* * *", None, toMD.A_CENTRE),
(toMD.T_EMPTY, 1, "", None, toMD.A_NONE),
]
theMD.doConvert()
assert theMD.theResult == "* * *\n\n"
toMD.doConvert()
assert toMD.result == "* * *\n\n"
# Skip
theMD._tokens = [
(theMD.T_SKIP, 1, "", None, theMD.A_NONE),
(theMD.T_EMPTY, 1, "", None, theMD.A_NONE),
toMD._tokens = [
(toMD.T_SKIP, 1, "", None, toMD.A_NONE),
(toMD.T_EMPTY, 1, "", None, toMD.A_NONE),
]
theMD.doConvert()
assert theMD.theResult == "\n\n\n"
toMD.doConvert()
assert toMD.result == "\n\n\n"
# END Test testCoreToMarkdown_ConvertDirect
@@ -216,9 +216,9 @@ def testCoreToMarkdown_ConvertDirect(mockGUI):
@pytest.mark.core
def testCoreToMarkdown_Complex(mockGUI, fncPath):
"""Test the save method of the ToMarkdown class."""
theProject = NWProject()
theMD = ToMarkdown(theProject)
theMD._isNovel = True
project = NWProject()
toMD = ToMarkdown(project)
toMD._isNovel = True
# Build Project
# =============
@@ -243,23 +243,23 @@ def testCoreToMarkdown_Complex(mockGUI, fncPath):
]
for i in range(len(docText)):
theMD._text = docText[i]
theMD.doPreProcessing()
theMD.tokenizeText()
theMD.doConvert()
assert theMD.theResult == resText[i]
toMD._text = docText[i]
toMD.doPreProcessing()
toMD.tokenizeText()
toMD.doConvert()
assert toMD.result == resText[i]
assert theMD.fullMD == resText
assert theMD.getFullResultSize() == len("".join(resText))
assert toMD.fullMD == resText
assert toMD.getFullResultSize() == len("".join(resText))
theMD.replaceTabs(nSpaces=4, spaceChar=" ")
toMD.replaceTabs(nSpaces=4, spaceChar=" ")
resText[6] = "#### A Section\n\n More text in scene two.\n\n"
# Check File
# ==========
saveFile = fncPath / "outFile.md"
theMD.saveMarkdown(saveFile)
toMD.saveMarkdown(saveFile)
assert readFile(saveFile) == "".join(resText)
# END Test testCoreToHtml_Complex
@@ -268,12 +268,12 @@ def testCoreToMarkdown_Complex(mockGUI, fncPath):
@pytest.mark.core
def testCoreToMarkdown_Format(mockGUI):
"""Test all the formatters for the ToMarkdown class."""
theProject = NWProject()
theMD = ToMarkdown(theProject)
project = NWProject()
toMD = ToMarkdown(project)
assert theMD._formatKeywords("", theMD.A_NONE) == ""
assert theMD._formatKeywords("tag: Jane", theMD.A_NONE) == "**Tag:** Jane\n\n"
assert theMD._formatKeywords("tag: Jane, John", theMD.A_NONE) == "**Tag:** Jane, John\n\n"
assert theMD._formatKeywords("tag: Jane", theMD.A_Z_BTMMRG) == "**Tag:** Jane \n"
assert toMD._formatKeywords("", toMD.A_NONE) == ""
assert toMD._formatKeywords("tag: Jane", toMD.A_NONE) == "**Tag:** Jane\n\n"
assert toMD._formatKeywords("tag: Jane, John", toMD.A_NONE) == "**Tag:** Jane, John\n\n"
assert toMD._formatKeywords("tag: Jane", toMD.A_Z_BTMMRG) == "**Tag:** Jane \n"
# END Test testCoreToMarkdown_Format
+30 -30
View File
@@ -134,9 +134,9 @@ def testCoreToOdt_TextFormatting(mockGUI):
"Heading_20_1", "Heading_20_2", "Heading_20_3", "Heading_20_4", "Header",
]
theKey = "071d6b2e4764749f8c78d3c1ab9099fa04c07d2d53fd3de61eb1bdf1cb4845c3"
assert odt._autoPara[theKey][0] == "P1"
assert isinstance(odt._autoPara[theKey][1], ODTParagraphStyle)
key = "071d6b2e4764749f8c78d3c1ab9099fa04c07d2d53fd3de61eb1bdf1cb4845c3"
assert odt._autoPara[key][0] == "P1"
assert isinstance(odt._autoPara[key][1], ODTParagraphStyle)
# Paragraph Formatting
# ====================
@@ -624,48 +624,48 @@ def testCoreToOdt_ConvertDirect(mockGUI):
"""Test the converter directly using the ToOdt class to reach some
otherwise hard to reach conditions.
"""
theProject = NWProject()
theDoc = ToOdt(theProject, isFlat=True)
project = NWProject()
doc = ToOdt(project, isFlat=True)
theDoc._isNovel = True
doc._isNovel = True
# Justified
theDoc = ToOdt(theProject, isFlat=True)
theDoc._tokens = [
(theDoc.T_TEXT, 1, "This is a paragraph", [], theDoc.A_JUSTIFY),
(theDoc.T_EMPTY, 1, "", None, theDoc.A_NONE),
doc = ToOdt(project, isFlat=True)
doc._tokens = [
(doc.T_TEXT, 1, "This is a paragraph", [], doc.A_JUSTIFY),
(doc.T_EMPTY, 1, "", None, doc.A_NONE),
]
theDoc.initDocument()
theDoc.doConvert()
theDoc.closeDocument()
doc.initDocument()
doc.doConvert()
doc.closeDocument()
assert (
'<style:style style:name="P1" style:family="paragraph" '
'style:parent-style-name="Text_20_body">'
'<style:paragraph-properties fo:text-align="justify" />'
'</style:style>'
) in xmlToText(theDoc._xAuto)
assert xmlToText(theDoc._xText) == (
) in xmlToText(doc._xAuto)
assert xmlToText(doc._xText) == (
'<office:text>'
'<text:p text:style-name="P1">This is a paragraph</text:p>'
'</office:text>'
)
# Page Break After
theDoc = ToOdt(theProject, isFlat=True)
theDoc._tokens = [
(theDoc.T_TEXT, 1, "This is a paragraph", [], theDoc.A_PBA),
(theDoc.T_EMPTY, 1, "", None, theDoc.A_NONE),
doc = ToOdt(project, isFlat=True)
doc._tokens = [
(doc.T_TEXT, 1, "This is a paragraph", [], doc.A_PBA),
(doc.T_EMPTY, 1, "", None, doc.A_NONE),
]
theDoc.initDocument()
theDoc.doConvert()
theDoc.closeDocument()
doc.initDocument()
doc.doConvert()
doc.closeDocument()
assert (
'<style:style style:name="P1" style:family="paragraph" '
'style:parent-style-name="Text_20_body">'
'<style:paragraph-properties fo:break-after="page" />'
'</style:style>'
) in xmlToText(theDoc._xAuto)
assert xmlToText(theDoc._xText) == (
) in xmlToText(doc._xAuto)
assert xmlToText(doc._xText) == (
'<office:text>'
'<text:p text:style-name="P1">This is a paragraph</text:p>'
'</office:text>'
@@ -767,12 +767,12 @@ def testCoreToOdt_SaveFull(mockGUI, fncPath, tstPaths):
extaxtTo = tstPaths.outDir / "coreToOdt_SaveFull"
with zipfile.ZipFile(fullFile, mode="r") as theZip:
theZip.extract("META-INF/manifest.xml", extaxtTo)
theZip.extract("settings.xml", extaxtTo)
theZip.extract("content.xml", extaxtTo)
theZip.extract("meta.xml", extaxtTo)
theZip.extract("styles.xml", extaxtTo)
with zipfile.ZipFile(fullFile, mode="r") as zipObj:
zipObj.extract("META-INF/manifest.xml", extaxtTo)
zipObj.extract("settings.xml", extaxtTo)
zipObj.extract("content.xml", extaxtTo)
zipObj.extract("meta.xml", extaxtTo)
zipObj.extract("styles.xml", extaxtTo)
maniOut = tstPaths.outDir / "coreToOdt_SaveFull" / "META-INF" / "manifest.xml"
settOut = tstPaths.outDir / "coreToOdt_SaveFull" / "settings.xml"
+172 -172
View File
@@ -39,23 +39,23 @@ from novelwriter.core.project import NWProject
@pytest.fixture(scope="function")
def mockItems(mockGUI, mockRnd):
"""Create a list of mock items."""
theProject = NWProject()
project = NWProject()
itemA = NWItem(theProject, "a000000000001")
itemA = NWItem(project, "a000000000001")
itemA._name = "Novel"
itemA._parent = None
itemA._type = nwItemType.ROOT
itemA._class = nwItemClass.NOVEL
itemA._expanded = True
itemB = NWItem(theProject, "b000000000001")
itemB = NWItem(project, "b000000000001")
itemB._name = "Act One"
itemB._parent = "a000000000001"
itemB._type = nwItemType.FOLDER
itemB._class = nwItemClass.NOVEL
itemB._expanded = True
itemC = NWItem(theProject, "c000000000001")
itemC = NWItem(project, "c000000000001")
itemC._name = "Chapter One"
itemC._parent = "b000000000001"
itemC._type = nwItemType.FILE
@@ -65,7 +65,7 @@ def mockItems(mockGUI, mockRnd):
itemC._wordCount = 50
itemC._paraCount = 2
itemD = NWItem(theProject, "c000000000002")
itemD = NWItem(project, "c000000000002")
itemD._name = "Scene One"
itemD._parent = "b000000000001"
itemD._type = nwItemType.FILE
@@ -75,28 +75,28 @@ def mockItems(mockGUI, mockRnd):
itemD._wordCount = 500
itemD._paraCount = 20
itemE = NWItem(theProject, "a000000000002")
itemE = NWItem(project, "a000000000002")
itemE._name = "Outtakes"
itemE._parent = None
itemE._type = nwItemType.ROOT
itemE._class = nwItemClass.ARCHIVE
itemE._expanded = False
itemF = NWItem(theProject, "a000000000003")
itemF = NWItem(project, "a000000000003")
itemF._name = "Trash"
itemF._parent = None
itemF._type = nwItemType.ROOT
itemF._class = nwItemClass.TRASH
itemF._expanded = False
itemG = NWItem(theProject, "a000000000004")
itemG = NWItem(project, "a000000000004")
itemG._name = "Characters"
itemG._parent = None
itemG._type = nwItemType.ROOT
itemG._class = nwItemClass.CHARACTER
itemG._expanded = True
itemH = NWItem(theProject, "b000000000002")
itemH = NWItem(project, "b000000000002")
itemH._name = "Jane Doe"
itemH._parent = "a000000000004"
itemH._type = nwItemType.FILE
@@ -112,126 +112,126 @@ def mockItems(mockGUI, mockRnd):
@pytest.mark.core
def testCoreTree_BuildTree(mockGUI, mockItems):
"""Test building a project tree from a list of items."""
theProject = NWProject()
theTree = NWTree(theProject)
project = NWProject()
tree = NWTree(project)
# Check that tree is empty (calls NWTree.__bool__)
assert bool(theTree) is False
assert bool(tree) is False
# Check for archive and trash folders
assert theTree.trashRoot is None
assert tree.trashRoot is None
aHandles = []
for nwItem in mockItems:
aHandles.append(nwItem.itemHandle)
assert theTree.append(nwItem) is True
assert theTree.updateItemData(nwItem.itemHandle) is True
assert tree.append(nwItem) is True
assert tree.updateItemData(nwItem.itemHandle) is True
assert theTree._changed is True
assert tree._changed is True
# Check that tree is not empty (calls __bool__)
assert bool(theTree) is True
assert bool(tree) is True
# Check the number of elements (calls __len__)
assert len(theTree) == len(mockItems)
assert len(tree) == len(mockItems)
# Check that we have the correct handles
assert theTree.handles() == aHandles
assert tree.handles() == aHandles
# Check by iterator (calls __iter__, __next__ and __getitem__)
for theItem, theHandle in zip(theTree, aHandles):
assert theItem.itemHandle == theHandle
for item, handle in zip(tree, aHandles):
assert item.itemHandle == handle
# Trash Folder
# ============
# Check that we have the correct archive and trash folders
assert theTree.trashRoot == "a000000000003"
assert theTree.findRoot(nwItemClass.ARCHIVE) == "a000000000002"
assert theTree.isTrash("a000000000003") is True
assert tree.trashRoot == "a000000000003"
assert tree.findRoot(nwItemClass.ARCHIVE) == "a000000000002"
assert tree.isTrash("a000000000003") is True
# Check that we have the root classes
assert theTree.rootClasses() == {
assert tree.rootClasses() == {
nwItemClass.NOVEL, nwItemClass.CHARACTER, nwItemClass.ARCHIVE, nwItemClass.TRASH
}
# Check the isTrash function
assert theTree.isTrash("0000000000000") is True # Doesn't exist
assert theTree.isTrash("a000000000003") is True # This the trash folder
assert tree.isTrash("0000000000000") is True # Doesn't exist
assert tree.isTrash("a000000000003") is True # This the trash folder
theTree["a000000000003"].setClass(nwItemClass.NO_CLASS) # type: ignore
assert theTree.isTrash("a000000000003") is True # This is still trash
theTree["a000000000003"].setClass(nwItemClass.TRASH) # type: ignore
tree["a000000000003"].setClass(nwItemClass.NO_CLASS) # type: ignore
assert tree.isTrash("a000000000003") is True # This is still trash
tree["a000000000003"].setClass(nwItemClass.TRASH) # type: ignore
assert theTree.isTrash("b000000000002") is False # This is not trash
assert tree.isTrash("b000000000002") is False # This is not trash
value = theTree["b000000000002"].itemParent # type: ignore
theTree["b000000000002"].setParent("a000000000003") # type: ignore
assert theTree.isTrash("b000000000002") is True # This is in trash
theTree["b000000000002"].setParent(value) # type: ignore
value = tree["b000000000002"].itemParent # type: ignore
tree["b000000000002"].setParent("a000000000003") # type: ignore
assert tree.isTrash("b000000000002") is True # This is in trash
tree["b000000000002"].setParent(value) # type: ignore
value = theTree["b000000000002"].itemRoot # type: ignore
theTree["b000000000002"].setRoot("a000000000003") # type: ignore
assert theTree.isTrash("b000000000002") is True # This is in trash
theTree["b000000000002"].setRoot(value) # type: ignore
value = tree["b000000000002"].itemRoot # type: ignore
tree["b000000000002"].setRoot("a000000000003") # type: ignore
assert tree.isTrash("b000000000002") is True # This is in trash
tree["b000000000002"].setRoot(value) # type: ignore
# Try to add another trash folder
itemT = NWItem(theProject, "1111111111111")
itemT = NWItem(project, "1111111111111")
itemT._name = "Trash"
itemT._type = nwItemType.ROOT
itemT._class = nwItemClass.TRASH
itemT._expanded = False
assert theTree.append(itemT) is False
assert len(theTree) == len(mockItems)
assert tree.append(itemT) is False
assert len(tree) == len(mockItems)
# Create or Add Items
# ===================
# Create a new item, but with invalid parent
assert theTree.create("New File", "blabla", nwItemType.FILE, nwItemClass.NO_CLASS) is None
assert tree.create("New File", "blabla", nwItemType.FILE, nwItemClass.NO_CLASS) is None
# Create a new, valid item
nHandle = theTree.create("New File", "b000000000001", nwItemType.FILE, nwItemClass.NO_CLASS)
nHandle = tree.create("New File", "b000000000001", nwItemType.FILE, nwItemClass.NO_CLASS)
assert isHandle(nHandle)
assert nHandle == "0000000000000"
# The new item should be the last item in the tree
theList = theTree.handles()
assert theList[-1] == nHandle
handles = tree.handles()
assert handles[-1] == nHandle
# Retrieve the item
itemT = theTree[nHandle]
itemT = tree[nHandle]
assert isinstance(itemT, NWItem)
assert len(theTree) == len(mockItems) + 1
assert len(tree) == len(mockItems) + 1
# We should not be allowed to add the item again
assert theTree.append(itemT) is False
assert len(theTree) == len(mockItems) + 1
assert tree.append(itemT) is False
assert len(tree) == len(mockItems) + 1
# Create an invalid item to add, which will be rejected
itemU = NWItem.duplicate(itemT, "blabla")
assert theTree.append(itemU) is False
assert len(theTree) == len(mockItems) + 1
assert tree.append(itemU) is False
assert len(tree) == len(mockItems) + 1
# Create a new root, but with a parent set anyway (the parent should be ignored)
zHandle = theTree.create("Custom", "a000000000001", nwItemType.ROOT, nwItemClass.CUSTOM)
zHandle = tree.create("Custom", "a000000000001", nwItemType.ROOT, nwItemClass.CUSTOM)
assert isinstance(zHandle, str)
itemZ = theTree[zHandle]
itemZ = tree[zHandle]
assert isinstance(itemZ, NWItem)
assert itemZ.itemParent is None
del theTree[zHandle]
del tree[zHandle]
# Duplicate Items
# ===============
# Duplicate a non-existing item
assert theTree.duplicate("blabla") is None
assert tree.duplicate("blabla") is None
# Duplicate the new item
itemV = theTree.duplicate(nHandle)
itemV = tree.duplicate(nHandle)
assert isinstance(itemV, NWItem)
assert len(theTree) == len(mockItems) + 2
assert len(tree) == len(mockItems) + 2
dHandle = itemV.itemHandle
assert dHandle == "0000000000002"
@@ -240,28 +240,28 @@ def testCoreTree_BuildTree(mockGUI, mockItems):
# ============
# Delete a non-existing item
del theTree["stuff"]
assert len(theTree) == len(mockItems) + 2
del tree["stuff"]
assert len(tree) == len(mockItems) + 2
# Delete the last items
del theTree[nHandle]
del theTree[dHandle]
assert len(theTree) == len(mockItems)
assert nHandle not in theTree
del tree[nHandle]
del tree[dHandle]
assert len(tree) == len(mockItems)
assert nHandle not in tree
# Delete the Novel, Archive and Trash folders
del theTree["a000000000001"]
assert len(theTree) == len(mockItems) - 1
assert "a000000000001" not in theTree
del tree["a000000000001"]
assert len(tree) == len(mockItems) - 1
assert "a000000000001" not in tree
del theTree["a000000000002"]
assert len(theTree) == len(mockItems) - 2
assert "a000000000002" not in theTree
del tree["a000000000002"]
assert len(tree) == len(mockItems) - 2
assert "a000000000002" not in tree
del theTree["a000000000003"]
assert len(theTree) == len(mockItems) - 3
assert "a000000000003" not in theTree
assert theTree.trashRoot is None
del tree["a000000000003"]
assert len(tree) == len(mockItems) - 3
assert "a000000000003" not in tree
assert tree.trashRoot is None
# END Test testCoreTree_BuildTree
@@ -269,28 +269,28 @@ def testCoreTree_BuildTree(mockGUI, mockItems):
@pytest.mark.core
def testCoreTree_PackUnpack(mockGUI, mockItems):
"""Test packing and unpacking data."""
theProject = NWProject()
theTree = NWTree(theProject)
project = NWProject()
tree = NWTree(project)
aHandles = []
for nwItem in mockItems:
aHandles.append(nwItem.itemHandle)
theTree.append(nwItem)
theTree.updateItemData(nwItem.itemHandle)
tree.append(nwItem)
tree.updateItemData(nwItem.itemHandle)
assert len(theTree) == len(mockItems)
assert len(tree) == len(mockItems)
# Pack
tree = theTree.pack()
packed = tree.pack()
for i, nwItem in enumerate(mockItems):
assert tree[i]["itemAttr"]["handle"] == nwItem.itemHandle
assert packed[i]["itemAttr"]["handle"] == nwItem.itemHandle
# Unpack
theTree.clear()
assert len(theTree) == 0
assert theTree.handles() == []
theTree.unpack(tree)
assert theTree.handles() == aHandles
tree.clear()
assert len(tree) == 0
assert tree.handles() == []
tree.unpack(packed)
assert tree.handles() == aHandles
# END Test testCoreTree_PackUnpack
@@ -298,35 +298,35 @@ def testCoreTree_PackUnpack(mockGUI, mockItems):
@pytest.mark.core
def testCoreTree_CheckConsistency(caplog: pytest.LogCaptureFixture, mockGUI, fncPath, mockRnd):
"""Check the project consistency."""
theProject = NWProject()
buildTestProject(theProject, fncPath)
project = NWProject()
buildTestProject(project, fncPath)
# By default, all is well
caplog.clear()
assert theProject.tree.checkConsistency("Recovered") == (0, 0)
assert project.tree.checkConsistency("Recovered") == (0, 0)
assert all(m.endswith("OK") for m in caplog.messages)
# Give the scene file an unknown parent
caplog.clear()
theProject.tree[C.hSceneDoc].setParent(C.hInvalid) # type: ignore
assert theProject.tree.checkConsistency("Recovered") == (1, 1)
project.tree[C.hSceneDoc].setParent(C.hInvalid) # type: ignore
assert project.tree.checkConsistency("Recovered") == (1, 1)
assert f"'{C.hSceneDoc}' ... ERROR" in caplog.text
# The scene file should have been added back to its home
itemS = theProject.tree[C.hSceneDoc]
itemS = project.tree[C.hSceneDoc]
assert isinstance(itemS, NWItem)
assert itemS.itemParent == C.hChapterDir
# Create a new file with no meta data, and let the function handle it as orphaned
xHandle = "0123456789abc"
contentPath = theProject.storage.contentPath
contentPath = project.storage.contentPath
assert isinstance(contentPath, Path)
assert contentPath == fncPath / "content"
(contentPath / f"{xHandle}.nwd").write_text("### Stuff", encoding="utf-8")
assert theProject.tree.checkConsistency("Recovered") == (1, 1)
assert xHandle in theProject.tree
itemX = theProject.tree[xHandle]
assert project.tree.checkConsistency("Recovered") == (1, 1)
assert xHandle in project.tree
itemX = project.tree[xHandle]
assert isinstance(itemX, NWItem)
# It should by default be added as a Novel file
@@ -339,13 +339,13 @@ def testCoreTree_CheckConsistency(caplog: pytest.LogCaptureFixture, mockGUI, fnc
itemX.setClass(nwItemClass.OBJECT)
itemX.setName("Stuff")
itemX.setParent(C.hInvalid)
theProject.storage.getDocument(xHandle).writeDocument("### Stuff") # This adds meta data
project.storage.getDocument(xHandle).writeDocument("### Stuff") # This adds meta data
# Remove the item in the project, and re-run the consistency check
del theProject.tree[xHandle]
assert theProject.tree.checkConsistency("Recovered") == (1, 1)
assert xHandle in theProject.tree
itemX = theProject.tree[xHandle]
del project.tree[xHandle]
assert project.tree.checkConsistency("Recovered") == (1, 1)
assert xHandle in project.tree
itemX = project.tree[xHandle]
assert isinstance(itemX, NWItem)
# It should again be added as a Novel file
@@ -355,11 +355,11 @@ def testCoreTree_CheckConsistency(caplog: pytest.LogCaptureFixture, mockGUI, fnc
assert itemX.itemName == "[Recovered] Stuff"
# If the tree is empty, a new root folder is created
theProject.tree.clear()
assert theProject.tree.checkConsistency("Recovered") == (4, 4)
assert len(theProject.tree) == 5
nHandle = theProject.tree.findRoot(nwItemClass.NOVEL)
assert theProject.tree[nHandle].itemName == "Recovered" # type: ignore
project.tree.clear()
assert project.tree.checkConsistency("Recovered") == (4, 4)
assert len(project.tree) == 5
nHandle = project.tree.findRoot(nwItemClass.NOVEL)
assert project.tree[nHandle].itemName == "Recovered" # type: ignore
# END Test testCoreTree_CheckConsistency
@@ -367,58 +367,58 @@ def testCoreTree_CheckConsistency(caplog: pytest.LogCaptureFixture, mockGUI, fnc
@pytest.mark.core
def testCoreTree_Methods(monkeypatch, mockGUI, mockItems):
"""Test various class methods."""
theProject = NWProject()
theTree = NWTree(theProject)
project = NWProject()
tree = NWTree(project)
for nwItem in mockItems:
theTree.append(nwItem)
theTree.updateItemData(nwItem.itemHandle)
tree.append(nwItem)
tree.updateItemData(nwItem.itemHandle)
assert len(theTree) == len(mockItems)
assert len(tree) == len(mockItems)
# Update item data, nonsense handle
assert theTree.updateItemData("stuff") is False
assert tree.updateItemData("stuff") is False
# Update item data, invalid item parent
corrParent = theTree["b000000000001"].itemParent # type: ignore
theTree["b000000000001"].setParent("0000000000000") # type: ignore
assert theTree.updateItemData("b000000000001") is False
corrParent = tree["b000000000001"].itemParent # type: ignore
tree["b000000000001"].setParent("0000000000000") # type: ignore
assert tree.updateItemData("b000000000001") is False
# Update item data, valid item parent
theTree["b000000000001"].setParent(corrParent) # type: ignore
assert theTree.updateItemData("b000000000001") is True
tree["b000000000001"].setParent(corrParent) # type: ignore
assert tree.updateItemData("b000000000001") is True
# Update item data, root is unreachable
with monkeypatch.context() as mp:
mp.setattr("novelwriter.core.tree.MAX_DEPTH", 0)
with pytest.raises(RecursionError):
theTree.updateItemData("b000000000001")
tree.updateItemData("b000000000001")
# Check type
assert theTree.checkType("blabla", nwItemType.FILE) is False
assert theTree.checkType("b000000000001", nwItemType.FILE) is False
assert theTree.checkType("c000000000001", nwItemType.FILE) is True
assert tree.checkType("blabla", nwItemType.FILE) is False
assert tree.checkType("b000000000001", nwItemType.FILE) is False
assert tree.checkType("c000000000001", nwItemType.FILE) is True
# Root item lookup
assert theTree.findRoot(nwItemClass.WORLD) is None
assert theTree.findRoot(nwItemClass.NOVEL) == "a000000000001"
assert theTree.findRoot(nwItemClass.CHARACTER) == "a000000000004"
assert tree.findRoot(nwItemClass.WORLD) is None
assert tree.findRoot(nwItemClass.NOVEL) == "a000000000001"
assert tree.findRoot(nwItemClass.CHARACTER) == "a000000000004"
# Iter roots
roots = list(theTree.iterRoots(None))
roots = list(tree.iterRoots(None))
assert roots[0][0] == "a000000000001"
assert roots[1][0] == "a000000000002"
assert roots[2][0] == "a000000000003"
assert roots[3][0] == "a000000000004"
# Add a fake item to root and check that it can handle it
theTree._roots["0000000000000"] = NWItem(theProject, "0000000000000")
assert theTree.findRoot(nwItemClass.WORLD) is None
del theTree._roots["0000000000000"]
tree._roots["0000000000000"] = NWItem(project, "0000000000000")
assert tree.findRoot(nwItemClass.WORLD) is None
del tree._roots["0000000000000"]
# Get item path
assert theTree.getItemPath("stuff") == []
assert theTree.getItemPath("c000000000001") == [
assert tree.getItemPath("stuff") == []
assert tree.getItemPath("c000000000001") == [
"c000000000001", "b000000000001", "a000000000001"
]
@@ -426,16 +426,16 @@ def testCoreTree_Methods(monkeypatch, mockGUI, mockItems):
with monkeypatch.context() as mp:
mp.setattr("novelwriter.core.tree.MAX_DEPTH", 0)
with pytest.raises(RecursionError):
theTree.getItemPath("c000000000001")
tree.getItemPath("c000000000001")
# Break the folder parent handle
theTree["b000000000001"]._parent = "stuff" # type: ignore
assert theTree.getItemPath("c000000000001") == [
tree["b000000000001"]._parent = "stuff" # type: ignore
assert tree.getItemPath("c000000000001") == [
"c000000000001", "b000000000001"
]
theTree["b000000000001"]._parent = "a000000000001" # type: ignore
assert theTree.getItemPath("c000000000001") == [
tree["b000000000001"]._parent = "a000000000001" # type: ignore
assert tree.getItemPath("c000000000001") == [
"c000000000001", "b000000000001", "a000000000001"
]
@@ -446,26 +446,26 @@ def testCoreTree_Methods(monkeypatch, mockGUI, mockItems):
def testCoreTree_MakeHandles(mockGUI):
"""Test generating item handles."""
random.seed(42)
theProject = NWProject()
theTree = NWTree(theProject)
project = NWProject()
tree = NWTree(project)
handles = ["1c803a3b1799d", "bdd6406671ad1", "3eb1346685257", "23b8c392456de"]
random.seed(42)
tHandle = theTree._makeHandle()
tHandle = tree._makeHandle()
assert tHandle == handles[0]
theTree._tree[handles[0]] = None # type: ignore
tree._tree[handles[0]] = None # type: ignore
# Add the next in line to the project to force duplicate
theTree._tree[handles[1]] = None # type: ignore
tHandle = theTree._makeHandle()
tree._tree[handles[1]] = None # type: ignore
tHandle = tree._makeHandle()
assert tHandle == handles[2]
theTree._tree[handles[2]] = None # type: ignore
tree._tree[handles[2]] = None # type: ignore
# Reset the seed to force collissions, which should still end up
# returning the next handle in the sequence
random.seed(42)
tHandle = theTree._makeHandle()
tHandle = tree._makeHandle()
assert tHandle == handles[3]
# END Test testCoreTree_MakeHandles
@@ -474,17 +474,17 @@ def testCoreTree_MakeHandles(mockGUI):
@pytest.mark.core
def testCoreTree_Stats(mockGUI, mockItems):
"""Test project stats methods."""
theProject = NWProject()
theTree = NWTree(theProject)
project = NWProject()
tree = NWTree(project)
for nwItem in mockItems:
theTree.append(nwItem)
tree.append(nwItem)
assert len(theTree) == len(mockItems)
theTree._order.append("stuff")
assert len(tree) == len(mockItems)
tree._order.append("stuff")
# Count Words
novelWords, noteWords = theTree.sumWords()
novelWords, noteWords = tree.sumWords()
assert novelWords == 550
assert noteWords == 400
@@ -494,33 +494,33 @@ def testCoreTree_Stats(mockGUI, mockItems):
@pytest.mark.core
def testCoreTree_Reorder(caplog, mockGUI, mockItems):
"""Test changing tree order."""
theProject = NWProject()
theTree = NWTree(theProject)
project = NWProject()
tree = NWTree(project)
aHandle = []
for nwItem in mockItems:
aHandle.append(nwItem.itemHandle)
theTree.append(nwItem)
tree.append(nwItem)
assert len(theTree) == len(mockItems)
assert len(tree) == len(mockItems)
bHandle = aHandle.copy()
bHandle[2], bHandle[3] = bHandle[3], bHandle[2]
assert aHandle != bHandle
assert theTree.handles() == aHandle
theTree.setOrder(bHandle)
assert theTree.handles() == bHandle
assert tree.handles() == aHandle
tree.setOrder(bHandle)
assert tree.handles() == bHandle
caplog.clear()
theTree.setOrder(bHandle + ["stuff"])
assert theTree.handles() == bHandle
tree.setOrder(bHandle + ["stuff"])
assert tree.handles() == bHandle
assert "Handle 'stuff' in new tree order is not in old order" in caplog.text
caplog.clear()
theTree._order.append("stuff")
theTree.setOrder(bHandle)
assert theTree.handles() == bHandle
tree._order.append("stuff")
tree.setOrder(bHandle)
assert tree.handles() == bHandle
assert "Handle 'stuff' in old tree order is not in new order" in caplog.text
# END Test testCoreTree_Reorder
@@ -529,40 +529,40 @@ def testCoreTree_Reorder(caplog, mockGUI, mockItems):
@pytest.mark.core
def testCoreTree_ToCFile(monkeypatch, fncPath, mockGUI, mockItems):
"""Test writing the ToC.txt file."""
theProject = NWProject()
theTree = NWTree(theProject)
project = NWProject()
tree = NWTree(project)
for nwItem in mockItems:
theTree.append(nwItem)
theTree.updateItemData(nwItem.itemHandle)
tree.append(nwItem)
tree.updateItemData(nwItem.itemHandle)
assert len(theTree) == len(mockItems)
theTree._order.append("stuff")
assert len(tree) == len(mockItems)
tree._order.append("stuff")
def mockIsFile(fileName):
"""Return True for items that are files in novelWriter and
should thus also be files in the project folder structure.
"""
dItem = theTree[fileName.name[:13]]
dItem = tree[fileName.name[:13]]
assert dItem is not None
return dItem.itemType == nwItemType.FILE
monkeypatch.setattr("pathlib.Path.is_file", mockIsFile)
theProject._storage._runtimePath = fncPath
project._storage._runtimePath = fncPath
(fncPath / "content").mkdir()
# Block extraction of the path
with monkeypatch.context() as mp:
mp.setattr("novelwriter.core.storage.NWStorage.contentPath", lambda *a: None)
assert theTree.writeToCFile() is False
assert tree.writeToCFile() is False
# Block opening the file
with monkeypatch.context() as mp:
mp.setattr("builtins.open", causeOSError)
assert theTree.writeToCFile() is False
assert tree.writeToCFile() is False
# Allow writing
assert theTree.writeToCFile() is True
assert tree.writeToCFile() is True
pathA = str(Path("content") / "c000000000001.nwd")
pathB = str(Path("content") / "c000000000002.nwd")
+3 -3
View File
@@ -37,7 +37,7 @@ def testDlgSplit_Main(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
# Create a new project
buildTestProject(nwGUI, projPath)
theProject = SHARED.project
project = SHARED.project
projTree = nwGUI.projView.projTree
docText = (
@@ -55,8 +55,8 @@ def testDlgSplit_Main(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
"#### New Section\n\nText\n\n"
)
hSplitDoc = theProject.newFile("Split Doc", C.hNovelRoot)
theProject.writeNewFile(hSplitDoc, 1, True, docText)
hSplitDoc = project.newFile("Split Doc", C.hNovelRoot)
project.writeNewFile(hSplitDoc, 1, True, docText)
projTree.revealNewTreeItem(hSplitDoc, nHandle=C.hNovelRoot, wordCount=True)
docText = f"# Split Doc\n\n{docText}"
+20 -20
View File
@@ -365,7 +365,7 @@ def testGuiEditor_Actions(qtbot, nwGUI, projPath, ipsumText, mockRnd):
text = "### A Scene\n\n%s" % "\n\n".join(ipsumText)
nwGUI.docEditor.replaceText(text)
theDoc = nwGUI.docEditor.document()
doc = nwGUI.docEditor.document()
# Select/Cut/Copy/Paste/Undo/Redo
# ===============================
@@ -374,17 +374,17 @@ def testGuiEditor_Actions(qtbot, nwGUI, projPath, ipsumText, mockRnd):
# Select All
assert nwGUI.docEditor.docAction(nwDocAction.SEL_ALL) is True
theCursor = nwGUI.docEditor.textCursor()
assert theCursor.hasSelection() is True
assert theCursor.selectedText() == text.replace("\n", "\u2029")
theCursor.clearSelection()
cursor = nwGUI.docEditor.textCursor()
assert cursor.hasSelection() is True
assert cursor.selectedText() == text.replace("\n", "\u2029")
cursor.clearSelection()
# Select Paragraph
nwGUI.docEditor.setCursorPosition(1000)
assert nwGUI.docEditor.getCursorPosition() == 1000
assert nwGUI.docEditor.docAction(nwDocAction.SEL_PARA) is True
theCursor = nwGUI.docEditor.textCursor()
assert theCursor.selectedText() == ipsumText[1]
cursor = nwGUI.docEditor.textCursor()
assert cursor.selectedText() == ipsumText[1]
# Cut Selected Text
nwGUI.docEditor.replaceText(text)
@@ -411,10 +411,10 @@ def testGuiEditor_Actions(qtbot, nwGUI, projPath, ipsumText, mockRnd):
assert nwGUI.docEditor.docAction(nwDocAction.COPY) is True
# Paste at End
nwGUI.docEditor.setCursorPosition(theDoc.characterCount())
theCursor = nwGUI.docEditor.textCursor()
theCursor.insertBlock()
theCursor.insertBlock()
nwGUI.docEditor.setCursorPosition(doc.characterCount())
cursor = nwGUI.docEditor.textCursor()
cursor.insertBlock()
cursor.insertBlock()
assert nwGUI.docEditor.docAction(nwDocAction.PASTE) is True
newText = nwGUI.docEditor.getText()
@@ -1017,8 +1017,8 @@ def testGuiEditor_BlockFormatting(qtbot, monkeypatch, nwGUI, projPath, ipsumText
# Invalid and Generic
# ===================
theText = "### A Scene\n\n%s" % ipsumText[0]
nwGUI.docEditor.replaceText(theText)
text = "### A Scene\n\n%s" % ipsumText[0]
nwGUI.docEditor.replaceText(text)
# Invalid Block
nwGUI.docEditor.setCursorPosition(0)
@@ -1561,9 +1561,9 @@ def testGuiEditor_WordCounters(qtbot, monkeypatch, nwGUI, projPath, ipsumText, m
SHARED.project.tree[C.hSceneDoc]._wordCount = 0 # type: ignore
assert nwGUI.openDocument(C.hSceneDoc) is True
theText = "\n\n".join(ipsumText)
cC, wC, pC = countWords(theText)
nwGUI.docEditor.replaceText(theText)
text = "\n\n".join(ipsumText)
cC, wC, pC = countWords(text)
nwGUI.docEditor.replaceText(text)
# Check that a busy counter is blocked
with monkeypatch.context() as mp:
@@ -1617,8 +1617,8 @@ def testGuiEditor_Search(qtbot, monkeypatch, nwGUI, prjLipsum):
# Select the Word "est"
nwGUI.docEditor.setCursorPosition(630)
nwGUI.docEditor._makeSelection(QTextCursor.WordUnderCursor)
theCursor = nwGUI.docEditor.textCursor()
assert theCursor.selectedText() == "est"
cursor = nwGUI.docEditor.textCursor()
assert cursor.selectedText() == "est"
# Activate search
nwGUI.mainMenu.aFind.activate(QAction.Trigger)
@@ -1747,8 +1747,8 @@ def testGuiEditor_Search(qtbot, monkeypatch, nwGUI, prjLipsum):
nwGUI.docEditor.docSearch.cancelSearch.activate(QAction.Trigger)
nwGUI.docEditor.setCursorPosition(630)
nwGUI.docEditor._makeSelection(QTextCursor.WordUnderCursor)
theCursor = nwGUI.docEditor.textCursor()
assert theCursor.selectedText() == "est"
cursor = nwGUI.docEditor.textCursor()
assert cursor.selectedText() == "est"
# Activate search again
nwGUI.mainMenu.aFind.activate(QAction.Trigger)
+35 -35
View File
@@ -187,8 +187,8 @@ def testGuiMenu_EditFormat(qtbot, monkeypatch, nwGUI, prjLipsum):
# Select Paragraph/All
nwGUI.docEditor.setCursorPosition(42)
nwGUI.mainMenu.aSelectPar.activate(QAction.Trigger)
theCursor = nwGUI.docEditor.textCursor()
assert theCursor.selectedText() == (
cursor = nwGUI.docEditor.textCursor()
assert cursor.selectedText() == (
"Pellentesque nec erat ut nulla posuere commodo. Curabitur nisi augue, imperdiet et porta "
"imperdiet, efficitur id leo. Cras finibus arcu at nibh commodo congue. Proin suscipit "
"placerat condimentum. Aenean ante enim, cursus id lorem a, blandit venenatis nibh. "
@@ -200,8 +200,8 @@ def testGuiMenu_EditFormat(qtbot, monkeypatch, nwGUI, prjLipsum):
nwGUI.docEditor.setCursorPosition(42)
nwGUI.mainMenu.aSelectAll.activate(QAction.Trigger)
theCursor = nwGUI.docEditor.textCursor()
assert len(theCursor.selectedText()) == 1895
cursor = nwGUI.docEditor.textCursor()
assert len(cursor.selectedText()) == 1895
# Clear the Text
nwGUI.docEditor.clear()
@@ -295,10 +295,10 @@ def testGuiMenu_EditFormat(qtbot, monkeypatch, nwGUI, prjLipsum):
"Here is some text\non multiple\nlines.\n\n"
"With another paragraph\nhere."
))
theCursor = nwGUI.docEditor.textCursor()
theCursor.setPosition(74)
theCursor.movePosition(QTextCursor.Right, QTextCursor.KeepAnchor, 29)
nwGUI.docEditor.setTextCursor(theCursor)
cursor = nwGUI.docEditor.textCursor()
cursor.setPosition(74)
cursor.movePosition(QTextCursor.Right, QTextCursor.KeepAnchor, 29)
nwGUI.docEditor.setTextCursor(cursor)
nwGUI.mainMenu.aFmtRmBreaks.activate(QAction.Trigger)
assert nwGUI.docEditor.getText() == (
"### New Text\n\n"
@@ -348,21 +348,21 @@ def testGuiMenu_ContextMenus(qtbot, nwGUI, prjLipsum):
assert nwGUI.openDocument("4c4f28287af27")
# Editor Context Menu
theCursor = nwGUI.docEditor.textCursor()
theCursor.setPosition(112)
nwGUI.docEditor.setTextCursor(theCursor)
theRect = nwGUI.docEditor.cursorRect()
cursor = nwGUI.docEditor.textCursor()
cursor.setPosition(112)
nwGUI.docEditor.setTextCursor(cursor)
rect = nwGUI.docEditor.cursorRect()
nwGUI.docEditor._openContextMenu(theRect.bottomRight())
qtbot.mouseClick(nwGUI.docEditor, Qt.LeftButton, pos=theRect.topLeft())
nwGUI.docEditor._openContextMenu(rect.bottomRight())
qtbot.mouseClick(nwGUI.docEditor, Qt.LeftButton, pos=rect.topLeft())
nwGUI.docEditor._makePosSelection(QTextCursor.WordUnderCursor, theRect.center())
theCursor = nwGUI.docEditor.textCursor()
assert theCursor.selectedText() == "imperdiet"
nwGUI.docEditor._makePosSelection(QTextCursor.WordUnderCursor, rect.center())
cursor = nwGUI.docEditor.textCursor()
assert cursor.selectedText() == "imperdiet"
nwGUI.docEditor._makePosSelection(QTextCursor.BlockUnderCursor, theRect.center())
theCursor = nwGUI.docEditor.textCursor()
assert theCursor.selectedText() == (
nwGUI.docEditor._makePosSelection(QTextCursor.BlockUnderCursor, rect.center())
cursor = nwGUI.docEditor.textCursor()
assert cursor.selectedText() == (
"Pellentesque nec erat ut nulla posuere commodo. Curabitur nisi augue, imperdiet et porta "
"imperdiet, efficitur id leo. Cras finibus arcu at nibh commodo congue. Proin suscipit "
"placerat condimentum. Aenean ante enim, cursus id lorem a, blandit venenatis nibh. "
@@ -375,21 +375,21 @@ def testGuiMenu_ContextMenus(qtbot, nwGUI, prjLipsum):
# Viewer Context Menu
assert nwGUI.viewDocument("4c4f28287af27")
theCursor = nwGUI.docViewer.textCursor()
theCursor.setPosition(112)
nwGUI.docViewer.setTextCursor(theCursor)
theRect = nwGUI.docViewer.cursorRect()
cursor = nwGUI.docViewer.textCursor()
cursor.setPosition(112)
nwGUI.docViewer.setTextCursor(cursor)
rect = nwGUI.docViewer.cursorRect()
nwGUI.docViewer._openContextMenu(theRect.bottomRight())
qtbot.mouseClick(nwGUI.docViewer, Qt.LeftButton, pos=theRect.topLeft())
nwGUI.docViewer._openContextMenu(rect.bottomRight())
qtbot.mouseClick(nwGUI.docViewer, Qt.LeftButton, pos=rect.topLeft())
nwGUI.docViewer._makePosSelection(QTextCursor.WordUnderCursor, theRect.center())
theCursor = nwGUI.docViewer.textCursor()
assert theCursor.selectedText() == "imperdiet"
nwGUI.docViewer._makePosSelection(QTextCursor.WordUnderCursor, rect.center())
cursor = nwGUI.docViewer.textCursor()
assert cursor.selectedText() == "imperdiet"
nwGUI.docEditor._makePosSelection(QTextCursor.BlockUnderCursor, theRect.center())
theCursor = nwGUI.docEditor.textCursor()
assert theCursor.selectedText() == (
nwGUI.docEditor._makePosSelection(QTextCursor.BlockUnderCursor, rect.center())
cursor = nwGUI.docEditor.textCursor()
assert cursor.selectedText() == (
"Pellentesque nec erat ut nulla posuere commodo. Curabitur nisi augue, imperdiet et porta "
"imperdiet, efficitur id leo. Cras finibus arcu at nibh commodo congue. Proin suscipit "
"placerat condimentum. Aenean ante enim, cursus id lorem a, blandit venenatis nibh. "
@@ -629,12 +629,12 @@ def testGuiMenu_Insert(qtbot, monkeypatch, nwGUI, fncPath, projPath, mockRnd):
assert not nwGUI.importDocument()
# Then a valid path, but bot a file that exists
theFile = fncPath / "import.txt"
monkeypatch.setattr(QFileDialog, "getOpenFileName", lambda *a, **k: (str(theFile), ""))
iFile = fncPath / "import.txt"
monkeypatch.setattr(QFileDialog, "getOpenFileName", lambda *a, **k: (str(iFile), ""))
assert not nwGUI.importDocument()
# Create the file and try again, but with no target document open
writeFile(theFile, "Foo")
writeFile(iFile, "Foo")
assert not nwGUI.importDocument()
# Open the document from before, and add some text to it
+33 -33
View File
@@ -370,7 +370,7 @@ def testGuiProjTree_MoveItemToTrash(qtbot, caplog, monkeypatch, nwGUI, projPath,
"""Test moving items to Trash."""
monkeypatch.setattr(GuiEditLabel, "getLabel", lambda *a, text: (text, True))
theProject = SHARED.project
project = SHARED.project
projTree = nwGUI.projView.projTree
# Create a project
@@ -392,7 +392,7 @@ def testGuiProjTree_MoveItemToTrash(qtbot, caplog, monkeypatch, nwGUI, projPath,
caplog.clear()
assert projTree.moveItemToTrash(C.hTitlePage) is False
assert theProject.tree.isTrash(C.hTitlePage) is False
assert project.tree.isTrash(C.hTitlePage) is False
assert "Could not delete item" in caplog.text
projTree._addTrashRoot = funcPointer
@@ -401,11 +401,11 @@ def testGuiProjTree_MoveItemToTrash(qtbot, caplog, monkeypatch, nwGUI, projPath,
with monkeypatch.context() as mp:
mp.setattr(QMessageBox, "result", lambda *a: QMessageBox.No)
assert projTree.moveItemToTrash(C.hTitlePage) is False
assert theProject.tree.isTrash(C.hTitlePage) is False
assert project.tree.isTrash(C.hTitlePage) is False
# Move a document to Trash
assert projTree.moveItemToTrash(C.hTitlePage) is True
assert theProject.tree.isTrash(C.hTitlePage) is True
assert project.tree.isTrash(C.hTitlePage) is True
# Cannot be moved again
caplog.clear()
@@ -422,7 +422,7 @@ def testGuiProjTree_PermanentlyDeleteItem(qtbot, caplog, monkeypatch, nwGUI, pro
"""Test permanently deleting items."""
monkeypatch.setattr(GuiEditLabel, "getLabel", lambda *a, text: (text, True))
theProject = SHARED.project
project = SHARED.project
projTree = nwGUI.projView.projTree
# Create a project
@@ -437,31 +437,31 @@ def testGuiProjTree_PermanentlyDeleteItem(qtbot, caplog, monkeypatch, nwGUI, pro
caplog.clear()
assert projTree.permDeleteItem(C.hNovelRoot) is False
assert "Root folders can only be deleted when they are empty" in caplog.text
assert C.hNovelRoot in theProject.tree
assert C.hNovelRoot in project.tree
# Deleting unused root item is allowed
caplog.clear()
assert projTree.permDeleteItem(C.hPlotRoot) is True
assert C.hPlotRoot not in theProject.tree
assert C.hPlotRoot not in project.tree
# User cancels action
with monkeypatch.context() as mp:
mp.setattr(QMessageBox, "result", lambda *a: QMessageBox.No)
assert projTree.permDeleteItem(C.hTitlePage) is False
assert C.hTitlePage in theProject.tree
assert C.hTitlePage in project.tree
# Deleting file is OK, and if it is open, it should close
assert nwGUI.openDocument(C.hTitlePage) is True
assert nwGUI.docEditor.docHandle == C.hTitlePage
assert projTree.permDeleteItem(C.hTitlePage) is True
assert C.hTitlePage not in theProject.tree
assert C.hTitlePage not in project.tree
assert nwGUI.docEditor.docHandle is None
# Deleting folder + files recursively is ok
assert projTree.permDeleteItem(C.hChapterDir) is True
assert C.hChapterDir not in theProject.tree
assert C.hChapterDoc not in theProject.tree
assert C.hSceneDoc not in theProject.tree
assert C.hChapterDir not in project.tree
assert C.hChapterDoc not in project.tree
assert C.hSceneDoc not in project.tree
nwGUI.closeProject()
@@ -473,7 +473,7 @@ def testGuiProjTree_EmptyTrash(qtbot, caplog, monkeypatch, nwGUI, projPath, mock
"""Test emptying Trash."""
monkeypatch.setattr(GuiEditLabel, "getLabel", lambda *a, text: (text, True))
theProject = SHARED.project
project = SHARED.project
projTree = nwGUI.projView.projTree
# No project open
@@ -491,26 +491,26 @@ def testGuiProjTree_EmptyTrash(qtbot, caplog, monkeypatch, nwGUI, projPath, mock
assert projTree.moveItemToTrash(C.hTitlePage) is True
assert projTree.moveItemToTrash(C.hChapterDir) is True
assert theProject.tree.isTrash(C.hTitlePage) is True
assert theProject.tree.isTrash(C.hChapterDir) is True
assert theProject.tree.isTrash(C.hChapterDoc) is True
assert theProject.tree.isTrash(C.hSceneDoc) is True
assert project.tree.isTrash(C.hTitlePage) is True
assert project.tree.isTrash(C.hChapterDir) is True
assert project.tree.isTrash(C.hChapterDoc) is True
assert project.tree.isTrash(C.hSceneDoc) is True
# User cancels
with monkeypatch.context() as mp:
mp.setattr(QMessageBox, "result", lambda *a: QMessageBox.No)
assert projTree.emptyTrash() is False
assert C.hTitlePage in theProject.tree
assert C.hChapterDir in theProject.tree
assert C.hChapterDoc in theProject.tree
assert C.hSceneDoc in theProject.tree
assert C.hTitlePage in project.tree
assert C.hChapterDir in project.tree
assert C.hChapterDoc in project.tree
assert C.hSceneDoc in project.tree
# Run again to empty all items
assert projTree.emptyTrash() is True
assert C.hTitlePage not in theProject.tree
assert C.hChapterDir not in theProject.tree
assert C.hChapterDoc not in theProject.tree
assert C.hSceneDoc not in theProject.tree
assert C.hTitlePage not in project.tree
assert C.hChapterDir not in project.tree
assert C.hChapterDoc not in project.tree
assert C.hSceneDoc not in project.tree
# Running Empty Trash again is cancelled due to empty folder
assert projTree.emptyTrash() is False
@@ -634,7 +634,7 @@ def testGuiProjTree_SplitDocument(qtbot, monkeypatch, nwGUI, projPath, mockRnd,
# Create a project
buildTestProject(nwGUI, projPath)
theProject = SHARED.project
project = SHARED.project
projTree = nwGUI.projView.projTree
docText = (
@@ -652,8 +652,8 @@ def testGuiProjTree_SplitDocument(qtbot, monkeypatch, nwGUI, projPath, mockRnd,
"#### New Section\n\nText\n\n"
)
hSplitDoc = theProject.newFile("Split Doc", C.hNovelRoot)
theProject.writeNewFile(hSplitDoc, 1, True, docText) # type: ignore
hSplitDoc = project.newFile("Split Doc", C.hNovelRoot)
project.writeNewFile(hSplitDoc, 1, True, docText) # type: ignore
projTree.revealNewTreeItem(hSplitDoc, nHandle=C.hNovelRoot, wordCount=True)
docText = f"# Split Doc\n\n{docText}"
@@ -700,25 +700,25 @@ def testGuiProjTree_SplitDocument(qtbot, monkeypatch, nwGUI, projPath, mockRnd,
mp.setattr("builtins.open", causeOSError)
assert projTree._splitDocument(hSplitDoc) is True
for tHandle in fstSet:
assert tHandle in theProject.tree
assert tHandle in project.tree
assert not (projPath / "content" / f"{tHandle}.nwd").is_file()
# Writing succeeds
assert projTree._splitDocument(hSplitDoc) is True
for tHandle in sndSet:
assert tHandle in theProject.tree
assert tHandle in project.tree
assert (projPath / "content" / f"{tHandle}.nwd").is_file()
# Add to a folder and move source to trash
splitData["intoFolder"] = True
splitData["moveToTrash"] = True
assert projTree._splitDocument(hSplitDoc) is True
assert "0000000000029" in theProject.tree # The folder
assert "0000000000029" in project.tree # The folder
for tHandle in trdSet:
assert tHandle in theProject.tree
assert tHandle in project.tree
assert (projPath / "content" / f"{tHandle}.nwd").is_file()
assert theProject.tree.isTrash(hSplitDoc) is True # type: ignore
assert project.tree.isTrash(hSplitDoc) is True # type: ignore
# Cancelled by user
with monkeypatch.context() as mp: