Clean up and add test coverage

This commit is contained in:
Veronica Berglyd Olsen
2023-11-20 18:14:00 +01:00
parent 71d17da483
commit d741a75de8
2 changed files with 209 additions and 30 deletions
+50 -30
View File
@@ -39,6 +39,7 @@ from PyQt5.QtWidgets import (
from novelwriter import CONFIG, SHARED
from novelwriter.common import formatInt, getFileSize
from novelwriter.error import formatException
logger = logging.getLogger(__name__)
@@ -156,7 +157,7 @@ class GuiDictionaries(QDialog):
i.stem for i in hunspell.iterdir() if i.is_file() and i.suffix == ".aff"
)
self._appendLog(self.tr(
"{0} additional dictionaries currently installed"
"Additional dictionaries found: {0}"
).format(len(self._currDicts)))
qApp.processEvents()
@@ -196,29 +197,21 @@ class GuiDictionaries(QDialog):
@pyqtSlot()
def _doImportHunspell(self):
"""Import a hunspell dictionary from .sox or .oxt file."""
temp = self.huInput.text()
output = self._installPath
if not output:
return
if output and temp and (path := Path(temp)).is_file():
hunspell = output / "hunspell"
hunspell.mkdir(exist_ok=True)
try:
with ZipFile(path, mode="r") as zipObj:
for item in zipObj.namelist():
zPath = Path(item)
if zPath.suffix in (".aff", ".dic"):
with zipObj.open(item) as zF:
oPath = hunspell / zPath.name
oPath.write_bytes(zF.read())
size = getFileSize(oPath)
self._appendLog(self.tr(
"Added: {0} [{1}B]"
).format(zPath.name, formatInt(size)))
except Exception as exc:
SHARED.error(self.tr("Could not process dictionary file."), exc=exc)
else:
SHARED.error(self.tr("File not found."))
procErr = self.tr("Could not process dictionary file")
if self._installPath:
temp = self.huInput.text()
if temp and (path := Path(temp)).is_file():
hunspell = self._installPath / "hunspell"
hunspell.mkdir(exist_ok=True)
try:
nAff, nDic = self._extractDicts(path, hunspell)
if nAff == 0 or nDic == 0:
self._appendLog(procErr, err=True)
except Exception as exc:
self._appendLog(procErr, err=True)
self._appendLog(formatException(exc), err=True)
else:
self._appendLog(procErr, err=True)
return
@pyqtSlot()
@@ -243,13 +236,40 @@ class GuiDictionaries(QDialog):
# Internal Functions
##
def _appendLog(self, text: str) -> None:
def _extractDicts(self, path: Path, output: Path) -> tuple[int, int]:
"""Extract a zip archive and return the number of .aff and .dic
files found in it.
"""
nAff = nDic = 0
with ZipFile(path, mode="r") as zipObj:
for item in zipObj.namelist():
zPath = Path(item)
if zPath.suffix not in (".aff", ".dic"):
continue
nAff += 1 if zPath.suffix == ".aff" else 0
nDic += 1 if zPath.suffix == ".dic" else 0
with zipObj.open(item) as zF:
oPath = output / zPath.name
oPath.write_bytes(zF.read())
size = getFileSize(oPath)
self._appendLog(self.tr(
"Added: {0} [{1}B]"
).format(zPath.name, formatInt(size)))
return nAff, nDic
def _appendLog(self, text: str, err: bool = False) -> None:
"""Append a line to the log output."""
self.infoBox.moveCursor(QTextCursor.MoveOperation.End)
if self.infoBox.textCursor().position() > 0:
self.infoBox.insertPlainText("\n")
self.infoBox.insertPlainText(text)
self.infoBox.moveCursor(QTextCursor.MoveOperation.End)
cursor = self.infoBox.textCursor()
cursor.movePosition(QTextCursor.MoveOperation.End)
if cursor.position() > 0:
cursor.insertText("\n")
if err:
cursor.insertHtml(f"<font color='red'>{text}</font>")
else:
cursor.insertText(text)
cursor.movePosition(QTextCursor.MoveOperation.End)
cursor.deleteChar()
self.infoBox.setTextCursor(cursor)
return
# END Class GuiDictionaries
+159
View File
@@ -0,0 +1,159 @@
"""
novelWriter Dictionary Downloader Tester
==========================================
This file is a part of novelWriter
Copyright 20182023, Veronica Berglyd Olsen
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
import pytest
import enchant
from zipfile import ZipFile
from tools import getGuiItem
from mocked import causeException
from PyQt5.QtGui import QDesktopServices
from PyQt5.QtWidgets import QFileDialog
from novelwriter import SHARED
from novelwriter.tools.dictionaries import GuiDictionaries
@pytest.mark.gui
def testToolDictionaries_Main(qtbot, monkeypatch, nwGUI, fncPath):
"""Test the Dictionaries downloader tool."""
monkeypatch.setattr(enchant, "get_user_config_dir", lambda *a: str(fncPath))
# Fail to open
with monkeypatch.context() as mp:
mp.setattr(enchant, "get_user_config_dir", lambda *a: causeException)
nwGUI.showDictionariesDialog()
assert SHARED.alert is not None
assert SHARED.alert.logMessage == "Could not initialise the dialog."
# Open the tool
nwGUI.showDictionariesDialog()
qtbot.waitUntil(lambda: getGuiItem("GuiDictionaries") is not None, timeout=1000)
nwDicts = getGuiItem("GuiDictionaries")
assert isinstance(nwDicts, GuiDictionaries)
assert nwDicts.isVisible()
assert nwDicts.inPath.text() == str(fncPath)
# Allow Open Dir
SHARED._alert = None
with monkeypatch.context() as mp:
mp.setattr(QDesktopServices, "openUrl", lambda *a: None)
nwDicts._doOpenInstallLocation()
assert SHARED.alert is None
# Fail Open Dir
nwDicts.inPath.setText("/foo/bar")
nwDicts._doOpenInstallLocation()
assert SHARED.alert is not None
assert SHARED.alert.logMessage == "Path not found."
nwDicts.inPath.setText(str(fncPath))
# Create Mock Dicts
foDict = fncPath / "freeoffice.sox"
with ZipFile(foDict, mode="w") as zipObj:
zipObj.writestr("en_GB.aff", "foobar")
zipObj.writestr("en_GB.dic", "foobar")
zipObj.writestr("README.txt", "foobar")
loDict = fncPath / "libreoffice.oxt"
with ZipFile(loDict, mode="w") as zipObj:
zipObj.writestr("en_US/en_US.aff", "foobar")
zipObj.writestr("en_US/en_US.dic", "foobar")
zipObj.writestr("README.txt", "foobar")
emDict = fncPath / "empty.oxt"
with ZipFile(emDict, mode="w") as zipObj:
zipObj.writestr("README.txt", "foobar")
noFile = fncPath / "foobar.oxt"
noDict = fncPath / "foobar.sox"
noDict.write_bytes(b"foobar")
assert nwDicts.infoBox.toPlainText().splitlines()[-1] == (
"Additional dictionaries found: 0"
)
# Import Free Office Dictionary
with monkeypatch.context() as mp:
mp.setattr(QFileDialog, "getOpenFileName", lambda *a, **k: (str(foDict), ""))
nwDicts._doBrowseHunspell()
assert nwDicts.huInput.text() == str(foDict)
nwDicts._doImportHunspell()
assert (fncPath / "hunspell").is_dir()
assert (fncPath / "hunspell" / "en_GB.aff").is_file()
assert (fncPath / "hunspell" / "en_GB.dic").is_file()
assert nwDicts.infoBox.blockCount() == 3
# Import Libre Office Dictionary
with monkeypatch.context() as mp:
mp.setattr(QFileDialog, "getOpenFileName", lambda *a, **k: (str(loDict), ""))
nwDicts._doBrowseHunspell()
assert nwDicts.huInput.text() == str(loDict)
nwDicts._doImportHunspell()
assert (fncPath / "hunspell").is_dir()
assert (fncPath / "hunspell" / "en_US.aff").is_file()
assert (fncPath / "hunspell" / "en_US.dic").is_file()
assert nwDicts.infoBox.blockCount() == 5
# Handle Unreadable File
with monkeypatch.context() as mp:
mp.setattr(QFileDialog, "getOpenFileName", lambda *a, **k: (str(noDict), ""))
nwDicts._doBrowseHunspell()
assert nwDicts.huInput.text() == str(noDict)
nwDicts._doImportHunspell()
assert nwDicts.infoBox.blockCount() == 7
# Handle File w/No Dicts
with monkeypatch.context() as mp:
mp.setattr(QFileDialog, "getOpenFileName", lambda *a, **k: (str(emDict), ""))
nwDicts._doBrowseHunspell()
assert nwDicts.huInput.text() == str(emDict)
nwDicts._doImportHunspell()
assert nwDicts.infoBox.blockCount() == 8
assert nwDicts.infoBox.toPlainText().splitlines()[-1] == (
"Could not process dictionary file"
)
# Handle Non-Existing File
with monkeypatch.context() as mp:
mp.setattr(QFileDialog, "getOpenFileName", lambda *a, **k: (str(noFile), ""))
nwDicts._doBrowseHunspell()
nwDicts._doImportHunspell()
assert nwDicts.infoBox.blockCount() == 9
assert nwDicts.infoBox.toPlainText().splitlines()[-1] == (
"Could not process dictionary file"
)
# Re-init
nwDicts.initDialog()
assert nwDicts.infoBox.blockCount() == 10
assert nwDicts.infoBox.toPlainText().splitlines()[-1] == (
"Additional dictionaries found: 2"
)
# Close
nwDicts._doClose()
# qtbot.stop()
# END Test testToolDictionaries_Main