File indexing completed on 2024-05-19 05:42:20
0001 // ct_lvtqtc_lakosentity.t.cpp -*-C++-*- 0002 0003 /* 0004 // Copyright 2023 Codethink Ltd <codethink@codethink.co.uk> 0005 // SPDX-License-Identifier: Apache-2.0 0006 // 0007 // Licensed under the Apache License, Version 2.0 (the "License"); 0008 // you may not use this file except in compliance with the License. 0009 // You may obtain a copy of the License at 0010 // 0011 // http://www.apache.org/licenses/LICENSE-2.0 0012 // 0013 // Unless required by applicable law or agreed to in writing, software 0014 // distributed under the License is distributed on an "AS IS" BASIS, 0015 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 0016 // See the License for the specific language governing permissions and 0017 // limitations under the License. 0018 */ 0019 #include <catch2-local-includes.h> 0020 0021 #include <ct_lvtldr_lakosiannode.h> 0022 #include <ct_lvtldr_nodestorage.h> 0023 0024 #include <ct_lvtqtc_componententity.h> 0025 #include <ct_lvtqtc_ellipsistextitem.h> 0026 #include <ct_lvtqtc_graphicsscene.h> 0027 #include <ct_lvtqtc_graphicsview.h> 0028 #include <ct_lvtqtc_packagedependency.h> 0029 #include <ct_lvtqtc_packageentity.h> 0030 0031 #include <ct_lvtshr_loaderinfo.h> 0032 0033 #include <ct_lvtldr_nodestoragetestutils.h> 0034 #include <ct_lvttst_fixture_qt.h> 0035 #include <ct_lvttst_tmpdir.h> 0036 0037 #include <preferences.h> 0038 0039 #include <memory> 0040 0041 #include <QDebug> 0042 0043 using namespace Codethink::lvtshr; 0044 using namespace Codethink::lvtqtc; 0045 using namespace Codethink::lvtldr; 0046 0047 using Codethink::lvtqtc::LakosEntity; 0048 using PackageDependencyType = Codethink::lvtqtc::PackageDependency; 0049 0050 TEST_CASE_METHOD(QTApplicationFixture, "Lakos entity cover string") 0051 { 0052 // There was a bug where the cover string isn't being updated after the name of the entity is being changed. 0053 // This test has been added to ensure no regression will happen. 0054 auto tmpDir = TmpDir{"lakos_entity_cover"}; 0055 auto dbPath = tmpDir.path() / "codedb.db"; 0056 auto nodeStorage = NodeStorageTestUtils::createEmptyNodeStorage(dbPath); 0057 0058 auto *package = nodeStorage.addPackage("Pkg", "Pkg", nullptr).value(); 0059 auto *component = nodeStorage.addComponent("Comp", "Comp", package).value(); 0060 auto *classEntity = 0061 nodeStorage.addLogicalEntity("SomeClass", "SomeClass", component, Codethink::lvtshr::UDTKind::Class).value(); 0062 0063 REQUIRE(package->name() == "Pkg"); 0064 package->setName("B"); 0065 REQUIRE(package->name() == "B"); 0066 0067 REQUIRE(component->name() == "Comp"); 0068 component->setName("CompB"); 0069 REQUIRE(component->name() == "CompB"); 0070 0071 REQUIRE(classEntity->name() == "SomeClass"); 0072 classEntity->setName("AnotherClass"); 0073 REQUIRE(classEntity->name() == "AnotherClass"); 0074 } 0075 0076 TEST_CASE_METHOD(QTApplicationFixture, "LakosEntity tests") 0077 { 0078 auto tmpDir = TmpDir{"lakosentity_tests"}; 0079 auto dbPath = tmpDir.path() / "codedb.db"; 0080 auto nodeStorage = NodeStorageTestUtils::createEmptyNodeStorage(dbPath); 0081 0082 auto *pkgGroupA = nodeStorage.addPackage("A", "A", nullptr).value(); 0083 auto *pkgChildA = nodeStorage.addPackage("PkgChildA", "A/PkgChildA", pkgGroupA).value(); 0084 0085 auto info = LoaderInfo{false, true, true}; 0086 LakosEntity *entityA = new PackageEntity(pkgGroupA, info); 0087 LakosEntity *childA = new PackageEntity(pkgChildA, info); 0088 childA->setParentItem(entityA); 0089 0090 auto *textItem = [entityA]() -> Codethink::lvtqtc::EllipsisTextItem * { 0091 for (auto *child : entityA->childItems()) { 0092 auto *castedChildren = dynamic_cast<Codethink::lvtqtc::EllipsisTextItem *>(child); 0093 if (castedChildren) { 0094 return castedChildren; 0095 } 0096 } 0097 return nullptr; 0098 }(); 0099 0100 REQUIRE(textItem); 0101 0102 entityA->expand(QtcUtil::CreateUndoAction::e_No); 0103 REQUIRE(entityA->isExpanded()); 0104 0105 Preferences::setLakosEntityNamePos(Qt::TopLeftCorner); 0106 REQUIRE(qFuzzyCompare(textItem->pos().x(), entityA->boundingRect().left())); 0107 REQUIRE(textItem->pos().y() < entityA->boundingRect().top()); 0108 0109 Preferences::setLakosEntityNamePos(Qt::TopRightCorner); 0110 REQUIRE(qFuzzyCompare(textItem->pos().x() + textItem->boundingRect().width(), entityA->boundingRect().right())); 0111 REQUIRE(textItem->pos().y() < entityA->boundingRect().top()); 0112 0113 Preferences::setLakosEntityNamePos(Qt::BottomRightCorner); 0114 REQUIRE(qFuzzyCompare(textItem->pos().x() + textItem->boundingRect().width(), entityA->boundingRect().right())); 0115 REQUIRE(qFuzzyCompare(textItem->pos().y(), entityA->boundingRect().bottom())); 0116 0117 Preferences::setLakosEntityNamePos(Qt::BottomLeftCorner); 0118 REQUIRE(qFuzzyCompare(textItem->pos().x(), entityA->boundingRect().left())); 0119 REQUIRE(qFuzzyCompare(textItem->pos().y(), entityA->boundingRect().bottom())); 0120 } 0121 0122 struct ChildrenLevelTestFixture : public QTApplicationFixture { 0123 ChildrenLevelTestFixture(): nodeStorage(NodeStorageTestUtils::createEmptyNodeStorage(tmpDir.path() / "codedb.db")) 0124 { 0125 auto *pkg = nodeStorage.addPackage("pkg", "pkg").value(); 0126 pkgEntity = std::make_unique<PackageEntity>(pkg, LoaderInfo{true, false, true}); 0127 } 0128 0129 void createEdge(LakosEntity *a, LakosEntity *b) 0130 { 0131 nodeStorage.addPhysicalDependency(a->internalNode(), b->internalNode()).expect("Unexpected error"); 0132 auto *relation = new PackageDependencyType(a, b); 0133 auto edgeCollection = std::make_shared<EdgeCollection>(); 0134 edgeCollection->setFrom(a); 0135 edgeCollection->setTo(b); 0136 edgeCollection->addRelation(relation); 0137 a->edgesCollection().push_back(edgeCollection); 0138 b->targetCollection().push_back(edgeCollection); 0139 } 0140 0141 LakosEntity *createNode(std::string const& name) 0142 { 0143 auto const info = LoaderInfo{true, true, true}; 0144 auto *aaa = nodeStorage.addComponent(name, name, pkgEntity->internalNode()).value(); 0145 auto *entity = new ComponentEntity(aaa, info); 0146 entity->setParentItem(pkgEntity.get()); 0147 return entity; 0148 } 0149 0150 TmpDir tmpDir = TmpDir{"ChildrenLevelTestFixtureTestDir"}; 0151 NodeStorage nodeStorage; 0152 std::unique_ptr<PackageEntity> pkgEntity; 0153 }; 0154 0155 TEST_CASE_METHOD(ChildrenLevelTestFixture, "Empty package") 0156 { 0157 auto levels = pkgEntity->childrenLevels(); 0158 REQUIRE(levels.empty()); 0159 } 0160 0161 TEST_CASE_METHOD(ChildrenLevelTestFixture, "Single level") 0162 { 0163 /** 0164 * aaa bbb ccc 0165 */ 0166 0167 auto *aaa = createNode("aaa"); 0168 auto *bbb = createNode("bbb"); 0169 auto *ccc = createNode("ccc"); 0170 0171 auto levels = pkgEntity->childrenLevels(); 0172 REQUIRE(levels.size() == 3); 0173 REQUIRE(levels[aaa] == 0); 0174 REQUIRE(levels[bbb] == 0); 0175 REQUIRE(levels[ccc] == 0); 0176 } 0177 0178 TEST_CASE_METHOD(ChildrenLevelTestFixture, "Basic children levels") 0179 { 0180 /** 0181 * aaa 0182 * v 0183 * bbb 0184 * v 0185 * ccc 0186 */ 0187 0188 auto *aaa = createNode("aaa"); 0189 auto *bbb = createNode("bbb"); 0190 auto *ccc = createNode("ccc"); 0191 createEdge(aaa, bbb); 0192 createEdge(bbb, ccc); 0193 0194 auto levels = pkgEntity->childrenLevels(); 0195 REQUIRE(levels.size() == 3); 0196 REQUIRE(levels[aaa] == 2); 0197 REQUIRE(levels[bbb] == 1); 0198 REQUIRE(levels[ccc] == 0); 0199 } 0200 0201 TEST_CASE_METHOD(ChildrenLevelTestFixture, "Children levels multilevel ddd") 0202 { 0203 /** 0204 * ccc eee 0205 * ^ ^ 0206 * | ddd 0207 * | ^ ^ 0208 * | / | 0209 * bbb / 0210 * ^ / 0211 * aaa 0212 */ 0213 0214 auto *aaa = createNode("aaa"); 0215 auto *bbb = createNode("bbb"); 0216 auto *ccc = createNode("ccc"); 0217 auto *ddd = createNode("ddd"); 0218 auto *eee = createNode("eee"); 0219 createEdge(aaa, bbb); 0220 createEdge(bbb, ccc); 0221 createEdge(bbb, ddd); 0222 createEdge(aaa, ddd); 0223 createEdge(ddd, eee); 0224 0225 auto levels = pkgEntity->childrenLevels(); 0226 REQUIRE(levels.size() == 5); 0227 REQUIRE(levels[aaa] == 3); 0228 REQUIRE(levels[bbb] == 2); 0229 REQUIRE(levels[ddd] == 1); 0230 REQUIRE(levels[ccc] == 0); 0231 REQUIRE(levels[eee] == 0); 0232 } 0233 0234 TEST_CASE_METHOD(ChildrenLevelTestFixture, "Children simple cycle") 0235 { 0236 /** 0237 * aaa <--> bbb 0238 */ 0239 0240 auto *aaa = createNode("aaa"); 0241 auto *bbb = createNode("bbb"); 0242 createEdge(aaa, bbb); 0243 createEdge(bbb, aaa); 0244 0245 auto levels = pkgEntity->childrenLevels(); 0246 REQUIRE(levels.size() == 2); 0247 REQUIRE(levels[aaa] == 0); 0248 REQUIRE(levels[bbb] == 0); 0249 } 0250 0251 TEST_CASE_METHOD(ChildrenLevelTestFixture, "Children level with cycle no clear startpoint") 0252 { 0253 /** 0254 * ccc eee // LVL 0 0255 * ^ ^ 0256 * | ddd ---- // LVL 1 0257 * | ^ ^ \ 0258 * | / | | 0259 * bbb / / // LVL 2 0260 * ^ / / 0261 * aaa <-- // LVL 3 0262 */ 0263 auto *aaa = createNode("aaa"); 0264 auto *bbb = createNode("bbb"); 0265 auto *ccc = createNode("ccc"); 0266 auto *ddd = createNode("ddd"); 0267 auto *eee = createNode("eee"); 0268 createEdge(aaa, bbb); 0269 createEdge(bbb, ccc); 0270 createEdge(bbb, ddd); 0271 createEdge(aaa, ddd); 0272 createEdge(ddd, eee); 0273 createEdge(ddd, aaa); 0274 0275 auto levels = pkgEntity->childrenLevels(); 0276 REQUIRE(levels.size() == 5); 0277 REQUIRE(levels[aaa] == 3); 0278 REQUIRE(levels[bbb] == 2); 0279 REQUIRE(levels[ddd] == 1); 0280 REQUIRE(levels[ccc] == 0); 0281 REQUIRE(levels[eee] == 0); 0282 } 0283 0284 TEST_CASE_METHOD(ChildrenLevelTestFixture, "Children level with cycle clear level 0") 0285 { 0286 /** 0287 * ccc eee 0288 * ^ ^ 0289 * | ddd ---- 0290 * | ^ ^ \ 0291 * | / | | 0292 * bbb / / 0293 * ^ / / 0294 * aaa <-- 0295 * ^ 0296 * xxx 0297 */ 0298 auto *xxx = createNode("xxx"); 0299 auto *aaa = createNode("aaa"); 0300 auto *bbb = createNode("bbb"); 0301 auto *ccc = createNode("ccc"); 0302 auto *ddd = createNode("ddd"); 0303 auto *eee = createNode("eee"); 0304 createEdge(xxx, aaa); 0305 createEdge(aaa, bbb); 0306 createEdge(bbb, ccc); 0307 createEdge(bbb, ddd); 0308 createEdge(aaa, ddd); 0309 createEdge(ddd, eee); 0310 createEdge(ddd, aaa); 0311 0312 auto levels = pkgEntity->childrenLevels(); 0313 REQUIRE(levels.size() == 6); 0314 REQUIRE(levels[xxx] == 4); 0315 REQUIRE(levels[aaa] == 3); 0316 REQUIRE(levels[bbb] == 2); 0317 REQUIRE(levels[ddd] == 1); 0318 REQUIRE(levels[ccc] == 0); 0319 REQUIRE(levels[eee] == 0); 0320 }