Clean up and add test coverage
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
"""
|
||||
novelWriter – Dictionary Downloader Tester
|
||||
==========================================
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2023, 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
|
||||
Reference in New Issue
Block a user