Added dynamic and static RAM file systems to use with file objects. (#1058)

* Added dynamic RAM file system to use with basic bacnet file object.

* Added static RAM file system to use with basic bacnet file object.

* Added check for read-only during AtomicWriteFile service API for BACnet File object.

* Change stm32f4xx example to use static RAM file system.

* Fixed bacfile_count() function return type
This commit is contained in:
Steve Karg
2025-08-08 15:35:13 -05:00
committed by GitHub
parent e67777e345
commit 3f8b8b5619
17 changed files with 1324 additions and 8 deletions
@@ -0,0 +1,45 @@
# SPDX-License-Identifier: MIT
cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
get_filename_component(basename ${CMAKE_CURRENT_SOURCE_DIR} NAME)
project(test_${basename}
VERSION 1.0.0
LANGUAGES C)
string(REGEX REPLACE
"/test/bacnet/[a-zA-Z_/-]*$"
"/src"
SRC_DIR
${CMAKE_CURRENT_SOURCE_DIR})
string(REGEX REPLACE
"/test/bacnet/[a-zA-Z_/-]*$"
"/test"
TST_DIR
${CMAKE_CURRENT_SOURCE_DIR})
set(ZTST_DIR "${TST_DIR}/ztest/src")
add_compile_definitions(
BIG_ENDIAN=0
CONFIG_ZTEST=1
)
include_directories(
${SRC_DIR}
${TST_DIR}/ztest/include
)
add_executable(${PROJECT_NAME}
# File(s) under test
${SRC_DIR}/bacnet/basic/sys/bramfs.c
# BACnet library files
${SRC_DIR}/bacnet/bacstr.c
${SRC_DIR}/bacnet/basic/sys/keylist.c
${SRC_DIR}/bacnet/datalink/cobs.c
# Support files and stubs (pathname alphabetical)
# Test and test library files
./src/main.c
${ZTST_DIR}/ztest_mock.c
${ZTST_DIR}/ztest.c
)
+225
View File
@@ -0,0 +1,225 @@
/* @file
* @brief tests the BACnet RAM File System (BRAMFS)
* @date August 2025
* @author Steve Karg <Steve Karg <skarg@users.sourceforge.net>
* @copyright SPDX-License-Identifier: MIT
*/
#include <limits.h>
#include <zephyr/ztest.h>
#include <bacnet/bacstr.h>
#include <bacnet/basic/sys/bramfs.h>
/**
* @addtogroup bacnet_tests
* @{
*/
/**
* @brief Unit Test for the BACnet RAM File System (BRAMFS)
*/
#if defined(CONFIG_ZTEST_NEW_API)
ZTEST(bramfs_tests, test_BRAMFS_stream)
#else
static void test_BRAMFS_stream(void)
#endif
{
const char *pathname = "testfile.txt";
size_t file_size = 0;
uint8_t null_file_data[256] = { 0 };
uint8_t test_file_data[256] = { 0 };
/* data less than 256 bytes */
uint8_t file_data[] = {
"This is a test file for the BACnet RAM File System (BRAMFS). "
"It contains some sample data to be read and written."
};
uint8_t file_data_2[] = {
"This is a second test file for the BACnet RAM File System (BRAMFS). "
"It contains some additional sample data to be read and written."
};
uint8_t file_data_small[] = { "Small file data" };
int32_t fileStartPosition = 0;
/* Initialize the BRAMFS */
bacfile_ramfs_init();
file_size = bacfile_ramfs_file_size(pathname);
zassert_equal(file_size, 0, "File size should be 0 after initialization");
zassert_true(
bacfile_ramfs_file_size_set(pathname, sizeof(null_file_data)),
"Failed to set file size");
file_size = bacfile_ramfs_file_size(pathname);
zassert_equal(
file_size, sizeof(null_file_data),
"File size should be 256 after setting");
file_size = bacfile_ramfs_read_stream_data(
pathname, 0, test_file_data, sizeof(test_file_data));
zassert_equal(
file_size, sizeof(test_file_data), "file_size=%zu", file_size);
zassert_true(
memcmp(test_file_data, null_file_data, sizeof(test_file_data)) == 0,
"File data should be zeroed out initially");
file_size = bacfile_ramfs_write_stream_data(
pathname, 0, file_data, sizeof(file_data));
zassert_equal(file_size, sizeof(file_data), "file_size=%zu", file_size);
file_size = bacfile_ramfs_read_stream_data(
pathname, 0, test_file_data, sizeof(test_file_data));
zassert_equal(file_size, sizeof(file_data), "file_size=%zu", file_size);
zassert_true(
memcmp(test_file_data, file_data, sizeof(file_data)) == 0,
"File data should match written data");
/* append data to the end of the file */
fileStartPosition = -1;
file_size = bacfile_ramfs_write_stream_data(
pathname, fileStartPosition, file_data_2, sizeof(file_data_2));
zassert_equal(file_size, sizeof(file_data_2), "file_size=%zu", file_size);
file_size = bacfile_ramfs_read_stream_data(
pathname, sizeof(file_data), test_file_data, sizeof(test_file_data));
zassert_equal(file_size, sizeof(file_data_2), "file_size=%zu", file_size);
zassert_true(
memcmp(test_file_data, file_data_2, sizeof(file_data_2)) == 0,
"File data should match appended data");
/* write a smaller file */
fileStartPosition = 0;
file_size = bacfile_ramfs_write_stream_data(
pathname, fileStartPosition, file_data_small, sizeof(file_data_small));
zassert_equal(
file_size, sizeof(file_data_small), "file_size=%zu", file_size);
file_size = bacfile_ramfs_read_stream_data(
pathname, 0, test_file_data, sizeof(test_file_data));
zassert_equal(
file_size, sizeof(file_data_small), "file_size=%zu", file_size);
zassert_true(
memcmp(test_file_data, file_data_small, sizeof(file_data_small)) == 0,
"File data should match smaller written data");
file_size = bacfile_ramfs_file_size(pathname);
zassert_equal(
file_size, sizeof(file_data_small),
"File size should be %u after shrinking", sizeof(file_data_small));
/* shrink the file by writing zero at zero */
zassert_true(
bacfile_ramfs_file_size_set(pathname, 0),
"Failed to set file size to 0");
file_size = bacfile_ramfs_file_size(pathname);
zassert_equal(file_size, 0, "File size should be 0 after shrinking");
/* check a NULL pathname */
file_size = bacfile_ramfs_file_size(NULL);
zassert_equal(file_size, 0, "File size should be 0 on a null pathname");
/* append data to the end of the file */
fileStartPosition = 5;
file_size = bacfile_ramfs_write_stream_data(
pathname, fileStartPosition, file_data, sizeof(file_data));
zassert_equal(file_size, sizeof(file_data), "file_size=%zu", file_size);
file_size = bacfile_ramfs_read_stream_data(
pathname, fileStartPosition, test_file_data, sizeof(test_file_data));
zassert_equal(file_size, sizeof(file_data), "file_size=%zu", file_size);
zassert_true(
memcmp(test_file_data, file_data, sizeof(file_data)) == 0,
"File data should match written data at position %d",
fileStartPosition);
file_size = bacfile_ramfs_file_size(pathname);
zassert_equal(
file_size, sizeof(file_data) + fileStartPosition,
"File size should be %u after appending",
sizeof(file_data) + fileStartPosition);
bacfile_ramfs_deinit();
}
/**
* @brief Unit Test for the BACnet RAM File System (BRAMFS)
*/
#if defined(CONFIG_ZTEST_NEW_API)
ZTEST(bramfs_tests, test_BRAMFS_records)
#else
static void test_BRAMFS_records(void)
#endif
{
const char *pathname = "testfile.txt";
bool status = false;
char record_1[] = { "This is the first record in the file." };
char record_2[] = { "This is the second record in the file." };
char record_3[] = { "This is the third record in the file." };
size_t record_len = 0;
/* Initialize the BRAMFS */
bacfile_ramfs_init();
/* no data in the file - expect failure */
record_len = bacnet_strnlen(record_1, sizeof(record_1));
status = bacfile_ramfs_read_record_data(
pathname, 0, 0, (uint8_t *)record_1, record_len);
zassert_false(status, "Read record 1 should fail on empty file");
record_len = bacnet_strnlen(record_1, sizeof(record_1));
status = bacfile_ramfs_read_record_data(
pathname, 0, 1, (uint8_t *)record_2, record_len);
zassert_false(status, "Read record 2 should fail on empty file");
record_len = bacnet_strnlen(record_3, sizeof(record_3));
status = bacfile_ramfs_read_record_data(
pathname, 0, 2, (uint8_t *)record_3, record_len);
zassert_false(status, "Read record 3 should fail on empty file");
/* write the first record */
record_len = bacnet_strnlen(record_1, sizeof(record_1));
status = bacfile_ramfs_write_record_data(
pathname, 0, 0, (const uint8_t *)record_1, record_len);
zassert_true(status, "Write record 1 should succeed");
/* read the first record */
status = bacfile_ramfs_read_record_data(
pathname, 0, 0, (uint8_t *)record_1, record_len);
zassert_true(status, "Read record 1 should succeed");
zassert_true(
memcmp(record_1, record_1, record_len) == 0,
"Record 1 data should match written data");
/* write the second record as an append */
record_len = bacnet_strnlen(record_2, sizeof(record_2));
status = bacfile_ramfs_write_record_data(
pathname, -1, 1, (const uint8_t *)record_2, record_len);
zassert_true(status, "Write record 2 should succeed");
/* read the second record */
status = bacfile_ramfs_read_record_data(
pathname, 0, 1, (uint8_t *)record_2, record_len);
zassert_true(status, "Read record 2 should succeed");
zassert_true(
memcmp(record_2, record_2, record_len) == 0,
"Record 2 data should match written data");
/* overwrite the third record at index 1 */
record_len = bacnet_strnlen(record_3, sizeof(record_3));
status = bacfile_ramfs_write_record_data(
pathname, 0, 1, (const uint8_t *)record_3, record_len);
zassert_true(status, "Write record 3 should succeed");
/* read the third record */
status = bacfile_ramfs_read_record_data(
pathname, 0, 1, (uint8_t *)record_2, record_len);
zassert_true(status, "Read record 2 should succeed");
zassert_true(
memcmp(record_2, record_3, record_len) == 0,
"Record 2 data should match written record 3 data");
/* read the first record again */
record_len = bacnet_strnlen(record_1, sizeof(record_1));
status = bacfile_ramfs_read_record_data(
pathname, 0, 0, (uint8_t *)record_1, record_len);
zassert_true(status, "Read record 1 should succeed");
zassert_true(
memcmp(record_1, record_1, record_len) == 0,
"Record 1 data should match written data");
bacfile_ramfs_deinit();
}
/**
* @}
*/
#if defined(CONFIG_ZTEST_NEW_API)
ZTEST_SUITE(bramfs_tests, NULL, NULL, NULL, NULL, NULL);
#else
void test_main(void)
{
ztest_test_suite(
bramfs_tests, ztest_unit_test(test_BRAMFS_stream),
ztest_unit_test(test_BRAMFS_records));
ztest_run_test_suite(bramfs_tests);
}
#endif
@@ -0,0 +1,45 @@
# SPDX-License-Identifier: MIT
cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
get_filename_component(basename ${CMAKE_CURRENT_SOURCE_DIR} NAME)
project(test_${basename}
VERSION 1.0.0
LANGUAGES C)
string(REGEX REPLACE
"/test/bacnet/[a-zA-Z_/-]*$"
"/src"
SRC_DIR
${CMAKE_CURRENT_SOURCE_DIR})
string(REGEX REPLACE
"/test/bacnet/[a-zA-Z_/-]*$"
"/test"
TST_DIR
${CMAKE_CURRENT_SOURCE_DIR})
set(ZTST_DIR "${TST_DIR}/ztest/src")
add_compile_definitions(
BIG_ENDIAN=0
CONFIG_ZTEST=1
)
include_directories(
${SRC_DIR}
${TST_DIR}/ztest/include
)
add_executable(${PROJECT_NAME}
# File(s) under test
${SRC_DIR}/bacnet/basic/sys/bsramfs.c
# BACnet library files
${SRC_DIR}/bacnet/bacstr.c
${SRC_DIR}/bacnet/basic/sys/keylist.c
${SRC_DIR}/bacnet/datalink/cobs.c
# Support files and stubs (pathname alphabetical)
# Test and test library files
./src/main.c
${ZTST_DIR}/ztest_mock.c
${ZTST_DIR}/ztest.c
)
+143
View File
@@ -0,0 +1,143 @@
/* @file
* @brief tests the BACnet RAM File System (BSRAMFS)
* @date August 2025
* @author Steve Karg <Steve Karg <skarg@users.sourceforge.net>
* @copyright SPDX-License-Identifier: MIT
*/
#include <limits.h>
#include <zephyr/ztest.h>
#include <bacnet/bacstr.h>
#include <bacnet/basic/sys/bsramfs.h>
/**
* @addtogroup bacnet_tests
* @{
*/
/**
* @brief Unit Test for the BACnet static RAM File System (BSRAMFS)
*/
#if defined(CONFIG_ZTEST_NEW_API)
ZTEST(bramfs_tests, test_BSRAMFS_stream)
#else
static void test_BSRAMFS_stream(void)
#endif
{
struct bacnet_file_sramfs_data file_data[3] = {
{ 0, NULL, "testfile1.txt", NULL },
{ 0, NULL, "testfile2.txt", NULL },
{ 0, NULL, "testfile3.txt", NULL }
};
size_t file_size = 0, i = 0;
uint8_t test_file_data[256] = { 0 };
/* data less than 256 bytes */
uint8_t file_data_1[] = {
"This is a first test file for the BACnet RAM File System (BSRAMFS). "
"It contains some sample data to be read and written."
};
uint8_t file_data_2[] = {
"This is a second test file for the BACnet RAM File System (BSRAMFS). "
"It contains some additional sample data to be read and written."
};
uint8_t file_data_3[] = { "Small file data" };
/* Initialize the BSRAMFS */
bacfile_sramfs_init();
for (i = 0; i < ARRAY_SIZE(file_data); i++) {
file_size = bacfile_sramfs_file_size(file_data[i].pathname);
zassert_equal(
file_size, 0, "File size should be 0 after initialization");
}
/* add static files to the file system */
file_data[0].data = (char *)file_data_1;
file_data[0].size = sizeof(file_data_1);
zassert_true(
bacfile_sramfs_add(&file_data[0]), "Failed to add file_data[0]");
file_data[1].data = (char *)file_data_2;
file_data[1].size = sizeof(file_data_2);
zassert_true(
bacfile_sramfs_add(&file_data[1]), "Failed to add file_data[1]");
file_data[2].data = (char *)file_data_3;
file_data[2].size = sizeof(file_data_3);
zassert_true(
bacfile_sramfs_add(&file_data[2]), "Failed to add file_data[2]");
/* read back the files and check the data */
file_size = bacfile_sramfs_read_stream_data(
file_data[0].pathname, 0, test_file_data, sizeof(test_file_data));
zassert_equal(file_size, sizeof(file_data_1), "file_size=%zu", file_size);
zassert_true(
memcmp(test_file_data, file_data_1, sizeof(file_data_1)) == 0,
"File data should match!");
}
/**
* @brief Unit Test for the BACnet RAM File System (BSRAMFS)
*/
#if defined(CONFIG_ZTEST_NEW_API)
ZTEST(bramfs_tests, test_BSRAMFS_records)
#else
static void test_BSRAMFS_records(void)
#endif
{
struct bacnet_file_sramfs_data file_data[1] = {
{ 0,
"This is the first record in the file.\0"
"This is the second record in the file.\0"
"This is the third record in the file.",
"testfile.txt", NULL }
};
bool status = false;
const char *pathname = file_data[0].pathname;
char record_1[MAX_OCTET_STRING_BYTES] = { 0 };
char record_2[MAX_OCTET_STRING_BYTES] = { 0 };
char record_3[MAX_OCTET_STRING_BYTES] = { 0 };
/* Initialize the BSRAMFS */
bacfile_sramfs_init();
/* no data in the file - expect failure */
status = bacfile_sramfs_read_record_data(
pathname, 0, 0, (uint8_t *)record_1, sizeof(record_1));
zassert_false(status, "Read record 1 should fail on empty file");
status = bacfile_sramfs_read_record_data(
pathname, 0, 1, (uint8_t *)record_2, sizeof(record_2));
zassert_false(status, "Read record 2 should fail on empty file");
status = bacfile_sramfs_read_record_data(
pathname, 0, 2, (uint8_t *)record_3, sizeof(record_3));
zassert_false(status, "Read record 3 should fail on empty file");
/* add the static file with records */
bacfile_sramfs_add(&file_data[0]);
/* read the first record */
status = bacfile_sramfs_read_record_data(
pathname, 0, 0, (uint8_t *)record_1, sizeof(record_1));
zassert_true(status, "Read record 1 should succeed");
/* read the second record */
status = bacfile_sramfs_read_record_data(
pathname, 0, 1, (uint8_t *)record_2, sizeof(record_2));
zassert_true(status, "Read record 2 should succeed");
/* read the third record */
status = bacfile_sramfs_read_record_data(
pathname, 0, 2, (uint8_t *)record_3, sizeof(record_3));
zassert_true(status, "Read record 3 should succeed");
}
/**
* @}
*/
#if defined(CONFIG_ZTEST_NEW_API)
ZTEST_SUITE(bramfs_tests, NULL, NULL, NULL, NULL, NULL);
#else
void test_main(void)
{
ztest_test_suite(
bramfs_tests, ztest_unit_test(test_BSRAMFS_stream),
ztest_unit_test(test_BSRAMFS_records));
ztest_run_test_suite(bramfs_tests);
}
#endif