Skip to content

Commit

Permalink
Add MTRErrorDomain mappings for a few more CHIP_ERROR values. (projec…
Browse files Browse the repository at this point in the history
…t-chip#36835)

Also adds some basic round-tripping tests to catch mistakes.
  • Loading branch information
bzbarsky-apple authored Dec 13, 2024
1 parent c9a5d13 commit 2b8f5d7
Show file tree
Hide file tree
Showing 6 changed files with 191 additions and 36 deletions.
79 changes: 46 additions & 33 deletions src/darwin/Framework/CHIP/MTRError.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ MTR_EXTERN NSErrorDomain const MTRInteractionErrorDomain MTR_AVAILABLE(ios(16.1)
* Errors reported by the server side of a Matter interaction via the normal
* Matter error-reporting mechanisms use MTRInteractionErrorDomain instead.
*/
// clang-format off
typedef NS_ERROR_ENUM(MTRErrorDomain, MTRErrorCode){
/**
* MTRErrorCodeGeneralError represents a generic Matter error with no
Expand All @@ -61,7 +60,7 @@ typedef NS_ERROR_ENUM(MTRErrorDomain, MTRErrorCode){
* MTRErrorCodeFabricExists is returned when trying to commission a device
* into a fabric when it's already part of that fabric.
*/
MTRErrorCodeFabricExists = 11,
MTRErrorCodeFabricExists = 11,

/**
* MTRErrorCodeUnknownSchema means the schema for the given cluster/attribute,
Expand Down Expand Up @@ -95,9 +94,25 @@ typedef NS_ERROR_ENUM(MTRErrorDomain, MTRErrorCode){
/**
* The operation was cancelled.
*/
MTRErrorCodeCancelled MTR_AVAILABLE(ios(17.6), macos(14.6), watchos(10.6), tvos(17.6))= 16,
MTRErrorCodeCancelled MTR_AVAILABLE(ios(17.6), macos(14.6), watchos(10.6), tvos(17.6)) = 16,

/**
* Access to some resource was denied.
*/
MTRErrorCodeAccessDenied MTR_AVAILABLE(ios(18.4), macos(15.4), watchos(11.4), tvos(18.4)) = 17,

/**
* A request was made to some entity, and that entity cannot handle the
* request right now, but might be able to at a different point in time.
*/
MTRErrorCodeBusy MTR_AVAILABLE(ios(18.4), macos(15.4), watchos(11.4), tvos(18.4)) = 18,

/**
* Something was requested that could not be located.
*/
MTRErrorCodeNotFound MTR_AVAILABLE(ios(18.4), macos(15.4), watchos(11.4), tvos(18.4)) = 19,
};
// clang-format on
#define MTRMaxErrorCode MTRErrorCodeNotFound

/**
* MTRInteractionErrorDomain contains errors that represent a Matter
Expand All @@ -109,38 +124,36 @@ typedef NS_ERROR_ENUM(MTRErrorDomain, MTRErrorCode){
* was reported. This key will be absent if there was no cluster-specific
* status.
*/
// clang-format off
typedef NS_ERROR_ENUM(MTRInteractionErrorDomain, MTRInteractionErrorCode){
// These values come from the general status code table in the Matter
// Interaction Model specification.
MTRInteractionErrorCodeFailure = 0x01,
MTRInteractionErrorCodeInvalidSubscription = 0x7d,
MTRInteractionErrorCodeUnsupportedAccess = 0x7e,
MTRInteractionErrorCodeUnsupportedEndpoint = 0x7f,
MTRInteractionErrorCodeInvalidAction = 0x80,
MTRInteractionErrorCodeUnsupportedCommand = 0x81,
MTRInteractionErrorCodeInvalidCommand = 0x85,
MTRInteractionErrorCodeUnsupportedAttribute = 0x86,
MTRInteractionErrorCodeConstraintError = 0x87,
MTRInteractionErrorCodeUnsupportedWrite = 0x88,
MTRInteractionErrorCodeResourceExhausted = 0x89,
MTRInteractionErrorCodeNotFound = 0x8b,
MTRInteractionErrorCodeUnreportableAttribute = 0x8c,
MTRInteractionErrorCodeInvalidDataType = 0x8d,
MTRInteractionErrorCodeUnsupportedRead = 0x8f,
MTRInteractionErrorCodeDataVersionMismatch = 0x92,
MTRInteractionErrorCodeTimeout = 0x94,
MTRInteractionErrorCodeBusy = 0x9c,
MTRInteractionErrorCodeUnsupportedCluster = 0xc3,
MTRInteractionErrorCodeNoUpstreamSubscription = 0xc5,
MTRInteractionErrorCodeNeedsTimedInteraction = 0xc6,
MTRInteractionErrorCodeUnsupportedEvent = 0xc7,
MTRInteractionErrorCodePathsExhausted = 0xc8,
MTRInteractionErrorCodeTimedRequestMismatch = 0xc9,
MTRInteractionErrorCodeFailsafeRequired = 0xca,
MTRInteractionErrorCodeInvalidInState MTR_AVAILABLE(ios(17.6), macos(14.6), watchos(10.6), tvos(17.6))= 0xcb,
MTRInteractionErrorCodeNoCommandResponse MTR_AVAILABLE(ios(17.6), macos(14.6), watchos(10.6), tvos(17.6))= 0xcc,
MTRInteractionErrorCodeFailure = 0x01,
MTRInteractionErrorCodeInvalidSubscription = 0x7d,
MTRInteractionErrorCodeUnsupportedAccess = 0x7e,
MTRInteractionErrorCodeUnsupportedEndpoint = 0x7f,
MTRInteractionErrorCodeInvalidAction = 0x80,
MTRInteractionErrorCodeUnsupportedCommand = 0x81,
MTRInteractionErrorCodeInvalidCommand = 0x85,
MTRInteractionErrorCodeUnsupportedAttribute = 0x86,
MTRInteractionErrorCodeConstraintError = 0x87,
MTRInteractionErrorCodeUnsupportedWrite = 0x88,
MTRInteractionErrorCodeResourceExhausted = 0x89,
MTRInteractionErrorCodeNotFound = 0x8b,
MTRInteractionErrorCodeUnreportableAttribute = 0x8c,
MTRInteractionErrorCodeInvalidDataType = 0x8d,
MTRInteractionErrorCodeUnsupportedRead = 0x8f,
MTRInteractionErrorCodeDataVersionMismatch = 0x92,
MTRInteractionErrorCodeTimeout = 0x94,
MTRInteractionErrorCodeBusy = 0x9c,
MTRInteractionErrorCodeUnsupportedCluster = 0xc3,
MTRInteractionErrorCodeNoUpstreamSubscription = 0xc5,
MTRInteractionErrorCodeNeedsTimedInteraction = 0xc6,
MTRInteractionErrorCodeUnsupportedEvent = 0xc7,
MTRInteractionErrorCodePathsExhausted = 0xc8,
MTRInteractionErrorCodeTimedRequestMismatch = 0xc9,
MTRInteractionErrorCodeFailsafeRequired = 0xca,
MTRInteractionErrorCodeInvalidInState MTR_AVAILABLE(ios(17.6), macos(14.6), watchos(10.6), tvos(17.6)) = 0xcb,
MTRInteractionErrorCodeNoCommandResponse MTR_AVAILABLE(ios(17.6), macos(14.6), watchos(10.6), tvos(17.6)) = 0xcc,
};
// clang-format on

NS_ASSUME_NONNULL_END
38 changes: 38 additions & 0 deletions src/darwin/Framework/CHIP/MTRError.mm
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ + (NSError *)errorForCHIPErrorCode:(CHIP_ERROR)errorCode logContext:(id)contextT
code = MTRErrorCodeFabricExists;
description = NSLocalizedString(@"The device is already a member of this fabric.", nil);
break;
case CHIP_ERROR_SCHEMA_MISMATCH.AsInteger():
code = MTRErrorCodeSchemaMismatch;
description = NSLocalizedString(@"Data does not match expected schema.", nil);
break;
case CHIP_ERROR_DECODE_FAILED.AsInteger():
code = MTRErrorCodeTLVDecodeFailed;
description = NSLocalizedString(@"TLV decoding failed.", nil);
Expand All @@ -122,6 +126,18 @@ + (NSError *)errorForCHIPErrorCode:(CHIP_ERROR)errorCode logContext:(id)contextT
code = MTRErrorCodeCancelled;
description = NSLocalizedString(@"The operation was cancelled.", nil);
break;
case CHIP_ERROR_ACCESS_DENIED.AsInteger():
code = MTRErrorCodeAccessDenied;
description = NSLocalizedString(@"Access denied.", nil);
break;
case CHIP_ERROR_BUSY.AsInteger():
code = MTRErrorCodeBusy;
description = NSLocalizedString(@"Operation cannot be completed at this time: resource busy.", nil);
break;
case CHIP_ERROR_NOT_FOUND.AsInteger():
code = MTRErrorCodeNotFound;
description = NSLocalizedString(@"Requested resource was not found.", nil);
break;
default:
code = MTRErrorCodeGeneralError;
description = [NSString stringWithFormat:NSLocalizedString(@"General error: %u", nil), errorCode.AsInteger()];
Expand All @@ -141,6 +157,11 @@ + (NSError *)errorForCHIPErrorCode:(CHIP_ERROR)errorCode logContext:(id)contextT
return error;
}

+ (NSError *)errorForCHIPIntegerCode:(uint32_t)errorCode
{
return [MTRError errorForCHIPErrorCode:chip::ChipError(errorCode)];
}

+ (NSError *)errorForIMStatus:(const chip::app::StatusIB &)status
{
if (status.IsSuccess()) {
Expand Down Expand Up @@ -303,6 +324,9 @@ + (CHIP_ERROR)errorToCHIPErrorCode:(NSError * _Nullable)error
case MTRErrorCodeFabricExists:
code = CHIP_ERROR_FABRIC_EXISTS.AsInteger();
break;
case MTRErrorCodeSchemaMismatch:
code = CHIP_ERROR_SCHEMA_MISMATCH.AsInteger();
break;
case MTRErrorCodeTLVDecodeFailed:
code = CHIP_ERROR_DECODE_FAILED.AsInteger();
break;
Expand All @@ -312,6 +336,15 @@ + (CHIP_ERROR)errorToCHIPErrorCode:(NSError * _Nullable)error
case MTRErrorCodeCancelled:
code = CHIP_ERROR_CANCELLED.AsInteger();
break;
case MTRErrorCodeAccessDenied:
code = CHIP_ERROR_ACCESS_DENIED.AsInteger();
break;
case MTRErrorCodeBusy:
code = CHIP_ERROR_BUSY.AsInteger();
break;
case MTRErrorCodeNotFound:
code = CHIP_ERROR_NOT_FOUND.AsInteger();
break;
case MTRErrorCodeGeneralError: {
id userInfoErrorCode = error.userInfo[@"errorCode"];
if ([userInfoErrorCode isKindOfClass:NSNumber.class]) {
Expand All @@ -328,6 +361,11 @@ + (CHIP_ERROR)errorToCHIPErrorCode:(NSError * _Nullable)error
return chip::ChipError(code);
}

+ (uint32_t)errorToCHIPIntegerCode:(NSError * _Nullable)error
{
return [self errorToCHIPErrorCode:error].AsInteger();
}

@end

@implementation MTRErrorHolder
Expand Down
5 changes: 2 additions & 3 deletions src/darwin/Framework/CHIP/MTRError_Internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@
*/

#import <Foundation/Foundation.h>
#import <Matter/MTRError.h>

#import "MTRDefines_Internal.h"
#import "MTRError_Testable.h"

#include <app/MessageDef/StatusIB.h>
#include <lib/core/CHIPError.h>
Expand All @@ -27,8 +27,7 @@
NS_ASSUME_NONNULL_BEGIN

MTR_DIRECT_MEMBERS
@interface MTRError : NSObject
+ (NSError *)errorWithCode:(MTRErrorCode)code;
@interface MTRError ()
+ (NSError * _Nullable)errorForCHIPErrorCode:(CHIP_ERROR)errorCode;
+ (NSError * _Nullable)errorForCHIPErrorCode:(CHIP_ERROR)errorCode logContext:(id _Nullable)contextToLog;
+ (NSError * _Nullable)errorForIMStatus:(const chip::app::StatusIB &)status;
Expand Down
37 changes: 37 additions & 0 deletions src/darwin/Framework/CHIP/MTRError_Testable.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* Copyright (c) 2024 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#import <Foundation/Foundation.h>
#import <Matter/MTRError.h>

#import "MTRDefines_Internal.h"

NS_ASSUME_NONNULL_BEGIN

MTR_TESTABLE
@interface MTRError : NSObject

+ (NSError *)errorWithCode:(MTRErrorCode)code;

// For tests only, since we can't use CHIP_ERROR from there. The "code"s used
// here are integer representations of CHIP_ERROR. Otherwise these functions
// are just like errorForCHIPErrorCode and errorToCHIPErrorCode.
+ (NSError *)errorForCHIPIntegerCode:(uint32_t)code;
+ (uint32_t)errorToCHIPIntegerCode:(NSError * _Nullable)error;

@end

NS_ASSUME_NONNULL_END
60 changes: 60 additions & 0 deletions src/darwin/Framework/CHIPTests/MTRErrorMappingTests.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/**
* Copyright (c) 2024 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#import <Matter/Matter.h>
#import <XCTest/XCTest.h>

// NOTE: This is a .mm file, so that it can include MTRError_Internal.h

#import "MTRError_Testable.h"

@interface MTRErrorMappingTests : XCTestCase
@end

@implementation MTRErrorMappingTests

- (void)testPublicNonInteractionAPIValues
{
for (int errorCode = 1; errorCode <= MTRMaxErrorCode; errorCode++) {
// A few error codes are not actually representing CHIP_ERROR values.
if (errorCode == MTRErrorCodeWrongAddressType || errorCode == MTRErrorCodeUnknownSchema) {
continue;
}

// All of these should round-trip appropriately.
__auto_type * error = [NSError errorWithDomain:MTRErrorDomain code:errorCode userInfo:nil];
__auto_type * newError1 = [MTRError errorWithCode:(MTRErrorCode) errorCode];
XCTAssertEqual(newError1.domain, error.domain, "Testing error code %d", errorCode);
XCTAssertEqual(newError1.code, error.code, "Testing error code %d", errorCode);

__auto_type chipError = [MTRError errorToCHIPIntegerCode:error];
__auto_type * newError2 = [MTRError errorForCHIPIntegerCode:chipError];
XCTAssertEqual(newError2.domain, error.domain, "Testing error code %d", errorCode);
XCTAssertEqual(newError2.code, error.code, "Testing error code %d", errorCode);
}

// Check that an unknown value becomes GeneralError.
__auto_type * error = [MTRError errorWithCode:(MTRErrorCode) (MTRMaxErrorCode + 1)];
XCTAssertEqual(error.domain, MTRErrorDomain);
XCTAssertEqual(error.code, MTRMaxErrorCode + 1);

__auto_type chipError = [MTRError errorToCHIPIntegerCode:error];
__auto_type * newError = [MTRError errorForCHIPIntegerCode:chipError];
XCTAssertEqual(newError.domain, MTRErrorDomain);
XCTAssertEqual(newError.code, MTRErrorCodeGeneralError);
}

@end
8 changes: 8 additions & 0 deletions src/darwin/Framework/Matter.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,8 @@
51565CB22A7AD77600469F18 /* MTRDeviceControllerDataStore.mm in Sources */ = {isa = PBXBuildFile; fileRef = 51565CB02A7AD77600469F18 /* MTRDeviceControllerDataStore.mm */; };
51565CB42A7AD78D00469F18 /* MTRDeviceControllerStorageDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 51565CB32A7AD78D00469F18 /* MTRDeviceControllerStorageDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; };
51565CB62A7B0D6600469F18 /* MTRDeviceControllerParameters.h in Headers */ = {isa = PBXBuildFile; fileRef = 51565CB52A7B0D6600469F18 /* MTRDeviceControllerParameters.h */; settings = {ATTRIBUTES = (Public, ); }; };
51578AE92D0B9B1D001716FF /* MTRErrorMappingTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 51578AE82D0B9B1D001716FF /* MTRErrorMappingTests.m */; };
51578AEB2D0B9DC0001716FF /* MTRError_Testable.h in Headers */ = {isa = PBXBuildFile; fileRef = 51578AEA2D0B9DC0001716FF /* MTRError_Testable.h */; };
515BE4ED2B72C0C5000BC1FD /* MTRUnfairLock.h in Headers */ = {isa = PBXBuildFile; fileRef = 515BE4EC2B72C0C5000BC1FD /* MTRUnfairLock.h */; };
515C1C6F284F9FFB00A48F0C /* MTRFramework.mm in Sources */ = {isa = PBXBuildFile; fileRef = 515C1C6D284F9FFB00A48F0C /* MTRFramework.mm */; };
515C1C70284F9FFB00A48F0C /* MTRFramework.h in Headers */ = {isa = PBXBuildFile; fileRef = 515C1C6E284F9FFB00A48F0C /* MTRFramework.h */; };
Expand Down Expand Up @@ -669,6 +671,8 @@
51565CB02A7AD77600469F18 /* MTRDeviceControllerDataStore.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MTRDeviceControllerDataStore.mm; sourceTree = "<group>"; };
51565CB32A7AD78D00469F18 /* MTRDeviceControllerStorageDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTRDeviceControllerStorageDelegate.h; sourceTree = "<group>"; };
51565CB52A7B0D6600469F18 /* MTRDeviceControllerParameters.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTRDeviceControllerParameters.h; sourceTree = "<group>"; };
51578AE82D0B9B1D001716FF /* MTRErrorMappingTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MTRErrorMappingTests.m; sourceTree = "<group>"; };
51578AEA2D0B9DC0001716FF /* MTRError_Testable.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTRError_Testable.h; sourceTree = "<group>"; };
515BE4EC2B72C0C5000BC1FD /* MTRUnfairLock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTRUnfairLock.h; sourceTree = "<group>"; };
515C1C6D284F9FFB00A48F0C /* MTRFramework.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MTRFramework.mm; sourceTree = "<group>"; };
515C1C6E284F9FFB00A48F0C /* MTRFramework.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTRFramework.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1540,6 +1544,7 @@
5109E9B32CB8B5DF0006884B /* MTRDeviceType.mm */,
5129BCFC26A9EE3300122DDF /* MTRError.h */,
B2E0D7AB245B0B5C003C5B48 /* MTRError_Internal.h */,
51578AEA2D0B9DC0001716FF /* MTRError_Testable.h */,
B2E0D7AA245B0B5C003C5B48 /* MTRError.mm */,
754F3DF327FBB94B00E60580 /* MTREventTLVValueDecoder_Internal.h */,
515C1C6E284F9FFB00A48F0C /* MTRFramework.h */,
Expand Down Expand Up @@ -1618,6 +1623,7 @@
5109E9B62CB8B83D0006884B /* MTRDeviceTypeTests.m */,
51D9CB0A2BA37DCE0049D6DB /* MTRDSTOffsetTests.m */,
3D0C484A29DA4FA0006D811F /* MTRErrorTests.m */,
51578AE82D0B9B1D001716FF /* MTRErrorMappingTests.m */,
5173A47829C0E82300F67F48 /* MTRFabricInfoTests.m */,
8874C1312B69C7060084BEFD /* MTRMetricsTests.m */,
510CECA6297F72470064E0B3 /* MTROperationalCertificateIssuerTests.m */,
Expand Down Expand Up @@ -1941,6 +1947,7 @@
9B5CCB5D2C6EC890009DD99B /* MTRDevice_XPC.h in Headers */,
991DC08B247704DC00C13860 /* MTRLogging_Internal.h in Headers */,
51FE723F2ACDEF3E00437032 /* MTRCommandPayloadExtensions_Internal.h in Headers */,
51578AEB2D0B9DC0001716FF /* MTRError_Testable.h in Headers */,
51D0B12E2B6177FD006E3511 /* MTRAccessGrant.h in Headers */,
5109E9B52CB8B5DF0006884B /* MTRDeviceType.h in Headers */,
1E4D655029C208DD00BC3478 /* MTRCommissionableBrowserDelegate.h in Headers */,
Expand Down Expand Up @@ -2348,6 +2355,7 @@
518D3F852AA14006008E0007 /* MTRControllerAdvertisingTests.m in Sources */,
51C8E3F82825CDB600D47D00 /* MTRTestKeys.m in Sources */,
51C984622A61CE2A00B0AD9A /* MTRFabricInfoChecker.m in Sources */,
51578AE92D0B9B1D001716FF /* MTRErrorMappingTests.m in Sources */,
99C65E10267282F1003402F6 /* MTRControllerTests.m in Sources */,
8874C1322B69C7060084BEFD /* MTRMetricsTests.m in Sources */,
1E5801C328941C050033A199 /* MTRTestOTAProvider.m in Sources */,
Expand Down

0 comments on commit 2b8f5d7

Please sign in to comment.