Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add better APIs for handling FeatureMap in MTRServerAttribute. #33760

Merged
merged 2 commits into from
Jun 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion src/darwin/Framework/CHIP/ServerEndpoint/MTRServerAttribute.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ MTR_AVAILABLE(ios(17.6), macos(14.6), watchos(10.6), tvos(17.6))
* Will fail if the attribute ID is not valid per the Matter specification or
* the attribute value is not a valid data-value.
*
* requiredPrivilege is the privilege required to read the attribute.
* requiredPrivilege is the privilege required to read the attribute. This
* initializer may fail if the provided attributeID is a global attribute and
* the provided requiredPrivilege value is not correct for that attribute ID.
*/
- (nullable instancetype)initReadonlyAttributeWithID:(NSNumber *)attributeID initialValue:(NSDictionary<NSString *, id> *)value requiredPrivilege:(MTRAccessControlEntryPrivilege)requiredPrivilege;

Expand All @@ -53,6 +55,14 @@ MTR_AVAILABLE(ios(17.6), macos(14.6), watchos(10.6), tvos(17.6))
*/
- (BOOL)setValue:(NSDictionary<NSString *, id> *)value;

/**
* Create an attribute description for a FeatureMap attribute with the provided
* value (expected to be an unsigned integer representing the value of the
* bitmap). This will automatically set requiredPrivilege to the right value
* for FeatureMap.
*/
+ (MTRServerAttribute *)newFeatureMapAttributeWithInitialValue:(NSNumber *)value;

@property (atomic, copy, readonly) NSNumber * attributeID;
@property (atomic, copy, readonly) NSDictionary<NSString *, id> * value;
/**
Expand Down
28 changes: 27 additions & 1 deletion src/darwin/Framework/CHIP/ServerEndpoint/MTRServerAttribute.mm
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#import "MTRUnfairLock.h"
#import "NSDataSpanConversion.h"

#import <Matter/MTRClusterConstants.h>
#import <Matter/MTRServerAttribute.h>

#include <app/reporting/reporting.h>
Expand Down Expand Up @@ -57,6 +58,20 @@ - (nullable instancetype)initAttributeWithID:(NSNumber *)attributeID initialValu
return nil;
}

if (attrId == MTRAttributeIDTypeGlobalAttributeFeatureMapID) {
// Some sanity checks: value should be an unsigned-integer NSNumber, and
// requiredReadPrivilege should be View.
if (requiredReadPrivilege != MTRAccessControlEntryPrivilegeView) {
MTR_LOG_ERROR("MTRServerAttribute for FeatureMap provided with invalid read privilege %d", requiredReadPrivilege);
return nil;
}

if (![MTRUnsignedIntegerValueType isEqual:value[MTRTypeKey]]) {
MTR_LOG_ERROR("MTRServerAttribute for FeatureMap provided with value that is not an unsigned integer: %@", value);
return nil;
}
}

return [self initWithAttributeID:[attributeID copy] value:[value copy] requiredReadPrivilege:requiredReadPrivilege writable:writable];
}

Expand All @@ -80,7 +95,8 @@ - (nullable instancetype)initWithAttributeID:(NSNumber *)attributeID value:(NSDi
_writable = writable;
_parentCluster = app::ConcreteClusterPath(kInvalidEndpointId, kInvalidClusterId);

// Now call setValue to store the value and its serialization.
// Now store the value and its serialization. This will also check that the
// value is serializable to TLV.
if ([self setValueInternal:value logIfNotAssociated:NO] == NO) {
return nil;
}
Expand All @@ -93,6 +109,16 @@ - (BOOL)setValue:(NSDictionary<NSString *, id> *)value
return [self setValueInternal:value logIfNotAssociated:YES];
}

+ (MTRServerAttribute *)newFeatureMapAttributeWithInitialValue:(NSNumber *)value
{
return [[MTRServerAttribute alloc] initReadonlyAttributeWithID:@(MTRAttributeIDTypeGlobalAttributeFeatureMapID)
initialValue:@{
MTRTypeKey : MTRUnsignedIntegerValueType,
MTRValueKey : value,
}
requiredPrivilege:MTRAccessControlEntryPrivilegeView];
}

- (BOOL)setValueInternal:(NSDictionary<NSString *, id> *)value logIfNotAssociated:(BOOL)logIfNotAssociated
{
id serializedValue;
Expand Down
35 changes: 35 additions & 0 deletions src/darwin/Framework/CHIPTests/MTRServerEndpointTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,11 @@ - (void)testServerAttribute
MTRValueKey : @(5),
};

__auto_type * signedIntValue = @{
MTRTypeKey : MTRSignedIntegerValueType,
MTRValueKey : @(5),
};

__auto_type * listOfStringsValue = @{
MTRTypeKey : MTRArrayValueType,
MTRValueKey : @[
Expand Down Expand Up @@ -192,6 +197,36 @@ - (void)testServerAttribute
__auto_type * attr = [[MTRServerAttribute alloc] initReadonlyAttributeWithID:invalidID initialValue:unsignedIntValue requiredPrivilege:MTRAccessControlEntryPrivilegeView];
XCTAssertNil(attr);
}

// Valid FeatureMap attribute
{
__auto_type * attr = [[MTRServerAttribute alloc] initReadonlyAttributeWithID:@(MTRAttributeIDTypeGlobalAttributeFeatureMapID) initialValue:unsignedIntValue requiredPrivilege:MTRAccessControlEntryPrivilegeView];
XCTAssertNotNil(attr);
XCTAssertEqualObjects(attr.attributeID, @(MTRAttributeIDTypeGlobalAttributeFeatureMapID));
XCTAssertEqualObjects(attr.value, unsignedIntValue);
XCTAssertEqual(attr.writable, NO);
}

// FeatureMap attribute with wrong value type
{
__auto_type * attr = [[MTRServerAttribute alloc] initReadonlyAttributeWithID:@(MTRAttributeIDTypeGlobalAttributeFeatureMapID) initialValue:signedIntValue requiredPrivilege:MTRAccessControlEntryPrivilegeView];
XCTAssertNil(attr);
}

// FeatureMap attribute with wrong permissions
{
__auto_type * attr = [[MTRServerAttribute alloc] initReadonlyAttributeWithID:@(MTRAttributeIDTypeGlobalAttributeFeatureMapID) initialValue:unsignedIntValue requiredPrivilege:MTRAccessControlEntryPrivilegeOperate];
XCTAssertNil(attr);
}

// FeatureMap attribute via factory
{
__auto_type * attr = [MTRServerAttribute newFeatureMapAttributeWithInitialValue:@(5)];
XCTAssertNotNil(attr);
XCTAssertEqualObjects(attr.attributeID, @(MTRAttributeIDTypeGlobalAttributeFeatureMapID));
XCTAssertEqualObjects(attr.value, unsignedIntValue);
XCTAssertEqual(attr.writable, NO);
}
}

- (void)testDeviceType
Expand Down
Loading