diff options
author | Patrick Klein <42714034+libklein@users.noreply.github.com> | 2021-12-08 07:40:09 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-12-08 07:40:09 +0300 |
commit | a0a063b57f6f577bed505ccd652763eeadd1b876 (patch) | |
tree | 23adb424daf8e154d2a3c1943ea941780e971c6b /tests | |
parent | b3896f260048551d1d08245f85038182cb5e303b (diff) |
Add -i/--include option to "generate" CLI command. (#7112)
Diffstat (limited to 'tests')
-rw-r--r-- | tests/TestCli.cpp | 4 | ||||
-rw-r--r-- | tests/TestPasswordGenerator.cpp | 338 | ||||
-rw-r--r-- | tests/TestPasswordGenerator.h | 16 |
3 files changed, 258 insertions, 100 deletions
diff --git a/tests/TestCli.cpp b/tests/TestCli.cpp index 1639e8a39..49b21dfa6 100644 --- a/tests/TestCli.cpp +++ b/tests/TestCli.cpp @@ -1195,6 +1195,10 @@ void TestCli::testGenerate_data() << QStringList{"generate", "-L", "2", "--upper", "-l", "--every-group"} << "^[a-z][A-Z]|[A-Z][a-z]$"; QTest::newRow("numbers + lowercase (every)") << QStringList{"generate", "-L", "2", "-n", "-l", "--every-group"} << "^[a-z][0-9]|[0-9][a-z]$"; + QTest::newRow("custom character set") + << QStringList{"generate", "-L", "200", "-n", "-c", "abc"} << "^[abc0-9]{200}$"; + QTest::newRow("custom character set without extra options uses only custom chars") + << QStringList{"generate", "-L", "200", "-c", "a"} << "^a{200}$"; } void TestCli::testGenerate() diff --git a/tests/TestPasswordGenerator.cpp b/tests/TestPasswordGenerator.cpp index 2ed2974a8..10b91f6af 100644 --- a/tests/TestPasswordGenerator.cpp +++ b/tests/TestPasswordGenerator.cpp @@ -16,7 +16,6 @@ */ #include "TestPasswordGenerator.h" -#include "core/PasswordGenerator.h" #include "crypto/Crypto.h" #include <QRegularExpression> @@ -24,120 +23,261 @@ QTEST_GUILESS_MAIN(TestPasswordGenerator) +Q_DECLARE_METATYPE(PasswordGenerator::CharClasses) +Q_DECLARE_METATYPE(PasswordGenerator::GeneratorFlags) + +namespace +{ + PasswordGenerator::CharClasses to_flags(PasswordGenerator::CharClass x) + { + return x; + } + + PasswordGenerator::GeneratorFlags to_flags(PasswordGenerator::GeneratorFlag x) + { + return x; + } +} // namespace + void TestPasswordGenerator::initTestCase() { QVERIFY(Crypto::init()); } -void TestPasswordGenerator::testAdditionalChars() +void TestPasswordGenerator::init() +{ + m_generator.reset(); +} + +void TestPasswordGenerator::testCustomCharacterSet_data() { - PasswordGenerator generator; - QVERIFY(!generator.isValid()); - generator.setAdditionalChars("aql"); - generator.setLength(2000); - QVERIFY(generator.isValid()); - QString password = generator.generatePassword(); + QTest::addColumn<PasswordGenerator::CharClasses>("activeCharacterClasses"); + QTest::addColumn<QString>("customCharacterSet"); + QTest::addColumn<QRegularExpression>("expected"); + + QTest::addRow("With active classes") << to_flags(PasswordGenerator::CharClass::UpperLetters) << "abc" + << QRegularExpression("^[abcA-Z]{2000}$"); + QTest::addRow("Without any active class") + << to_flags(PasswordGenerator::CharClass::NoClass) << "abc" << QRegularExpression("^[abc]{2000}$"); +} + +void TestPasswordGenerator::testCustomCharacterSet() +{ + QFETCH(PasswordGenerator::CharClasses, activeCharacterClasses); + QFETCH(QString, customCharacterSet); + QFETCH(QRegularExpression, expected); + + m_generator.setCharClasses(activeCharacterClasses); + m_generator.setCustomCharacterSet(customCharacterSet); + m_generator.setLength(2000); + + QVERIFY(m_generator.isValid()); + QString password = m_generator.generatePassword(); QCOMPARE(password.size(), 2000); - QRegularExpression regex(R"(^[aql]+$)"); - QVERIFY(regex.match(password).hasMatch()); + QVERIFY(expected.match(password).hasMatch()); +} + +void TestPasswordGenerator::testCharClasses_data() +{ + QTest::addColumn<PasswordGenerator::CharClasses>("activeCharacterClasses"); + QTest::addColumn<QRegularExpression>("expected"); + + QTest::addRow("Lower Letters") << to_flags(PasswordGenerator::CharClass::LowerLetters) + << QRegularExpression(R"(^[a-z]{2000}$)"); + QTest::addRow("Upper Letters") << to_flags(PasswordGenerator::CharClass::UpperLetters) + << QRegularExpression(R"(^[A-Z]{2000}$)"); + QTest::addRow("Numbers") << to_flags(PasswordGenerator::CharClass::Numbers) << QRegularExpression(R"(^\d{2000}$)"); + QTest::addRow("Braces") << to_flags(PasswordGenerator::CharClass::Braces) + << QRegularExpression(R"(^[\(\)\[\]\{\}]{2000}$)"); + QTest::addRow("Punctuation") << to_flags(PasswordGenerator::CharClass::Punctuation) + << QRegularExpression(R"(^[\.,:;]{2000}$)"); + QTest::addRow("Quotes") << to_flags(PasswordGenerator::CharClass::Quotes) << QRegularExpression(R"(^["']{2000}$)"); + QTest::addRow("Dashes") << to_flags(PasswordGenerator::CharClass::Dashes) + << QRegularExpression(R"(^[\-/\\_|]{2000}$)"); + QTest::addRow("Math") << to_flags(PasswordGenerator::CharClass::Math) << QRegularExpression(R"(^[!\*\+\-<=>\?]+$)"); + QTest::addRow("Logograms") << to_flags(PasswordGenerator::CharClass::Logograms) + << QRegularExpression(R"(^[#`~%&^$@]{2000}$)"); + QTest::addRow("Extended ASCII") << to_flags(PasswordGenerator::CharClass::EASCII) + << QRegularExpression(R"(^[^a-zA-Z0-9\.,:;"'\-/\\_|!\*\+\-<=>\?#`~%&^$@]{2000}$)"); + QTest::addRow("Combinations 1") << (PasswordGenerator::CharClass::LowerLetters + | PasswordGenerator::CharClass::UpperLetters + | PasswordGenerator::CharClass::Braces) + << QRegularExpression(R"(^[a-zA-Z\(\)\[\]\{\}]{2000}$)"); + QTest::addRow("Combinations 2") << (PasswordGenerator::CharClass::Quotes | PasswordGenerator::CharClass::Numbers + | PasswordGenerator::CharClass::Dashes) + << QRegularExpression(R"(^["'\d\-/\\_|]{2000}$)"); } void TestPasswordGenerator::testCharClasses() { - PasswordGenerator generator; - QVERIFY(!generator.isValid()); - generator.setCharClasses(PasswordGenerator::CharClass::LowerLetters); - generator.setLength(16); - QVERIFY(generator.isValid()); - QCOMPARE(generator.generatePassword().size(), 16); - - generator.setLength(2000); - QString password = generator.generatePassword(); + + QFETCH(PasswordGenerator::CharClasses, activeCharacterClasses); + QFETCH(QRegularExpression, expected); + + m_generator.setCharClasses(activeCharacterClasses); + m_generator.setLength(2000); + + QVERIFY(m_generator.isValid()); + QString password = m_generator.generatePassword(); QCOMPARE(password.size(), 2000); - QRegularExpression regex(R"(^[a-z]+$)"); - QVERIFY(regex.match(password).hasMatch()); - - generator.setCharClasses(PasswordGenerator::CharClass::UpperLetters); - password = generator.generatePassword(); - regex.setPattern(R"(^[A-Z]+$)"); - QVERIFY(regex.match(password).hasMatch()); - - generator.setCharClasses(PasswordGenerator::CharClass::Numbers); - password = generator.generatePassword(); - regex.setPattern(R"(^\d+$)"); - QVERIFY(regex.match(password).hasMatch()); - - generator.setCharClasses(PasswordGenerator::CharClass::Braces); - password = generator.generatePassword(); - regex.setPattern(R"(^[\(\)\[\]\{\}]+$)"); - QVERIFY(regex.match(password).hasMatch()); - - generator.setCharClasses(PasswordGenerator::CharClass::Punctuation); - password = generator.generatePassword(); - regex.setPattern(R"(^[\.,:;]+$)"); - QVERIFY(regex.match(password).hasMatch()); - - generator.setCharClasses(PasswordGenerator::CharClass::Quotes); - password = generator.generatePassword(); - regex.setPattern(R"(^["']+$)"); - QVERIFY(regex.match(password).hasMatch()); - - generator.setCharClasses(PasswordGenerator::CharClass::Dashes); - password = generator.generatePassword(); - regex.setPattern(R"(^[\-/\\_|]+$)"); - QVERIFY(regex.match(password).hasMatch()); - - generator.setCharClasses(PasswordGenerator::CharClass::Math); - password = generator.generatePassword(); - regex.setPattern(R"(^[!\*\+\-<=>\?]+$)"); - QVERIFY(regex.match(password).hasMatch()); - - generator.setCharClasses(PasswordGenerator::CharClass::Logograms); - password = generator.generatePassword(); - regex.setPattern(R"(^[#`~%&^$@]+$)"); - QVERIFY(regex.match(password).hasMatch()); - - generator.setCharClasses(PasswordGenerator::CharClass::EASCII); - password = generator.generatePassword(); - regex.setPattern(R"(^[^a-zA-Z0-9\.,:;"'\-/\\_|!\*\+\-<=>\?#`~%&^$@]+$)"); - QVERIFY(regex.match(password).hasMatch()); - - generator.setCharClasses(PasswordGenerator::CharClass::LowerLetters | PasswordGenerator::CharClass::UpperLetters - | PasswordGenerator::CharClass::Braces); - password = generator.generatePassword(); - regex.setPattern(R"(^[a-zA-Z\(\)\[\]\{\}]+$)"); - QVERIFY(regex.match(password).hasMatch()); - - generator.setCharClasses(PasswordGenerator::CharClass::Quotes | PasswordGenerator::CharClass::Numbers - | PasswordGenerator::CharClass::Dashes); - password = generator.generatePassword(); - regex.setPattern(R"(^["'\d\-/\\_|]+$)"); - QVERIFY(regex.match(password).hasMatch()); + QVERIFY(expected.match(password).hasMatch()); +} + +void TestPasswordGenerator::testLookalikeExclusion_data() +{ + QTest::addColumn<PasswordGenerator::CharClasses>("activeCharacterClasses"); + QTest::addColumn<QRegularExpression>("expected"); + QTest::addRow("Upper Letters") << (PasswordGenerator::CharClass::LowerLetters + | PasswordGenerator::CharClass::UpperLetters) + << QRegularExpression("^[^lBGIO]{2000}$"); + + QTest::addRow("Letters and Numbers") << (PasswordGenerator::CharClass::LowerLetters + | PasswordGenerator::CharClass::UpperLetters + | PasswordGenerator::CharClass::Numbers) + << QRegularExpression("^[^lBGIO0168]{2000}$"); + + QTest::addRow("Letters, Numbers and extended ASCII") + << (PasswordGenerator::CharClass::LowerLetters | PasswordGenerator::CharClass::UpperLetters + | PasswordGenerator::CharClass::Numbers | PasswordGenerator::CharClass::EASCII) + << QRegularExpression("^[^lBGIO0168﹒]{2000}$"); } void TestPasswordGenerator::testLookalikeExclusion() { - PasswordGenerator generator; - generator.setLength(2000); - generator.setCharClasses(PasswordGenerator::CharClass::LowerLetters | PasswordGenerator::CharClass::UpperLetters); - QVERIFY(generator.isValid()); - QString password = generator.generatePassword(); + QFETCH(PasswordGenerator::CharClasses, activeCharacterClasses); + QFETCH(QRegularExpression, expected); + + m_generator.setFlags(PasswordGenerator::ExcludeLookAlike); + m_generator.setCharClasses(activeCharacterClasses); + m_generator.setLength(2000); + + QVERIFY(m_generator.isValid()); + QString password = m_generator.generatePassword(); QCOMPARE(password.size(), 2000); + QVERIFY(expected.match(password).hasMatch()); +} + +void TestPasswordGenerator::testValidity_data() +{ + QTest::addColumn<PasswordGenerator::CharClasses>("activeCharacterClasses"); + QTest::addColumn<PasswordGenerator::GeneratorFlags>("generatorFlags"); + QTest::addColumn<QString>("customCharacterSet"); + QTest::addColumn<QString>("excludedCharacters"); + QTest::addColumn<int>("length"); + QTest::addColumn<bool>("isValid"); + + QTest::addRow("No active class") << to_flags(PasswordGenerator::CharClass::NoClass) + << PasswordGenerator::GeneratorFlags() << QString() << QString() + << PasswordGenerator::DefaultLength << false; + QTest::addRow("0 length") << to_flags(PasswordGenerator::CharClass::DefaultCharset) + << PasswordGenerator::GeneratorFlags() << QString() << QString() << 0 << false; + QTest::addRow("All active classes excluded") + << to_flags(PasswordGenerator::CharClass::Numbers) << PasswordGenerator::GeneratorFlags() << QString() + << QString("0123456789") << PasswordGenerator::DefaultLength << false; + QTest::addRow("All active classes excluded") + << to_flags(PasswordGenerator::CharClass::NoClass) << PasswordGenerator::GeneratorFlags() << QString() + << QString("0123456789") << PasswordGenerator::DefaultLength << false; + QTest::addRow("One from every class with too few classes") + << (PasswordGenerator::CharClass::LowerLetters | PasswordGenerator::CharClass::UpperLetters) + << to_flags(PasswordGenerator::GeneratorFlag::CharFromEveryGroup) << QString() << QString() << 1 << false; + QTest::addRow("One from every class with excluded classes") + << (PasswordGenerator::CharClass::LowerLetters | PasswordGenerator::CharClass::UpperLetters + | PasswordGenerator::CharClass::Numbers) + << to_flags(PasswordGenerator::GeneratorFlag::CharFromEveryGroup) << QString() << QString("0123456789") << 2 + << true; + QTest::addRow("Defaults valid") << to_flags(PasswordGenerator::CharClass::DefaultCharset) + << to_flags(PasswordGenerator::GeneratorFlag::DefaultFlags) + << PasswordGenerator::DefaultCustomCharacterSet + << PasswordGenerator::DefaultExcludedChars << PasswordGenerator::DefaultLength + << true; + QTest::addRow("No active classes but custom charset") + << to_flags(PasswordGenerator::CharClass::NoClass) << to_flags(PasswordGenerator::GeneratorFlag::DefaultFlags) + << QString("a") << QString() << 1 << true; +} + +void TestPasswordGenerator::testValidity() +{ + QFETCH(PasswordGenerator::CharClasses, activeCharacterClasses); + QFETCH(PasswordGenerator::GeneratorFlags, generatorFlags); + QFETCH(QString, customCharacterSet); + QFETCH(QString, excludedCharacters); + QFETCH(int, length); + QFETCH(bool, isValid); + + m_generator.setCharClasses(activeCharacterClasses); + m_generator.setFlags(generatorFlags); + m_generator.setCustomCharacterSet(customCharacterSet); + m_generator.setExcludedCharacterSet(excludedCharacters); + m_generator.setLength(length); + QCOMPARE(m_generator.isValid(), isValid); +} + +void TestPasswordGenerator::testMinLength_data() +{ + QTest::addColumn<PasswordGenerator::CharClasses>("activeCharacterClasses"); + QTest::addColumn<PasswordGenerator::GeneratorFlags>("generatorFlags"); + QTest::addColumn<QString>("customCharacterSet"); + QTest::addColumn<QString>("excludedCharacters"); + QTest::addColumn<int>("expectedMinLength"); + + QTest::addRow("No restriction without charsFromEveryGroup") + << to_flags(PasswordGenerator::CharClass::Numbers) + << to_flags(PasswordGenerator::GeneratorFlag::CharFromEveryGroup) + << PasswordGenerator::DefaultCustomCharacterSet << PasswordGenerator::DefaultExcludedChars << 1; + + QTest::addRow("Min length should equal number of active classes") + << (PasswordGenerator::CharClass::LowerLetters | PasswordGenerator::CharClass::UpperLetters + | PasswordGenerator::CharClass::Numbers) + << to_flags(PasswordGenerator::GeneratorFlag::CharFromEveryGroup) << QString() << QString() << 3; + QTest::addRow("Classes fully excluded by excluded characters do not count towards min length") + << (PasswordGenerator::CharClass::Numbers | PasswordGenerator::LowerLetters + | PasswordGenerator::CharClass::UpperLetters) + << to_flags(PasswordGenerator::GeneratorFlag::CharFromEveryGroup) << QString() << QString("0123456789") << 2; + + QTest::addRow("Custom charset counts as class") + << to_flags(PasswordGenerator::CharClass::UpperLetters) + << to_flags(PasswordGenerator::GeneratorFlag::CharFromEveryGroup) << QString("a") << QString() << 2; + QTest::addRow("Custom characters count even if included by an active class already") + << (PasswordGenerator::CharClass::LowerLetters | PasswordGenerator::CharClass::UpperLetters + | PasswordGenerator::CharClass::Numbers) + << to_flags(PasswordGenerator::GeneratorFlag::CharFromEveryGroup) << QString("012345") << QString() << 4; +} + +void TestPasswordGenerator::testMinLength() +{ + QFETCH(PasswordGenerator::CharClasses, activeCharacterClasses); + QFETCH(PasswordGenerator::GeneratorFlags, generatorFlags); + QFETCH(QString, customCharacterSet); + QFETCH(QString, excludedCharacters); + QFETCH(int, expectedMinLength); + + m_generator.setCharClasses(activeCharacterClasses); + m_generator.setFlags(generatorFlags); + m_generator.setCustomCharacterSet(customCharacterSet); + m_generator.setExcludedCharacterSet(excludedCharacters); + QCOMPARE(m_generator.getMinLength(), expectedMinLength); +} + +void TestPasswordGenerator::testReset() +{ + PasswordGenerator default_generator; + + // Modify generator + m_generator.setCharClasses(PasswordGenerator::CharClass::NoClass); + m_generator.setFlags(PasswordGenerator::GeneratorFlag::NoFlags); + m_generator.setCustomCharacterSet("avc"); + m_generator.setExcludedCharacterSet("asdv"); + m_generator.setLength(m_generator.getLength() + 1); + + Q_ASSERT(m_generator.getActiveClasses() != default_generator.getActiveClasses()); + Q_ASSERT(m_generator.getFlags() != default_generator.getFlags()); + Q_ASSERT(m_generator.getCustomCharacterSet() != default_generator.getCustomCharacterSet()); + Q_ASSERT(m_generator.getExcludedCharacterSet() != default_generator.getExcludedCharacterSet()); - generator.setFlags(PasswordGenerator::GeneratorFlag::ExcludeLookAlike); - password = generator.generatePassword(); - QRegularExpression regex("^[^lBGIO]+$"); - QVERIFY(regex.match(password).hasMatch()); - - generator.setCharClasses(PasswordGenerator::CharClass::LowerLetters | PasswordGenerator::CharClass::UpperLetters - | PasswordGenerator::CharClass::Numbers); - password = generator.generatePassword(); - regex.setPattern("^[^lBGIO0168]+$"); - QVERIFY(regex.match(password).hasMatch()); - - generator.setCharClasses(PasswordGenerator::CharClass::LowerLetters | PasswordGenerator::CharClass::UpperLetters - | PasswordGenerator::CharClass::Numbers | PasswordGenerator::CharClass::EASCII); - password = generator.generatePassword(); - regex.setPattern("^[^lBGIO0168﹒]+$"); - QVERIFY(regex.match(password).hasMatch()); + m_generator.reset(); + QCOMPARE(m_generator.getActiveClasses(), default_generator.getActiveClasses()); + QCOMPARE(m_generator.getFlags(), default_generator.getFlags()); + QCOMPARE(m_generator.getCustomCharacterSet(), default_generator.getCustomCharacterSet()); + QCOMPARE(m_generator.getExcludedCharacterSet(), default_generator.getExcludedCharacterSet()); + QCOMPARE(m_generator.getLength(), default_generator.getLength()); } diff --git a/tests/TestPasswordGenerator.h b/tests/TestPasswordGenerator.h index 454d16e06..b5bfa7d23 100644 --- a/tests/TestPasswordGenerator.h +++ b/tests/TestPasswordGenerator.h @@ -18,17 +18,31 @@ #ifndef KEEPASSXC_TESTPASSWORDGENERATOR_H #define KEEPASSXC_TESTPASSWORDGENERATOR_H +#include "core/PasswordGenerator.h" #include <QObject> class TestPasswordGenerator : public QObject { Q_OBJECT +private: + PasswordGenerator m_generator; + private slots: void initTestCase(); - void testAdditionalChars(); + void init(); + + void testCustomCharacterSet_data(); + void testCustomCharacterSet(); + void testCharClasses_data(); void testCharClasses(); + void testLookalikeExclusion_data(); void testLookalikeExclusion(); + void testMinLength_data(); + void testMinLength(); + void testValidity_data(); + void testValidity(); + void testReset(); }; #endif // KEEPASSXC_TESTPASSWORDGENERATOR_H |