Merge branch 'main' into multi_root

This commit is contained in:
Veronica Berglyd Olsen
2022-04-16 18:49:46 +02:00
40 changed files with 1461 additions and 801 deletions
+18 -1
View File
@@ -24,6 +24,8 @@ import sys
import pytest
import shutil
from dataclasses import dataclass
from mock import MockGuiMain
from tools import cleanProject
@@ -249,9 +251,24 @@ def nwOldProj(tmpDir):
##
# Useful Fixtures
# Data Fixtures
##
@dataclass
class TestConst:
statusKeys = ["sa3b179", "s1c8031", "s06671a", "sbdd640"]
importKeys = ["i466852", "i3eb13b", "i392456", "i23b8c1"]
@pytest.fixture(scope="session")
def constData():
"""A named tuple of known contstant values. For those that depend on
the random number generator, they assume the seed is 42.
"""
return TestConst()
@pytest.fixture(scope="session")
def ipsumText():
"""Return five paragraphs of Lorem Ipsum text.
+32 -32
View File
@@ -1,12 +1,12 @@
<?xml version='1.0' encoding='utf-8'?>
<novelWriterXML appVersion="1.7-alpha0" hexVersion="0x010700a0" fileVersion="1.4" timeStamp="2022-04-03 21:36:12">
<novelWriterXML appVersion="1.7-alpha0" hexVersion="0x010700a0" fileVersion="1.4" timeStamp="2022-04-16 14:19:39">
<project>
<name>Lorem Ipsum</name>
<title>Lorem Ipsum</title>
<author>lipsum.com</author>
<saveCount>23</saveCount>
<saveCount>24</saveCount>
<autoCount>24</autoCount>
<editTime>1854</editTime>
<editTime>1856</editTime>
</project>
<settings>
<doBackup>False</doBackup>
@@ -31,102 +31,102 @@
<section></section>
</titleFormat>
<status>
<entry red="100" green="100" blue="100">New</entry>
<entry red="200" green="50" blue="0">Note</entry>
<entry red="200" green="150" blue="0">Draft</entry>
<entry red="50" green="200" blue="0">Finished</entry>
<entry key="sbaa94f" count="3" red="100" green="100" blue="100">New</entry>
<entry key="s27bf7c" count="0" red="200" green="50" blue="0">Note</entry>
<entry key="s92a87b" count="5" red="200" green="150" blue="0">Draft</entry>
<entry key="sedd043" count="7" red="50" green="200" blue="0">Finished</entry>
</status>
<importance>
<entry red="100" green="100" blue="100">New</entry>
<entry red="200" green="50" blue="0">Minor</entry>
<entry red="200" green="150" blue="0">Major</entry>
<entry red="50" green="200" blue="0">Main</entry>
<entry key="i613591" count="6" red="100" green="100" blue="100">New</entry>
<entry key="i560cbf" count="0" red="200" green="50" blue="0">Minor</entry>
<entry key="i37861c" count="0" red="200" green="150" blue="0">Major</entry>
<entry key="id6b1d0" count="0" red="50" green="200" blue="0">Main</entry>
</importance>
</settings>
<content count="21">
<item handle="b3643d0f92e32" parent="None" root="b3643d0f92e32" order="0" type="ROOT" class="NOVEL">
<meta expanded="True"/>
<name status="New" import="New">Novel</name>
<name status="sbaa94f" import="i613591">Novel</name>
</item>
<item handle="7a992350f3eb6" parent="b3643d0f92e32" root="b3643d0f92e32" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="230" wordCount="40" paraCount="3" cursorPos="148"/>
<name status="Finished" import="New" exported="True">Lorem Ipsum</name>
<name status="sedd043" import="i613591" exported="True">Lorem Ipsum</name>
</item>
<item handle="8c58a65414c23" parent="b3643d0f92e32" root="b3643d0f92e32" order="1" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="1058" wordCount="176" paraCount="2" cursorPos="43"/>
<name status="Finished" import="New" exported="True">Front Matter</name>
<name status="sedd043" import="i613591" exported="True">Front Matter</name>
</item>
<item handle="88d59a277361b" parent="b3643d0f92e32" root="b3643d0f92e32" order="2" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="584" wordCount="92" paraCount="1" cursorPos="4"/>
<name status="Draft" import="New" exported="True">Prologue</name>
<name status="s92a87b" import="i613591" exported="True">Prologue</name>
</item>
<item handle="db7e733775d4d" parent="b3643d0f92e32" root="b3643d0f92e32" order="3" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="35" wordCount="6" paraCount="1" cursorPos="42"/>
<name status="New" import="New" exported="True">Act One</name>
<name status="sbaa94f" import="i613591" exported="True">Act One</name>
</item>
<item handle="45e6b01ca35c1" parent="b3643d0f92e32" root="b3643d0f92e32" order="4" type="FOLDER" class="NOVEL">
<meta expanded="True"/>
<name status="Draft" import="New">Chapter One</name>
<name status="s92a87b" import="i613591">Chapter One</name>
</item>
<item handle="fb609cd8319dc" parent="45e6b01ca35c1" root="b3643d0f92e32" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="419" wordCount="67" paraCount="1" cursorPos="56"/>
<name status="Draft" import="New" exported="True">Chapter One</name>
<name status="s92a87b" import="i613591" exported="True">Chapter One</name>
</item>
<item handle="88243afbe5ed8" parent="45e6b01ca35c1" root="b3643d0f92e32" order="1" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="2758" wordCount="404" paraCount="4" cursorPos="1528"/>
<name status="Finished" import="New" exported="True">Scene One</name>
<name status="sedd043" import="i613591" exported="True">Scene One</name>
</item>
<item handle="f96ec11c6a3da" parent="45e6b01ca35c1" root="b3643d0f92e32" order="2" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="4043" wordCount="600" paraCount="6" cursorPos="2335"/>
<name status="Finished" import="New" exported="True">Scene Two</name>
<name status="sedd043" import="i613591" exported="True">Scene Two</name>
</item>
<item handle="846352075de7d" parent="b3643d0f92e32" root="b3643d0f92e32" order="5" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="631" wordCount="109" paraCount="3" cursorPos="376"/>
<name status="New" import="New" exported="False">Interlude</name>
<name status="sbaa94f" import="i613591" exported="False">Interlude</name>
</item>
<item handle="6bd935d2490cd" parent="b3643d0f92e32" root="b3643d0f92e32" order="6" type="FOLDER" class="NOVEL">
<meta expanded="True"/>
<name status="Draft" import="New">Chapter Two</name>
<name status="s92a87b" import="i613591">Chapter Two</name>
</item>
<item handle="441420a886d82" parent="6bd935d2490cd" root="b3643d0f92e32" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="477" wordCount="70" paraCount="1" cursorPos="56"/>
<name status="Draft" import="New" exported="True">Chapter Two</name>
<name status="s92a87b" import="i613591" exported="True">Chapter Two</name>
</item>
<item handle="eb103bc70c90c" parent="6bd935d2490cd" root="b3643d0f92e32" order="1" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="3006" wordCount="439" paraCount="4" cursorPos="57"/>
<name status="Finished" import="New" exported="True">Scene Three</name>
<name status="sedd043" import="i613591" exported="True">Scene Three</name>
</item>
<item handle="f8c0562e50f1b" parent="6bd935d2490cd" root="b3643d0f92e32" order="2" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="3839" wordCount="563" paraCount="6" cursorPos="56"/>
<name status="Finished" import="New" exported="True">Scene Four</name>
<name status="sedd043" import="i613591" exported="True">Scene Four</name>
</item>
<item handle="47666c91c7ccf" parent="6bd935d2490cd" root="b3643d0f92e32" order="3" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="3644" wordCount="543" paraCount="5" cursorPos="351"/>
<name status="Finished" import="New" exported="True">Scene Five</name>
<name status="sedd043" import="i613591" exported="True">Scene Five</name>
</item>
<item handle="67a8707f2f249" parent="None" root="67a8707f2f249" order="1" type="ROOT" class="CHARACTER">
<meta expanded="True"/>
<name status="New" import="New">Characters</name>
<name status="sbaa94f" import="i613591">Characters</name>
</item>
<item handle="4c4f28287af27" parent="67a8707f2f249" root="67a8707f2f249" order="0" type="FILE" class="CHARACTER" layout="NOTE">
<meta charCount="1864" wordCount="284" paraCount="3" cursorPos="1883"/>
<name status="New" import="New" exported="True">Mr. Nobody</name>
<name status="sbaa94f" import="i613591" exported="True">Mr. Nobody</name>
</item>
<item handle="6c6afb1247750" parent="None" root="6c6afb1247750" order="2" type="ROOT" class="PLOT">
<meta expanded="True"/>
<name status="New" import="New">Plot</name>
<name status="sbaa94f" import="i613591">Plot</name>
</item>
<item handle="2426c6f0ca922" parent="6c6afb1247750" root="6c6afb1247750" order="0" type="FILE" class="PLOT" layout="NOTE">
<meta charCount="1369" wordCount="195" paraCount="2" cursorPos="1387"/>
<name status="New" import="New" exported="True">Main</name>
<name status="sbaa94f" import="i613591" exported="True">Main</name>
</item>
<item handle="60bdf227455cc" parent="None" root="60bdf227455cc" order="3" type="ROOT" class="WORLD">
<meta expanded="True"/>
<name status="New" import="New">World</name>
<name status="sbaa94f" import="i613591">World</name>
</item>
<item handle="04468803b92e1" parent="60bdf227455cc" root="60bdf227455cc" order="0" type="FILE" class="WORLD" layout="NOTE">
<meta charCount="1770" wordCount="259" paraCount="3" cursorPos="1792"/>
<name status="New" import="New" exported="True">Ancient Europe</name>
<name status="sbaa94f" import="i613591" exported="True">Ancient Europe</name>
</item>
</content>
</novelWriterXML>
+19 -19
View File
@@ -1,13 +1,13 @@
<?xml version='1.0' encoding='utf-8'?>
<novelWriterXML appVersion="1.7-alpha0" hexVersion="0x010700a0" fileVersion="1.4" timeStamp="2022-04-03 21:36:18">
<novelWriterXML appVersion="1.7-alpha0" hexVersion="0x010700a0" fileVersion="1.4" timeStamp="2022-04-16 14:19:35">
<project>
<name>Test Minimal</name>
<title>Minimal</title>
<author>Jane Doe</author>
<author>John Doh</author>
<saveCount>14</saveCount>
<saveCount>15</saveCount>
<autoCount>2</autoCount>
<editTime>135</editTime>
<editTime>146</editTime>
</project>
<settings>
<doBackup>True</doBackup>
@@ -29,50 +29,50 @@
<section></section>
</titleFormat>
<status>
<entry red="100" green="100" blue="100">New</entry>
<entry red="200" green="50" blue="0">Note</entry>
<entry red="200" green="150" blue="0">Draft</entry>
<entry red="50" green="200" blue="0">Finished</entry>
<entry key="s72322d" count="5" red="100" green="100" blue="100">New</entry>
<entry key="sb6adc7" count="0" red="200" green="50" blue="0">Note</entry>
<entry key="s2ae76d" count="0" red="200" green="150" blue="0">Draft</entry>
<entry key="s541953" count="0" red="50" green="200" blue="0">Finished</entry>
</status>
<importance>
<entry red="100" green="100" blue="100">New</entry>
<entry red="200" green="50" blue="0">Minor</entry>
<entry red="200" green="150" blue="0">Major</entry>
<entry red="50" green="200" blue="0">Main</entry>
<entry key="iffcacb" count="3" red="100" green="100" blue="100">New</entry>
<entry key="i6b130b" count="0" red="200" green="50" blue="0">Minor</entry>
<entry key="iece803" count="0" red="200" green="150" blue="0">Major</entry>
<entry key="i5ba06e" count="0" red="50" green="200" blue="0">Main</entry>
</importance>
</settings>
<content count="8">
<item handle="a508bb932959c" parent="None" root="a508bb932959c" order="0" type="ROOT" class="NOVEL">
<meta expanded="True"/>
<name status="New" import="New">Novel</name>
<name status="s72322d" import="iffcacb">Novel</name>
</item>
<item handle="a35baf2e93843" parent="a508bb932959c" root="a508bb932959c" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="28" wordCount="6" paraCount="1" cursorPos="33"/>
<name status="New" import="New" exported="True">Title Page</name>
<name status="s72322d" import="iffcacb" exported="True">Title Page</name>
</item>
<item handle="a6d311a93600a" parent="a508bb932959c" root="a508bb932959c" order="1" type="FOLDER" class="NOVEL">
<meta expanded="True"/>
<name status="New" import="New">New Chapter</name>
<name status="s72322d" import="iffcacb">New Chapter</name>
</item>
<item handle="f5ab3e30151e1" parent="a6d311a93600a" root="a508bb932959c" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="11" wordCount="2" paraCount="0" cursorPos="16"/>
<name status="New" import="New" exported="True">New Chapter</name>
<name status="s72322d" import="iffcacb" exported="True">New Chapter</name>
</item>
<item handle="8c659a11cd429" parent="a6d311a93600a" root="a508bb932959c" order="1" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="9" wordCount="2" paraCount="0" cursorPos="15"/>
<name status="New" import="New" exported="True">New Scene</name>
<name status="s72322d" import="iffcacb" exported="True">New Scene</name>
</item>
<item handle="7695ce551d265" parent="None" root="7695ce551d265" order="1" type="ROOT" class="PLOT">
<meta expanded="False"/>
<name status="New" import="New">Plot</name>
<name status="s72322d" import="iffcacb">Plot</name>
</item>
<item handle="afb3043c7b2b3" parent="None" root="afb3043c7b2b3" order="2" type="ROOT" class="CHARACTER">
<meta expanded="False"/>
<name status="New" import="New">Characters</name>
<name status="s72322d" import="iffcacb">Characters</name>
</item>
<item handle="9d5247ab588e0" parent="None" root="9d5247ab588e0" order="3" type="ROOT" class="WORLD">
<meta expanded="False"/>
<name status="New" import="New">World</name>
<name status="s72322d" import="iffcacb">World</name>
</item>
</content>
</novelWriterXML>
@@ -1,5 +1,5 @@
<?xml version='1.0' encoding='utf-8'?>
<novelWriterXML appVersion="1.7-alpha0" hexVersion="0x010700a0" fileVersion="1.4" timeStamp="2022-04-03 21:38:23">
<novelWriterXML appVersion="1.7-alpha0" hexVersion="0x010700a0" fileVersion="1.4" timeStamp="2022-04-16 14:14:40">
<project>
<name>Test Custom</name>
<title>Test Novel</title>
@@ -29,110 +29,110 @@
<section></section>
</titleFormat>
<status>
<entry red="100" green="100" blue="100">New</entry>
<entry red="200" green="50" blue="0">Note</entry>
<entry red="200" green="150" blue="0">Draft</entry>
<entry red="50" green="200" blue="0">Finished</entry>
<entry key="sbc8960" count="17" red="100" green="100" blue="100">New</entry>
<entry key="s1a3d1f" count="0" red="200" green="50" blue="0">Note</entry>
<entry key="sad3c2d" count="0" red="200" green="150" blue="0">Draft</entry>
<entry key="sbd9c66" count="0" red="50" green="200" blue="0">Finished</entry>
</status>
<importance>
<entry red="100" green="100" blue="100">New</entry>
<entry red="200" green="50" blue="0">Minor</entry>
<entry red="200" green="150" blue="0">Major</entry>
<entry red="50" green="200" blue="0">Main</entry>
<entry key="ie465e1" count="0" red="100" green="100" blue="100">New</entry>
<entry key="i8b9d24" count="0" red="200" green="50" blue="0">Minor</entry>
<entry key="i16419f" count="0" red="200" green="150" blue="0">Major</entry>
<entry key="i972a84" count="0" red="50" green="200" blue="0">Main</entry>
</importance>
</settings>
<content count="23">
<item handle="73475cb40a568" parent="None" root="73475cb40a568" order="0" type="ROOT" class="NOVEL">
<meta expanded="False"/>
<name status="New" import="None">Novel</name>
<name status="sbc8960" import="None">Novel</name>
</item>
<item handle="44cb730c42048" parent="None" root="44cb730c42048" order="0" type="ROOT" class="PLOT">
<meta expanded="False"/>
<name status="New" import="None">Plot</name>
<name status="sbc8960" import="None">Plot</name>
</item>
<item handle="71ee45a3c0db9" parent="None" root="71ee45a3c0db9" order="0" type="ROOT" class="CHARACTER">
<meta expanded="False"/>
<name status="New" import="None">Characters</name>
<name status="sbc8960" import="None">Characters</name>
</item>
<item handle="811786ad1ae74" parent="None" root="811786ad1ae74" order="0" type="ROOT" class="WORLD">
<meta expanded="False"/>
<name status="New" import="None">Locations</name>
<name status="sbc8960" import="None">Locations</name>
</item>
<item handle="25fc0e7096fc6" parent="None" root="25fc0e7096fc6" order="0" type="ROOT" class="TIMELINE">
<meta expanded="False"/>
<name status="New" import="None">Timeline</name>
<name status="sbc8960" import="None">Timeline</name>
</item>
<item handle="31489056e0916" parent="None" root="31489056e0916" order="0" type="ROOT" class="OBJECT">
<meta expanded="False"/>
<name status="New" import="None">Objects</name>
<name status="sbc8960" import="None">Objects</name>
</item>
<item handle="98010bd9270f9" parent="None" root="98010bd9270f9" order="0" type="ROOT" class="ENTITY">
<meta expanded="False"/>
<name status="New" import="None">Entities</name>
<name status="sbc8960" import="None">Entities</name>
</item>
<item handle="0e17daca5f3e1" parent="73475cb40a568" root="73475cb40a568" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="0" wordCount="0" paraCount="0" cursorPos="0"/>
<name status="New" import="None" exported="True">Title Page</name>
<name status="sbc8960" import="None" exported="True">Title Page</name>
</item>
<item handle="1a6562590ef19" parent="73475cb40a568" root="73475cb40a568" order="0" type="FOLDER" class="NOVEL">
<meta expanded="False"/>
<name status="New" import="None">Chapter 1</name>
<name status="sbc8960" import="None">Chapter 1</name>
</item>
<item handle="031b4af5197ec" parent="1a6562590ef19" root="73475cb40a568" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="0" wordCount="0" paraCount="0" cursorPos="0"/>
<name status="New" import="None" exported="True">Chapter 1</name>
<name status="sbc8960" import="None" exported="True">Chapter 1</name>
</item>
<item handle="41cfc0d1f2d12" parent="1a6562590ef19" root="73475cb40a568" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="0" wordCount="0" paraCount="0" cursorPos="0"/>
<name status="New" import="None" exported="True">Scene 1.1</name>
<name status="sbc8960" import="None" exported="True">Scene 1.1</name>
</item>
<item handle="2858dcd1057d3" parent="1a6562590ef19" root="73475cb40a568" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="0" wordCount="0" paraCount="0" cursorPos="0"/>
<name status="New" import="None" exported="True">Scene 1.2</name>
<name status="sbc8960" import="None" exported="True">Scene 1.2</name>
</item>
<item handle="2fca346db6561" parent="1a6562590ef19" root="73475cb40a568" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="0" wordCount="0" paraCount="0" cursorPos="0"/>
<name status="New" import="None" exported="True">Scene 1.3</name>
<name status="sbc8960" import="None" exported="True">Scene 1.3</name>
</item>
<item handle="02d20bbd7e394" parent="73475cb40a568" root="73475cb40a568" order="0" type="FOLDER" class="NOVEL">
<meta expanded="False"/>
<name status="New" import="None">Chapter 2</name>
<name status="sbc8960" import="None">Chapter 2</name>
</item>
<item handle="7688b6ef52555" parent="02d20bbd7e394" root="73475cb40a568" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="0" wordCount="0" paraCount="0" cursorPos="0"/>
<name status="New" import="None" exported="True">Chapter 2</name>
<name status="sbc8960" import="None" exported="True">Chapter 2</name>
</item>
<item handle="c837649cce43f" parent="02d20bbd7e394" root="73475cb40a568" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="0" wordCount="0" paraCount="0" cursorPos="0"/>
<name status="New" import="None" exported="True">Scene 2.1</name>
<name status="sbc8960" import="None" exported="True">Scene 2.1</name>
</item>
<item handle="6208ef0f7750c" parent="02d20bbd7e394" root="73475cb40a568" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="0" wordCount="0" paraCount="0" cursorPos="0"/>
<name status="New" import="None" exported="True">Scene 2.2</name>
<name status="sbc8960" import="None" exported="True">Scene 2.2</name>
</item>
<item handle="3e1e967e9b793" parent="02d20bbd7e394" root="73475cb40a568" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="0" wordCount="0" paraCount="0" cursorPos="0"/>
<name status="New" import="None" exported="True">Scene 2.3</name>
<name status="sbc8960" import="None" exported="True">Scene 2.3</name>
</item>
<item handle="39fa9ec190eee" parent="73475cb40a568" root="73475cb40a568" order="0" type="FOLDER" class="NOVEL">
<meta expanded="False"/>
<name status="New" import="None">Chapter 3</name>
<name status="sbc8960" import="None">Chapter 3</name>
</item>
<item handle="d029fa3a95e17" parent="39fa9ec190eee" root="73475cb40a568" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="0" wordCount="0" paraCount="0" cursorPos="0"/>
<name status="New" import="None" exported="True">Chapter 3</name>
<name status="sbc8960" import="None" exported="True">Chapter 3</name>
</item>
<item handle="81b8a03f97e87" parent="39fa9ec190eee" root="73475cb40a568" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="0" wordCount="0" paraCount="0" cursorPos="0"/>
<name status="New" import="None" exported="True">Scene 3.1</name>
<name status="sbc8960" import="None" exported="True">Scene 3.1</name>
</item>
<item handle="da4ea2a5506f2" parent="39fa9ec190eee" root="73475cb40a568" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="0" wordCount="0" paraCount="0" cursorPos="0"/>
<name status="New" import="None" exported="True">Scene 3.2</name>
<name status="sbc8960" import="None" exported="True">Scene 3.2</name>
</item>
<item handle="a68b412c42825" parent="39fa9ec190eee" root="73475cb40a568" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="0" wordCount="0" paraCount="0" cursorPos="0"/>
<name status="New" import="None" exported="True">Scene 3.3</name>
<name status="sbc8960" import="None" exported="True">Scene 3.3</name>
</item>
</content>
</novelWriterXML>
@@ -1,5 +1,5 @@
<?xml version='1.0' encoding='utf-8'?>
<novelWriterXML appVersion="1.7-alpha0" hexVersion="0x010700a0" fileVersion="1.4" timeStamp="2022-04-03 21:38:23">
<novelWriterXML appVersion="1.7-alpha0" hexVersion="0x010700a0" fileVersion="1.4" timeStamp="2022-04-16 14:15:44">
<project>
<name>Test Custom</name>
<title>Test Novel</title>
@@ -29,74 +29,74 @@
<section></section>
</titleFormat>
<status>
<entry red="100" green="100" blue="100">New</entry>
<entry red="200" green="50" blue="0">Note</entry>
<entry red="200" green="150" blue="0">Draft</entry>
<entry red="50" green="200" blue="0">Finished</entry>
<entry key="sbc8960" count="8" red="100" green="100" blue="100">New</entry>
<entry key="s1a3d1f" count="0" red="200" green="50" blue="0">Note</entry>
<entry key="sad3c2d" count="0" red="200" green="150" blue="0">Draft</entry>
<entry key="sbd9c66" count="0" red="50" green="200" blue="0">Finished</entry>
</status>
<importance>
<entry red="100" green="100" blue="100">New</entry>
<entry red="200" green="50" blue="0">Minor</entry>
<entry red="200" green="150" blue="0">Major</entry>
<entry red="50" green="200" blue="0">Main</entry>
<entry key="ie465e1" count="0" red="100" green="100" blue="100">New</entry>
<entry key="i8b9d24" count="0" red="200" green="50" blue="0">Minor</entry>
<entry key="i16419f" count="0" red="200" green="150" blue="0">Major</entry>
<entry key="i972a84" count="0" red="50" green="200" blue="0">Main</entry>
</importance>
</settings>
<content count="14">
<item handle="73475cb40a568" parent="None" root="73475cb40a568" order="0" type="ROOT" class="NOVEL">
<meta expanded="False"/>
<name status="New" import="None">Novel</name>
<name status="sbc8960" import="None">Novel</name>
</item>
<item handle="44cb730c42048" parent="None" root="44cb730c42048" order="0" type="ROOT" class="PLOT">
<meta expanded="False"/>
<name status="New" import="None">Plot</name>
<name status="sbc8960" import="None">Plot</name>
</item>
<item handle="71ee45a3c0db9" parent="None" root="71ee45a3c0db9" order="0" type="ROOT" class="CHARACTER">
<meta expanded="False"/>
<name status="New" import="None">Characters</name>
<name status="sbc8960" import="None">Characters</name>
</item>
<item handle="811786ad1ae74" parent="None" root="811786ad1ae74" order="0" type="ROOT" class="WORLD">
<meta expanded="False"/>
<name status="New" import="None">Locations</name>
<name status="sbc8960" import="None">Locations</name>
</item>
<item handle="25fc0e7096fc6" parent="None" root="25fc0e7096fc6" order="0" type="ROOT" class="TIMELINE">
<meta expanded="False"/>
<name status="New" import="None">Timeline</name>
<name status="sbc8960" import="None">Timeline</name>
</item>
<item handle="31489056e0916" parent="None" root="31489056e0916" order="0" type="ROOT" class="OBJECT">
<meta expanded="False"/>
<name status="New" import="None">Objects</name>
<name status="sbc8960" import="None">Objects</name>
</item>
<item handle="98010bd9270f9" parent="None" root="98010bd9270f9" order="0" type="ROOT" class="ENTITY">
<meta expanded="False"/>
<name status="New" import="None">Entities</name>
<name status="sbc8960" import="None">Entities</name>
</item>
<item handle="0e17daca5f3e1" parent="73475cb40a568" root="73475cb40a568" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="0" wordCount="0" paraCount="0" cursorPos="0"/>
<name status="New" import="None" exported="True">Title Page</name>
<name status="sbc8960" import="None" exported="True">Title Page</name>
</item>
<item handle="1a6562590ef19" parent="73475cb40a568" root="73475cb40a568" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="0" wordCount="0" paraCount="0" cursorPos="0"/>
<name status="New" import="None" exported="True">Scene 1</name>
<name status="sbc8960" import="None" exported="True">Scene 1</name>
</item>
<item handle="031b4af5197ec" parent="73475cb40a568" root="73475cb40a568" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="0" wordCount="0" paraCount="0" cursorPos="0"/>
<name status="New" import="None" exported="True">Scene 2</name>
<name status="sbc8960" import="None" exported="True">Scene 2</name>
</item>
<item handle="41cfc0d1f2d12" parent="73475cb40a568" root="73475cb40a568" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="0" wordCount="0" paraCount="0" cursorPos="0"/>
<name status="New" import="None" exported="True">Scene 3</name>
<name status="sbc8960" import="None" exported="True">Scene 3</name>
</item>
<item handle="2858dcd1057d3" parent="73475cb40a568" root="73475cb40a568" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="0" wordCount="0" paraCount="0" cursorPos="0"/>
<name status="New" import="None" exported="True">Scene 4</name>
<name status="sbc8960" import="None" exported="True">Scene 4</name>
</item>
<item handle="2fca346db6561" parent="73475cb40a568" root="73475cb40a568" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="0" wordCount="0" paraCount="0" cursorPos="0"/>
<name status="New" import="None" exported="True">Scene 5</name>
<name status="sbc8960" import="None" exported="True">Scene 5</name>
</item>
<item handle="02d20bbd7e394" parent="73475cb40a568" root="73475cb40a568" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="0" wordCount="0" paraCount="0" cursorPos="0"/>
<name status="New" import="None" exported="True">Scene 6</name>
<name status="sbc8960" import="None" exported="True">Scene 6</name>
</item>
</content>
</novelWriterXML>
@@ -1,5 +1,5 @@
<?xml version='1.0' encoding='utf-8'?>
<novelWriterXML appVersion="1.7-alpha0" hexVersion="0x010700a0" fileVersion="1.4" timeStamp="2022-04-03 21:38:23">
<novelWriterXML appVersion="1.7-alpha0" hexVersion="0x010700a0" fileVersion="1.4" timeStamp="2022-04-16 14:17:50">
<project>
<name>New Project</name>
<title></title>
@@ -27,58 +27,58 @@
<section></section>
</titleFormat>
<status>
<entry red="100" green="100" blue="100">New</entry>
<entry red="200" green="50" blue="0">Note</entry>
<entry red="200" green="150" blue="0">Draft</entry>
<entry red="50" green="200" blue="0">Finished</entry>
<entry key="sbc8960" count="6" red="100" green="100" blue="100">New</entry>
<entry key="s1a3d1f" count="0" red="200" green="50" blue="0">Note</entry>
<entry key="sad3c2d" count="0" red="200" green="150" blue="0">Draft</entry>
<entry key="sbd9c66" count="0" red="50" green="200" blue="0">Finished</entry>
</status>
<importance>
<entry red="100" green="100" blue="100">New</entry>
<entry red="200" green="50" blue="0">Minor</entry>
<entry red="200" green="150" blue="0">Major</entry>
<entry red="50" green="200" blue="0">Main</entry>
<entry key="ie465e1" count="3" red="100" green="100" blue="100">New</entry>
<entry key="i8b9d24" count="0" red="200" green="50" blue="0">Minor</entry>
<entry key="i16419f" count="0" red="200" green="150" blue="0">Major</entry>
<entry key="i972a84" count="0" red="50" green="200" blue="0">Main</entry>
</importance>
</settings>
<content count="10">
<item handle="73475cb40a568" parent="None" root="73475cb40a568" order="0" type="ROOT" class="NOVEL">
<meta expanded="False"/>
<name status="New" import="New">Novel</name>
<name status="sbc8960" import="ie465e1">Novel</name>
</item>
<item handle="44cb730c42048" parent="None" root="44cb730c42048" order="0" type="ROOT" class="PLOT">
<meta expanded="False"/>
<name status="New" import="New">Plot</name>
<name status="sbc8960" import="ie465e1">Plot</name>
</item>
<item handle="71ee45a3c0db9" parent="None" root="71ee45a3c0db9" order="0" type="ROOT" class="CHARACTER">
<meta expanded="False"/>
<name status="New" import="New">Characters</name>
<name status="sbc8960" import="ie465e1">Characters</name>
</item>
<item handle="811786ad1ae74" parent="None" root="811786ad1ae74" order="0" type="ROOT" class="WORLD">
<meta expanded="False"/>
<name status="New" import="New">World</name>
<name status="sbc8960" import="ie465e1">World</name>
</item>
<item handle="25fc0e7096fc6" parent="73475cb40a568" root="73475cb40a568" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="0" wordCount="0" paraCount="0" cursorPos="0"/>
<name status="New" import="New" exported="True">Title Page</name>
<name status="sbc8960" import="ie465e1" exported="True">Title Page</name>
</item>
<item handle="31489056e0916" parent="73475cb40a568" root="73475cb40a568" order="0" type="FOLDER" class="NOVEL">
<meta expanded="False"/>
<name status="New" import="New">New Chapter</name>
<name status="sbc8960" import="ie465e1">New Chapter</name>
</item>
<item handle="98010bd9270f9" parent="31489056e0916" root="73475cb40a568" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="0" wordCount="0" paraCount="0" cursorPos="0"/>
<name status="New" import="New" exported="True">New Chapter</name>
<name status="sbc8960" import="ie465e1" exported="True">New Chapter</name>
</item>
<item handle="0e17daca5f3e1" parent="31489056e0916" root="73475cb40a568" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="0" wordCount="0" paraCount="0" cursorPos="0"/>
<name status="New" import="New" exported="True">New Scene</name>
<name status="sbc8960" import="ie465e1" exported="True">New Scene</name>
</item>
<item handle="1a6562590ef19" parent="31489056e0916" root="73475cb40a568" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="0" wordCount="0" paraCount="0" cursorPos="0"/>
<name status="New" import="None" exported="True">Hello</name>
<name status="sbc8960" import="None" exported="True">Hello</name>
</item>
<item handle="031b4af5197ec" parent="71ee45a3c0db9" root="71ee45a3c0db9" order="0" type="FILE" class="CHARACTER" layout="NOTE">
<meta charCount="0" wordCount="0" paraCount="0" cursorPos="0"/>
<name status="New" import="None" exported="True">Jane</name>
<name status="sbc8960" import="None" exported="True">Jane</name>
</item>
</content>
</novelWriterXML>
@@ -1,5 +1,5 @@
<?xml version='1.0' encoding='utf-8'?>
<novelWriterXML appVersion="1.7-alpha0" hexVersion="0x010700a0" fileVersion="1.4" timeStamp="2022-04-03 21:54:40">
<novelWriterXML appVersion="1.7-alpha0" hexVersion="0x010700a0" fileVersion="1.4" timeStamp="2022-04-16 14:13:27">
<project>
<name>New Project</name>
<title></title>
@@ -27,50 +27,50 @@
<section></section>
</titleFormat>
<status>
<entry red="100" green="100" blue="100">New</entry>
<entry red="200" green="50" blue="0">Note</entry>
<entry red="200" green="150" blue="0">Draft</entry>
<entry red="50" green="200" blue="0">Finished</entry>
<entry key="sbc8960" count="5" red="100" green="100" blue="100">New</entry>
<entry key="s1a3d1f" count="0" red="200" green="50" blue="0">Note</entry>
<entry key="sad3c2d" count="0" red="200" green="150" blue="0">Draft</entry>
<entry key="sbd9c66" count="0" red="50" green="200" blue="0">Finished</entry>
</status>
<importance>
<entry red="100" green="100" blue="100">New</entry>
<entry red="200" green="50" blue="0">Minor</entry>
<entry red="200" green="150" blue="0">Major</entry>
<entry red="50" green="200" blue="0">Main</entry>
<entry key="ie465e1" count="3" red="100" green="100" blue="100">New</entry>
<entry key="i8b9d24" count="0" red="200" green="50" blue="0">Minor</entry>
<entry key="i16419f" count="0" red="200" green="150" blue="0">Major</entry>
<entry key="i972a84" count="0" red="50" green="200" blue="0">Main</entry>
</importance>
</settings>
<content count="8">
<item handle="73475cb40a568" parent="None" root="73475cb40a568" order="0" type="ROOT" class="NOVEL">
<meta expanded="False"/>
<name status="New" import="New">Novel</name>
<name status="sbc8960" import="ie465e1">Novel</name>
</item>
<item handle="44cb730c42048" parent="None" root="44cb730c42048" order="0" type="ROOT" class="PLOT">
<meta expanded="False"/>
<name status="New" import="New">Plot</name>
<name status="sbc8960" import="ie465e1">Plot</name>
</item>
<item handle="71ee45a3c0db9" parent="None" root="71ee45a3c0db9" order="0" type="ROOT" class="CHARACTER">
<meta expanded="False"/>
<name status="New" import="New">Characters</name>
<name status="sbc8960" import="ie465e1">Characters</name>
</item>
<item handle="811786ad1ae74" parent="None" root="811786ad1ae74" order="0" type="ROOT" class="WORLD">
<meta expanded="False"/>
<name status="New" import="New">World</name>
<name status="sbc8960" import="ie465e1">World</name>
</item>
<item handle="25fc0e7096fc6" parent="73475cb40a568" root="73475cb40a568" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="0" wordCount="0" paraCount="0" cursorPos="0"/>
<name status="New" import="New" exported="True">Title Page</name>
<name status="sbc8960" import="ie465e1" exported="True">Title Page</name>
</item>
<item handle="31489056e0916" parent="73475cb40a568" root="73475cb40a568" order="0" type="FOLDER" class="NOVEL">
<meta expanded="False"/>
<name status="New" import="New">New Chapter</name>
<name status="sbc8960" import="ie465e1">New Chapter</name>
</item>
<item handle="98010bd9270f9" parent="31489056e0916" root="73475cb40a568" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="0" wordCount="0" paraCount="0" cursorPos="0"/>
<name status="New" import="New" exported="True">New Chapter</name>
<name status="sbc8960" import="ie465e1" exported="True">New Chapter</name>
</item>
<item handle="0e17daca5f3e1" parent="31489056e0916" root="73475cb40a568" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="0" wordCount="0" paraCount="0" cursorPos="0"/>
<name status="New" import="New" exported="True">New Scene</name>
<name status="sbc8960" import="ie465e1" exported="True">New Scene</name>
</item>
</content>
</novelWriterXML>
@@ -1,5 +1,5 @@
<?xml version='1.0' encoding='utf-8'?>
<novelWriterXML appVersion="1.7-alpha0" hexVersion="0x010700a0" fileVersion="1.4" timeStamp="2022-04-03 22:49:41">
<novelWriterXML appVersion="1.7-alpha0" hexVersion="0x010700a0" fileVersion="1.4" timeStamp="2022-04-16 18:46:31">
<project>
<name>New Project</name>
<title></title>
@@ -27,82 +27,82 @@
<section></section>
</titleFormat>
<status>
<entry red="100" green="100" blue="100">New</entry>
<entry red="200" green="50" blue="0">Note</entry>
<entry red="200" green="150" blue="0">Draft</entry>
<entry red="50" green="200" blue="0">Finished</entry>
<entry key="sbc8960" count="6" red="100" green="100" blue="100">New</entry>
<entry key="s1a3d1f" count="0" red="200" green="50" blue="0">Note</entry>
<entry key="sad3c2d" count="0" red="200" green="150" blue="0">Draft</entry>
<entry key="sbd9c66" count="0" red="50" green="200" blue="0">Finished</entry>
</status>
<importance>
<entry red="100" green="100" blue="100">New</entry>
<entry red="200" green="50" blue="0">Minor</entry>
<entry red="200" green="150" blue="0">Major</entry>
<entry red="50" green="200" blue="0">Main</entry>
<entry key="ie465e1" count="3" red="100" green="100" blue="100">New</entry>
<entry key="i8b9d24" count="0" red="200" green="50" blue="0">Minor</entry>
<entry key="i16419f" count="0" red="200" green="150" blue="0">Major</entry>
<entry key="i972a84" count="0" red="50" green="200" blue="0">Main</entry>
</importance>
</settings>
<content count="16">
<item handle="73475cb40a568" parent="None" root="73475cb40a568" order="0" type="ROOT" class="NOVEL">
<meta expanded="False"/>
<name status="New" import="New">Novel</name>
<name status="sbc8960" import="ie465e1">Novel</name>
</item>
<item handle="44cb730c42048" parent="None" root="44cb730c42048" order="0" type="ROOT" class="PLOT">
<meta expanded="False"/>
<name status="New" import="New">Plot</name>
<name status="sbc8960" import="ie465e1">Plot</name>
</item>
<item handle="71ee45a3c0db9" parent="None" root="71ee45a3c0db9" order="0" type="ROOT" class="CHARACTER">
<meta expanded="False"/>
<name status="New" import="New">Characters</name>
<name status="sbc8960" import="ie465e1">Characters</name>
</item>
<item handle="811786ad1ae74" parent="None" root="811786ad1ae74" order="0" type="ROOT" class="WORLD">
<meta expanded="False"/>
<name status="New" import="New">World</name>
<name status="sbc8960" import="ie465e1">World</name>
</item>
<item handle="25fc0e7096fc6" parent="73475cb40a568" root="73475cb40a568" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="0" wordCount="0" paraCount="0" cursorPos="0"/>
<name status="New" import="New" exported="True">Title Page</name>
<name status="sbc8960" import="ie465e1" exported="True">Title Page</name>
</item>
<item handle="31489056e0916" parent="73475cb40a568" root="73475cb40a568" order="0" type="FOLDER" class="NOVEL">
<meta expanded="False"/>
<name status="New" import="New">New Chapter</name>
<name status="sbc8960" import="ie465e1">New Chapter</name>
</item>
<item handle="98010bd9270f9" parent="31489056e0916" root="73475cb40a568" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="0" wordCount="0" paraCount="0" cursorPos="0"/>
<name status="New" import="New" exported="True">New Chapter</name>
<name status="sbc8960" import="ie465e1" exported="True">New Chapter</name>
</item>
<item handle="0e17daca5f3e1" parent="31489056e0916" root="73475cb40a568" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="0" wordCount="0" paraCount="0" cursorPos="0"/>
<name status="New" import="New" exported="True">New Scene</name>
<name status="sbc8960" import="ie465e1" exported="True">New Scene</name>
</item>
<item handle="1a6562590ef19" parent="None" root="1a6562590ef19" order="0" type="ROOT" class="NOVEL">
<meta expanded="False"/>
<name status="New" import="None">Novel</name>
<name status="sbc8960" import="None">Novel</name>
</item>
<item handle="031b4af5197ec" parent="None" root="031b4af5197ec" order="0" type="ROOT" class="PLOT">
<meta expanded="False"/>
<name status="New" import="None">Plot</name>
<name status="sbc8960" import="None">Plot</name>
</item>
<item handle="41cfc0d1f2d12" parent="None" root="41cfc0d1f2d12" order="0" type="ROOT" class="CHARACTER">
<meta expanded="False"/>
<name status="New" import="None">Character</name>
<name status="sbc8960" import="None">Character</name>
</item>
<item handle="2858dcd1057d3" parent="None" root="2858dcd1057d3" order="0" type="ROOT" class="WORLD">
<meta expanded="False"/>
<name status="New" import="None">World</name>
<name status="sbc8960" import="None">World</name>
</item>
<item handle="2fca346db6561" parent="None" root="2fca346db6561" order="0" type="ROOT" class="TIMELINE">
<meta expanded="False"/>
<name status="New" import="None">Timeline</name>
<name status="sbc8960" import="None">Timeline</name>
</item>
<item handle="02d20bbd7e394" parent="None" root="02d20bbd7e394" order="0" type="ROOT" class="OBJECT">
<meta expanded="False"/>
<name status="New" import="None">Object</name>
<name status="sbc8960" import="None">Object</name>
</item>
<item handle="7688b6ef52555" parent="None" root="7688b6ef52555" order="0" type="ROOT" class="CUSTOM">
<meta expanded="False"/>
<name status="New" import="None">Custom1</name>
<name status="sbc8960" import="None">Custom1</name>
</item>
<item handle="c837649cce43f" parent="None" root="c837649cce43f" order="0" type="ROOT" class="CUSTOM">
<meta expanded="False"/>
<name status="New" import="None">Custom2</name>
<name status="sbc8960" import="None">Custom2</name>
</item>
</content>
</novelWriterXML>
@@ -1,5 +1,5 @@
<?xml version='1.0' encoding='utf-8'?>
<novelWriterXML appVersion="1.7-alpha0" hexVersion="0x010700a0" fileVersion="1.4" timeStamp="2022-04-03 21:31:53">
<novelWriterXML appVersion="1.7-alpha0" hexVersion="0x010700a0" fileVersion="1.4" timeStamp="2022-04-16 12:58:48">
<project>
<name>New Project</name>
<title></title>
@@ -27,62 +27,62 @@
<section></section>
</titleFormat>
<status>
<entry red="100" green="100" blue="100">New</entry>
<entry red="200" green="50" blue="0">Note</entry>
<entry red="200" green="150" blue="0">Draft</entry>
<entry red="50" green="200" blue="0">Finished</entry>
<entry key="sa3b179" count="5" red="100" green="100" blue="100">New</entry>
<entry key="s1c8031" count="0" red="200" green="50" blue="0">Note</entry>
<entry key="s06671a" count="0" red="200" green="150" blue="0">Draft</entry>
<entry key="sbdd640" count="0" red="50" green="200" blue="0">Finished</entry>
</status>
<importance>
<entry red="100" green="100" blue="100">New</entry>
<entry red="200" green="50" blue="0">Minor</entry>
<entry red="200" green="150" blue="0">Major</entry>
<entry red="50" green="200" blue="0">Main</entry>
<entry key="i466852" count="3" red="100" green="100" blue="100">New</entry>
<entry key="i3eb13b" count="0" red="200" green="50" blue="0">Minor</entry>
<entry key="i392456" count="0" red="200" green="150" blue="0">Major</entry>
<entry key="i23b8c1" count="0" red="50" green="200" blue="0">Main</entry>
</importance>
</settings>
<content count="12">
<item handle="73475cb40a568" parent="None" root="73475cb40a568" order="0" type="ROOT" class="NOVEL">
<meta expanded="True"/>
<name status="New" import="New">Novel</name>
<name status="sa3b179" import="i466852">Novel</name>
</item>
<item handle="25fc0e7096fc6" parent="73475cb40a568" root="73475cb40a568" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="11" wordCount="2" paraCount="0" cursorPos="0"/>
<name status="New" import="New" exported="True">Title Page</name>
<name status="sa3b179" import="i466852" exported="True">Title Page</name>
</item>
<item handle="31489056e0916" parent="73475cb40a568" root="73475cb40a568" order="1" type="FOLDER" class="NOVEL">
<meta expanded="True"/>
<name status="New" import="New">New Chapter</name>
<name status="sa3b179" import="i466852">New Chapter</name>
</item>
<item handle="98010bd9270f9" parent="31489056e0916" root="73475cb40a568" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="11" wordCount="2" paraCount="0" cursorPos="0"/>
<name status="New" import="New" exported="True">New Chapter</name>
<name status="sa3b179" import="i466852" exported="True">New Chapter</name>
</item>
<item handle="0e17daca5f3e1" parent="31489056e0916" root="73475cb40a568" order="1" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="612" wordCount="95" paraCount="10" cursorPos="768"/>
<name status="New" import="New" exported="True">New Scene</name>
<name status="sa3b179" import="i466852" exported="True">New Scene</name>
</item>
<item handle="44cb730c42048" parent="None" root="44cb730c42048" order="1" type="ROOT" class="PLOT">
<meta expanded="True"/>
<name status="New" import="New">Plot</name>
<name status="sa3b179" import="i466852">Plot</name>
</item>
<item handle="031b4af5197ec" parent="44cb730c42048" root="44cb730c42048" order="0" type="FILE" class="PLOT" layout="NOTE">
<meta charCount="48" wordCount="10" paraCount="1" cursorPos="69"/>
<name status="New" import="None" exported="True">New File</name>
<name status="sa3b179" import="None" exported="True">New File</name>
</item>
<item handle="71ee45a3c0db9" parent="None" root="71ee45a3c0db9" order="2" type="ROOT" class="CHARACTER">
<meta expanded="True"/>
<name status="New" import="New">Characters</name>
<name status="sa3b179" import="i466852">Characters</name>
</item>
<item handle="1a6562590ef19" parent="71ee45a3c0db9" root="71ee45a3c0db9" order="0" type="FILE" class="CHARACTER" layout="NOTE">
<meta charCount="34" wordCount="8" paraCount="1" cursorPos="51"/>
<name status="New" import="None" exported="True">New File</name>
<name status="sa3b179" import="None" exported="True">New File</name>
</item>
<item handle="811786ad1ae74" parent="None" root="811786ad1ae74" order="3" type="ROOT" class="WORLD">
<meta expanded="True"/>
<name status="New" import="New">World</name>
<name status="sa3b179" import="i466852">World</name>
</item>
<item handle="41cfc0d1f2d12" parent="811786ad1ae74" root="811786ad1ae74" order="0" type="FILE" class="WORLD" layout="NOTE">
<meta charCount="51" wordCount="9" paraCount="1" cursorPos="68"/>
<name status="New" import="None" exported="True">New File</name>
<name status="sa3b179" import="None" exported="True">New File</name>
</item>
<item handle="2fca346db6561" parent="None" root="2fca346db6561" order="4" type="TRASH" class="TRASH">
<meta expanded="True"/>
@@ -1,5 +1,5 @@
<?xml version='1.0' encoding='utf-8'?>
<novelWriterXML appVersion="1.7-alpha0" hexVersion="0x010700a0" fileVersion="1.4" timeStamp="2022-04-03 21:00:21">
<novelWriterXML appVersion="1.7-alpha0" hexVersion="0x010700a0" fileVersion="1.4" timeStamp="2022-04-16 12:48:08">
<project>
<name>New Project</name>
<title></title>
@@ -27,50 +27,50 @@
<section></section>
</titleFormat>
<status>
<entry red="100" green="100" blue="100">New</entry>
<entry red="200" green="50" blue="0">Note</entry>
<entry red="200" green="150" blue="0">Draft</entry>
<entry red="50" green="200" blue="0">Finished</entry>
<entry key="sa3b179" count="5" red="100" green="100" blue="100">New</entry>
<entry key="s1c8031" count="0" red="200" green="50" blue="0">Note</entry>
<entry key="s06671a" count="0" red="200" green="150" blue="0">Draft</entry>
<entry key="sbdd640" count="0" red="50" green="200" blue="0">Finished</entry>
</status>
<importance>
<entry red="100" green="100" blue="100">New</entry>
<entry red="200" green="50" blue="0">Minor</entry>
<entry red="200" green="150" blue="0">Major</entry>
<entry red="50" green="200" blue="0">Main</entry>
<entry key="i466852" count="0" red="100" green="100" blue="100">New</entry>
<entry key="i3eb13b" count="0" red="200" green="50" blue="0">Minor</entry>
<entry key="i392456" count="0" red="200" green="150" blue="0">Major</entry>
<entry key="i23b8c1" count="0" red="50" green="200" blue="0">Main</entry>
</importance>
</settings>
<content count="8">
<item handle="73475cb40a568" parent="None" root="73475cb40a568" order="0" type="ROOT" class="NOVEL">
<meta expanded="False"/>
<name status="New" import="None">Novel</name>
<name status="sa3b179" import="None">Novel</name>
</item>
<item handle="25fc0e7096fc6" parent="73475cb40a568" root="73475cb40a568" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="11" wordCount="2" paraCount="0" cursorPos="0"/>
<name status="New" import="None" exported="True">Title Page</name>
<name status="sa3b179" import="None" exported="True">Title Page</name>
</item>
<item handle="31489056e0916" parent="73475cb40a568" root="73475cb40a568" order="1" type="FOLDER" class="NOVEL">
<meta expanded="False"/>
<name status="New" import="None">New Chapter</name>
<name status="sa3b179" import="None">New Chapter</name>
</item>
<item handle="98010bd9270f9" parent="31489056e0916" root="73475cb40a568" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="11" wordCount="2" paraCount="0" cursorPos="0"/>
<name status="New" import="None" exported="True">New Chapter</name>
<name status="sa3b179" import="None" exported="True">New Chapter</name>
</item>
<item handle="0e17daca5f3e1" parent="31489056e0916" root="73475cb40a568" order="1" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="9" wordCount="2" paraCount="0" cursorPos="0"/>
<name status="New" import="None" exported="True">New Scene</name>
<name status="sa3b179" import="None" exported="True">New Scene</name>
</item>
<item handle="44cb730c42048" parent="None" root="44cb730c42048" order="1" type="ROOT" class="PLOT">
<meta expanded="False"/>
<name status="New" import="None">Plot</name>
<name status="sa3b179" import="None">Plot</name>
</item>
<item handle="71ee45a3c0db9" parent="None" root="71ee45a3c0db9" order="2" type="ROOT" class="CHARACTER">
<meta expanded="False"/>
<name status="New" import="None">Characters</name>
<name status="sa3b179" import="None">Characters</name>
</item>
<item handle="811786ad1ae74" parent="None" root="811786ad1ae74" order="3" type="ROOT" class="WORLD">
<meta expanded="False"/>
<name status="New" import="None">World</name>
<name status="sa3b179" import="None">World</name>
</item>
</content>
</novelWriterXML>
@@ -1,5 +1,5 @@
<?xml version='1.0' encoding='utf-8'?>
<novelWriterXML appVersion="1.7-alpha0" hexVersion="0x010700a0" fileVersion="1.4" timeStamp="2022-04-03 21:00:18">
<novelWriterXML appVersion="1.7-alpha0" hexVersion="0x010700a0" fileVersion="1.4" timeStamp="2022-04-16 18:15:12">
<project>
<name>Project Name</name>
<title>Project Title</title>
@@ -23,7 +23,7 @@
<autoReplace>
<entry key="A">B</entry>
<entry key="C">D</entry>
<entry key="This">With This Stuff </entry>
<entry key="This">With This Stuff</entry>
</autoReplace>
<titleFormat>
<title>%title%</title>
@@ -33,50 +33,50 @@
<section></section>
</titleFormat>
<status>
<entry red="100" green="100" blue="100">New</entry>
<entry red="200" green="50" blue="0">Note</entry>
<entry red="50" green="200" blue="0">Finished</entry>
<entry red="20" green="30" blue="40">Final</entry>
<entry key="sa3b179" count="5" red="100" green="100" blue="100">New</entry>
<entry key="s1c8031" count="0" red="200" green="50" blue="0">Note</entry>
<entry key="sbdd640" count="0" red="50" green="200" blue="0">Finished</entry>
<entry key="sbc8960" count="0" red="20" green="30" blue="40">Final</entry>
</status>
<importance>
<entry red="100" green="100" blue="100">New</entry>
<entry red="200" green="50" blue="0">Minor</entry>
<entry red="200" green="150" blue="0">Major</entry>
<entry red="0" green="0" blue="0">Final</entry>
<entry key="i466852" count="0" red="100" green="100" blue="100">New</entry>
<entry key="i3eb13b" count="0" red="200" green="50" blue="0">Minor</entry>
<entry key="i392456" count="0" red="200" green="150" blue="0">Major</entry>
<entry key="i1a3d1f" count="0" red="100" green="100" blue="100">Final</entry>
</importance>
</settings>
<content count="8">
<item handle="73475cb40a568" parent="None" root="73475cb40a568" order="0" type="ROOT" class="NOVEL">
<meta expanded="False"/>
<name status="New" import="None">Novel</name>
<name status="sa3b179" import="None">Novel</name>
</item>
<item handle="25fc0e7096fc6" parent="73475cb40a568" root="73475cb40a568" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="11" wordCount="2" paraCount="0" cursorPos="0"/>
<name status="New" import="None" exported="True">Title Page</name>
<name status="sa3b179" import="None" exported="True">Title Page</name>
</item>
<item handle="31489056e0916" parent="73475cb40a568" root="73475cb40a568" order="1" type="FOLDER" class="NOVEL">
<meta expanded="False"/>
<name status="New" import="None">New Chapter</name>
<name status="sa3b179" import="None">New Chapter</name>
</item>
<item handle="98010bd9270f9" parent="31489056e0916" root="73475cb40a568" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="11" wordCount="2" paraCount="0" cursorPos="0"/>
<name status="New" import="None" exported="True">New Chapter</name>
<name status="sa3b179" import="None" exported="True">New Chapter</name>
</item>
<item handle="0e17daca5f3e1" parent="31489056e0916" root="73475cb40a568" order="1" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta charCount="9" wordCount="2" paraCount="0" cursorPos="0"/>
<name status="New" import="None" exported="True">New Scene</name>
<name status="sa3b179" import="None" exported="True">New Scene</name>
</item>
<item handle="44cb730c42048" parent="None" root="44cb730c42048" order="1" type="ROOT" class="PLOT">
<meta expanded="False"/>
<name status="New" import="None">Plot</name>
<name status="sa3b179" import="None">Plot</name>
</item>
<item handle="71ee45a3c0db9" parent="None" root="71ee45a3c0db9" order="2" type="ROOT" class="CHARACTER">
<meta expanded="False"/>
<name status="New" import="None">Characters</name>
<name status="sa3b179" import="None">Characters</name>
</item>
<item handle="811786ad1ae74" parent="None" root="811786ad1ae74" order="3" type="ROOT" class="WORLD">
<meta expanded="False"/>
<name status="New" import="None">World</name>
<name status="sa3b179" import="None">World</name>
</item>
</content>
</novelWriterXML>
+24 -3
View File
@@ -31,9 +31,9 @@ from novelwriter.guimain import GuiMain
from novelwriter.common import (
checkString, checkInt, checkFloat, checkBool, checkHandle, isHandle,
isTitleTag, isItemClass, isItemType, isItemLayout, hexToInt, checkIntRange,
checkIntTuple, formatInt, formatTimeStamp, formatTime, splitVersionNumber,
transferCase, fuzzyTime, numberToRoman, jsonEncode, readTextFile,
makeFileNameSafe, sha256sum, getGuiItem, NWConfigParser
minmax, checkIntTuple, formatInt, formatTimeStamp, formatTime, simplified,
splitVersionNumber, transferCase, fuzzyTime, numberToRoman, jsonEncode,
readTextFile, makeFileNameSafe, sha256sum, getGuiItem, NWConfigParser
)
@@ -226,6 +226,16 @@ def testBaseCommon_CheckIntRange():
# END Test testBaseCommon_CheckIntRange
@pytest.mark.base
def testBaseCommon_MinMax():
"""Test the minmax function.
"""
for i in range(-5, 15):
assert 0 <= minmax(i, 0, 10) <= 10
# END Test testBaseCommon_MinMax
@pytest.mark.base
def testBaseCommon_CheckIntTuple():
"""Test the checkIntTuple function.
@@ -270,6 +280,17 @@ def testBaseCommon_FormatTime():
# END Test testBaseCommon_FormatTime
@pytest.mark.base
def testBaseCommon_Simplified():
"""Test the simplified function.
"""
assert simplified("Hello World") == "Hello World"
assert simplified(" Hello World ") == "Hello World"
assert simplified("\tHello\n\r\tWorld") == "Hello World"
# END Test testBaseCommon_Simplified
@pytest.mark.base
def testBaseCommon_SplitVersionNumber():
"""Test the splitVersionNumber function.
+37 -44
View File
@@ -20,6 +20,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
import pytest
import random
from lxml import etree
@@ -31,9 +32,10 @@ from novelwriter.enum import nwItemClass, nwItemType, nwItemLayout
@pytest.mark.core
def testCoreItem_Setters(mockGUI):
def testCoreItem_Setters(mockGUI, constData):
"""Test all the simple setters for the NWItem class.
"""
random.seed(42)
theProject = NWProject(mockGUI)
theItem = NWItem(theProject)
@@ -42,6 +44,8 @@ def testCoreItem_Setters(mockGUI):
assert theItem.itemName == "A Name"
theItem.setName("\t A Name ")
assert theItem.itemName == "A Name"
theItem.setName("\t A\t\u2009\u202f\u2002\u2003\u2028\u2029Name ")
assert theItem.itemName == "A Name"
theItem.setName(123)
assert theItem.itemName == ""
@@ -89,50 +93,32 @@ def testCoreItem_Setters(mockGUI):
# Importance
theItem._class = nwItemClass.CHARACTER
theItem.setImport("Nonsense")
assert theItem.itemImport == "New"
theItem.setImport("New")
assert theItem.itemImport == "New"
theItem.setImport("Minor")
assert theItem.itemImport == "Minor"
theItem.setImport("Major")
assert theItem.itemImport == "Major"
theItem.setImport("Main")
assert theItem.itemImport == "Main"
theItem.setImport("Word")
assert theItem.itemImport == constData.importKeys[0] # Default
for key in constData.importKeys:
theItem.setImport(key)
assert theItem.itemImport == key
# Status
theItem._class = nwItemClass.NOVEL
theItem.setStatus("Nonsense")
assert theItem.itemStatus == "New"
theItem.setStatus("New")
assert theItem.itemStatus == "New"
theItem.setStatus("Note")
assert theItem.itemStatus == "Note"
theItem.setStatus("Draft")
assert theItem.itemStatus == "Draft"
theItem.setStatus("Finished")
assert theItem.itemStatus == "Finished"
theItem.setStatus("Word")
assert theItem.itemStatus == constData.statusKeys[0] # Default
for key in constData.statusKeys:
theItem.setStatus(key)
assert theItem.itemStatus == key
# Status/Importance Wrapper
theItem._class = nwItemClass.CHARACTER
theItem.setImportStatus("New")
assert theItem.itemImport == "New"
theItem.setImportStatus("Minor")
assert theItem.itemImport == "Minor"
theItem.setImportStatus("Note")
assert theItem.itemImport == "New"
theItem.setImportStatus("Draft")
assert theItem.itemImport == "New"
for key in constData.importKeys:
theItem.setImport(key)
assert theItem.itemImport == key
assert theItem.itemStatus == constData.statusKeys[3] # Should not change
theItem._class = nwItemClass.NOVEL
theItem.setImportStatus("New")
assert theItem.itemStatus == "New"
theItem.setImportStatus("Minor")
assert theItem.itemStatus == "New"
theItem.setImportStatus("Note")
assert theItem.itemStatus == "Note"
theItem.setImportStatus("Draft")
assert theItem.itemStatus == "Draft"
for key in constData.statusKeys:
theItem.setStatus(key)
assert theItem.itemImport == constData.importKeys[3] # Should not change
assert theItem.itemStatus == key
# Expanded
theItem.setExpanded(8)
@@ -366,9 +352,10 @@ def testCoreItem_LayoutSetter(mockGUI):
@pytest.mark.core
def testCoreItem_XMLPackUnpack(mockGUI, caplog):
def testCoreItem_XMLPackUnpack(mockGUI, caplog, constData):
"""Test packing and unpacking XML objects for the NWItem class.
"""
random.seed(42)
theProject = NWProject(mockGUI)
nwXML = etree.Element("novelWriterXML")
@@ -383,7 +370,7 @@ def testCoreItem_XMLPackUnpack(mockGUI, caplog):
theItem.setName("A Name")
theItem.setClass("NOVEL")
theItem.setType("FILE")
theItem.setStatus("Main")
theItem.setImport(constData.importKeys[3])
theItem.setLayout("NOTE")
theItem.setExported(False)
theItem.setParaCount(3)
@@ -398,15 +385,16 @@ def testCoreItem_XMLPackUnpack(mockGUI, caplog):
b'<content>'
b'<item handle="0123456789abc" parent="0123456789abc" root="0123456789abc" order="1" '
b'type="FILE" class="NOVEL" layout="NOTE"><meta charCount="7" wordCount="5" paraCount="3" '
b'cursorPos="11"/><name status="New" import="None" exported="False">A Name</name></item>'
b'cursorPos="11"/><name status="None" import="%s" exported="False">A Name</name></item>'
b'</content>'
)
) % bytes(constData.importKeys[3], encoding="utf8")
# Unpack
theItem = NWItem(theProject)
assert theItem.unpackXML(xContent[0])
assert theItem.itemHandle == "0123456789abc"
assert theItem.itemParent == "0123456789abc"
assert theItem.itemRoot == "0123456789abc"
assert theItem.itemOrder == 1
assert theItem.isExported is False
assert theItem.paraCount == 3
@@ -416,6 +404,8 @@ def testCoreItem_XMLPackUnpack(mockGUI, caplog):
assert theItem.itemClass == nwItemClass.NOVEL
assert theItem.itemType == nwItemType.FILE
assert theItem.itemLayout == nwItemLayout.NOTE
assert theItem.itemStatus == constData.statusKeys[0] # Was None, should now be default
assert theItem.itemImport == constData.importKeys[3]
# Folder
# ======
@@ -428,7 +418,7 @@ def testCoreItem_XMLPackUnpack(mockGUI, caplog):
theItem.setName("A Name")
theItem.setClass("NOVEL")
theItem.setType("FOLDER")
theItem.setStatus("Main")
theItem.setStatus(constData.statusKeys[1])
theItem.setLayout("NOTE")
theItem.setExpanded(True)
theItem.setExported(False)
@@ -443,16 +433,17 @@ def testCoreItem_XMLPackUnpack(mockGUI, caplog):
assert etree.tostring(xContent, pretty_print=False, encoding="utf-8") == (
b'<content>'
b'<item handle="0123456789abc" parent="0123456789abc" root="0123456789abc" order="1" '
b'type="FOLDER" class="NOVEL"><meta expanded="True"/><name status="New" '
b'type="FOLDER" class="NOVEL"><meta expanded="True"/><name status="%s" '
b'import="None">A Name</name></item>'
b'</content>'
)
) % bytes(constData.statusKeys[1], encoding="utf8")
# Unpack
theItem = NWItem(theProject)
assert theItem.unpackXML(xContent[0])
assert theItem.itemHandle == "0123456789abc"
assert theItem.itemParent == "0123456789abc"
assert theItem.itemRoot == "0123456789abc"
assert theItem.itemOrder == 1
assert theItem.isExpanded is True
assert theItem.isExported is True
@@ -463,6 +454,8 @@ def testCoreItem_XMLPackUnpack(mockGUI, caplog):
assert theItem.itemClass == nwItemClass.NOVEL
assert theItem.itemType == nwItemType.FOLDER
assert theItem.itemLayout == nwItemLayout.NO_LAYOUT
assert theItem.itemStatus == constData.statusKeys[1]
assert theItem.itemImport == constData.importKeys[0] # Was None, should now be default
# Errors
# ======
+141 -69
View File
@@ -19,8 +19,9 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
import pytest
import os
import pytest
import random
from shutil import copyfile
from zipfile import ZipFile
@@ -44,6 +45,7 @@ def testCoreProject_NewMinimal(fncDir, outDir, refDir, mockGUI):
testFile = os.path.join(outDir, "coreProject_NewMinimal_nwProject.nwx")
compFile = os.path.join(refDir, "coreProject_NewMinimal_nwProject.nwx")
random.seed(42)
theProject = NWProject(mockGUI)
theProject.projTree.setSeed(42)
@@ -112,6 +114,7 @@ def testCoreProject_NewCustomA(fncDir, outDir, refDir, mockGUI):
"numScenes": 3,
"chFolders": True,
}
random.seed(42)
theProject = NWProject(mockGUI)
theProject.projTree.setSeed(42)
@@ -154,6 +157,7 @@ def testCoreProject_NewCustomB(fncDir, outDir, refDir, mockGUI):
"numScenes": 6,
"chFolders": True,
}
random.seed(42)
theProject = NWProject(mockGUI)
theProject.projTree.setSeed(42)
@@ -262,6 +266,7 @@ def testCoreProject_NewRoot(fncDir, outDir, refDir, mockGUI):
testFile = os.path.join(outDir, "coreProject_NewRoot_nwProject.nwx")
compFile = os.path.join(refDir, "coreProject_NewRoot_nwProject.nwx")
random.seed(42)
theProject = NWProject(mockGUI)
theProject.projTree.setSeed(42)
@@ -299,6 +304,7 @@ def testCoreProject_NewFile(fncDir, outDir, refDir, mockGUI):
testFile = os.path.join(outDir, "coreProject_NewFile_nwProject.nwx")
compFile = os.path.join(refDir, "coreProject_NewFile_nwProject.nwx")
random.seed(42)
theProject = NWProject(mockGUI)
theProject.projTree.setSeed(42)
@@ -680,13 +686,127 @@ def testCoreProject_AccessItems(nwMinimal, mockGUI):
@pytest.mark.core
def testCoreProject_Methods(monkeypatch, nwMinimal, mockGUI, tmpDir):
def testCoreProject_StatusImport(mockGUI, fncDir, constData):
"""Test the status and importance flag handling.
"""
theProject = NWProject(mockGUI)
random.seed(42)
theProject.projTree.setSeed(42)
assert theProject.newProject({"projPath": fncDir}) is True
# Change Status
# =============
theProject.projTree["44cb730c42048"].setStatus("Finished")
theProject.projTree["71ee45a3c0db9"].setStatus("Draft")
theProject.projTree["811786ad1ae74"].setStatus("Note")
theProject.projTree["25fc0e7096fc6"].setStatus("Finished")
assert theProject.projTree["44cb730c42048"].itemStatus == constData.statusKeys[3]
assert theProject.projTree["71ee45a3c0db9"].itemStatus == constData.statusKeys[2]
assert theProject.projTree["811786ad1ae74"].itemStatus == constData.statusKeys[1]
assert theProject.projTree["25fc0e7096fc6"].itemStatus == constData.statusKeys[3]
newList = [
{"key": constData.statusKeys[0], "name": "New", "cols": (1, 1, 1)},
{"key": constData.statusKeys[1], "name": "Draft", "cols": (2, 2, 2)}, # These are swapped
{"key": constData.statusKeys[2], "name": "Note", "cols": (3, 3, 3)}, # These are swapped
{"key": constData.statusKeys[3], "name": "Edited", "cols": (4, 4, 4)}, # Renamed
{"key": None, "name": "Finished", "cols": (5, 5, 5)}, # New, reused name
]
assert theProject.setStatusColours(None, None) is False
assert theProject.setStatusColours([], []) is False
assert theProject.setStatusColours(newList, []) is True
assert theProject.statusItems.name(constData.statusKeys[0]) == "New"
assert theProject.statusItems.name(constData.statusKeys[1]) == "Draft"
assert theProject.statusItems.name(constData.statusKeys[2]) == "Note"
assert theProject.statusItems.name(constData.statusKeys[3]) == "Edited"
assert theProject.statusItems.cols(constData.statusKeys[0]) == (1, 1, 1)
assert theProject.statusItems.cols(constData.statusKeys[1]) == (2, 2, 2)
assert theProject.statusItems.cols(constData.statusKeys[2]) == (3, 3, 3)
assert theProject.statusItems.cols(constData.statusKeys[3]) == (4, 4, 4)
# Check the new entry
lastKey = theProject.statusItems.check("Finished")
assert lastKey == "sbc8960"
assert theProject.statusItems.name(lastKey) == "Finished"
assert theProject.statusItems.cols(lastKey) == (5, 5, 5)
# Delete last entry
assert theProject.setStatusColours([], [lastKey]) is True
assert theProject.statusItems.name(lastKey) == "New"
# Change Importance
# =================
fHandle = theProject.newFile("Jane Doe", nwItemClass.CHARACTER, "73475cb40a568")
theProject.projTree[fHandle].setImport("Main")
assert theProject.projTree[fHandle].itemImport == constData.importKeys[3]
newList = [
{"key": constData.importKeys[0], "name": "New", "cols": (1, 1, 1)},
{"key": constData.importKeys[1], "name": "Minor", "cols": (2, 2, 2)},
{"key": constData.importKeys[2], "name": "Major", "cols": (3, 3, 3)},
{"key": constData.importKeys[3], "name": "Min", "cols": (4, 4, 4)},
{"key": None, "name": "Max", "cols": (5, 5, 5)},
]
assert theProject.setImportColours(None, None) is False
assert theProject.setImportColours([], []) is False
assert theProject.setImportColours(newList, []) is True
assert theProject.importItems.name(constData.importKeys[0]) == "New"
assert theProject.importItems.name(constData.importKeys[1]) == "Minor"
assert theProject.importItems.name(constData.importKeys[2]) == "Major"
assert theProject.importItems.name(constData.importKeys[3]) == "Min"
assert theProject.importItems.cols(constData.importKeys[0]) == (1, 1, 1)
assert theProject.importItems.cols(constData.importKeys[1]) == (2, 2, 2)
assert theProject.importItems.cols(constData.importKeys[2]) == (3, 3, 3)
assert theProject.importItems.cols(constData.importKeys[3]) == (4, 4, 4)
# Check the new entry
lastKey = theProject.importItems.check("Max")
assert lastKey == "i1a3d1f"
assert theProject.importItems.name(lastKey) == "Max"
assert theProject.importItems.cols(lastKey) == (5, 5, 5)
# Delete last entry
assert theProject.setImportColours([], [lastKey]) is True
assert theProject.importItems.name(lastKey) == "New"
# Delete Status/Import
# ====================
theProject.statusItems.resetCounts()
for key in list(theProject.statusItems.keys()):
assert theProject.statusItems.remove(key) is True
theProject.importItems.resetCounts()
for key in list(theProject.importItems.keys()):
assert theProject.importItems.remove(key) is True
assert len(theProject.statusItems) == 0
assert len(theProject.importItems) == 0
assert theProject.saveProject() is True
assert theProject.closeProject() is True
# This should restore the default status/import labels
random.seed(42)
assert theProject.openProject(fncDir) is True
assert theProject.saveProject() is True
assert list(theProject.statusItems.keys()) == constData.statusKeys
assert list(theProject.importItems.keys()) == constData.importKeys
# END Test testCoreProject_StatusImport
@pytest.mark.core
def testCoreProject_Methods(monkeypatch, mockGUI, tmpDir, fncDir):
"""Test other project class methods and functions.
"""
theProject = NWProject(mockGUI)
theProject.projTree.setSeed(42)
assert theProject.openProject(nwMinimal)
assert theProject.projPath == nwMinimal
assert theProject.newProject({"projPath": fncDir}) is True
# Setting project path
assert theProject.setProjectPath(None)
@@ -697,16 +817,16 @@ def testCoreProject_Methods(monkeypatch, nwMinimal, mockGUI, tmpDir):
assert theProject.projPath == os.path.expanduser("~")
# Create a new folder and populate it
projPath = os.path.join(nwMinimal, "mock1")
projPath = os.path.join(fncDir, "mock1")
assert theProject.setProjectPath(projPath, newProject=True)
# Make os.mkdir fail
monkeypatch.setattr("os.mkdir", causeOSError)
projPath = os.path.join(nwMinimal, "mock2")
projPath = os.path.join(fncDir, "mock2")
assert not theProject.setProjectPath(projPath, newProject=True)
# Set back
assert theProject.setProjectPath(nwMinimal)
assert theProject.setProjectPath(fncDir)
# Project Name
assert theProject.setProjectName(" A Name ")
@@ -744,9 +864,10 @@ def testCoreProject_Methods(monkeypatch, nwMinimal, mockGUI, tmpDir):
# Trash folder
# Should create on first call, and just returned on later calls
assert theProject.projTree["73475cb40a568"] is None
assert theProject.trashFolder() == "73475cb40a568"
assert theProject.trashFolder() == "73475cb40a568"
hTrash = "1a6562590ef19"
assert theProject.projTree[hTrash] is None
assert theProject.trashFolder() == hTrash
assert theProject.trashFolder() == hTrash
# Project backup
assert theProject.doBackup is True
@@ -770,9 +891,10 @@ def testCoreProject_Methods(monkeypatch, nwMinimal, mockGUI, tmpDir):
# Spell language
theProject.projChanged = False
assert theProject.setSpellLang(None)
assert theProject.projSpell is None
assert theProject.setSpellLang("None")
assert theProject.setSpellLang(None) is False
assert theProject.projSpell is None
assert theProject.setSpellLang("None") is False # Should be interpreded as None
assert theProject.projSpell is None
assert theProject.setSpellLang("en_GB")
assert theProject.projSpell == "en_GB"
@@ -812,14 +934,14 @@ def testCoreProject_Methods(monkeypatch, nwMinimal, mockGUI, tmpDir):
# Change project tree order
oldOrder = [
"a508bb932959c", "a35baf2e93843", "a6d311a93600a",
"f5ab3e30151e1", "8c659a11cd429", "7695ce551d265",
"afb3043c7b2b3", "9d5247ab588e0", "73475cb40a568",
"73475cb40a568", "44cb730c42048", "71ee45a3c0db9",
"811786ad1ae74", "25fc0e7096fc6", "31489056e0916",
"98010bd9270f9", "0e17daca5f3e1", "1a6562590ef19",
]
newOrder = [
"f5ab3e30151e1", "8c659a11cd429", "7695ce551d265",
"a508bb932959c", "a35baf2e93843", "a6d311a93600a",
"afb3043c7b2b3", "9d5247ab588e0",
"811786ad1ae74", "25fc0e7096fc6", "31489056e0916",
"73475cb40a568", "44cb730c42048", "71ee45a3c0db9",
"98010bd9270f9", "0e17daca5f3e1",
]
assert theProject.projTree.handles() == oldOrder
assert theProject.setTreeOrder(newOrder)
@@ -827,56 +949,6 @@ def testCoreProject_Methods(monkeypatch, nwMinimal, mockGUI, tmpDir):
assert theProject.setTreeOrder(oldOrder)
assert theProject.projTree.handles() == oldOrder
# Change status
theProject.projTree["a35baf2e93843"].setStatus("Finished")
theProject.projTree["a6d311a93600a"].setStatus("Draft")
theProject.projTree["f5ab3e30151e1"].setStatus("Note")
theProject.projTree["8c659a11cd429"].setStatus("Finished")
newList = [
("New", 1, 1, 1, "New"),
("Draft", 2, 2, 2, "Note"), # These are swapped
("Note", 3, 3, 3, "Draft"), # These are swapped
("Edited", 4, 4, 4, "Finished"), # Renamed
("Finished", 5, 5, 5, None), # New, with reused name
]
assert theProject.setStatusColours(newList)
assert theProject.statusItems._theLabels == [
"New", "Draft", "Note", "Edited", "Finished"
]
assert theProject.statusItems._theColours == [
(1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4), (5, 5, 5)
]
assert theProject.projTree["a35baf2e93843"].itemStatus == "Edited" # Renamed
assert theProject.projTree["a6d311a93600a"].itemStatus == "Note" # Swapped
assert theProject.projTree["f5ab3e30151e1"].itemStatus == "Draft" # Swapped
assert theProject.projTree["8c659a11cd429"].itemStatus == "Edited" # Renamed
# Change importance
fHandle = theProject.newFile("Jane Doe", nwItemClass.CHARACTER, "afb3043c7b2b3")
theProject.projTree[fHandle].setImport("Main")
newList = [
("New", 1, 1, 1, "New"),
("Minor", 2, 2, 2, "Minor"),
("Major", 3, 3, 3, "Major"),
("Min", 4, 4, 4, "Main"),
("Max", 5, 5, 5, None),
]
assert theProject.setImportColours(newList)
assert theProject.importItems._theLabels == [
"New", "Minor", "Major", "Min", "Max"
]
assert theProject.importItems._theColours == [
(1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4), (5, 5, 5)
]
assert theProject.projTree[fHandle].itemImport == "Min"
# Check status counts
assert theProject.statusItems._theCounts == [0, 0, 0, 0, 0]
assert theProject.importItems._theCounts == [0, 0, 0, 0, 0]
theProject.countStatus()
assert theProject.statusItems._theCounts == [1, 1, 1, 2, 0]
assert theProject.importItems._theCounts == [3, 0, 0, 1, 0]
# Session stats
theProject.currWCount = 200
theProject.lastWCount = 100
@@ -890,7 +962,7 @@ def testCoreProject_Methods(monkeypatch, nwMinimal, mockGUI, tmpDir):
assert not theProject._appendSessionStats(idleTime=0)
# Write entry
assert theProject.projMeta == os.path.join(nwMinimal, "meta")
assert theProject.projMeta == os.path.join(fncDir, "meta")
statsFile = os.path.join(theProject.projMeta, nwFiles.SESS_STATS)
theProject.projOpened = 1600002000
+290 -86
View File
@@ -20,6 +20,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
import pytest
import random
from lxml import etree
@@ -29,103 +30,300 @@ from novelwriter.core.status import NWStatus
@pytest.mark.core
def testCoreStatus_Entries():
"""Test all the simple setters for the NWItem class.
def testCoreStatus_Internal(constData):
"""Test all the internal functions of the NWStatus class.
"""
theStatus = NWStatus()
random.seed(42)
theStatus = NWStatus(NWStatus.STATUS)
theImport = NWStatus(NWStatus.IMPORT)
# Add entries
theStatus.addEntry("New", (100, 100, 100))
theStatus.addEntry("Minor", (200, 50, 0))
theStatus.addEntry("Major", (200, 150, 0))
theStatus.addEntry("Main", (50, 200, 0))
with pytest.raises(Exception):
NWStatus(999)
assert theStatus._theLabels == ["New", "Minor", "Major", "Main"]
assert theStatus._theColours == [(100, 100, 100), (200, 50, 0), (200, 150, 0), (50, 200, 0)]
assert theStatus._theCounts == [0, 0, 0, 0]
assert theStatus._theMap["New"] == 0
assert theStatus._theMap["Minor"] == 1
assert theStatus._theMap["Major"] == 2
assert theStatus._theMap["Main"] == 3
assert theStatus._theLength == 4
# Generate Key
# ============
# Lookups
assert theStatus._getIndex(None) is None
assert theStatus._getIndex("stuff") is None
assert theStatus._getIndex("Main") == 3
assert theStatus._newKey() == constData.statusKeys[0]
assert theStatus._newKey() == constData.statusKeys[1]
# Checks
assert theStatus.checkEntry(123) == "New"
assert theStatus.checkEntry("Stuff") == "New"
assert theStatus.checkEntry("New ") == "New"
assert theStatus.checkEntry(" Main ") == "Main"
# Key collision, should move to key 3
theStatus.write(constData.statusKeys[2], "Crash", (0, 0, 0))
assert theStatus._newKey() == constData.statusKeys[3]
# Icons
assert isinstance(theStatus.getIcon("Stuff"), QIcon)
assert isinstance(theStatus.getIcon("New"), QIcon)
assert theImport._newKey() == constData.importKeys[0]
assert theImport._newKey() == constData.importKeys[1]
# Set new list
newList = [
("New", 1, 1, 1, "New"),
("Minor", 2, 2, 2, "Minor"),
("Major", 3, 3, 3, "Major"),
("Min", 4, 4, 4, "Main"),
("Max", 5, 5, 5, None),
]
assert theStatus.setNewEntries(None) == {}
assert theStatus.setNewEntries(newList) == {"Main": "Min"}
# Key collision, should move to key 3
theImport.write(constData.importKeys[2], "Crash", (0, 0, 0))
assert theImport._newKey() == constData.importKeys[3]
assert theStatus._theLabels == ["New", "Minor", "Major", "Min", "Max"]
assert theStatus._theColours == [(1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4), (5, 5, 5)]
assert theStatus._theCounts == [0, 0, 0, 0, 0]
assert theStatus._theMap["New"] == 0
assert theStatus._theMap["Minor"] == 1
assert theStatus._theMap["Major"] == 2
assert theStatus._theMap["Min"] == 3
assert theStatus._theMap["Max"] == 4
assert theStatus._theLength == 5
# Check Key
# =========
# Add counts
countTo = [3, 5, 7, 9, 11]
for i, n in enumerate(countTo):
for _ in range(n):
theStatus.countEntry(theStatus._theLabels[i])
assert theStatus._theCounts == countTo
assert theStatus._isKey(None) is False # Not a string
assert theStatus._isKey("s00000") is False # Too short
assert theStatus._isKey("s000000") is True # Correct length
assert theStatus._isKey("s0000000") is False # Too long
assert theStatus._isKey("i000000") is False # Wrong type
assert theStatus._isKey("q000000") is False # Wrong type
assert theStatus._isKey("s12345H") is False # Not a hex value
assert theStatus._isKey("s12345F") is False # Not a lower case hex value
assert theStatus._isKey("s12345f") is True # Valid hex value
assert theImport._isKey(None) is False # Not a string
assert theImport._isKey("i00000") is False # Too short
assert theImport._isKey("i000000") is True # Correct length
assert theImport._isKey("i0000000") is False # Too long
assert theImport._isKey("s000000") is False # Wrong type
assert theImport._isKey("q000000") is False # Wrong type
assert theImport._isKey("i12345H") is False # Not a hex value
assert theImport._isKey("i12345F") is False # Not a lower case hex value
assert theImport._isKey("i12345f") is True # Valid hex value
# END Test testCoreStatus_Internal
@pytest.mark.core
def testCoreStatus_Iterator(constData):
"""Test the iterator functions of the NWStatus class.
"""
random.seed(42)
theStatus = NWStatus(NWStatus.STATUS)
theStatus.write(None, "New", (100, 100, 100))
theStatus.write(None, "Note", (200, 50, 0))
theStatus.write(None, "Draft", (200, 150, 0))
theStatus.write(None, "Finished", (50, 200, 0))
# Direct access
entry = theStatus[constData.statusKeys[0]]
assert entry["cols"] == (100, 100, 100)
assert entry["name"] == "New"
assert entry["count"] == 0
assert isinstance(entry["icon"], QIcon)
# Iterate
for i, (sA, sB, sC, sD) in enumerate(theStatus):
assert sA == theStatus._theLabels[i]
assert sB == theStatus._theColours[i]
assert sC == theStatus._theCounts[i]
assert sD == theStatus._theIcons[i]
entries = list(theStatus)
assert len(entries) == 4
assert len(theStatus) == 4
sA, sB, sC, sD = theStatus[9]
assert sA is None
assert sB is None
assert sC is None
assert isinstance(sD, QIcon)
# Keys
assert list(theStatus.keys()) == constData.statusKeys
# Items
for index, (key, entry) in enumerate(theStatus.items()):
assert key == constData.statusKeys[index]
assert "cols" in entry
assert "name" in entry
assert "count" in entry
assert "icon" in entry
# Valuse
for entry in theStatus.values():
assert "cols" in entry
assert "name" in entry
assert "count" in entry
assert "icon" in entry
# END Test testCoreStatus_Iterator
@pytest.mark.core
def testCoreStatus_Entries(constData):
"""Test all the simple setters for the NWStatus class.
"""
random.seed(42)
theStatus = NWStatus(NWStatus.STATUS)
# Write
# =====
# Have a key
theStatus.write(constData.statusKeys[0], "Entry 1", (200, 100, 50))
assert theStatus[constData.statusKeys[0]]["name"] == "Entry 1"
assert theStatus[constData.statusKeys[0]]["cols"] == (200, 100, 50)
# Don't have a key
theStatus.write(None, "Entry 2", (210, 110, 60))
assert theStatus[constData.statusKeys[1]]["name"] == "Entry 2"
assert theStatus[constData.statusKeys[1]]["cols"] == (210, 110, 60)
# Wrong colour spec
theStatus.write(None, "Entry 3", "what?")
assert theStatus[constData.statusKeys[2]]["name"] == "Entry 3"
assert theStatus[constData.statusKeys[2]]["cols"] == (100, 100, 100)
# Wrong colour count
theStatus.write(None, "Entry 4", (10, 20))
assert theStatus[constData.statusKeys[3]]["name"] == "Entry 4"
assert theStatus[constData.statusKeys[3]]["cols"] == (100, 100, 100)
# Check reverse map
assert theStatus._reverse == {
"Entry 1": constData.statusKeys[0],
"Entry 2": constData.statusKeys[1],
"Entry 3": constData.statusKeys[2],
"Entry 4": constData.statusKeys[3],
}
# Check
# =====
# Normal lookup
for key in constData.statusKeys:
assert theStatus.check(key) == key
# Reverse map lookup
assert theStatus.check("Entry 1") == constData.statusKeys[0]
assert theStatus.check("Entry 2") == constData.statusKeys[1]
assert theStatus.check("Entry 3") == constData.statusKeys[2]
assert theStatus.check("Entry 4") == constData.statusKeys[3]
# Non-existing name
assert theStatus.check("Entry 5") == constData.statusKeys[0]
# Name Access
# ===========
assert theStatus.name(constData.statusKeys[0]) == "Entry 1"
assert theStatus.name(constData.statusKeys[1]) == "Entry 2"
assert theStatus.name(constData.statusKeys[2]) == "Entry 3"
assert theStatus.name(constData.statusKeys[3]) == "Entry 4"
assert theStatus.name("blablabla") == "Entry 1"
# Colour Access
# =============
assert theStatus.cols(constData.statusKeys[0]) == (200, 100, 50)
assert theStatus.cols(constData.statusKeys[1]) == (210, 110, 60)
assert theStatus.cols(constData.statusKeys[2]) == (100, 100, 100)
assert theStatus.cols(constData.statusKeys[3]) == (100, 100, 100)
assert theStatus.cols("blablabla") == (200, 100, 50)
# Icon Access
# ===========
assert isinstance(theStatus.icon(constData.statusKeys[0]), QIcon)
assert isinstance(theStatus.icon(constData.statusKeys[1]), QIcon)
assert isinstance(theStatus.icon(constData.statusKeys[2]), QIcon)
assert isinstance(theStatus.icon(constData.statusKeys[3]), QIcon)
assert isinstance(theStatus.icon("blablabla"), QIcon)
# Increment and Count Access
# ==========================
countTo = [3, 5, 7, 9]
for i, n in enumerate(countTo):
for _ in range(n):
theStatus.increment(constData.statusKeys[i])
assert theStatus.count(constData.statusKeys[0]) == countTo[0]
assert theStatus.count(constData.statusKeys[1]) == countTo[1]
assert theStatus.count(constData.statusKeys[2]) == countTo[2]
assert theStatus.count(constData.statusKeys[3]) == countTo[3]
assert theStatus.count("blablabla") == countTo[0]
# Clear counts
theStatus.resetCounts()
assert theStatus._theCounts == [0, 0, 0, 0, 0]
assert theStatus.count(constData.statusKeys[0]) == 0
assert theStatus.count(constData.statusKeys[1]) == 0
assert theStatus.count(constData.statusKeys[2]) == 0
assert theStatus.count(constData.statusKeys[3]) == 0
# Reorder
# =======
cOrder = list(theStatus.keys())
assert cOrder == constData.statusKeys
# Wrong length
assert theStatus.reorder([]) is False
# No change
assert theStatus.reorder(cOrder) is False
# Actual reaorder
nOrder = [
constData.statusKeys[0],
constData.statusKeys[2],
constData.statusKeys[1],
constData.statusKeys[3],
]
assert theStatus.reorder(nOrder) is True
assert list(theStatus.keys()) == nOrder
# Add an unknown key
wOrder = nOrder.copy()
wOrder[3] = theStatus._newKey()
assert theStatus.reorder(wOrder) is False
assert list(theStatus.keys()) == nOrder
# Put it back
assert theStatus.reorder(cOrder) is True
assert list(theStatus.keys()) == cOrder
# Default
# =======
default = theStatus._default
theStatus._default = None
assert theStatus.check("Entry 5") == ""
assert theStatus.name("blablabla") == ""
assert theStatus.cols("blablabla") == (100, 100, 100)
assert theStatus.count("blablabla") == 0
assert isinstance(theStatus.icon("blablabla"), QIcon)
theStatus._default = default
# Remove
# ======
# Non-existing entry
assert theStatus.remove("blablabla") is False
# Non-zero entry
theStatus.increment(constData.statusKeys[3])
assert theStatus.remove(constData.statusKeys[3]) is False
# Delete last entry
theStatus.resetCounts()
lastName = theStatus.name(constData.statusKeys[3])
assert lastName == "Entry 4"
assert theStatus.remove(constData.statusKeys[3]) is True
assert theStatus.check(constData.statusKeys[3]) == theStatus._default
assert theStatus.check(lastName) == theStatus._default
# Delete default entry, Entry 2 is new default
firstName = theStatus.name(theStatus._default)
assert firstName == "Entry 1"
assert theStatus.remove(theStatus._default) is True
assert theStatus.name(firstName) == "Entry 2"
# Remove remaining entries
assert theStatus.remove(constData.statusKeys[1]) is True
assert theStatus.remove(constData.statusKeys[2]) is True
assert len(theStatus) == 0
assert theStatus._default is None
# END Test testCoreStatus_Entries
@pytest.mark.core
def testCoreStatus_XMLPackUnpack():
"""Test all the simple setters for the NWItem class.
def testCoreStatus_XMLPackUnpack(constData):
"""Test all the XML pack/unpack of the NWStatus class.
"""
theStatus = NWStatus()
theStatus.addEntry("New", (100, 100, 100))
theStatus.addEntry("Minor", (200, 50, 0))
theStatus.addEntry("Major", (200, 150, 0))
theStatus.addEntry("Main", (50, 200, 0))
random.seed(42)
theStatus = NWStatus(NWStatus.STATUS)
theStatus.write(None, "New", (100, 100, 100))
theStatus.write(None, "Note", (200, 50, 0))
theStatus.write(None, "Draft", (200, 150, 0))
theStatus.write(None, "Finished", (50, 200, 0))
countTo = [3, 5, 7, 9]
for i, n in enumerate(countTo):
for _ in range(n):
theStatus.countEntry(theStatus._theLabels[i])
theStatus.increment(constData.statusKeys[i])
nwXML = etree.Element("novelWriterXML")
@@ -134,23 +332,29 @@ def testCoreStatus_XMLPackUnpack():
theStatus.packXML(xStatus)
assert etree.tostring(xStatus, pretty_print=False, encoding="utf-8") == (
b'<status>'
b'<entry red="100" green="100" blue="100">New</entry>'
b'<entry red="200" green="50" blue="0">Minor</entry>'
b'<entry red="200" green="150" blue="0">Major</entry>'
b'<entry red="50" green="200" blue="0">Main</entry>'
b'<entry key="sa3b179" count="3" red="100" green="100" blue="100">New</entry>'
b'<entry key="s1c8031" count="5" red="200" green="50" blue="0">Note</entry>'
b'<entry key="s06671a" count="7" red="200" green="150" blue="0">Draft</entry>'
b'<entry key="sbdd640" count="9" red="50" green="200" blue="0">Finished</entry>'
b'</status>'
)
# Unpack
theStatus = NWStatus()
theStatus = NWStatus(NWStatus.STATUS)
assert theStatus.unpackXML(xStatus)
assert theStatus._theLabels == ["New", "Minor", "Major", "Main"]
assert theStatus._theColours == [(100, 100, 100), (200, 50, 0), (200, 150, 0), (50, 200, 0)]
assert theStatus._theCounts == [0, 0, 0, 0]
assert theStatus._theMap["New"] == 0
assert theStatus._theMap["Minor"] == 1
assert theStatus._theMap["Major"] == 2
assert theStatus._theMap["Main"] == 3
assert theStatus._theLength == 4
assert len(theStatus._store) == 4
assert list(theStatus._store.keys()) == constData.statusKeys
assert theStatus._store[constData.statusKeys[0]]["name"] == "New"
assert theStatus._store[constData.statusKeys[1]]["name"] == "Note"
assert theStatus._store[constData.statusKeys[2]]["name"] == "Draft"
assert theStatus._store[constData.statusKeys[3]]["name"] == "Finished"
assert theStatus._store[constData.statusKeys[0]]["cols"] == (100, 100, 100)
assert theStatus._store[constData.statusKeys[1]]["cols"] == (200, 50, 0)
assert theStatus._store[constData.statusKeys[2]]["cols"] == (200, 150, 0)
assert theStatus._store[constData.statusKeys[3]]["cols"] == (50, 200, 0)
assert theStatus._store[constData.statusKeys[0]]["count"] == countTo[0]
assert theStatus._store[constData.statusKeys[1]]["count"] == countTo[1]
assert theStatus._store[constData.statusKeys[2]]["count"] == countTo[2]
assert theStatus._store[constData.statusKeys[3]]["count"] == countTo[3]
# END Test testCoreStatus_XMLPackUnpack
+25 -11
View File
@@ -20,6 +20,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
import pytest
import random
from tools import getGuiItem
@@ -88,7 +89,7 @@ def testDlgItemEditor_Dialog(qtbot, monkeypatch, nwGUI, fncProj):
@pytest.mark.gui
def testDlgItemEditor_Novel(qtbot, monkeypatch, nwGUI, fncProj):
def testDlgItemEditor_Novel(qtbot, monkeypatch, nwGUI, fncProj, constData):
"""Test the item editor dialog for a novel document.
"""
# Block message box
@@ -96,9 +97,13 @@ def testDlgItemEditor_Novel(qtbot, monkeypatch, nwGUI, fncProj):
monkeypatch.setattr(GuiProjectTree, "hasFocus", lambda *a: True)
# Create Project and Open Document
random.seed(42)
nwGUI.theProject.projTree.setSeed(42)
assert nwGUI.newProject({"projPath": fncProj})
assert nwGUI.openDocument("0e17daca5f3e1")
assert nwGUI.theProject.statusItems.name(constData.statusKeys[0]) == "New"
assert nwGUI.theProject.statusItems.name(constData.statusKeys[1]) == "Note"
assert nwGUI.openDocument("0e17daca5f3e1") is True
# Check that an invalid handle is managed
itemEdit = GuiItemEditor(nwGUI, "whatever")
@@ -111,7 +116,7 @@ def testDlgItemEditor_Novel(qtbot, monkeypatch, nwGUI, fncProj):
# Check Existing Settings
assert itemEdit.editName.text() == "New Scene"
assert itemEdit.editStatus.currentData() == "New"
assert itemEdit.editStatus.currentData() == constData.statusKeys[0]
assert itemEdit.editLayout.currentData() == nwItemLayout.DOCUMENT
assert itemEdit.editExport.isChecked() is True
@@ -125,7 +130,7 @@ def testDlgItemEditor_Novel(qtbot, monkeypatch, nwGUI, fncProj):
# Check New Settings
itemEdit._doSave()
assert itemEdit.theItem.itemName == "Great Scene"
assert itemEdit.theItem.itemStatus == "Note"
assert itemEdit.theItem.itemStatus == constData.statusKeys[1]
assert itemEdit.theItem.itemLayout == nwItemLayout.NOTE
assert itemEdit.theItem.isExported is False
@@ -141,7 +146,7 @@ def testDlgItemEditor_Novel(qtbot, monkeypatch, nwGUI, fncProj):
@pytest.mark.gui
def testDlgItemEditor_Note(qtbot, monkeypatch, nwGUI, fncProj):
def testDlgItemEditor_Note(qtbot, monkeypatch, nwGUI, fncProj, constData):
"""Test the item editor dialog for a project note.
"""
# Block message box
@@ -149,8 +154,13 @@ def testDlgItemEditor_Note(qtbot, monkeypatch, nwGUI, fncProj):
monkeypatch.setattr(GuiProjectTree, "hasFocus", lambda *a: True)
# Create Project and Open Document
random.seed(42)
nwGUI.theProject.projTree.setSeed(42)
assert nwGUI.newProject({"projPath": fncProj})
assert nwGUI.theProject.statusItems.name(constData.statusKeys[0]) == "New"
assert nwGUI.theProject.statusItems.name(constData.statusKeys[1]) == "Note"
assert nwGUI.theProject.importItems.name(constData.importKeys[0]) == "New"
assert nwGUI.theProject.importItems.name(constData.importKeys[1]) == "Minor"
# Create Note
nwGUI.treeView.clearSelection()
@@ -166,7 +176,7 @@ def testDlgItemEditor_Note(qtbot, monkeypatch, nwGUI, fncProj):
# Check Existing Settings
assert itemEdit.editName.text() == "New File"
assert itemEdit.editStatus.currentData() == "New"
assert itemEdit.editStatus.currentData() == constData.importKeys[0]
assert itemEdit.editLayout.currentData() == nwItemLayout.NOTE
assert itemEdit.editExport.isChecked() is True
@@ -178,8 +188,8 @@ def testDlgItemEditor_Note(qtbot, monkeypatch, nwGUI, fncProj):
# Check New Settings
assert itemEdit.theItem.itemName == "New Character"
assert itemEdit.theItem.itemStatus == "New"
assert itemEdit.theItem.itemImport == "Minor"
assert itemEdit.theItem.itemStatus == constData.statusKeys[0]
assert itemEdit.theItem.itemImport == constData.importKeys[1]
assert itemEdit.theItem.itemLayout == nwItemLayout.NOTE
assert itemEdit.theItem.isExported is False
@@ -191,7 +201,7 @@ def testDlgItemEditor_Note(qtbot, monkeypatch, nwGUI, fncProj):
@pytest.mark.gui
def testDlgItemEditor_Folder(qtbot, monkeypatch, nwGUI, fncProj):
def testDlgItemEditor_Folder(qtbot, monkeypatch, nwGUI, fncProj, constData):
"""Test the item editor dialog for a folder.
"""
# Block message box
@@ -199,6 +209,7 @@ def testDlgItemEditor_Folder(qtbot, monkeypatch, nwGUI, fncProj):
monkeypatch.setattr(GuiProjectTree, "hasFocus", lambda *a: True)
# Create Project and Open Document
random.seed(42)
nwGUI.theProject.projTree.setSeed(42)
assert nwGUI.newProject({"projPath": fncProj})
@@ -206,9 +217,12 @@ def testDlgItemEditor_Folder(qtbot, monkeypatch, nwGUI, fncProj):
itemEdit = GuiItemEditor(nwGUI, "31489056e0916")
itemEdit.show()
assert nwGUI.theProject.statusItems.name(constData.statusKeys[0]) == "New"
assert nwGUI.theProject.statusItems.name(constData.statusKeys[1]) == "Note"
# Check Existing Settings
assert itemEdit.editName.text() == "New Chapter"
assert itemEdit.editStatus.currentData() == "New"
assert itemEdit.editStatus.currentData() == constData.statusKeys[0]
assert itemEdit.editLayout.currentData() == nwItemLayout.NO_LAYOUT
assert itemEdit.editExport.isChecked() is False
@@ -222,7 +236,7 @@ def testDlgItemEditor_Folder(qtbot, monkeypatch, nwGUI, fncProj):
# Check New Settings
itemEdit._doSave()
assert itemEdit.theItem.itemName == "Chapter One"
assert itemEdit.theItem.itemStatus == "Note"
assert itemEdit.theItem.itemStatus == constData.statusKeys[1]
assert itemEdit.theItem.itemLayout == nwItemLayout.NO_LAYOUT
assert itemEdit.theItem.isExported is False
+2 -1
View File
@@ -42,7 +42,8 @@ def testDlgLoadProject_Main(qtbot, monkeypatch, nwGUI, nwMinimal):
"""Test the load project wizard.
"""
# Block message box
monkeypatch.setattr(QMessageBox, "question", lambda *args: QMessageBox.Yes)
monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)
monkeypatch.setattr(QMessageBox, "information", lambda *a: QMessageBox.Yes)
assert nwGUI.openProject(nwMinimal)
assert nwGUI.closeProject()
+55 -21
View File
@@ -19,17 +19,16 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
import pytest
import os
import pytest
import random
from shutil import copyfile
from tools import cmpFiles, getGuiItem
from PyQt5.QtGui import QColor
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import (
QDialog, QAction, QMessageBox, QColorDialog, QTreeWidgetItem
)
from PyQt5.QtWidgets import QDialog, QAction, QMessageBox, QColorDialog
from novelwriter.dialogs import GuiProjectSettings
@@ -39,7 +38,9 @@ stepDelay = 20
@pytest.mark.gui
def testDlgProjSettings_Dialog(qtbot, monkeypatch, nwGUI, fncDir, fncProj, outDir, refDir):
def testDlgProjSettings_Dialog(
qtbot, monkeypatch, nwGUI, fncDir, fncProj, outDir, refDir, constData
):
"""Test the full project settings dialog.
"""
projFile = os.path.join(fncProj, "nwProject.nwx")
@@ -55,6 +56,7 @@ def testDlgProjSettings_Dialog(qtbot, monkeypatch, nwGUI, fncDir, fncProj, outDi
assert getGuiItem("GuiProjectSettings") is None
# Create new project
random.seed(42)
nwGUI.theProject.projTree.setSeed(42)
assert nwGUI.newProject({"projPath": fncProj})
nwGUI.mainConf.backupPath = fncDir
@@ -111,19 +113,9 @@ def testDlgProjSettings_Dialog(qtbot, monkeypatch, nwGUI, fncDir, fncProj, outDi
projEdit._tabBox.setCurrentWidget(projEdit.tabStatus)
assert projEdit.tabStatus.colChanged is False
assert projEdit.tabStatus.getNewList() is None
assert projEdit.tabStatus.getNewList() == ([], [])
assert projEdit.tabStatus.listBox.topLevelItemCount() == 4
# Fake drag'n'drop should change changed status
projEdit.tabStatus._rowsMoved()
assert projEdit.tabStatus.colChanged is True
projEdit.tabStatus.colChanged = False
projEdit.tabStatus.listBox.clearSelection()
assert projEdit.tabStatus._getSelectedItem() is None
projEdit.tabStatus.listBox.topLevelItem(0).setSelected(True)
assert isinstance(projEdit.tabStatus._getSelectedItem(), QTreeWidgetItem)
# Can't delete the first item (it's in use)
projEdit.tabStatus.listBox.clearSelection()
projEdit.tabStatus.listBox.topLevelItem(0).setSelected(True)
@@ -150,11 +142,53 @@ def testDlgProjSettings_Dialog(qtbot, monkeypatch, nwGUI, fncDir, fncProj, outDi
qtbot.wait(stepDelay)
assert projEdit.tabStatus.colChanged is True
assert projEdit.tabStatus.getNewList() == [
("New", 100, 100, 100, "New"),
("Note", 200, 50, 0, "Note"),
("Finished", 50, 200, 0, "Finished"),
("Final", 20, 30, 40, None)
assert projEdit.tabStatus.getNewList() == (
[
{
"key": constData.statusKeys[0],
"name": "New",
"cols": (100, 100, 100)
}, {
"key": constData.statusKeys[1],
"name": "Note",
"cols": (200, 50, 0)
}, {
"key": constData.statusKeys[3],
"name": "Finished",
"cols": (50, 200, 0)
}, {
"key": None,
"name": "Final",
"cols": (20, 30, 40)
}
], [
constData.statusKeys[2] # Deleted item
]
)
# Move items
projEdit.tabStatus.listBox.clearSelection()
projEdit.tabStatus._moveItem(1)
assert [x["key"] for x in projEdit.tabStatus.getNewList()[0]] == [
constData.statusKeys[0], constData.statusKeys[1], constData.statusKeys[3], None
]
projEdit.tabStatus.listBox.clearSelection()
projEdit.tabStatus.listBox.topLevelItem(0).setSelected(True)
projEdit.tabStatus._moveItem(-1)
assert [x["key"] for x in projEdit.tabStatus.getNewList()[0]] == [
constData.statusKeys[0], constData.statusKeys[1], constData.statusKeys[3], None
]
projEdit.tabStatus.listBox.clearSelection()
projEdit.tabStatus.listBox.topLevelItem(3).setSelected(True)
projEdit.tabStatus._moveItem(-1)
assert [x["key"] for x in projEdit.tabStatus.getNewList()[0]] == [
constData.statusKeys[0], constData.statusKeys[1], None, constData.statusKeys[3]
]
projEdit.tabStatus._moveItem(1)
assert [x["key"] for x in projEdit.tabStatus.getNewList()[0]] == [
constData.statusKeys[0], constData.statusKeys[1], constData.statusKeys[3], None
]
# Importance Tab
+1
View File
@@ -40,6 +40,7 @@ stepDelay = 20
def testDlgWordList_Dialog(qtbot, monkeypatch, nwGUI, nwMinimal):
"""test the word list editor.
"""
monkeypatch.setattr(QMessageBox, "information", lambda *a: QMessageBox.Yes)
monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)
monkeypatch.setattr(QMessageBox, "critical", lambda *a: QMessageBox.Yes)
monkeypatch.setattr(GuiWordList, "exec_", lambda *a: None)
+1
View File
@@ -43,6 +43,7 @@ def testGuiEditor_Init(qtbot, monkeypatch, nwGUI, nwMinimal, ipsumText):
"""
# Block message box
monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)
monkeypatch.setattr(QMessageBox, "information", lambda *a: QMessageBox.Yes)
# Open project
assert nwGUI.openProject(nwMinimal)
+3 -1
View File
@@ -19,8 +19,9 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
import pytest
import os
import random
import pytest
from shutil import copyfile
from tools import cmpFiles
@@ -139,6 +140,7 @@ def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, fncProj, refDir, outDir):
monkeypatch.setattr(GuiDocEditor, "hasFocus", lambda *a: True)
# Create new, save, close project
random.seed(42)
nwGUI.theProject.projTree.setSeed(42)
assert nwGUI.newProject({"projPath": fncProj})
assert nwGUI.saveProject()
+1
View File
@@ -35,6 +35,7 @@ def testGuiTheme_Main(qtbot, monkeypatch, nwMinimal, tmpDir):
"""Test the theme and icon classes.
"""
# Block message box
monkeypatch.setattr(QMessageBox, "information", lambda *a: QMessageBox.Yes)
monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)
monkeypatch.setattr(QMessageBox, "warning", lambda *a: QMessageBox.Yes)