@@ -103,6 +103,19 @@ - (void)controller:(MTRDeviceController *)controller
103
103
}
104
104
@end
105
105
106
+ @interface MTRPerControllerStorageTestsDeallocDelegate : NSObject <MTRDeviceControllerDelegate>
107
+ @property (nonatomic , nullable ) dispatch_block_t onDevicesChanged;
108
+ @end
109
+
110
+ @implementation MTRPerControllerStorageTestsDeallocDelegate
111
+ - (void )devicesChangedForController : (MTRDeviceController *)controller
112
+ {
113
+ if (self.onDevicesChanged ) {
114
+ self.onDevicesChanged ();
115
+ }
116
+ }
117
+ @end
118
+
106
119
@interface MTRPerControllerStorageTestsCertificateIssuer : NSObject <MTROperationalCertificateIssuer>
107
120
- (instancetype )initWithRootCertificate : (MTRCertificateDERBytes)rootCertificate
108
121
intermediateCertificate : (MTRCertificateDERBytes _Nullable)intermediateCertificate
@@ -3652,9 +3665,31 @@ - (void)testMTRDeviceDealloc
3652
3665
// We should have established CASE using our operational key.
3653
3666
XCTAssertEqual (operationalKeys.signatureCount , 1 );
3654
3667
3668
+ // Before the test, clear the device controller in-memory MapTable
3669
+ [controller forgetDeviceWithNodeID: deviceID];
3670
+
3655
3671
__block BOOL subscriptionReportEnd1 = NO ;
3656
3672
XCTestExpectation * subscriptionCallbackDeleted = [self expectationWithDescription: @" Subscription callback deleted" ];
3673
+ XCTestExpectation * controllerAddedDevice = [self expectationWithDescription: @" Controller added device" ];
3674
+ XCTestExpectation * controllerRemovedDevice = [self expectationWithDescription: @" Controller removed device" ];
3657
3675
@autoreleasepool {
3676
+ // Expected the test device was added and removed
3677
+ MTRPerControllerStorageTestsDeallocDelegate * controllerDelegate = [[MTRPerControllerStorageTestsDeallocDelegate alloc ] init ];
3678
+ __block NSUInteger lastDeviceCount = controller.devices .count ;
3679
+ controllerDelegate.onDevicesChanged = ^{
3680
+ // Use self as lock for lastDeviceCount access, so sanitizer doesn't complain
3681
+ @synchronized (self) {
3682
+ NSArray <MTRDevice *> * devices = controller.devices ;
3683
+ if (devices.count > lastDeviceCount) {
3684
+ [controllerAddedDevice fulfill ];
3685
+ } else if (devices.count < lastDeviceCount) {
3686
+ [controllerRemovedDevice fulfill ];
3687
+ }
3688
+ lastDeviceCount = devices.count ;
3689
+ }
3690
+ };
3691
+ [controller addDeviceControllerDelegate: controllerDelegate queue: queue];
3692
+
3658
3693
__auto_type * device = [MTRDevice deviceWithNodeID: deviceID controller: controller];
3659
3694
__auto_type * delegate = [[MTRDeviceTestDelegate alloc ] init ];
3660
3695
@@ -3675,13 +3710,16 @@ - (void)testMTRDeviceDealloc
3675
3710
[device setDelegate: delegate queue: queue];
3676
3711
3677
3712
[self waitForExpectations: @[ subscriptionReportBegin ] timeout: 60 ];
3713
+
3714
+ XCTAssertEqual (controller.devices .count , 1 );
3678
3715
}
3679
3716
3680
3717
// report should still be ongoing
3681
3718
XCTAssertFalse (subscriptionReportEnd1);
3719
+ XCTAssertEqual (controller.devices .count , 0 );
3682
3720
3683
3721
// dealloc -> delete should be called soon after the autoreleasepool reaps
3684
- [self waitForExpectations:@[ subscriptionCallbackDeleted ] timeout:60];
3722
+ [self waitForExpectations: @[ subscriptionCallbackDeleted, controllerAddedDevice, controllerRemovedDevice ] timeout: 60 ];
3685
3723
3686
3724
// Reset our commissionee.
3687
3725
__auto_type * baseDevice = [MTRBaseDevice deviceWithNodeID: deviceID controller: controller];
0 commit comments