// Интеграционный тест: цепочка VaultManager + FileStore + DocumentManager + VaultIndex + GitManager + MdParser #include #include #include #include #include #include #include "app/VaultManager.h" #include "core/SettingsStore.h" #include "core/FileStore.h" #include "core/DocumentManager.h" #include "core/VaultIndex.h" #include "git/GitManager.h" #include "markdown/MdParser.h" static int fail(const char *msg, const QString &detail=QString()){ std::fprintf(stderr,"FAIL: %s %s\n",msg,qPrintable(detail)); return 1;} int main(int argc, char *argv[]){ QCoreApplication app(argc, argv); app.setOrganizationName("FloraInteg"); app.setApplicationName("integ_test"); QTemporaryDir tmp; if(!tmp.isValid()) return fail("tmp"); QSettings::setPath(QSettings::IniFormat, QSettings::UserScope, tmp.path()); QSettings::setDefaultFormat(QSettings::IniFormat); SettingsStore settings; GitManager git; VaultManager vaultMgr(&settings, &git); QString vaultPath = tmp.path()+"/myvault"; QString err = vaultMgr.createVault(vaultPath); if(!err.isEmpty()) return fail("createVault",err); if(!settings.hasVault(vaultPath)) return fail("hasVault"); if(!git.hasCommits(vaultPath) && false) {} // may be no commits yet // FileStore operations FileStore fs; err = fs.openVault(vaultPath); if(!err.isEmpty()) return fail("openVault",err); err = fs.createFile(vaultPath, "note1"); if(!err.isEmpty()) return fail("createFile note1",err); err = fs.createFolder(vaultPath, "folder1"); if(!err.isEmpty()) return fail("createFolder",err); QString note1 = vaultPath+"/note1.md"; QString folder1 = vaultPath+"/folder1"; // create inside folder err = fs.createFile(folder1, "inner.md"); if(!err.isEmpty()) return fail("inner",err); QString inner = folder1+"/inner.md"; // DocumentManager: open and edit DocumentManager dm; dm.setAutosaveIntervalMs(500); int idx = dm.openDocument(note1); if(idx!=0) return fail("open note1"); dm.updateContent(idx, "# Header #tagA\n\nLink to [[inner]] and #tagB\n"); dm.saveDocument(idx); if(dm.isDirty(idx)) return fail("still dirty"); int idx2 = dm.openDocument(inner); if(idx2!=1) return fail("open inner"); dm.updateContent(idx2, "# Inner\n\nBack to [[note1]] #tagA\n"); dm.saveDocument(idx2); // Git commit all if(!git.commitAll(vaultPath, "initial content")) return fail("commitAll", git.lastError()); if(!git.hasCommits(vaultPath)) return fail("hasCommits after"); // VaultIndex should find tags and links VaultIndex vi; vi.rebuild(vaultPath); if(vi.fileCount()!=2) return fail("fileCount 2", QString::number(vi.fileCount())); QStringList tags = vi.tagsOfFile(note1); if(!tags.contains("tagA") || !tags.contains("tagB")) return fail("tags note1", tags.join(",")); auto links = vi.linksOfFile(note1); bool foundInner=false; for(auto l: links) if(l.toMap().value("path").toString()==inner) foundInner=true; if(!foundInner) return fail("link note1->inner"); if(vi.filesWithTag("tagA").size()!=2) return fail("tagA files 2"); // MdParser render MdParser parser; QString content = dm.contentAt(idx); QString html = parser.render(content, vaultPath, QFileInfo(note1).absolutePath()); if(!html.contains("tagA") && !html.contains("tag")) {} // tags are not rendered as html, but links should be if(!html.contains("flora://open")) return fail("md render link", html); if(html.contains("onload")) return fail("xss"); // Daily note QString dn = fs.dailyNotePath("2026-09-01"); if(dn.isEmpty()) return fail("dailyNote"); if(!QFileInfo::exists(dn)) return fail("dailyNote not exists"); int dnIdx = dm.openDocument(dn); if(dnIdx<0) return fail("open daily"); dm.updateContent(dnIdx, "# 2026-09-01\n\nDaily #daily\n"); dm.saveDocument(dnIdx); vi.rebuild(vaultPath); if(vi.fileCount()!=3) return fail("fileCount 3 after daily"); if(!vi.tagsOfFile(dn).contains("daily")) return fail("daily tag"); // Rename and move err = fs.renameItem(note1, "renamed.md"); if(!err.isEmpty()) return fail("rename",err); QString renamed = vaultPath+"/renamed.md"; if(!QFileInfo::exists(renamed)) return fail("renamed not exists"); // DocumentManager path still old, but file moved - should handle? reopen dm.closeTab(idx); // close old (should be at index? after previous ops indices shifted - find renamed) // open renamed int idxR = dm.openDocument(renamed); if(idxR<0) return fail("open renamed"); // Move inner to root err = fs.moveItem(inner, vaultPath); if(!err.isEmpty()) return fail("move inner to root",err); if(!QFileInfo::exists(vaultPath+"/inner.md")) return fail("moved inner not at root"); // Remove folder (now empty) err = fs.removeItem(folder1); if(!err.isEmpty()) return fail("remove folder",err); if(QDir(folder1).exists()) return fail("folder still exists"); // Git status checks QString st = git.fileGitStatus(vaultPath, renamed); if(st.isEmpty()) return fail("git status empty"); // commit again if(!git.commitAll(vaultPath, "after moves")) return fail("commit after moves", git.lastError()); // SettingsStore viewMode persistence across vaults settings.setViewModeForFile(vaultPath, renamed, "preview"); if(settings.viewModeForFile(vaultPath, renamed)!="preview") return fail("viewMode", settings.viewModeForFile(vaultPath, renamed)); std::printf("INTEGRATION TEST OK\n"); return 0; }