def testCoreProject_NewFile(fncDir, outDir, refDir, mockGUI): """Check that new files can be added to the project. """ projFile = os.path.join(fncDir, "nwProject.nwx") testFile = os.path.join(outDir, "coreProject_NewFile_nwProject.nwx") compFile = os.path.join(refDir, "coreProject_NewFile_nwProject.nwx") theProject = NWProject(mockGUI) theProject.projTree.setSeed(42) assert theProject.newProject({"projPath": fncDir}) is True assert theProject.setProjectPath(fncDir) is True assert theProject.saveProject() is True assert theProject.closeProject() is True assert theProject.openProject(projFile) is True assert isinstance( theProject.newFile("Hello", nwItemClass.NOVEL, "31489056e0916"), str) assert isinstance( theProject.newFile("Jane", nwItemClass.CHARACTER, "71ee45a3c0db9"), str) assert theProject.projChanged assert theProject.saveProject() is True assert theProject.closeProject() is True copyfile(projFile, testFile) assert cmpFiles(testFile, compFile, [2, 6, 7, 8]) assert theProject.projChanged is False
def testCoreProject_AccessItems(nwMinimal, mockGUI): """Test helper functions for the project folder. """ theProject = NWProject(mockGUI) theProject.openProject(nwMinimal) # Move Novel ROOT to after its files oldOrder = [ "a508bb932959c", # ROOT: Novel "a35baf2e93843", # FILE: Title Page "a6d311a93600a", # FOLDER: New Chapter "f5ab3e30151e1", # FILE: New Chapter "8c659a11cd429", # FILE: New Scene "7695ce551d265", # ROOT: Plot "afb3043c7b2b3", # ROOT: Characters "9d5247ab588e0", # ROOT: World ] newOrder = [ "a35baf2e93843", # FILE: Title Page "f5ab3e30151e1", # FILE: New Chapter "8c659a11cd429", # FILE: New Scene "a6d311a93600a", # FOLDER: New Chapter "a508bb932959c", # ROOT: Novel "7695ce551d265", # ROOT: Plot "afb3043c7b2b3", # ROOT: Characters "9d5247ab588e0", # ROOT: World ] assert theProject.projTree.handles() == oldOrder assert theProject.setTreeOrder(newOrder) assert theProject.projTree.handles() == newOrder # Add a non-existing item theProject.projTree._treeOrder.append("01234567789abc") # Add an item with a non-existent parent nHandle = theProject.newFile("Test File", nwItemClass.NOVEL, "a6d311a93600a") theProject.projTree[nHandle].setParent("cba9876543210") assert theProject.projTree[nHandle].itemParent == "cba9876543210" retOrder = [] for tItem in theProject.getProjectItems(): retOrder.append(tItem.itemHandle) assert retOrder == [ "a508bb932959c", # ROOT: Novel "7695ce551d265", # ROOT: Plot "afb3043c7b2b3", # ROOT: Characters "9d5247ab588e0", # ROOT: World nHandle, # FILE: Test File "a35baf2e93843", # FILE: Title Page "a6d311a93600a", # FOLDER: New Chapter "f5ab3e30151e1", # FILE: New Chapter "8c659a11cd429", # FILE: New Scene ] assert theProject.projTree[nHandle].itemParent is None
def testCoreIndex_ExtractData(nwMinimal, mockGUI): """Check the index data extraction functions. """ theProject = NWProject(mockGUI) theProject.projTree.setSeed(42) assert theProject.openProject(nwMinimal) is True theIndex = NWIndex(theProject) nHandle = theProject.newFile("Hello", nwItemClass.NOVEL, "a508bb932959c") cHandle = theProject.newFile("Jane", nwItemClass.CHARACTER, "afb3043c7b2b3") assert theIndex.getNovelData("", "") is None assert theIndex.getNovelData("a508bb932959c", "") is None assert theIndex.scanText(cHandle, ("# Jane Smith\n" "@tag: Jane\n")) assert theIndex.scanText(nHandle, ("# Hello World!\n" "@pov: Jane\n" "@char: Jane\n\n" "% this is a comment\n\n" "This is a story about Jane Smith.\n\n" "Well, not really.\n")) # The novel structure should contain the pointer to the novel file header theKeys = [] for aKey, _, _, _ in theIndex.novelStructure(): theKeys.append(aKey) assert theKeys == ["%s:T000001" % nHandle] # Check that excluded files can be skipped theProject.projTree[nHandle].setExported(False) theKeys = [] for aKey, _, _, _ in theIndex.novelStructure(skipExcluded=False): theKeys.append(aKey) assert theKeys == ["%s:T000001" % nHandle] theKeys = [] for aKey, _, _, _ in theIndex.novelStructure(skipExcluded=True): theKeys.append(aKey) assert theKeys == [] theKeys = [] for aKey, _, _, _ in theIndex.novelStructure(): theKeys.append(aKey) assert theKeys == [] # The novel file should have the correct counts cC, wC, pC = theIndex.getCounts(nHandle) assert cC == 62 # Characters in text and title only assert wC == 12 # Words in text and title only assert pC == 2 # Paragraphs in text only # getReferences # ============= # Look up an ivalid handle theRefs = theIndex.getReferences("Not a handle") assert theRefs["@pov"] == [] assert theRefs["@char"] == [] # The novel file should now refer to Jane as @pov and @char theRefs = theIndex.getReferences(nHandle) assert theRefs["@pov"] == ["Jane"] assert theRefs["@char"] == ["Jane"] # getBackReferenceList # ==================== # None handle should return an empty dict assert theIndex.getBackReferenceList(None) == {} # The character file should have a record of the reference from the novel file theRefs = theIndex.getBackReferenceList(cHandle) assert theRefs == {nHandle: "T000001"} # getTagSource # ============ assert theIndex.getTagSource("Jane") == (cHandle, 2, "T000001") assert theIndex.getTagSource("John") == (None, 0, "T000000") # getCounts # ========= # For whole text and sections # Get section counts for a novel file assert theIndex.scanText( nHandle, ("# Hello World!\n" "@pov: Jane\n" "@char: Jane\n\n" "% this is a comment\n\n" "This is a story about Jane Smith.\n\n" "Well, not really.\n\n" "# Hello World!\n" "@pov: Jane\n" "@char: Jane\n\n" "% this is a comment\n\n" "This is a story about Jane Smith.\n\n" "Well, not really. She's still awesome though.\n")) # Whole document cC, wC, pC = theIndex.getCounts(nHandle) assert cC == 152 assert wC == 28 assert pC == 4 # First part cC, wC, pC = theIndex.getCounts(nHandle, "T000001") assert cC == 62 assert wC == 12 assert pC == 2 # Second part cC, wC, pC = theIndex.getCounts(nHandle, "T000011") assert cC == 90 assert wC == 16 assert pC == 2 # Get section counts for a note file assert theIndex.scanText( cHandle, ("# Hello World!\n" "@pov: Jane\n" "@char: Jane\n\n" "% this is a comment\n\n" "This is a story about Jane Smith.\n\n" "Well, not really.\n\n" "# Hello World!\n" "@pov: Jane\n" "@char: Jane\n\n" "% this is a comment\n\n" "This is a story about Jane Smith.\n\n" "Well, not really. She's still awesome though.\n")) # Whole document cC, wC, pC = theIndex.getCounts(cHandle) assert cC == 152 assert wC == 28 assert pC == 4 # First part cC, wC, pC = theIndex.getCounts(cHandle, "T000001") assert cC == 62 assert wC == 12 assert pC == 2 # Second part cC, wC, pC = theIndex.getCounts(cHandle, "T000011") assert cC == 90 assert wC == 16 assert pC == 2 # Novel Stats # =========== hHandle = theProject.newFile("Chapter", nwItemClass.NOVEL, "a508bb932959c") sHandle = theProject.newFile("Scene One", nwItemClass.NOVEL, "a508bb932959c") tHandle = theProject.newFile("Scene Two", nwItemClass.NOVEL, "a508bb932959c") theProject.projTree[hHandle].itemLayout == nwItemLayout.DOCUMENT theProject.projTree[sHandle].itemLayout == nwItemLayout.DOCUMENT theProject.projTree[tHandle].itemLayout == nwItemLayout.DOCUMENT assert theIndex.scanText(hHandle, "## Chapter One\n\n") assert theIndex.scanText(sHandle, "### Scene One\n\n") assert theIndex.scanText(tHandle, "### Scene Two\n\n") assert theIndex._listNovelHandles(False) == [ nHandle, hHandle, sHandle, tHandle ] assert theIndex._listNovelHandles(True) == [hHandle, sHandle, tHandle] # Add a fake handle to the tree and check that it's ignored theProject.projTree._treeOrder.append("0000000000000") assert theIndex._listNovelHandles(False) == [ nHandle, hHandle, sHandle, tHandle ] theProject.projTree._treeOrder.remove("0000000000000") # Extract stats assert theIndex.getNovelWordCount(False) == 34 assert theIndex.getNovelWordCount(True) == 6 assert theIndex.getNovelTitleCounts(False) == [0, 2, 1, 2, 0] assert theIndex.getNovelTitleCounts(True) == [0, 0, 1, 2, 0] # Table of Contents assert theIndex.getTableOfContents(0, True) == [] assert theIndex.getTableOfContents(1, True) == [] assert theIndex.getTableOfContents(2, True) == [ ("%s:T000001" % hHandle, 2, "Chapter One", 6), ] assert theIndex.getTableOfContents(3, True) == [ ("%s:T000001" % hHandle, 2, "Chapter One", 2), ("%s:T000001" % sHandle, 3, "Scene One", 2), ("%s:T000001" % tHandle, 3, "Scene Two", 2), ] assert theIndex.getTableOfContents(0, False) == [] assert theIndex.getTableOfContents(1, False) == [ ("%s:T000001" % nHandle, 1, "Hello World!", 12), ("%s:T000011" % nHandle, 1, "Hello World!", 22), ] # Header Word Counts bHandle = "0000000000000" assert theIndex.getHandleWordCounts(bHandle) == [] assert theIndex.getHandleWordCounts(hHandle) == [("%s:T000001" % hHandle, 2)] assert theIndex.getHandleWordCounts(sHandle) == [("%s:T000001" % sHandle, 2)] assert theIndex.getHandleWordCounts(tHandle) == [("%s:T000001" % tHandle, 2)] assert theIndex.getHandleWordCounts(nHandle) == [ ("%s:T000001" % nHandle, 12), ("%s:T000011" % nHandle, 16) ] assert theProject.closeProject() # Header Record bHandle = "0000000000000" assert theIndex.getHandleHeaders(bHandle) == [] assert theIndex.getHandleHeaders(hHandle) == [("T000001", "H2", "Chapter One")] assert theIndex.getHandleHeaders(sHandle) == [("T000001", "H3", "Scene One")] assert theIndex.getHandleHeaders(tHandle) == [("T000001", "H3", "Scene Two")] assert theIndex.getHandleHeaders(nHandle) == [ ("T000001", "H1", "Hello World!"), ("T000011", "H1", "Hello World!") ]
def testCoreIndex_ScanText(nwMinimal, mockGUI): """Check the index text scanner. """ theProject = NWProject(mockGUI) theProject.projTree.setSeed(42) assert theProject.openProject(nwMinimal) is True theIndex = NWIndex(theProject) # Some items for fail to scan tests dHandle = theProject.newFolder("Folder", nwItemClass.NOVEL, "a508bb932959c") xHandle = theProject.newFile("No Layout", nwItemClass.NOVEL, "a508bb932959c") xItem = theProject.projTree[xHandle] xItem.setLayout(nwItemLayout.NO_LAYOUT) # Check invalid data assert theIndex.scanText(None, "Hello World!") is False assert theIndex.scanText(dHandle, "Hello World!") is False assert theIndex.scanText(xHandle, "Hello World!") is False xItem.setLayout(nwItemLayout.DOCUMENT) xItem.setParent(None) assert theIndex.scanText(xHandle, "Hello World!") is False # Create the trash folder tHandle = theProject.trashFolder() assert theProject.projTree[tHandle] is not None xItem.setParent(tHandle) assert theIndex.scanText(xHandle, "Hello World!") is False # Create the archive root aHandle = theProject.newRoot("Archive", nwItemClass.ARCHIVE) assert theProject.projTree[aHandle] is not None xItem.setParent(aHandle) assert theIndex.scanText(xHandle, "Hello World!") is False # Make some usable items tHandle = theProject.newFile("Title", nwItemClass.NOVEL, "a508bb932959c") pHandle = theProject.newFile("Page", nwItemClass.NOVEL, "a508bb932959c") nHandle = theProject.newFile("Hello", nwItemClass.NOVEL, "a508bb932959c") cHandle = theProject.newFile("Jane", nwItemClass.CHARACTER, "afb3043c7b2b3") sHandle = theProject.newFile("Scene", nwItemClass.NOVEL, "a508bb932959c") # Text Indexing # ============= # Index correct text assert theIndex.scanText(cHandle, ("# Jane Smith\n" "@tag: Jane\n")) assert theIndex.scanText(nHandle, ("# Hello World!\n" "@pov: Jane\n" "@char: Jane\n\n" "% this is a comment\n\n" "This is a story about Jane Smith.\n\n" "Well, not really.\n")) assert theIndex._tagIndex == {"Jane": [2, cHandle, "CHARACTER", "T000001"]} assert theIndex.getNovelData(nHandle, "T000001")["title"] == "Hello World!" # Title Indexing # ============== # Document File assert theIndex.scanText( nHandle, ( "# Title One\n\n" "% synopsis: Synopsis One.\n\n" "Paragraph One.\n\n" "## Title Two\n\n" "% synopsis: Synopsis Two.\n\n" "Paragraph Two.\n\n" "### Title Three\n\n" "% synopsis: Synopsis Three.\n\n" "Paragraph Three.\n\n" "#### Title Four\n\n" "% synopsis: Synopsis Four.\n\n" "Paragraph Four.\n\n" "##### Title Five\n\n" # Not interpreted as a title, the hashes are counted as a word "Paragraph Five.\n\n")) assert nHandle not in theIndex._refIndex assert theIndex._fileIndex[nHandle]["T000001"]["level"] == "H1" assert theIndex._fileIndex[nHandle]["T000007"]["level"] == "H2" assert theIndex._fileIndex[nHandle]["T000013"]["level"] == "H3" assert theIndex._fileIndex[nHandle]["T000019"]["level"] == "H4" assert theIndex._fileIndex[nHandle]["T000001"]["title"] == "Title One" assert theIndex._fileIndex[nHandle]["T000007"]["title"] == "Title Two" assert theIndex._fileIndex[nHandle]["T000013"]["title"] == "Title Three" assert theIndex._fileIndex[nHandle]["T000019"]["title"] == "Title Four" assert theIndex._fileIndex[nHandle]["T000001"]["layout"] == "DOCUMENT" assert theIndex._fileIndex[nHandle]["T000007"]["layout"] == "DOCUMENT" assert theIndex._fileIndex[nHandle]["T000013"]["layout"] == "DOCUMENT" assert theIndex._fileIndex[nHandle]["T000019"]["layout"] == "DOCUMENT" assert theIndex._fileIndex[nHandle]["T000001"]["cCount"] == 23 assert theIndex._fileIndex[nHandle]["T000007"]["cCount"] == 23 assert theIndex._fileIndex[nHandle]["T000013"]["cCount"] == 27 assert theIndex._fileIndex[nHandle]["T000019"]["cCount"] == 56 assert theIndex._fileIndex[nHandle]["T000001"]["wCount"] == 4 assert theIndex._fileIndex[nHandle]["T000007"]["wCount"] == 4 assert theIndex._fileIndex[nHandle]["T000013"]["wCount"] == 4 assert theIndex._fileIndex[nHandle]["T000019"]["wCount"] == 9 assert theIndex._fileIndex[nHandle]["T000001"]["pCount"] == 1 assert theIndex._fileIndex[nHandle]["T000007"]["pCount"] == 1 assert theIndex._fileIndex[nHandle]["T000013"]["pCount"] == 1 assert theIndex._fileIndex[nHandle]["T000019"]["pCount"] == 3 assert theIndex._fileIndex[nHandle]["T000001"][ "synopsis"] == "Synopsis One." assert theIndex._fileIndex[nHandle]["T000007"][ "synopsis"] == "Synopsis Two." assert theIndex._fileIndex[nHandle]["T000013"][ "synopsis"] == "Synopsis Three." assert theIndex._fileIndex[nHandle]["T000019"][ "synopsis"] == "Synopsis Four." # Note File assert theIndex.scanText(cHandle, ("# Title One\n\n" "@tag: One\n\n" "% synopsis: Synopsis One.\n\n" "Paragraph One.\n\n")) assert cHandle not in theIndex._refIndex assert theIndex._fileIndex[cHandle]["T000001"]["level"] == "H1" assert theIndex._fileIndex[cHandle]["T000001"]["title"] == "Title One" assert theIndex._fileIndex[cHandle]["T000001"]["layout"] == "NOTE" assert theIndex._fileIndex[cHandle]["T000001"]["cCount"] == 23 assert theIndex._fileIndex[cHandle]["T000001"]["wCount"] == 4 assert theIndex._fileIndex[cHandle]["T000001"]["pCount"] == 1 assert theIndex._fileIndex[cHandle]["T000001"][ "synopsis"] == "Synopsis One." # Valid and Invalid References assert theIndex.scanText( sHandle, ( "# Title One\n\n" "@pov: One\n\n" # Valid "@char: Two\n\n" # Invalid tag "@:\n\n" # Invalid line "% synopsis: Synopsis One.\n\n" "Paragraph One.\n\n")) assert theIndex._refIndex[sHandle]["T000001"] == ([[3, "@pov", "One"], [5, "@char", "Two"]]) # Special Titles # ============== assert theIndex.scanText(tHandle, ("#! My Project\n\n" ">> By Jane Doe <<\n\n")) assert tHandle not in theIndex._refIndex assert theIndex._fileIndex[tHandle]["T000001"]["level"] == "H1" assert theIndex._fileIndex[tHandle]["T000001"]["title"] == "My Project" assert theIndex._fileIndex[tHandle]["T000001"]["layout"] == "DOCUMENT" assert theIndex._fileIndex[tHandle]["T000001"]["cCount"] == 21 assert theIndex._fileIndex[tHandle]["T000001"]["wCount"] == 5 assert theIndex._fileIndex[tHandle]["T000001"]["pCount"] == 1 assert theIndex._fileIndex[tHandle]["T000001"]["synopsis"] == "" assert theIndex.scanText(tHandle, ("##! Prologue\n\n" "In the beginning there was time ...\n\n")) assert tHandle not in theIndex._refIndex assert theIndex._fileIndex[tHandle]["T000001"]["level"] == "H2" assert theIndex._fileIndex[tHandle]["T000001"]["title"] == "Prologue" assert theIndex._fileIndex[tHandle]["T000001"]["layout"] == "DOCUMENT" assert theIndex._fileIndex[tHandle]["T000001"]["cCount"] == 43 assert theIndex._fileIndex[tHandle]["T000001"]["wCount"] == 8 assert theIndex._fileIndex[tHandle]["T000001"]["pCount"] == 1 assert theIndex._fileIndex[tHandle]["T000001"]["synopsis"] == "" # Page wo/Title # ============= theProject.projTree[pHandle]._layout = nwItemLayout.DOCUMENT assert theIndex.scanText(pHandle, ("This is a page with some text on it.\n\n")) assert pHandle in theIndex._fileIndex assert theIndex._fileIndex[pHandle]["T000000"]["level"] == "H0" assert theIndex._fileIndex[pHandle]["T000000"]["title"] == "" assert theIndex._fileIndex[pHandle]["T000000"]["layout"] == "DOCUMENT" assert theIndex._fileIndex[pHandle]["T000000"]["cCount"] == 36 assert theIndex._fileIndex[pHandle]["T000000"]["wCount"] == 9 assert theIndex._fileIndex[pHandle]["T000000"]["pCount"] == 1 assert theIndex._fileIndex[pHandle]["T000000"]["synopsis"] == "" theProject.projTree[pHandle]._layout = nwItemLayout.NOTE assert theIndex.scanText(pHandle, ("This is a page with some text on it.\n\n")) assert pHandle in theIndex._fileIndex assert theIndex._fileIndex[pHandle]["T000000"]["level"] == "H0" assert theIndex._fileIndex[pHandle]["T000000"]["title"] == "" assert theIndex._fileIndex[pHandle]["T000000"]["layout"] == "NOTE" assert theIndex._fileIndex[pHandle]["T000000"]["cCount"] == 36 assert theIndex._fileIndex[pHandle]["T000000"]["wCount"] == 9 assert theIndex._fileIndex[pHandle]["T000000"]["pCount"] == 1 assert theIndex._fileIndex[pHandle]["T000000"]["synopsis"] == "" assert theProject.closeProject() is True
def testCoreIndex_CheckThese(nwMinimal, mockGUI): """Test the tag checker function checkThese. """ theProject = NWProject(mockGUI) theProject.projTree.setSeed(42) assert theProject.openProject(nwMinimal) is True theIndex = NWIndex(theProject) nHandle = theProject.newFile("Hello", nwItemClass.NOVEL, "a508bb932959c") cHandle = theProject.newFile("Jane", nwItemClass.CHARACTER, "afb3043c7b2b3") nItem = theProject.projTree[nHandle] cItem = theProject.projTree[cHandle] assert theIndex.novelChangedSince(0) is False assert theIndex.notesChangedSince(0) is False assert theIndex.indexChangedSince(0) is False assert theIndex.scanText(cHandle, ("# Jane Smith\n" "@tag: Jane\n" "@tag:\n" "@:\n")) assert theIndex.scanText( nHandle, ( "# Hello World!\n" "@pov: Jane\n" "@invalid: John\n" # Checks for issue #688 )) assert theIndex._tagIndex == {"Jane": [2, cHandle, "CHARACTER", "T000001"]} assert theIndex.getNovelData(nHandle, "T000001")["title"] == "Hello World!" assert theIndex.getReferences(nHandle, "T000001") == { "@char": [], "@custom": [], "@entity": [], "@focus": [], "@location": [], "@object": [], "@plot": [], "@pov": ["Jane"], "@time": [] } assert theIndex.novelChangedSince(0) is True assert theIndex.notesChangedSince(0) is True assert theIndex.indexChangedSince(0) is True assert theIndex.getHandleHeaderLevel(cHandle) == "H1" assert theIndex.getHandleHeaderLevel(nHandle) == "H1" # Zero Items assert theIndex.checkThese([], cItem) == [] # One Item assert theIndex.checkThese(["@tag"], cItem) == [True] assert theIndex.checkThese(["@who"], cItem) == [False] # Two Items assert theIndex.checkThese(["@tag", "Jane"], cItem) == [True, True] assert theIndex.checkThese(["@tag", "John"], cItem) == [True, True] assert theIndex.checkThese(["@tag", "Jane"], nItem) == [True, False] assert theIndex.checkThese(["@tag", "John"], nItem) == [True, True] assert theIndex.checkThese(["@pov", "John"], nItem) == [True, False] assert theIndex.checkThese(["@pov", "Jane"], nItem) == [True, True] assert theIndex.checkThese(["@ pov", "Jane"], nItem) == [False, False] assert theIndex.checkThese(["@what", "Jane"], nItem) == [False, False] # Three Items assert theIndex.checkThese(["@tag", "Jane", "John"], cItem) == [True, True, False] assert theIndex.checkThese(["@who", "Jane", "John"], cItem) == [False, False, False] assert theIndex.checkThese(["@pov", "Jane", "John"], nItem) == [True, True, False] assert theProject.closeProject() is True
def testCoreProject_Methods(monkeypatch, nwMinimal, mockGUI, tmpDir): """Test other project class methods and functions. """ theProject = NWProject(mockGUI) theProject.projTree.setSeed(42) assert theProject.openProject(nwMinimal) assert theProject.projPath == nwMinimal # Setting project path assert theProject.setProjectPath(None) assert theProject.projPath is None assert theProject.setProjectPath("") assert theProject.projPath is None assert theProject.setProjectPath("~") assert theProject.projPath == os.path.expanduser("~") # Create a new folder and populate it projPath = os.path.join(nwMinimal, "mock1") assert theProject.setProjectPath(projPath, newProject=True) # Make os.mkdir fail monkeypatch.setattr("os.mkdir", causeOSError) projPath = os.path.join(nwMinimal, "mock2") assert not theProject.setProjectPath(projPath, newProject=True) # Set back assert theProject.setProjectPath(nwMinimal) # Project Name assert theProject.setProjectName(" A Name ") assert theProject.projName == "A Name" # Project Title assert theProject.setBookTitle(" A Title ") assert theProject.bookTitle == "A Title" # Project Authors # Check that the list is cleaned up and that it can be extracted as # a properly formatted string, depending on number of names assert not theProject.setBookAuthors([]) assert theProject.setBookAuthors(" Jane Doe \n John Doh \n ") assert theProject.bookAuthors == ["Jane Doe", "John Doh"] assert theProject.setBookAuthors("") assert theProject.getAuthors() == "" assert theProject.setBookAuthors("Jane Doe") assert theProject.getAuthors() == "Jane Doe" assert theProject.setBookAuthors("Jane Doe\nJohn Doh") assert theProject.getAuthors() == "Jane Doe and John Doh" assert theProject.setBookAuthors("Jane Doe\nJohn Doh\nBod Owens") assert theProject.getAuthors() == "Jane Doe, John Doh and Bod Owens" # Edit Time theProject.editTime = 1234 theProject.projOpened = 1600000000 with monkeypatch.context() as mp: mp.setattr("novelwriter.core.project.time", lambda: 1600005600) assert theProject.getCurrentEditTime() == 6834 # Trash folder # Should create on first call, and just returned on later calls assert theProject.projTree["73475cb40a568"] is None assert theProject.trashFolder() == "73475cb40a568" assert theProject.trashFolder() == "73475cb40a568" # Project backup assert theProject.doBackup is True assert theProject.setProjBackup(False) assert theProject.doBackup is False assert not theProject.setProjBackup(True) theProject.mainConf.backupPath = tmpDir assert theProject.setProjBackup(True) assert theProject.setProjectName("") assert not theProject.setProjBackup(True) assert theProject.setProjectName("A Name") assert theProject.setProjBackup(True) # Spell check theProject.projChanged = False assert theProject.setSpellCheck(True) assert not theProject.setSpellCheck(False) assert theProject.projChanged # Spell language theProject.projChanged = False assert theProject.setSpellLang(None) assert theProject.projSpell is None assert theProject.setSpellLang("None") assert theProject.projSpell is None assert theProject.setSpellLang("en_GB") assert theProject.projSpell == "en_GB" assert theProject.projChanged # Project Language theProject.projChanged = False theProject.projLang = "en" assert theProject.setProjectLang(None) is True assert theProject.projLang is None assert theProject.setProjectLang("en_GB") is True assert theProject.projLang == "en_GB" # Automatic outline update theProject.projChanged = False assert theProject.setAutoOutline(True) assert not theProject.setAutoOutline(False) assert theProject.projChanged # Last edited theProject.projChanged = False assert theProject.setLastEdited("0123456789abc") assert theProject.lastEdited == "0123456789abc" assert theProject.projChanged # Last viewed theProject.projChanged = False assert theProject.setLastViewed("0123456789abc") assert theProject.lastViewed == "0123456789abc" assert theProject.projChanged # Autoreplace theProject.projChanged = False assert theProject.setAutoReplace({"A": "B", "C": "D"}) assert theProject.autoReplace == {"A": "B", "C": "D"} assert theProject.projChanged # Change project tree order oldOrder = [ "a508bb932959c", "a35baf2e93843", "a6d311a93600a", "f5ab3e30151e1", "8c659a11cd429", "7695ce551d265", "afb3043c7b2b3", "9d5247ab588e0", "73475cb40a568", ] newOrder = [ "f5ab3e30151e1", "8c659a11cd429", "7695ce551d265", "a508bb932959c", "a35baf2e93843", "a6d311a93600a", "afb3043c7b2b3", "9d5247ab588e0", ] assert theProject.projTree.handles() == oldOrder assert theProject.setTreeOrder(newOrder) assert theProject.projTree.handles() == newOrder assert theProject.setTreeOrder(oldOrder) assert theProject.projTree.handles() == oldOrder # Change status theProject.projTree["a35baf2e93843"].setStatus("Finished") theProject.projTree["a6d311a93600a"].setStatus("Draft") theProject.projTree["f5ab3e30151e1"].setStatus("Note") theProject.projTree["8c659a11cd429"].setStatus("Finished") newList = [ ("New", 1, 1, 1, "New"), ("Draft", 2, 2, 2, "Note"), # These are swapped ("Note", 3, 3, 3, "Draft"), # These are swapped ("Edited", 4, 4, 4, "Finished"), # Renamed ("Finished", 5, 5, 5, None), # New, with reused name ] assert theProject.setStatusColours(newList) assert theProject.statusItems._theLabels == [ "New", "Draft", "Note", "Edited", "Finished" ] assert theProject.statusItems._theColours == [(1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4), (5, 5, 5)] assert theProject.projTree[ "a35baf2e93843"].itemStatus == "Edited" # Renamed assert theProject.projTree["a6d311a93600a"].itemStatus == "Note" # Swapped assert theProject.projTree["f5ab3e30151e1"].itemStatus == "Draft" # Swapped assert theProject.projTree[ "8c659a11cd429"].itemStatus == "Edited" # Renamed # Change importance fHandle = theProject.newFile("Jane Doe", nwItemClass.CHARACTER, "afb3043c7b2b3") theProject.projTree[fHandle].setImport("Main") newList = [ ("New", 1, 1, 1, "New"), ("Minor", 2, 2, 2, "Minor"), ("Major", 3, 3, 3, "Major"), ("Min", 4, 4, 4, "Main"), ("Max", 5, 5, 5, None), ] assert theProject.setImportColours(newList) assert theProject.importItems._theLabels == [ "New", "Minor", "Major", "Min", "Max" ] assert theProject.importItems._theColours == [(1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4), (5, 5, 5)] assert theProject.projTree[fHandle].itemImport == "Min" # Check status counts assert theProject.statusItems._theCounts == [0, 0, 0, 0, 0] assert theProject.importItems._theCounts == [0, 0, 0, 0, 0] theProject.countStatus() assert theProject.statusItems._theCounts == [1, 1, 1, 2, 0] assert theProject.importItems._theCounts == [3, 0, 0, 1, 0] # Session stats theProject.currWCount = 200 theProject.lastWCount = 100 with monkeypatch.context() as mp: mp.setattr("os.path.isdir", lambda *a, **k: False) assert not theProject._appendSessionStats(idleTime=0) # Block open with monkeypatch.context() as mp: mp.setattr("builtins.open", causeOSError) assert not theProject._appendSessionStats(idleTime=0) # Write entry assert theProject.projMeta == os.path.join(nwMinimal, "meta") statsFile = os.path.join(theProject.projMeta, nwFiles.SESS_STATS) theProject.projOpened = 1600002000 theProject.currNovelWC = 200 theProject.currNotesWC = 100 with monkeypatch.context() as mp: mp.setattr("novelwriter.core.project.time", lambda: 1600005600) assert theProject._appendSessionStats(idleTime=99) assert readFile(statsFile) == ( "# Offset 100\n" "# Start Time End Time Novel Notes Idle\n" "%s %s 200 100 99\n") % ( formatTimeStamp(1600002000), formatTimeStamp(1600005600)) # Pack XML Value xElem = etree.Element("element") theProject._packProjectValue(xElem, "A", "B", allowNone=False) assert etree.tostring(xElem, pretty_print=False, encoding="utf-8") == (b"<element><A>B</A></element>") xElem = etree.Element("element") theProject._packProjectValue(xElem, "A", "", allowNone=False) assert etree.tostring(xElem, pretty_print=False, encoding="utf-8") == (b"<element/>") # Pack XML Key/Value xElem = etree.Element("element") theProject._packProjectKeyValue(xElem, "item", {"A": "B", "C": "D"}) assert etree.tostring(xElem, pretty_print=False, encoding="utf-8") == (b"<element>" b"<item>" b"<entry key=\"A\">B</entry>" b"<entry key=\"C\">D</entry>" b"</item>" b"</element>")
def testCoreIndex_ItemIndex(mockGUI, fncDir, mockRnd): """Check the ItemIndex class. """ theProject = NWProject(mockGUI) buildTestProject(theProject, fncDir) nHandle = "0000000000014" cHandle = "0000000000016" sHandle = "0000000000017" assert theProject.index.saveIndex() is True itemIndex = theProject.index._itemIndex # The index should be empty assert nHandle not in itemIndex assert cHandle not in itemIndex assert sHandle not in itemIndex # Add Items # ========= assert cHandle not in itemIndex # Add the novel chapter file itemIndex.add(cHandle, theProject.tree[cHandle]) assert cHandle in itemIndex assert itemIndex[cHandle].item == theProject.tree[cHandle] assert itemIndex.mainItemHeader(cHandle) == "H0" assert itemIndex.allItemTags(cHandle) == [] assert list(itemIndex.iterItemHeaders(cHandle))[0][0] == "T000000" # Add a heading to the item, which should replace the T000000 heading itemIndex.addItemHeading(cHandle, "T000001", "H2", "Chapter One") assert itemIndex.mainItemHeader(cHandle) == "H2" assert list(itemIndex.iterItemHeaders(cHandle))[0][0] == "T000001" # Set the remainig data values itemIndex.setHeadingCounts(cHandle, "T000001", 60, 10, 2) itemIndex.setHeadingSynopsis(cHandle, "T000001", "In the beginning ...") itemIndex.setHeadingTag(cHandle, "T000001", "One") itemIndex.addHeadingReferences(cHandle, "T000001", ["Jane"], "@pov") itemIndex.addHeadingReferences(cHandle, "T000001", ["Jane"], "@focus") itemIndex.addHeadingReferences(cHandle, "T000001", ["Jane", "John"], "@char") idxData = itemIndex.packData() assert idxData[cHandle]["level"] == "H2" assert idxData[cHandle]["headings"]["T000001"] == { "level": "H2", "title": "Chapter One", "tag": "One", "cCount": 60, "wCount": 10, "pCount": 2, "synopsis": "In the beginning ...", } assert "@pov" in idxData[cHandle]["references"]["T000001"]["Jane"] assert "@focus" in idxData[cHandle]["references"]["T000001"]["Jane"] assert "@char" in idxData[cHandle]["references"]["T000001"]["Jane"] assert "@char" in idxData[cHandle]["references"]["T000001"]["John"] # Add the other two files itemIndex.add(nHandle, theProject.tree[nHandle]) itemIndex.add(sHandle, theProject.tree[sHandle]) itemIndex.addItemHeading(nHandle, "T000001", "H1", "Novel") itemIndex.addItemHeading(sHandle, "T000001", "H3", "Scene One") # Check Item and Heading Direct Access # ==================================== # Check repr strings assert repr(itemIndex[nHandle]) == f"<IndexItem handle='{nHandle}'>" assert repr( itemIndex[nHandle]["T000001"]) == "<IndexHeading key='T000001'>" # Check content of a single item assert "T000001" in itemIndex[nHandle] assert itemIndex[cHandle].allTags() == ["One"] # Check the content of a single heading assert itemIndex[cHandle]["T000001"].key == "T000001" assert itemIndex[cHandle]["T000001"].level == "H2" assert itemIndex[cHandle]["T000001"].title == "Chapter One" assert itemIndex[cHandle]["T000001"].tag == "One" assert itemIndex[cHandle]["T000001"].charCount == 60 assert itemIndex[cHandle]["T000001"].wordCount == 10 assert itemIndex[cHandle]["T000001"].paraCount == 2 assert itemIndex[cHandle]["T000001"].synopsis == "In the beginning ..." assert "Jane" in itemIndex[cHandle]["T000001"].references assert "John" in itemIndex[cHandle]["T000001"].references # Check heading level setter itemIndex[cHandle]["T000001"].setLevel("H3") # Change it assert itemIndex[cHandle]["T000001"].level == "H3" itemIndex[cHandle]["T000001"].setLevel("H2") # Set it back assert itemIndex[cHandle]["T000001"].level == "H2" itemIndex[cHandle]["T000001"].setLevel("H5") # Invalid level assert itemIndex[cHandle]["T000001"].level == "H2" # Data Extraction # =============== # Get headers allHeads = list(itemIndex.iterAllHeaders()) assert allHeads[0][0] == cHandle assert allHeads[1][0] == nHandle assert allHeads[2][0] == sHandle assert allHeads[0][1] == "T000001" assert allHeads[1][1] == "T000001" assert allHeads[2][1] == "T000001" # Ask for stuff that doesn't exist assert itemIndex.mainItemHeader("blablabla") == "H0" assert itemIndex.allItemTags("blablabla") == [] # Novel Structure # =============== # Add a second novel mHandle = theProject.newRoot(nwItemClass.NOVEL) uHandle = theProject.newFile("Title Page", mHandle) itemIndex.add(uHandle, theProject.tree[uHandle]) itemIndex.addItemHeading(uHandle, "T000001", "H1", "Novel 2") assert uHandle in itemIndex # Structure of all novels nStruct = list(itemIndex.iterNovelStructure()) assert len(nStruct) == 4 assert nStruct[0][0] == nHandle assert nStruct[1][0] == cHandle assert nStruct[2][0] == sHandle assert nStruct[3][0] == uHandle # Novel structure with root handle set nStruct = list(itemIndex.iterNovelStructure(rootHandle="0000000000010")) assert len(nStruct) == 3 assert nStruct[0][0] == nHandle assert nStruct[1][0] == cHandle assert nStruct[2][0] == sHandle nStruct = list(itemIndex.iterNovelStructure(rootHandle=mHandle)) assert len(nStruct) == 1 assert nStruct[0][0] == uHandle # Inject garbage into tree theProject.tree._treeOrder.append("stuff") nStruct = list(itemIndex.iterNovelStructure()) assert len(nStruct) == 4 assert nStruct[0][0] == nHandle assert nStruct[1][0] == cHandle assert nStruct[2][0] == sHandle assert nStruct[3][0] == uHandle # Skip excluded theProject.tree[sHandle].setExported(False) nStruct = list(itemIndex.iterNovelStructure(skipExcl=True)) assert len(nStruct) == 3 assert nStruct[0][0] == nHandle assert nStruct[1][0] == cHandle assert nStruct[2][0] == uHandle # Delete new item del itemIndex[uHandle] assert uHandle not in itemIndex # Unpack Error Handling # ===================== # Pack/unpack should restore state content = itemIndex.packData() itemIndex.clear() itemIndex.unpackData(content) assert itemIndex.packData() == content itemIndex.clear() # Data must be dictionary with pytest.raises(ValueError): itemIndex.unpackData("stuff") # Keys must be valid handles with pytest.raises(ValueError): itemIndex.unpackData({"stuff": "more stuff"}) # Unknown keys should be skipped itemIndex.unpackData({"0000000000000": {}}) assert itemIndex._items == {} # Known keys can be added, even witout data itemIndex.unpackData({nHandle: {}}) assert nHandle in itemIndex # Title tags must be valid with pytest.raises(ValueError): itemIndex.unpackData({cHandle: {"headings": {"TTTTTTT": {}}}}) # Reference without a heading should be rejected itemIndex.unpackData({ cHandle: { "headings": { "T000001": {} }, "references": { "T000001": {}, "T000002": {} }, } }) assert "T000001" in itemIndex[cHandle] assert "T000002" not in itemIndex[cHandle] itemIndex.clear() # Tag keys must be strings with pytest.raises(ValueError): itemIndex.unpackData({ cHandle: { "headings": { "T000001": {} }, "references": { "T000001": { 1234: "@pov" } }, } }) # Type must be strings with pytest.raises(ValueError): itemIndex.unpackData({ cHandle: { "headings": { "T000001": {} }, "references": { "T000001": { "John": [] } }, } }) # Types must be valid with pytest.raises(ValueError): itemIndex.unpackData({ cHandle: { "headings": { "T000001": {} }, "references": { "T000001": { "John": "@pov,@char,@stuff" } }, } }) # This should pass itemIndex.unpackData({ cHandle: { "headings": { "T000001": {} }, "references": { "T000001": { "John": "@pov,@char" } }, } })
def testCoreIndex_ExtractData(mockGUI, fncDir, mockRnd): """Check the index data extraction functions. """ theProject = NWProject(mockGUI) buildTestProject(theProject, fncDir) theIndex = theProject.index theIndex.reIndexHandle("0000000000010") theIndex.reIndexHandle("0000000000011") theIndex.reIndexHandle("0000000000012") theIndex.reIndexHandle("0000000000013") theIndex.reIndexHandle("0000000000014") theIndex.reIndexHandle("0000000000015") theIndex.reIndexHandle("0000000000016") theIndex.reIndexHandle("0000000000017") nHandle = theProject.newFile("Hello", "0000000000010") cHandle = theProject.newFile("Jane", "0000000000012") assert theIndex.getNovelData("", "") is None assert theIndex.getNovelData("0000000000010", "") is None assert theIndex.scanText(cHandle, ("# Jane Smith\n" "@tag: Jane\n")) assert theIndex.scanText(nHandle, ("# Hello World!\n" "@pov: Jane\n" "@char: Jane\n\n" "% this is a comment\n\n" "This is a story about Jane Smith.\n\n" "Well, not really.\n")) # The novel structure should contain the pointer to the novel file header theKeys = [] for aKey, _, _, _ in theIndex.novelStructure(): theKeys.append(aKey) assert theKeys == [ "0000000000014:T000001", "0000000000016:T000001", "0000000000017:T000001", "%s:T000001" % nHandle, ] # Check that excluded files can be skipped theProject.tree[nHandle].setExported(False) theKeys = [] for aKey, _, _, _ in theIndex.novelStructure(skipExcl=False): theKeys.append(aKey) assert theKeys == [ "0000000000014:T000001", "0000000000016:T000001", "0000000000017:T000001", "%s:T000001" % nHandle, ] theKeys = [] for aKey, _, _, _ in theIndex.novelStructure(skipExcl=True): theKeys.append(aKey) assert theKeys == [ "0000000000014:T000001", "0000000000016:T000001", "0000000000017:T000001", ] # The novel file should have the correct counts cC, wC, pC = theIndex.getCounts(nHandle) assert cC == 62 # Characters in text and title only assert wC == 12 # Words in text and title only assert pC == 2 # Paragraphs in text only # getReferences # ============= # Look up an ivalid handle theRefs = theIndex.getReferences("Not a handle") assert theRefs["@pov"] == [] assert theRefs["@char"] == [] # The novel file should now refer to Jane as @pov and @char theRefs = theIndex.getReferences(nHandle) assert theRefs["@pov"] == ["Jane"] assert theRefs["@char"] == ["Jane"] # getBackReferenceList # ==================== # None handle should return an empty dict assert theIndex.getBackReferenceList(None) == {} # The Title Page file should have no references as it has no tag assert theIndex.getBackReferenceList("0000000000014") == {} # The character file should have a record of the reference from the novel file theRefs = theIndex.getBackReferenceList(cHandle) assert theRefs == {nHandle: "T000001"} # getTagSource # ============ assert theIndex.getTagSource("Jane") == (cHandle, "T000001") assert theIndex.getTagSource("John") == (None, "T000000") # getCounts # ========= # For whole text and sections # Invalid handle or title should return 0s assert theIndex.getCounts("stuff") == (0, 0, 0) assert theIndex.getCounts(nHandle, "stuff") == (0, 0, 0) # Get section counts for a novel file assert theIndex.scanText( nHandle, ("# Hello World!\n" "@pov: Jane\n" "@char: Jane\n\n" "% this is a comment\n\n" "This is a story about Jane Smith.\n\n" "Well, not really.\n\n" "# Hello World!\n" "@pov: Jane\n" "@char: Jane\n\n" "% this is a comment\n\n" "This is a story about Jane Smith.\n\n" "Well, not really. She's still awesome though.\n")) # Whole document cC, wC, pC = theIndex.getCounts(nHandle) assert cC == 152 assert wC == 28 assert pC == 4 # First part cC, wC, pC = theIndex.getCounts(nHandle, "T000001") assert cC == 62 assert wC == 12 assert pC == 2 # Second part cC, wC, pC = theIndex.getCounts(nHandle, "T000011") assert cC == 90 assert wC == 16 assert pC == 2 # Get section counts for a note file assert theIndex.scanText( cHandle, ("# Hello World!\n" "@pov: Jane\n" "@char: Jane\n\n" "% this is a comment\n\n" "This is a story about Jane Smith.\n\n" "Well, not really.\n\n" "# Hello World!\n" "@pov: Jane\n" "@char: Jane\n\n" "% this is a comment\n\n" "This is a story about Jane Smith.\n\n" "Well, not really. She's still awesome though.\n")) # Whole document cC, wC, pC = theIndex.getCounts(cHandle) assert cC == 152 assert wC == 28 assert pC == 4 # First part cC, wC, pC = theIndex.getCounts(cHandle, "T000001") assert cC == 62 assert wC == 12 assert pC == 2 # Second part cC, wC, pC = theIndex.getCounts(cHandle, "T000011") assert cC == 90 assert wC == 16 assert pC == 2 # Novel Stats # =========== hHandle = theProject.newFile("Chapter", "0000000000010") sHandle = theProject.newFile("Scene One", "0000000000010") tHandle = theProject.newFile("Scene Two", "0000000000010") theProject.tree[hHandle].itemLayout == nwItemLayout.DOCUMENT theProject.tree[sHandle].itemLayout == nwItemLayout.DOCUMENT theProject.tree[tHandle].itemLayout == nwItemLayout.DOCUMENT assert theIndex.scanText(hHandle, "## Chapter One\n\n") assert theIndex.scanText(sHandle, "### Scene One\n\n") assert theIndex.scanText(tHandle, "### Scene Two\n\n") assert [ (h, t) for h, t, _ in theIndex._itemIndex.iterNovelStructure(skipExcl=False) ] == [ ("0000000000014", "T000001"), ("0000000000016", "T000001"), ("0000000000017", "T000001"), (nHandle, "T000001"), (nHandle, "T000011"), (hHandle, "T000001"), (sHandle, "T000001"), (tHandle, "T000001"), ] assert [ (h, t) for h, t, _ in theIndex._itemIndex.iterNovelStructure(skipExcl=True) ] == [ ("0000000000014", "T000001"), ("0000000000016", "T000001"), ("0000000000017", "T000001"), (hHandle, "T000001"), (sHandle, "T000001"), (tHandle, "T000001"), ] # Add a fake handle to the tree and check that it's ignored theProject.tree._treeOrder.append("0000000000000") assert [ (h, t) for h, t, _ in theIndex._itemIndex.iterNovelStructure(skipExcl=False) ] == [ ("0000000000014", "T000001"), ("0000000000016", "T000001"), ("0000000000017", "T000001"), (nHandle, "T000001"), (nHandle, "T000011"), (hHandle, "T000001"), (sHandle, "T000001"), (tHandle, "T000001"), ] theProject.tree._treeOrder.remove("0000000000000") # Extract stats assert theIndex.getNovelWordCount(skipExcl=False) == 43 assert theIndex.getNovelWordCount(skipExcl=True) == 15 assert theIndex.getNovelTitleCounts(skipExcl=False) == [0, 3, 2, 3, 0] assert theIndex.getNovelTitleCounts(skipExcl=True) == [0, 1, 2, 3, 0] # Table of Contents assert theIndex.getTableOfContents(0, skipExcl=True) == [] assert theIndex.getTableOfContents(1, skipExcl=True) == [ ("0000000000014:T000001", 1, "New Novel", 15), ] assert theIndex.getTableOfContents(2, skipExcl=True) == [ ("0000000000014:T000001", 1, "New Novel", 5), ("0000000000016:T000001", 2, "New Chapter", 4), ("%s:T000001" % hHandle, 2, "Chapter One", 6), ] assert theIndex.getTableOfContents(3, skipExcl=True) == [ ("0000000000014:T000001", 1, "New Novel", 5), ("0000000000016:T000001", 2, "New Chapter", 2), ("0000000000017:T000001", 3, "New Scene", 2), ("%s:T000001" % hHandle, 2, "Chapter One", 2), ("%s:T000001" % sHandle, 3, "Scene One", 2), ("%s:T000001" % tHandle, 3, "Scene Two", 2), ] assert theIndex.getTableOfContents(0, skipExcl=False) == [] assert theIndex.getTableOfContents(1, skipExcl=False) == [ ("0000000000014:T000001", 1, "New Novel", 9), ("%s:T000001" % nHandle, 1, "Hello World!", 12), ("%s:T000011" % nHandle, 1, "Hello World!", 22), ] # Header Word Counts bHandle = "0000000000000" assert theIndex.getHandleWordCounts(bHandle) == [] assert theIndex.getHandleWordCounts(hHandle) == [("%s:T000001" % hHandle, 2)] assert theIndex.getHandleWordCounts(sHandle) == [("%s:T000001" % sHandle, 2)] assert theIndex.getHandleWordCounts(tHandle) == [("%s:T000001" % tHandle, 2)] assert theIndex.getHandleWordCounts(nHandle) == [ ("%s:T000001" % nHandle, 12), ("%s:T000011" % nHandle, 16) ] assert theIndex.saveIndex() is True assert theProject.saveProject() is True assert theProject.closeProject() is True # Header Record bHandle = "0000000000000" assert theIndex.getHandleHeaders(bHandle) == [] assert theIndex.getHandleHeaders(hHandle) == [("T000001", "H2", "Chapter One")] assert theIndex.getHandleHeaders(sHandle) == [("T000001", "H3", "Scene One")] assert theIndex.getHandleHeaders(tHandle) == [("T000001", "H3", "Scene Two")] assert theIndex.getHandleHeaders(nHandle) == [ ("T000001", "H1", "Hello World!"), ("T000011", "H1", "Hello World!") ]
def testCoreIndex_ScanText(mockGUI, fncDir, mockRnd): """Check the index text scanner. """ theProject = NWProject(mockGUI) buildTestProject(theProject, fncDir) theIndex = theProject.index # Some items for fail to scan tests dHandle = theProject.newFolder("Folder", "0000000000010") xHandle = theProject.newFile("No Layout", "0000000000010") xItem = theProject.tree[xHandle] xItem.setLayout(nwItemLayout.NO_LAYOUT) # Check invalid data assert theIndex.scanText(None, "Hello World!") is False assert theIndex.scanText(dHandle, "Hello World!") is False assert theIndex.scanText(xHandle, "Hello World!") is False xItem.setLayout(nwItemLayout.DOCUMENT) xItem.setParent(None) assert theIndex.scanText(xHandle, "Hello World!") is False # Create the trash folder tHandle = theProject.trashFolder() assert theProject.tree[tHandle] is not None xItem.setParent(tHandle) theProject.tree.updateItemData(xItem.itemHandle) assert xItem.itemRoot == tHandle assert xItem.itemClass == nwItemClass.TRASH assert theIndex.scanText(xHandle, "Hello World!") is False # Create the archive root aHandle = theProject.newRoot(nwItemClass.ARCHIVE) assert theProject.tree[aHandle] is not None xItem.setParent(aHandle) theProject.tree.updateItemData(xItem.itemHandle) assert theIndex.scanText(xHandle, "Hello World!") is False # Make some usable items tHandle = theProject.newFile("Title", "0000000000010") pHandle = theProject.newFile("Page", "0000000000010") nHandle = theProject.newFile("Hello", "0000000000010") cHandle = theProject.newFile("Jane", "0000000000012") sHandle = theProject.newFile("Scene", "0000000000010") # Text Indexing # ============= # Index correct text assert theIndex.scanText(cHandle, ("# Jane Smith\n" "@tag: Jane\n")) assert theIndex.scanText(nHandle, ("# Hello World!\n" "@pov: Jane\n" "@char: Jane\n\n" "% this is a comment\n\n" "This is a story about Jane Smith.\n\n" "Well, not really.\n")) assert theIndex._tagsIndex.tagHandle("Jane") == cHandle assert theIndex._tagsIndex.tagHeading("Jane") == "T000001" assert theIndex._tagsIndex.tagClass("Jane") == "CHARACTER" assert theIndex.getNovelData(nHandle, "T000001").title == "Hello World!" # Title Indexing # ============== # Document File assert theIndex.scanText( nHandle, ( "# Title One\n\n" "% synopsis: Synopsis One.\n\n" "Paragraph One.\n\n" "## Title Two\n\n" "% synopsis: Synopsis Two.\n\n" "Paragraph Two.\n\n" "### Title Three\n\n" "% synopsis: Synopsis Three.\n\n" "Paragraph Three.\n\n" "#### Title Four\n\n" "% synopsis: Synopsis Four.\n\n" "Paragraph Four.\n\n" "##### Title Five\n\n" # Not interpreted as a title, the hashes are counted as a word "Paragraph Five.\n\n")) assert theIndex._itemIndex[nHandle]["T000001"].references == {} assert theIndex._itemIndex[nHandle]["T000007"].references == {} assert theIndex._itemIndex[nHandle]["T000013"].references == {} assert theIndex._itemIndex[nHandle]["T000019"].references == {} assert theIndex._itemIndex[nHandle]["T000001"].level == "H1" assert theIndex._itemIndex[nHandle]["T000007"].level == "H2" assert theIndex._itemIndex[nHandle]["T000013"].level == "H3" assert theIndex._itemIndex[nHandle]["T000019"].level == "H4" assert theIndex._itemIndex[nHandle]["T000001"].title == "Title One" assert theIndex._itemIndex[nHandle]["T000007"].title == "Title Two" assert theIndex._itemIndex[nHandle]["T000013"].title == "Title Three" assert theIndex._itemIndex[nHandle]["T000019"].title == "Title Four" assert theIndex._itemIndex[nHandle]["T000001"].charCount == 23 assert theIndex._itemIndex[nHandle]["T000007"].charCount == 23 assert theIndex._itemIndex[nHandle]["T000013"].charCount == 27 assert theIndex._itemIndex[nHandle]["T000019"].charCount == 56 assert theIndex._itemIndex[nHandle]["T000001"].wordCount == 4 assert theIndex._itemIndex[nHandle]["T000007"].wordCount == 4 assert theIndex._itemIndex[nHandle]["T000013"].wordCount == 4 assert theIndex._itemIndex[nHandle]["T000019"].wordCount == 9 assert theIndex._itemIndex[nHandle]["T000001"].paraCount == 1 assert theIndex._itemIndex[nHandle]["T000007"].paraCount == 1 assert theIndex._itemIndex[nHandle]["T000013"].paraCount == 1 assert theIndex._itemIndex[nHandle]["T000019"].paraCount == 3 assert theIndex._itemIndex[nHandle]["T000001"].synopsis == "Synopsis One." assert theIndex._itemIndex[nHandle]["T000007"].synopsis == "Synopsis Two." assert theIndex._itemIndex[nHandle][ "T000013"].synopsis == "Synopsis Three." assert theIndex._itemIndex[nHandle]["T000019"].synopsis == "Synopsis Four." # Note File assert theIndex.scanText(cHandle, ("# Title One\n\n" "@tag: One\n\n" "% synopsis: Synopsis One.\n\n" "Paragraph One.\n\n")) assert theIndex._itemIndex[cHandle]["T000001"].references == {} assert theIndex._itemIndex[cHandle]["T000001"].level == "H1" assert theIndex._itemIndex[cHandle]["T000001"].title == "Title One" assert theIndex._itemIndex[cHandle]["T000001"].charCount == 23 assert theIndex._itemIndex[cHandle]["T000001"].wordCount == 4 assert theIndex._itemIndex[cHandle]["T000001"].paraCount == 1 assert theIndex._itemIndex[cHandle]["T000001"].synopsis == "Synopsis One." # Valid and Invalid References assert theIndex.scanText( sHandle, ( "# Title One\n\n" "@pov: One\n\n" # Valid "@char: Two\n\n" # Invalid tag "@:\n\n" # Invalid line "% synopsis: Synopsis One.\n\n" "Paragraph One.\n\n")) assert theIndex._itemIndex[sHandle]["T000001"].references == { "One": {"@pov"}, "Two": {"@char"} } # Special Titles # ============== assert theIndex.scanText(tHandle, ("#! My Project\n\n" ">> By Jane Doe <<\n\n")) assert theIndex._itemIndex[cHandle]["T000001"].references == {} assert theIndex._itemIndex[tHandle]["T000001"].level == "H1" assert theIndex._itemIndex[tHandle]["T000001"].title == "My Project" assert theIndex._itemIndex[tHandle]["T000001"].charCount == 21 assert theIndex._itemIndex[tHandle]["T000001"].wordCount == 5 assert theIndex._itemIndex[tHandle]["T000001"].paraCount == 1 assert theIndex._itemIndex[tHandle]["T000001"].synopsis == "" assert theIndex.scanText(tHandle, ("##! Prologue\n\n" "In the beginning there was time ...\n\n")) assert theIndex._itemIndex[cHandle]["T000001"].references == {} assert theIndex._itemIndex[tHandle]["T000001"].level == "H2" assert theIndex._itemIndex[tHandle]["T000001"].title == "Prologue" assert theIndex._itemIndex[tHandle]["T000001"].charCount == 43 assert theIndex._itemIndex[tHandle]["T000001"].wordCount == 8 assert theIndex._itemIndex[tHandle]["T000001"].paraCount == 1 assert theIndex._itemIndex[tHandle]["T000001"].synopsis == "" # Page wo/Title # ============= theProject.tree[pHandle]._layout = nwItemLayout.DOCUMENT assert theIndex.scanText(pHandle, ("This is a page with some text on it.\n\n")) assert theIndex._itemIndex[pHandle]["T000000"].references == {} assert theIndex._itemIndex[pHandle]["T000000"].level == "H0" assert theIndex._itemIndex[pHandle]["T000000"].title == "" assert theIndex._itemIndex[pHandle]["T000000"].charCount == 36 assert theIndex._itemIndex[pHandle]["T000000"].wordCount == 9 assert theIndex._itemIndex[pHandle]["T000000"].paraCount == 1 assert theIndex._itemIndex[pHandle]["T000000"].synopsis == "" theProject.tree[pHandle]._layout = nwItemLayout.NOTE assert theIndex.scanText(pHandle, ("This is a page with some text on it.\n\n")) assert theIndex._itemIndex[pHandle]["T000000"].references == {} assert theIndex._itemIndex[pHandle]["T000000"].level == "H0" assert theIndex._itemIndex[pHandle]["T000000"].title == "" assert theIndex._itemIndex[pHandle]["T000000"].charCount == 36 assert theIndex._itemIndex[pHandle]["T000000"].wordCount == 9 assert theIndex._itemIndex[pHandle]["T000000"].paraCount == 1 assert theIndex._itemIndex[pHandle]["T000000"].synopsis == "" assert theProject.closeProject() is True
def testCoreIndex_CheckThese(mockGUI, fncDir, mockRnd): """Test the tag checker function checkThese. """ theProject = NWProject(mockGUI) buildTestProject(theProject, fncDir) theIndex = theProject.index nHandle = theProject.newFile("Hello", "0000000000010") cHandle = theProject.newFile("Jane", "0000000000012") nItem = theProject.tree[nHandle] cItem = theProject.tree[cHandle] assert theIndex.rootChangedSince("0000000000010", 0) is False assert theIndex.indexChangedSince(0) is False assert theIndex.scanText(cHandle, ("# Jane Smith\n" "@tag: Jane\n" "@tag:\n" "@:\n")) assert theIndex.scanText( nHandle, ( "# Hello World!\n" "@pov: Jane\n" "@invalid: John\n" # Checks for issue #688 )) assert theIndex._tagsIndex.tagHandle("Jane") == cHandle assert theIndex._tagsIndex.tagHeading("Jane") == "T000001" assert theIndex._tagsIndex.tagClass("Jane") == "CHARACTER" assert theIndex.getNovelData(nHandle, "T000001").title == "Hello World!" assert theIndex.getReferences(nHandle, "T000001") == { "@char": [], "@custom": [], "@entity": [], "@focus": [], "@location": [], "@object": [], "@plot": [], "@pov": ["Jane"], "@time": [] } assert theIndex.rootChangedSince("0000000000010", 0) is True assert theIndex.indexChangedSince(0) is True assert theIndex.getHandleHeaderLevel(cHandle) == "H1" assert theIndex.getHandleHeaderLevel(nHandle) == "H1" # Zero Items assert theIndex.checkThese([], cItem) == [] # One Item assert theIndex.checkThese(["@tag"], cItem) == [True] assert theIndex.checkThese(["@who"], cItem) == [False] # Two Items assert theIndex.checkThese(["@tag", "Jane"], cItem) == [True, True] assert theIndex.checkThese(["@tag", "John"], cItem) == [True, True] assert theIndex.checkThese(["@tag", "Jane"], nItem) == [True, False] assert theIndex.checkThese(["@tag", "John"], nItem) == [True, True] assert theIndex.checkThese(["@pov", "John"], nItem) == [True, False] assert theIndex.checkThese(["@pov", "Jane"], nItem) == [True, True] assert theIndex.checkThese(["@ pov", "Jane"], nItem) == [False, False] assert theIndex.checkThese(["@what", "Jane"], nItem) == [False, False] # Three Items assert theIndex.checkThese(["@tag", "Jane", "John"], cItem) == [True, True, False] assert theIndex.checkThese(["@who", "Jane", "John"], cItem) == [False, False, False] assert theIndex.checkThese(["@pov", "Jane", "John"], nItem) == [True, True, False] assert theProject.closeProject() is True