// SPDX-License-Identifier: LGPL-2.1-or-later #include "App/MappedName.h" #include #include #include #include #include #include class StringIDTest: public ::testing::Test { protected: // void SetUp() override {} // void TearDown() override {} static App::StringID givenFlaggedStringID(App::StringID::Flag flag) { const long value {42}; const QByteArray data {"data", 4}; return App::StringID {value, data, flag}; } }; TEST_F(StringIDTest, stringIDManualConstructionNoFlags) // NOLINT { // Arrange const long expectedValue {42}; const QByteArray expectedData {"data", 4}; // Act auto id = App::StringID(expectedValue, expectedData); // Assert EXPECT_EQ(expectedValue, id.value()); EXPECT_EQ(expectedData, id.data()); EXPECT_FALSE(id.isBinary()); } TEST_F(StringIDTest, stringIDManualConstructionWithFlag) // NOLINT { // Arrange const long expectedValue {42}; const QByteArray expectedData {"data", 4}; const App::StringID::Flags expectedFlags {App::StringID::Flag::Binary}; // Act auto id = App::StringID(expectedValue, expectedData, expectedFlags); // Assert EXPECT_EQ(expectedValue, id.value()); EXPECT_EQ(expectedData, id.data()); EXPECT_TRUE(id.isBinary()); } TEST_F(StringIDTest, stringIDDefaultConstruction) // NOLINT { // Arrange & Act auto id = App::StringID(); // Assert EXPECT_EQ(0, id.value()); } TEST_F(StringIDTest, value) // NOLINT { // Arrange const long expectedValueA {0}; auto idA = App::StringID(expectedValueA, nullptr); const long expectedValueB {42}; auto idB = App::StringID(expectedValueB, nullptr); const long expectedValueC {314159}; auto idC = App::StringID(expectedValueC, nullptr); // Act auto valueA = idA.value(); auto valueB = idB.value(); auto valueC = idC.value(); // Assert EXPECT_EQ(expectedValueA, valueA); EXPECT_EQ(expectedValueB, valueB); EXPECT_EQ(expectedValueC, valueC); } TEST_F(StringIDTest, relatedIDs) // NOLINT { // Nothing to test -- relatedIDs are storage-only in this class } TEST_F(StringIDTest, isBinary) // NOLINT { // Arrange auto flaggedID = givenFlaggedStringID(App::StringID::Flag::Binary); auto controlID = App::StringID {}; // Act & Assert EXPECT_TRUE(flaggedID.isBinary()); EXPECT_FALSE(controlID.isBinary()); } TEST_F(StringIDTest, isHashed) // NOLINT { // Arrange auto flaggedID = givenFlaggedStringID(App::StringID::Flag::Hashed); auto controlID = App::StringID {}; // Act & Assert EXPECT_TRUE(flaggedID.isHashed()); EXPECT_FALSE(controlID.isHashed()); } TEST_F(StringIDTest, isPostfixed) // NOLINT { // Arrange auto flaggedID = givenFlaggedStringID(App::StringID::Flag::Postfixed); auto controlID = App::StringID {}; // Act & Assert EXPECT_TRUE(flaggedID.isPostfixed()); EXPECT_FALSE(controlID.isPostfixed()); } TEST_F(StringIDTest, isPostfixEncoded) // NOLINT { // Arrange auto flaggedID = givenFlaggedStringID(App::StringID::Flag::PostfixEncoded); auto controlID = App::StringID {}; // Act & Assert EXPECT_TRUE(flaggedID.isPostfixEncoded()); EXPECT_FALSE(controlID.isPostfixEncoded()); } TEST_F(StringIDTest, isIndexed) // NOLINT { // Arrange auto flaggedID = givenFlaggedStringID(App::StringID::Flag::Indexed); auto controlID = App::StringID {}; // Act & Assert EXPECT_TRUE(flaggedID.isIndexed()); EXPECT_FALSE(controlID.isIndexed()); } TEST_F(StringIDTest, isPrefixID) // NOLINT { // Arrange auto flaggedID = givenFlaggedStringID(App::StringID::Flag::PrefixID); auto controlID = App::StringID {}; // Act & Assert EXPECT_TRUE(flaggedID.isPrefixID()); EXPECT_FALSE(controlID.isPrefixID()); } TEST_F(StringIDTest, isPrefixIDIndex) // NOLINT { // Arrange auto flaggedID = givenFlaggedStringID(App::StringID::Flag::PrefixIDIndex); auto controlID = App::StringID {}; // Act & Assert EXPECT_TRUE(flaggedID.isPrefixIDIndex()); EXPECT_FALSE(controlID.isPrefixIDIndex()); } TEST_F(StringIDTest, isMarked) // NOLINT { // Arrange auto flaggedID = givenFlaggedStringID(App::StringID::Flag::Marked); auto controlID = App::StringID {}; // Act & Assert EXPECT_TRUE(flaggedID.isMarked()); EXPECT_FALSE(controlID.isMarked()); } TEST_F(StringIDTest, isPersistent) // NOLINT { // Arrange auto flaggedID = givenFlaggedStringID(App::StringID::Flag::Persistent); auto controlID = App::StringID {}; // Act & Assert EXPECT_TRUE(flaggedID.isPersistent()); EXPECT_FALSE(controlID.isPersistent()); } TEST_F(StringIDTest, isFromSameHasher) // NOLINT { // Nothing to test except when used by StringHasher } TEST_F(StringIDTest, getHasher) // NOLINT { // Nothing to test except when used by StringHasher } TEST_F(StringIDTest, data) // NOLINT { // Arrange QByteArray expectedData {"data", 4}; auto id = App::StringID(1, expectedData); // Act auto data = id.data(); // Assert EXPECT_EQ(expectedData, data); } TEST_F(StringIDTest, postfix) // NOLINT { // Nothing to test except when used by StringHasher } TEST_F(StringIDTest, getPyObject) // NOLINT { // Arrange Py_Initialize(); auto id = new App::StringID(1, nullptr); id->ref(); // Act Py::Object py(id->getPyObject(), true); id->unref(); // Assert EXPECT_TRUE(PyObject_TypeCheck(py.ptr(), &App::StringIDPy::Type)); } TEST_F(StringIDTest, getPyObjectWithIndex) // NOLINT { // Arrange Py_Initialize(); auto id = new App::StringID(1, nullptr); id->ref(); // Act Py::Object py(id->getPyObjectWithIndex(2), true); id->unref(); // Assert ASSERT_TRUE(PyObject_TypeCheck(py.ptr(), &App::StringIDPy::Type)); } TEST_F(StringIDTest, toStringWithoutIndex) // NOLINT { // Arrange const long bigHex = 0xfcad10; auto idA = App::StringID(1, QByteArray {"data", 4}); auto idB = App::StringID(bigHex, QByteArray {"data", 4}); // Act auto resultA = idA.toString(); auto resultB = idB.toString(); // Assert EXPECT_EQ(std::string("#1"), resultA); EXPECT_EQ(std::string("#fcad10"), resultB); // Make sure result is in hex } TEST_F(StringIDTest, toStringWithIndex) // NOLINT { // Arrange const long bigHex = 0xfcad10; auto id = App::StringID(1, QByteArray {"data", 4}); // Act auto resultA = id.toString(bigHex); auto resultB = id.toString(0); // Assert EXPECT_EQ(std::string("#1:fcad10"), resultA); EXPECT_EQ(std::string("#1"), resultB); } TEST_F(StringIDTest, fromStringWithEOFAndLengthGood) // NOLINT { // Arrange const std::string testString {"#1:fcad"}; // Act auto result = App::StringID::fromString(testString.c_str(), true, static_cast(testString.length())); // Assert EXPECT_EQ(result.id, 1); EXPECT_EQ(result.index, 0xfcad); } TEST_F(StringIDTest, fromStringExtraData) // NOLINT { // Arrange const std::string testString {"#1:fcad#2:bad"}; // Act auto trueResult = App::StringID::fromString(testString.c_str(), true, static_cast(testString.length())); auto falseResult = App::StringID::fromString(testString.c_str(), false, static_cast(testString.length())); // Assert EXPECT_EQ(trueResult.id, -1); EXPECT_EQ(falseResult.id, 1); } TEST_F(StringIDTest, fromStringLengthUnspecified) // NOLINT { // Arrange const std::string testString {"#1:fcad#2:bad"}; // Act auto trueResult = App::StringID::fromString(testString.c_str(), true); auto falseResult = App::StringID::fromString(testString.c_str(), false); // Assert EXPECT_EQ(trueResult.id, -1); EXPECT_EQ(falseResult.id, 1); } TEST_F(StringIDTest, fromStringShorterLength) // NOLINT { // Arrange const int dataLength {7}; const std::string testString {"#1:fcad#2:bad"}; // Act auto trueResult = App::StringID::fromString(testString.c_str(), true, dataLength); auto falseResult = App::StringID::fromString(testString.c_str(), false, dataLength); // Assert EXPECT_EQ(trueResult.id, 1); EXPECT_EQ(falseResult.id, 1); } TEST_F(StringIDTest, fromStringNoHashtag) // NOLINT { // Arrange const std::string testString {"1:fcad"}; // Act auto result = App::StringID::fromString(testString.c_str(), true); // Assert EXPECT_EQ(result.id, -1); } TEST_F(StringIDTest, fromStringNotHex) // NOLINT { // Arrange const std::string testStringA {"1:freecad"}; const std::string testStringB {"zoink:2"}; // Act auto resultA = App::StringID::fromString(testStringA.c_str(), false); auto resultB = App::StringID::fromString(testStringB.c_str(), false); // Assert EXPECT_EQ(resultA.id, -1); EXPECT_EQ(resultB.id, -1); } TEST_F(StringIDTest, fromStringQByteArray) // NOLINT { // Arrange const QByteArray testString {"#1:fcad", 7}; // Act auto result = App::StringID::fromString(testString, true); // Assert EXPECT_EQ(result.id, 1); EXPECT_EQ(result.index, 0xfcad); } TEST_F(StringIDTest, dataToTextHashed) // NOLINT { // Arrange QByteArray buffer {"120ca87015d849dbea060eaf2295fcc4ee981427", 40}; // NOLINT auto id = App::StringID(1, buffer, App::StringID::Flag::Hashed); // Act auto result = id.dataToText(0); // Assert EXPECT_EQ(result, buffer.toBase64().constData()); } TEST_F(StringIDTest, dataToTextBinary) // NOLINT { // Arrange QByteArray buffer {"120ca87015d849dbea060eaf2295fcc4ee981427", 40}; // NOLINT auto id = App::StringID(1, buffer, App::StringID::Flag::Binary); // Act auto result = id.dataToText(0); // Assert EXPECT_EQ(result, buffer.toBase64().constData()); } TEST_F(StringIDTest, dataToTextNoIndex) // NOLINT { // Arrange QByteArray data {"data", 4}; auto id = App::StringID(1, data); // Act auto result = id.dataToText(0); // Assert EXPECT_EQ(result, "data"); } TEST_F(StringIDTest, dataToTextWithIndex) // NOLINT { // Arrange QByteArray data {"data", 4}; auto id = App::StringID(1, data); // Act auto resultA = id.dataToText(1); auto resultB = id.dataToText(1024); // NOLINT // Assert EXPECT_EQ(resultA, "data1"); EXPECT_EQ(resultB, "data1024"); // Not hex! } TEST_F(StringIDTest, dataToTextWithPostfix) // NOLINT { // Arrange QByteArray data {"data", 4}; QByteArray postfix {"postfix", 7}; // NOLINT auto id = App::StringID(1, data); id.setPostfix(postfix); // Act auto result = id.dataToText(1); // Assert EXPECT_EQ(result, "data1postfix"); } TEST_F(StringIDTest, dataToBytesNoIndex) // NOLINT { // Arrange QByteArray data {"data", 4}; auto id = App::StringID(1, data); // Act auto result = id.dataToBytes(); // Assert EXPECT_EQ(data, result); } TEST_F(StringIDTest, dataToBytesWithIndex) // NOLINT { // Arrange QByteArray data {"data", 4}; const int index {1234}; auto id = App::StringID(1, data); // Act auto result = id.dataToBytes(index); // Assert EXPECT_EQ(data + QByteArray::number(index), result); } TEST_F(StringIDTest, dataToBytesWithPostfix) // NOLINT { // Arrange QByteArray data {"data", 4}; QByteArray postfix {"postfix", 7}; // NOLINT auto id = App::StringID(1, data); id.setPostfix(postfix); // Act auto result = id.dataToBytes(); // Assert EXPECT_EQ(data + postfix, result); } TEST_F(StringIDTest, dataToBytesWithIndexAndPostfix) // NOLINT { // Arrange QByteArray data {"data", 4}; QByteArray postfix {"postfix", 7}; // NOLINT const int index {1234}; auto id = App::StringID(1, data); id.setPostfix(postfix); // Act auto result = id.dataToBytes(index); // Assert EXPECT_EQ(data + QByteArray::number(index) + postfix, result); } TEST_F(StringIDTest, mark) // NOLINT { // Arrange QByteArray data {"data", 4}; auto id = App::StringID(1, data); ASSERT_FALSE(id.isMarked()); // Act id.mark(); // Assert EXPECT_TRUE(id.isMarked()); } TEST_F(StringIDTest, setPersistent) // NOLINT { // Arrange QByteArray data {"data", 4}; auto id = App::StringID(1, data); ASSERT_FALSE(id.isPersistent()); // Act id.setPersistent(true); // Assert EXPECT_TRUE(id.isPersistent()); } TEST_F(StringIDTest, operatorLessThan) // NOLINT { // Can't test without a _hasher } TEST_F(StringIDTest, compare) // NOLINT { // Can't test without a _hasher } TEST_F(StringIDTest, IndexIDBooleanConversion) // NOLINT { // Arrange const long id {42}; const int index {123}; App::StringID::IndexID indexIdTrue {id, index}; App::StringID::IndexID indexIdFalse {0, index}; // Act & Assert EXPECT_TRUE(indexIdTrue); EXPECT_FALSE(indexIdFalse); } TEST_F(StringIDTest, IndexIDStreamInsertionOperator) // NOLINT { // Arrange const long id {42}; const int index {123}; App::StringID::IndexID indexIdNonZero {id, index}; App::StringID::IndexID indexIdZero {id, 0}; std::ostringstream stream; // Act stream << indexIdNonZero << " " << indexIdZero; // Assert EXPECT_EQ("42:123 42", stream.str()); } class StringIDRefTest: public ::testing::Test { protected: // void SetUp() override {} // void TearDown() override {} App::StringID* createStringID() const { return new App::StringID {_id, _data}; } private: QByteArray _data {"data", 4}; int _id {1}; }; TEST_F(StringIDRefTest, defaultConstructor) // NOLINT { // Arrange & Act auto idRef = App::StringIDRef(); // Assert EXPECT_FALSE(idRef); } TEST_F(StringIDRefTest, constructFromNewStringID) // NOLINT { // Arrange & Act auto idRef = App::StringIDRef(createStringID()); // Assert EXPECT_TRUE(idRef); EXPECT_EQ(1, idRef.getRefCount()); // NOTE: the dynamically-allocated StringID is automatically deallocated by the StringIDRef // when its destructor is called (upon exit from this test function). } TEST_F(StringIDRefTest, constructFromStringIDAndIndex) // NOLINT { // Arrange const int index {42}; // Act auto idRef = App::StringIDRef(createStringID(), index); // Assert EXPECT_TRUE(idRef); EXPECT_EQ(1, idRef.getRefCount()); EXPECT_EQ(index, idRef.getIndex()); // NOTE: the dynamically-allocated StringID is automatically deallocated by the StringIDRef // when its destructor is called (upon exit from this test function). } TEST_F(StringIDRefTest, copyConstructor) // NOLINT { // Arrange const int index {42}; auto idRef = App::StringIDRef(createStringID(), index); // Act auto newIdRef = App::StringIDRef(idRef); // Assert EXPECT_TRUE(newIdRef); EXPECT_EQ(2, newIdRef.getRefCount()); EXPECT_EQ(index, idRef.getIndex()); EXPECT_EQ(index, newIdRef.getIndex()); } TEST_F(StringIDRefTest, copyConstructorWithIndex) // NOLINT { // Arrange const int index {42}; const int otherIndex {12345}; auto idRef = App::StringIDRef(createStringID(), index); // Act auto newIdRef = App::StringIDRef(idRef, otherIndex); // Assert EXPECT_TRUE(newIdRef); EXPECT_EQ(2, newIdRef.getRefCount()); EXPECT_EQ(index, idRef.getIndex()); EXPECT_EQ(otherIndex, newIdRef.getIndex()); } TEST_F(StringIDRefTest, moveConstructor) // NOLINT { // Arrange auto idRef = App::StringIDRef(createStringID()); // Act auto newIdRef = App::StringIDRef(std::move(idRef)); // Assert EXPECT_EQ(1, newIdRef.getRefCount()); } TEST_F(StringIDRefTest, destructor) // NOLINT { // Arrange auto idRef = App::StringIDRef(createStringID()); { auto newIdRef = App::StringIDRef(idRef); ASSERT_EQ(2, idRef.getRefCount()); // Verify the test setup // Act // The scope ends, causing newIdRef destructor execution } // Assert EXPECT_EQ(1, idRef.getRefCount()); } TEST_F(StringIDRefTest, reset) // NOLINT { // Arrange auto idRef = App::StringIDRef(createStringID()); // Act idRef.reset(); // Assert EXPECT_FALSE(idRef); } TEST_F(StringIDRefTest, resetWithStringID) // NOLINT { // Arrange const int index {42}; auto idRef = App::StringIDRef(createStringID(), index); // Act idRef.reset(createStringID()); // Assert EXPECT_TRUE(idRef); EXPECT_NE(index, idRef.getIndex()); } TEST_F(StringIDRefTest, resetWithStringIDAndIndex) // NOLINT { // Arrange const int indexA {42}; const int indexB {12345}; auto idRef = App::StringIDRef(createStringID(), indexA); // Act idRef.reset(createStringID(), indexB); // Assert EXPECT_TRUE(idRef); EXPECT_EQ(indexB, idRef.getIndex()); } TEST_F(StringIDRefTest, swap) // NOLINT { // Arrange const int indexA {42}; const int indexB {12345}; auto idRefA = App::StringIDRef(createStringID(), indexA); auto idRefB = App::StringIDRef(createStringID(), indexB); // Act idRefA.swap(idRefB); // Assert EXPECT_EQ(indexB, idRefA.getIndex()); EXPECT_EQ(indexA, idRefB.getIndex()); } #if defined(__clang__) # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wself-assign-overloaded" #endif TEST_F(StringIDRefTest, assignmentFromSelf) // NOLINT { // Arrange auto idRef = App::StringIDRef(createStringID()); // Act idRef = idRef; // Assert EXPECT_EQ(1, idRef.getRefCount()); } #if defined(__clang__) # pragma clang diagnostic pop #endif TEST_F(StringIDRefTest, assignmentToEmptyFromStringID) // NOLINT { // Arrange Py_Initialize(); auto idRef = App::StringIDRef(); ASSERT_FALSE(idRef); // Verify setup // Act idRef = createStringID(); // Assert EXPECT_TRUE(idRef); } TEST_F(StringIDRefTest, assignmentFromStringIDRef) // NOLINT { // Arrange auto firstIdRef = App::StringIDRef(createStringID()); auto firstIdRefExtra = firstIdRef; auto secondIdRef = App::StringIDRef(createStringID()); // Act firstIdRef = secondIdRef; // Assert EXPECT_EQ(2, secondIdRef.getRefCount()); EXPECT_EQ(2, firstIdRef.getRefCount()); EXPECT_EQ(1, firstIdRefExtra.getRefCount()); } TEST_F(StringIDRefTest, moveAssignmentFromStringIDRef) // NOLINT { auto emptyIdRef = App::StringIDRef(); auto goodIdRef = App::StringIDRef(createStringID()); ASSERT_FALSE(emptyIdRef); // Verify setup // Act emptyIdRef = std::move(goodIdRef); // Assert EXPECT_TRUE(emptyIdRef); EXPECT_EQ(1, emptyIdRef.getRefCount()); } TEST_F(StringIDRefTest, operatorLess) // NOLINT { // Arrange auto emptySIDA = App::StringIDRef(); auto emptySIDB = App::StringIDRef(); auto lowID = App::StringIDRef(new App::StringID {1, nullptr}); auto highID = App::StringIDRef(new App::StringID {2, nullptr}); // Act & Assert EXPECT_FALSE(emptySIDA < emptySIDB); EXPECT_FALSE(emptySIDB < emptySIDA); EXPECT_TRUE(emptySIDA < lowID); EXPECT_TRUE(emptySIDA < highID); EXPECT_TRUE(lowID < highID); EXPECT_FALSE(highID < lowID); // NOTE: Cannot test the impact of hasher without a StringHasher } TEST_F(StringIDRefTest, operatorEquality) // NOLINT { // Arrange auto emptySIDA = App::StringIDRef(); auto emptySIDB = App::StringIDRef(); auto nonEmptyA = App::StringIDRef(new App::StringID {1, nullptr}); auto nonEmptyB = App::StringIDRef(new App::StringID {1, nullptr}); auto nonEmptyOther = App::StringIDRef(new App::StringID {2, nullptr}); // Act & Assert EXPECT_TRUE(emptySIDA == emptySIDB); EXPECT_TRUE(nonEmptyA == nonEmptyB); EXPECT_FALSE(emptySIDA == nonEmptyA); EXPECT_FALSE(nonEmptyA == nonEmptyOther); } TEST_F(StringIDRefTest, operatorInequality) // NOLINT { // Arrange auto emptySIDA = App::StringIDRef(); auto emptySIDB = App::StringIDRef(); auto nonEmptyA = App::StringIDRef(new App::StringID {1, nullptr}); auto nonEmptyB = App::StringIDRef(new App::StringID {1, nullptr}); auto nonEmptyOther = App::StringIDRef(new App::StringID {2, nullptr}); // Act & Assert EXPECT_FALSE(emptySIDA != emptySIDB); EXPECT_FALSE(nonEmptyA != nonEmptyB); EXPECT_TRUE(emptySIDA != nonEmptyA); EXPECT_TRUE(nonEmptyA != nonEmptyOther); } TEST_F(StringIDRefTest, booleanConversion) // NOLINT { // Arrange auto emptySID = App::StringIDRef(); auto nonEmpty = App::StringIDRef(new App::StringID {1, nullptr}); // Act & Assert EXPECT_FALSE(emptySID); EXPECT_TRUE(nonEmpty); } TEST_F(StringIDRefTest, getRefCount) // NOLINT { // Arrange auto stringID = createStringID(); auto stringIDRef = App::StringIDRef(stringID); // Act auto firstCount = stringIDRef.getRefCount(); auto stringIDRef2 = App::StringIDRef(stringID); auto secondCount = stringIDRef.getRefCount(); // Assert EXPECT_EQ(1, firstCount); EXPECT_EQ(2, secondCount); } TEST_F(StringIDRefTest, toString) // NOLINT { // Arrange auto emptySID = App::StringIDRef(); auto nonEmpty = App::StringIDRef(createStringID()); // Act auto empty = emptySID.toString(); auto nonempty = nonEmpty.toString(); // Assert // Only confirm that the function call is passed along: the real test is in the StringID class EXPECT_TRUE(empty.empty()); EXPECT_FALSE(nonempty.empty()); } TEST_F(StringIDRefTest, dataToText) // NOLINT { // Arrange auto emptySID = App::StringIDRef(); auto nonEmpty = App::StringIDRef(createStringID()); // Act auto empty = emptySID.dataToText(); auto nonempty = nonEmpty.dataToText(); // Assert // Only confirm that the function call is passed along: the real test is in the StringID class EXPECT_TRUE(empty.empty()); EXPECT_FALSE(nonempty.empty()); } TEST_F(StringIDRefTest, constData) // NOLINT { // Arrange auto sid = App::StringIDRef(createStringID()); // Act auto constData = sid.constData(); // Assert ASSERT_NE(constData, nullptr); EXPECT_STREQ(constData, "data"); } TEST_F(StringIDRefTest, deref) // NOLINT { // Arrange auto sid = createStringID(); auto ref = App::StringIDRef(sid); // Act & Assert EXPECT_EQ(sid, &(ref.deref())); } TEST_F(StringIDRefTest, value) // NOLINT { // Arrange auto empty = App::StringIDRef(); auto nonEmpty = App::StringIDRef(createStringID()); // Act auto emptyValue = empty.value(); auto nonEmptyValue = nonEmpty.value(); // Assert EXPECT_EQ(0, emptyValue); EXPECT_NE(0, nonEmptyValue); } TEST_F(StringIDRefTest, relatedIDs) // NOLINT { // Nothing to test without a StringHasher } TEST_F(StringIDRefTest, isBinary) // NOLINT { // Arrange auto nothing = App::StringIDRef(); auto binary = App::StringIDRef(new App::StringID {1, nullptr, App::StringID::Flag::Binary}); auto nonBinary = App::StringIDRef(new App::StringID {1, nullptr, App::StringID::Flag::None}); // Act & Assert EXPECT_FALSE(nothing.isBinary()); EXPECT_TRUE(binary.isBinary()); EXPECT_FALSE(nonBinary.isBinary()); } TEST_F(StringIDRefTest, isHashed) // NOLINT { // Arrange auto nothing = App::StringIDRef(); auto hashed = App::StringIDRef(new App::StringID {1, nullptr, App::StringID::Flag::Hashed}); auto nonHashed = App::StringIDRef(new App::StringID {1, nullptr, App::StringID::Flag::None}); // Act & Assert EXPECT_FALSE(nothing.isHashed()); EXPECT_TRUE(hashed.isHashed()); EXPECT_FALSE(nonHashed.isHashed()); } TEST_F(StringIDRefTest, toBytes) // NOLINT { // Arrange QByteArray byteStorage; auto ref = App::StringIDRef(createStringID()); // Act ref.toBytes(byteStorage); // Assert EXPECT_FALSE(byteStorage.isNull()); } TEST_F(StringIDRefTest, getPyObject) // NOLINT { Py_Initialize(); // Arrange auto ref = App::StringIDRef(createStringID()); auto empty = App::StringIDRef(); // Act Py::Object pyObject(ref.getPyObject(), true); Py::Object none(empty.getPyObject(), true); // Assert EXPECT_TRUE(PyObject_TypeCheck(pyObject.ptr(), &App::StringIDPy::Type)); EXPECT_EQ(none.ptr(), Py_None); } TEST_F(StringIDRefTest, mark) // NOLINT { // Arrange auto ref = App::StringIDRef(createStringID()); ASSERT_FALSE(ref.isMarked()); // Act ref.mark(); // Assert EXPECT_TRUE(ref.isMarked()); } TEST_F(StringIDRefTest, isMarked) // NOLINT { // Arrange auto marked = App::StringIDRef(new App::StringID(1, nullptr, App::StringID::Flag::Marked)); auto notMarked = App::StringIDRef(createStringID()); // Act & Assert EXPECT_TRUE(marked.isMarked()); EXPECT_FALSE(notMarked.isMarked()); } TEST_F(StringIDRefTest, isFromSameHasher) // NOLINT { // Nothing to test, requires a StringHasher } TEST_F(StringIDRefTest, getHasher) // NOLINT { // Nothing to test, requires a StringHasher } TEST_F(StringIDRefTest, setPersistent) // NOLINT { // Arrange auto persistent = App::StringIDRef(createStringID()); ASSERT_FALSE(persistent.deref().isPersistent()); // Act persistent.setPersistent(true); // Assert ASSERT_TRUE(persistent.deref().isPersistent()); } class StringHasherTest: public ::testing::Test { protected: void SetUp() override { Py_Initialize(); _hasher = Base::Reference(new App::StringHasher); } void TearDown() override { _hasher->clear(); } Base::Reference Hasher() { return _hasher; } static Data::MappedName givenMappedName(const char* name, const char* postfix = nullptr) { QByteArray expectedPrefix {name, static_cast(std::strlen(name))}; Data::MappedName mappedName(expectedPrefix); if (postfix) { QByteArray expectedPostfix {postfix, static_cast(std::strlen(postfix))}; Data::MappedName mappedNameA(mappedName, expectedPostfix.data()); return mappedNameA; } return mappedName; } /// Put a couple of things into the hash table: at the end of this call the size of the table /// is 2, one postfix string and one prefix+postfix combination. App::StringIDRef givenSomeHashedValues() { const std::string prefix {"Test1"}; const std::string postfix {";:M;FUS;:Hb:7,F"}; auto mappedName = givenMappedName(prefix.c_str(), postfix.c_str()); QVector sids; auto ID = Hasher()->getID(mappedName, sids); ID.mark(); // For this to be included in the count, and thus the memsize in needs to be // marked. return ID; } private: Base::Reference _hasher; }; TEST_F(StringHasherTest, defaultConstructor) // NOLINT { // Arrange // Done in Setup() // Act // Done in Setup() // Assert EXPECT_EQ(0, Hasher()->size()); } TEST_F(StringHasherTest, getMemSize) // NOLINT { // Arrange givenSomeHashedValues(); // Act auto result = Hasher()->getMemSize(); // Assert // getMemSize is advisory only, so the only thing we can confidently assert is that it is larger // than the number of values in the hash table. EXPECT_LT(Hasher()->size(), result); } TEST_F(StringHasherTest, Save) // NOLINT { // Arrange // Act // Assert } TEST_F(StringHasherTest, Restore) // NOLINT { // Arrange // Act // Assert } TEST_F(StringHasherTest, SaveDocFile) // NOLINT { // Arrange // Act // Assert } TEST_F(StringHasherTest, RestoreDocFile) // NOLINT { // Arrange // Act // Assert } TEST_F(StringHasherTest, setPersistenceFileName) // NOLINT { // Arrange // Act // Assert } TEST_F(StringHasherTest, getPersistenceFileName) // NOLINT { // Arrange // Act // Assert } TEST_F(StringHasherTest, getIDFromQByteArrayShort) // NOLINT { // Arrange const std::array string {"data"}; QByteArray qba(string.data(), string.size()); Hasher()->setThreshold(string.size() + 1); // Act auto id = Hasher()->getID(qba, App::StringHasher::Option::Hashable); // Assert EXPECT_STREQ(string.data(), id.constData()); EXPECT_FALSE(id.isHashed()); EXPECT_NE(qba.constData(), id.constData()); // A copy was made, the pointers differ EXPECT_EQ(2, id.getRefCount()); } TEST_F(StringHasherTest, getIDFromQByteArrayLongHashable) // NOLINT { // Arrange const std::array string {"data that is longer than our hasher threshold"}; QByteArray qba(string.data(), string.size()); Hasher()->setThreshold(string.size() - 1); // Act auto id = Hasher()->getID(qba, App::StringHasher::Option::Hashable); // Assert EXPECT_STRNE(string.data(), id.constData()); EXPECT_TRUE(id.isHashed()); EXPECT_NE(qba.constData(), id.constData()); // A copy was made, the pointers differ } TEST_F(StringHasherTest, getIDFromQByteArrayLongUnhashable) // NOLINT { // Arrange const std::array string {"data that is longer than our hasher threshold"}; QByteArray qba(string.data(), string.size()); Hasher()->setThreshold(string.size() - 1); // Act auto id = Hasher()->getID(qba, App::StringHasher::Option::None); // Assert EXPECT_STREQ(string.data(), id.constData()); EXPECT_FALSE(id.isHashed()); EXPECT_NE(qba.constData(), id.constData()); // A copy was made, the pointers differ } TEST_F(StringHasherTest, getIDFromQByteArrayNoCopy) // NOLINT { // Arrange const std::array string {"data"}; QByteArray qba(string.data(), string.size()); Hasher()->setThreshold(string.size() + 1); // Act auto id = Hasher()->getID(qba, App::StringHasher::Option::NoCopy); // Assert EXPECT_STREQ(string.data(), id.constData()); EXPECT_EQ(qba.constData(), id.constData()); // No copy was made, the pointers are the same } TEST_F(StringHasherTest, getIDFromQByteArrayTwoDifferentStrings) // NOLINT { // Arrange const std::array stringA {"dataA"}; QByteArray qbaA(stringA.data(), stringA.size()); const std::array stringB {"dataB"}; QByteArray qbaB(stringB.data(), stringB.size()); // Act auto idA = Hasher()->getID(qbaA); auto idB = Hasher()->getID(qbaB); // Assert EXPECT_NE(idA.dataToText(), idB.dataToText()); } TEST_F(StringHasherTest, getIDFromQByteArrayTwoIdenticalStrings) // NOLINT { // Arrange const std::array stringA {"data"}; QByteArray qbaA(stringA.data(), stringA.size()); const std::array stringB {"data"}; QByteArray qbaB(stringB.data(), stringB.size()); // Act auto idA = Hasher()->getID(qbaA); auto idB = Hasher()->getID(qbaB); // Assert EXPECT_EQ(idA.dataToText(), idB.dataToText()); } TEST_F(StringHasherTest, getIDFromQByteArrayBinaryFlag) // NOLINT { // Arrange const std::array string {"data"}; QByteArray qba(string.data(), string.size()); // Act auto id = Hasher()->getID(qba, App::StringHasher::Option::Binary); // Assert EXPECT_TRUE(id.isBinary()); } TEST_F(StringHasherTest, getIDFromCString) // NOLINT { // Arrange // Act // Assert } /* * Things that have to be tested for getIDFromMappedName: * 1. With and without postfix (every other path must test both) * 2. Existing entry: short circuits * 3. Raw data and non-raw * 4. Postfix contains # and not * 5. Indexed name and not * 6. sids empty and sids with content * 7. sids whose hasher==this and whose hasher is something else * 8. If sids.size() > 10, duplicates get removed */ TEST_F(StringHasherTest, getIDFromMappedNameWithoutPostfixWithoutIndex) // NOLINT { // Arrange const char* name {"Face"}; QByteArray expectedPrefix {name, static_cast(std::strlen(name))}; Data::MappedName mappedName1(expectedPrefix); QVector sids; // Act auto id = Hasher()->getID(mappedName1, sids); // Assert EXPECT_EQ(id.dataToText(), mappedName1.toString()); } TEST_F(StringHasherTest, getIDFromMappedNameWithoutPostfixWithIndex) // NOLINT { // Arrange const char* expectedName {"Face"}; QByteArray expectedPrefix {expectedName, static_cast(std::strlen(expectedName))}; const char* name {"Face3"}; QByteArray prefix {name, static_cast(std::strlen(name))}; Data::MappedName mappedName1(prefix); QVector sids; // Act auto id = Hasher()->getID(mappedName1, sids); // Assert EXPECT_EQ(id.dataToText(), mappedName1.toString()); } TEST_F(StringHasherTest, getIDFromMappedNameWithoutIndexWithPostfix) // NOLINT { // Arrange const char* name {"Face"}; QByteArray expectedPrefix {name, static_cast(std::strlen(name))}; const char* postfix {";:M;FUS;:Hb:7,F"}; QByteArray expectedPostfix {postfix, static_cast(std::strlen(postfix))}; Data::MappedName mappedName1(expectedPrefix); Data::MappedName mappedName2(mappedName1, expectedPostfix.data()); QVector sids; // Act auto id = Hasher()->getID(mappedName2, sids); // Assert EXPECT_EQ(expectedPrefix, id.deref().data()); EXPECT_EQ(expectedPostfix, id.deref().postfix()); } TEST_F(StringHasherTest, getIDFromMappedNameWithIndexWithPostfix) // NOLINT { // Arrange const char* name {"Face3"}; QByteArray expectedPrefix {name, static_cast(std::strlen(name))}; const char* postfix {";:M;FUS;:Hb:7,F"}; QByteArray expectedPostfix {postfix, static_cast(std::strlen(postfix))}; Data::MappedName mappedName1(expectedPrefix); Data::MappedName mappedName2(mappedName1, expectedPostfix.data()); QVector sids; // Act auto id = Hasher()->getID(mappedName2, sids); // Assert EXPECT_EQ(id.dataToText(), mappedName2.toString()); } TEST_F(StringHasherTest, getIDFromMappedNameExistingNameNoIndex) // NOLINT { // Arrange Data::MappedName mappedName1 = givenMappedName("SomeTestName"); QVector sids; auto firstIDInserted = Hasher()->getID(mappedName1, sids); ASSERT_EQ(1, Hasher()->size()); // Act auto secondIDInserted = Hasher()->getID(mappedName1, sids); // Assert EXPECT_EQ(secondIDInserted.dataToText(), mappedName1.toString()); } TEST_F(StringHasherTest, getIDFromMappedNameExistingNameWithIndex) // NOLINT { // Arrange auto mappedNameA = givenMappedName("Test1"); auto mappedNameB = givenMappedName("Test2"); QVector sids; auto firstIDInserted = Hasher()->getID(mappedNameA, sids); // Act auto secondIDInserted = Hasher()->getID(mappedNameB, sids); // Assert EXPECT_EQ(firstIDInserted.dataToText(), mappedNameA.toString()); EXPECT_EQ(secondIDInserted.dataToText(), mappedNameB.toString()); } TEST_F(StringHasherTest, getIDFromMappedNameExistingNameWithIndexAndPostfix) // NOLINT { // Arrange auto mappedNameA = givenMappedName("Test1", ";:M;FUS;:Hb:7,F"); auto mappedNameB = givenMappedName("Test2", ";:M;FUS;:Hb:7,F"); QVector sids; auto firstIDInserted = Hasher()->getID(mappedNameA, sids); // Act auto secondIDInserted = Hasher()->getID(mappedNameB, sids); // Assert EXPECT_EQ(firstIDInserted.dataToText(), mappedNameA.toString()); EXPECT_EQ(secondIDInserted.dataToText(), mappedNameB.toString()); } TEST_F(StringHasherTest, getIDFromMappedNameDuplicateWithEncodedPostfix) // NOLINT { // Arrange auto mappedNameA = givenMappedName("Test1", ";:M;FUS;:Hb:7,F"); auto mappedNameB = givenMappedName("Test1", "#1"); QVector sids; auto firstIDInserted = Hasher()->getID(mappedNameA, sids); // Act auto secondIDInserted = Hasher()->getID(mappedNameB, sids); // Assert EXPECT_EQ(firstIDInserted.dataToText(), mappedNameA.toString()); EXPECT_EQ(secondIDInserted.dataToText(), mappedNameB.toString()); } TEST_F(StringHasherTest, getIDFromIntegerIDNoSuchID) // NOLINT { // Arrange // Do nothing, so the hash table is empty // Act auto result = Hasher()->getID(1); // Assert EXPECT_FALSE(result); } TEST_F(StringHasherTest, getIDFromIntegerIDBadID) // NOLINT { // Arrange const std::string prefix {"Test1"}; auto mappedName = givenMappedName(prefix.c_str()); QVector sids; auto inserted = Hasher()->getID(mappedName, sids); ASSERT_EQ(1, Hasher()->size()); // Act auto result = Hasher()->getID(-1); // Assert EXPECT_FALSE(result); } TEST_F(StringHasherTest, getIDMap) // NOLINT { // Arrange givenSomeHashedValues(); // Act auto map = Hasher()->getIDMap(); // Assert EXPECT_GT(map.size(), 0); } TEST_F(StringHasherTest, clear) // NOLINT { // Arrange givenSomeHashedValues(); // Act Hasher()->clear(); // Assert EXPECT_EQ(0, Hasher()->size()); } TEST_F(StringHasherTest, size) // NOLINT { // Arrange givenSomeHashedValues(); // Act auto result = Hasher()->size(); // Assert EXPECT_GT(result, 0); } TEST_F(StringHasherTest, count) // NOLINT { // Arrange givenSomeHashedValues(); // Act auto result = Hasher()->count(); // Assert EXPECT_GT(result, 0); } TEST_F(StringHasherTest, getPyObject) // NOLINT { // Arrange - done in setUp() // Act Py::Object py(Hasher()->getPyObject(), true); // Assert EXPECT_TRUE(PyObject_TypeCheck(py.ptr(), &App::StringHasherPy::Type)); } TEST_F(StringHasherTest, setGetSaveAll) // NOLINT { // Arrange - done by setUp() // Act Hasher()->setSaveAll(true); bool expectedTrue = Hasher()->getSaveAll(); Hasher()->setSaveAll(false); bool expectedFalse = Hasher()->getSaveAll(); // Assert EXPECT_TRUE(expectedTrue); EXPECT_FALSE(expectedFalse); } TEST_F(StringHasherTest, setGetThreshold) // NOLINT { // Arrange const int expectedThreshold {42}; // Act Hasher()->setThreshold(expectedThreshold); auto foundThreshold = Hasher()->getThreshold(); // Assert EXPECT_EQ(expectedThreshold, foundThreshold); } TEST_F(StringHasherTest, clearMarks) // NOLINT { // Arrange auto ref = givenSomeHashedValues(); ref.mark(); ASSERT_TRUE(ref.isMarked()); // Act Hasher()->clearMarks(); // Assert ASSERT_FALSE(ref.isMarked()); } TEST_F(StringHasherTest, compact) // NOLINT { // Arrange givenSomeHashedValues(); // Act Hasher()->compact(); // Assert EXPECT_EQ(0, Hasher()->count()); }