blob: c0671994ff96b426c6344c8f88df034cf18b9a8e [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 <stdio.h>
#include <pw_unit_test/framework.h>
#include <lib/core/StringBuilderAdapters.h>
#include <lib/support/BytesToHex.h>
#include <lib/support/CHIPMem.h>
#include <lib/support/CHIPMemString.h>
#include <lib/support/CHIPPlatformMemory.h>
#include <lib/support/verhoeff/Verhoeff.h>
#include <setup_payload/AdditionalDataPayloadGenerator.h>
#include <setup_payload/AdditionalDataPayloadParser.h>
#include <setup_payload/SetupPayload.h>
#include <system/SystemPacketBuffer.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(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)
{
EXPECT_FALSE(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);
}
class TestAdditionalDataPayload : public ::testing::Test
{
public:
static void SetUpTestSuite() { ASSERT_EQ(chip::Platform::MemoryInit(), CHIP_NO_ERROR); }
static void TearDownTestSuite() { chip::Platform::MemoryShutdown(); }
};
TEST_F(TestAdditionalDataPayload, TestGeneratingAdditionalDataPayloadWithoutRotatingDeviceId)
{
BitFlags<AdditionalDataFields> additionalDataFields;
char output[kAdditionalDataPayloadLength];
AdditionalDataPayloadGeneratorParams additionalDataPayloadParams;
EXPECT_EQ(GenerateAdditionalDataPayload(additionalDataPayloadParams, additionalDataFields, output), CHIP_NO_ERROR);
EXPECT_STREQ(output, kAdditionalDataPayloadWithoutRotatingDeviceId);
}
#if CHIP_ENABLE_ROTATING_DEVICE_ID
TEST_F(TestAdditionalDataPayload, TestGeneratingAdditionalDataPayloadWithRotatingDeviceId)
{
BitFlags<AdditionalDataFields> additionalDataFields;
additionalDataFields.Set(AdditionalDataFields::RotatingDeviceId);
AdditionalDataPayloadGeneratorParams additionalDataPayloadParams;
additionalDataPayloadParams.rotatingDeviceIdLifetimeCounter = kLifetimeCounter;
additionalDataPayloadParams.rotatingDeviceIdUniqueId = ByteSpan(kUniqueId);
char output[kAdditionalDataPayloadLength];
EXPECT_EQ(GenerateAdditionalDataPayload(additionalDataPayloadParams, additionalDataFields, output), CHIP_NO_ERROR);
EXPECT_STREQ(output, kAdditionalDataPayloadWithRotatingDeviceId);
}
TEST_F(TestAdditionalDataPayload, TestGeneratingAdditionalDataPayloadWithRotatingDeviceIdAndMaxLifetimeCounter)
{
BitFlags<AdditionalDataFields> additionalDataFields;
additionalDataFields.Set(AdditionalDataFields::RotatingDeviceId);
AdditionalDataPayloadGeneratorParams additionalDataPayloadParams;
additionalDataPayloadParams.rotatingDeviceIdLifetimeCounter = std::numeric_limits<uint16_t>::max();
additionalDataPayloadParams.rotatingDeviceIdUniqueId = ByteSpan(kUniqueId);
char output[kAdditionalDataPayloadLength];
EXPECT_EQ(GenerateAdditionalDataPayload(additionalDataPayloadParams, additionalDataFields, output), CHIP_NO_ERROR);
EXPECT_STREQ(output, kAdditionalDataPayloadWithRotatingDeviceIdAndMaxLifetimeCounter);
}
TEST_F(TestAdditionalDataPayload, TestGeneratingAdditionalDataPayloadWithRotatingDeviceIdWithNullInputs)
{
BitFlags<AdditionalDataFields> additionalDataFields;
additionalDataFields.Set(AdditionalDataFields::RotatingDeviceId);
AdditionalDataPayloadGeneratorParams additionalDataPayloadParams;
char output[kAdditionalDataPayloadLength];
EXPECT_EQ(GenerateAdditionalDataPayload(additionalDataPayloadParams, additionalDataFields, output),
CHIP_ERROR_INVALID_ARGUMENT);
}
TEST_F(TestAdditionalDataPayload, TestGeneratingRotatingDeviceIdAsString)
{
CHIP_ERROR err = CHIP_NO_ERROR;
char rotatingDeviceIdHexBuffer[RotatingDeviceId::kHexMaxLength];
size_t rotatingDeviceIdValueOutputSize = 0;
AdditionalDataPayloadGeneratorParams additionalDataPayloadParams;
additionalDataPayloadParams.rotatingDeviceIdLifetimeCounter = kLifetimeCounter;
additionalDataPayloadParams.rotatingDeviceIdUniqueId = ByteSpan(kUniqueId);
err = AdditionalDataPayloadGenerator().generateRotatingDeviceIdAsHexString(
additionalDataPayloadParams, rotatingDeviceIdHexBuffer, ArraySize(rotatingDeviceIdHexBuffer),
rotatingDeviceIdValueOutputSize);
EXPECT_EQ(err, CHIP_NO_ERROR);
EXPECT_STREQ(rotatingDeviceIdHexBuffer, kRotatingDeviceId);
// Parsing out the lifetime counter value
long lifetimeCounter;
char lifetimeCounterStr[3];
Platform::CopyString(lifetimeCounterStr, rotatingDeviceIdHexBuffer);
char * parseEnd;
lifetimeCounter = strtol(lifetimeCounterStr, &parseEnd, 16);
EXPECT_EQ(lifetimeCounter, kLifetimeCounter);
}
TEST_F(TestAdditionalDataPayload, TestGeneratingRotatingDeviceIdAsStringWithNullInputs)
{
CHIP_ERROR err = CHIP_NO_ERROR;
char rotatingDeviceIdHexBuffer[RotatingDeviceId::kHexMaxLength];
size_t rotatingDeviceIdValueOutputSize = 0;
AdditionalDataPayloadGeneratorParams additionalDataPayloadParams;
additionalDataPayloadParams.rotatingDeviceIdLifetimeCounter = 0;
additionalDataPayloadParams.rotatingDeviceIdUniqueId = ByteSpan();
err = AdditionalDataPayloadGenerator().generateRotatingDeviceIdAsHexString(
additionalDataPayloadParams, rotatingDeviceIdHexBuffer, ArraySize(rotatingDeviceIdHexBuffer),
rotatingDeviceIdValueOutputSize);
EXPECT_EQ(err, CHIP_ERROR_INVALID_ARGUMENT);
}
TEST_F(TestAdditionalDataPayload, TestGeneratingRotatingDeviceIdWithSmallBuffer)
{
CHIP_ERROR err = CHIP_NO_ERROR;
char rotatingDeviceIdHexBuffer[kShortRotatingIdLength];
size_t rotatingDeviceIdValueOutputSize = 0;
AdditionalDataPayloadGeneratorParams additionalDataPayloadParams;
additionalDataPayloadParams.rotatingDeviceIdLifetimeCounter = kLifetimeCounter;
additionalDataPayloadParams.rotatingDeviceIdUniqueId = ByteSpan(kUniqueId);
err = AdditionalDataPayloadGenerator().generateRotatingDeviceIdAsHexString(
additionalDataPayloadParams, rotatingDeviceIdHexBuffer, ArraySize(rotatingDeviceIdHexBuffer),
rotatingDeviceIdValueOutputSize);
EXPECT_EQ(err, CHIP_ERROR_BUFFER_TOO_SMALL);
}
#endif // CHIP_ENABLE_ROTATING_DEVICE_ID
TEST_F(TestAdditionalDataPayload, TestParsingAdditionalDataPayloadWithRotatingDeviceId)
{
chip::SetupPayloadData::AdditionalDataPayload resultPayload;
EXPECT_EQ(ParseAdditionalDataPayload(kAdditionalDataPayloadWithRotatingDeviceId,
strlen(kAdditionalDataPayloadWithRotatingDeviceId), resultPayload),
CHIP_NO_ERROR);
EXPECT_STREQ(resultPayload.rotatingDeviceId.c_str(), kRotatingDeviceId);
}
TEST_F(TestAdditionalDataPayload, TestParsingAdditionalDataPayloadWithoutRotatingDeviceId)
{
chip::SetupPayloadData::AdditionalDataPayload resultPayload;
EXPECT_EQ(ParseAdditionalDataPayload(kAdditionalDataPayloadWithoutRotatingDeviceId,
strlen(kAdditionalDataPayloadWithoutRotatingDeviceId), resultPayload),
CHIP_NO_ERROR);
EXPECT_STREQ(resultPayload.rotatingDeviceId.c_str(), "");
}
TEST_F(TestAdditionalDataPayload, TestParsingAdditionalDataPayloadWithInvalidRotatingDeviceIdLength)
{
chip::SetupPayloadData::AdditionalDataPayload resultPayload;
EXPECT_EQ(ParseAdditionalDataPayload(kAdditionalDataPayloadWithInvalidRotatingDeviceIdLength,
strlen(kAdditionalDataPayloadWithInvalidRotatingDeviceIdLength), resultPayload),
CHIP_ERROR_TLV_UNDERRUN);
}
TEST_F(TestAdditionalDataPayload, TestParsingAdditionalDataPayloadWithLongRotatingDeviceId)
{
chip::SetupPayloadData::AdditionalDataPayload resultPayload;
EXPECT_EQ(ParseAdditionalDataPayload(kAdditionalDataPayloadWithLongRotatingDeviceId,
strlen(kAdditionalDataPayloadWithLongRotatingDeviceId), resultPayload),
CHIP_ERROR_INVALID_STRING_LENGTH);
}
TEST_F(TestAdditionalDataPayload, TestParsingAdditionalDataPayloadWithShortRotatingDeviceId)
{
chip::SetupPayloadData::AdditionalDataPayload resultPayload;
EXPECT_EQ(ParseAdditionalDataPayload(kAdditionalDataPayloadWithShortRotatingDeviceId,
strlen(kAdditionalDataPayloadWithShortRotatingDeviceId), resultPayload),
CHIP_NO_ERROR);
EXPECT_STREQ(resultPayload.rotatingDeviceId.c_str(), kShortRotatingDeviceId);
}
} // namespace