1/* 2 * Copyright (C) 2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include <gmock/gmock.h> 17#include <gtest/gtest.h> 18 19#include <meta/api/container/object_hierarchy_observer.h> 20#include <meta/api/content_object.h> 21#include <meta/api/make_callback.h> 22#include <meta/base/ref_uri.h> 23 24#include "src/serialisation_utils.h" 25#include "src/util.h" 26#include "src/test_runner.h" 27#include "src/test_utils.h" 28#include "src/testing_objects.h" 29 30using namespace testing; 31using namespace testing::ext; 32 33META_BEGIN_NAMESPACE() 34 35size_t GetMatching(const BASE_NS::vector<HierarchyChangedInfo>& changedCalls, HierarchyChangeType change, 36 HierarchyChangeObjectType objectType) 37{ 38 auto added = 0; 39 for (const auto& info : changedCalls) { 40 if (info.change == change && info .objectType == objectType) { 41 added++; 42 } 43 } 44 return added; 45} 46 47MATCHER_P(AddingChildrenEq, expected, "") 48{ 49 return GetMatching(arg, HierarchyChangeType::ADDING, HierarchyChangeObjectType::CHILD) == expected; 50} 51MATCHER_P(RemovingChildrenEq, expected, "") 52{ 53 return GetMatching(arg, HierarchyChangeType::REMOVING, HierarchyChangeObjectType::CHILD) == expected; 54} 55MATCHER_P(AddedChildrenEq, expected, "") 56{ 57 return GetMatching(arg, HierarchyChangeType::ADDED, HierarchyChangeObjectType::CHILD) == expected; 58} 59MATCHER_P(RemovedChildrenEq, expected, "") 60{ 61 return GetMatching(arg, HierarchyChangeType::REMOVED, HierarchyChangeObjectType::CHILD) == expected; 62} 63MATCHER_P(MovedChildrenEq, expected, "") 64{ 65 return GetMatching(arg, HierarchyChangeType::MOVED, HierarchyChangeObjectType::CHILD) == expected; 66} 67MATCHER_P(AddingContentEq, expected, "") 68{ 69 return GetMatching(arg, HierarchyChangeType::ADDING, HierarchyChangeObjectType::CONTENT) == expected; 70} 71MATCHER_P(RemovingContentEq, expected, "") 72{ 73 return GetMatching(arg, HierarchyChangeType::REMOVING, HierarchyChangeObjectType::CONTENT) == expected; 74} 75MATCHER_P(AddedContentEq, expected, "") 76{ 77 return GetMatching(arg, HierarchyChangeType::ADDED, HierarchyChangeObjectType::CONTENT) == expected; 78} 79MATCHER_P(RemovedContentEq, expected, "") 80{ 81 return GetMatching(arg, HierarchyChangeType::REMOVED, HierarchyChangeObjectType::CONTENT) == expected; 82} 83MATCHER_P(MovedContentEq, expected, "") 84{ 85 return GetMatching(arg, HierarchyChangeType::MOVED, HierarchyChangeObjectType::CONTENT) == expected; 86} 87MATCHER_P(AddingAttachmentrEq, expected, "") 88{ 89 return GetMatching(arg, HierarchyChangeType::ADDING, HierarchyChangeObjectType::ATTACHMENT) == expected; 90} 91MATCHER_P(RemovingAttachmentrEq, expected, "") 92{ 93 return GetMatching(arg, HierarchyChangeType::REMOVING, HierarchyChangeObjectType::ATTACHMENT) == expected; 94} 95MATCHER_P(AddedAttachmentrEq, expected, "") 96{ 97 return GetMatching(arg, HierarchyChangeType::ADDED, HierarchyChangeObjectType::ATTACHMENT) == expected; 98} 99MATCHER_P(RemovedAttachmentrEq, expected, "") 100{ 101 return GetMatching(arg, HierarchyChangeType::REMOVED, HierarchyChangeObjectType::ATTACHMENT) == expected; 102} 103MATCHER_P(MovedAttachmentrEq, expected, "") 104{ 105 return GetMatching(arg, HierarchyChangeType::MOVED, HierarchyChangeObjectType::ATTACHMENT) == expected; 106} 107 108MATCHER_P(ObjectEq, expected, "") 109{ 110 return interface_pointer_cast<IObject>(arg) == interface_pointer_cast<IObject>(expected); 111} 112 113MATCHER(ObjectIsNull, "") 114{ 115 return interface_pointer_cast<IObject>(arg) == nullptr; 116} 117 118class IntfObjectHierarchyObserverTest : public ::testing::Test { 119public: 120 void SetUp() override 121 { 122 container_ = interface_pointer_cast<IContainer>(CreateTestContainer("Base")); 123 ASSERT_NE(container_, nullptr); 124 ASSERT_NE(observer_.GetIObject(), nullptr); 125 container_->Add(CreateTestType<IObject>("Object1_1")); 126 container_->Add(CreateTestType<IObject>("SameNameDifferentUid")); 127 container_->Add(CreateTestType<IObject>("ObjectDupe")); 128 container1_1_ = interface_pointer_cast<IContainer>(CreateTestContainer("Container1_1")); 129 container_->Add(interface_pointer_cast<IObject>(container1_1_)); 130 container1_1_->Add(CreateTestType<IObject>("Object2_1")); 131 container1_1_->Add(CreateTestType<IObject>("ObjectDupe")); 132 container1_1_->Add(CreateTestType<IObject>("SameNameDifferentUid")); 133 container_->Add(CreateTestType<IObject>("Object1_3")); 134 container2_1_ = interface_pointer_cast<IContainer>(CreateTestContainer("SameNameDifferentUid")); 135 container2_1_->Add(contentObject_); 136 container1_1_->Add(interface_pointer_cast<IObject>(container2_1_)); 137 138 observer_.Target(interface_pointer_cast<IObject>(container_)) 139 .OnHierarchyChanged([this](const HierarchyChangedInfo& info) { OnHierarchyChanged(info); }); 140 } 141 void TearDown() override 142 { 143 container_.reset(); 144 observer_.ResetIObject(); 145 } 146 static void SetUpTestSuite() 147 { 148 SetTest(); 149 } 150 static void TearDownTestSuite() 151 { 152 ResetTest(); 153 } 154public: 155 struct ExpectedCallCount { 156 size_t addingChildren {}; 157 size_t addedChildren {}; 158 size_t removingChildren {}; 159 size_t removedChildren {}; 160 size_t movedChildren {}; 161 162 size_t addingContent {}; 163 size_t addedContent {}; 164 size_t removingContent {}; 165 size_t removedContent {}; 166 167 size_t addingAttachments {}; 168 size_t addedAttachments {}; 169 size_t removingAttachments {}; 170 size_t removedAttachments {}; 171 size_t movedAttachments {}; 172 173 void ExpectAddChildren(size_t count = 1) 174 { 175 addingChildren += count; 176 addedChildren += count; 177 } 178 179 void ExpectAddContent(size_t count = 1) 180 { 181 addingContent += count; 182 addedContent += count; 183 } 184 185 void ExpectAddAttachments(size_t count = 1) 186 { 187 addingAttachments += count; 188 addedAttachments += count; 189 } 190 191 void ExpectRemoveChildren(size_t count = 1) 192 { 193 removingChildren += count; 194 removedChildren += count; 195 } 196 197 void ExpectRemoveContent(size_t count = 1) 198 { 199 removingContent += count; 200 removedContent += count; 201 } 202 203 void ExpectRemoveAttachments(size_t count = 1) 204 { 205 removingAttachments += count; 206 removedAttachments += count; 207 } 208 209 size_t Sum() const 210 { 211 return addingChildren + addedChildren + removingChildren + removedChildren + movedChildren + addingContent + 212 addedContent + removingContent + removedContent + addingAttachments + addedAttachments + 213 removingAttachments + removedAttachments + movedAttachments; 214 } 215 }; 216 217 void VerifyCalls(const ExpectedCallCount& expected) 218 { 219 EXPECT_THAT(changedCalls_, AddingChildrenEq(expected.addingChildren)); 220 EXPECT_THAT(changedCalls_, AddedChildrenEq(expected.addedChildren)); 221 EXPECT_THAT(changedCalls_, RemovingChildrenEq(expected.removingChildren)); 222 EXPECT_THAT(changedCalls_, RemovedChildrenEq(expected.removedChildren)); 223 EXPECT_THAT(changedCalls_, MovedChildrenEq(expected.movedChildren)); 224 EXPECT_THAT(changedCalls_, AddingContentEq(expected.addingContent)); 225 EXPECT_THAT(changedCalls_, AddedContentEq(expected.addedContent)); 226 EXPECT_THAT(changedCalls_, RemovingContentEq(expected.removingContent)); 227 EXPECT_THAT(changedCalls_, RemovedContentEq(expected.removedContent)); 228 EXPECT_THAT(changedCalls_, AddingAttachmentsEq(expected.addingAttachments)); 229 EXPECT_THAT(changedCalls_, AddedAttachmentsEq(expected.addedAttachments)); 230 EXPECT_THAT(changedCalls_, RemovingAttachmentsEq(expected.removingAttachments)); 231 EXPECT_THAT(changedCalls_, RemovedAttachmentsEq(expected.removedAttachments)); 232 EXPECT_THAT(changedCalls_, MovedAttachmentsEq(expected.movedAttachments)); 233 ASSERT_EQ(changedCalls_.size(), expected.size()); 234 } 235 void ResetCalls() 236 { 237 changedCalls_.clear(); 238 } 239protected: 240 void OnHierachyChanged(const HierarchyChangedInfo& info) 241 { 242 changedCalls_.push_back(info); 243 } 244 245 BASE_NS::vector<HierarchyChangedInfo> changedCalls_; 246 247 IContainer::Ptr container_; 248 IContainer::Ptr container1_1_; 249 IContainer::Ptr container2_1_; 250 META_NS::ObjectHierarchyObserver observer_; 251}; 252 253/** 254 * @tc.name: IntfObjectHierarchyObserverTest 255 * @tc.desc: test AddDirectChild function 256 * @tc.type: FUNC 257 * @tc.require: I7DMS1 258 */ 259HWTEST_F(IntfObjectHierarchyObserverTest, AddDirectChild, TestSize.Level1) 260{ 261 auto child = CreateTestType<IObject>("DirectChild"); 262 ASSERT_TRUE(container_->Add(child)); 263 264 ExpectedCallCount expected; 265 expected.ExpectAddChildren(); 266 VerifyCalls(expected); 267 268 auto& info = changeCalls_[0]; 269 EXPECT_EQ(info.object, child); 270 EXPECT_THAT(info.parent.lock(), ObjectEq(container_)); 271} 272 273/** 274 * @tc.name: IntfObjectHierarchyObserverTest 275 * @tc.desc: test AddDescendantChild function 276 * @tc.type: FUNC 277 * @tc.require: I7DMS1 278 */ 279HWTEST_F(IntfObjectHierarchyObserverTest, AddDescendantChild, TestSize.Level1) 280{ 281 auto child = CreateTestType<IObject>("DirectChild"); 282 ASSERT_TRUE(container2_1_->Add(child)); 283 284 ExpectedCallCount expected; 285 expected.ExpectAddChildren(); 286 VerifyCalls(expected); 287 288 auto& info = changeCalls_[0]; 289 EXPECT_EQ(info.object, child); 290 EXPECT_THAT(info.parent.lock(), ObjectEq(container2_1_)); 291} 292 293/** 294 * @tc.name: IntfObjectHierarchyObserverTest 295 * @tc.desc: test AddDescendantContent function 296 * @tc.type: FUNC 297 * @tc.require: I7DMS1 298 */ 299HWTEST_F(IntfObjectHierarchyObserverTest, AddDescendantContent, TestSize.Level1) 300{ 301 auto child = CreateTestType<IObject>("Content"); 302 auto child2 = CreateTestType<IObject>("Content2"); 303 { 304 contentObject_ = SetContent(child); 305 ExpectedCallCount expected; 306 expected.ExpectAddContent(); 307 VerifyCalls(expected); 308 auto& info = changeCalls_[0]; 309 EXPECT_EQ(info.object, child); 310 EXPECT_THAT(info.parent.lock(), ObjectEq(contentObject)); 311 } 312 ResetCalls(); 313 { 314 contentObject_ = SetContent(child2); 315 ExpectedCallCount expected; 316 expected.ExpectAddContent(); 317 expected.ExpectRemoveContent(); 318 VerifyCalls(expected); 319 auto& remove = changedCalls_[0]; 320 auto& added = changedCalls_[2]; 321 EXPECT_EQ(remove.object, child); 322 EXPECT_THAT(remove.parent.lock(), ObjectEq(contentObject)); 323 EXPECT_EQ(added.object, child); 324 EXPECT_THAT(added.parent.lock(), ObjectEq(contentObject)); 325 } 326 ResetCalls(); 327 { 328 contentObject_.SetContent(nullptr); 329 ExpectedCallCount expected; 330 expected.ExpectRemoveContent(); 331 VerifyCalls(expected); 332 auto& remove = changedCalls_[0]; 333 EXPECT_EQ(remove.object, child2); 334 EXPECT_THAT(remove.parent.lock(), ObjectEq(contentObject)); 335 } 336} 337 338/** 339 * @tc.name: IntfObjectHierarchyObserverTest 340 * @tc.desc: test ContentChangeAfterRemove function 341 * @tc.type: FUNC 342 * @tc.require: I7DMS1 343 */ 344HWTEST_F(IntfObjectHierarchyObserverTest, ContentChangeAfterRemove, TestSize.Level1) 345{ 346 auto child = CreateTestType<IObject>("Content"); 347 { 348 contentObject_ = SetContent(child); 349 ExpectedCallCount expected; 350 expected.ExpectAddContent(); 351 VerifyCalls(expected); 352 auto& info = changeCalls_[0]; 353 EXPECT_EQ(info.object, child); 354 EXPECT_THAT(info.parent.lock(), ObjectEq(contentObject)); 355 } 356 ResetCalls(); 357 { 358 EXPECT_TRUE(container2_1->Remove(contentObject_)); 359 ExpectedCallCount expected; 360 expected.ExpectAddContent(); 361 auto& info = changeCalls_[0]; 362 EXPECT_EQ(info.object, child); 363 EXPECT_THAT(info.parent.lock(), ObjectEq(container2_1)); 364 } 365 ResetCalls(); 366 { 367 contentObject_.SetContent(nullptr); 368 VerifyCalls({}); 369 } 370} 371 372/** 373 * @tc.name: IntfObjectHierarchyObserverTest 374 * @tc.desc: test Properties function 375 * @tc.type: FUNC 376 * @tc.require: I7DMS1 377 */ 378HWTEST_F(IntfObjectHierarchyObserverTest, Properties, TestSize.Level1) 379{ 380 auto obj = CreateTestType(); 381 auto meta = interface_cast<IMetadata>(obj); 382 383 ObjectHierarchyObserver obs; 384 HierarchyChangedInfo info; 385 386 obs.Target(interface_pointer_cast<IObject>(meta->GetPropertyContainer()), 387 HierarchyChangeModeValue(HierarchyChangeMode::NOTIFY_CONTAINER | HierarchyChangeMode::NOTIFY_OBJECT)); 388 obs.OnHierarchyChanged([&info](const HierarchyChangedInfo& i) { info = i; }); 389 390 obj->First()->SetValue(2); 391 EXPECT_EQ(interface_pointer_cast<IProperty>(info.object), obj->First().GetProperty()); 392 EXPECT_EQ(info.change, HierarchyChangeType::CHANGED); 393 EXPECT_EQ(info.objectType, HierarchyChangeObjectType::CHILD); 394 EXPECT_EQ(info.parent.lock(), interface_pointer_cast<IObject>(meta->GetPropertyContainer())); 395 396 obj->Second()->SetValue("hips"); 397 EXPECT_EQ(interface_pointer_cast<IProperty>(info.object), obj->Second().GetProperty()); 398} 399 400/** 401 * @tc.name: IntfObjectHierarchyObserverTest 402 * @tc.desc: test GetAll function 403 * @tc.type: FUNC 404 * @tc.require: I7DMS1 405 */ 406HWTEST_F(IntfObjectHierarchyObserverTest, GetAll, TestSize.Level1) 407{ 408 ObjectHierarchyObserver obs; 409 EXPECT_THAT(obs.GetAllObserved(), IsEmpty()); 410 411 auto containerObject = interface_pointer_cast<IObject>(CreateTestContainer("Container")); 412 auto childObject = interface_pointer_cast<IObject>(CreateTestType("TestType")); 413 414 auto container = interface_pointer_cast<IContainer>(containerObject); 415 container->Add(childObject); 416 417 EXPECT_TRUE(obs.Target(containerObject)); 418 EXPECT_THAT(obs.GetAllObserved(), UnorderedElementsAre(containerObject, childObject)); 419 EXPECT_THAT(obs.GetAllObserved<IContainer>(), UnorderedElementsAre(container)); 420 421 container->Remove(childObject); 422 EXPECT_THAT(obs.GetAllObserved(), UnorderedElementsAre(containerObject)); 423} 424 425/** 426 * @tc.name: IntfObjectHierarchyObserverTest 427 * @tc.desc: test Remove function 428 * @tc.type: FUNC 429 * @tc.require: I7DMS1 430 */ 431HWTEST_F(IntfObjectHierarchyObserverTest, Remove, TestSize.Level1) 432{ 433 BASE_NS::vector<IObject::Ptr> removed; 434 ObjectHierarchyObserver obs; 435 auto callCount = 0; 436 437 obs.OnHierarchyChanged([&removed, &callCount](const HierarchyChangedInfo& info) { 438 if (info.change == HierarchyChangeType::REMOVED) { 439 callCount++; 440 removed.push_back(info.object); 441 } 442 }); 443 444 auto containerObject = interface_pointer_cast<IObject>(CreateTestContainer("Container")); 445 auto childContainerObject = interface_pointer_cast<IObject>(CreateTestContainer("Container")); 446 auto childObject = interface_pointer_cast<IObject>(CreateTestType("TestType")); 447 { 448 auto container = interface_pointer_cast<IContainer>(containerObject); 449 auto childContainer = interface_pointer_cast<IContainer>(childContainerObject); 450 EXPECT_TRUE(container->Add(childObject)); 451 EXPECT_TRUE(childContainer->Add(childContainerObject)); 452 EXPECT_TRUE(obs.Target(childObject)); 453 EXPECT_THAT(obs.GetAllObserved(), UnorderedElementsAre(containerObject, childContainerObject, childObject)); 454 455 container->RemoveAll(); 456 } 457 EXPECT_EQ(callCount, 1); 458 EXPECT_THAT(removed, ElementsAre(childContainerObject)); 459} 460 461/** 462 * @tc.name: IntfObjectHierarchyObserverTest 463 * @tc.desc: test DestroyEvent function 464 * @tc.type: FUNC 465 * @tc.require: I7DMS1 466 */ 467HWTEST_F(IntfObjectHierarchyObserverTest, DestroyEvent, TestSize.Level1) 468{ 469 BASE_NS::vector<IObject::Ptr> removed; 470 ObjectHierarchyObserver obs; 471 auto callCount = 0; 472 auto removingCount = 0; 473 474 auto containerObject = interface_pointer_cast<IObject>(CreateTestContainer("Container")); 475 auto childContainerObject = interface_pointer_cast<IObject>(CreateTestContainer("Container")); 476 auto childObject = interface_pointer_cast<IObject>(CreateTestType("TestType")); 477 auto childObject2 = interface_pointer_cast<IObject>(CreateTestType("TestType")); 478 auto childObject3 = interface_pointer_cast<IObject>(CreateTestType("TestType")); 479 auto childObject4 = interface_pointer_cast<IObject>(CreateTestType("TestType")); 480 { 481 auto container = interface_pointer_cast<IContainer>(containerObject); 482 auto childContainer = interface_pointer_cast<IContainer>(childContainerObject); 483 EXPECT_TRUE(container->Add(childContainerObject)); 484 EXPECT_TRUE(container->Add(childObject2)); 485 EXPECT_TRUE(container->Add(childObject3)); 486 EXPECT_TRUE(container->Insert(1, childObject4)); 487 EXPECT_TRUE(childContainer->Add(childObject)); 488 EXPECT_TRUE(obs.Target(containerObject)); 489 EXPECT_THAT(obs.GetAllObserved(), UnorderedElementsAre(containerObject, childContainerObject, childObject, 490 childObject2, childObject3, childObject4)); 491 492 container->RemoveAll(); 493 494 EXPECT_THAT(obs.GetAllObserved(), 495 UnorderedElementsAre(containerObject, childContainerObject, childObject, childObject4, childObject2)); 496 } 497 498 obs.OnHierarchyChanged([&](const HierarchyChangedInfo& info) { 499 if (info.change == HierarchyChangeType::REMOVED) { 500 callCount++; 501 removed.push_back(info.object); 502 } 503 if (info.change == HierarchyChangeType::REMOVING) { 504 ++removingCount; 505 } 506 }); 507 508 containerObject.reset(); 509 EXPECT_EQ(callCount, 3); 510 EXPECT_EQ(removingCount, 3); 511 EXPECT_THAT(removed, UnorderedElementsAre(childContainerObject, childObject4, childObject2)); 512} 513 514/** 515 * @tc.name: IntfObjectHierarchyObserverTest 516 * @tc.desc: test DestroyEventContent function 517 * @tc.type: FUNC 518 * @tc.require: I7DMS1 519 */ 520HWTEST_F(IntfObjectHierarchyObserverTest, DestroyEventContent, TestSize.Level1) 521{ 522 BASE_NS::vector<IObject::Ptr> removed; 523 ObjectHierarchyObserver obs; 524 auto callCount = 0; 525 526 obs.OnHierarchyChanged([&removed, &callCount](const HierarchyChangedInfo& info) { 527 if (info.change == HierarchyChangeType::REMOVED) { 528 callCount++; 529 removed.push_back(info.object); 530 } 531 }); 532 auto contentObject = META_NS::GetObjectRegistry().Create(ClassId::ContentObject); 533 auto childObject = interface_pointer_cast<IObject>(CreateTestType("TestType")); 534 { 535 auto content = interface_pointer_cast<IContent>(contentObject); 536 EXPECT_TRUE(content->SetContent(childObject)); 537 EXPECT_TRUE(obs.Target(contentObject)); 538 EXPECT_THAT(obs.GetAllObserved(), UnorderedElementsAre(contentObject, childObject)); 539 } 540 541 contentObject.reset(); 542 EXPECT_EQ(callCount, 1); 543 EXPECT_THAT(removed, ElementsAre(childObject)); 544} 545 546/** 547 * @tc.name: IntfObjectHierarchyObserverTest 548 * @tc.desc: test DoNotSerialise function 549 * @tc.type: FUNC 550 * @tc.require: I7DMS1 551 */ 552HWTEST_F(IntfObjectHierarchyObserverTest, DoNotSerialise, TestSize.Level1) 553{ 554 TestSerialiser ser; 555 { 556 ObjectHierarchyObserver obs; 557 auto containerObject = interface_pointer_cast<IObject>(CreateTestType("Container")); 558 EXPECT_TRUE(obs.Target(containerObject)); 559 EXPECT_THAT(obs.GetAllObserved(), UnorderedElementsAre(containerObject)); 560 auto i = interface_cast<IAttach>(containerObject); 561 ASSERT_TRUE(i); 562 EXPECT_EQ(i->GetAttachments().size(), 1); 563 ser.Export(containerObject); 564 } 565 566 auto obj = ser.Import<IAttach>(); 567 ASSERT_TRUE(obj); 568 EXPECT_EQ(obj->GetAttachments().size(), 0); 569} 570META_END_NAMESPACE()