From 48ea024d7e1846beadfca557fa8f5a367c3a126f Mon Sep 17 00:00:00 2001 From: louib Date: Wed, 21 Jun 2017 17:34:49 -0400 Subject: [PATCH] Adding support for listing a group. (#652) * Adding support for listing a group. * added findGroupByPath * Removing useless asserts. * Code review. --- src/cli/List.cpp | 17 ++++++++-- src/core/Group.cpp | 37 +++++++++++++++++++-- src/core/Group.h | 3 +- tests/TestGroup.cpp | 81 +++++++++++++++++++++++++++++++++++++++++++++ tests/TestGroup.h | 1 + 5 files changed, 133 insertions(+), 6 deletions(-) diff --git a/src/cli/List.cpp b/src/cli/List.cpp index c7a8626464..b0b7918822 100644 --- a/src/cli/List.cpp +++ b/src/cli/List.cpp @@ -44,6 +44,9 @@ int List::execute(int argc, char** argv) QCommandLineParser parser; parser.setApplicationDescription(QCoreApplication::translate("main", "List database entries.")); parser.addPositionalArgument("database", QCoreApplication::translate("main", "Path of the database.")); + parser.addPositionalArgument("group", + QCoreApplication::translate("main", "Path of the group to list. Default is /"), + QString("[group]")); QCommandLineOption printUuidsOption( QStringList() << "u" << "print-uuids", @@ -57,7 +60,7 @@ int List::execute(int argc, char** argv) parser.process(arguments); const QStringList args = parser.positionalArguments(); - if (args.size() != 1) { + if (args.size() != 1 && args.size() != 2) { QCoreApplication app(argc, argv); parser.showHelp(); return EXIT_FAILURE; @@ -76,7 +79,17 @@ int List::execute(int argc, char** argv) return EXIT_FAILURE; } - out << db->rootGroup()->print(parser.isSet("print-uuids")); + Group* group = db->rootGroup(); + if (args.size() == 2) { + QString groupPath = args.at(1); + group = db->rootGroup()->findGroupByPath(groupPath); + if (group == nullptr) { + qCritical("Cannot find group %s.", qPrintable(groupPath)); + return EXIT_FAILURE; + } + } + + out << group->print(parser.isSet("print-uuids")); out.flush(); return EXIT_SUCCESS; } diff --git a/src/core/Group.cpp b/src/core/Group.cpp index 0bebfcb0d6..edbed947e9 100644 --- a/src/core/Group.cpp +++ b/src/core/Group.cpp @@ -486,7 +486,6 @@ QList Group::entriesRecursive(bool includeHistoryItems) const Entry* Group::findEntry(QString entryId) { - Q_ASSERT(!entryId.isEmpty()); Q_ASSERT(!entryId.isNull()); if (Uuid::isUuid(entryId)) { @@ -527,12 +526,11 @@ Entry* Group::findEntryByUuid(const Uuid& uuid) Entry* Group::findEntryByPath(QString entryPath, QString basePath) { - Q_ASSERT(!entryPath.isEmpty()); Q_ASSERT(!entryPath.isNull()); for (Entry* entry : asConst(m_entries)) { QString currentEntryPath = basePath + entry->title(); - if (entryPath == currentEntryPath) { + if (entryPath == currentEntryPath || entryPath == QString("/" + currentEntryPath)) { return entry; } } @@ -547,6 +545,39 @@ Entry* Group::findEntryByPath(QString entryPath, QString basePath) return nullptr; } +Group* Group::findGroupByPath(QString groupPath, QString basePath) +{ + + Q_ASSERT(!groupPath.isNull()); + + QStringList possiblePaths; + possiblePaths << groupPath; + if (!groupPath.startsWith("/")) { + possiblePaths << QString("/" + groupPath); + } + if (!groupPath.endsWith("/")) { + possiblePaths << QString(groupPath + "/"); + } + if (!groupPath.endsWith("/") && !groupPath.endsWith("/")) { + possiblePaths << QString("/" + groupPath + "/"); + } + + if (possiblePaths.contains(basePath)) { + return this; + } + + for (Group* innerGroup : children()) { + QString innerBasePath = basePath + innerGroup->name() + "/"; + Group* group = innerGroup->findGroupByPath(groupPath, innerBasePath); + if (group != nullptr) { + return group; + } + } + + return nullptr; + +} + QString Group::print(bool printUuids, QString baseName, int depth) { diff --git a/src/core/Group.h b/src/core/Group.h index 7c76e412d0..f8c976eeb5 100644 --- a/src/core/Group.h +++ b/src/core/Group.h @@ -79,10 +79,11 @@ class Group : public QObject static const int DefaultIconNumber; static const int RecycleBinIconNumber; + Group* findChildByName(const QString& name); Entry* findEntry(QString entryId); Entry* findEntryByUuid(const Uuid& uuid); Entry* findEntryByPath(QString entryPath, QString basePath = QString("")); - Group* findChildByName(const QString& name); + Group* findGroupByPath(QString groupPath, QString basePath = QString("/")); void setUuid(const Uuid& uuid); void setName(const QString& name); void setNotes(const QString& notes); diff --git a/tests/TestGroup.cpp b/tests/TestGroup.cpp index d2a8465bfe..50997dcca1 100644 --- a/tests/TestGroup.cpp +++ b/tests/TestGroup.cpp @@ -599,6 +599,15 @@ void TestGroup::testFindEntry() QVERIFY(entry != nullptr); QCOMPARE(entry->title(), QString("entry1")); + // We also can find the entry with the leading slash. + entry = db->rootGroup()->findEntry(QString("/entry1")); + QVERIFY(entry != nullptr); + QCOMPARE(entry->title(), QString("entry1")); + + // But two slashes should not be accepted. + entry = db->rootGroup()->findEntry(QString("//entry1")); + QVERIFY(entry == nullptr); + entry = db->rootGroup()->findEntry(entry2->uuid().toHex()); QVERIFY(entry != nullptr); QCOMPARE(entry->title(), QString("entry2")); @@ -607,6 +616,14 @@ void TestGroup::testFindEntry() QVERIFY(entry != nullptr); QCOMPARE(entry->title(), QString("entry2")); + entry = db->rootGroup()->findEntry(QString("/entry2")); + QVERIFY(entry == nullptr); + + // We also can find the entry with the leading slash. + entry = db->rootGroup()->findEntry(QString("/group1/entry2")); + QVERIFY(entry != nullptr); + QCOMPARE(entry->title(), QString("entry2")); + // Should also find the entry only by title. entry = db->rootGroup()->findEntry(QString("entry2")); QVERIFY(entry != nullptr); @@ -629,6 +646,70 @@ void TestGroup::testFindEntry() delete db; } +void TestGroup::testFindGroupByPath() +{ + Database* db = new Database(); + + Group* group1 = new Group(); + group1->setName("group1"); + group1->setParent(db->rootGroup()); + + Group* group2 = new Group(); + group2->setName("group2"); + group2->setParent(group1); + + Group* group; + + group = db->rootGroup()->findGroupByPath("/"); + QVERIFY(group != nullptr); + QCOMPARE(group->uuid(), db->rootGroup()->uuid()); + + // We also accept it if the leading slash is missing. + group = db->rootGroup()->findGroupByPath(""); + QVERIFY(group != nullptr); + QCOMPARE(group->uuid(), db->rootGroup()->uuid()); + + group = db->rootGroup()->findGroupByPath("/group1/"); + QVERIFY(group != nullptr); + QCOMPARE(group->uuid(), group1->uuid()); + + // We also accept it if the leading slash is missing. + group = db->rootGroup()->findGroupByPath("group1/"); + QVERIFY(group != nullptr); + QCOMPARE(group->uuid(), group1->uuid()); + + // Too many slashes at the end + group = db->rootGroup()->findGroupByPath("group1//"); + QVERIFY(group == nullptr); + + // Missing a slash at the end. + group = db->rootGroup()->findGroupByPath("/group1"); + QVERIFY(group != nullptr); + QCOMPARE(group->uuid(), group1->uuid()); + + // Too many slashes at the start + group = db->rootGroup()->findGroupByPath("//group1"); + QVERIFY(group == nullptr); + + group = db->rootGroup()->findGroupByPath("/group1/group2/"); + QVERIFY(group != nullptr); + QCOMPARE(group->uuid(), group2->uuid()); + + // We also accept it if the leading slash is missing. + group = db->rootGroup()->findGroupByPath("group1/group2/"); + QVERIFY(group != nullptr); + QCOMPARE(group->uuid(), group2->uuid()); + + group = db->rootGroup()->findGroupByPath("group1/group2"); + QVERIFY(group != nullptr); + QCOMPARE(group->uuid(), group2->uuid()); + + group = db->rootGroup()->findGroupByPath("invalid"); + QVERIFY(group == nullptr); + + delete db; +} + void TestGroup::testPrint() { Database* db = new Database(); diff --git a/tests/TestGroup.h b/tests/TestGroup.h index 9b36ebabc5..16bb42acdc 100644 --- a/tests/TestGroup.h +++ b/tests/TestGroup.h @@ -40,6 +40,7 @@ private slots: void testMergeDatabase(); void testMergeConflictKeepBoth(); void testFindEntry(); + void testFindGroupByPath(); void testPrint(); private: