Add full test coverage of index class

This commit is contained in:
Veronica Berglyd Olsen
2022-06-05 13:17:24 +02:00
parent 22099c1b56
commit 63068f1018
3 changed files with 305 additions and 42 deletions
+271 -22
View File
@@ -29,7 +29,7 @@ from mock import causeException
from tools import buildTestProject, cmpFiles, writeFile
from novelwriter.core.project import NWProject
from novelwriter.core.index import NWIndex, countWords
from novelwriter.core.index import NWIndex, countWords, TagsIndex
from novelwriter.enum import nwItemClass, nwItemLayout
@@ -46,6 +46,8 @@ def testCoreIndex_LoadSave(monkeypatch, nwLipsum, mockGUI, outDir, refDir):
assert theProject.openProject(nwLipsum)
theIndex = NWIndex(theProject)
assert repr(theIndex) == "<NWIndex project='Lorem Ipsum'>"
notIndexable = {
"b3643d0f92e32": False, # Novel ROOT
"45e6b01ca35c1": False, # Chapter One FOLDER
@@ -761,6 +763,166 @@ def testCoreIndex_ExtractData(mockGUI, fncDir, mockRnd):
# END Test testCoreIndex_ExtractData
@pytest.mark.core
def testCoreIndex_TagsIndex():
"""Check the TagsIndex class.
"""
tagsIndex = TagsIndex()
assert tagsIndex._tags == {}
# Expected data
content = {
"Tag1": {
"handle": "0000000000001",
"heading": "T000001",
"class": nwItemClass.NOVEL.name,
},
"Tag2": {
"handle": "0000000000002",
"heading": "T000002",
"class": nwItemClass.CHARACTER.name,
},
"Tag3": {
"handle": "0000000000003",
"heading": "T000003",
"class": nwItemClass.PLOT.name,
},
}
# Add data
tagsIndex.add("Tag1", "0000000000001", "T000001", nwItemClass.NOVEL)
tagsIndex.add("Tag2", "0000000000002", "T000002", nwItemClass.CHARACTER)
tagsIndex.add("Tag3", "0000000000003", "T000003", nwItemClass.PLOT)
assert tagsIndex._tags == content
# Get items
assert tagsIndex["Tag1"] == content["Tag1"]
assert tagsIndex["Tag2"] == content["Tag2"]
assert tagsIndex["Tag3"] == content["Tag3"]
assert tagsIndex["Tag4"] is None
# Contains
assert "Tag1" in tagsIndex
assert "Tag2" in tagsIndex
assert "Tag3" in tagsIndex
assert "Tag4" not in tagsIndex
# Read back handles
assert tagsIndex.tagHandle("Tag1") == "0000000000001"
assert tagsIndex.tagHandle("Tag2") == "0000000000002"
assert tagsIndex.tagHandle("Tag3") == "0000000000003"
assert tagsIndex.tagHandle("Tag4") is None
# Read back headings
assert tagsIndex.tagHeading("Tag1") == "T000001"
assert tagsIndex.tagHeading("Tag2") == "T000002"
assert tagsIndex.tagHeading("Tag3") == "T000003"
assert tagsIndex.tagHeading("Tag4") == "T000000"
# Read back classes
assert tagsIndex.tagClass("Tag1") == nwItemClass.NOVEL.name
assert tagsIndex.tagClass("Tag2") == nwItemClass.CHARACTER.name
assert tagsIndex.tagClass("Tag3") == nwItemClass.PLOT.name
assert tagsIndex.tagClass("Tag4") is None
# Pack Data
assert tagsIndex.packData() == content
# Delete the second key and a nomn-existant key
del tagsIndex["Tag2"]
del tagsIndex["Tag4"]
assert "Tag1" in tagsIndex
assert "Tag2" not in tagsIndex
assert "Tag3" in tagsIndex
assert "Tag4" not in tagsIndex
# Clear and reload
tagsIndex.clear()
assert tagsIndex._tags == {}
assert tagsIndex.packData() == {}
tagsIndex.unpackData(content)
assert tagsIndex._tags == content
assert tagsIndex.packData() == content
# Unpack Errors
# =============
tagsIndex.clear()
# Invalid data type
with pytest.raises(ValueError):
tagsIndex.unpackData([])
# Invalid key
with pytest.raises(ValueError):
tagsIndex.unpackData({
1234: {
"handle": "0000000000001",
"heading": "T000001",
"class": "NOVEL",
}
})
# Missing handle
with pytest.raises(KeyError):
tagsIndex.unpackData({
"Tag1": {
"heading": "T000001",
"class": "NOVEL",
}
})
# Missing heading
with pytest.raises(KeyError):
tagsIndex.unpackData({
"Tag1": {
"handle": "0000000000001",
"class": "NOVEL",
}
})
# Missing class
with pytest.raises(KeyError):
tagsIndex.unpackData({
"Tag1": {
"handle": "0000000000001",
"heading": "T000001",
}
})
# Invalid handle
with pytest.raises(ValueError):
tagsIndex.unpackData({
"Tag1": {
"handle": "blablabla",
"heading": "T000001",
"class": "NOVEL",
}
})
# Invalid heading
with pytest.raises(ValueError):
tagsIndex.unpackData({
"Tag1": {
"handle": "0000000000001",
"heading": "blabla",
"class": "NOVEL",
}
})
# Invalid class
with pytest.raises(ValueError):
tagsIndex.unpackData({
"Tag1": {
"handle": "0000000000001",
"heading": "T000001",
"class": "blabla",
}
})
# END Test testCoreIndex_TagsIndex
@pytest.mark.core
def testCoreIndex_ItemIndex(mockGUI, fncDir, mockRnd):
"""Check the ItemIndex class.
@@ -780,26 +942,6 @@ def testCoreIndex_ItemIndex(mockGUI, fncDir, mockRnd):
assert cHandle not in itemIndex
assert sHandle not in itemIndex
# Unpack Data
# ===========
# 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
itemIndex.clear()
# Add Items
# =========
assert cHandle not in itemIndex
@@ -820,7 +962,7 @@ def testCoreIndex_ItemIndex(mockGUI, fncDir, mockRnd):
# Set the remainig data values
itemIndex.setHeadingCounts(cHandle, "T000001", 60, 10, 2)
itemIndex.setHeadingSynopsis(cHandle, "T000001", "In the beginning ...")
itemIndex.setHeadingTag(cHandle, "T000001", "One") # Although it isn't allowed to have a tag
itemIndex.setHeadingTag(cHandle, "T000001", "One")
itemIndex.addHeadingReferences(cHandle, "T000001", ["Jane"], "@pov")
itemIndex.addHeadingReferences(cHandle, "T000001", ["Jane"], "@focus")
itemIndex.addHeadingReferences(cHandle, "T000001", ["Jane", "John"], "@char")
@@ -842,6 +984,37 @@ def testCoreIndex_ItemIndex(mockGUI, fncDir, mockRnd):
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
# ===============
@@ -908,6 +1081,82 @@ def testCoreIndex_ItemIndex(mockGUI, fncDir, mockRnd):
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"}},
}
})
# END Test testCoreIndex_ItemIndex