From 9772c85ece343c58579da6bf2c511e6c6aa1bea0 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Mon, 7 Dec 2020 23:34:12 +0100 Subject: [PATCH] Rewritten Config class test --- nw/config.py | 91 ++-- tests/conftest.py | 3 + ...riter.conf => baseConfig_novelwriter.conf} | 0 tests/test_base_config.py | 505 ++++++++++++++++++ tests/test_config.py | 165 ------ 5 files changed, 559 insertions(+), 205 deletions(-) rename tests/reference/{novelwriter.conf => baseConfig_novelwriter.conf} (100%) create mode 100644 tests/test_base_config.py delete mode 100644 tests/test_config.py diff --git a/nw/config.py b/nw/config.py index 04c1a4db..9c232109 100644 --- a/nw/config.py +++ b/nw/config.py @@ -27,12 +27,12 @@ import logging import configparser +import shutil import json import sys import os from time import time -from shutil import which from PyQt5.Qt import PYQT_VERSION_STR from PyQt5.QtCore import QT_VERSION_STR, QStandardPaths, QSysInfo @@ -44,10 +44,11 @@ logger = logging.getLogger(__name__) class Config: - CNF_STR = 0 - CNF_INT = 1 - CNF_BOOL = 2 - CNF_LIST = 3 + CNF_STR = 0 + CNF_INT = 1 + CNF_BOOL = 2 + CNF_S_LST = 3 + CNF_I_LST = 4 def __init__(self): @@ -211,12 +212,8 @@ class Config: self.osUnknown = True # Other System Info - if self.verQtValue >= 50600: - self.hostName = QSysInfo.machineHostName() - self.kernelVer = QSysInfo.kernelVersion() - else: - self.hostName = "Unknown" - self.kernelVer = "Unknown" + self.hostName = "Unknown" + self.kernelVer = "Unknown" # Packages self.hasEnchant = False # The pyenchant package @@ -321,6 +318,11 @@ class Config: self.errData.append(str(e)) self.dataPath = None + # Host and Kernel + if self.verQtValue >= 50600: + self.hostName = QSysInfo.machineHostName() + self.kernelVer = QSysInfo.kernelVersion() + # Load recent projects cache self.loadRecentCache() @@ -388,25 +390,25 @@ class Config: ## Sizes cnfSec = "Sizes" self.winGeometry = self._parseLine( - cnfParse, cnfSec, "geometry", self.CNF_LIST, self.winGeometry + cnfParse, cnfSec, "geometry", self.CNF_I_LST, self.winGeometry ) self.treeColWidth = self._parseLine( - cnfParse, cnfSec, "treecols", self.CNF_LIST, self.treeColWidth + cnfParse, cnfSec, "treecols", self.CNF_I_LST, self.treeColWidth ) self.projColWidth = self._parseLine( - cnfParse, cnfSec, "projcols", self.CNF_LIST, self.projColWidth + cnfParse, cnfSec, "projcols", self.CNF_I_LST, self.projColWidth ) self.mainPanePos = self._parseLine( - cnfParse, cnfSec, "mainpane", self.CNF_LIST, self.mainPanePos + cnfParse, cnfSec, "mainpane", self.CNF_I_LST, self.mainPanePos ) self.docPanePos = self._parseLine( - cnfParse, cnfSec, "docpane", self.CNF_LIST, self.docPanePos + cnfParse, cnfSec, "docpane", self.CNF_I_LST, self.docPanePos ) self.viewPanePos = self._parseLine( - cnfParse, cnfSec, "viewpane", self.CNF_LIST, self.viewPanePos + cnfParse, cnfSec, "viewpane", self.CNF_I_LST, self.viewPanePos ) self.outlnPanePos = self._parseLine( - cnfParse, cnfSec, "outlinepane", self.CNF_LIST, self.outlnPanePos + cnfParse, cnfSec, "outlinepane", self.CNF_I_LST, self.outlnPanePos ) self.isFullScreen = self._parseLine( cnfParse, cnfSec, "fullscreen", self.CNF_BOOL, self.isFullScreen @@ -484,10 +486,10 @@ class Config: cnfParse, cnfSec, "autoscrollpos", self.CNF_INT, self.autoScrollPos ) self.fmtSingleQuotes = self._parseLine( - cnfParse, cnfSec, "fmtsinglequote", self.CNF_LIST, self.fmtSingleQuotes + cnfParse, cnfSec, "fmtsinglequote", self.CNF_S_LST, self.fmtSingleQuotes ) self.fmtDoubleQuotes = self._parseLine( - cnfParse, cnfSec, "fmtdoublequote", self.CNF_LIST, self.fmtDoubleQuotes + cnfParse, cnfSec, "fmtdoublequote", self.CNF_S_LST, self.fmtDoubleQuotes ) self.spellTool = self._parseLine( cnfParse, cnfSec, "spelltool", self.CNF_STR, self.spellTool @@ -901,23 +903,28 @@ class Config: # Internal Functions ## - def _unpackList(self, inStr, listLen, listDefault, castTo=int): - """Unpack a comma separated string of items into a list. - """ - inData = inStr.split(",") - outData = [] - for i in range(listLen): - try: - outData.append(castTo(inData[i])) - except Exception: - outData.append(listDefault[i]) - return outData - def _packList(self, inData): - """Pack a list of items into a comma separated string. + """Pack a list of items into a comma-separated string. """ return ", ".join([str(inVal) for inVal in inData]) + def _unpackList(self, inStr, listDefault, cnfType): + """Unpack a comma-separated string of items into a list. + """ + inData = inStr.split(",") + outData = listDefault.copy() + for i in range(min(len(inData), len(listDefault))): + try: + if cnfType == self.CNF_S_LST: + outData[i] = inData[i].strip() + elif cnfType == self.CNF_I_LST: + outData[i] = int(inData[i].strip()) + else: + continue + except Exception: + continue + return outData + def _parseLine(self, cnfParse, cnfSec, cnfName, cnfType, cnfDefault): """Parse a line and return the correct datatype. """ @@ -930,18 +937,24 @@ class Config: return cnfParse.getint(cnfSec, cnfName) elif cnfType == self.CNF_BOOL: return cnfParse.getboolean(cnfSec, cnfName) - elif cnfType == self.CNF_LIST: + elif cnfType == self.CNF_I_LST: return self._unpackList( - cnfParse.get(cnfSec, cnfName), len(cnfDefault), cnfDefault + cnfParse.get(cnfSec, cnfName), cnfDefault, self.CNF_I_LST + ) + elif cnfType == self.CNF_S_LST: + return self._unpackList( + cnfParse.get(cnfSec, cnfName), cnfDefault, self.CNF_S_LST ) except ValueError as e: logger.error("Failed to load value from config file.") logger.error(str(e)) + return cnfDefault return cnfDefault def _checkNone(self, checkVal): - """Convert a string to a none type. + """Return a NoneType if the value correspomds to None, otherwise + return the value unchanged. """ if checkVal is None: return None @@ -961,10 +974,8 @@ class Config: self.hasEnchant = False logger.debug("Checking package 'pyenchant': Missing") - try: - self.hasAssistant = which("assistant") - except Exception: - self.hasAssistant = False + assistPath = shutil.which("assistant") + self.hasAssistant = assistPath is not None if self.hasAssistant: logger.debug("Checking executable 'assistant': Ok") else: diff --git a/tests/conftest.py b/tests/conftest.py index 0d66d0ea..ea9a92b3 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -73,6 +73,9 @@ def fncDir(tmpDir): def tmpConf(tmpDir): """Create a temporary novelWriter configuration object. """ + confFile = os.path.join(tmpDir, "novelwriter.conf") + if os.path.isfile(confFile): + os.unlink(confFile) theConf = Config() theConf.initConfig(tmpDir, tmpDir) theConf.setLastPath("") diff --git a/tests/reference/novelwriter.conf b/tests/reference/baseConfig_novelwriter.conf similarity index 100% rename from tests/reference/novelwriter.conf rename to tests/reference/baseConfig_novelwriter.conf diff --git a/tests/test_base_config.py b/tests/test_base_config.py new file mode 100644 index 00000000..f7aacc50 --- /dev/null +++ b/tests/test_base_config.py @@ -0,0 +1,505 @@ +# -*- coding: utf-8 -*- +"""novelWriter Config Class Tester +""" + +import pytest +import sys +import os +import configparser + +from shutil import copyfile + +from dummy import causeOSError +from tools import cmpFiles, readFile + +from nw.config import Config +from nw.constants import nwConst, nwFiles + +@pytest.mark.base +def testBaseConfig_Constructor(monkeypatch): + """Test config contructor. + """ + # Linux + monkeypatch.setattr("sys.platform", "linux") + tstConf = Config() + assert tstConf.osLinux is True + assert tstConf.osDarwin is False + assert tstConf.osWindows is False + assert tstConf.osUnknown is False + monkeypatch.undo() + + # macOS + monkeypatch.setattr("sys.platform", "darwin") + tstConf = Config() + assert tstConf.osLinux is False + assert tstConf.osDarwin is True + assert tstConf.osWindows is False + assert tstConf.osUnknown is False + monkeypatch.undo() + + # Windows + monkeypatch.setattr("sys.platform", "win32") + tstConf = Config() + assert tstConf.osLinux is False + assert tstConf.osDarwin is False + assert tstConf.osWindows is True + assert tstConf.osUnknown is False + monkeypatch.undo() + + # Cygwin + monkeypatch.setattr("sys.platform", "cygwin") + tstConf = Config() + assert tstConf.osLinux is False + assert tstConf.osDarwin is False + assert tstConf.osWindows is True + assert tstConf.osUnknown is False + monkeypatch.undo() + + # Other + monkeypatch.setattr("sys.platform", "some_ther_os") + tstConf = Config() + assert tstConf.osLinux is False + assert tstConf.osDarwin is False + assert tstConf.osWindows is False + assert tstConf.osUnknown is True + monkeypatch.undo() + +# END Test testBaseConfig_Constructor + +@pytest.mark.base +def testBaseConfig_Init(monkeypatch, tmpDir, fncDir, outDir, refDir): + """Test config intialisation. + """ + tstConf = Config() + + confFile = os.path.join(tmpDir, "novelwriter.conf") + testFile = os.path.join(outDir, "baseConfig_novelwriter.conf") + compFile = os.path.join(refDir, "baseConfig_novelwriter.conf") + + # Make sure we don't have any old conf file + if os.path.isfile(confFile): + os.unlink(confFile) + + # Let the config class figure out the path + monkeypatch.setattr("PyQt5.QtCore.QStandardPaths.writableLocation", lambda *args: fncDir) + tstConf.verQtValue = 50600 + tstConf.initConfig() + assert tstConf.confPath == os.path.join(fncDir, tstConf.appHandle) + assert tstConf.dataPath == os.path.join(fncDir, tstConf.appHandle) + assert not os.path.isfile(confFile) + tstConf.verQtValue = 50000 + tstConf.initConfig() + assert tstConf.confPath == os.path.join(fncDir, tstConf.appHandle) + assert tstConf.dataPath == os.path.join(fncDir, tstConf.appHandle) + assert not os.path.isfile(confFile) + monkeypatch.undo() + + # Fail to make folders + monkeypatch.setattr("os.mkdir", causeOSError) + + tstConfDir = os.path.join(fncDir, "test_conf") + tstConf.initConfig(confPath=tstConfDir, dataPath=tmpDir) + assert tstConf.confPath is None + assert tstConf.dataPath == tmpDir + assert not os.path.isfile(confFile) + + tstDataDir = os.path.join(fncDir, "test_data") + tstConf.initConfig(confPath=tmpDir, dataPath=tstDataDir) + assert tstConf.confPath == tmpDir + assert tstConf.dataPath is None + assert os.path.isfile(confFile) + os.unlink(confFile) + + monkeypatch.undo() + + # Test load/save with no path + tstConf.confPath = None + assert not tstConf.loadConfig() + assert not tstConf.saveConfig() + + # Run again and set the paths directly and correctly + # This should create a config file as well + monkeypatch.setattr("os.path.expanduser", lambda *args: "") + tstConf.spellTool = nwConst.SP_INTERNAL + tstConf.initConfig(confPath=tmpDir, dataPath=tmpDir) + assert tstConf.confPath == tmpDir + assert tstConf.dataPath == tmpDir + assert os.path.isfile(confFile) + + copyfile(confFile, testFile) + assert cmpFiles(testFile, compFile, [2, 9]) + monkeypatch.undo() + + # Load and save with OSError + monkeypatch.setattr("builtins.open", causeOSError) + + assert not tstConf.loadConfig() + assert tstConf.hasError is True + assert tstConf.errData != [] + assert tstConf.getErrData().startswith("Could not") + assert tstConf.hasError is False + assert tstConf.errData == [] + + assert not tstConf.saveConfig() + assert tstConf.hasError is True + assert tstConf.errData != [] + assert tstConf.getErrData().startswith("Could not") + assert tstConf.hasError is False + assert tstConf.errData == [] + + monkeypatch.undo() + + assert tstConf.loadConfig() + assert tstConf.saveConfig() + + copyfile(confFile, testFile) + assert cmpFiles(testFile, compFile, [2, 9]) + +# END Test testBaseConfig_Init + +@pytest.mark.base +def testBaseConfig_RecentCache(monkeypatch, tmpConf, tmpDir, fncDir): + """Test recent cache file. + """ + # Check failing + tmpConf.dataPath = None + assert not tmpConf.loadRecentCache() + assert not tmpConf.saveRecentCache() + tmpConf.dataPath = tmpDir + + # Add a couple of values + pathOne = os.path.join(fncDir, "projPathOne", nwFiles.PROJ_FILE) + pathTwo = os.path.join(fncDir, "projPathTwo", nwFiles.PROJ_FILE) + assert tmpConf.updateRecentCache(pathOne, "Proj One", 100, 1600002000) + assert tmpConf.updateRecentCache(pathTwo, "Proj Two", 200, 1600005600) + assert tmpConf.recentProj == { + pathOne: {"time": 1600002000, "title": "Proj One", "words": 100}, + pathTwo: {"time": 1600005600, "title": "Proj Two", "words": 200}, + } + + # Fail to Save + monkeypatch.setattr("builtins.open", causeOSError) + assert not tmpConf.saveRecentCache() + monkeypatch.undo() + + # Save Proper + cacheFile = os.path.join(tmpDir, nwFiles.RECENT_FILE) + assert tmpConf.saveRecentCache() + assert tmpConf.saveRecentCache() + assert os.path.isfile(cacheFile) + + # Fail to Load + monkeypatch.setattr("builtins.open", causeOSError) + tmpConf.recentProj = {} + assert not tmpConf.loadRecentCache() + assert tmpConf.recentProj == {} + monkeypatch.undo() + + # Load Proper + tmpConf.recentProj = {} + assert tmpConf.loadRecentCache() + assert tmpConf.recentProj == { + pathOne: {"time": 1600002000, "title": "Proj One", "words": 100}, + pathTwo: {"time": 1600005600, "title": "Proj Two", "words": 200}, + } + + # Remove Non-Existent Entry + assert not tmpConf.removeFromRecentCache("dummy") + assert tmpConf.recentProj == { + pathOne: {"time": 1600002000, "title": "Proj One", "words": 100}, + pathTwo: {"time": 1600005600, "title": "Proj Two", "words": 200}, + } + + # Remove Second Entry + assert tmpConf.removeFromRecentCache(pathTwo) + assert tmpConf.recentProj == { + pathOne: {"time": 1600002000, "title": "Proj One", "words": 100}, + } + +# END Test testBaseConfig_RecentCache + +@pytest.mark.base +def testBaseConfig_SetPath(tmpConf, tmpDir): + """Test path setters. + """ + # Conf Path + assert tmpConf.setConfPath(None) + assert not tmpConf.setConfPath(os.path.join("somewhere", "over", "the", "rainbow")) + assert tmpConf.setConfPath(os.path.join(tmpDir, "novelwriter.conf")) + assert tmpConf.confPath == tmpDir + assert tmpConf.confFile == "novelwriter.conf" + assert not tmpConf.confChanged + + # Data Path + assert tmpConf.setDataPath(None) + assert not tmpConf.setDataPath(os.path.join("somewhere", "over", "the", "rainbow")) + assert tmpConf.setDataPath(tmpDir) + assert tmpConf.dataPath == tmpDir + assert not tmpConf.confChanged + + # Last Path + assert tmpConf.setLastPath(None) + assert tmpConf.lastPath == "" + + assert tmpConf.setLastPath(os.path.join(tmpDir, "file.tmp")) + assert tmpConf.lastPath == tmpDir + + assert tmpConf.setLastPath("") + assert tmpConf.lastPath == "" + +# END Test testBaseConfig_SetPath + +@pytest.mark.base +def testBaseConfig_SettersGetters(tmpConf, tmpDir, outDir, refDir): + """Set various sizes and positions + """ + confFile = os.path.join(tmpDir, "novelwriter.conf") + testFile = os.path.join(outDir, "baseConfig_novelwriter.conf") + compFile = os.path.join(refDir, "baseConfig_novelwriter.conf") + + # GUI Scaling + # =========== + tmpConf.guiScale = 1.0 + assert tmpConf.pxInt(10) == 10 + assert tmpConf.pxInt(13) == 13 + assert tmpConf.rpxInt(10) == 10 + assert tmpConf.rpxInt(13) == 13 + + tmpConf.guiScale = 2.0 + assert tmpConf.pxInt(10) == 20 + assert tmpConf.pxInt(13) == 26 + assert tmpConf.rpxInt(10) == 5 + assert tmpConf.rpxInt(13) == 6 + + # Setter + Getter Combos + # ====================== + + # Window Size + tmpConf.guiScale = 1.0 + assert tmpConf.setWinSize(1205, 655) + assert not tmpConf.confChanged + + tmpConf.guiScale = 2.0 + assert tmpConf.setWinSize(70, 70) + assert tmpConf.getWinSize() == [70, 70] + assert tmpConf.winGeometry == [35, 35] + + tmpConf.guiScale = 1.0 + assert tmpConf.setWinSize(70, 70) + assert tmpConf.getWinSize() == [70, 70] + assert tmpConf.winGeometry == [70, 70] + + assert tmpConf.setWinSize(1200, 650) + + # Project Tree Columns + tmpConf.guiScale = 2.0 + assert tmpConf.setTreeColWidths([10, 20, 25]) + assert tmpConf.getTreeColWidths() == [10, 20, 24] + assert tmpConf.treeColWidth == [5, 10, 12] + + tmpConf.guiScale = 1.0 + assert tmpConf.setTreeColWidths([10, 20, 25]) + assert tmpConf.getTreeColWidths() == [10, 20, 25] + assert tmpConf.treeColWidth == [10, 20, 25] + + assert tmpConf.setTreeColWidths([200, 50, 30]) + + # Project Settings Tree Columns + tmpConf.guiScale = 2.0 + assert tmpConf.setProjColWidths([10, 20, 30]) + assert tmpConf.getProjColWidths() == [10, 20, 30] + assert tmpConf.projColWidth == [5, 10, 15] + + tmpConf.guiScale = 1.0 + assert tmpConf.setProjColWidths([10, 20, 30]) + assert tmpConf.getProjColWidths() == [10, 20, 30] + assert tmpConf.projColWidth == [10, 20, 30] + + assert tmpConf.setProjColWidths([200, 60, 140]) + + # Main Pane Splitter + tmpConf.guiScale = 2.0 + assert tmpConf.setMainPanePos([200, 700]) + assert tmpConf.getMainPanePos() == [200, 700] + assert tmpConf.mainPanePos == [100, 350] + + tmpConf.guiScale = 1.0 + assert tmpConf.setMainPanePos([200, 700]) + assert tmpConf.getMainPanePos() == [200, 700] + assert tmpConf.mainPanePos == [200, 700] + + assert tmpConf.setMainPanePos([300, 800]) + + # Doc Pane Splitter + tmpConf.guiScale = 2.0 + assert tmpConf.setDocPanePos([300, 300]) + assert tmpConf.getDocPanePos() == [300, 300] + assert tmpConf.docPanePos == [150, 150] + + tmpConf.guiScale = 1.0 + assert tmpConf.setDocPanePos([300, 300]) + assert tmpConf.getDocPanePos() == [300, 300] + assert tmpConf.docPanePos == [300, 300] + + assert tmpConf.setDocPanePos([400, 400]) + + # View Pane Splitter + tmpConf.guiScale = 2.0 + assert tmpConf.setViewPanePos([400, 250]) + assert tmpConf.getViewPanePos() == [400, 250] + assert tmpConf.viewPanePos == [200, 125] + + tmpConf.guiScale = 1.0 + assert tmpConf.setViewPanePos([400, 250]) + assert tmpConf.getViewPanePos() == [400, 250] + assert tmpConf.viewPanePos == [400, 250] + + assert tmpConf.setViewPanePos([500, 150]) + + # Outline Pane Splitter + tmpConf.guiScale = 2.0 + assert tmpConf.setOutlinePanePos([400, 250]) + assert tmpConf.getOutlinePanePos() == [400, 250] + assert tmpConf.outlnPanePos == [200, 125] + + tmpConf.guiScale = 1.0 + assert tmpConf.setOutlinePanePos([400, 250]) + assert tmpConf.getOutlinePanePos() == [400, 250] + assert tmpConf.outlnPanePos == [400, 250] + + assert tmpConf.setOutlinePanePos([500, 150]) + + # Getters Only + # ============ + tmpConf.guiScale = 1.0 + assert tmpConf.getTextWidth() == 600 + assert tmpConf.getTextMargin() == 40 + assert tmpConf.getTabWidth() == 40 + assert tmpConf.getFocusWidth() == 800 + + tmpConf.guiScale = 2.0 + assert tmpConf.getTextWidth() == 1200 + assert tmpConf.getTextMargin() == 80 + assert tmpConf.getTabWidth() == 80 + assert tmpConf.getFocusWidth() == 1600 + + # Flag Setters + # ============ + assert not tmpConf.setShowRefPanel(False) + assert not tmpConf.showRefPanel + assert tmpConf.setShowRefPanel(True) + + assert not tmpConf.setViewComments(False) + assert not tmpConf.viewComments + assert tmpConf.setViewComments(True) + + assert not tmpConf.setViewSynopsis(False) + assert not tmpConf.viewSynopsis + assert tmpConf.setViewSynopsis(True) + + # Check Final File + # ================ + + assert tmpConf.confChanged + assert tmpConf.saveConfig() + assert not tmpConf.confChanged + + copyfile(confFile, testFile) + assert cmpFiles(testFile, compFile, [2, 9]) + +# END Test testBaseConfig_SettersGetters + +@pytest.mark.base +def testBaseConfig_Internal(monkeypatch, tmpConf): + """Check internal functions. + """ + # Function _packList + assert tmpConf._packList(["A", 1, 2.0, None, False]) == "A, 1, 2.0, None, False" + + # Function _unpackList + assert tmpConf._unpackList("1, 2, 3", [0, 0, 0], tmpConf.CNF_I_LST) == [1, 2, 3] + assert tmpConf._unpackList("1, 2 ", [0, 0, 0], tmpConf.CNF_I_LST) == [1, 2, 0] + assert tmpConf._unpackList("A, B, C", [0, 0, 0], tmpConf.CNF_I_LST) == [0, 0, 0] + assert tmpConf._unpackList("1, 2, 3", ["X", "Y", "Z"], tmpConf.CNF_S_LST) == ["1", "2", "3"] + assert tmpConf._unpackList("A, B ", ["X", "Y", "Z"], tmpConf.CNF_S_LST) == ["A", "B", "Z"] + assert tmpConf._unpackList("A, B, C", ["X", "Y", "Z"], tmpConf.CNF_S_LST) == ["A", "B", "C"] + assert tmpConf._unpackList("A, B, C", ["X", "Y", "Z"], tmpConf.CNF_STR) == ["X", "Y", "Z"] + + # Function _parseLine + cnfParse = configparser.ConfigParser() + cnfParse.read_string( + "[Main]\n" + "val_string = dummy\n" + "val_int = 123\n" + "val_bool = True\n" + "val_list_string = A, B, C\n" + "val_list_int = 1, 2, 3\n" + ) + + assert tmpConf._parseLine( + cnfParse, "Main", "val_string", tmpConf.CNF_STR, "default" + ) == "dummy" + assert tmpConf._parseLine( + cnfParse, "Main", "nope", tmpConf.CNF_STR, "default" + ) == "default" + + assert tmpConf._parseLine( + cnfParse, "Main", "val_int", tmpConf.CNF_INT, "0" + ) == 123 + assert tmpConf._parseLine( + cnfParse, "Main", "nope", tmpConf.CNF_INT, 0 + ) == 0 + assert tmpConf._parseLine( + cnfParse, "Main", "val_string", tmpConf.CNF_INT, 0 + ) == 0 + + assert tmpConf._parseLine( + cnfParse, "Main", "val_bool", tmpConf.CNF_BOOL, False + ) is True + assert tmpConf._parseLine( + cnfParse, "Main", "nope", tmpConf.CNF_BOOL, False + ) is False + assert tmpConf._parseLine( + cnfParse, "Main", "val_string", tmpConf.CNF_BOOL, False + ) is False + + assert tmpConf._parseLine( + cnfParse, "Main", "val_list_string", tmpConf.CNF_S_LST, ["W", "X", "Y", "Z"] + ) == ["A", "B", "C", "Z"] + assert tmpConf._parseLine( + cnfParse, "Main", "nope", tmpConf.CNF_S_LST, ["W", "X", "Y", "Z"] + ) == ["W", "X", "Y", "Z"] + + assert tmpConf._parseLine( + cnfParse, "Main", "val_list_int", tmpConf.CNF_I_LST, [6, 7, 8, 9] + ) == [1, 2, 3, 9] + assert tmpConf._parseLine( + cnfParse, "Main", "nope", tmpConf.CNF_S_LST, [6, 7, 8, 9] + ) == [6, 7, 8, 9] + + # Function _checkNone + assert tmpConf._checkNone(None) is None + assert tmpConf._checkNone("None") is None + assert tmpConf._checkNone("stuff") == "stuff" + + # Function _checkOptionalPackages + # (Assumes enchant package exists ans is importable) + tmpConf._checkOptionalPackages() + assert tmpConf.hasEnchant is True + + monkeypatch.setitem(sys.modules, "enchant", None) + tmpConf._checkOptionalPackages() + assert tmpConf.hasEnchant is False + monkeypatch.undo() + + monkeypatch.setattr("shutil.which", lambda *args: "dummy") + tmpConf._checkOptionalPackages() + assert tmpConf.hasAssistant is True + monkeypatch.undo() + + monkeypatch.setattr("shutil.which", lambda *args: None) + tmpConf._checkOptionalPackages() + assert tmpConf.hasAssistant is False + monkeypatch.undo() + +# END Test testBaseConfig_Internal diff --git a/tests/test_config.py b/tests/test_config.py deleted file mode 100644 index 94ff5d1c..00000000 --- a/tests/test_config.py +++ /dev/null @@ -1,165 +0,0 @@ -# -*- coding: utf-8 -*- -"""novelWriter Config Class Tester -""" - -import pytest -import os - -from tools import cmpFiles - -@pytest.mark.core -def testConfigCore(tmpConf, tmpDir, refDir): - refConf = os.path.join(refDir, "novelwriter.conf") - testConf = os.path.join(tmpConf.confPath, "novelwriter.conf") - - assert tmpConf.confPath == tmpDir - assert tmpConf.saveConfig() - assert cmpFiles(testConf, refConf, [2, 9]) - assert not tmpConf.confChanged - - assert tmpConf.loadConfig() - assert not tmpConf.confChanged - -@pytest.mark.core -def testConfigSetConfPath(tmpConf, tmpDir): - assert tmpConf.setConfPath(None) - assert not tmpConf.setConfPath(os.path.join("somewhere", "over", "the", "rainbow")) - assert tmpConf.setConfPath(os.path.join(tmpDir, "novelwriter.conf")) - assert tmpConf.confPath == tmpDir - assert tmpConf.confFile == "novelwriter.conf" - assert not tmpConf.confChanged - -@pytest.mark.core -def testConfigSetDataPath(tmpConf, tmpDir): - assert tmpConf.setDataPath(None) - assert not tmpConf.setDataPath(os.path.join("somewhere", "over", "the", "rainbow")) - assert tmpConf.setDataPath(tmpDir) - assert tmpConf.dataPath == tmpDir - assert not tmpConf.confChanged - -@pytest.mark.core -def testConfigSetWinSize(tmpConf, tmpDir, refDir): - refConf = os.path.join(refDir, "novelwriter.conf") - testConf = os.path.join(tmpConf.confPath, "novelwriter.conf") - tmpConf.guiScale = 1.0 - - assert tmpConf.confPath == tmpDir - assert tmpConf.setWinSize(1205, 655) - assert not tmpConf.confChanged - assert tmpConf.setWinSize(70, 70) - assert tmpConf.confChanged - assert tmpConf.setWinSize(1200, 650) - assert tmpConf.saveConfig() - - assert cmpFiles(testConf, refConf, [2, 9]) - assert not tmpConf.confChanged - -@pytest.mark.core -def testConfigSetTreeColWidths(tmpConf, tmpDir, refDir): - refConf = os.path.join(refDir, "novelwriter.conf") - testConf = os.path.join(tmpConf.confPath, "novelwriter.conf") - - assert tmpConf.confPath == tmpDir - tmpConf.guiScale = 1.0 - - assert tmpConf.setTreeColWidths([10, 20, 25]) - assert tmpConf.treeColWidth == [10, 20, 25] - assert tmpConf.setTreeColWidths([200, 50, 30]) - - assert tmpConf.setProjColWidths([10, 20, 30]) - assert tmpConf.projColWidth == [10, 20, 30] - assert tmpConf.setProjColWidths([200, 60, 140]) - - assert tmpConf.confChanged - assert tmpConf.saveConfig() - - assert cmpFiles(testConf, refConf, [2, 9]) - assert not tmpConf.confChanged - -@pytest.mark.core -def testConfigSetPanePos(tmpConf, tmpDir, refDir): - refConf = os.path.join(refDir, "novelwriter.conf") - testConf = os.path.join(tmpConf.confPath, "novelwriter.conf") - - assert tmpConf.confPath == tmpDir - - tmpConf.guiScale = 2.0 - assert tmpConf.setMainPanePos([200, 700]) - assert tmpConf.mainPanePos == [100, 350] - assert tmpConf.getMainPanePos() == [200, 700] - - assert tmpConf.setDocPanePos([300, 300]) - assert tmpConf.docPanePos == [150, 150] - assert tmpConf.getDocPanePos() == [300, 300] - - assert tmpConf.setViewPanePos([400, 250]) - assert tmpConf.viewPanePos == [200, 125] - assert tmpConf.getViewPanePos() == [400, 250] - - assert tmpConf.setOutlinePanePos([400, 250]) - assert tmpConf.outlnPanePos == [200, 125] - assert tmpConf.getOutlinePanePos() == [400, 250] - - tmpConf.guiScale = 1.0 - assert tmpConf.setMainPanePos([300, 800]) - assert tmpConf.setDocPanePos([400, 400]) - assert tmpConf.setViewPanePos([500, 150]) - assert tmpConf.setOutlinePanePos([500, 150]) - - assert tmpConf.confChanged - assert tmpConf.saveConfig() - - assert cmpFiles(testConf, refConf, [2, 9]) - assert not tmpConf.confChanged - -@pytest.mark.core -def testConfigFlags(tmpConf, tmpDir, refDir): - refConf = os.path.join(refDir, "novelwriter.conf") - testConf = os.path.join(tmpConf.confPath, "novelwriter.conf") - - assert tmpConf.confPath == tmpDir - - assert not tmpConf.setShowRefPanel(False) - assert tmpConf.setShowRefPanel(True) - - assert not tmpConf.setViewComments(False) - assert not tmpConf.viewComments - assert tmpConf.setViewComments(True) - - assert not tmpConf.setViewSynopsis(False) - assert not tmpConf.viewSynopsis - assert tmpConf.setViewSynopsis(True) - - assert tmpConf.confChanged - assert tmpConf.saveConfig() - - assert cmpFiles(testConf, refConf, [2, 9]) - assert not tmpConf.confChanged - -@pytest.mark.core -def testTextSizes(tmpConf, tmpDir, refDir): - assert tmpConf.confPath == tmpDir - - tmpConf.guiScale = 2.0 - assert tmpConf.getTextWidth() == 1200 - assert tmpConf.getTextMargin() == 80 - assert tmpConf.getTabWidth() == 80 - assert tmpConf.getFocusWidth() == 1600 - tmpConf.guiScale = 1.0 - - assert not tmpConf.confChanged - -@pytest.mark.core -def testConfigErrors(tmpConf): - nonPath = os.path.join("somewhere", "over", "the", "rainbow") - assert tmpConf.initConfig(nonPath, nonPath) - assert tmpConf.hasError - assert not tmpConf.loadConfig() - assert not tmpConf.saveConfig() - assert not tmpConf.loadRecentCache() - assert len(tmpConf.getErrData()) > 0 - -@pytest.mark.core -def testConfigInternals(tmpConf): - assert tmpConf._checkNone(None) is None - assert tmpConf._checkNone("None") is None