ChibiOS/test/mfs/configuration.xml

1018 lines
40 KiB
XML

<?xml version="1.0" encoding="UTF-8"?>
<SPC5-Config version="1.0.0">
<application name="ChibiOS/HAL MFS Test Suite" version="1.0.0" standalone="true" locked="false">
<description>Test Specification for ChibiOS/HAL MFS Complex Driver.</description>
<component id="org.chibios.spc5.components.portable.generic_startup">
<component id="org.chibios.spc5.components.portable.chibios_unitary_tests_engine" />
</component>
<instances>
<instance locked="false" id="org.chibios.spc5.components.portable.generic_startup" />
<instance locked="false" id="org.chibios.spc5.components.portable.chibios_unitary_tests_engine">
<description>
<brief>
<value>ChibiOS/HAL MFS Test Suite.</value>
</brief>
<copyright>
<value><![CDATA[/*
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
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.
*/]]></value>
</copyright>
<introduction>
<value>Test suite for ChibiOS/HAL MFS. The purpose of this suite is to perform unit tests on the MFS module and to converge to 100% code coverage through successive improvements.</value>
</introduction>
</description>
<global_data_and_code>
<code_prefix>
<value>mfs_</value>
</code_prefix>
<global_definitions>
<value><![CDATA[#include "mfs.h"
#define TEST_SUITE_NAME "ChibiOS/HAL MFS Test Suite"
#define TEST_REPORT_HOOK_HEADER test_print_mfs_info();
extern const MFSConfig mfscfg1;
extern MFSDriver mfs1;
extern uint8_t mfs_buffer[512];
flash_error_t bank_erase(mfs_bank_t bank);
flash_error_t bank_verify_erased(mfs_bank_t bank);
void test_print_mfs_info(void);]]></value>
</global_definitions>
<global_code>
<value><![CDATA[#include "mfs.h"
MFSDriver mfs1;
uint8_t mfs_buffer[512];
void test_print_mfs_info(void) {
}
flash_error_t bank_erase(mfs_bank_t bank) {
flash_sector_t sector, n;
if (bank == MFS_BANK_0) {
sector = mfscfg1.bank0_start;
n = mfscfg1.bank0_sectors;
}
else {
sector = mfscfg1.bank1_start;
n = mfscfg1.bank1_sectors;
}
while (n--) {
flash_error_t ferr;
ferr = flashStartEraseSector(mfscfg1.flashp, sector);
if (ferr != FLASH_NO_ERROR)
return ferr;
ferr = flashWaitErase(mfscfg1.flashp);
if (ferr != FLASH_NO_ERROR)
return ferr;
sector++;
}
return FLASH_NO_ERROR;
}
flash_error_t bank_verify_erased(mfs_bank_t bank) {
flash_sector_t sector, n;
if (bank == MFS_BANK_0) {
sector = mfscfg1.bank0_start;
n = mfscfg1.bank0_sectors;
}
else {
sector = mfscfg1.bank1_start;
n = mfscfg1.bank1_sectors;
}
while (n--) {
flash_error_t ferr;
ferr = flashVerifyErase(mfscfg1.flashp, sector);
if (ferr != FLASH_NO_ERROR)
return ferr;
sector++;
}
return FLASH_NO_ERROR;
}]]></value>
</global_code>
</global_data_and_code>
<sequences>
<sequence>
<type index="0">
<value>Internal Tests</value>
</type>
<brief>
<value>Functional tests.</value>
</brief>
<description>
<value>The APIs are tested for functionality, correct cases and expected error cases are tested.</value>
</description>
<condition>
<value />
</condition>
<shared_code>
<value><![CDATA[#include <string.h>
#include "mfs.h"
static const uint8_t pattern1[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
};
static const uint8_t pattern2[] = {
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47
};
static const uint8_t pattern3[] = {
48, 49, 50, 51, 52, 53, 54, 55, 56, 57
};
static const uint8_t pattern512[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63
};]]></value>
</shared_code>
<cases>
<case>
<brief>
<value>Testing mfsStart() behavior.</value>
</brief>
<description>
<value>The initialization function is tested. This function can fail only in case of Flash Array failures or in case of unexpected internal errors.</value>
</description>
<condition>
<value />
</condition>
<various_code>
<setup_code>
<value><![CDATA[mfsObjectInit(&mfs1);]]></value>
</setup_code>
<teardown_code>
<value><![CDATA[mfsStop(&mfs1);]]></value>
</teardown_code>
<local_variables>
<value />
</local_variables>
</various_code>
<steps>
<step>
<description>
<value>Erasing the flash array using a low level function.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[flash_error_t ferr;
ferr = bank_erase(MFS_BANK_0);
test_assert(ferr == FLASH_NO_ERROR, "Bank 0 erase failure");
ferr = bank_erase(MFS_BANK_1);
test_assert(ferr == FLASH_NO_ERROR, "Bank 1 erase failure");]]></value>
</code>
</step>
<step>
<description>
<value>Calling mfsStart() on an uninitialized flash array, MFS_NO_ERROR is expected.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[mfs_error_t err;
err = mfsStart(&mfs1, &mfscfg1);
test_assert(err == MFS_NO_ERROR, "initialization error with erased flash");]]></value>
</code>
</step>
<step>
<description>
<value>Calling mfsStart() on a newly initialized flash array, MFS_NO_ERROR is expected.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[mfs_error_t err;
err = mfsStart(&mfs1, &mfscfg1);
test_assert(err == MFS_NO_ERROR, "initialization error with initialized flash");]]></value>
</code>
</step>
</steps>
</case>
<case>
<brief>
<value>Checking for non existing record.</value>
</brief>
<description>
<value>The records space is explored with an initialized but empty managed storage, no record should exist.</value>
</description>
<condition>
<value />
</condition>
<various_code>
<setup_code>
<value><![CDATA[mfsStart(&mfs1, &mfscfg1);]]></value>
</setup_code>
<teardown_code>
<value><![CDATA[mfsStop(&mfs1);]]></value>
</teardown_code>
<local_variables>
<value />
</local_variables>
</various_code>
<steps>
<step>
<description>
<value>Exploring the records space, MFS_ERR_NOT_FOUND is expected for each index.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[mfs_error_t err;
mfs_id_t id;
size_t size;
for (id = 1; id <= MFS_CFG_MAX_RECORDS; id++) {
size = sizeof mfs_buffer;
err = mfsReadRecord(&mfs1, id, &size, mfs_buffer);
test_assert(err == MFS_ERR_NOT_FOUND,
"found a record that should not exists");
}]]></value>
</code>
</step>
</steps>
</case>
<case>
<brief>
<value>Creating, updating and erasing a record.</value>
</brief>
<description>
<value>A record is created, updated several times with different payloads and finally erased.</value>
</description>
<condition>
<value />
</condition>
<various_code>
<setup_code>
<value><![CDATA[mfsStart(&mfs1, &mfscfg1);]]></value>
</setup_code>
<teardown_code>
<value><![CDATA[mfsStop(&mfs1);]]></value>
</teardown_code>
<local_variables>
<value><![CDATA[size_t size;]]></value>
</local_variables>
</various_code>
<steps>
<step>
<description>
<value>The record must not already exists, MFS_ERR_NOT_FOUND is expected.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[size = sizeof mfs_buffer;
mfs_error_t err = mfsReadRecord(&mfs1, 1, &size, mfs_buffer);
test_assert(err == MFS_ERR_NOT_FOUND , "record was already present");]]></value>
</code>
</step>
<step>
<description>
<value>Creating the record then retrieving it again, MFS_NO_ERROR is expected, record content and size are compared with the original.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[mfs_error_t err;
err = mfsWriteRecord(&mfs1, 1, sizeof pattern1, pattern1);
test_assert(err == MFS_NO_ERROR, "error creating the record");
size = sizeof mfs_buffer;
err = mfsReadRecord(&mfs1, 1, &size, mfs_buffer);
test_assert(err == MFS_NO_ERROR, "record not found");
test_assert(size == sizeof pattern1, "unexpected record length");
test_assert(memcmp(pattern1, mfs_buffer, size) == 0, "wrong record content");]]></value>
</code>
</step>
<step>
<description>
<value>Updating the record then retrieving it again, MFS_NO_ERROR is expected, record content and size are compared with the original.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[mfs_error_t err;
err = mfsWriteRecord(&mfs1, 1, sizeof pattern2, pattern2);
test_assert(err == MFS_NO_ERROR, "error updating the record");
size = sizeof mfs_buffer;
err = mfsReadRecord(&mfs1, 1, &size, mfs_buffer);
test_assert(err == MFS_NO_ERROR, "record not found");
test_assert(size == sizeof pattern2, "unexpected record length");
test_assert(memcmp(pattern2, mfs_buffer, size) == 0, "wrong record content");]]></value>
</code>
</step>
<step>
<description>
<value>Erasing the record then trying to retrieve it again, MFS_NO_ERROR is expected on erase, MFS_ERR_NOT_FOUND is expected on retrieve.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[mfs_error_t err;
err = mfsEraseRecord(&mfs1, 1);
test_assert(err == MFS_NO_ERROR, "error erasing the record");
size = sizeof mfs_buffer;
err = mfsReadRecord(&mfs1, 1, &size, mfs_buffer);
test_assert(err == MFS_ERR_NOT_FOUND, "record not erased");]]></value>
</code>
</step>
</steps>
</case>
<case>
<brief>
<value>Erasing the whole storage.</value>
</brief>
<description>
<value>The managed storage is erased and re-initialized.</value>
</description>
<condition>
<value />
</condition>
<various_code>
<setup_code>
<value><![CDATA[bank_erase(MFS_BANK_0);
bank_erase(MFS_BANK_1);
mfsStart(&mfs1, &mfscfg1);]]></value>
</setup_code>
<teardown_code>
<value><![CDATA[mfsStop(&mfs1);]]></value>
</teardown_code>
<local_variables>
<value />
</local_variables>
</various_code>
<steps>
<step>
<description>
<value>Creating records 1, 2 and 3, MFS_NO_ERROR is expected.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[mfs_error_t err;
err = mfsWriteRecord(&mfs1, 1, sizeof pattern1, pattern1);
test_assert(err == MFS_NO_ERROR, "error creating record 1");
err = mfsWriteRecord(&mfs1, 2, sizeof pattern2, pattern2);
test_assert(err == MFS_NO_ERROR, "error creating record 2");
err = mfsWriteRecord(&mfs1, 3, sizeof pattern3, pattern3);
test_assert(err == MFS_NO_ERROR, "error creating record 3");]]></value>
</code>
</step>
<step>
<description>
<value>Erasing storage and verify that the records have been removed, MFS_NO_ERROR is expected on erase, MFS_ERR_NOT_FOUND is expected on retrieve.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[mfs_error_t err;
size_t size;
err = mfsErase(&mfs1);
test_assert(err == MFS_NO_ERROR, "storage erase error");
size = sizeof mfs_buffer;
err = mfsReadRecord(&mfs1, 1, &size, mfs_buffer);
test_assert(err == MFS_ERR_NOT_FOUND, "record 0 still present");
size = sizeof mfs_buffer;
err = mfsReadRecord(&mfs1, 2, &size, mfs_buffer);
test_assert(err == MFS_ERR_NOT_FOUND, "record 1 still present");
size = sizeof mfs_buffer;
err = mfsReadRecord(&mfs1, 3, &size, mfs_buffer);
test_assert(err == MFS_ERR_NOT_FOUND, "record 2 still present");]]></value>
</code>
</step>
</steps>
</case>
<case>
<brief>
<value>Testing storage size limit.</value>
</brief>
<description>
<value>The storage is entirely filled with different records and the final error is tested.</value>
</description>
<condition>
<value />
</condition>
<various_code>
<setup_code>
<value><![CDATA[mfsStart(&mfs1, &mfscfg1);
mfsErase(&mfs1);]]></value>
</setup_code>
<teardown_code>
<value><![CDATA[mfsStop(&mfs1);]]></value>
</teardown_code>
<local_variables>
<value />
</local_variables>
</various_code>
<steps>
<step>
<description>
<value>Filling up the storage by writing records with increasing IDs, MFS_NO_ERROR is expected.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[mfs_id_t id;
mfs_id_t id_max = (mfscfg1.bank_size - sizeof (mfs_bank_header_t)) /
(sizeof (mfs_data_header_t) + sizeof pattern512);
for (id = 1; id <= id_max; id++) {
mfs_error_t err;
size_t size;
err = mfsWriteRecord(&mfs1, id, sizeof pattern512, pattern512);
test_assert(err == MFS_NO_ERROR, "error creating the record");
size = sizeof mfs_buffer;
err = mfsReadRecord(&mfs1, id, &size, mfs_buffer);
test_assert(err == MFS_NO_ERROR,
"record not found");
test_assert(size == sizeof pattern512,
"unexpected record length");
test_assert(memcmp(pattern512, mfs_buffer, size) == 0,
"wrong record content");
}]]></value>
</code>
</step>
<step>
<description>
<value>Creating one more record, should fail, MFS_ERR_OUT_OF_MEM is expected.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[mfs_error_t err;
mfs_id_t id_max = (mfscfg1.bank_size - sizeof (mfs_bank_header_t)) /
(sizeof (mfs_data_header_t) + sizeof pattern512);
err = mfsWriteRecord(&mfs1, id_max, sizeof pattern512 , pattern512);
test_assert(err == MFS_ERR_OUT_OF_MEM, "creation didn't fail");]]></value>
</code>
</step>
<step>
<description>
<value>Adding a smaller record to fill the final gap. A reinitialization is performed and MFS_NO_ERROR is expected.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[mfs_error_t err;
size_t remaining;
remaining = (size_t)flashGetSectorOffset(mfscfg1.flashp, mfscfg1.bank0_start) +
(size_t)mfscfg1.bank_size - (size_t)mfs1.next_offset;
test_assert(remaining >= sizeof (mfs_data_header_t), "not enough space");
if (remaining > sizeof (mfs_data_header_t) * 2) {
err = mfsWriteRecord(&mfs1, MFS_CFG_MAX_RECORDS,
remaining - (sizeof (mfs_data_header_t) * 2),
pattern512);
test_assert(err == MFS_NO_ERROR, "error filling remaining space");
err = mfsEraseRecord(&mfs1, MFS_CFG_MAX_RECORDS);
test_assert(err == MFS_NO_ERROR, "error filling remaining space");
}
else {
if (remaining == sizeof (mfs_data_header_t) * 2) {
err = mfsEraseRecord(&mfs1, 2);
test_assert(err == MFS_NO_ERROR, "error filling remaining space");
}
err = mfsEraseRecord(&mfs1, 1);
test_assert(err == MFS_NO_ERROR, "error filling remaining space");
}
remaining = (size_t)flashGetSectorOffset(mfscfg1.flashp, mfscfg1.bank0_start) +
(size_t)mfscfg1.bank_size - (size_t)mfs1.next_offset;
test_assert(remaining == 0U, "remaining space not zero");
mfsStop(&mfs1);
err = mfsStart(&mfs1, &mfscfg1);
test_assert(err == MFS_NO_ERROR, "initialization error");]]></value>
</code>
</step>
</steps>
</case>
<case>
<brief>
<value>Testing garbage collection by writing.</value>
</brief>
<description>
<value>The garbage collection procedure is triggeredby a write operation and the state of both banks is checked.</value>
</description>
<condition>
<value />
</condition>
<various_code>
<setup_code>
<value><![CDATA[mfsStart(&mfs1, &mfscfg1);
mfsErase(&mfs1);]]></value>
</setup_code>
<teardown_code>
<value><![CDATA[mfsStop(&mfs1);]]></value>
</teardown_code>
<local_variables>
<value />
</local_variables>
</various_code>
<steps>
<step>
<description>
<value>Filling up the storage by writing records with increasing IDs, MFS_NO_ERROR is expected.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[mfs_id_t id;
mfs_id_t id_max = (mfscfg1.bank_size - sizeof (mfs_bank_header_t)) /
(sizeof (mfs_data_header_t) + sizeof pattern512);
for (id = 1; id <= id_max; id++) {
mfs_error_t err;
size_t size;
err = mfsWriteRecord(&mfs1, id, sizeof pattern512, pattern512);
test_assert(err == MFS_NO_ERROR, "error creating the record");
size = sizeof mfs_buffer;
err = mfsReadRecord(&mfs1, id, &size, mfs_buffer);
test_assert(err == MFS_NO_ERROR,
"record not found");
test_assert(size == sizeof pattern512,
"unexpected record length");
test_assert(memcmp(pattern512, mfs_buffer, size) == 0,
"wrong record content");
}]]></value>
</code>
</step>
<step>
<description>
<value>Erasing one record, MFS_NO_ERROR is expected.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[mfs_error_t err;
size_t size;
err = mfsEraseRecord(&mfs1, 1);
test_assert(err == MFS_NO_ERROR, "error erasing the record");
size = sizeof mfs_buffer;
err = mfsReadRecord(&mfs1, 1, &size, mfs_buffer);
test_assert(err == MFS_ERR_NOT_FOUND, "record not erased");]]></value>
</code>
</step>
<step>
<description>
<value>Writing one more record triggers garbage collection, MFS_WARN_GC is expected, KS state is checked for correctness after the operation.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[mfs_error_t err;
size_t size;
test_assert(mfs1.current_counter == 1, "not first instance");
err = mfsWriteRecord(&mfs1, 1, sizeof pattern512, pattern512);
test_assert(err == MFS_WARN_GC, "error creating the record");
test_assert(mfs1.current_counter == 2, "not second instance");
size = sizeof mfs_buffer;
err = mfsReadRecord(&mfs1, 1, &size, mfs_buffer);
test_assert(err == MFS_NO_ERROR, "record not found");
test_assert(size == sizeof pattern512, "unexpected record length");
test_assert(memcmp(pattern512, mfs_buffer, size) == 0, "wrong record content");
test_assert(mfs1.current_bank == MFS_BANK_1, "unexpected bank");
test_assert(bank_verify_erased(MFS_BANK_0) == FLASH_NO_ERROR, "bank 0 not erased");]]></value>
</code>
</step>
<step>
<description>
<value>Checking for all records in the new bank, MFS_NOERROR is expected for each record.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[mfs_id_t id;
mfs_id_t id_max = (mfscfg1.bank_size - sizeof (mfs_bank_header_t)) /
(sizeof (mfs_data_header_t) + sizeof pattern512);
for (id = 1; id <= MFS_CFG_MAX_RECORDS; id++) {
mfs_error_t err;
size_t size;
if (id <= id_max) {
size = sizeof mfs_buffer;
err = mfsReadRecord(&mfs1, id, &size, mfs_buffer);
test_assert(err == MFS_NO_ERROR, "record not found");
test_assert(size == sizeof pattern512, "unexpected record length");
test_assert(memcmp(pattern512, mfs_buffer, size) == 0, "wrong record content");
}
else {
size = sizeof mfs_buffer;
err = mfsReadRecord(&mfs1, id, &size, mfs_buffer);
test_assert(err == MFS_ERR_NOT_FOUND, "found unexpected record");
}
}]]></value>
</code>
</step>
<step>
<description>
<value>Erasing one record, MFS_NO_ERROR is expected.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[mfs_error_t err;
size_t size;
err = mfsEraseRecord(&mfs1, 1);
test_assert(err == MFS_NO_ERROR, "error erasing the record");
size = sizeof mfs_buffer;
err = mfsReadRecord(&mfs1, 1, &size, mfs_buffer);
test_assert(err == MFS_ERR_NOT_FOUND, "record not erased");]]></value>
</code>
</step>
<step>
<description>
<value>Writing one more record triggers garbage collection, MFS_WARN_GC is expected, MFS object state is checked for correctness after the operation.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[mfs_error_t err;
size_t size;
test_assert(mfs1.current_counter == 2, "not second instance");
err = mfsWriteRecord(&mfs1, 1, sizeof pattern512, pattern512);
test_assert(err == MFS_WARN_GC, "error creating the record");
test_assert(mfs1.current_counter == 3, "not third instance");
size = sizeof mfs_buffer;
err = mfsReadRecord(&mfs1, 1, &size, mfs_buffer);
test_assert(err == MFS_NO_ERROR, "record not found");
test_assert(size == sizeof pattern512, "unexpected record length");
test_assert(memcmp(pattern512, mfs_buffer, size) == 0, "wrong record content");
test_assert(mfs1.current_bank == MFS_BANK_0, "unexpected bank");
test_assert(bank_verify_erased(MFS_BANK_1) == FLASH_NO_ERROR, "bank 1 not erased");]]></value>
</code>
</step>
<step>
<description>
<value>Checking for all records in the new bank, MFS_NO_ERROR is expected for each record.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[mfs_id_t id;
mfs_id_t id_max = (mfscfg1.bank_size - sizeof (mfs_bank_header_t)) /
(sizeof (mfs_data_header_t) + sizeof pattern512);
for (id = 1; id <= MFS_CFG_MAX_RECORDS; id++) {
mfs_error_t err;
size_t size;
if (id <= id_max) {
size = sizeof mfs_buffer;
err = mfsReadRecord(&mfs1, id, &size, mfs_buffer);
test_assert(err == MFS_NO_ERROR, "record not found");
test_assert(size == sizeof pattern512, "unexpected record length");
test_assert(memcmp(pattern512, mfs_buffer, size) == 0, "wrong record content");
}
else {
size = sizeof mfs_buffer;
err = mfsReadRecord(&mfs1, id, &size, mfs_buffer);
test_assert(err == MFS_ERR_NOT_FOUND, "found unexpected record");
}
}]]></value>
</code>
</step>
</steps>
</case>
<case>
<brief>
<value>Testing garbage collection by erasing</value>
</brief>
<description>
<value>The garbage collection procedure is triggered by an erase operation and the state of both banks is checked.</value>
</description>
<condition>
<value />
</condition>
<various_code>
<setup_code>
<value><![CDATA[mfsStart(&mfs1, &mfscfg1);
mfsErase(&mfs1);]]></value>
</setup_code>
<teardown_code>
<value><![CDATA[mfsStop(&mfs1);]]></value>
</teardown_code>
<local_variables>
<value />
</local_variables>
</various_code>
<steps>
<step>
<description>
<value>Filling up the storage by writing records with increasing IDs, MFS_NO_ERROR is expected.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[mfs_id_t id;
mfs_id_t id_max = (mfscfg1.bank_size - sizeof (mfs_bank_header_t)) /
(sizeof (mfs_data_header_t) + (sizeof pattern512 / 2));
for (id = 1; id <= id_max; id++) {
mfs_error_t err;
size_t size;
err = mfsWriteRecord(&mfs1, id, (sizeof pattern512 / 2), pattern512);
test_assert(err == MFS_NO_ERROR, "error creating the record");
size = sizeof mfs_buffer;
err = mfsReadRecord(&mfs1, id, &size, mfs_buffer);
test_assert(err == MFS_NO_ERROR, "record not found");
test_assert(size == (sizeof pattern512 / 2), "unexpected record length");
test_assert(memcmp(pattern512, mfs_buffer, size) == 0, "wrong record content");
}]]></value>
</code>
</step>
<step>
<description>
<value>Erase records until the flash bank is filled entirely.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[mfs_error_t err;
size_t size;
mfs_id_t id;
mfs_id_t id_max = (mfscfg1.bank_size - sizeof (mfs_bank_header_t)) /
(sizeof (mfs_data_header_t) + (sizeof pattern512 / 2));
mfs_id_t n = ((mfscfg1.bank_size - sizeof (mfs_bank_header_t)) -
(id_max * (sizeof (mfs_data_header_t) + (sizeof pattern512 / 2)))) /
sizeof (mfs_data_header_t);
for (id = 1; id <= n; id++) {
err = mfsEraseRecord(&mfs1, id);
test_assert(err == MFS_NO_ERROR, "error erasing the record");
size = sizeof mfs_buffer;
err = mfsReadRecord(&mfs1, id, &size, mfs_buffer);
test_assert(err == MFS_ERR_NOT_FOUND, "record not erased");
}]]></value>
</code>
</step>
<step>
<description>
<value>Erasing one more record triggers garbage collection, MFS_WARN_GC is expected, KS state is checked for correctness after the operation.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[mfs_error_t err;
size_t size;
mfs_id_t id_max = (mfscfg1.bank_size - sizeof (mfs_bank_header_t)) /
(sizeof (mfs_data_header_t) + (sizeof pattern512 / 2));
test_assert(mfs1.current_counter == 1, "not first instance");
err = mfsEraseRecord(&mfs1, id_max);
test_assert(err == MFS_WARN_GC, "error erasing the record");
test_assert(mfs1.current_counter == 2, "not second instance");
size = sizeof mfs_buffer;
err = mfsReadRecord(&mfs1, id_max, &size, mfs_buffer);
test_assert(err == MFS_ERR_NOT_FOUND, "record not erased");
test_assert(mfs1.current_bank == MFS_BANK_1, "unexpected bank");
test_assert(bank_verify_erased(MFS_BANK_0) == FLASH_NO_ERROR, "bank 0 not erased");]]></value>
</code>
</step>
</steps>
</case>
</cases>
</sequence>
<sequence>
<type index="0">
<value>Internal Tests</value>
</type>
<brief>
<value>API Invalid Cases tests.</value>
</brief>
<description>
<value>This test sequence tests the error coded returned by the various APIs when called when the system is not initialized.</value>
</description>
<condition>
<value />
</condition>
<shared_code>
<value><![CDATA[#include "mfs.h"]]></value>
</shared_code>
<cases>
<case>
<brief>
<value>Initialization error from APIs.</value>
</brief>
<description>
<value>The API functions are invoked without prior initialization.</value>
</description>
<condition>
<value />
</condition>
<various_code>
<setup_code>
<value />
</setup_code>
<teardown_code>
<value />
</teardown_code>
<local_variables>
<value />
</local_variables>
</various_code>
<steps>
<step>
<description>
<value>The function mfsErase() is called, MFS_ERR_INV_STATE is expected.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[mfs_error_t err = mfsErase(&mfs1);
test_assert(err == MFS_ERR_INV_STATE, "mfsErase() returned wrong status");]]></value>
</code>
</step>
<step>
<description>
<value>The function mfsWriteRecord() is called, MFS_ERR_INV_STATE is expected.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[mfs_error_t err = mfsWriteRecord(&mfs1, 1, 16, mfs_buffer);
test_assert(err == MFS_ERR_INV_STATE, "mfsWriteRecord() returned wrong status");]]></value>
</code>
</step>
<step>
<description>
<value>The function mfsEraseRecord() is called, MFS_ERR_INV_STATE is expected.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[mfs_error_t err = mfsEraseRecord(&mfs1, 1);
test_assert(err == MFS_ERR_INV_STATE, "mfsEraseRecord() returned wrong status");]]></value>
</code>
</step>
<step>
<description>
<value>The function mfsReadRecord() is called, MFS_ERR_INV_STATE is expected.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[size_t size = sizeof mfs_buffer;
mfs_error_t err = mfsReadRecord(&mfs1, 1, &size, mfs_buffer);
test_assert(err == MFS_ERR_INV_STATE, "mfsReadRecord() returned wrong status");]]></value>
</code>
</step>
<step>
<description>
<value>The function mfsPerformGarbageCollection() is called, MFS_ERR_INV_STATE is expected.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[mfs_error_t err = mfsPerformGarbageCollection(&mfs1);
test_assert(err == MFS_ERR_INV_STATE, "mfsPerformGarbageCollection() returned wrong status");]]></value>
</code>
</step>
</steps>
</case>
<case>
<brief>
<value>Erasing non existing record.</value>
</brief>
<description>
<value>An erase operation is attempted on an non-existing record.</value>
</description>
<condition>
<value />
</condition>
<various_code>
<setup_code>
<value><![CDATA[mfsStart(&mfs1, &mfscfg1);
mfsErase(&mfs1);]]></value>
</setup_code>
<teardown_code>
<value><![CDATA[mfsStop(&mfs1);]]></value>
</teardown_code>
<local_variables>
<value />
</local_variables>
</various_code>
<steps>
<step>
<description>
<value>Record one is erased, the error MFS_ERR_NOT_FOUND is expected.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[mfs_error_t err;
err = mfsEraseRecord(&mfs1, 1);
test_assert(err != MFS_NO_ERROR, "record was present");
test_assert(err == MFS_ERR_NOT_FOUND, "invalid error code");]]></value>
</code>
</step>
</steps>
</case>
</cases>
</sequence>
</sequences>
</instance>
</instances>
<exportedFeatures />
</application>
</SPC5-Config>