3 * Copyright (c) 2020 Project CHIP Authors
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
19 #include <mdns/minimal/records/ResourceRecord.h>
20 #include <support/UnitTestRegistration.h>
22 #include <nlunit-test.h>
27 using namespace chip::Encoding::BigEndian;
28 using namespace mdns::Minimal;
30 const QNamePart kNames[] = { "foo", "bar" };
32 class FakeResourceRecord : public ResourceRecord
35 FakeResourceRecord(const char * data) : ResourceRecord(QType::ANY, kNames), mData(data) {}
38 bool WriteData(BufferWriter & out) const override
48 void CanWriteSimpleRecord(nlTestSuite * inSuite, void * inContext)
50 uint8_t headerBuffer[HeaderRef::kSizeBytes];
51 uint8_t dataBuffer[128];
53 HeaderRef header(headerBuffer);
56 BufferWriter output(dataBuffer, sizeof(dataBuffer));
57 FakeResourceRecord record("somedata");
59 record.SetTtl(0x11223344);
61 const uint8_t expectedOutput[] = {
63 3, 'f', 'o', 'o', // QNAME part: foo
64 3, 'b', 'a', 'r', // QNAME part: bar
66 0, 255, // QType ANY (totally fake)
68 0x11, 0x22, 0x33, 0x44, // TTL
70 's', 'o', 'm', 'e', 'd', 'a', 't', 'a',
73 NL_TEST_ASSERT(inSuite, record.Append(header, ResourceType::kAnswer, output));
74 NL_TEST_ASSERT(inSuite, header.GetAnswerCount() == 1);
75 NL_TEST_ASSERT(inSuite, header.GetAuthorityCount() == 0);
76 NL_TEST_ASSERT(inSuite, header.GetAdditionalCount() == 0);
77 NL_TEST_ASSERT(inSuite, output.Needed() == sizeof(expectedOutput));
78 NL_TEST_ASSERT(inSuite, memcmp(dataBuffer, expectedOutput, sizeof(expectedOutput)) == 0);
81 void CanWriteMultipleRecords(nlTestSuite * inSuite, void * inContext)
83 uint8_t headerBuffer[HeaderRef::kSizeBytes];
84 uint8_t dataBuffer[128];
86 HeaderRef header(headerBuffer);
89 BufferWriter output(dataBuffer, sizeof(dataBuffer));
90 FakeResourceRecord record1("somedata");
91 FakeResourceRecord record2("moredata");
92 FakeResourceRecord record3("xyz");
94 record1.SetTtl(0x11223344);
98 const uint8_t expectedOutput[] = {
99 3, 'f', 'o', 'o', // QNAME part: foo
100 3, 'b', 'a', 'r', // QNAME part: bar
102 0, 255, // QType ANY (totally fake)
104 0x11, 0x22, 0x33, 0x44, // TTL
106 's', 'o', 'm', 'e', 'd', 'a', 't', 'a', //
107 3, 'f', 'o', 'o', // QNAME part: foo
108 3, 'b', 'a', 'r', // QNAME part: bar
110 0, 255, // QType ANY (totally fake)
114 'm', 'o', 'r', 'e', 'd', 'a', 't', 'a', //
115 3, 'f', 'o', 'o', // QNAME part: foo
116 3, 'b', 'a', 'r', // QNAME part: bar
118 0, 255, // QType ANY (totally fake)
120 0, 0, 0, 0xFF, // TTL
125 NL_TEST_ASSERT(inSuite, record1.Append(header, ResourceType::kAnswer, output));
126 NL_TEST_ASSERT(inSuite, header.GetAnswerCount() == 1);
127 NL_TEST_ASSERT(inSuite, header.GetAuthorityCount() == 0);
128 NL_TEST_ASSERT(inSuite, header.GetAdditionalCount() == 0);
130 NL_TEST_ASSERT(inSuite, record2.Append(header, ResourceType::kAuthority, output));
131 NL_TEST_ASSERT(inSuite, header.GetAnswerCount() == 1);
132 NL_TEST_ASSERT(inSuite, header.GetAuthorityCount() == 1);
133 NL_TEST_ASSERT(inSuite, header.GetAdditionalCount() == 0);
135 NL_TEST_ASSERT(inSuite, record3.Append(header, ResourceType::kAdditional, output));
136 NL_TEST_ASSERT(inSuite, header.GetAnswerCount() == 1);
137 NL_TEST_ASSERT(inSuite, header.GetAuthorityCount() == 1);
138 NL_TEST_ASSERT(inSuite, header.GetAdditionalCount() == 1);
140 NL_TEST_ASSERT(inSuite, output.Needed() == sizeof(expectedOutput));
141 NL_TEST_ASSERT(inSuite, memcmp(dataBuffer, expectedOutput, sizeof(expectedOutput)) == 0);
144 void RecordOrderIsEnforced(nlTestSuite * inSuite, void * inContext)
146 uint8_t headerBuffer[HeaderRef::kSizeBytes];
147 uint8_t dataBuffer[128];
149 HeaderRef header(headerBuffer);
151 BufferWriter output(dataBuffer, sizeof(dataBuffer));
152 FakeResourceRecord record("somedata");
155 header.SetAuthorityCount(1);
156 NL_TEST_ASSERT(inSuite, record.Append(header, ResourceType::kAnswer, output) == false);
159 header.SetAdditionalCount(1);
160 NL_TEST_ASSERT(inSuite, record.Append(header, ResourceType::kAnswer, output) == false);
161 NL_TEST_ASSERT(inSuite, record.Append(header, ResourceType::kAuthority, output) == false);
164 void ErrorsOutOnSmallBuffers(nlTestSuite * inSuite, void * inContext)
166 uint8_t headerBuffer[HeaderRef::kSizeBytes];
167 uint8_t dataBuffer[123];
169 HeaderRef header(headerBuffer);
171 FakeResourceRecord record("somedata");
173 const uint8_t expectedOutput[] = {
175 3, 'f', 'o', 'o', // QNAME part: foo
176 3, 'b', 'a', 'r', // QNAME part: bar
178 0, 255, // QType ANY (totally fake)
182 's', 'o', 'm', 'e', 'd', 'a', 't', 'a',
186 uint8_t clearHeader[HeaderRef::kSizeBytes];
188 memcpy(clearHeader, headerBuffer, HeaderRef::kSizeBytes);
190 for (size_t i = 0; i < sizeof(expectedOutput); i++)
192 memset(dataBuffer, 0, sizeof(dataBuffer));
193 BufferWriter output(dataBuffer, i);
195 NL_TEST_ASSERT(inSuite, record.Append(header, ResourceType::kAnswer, output) == false);
198 NL_TEST_ASSERT(inSuite, memcmp(headerBuffer, clearHeader, HeaderRef::kSizeBytes) == 0);
201 memset(dataBuffer, 0, sizeof(dataBuffer));
202 BufferWriter output(dataBuffer, sizeof(expectedOutput));
204 NL_TEST_ASSERT(inSuite, record.Append(header, ResourceType::kAnswer, output));
205 NL_TEST_ASSERT(inSuite, output.Needed() == sizeof(expectedOutput));
206 NL_TEST_ASSERT(inSuite, memcmp(dataBuffer, expectedOutput, sizeof(expectedOutput)) == 0);
207 NL_TEST_ASSERT(inSuite, memcmp(headerBuffer, clearHeader, HeaderRef::kSizeBytes) != 0);
210 void RecordCount(nlTestSuite * inSuite, void * inContext)
212 constexpr int kAppendCount = 10;
213 uint8_t headerBuffer[HeaderRef::kSizeBytes];
214 uint8_t dataBuffer[123];
216 HeaderRef header(headerBuffer);
219 FakeResourceRecord record("somedata");
221 for (int i = 0; i < kAppendCount; i++)
223 BufferWriter output(dataBuffer, sizeof(dataBuffer));
224 NL_TEST_ASSERT(inSuite, record.Append(header, ResourceType::kAnswer, output));
225 NL_TEST_ASSERT(inSuite, header.GetAnswerCount() == i + 1);
226 NL_TEST_ASSERT(inSuite, header.GetAuthorityCount() == 0);
227 NL_TEST_ASSERT(inSuite, header.GetAdditionalCount() == 0);
230 for (int i = 0; i < kAppendCount; i++)
232 BufferWriter output(dataBuffer, sizeof(dataBuffer));
233 NL_TEST_ASSERT(inSuite, record.Append(header, ResourceType::kAuthority, output));
234 NL_TEST_ASSERT(inSuite, header.GetAnswerCount() == kAppendCount);
235 NL_TEST_ASSERT(inSuite, header.GetAuthorityCount() == i + 1);
236 NL_TEST_ASSERT(inSuite, header.GetAdditionalCount() == 0);
239 for (int i = 0; i < kAppendCount; i++)
241 BufferWriter output(dataBuffer, sizeof(dataBuffer));
242 NL_TEST_ASSERT(inSuite, record.Append(header, ResourceType::kAdditional, output));
243 NL_TEST_ASSERT(inSuite, header.GetAnswerCount() == kAppendCount);
244 NL_TEST_ASSERT(inSuite, header.GetAuthorityCount() == kAppendCount);
245 NL_TEST_ASSERT(inSuite, header.GetAdditionalCount() == i + 1);
249 const nlTest sTests[] = {
250 NL_TEST_DEF("CanWriteSimpleRecord", CanWriteSimpleRecord), //
251 NL_TEST_DEF("CanWriteMultipleRecords", CanWriteMultipleRecords), //
252 NL_TEST_DEF("RecordOrderIsEnforced", RecordOrderIsEnforced), //
253 NL_TEST_DEF("ErrorsOutOnSmallBuffers", ErrorsOutOnSmallBuffers), //
254 NL_TEST_DEF("RecordCount", RecordCount), //
255 NL_TEST_SENTINEL() //
260 int TestResourceRecord(void)
262 nlTestSuite theSuite = { "ResourceRecord", sTests, nullptr, nullptr };
263 nlTestRunner(&theSuite, nullptr);
264 return nlTestRunnerStats(&theSuite);
267 CHIP_REGISTER_TEST_SUITE(TestResourceRecord)