Add test coverage of GUI theme
This commit is contained in:
@@ -247,7 +247,7 @@ class GuiTheme:
|
|||||||
self.iconCache.updateTheme(self.themeIcons)
|
self.iconCache.updateTheme(self.themeIcons)
|
||||||
|
|
||||||
# CSS File
|
# CSS File
|
||||||
cssData = readTextFile(themeFile[:-5]+".css")
|
cssData = readTextFile(themeFile[:-5]+".qss")
|
||||||
if cssData:
|
if cssData:
|
||||||
qApp.setStyleSheet(cssData)
|
qApp.setStyleSheet(cssData)
|
||||||
|
|
||||||
|
|||||||
+147
-125
@@ -19,157 +19,179 @@ You should have received a copy of the GNU General Public License
|
|||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
import pytest
|
import pytest
|
||||||
import novelwriter
|
|
||||||
|
|
||||||
from PyQt5.QtGui import QColor, QPixmap, QIcon
|
from configparser import ConfigParser
|
||||||
from PyQt5.QtWidgets import QMessageBox
|
|
||||||
|
|
||||||
keyDelay = 2
|
from mock import causeOSError
|
||||||
typeDelay = 1
|
from tools import writeFile
|
||||||
stepDelay = 20
|
|
||||||
|
from PyQt5.QtGui import QPalette
|
||||||
|
from PyQt5.QtWidgets import QApplication, QMessageBox
|
||||||
|
|
||||||
|
from novelwriter.config import Config
|
||||||
|
from novelwriter.gui.theme import GuiTheme
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.gui
|
@pytest.mark.gui
|
||||||
def testGuiTheme_Main(qtbot, monkeypatch, nwMinimal, tmpDir):
|
def testGuiTheme_Main(qtbot, monkeypatch, nwGUI, fncDir):
|
||||||
"""Test the theme and icon classes.
|
"""Test the theme class init.
|
||||||
"""
|
"""
|
||||||
# Block message box
|
|
||||||
monkeypatch.setattr(QMessageBox, "information", lambda *a: QMessageBox.Yes)
|
monkeypatch.setattr(QMessageBox, "information", lambda *a: QMessageBox.Yes)
|
||||||
monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)
|
monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)
|
||||||
monkeypatch.setattr(QMessageBox, "warning", lambda *a: QMessageBox.Yes)
|
monkeypatch.setattr(QMessageBox, "warning", lambda *a: QMessageBox.Yes)
|
||||||
|
|
||||||
nwGUI = novelwriter.main(
|
mainTheme: GuiTheme = nwGUI.mainTheme
|
||||||
["--testmode", "--config=%s" % nwMinimal, "--data=%s" % tmpDir, nwMinimal]
|
mainConf: Config = nwGUI.mainConf
|
||||||
)
|
|
||||||
qtbot.addWidget(nwGUI)
|
|
||||||
nwGUI.show()
|
|
||||||
qtbot.wait(stepDelay)
|
|
||||||
|
|
||||||
# Change Settings
|
# Methods
|
||||||
assert novelwriter.CONFIG.confPath == nwMinimal
|
# =======
|
||||||
novelwriter.CONFIG.guiTheme = "default_dark"
|
|
||||||
novelwriter.CONFIG.guiSyntax = "tomorrow_night_eighties"
|
|
||||||
novelwriter.CONFIG.guiFont = "Cantarell"
|
|
||||||
novelwriter.CONFIG.guiFontSize = 11
|
|
||||||
novelwriter.CONFIG.confChanged = True
|
|
||||||
assert novelwriter.CONFIG.saveConfig()
|
|
||||||
|
|
||||||
nwGUI.closeMain()
|
mSize = mainTheme.getTextWidth("m")
|
||||||
nwGUI.close()
|
assert mSize > 0
|
||||||
del nwGUI
|
assert mainTheme.getTextWidth("m", mainTheme.guiFont) == mSize
|
||||||
|
|
||||||
# Re-open
|
# Init Fonts
|
||||||
assert novelwriter.CONFIG.confPath == nwMinimal
|
# ==========
|
||||||
nwGUI = novelwriter.main(
|
|
||||||
["--testmode", "--config=%s" % nwMinimal, "--data=%s" % tmpDir, nwMinimal]
|
|
||||||
)
|
|
||||||
assert nwGUI.mainConf.confPath == nwMinimal
|
|
||||||
qtbot.addWidget(nwGUI)
|
|
||||||
nwGUI.show()
|
|
||||||
qtbot.wait(stepDelay)
|
|
||||||
|
|
||||||
assert novelwriter.CONFIG.guiTheme == "default_dark"
|
# The defaults should be set
|
||||||
assert novelwriter.CONFIG.guiSyntax == "tomorrow_night_eighties"
|
defaultFont = mainConf.guiFont
|
||||||
assert novelwriter.CONFIG.guiFont != ""
|
defaultSize = mainConf.guiFontSize
|
||||||
assert novelwriter.CONFIG.guiFontSize > 0
|
|
||||||
|
|
||||||
# Check GUI Colours
|
# CHange them to nonsense values
|
||||||
thePalette = nwGUI.palette()
|
mainConf.guiFont = "notafont"
|
||||||
assert thePalette.window().color() == QColor(54, 54, 54)
|
mainConf.guiFontSize = 99
|
||||||
assert thePalette.windowText().color() == QColor(174, 174, 174)
|
|
||||||
assert thePalette.base().color() == QColor(62, 62, 62)
|
|
||||||
assert thePalette.alternateBase().color() == QColor(78, 78, 78)
|
|
||||||
assert thePalette.text().color() == QColor(174, 174, 174)
|
|
||||||
assert thePalette.toolTipBase().color() == QColor(255, 255, 192)
|
|
||||||
assert thePalette.toolTipText().color() == QColor(21, 21, 13)
|
|
||||||
assert thePalette.button().color() == QColor(62, 62, 62)
|
|
||||||
assert thePalette.buttonText().color() == QColor(174, 174, 174)
|
|
||||||
assert thePalette.brightText().color() == QColor(174, 174, 174)
|
|
||||||
assert thePalette.highlight().color() == QColor(44, 152, 247)
|
|
||||||
assert thePalette.highlightedText().color() == QColor(255, 255, 255)
|
|
||||||
assert thePalette.link().color() == QColor(44, 152, 247)
|
|
||||||
assert thePalette.linkVisited().color() == QColor(44, 152, 247)
|
|
||||||
|
|
||||||
assert nwGUI.mainTheme.statNone == [150, 152, 150]
|
# Let the theme class set them back to default
|
||||||
assert nwGUI.mainTheme.statSaved == [39, 135, 78]
|
mainTheme._setGuiFont()
|
||||||
assert nwGUI.mainTheme.statUnsaved == [138, 32, 32]
|
assert mainConf.guiFont == defaultFont
|
||||||
|
assert mainConf.guiFontSize == defaultSize
|
||||||
|
|
||||||
# Check Syntax Colours
|
# A second call should just restore the defaults again
|
||||||
assert nwGUI.mainTheme.colBack == [45, 45, 45]
|
mainTheme._setGuiFont()
|
||||||
assert nwGUI.mainTheme.colText == [204, 204, 204]
|
assert mainConf.guiFont == defaultFont
|
||||||
assert nwGUI.mainTheme.colLink == [102, 153, 204]
|
assert mainConf.guiFontSize == defaultSize
|
||||||
assert nwGUI.mainTheme.colHead == [102, 153, 204]
|
|
||||||
assert nwGUI.mainTheme.colHeadH == [102, 153, 204]
|
|
||||||
assert nwGUI.mainTheme.colEmph == [249, 145, 57]
|
|
||||||
assert nwGUI.mainTheme.colDialN == [242, 119, 122]
|
|
||||||
assert nwGUI.mainTheme.colDialD == [153, 204, 153]
|
|
||||||
assert nwGUI.mainTheme.colDialS == [255, 204, 102]
|
|
||||||
assert nwGUI.mainTheme.colHidden == [153, 153, 153]
|
|
||||||
assert nwGUI.mainTheme.colKey == [242, 119, 122]
|
|
||||||
assert nwGUI.mainTheme.colVal == [204, 153, 204]
|
|
||||||
assert nwGUI.mainTheme.colSpell == [242, 119, 122]
|
|
||||||
assert nwGUI.mainTheme.colError == [153, 204, 153]
|
|
||||||
assert nwGUI.mainTheme.colRepTag == [102, 204, 204]
|
|
||||||
assert nwGUI.mainTheme.colMod == [249, 145, 57]
|
|
||||||
|
|
||||||
# Test Icon class
|
# Scan for Themes
|
||||||
iconCache = nwGUI.mainTheme.iconCache
|
# ===============
|
||||||
assert iconCache.updateTheme("invalid") is False
|
|
||||||
|
|
||||||
# Ask for a non-existent key
|
assert mainTheme._listConf({}, "not_a_path") is False
|
||||||
anImg = iconCache.loadDecoration("nonsense", 20, 20)
|
|
||||||
assert isinstance(anImg, QPixmap)
|
|
||||||
assert anImg.isNull()
|
|
||||||
|
|
||||||
# Add a non-existent file and request it
|
themeOne = os.path.join(fncDir, "themes", "themeone.conf")
|
||||||
iconCache.IMAGE_MAP["nonsense"] = "nofile.jpg"
|
themeTwo = os.path.join(fncDir, "themes", "themetwo.conf")
|
||||||
anImg = iconCache.loadDecoration("nonsense", 20, 20)
|
writeFile(themeOne, "# Stuff")
|
||||||
assert isinstance(anImg, QPixmap)
|
writeFile(themeTwo, "# Stuff")
|
||||||
assert anImg.isNull()
|
|
||||||
|
|
||||||
# Get a real image, with different size parameters
|
result = {}
|
||||||
anImg = iconCache.loadDecoration("wiz-back", 20, None)
|
assert mainTheme._listConf(result, os.path.join(fncDir, "themes")) is True
|
||||||
assert isinstance(anImg, QPixmap)
|
assert result["themeone"] == themeOne
|
||||||
assert not anImg.isNull()
|
assert result["themetwo"] == themeTwo
|
||||||
assert anImg.width() == 20
|
|
||||||
assert anImg.height() >= 56
|
|
||||||
|
|
||||||
anImg = iconCache.loadDecoration("wiz-back", None, 70)
|
# Parse Colours
|
||||||
assert isinstance(anImg, QPixmap)
|
# =============
|
||||||
assert not anImg.isNull()
|
|
||||||
assert anImg.height() == 70
|
|
||||||
assert anImg.width() >= 24
|
|
||||||
|
|
||||||
anImg = iconCache.loadDecoration("wiz-back", 30, 70)
|
parser = ConfigParser()
|
||||||
assert isinstance(anImg, QPixmap)
|
parser["Palette"] = {
|
||||||
assert not anImg.isNull()
|
"colour1": "100, 150, 200",
|
||||||
assert anImg.height() == 70
|
"colour2": "100, 150, 200, 250",
|
||||||
assert anImg.width() == 30
|
"colour3": "250, 250",
|
||||||
|
"colour4": "-10, 127, 300",
|
||||||
|
}
|
||||||
|
|
||||||
anImg = iconCache.loadDecoration("wiz-back", None, None)
|
# Test the parser for several valid and invalid values
|
||||||
assert isinstance(anImg, QPixmap)
|
assert mainTheme._parseColour(parser, "Palette", "colour1") == [100, 150, 200]
|
||||||
assert not anImg.isNull()
|
assert mainTheme._parseColour(parser, "Palette", "colour2") == [100, 150, 200]
|
||||||
assert anImg.height() >= 1500
|
assert mainTheme._parseColour(parser, "Palette", "colour3") == [0, 0, 0]
|
||||||
assert anImg.width() >= 500
|
assert mainTheme._parseColour(parser, "Palette", "colour4") == [0, 127, 255]
|
||||||
|
assert mainTheme._parseColour(parser, "Palette", "colour5") == [0, 0, 0]
|
||||||
|
|
||||||
# Load icons
|
# The palette should load with the parsed values
|
||||||
anIcon = iconCache.getIcon("nonsense")
|
mainTheme._setPalette(parser, "Palette", "colour1", QPalette.Window)
|
||||||
assert isinstance(anIcon, QIcon)
|
assert mainTheme._guiPalette.color(QPalette.Window).getRgb() == (100, 150, 200, 255)
|
||||||
assert anIcon.isNull()
|
mainTheme._setPalette(parser, "Palette", "colour2", QPalette.Window)
|
||||||
|
assert mainTheme._guiPalette.color(QPalette.Window).getRgb() == (100, 150, 200, 255)
|
||||||
|
mainTheme._setPalette(parser, "Palette", "colour3", QPalette.Window)
|
||||||
|
assert mainTheme._guiPalette.color(QPalette.Window).getRgb() == (0, 0, 0, 255)
|
||||||
|
mainTheme._setPalette(parser, "Palette", "colour4", QPalette.Window)
|
||||||
|
assert mainTheme._guiPalette.color(QPalette.Window).getRgb() == (0, 127, 255, 255)
|
||||||
|
mainTheme._setPalette(parser, "Palette", "colour5", QPalette.Window)
|
||||||
|
assert mainTheme._guiPalette.color(QPalette.Window).getRgb() == (0, 0, 0, 255)
|
||||||
|
|
||||||
anIcon = iconCache.getIcon("novelwriter")
|
# qtbot.stop()
|
||||||
assert isinstance(anIcon, QIcon)
|
|
||||||
assert not anIcon.isNull()
|
|
||||||
|
|
||||||
# Check return empty icon if file not found
|
|
||||||
iconCache.ICON_KEYS.add("testicon3")
|
|
||||||
anIcon = iconCache.getIcon("testicon3")
|
|
||||||
assert isinstance(anIcon, QIcon)
|
|
||||||
assert anIcon.isNull()
|
|
||||||
|
|
||||||
# qtbot.stopForInteraction()
|
|
||||||
nwGUI.closeMain()
|
|
||||||
nwGUI.close()
|
|
||||||
|
|
||||||
# END Test testGuiTheme_Main
|
# END Test testGuiTheme_Main
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.gui
|
||||||
|
def testGuiTheme_Themes(qtbot, monkeypatch, nwGUI, fncDir):
|
||||||
|
"""Test the theme class init.
|
||||||
|
"""
|
||||||
|
monkeypatch.setattr(QMessageBox, "information", lambda *a: QMessageBox.Yes)
|
||||||
|
monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)
|
||||||
|
monkeypatch.setattr(QMessageBox, "warning", lambda *a: QMessageBox.Yes)
|
||||||
|
|
||||||
|
mainTheme: GuiTheme = nwGUI.mainTheme
|
||||||
|
mainConf: Config = nwGUI.mainConf
|
||||||
|
|
||||||
|
# List Themes
|
||||||
|
# ===========
|
||||||
|
|
||||||
|
shutil.copy(
|
||||||
|
os.path.join(mainConf.assetPath, "themes", "default_dark.conf"),
|
||||||
|
os.path.join(fncDir, "themes")
|
||||||
|
)
|
||||||
|
shutil.copy(
|
||||||
|
os.path.join(mainConf.assetPath, "themes", "default.conf"),
|
||||||
|
os.path.join(fncDir, "themes")
|
||||||
|
)
|
||||||
|
writeFile(os.path.join(fncDir, "themes", "default.qss"), "/* Stuff */")
|
||||||
|
|
||||||
|
# Load the theme info
|
||||||
|
themesList = mainTheme.listThemes()
|
||||||
|
assert themesList[0] == ("default_dark", "Default Dark Theme")
|
||||||
|
assert themesList[1] == ("default", "Default Theme")
|
||||||
|
|
||||||
|
# A second call should returned the cached list
|
||||||
|
assert mainTheme.listThemes() == mainTheme._themeList
|
||||||
|
|
||||||
|
# Check handling of broken theme settings
|
||||||
|
mainConf.guiTheme = "not_a_theme"
|
||||||
|
assert mainTheme.loadTheme() is False
|
||||||
|
|
||||||
|
# Check handling of unreadable file
|
||||||
|
mainConf.guiTheme = "default"
|
||||||
|
with monkeypatch.context() as mp:
|
||||||
|
mp.setattr("builtins.open", causeOSError)
|
||||||
|
assert mainTheme.loadTheme() is False
|
||||||
|
|
||||||
|
# Load Default Theme
|
||||||
|
# ==================
|
||||||
|
|
||||||
|
# Set a mock colour for the window background
|
||||||
|
mainTheme._guiPalette.color(QPalette.Window).setRgb(0, 0, 0, 0)
|
||||||
|
|
||||||
|
# Load the default theme
|
||||||
|
mainConf.guiTheme = "default"
|
||||||
|
assert mainTheme.loadTheme() is True
|
||||||
|
|
||||||
|
# This should load a standard palette
|
||||||
|
wCol = QApplication.style().standardPalette().color(QPalette.Window).getRgb()
|
||||||
|
assert mainTheme._guiPalette.color(QPalette.Window).getRgb() == wCol
|
||||||
|
|
||||||
|
# Load Default Dark Theme
|
||||||
|
# =======================
|
||||||
|
|
||||||
|
mainConf.guiTheme = "default_dark"
|
||||||
|
assert mainTheme.loadTheme() is True
|
||||||
|
|
||||||
|
# Check a few values
|
||||||
|
assert mainTheme._guiPalette.color(QPalette.Window).getRgb() == (54, 54, 54, 255)
|
||||||
|
assert mainTheme._guiPalette.color(QPalette.WindowText).getRgb() == (174, 174, 174, 255)
|
||||||
|
assert mainTheme._guiPalette.color(QPalette.Base).getRgb() == (62, 62, 62, 255)
|
||||||
|
assert mainTheme._guiPalette.color(QPalette.AlternateBase).getRgb() == (78, 78, 78, 255)
|
||||||
|
|
||||||
|
# qtbot.stop()
|
||||||
|
|
||||||
|
# END Test testGuiTheme_Themes
|
||||||
|
|||||||
Reference in New Issue
Block a user