diff --git a/nw/core/project.py b/nw/core/project.py index 43885cce..5efce6ad 100644 --- a/nw/core/project.py +++ b/nw/core/project.py @@ -489,7 +489,7 @@ class NWProject(): # parser will lose the autoReplace settings if allowed to # read the file. Introduced in version 0.10. - if fileVersion == "1.0": + if fileVersion == "1.0" and self.mainConf.blockGUI: msgBox = QMessageBox() msgRes = msgBox.question(self.theParent, "Old Project Version", ( "The project file and data is created by a novelWriter version " @@ -501,7 +501,7 @@ class NWProject(): if msgRes != QMessageBox.Yes: return False - elif fileVersion != "1.1" and fileVersion != "1.2": + elif fileVersion != "1.1" and fileVersion != "1.2" and self.mainConf.blockGUI: self.makeAlert(( "Unknown or unsupported novelWriter project file format. " "The project cannot be opened by this version of novelWriter. " diff --git a/tests/conftest.py b/tests/conftest.py index 61bd1211..14988efa 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -118,3 +118,16 @@ def nwLipsum(nwTemp): if path.isdir(lipsumDir): shutil.rmtree(lipsumDir) return + +@pytest.fixture(scope="function") +def nwOldProj(nwTemp): + testDir = path.dirname(__file__) + oldProjStore = path.join(testDir, "oldproj") + oldProjDir = path.join(nwTemp, "oldproj") + if path.isdir(oldProjDir): + shutil.rmtree(oldProjDir) + shutil.copytree(oldProjStore, oldProjDir) + yield oldProjDir + if path.isdir(oldProjDir): + shutil.rmtree(oldProjDir) + return diff --git a/tests/oldproj/data_1/9752e7f9d8af_main.nwd b/tests/oldproj/data_1/9752e7f9d8af_main.nwd new file mode 100644 index 00000000..5b25ad52 --- /dev/null +++ b/tests/oldproj/data_1/9752e7f9d8af_main.nwd @@ -0,0 +1,4 @@ +### Scene Four + +Scene Four + diff --git a/tests/oldproj/data_7/ff63b8afc4cd_main.nwd b/tests/oldproj/data_7/ff63b8afc4cd_main.nwd new file mode 100644 index 00000000..818712f7 --- /dev/null +++ b/tests/oldproj/data_7/ff63b8afc4cd_main.nwd @@ -0,0 +1,4 @@ +# Antagonist + +Antagonist + diff --git a/tests/oldproj/data_8/8124a4292d8b_main.nwd b/tests/oldproj/data_8/8124a4292d8b_main.nwd new file mode 100644 index 00000000..5fe1d9fe --- /dev/null +++ b/tests/oldproj/data_8/8124a4292d8b_main.nwd @@ -0,0 +1,4 @@ +### Scene Two + +Scene Two + diff --git a/tests/oldproj/data_9/058ae29f0dfd_main.nwd b/tests/oldproj/data_9/058ae29f0dfd_main.nwd new file mode 100644 index 00000000..79e4dc06 --- /dev/null +++ b/tests/oldproj/data_9/058ae29f0dfd_main.nwd @@ -0,0 +1,4 @@ +# Protagonist + +Protagonist + diff --git a/tests/oldproj/data_9/1239bf2f8b69_main.nwd b/tests/oldproj/data_9/1239bf2f8b69_main.nwd new file mode 100644 index 00000000..2d701cd4 --- /dev/null +++ b/tests/oldproj/data_9/1239bf2f8b69_main.nwd @@ -0,0 +1,4 @@ +### Scene Three + +Scene Three + diff --git a/tests/oldproj/data_a/764d5acf5a21_main.nwd b/tests/oldproj/data_a/764d5acf5a21_main.nwd new file mode 100644 index 00000000..7ef7c622 --- /dev/null +++ b/tests/oldproj/data_a/764d5acf5a21_main.nwd @@ -0,0 +1,4 @@ +### Scene Five + +Scene Five + diff --git a/tests/oldproj/data_f/528d831f5b24_main.nwd b/tests/oldproj/data_f/528d831f5b24_main.nwd new file mode 100644 index 00000000..8fecdb8e --- /dev/null +++ b/tests/oldproj/data_f/528d831f5b24_main.nwd @@ -0,0 +1,4 @@ +### Scene One + +Scene One + diff --git a/tests/oldproj/meta/sessionInfo.log b/tests/oldproj/meta/sessionInfo.log new file mode 100644 index 00000000..92da5e9a --- /dev/null +++ b/tests/oldproj/meta/sessionInfo.log @@ -0,0 +1,2 @@ +Start: 2020-09-26 16:13:00 End: 2020-09-26 16:15:54 Words: 24 +Start: 2020-09-26 16:16:28 End: 2020-09-26 16:16:40 Words: -1 diff --git a/tests/oldproj/meta/tagsIndex.json b/tests/oldproj/meta/tagsIndex.json new file mode 100644 index 00000000..d02515f6 --- /dev/null +++ b/tests/oldproj/meta/tagsIndex.json @@ -0,0 +1,72 @@ +{ + "tagIndex": {}, + "refIndex": { + "f528d831f5b24": [], + "88124a4292d8b": [], + "91239bf2f8b69": [], + "19752e7f9d8af": [], + "a764d5acf5a21": [], + "9058ae29f0dfd": [], + "7ff63b8afc4cd": [] + }, + "novelIndex": { + "f528d831f5b24": [ + [ + 1, + 3, + "Scene One", + "SCENE" + ] + ], + "88124a4292d8b": [ + [ + 1, + 3, + "Scene Two", + "SCENE" + ] + ], + "91239bf2f8b69": [ + [ + 1, + 3, + "Scene Three", + "SCENE" + ] + ], + "19752e7f9d8af": [ + [ + 1, + 3, + "Scene Four", + "SCENE" + ] + ], + "a764d5acf5a21": [ + [ + 1, + 3, + "Scene Five", + "SCENE" + ] + ] + }, + "noteIndex": { + "9058ae29f0dfd": [ + [ + 1, + 1, + "Protagonist", + "NOTE" + ] + ], + "7ff63b8afc4cd": [ + [ + 1, + 1, + "Antagonist", + "NOTE" + ] + ] + } +} \ No newline at end of file diff --git a/tests/oldproj/nwProject.nwx b/tests/oldproj/nwProject.nwx new file mode 100644 index 00000000..8ba21098 --- /dev/null +++ b/tests/oldproj/nwProject.nwx @@ -0,0 +1,148 @@ + + + + + + True + + + False + a764d5acf5a21 + None + 23 + + + New + Note + Draft + Finished + + + New + Minor + Major + Main + + + + + Novel + ROOT + NOVEL + New + True + + + Chapter One + FOLDER + NOVEL + New + True + + + Scene One + FILE + NOVEL + New + False + SCENE + 18 + 4 + 1 + 3 + + + Scene Two + FILE + NOVEL + New + False + SCENE + 18 + 4 + 1 + 2 + + + Scene Three + FILE + NOVEL + New + False + SCENE + 22 + 4 + 1 + 2 + + + Scene Four + FILE + NOVEL + New + False + SCENE + 20 + 4 + 1 + 2 + + + Scene Five + FILE + NOVEL + New + False + SCENE + 20 + 4 + 1 + 2 + + + Characters + ROOT + CHARACTER + New + True + + + Protagonist + FILE + CHARACTER + New + False + NOTE + 11 + 1 + 0 + 28 + + + Antagonist + FILE + CHARACTER + New + False + NOTE + 13 + 2 + 1 + 26 + + + Plot + ROOT + PLOT + New + False + + + World + ROOT + WORLD + New + False + + + diff --git a/tests/test_project.py b/tests/test_project.py index 7502176a..be7e425d 100644 --- a/tests/test_project.py +++ b/tests/test_project.py @@ -3,7 +3,7 @@ """ import pytest -from os import path +from os import path, mkdir from shutil import copyfile from nwtools import cmpFiles @@ -577,3 +577,87 @@ def testOrphanedFiles(nwDummy, nwLipsum): assert theProject.saveProject(nwLipsum) assert theProject.closeProject() + +@pytest.mark.project +def testOldProject(nwDummy, nwOldProj): + theProject = NWProject(nwDummy) + theProject.mainConf.blockGUI = False + + # Create dummy files for known legacy files + deleteFiles = [ + path.join(nwOldProj, "cache", "nwProject.nwx.0"), + path.join(nwOldProj, "cache", "nwProject.nwx.1"), + path.join(nwOldProj, "cache", "nwProject.nwx.2"), + path.join(nwOldProj, "cache", "nwProject.nwx.3"), + path.join(nwOldProj, "cache", "nwProject.nwx.4"), + path.join(nwOldProj, "cache", "nwProject.nwx.5"), + path.join(nwOldProj, "cache", "nwProject.nwx.6"), + path.join(nwOldProj, "cache", "nwProject.nwx.7"), + path.join(nwOldProj, "cache", "nwProject.nwx.8"), + path.join(nwOldProj, "cache", "nwProject.nwx.9"), + path.join(nwOldProj, "meta", "mainOptions.json"), + path.join(nwOldProj, "meta", "exportOptions.json"), + path.join(nwOldProj, "meta", "outlineOptions.json"), + path.join(nwOldProj, "meta", "timelineOptions.json"), + path.join(nwOldProj, "meta", "docMergeOptions.json"), + path.join(nwOldProj, "meta", "sessionLogOptions.json"), + ] + + # Add some files that shouldn't be there + deleteFiles.append(path.join(nwOldProj, "data_f", "whatnow.nwd")) + deleteFiles.append(path.join(nwOldProj, "data_f", "whatnow.txt")) + + # Add some folders that shouldn't be there + mkdir(path.join(nwOldProj, "stuff")) + mkdir(path.join(nwOldProj, "data_1", "stuff")) + + for aFile in deleteFiles: + with open(aFile, mode="w+", encoding="utf8") as outFile: + outFile.write("Hi") + for aFile in deleteFiles: + assert path.isfile(aFile) + + # Open project and check that files that are not supposed to be + # there have been removed + assert theProject.openProject(nwOldProj) + for aFile in deleteFiles: + assert not path.isfile(aFile) + + assert not path.isdir(path.join(nwOldProj, "data_1", "stuff")) + assert not path.isdir(path.join(nwOldProj, "data_1")) + assert not path.isdir(path.join(nwOldProj, "data_7")) + assert not path.isdir(path.join(nwOldProj, "data_8")) + assert not path.isdir(path.join(nwOldProj, "data_9")) + assert not path.isdir(path.join(nwOldProj, "data_a")) + assert not path.isdir(path.join(nwOldProj, "data_f")) + + # Check stuff that has been moved + assert path.isdir(path.join(nwOldProj, "junk")) + assert path.isdir(path.join(nwOldProj, "junk", "stuff")) + assert path.isfile(path.join(nwOldProj, "junk", "whatnow.nwd")) + assert path.isfile(path.join(nwOldProj, "junk", "whatnow.txt")) + + # Check that files we want to keep are in the right place + assert path.isdir(path.join(nwOldProj, "cache")) + assert path.isdir(path.join(nwOldProj, "content")) + assert path.isdir(path.join(nwOldProj, "meta")) + + assert path.isfile(path.join(nwOldProj, "content", "f528d831f5b24.nwd")) + assert path.isfile(path.join(nwOldProj, "content", "88124a4292d8b.nwd")) + assert path.isfile(path.join(nwOldProj, "content", "91239bf2f8b69.nwd")) + assert path.isfile(path.join(nwOldProj, "content", "19752e7f9d8af.nwd")) + assert path.isfile(path.join(nwOldProj, "content", "a764d5acf5a21.nwd")) + assert path.isfile(path.join(nwOldProj, "content", "9058ae29f0dfd.nwd")) + assert path.isfile(path.join(nwOldProj, "content", "7ff63b8afc4cd.nwd")) + + assert path.isfile(path.join(nwOldProj, "meta", "tagsIndex.json")) + assert path.isfile(path.join(nwOldProj, "meta", "sessionInfo.log")) + + # Close the project + theProject.closeProject() + + # Check that new files have been created + assert path.isfile(path.join(nwOldProj, "meta", "guiOptions.json")) + assert path.isfile(path.join(nwOldProj, "meta", "sessionStats.log")) + assert path.isfile(path.join(nwOldProj, "ToC.json")) + assert path.isfile(path.join(nwOldProj, "ToC.txt"))