Skip to content

Commit

Permalink
TLVReader: Add test for Expect() and handle corner case better
Browse files Browse the repository at this point in the history
Expect(tag) implies that we should actually be positioned on an element.
Also make a note about the position of the reader after Next(...)
  • Loading branch information
ksperling-apple committed Nov 2, 2023
1 parent 94a6f93 commit 3c0f5c3
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 4 deletions.
5 changes: 3 additions & 2 deletions src/lib/core/TLVReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,8 @@ CHIP_ERROR TLVReader::Next()

CHIP_ERROR TLVReader::Expect(Tag expectedTag)
{
VerifyOrReturnError(mElemTag == expectedTag, CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
VerifyOrReturnError(GetType() != kTLVType_NotSpecified, CHIP_ERROR_WRONG_TLV_TYPE);
VerifyOrReturnError(GetTag() == expectedTag, CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
return CHIP_NO_ERROR;
}

Expand All @@ -598,8 +599,8 @@ CHIP_ERROR TLVReader::Next(Tag expectedTag)

CHIP_ERROR TLVReader::Expect(TLVType expectedType, Tag expectedTag)
{
ReturnErrorOnFailure(Expect(expectedTag));
VerifyOrReturnError(GetType() == expectedType, CHIP_ERROR_WRONG_TLV_TYPE);
VerifyOrReturnError(GetTag() == expectedTag, CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
return CHIP_NO_ERROR;
}

Expand Down
11 changes: 9 additions & 2 deletions src/lib/core/TLVReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,10 @@ class DLL_EXPORT TLVReader
* Advances the TLVReader object to the next TLV element to be read, asserting the tag of
* the new element.
*
* This is a convenience method that combines the behavior of Next() and Expect().
* This is a convenience method that combines the behavior of Next() and Expect(...).
*
* Note that if this method returns an error, the reader may or may not have been advanced already.
* In use cases where this is important, separate calls to Next() and Expect(...) should be made.
*
* @retval #CHIP_NO_ERROR If the reader was successfully positioned on a new element
* matching the expected parameters.
Expand All @@ -179,6 +182,7 @@ class DLL_EXPORT TLVReader
* Checks that the TLV reader is positioned at an element with the expected tag.
*
* @retval #CHIP_NO_ERROR If the reader is positioned on the expected element.
* @retval #CHIP_ERROR_WRONG_TLV_TYPE If the reader is not positioned on an element.
* @retval #CHIP_ERROR_UNEXPECTED_TLV_ELEMENT
* If the tag associated with the new element does not match the
* value of the @p expectedTag argument.
Expand All @@ -189,7 +193,10 @@ class DLL_EXPORT TLVReader
* Advances the TLVReader object to the next TLV element to be read, asserting the type and tag of
* the new element.
*
* This is a convenience method that combines the behavior of Next() and Expect().
* This is a convenience method that combines the behavior of Next() and Expect(...).
*
* Note that if this method returns an error, the reader may or may not have been advanced already.
* In use cases where this is important, separate calls to Next() and Expect(...) should be made.
*
* @retval #CHIP_NO_ERROR If the reader was successfully positioned on a new element
* matching the expected parameters.
Expand Down
55 changes: 55 additions & 0 deletions src/lib/core/tests/TestTLV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3628,6 +3628,59 @@ void TestTLVReaderErrorHandling(nlTestSuite * inSuite)
chip::Platform::MemoryFree(const_cast<uint8_t *>(data));
}

void TestTLVReaderExpect(nlTestSuite * inSuite)
{
// Prepare some test data
uint8_t buffer[20];
TLVWriter writer;
writer.Init(buffer, sizeof(buffer));
TLVType outerContainer;
NL_TEST_ASSERT_SUCCESS(inSuite, writer.StartContainer(AnonymousTag(), kTLVType_Structure, outerContainer));
NL_TEST_ASSERT_SUCCESS(inSuite, writer.PutBoolean(ContextTag(23), false));
NL_TEST_ASSERT_SUCCESS(inSuite, writer.EndContainer(outerContainer));

TLVReader reader;
reader.Init(buffer, writer.GetLengthWritten());

// Positioned before the first element
NL_TEST_ASSERT(inSuite, reader.GetType() == kTLVType_NotSpecified);

NL_TEST_ASSERT(inSuite, reader.Expect(AnonymousTag()) == CHIP_ERROR_WRONG_TLV_TYPE);
NL_TEST_ASSERT(inSuite, reader.Expect(ContextTag(23)) == CHIP_ERROR_WRONG_TLV_TYPE);
NL_TEST_ASSERT(inSuite, reader.Expect(kTLVType_Boolean, AnonymousTag()) == CHIP_ERROR_WRONG_TLV_TYPE);

// Positioned on kTLVType_Structure / AnonymousTag(),
NL_TEST_ASSERT_SUCCESS(inSuite, reader.Next());
NL_TEST_ASSERT(inSuite, reader.GetType() == kTLVType_Structure);
NL_TEST_ASSERT(inSuite, reader.GetTag() == AnonymousTag());

NL_TEST_ASSERT(inSuite, reader.Expect(ContextTag(23)) == CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
NL_TEST_ASSERT_SUCCESS(inSuite, reader.Expect(AnonymousTag()));

NL_TEST_ASSERT(inSuite, reader.Expect(kTLVType_SignedInteger, AnonymousTag()) == CHIP_ERROR_WRONG_TLV_TYPE);
NL_TEST_ASSERT_SUCCESS(inSuite, reader.Expect(kTLVType_Structure, AnonymousTag()));

// Positioned before first struct element
NL_TEST_ASSERT_SUCCESS(inSuite, reader.EnterContainer(outerContainer));
NL_TEST_ASSERT(inSuite, reader.GetType() == kTLVType_NotSpecified);

NL_TEST_ASSERT(inSuite, reader.Expect(AnonymousTag()) == CHIP_ERROR_WRONG_TLV_TYPE);
NL_TEST_ASSERT(inSuite, reader.Expect(ContextTag(23)) == CHIP_ERROR_WRONG_TLV_TYPE);
NL_TEST_ASSERT(inSuite, reader.Expect(kTLVType_Boolean, AnonymousTag()) == CHIP_ERROR_WRONG_TLV_TYPE);

// Positioned on kTLVType_Boolean / ContextTag(23)
NL_TEST_ASSERT_SUCCESS(inSuite, reader.Next());
NL_TEST_ASSERT(inSuite, reader.GetType() == kTLVType_Boolean);
NL_TEST_ASSERT(inSuite, reader.GetTag() == ContextTag(23));

NL_TEST_ASSERT(inSuite, reader.Expect(AnonymousTag()) == CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
NL_TEST_ASSERT(inSuite, reader.Expect(ContextTag(42)) == CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
NL_TEST_ASSERT_SUCCESS(inSuite, reader.Expect(ContextTag(23)));

NL_TEST_ASSERT(inSuite, reader.Expect(kTLVType_SignedInteger, ContextTag(23)) == CHIP_ERROR_WRONG_TLV_TYPE);
NL_TEST_ASSERT_SUCCESS(inSuite, reader.Expect(kTLVType_Boolean, ContextTag(23)));
}

/**
* Test that CHIP TLV reader returns an error when a read is requested that
* would truncate the output.
Expand Down Expand Up @@ -3789,6 +3842,8 @@ void CheckTLVReader(nlTestSuite * inSuite, void * inContext)

TestTLVReaderErrorHandling(inSuite);

TestTLVReaderExpect(inSuite);

TestTLVReaderTruncatedReads(inSuite);

TestTLVReaderInPractice(inSuite);
Expand Down

0 comments on commit 3c0f5c3

Please sign in to comment.