blob: ef7c9b5a005cdcbac9cfe2f3c7adac6cc2134daa [file] [log] [blame]
/*
*
* Copyright (c) 2021-2022 Project CHIP Authors
*
* 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.
*/
/**
* @file
* This file implements a unit test suite for the additional payload generation
* code functionality.
*
*/
#include <math.h>
#include <memory>
#include <nlunit-test.h>
#include <stdio.h>
#include <lib/support/BytesToHex.h>
#include <lib/support/CHIPMem.h>
#include <lib/support/CHIPMemString.h>
#include <lib/support/CHIPPlatformMemory.h>
#include <lib/support/UnitTestContext.h>
#include <setup_payload/AdditionalDataPayloadGenerator.h>
#include <setup_payload/AdditionalDataPayloadParser.h>
#include <setup_payload/SetupPayload.h>
#include <system/SystemPacketBuffer.h>
#include <lib/support/UnitTestRegistration.h>
#include <lib/support/verhoeff/Verhoeff.h>
using namespace chip;
namespace {
constexpr char kAdditionalDataPayloadWithoutRotatingDeviceId[] = "1518";
constexpr char kAdditionalDataPayloadWithRotatingDeviceId[] = "153000120A00D00561E77A68A9FD975057375B9283A818";
constexpr char kAdditionalDataPayloadWithInvalidRotatingDeviceIdLength[] = "153000FF0A001998AB7130E38B7E9A401CFE9F7B79AF18";
constexpr char kAdditionalDataPayloadWithLongRotatingDeviceId[] = "153000130A00191998AB7130E38B7E9A401CFE9F7B79AF18";
constexpr char kAdditionalDataPayloadWithShortRotatingDeviceId[] = "153000110A001998AB7130E38B7E9A401CFE9F7B7918";
constexpr char kRotatingDeviceId[] = "0A00D00561E77A68A9FD975057375B9283A8";
constexpr char kShortRotatingDeviceId[] = "0A001998AB7130E38B7E9A401CFE9F7B79";
constexpr uint16_t kAdditionalDataPayloadLength = 51;
#if CHIP_ENABLE_ROTATING_DEVICE_ID
constexpr uint8_t kUniqueId[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
constexpr char kAdditionalDataPayloadWithRotatingDeviceIdAndMaxLifetimeCounter[] = "15300012FFFF8BEA0C775F001981365D6362E1C0665A18";
constexpr uint16_t kLifetimeCounter = 10;
constexpr uint16_t kShortRotatingIdLength = 5;
#endif // CHIP_ENABLE_ROTATING_DEVICE_ID
CHIP_ERROR GenerateAdditionalDataPayload(nlTestSuite * inSuite, AdditionalDataPayloadGeneratorParams & additionalDataPayloadParams,
BitFlags<AdditionalDataFields> additionalDataFields, char * additionalDataPayloadOutput)
{
CHIP_ERROR err = CHIP_NO_ERROR;
chip::System::PacketBufferHandle bufferHandle;
err = AdditionalDataPayloadGenerator().generateAdditionalDataPayload(additionalDataPayloadParams, bufferHandle,
additionalDataFields);
if (err == CHIP_NO_ERROR)
{
NL_TEST_ASSERT(inSuite, !bufferHandle.IsNull());
}
else
{
return err;
}
char output[kAdditionalDataPayloadLength];
err = chip::Encoding::BytesToUppercaseHexString(bufferHandle->Start(), bufferHandle->DataLength(), output, ArraySize(output));
if (err == CHIP_NO_ERROR)
{
memmove(additionalDataPayloadOutput, output, kAdditionalDataPayloadLength);
}
return err;
}
CHIP_ERROR ParseAdditionalDataPayload(const char * additionalDataPayload, size_t additionalDataPayloadLength,
chip::SetupPayloadData::AdditionalDataPayload & outPayload)
{
if (additionalDataPayloadLength % 2 != 0)
{
return CHIP_ERROR_INVALID_STRING_LENGTH;
}
size_t additionalDataPayloadBytesLength = additionalDataPayloadLength / 2;
std::unique_ptr<uint8_t[]> additionalDataPayloadBytes(new uint8_t[additionalDataPayloadBytesLength]);
size_t bufferSize = chip::Encoding::HexToBytes(additionalDataPayload, additionalDataPayloadLength,
additionalDataPayloadBytes.get(), additionalDataPayloadBytesLength);
return AdditionalDataPayloadParser(additionalDataPayloadBytes.get(), bufferSize).populatePayload(outPayload);
}
void TestGeneratingAdditionalDataPayloadWithoutRotatingDeviceId(nlTestSuite * inSuite, void * inContext)
{
BitFlags<AdditionalDataFields> additionalDataFields;
char output[kAdditionalDataPayloadLength];
AdditionalDataPayloadGeneratorParams additionalDataPayloadParams;
NL_TEST_ASSERT(inSuite,
GenerateAdditionalDataPayload(inSuite, additionalDataPayloadParams, additionalDataFields, output) ==
CHIP_NO_ERROR);
NL_TEST_ASSERT(inSuite, strcmp(output, kAdditionalDataPayloadWithoutRotatingDeviceId) == 0);
}
#if CHIP_ENABLE_ROTATING_DEVICE_ID
void TestGeneratingAdditionalDataPayloadWithRotatingDeviceId(nlTestSuite * inSuite, void * inContext)
{
BitFlags<AdditionalDataFields> additionalDataFields;
additionalDataFields.Set(AdditionalDataFields::RotatingDeviceId);
AdditionalDataPayloadGeneratorParams additionalDataPayloadParams;
additionalDataPayloadParams.rotatingDeviceIdLifetimeCounter = kLifetimeCounter;
additionalDataPayloadParams.rotatingDeviceIdUniqueId = ByteSpan{ kUniqueId, sizeof(kUniqueId) };
char output[kAdditionalDataPayloadLength];
NL_TEST_ASSERT(inSuite,
GenerateAdditionalDataPayload(inSuite, additionalDataPayloadParams, additionalDataFields, output) ==
CHIP_NO_ERROR);
NL_TEST_ASSERT(inSuite, strcmp(output, kAdditionalDataPayloadWithRotatingDeviceId) == 0);
}
void TestGeneratingAdditionalDataPayloadWithRotatingDeviceIdAndMaxLifetimeCounter(nlTestSuite * inSuite, void * inContext)
{
BitFlags<AdditionalDataFields> additionalDataFields;
additionalDataFields.Set(AdditionalDataFields::RotatingDeviceId);
AdditionalDataPayloadGeneratorParams additionalDataPayloadParams;
additionalDataPayloadParams.rotatingDeviceIdLifetimeCounter = std::numeric_limits<uint16_t>::max();
additionalDataPayloadParams.rotatingDeviceIdUniqueId = ByteSpan{ kUniqueId, sizeof(kUniqueId) };
char output[kAdditionalDataPayloadLength];
NL_TEST_ASSERT(inSuite,
GenerateAdditionalDataPayload(inSuite, additionalDataPayloadParams, additionalDataFields, output) ==
CHIP_NO_ERROR);
NL_TEST_ASSERT(inSuite, strcmp(output, kAdditionalDataPayloadWithRotatingDeviceIdAndMaxLifetimeCounter) == 0);
}
void TestGeneratingAdditionalDataPayloadWithRotatingDeviceIdWithNullInputs(nlTestSuite * inSuite, void * inContext)
{
BitFlags<AdditionalDataFields> additionalDataFields;
additionalDataFields.Set(AdditionalDataFields::RotatingDeviceId);
AdditionalDataPayloadGeneratorParams additionalDataPayloadParams;
char output[kAdditionalDataPayloadLength];
NL_TEST_ASSERT(inSuite,
GenerateAdditionalDataPayload(inSuite, additionalDataPayloadParams, additionalDataFields, output) ==
CHIP_ERROR_INVALID_ARGUMENT);
}
void TestGeneratingRotatingDeviceIdAsString(nlTestSuite * inSuite, void * inContext)
{
CHIP_ERROR err = CHIP_NO_ERROR;
char rotatingDeviceIdHexBuffer[RotatingDeviceId::kHexMaxLength];
size_t rotatingDeviceIdValueOutputSize = 0;
AdditionalDataPayloadGeneratorParams additionalDataPayloadParams;
additionalDataPayloadParams.rotatingDeviceIdLifetimeCounter = kLifetimeCounter;
additionalDataPayloadParams.rotatingDeviceIdUniqueId = ByteSpan{ kUniqueId, sizeof(kUniqueId) };
err = AdditionalDataPayloadGenerator().generateRotatingDeviceIdAsHexString(
additionalDataPayloadParams, rotatingDeviceIdHexBuffer, ArraySize(rotatingDeviceIdHexBuffer),
rotatingDeviceIdValueOutputSize);
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
NL_TEST_ASSERT(inSuite, strcmp(rotatingDeviceIdHexBuffer, kRotatingDeviceId) == 0);
// Parsing out the lifetime counter value
long lifetimeCounter;
char lifetimeCounterStr[3];
Platform::CopyString(lifetimeCounterStr, rotatingDeviceIdHexBuffer);
char * parseEnd;
lifetimeCounter = strtol(lifetimeCounterStr, &parseEnd, 16);
NL_TEST_ASSERT(inSuite, lifetimeCounter == kLifetimeCounter);
}
void TestGeneratingRotatingDeviceIdAsStringWithNullInputs(nlTestSuite * inSuite, void * inContext)
{
CHIP_ERROR err = CHIP_NO_ERROR;
char rotatingDeviceIdHexBuffer[RotatingDeviceId::kHexMaxLength];
size_t rotatingDeviceIdValueOutputSize = 0;
AdditionalDataPayloadGeneratorParams additionalDataPayloadParams;
additionalDataPayloadParams.rotatingDeviceIdLifetimeCounter = 0;
additionalDataPayloadParams.rotatingDeviceIdUniqueId = MutableByteSpan{ nullptr, sizeof(kUniqueId) };
err = AdditionalDataPayloadGenerator().generateRotatingDeviceIdAsHexString(
additionalDataPayloadParams, rotatingDeviceIdHexBuffer, ArraySize(rotatingDeviceIdHexBuffer),
rotatingDeviceIdValueOutputSize);
NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_INVALID_ARGUMENT);
}
void TestGeneratingRotatingDeviceIdWithSmallBuffer(nlTestSuite * inSuite, void * inContext)
{
CHIP_ERROR err = CHIP_NO_ERROR;
char rotatingDeviceIdHexBuffer[kShortRotatingIdLength];
size_t rotatingDeviceIdValueOutputSize = 0;
AdditionalDataPayloadGeneratorParams additionalDataPayloadParams;
additionalDataPayloadParams.rotatingDeviceIdLifetimeCounter = kLifetimeCounter;
additionalDataPayloadParams.rotatingDeviceIdUniqueId = ByteSpan{ kUniqueId, sizeof(kUniqueId) };
err = AdditionalDataPayloadGenerator().generateRotatingDeviceIdAsHexString(
additionalDataPayloadParams, rotatingDeviceIdHexBuffer, ArraySize(rotatingDeviceIdHexBuffer),
rotatingDeviceIdValueOutputSize);
NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_BUFFER_TOO_SMALL);
}
#endif // CHIP_ENABLE_ROTATING_DEVICE_ID
void TestParsingAdditionalDataPayloadWithRotatingDeviceId(nlTestSuite * inSuite, void * inContext)
{
chip::SetupPayloadData::AdditionalDataPayload resultPayload;
NL_TEST_ASSERT(inSuite,
ParseAdditionalDataPayload(kAdditionalDataPayloadWithRotatingDeviceId,
strlen(kAdditionalDataPayloadWithRotatingDeviceId), resultPayload) == CHIP_NO_ERROR);
NL_TEST_ASSERT(inSuite, strcmp(resultPayload.rotatingDeviceId.c_str(), kRotatingDeviceId) == 0);
}
void TestParsingAdditionalDataPayloadWithoutRotatingDeviceId(nlTestSuite * inSuite, void * inContext)
{
chip::SetupPayloadData::AdditionalDataPayload resultPayload;
NL_TEST_ASSERT(inSuite,
ParseAdditionalDataPayload(kAdditionalDataPayloadWithoutRotatingDeviceId,
strlen(kAdditionalDataPayloadWithoutRotatingDeviceId),
resultPayload) == CHIP_NO_ERROR);
NL_TEST_ASSERT(inSuite, strcmp(resultPayload.rotatingDeviceId.c_str(), "") == 0);
}
void TestParsingAdditionalDataPayloadWithInvalidRotatingDeviceIdLength(nlTestSuite * inSuite, void * inContext)
{
chip::SetupPayloadData::AdditionalDataPayload resultPayload;
NL_TEST_ASSERT(inSuite,
ParseAdditionalDataPayload(kAdditionalDataPayloadWithInvalidRotatingDeviceIdLength,
strlen(kAdditionalDataPayloadWithInvalidRotatingDeviceIdLength),
resultPayload) == CHIP_ERROR_TLV_UNDERRUN);
}
void TestParsingAdditionalDataPayloadWithLongRotatingDeviceId(nlTestSuite * inSuite, void * inContext)
{
chip::SetupPayloadData::AdditionalDataPayload resultPayload;
NL_TEST_ASSERT(inSuite,
ParseAdditionalDataPayload(kAdditionalDataPayloadWithLongRotatingDeviceId,
strlen(kAdditionalDataPayloadWithLongRotatingDeviceId),
resultPayload) == CHIP_ERROR_INVALID_STRING_LENGTH);
}
void TestParsingAdditionalDataPayloadWithShortRotatingDeviceId(nlTestSuite * inSuite, void * inContext)
{
chip::SetupPayloadData::AdditionalDataPayload resultPayload;
NL_TEST_ASSERT(inSuite,
ParseAdditionalDataPayload(kAdditionalDataPayloadWithShortRotatingDeviceId,
strlen(kAdditionalDataPayloadWithShortRotatingDeviceId),
resultPayload) == CHIP_NO_ERROR);
NL_TEST_ASSERT(inSuite, strcmp(resultPayload.rotatingDeviceId.c_str(), kShortRotatingDeviceId) == 0);
}
/**
* Test Suite that lists all the Test functions.
*/
// clang-format off
const nlTest sTests[] =
{
NL_TEST_DEF("Test Generating Additional Data Payload without Rotatin gDevice Id", TestGeneratingAdditionalDataPayloadWithoutRotatingDeviceId),
#if CHIP_ENABLE_ROTATING_DEVICE_ID
NL_TEST_DEF("Test Generating Additional Data Payload with Rotating Device Id", TestGeneratingAdditionalDataPayloadWithRotatingDeviceId),
NL_TEST_DEF("Test Generating Additional Data Payload with Rotating Device Id + Max Lifetime Counter", TestGeneratingAdditionalDataPayloadWithRotatingDeviceIdAndMaxLifetimeCounter),
NL_TEST_DEF("Test Generating Additional Data Payload with Rotating Device Id + Null/Empty Inputs", TestGeneratingAdditionalDataPayloadWithRotatingDeviceIdWithNullInputs),
NL_TEST_DEF("Test Generating Rotating Device Id as string", TestGeneratingRotatingDeviceIdAsString),
NL_TEST_DEF("Test Generating Rotating Device Id as string with null/invalid inputs", TestGeneratingRotatingDeviceIdAsStringWithNullInputs),
NL_TEST_DEF("Test Generating Rotating Device Id as string with small buffer", TestGeneratingRotatingDeviceIdWithSmallBuffer),
#endif
NL_TEST_DEF("Test Parsing Additional Data Payload with Rotating Device Id", TestParsingAdditionalDataPayloadWithRotatingDeviceId),
NL_TEST_DEF("Test Parsing Additional Data Payload without Rotating Device Id", TestParsingAdditionalDataPayloadWithoutRotatingDeviceId),
NL_TEST_DEF("Test Parsing Additional Data Payload with Invalid Rotating Device Id Length", TestParsingAdditionalDataPayloadWithInvalidRotatingDeviceIdLength),
NL_TEST_DEF("Test Parsing Additional Data Payload with Long Rotating Device Id", TestParsingAdditionalDataPayloadWithLongRotatingDeviceId),
NL_TEST_DEF("Test Parsing Additional Data Payload with Short Rotating Device Id", TestParsingAdditionalDataPayloadWithShortRotatingDeviceId),
NL_TEST_SENTINEL()
};
// clang-format on
} // namespace
/**
* Set up the test suite.
*/
int TestAdditionalDataPayload_Setup(void * inContext)
{
CHIP_ERROR error = chip::Platform::MemoryInit();
if (error != CHIP_NO_ERROR)
return FAILURE;
return SUCCESS;
}
/**
* Tear down the test suite.
*/
int TestAdditionalDataPayload_Teardown(void * inContext)
{
chip::Platform::MemoryShutdown();
return SUCCESS;
}
/**
* Main
*/
int TestAdditionalDataPayload()
{
// clang-format off
nlTestSuite theSuite =
{
"chip-additional-data-payload-general-Tests",
&sTests[0],
TestAdditionalDataPayload_Setup,
TestAdditionalDataPayload_Teardown
};
// clang-format on
// Generate machine-readable, comma-separated value (CSV) output.
nl_test_set_output_style(OUTPUT_CSV);
return chip::ExecuteTestsWithoutContext(&theSuite);
}
CHIP_REGISTER_TEST_SUITE(TestAdditionalDataPayload);