""" novelWriter – Test Suite Tools ============================== This file is a part of novelWriter Copyright (C) 2019 Veronica Berglyd Olsen and novelWriter contributors 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 . """ # noqa from __future__ import annotations import shutil import xml.etree.ElementTree as ET from datetime import datetime from pathlib import Path from PyQt6.QtWidgets import QDialog, QVBoxLayout, QWidget from novelwriter import logger XML_IGNORE = (" bool: """Compare two files, with optional line ignore.""" if ignoreLines is None: ignoreLines = [] try: with open(fileOne, mode="r", encoding="utf-8") as fo: txtOne = fo.read().strip().splitlines() except Exception as exc: print(str(exc)) return False try: with open(fileTwo, mode="r", encoding="utf-8") as fo: txtTwo = fo.read().strip().splitlines() except Exception as exc: print(str(exc)) return False if len(txtOne) != len(txtTwo): print("Files are not the same length") return False diffFound = False for n in range(len(txtOne)): lnOne = txtOne[n].strip() lnTwo = txtTwo[n].strip() if n+1 in ignoreLines: print(f"Ignoring line {n+1}") continue if ignoreStart is not None: if lnOne.startswith(ignoreStart): print(f"Ignoring line {n+1}") continue if lnOne != lnTwo: print(f"Diff on line {n+1}:") print(f" << '{lnOne}'") print(f" >> '{lnTwo}'") diffFound = True return not diffFound def xmlToText(xElem): """Get the text content of an XML element.""" text = ET.tostring(xElem, encoding="utf-8", xml_declaration=False).decode() bits = text.partition(">") node = bits[0].partition(" ") rest = " ".join(x for x in node[2].split() if not x.startswith("xmlns")).replace("/", " /") return f"{node[0]}{rest}{bits[1]}{bits[2]}" def readFile(fileName: str | Path): """Return the content of a file as a string.""" with open(fileName, mode="r", encoding="utf-8") as inFile: return inFile.read() def writeFile(fileName: str | Path, fileData: str): """Write the contents of a string to a file.""" with open(fileName, mode="w", encoding="utf-8") as outFile: outFile.write(fileData) def cleanProject(path: str | Path): """Delete all generated files in a project.""" path = Path(path) cacheDir = path / "cache" if cacheDir.is_dir(): shutil.rmtree(cacheDir) metaDir = path / "meta" if metaDir.is_dir(): shutil.rmtree(metaDir) bakFile = path / "nwProject.bak" if bakFile.is_file(): bakFile.unlink() tocFile = path / "ToC.txt" if tocFile.is_file(): tocFile.unlink() def clearLogHandlers(): """Clear all log handlers.""" for handler in logger.handlers: logger.removeHandler(handler) def buildTestProject(obj: object, projPath: Path) -> None: """Build a standard test project in projPath using the project object as the parent. """ from novelwriter.core.project import NWProject from novelwriter.enum import nwItemClass from novelwriter.guimain import GuiMain if isinstance(obj, NWProject): nwGUI = None project = obj elif isinstance(obj, GuiMain): from novelwriter import SHARED nwGUI = obj project = SHARED.project else: return project.storage.createNewProject(projPath) project.setDefaultStatusImport() project.data.setUuid("d0f3fe10-c6e6-4310-8bfd-181eb4224eed") project.data.setName("New Project") project.data.setAuthor("Jane Doe") # Creating a minimal project with a few root folders and a # single chapter folder with a single file. nrHandle = project.newRoot(nwItemClass.NOVEL) project.newRoot(nwItemClass.PLOT) project.newRoot(nwItemClass.CHARACTER) project.newRoot(nwItemClass.WORLD) tdHandle = project.newFile("Title Page", nrHandle) cfHandle = project.newFolder("New Folder", nrHandle) or "" cdHandle = project.newFile("New Chapter", cfHandle) sdHandle = project.newFile("New Scene", cfHandle) aDoc = project.storage.getDocument(tdHandle) aDoc.writeDocument("#! New Novel\n\n>> By Jane Doe <<\n") project.index.reIndexHandle(tdHandle) aDoc = project.storage.getDocument(cdHandle) aDoc.writeDocument("## {0}\n\n".format(project.tr("New Chapter"))) project.index.reIndexHandle(cdHandle) aDoc = project.storage.getDocument(sdHandle) aDoc.writeDocument("### {0}\n\n".format(project.tr("New Scene"))) project.index.reIndexHandle(sdHandle) project.session.startSession() project.setProjectChanged(True) project.saveProject(autoSave=True) project._valid = True project._tree._ready = True if nwGUI is not None: nwGUI.projView.openProjectTasks() nwGUI.novelView.openProjectTasks() return class SimpleDialog(QDialog): def __init__(self, widget: QWidget | None = None) -> None: super().__init__() self._widget = widget layout = QVBoxLayout() layout.setContentsMargins(40, 40, 40, 40) self.setLayout(layout) if widget: layout.addWidget(widget) @property def widget(self) -> QWidget | None: return self._widget def addWidget(self, widget: QWidget) -> None: self._widget = widget layout = self.layout() assert layout is not None layout.addWidget(widget)