diff --git a/examples/chip-tool/commands/tests/TestCommand.cpp b/examples/chip-tool/commands/tests/TestCommand.cpp index 7263614751e3d9..c6f24989470966 100644 --- a/examples/chip-tool/commands/tests/TestCommand.cpp +++ b/examples/chip-tool/commands/tests/TestCommand.cpp @@ -92,6 +92,30 @@ bool TestCommand::CheckConstraintFormat(const char * itemName, const char * curr return true; } +bool TestCommand::CheckConstraintStartsWith(const char * itemName, const chip::Span current, const char * expected) +{ + std::string value(current.data(), current.size()); + if (value.rfind(expected, 0) != 0) + { + Exit(std::string(itemName) + " (\"" + value + "\") does not starts with: \"" + std::string(expected) + "\""); + return false; + } + + return true; +} + +bool TestCommand::CheckConstraintEndsWith(const char * itemName, const chip::Span current, const char * expected) +{ + std::string value(current.data(), current.size()); + if (value.find(expected, value.size() - strlen(expected)) == std::string::npos) + { + Exit(std::string(itemName) + " (\"" + value + "\") does not ends with: \"" + std::string(expected) + "\""); + return false; + } + + return true; +} + bool TestCommand::CheckConstraintMinLength(const char * itemName, uint64_t current, uint64_t expected) { if (current < expected) diff --git a/examples/chip-tool/commands/tests/TestCommand.h b/examples/chip-tool/commands/tests/TestCommand.h index 7e3f756cd5fc8d..b5938f44d0a362 100644 --- a/examples/chip-tool/commands/tests/TestCommand.h +++ b/examples/chip-tool/commands/tests/TestCommand.h @@ -70,6 +70,8 @@ class TestCommand : public CHIPCommand bool CheckConstraintFormat(const char * itemName, const char * current, const char * expected); bool CheckConstraintMinLength(const char * itemName, uint64_t current, uint64_t expected); bool CheckConstraintMaxLength(const char * itemName, uint64_t current, uint64_t expected); + bool CheckConstraintStartsWith(const char * itemName, const chip::Span current, const char * expected); + bool CheckConstraintEndsWith(const char * itemName, const chip::Span current, const char * expected); template bool CheckConstraintMinValue(const char * itemName, T current, T expected) { diff --git a/examples/chip-tool/templates/partials/test_cluster.zapt b/examples/chip-tool/templates/partials/test_cluster.zapt index e8a3ba9bf7b23b..43ba5fbd977d83 100644 --- a/examples/chip-tool/templates/partials/test_cluster.zapt +++ b/examples/chip-tool/templates/partials/test_cluster.zapt @@ -258,6 +258,8 @@ class {{filename}}: public TestCommand {{/if}} {{#if expectedConstraints.type}}VerifyOrReturn(CheckConstraintType("{{>item}}", "", "{{expectedConstraints.type}}"));{{/if}} {{~#if expectedConstraints.format}}VerifyOrReturn(CheckConstraintFormat("{{>item}}", "", "{{expectedConstraints.format}}"));{{/if}} + {{~#if expectedConstraints.startsWith}}VerifyOrReturn(CheckConstraintStartsWith("{{>item}}", {{>item}}, "{{expectedConstraints.startsWith}}"));{{/if}} + {{~#if expectedConstraints.endsWith}}VerifyOrReturn(CheckConstraintEndsWith("{{>item}}", {{>item}}, "{{expectedConstraints.endsWith}}"));{{/if}} {{~#if expectedConstraints.minLength}}VerifyOrReturn(CheckConstraintMinLength("{{>item}}", {{>item}}.size(), {{expectedConstraints.minLength}}));{{/if}} {{~#if expectedConstraints.maxLength}}VerifyOrReturn(CheckConstraintMaxLength("{{>item}}", {{>item}}.size(), {{expectedConstraints.maxLength}}));{{/if}} {{~#if expectedConstraints.minValue}}VerifyOrReturn(CheckConstraintMinValue<{{chipType}}>("{{>item}}", {{>item}}, {{expectedConstraints.minValue}}));{{/if}} diff --git a/src/app/tests/suites/TestConstraints.yaml b/src/app/tests/suites/TestConstraints.yaml index 444d803d337f1e..e8234346f28b69 100644 --- a/src/app/tests/suites/TestConstraints.yaml +++ b/src/app/tests/suites/TestConstraints.yaml @@ -19,7 +19,7 @@ config: endpoint: 1 tests: - # Tests for UInt32 attribute + # Tests for INT32U attribute - label: "Write attribute INT32U Value" command: "writeAttribute" @@ -53,3 +53,45 @@ tests: attribute: "int32u" arguments: value: 0 + + # Tests for CHAR_STRING attribute + + - label: "Write attribute CHAR_STRING Value" + command: "writeAttribute" + attribute: "char_string" + arguments: + value: "** Test **" + + - label: "Read attribute CHAR_STRING Value MinLength Constraints" + command: "readAttribute" + attribute: "char_string" + response: + constraints: + minLength: 5 + + - label: "Read attribute CHAR_STRING Value MaxLength Constraints" + command: "readAttribute" + attribute: "char_string" + response: + constraints: + maxLength: 20 + + - label: "Read attribute CHAR_STRING Value StartsWith Constraints" + command: "readAttribute" + attribute: "char_string" + response: + constraints: + startsWith: "**" + + - label: "Read attribute CHAR_STRING Value EndsWith Constraints" + command: "readAttribute" + attribute: "char_string" + response: + constraints: + endsWith: "**" + + - label: "Write attribute CHAR_STRING Value Back to Default Value" + command: "writeAttribute" + attribute: "char_string" + arguments: + value: "" diff --git a/src/darwin/Framework/CHIP/templates/partials/test_cluster.zapt b/src/darwin/Framework/CHIP/templates/partials/test_cluster.zapt index 2a0ae3d1597f1b..820969ceb68f64 100644 --- a/src/darwin/Framework/CHIP/templates/partials/test_cluster.zapt +++ b/src/darwin/Framework/CHIP/templates/partials/test_cluster.zapt @@ -106,6 +106,18 @@ bool testSendCluster{{parent.filename}}_{{asTestIndex index}}_{{asUpperCamelCase XCTAssertGreaterThanOrEqual([actualValue length], {{expectedConstraints.minLength}}); } {{/if}} + {{#if expectedConstraints.startsWith}} + { + {{> actualValue}} + XCTAssertTrue([actualValue hasPrefix:@"{{expectedConstraints.startsWith}}"]); + } + {{/if}} + {{#if expectedConstraints.endsWith}} + { + {{> actualValue}} + XCTAssertTrue([actualValue hasSuffix:@"{{expectedConstraints.endsWith}}"]); + } + {{/if}} {{#if expectedConstraints.maxLength}} { {{> actualValue}} diff --git a/src/darwin/Framework/CHIPTests/CHIPClustersTests.m b/src/darwin/Framework/CHIPTests/CHIPClustersTests.m index f73d27bc8639ce..46239d5636042c 100644 --- a/src/darwin/Framework/CHIPTests/CHIPClustersTests.m +++ b/src/darwin/Framework/CHIPTests/CHIPClustersTests.m @@ -26798,6 +26798,146 @@ - (void)testSendClusterTestConstraints_000004_WriteAttribute [self waitForExpectationsWithTimeout:kTimeoutInSeconds handler:nil]; } +- (void)testSendClusterTestConstraints_000005_WriteAttribute +{ + XCTestExpectation * expectation = [self expectationWithDescription:@"Write attribute CHAR_STRING Value"]; + + CHIPDevice * device = GetConnectedDevice(); + dispatch_queue_t queue = dispatch_get_main_queue(); + CHIPTestTestCluster * cluster = [[CHIPTestTestCluster alloc] initWithDevice:device endpoint:1 queue:queue]; + XCTAssertNotNil(cluster); + + id charStringArgument; + charStringArgument = @"** Test **"; + [cluster writeAttributeCharStringWithValue:charStringArgument + completionHandler:^(NSError * _Nullable err) { + NSLog(@"Write attribute CHAR_STRING Value Error: %@", err); + + XCTAssertEqual([CHIPErrorTestUtils errorToZCLErrorCode:err], 0); + + [expectation fulfill]; + }]; + + [self waitForExpectationsWithTimeout:kTimeoutInSeconds handler:nil]; +} +- (void)testSendClusterTestConstraints_000006_ReadAttribute +{ + XCTestExpectation * expectation = [self expectationWithDescription:@"Read attribute CHAR_STRING Value MinLength Constraints"]; + + CHIPDevice * device = GetConnectedDevice(); + dispatch_queue_t queue = dispatch_get_main_queue(); + CHIPTestTestCluster * cluster = [[CHIPTestTestCluster alloc] initWithDevice:device endpoint:1 queue:queue]; + XCTAssertNotNil(cluster); + + [cluster readAttributeCharStringWithCompletionHandler:^(NSString * _Nullable value, NSError * _Nullable err) { + NSLog(@"Read attribute CHAR_STRING Value MinLength Constraints Error: %@", err); + + XCTAssertEqual([CHIPErrorTestUtils errorToZCLErrorCode:err], 0); + + { + id actualValue = value; + XCTAssertGreaterThanOrEqual([actualValue length], 5); + } + + [expectation fulfill]; + }]; + + [self waitForExpectationsWithTimeout:kTimeoutInSeconds handler:nil]; +} +- (void)testSendClusterTestConstraints_000007_ReadAttribute +{ + XCTestExpectation * expectation = [self expectationWithDescription:@"Read attribute CHAR_STRING Value MaxLength Constraints"]; + + CHIPDevice * device = GetConnectedDevice(); + dispatch_queue_t queue = dispatch_get_main_queue(); + CHIPTestTestCluster * cluster = [[CHIPTestTestCluster alloc] initWithDevice:device endpoint:1 queue:queue]; + XCTAssertNotNil(cluster); + + [cluster readAttributeCharStringWithCompletionHandler:^(NSString * _Nullable value, NSError * _Nullable err) { + NSLog(@"Read attribute CHAR_STRING Value MaxLength Constraints Error: %@", err); + + XCTAssertEqual([CHIPErrorTestUtils errorToZCLErrorCode:err], 0); + + { + id actualValue = value; + XCTAssertLessThanOrEqual([actualValue length], 20); + } + + [expectation fulfill]; + }]; + + [self waitForExpectationsWithTimeout:kTimeoutInSeconds handler:nil]; +} +- (void)testSendClusterTestConstraints_000008_ReadAttribute +{ + XCTestExpectation * expectation = [self expectationWithDescription:@"Read attribute CHAR_STRING Value StartsWith Constraints"]; + + CHIPDevice * device = GetConnectedDevice(); + dispatch_queue_t queue = dispatch_get_main_queue(); + CHIPTestTestCluster * cluster = [[CHIPTestTestCluster alloc] initWithDevice:device endpoint:1 queue:queue]; + XCTAssertNotNil(cluster); + + [cluster readAttributeCharStringWithCompletionHandler:^(NSString * _Nullable value, NSError * _Nullable err) { + NSLog(@"Read attribute CHAR_STRING Value StartsWith Constraints Error: %@", err); + + XCTAssertEqual([CHIPErrorTestUtils errorToZCLErrorCode:err], 0); + + { + id actualValue = value; + XCTAssertTrue([actualValue hasPrefix:@"**"]); + } + + [expectation fulfill]; + }]; + + [self waitForExpectationsWithTimeout:kTimeoutInSeconds handler:nil]; +} +- (void)testSendClusterTestConstraints_000009_ReadAttribute +{ + XCTestExpectation * expectation = [self expectationWithDescription:@"Read attribute CHAR_STRING Value EndsWith Constraints"]; + + CHIPDevice * device = GetConnectedDevice(); + dispatch_queue_t queue = dispatch_get_main_queue(); + CHIPTestTestCluster * cluster = [[CHIPTestTestCluster alloc] initWithDevice:device endpoint:1 queue:queue]; + XCTAssertNotNil(cluster); + + [cluster readAttributeCharStringWithCompletionHandler:^(NSString * _Nullable value, NSError * _Nullable err) { + NSLog(@"Read attribute CHAR_STRING Value EndsWith Constraints Error: %@", err); + + XCTAssertEqual([CHIPErrorTestUtils errorToZCLErrorCode:err], 0); + + { + id actualValue = value; + XCTAssertTrue([actualValue hasSuffix:@"**"]); + } + + [expectation fulfill]; + }]; + + [self waitForExpectationsWithTimeout:kTimeoutInSeconds handler:nil]; +} +- (void)testSendClusterTestConstraints_000010_WriteAttribute +{ + XCTestExpectation * expectation = [self expectationWithDescription:@"Write attribute CHAR_STRING Value Back to Default Value"]; + + CHIPDevice * device = GetConnectedDevice(); + dispatch_queue_t queue = dispatch_get_main_queue(); + CHIPTestTestCluster * cluster = [[CHIPTestTestCluster alloc] initWithDevice:device endpoint:1 queue:queue]; + XCTAssertNotNil(cluster); + + id charStringArgument; + charStringArgument = @""; + [cluster writeAttributeCharStringWithValue:charStringArgument + completionHandler:^(NSError * _Nullable err) { + NSLog(@"Write attribute CHAR_STRING Value Back to Default Value Error: %@", err); + + XCTAssertEqual([CHIPErrorTestUtils errorToZCLErrorCode:err], 0); + + [expectation fulfill]; + }]; + + [self waitForExpectationsWithTimeout:kTimeoutInSeconds handler:nil]; +} - (void)testSendClusterTestDelayCommands_000000_WaitForMs { diff --git a/zzz_generated/chip-tool/zap-generated/test/Commands.h b/zzz_generated/chip-tool/zap-generated/test/Commands.h index 1164ba41571d18..b280c1320b6cd6 100644 --- a/zzz_generated/chip-tool/zap-generated/test/Commands.h +++ b/zzz_generated/chip-tool/zap-generated/test/Commands.h @@ -38695,6 +38695,30 @@ class TestConstraints : public TestCommand ChipLogProgress(chipTool, " ***** Test Step 4 : Write attribute INT32U Value Back to Default Value\n"); err = TestWriteAttributeInt32uValueBackToDefaultValue_4(); break; + case 5: + ChipLogProgress(chipTool, " ***** Test Step 5 : Write attribute CHAR_STRING Value\n"); + err = TestWriteAttributeCharStringValue_5(); + break; + case 6: + ChipLogProgress(chipTool, " ***** Test Step 6 : Read attribute CHAR_STRING Value MinLength Constraints\n"); + err = TestReadAttributeCharStringValueMinLengthConstraints_6(); + break; + case 7: + ChipLogProgress(chipTool, " ***** Test Step 7 : Read attribute CHAR_STRING Value MaxLength Constraints\n"); + err = TestReadAttributeCharStringValueMaxLengthConstraints_7(); + break; + case 8: + ChipLogProgress(chipTool, " ***** Test Step 8 : Read attribute CHAR_STRING Value StartsWith Constraints\n"); + err = TestReadAttributeCharStringValueStartsWithConstraints_8(); + break; + case 9: + ChipLogProgress(chipTool, " ***** Test Step 9 : Read attribute CHAR_STRING Value EndsWith Constraints\n"); + err = TestReadAttributeCharStringValueEndsWithConstraints_9(); + break; + case 10: + ChipLogProgress(chipTool, " ***** Test Step 10 : Write attribute CHAR_STRING Value Back to Default Value\n"); + err = TestWriteAttributeCharStringValueBackToDefaultValue_10(); + break; } if (CHIP_NO_ERROR != err) @@ -38706,7 +38730,7 @@ class TestConstraints : public TestCommand private: std::atomic_uint16_t mTestIndex; - const uint16_t mTestCount = 5; + const uint16_t mTestCount = 11; static void OnFailureCallback_0(void * context, EmberAfStatus status) { @@ -38752,6 +38776,60 @@ class TestConstraints : public TestCommand static void OnSuccessCallback_4(void * context) { (static_cast(context))->OnSuccessResponse_4(); } + static void OnFailureCallback_5(void * context, EmberAfStatus status) + { + (static_cast(context))->OnFailureResponse_5(chip::to_underlying(status)); + } + + static void OnSuccessCallback_5(void * context) { (static_cast(context))->OnSuccessResponse_5(); } + + static void OnFailureCallback_6(void * context, EmberAfStatus status) + { + (static_cast(context))->OnFailureResponse_6(chip::to_underlying(status)); + } + + static void OnSuccessCallback_6(void * context, chip::CharSpan charString) + { + (static_cast(context))->OnSuccessResponse_6(charString); + } + + static void OnFailureCallback_7(void * context, EmberAfStatus status) + { + (static_cast(context))->OnFailureResponse_7(chip::to_underlying(status)); + } + + static void OnSuccessCallback_7(void * context, chip::CharSpan charString) + { + (static_cast(context))->OnSuccessResponse_7(charString); + } + + static void OnFailureCallback_8(void * context, EmberAfStatus status) + { + (static_cast(context))->OnFailureResponse_8(chip::to_underlying(status)); + } + + static void OnSuccessCallback_8(void * context, chip::CharSpan charString) + { + (static_cast(context))->OnSuccessResponse_8(charString); + } + + static void OnFailureCallback_9(void * context, EmberAfStatus status) + { + (static_cast(context))->OnFailureResponse_9(chip::to_underlying(status)); + } + + static void OnSuccessCallback_9(void * context, chip::CharSpan charString) + { + (static_cast(context))->OnSuccessResponse_9(charString); + } + + static void OnFailureCallback_10(void * context, EmberAfStatus status) + { + (static_cast(context))->OnFailureResponse_10(chip::to_underlying(status)); + } + + static void OnSuccessCallback_10(void * context) { (static_cast(context))->OnSuccessResponse_10(); } + // // Tests methods // @@ -38846,6 +38924,116 @@ class TestConstraints : public TestCommand void OnFailureResponse_4(uint8_t status) { ThrowFailureResponse(); } void OnSuccessResponse_4() { NextTest(); } + + CHIP_ERROR TestWriteAttributeCharStringValue_5() + { + const chip::EndpointId endpoint = mEndpointId.HasValue() ? mEndpointId.Value() : 1; + chip::Controller::TestClusterClusterTest cluster; + cluster.Associate(mDevice, endpoint); + + chip::CharSpan charStringArgument; + charStringArgument = chip::Span("** Test **garbage: not in length on purpose", 10); + + return cluster.WriteAttribute( + charStringArgument, this, OnSuccessCallback_5, OnFailureCallback_5); + } + + void OnFailureResponse_5(uint8_t status) { ThrowFailureResponse(); } + + void OnSuccessResponse_5() { NextTest(); } + + CHIP_ERROR TestReadAttributeCharStringValueMinLengthConstraints_6() + { + const chip::EndpointId endpoint = mEndpointId.HasValue() ? mEndpointId.Value() : 1; + chip::Controller::TestClusterClusterTest cluster; + cluster.Associate(mDevice, endpoint); + + return cluster.ReadAttribute(this, OnSuccessCallback_6, + OnFailureCallback_6); + } + + void OnFailureResponse_6(uint8_t status) { ThrowFailureResponse(); } + + void OnSuccessResponse_6(chip::CharSpan charString) + { + VerifyOrReturn(CheckConstraintMinLength("charString", charString.size(), 5)); + + NextTest(); + } + + CHIP_ERROR TestReadAttributeCharStringValueMaxLengthConstraints_7() + { + const chip::EndpointId endpoint = mEndpointId.HasValue() ? mEndpointId.Value() : 1; + chip::Controller::TestClusterClusterTest cluster; + cluster.Associate(mDevice, endpoint); + + return cluster.ReadAttribute(this, OnSuccessCallback_7, + OnFailureCallback_7); + } + + void OnFailureResponse_7(uint8_t status) { ThrowFailureResponse(); } + + void OnSuccessResponse_7(chip::CharSpan charString) + { + VerifyOrReturn(CheckConstraintMaxLength("charString", charString.size(), 20)); + + NextTest(); + } + + CHIP_ERROR TestReadAttributeCharStringValueStartsWithConstraints_8() + { + const chip::EndpointId endpoint = mEndpointId.HasValue() ? mEndpointId.Value() : 1; + chip::Controller::TestClusterClusterTest cluster; + cluster.Associate(mDevice, endpoint); + + return cluster.ReadAttribute(this, OnSuccessCallback_8, + OnFailureCallback_8); + } + + void OnFailureResponse_8(uint8_t status) { ThrowFailureResponse(); } + + void OnSuccessResponse_8(chip::CharSpan charString) + { + VerifyOrReturn(CheckConstraintStartsWith("charString", charString, "**")); + + NextTest(); + } + + CHIP_ERROR TestReadAttributeCharStringValueEndsWithConstraints_9() + { + const chip::EndpointId endpoint = mEndpointId.HasValue() ? mEndpointId.Value() : 1; + chip::Controller::TestClusterClusterTest cluster; + cluster.Associate(mDevice, endpoint); + + return cluster.ReadAttribute(this, OnSuccessCallback_9, + OnFailureCallback_9); + } + + void OnFailureResponse_9(uint8_t status) { ThrowFailureResponse(); } + + void OnSuccessResponse_9(chip::CharSpan charString) + { + VerifyOrReturn(CheckConstraintEndsWith("charString", charString, "**")); + + NextTest(); + } + + CHIP_ERROR TestWriteAttributeCharStringValueBackToDefaultValue_10() + { + const chip::EndpointId endpoint = mEndpointId.HasValue() ? mEndpointId.Value() : 1; + chip::Controller::TestClusterClusterTest cluster; + cluster.Associate(mDevice, endpoint); + + chip::CharSpan charStringArgument; + charStringArgument = chip::Span("garbage: not in length on purpose", 0); + + return cluster.WriteAttribute( + charStringArgument, this, OnSuccessCallback_10, OnFailureCallback_10); + } + + void OnFailureResponse_10(uint8_t status) { ThrowFailureResponse(); } + + void OnSuccessResponse_10() { NextTest(); } }; class TestDelayCommands : public TestCommand