mirror of
https://github.com/espressif/esp-idf
synced 2025-03-09 09:09:10 -04:00
remove(nvs_flash/test_nvs_host): Old make based host tests removed after complete migration
This commit is contained in:
parent
ffdf59a898
commit
6a23790608
@ -34,22 +34,16 @@ check_public_headers:
|
||||
- IDF_TARGET=esp32p4 python tools/ci/check_public_headers.py --jobs 4 --prefix riscv32-esp-elf-
|
||||
- IDF_TARGET=esp32c61 python tools/ci/check_public_headers.py --jobs 4 --prefix riscv32-esp-elf-
|
||||
|
||||
test_nvs_on_host:
|
||||
extends: .host_test_template
|
||||
script:
|
||||
- cd components/nvs_flash/test_nvs_host
|
||||
- make test
|
||||
|
||||
test_nvs_coverage:
|
||||
extends:
|
||||
- .host_test_template
|
||||
- .rules:labels:nvs_coverage
|
||||
artifacts:
|
||||
paths:
|
||||
- components/nvs_flash/test_nvs_host/coverage_report
|
||||
- components/nvs_flash/host_test/nvs_host_test/coverage_report
|
||||
script:
|
||||
- cd components/nvs_flash/test_nvs_host
|
||||
- make coverage_report
|
||||
- cd components/nvs_flash/host_test/nvs_host_test
|
||||
- idf.py build coverage
|
||||
# the 'long' host tests take approx 11 hours on our current runners. Adding some margin here for possible CPU contention
|
||||
timeout: 18 hours
|
||||
|
||||
|
@ -5,4 +5,19 @@ set(COMPONENTS main)
|
||||
# This test app doesn't require FreeRTOS, using mock instead
|
||||
list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/mocks/freertos/")
|
||||
|
||||
idf_build_set_property(COMPILE_DEFINITIONS "NO_DEBUG_STORAGE" APPEND)
|
||||
project(nvs_host_test)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/coverage_report/index.html"
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
COMMAND gcovr --root $ENV{IDF_PATH}/components/nvs_flash --html-details
|
||||
--exclude ${CMAKE_CURRENT_SOURCE_DIR}/managed_components/*
|
||||
-o ${CMAKE_CURRENT_BINARY_DIR}/coverage_report/index.html ${CMAKE_CURRENT_BINARY_DIR}
|
||||
COMMENT "Generate coverage report"
|
||||
)
|
||||
|
||||
add_custom_target(coverage
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
DEPENDS "coverage_report/index.html"
|
||||
)
|
||||
|
@ -1,2 +1,31 @@
|
||||
| Supported Targets | Linux |
|
||||
| ----------------- | ----- |
|
||||
|
||||
# To build
|
||||
Navigate to the host test folder and run the IDF build command for linux target
|
||||
|
||||
```
|
||||
cd $IDF_PATH
|
||||
. ./export.sh
|
||||
cd components/nvs_flash/host_test/nvs_host_test
|
||||
idf.py --preview set-target linux
|
||||
idf.py build
|
||||
```
|
||||
|
||||
# To run tests locally
|
||||
Navigate to the IDF root directory and run the binary from there. This ensures all calls to relative paths from test cases are resolved correctly.
|
||||
This is limitation of ci pipeline as it was not possible to specify the working directory of the host tests.
|
||||
|
||||
```
|
||||
cd $IDF_PATH
|
||||
./components/nvs_flash/host_test/nvs_host_test/build/nvs_host_test.elf
|
||||
```
|
||||
|
||||
# To create coverage report
|
||||
After running the tests, the coverage report can be generated following way.
|
||||
|
||||
```
|
||||
cd components/nvs_flash/host_test/nvs_host_test
|
||||
idf.py build coverage
|
||||
open ./build/coverage_report/index.html
|
||||
```
|
@ -12,6 +12,9 @@ idf_component_register(SRCS "test_nvs.cpp"
|
||||
REQUIRES nvs_flash
|
||||
PRIV_REQUIRES spi_flash)
|
||||
|
||||
target_compile_options(${COMPONENT_LIB} PUBLIC --coverage)
|
||||
target_link_libraries(${COMPONENT_LIB} PUBLIC --coverage)
|
||||
|
||||
if(CMAKE_C_COMPILER_ID MATCHES "Clang")
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE -std=gnu++20)
|
||||
endif()
|
||||
|
@ -3742,7 +3742,7 @@ TEST_CASE("check and read data from partition generated via manufacturing utilit
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("nvs multiple write with same key but different types", "[nvs][xxx]")
|
||||
TEST_CASE("nvs multiple write with same key but different types", "[nvs]")
|
||||
{
|
||||
PartitionEmulationFixture f(0, 10);
|
||||
|
||||
|
@ -1,113 +0,0 @@
|
||||
TEST_PROGRAM=test_nvs
|
||||
all: $(TEST_PROGRAM)
|
||||
|
||||
SOURCE_FILES = \
|
||||
$(addprefix ../src/, \
|
||||
nvs_types.cpp \
|
||||
nvs_api.cpp \
|
||||
nvs_page.cpp \
|
||||
nvs_pagemanager.cpp \
|
||||
nvs_storage.cpp \
|
||||
nvs_item_hash_list.cpp \
|
||||
nvs_handle_simple.cpp \
|
||||
nvs_handle_locked.cpp \
|
||||
nvs_partition_manager.cpp \
|
||||
nvs_partition.cpp \
|
||||
nvs_encrypted_partition.cpp \
|
||||
nvs_cxx_api.cpp \
|
||||
nvs_platform.cpp \
|
||||
) \
|
||||
spi_flash_emulation.cpp \
|
||||
test_compressed_enum_table.cpp \
|
||||
test_spi_flash_emulation.cpp \
|
||||
test_intrusive_list.cpp \
|
||||
test_nvs.cpp \
|
||||
test_nvs_partition.cpp \
|
||||
test_partition_manager.cpp \
|
||||
test_partition_linux.cpp \
|
||||
main.cpp
|
||||
|
||||
SOURCE_FILES_C = ../../esp_rom/linux/esp_rom_crc.c esp_err_check_mock.c
|
||||
|
||||
ifeq ($(shell $(CC) -v 2>&1 | grep -c "clang version"), 1)
|
||||
COMPILER := clang
|
||||
else
|
||||
COMPILER := gcc
|
||||
endif
|
||||
|
||||
CPPFLAGS += -I../private_include -I../include -I../src -I../../heap/include -I../../esp_rom/include -I../../esp_rom/include/linux -I../../esp_rom/linux/include/linux -I../../log/include -I./ -I../../esp_common/include -I../../esp32/include -I ../../mbedtls/mbedtls/include -I ../../spi_flash/include -I ../../esp_partition/include -I ../../hal/include -I ../../xtensa/include -I ../../soc/linux/include -I ../../../tools/catch -fprofile-arcs -ftest-coverage -g2 -ggdb
|
||||
CFLAGS += -fprofile-arcs -ftest-coverage -DLINUX_TARGET -DLINUX_HOST_LEGACY_TEST
|
||||
CXXFLAGS += -std=c++11 -Wall -Werror -DLINUX_TARGET -DLINUX_HOST_LEGACY_TEST
|
||||
LDFLAGS += -lstdc++ -Wall -fprofile-arcs -ftest-coverage
|
||||
|
||||
ifeq ($(shell uname -s),Linux)
|
||||
LDFLAGS += -lbsd
|
||||
endif
|
||||
|
||||
ifeq ($(COMPILER),clang)
|
||||
CFLAGS += -fsanitize=address
|
||||
CXXFLAGS += -fsanitize=address
|
||||
LDFLAGS += -fsanitize=address
|
||||
endif
|
||||
|
||||
OBJ_FILES = $(SOURCE_FILES:.cpp=.o)
|
||||
OBJ_FILES_C = $(SOURCE_FILES_C:.c=.o)
|
||||
|
||||
COVERAGE_FILES = $(OBJ_FILES:.o=.gc*)
|
||||
MBEDTLS_LIB := ../../mbedtls/mbedtls/library/libmbedcrypto.a
|
||||
|
||||
$(OBJ_FILES): %.o: %.cpp
|
||||
$(OBJ_FILES_C): %.c: %.c
|
||||
|
||||
$(MBEDTLS_LIB):
|
||||
$(MAKE) -C ../../mbedtls/mbedtls/ lib
|
||||
|
||||
$(TEST_PROGRAM): $(OBJ_FILES) $(OBJ_FILES_C) $(MBEDTLS_LIB) | clean-coverage
|
||||
g++ -o $@ $^ $(LDFLAGS)
|
||||
|
||||
$(OUTPUT_DIR):
|
||||
mkdir -p $(OUTPUT_DIR)
|
||||
|
||||
test: $(TEST_PROGRAM)
|
||||
./$(TEST_PROGRAM) -d yes exclude:[long]
|
||||
|
||||
long-test: $(TEST_PROGRAM)
|
||||
./$(TEST_PROGRAM) -d yes
|
||||
|
||||
$(COVERAGE_FILES): $(TEST_PROGRAM) long-test
|
||||
|
||||
coverage.info: $(COVERAGE_FILES)
|
||||
find ../src/ -name "*.gcno" -exec gcov -r -pb {} +
|
||||
lcov --capture --directory ../src --no-external --output-file coverage.info
|
||||
|
||||
coverage_report: coverage.info
|
||||
genhtml coverage.info --output-directory coverage_report
|
||||
@echo "Coverage report is in coverage_report/index.html"
|
||||
|
||||
clean-coverage:
|
||||
rm -f $(COVERAGE_FILES) *.gcov
|
||||
rm -rf coverage_report/
|
||||
rm -f coverage.info
|
||||
|
||||
clean: clean-coverage
|
||||
$(MAKE) -C ../../mbedtls/mbedtls/ clean
|
||||
rm -f $(OBJ_FILES) $(OBJ_FILES_C) $(TEST_PROGRAM)
|
||||
rm -f ../nvs_partition_generator/partition_single_page.bin
|
||||
rm -f ../nvs_partition_generator/partition_multipage_blob.bin
|
||||
rm -f ../nvs_partition_generator/partition_encrypted.bin
|
||||
rm -f ../nvs_partition_generator/partition_encrypted_hmac.bin
|
||||
rm -f ../nvs_partition_generator/partition_encrypted_using_keygen.bin
|
||||
rm -f ../nvs_partition_generator/partition_encrypted_using_keyfile.bin
|
||||
rm -f ../nvs_partition_generator/partition_encrypted_using_keygen_hmac.bin
|
||||
rm -f ../nvs_partition_generator/partition_decrypted.bin
|
||||
rm -f ../nvs_partition_generator/partition_decrypted_hmac.bin
|
||||
rm -f ../nvs_partition_generator/partition_encoded.bin
|
||||
rm -f ../nvs_partition_generator/Test-1-partition-encrypted-hmac.bin
|
||||
rm -f ../nvs_partition_generator/Test-1-partition-encrypted.bin
|
||||
rm -f ../nvs_partition_generator/Test-1-partition.bin
|
||||
rm -f ../../../tools/mass_mfg/samples/sample_values_multipage_blob_created.csv
|
||||
rm -f ../../../tools/mass_mfg/samples/sample_values_singlepage_blob_created.csv
|
||||
|
||||
|
||||
|
||||
.PHONY: clean clean-coverage all test long-test
|
@ -1,22 +0,0 @@
|
||||
# Build
|
||||
|
||||
```bash
|
||||
make -j 6
|
||||
```
|
||||
|
||||
# Run
|
||||
* Run particular test case:
|
||||
```bash
|
||||
./test_nvs "<particular test case>"
|
||||
|
||||
```
|
||||
* Run all quick tests:
|
||||
```bash
|
||||
./test_nvs -d yes exclude:[long]
|
||||
```
|
||||
|
||||
* Run all tests (takes several hours)
|
||||
```bash
|
||||
./test_nvs -d yes
|
||||
```
|
||||
|
@ -1,2 +0,0 @@
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#include "catch.hpp"
|
@ -1,6 +0,0 @@
|
||||
#define CONFIG_NVS_ENCRYPTION 1
|
||||
#define CONFIG_LOG_DEFAULT_LEVEL 3
|
||||
#define CONFIG_LOG_MAXIMUM_LEVEL 3
|
||||
#define CONFIG_LOG_TIMESTAMP_SOURCE_RTOS 1
|
||||
#define CONFIG_IDF_TARGET_LINUX 1
|
||||
#define CONFIG_NVS_ASSERT_ERROR_CHECK 1
|
@ -1,133 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "esp_partition.h"
|
||||
#include "spi_flash_emulation.h"
|
||||
#include "spi_flash_mmap.h"
|
||||
|
||||
static SpiFlashEmulator* s_emulator = nullptr;
|
||||
|
||||
void spi_flash_emulator_set(SpiFlashEmulator* e)
|
||||
{
|
||||
s_emulator = e;
|
||||
}
|
||||
|
||||
esp_err_t esp_partition_erase_range(const esp_partition_t* partition,
|
||||
size_t offset, size_t size)
|
||||
{
|
||||
if (!s_emulator) {
|
||||
return ESP_ERR_FLASH_OP_TIMEOUT;
|
||||
}
|
||||
|
||||
const uint32_t sec_size = esp_partition_get_main_flash_sector_size();
|
||||
if (size % sec_size != 0) {
|
||||
return ESP_ERR_INVALID_SIZE;
|
||||
}
|
||||
|
||||
if (offset % sec_size != 0) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
size_t start_sector = offset / sec_size;
|
||||
size_t num_sectors = size / sec_size;
|
||||
for (size_t sector = start_sector; sector < (start_sector + num_sectors); sector++) {
|
||||
if (!s_emulator->erase(sector)) {
|
||||
return ESP_ERR_FLASH_OP_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_partition_read(const esp_partition_t* partition,
|
||||
size_t src_offset, void* dst, size_t size)
|
||||
{
|
||||
if (!s_emulator) {
|
||||
return ESP_ERR_FLASH_OP_TIMEOUT;
|
||||
}
|
||||
|
||||
if (!s_emulator->read(reinterpret_cast<uint32_t*>(dst), src_offset, size)) {
|
||||
return ESP_ERR_FLASH_OP_FAIL;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_partition_read_raw(const esp_partition_t* partition,
|
||||
size_t src_offset, void* dst, size_t size)
|
||||
{
|
||||
if (!s_emulator) {
|
||||
return ESP_ERR_FLASH_OP_TIMEOUT;
|
||||
}
|
||||
|
||||
if (!s_emulator->read(reinterpret_cast<uint32_t*>(dst), src_offset, size)) {
|
||||
return ESP_ERR_FLASH_OP_FAIL;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_partition_write(const esp_partition_t* partition,
|
||||
size_t dst_offset, const void* src, size_t size)
|
||||
{
|
||||
if (!s_emulator) {
|
||||
return ESP_ERR_FLASH_OP_TIMEOUT;
|
||||
}
|
||||
|
||||
if (!s_emulator->write(dst_offset, reinterpret_cast<const uint32_t*>(src), size)) {
|
||||
return ESP_ERR_FLASH_OP_FAIL;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_partition_write_raw(const esp_partition_t* partition,
|
||||
size_t dst_offset, const void* src, size_t size)
|
||||
{
|
||||
if (!s_emulator) {
|
||||
return ESP_ERR_FLASH_OP_TIMEOUT;
|
||||
}
|
||||
|
||||
if (!s_emulator->write(dst_offset, reinterpret_cast<const uint32_t*>(src), size)) {
|
||||
return ESP_ERR_FLASH_OP_FAIL;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// timing data for ESP8266, 160MHz CPU frequency, 80MHz flash frequency
|
||||
// all values in microseconds
|
||||
// values are for block sizes starting at 4 bytes and going up to 4096 bytes
|
||||
static size_t readTimes[] = {7, 5, 6, 7, 11, 18, 32, 60, 118, 231, 459};
|
||||
static size_t writeTimes[] = {19, 23, 35, 57, 106, 205, 417, 814, 1622, 3200, 6367};
|
||||
static size_t blockEraseTime = 37142;
|
||||
|
||||
|
||||
static size_t timeInterp(uint32_t bytes, size_t* lut)
|
||||
{
|
||||
const int lut_size = sizeof(readTimes)/sizeof(readTimes[0]);
|
||||
int lz = __builtin_clz(bytes / 4);
|
||||
int log_size = 32 - lz;
|
||||
size_t x2 = 1 << (log_size + 2);
|
||||
size_t y2 = lut[std::min(log_size, lut_size - 1)];
|
||||
size_t x1 = 1 << (log_size + 1);
|
||||
size_t y1 = lut[log_size - 1];
|
||||
return (bytes - x1) * (y2 - y1) / (x2 - x1) + y1;
|
||||
}
|
||||
|
||||
size_t SpiFlashEmulator::getReadOpTime(uint32_t bytes)
|
||||
{
|
||||
return timeInterp(bytes, readTimes);
|
||||
}
|
||||
|
||||
size_t SpiFlashEmulator::getWriteOpTime(uint32_t bytes)
|
||||
{
|
||||
return timeInterp(bytes, writeTimes);
|
||||
}
|
||||
|
||||
size_t SpiFlashEmulator::getEraseOpTime()
|
||||
{
|
||||
return blockEraseTime;
|
||||
}
|
@ -1,245 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef spi_flash_emulation_h
|
||||
#define spi_flash_emulation_h
|
||||
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
#include <random>
|
||||
#include "esp_partition.h"
|
||||
#include "catch.hpp"
|
||||
|
||||
class SpiFlashEmulator;
|
||||
|
||||
void spi_flash_emulator_set(SpiFlashEmulator*);
|
||||
|
||||
class SpiFlashEmulator
|
||||
{
|
||||
public:
|
||||
SpiFlashEmulator(size_t sectorCount) : mUpperSectorBound(sectorCount)
|
||||
{
|
||||
const uint32_t sec_size = esp_partition_get_main_flash_sector_size();
|
||||
mData.resize(sectorCount * sec_size / 4, 0xffffffff);
|
||||
mEraseCnt.resize(sectorCount);
|
||||
spi_flash_emulator_set(this);
|
||||
}
|
||||
|
||||
SpiFlashEmulator(const char *filename)
|
||||
{
|
||||
load(filename);
|
||||
const uint32_t sec_size = esp_partition_get_main_flash_sector_size();
|
||||
// At least one page should be free, hence we create mData of size of 2 sectors.
|
||||
mData.resize(mData.size() + sec_size / 4, 0xffffffff);
|
||||
mUpperSectorBound = mData.size() * 4 / sec_size;
|
||||
spi_flash_emulator_set(this);
|
||||
}
|
||||
|
||||
~SpiFlashEmulator()
|
||||
{
|
||||
spi_flash_emulator_set(nullptr);
|
||||
}
|
||||
|
||||
bool read(uint32_t* dest, size_t srcAddr, size_t size) const
|
||||
{
|
||||
if (srcAddr % 4 != 0 ||
|
||||
size % 4 != 0 ||
|
||||
srcAddr + size > mData.size() * 4) {
|
||||
return false;
|
||||
}
|
||||
|
||||
copy(begin(mData) + srcAddr / 4, begin(mData) + (srcAddr + size) / 4, dest);
|
||||
|
||||
++mReadOps;
|
||||
mReadBytes += size;
|
||||
mTotalTime += getReadOpTime(static_cast<uint32_t>(size));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool write(size_t dstAddr, const uint32_t* src, size_t size)
|
||||
{
|
||||
const uint32_t sec_size = esp_partition_get_main_flash_sector_size();
|
||||
uint32_t sectorNumber = dstAddr/sec_size;
|
||||
if (sectorNumber < mLowerSectorBound || sectorNumber >= mUpperSectorBound) {
|
||||
WARN("invalid flash operation detected: erase sector=" << sectorNumber);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dstAddr % 4 != 0 ||
|
||||
size % 4 != 0 ||
|
||||
dstAddr + size > mData.size() * 4) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < size / 4; ++i) {
|
||||
if (mFailCountdown != SIZE_MAX && mFailCountdown-- == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t sv = src[i];
|
||||
size_t pos = dstAddr / 4 + i;
|
||||
uint32_t& dv = mData[pos];
|
||||
|
||||
if (((~dv) & sv) != 0) { // are we trying to set some 0 bits to 1?
|
||||
WARN("invalid flash operation detected: dst=" << dstAddr << " size=" << size << " i=" << i);
|
||||
return false;
|
||||
}
|
||||
|
||||
dv = sv;
|
||||
}
|
||||
++mWriteOps;
|
||||
mWriteBytes += size;
|
||||
mTotalTime += getWriteOpTime(static_cast<uint32_t>(size));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool erase(size_t sectorNumber)
|
||||
{
|
||||
const uint32_t sec_size = esp_partition_get_main_flash_sector_size();
|
||||
size_t offset = sectorNumber * sec_size / 4;
|
||||
if (offset > mData.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sectorNumber < mLowerSectorBound || sectorNumber >= mUpperSectorBound) {
|
||||
WARN("invalid flash operation detected: erase sector=" << sectorNumber);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mFailCountdown != SIZE_MAX && mFailCountdown-- == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::fill_n(begin(mData) + offset, sec_size / 4, 0xffffffff);
|
||||
|
||||
++mEraseOps;
|
||||
mEraseCnt[sectorNumber]++;
|
||||
mTotalTime += getEraseOpTime();
|
||||
return true;
|
||||
}
|
||||
|
||||
void randomize(uint32_t seed)
|
||||
{
|
||||
std::random_device rd;
|
||||
std::mt19937 gen(rd());
|
||||
gen.seed(seed);
|
||||
std::generate_n(mData.data(), mData.size(), gen);
|
||||
}
|
||||
|
||||
size_t size() const
|
||||
{
|
||||
return mData.size() * 4;
|
||||
}
|
||||
|
||||
const uint32_t* words() const
|
||||
{
|
||||
return mData.data();
|
||||
}
|
||||
|
||||
const uint8_t* bytes() const
|
||||
{
|
||||
return reinterpret_cast<const uint8_t*>(mData.data());
|
||||
}
|
||||
|
||||
void load(const char* filename)
|
||||
{
|
||||
const uint32_t sector_size = esp_partition_get_main_flash_sector_size();
|
||||
size_t sec_size = sector_size;
|
||||
FILE* f = fopen(filename, "rb");
|
||||
fseek(f, 0, SEEK_END);
|
||||
off_t size = ftell(f);
|
||||
assert(size % sec_size == 0);
|
||||
mData.resize(size / sizeof(uint32_t));
|
||||
fseek(f, 0, SEEK_SET);
|
||||
auto s = fread(mData.data(), sec_size, size / sec_size, f);
|
||||
assert(s == static_cast<size_t>(size / sec_size));
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
void save(const char* filename)
|
||||
{
|
||||
const uint32_t sector_size = esp_partition_get_main_flash_sector_size();
|
||||
size_t sec_size = sector_size;
|
||||
FILE* f = fopen(filename, "wb");
|
||||
auto n_sectors = mData.size() * sizeof(uint32_t) / sec_size;
|
||||
auto s = fwrite(mData.data(), sec_size, n_sectors, f);
|
||||
assert(s == n_sectors);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
void clearStats()
|
||||
{
|
||||
mReadBytes = 0;
|
||||
mWriteBytes = 0;
|
||||
mEraseOps = 0;
|
||||
mReadOps = 0;
|
||||
mWriteOps = 0;
|
||||
mTotalTime = 0;
|
||||
}
|
||||
|
||||
size_t getReadOps() const
|
||||
{
|
||||
return mReadOps;
|
||||
}
|
||||
size_t getWriteOps() const
|
||||
{
|
||||
return mWriteOps;
|
||||
}
|
||||
size_t getEraseOps() const
|
||||
{
|
||||
return mEraseOps;
|
||||
}
|
||||
size_t getReadBytes() const
|
||||
{
|
||||
return mReadBytes;
|
||||
}
|
||||
size_t getWriteBytes() const
|
||||
{
|
||||
return mWriteBytes;
|
||||
}
|
||||
size_t getTotalTime() const
|
||||
{
|
||||
return mTotalTime;
|
||||
}
|
||||
|
||||
void setBounds(uint32_t lowerSector, uint32_t upperSector) {
|
||||
mLowerSectorBound = lowerSector;
|
||||
mUpperSectorBound = upperSector;
|
||||
}
|
||||
|
||||
void failAfter(uint32_t count) {
|
||||
mFailCountdown = count;
|
||||
}
|
||||
|
||||
size_t getSectorEraseCount(uint32_t sector) const {
|
||||
return mEraseCnt[sector];
|
||||
}
|
||||
|
||||
protected:
|
||||
static size_t getReadOpTime(uint32_t bytes);
|
||||
static size_t getWriteOpTime(uint32_t bytes);
|
||||
static size_t getEraseOpTime();
|
||||
|
||||
|
||||
std::vector<uint32_t> mData;
|
||||
std::vector<uint32_t> mEraseCnt;
|
||||
|
||||
mutable size_t mReadOps = 0;
|
||||
mutable size_t mWriteOps = 0;
|
||||
mutable size_t mReadBytes = 0;
|
||||
mutable size_t mWriteBytes = 0;
|
||||
mutable size_t mEraseOps = 0;
|
||||
mutable size_t mTotalTime = 0;
|
||||
size_t mLowerSectorBound = 0;
|
||||
size_t mUpperSectorBound = 0;
|
||||
|
||||
size_t mFailCountdown = SIZE_MAX;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif /* spi_flash_emulation_h */
|
@ -1,48 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "catch.hpp"
|
||||
#include "compressed_enum_table.hpp"
|
||||
#include <cstring>
|
||||
|
||||
TEST_CASE("test if CompressedEnumTable works as expected", "[enumtable]")
|
||||
{
|
||||
|
||||
enum class TEnum1 : uint32_t {
|
||||
ZERO = 0,
|
||||
ONE = 1,
|
||||
TWO = 2,
|
||||
THREE = 3,
|
||||
};
|
||||
CompressedEnumTable<TEnum1, 2, 252> table;
|
||||
memset(table.data(), 0xff, table.byteSize());
|
||||
TEnum1 tmp;
|
||||
for (size_t i = 0; i < table.count(); ++i) {
|
||||
CHECK(table.get(i, &tmp) == ESP_OK);
|
||||
CHECK(tmp == TEnum1::THREE);
|
||||
}
|
||||
|
||||
CHECK(table.set(0, TEnum1::ONE) == ESP_OK);
|
||||
CHECK(table.set(1, TEnum1::TWO) == ESP_OK);
|
||||
CHECK(table.set(2, TEnum1::ZERO) == ESP_OK);
|
||||
CHECK(table.set(3, TEnum1::ONE) == ESP_OK);
|
||||
CHECK(table.set(4, TEnum1::TWO) == ESP_OK);
|
||||
CHECK(table.set(5, TEnum1::ZERO) == ESP_OK);
|
||||
CHECK(table.set(6, TEnum1::ONE) == ESP_OK);
|
||||
CHECK(table.set(7, TEnum1::TWO) == ESP_OK);
|
||||
CHECK(table.set(8, TEnum1::ZERO) == ESP_OK);
|
||||
CHECK(table.set(9, TEnum1::ZERO) == ESP_OK);
|
||||
CHECK(table.set(10, TEnum1::ONE) == ESP_OK);
|
||||
CHECK(table.set(11, TEnum1::TWO) == ESP_OK);
|
||||
// table.set(12, ...
|
||||
CHECK(table.set(13, TEnum1::ZERO) == ESP_OK);
|
||||
CHECK(table.set(14, TEnum1::ONE) == ESP_OK);
|
||||
CHECK(table.set(15, TEnum1::TWO) == ESP_OK);
|
||||
|
||||
// b10010011100100001001001001001001
|
||||
// h 9 3 9 0 9 2 4 9
|
||||
|
||||
CHECK(table.data()[0] == 0x93909249);
|
||||
}
|
@ -1,152 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "nvs_partition.hpp"
|
||||
#include "nvs_encrypted_partition.hpp"
|
||||
#include "spi_flash_emulation.h"
|
||||
#include "spi_flash_mmap.h"
|
||||
#include "nvs.h"
|
||||
|
||||
class PartitionEmulation : public nvs::Partition {
|
||||
public:
|
||||
PartitionEmulation(SpiFlashEmulator *spi_flash_emulator,
|
||||
uint32_t address,
|
||||
uint32_t size,
|
||||
const char *partition_name = NVS_DEFAULT_PART_NAME)
|
||||
: partition_name(partition_name), flash_emu(spi_flash_emulator), address(address), size(size)
|
||||
{
|
||||
assert(partition_name);
|
||||
assert(flash_emu);
|
||||
assert(size);
|
||||
readonly = false;
|
||||
}
|
||||
|
||||
const char *get_partition_name() override
|
||||
{
|
||||
return partition_name;
|
||||
}
|
||||
|
||||
esp_err_t read_raw(size_t src_offset, void* dst, size_t size) override
|
||||
{
|
||||
if (!flash_emu->read(reinterpret_cast<uint32_t*>(dst), src_offset, size)) {
|
||||
return ESP_ERR_FLASH_OP_FAIL;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t read(size_t src_offset, void* dst, size_t size) override
|
||||
{
|
||||
if (!flash_emu->read(reinterpret_cast<uint32_t*>(dst), src_offset, size)) {
|
||||
return ESP_ERR_FLASH_OP_FAIL;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t write_raw(size_t dst_offset, const void* src, size_t size) override
|
||||
{
|
||||
if (!flash_emu->write(dst_offset, reinterpret_cast<const uint32_t*>(src), size)) {
|
||||
return ESP_ERR_FLASH_OP_FAIL;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t write(size_t dst_offset, const void* src, size_t size) override
|
||||
{
|
||||
if (!flash_emu->write(dst_offset, reinterpret_cast<const uint32_t*>(src), size)) {
|
||||
return ESP_ERR_FLASH_OP_FAIL;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t erase_range(size_t dst_offset, size_t size) override
|
||||
{
|
||||
const uint32_t sec_size = esp_partition_get_main_flash_sector_size();
|
||||
if (size % sec_size != 0) {
|
||||
return ESP_ERR_INVALID_SIZE;
|
||||
}
|
||||
|
||||
if (dst_offset % sec_size != 0) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
size_t start_sector = dst_offset / sec_size;
|
||||
size_t num_sectors = size / sec_size;
|
||||
for (size_t sector = start_sector; sector < (start_sector + num_sectors); sector++) {
|
||||
if (!flash_emu->erase(sector)) {
|
||||
return ESP_ERR_FLASH_OP_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
uint32_t get_address() override
|
||||
{
|
||||
return address;
|
||||
}
|
||||
|
||||
uint32_t get_size() override
|
||||
{
|
||||
return size;
|
||||
}
|
||||
|
||||
bool get_readonly() override
|
||||
{
|
||||
return readonly;
|
||||
}
|
||||
|
||||
private:
|
||||
const char *partition_name;
|
||||
|
||||
SpiFlashEmulator *flash_emu;
|
||||
|
||||
uint32_t address;
|
||||
|
||||
uint32_t size;
|
||||
|
||||
bool readonly;
|
||||
};
|
||||
|
||||
struct PartitionEmulationFixture {
|
||||
PartitionEmulationFixture(uint32_t start_sector = 0,
|
||||
uint32_t sector_size = 1,
|
||||
const char *partition_name = NVS_DEFAULT_PART_NAME)
|
||||
: emu(start_sector + sector_size),
|
||||
part(&emu, start_sector * esp_partition_get_main_flash_sector_size(), sector_size * esp_partition_get_main_flash_sector_size(), partition_name) {
|
||||
}
|
||||
|
||||
~PartitionEmulationFixture() { }
|
||||
|
||||
SpiFlashEmulator emu;
|
||||
|
||||
PartitionEmulation part;
|
||||
};
|
||||
|
||||
struct EncryptedPartitionFixture {
|
||||
EncryptedPartitionFixture(nvs_sec_cfg_t *cfg,
|
||||
uint32_t start_sector = 0,
|
||||
uint32_t sector_size = 1,
|
||||
const char *partition_name = NVS_DEFAULT_PART_NAME)
|
||||
: esp_partition(), emu(start_sector + sector_size),
|
||||
part(&esp_partition) {
|
||||
const uint32_t sec_size = esp_partition_get_main_flash_sector_size();
|
||||
esp_partition.address = start_sector * sec_size;
|
||||
esp_partition.size = sector_size * sec_size;
|
||||
strncpy(esp_partition.label, partition_name, PART_NAME_MAX_SIZE);
|
||||
assert(part.init(cfg) == ESP_OK);
|
||||
}
|
||||
|
||||
~EncryptedPartitionFixture() { }
|
||||
|
||||
esp_partition_t esp_partition;
|
||||
|
||||
SpiFlashEmulator emu;
|
||||
|
||||
nvs::NVSEncryptedPartition part;
|
||||
};
|
@ -1,212 +0,0 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// 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 "catch.hpp"
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include "intrusive_list.h"
|
||||
|
||||
struct TestNode : public intrusive_list_node<TestNode> {
|
||||
TestNode(const char* name_ = "", int num_ = 0) : num(num_)
|
||||
{
|
||||
strncpy(name, name_, sizeof(name) - 1);
|
||||
name[sizeof(name) - 1] = 0;
|
||||
}
|
||||
char name[32];
|
||||
int num;
|
||||
};
|
||||
|
||||
typedef intrusive_list<TestNode> TestList;
|
||||
|
||||
|
||||
TEST_CASE("can add items to the list", "[list]")
|
||||
{
|
||||
TestList list;
|
||||
TestNode n1("one", 1);
|
||||
TestNode n2("two", 2);
|
||||
TestNode n3("three", 3);
|
||||
|
||||
list.push_back(&n1);
|
||||
REQUIRE(list.begin()->num == 1);
|
||||
REQUIRE(list.front().num == 1);
|
||||
REQUIRE(list.back().num == 1);
|
||||
list.push_front(&n2);
|
||||
REQUIRE(list.begin()->num == 2);
|
||||
REQUIRE(list.front().num == 2);
|
||||
REQUIRE(list.back().num == 1);
|
||||
|
||||
list.insert(list.begin(), &n3);
|
||||
REQUIRE(list.begin()->num == 3);
|
||||
REQUIRE(list.front().num == 3);
|
||||
REQUIRE(list.back().num == 1);
|
||||
|
||||
|
||||
auto second = ++list.begin();
|
||||
REQUIRE(second->num == 2);
|
||||
|
||||
second++;
|
||||
REQUIRE(second->num == 1);
|
||||
}
|
||||
|
||||
TEST_CASE("can iterate over items", "[list]")
|
||||
{
|
||||
TestList list;
|
||||
|
||||
TestNode n1("one", 1);
|
||||
TestNode n2("two", 2);
|
||||
TestNode n3("three", 3);
|
||||
|
||||
|
||||
list.push_back(&n1);
|
||||
list.push_back(&n2);
|
||||
list.push_back(&n3);
|
||||
|
||||
int val = 1;
|
||||
for (auto it = std::begin(list); it != std::end(list); ++it) {
|
||||
REQUIRE(it->num == val);
|
||||
++val;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("iterator's prefix and postfix increments and decrements behave as expected", "[list]")
|
||||
{
|
||||
TestList list;
|
||||
|
||||
TestNode n1("one", 1);
|
||||
TestNode n2("two", 2);
|
||||
TestNode n3("three", 3);
|
||||
|
||||
|
||||
list.push_back(&n1);
|
||||
list.push_back(&n2);
|
||||
list.push_back(&n3);
|
||||
|
||||
auto it = std::begin(list);
|
||||
REQUIRE((++it)->num == 2);
|
||||
REQUIRE(it++->num == 2);
|
||||
REQUIRE((--it)->num == 2);
|
||||
REQUIRE(it--->num == 2);
|
||||
}
|
||||
|
||||
TEST_CASE("can pop_front from the list", "[list]")
|
||||
{
|
||||
TestList list;
|
||||
|
||||
TestNode n1("one", 1);
|
||||
TestNode n2("two", 2);
|
||||
TestNode n3("three", 3);
|
||||
|
||||
list.push_back(&n1);
|
||||
list.push_back(&n2);
|
||||
list.push_back(&n3);
|
||||
|
||||
list.pop_front();
|
||||
list.pop_front();
|
||||
list.pop_front();
|
||||
|
||||
REQUIRE(std::begin(list) == std::end(list));
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("can erase first item in the list", "[list]")
|
||||
{
|
||||
TestList list;
|
||||
TestNode n1("one", 1);
|
||||
TestNode n2("two", 2);
|
||||
TestNode n3("three", 3);
|
||||
|
||||
list.push_back(&n1);
|
||||
list.push_back(&n2);
|
||||
list.push_back(&n3);
|
||||
|
||||
list.erase(std::begin(list));
|
||||
|
||||
REQUIRE(list.front().num == 2);
|
||||
REQUIRE(list.back().num == 3);
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("can erase last item in the list", "[list]")
|
||||
{
|
||||
TestList list;
|
||||
TestNode n1("one", 1);
|
||||
TestNode n2("two", 2);
|
||||
TestNode n3("three", 3);
|
||||
|
||||
list.push_back(&n1);
|
||||
list.push_back(&n2);
|
||||
list.push_back(&n3);
|
||||
|
||||
list.erase(&list.back());
|
||||
|
||||
REQUIRE(list.front().num == 1);
|
||||
REQUIRE(list.back().num == 2);
|
||||
}
|
||||
|
||||
TEST_CASE("can erase item in the middle of the list", "[list]")
|
||||
{
|
||||
TestList list;
|
||||
TestNode n1("one", 1);
|
||||
TestNode n2("two", 2);
|
||||
TestNode n3("three", 3);
|
||||
|
||||
list.push_back(&n1);
|
||||
list.push_back(&n2);
|
||||
list.push_back(&n3);
|
||||
|
||||
list.erase(++std::begin(list));
|
||||
|
||||
REQUIRE(list.front().num == 1);
|
||||
REQUIRE(list.back().num == 3);
|
||||
}
|
||||
|
||||
TEST_CASE("can erase all items in the list", "[list]")
|
||||
{
|
||||
TestList list;
|
||||
TestNode n1("one", 1);
|
||||
TestNode n2("two", 2);
|
||||
TestNode n3("three", 3);
|
||||
|
||||
list.push_back(&n1);
|
||||
list.push_back(&n2);
|
||||
list.push_back(&n3);
|
||||
|
||||
list.erase(std::begin(list));
|
||||
list.erase(std::begin(list));
|
||||
list.erase(std::begin(list));
|
||||
REQUIRE(std::begin(list) == std::end(list));
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("can erase all items in the list using clear method", "[list]")
|
||||
{
|
||||
TestList list;
|
||||
TestNode n1("one", 1);
|
||||
TestNode n2("two", 2);
|
||||
TestNode n3("three", 3);
|
||||
TestNode n4("four", 4);
|
||||
TestNode n5("five", 5);
|
||||
TestNode n6("six", 6);
|
||||
|
||||
|
||||
list.push_back(&n1);
|
||||
list.push_back(&n2);
|
||||
list.insert(++list.begin(), &n3);
|
||||
list.insert(++list.begin(), &n4);
|
||||
list.push_front(&n5);
|
||||
list.insert(list.begin(), &n6);
|
||||
|
||||
list.clear();
|
||||
|
||||
REQUIRE(std::begin(list) == std::end(list));
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,42 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "catch.hpp"
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include "nvs_test_api.h"
|
||||
#include "nvs_handle_simple.hpp"
|
||||
#include "nvs_partition.hpp"
|
||||
#include "spi_flash_emulation.h"
|
||||
#include "test_fixtures.hpp"
|
||||
#include <iostream>
|
||||
|
||||
TEST_CASE("encrypted partition read size must be item size", "[nvs]")
|
||||
{
|
||||
char foo [32] = { };
|
||||
nvs_sec_cfg_t xts_cfg;
|
||||
for (int count = 0; count < NVS_KEY_SIZE; count++) {
|
||||
xts_cfg.eky[count] = 0x11;
|
||||
xts_cfg.tky[count] = 0x22;
|
||||
}
|
||||
EncryptedPartitionFixture fix(&xts_cfg);
|
||||
|
||||
CHECK(fix.part.read(0, foo, sizeof (foo) - 1) == ESP_ERR_INVALID_SIZE);
|
||||
}
|
||||
|
||||
TEST_CASE("encrypted partition write size must be mod item size", "[nvs]")
|
||||
{
|
||||
char foo [64] = { };
|
||||
nvs_sec_cfg_t xts_cfg;
|
||||
for (int count = 0; count < NVS_KEY_SIZE; count++) {
|
||||
xts_cfg.eky[count] = 0x11;
|
||||
xts_cfg.tky[count] = 0x22;
|
||||
}
|
||||
EncryptedPartitionFixture fix(&xts_cfg);
|
||||
|
||||
CHECK(fix.part.write(0, foo, sizeof (foo) - 1) == ESP_ERR_INVALID_SIZE);
|
||||
CHECK(fix.part.write(0, foo, sizeof (foo) / 2) == ESP_OK);
|
||||
CHECK(fix.part.write(sizeof(foo) / 2, foo, sizeof (foo)) == ESP_OK);
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "catch.hpp"
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include "nvs_test_api.h"
|
||||
#include "nvs_handle_simple.hpp"
|
||||
#include "nvs_partition_manager.hpp"
|
||||
#include "spi_flash_emulation.h"
|
||||
#include "nvs_test_api.h"
|
||||
#include "test_fixtures.hpp"
|
||||
#include "esp_partition.h"
|
||||
|
||||
/*
|
||||
TEST_CASE("Partition manager initializes multiple partitions", "[partition_mgr]")
|
||||
{
|
||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
||||
SpiFlashEmulator emu(10);
|
||||
const uint32_t sec_size = esp_partition_get_main_flash_sector_size();
|
||||
PartitionEmulation part_0(&emu, NVS_FLASH_SECTOR * sec_size, NVS_FLASH_SECTOR_COUNT_MIN * sec_size, "test1");
|
||||
PartitionEmulation part_1(&emu, NVS_FLASH_SECTOR * sec_size, NVS_FLASH_SECTOR_COUNT_MIN * sec_size, "test2");
|
||||
|
||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->init_custom(&part_0, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
||||
== ESP_OK);
|
||||
// TODO: why does this work, actually? same sectors used as above
|
||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->init_custom(&part_1, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
||||
== ESP_OK);
|
||||
nvs::Storage *storage1 = nvs::NVSPartitionManager::get_instance()->lookup_storage_from_name("test1");
|
||||
REQUIRE(storage1 != nullptr);
|
||||
nvs::Storage *storage2 = nvs::NVSPartitionManager::get_instance()->lookup_storage_from_name("test2");
|
||||
REQUIRE(storage2 != nullptr);
|
||||
|
||||
CHECK(storage1 != storage2);
|
||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->deinit_partition(part_0.get_partition_name()) == ESP_OK);
|
||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->deinit_partition(part_1.get_partition_name()) == ESP_OK);
|
||||
}
|
||||
*/
|
@ -1,178 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "catch.hpp"
|
||||
#include "esp_partition.h"
|
||||
#include "spi_flash_emulation.h"
|
||||
#include "spi_flash_mmap.h"
|
||||
#include <functional>
|
||||
|
||||
template <typename Tit>
|
||||
bool range_empty_n(Tit it_begin, size_t n)
|
||||
{
|
||||
return std::all_of(it_begin, it_begin + n, bind(std::equal_to<uint32_t>(), std::placeholders::_1, 0xffffffff));
|
||||
}
|
||||
|
||||
struct FlashEmuFixture {
|
||||
FlashEmuFixture(size_t sectors) : esp_part(), emu(sectors) { }
|
||||
|
||||
esp_partition_t esp_part;
|
||||
SpiFlashEmulator emu;
|
||||
};
|
||||
|
||||
TEST_CASE("flash starts with all bytes == 0xff", "[spi_flash_emu]")
|
||||
{
|
||||
FlashEmuFixture f(4);
|
||||
|
||||
uint32_t sec_size = esp_partition_get_main_flash_sector_size();
|
||||
uint8_t sector[sec_size];
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
CHECK(esp_partition_read(&f.esp_part, 0, sector, sizeof(sector)) == ESP_OK);
|
||||
for (auto v: sector) {
|
||||
CHECK(v == 0xff);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("invalid writes are checked", "[spi_flash_emu]")
|
||||
{
|
||||
FlashEmuFixture f(1);
|
||||
|
||||
uint32_t val = 0;
|
||||
CHECK(esp_partition_write(&f.esp_part, 0, &val, 4) == ESP_OK);
|
||||
val = 1;
|
||||
CHECK(esp_partition_write(&f.esp_part, 0, &val, 4) == ESP_ERR_FLASH_OP_FAIL);
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("out of bounds writes fail", "[spi_flash_emu]")
|
||||
{
|
||||
FlashEmuFixture f(4);
|
||||
uint32_t vals[8];
|
||||
std::fill_n(vals, 8, 0);
|
||||
CHECK(esp_partition_write(&f.esp_part, 0, &vals, sizeof(vals)) == ESP_OK);
|
||||
|
||||
CHECK(esp_partition_write(&f.esp_part, 4*4096 - sizeof(vals), &vals, sizeof(vals)) == ESP_OK);
|
||||
|
||||
CHECK(esp_partition_write(&f.esp_part, 4*4096 - sizeof(vals) + 4, &vals, sizeof(vals)) == ESP_ERR_FLASH_OP_FAIL);
|
||||
}
|
||||
|
||||
TEST_CASE("after erase the sector is set to 0xff", "[spi_flash_emu]")
|
||||
{
|
||||
FlashEmuFixture f(4);
|
||||
uint32_t val1 = 0xab00cd12;
|
||||
CHECK(esp_partition_write(&f.esp_part, 0, &val1, sizeof(val1)) == ESP_OK);
|
||||
uint32_t val2 = 0x5678efab;
|
||||
CHECK(esp_partition_write(&f.esp_part, 4096 - 4, &val2, sizeof(val2)) == ESP_OK);
|
||||
|
||||
CHECK(f.emu.words()[0] == val1);
|
||||
CHECK(range_empty_n(f.emu.words() + 1, 4096 / 4 - 2));
|
||||
CHECK(f.emu.words()[4096 / 4 - 1] == val2);
|
||||
|
||||
uint32_t sec_size = esp_partition_get_main_flash_sector_size();
|
||||
CHECK(esp_partition_erase_range(&f.esp_part, 0, sec_size) == ESP_OK);
|
||||
|
||||
CHECK(f.emu.words()[0] == 0xffffffff);
|
||||
CHECK(range_empty_n(f.emu.words() + 1, 4096 / 4 - 2));
|
||||
CHECK(f.emu.words()[4096 / 4 - 1] == 0xffffffff);
|
||||
}
|
||||
|
||||
TEST_CASE("EMU raw read function works", "[spi_flash_emu]")
|
||||
{
|
||||
FlashEmuFixture f(4);
|
||||
uint32_t value = 0xdeadbeef;
|
||||
uint32_t read_value = 0;
|
||||
CHECK(esp_partition_write(&f.esp_part, 0, &value, sizeof(value)) == ESP_OK);
|
||||
|
||||
CHECK(esp_partition_read_raw(&f.esp_part, 0, &read_value, sizeof(read_value)) == ESP_OK);
|
||||
|
||||
CHECK(read_value == 0xdeadbeef);
|
||||
}
|
||||
|
||||
TEST_CASE("EMU raw write function works", "[spi_flash_emu]")
|
||||
{
|
||||
FlashEmuFixture f(4);
|
||||
uint32_t value = 0xdeadbeef;
|
||||
uint32_t read_value = 0;
|
||||
CHECK(esp_partition_write_raw(&f.esp_part, 0, &value, sizeof(value)) == ESP_OK);
|
||||
|
||||
CHECK(esp_partition_read(&f.esp_part, 0, &read_value, sizeof(read_value)) == ESP_OK);
|
||||
|
||||
CHECK(read_value == 0xdeadbeef);
|
||||
}
|
||||
|
||||
TEST_CASE("read/write/erase operation times are calculated correctly", "[spi_flash_emu]")
|
||||
{
|
||||
FlashEmuFixture f(1);
|
||||
uint8_t data[512];
|
||||
esp_partition_read(&f.esp_part, 0, data, 4);
|
||||
CHECK(f.emu.getTotalTime() == 7);
|
||||
CHECK(f.emu.getReadOps() == 1);
|
||||
CHECK(f.emu.getReadBytes() == 4);
|
||||
f.emu.clearStats();
|
||||
esp_partition_read(&f.esp_part, 0, data, 8);
|
||||
CHECK(f.emu.getTotalTime() == 5);
|
||||
CHECK(f.emu.getReadOps() == 1);
|
||||
CHECK(f.emu.getReadBytes() == 8);
|
||||
f.emu.clearStats();
|
||||
esp_partition_read(&f.esp_part, 0, data, 16);
|
||||
CHECK(f.emu.getTotalTime() == 6);
|
||||
CHECK(f.emu.getReadOps() == 1);
|
||||
CHECK(f.emu.getReadBytes() == 16);
|
||||
f.emu.clearStats();
|
||||
esp_partition_read(&f.esp_part, 0, data, 128);
|
||||
CHECK(f.emu.getTotalTime() == 18);
|
||||
CHECK(f.emu.getReadOps() == 1);
|
||||
CHECK(f.emu.getReadBytes() == 128);
|
||||
f.emu.clearStats();
|
||||
esp_partition_read(&f.esp_part, 0, data, 256);
|
||||
CHECK(f.emu.getTotalTime() == 32);
|
||||
f.emu.clearStats();
|
||||
esp_partition_read(&f.esp_part, 0, data, (128+256)/2);
|
||||
CHECK(f.emu.getTotalTime() == (18+32)/2);
|
||||
f.emu.clearStats();
|
||||
|
||||
esp_partition_write(&f.esp_part, 0, data, 4);
|
||||
CHECK(f.emu.getTotalTime() == 19);
|
||||
CHECK(f.emu.getWriteOps() == 1);
|
||||
CHECK(f.emu.getWriteBytes() == 4);
|
||||
f.emu.clearStats();
|
||||
CHECK(f.emu.getWriteOps() == 0);
|
||||
CHECK(f.emu.getWriteBytes() == 0);
|
||||
esp_partition_write(&f.esp_part, 0, data, 8);
|
||||
CHECK(f.emu.getTotalTime() == 23);
|
||||
f.emu.clearStats();
|
||||
esp_partition_write(&f.esp_part, 0, data, 16);
|
||||
CHECK(f.emu.getTotalTime() == 35);
|
||||
CHECK(f.emu.getWriteOps() == 1);
|
||||
CHECK(f.emu.getWriteBytes() == 16);
|
||||
f.emu.clearStats();
|
||||
esp_partition_write(&f.esp_part, 0, data, 128);
|
||||
CHECK(f.emu.getTotalTime() == 205);
|
||||
f.emu.clearStats();
|
||||
esp_partition_write(&f.esp_part, 0, data, 256);
|
||||
CHECK(f.emu.getTotalTime() == 417);
|
||||
f.emu.clearStats();
|
||||
esp_partition_write(&f.esp_part, 0, data, (128+256)/2);
|
||||
CHECK(f.emu.getTotalTime() == (205+417)/2);
|
||||
f.emu.clearStats();
|
||||
|
||||
const uint32_t sec_size = esp_partition_get_main_flash_sector_size();
|
||||
esp_partition_erase_range(&f.esp_part, 0, sec_size);
|
||||
CHECK(f.emu.getEraseOps() == 1);
|
||||
CHECK(f.emu.getTotalTime() == 37142);
|
||||
}
|
||||
|
||||
TEST_CASE("data is randomized predictably", "[spi_flash_emu]")
|
||||
{
|
||||
SpiFlashEmulator emu1(3);
|
||||
emu1.randomize(0x12345678);
|
||||
|
||||
SpiFlashEmulator emu2(3);
|
||||
emu2.randomize(0x12345678);
|
||||
|
||||
CHECK(std::equal(emu1.bytes(), emu1.bytes() + emu1.size(), emu2.bytes()));
|
||||
}
|
@ -499,9 +499,6 @@ components/nvs_flash/src/nvs_pagemanager.hpp
|
||||
components/nvs_flash/src/nvs_partition_lookup.cpp
|
||||
components/nvs_flash/src/nvs_partition_lookup.hpp
|
||||
components/nvs_flash/src/nvs_test_api.h
|
||||
components/nvs_flash/test_nvs_host/main.cpp
|
||||
components/nvs_flash/test_nvs_host/sdkconfig.h
|
||||
components/nvs_flash/test_nvs_host/test_intrusive_list.cpp
|
||||
components/protocomm/include/transports/protocomm_console.h
|
||||
components/protocomm/include/transports/protocomm_httpd.h
|
||||
components/riscv/include/riscv/csr.h
|
||||
|
Loading…
x
Reference in New Issue
Block a user