/* * * Copyright (c) 2020 Project CHIP Authors * All rights reserved. * * 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. */ #include #include #include namespace { using namespace mdns::Minimal; /// Convenience method to have a serialized QName: /// /// static const uint8_t kData[] = "datahere\00"; /// AsSerializedQName(kData); /// /// NOTE: this MUST be using the string "" format to add an extra NULL /// terminator that this method discards. template static SerializedQNameIterator AsSerializedQName(const uint8_t (&v)[N]) { // NOTE: the -1 is because we format these items as STRINGS and that // appends an extra NULL terminator return SerializedQNameIterator(BytesRange(v, v + N - 1), v); } TEST(TestQName, IteratorTest) { { static const uint8_t kOneItem[] = "\04test\00"; SerializedQNameIterator it = AsSerializedQName(kOneItem); EXPECT_TRUE(it.Next()); EXPECT_STREQ(it.Value(), "test"); EXPECT_FALSE(it.Next()); EXPECT_TRUE(it.IsValid()); } { static const uint8_t kManyItems[] = "\04this\02is\01a\04test\00"; SerializedQNameIterator it = AsSerializedQName(kManyItems); EXPECT_TRUE(it.Next()); EXPECT_STREQ(it.Value(), "this"); EXPECT_TRUE(it.Next()); EXPECT_STREQ(it.Value(), "is"); EXPECT_TRUE(it.Next()); EXPECT_STREQ(it.Value(), "a"); EXPECT_TRUE(it.Next()); EXPECT_STREQ(it.Value(), "test"); EXPECT_FALSE(it.Next()); EXPECT_TRUE(it.IsValid()); } { static const uint8_t kPtrItems[] = "abc\02is\01a\04test\00\04this\xc0\03"; SerializedQNameIterator it(BytesRange(kPtrItems, kPtrItems + sizeof(kPtrItems)), kPtrItems + 14); EXPECT_TRUE(it.Next()); EXPECT_STREQ(it.Value(), "this"); EXPECT_TRUE(it.Next()); EXPECT_STREQ(it.Value(), "is"); EXPECT_TRUE(it.Next()); EXPECT_STREQ(it.Value(), "a"); EXPECT_TRUE(it.Next()); EXPECT_STREQ(it.Value(), "test"); EXPECT_FALSE(it.Next()); EXPECT_TRUE(it.IsValid()); } } TEST(TestQName, ErrorTest) { { // Truncated before the end static const uint8_t kData[] = "\04test"; SerializedQNameIterator it = AsSerializedQName(kData); EXPECT_FALSE(it.Next()); EXPECT_FALSE(it.IsValid()); } { // Truncated before the end static const uint8_t kData[] = "\02"; SerializedQNameIterator it = AsSerializedQName(kData); EXPECT_FALSE(it.Next()); EXPECT_FALSE(it.IsValid()); } { // Truncated before the end static const uint8_t kData[] = "\xc0"; SerializedQNameIterator it = AsSerializedQName(kData); EXPECT_FALSE(it.Next()); EXPECT_FALSE(it.IsValid()); } } TEST(TestQName, InvalidReferencing) { { // Truncated before the end (but seemingly valid in case of error) // does NOT use AsSerializedQName (because out of range) static const uint8_t kData[] = "\00\xc0\x00"; SerializedQNameIterator it(BytesRange(kData, kData + 2), kData + 1); EXPECT_FALSE(it.Next()); EXPECT_FALSE(it.IsValid()); } { // Infinite recursion static const uint8_t kData[] = "\04test\xc0\x00"; SerializedQNameIterator it = AsSerializedQName(kData); EXPECT_TRUE(it.Next()); EXPECT_FALSE(it.Next()); EXPECT_FALSE(it.IsValid()); } { // Infinite recursion by referencing own element (inside the stream) static const uint8_t kData[] = "\04test\xc0\x05"; SerializedQNameIterator it = AsSerializedQName(kData); EXPECT_TRUE(it.Next()); EXPECT_FALSE(it.Next()); EXPECT_FALSE(it.IsValid()); } { // Infinite recursion by referencing own element at the start static const uint8_t kData[] = "\xc0\x00"; SerializedQNameIterator it = AsSerializedQName(kData); EXPECT_FALSE(it.Next()); EXPECT_FALSE(it.IsValid()); } { // Reference that goes forwad instead of backward static const uint8_t kData[] = "\04test\xc0\x07"; SerializedQNameIterator it = AsSerializedQName(kData); EXPECT_TRUE(it.Next()); EXPECT_FALSE(it.Next()); EXPECT_FALSE(it.IsValid()); } } TEST(TestQName, Comparison) { static const uint8_t kManyItems[] = "\04this\02is\01a\04test\00"; { const QNamePart kTestName[] = { "this" }; EXPECT_NE(AsSerializedQName(kManyItems), FullQName(kTestName)); } { const QNamePart kTestName[] = { "this", "is" }; EXPECT_NE(AsSerializedQName(kManyItems), FullQName(kTestName)); } { const QNamePart kTestName[] = { "is", "a", "test" }; EXPECT_NE(AsSerializedQName(kManyItems), FullQName(kTestName)); } { const QNamePart kTestName[] = { "this", "is", "a", "test" }; EXPECT_EQ(AsSerializedQName(kManyItems), FullQName(kTestName)); } { const QNamePart kTestName[] = { "this", "is", "a", "test", "suffix" }; EXPECT_NE(AsSerializedQName(kManyItems), FullQName(kTestName)); } { const QNamePart kTestName[] = { "prefix", "this", "is", "a", "test" }; EXPECT_NE(AsSerializedQName(kManyItems), FullQName(kTestName)); } } TEST(TestQName, CaseInsensitiveSerializedCompare) { static const uint8_t kManyItems[] = "\04thIs\02iS\01a\04tEst\00"; { const QNamePart kTestName[] = { "this", "is", "a", "test" }; EXPECT_EQ(SerializedQNameIterator(BytesRange(kManyItems, kManyItems + sizeof(kManyItems)), kManyItems), FullQName(kTestName)); } { const QNamePart kTestName[] = { "THIS", "IS", "A", "test" }; EXPECT_EQ(SerializedQNameIterator(BytesRange(kManyItems, kManyItems + sizeof(kManyItems)), kManyItems), FullQName(kTestName)); } { const QNamePart kTestName[] = { "THIS", "IS", "A", "TEST" }; EXPECT_EQ(SerializedQNameIterator(BytesRange(kManyItems, kManyItems + sizeof(kManyItems)), kManyItems), FullQName(kTestName)); } } TEST(TestQName, CaseInsensitiveFullQNameCompare) { { const QNamePart kName1[] = { "this", "is", "a", "test" }; const QNamePart kName2[] = { "this", "IS", "a", "TEST" }; EXPECT_EQ(FullQName(kName1), FullQName(kName2)); } { const QNamePart kName1[] = { "THIS", "IS", "a", "tesT" }; const QNamePart kName2[] = { "this", "IS", "A", "TEst" }; EXPECT_EQ(FullQName(kName1), FullQName(kName2)); } { const QNamePart kName1[] = { "THIS", "IS", "a", "test" }; const QNamePart kName2[] = { "this", "IS", "A", "NEST" }; EXPECT_NE(FullQName(kName1), FullQName(kName2)); } { const QNamePart kName1[] = { "THIS", "IS", "a" }; const QNamePart kName2[] = { "this", "IS", "A", "NEST" }; EXPECT_NE(FullQName(kName1), FullQName(kName2)); } { const QNamePart kName1[] = { "THIS", "IS", "a" }; const QNamePart kName2[] = { "this", "IS" }; EXPECT_NE(FullQName(kName1), FullQName(kName2)); } { const QNamePart kName[] = { "this" }; EXPECT_NE(FullQName(), FullQName(kName)); EXPECT_NE(FullQName(kName), FullQName()); } } TEST(TestQName, SerializedCompare) { static const uint8_t kThisIsATest1[] = "\04this\02is\01a\04test\00"; static const uint8_t kThisIsATest2[] = "\04ThIs\02is\01A\04tESt\00"; static const uint8_t kThisIsDifferent[] = "\04this\02is\09different\00"; static const uint8_t kThisIs[] = "\04this\02is"; EXPECT_EQ(AsSerializedQName(kThisIsATest1), AsSerializedQName(kThisIsATest1)); EXPECT_EQ(AsSerializedQName(kThisIsATest2), AsSerializedQName(kThisIsATest2)); EXPECT_EQ(AsSerializedQName(kThisIsATest1), AsSerializedQName(kThisIsATest2)); EXPECT_NE(AsSerializedQName(kThisIsATest1), AsSerializedQName(kThisIsDifferent)); EXPECT_NE(AsSerializedQName(kThisIsDifferent), AsSerializedQName(kThisIsATest1)); EXPECT_NE(AsSerializedQName(kThisIsDifferent), AsSerializedQName(kThisIs)); EXPECT_NE(AsSerializedQName(kThisIs), AsSerializedQName(kThisIsDifferent)); // These items have back references and are "this.is.a.test" static const uint8_t kPtrItems[] = "\03abc\02is\01a\04test\00\04this\xc0\04"; SerializedQNameIterator thisIsATestPtr(BytesRange(kPtrItems, kPtrItems + sizeof(kPtrItems)), kPtrItems + 15); EXPECT_EQ(thisIsATestPtr, AsSerializedQName(kThisIsATest1)); EXPECT_EQ(thisIsATestPtr, AsSerializedQName(kThisIsATest2)); EXPECT_EQ(AsSerializedQName(kThisIsATest1), thisIsATestPtr); EXPECT_EQ(AsSerializedQName(kThisIsATest2), thisIsATestPtr); EXPECT_NE(thisIsATestPtr, AsSerializedQName(kThisIs)); EXPECT_NE(AsSerializedQName(kThisIs), thisIsATestPtr); } } // namespace