mirror of
https://github.com/espressif/openthread.git
synced 2026-08-06 18:57:47 +00:00
[test] add fake platform (#10594)
This commit adds a fake platform for unit/component tests. This platform uses virtual time so it should be able to run fast. Note that the fake platforms leverage C++ virtual methods to allow mocking. This commit verifies setting active dataset triggers the active dataset change event by the notifier.
This commit is contained in:
@@ -12,6 +12,7 @@ aparent
|
||||
apending
|
||||
asender
|
||||
asent
|
||||
atleast
|
||||
ect
|
||||
intialize
|
||||
nd
|
||||
|
||||
@@ -79,11 +79,11 @@ jobs:
|
||||
sudo rm /etc/apt/sources.list.d/* && sudo apt-get update
|
||||
sudo apt-get --no-install-recommends install -y ninja-build lcov
|
||||
- name: Build Simulation
|
||||
run: ./script/cmake-build simulation -DOT_BORDER_ROUTING=ON -DOT_NCP_INFRA_IF=ON
|
||||
run: ./script/cmake-build simulation -DOT_BUILD_GTEST=ON -DOT_BORDER_ROUTING=ON -DOT_NCP_INFRA_IF=ON
|
||||
- name: Test Simulation
|
||||
run: cd build/simulation && ninja test
|
||||
- name: Build Multipan Simulation
|
||||
run: ./script/cmake-build simulation -DOT_MULTIPAN_TEST=ON
|
||||
run: ./script/cmake-build simulation -DOT_BUILD_GTEST=ON -DOT_MULTIPAN_TEST=ON
|
||||
- name: Test Multipan Simulation
|
||||
run: cd build/simulation && ninja test
|
||||
- name: Build POSIX
|
||||
|
||||
@@ -104,6 +104,7 @@ target_link_libraries(openthread-radio-spinel
|
||||
INTERFACE
|
||||
ot-lib-config
|
||||
PRIVATE
|
||||
openthread-platform
|
||||
ot-config
|
||||
)
|
||||
|
||||
|
||||
@@ -26,8 +26,13 @@
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
option(OT_BUILD_GTEST "enable gtest")
|
||||
|
||||
if(OT_FTD AND BUILD_TESTING)
|
||||
add_subdirectory(unit)
|
||||
if(OT_BUILD_GTEST)
|
||||
add_subdirectory(gtest)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
option(OT_FUZZ_TARGETS "enable fuzz targets" OFF)
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
#
|
||||
# Copyright (c) 2024, The OpenThread Authors.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. Neither the name of the copyright holder nor the
|
||||
# names of its contributors may be used to endorse or promote products
|
||||
# derived from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
project(openthread-gtest)
|
||||
|
||||
# GoogleTest requires at least C++14
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
googletest
|
||||
URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip
|
||||
)
|
||||
# For Windows: Prevent overriding the parent project's compiler/linker settings
|
||||
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||
FetchContent_MakeAvailable(googletest)
|
||||
|
||||
include(GoogleTest)
|
||||
|
||||
add_library(ot-fake-platform
|
||||
fake_platform.cpp
|
||||
)
|
||||
target_link_libraries(ot-fake-platform
|
||||
ot-config
|
||||
)
|
||||
|
||||
add_library(ot-fake-ftd INTERFACE)
|
||||
target_link_libraries(ot-fake-ftd INTERFACE
|
||||
openthread-ftd
|
||||
ot-fake-platform
|
||||
)
|
||||
|
||||
add_executable(ot-ftd-gtest
|
||||
dataset_test.cpp
|
||||
)
|
||||
target_link_libraries(ot-ftd-gtest
|
||||
ot-fake-ftd
|
||||
GTest::gmock_main
|
||||
)
|
||||
gtest_discover_tests(ot-ftd-gtest)
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (c) 2024, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <openthread/border_agent.h>
|
||||
#include <openthread/dataset.h>
|
||||
#include <openthread/dataset_ftd.h>
|
||||
#include <openthread/instance.h>
|
||||
#include <openthread/ip6.h>
|
||||
#include <openthread/thread.h>
|
||||
#include <openthread/platform/time.h>
|
||||
#include "gmock/gmock.h"
|
||||
|
||||
#include "fake_platform.hpp"
|
||||
|
||||
using namespace ot;
|
||||
using ::testing::AnyNumber;
|
||||
using ::testing::AtLeast;
|
||||
using ::testing::MockFunction;
|
||||
using ::testing::Truly;
|
||||
|
||||
template <typename R, typename... A> class MockCallback : public testing::MockFunction<R(A...)>
|
||||
{
|
||||
public:
|
||||
static R CallWithContext(A... aArgs, void *aContext)
|
||||
{
|
||||
return static_cast<MockCallback *>(aContext)->Call(aArgs...);
|
||||
};
|
||||
};
|
||||
|
||||
TEST(otDatasetSetActiveTlvs, shouldTriggerStateCallbackOnSuccess)
|
||||
{
|
||||
FakePlatform fakePlatform;
|
||||
|
||||
typedef MockCallback<void, otChangedFlags> MockStateCallback;
|
||||
|
||||
MockStateCallback mockStateCallback;
|
||||
|
||||
EXPECT_CALL(mockStateCallback, Call).Times(AnyNumber());
|
||||
|
||||
EXPECT_CALL(mockStateCallback, Call(Truly([](otChangedFlags aChangedFlags) -> bool {
|
||||
return (aChangedFlags & OT_CHANGED_ACTIVE_DATASET);
|
||||
})))
|
||||
.Times(AtLeast(1));
|
||||
|
||||
otError error = otSetStateChangedCallback(FakePlatform::CurrentInstance(), MockStateCallback::CallWithContext,
|
||||
&mockStateCallback);
|
||||
assert(error == OT_ERROR_NONE);
|
||||
|
||||
otOperationalDataset dataset;
|
||||
otOperationalDatasetTlvs datasetTlvs;
|
||||
|
||||
error = otDatasetCreateNewNetwork(FakePlatform::CurrentInstance(), &dataset);
|
||||
assert(error == OT_ERROR_NONE);
|
||||
|
||||
otDatasetConvertToTlvs(&dataset, &datasetTlvs);
|
||||
error = otDatasetSetActiveTlvs(FakePlatform::CurrentInstance(), &datasetTlvs);
|
||||
assert(error == OT_ERROR_NONE);
|
||||
|
||||
fakePlatform.GoInMs(10000);
|
||||
}
|
||||
@@ -0,0 +1,509 @@
|
||||
/*
|
||||
* Copyright (c) 2024, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "fake_platform.hpp"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <openthread/instance.h>
|
||||
#include <openthread/tasklet.h>
|
||||
#include <openthread/tcat.h>
|
||||
#include <openthread/platform/alarm-micro.h>
|
||||
#include <openthread/platform/alarm-milli.h>
|
||||
#include <openthread/platform/ble.h>
|
||||
#include <openthread/platform/diag.h>
|
||||
#include <openthread/platform/dso_transport.h>
|
||||
#include <openthread/platform/entropy.h>
|
||||
#include <openthread/platform/logging.h>
|
||||
#include <openthread/platform/misc.h>
|
||||
#include <openthread/platform/toolchain.h>
|
||||
#include "openthread/error.h"
|
||||
|
||||
using namespace ot;
|
||||
|
||||
namespace ot {
|
||||
|
||||
FakePlatform *FakePlatform::sPlatform = nullptr;
|
||||
|
||||
FakePlatform::FakePlatform()
|
||||
{
|
||||
assert(sPlatform == nullptr);
|
||||
sPlatform = this;
|
||||
|
||||
mTransmitFrame.mPsdu = mTransmitBuffer;
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTIPLE_INSTANCE_ENABLE
|
||||
#if OPENTHREAD_CONFIG_MULTIPLE_STATIC_INSTANCE_ENABLE
|
||||
mInstance = otInstanceInitMultiple(0);
|
||||
#else
|
||||
{
|
||||
size_t instanceBufferLength = 0;
|
||||
void *instanceBuffer = nullptr;
|
||||
|
||||
otInstanceInit(nullptr, &instanceBufferLength);
|
||||
|
||||
instanceBuffer = malloc(instanceBufferLength);
|
||||
assert(instanceBuffer != nullptr);
|
||||
memset(instanceBuffer, 0, instanceBufferLength);
|
||||
|
||||
mInstance = otInstanceInit(instanceBuffer, &instanceBufferLength);
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
mInstance = otInstanceInitSingle();
|
||||
#endif
|
||||
}
|
||||
|
||||
FakePlatform::~FakePlatform()
|
||||
{
|
||||
otInstanceFinalize(mInstance);
|
||||
sPlatform = nullptr;
|
||||
}
|
||||
|
||||
void FakePlatform::StartMicroAlarm(uint32_t aT0, uint32_t aDt)
|
||||
{
|
||||
uint64_t start = mNow;
|
||||
uint32_t now = mNow;
|
||||
|
||||
if (static_cast<int32_t>(aT0 - now) > 0 || static_cast<int32_t>(aT0 - now) + static_cast<int64_t>(aDt) > 0)
|
||||
{
|
||||
start += static_cast<uint64_t>(aDt) + static_cast<int32_t>(aT0 - now);
|
||||
}
|
||||
|
||||
mMicroAlarmStart = start;
|
||||
}
|
||||
void FakePlatform::StartMilliAlarm(uint32_t aT0, uint32_t aDt)
|
||||
{
|
||||
uint64_t start = mNow - (mNow % OT_US_PER_MS);
|
||||
uint32_t now = (mNow / OT_US_PER_MS);
|
||||
|
||||
if (static_cast<int32_t>(aT0 - now) > 0 || static_cast<int32_t>(aT0 - now) + static_cast<int64_t>(aDt) > 0)
|
||||
{
|
||||
start += (static_cast<uint64_t>(aDt) + static_cast<int32_t>(aT0 - now)) * OT_US_PER_MS;
|
||||
}
|
||||
|
||||
mMilliAlarmStart = start;
|
||||
}
|
||||
|
||||
void FakePlatform::StopMicroAlarm() { mMicroAlarmStart = kAlarmStop; }
|
||||
|
||||
void FakePlatform::StopMilliAlarm() { mMilliAlarmStart = kAlarmStop; }
|
||||
|
||||
void FakePlatform::ProcessAlarm(uint64_t &aTimeout)
|
||||
{
|
||||
uint64_t end = mNow + aTimeout;
|
||||
|
||||
uint64_t *alarm = &end;
|
||||
|
||||
if (mMicroAlarmStart < *alarm)
|
||||
{
|
||||
alarm = &mMicroAlarmStart;
|
||||
}
|
||||
|
||||
if (mMilliAlarmStart < *alarm)
|
||||
{
|
||||
alarm = &mMilliAlarmStart;
|
||||
}
|
||||
|
||||
if (mNow < *alarm)
|
||||
{
|
||||
aTimeout -= *alarm - mNow;
|
||||
mNow = *alarm;
|
||||
}
|
||||
*alarm = kAlarmStop;
|
||||
|
||||
if (alarm == &mMicroAlarmStart)
|
||||
{
|
||||
otPlatAlarmMicroFired(mInstance);
|
||||
}
|
||||
else if (alarm == &mMilliAlarmStart)
|
||||
{
|
||||
otPlatAlarmMilliFired(mInstance);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t FakePlatform::Run(uint64_t aTimeoutInUs)
|
||||
{
|
||||
if (otTaskletsArePending(mInstance))
|
||||
{
|
||||
otTaskletsProcess(mInstance);
|
||||
}
|
||||
else
|
||||
{
|
||||
ProcessAlarm(aTimeoutInUs);
|
||||
}
|
||||
|
||||
return aTimeoutInUs;
|
||||
}
|
||||
|
||||
void FakePlatform::GoInUs(uint64_t aTimeoutInUs)
|
||||
{
|
||||
while ((aTimeoutInUs = Run(aTimeoutInUs)) > 0)
|
||||
{
|
||||
// nothing
|
||||
}
|
||||
}
|
||||
|
||||
otError FakePlatform::Transmit(otRadioFrame *aFrame)
|
||||
{
|
||||
otPlatRadioTxStarted(mInstance, aFrame);
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
otError FakePlatform::SettingsGet(uint16_t aKey, uint16_t aIndex, uint8_t *aValue, uint16_t *aValueLength) const
|
||||
{
|
||||
auto setting = mSettings.find(aKey);
|
||||
|
||||
if (setting == mSettings.end())
|
||||
{
|
||||
return OT_ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (aIndex > setting->second.size())
|
||||
{
|
||||
return OT_ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (aValueLength == nullptr)
|
||||
{
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
const auto &data = setting->second[aIndex];
|
||||
|
||||
if (aValue == nullptr)
|
||||
{
|
||||
*aValueLength = data.size();
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
if (*aValueLength >= data.size())
|
||||
{
|
||||
*aValueLength = data.size();
|
||||
}
|
||||
|
||||
memcpy(aValue, &data[0], *aValueLength);
|
||||
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
otError FakePlatform::SettingsSet(uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength)
|
||||
{
|
||||
auto setting = std::vector<uint8_t>(aValue, aValue + aValueLength);
|
||||
|
||||
mSettings[aKey].clear();
|
||||
mSettings[aKey].push_back(setting);
|
||||
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
otError FakePlatform::SettingsAdd(uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength)
|
||||
{
|
||||
auto setting = std::vector<uint8_t>(aValue, aValue + aValueLength);
|
||||
|
||||
mSettings[aKey].push_back(setting);
|
||||
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
otError FakePlatform::SettingsDelete(uint16_t aKey, int aIndex)
|
||||
{
|
||||
auto setting = mSettings.find(aKey);
|
||||
if (setting == mSettings.end())
|
||||
{
|
||||
return OT_ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (aIndex >= setting->second.size())
|
||||
{
|
||||
return OT_ERROR_NOT_FOUND;
|
||||
}
|
||||
setting->second.erase(setting->second.begin() + aIndex);
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
void FakePlatform::SettingsWipe() { mSettings.clear(); }
|
||||
|
||||
void FakePlatform::FlashInit() { memset(mFlash, 0xff, sizeof(mFlash)); }
|
||||
void FakePlatform::FlashErase(uint8_t aSwapIndex)
|
||||
{
|
||||
uint32_t address;
|
||||
|
||||
assert(aSwapIndex < kFlashSwapNum);
|
||||
|
||||
address = aSwapIndex ? kFlashSwapSize : 0;
|
||||
|
||||
memset(mFlash + address, 0xff, kFlashSwapSize);
|
||||
}
|
||||
|
||||
void FakePlatform::FlashRead(uint8_t aSwapIndex, uint32_t aOffset, void *aData, uint32_t aSize) const
|
||||
{
|
||||
uint32_t address;
|
||||
|
||||
assert(aSwapIndex < kFlashSwapNum);
|
||||
assert(aSize <= kFlashSwapSize);
|
||||
assert(aOffset <= (kFlashSwapSize - aSize));
|
||||
|
||||
address = aSwapIndex ? kFlashSwapSize : 0;
|
||||
|
||||
memcpy(aData, mFlash + address + aOffset, aSize);
|
||||
}
|
||||
|
||||
void FakePlatform::FlashWrite(uint8_t aSwapIndex, uint32_t aOffset, const void *aData, uint32_t aSize)
|
||||
{
|
||||
uint32_t address;
|
||||
|
||||
assert(aSwapIndex < kFlashSwapNum);
|
||||
assert(aSize <= kFlashSwapSize);
|
||||
assert(aOffset <= (kFlashSwapSize - aSize));
|
||||
|
||||
address = aSwapIndex ? kFlashSwapSize : 0;
|
||||
|
||||
for (uint32_t index = 0; index < aSize; index++)
|
||||
{
|
||||
mFlash[address + aOffset + index] &= static_cast<const uint8_t *>(aData)[index];
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ot
|
||||
|
||||
extern "C" {
|
||||
|
||||
void otTaskletsSignalPending(otInstance *) {}
|
||||
|
||||
void otPlatAlarmMilliStop(otInstance *) { FakePlatform::CurrentPlatform().StopMilliAlarm(); }
|
||||
|
||||
void otPlatAlarmMilliStartAt(otInstance *, uint32_t aT0, uint32_t aDt)
|
||||
{
|
||||
FakePlatform::CurrentPlatform().StartMilliAlarm(aT0, aDt);
|
||||
}
|
||||
|
||||
uint32_t otPlatAlarmMilliGetNow(void) { return FakePlatform::CurrentPlatform().GetNow() / OT_US_PER_MS; }
|
||||
void otPlatAlarmMicroStop(otInstance *) { FakePlatform::CurrentPlatform().StopMicroAlarm(); }
|
||||
|
||||
void otPlatAlarmMicroStartAt(otInstance *, uint32_t aT0, uint32_t aDt)
|
||||
{
|
||||
FakePlatform::CurrentPlatform().StartMicroAlarm(aT0, aDt);
|
||||
}
|
||||
|
||||
uint64_t otPlatTimeGet(void) { return FakePlatform::CurrentPlatform().GetNow(); }
|
||||
uint16_t otPlatTimeGetXtalAccuracy(void) { return 0; }
|
||||
|
||||
uint32_t otPlatAlarmMicroGetNow(void) { return otPlatTimeGet(); }
|
||||
|
||||
void otPlatRadioGetIeeeEui64(otInstance *, uint8_t *aIeeeEui64)
|
||||
{
|
||||
uint64_t eui64 = FakePlatform::CurrentPlatform().GetEui64();
|
||||
memcpy(aIeeeEui64, &eui64, sizeof(eui64));
|
||||
}
|
||||
|
||||
void otPlatRadioSetPanId(otInstance *, uint16_t) {}
|
||||
|
||||
void otPlatRadioSetExtendedAddress(otInstance *, const otExtAddress *) {}
|
||||
|
||||
void otPlatRadioSetShortAddress(otInstance *, uint16_t) {}
|
||||
|
||||
void otPlatRadioSetPromiscuous(otInstance *, bool) {}
|
||||
|
||||
void otPlatRadioSetRxOnWhenIdle(otInstance *, bool) {}
|
||||
|
||||
bool otPlatRadioIsEnabled(otInstance *) { return true; }
|
||||
|
||||
otError otPlatRadioEnable(otInstance *) { return OT_ERROR_NONE; }
|
||||
|
||||
otError otPlatRadioDisable(otInstance *) { return OT_ERROR_NONE; }
|
||||
|
||||
otError otPlatRadioSleep(otInstance *) { return OT_ERROR_NONE; }
|
||||
|
||||
otError otPlatRadioReceive(otInstance *, uint8_t) { return OT_ERROR_NONE; }
|
||||
|
||||
otError otPlatRadioTransmit(otInstance *, otRadioFrame *aFrame)
|
||||
{
|
||||
return FakePlatform::CurrentPlatform().Transmit(aFrame);
|
||||
}
|
||||
|
||||
otRadioFrame *otPlatRadioGetTransmitBuffer(otInstance *) { return FakePlatform::CurrentPlatform().GetTransmitBuffer(); }
|
||||
|
||||
int8_t otPlatRadioGetRssi(otInstance *) { return 0; }
|
||||
|
||||
otRadioCaps otPlatRadioGetCaps(otInstance *) { return OT_RADIO_CAPS_NONE; }
|
||||
|
||||
bool otPlatRadioGetPromiscuous(otInstance *) { return false; }
|
||||
|
||||
void otPlatRadioEnableSrcMatch(otInstance *, bool) {}
|
||||
|
||||
otError otPlatRadioAddSrcMatchShortEntry(otInstance *, uint16_t) { return OT_ERROR_NONE; }
|
||||
|
||||
otError otPlatRadioAddSrcMatchExtEntry(otInstance *, const otExtAddress *) { return OT_ERROR_NONE; }
|
||||
|
||||
otError otPlatRadioClearSrcMatchShortEntry(otInstance *, uint16_t) { return OT_ERROR_NONE; }
|
||||
|
||||
otError otPlatRadioClearSrcMatchExtEntry(otInstance *, const otExtAddress *) { return OT_ERROR_NONE; }
|
||||
|
||||
void otPlatRadioClearSrcMatchShortEntries(otInstance *) {}
|
||||
|
||||
void otPlatRadioClearSrcMatchExtEntries(otInstance *) {}
|
||||
|
||||
otError otPlatRadioEnergyScan(otInstance *, uint8_t, uint16_t) { return OT_ERROR_NOT_IMPLEMENTED; }
|
||||
|
||||
otError otPlatRadioSetTransmitPower(otInstance *, int8_t) { return OT_ERROR_NOT_IMPLEMENTED; }
|
||||
|
||||
int8_t otPlatRadioGetReceiveSensitivity(otInstance *) { return -100; }
|
||||
|
||||
otError otPlatRadioSetCcaEnergyDetectThreshold(otInstance *, int8_t) { return OT_ERROR_NONE; }
|
||||
|
||||
otError otPlatRadioGetCcaEnergyDetectThreshold(otInstance *, int8_t *) { return OT_ERROR_NONE; }
|
||||
|
||||
otError otPlatRadioGetCoexMetrics(otInstance *, otRadioCoexMetrics *) { return OT_ERROR_NONE; }
|
||||
|
||||
otError otPlatRadioGetTransmitPower(otInstance *, int8_t *) { return OT_ERROR_NONE; }
|
||||
|
||||
bool otPlatRadioIsCoexEnabled(otInstance *) { return true; }
|
||||
|
||||
otError otPlatRadioSetCoexEnabled(otInstance *, bool) { return OT_ERROR_NOT_IMPLEMENTED; }
|
||||
|
||||
void otPlatReset(otInstance *) {}
|
||||
|
||||
otPlatResetReason otPlatGetResetReason(otInstance *) { return OT_PLAT_RESET_REASON_POWER_ON; }
|
||||
|
||||
void otPlatWakeHost(void) {}
|
||||
|
||||
otError otPlatEntropyGet(uint8_t *aOutput, uint16_t aOutputLength)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
assert(aOutput != nullptr);
|
||||
|
||||
for (uint16_t length = 0; length < aOutputLength; length++)
|
||||
{
|
||||
aOutput[length] = static_cast<uint8_t>(rand());
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void otPlatDiagSetOutputCallback(otInstance *, otPlatDiagOutputCallback, void *) {}
|
||||
|
||||
void otPlatDiagModeSet(bool) {}
|
||||
|
||||
bool otPlatDiagModeGet() { return false; }
|
||||
|
||||
void otPlatDiagChannelSet(uint8_t) {}
|
||||
|
||||
void otPlatDiagTxPowerSet(int8_t) {}
|
||||
|
||||
void otPlatDiagRadioReceived(otInstance *, otRadioFrame *, otError) {}
|
||||
|
||||
void otPlatDiagAlarmCallback(otInstance *) {}
|
||||
|
||||
OT_TOOL_WEAK void otPlatLog(otLogLevel aLevel, otLogRegion aRegion, const char *aFormat, ...) {}
|
||||
|
||||
void *otPlatCAlloc(size_t aNum, size_t aSize) { return calloc(aNum, aSize); }
|
||||
|
||||
void otPlatFree(void *aPtr) { free(aPtr); }
|
||||
|
||||
bool otPlatInfraIfHasAddress(uint32_t, const otIp6Address *) { return false; }
|
||||
|
||||
otError otPlatInfraIfSendIcmp6Nd(uint32_t, const otIp6Address *, const uint8_t *, uint16_t) { return OT_ERROR_FAILED; }
|
||||
|
||||
otError otPlatInfraIfDiscoverNat64Prefix(uint32_t) { return OT_ERROR_FAILED; }
|
||||
|
||||
void otPlatDsoEnableListening(otInstance *aInstance, bool) {}
|
||||
|
||||
void otPlatDsoConnect(otPlatDsoConnection *, const otSockAddr *) {}
|
||||
|
||||
void otPlatDsoSend(otPlatDsoConnection *, otMessage *) {}
|
||||
|
||||
void otPlatDsoDisconnect(otPlatDsoConnection *, otPlatDsoDisconnectMode) {}
|
||||
|
||||
otError otPlatBleEnable(otInstance *) { return OT_ERROR_NONE; }
|
||||
|
||||
otError otPlatBleDisable(otInstance *) { return OT_ERROR_NONE; }
|
||||
|
||||
otError otPlatBleGetAdvertisementBuffer(otInstance *, uint8_t **aAdvertisementBuffer) { return OT_ERROR_NO_BUFS; }
|
||||
|
||||
otError otPlatBleGapAdvStart(otInstance *, uint16_t) { return OT_ERROR_NONE; }
|
||||
|
||||
otError otPlatBleGapAdvStop(otInstance *) { return OT_ERROR_NONE; }
|
||||
|
||||
otError otPlatBleGapDisconnect(otInstance *) { return OT_ERROR_NONE; }
|
||||
|
||||
otError otPlatBleGattMtuGet(otInstance *, uint16_t *) { return OT_ERROR_NONE; }
|
||||
|
||||
otError otPlatBleGattServerIndicate(otInstance *, uint16_t, const otBleRadioPacket *) { return OT_ERROR_NONE; }
|
||||
|
||||
void otPlatBleGetLinkCapabilities(otInstance *, otBleLinkCapabilities *) {}
|
||||
|
||||
bool otPlatBleSupportsMultiRadio(otInstance *) { return false; }
|
||||
|
||||
otError otPlatBleGapAdvSetData(otInstance *, uint8_t *, uint16_t) { return OT_ERROR_NONE; }
|
||||
|
||||
otError otPlatSettingsGet(otInstance *, uint16_t aKey, int aIndex, uint8_t *aValue, uint16_t *aValueLength)
|
||||
{
|
||||
return FakePlatform::CurrentPlatform().SettingsGet(aKey, aIndex, aValue, aValueLength);
|
||||
}
|
||||
|
||||
otError otPlatSettingsSet(otInstance *, uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength)
|
||||
{
|
||||
return FakePlatform::CurrentPlatform().SettingsSet(aKey, aValue, aValueLength);
|
||||
}
|
||||
|
||||
otError otPlatSettingsAdd(otInstance *, uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength)
|
||||
{
|
||||
return FakePlatform::CurrentPlatform().SettingsAdd(aKey, aValue, aValueLength);
|
||||
}
|
||||
|
||||
otError otPlatSettingsDelete(otInstance *, uint16_t aKey, int aIndex)
|
||||
{
|
||||
return FakePlatform::CurrentPlatform().SettingsDelete(aKey, aIndex);
|
||||
}
|
||||
|
||||
void otPlatSettingsWipe(otInstance *) { FakePlatform::CurrentPlatform().SettingsWipe(); }
|
||||
|
||||
void otPlatFlashInit(otInstance *) { return FakePlatform::CurrentPlatform().FlashInit(); }
|
||||
|
||||
uint32_t otPlatFlashGetSwapSize(otInstance *) { return FakePlatform::CurrentPlatform().FlashGetSwapSize(); }
|
||||
|
||||
void otPlatFlashErase(otInstance *, uint8_t aSwapIndex) { FakePlatform::CurrentPlatform().FlashErase(aSwapIndex); }
|
||||
|
||||
void otPlatFlashRead(otInstance *, uint8_t aSwapIndex, uint32_t aOffset, void *aData, uint32_t aSize)
|
||||
{
|
||||
FakePlatform::CurrentPlatform().FlashRead(aSwapIndex, aOffset, aData, aSize);
|
||||
}
|
||||
|
||||
void otPlatFlashWrite(otInstance *, uint8_t aSwapIndex, uint32_t aOffset, const void *aData, uint32_t aSize)
|
||||
{
|
||||
FakePlatform::CurrentPlatform().FlashWrite(aSwapIndex, aOffset, aData, aSize);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (c) 2024, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef OT_GTEST_FAKE_PLATFORM_HPP_
|
||||
#define OT_GTEST_FAKE_PLATFORM_HPP_
|
||||
|
||||
#include <openthread/config.h>
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <openthread/instance.h>
|
||||
#include <openthread/platform/radio.h>
|
||||
#include <openthread/platform/time.h>
|
||||
|
||||
namespace ot {
|
||||
|
||||
class FakePlatform
|
||||
{
|
||||
public:
|
||||
FakePlatform();
|
||||
virtual ~FakePlatform();
|
||||
|
||||
static FakePlatform &CurrentPlatform() { return *sPlatform; }
|
||||
static otInstance *CurrentInstance() { return CurrentPlatform().mInstance; }
|
||||
|
||||
/**
|
||||
* Run until something happened or timeout.
|
||||
*
|
||||
* @param aTimeout The timeout in us.
|
||||
*
|
||||
* @returns the remaining timeout.
|
||||
*/
|
||||
uint64_t Run(uint64_t aTimeoutInUs = 0);
|
||||
|
||||
void GoInUs(uint64_t aTimeoutInUs = 0);
|
||||
|
||||
void GoInMs(uint32_t aTimeoutInMs = 0) { GoInUs(aTimeoutInMs * OT_US_PER_MS); }
|
||||
|
||||
virtual uint64_t GetNow() const { return mNow; }
|
||||
|
||||
virtual void StartMilliAlarm(uint32_t aT0, uint32_t aDt);
|
||||
virtual void StopMilliAlarm();
|
||||
virtual void StartMicroAlarm(uint32_t aT0, uint32_t aDt);
|
||||
virtual void StopMicroAlarm();
|
||||
|
||||
virtual otRadioFrame *GetTransmitBuffer() { return &mTransmitFrame; }
|
||||
virtual otError Transmit(otRadioFrame *aFrame);
|
||||
|
||||
virtual otError SettingsGet(uint16_t aKey, uint16_t aIndex, uint8_t *aValue, uint16_t *aValueLength) const;
|
||||
virtual otError SettingsSet(uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength);
|
||||
virtual otError SettingsAdd(uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength);
|
||||
virtual otError SettingsDelete(uint16_t aKey, int aIndex);
|
||||
virtual void SettingsWipe();
|
||||
|
||||
virtual void FlashInit();
|
||||
virtual void FlashErase(uint8_t aSwapIndex);
|
||||
virtual void FlashRead(uint8_t aSwapIndex, uint32_t aOffset, void *aData, uint32_t aSize) const;
|
||||
virtual void FlashWrite(uint8_t aSwapIndex, uint32_t aOffset, const void *aData, uint32_t aSize);
|
||||
virtual uint32_t FlashGetSwapSize() const { return kFlashSwapSize; }
|
||||
|
||||
virtual uint64_t GetEui64() const { return 0; }
|
||||
|
||||
protected:
|
||||
void ProcessAlarm(uint64_t &aTimeout);
|
||||
|
||||
static constexpr uint64_t kAlarmStop = 0xffffffffffffffffUL;
|
||||
|
||||
static constexpr uint32_t kFlashSwapSize = 2048;
|
||||
static constexpr uint32_t kFlashSwapNum = 2;
|
||||
|
||||
static FakePlatform *sPlatform;
|
||||
|
||||
otInstance *mInstance = nullptr;
|
||||
|
||||
uint64_t mNow = 0;
|
||||
uint64_t mMicroAlarmStart = kAlarmStop;
|
||||
uint64_t mMilliAlarmStart = kAlarmStop;
|
||||
|
||||
otRadioFrame mTransmitFrame;
|
||||
uint8_t mTransmitBuffer[OT_RADIO_FRAME_MAX_SIZE];
|
||||
|
||||
uint8_t mFlash[kFlashSwapSize * kFlashSwapNum];
|
||||
|
||||
std::map<uint32_t, std::vector<std::vector<uint8_t>>> mSettings;
|
||||
};
|
||||
|
||||
} // namespace ot
|
||||
|
||||
#endif // OT_GTEST_FAKE_PLATFORM_HPP_
|
||||
Reference in New Issue
Block a user