Updated tests for NWSpell* classes

This commit is contained in:
Veronica K. B. Olsen
2020-12-03 18:37:52 +01:00
parent c13bd18271
commit c7c70a35a0
7 changed files with 219 additions and 33 deletions
+18 -14
View File
@@ -28,8 +28,7 @@
import nw
import logging
import os
from difflib import get_close_matches
import difflib
from nw.constants import nwConst, isoLanguage
@@ -70,14 +69,16 @@ class NWSpellCheck():
"""
if self.projectDict is not None and newWord not in self.projDict:
newWord = newWord.strip()
self.projDict.append(newWord)
try:
with open(self.projectDict, mode="a+", encoding="utf-8") as outFile:
outFile.write("%s\n" % newWord)
self.projDict.append(newWord)
except Exception as e:
logger.error("Failed to add word to project word list %s" % str(self.projectDict))
logger.error(str(e))
return
return False
return True
return False
def listDictionaries(self):
"""Dummy function.
@@ -109,9 +110,12 @@ class NWSpellCheck():
"""
self.projDict = []
if projectDict is not None:
self.projectDict = projectDict
if not os.path.isfile(projectDict):
return
self.projectDict = None
return False
else:
self.projectDict = projectDict
try:
logger.debug("Loading project word list")
with open(projectDict, mode="r", encoding="utf-8") as wordsFile:
@@ -123,7 +127,9 @@ class NWSpellCheck():
except Exception as e:
logger.error("Failed to load project word list")
logger.error(str(e))
return
return False
return True
# END Class NWSpellCheck
@@ -287,7 +293,7 @@ class NWSpellSimple(NWSpellCheck):
if len(theWord) == 0:
return []
theMatches = get_close_matches(theWord.lower(), self.WORDS, n=10, cutoff=0.75)
theMatches = difflib.get_close_matches(theWord.lower(), self.WORDS, n=10, cutoff=0.75)
theOptions = []
for aWord in theMatches:
if len(aWord) == 0:
@@ -314,14 +320,12 @@ class NWSpellSimple(NWSpellCheck):
retList = []
for dictFile in os.listdir(self.mainConf.dictPath):
theBits = os.path.splitext(dictFile)
if len(theBits) != 2:
continue
if theBits[1] != ".dict":
fRoot, fExt = os.path.splitext(dictFile)
if fExt != ".dict":
continue
spName = "%s [%s]" % (self.expandLanguage(theBits[0]), nwConst.SP_INTERNAL)
retList.append((theBits[0], spName))
spName = "%s [%s]" % (self.expandLanguage(fRoot), nwConst.SP_INTERNAL)
retList.append((fRoot, spName))
return retList
+9 -9
View File
@@ -59,12 +59,12 @@ Available markers are:
To filter specific groups of tests, use the `-k` switch.
The commands for the respective test categories are listed below.
| Type | Test Target | Source File(s) | Marker | Filter |
| :--- | :----------------- | :------------------ | :-------- | :-------------------- |
| Unit | Core functions | nw/core/tools.py | `-m core` | `-k testCoreTools` |
| Unit | NWDoc class | nw/core/document.py | `-m core` | `-k testCoreDocument` |
| Unit | NWIndex class | nw/core/index.py | `-m core` | `-k testCoreIndex` |
| Unit | NWItem class | nw/core/item.py | `-m core` | `-k testCoreItem` |
| Unit | NWTree class | nw/core/tree.py | `-m core` | `-k testCoreTree` |
| Unit | OptionsState class | nw/core/options.py | `-m core` | `-k testCoreOptions` |
| Type | Test Target | Source File(s) | Marker | Filter |
| :--- | :----------------- | :-------------------- | :-------- | :-------------------- |
| Unit | Core functions | nw/core/tools.py | `-m core` | `-k testCoreTools` |
| Unit | NWDoc class | nw/core/document.py | `-m core` | `-k testCoreDocument` |
| Unit | NWIndex class | nw/core/index.py | `-m core` | `-k testCoreIndex` |
| Unit | NWItem class | nw/core/item.py | `-m core` | `-k testCoreItem` |
| Unit | NWSpell* classes | nw/core/spellcheck.py | `-m core` | `-k testCoreSpell` |
| Unit | NWTree class | nw/core/tree.py | `-m core` | `-k testCoreTree` |
| Unit | OptionsState class | nw/core/options.py | `-m core` | `-k testCoreOptions` |
+1 -1
View File
@@ -47,5 +47,5 @@ class StatusBar():
# Dummy functions that will raise errors instead.
# =========================================================================== #
def dummyIO(*args, **kwargs):
def causeOSError(*args, **kwargs):
raise OSError
+4 -5
View File
@@ -5,6 +5,8 @@
import os
import pytest
from dummy import causeOSError
from nw.core import NWProject, NWDoc
from nw.core.item import NWItem
from nw.constants import nwItemClass, nwItemLayout
@@ -75,10 +77,7 @@ def testCoreDocument_LoadSave(monkeypatch, dummyGUI, nwMinimal):
assert inFile.read() == theText
# Cause open() to fail while saving
def dummyIO(*args, **kwargs):
raise OSError
monkeypatch.setattr("builtins.open", dummyIO)
monkeypatch.setattr("builtins.open", causeOSError)
assert not theDoc.saveDocument(theText)
monkeypatch.undo()
@@ -91,7 +90,7 @@ def testCoreDocument_LoadSave(monkeypatch, dummyGUI, nwMinimal):
assert os.path.isfile(docPath)
# Cause the delete to fail
monkeypatch.setattr("os.unlink", dummyIO)
monkeypatch.setattr("os.unlink", causeOSError)
assert not theDoc.deleteDocument(xHandle)
monkeypatch.undo()
+3 -4
View File
@@ -6,6 +6,8 @@ import os
import json
import pytest
from dummy import causeOSError
from nw.core import NWProject
from nw.core.options import OptionState
from nw.constants import nwFiles
@@ -44,10 +46,7 @@ def testCoreOptions_LoadSave(monkeypatch, dummyGUI, tmpDir):
assert theProject.projMeta == tmpDir
# Cause open() to fail
def dummyIO(*args, **kwargs):
raise OSError
monkeypatch.setattr("builtins.open", dummyIO)
monkeypatch.setattr("builtins.open", causeOSError)
assert not theOpts.loadSettings()
assert not theOpts.saveSettings()
monkeypatch.undo()
+172
View File
@@ -0,0 +1,172 @@
# -*- coding: utf-8 -*-
"""novelWriter Spell Check Class Tester
"""
import os
import sys
import pytest
from difflib import get_close_matches
from dummy import causeOSError
from tools import readFile, writeFile
from nw.core.spellcheck import NWSpellCheck, NWSpellEnchant, NWSpellSimple
from nw.constants import nwConst
@pytest.mark.core
def testCoreSpell_Super(monkeypatch, tmpDir, tmpConf):
"""Test the spell checker super class
"""
wList = os.path.join(tmpDir, "wordlist.txt")
writeFile(wList, "a_word\nb_word\nc_word\n")
spChk = NWSpellCheck()
spChk.mainConf = tmpConf
# Check that dummy functions return results that reflects that spell
# checking is effectively disabled
assert spChk.setLanguage("", "") is None
assert spChk.checkWord("")
assert spChk.suggestWords("") == []
assert spChk.listDictionaries() == []
assert spChk.describeDict() == ("", "")
# Check language info
assert NWSpellCheck.expandLanguage("en") == "English"
assert NWSpellCheck.expandLanguage("en_GB") == "English (GB)"
# Add a word to the user's dictionary
assert spChk._readProjectDictionary("dummy") is False
monkeypatch.setattr("builtins.open", causeOSError)
assert spChk._readProjectDictionary(wList) is False
monkeypatch.undo()
assert spChk._readProjectDictionary(wList) is True
assert spChk.projectDict == wList
# Cannot write to file
monkeypatch.setattr("builtins.open", causeOSError)
assert spChk.addWord("d_word") is False
monkeypatch.undo()
assert readFile(wList) == "a_word\nb_word\nc_word\n"
# First time, OK
assert spChk.addWord("d_word") is True
assert readFile(wList) == "a_word\nb_word\nc_word\nd_word\n"
# But not added twice
assert spChk.addWord("d_word") is False
assert readFile(wList) == "a_word\nb_word\nc_word\nd_word\n"
# END Test testCoreSpell_Super
@pytest.mark.core
def testCoreSpell_Enchant(monkeypatch, tmpDir, tmpConf):
"""Test the pyenchant spell checker
"""
wList = os.path.join(tmpDir, "wordlist.txt")
writeFile(wList, "a_word\nb_word\nc_word\n")
# Block the enchant package (and trigger the dummy class)
monkeypatch.setitem(sys.modules, "enchant", None)
spChk = NWSpellEnchant()
spChk.setLanguage("en", wList)
assert spChk.setLanguage("", "") is None
assert spChk.checkWord("")
assert spChk.suggestWords("") == []
assert spChk.listDictionaries() == []
assert spChk.describeDict() == ("", "")
monkeypatch.undo()
# Load the proper enchant package
spChk = NWSpellEnchant()
spChk.mainConf = tmpConf
spChk.setLanguage("en", wList)
assert spChk.checkWord("a_word")
assert spChk.checkWord("b_word")
assert spChk.checkWord("c_word")
assert not spChk.checkWord("d_word")
spChk.addWord("d_word")
assert spChk.checkWord("d_word")
wSuggest = spChk.suggestWords("wrod")
assert len(wSuggest) > 0
assert "word" in wSuggest
dList = spChk.listDictionaries()
assert len(dList) > 0
aTag, aName = spChk.describeDict()
assert aTag == "en"
assert aName != ""
# END Test testCoreSpell_Enchant
@pytest.mark.core
def testCoreSpell_Simple(monkeypatch, tmpDir, tmpConf):
"""Test the fallback simple spell checker
"""
wList = os.path.join(tmpDir, "wordlist.txt")
wDict = os.path.join(tmpDir, "en.dict")
writeFile(wList, "a_word\nb_word\nc_word\n")
writeFile(wDict, "# Comment\ne_word\nf_word\ng_word\n")
spChk = NWSpellSimple()
spChk.mainConf = tmpConf
spChk.mainConf.dictPath = tmpDir
# Load dictionary, but fail
monkeypatch.setattr("builtins.open", causeOSError)
spChk.setLanguage("en", wList)
assert spChk.spellLanguage is None
assert spChk.WORDS == spChk.projDict
monkeypatch.undo()
# Load dictionary properly
spChk.setLanguage("en", wList)
assert spChk.projDict == ["a_word", "b_word", "c_word"]
assert spChk.WORDS == ["e_word", "f_word", "g_word", "a_word", "b_word", "c_word"]
# Check words
assert spChk.checkWord("a_word")
assert spChk.checkWord("b_word")
assert spChk.checkWord("c_word")
assert not spChk.checkWord("d_word")
assert spChk.checkWord("e_word")
assert spChk.checkWord("f_word")
assert spChk.checkWord("g_word")
# Add word
spChk.addWord("d_word")
assert spChk.checkWord("d_word")
# Check spelling
assert spChk.suggestWords(" \t") == []
wSuggest = spChk.suggestWords("d_wrod")
assert len(wSuggest) > 0
assert "d_word" in wSuggest
# Break the matching
monkeypatch.setattr("difflib.get_close_matches", lambda *args, **kwargs: [""])
assert spChk.suggestWords("word") == []
monkeypatch.undo()
# Capitalisation
wSuggest = spChk.suggestWords("D_wrod")
assert len(wSuggest) > 0
assert "D_word" in wSuggest
# List dictionaries
assert spChk.listDictionaries() == [("en", "English [%s]" % nwConst.SP_INTERNAL)]
# Description
aTag, aName = spChk.describeDict()
assert aTag == "en"
assert aName == nwConst.SP_INTERNAL
# END Test testCoreSpell_Simple
+12
View File
@@ -70,3 +70,15 @@ def getGuiItem(theName):
if qWidget.objectName() == theName:
return qWidget
return None
def readFile(fileName):
"""Returns the content of a file as a string.
"""
with open(fileName, mode="r", encoding="utf8") as inFile:
return inFile.read()
def writeFile(fileName, fileData):
"""Write the contents of a string to a file.
"""
with open(fileName, mode="w", encoding="utf8") as outFile:
outFile.write(fileData)