def testCoreToken_TextOps(monkeypatch, nwMinimal, dummyGUI):
    """Test handling files and text in the Tokenizer class.
    """
    theProject = NWProject(dummyGUI)
    theProject.projTree.setSeed(42)
    theProject.projLang = "en"
    theProject._loadProjectLocalisation()

    theToken = Tokenizer(theProject, dummyGUI)
    theToken.setKeepMarkdown(True)

    assert theProject.openProject(nwMinimal)
    sHandle = "8c659a11cd429"

    # Set some content to work with

    docText = (
        "### Scene Six\n\n"
        "This is text with _italic text_, some **bold text**, some ~~deleted text~~, "
        "and some **_mixed text_** and **some _nested_ text**.\n\n"
        "#### Replace\n\n"
        "Also, replace <A> and <B>.\n\n"
    )
    docTextR = docText.replace("<A>", "this").replace("<B>", "that")

    nDoc = NWDoc(theProject, dummyGUI)
    nDoc.openDocument(sHandle)
    nDoc.saveDocument(docText)
    nDoc.clearDocument()

    theProject.setAutoReplace({"A": "this", "B": "that"})

    assert theProject.saveProject()

    # Root heading
    assert theToken.addRootHeading("dummy") is False
    assert theToken.addRootHeading(sHandle) is False
    assert theToken.addRootHeading("7695ce551d265") is True
    assert theToken.theMarkdown[-1] == "# Notes: Plot\n\n"

    # Set text
    assert theToken.setText("dummy") is False
    assert theToken.setText(sHandle) is True
    assert theToken.theText == docText

    with monkeypatch.context() as mp:
        mp.setattr("nw.constants.nwConst.MAX_DOCSIZE", 100)
        assert theToken.setText(sHandle, docText) is True
        assert theToken.theText == (
            "# ERROR\n\n"
            "Document 'New Scene' is too big (0.00 MB). Skipping.\n\n"
        )

    assert theToken.setText(sHandle, docText) is True
    assert theToken.theText == docText

    assert theToken.isNone is False
    assert theToken.isTitle is False
    assert theToken.isBook is False
    assert theToken.isPage is False
    assert theToken.isPart is False
    assert theToken.isUnNum is False
    assert theToken.isChap is False
    assert theToken.isScene is True
    assert theToken.isNote is False
    assert theToken.isNovel is True

    # Pre Processing
    theToken.doPreProcessing()
    assert theToken.theText == docTextR

    # Post Processing
    theToken.theResult = r"This is text with escapes: \** \~~ \__"
    theToken.doPostProcessing()
    assert theToken.theResult == "This is text with escapes: ** ~~ __"

    # Save File
    savePath = os.path.join(nwMinimal, "dump.nwd")
    theToken.saveRawMarkdown(savePath)
    assert readFile(savePath) == "# Notes: Plot\n\n"
Beispiel #2
0
    def _doSplit(self):
        """Perform the split of the file, create a new folder in the
        same parent folder, and multiple files depending on split level
        settings. The old file is not removed in the split process, and
        must be deleted manually.
        """
        logger.verbose("GuiDocSplit split button clicked")

        if self.sourceItem is None:
            self.theParent.makeAlert(
                ("No source document selected. Nothing to do."), nwAlert.ERROR)
            return

        srcItem = self.theProject.projTree[self.sourceItem]
        if srcItem is None:
            self.theParent.makeAlert(("Could not parse source document."),
                                     nwAlert.ERROR)
            return

        theDoc = NWDoc(self.theProject, self.theParent)
        theText = theDoc.openDocument(self.sourceItem, False)
        theLines = theText.splitlines()
        nLines = len(theLines)
        theLines.insert(0, "%Split Doc")
        logger.debug("Splitting document %s with %d lines" %
                     (self.sourceItem, nLines))

        finalOrder = []
        for i in range(self.listBox.count()):
            listItem = self.listBox.item(i)
            wTitle = listItem.text()
            lineNo = listItem.data(Qt.UserRole)
            finalOrder.append([wTitle, lineNo, nLines])
            if i > 0:
                finalOrder[i - 1][2] = lineNo

        nFiles = len(finalOrder)
        if nFiles == 0:
            self.theParent.makeAlert(("No headers found. Nothing to do."),
                                     nwAlert.ERROR)
            return

        # Check that another folder can be created
        parTree = self.theProject.projTree.getItemPath(srcItem.itemParent)
        if len(parTree) >= nwConst.MAX_DEPTH - 1:
            self.theParent.makeAlert(
                ("Cannot add new folder for the document split. "
                 "Maximum folder depth has been reached. "
                 "Please move the file to another level in the project tree."),
                nwAlert.ERROR)
            return

        msgYes = self.theParent.askQuestion(
            "Split Document",
            ("The document will be split into %d file(s) in a new folder. "
             "The original document will remain intact.<br><br>"
             "Continue with the splitting process?") % nFiles)
        if not msgYes:
            return

        # Create the folder
        fHandle = self.theProject.newFolder(srcItem.itemName,
                                            srcItem.itemClass,
                                            srcItem.itemParent)
        self.theParent.treeView.revealNewTreeItem(fHandle)
        logger.verbose("Creating folder %s" % fHandle)

        # Loop through, and create the files
        for wTitle, iStart, iEnd in finalOrder:

            itemLayout = nwItemLayout.NOTE
            if srcItem.itemClass == nwItemClass.NOVEL:
                if wTitle.startswith("# "):
                    itemLayout = nwItemLayout.PARTITION
                elif wTitle.startswith("## "):
                    itemLayout = nwItemLayout.CHAPTER
                elif wTitle.startswith("### "):
                    itemLayout = nwItemLayout.SCENE
                elif wTitle.startswith("#### "):
                    itemLayout = nwItemLayout.SCENE

            wTitle = wTitle.lstrip("#")
            wTitle = wTitle.strip()

            nHandle = self.theProject.newFile(wTitle, srcItem.itemClass,
                                              fHandle)
            newItem = self.theProject.projTree[nHandle]
            newItem.setLayout(itemLayout)
            newItem.setStatus(srcItem.itemStatus)
            logger.verbose(
                "Creating new document %s with text from line %d to %d" %
                (nHandle, iStart, iEnd - 1))

            theText = "\n".join(theLines[iStart:iEnd])
            theText = theText.rstrip("\n") + "\n\n"
            theDoc.openDocument(nHandle, False)
            theDoc.saveDocument(theText)
            theDoc.clearDocument()
            self.theParent.treeView.revealNewTreeItem(nHandle)

        self._doClose()

        return
