Skip to content

Commit 9078723

Browse files
bzbarsky-applepull[bot]
authored andcommitted
String values in YAML should test edge cases better. (#11687)
This adds garbage to the ends of all the strings and octet strings being sent in yaml tests, and makes sure that garbage is not included in the length, so the span is correct. The idea is to catch cases where someone uses a span's pointer without checking its length. This also adds a way to embed a 0 byte in an octet string (by using \x00 in the yaml string) and adds support for both sending and checking for such values.
1 parent 2faf5fb commit 9078723

File tree

10 files changed

+549
-417
lines changed

10 files changed

+549
-417
lines changed

examples/chip-tool/commands/tests/TestCommand.cpp

+7-9
Original file line numberDiff line numberDiff line change
@@ -109,25 +109,23 @@ bool TestCommand::CheckConstraintMaxLength(const char * itemName, uint64_t curre
109109
return true;
110110
}
111111

112-
bool TestCommand::CheckValueAsString(const char * itemName, const chip::ByteSpan current, const char * expected)
112+
bool TestCommand::CheckValueAsString(const char * itemName, chip::ByteSpan current, chip::ByteSpan expected)
113113
{
114-
const chip::ByteSpan expectedArgument = chip::ByteSpan(chip::Uint8::from_const_char(expected), strlen(expected));
115-
116-
if (!current.data_equal(expectedArgument))
114+
if (!current.data_equal(expected))
117115
{
118-
Exit(std::string(itemName) + " value mismatch, expecting " + std::string(expected));
116+
Exit(std::string(itemName) + " value mismatch, expecting " +
117+
std::string(chip::Uint8::to_const_char(expected.data()), expected.size()));
119118
return false;
120119
}
121120

122121
return true;
123122
}
124123

125-
bool TestCommand::CheckValueAsString(const char * itemName, const chip::CharSpan current, const char * expected)
124+
bool TestCommand::CheckValueAsString(const char * itemName, chip::CharSpan current, chip::CharSpan expected)
126125
{
127-
const chip::CharSpan expectedArgument(expected, strlen(expected));
128-
if (!current.data_equal(expectedArgument))
126+
if (!current.data_equal(expected))
129127
{
130-
Exit(std::string(itemName) + " value mismatch, expected '" + expected + "' but got '" +
128+
Exit(std::string(itemName) + " value mismatch, expected '" + std::string(expected.data(), expected.size()) + "' but got '" +
131129
std::string(current.data(), current.size()) + "'");
132130
return false;
133131
}

examples/chip-tool/commands/tests/TestCommand.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -171,9 +171,9 @@ class TestCommand : public CHIPCommand
171171
return false;
172172
}
173173

174-
bool CheckValueAsString(const char * itemName, chip::ByteSpan current, const char * expected);
174+
bool CheckValueAsString(const char * itemName, chip::ByteSpan current, chip::ByteSpan expected);
175175

176-
bool CheckValueAsString(const char * itemName, chip::CharSpan current, const char * expected);
176+
bool CheckValueAsString(const char * itemName, chip::CharSpan current, chip::CharSpan expected);
177177

178178
template <typename T>
179179
bool CheckValuePresent(const char * itemName, const chip::Optional<T> & value)

examples/chip-tool/templates/partials/test_cluster_command_value.zapt

+2-2
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@
3232
{{#if_chip_enum type}}
3333
static_cast<{{zapTypeToEncodableClusterObjectType type ns=ns}}>({{definedValue}});
3434
{{else if (isCharString type)}}
35-
chip::Span<const char>("{{definedValue}}", strlen("{{definedValue}}"));
35+
chip::Span<const char>("{{definedValue}}garbage: not in length on purpose", {{definedValue.length}});
3636
{{else if (isOctetString type)}}
37-
chip::ByteSpan(chip::Uint8::from_const_char("{{definedValue}}"), strlen("{{definedValue}}"));
37+
chip::ByteSpan(chip::Uint8::from_const_char("{{octetStringEscapedForCLiteral definedValue}}garbage: not in length on purpose"), {{definedValue.length}});
3838
{{else}}
3939
{{#if_is_bitmap type}}
4040
static_cast<{{zapTypeToEncodableClusterObjectType type ns=ns}}>({{definedValue}});

examples/chip-tool/templates/partials/test_cluster_value_equals.zapt

+2-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@
2929
than "global") that are not present in the struct ? }}
3030
{{else}}
3131
VerifyOrReturn(CheckValue
32-
{{~#if (isString type)}}AsString("{{label}}", {{actual}}, "{{expected}}")
32+
{{~#if (isOctetString type)}}AsString("{{label}}", {{actual}}, chip::ByteSpan(chip::Uint8::from_const_char("{{octetStringEscapedForCLiteral expected}}"), {{expected.length}}))
33+
{{else if (isCharString type)}}AsString("{{label}}", {{actual}}, chip::CharSpan("{{expected}}", {{expected.length}}))
3334
{{else}}<{{chipType}}>("{{label}}", {{actual}}, {{expected}}{{asTypeLiteralSuffix type}})
3435
{{/if}}
3536
);

src/app/tests/suites/TV_TargetNavigatorCluster.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,4 @@ tests:
3636
- name: "target"
3737
value: 1
3838
- name: "data"
39-
value: 1
39+
value: "1"

src/app/tests/suites/TestCluster.yaml

+12
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,18 @@ tests:
594594
response:
595595
value: ""
596596

597+
- label: "Write attribute OCTET_STRING with embedded null"
598+
command: "writeAttribute"
599+
attribute: "octet_string"
600+
arguments:
601+
value: "Tes\x00ti\x00ng"
602+
603+
- label: "Read attribute OCTET_STRING with embedded null"
604+
command: "readAttribute"
605+
attribute: "octet_string"
606+
response:
607+
value: "Tes\x00ti\x00ng"
608+
597609
- label: "Write attribute OCTET_STRING"
598610
command: "writeAttribute"
599611
attribute: "octet_string"

src/app/zap-templates/common/ClusterTestGeneration.js

+13
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,18 @@ function expectedValueHasProp(value, name)
582582
return name in value;
583583
}
584584

585+
function octetStringEscapedForCLiteral(value)
586+
{
587+
return value.replace(/\p{Control}/gu, ch => {
588+
let code = ch.charCodeAt(0);
589+
code = code.toString();
590+
if (code.length == 1) {
591+
code = "0" + code;
592+
}
593+
return "\\x" + code;
594+
});
595+
}
596+
585597
//
586598
// Module exports
587599
//
@@ -593,3 +605,4 @@ exports.chip_tests_pics = chip_tests_pics;
593605
exports.isTestOnlyCluster = isTestOnlyCluster;
594606
exports.isLiteralNull = isLiteralNull;
595607
exports.expectedValueHasProp = expectedValueHasProp;
608+
exports.octetStringEscapedForCLiteral = octetStringEscapedForCLiteral;

src/darwin/Framework/CHIP/templates/partials/test_cluster.zapt

+2-4
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@ bool testSendCluster{{parent.filename}}_{{asTestIndex index}}_{{asUpperCamelCase
2121
{{#chip_tests_item_parameters}}
2222
{{#if (isString type)}}
2323
{{#if (isOctetString type)}}
24-
NSString * {{asLowerCamelCase name}}ArgumentString= @"{{definedValue}}";
25-
NSData * {{asLowerCamelCase name}}Argument = [{{asLowerCamelCase name}}ArgumentString dataUsingEncoding:NSUTF8StringEncoding];
24+
NSData * {{asLowerCamelCase name}}Argument = [[NSData alloc] initWithBytes:"{{octetStringEscapedForCLiteral definedValue}}" length:{{definedValue.length}}];
2625
{{else}}
2726
NSString * {{asLowerCamelCase name}}Argument= @"{{definedValue}}";
2827
{{/if}}
@@ -67,8 +66,7 @@ bool testSendCluster{{parent.filename}}_{{asTestIndex index}}_{{asUpperCamelCase
6766
{{else}}
6867
{{#if (isString type)}}
6968
{{#if (isOctetString type)}}
70-
NSString * {{asLowerCamelCase name}}ArgumentString= @"{{expectedValue}}";
71-
NSData * {{asLowerCamelCase name}}Argument = [{{asLowerCamelCase name}}ArgumentString dataUsingEncoding:NSUTF8StringEncoding];
69+
NSData * {{asLowerCamelCase name}}Argument = [[NSData alloc] initWithBytes:"{{octetStringEscapedForCLiteral expectedValue}}" length:{{expectedValue.length}}];
7270
XCTAssertTrue([values[@"{{#if parent.isAttribute}}value{{else}}{{name}}{{/if}}"] isEqualToData:{{asLowerCamelCase name}}Argument]);
7371
{{else}}
7472
NSString * {{asLowerCamelCase name}}Argument= @"{{expectedValue}}";

0 commit comments

Comments
 (0)