Updated tests for NWSpell* classes
This commit is contained in:
+18
-14
@@ -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
@@ -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
@@ -47,5 +47,5 @@ class StatusBar():
|
||||
# Dummy functions that will raise errors instead.
|
||||
# =========================================================================== #
|
||||
|
||||
def dummyIO(*args, **kwargs):
|
||||
def causeOSError(*args, **kwargs):
|
||||
raise OSError
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user