Add test coverage of status class

This commit is contained in:
Veronica Berglyd Olsen
2024-04-10 22:19:15 +02:00
parent adfd003532
commit d1dbb0b378
3 changed files with 146 additions and 78 deletions
+5 -2
View File
@@ -57,8 +57,11 @@ class StatusEntry:
@classmethod @classmethod
def duplicate(cls, source: StatusEntry) -> StatusEntry: def duplicate(cls, source: StatusEntry) -> StatusEntry:
"""Create a shallow copy of the source object.""" """Create a deep copy of the source object."""
return dataclasses.replace(source) cls = dataclasses.replace(source)
cls.color = QColor(source.color)
cls.icon = QIcon(source.icon)
return cls
# END Class StatusEntry # END Class StatusEntry
+1 -1
View File
@@ -75,7 +75,7 @@ class MockStatusBar:
class MockTheme: class MockTheme:
def __init__(self): def __init__(self):
self.baseIconHeight = 10 self.baseIconHeight = 20
return return
def getPixmap(self, *a): def getPixmap(self, *a):
+140 -75
View File
@@ -26,7 +26,7 @@ from tools import C
from PyQt5.QtGui import QColor, QIcon from PyQt5.QtGui import QColor, QIcon
from novelwriter.core.status import NWStatus from novelwriter.core.status import NWStatus, StatusEntry, _ShapeCache
from novelwriter.enum import nwStatusShape from novelwriter.enum import nwStatusShape
statusKeys = [C.sNew, C.sNote, C.sDraft, C.sFinished] statusKeys = [C.sNew, C.sNote, C.sDraft, C.sFinished]
@@ -34,7 +34,36 @@ importKeys = [C.iNew, C.iMinor, C.iMajor, C.iMain]
@pytest.mark.core @pytest.mark.core
def testCoreStatus_Internal(mockRnd): def testCoreStatus_StatusEntry():
"""Test the StatusEntry class."""
color = QColor(255, 0, 0)
icon = NWStatus.createIcon(24, color, nwStatusShape.CIRCLE)
entry = StatusEntry("Test", color, nwStatusShape.CIRCLE, icon, 42)
# Check values
assert entry.name == "Test"
assert entry.color is color
assert entry.shape == nwStatusShape.CIRCLE
assert entry.icon is icon
assert entry.count == 42
# Make a copy
other = StatusEntry.duplicate(entry)
assert other is not entry
# Check copy is not the same
assert other.name == "Test"
assert other.color is not color # Not the same object
assert other.color == color # But same colours
assert other.shape == nwStatusShape.CIRCLE
assert other.icon is not icon # Not the same icon, but a copy
assert other.count == 42
# END Test testCoreStatus_StatusEntry
@pytest.mark.core
def testCoreStatus_Internal(mockGUI, mockRnd):
"""Test all the internal functions of the NWStatus class.""" """Test all the internal functions of the NWStatus class."""
nStatus = NWStatus(NWStatus.STATUS) nStatus = NWStatus(NWStatus.STATUS)
nImport = NWStatus(NWStatus.IMPORT) nImport = NWStatus(NWStatus.IMPORT)
@@ -82,18 +111,25 @@ def testCoreStatus_Internal(mockRnd):
assert nImport._isKey("i12345F") is False # Not a lower case hex value assert nImport._isKey("i12345F") is False # Not a lower case hex value
assert nImport._isKey("i12345f") is True # Valid hex value assert nImport._isKey("i12345f") is True # Valid hex value
assert nStatus._checkKey(None) == "s000008" # Creates next key
assert nStatus._checkKey("s654321") == "s654321" # Status key accepted
assert nStatus._checkKey("i123456") == "s000009" # Import key not accepted
assert nImport._checkKey(None) == "i00000a" # Creates next key
assert nImport._checkKey("s654321") == "i00000b" # Status key not accepted
assert nImport._checkKey("i123456") == "i123456" # Import key accepted
# END Test testCoreStatus_Internal # END Test testCoreStatus_Internal
@pytest.mark.core @pytest.mark.core
def testCoreStatus_Iterator(mockRnd): def testCoreStatus_Iterator(mockGUI, mockRnd):
"""Test the iterator functions of the NWStatus class.""" """Test the iterator functions of the NWStatus class."""
nStatus = NWStatus(NWStatus.STATUS) nStatus = NWStatus(NWStatus.STATUS)
nStatus.add(None, "New", (100, 100, 100), "SQUARE", 0) nStatus.add(None, "New", (100, 100, 100), "SQUARE", 0)
nStatus.add(None, "Note", (200, 50, 0), "SQUARE", 0) nStatus.add(None, "Note", (200, 50, 0), "CIRCLE", 1)
nStatus.add(None, "Draft", (200, 150, 0), "SQUARE", 0) nStatus.add(None, "Draft", (200, 150, 0), "SQUARE", 2)
nStatus.add(None, "Finished", (50, 200, 0), "SQUARE", 0) nStatus.add(None, "Finished", (50, 200, 0), "CIRCLE", 3)
# Direct access # Direct access
entry = nStatus[statusKeys[0]] entry = nStatus[statusKeys[0]]
@@ -106,36 +142,63 @@ def testCoreStatus_Iterator(mockRnd):
assert len(nStatus._store) == 4 assert len(nStatus._store) == 4
assert len(nStatus) == 4 assert len(nStatus) == 4
# Content : Keys
assert [k for k, _ in nStatus.iterItems()] == [
"s000000", "s000001", "s000002", "s000003"
]
# Content : Names
assert [e.name for _, e in nStatus.iterItems()] == [
"New", "Note", "Draft", "Finished"
]
# Content : Colours
assert [e.color for _, e in nStatus.iterItems()] == [
QColor(100, 100, 100), QColor(200, 50, 0), QColor(200, 150, 0), QColor(50, 200, 0)
]
# Content : Shape
assert [e.shape for _, e in nStatus.iterItems()] == [
nwStatusShape.SQUARE, nwStatusShape.CIRCLE, nwStatusShape.SQUARE, nwStatusShape.CIRCLE
]
# Content : Count
assert [e.count for _, e in nStatus.iterItems()] == [0, 1, 2, 3]
# END Test testCoreStatus_Iterator # END Test testCoreStatus_Iterator
@pytest.mark.core @pytest.mark.core
def testCoreStatus_Entries(mockRnd): def testCoreStatus_Entries(mockGUI, mockRnd):
"""Test all the simple setters for the NWStatus class.""" """Test all the simple setters for the NWStatus class."""
nStatus = NWStatus(NWStatus.STATUS) nStatus = NWStatus(NWStatus.STATUS)
# Write # Add
# ===== # ===
# Have a key # Has a key
nStatus.add(statusKeys[0], "Entry 1", (200, 100, 50), "SQUARE", 0) nStatus.add(statusKeys[0], "Entry 1", (200, 100, 50), "SQUARE", 0)
assert nStatus[statusKeys[0]].name == "Entry 1" assert nStatus[statusKeys[0]].name == "Entry 1"
assert nStatus[statusKeys[0]].color == QColor(200, 100, 50) assert nStatus[statusKeys[0]].color == QColor(200, 100, 50)
assert nStatus[statusKeys[0]].shape == nwStatusShape.SQUARE
# Don't have a key # Doesn't have a key
nStatus.add(None, "Entry 2", (210, 110, 60), "SQUARE", 0) nStatus.add(None, "Entry 2", (210, 110, 60), "SQUARE", 0)
assert nStatus[statusKeys[1]].name == "Entry 2" assert nStatus[statusKeys[1]].name == "Entry 2"
assert nStatus[statusKeys[1]].color == QColor(210, 110, 60) assert nStatus[statusKeys[1]].color == QColor(210, 110, 60)
assert nStatus[statusKeys[1]].shape == nwStatusShape.SQUARE
# Wrong colour spec # Wrong colour spec, unknown shape
nStatus.add(None, "Entry 3", "what?", "SQUARE", 0) # type: ignore nStatus.add(None, "Entry 3", "what?", "", 0) # type: ignore
assert nStatus[statusKeys[2]].name == "Entry 3" assert nStatus[statusKeys[2]].name == "Entry 3"
assert nStatus[statusKeys[2]].color == QColor(100, 100, 100) assert nStatus[statusKeys[2]].color == QColor(100, 100, 100)
assert nStatus[statusKeys[2]].shape == nwStatusShape.SQUARE
# Wrong colour count # Wrong colour count
nStatus.add(None, "Entry 4", (10, 20), "SQUARE", 0) # type: ignore nStatus.add(None, "Entry 4", (10, 20), "CIRCLE", 0) # type: ignore
assert nStatus[statusKeys[3]].name == "Entry 4" assert nStatus[statusKeys[3]].name == "Entry 4"
assert nStatus[statusKeys[3]].color == QColor(100, 100, 100) assert nStatus[statusKeys[3]].color == QColor(100, 100, 100)
assert nStatus[statusKeys[3]].shape == nwStatusShape.CIRCLE
# Check # Check
# ===== # =====
@@ -174,6 +237,15 @@ def testCoreStatus_Entries(mockRnd):
assert isinstance(nStatus[statusKeys[3]].icon, QIcon) assert isinstance(nStatus[statusKeys[3]].icon, QIcon)
assert isinstance(nStatus["blablabla"].icon, QIcon) assert isinstance(nStatus["blablabla"].icon, QIcon)
# Shape Access
# ============
assert nStatus[statusKeys[0]].shape == nwStatusShape.SQUARE
assert nStatus[statusKeys[1]].shape == nwStatusShape.SQUARE
assert nStatus[statusKeys[2]].shape == nwStatusShape.SQUARE
assert nStatus[statusKeys[3]].shape == nwStatusShape.CIRCLE
assert nStatus["blablabla"].shape == nwStatusShape.SQUARE
# Increment and Count Access # Increment and Count Access
# ========================== # ==========================
@@ -195,37 +267,19 @@ def testCoreStatus_Entries(mockRnd):
assert nStatus[statusKeys[2]].count == 0 assert nStatus[statusKeys[2]].count == 0
assert nStatus[statusKeys[3]].count == 0 assert nStatus[statusKeys[3]].count == 0
# Reorder # Update
# ======= # ======
# cOrder = list(nStatus._store.keys()) assert list(nStatus._store.keys()) == statusKeys
# assert cOrder == statusKeys
# # Wrong length # Reverse
# assert nStatus.reorder([]) is False order: list[tuple[str | None, StatusEntry]] = list(nStatus.iterItems())
nStatus.update(list(reversed(order)))
assert list(nStatus._store.keys()) == list(reversed(statusKeys))
# # No change # Restore
# assert nStatus.reorder(cOrder) is False nStatus.update(order)
assert list(nStatus._store.keys()) == statusKeys
# # Actual re-order
# nOrder = [
# statusKeys[0],
# statusKeys[2],
# statusKeys[1],
# statusKeys[3],
# ]
# assert nStatus.reorder(nOrder) is True
# assert list(nStatus._store.keys()) == nOrder
# # Add an unknown key
# wOrder = nOrder.copy()
# wOrder[3] = nStatus._newKey()
# assert nStatus.reorder(wOrder) is False
# assert list(nStatus._store.keys()) == nOrder
# # Put it back
# assert nStatus.reorder(cOrder) is True
# assert list(nStatus._store.keys()) == cOrder
# Default # Default
# ======= # =======
@@ -242,46 +296,31 @@ def testCoreStatus_Entries(mockRnd):
nStatus._default = default nStatus._default = default
# # Remove # Remove
# # ====== # ======
# This uses update with deleted items
# # Non-existing entry order: list[tuple[str | None, StatusEntry]] = list(nStatus.iterItems())
# assert nStatus.remove("blablabla") is False
# # Non-zero entry # Remove Entry 0
# nStatus.increment(statusKeys[3]) nStatus.update([order[1], order[3], order[2]])
# assert nStatus.remove(statusKeys[3]) is False assert list(nStatus._store.keys()) == [statusKeys[1], statusKeys[3], statusKeys[2]]
assert nStatus._default == statusKeys[1]
# # Delete last entry # Remove Entry 1
# nStatus.resetCounts() nStatus.update([order[3], order[2]])
# lastName = nStatus[statusKeys[3]].name assert list(nStatus._store.keys()) == [statusKeys[3], statusKeys[2]]
# assert lastName == "Entry 4" assert nStatus._default == statusKeys[3]
# 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 = nStatus[nStatus._default].name
# assert firstName == "Entry 1"
# assert nStatus.remove(nStatus._default) is True # type: ignore
# assert nStatus[firstName].name == "Entry 2"
# # Remove remaining entries
# assert nStatus.remove(statusKeys[1]) is True
# assert nStatus.remove(statusKeys[2]) is True
# assert len(nStatus) == 0
# assert nStatus._default is None
# END Test testCoreStatus_Entries # END Test testCoreStatus_Entries
@pytest.mark.core @pytest.mark.core
def testCoreStatus_PackUnpack(mockRnd): def testCoreStatus_Pack(mockGUI, mockRnd):
"""Test all the pack/unpack of the NWStatus class.""" """Test data packing of the NWStatus class."""
nStatus = NWStatus(NWStatus.STATUS) nStatus = NWStatus(NWStatus.STATUS)
nStatus.add(None, "New", (100, 100, 100), "SQUARE", 0) nStatus.add(None, "New", (100, 100, 100), "SQUARE", 0)
nStatus.add(None, "Note", (200, 50, 0), "SQUARE", 0) nStatus.add(None, "Note", (200, 50, 0), "CIRCLE", 0)
nStatus.add(None, "Draft", (200, 150, 0), "SQUARE", 0) nStatus.add(None, "Draft", (200, 150, 0), "SQUARE", 0)
nStatus.add(None, "Finished", (50, 200, 0), "SQUARE", 0) nStatus.add(None, "Finished", (50, 200, 0), "SQUARE", 0)
@@ -306,7 +345,7 @@ def testCoreStatus_PackUnpack(mockRnd):
"red": "200", "red": "200",
"green": "50", "green": "50",
"blue": "0", "blue": "0",
"shape": "SQUARE", "shape": "CIRCLE",
}), }),
("Draft", { ("Draft", {
"key": statusKeys[2], "key": statusKeys[2],
@@ -326,4 +365,30 @@ def testCoreStatus_PackUnpack(mockRnd):
}), }),
] ]
# END Test testCoreStatus_PackUnpack # END Test testCoreStatus_Pack
@pytest.mark.core
def testCoreStatus_ShapeCache():
"""Test the _ShapeCache class."""
shapes = _ShapeCache()
# Generate all shapes
square = shapes.getShape(nwStatusShape.SQUARE)
circle = shapes.getShape(nwStatusShape.CIRCLE)
triangle = shapes.getShape(nwStatusShape.TRIANGLE)
diamond = shapes.getShape(nwStatusShape.DIAMOND)
pentagon = shapes.getShape(nwStatusShape.PENTAGON)
star = shapes.getShape(nwStatusShape.STAR)
pacman = shapes.getShape(nwStatusShape.PACMAN)
# Request again should return from cache
assert shapes.getShape(nwStatusShape.SQUARE) is square
assert shapes.getShape(nwStatusShape.CIRCLE) is circle
assert shapes.getShape(nwStatusShape.TRIANGLE) is triangle
assert shapes.getShape(nwStatusShape.DIAMOND) is diamond
assert shapes.getShape(nwStatusShape.PENTAGON) is pentagon
assert shapes.getShape(nwStatusShape.STAR) is star
assert shapes.getShape(nwStatusShape.PACMAN) is pacman
# END Test testCoreStatus_ShapeCache