Beispiel #3
0
def testCoreDocument_LoadSave(monkeypatch, dummyGUI, nwMinimal):
    """Test loading and saving a document with the NWDoc class.
    """
    theProject = NWProject(dummyGUI)
    assert theProject.openProject(nwMinimal)
    assert theProject.projPath == nwMinimal

    theDoc = NWDoc(theProject, dummyGUI)
    sHandle = "8c659a11cd429"

    # Not a valid handle
    assert theDoc.openDocument("dummy") is None

    # Non-existent handle
    assert theDoc.openDocument("0000000000000") is None

    # Cause open() to fail while loading
    def dummyOpen(*args, **kwargs):
        raise OSError

    with monkeypatch.context() as mp:
        mp.setattr("builtins.open", dummyOpen)
        assert theDoc.openDocument(sHandle) is None

    # Load the text
    assert theDoc.openDocument(sHandle) == "### New Scene\n\n"

    # Try to open a new (non-existent) file
    nHandle = theProject.projTree.findRoot(nwItemClass.NOVEL)
    assert nHandle is not None
    xHandle = theProject.newFile("New File", nwItemClass.NOVEL, nHandle)
    assert theDoc.openDocument(xHandle) == ""

    # Check cached item
    assert isinstance(theDoc._theItem, NWItem)
    assert theDoc.openDocument(xHandle, isOrphan=True) == ""
    assert theDoc._theItem is None

    # Set handle and save again
    theText = "### Test File\n\nText ...\n\n"
    assert theDoc.openDocument(xHandle) == ""
    assert theDoc.saveDocument(theText)

    # Save again to ensure temp file and previous file is handled
    assert theDoc.saveDocument(theText)

    # Check file content
    docPath = os.path.join(nwMinimal, "content", xHandle + ".nwd")
    with open(docPath, mode="r", encoding="utf8") as inFile:
        assert inFile.read() == ("%%~name: New File\n"
                                 f"%%~path: a508bb932959c/{xHandle}\n"
                                 "%%~kind: NOVEL/SCENE\n"
                                 "### Test File\n\n"
                                 "Text ...\n\n")

    # Force no meta data
    theDoc._theItem = None
    assert theDoc.saveDocument(theText)

    with open(docPath, mode="r", encoding="utf8") as inFile:
        assert inFile.read() == theText

    # Cause open() to fail while saving
    with monkeypatch.context() as mp:
        mp.setattr("builtins.open", causeOSError)
        assert not theDoc.saveDocument(theText)

    # Saving with no handle
    theDoc.clearDocument()
    assert not theDoc.saveDocument(theText)

    # Delete the last document
    assert not theDoc.deleteDocument("dummy")
    assert os.path.isfile(docPath)

    # Cause the delete to fail
    with monkeypatch.context() as mp:
        mp.setattr("os.unlink", causeOSError)
        assert not theDoc.deleteDocument(xHandle)

    # Make the delete pass
    assert theDoc.deleteDocument(xHandle)
    assert not os.path.isfile(docPath)