Merge pull request #1388 from hicknhack-software/hotfix/1387_entry-size

Add extend entry-size calculation (resolved #1387)
This commit is contained in:
TheZ3ro 2018-01-23 19:36:57 +01:00 committed by GitHub
commit 50beac2baf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 197 additions and 60 deletions

View File

@ -103,6 +103,15 @@ int AutoTypeAssociations::size() const
return m_associations.size();
}
int AutoTypeAssociations::associationsSize() const
{
int size = 0;
for (const Association &association : m_associations) {
size += association.sequence.toUtf8().size() + association.window.toUtf8().size();
}
return size;
}
void AutoTypeAssociations::clear()
{
m_associations.clear();

View File

@ -43,6 +43,7 @@ public:
AutoTypeAssociations::Association get(int index) const;
QList<AutoTypeAssociations::Association> getAll() const;
int size() const;
int associationsSize() const;
void clear();
private:

View File

@ -582,22 +582,24 @@ void Entry::truncateHistory()
int histMaxSize = db->metadata()->historyMaxSize();
if (histMaxSize > -1) {
int size = 0;
QSet<QByteArray> foundAttachments = attachments()->values().toSet();
QSet<QByteArray> foundAttachments = attachments()->values();
QMutableListIterator<Entry*> i(m_history);
i.toBack();
const QRegularExpression delimiter(",|:|;");
while (i.hasPrevious()) {
Entry* historyItem = i.previous();
// don't calculate size if it's already above the maximum
if (size <= histMaxSize) {
size += historyItem->attributes()->attributesSize();
const QSet<QByteArray> newAttachments = historyItem->attachments()->values().toSet() - foundAttachments;
for (const QByteArray& attachment : newAttachments) {
size += attachment.size();
size += historyItem->autoTypeAssociations()->associationsSize();
size += historyItem->attachments()->attachmentsSize();
const QStringList tags = historyItem->tags().split(delimiter, QString::SkipEmptyParts);
for (const QString& tag : tags) {
size += tag.toUtf8().size();
}
foundAttachments += newAttachments;
foundAttachments += historyItem->attachments()->values();
}
if (size > histMaxSize) {
@ -633,7 +635,7 @@ Entry* Entry::clone(CloneFlags flags) const
entry->m_attributes->set(EntryAttributes::PasswordKey, password.toUpper(), m_attributes->isProtected(EntryAttributes::PasswordKey));
}
entry->m_autoTypeAssociations->copyDataFrom(this->m_autoTypeAssociations);
entry->m_autoTypeAssociations->copyDataFrom(m_autoTypeAssociations);
if (flags & CloneIncludeHistory) {
for (Entry* historyItem : m_history) {
Entry* historyItemClone = historyItem->clone(flags & ~CloneIncludeHistory & ~CloneNewUuid);
@ -679,6 +681,7 @@ void Entry::beginUpdate()
m_tmpHistoryItem->m_data = m_data;
m_tmpHistoryItem->m_attributes->copyDataFrom(m_attributes);
m_tmpHistoryItem->m_attachments->copyDataFrom(m_attachments);
m_tmpHistoryItem->m_autoTypeAssociations->copyDataFrom(m_autoTypeAssociations);
m_modifiedSinceBegin = false;
}

View File

@ -18,6 +18,7 @@
#include "EntryAttachments.h"
#include <QStringList>
#include <QSet>
EntryAttachments::EntryAttachments(QObject* parent)
: QObject(parent)
@ -34,9 +35,9 @@ bool EntryAttachments::hasKey(const QString& key) const
return m_attachments.contains(key);
}
QList<QByteArray> EntryAttachments::values() const
QSet<QByteArray> EntryAttachments::values() const
{
return m_attachments.values();
return m_attachments.values().toSet();
}
QByteArray EntryAttachments::value(const QString& key) const
@ -151,3 +152,12 @@ bool EntryAttachments::operator!=(const EntryAttachments& other) const
{
return m_attachments != other.m_attachments;
}
int EntryAttachments::attachmentsSize() const
{
int size = 0;
for (auto it = m_attachments.constBegin(); it != m_attachments.constEnd(); ++it) {
size += it.key().toUtf8().size() + it.value().size();
}
return size;
}

View File

@ -31,7 +31,7 @@ public:
explicit EntryAttachments(QObject* parent = nullptr);
QList<QString> keys() const;
bool hasKey(const QString& key) const;
QList<QByteArray> values() const;
QSet<QByteArray> values() const;
QByteArray value(const QString& key) const;
void set(const QString& key, const QByteArray& value);
void remove(const QString& key);
@ -41,6 +41,7 @@ public:
void copyDataFrom(const EntryAttachments* other);
bool operator==(const EntryAttachments& other) const;
bool operator!=(const EntryAttachments& other) const;
int attachmentsSize() const;
signals:
void modified();

View File

@ -283,14 +283,11 @@ void EntryAttributes::clear()
emit modified();
}
int EntryAttributes::attributesSize()
int EntryAttributes::attributesSize() const
{
int size = 0;
QMapIterator<QString, QString> i(m_attributes);
while (i.hasNext()) {
i.next();
size += i.value().toUtf8().size();
for (auto it = m_attributes.constBegin(); it != m_attributes.constEnd(); ++it) {
size += it.key().toUtf8().size() + it.value().toUtf8().size();
}
return size;
}

View File

@ -45,7 +45,7 @@ public:
void copyCustomKeysFrom(const EntryAttributes* other);
bool areCustomKeysDifferent(const EntryAttributes* other);
void clear();
int attributesSize();
int attributesSize() const;
void copyDataFrom(const EntryAttributes* other);
bool operator==(const EntryAttributes& other) const;
bool operator!=(const EntryAttributes& other) const;

View File

@ -20,7 +20,6 @@
#include <QTest>
#include "core/Database.h"
#include "core/Entry.h"
#include "core/Group.h"
#include "crypto/Crypto.h"
@ -48,6 +47,7 @@ void TestEntry::testHistoryItemDeletion()
delete entry;
}
void TestEntry::testCopyDataFrom()
{
Entry* entry = new Entry();

View File

@ -288,14 +288,14 @@ void TestModified::testEntrySets()
delete db;
}
void TestModified::testHistoryItem()
void TestModified::testHistoryItems()
{
Entry* entry = new Entry();
QScopedPointer<Entry> entry(new Entry());
QDateTime created = entry->timeInfo().creationTime();
entry->setUuid(Uuid::random());
entry->setTitle("a");
entry->setTags("a");
EntryAttributes* attributes = new EntryAttributes();
QScopedPointer<EntryAttributes> attributes(new EntryAttributes());
attributes->copyCustomKeysFrom(entry->attributes());
Entry* historyEntry;
@ -338,15 +338,12 @@ void TestModified::testHistoryItem()
attributes->set("k", "myvalue");
entry->beginUpdate();
entry->attributes()->copyCustomKeysFrom(attributes);
entry->attributes()->copyCustomKeysFrom(attributes.data());
entry->endUpdate();
QCOMPARE(entry->historyItems().size(), ++historyItemsSize);
QVERIFY(!entry->historyItems().at(historyItemsSize - 1)->attributes()->keys().contains("k"));
delete attributes;
delete entry;
Database* db = new Database();
QScopedPointer<Database> db(new Database());
Group* root = db->rootGroup();
db->metadata()->setHistoryMaxItems(3);
db->metadata()->setHistoryMaxSize(-1);
@ -400,12 +397,16 @@ void TestModified::testHistoryItem()
entry2->endUpdate();
QCOMPARE(entry2->historyItems().size(), 0);
db->metadata()->setHistoryMaxItems(-1);
db->metadata()->setHistoryMaxSize(17000);
const int historyMaxSize = 19000;
db->metadata()->setHistoryMaxItems(-1);
db->metadata()->setHistoryMaxSize(historyMaxSize);
const QString key("test");
entry2->beginUpdate();
entry2->attachments()->set("test", QByteArray(18000, 'X'));
entry2->attachments()->set(key, QByteArray(18000, 'X'));
entry2->endUpdate();
QCOMPARE(entry2->attachments()->attachmentsSize(), 18000 + key.size());
QCOMPARE(entry2->historyItems().size(), 1);
historyEntry2 = entry2->historyItems().at(0);
@ -417,53 +418,167 @@ void TestModified::testHistoryItem()
QCOMPARE(entry2->historyItems().size(), 2);
entry2->beginUpdate();
entry2->attachments()->remove("test");
entry2->attachments()->remove(key);
entry2->endUpdate();
QCOMPARE(entry2->historyItems().size(), 0);
QCOMPARE(entry2->attachments()->attachmentsSize(), 0);
QCOMPARE(entry2->historyItems().size(), 1);
entry2->beginUpdate();
entry2->attachments()->set("test2", QByteArray(6000, 'a'));
entry2->endUpdate();
QCOMPARE(entry2->historyItems().size(), 1);
QCOMPARE(entry2->attachments()->attachmentsSize(), 6000 + key.size() + 1);
QCOMPARE(entry2->historyItems().size(), 2);
entry2->beginUpdate();
entry2->attachments()->set("test3", QByteArray(6000, 'b'));
entry2->endUpdate();
QCOMPARE(entry2->attachments()->attachmentsSize(), 12000 + (key.size() + 1) * 2);
QCOMPARE(entry2->historyItems().size(), 2);
entry2->beginUpdate();
entry2->attachments()->set("test4", QByteArray(6000, 'c'));
entry2->endUpdate();
QCOMPARE(entry2->attachments()->attachmentsSize(), 18000 + (key.size() + 1) * 3);
QCOMPARE(entry2->historyItems().size(), 3);
entry2->beginUpdate();
entry2->attachments()->set("test5", QByteArray(6000, 'd'));
entry2->endUpdate();
QCOMPARE(entry2->historyItems().size(), 4);
Entry* entry3 = new Entry();
entry3->setGroup(root);
QCOMPARE(entry3->historyItems().size(), 0);
entry3->beginUpdate();
entry3->attachments()->set("test", QByteArray(6000, 'a'));
entry3->endUpdate();
QCOMPARE(entry3->historyItems().size(), 1);
entry3->beginUpdate();
entry3->attachments()->set("test", QByteArray(6000, 'b'));
entry3->endUpdate();
QCOMPARE(entry3->historyItems().size(), 2);
entry3->beginUpdate();
entry3->attachments()->set("test", QByteArray(6000, 'c'));
entry3->endUpdate();
QCOMPARE(entry3->historyItems().size(), 3);
entry3->beginUpdate();
entry3->attachments()->set("test", QByteArray(6000, 'd'));
entry3->endUpdate();
QCOMPARE(entry3->historyItems().size(), 2);
delete db;
QCOMPARE(entry2->attachments()->attachmentsSize(), 24000 + (key.size() + 1) * 4);
QCOMPARE(entry2->historyItems().size(), 1);
}
void TestModified::testHistoryMaxSize()
{
QScopedPointer<Database> db(new Database());
const QString key("test");
auto entry1 = new Entry();
entry1->setGroup(db->rootGroup());
QCOMPARE(entry1->historyItems().size(), 0);
const int reservedSize1 = entry1->attributes()->attributesSize();
db->metadata()->setHistoryMaxItems(-1);
db->metadata()->setHistoryMaxSize(18000 + key.size() * 3 + reservedSize1 * 4);
entry1->beginUpdate();
entry1->attachments()->set(key, QByteArray(6000, 'a'));
entry1->endUpdate();
QCOMPARE(entry1->attachments()->attachmentsSize(), 6000 + key.size());
QCOMPARE(entry1->historyItems().size(), 1);
entry1->beginUpdate();
entry1->attachments()->set(key, QByteArray(6000, 'b'));
entry1->endUpdate();
QCOMPARE(entry1->attachments()->attachmentsSize(), 6000 + key.size());
QCOMPARE(entry1->historyItems().size(), 2);
entry1->beginUpdate();
entry1->attachments()->set(key, QByteArray(6000, 'c'));
entry1->endUpdate();
QCOMPARE(entry1->attachments()->attachmentsSize(), 6000 + key.size());
QCOMPARE(entry1->historyItems().size(), 3);
entry1->beginUpdate();
entry1->attachments()->set(key, QByteArray(6000, 'd'));
entry1->endUpdate();
QCOMPARE(entry1->attachments()->attachmentsSize(), 6000 + key.size());
QCOMPARE(entry1->historyItems().size(), 4);
auto entry2 = new Entry();
entry2->setGroup(db->rootGroup());
QCOMPARE(entry2->historyItems().size(), 0);
const int historyMaxSize = 17000;
const int reservedSize2 = entry2->attributes()->attributesSize();
db->metadata()->setHistoryMaxSize(historyMaxSize);
entry2->beginUpdate();
entry2->attachments()->set(key, QByteArray(historyMaxSize - key.size() - reservedSize2 + 1, 'a'));
entry2->endUpdate();
QCOMPARE(entry2->attachments()->attachmentsSize(), historyMaxSize - reservedSize2 + 1);
QCOMPARE(entry2->historyItems().size(), 1);
// history size overflow
entry2->beginUpdate();
entry2->attachments()->set(key, QByteArray(historyMaxSize - key.size() - reservedSize2 + 1, 'b'));
entry2->endUpdate();
QCOMPARE(entry2->historyItems().size(), 0);
entry2->beginUpdate();
entry2->attachments()->remove(key);
entry2->endUpdate();
QCOMPARE(entry2->attachments()->attachmentsSize(), 0);
QCOMPARE(entry2->historyItems().size(), 0);
entry2->beginUpdate();
entry2->attachments()->set(key, QByteArray(historyMaxSize - key.size() - reservedSize2 + 1, 'a'));
entry2->endUpdate();
QCOMPARE(entry2->attachments()->attachmentsSize(), historyMaxSize - reservedSize2 + 1);
QCOMPARE(entry2->historyItems().size(), 1);
// history size overflow
entry2->beginUpdate();
entry2->attachments()->set(key, QByteArray(historyMaxSize - key.size() - reservedSize2 + 1, 'b'));
entry2->endUpdate();
QCOMPARE(entry2->historyItems().size(), 0);
entry2->beginUpdate();
entry2->attachments()->remove(key);
entry2->endUpdate();
QCOMPARE(entry2->attachments()->attachmentsSize(), 0);
QCOMPARE(entry2->historyItems().size(), 0);
entry2->beginUpdate();
entry2->setTags(QByteArray(historyMaxSize - reservedSize2 + 1, 'a'));
entry2->endUpdate();
QCOMPARE(entry2->tags().size(), historyMaxSize - reservedSize2 + 1);
QCOMPARE(entry2->historyItems().size(), 1);
// history size overflow
entry2->beginUpdate();
entry2->setTags(QByteArray(historyMaxSize - reservedSize2 + 1, 'b'));
entry2->endUpdate();
QCOMPARE(entry2->historyItems().size(), 0);
entry2->beginUpdate();
entry2->setTags("");
entry2->endUpdate();
QCOMPARE(entry2->historyItems().size(), 0);
entry2->beginUpdate();
entry2->attributes()->set(key, QByteArray(historyMaxSize - key.size() - reservedSize2 + 1, 'a'));
entry2->endUpdate();
QCOMPARE(entry2->attributes()->attributesSize(), historyMaxSize + 1);
QCOMPARE(entry2->historyItems().size(), 1);
// history size overflow
entry2->beginUpdate();
entry2->attributes()->set(key, QByteArray(historyMaxSize - key.size() - reservedSize2 + 1, 'b'));
entry2->endUpdate();
QCOMPARE(entry2->attributes()->attributesSize(), historyMaxSize + 1);
QCOMPARE(entry2->historyItems().size(), 0);
entry2->beginUpdate();
entry2->attributes()->remove(key);
entry2->endUpdate();
QCOMPARE(entry2->attributes()->attributesSize(), reservedSize2);
QCOMPARE(entry2->historyItems().size(), 0);
entry2->beginUpdate();
AutoTypeAssociations::Association association;
association.window = key;
association.sequence = QByteArray(historyMaxSize - key.size() - reservedSize2 + 1, 'a');
entry2->autoTypeAssociations()->add(association);
entry2->endUpdate();
QCOMPARE(entry2->autoTypeAssociations()->associationsSize(), historyMaxSize - reservedSize2 + 1);
QCOMPARE(entry2->historyItems().size(), 1);
entry2->beginUpdate();
entry2->autoTypeAssociations()->remove(0);
entry2->endUpdate();
QCOMPARE(entry2->autoTypeAssociations()->associationsSize(), 0);
QCOMPARE(entry2->historyItems().size(), 0);
}

View File

@ -29,7 +29,8 @@ private slots:
void testSignals();
void testGroupSets();
void testEntrySets();
void testHistoryItem();
void testHistoryItems();
void testHistoryMaxSize();
};
#endif // KEEPASSX_TESTMODIFIED_H