/* * mbed Microcontroller Library * Copyright (c) 2006-2016 ARM Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ /** @file example2.cpp Test case to demonstrate a subset of the API functions each work correctly. * * Overview of test: * - initialises cfstore * - creates a key called "com.arm.mbed.spv.assets.asset2.payload" with value blob length = 15 = strlen("Grumpy old man")+1. * - writes the data for the key to be "Grumpy old man" * - closes kv. * - opens kv for reading/writing * - reads the value blob and checks its == "Grumpy old man" * - writes the first 11 chars of the value blob to be "Grumpy man" plus a NULL; * - reads the value blob back and checks its as expected * * This test is coded so as to work in the following modes: * - flash sync mode i.e. with caps.asynchronous_ops == false * - flash async mode i.e. with caps.asynchronous_ops == true */ #include "mbed.h" #include "cfstore_config.h" #include "cfstore_test.h" #include "cfstore_debug.h" #include "Driver_Common.h" #include "configuration_store.h" #include "utest/utest.h" #include "unity/unity.h" #include "greentea-client/test_env.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> #include <inttypes.h> using namespace utest::v1; static char cfstore_example2_utest_msg_g[CFSTORE_UTEST_MSG_BUF_SIZE]; /* defines */ /// @cond CFSTORE_DOXYGEN_DISABLE #define PvMemSet memset #define PvStrLen strlen /// @endcond /* report whether built/configured for flash sync or async mode */ static control_t cfstore_example2_test_00(const size_t call_count) { int32_t ret = ARM_DRIVER_ERROR; (void) call_count; ret = cfstore_test_startup(); CFSTORE_TEST_UTEST_MESSAGE(cfstore_example2_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to perform test startup (ret=%d).\n", __func__, (int) ret); TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_example2_utest_msg_g); return CaseNext; } /// @cond CFSTORE_DOXYGEN_DISABLE ARM_CFSTORE_DRIVER *drv = &cfstore_driver; /// @endcond static int32_t CreateKeyValueStore( const char *keyName, const char *data, ARM_CFSTORE_SIZE *dataLength, ARM_CFSTORE_KEYDESC *keyDesc) { int32_t cfsStatus = ARM_DRIVER_ERROR; ARM_CFSTORE_SIZE valueLength = 0; ARM_CFSTORE_HANDLE_INIT(hkey); valueLength = *dataLength; cfsStatus = drv->Create(keyName, valueLength, keyDesc, hkey); TEST_ASSERT_EQUAL(ARM_DRIVER_OK, cfsStatus); valueLength = *dataLength; cfsStatus = drv->Write(hkey, data, &valueLength); /* * (1) Note the following: * - if cfsStatus > 0 then Write() has completed synchronously and returned the number of bytes written (irrespective of the caps.asynchronous_ops attribute). * - if cfsStatus == ARM_DRIVER_OK then: * - if caps.asynchronous_ops == true then the operation will be completed with registered client callback passed to Initialize(). * - if caps.asynchronous_ops == false then the operation has completed synchronously and no bytes were written. * - if cfsStatus < ARM_DRIVER_OK then an error has occurred */ CFSTORE_TEST_UTEST_MESSAGE(cfstore_example2_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to write key (rc=%d)\n", __func__, (int) cfsStatus); TEST_ASSERT_MESSAGE(cfsStatus >= ARM_DRIVER_OK, cfstore_example2_utest_msg_g); CFSTORE_TEST_UTEST_MESSAGE(cfstore_example2_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%sError: valueLength(%d) does not match the expected dataLength(%d)\n", __func__, (int) valueLength, (int) *dataLength); TEST_ASSERT_MESSAGE(*dataLength == valueLength, cfstore_example2_utest_msg_g); CFSTORE_TEST_UTEST_MESSAGE(cfstore_example2_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%sError: Write() return value cfsStatus(%d) does not match the expected dataLength(%d)\n", __func__, (int) cfsStatus, (int) *dataLength); TEST_ASSERT_MESSAGE((int32_t) *dataLength == cfsStatus, cfstore_example2_utest_msg_g); drv->Close(hkey); /* CreateKeyValueStore() returns what was returned from Write(). See (1) above for description. */ return cfsStatus; } static control_t cfstore_example2_test_01(const size_t call_count) { int32_t cfsStatus; ARM_CFSTORE_HANDLE_INIT(hkey); ARM_CFSTORE_HANDLE_INIT(updatedKeyH); ARM_CFSTORE_FMODE flags; ARM_CFSTORE_KEYDESC kdesc; ARM_CFSTORE_SIZE valueLen; char* ptr = NULL; const char key[] = "com.arm.mbed.spv.assets.asset2.payload"; const char value[] = "Grumpy old man"; (void) call_count; // It must not exceed the value_len field specified when the Key-Value pair was created const char newDataToWrite[] = "Grumpy man"; char readBuf[CFSTORE_KEY_NAME_MAX_LENGTH + 1]; ARM_CFSTORE_SIZE len = 0; // Write a key-value pair PvMemSet(&kdesc, 0, sizeof(kdesc)); PvMemSet(&flags, 0, sizeof(flags)); PvMemSet(readBuf, 0, CFSTORE_KEY_NAME_MAX_LENGTH + 1); kdesc.drl = ARM_RETENTION_WHILE_DEVICE_ACTIVE; /* The length supplied to Write() is the number of octets to store in the blob. * Specifying the following value for valueLen will store the terminating null to * a string, for example. */ valueLen = PvStrLen(value) + 1; cfsStatus = drv->Initialize(NULL, NULL); CFSTORE_TEST_UTEST_MESSAGE(cfstore_example2_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Initialize() failed (cfsStatus=%d)\n", __func__, (int) cfsStatus); TEST_ASSERT_MESSAGE(cfsStatus >= ARM_DRIVER_OK, cfstore_example2_utest_msg_g); cfsStatus = CreateKeyValueStore(key, value, &valueLen, &kdesc); /* CreateKeyValueStore() returns the number of characters written, which can vary between 0 and the supplied arg valueLen * - in the case that this example is compiled for flash mode sync, CreateKeyValueStore(), on success should always return valueLen * - in the case that this example is compiled for flash mode async, CreateKeyValueStore() on success may return a value 0 to valueLen * with async notification of the completed transaction. */ CFSTORE_TEST_UTEST_MESSAGE(cfstore_example2_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%sError: valueLen(%d) does not match the expected returned value from CreateKeyValueStore(%d)\n", __func__, (int) valueLen, (int) cfsStatus); TEST_ASSERT_MESSAGE(cfsStatus == (int32_t) valueLen, cfstore_example2_utest_msg_g); // Read key-value pair with 'Write' permission flags.read = true; flags.write = true; cfsStatus = drv->Open(key, flags, hkey); TEST_ASSERT_EQUAL(ARM_DRIVER_OK, cfsStatus); len = sizeof(readBuf); cfsStatus = drv->Read(hkey, readBuf, &len); /* Read() returns the number of characters read, which can vary between 0 and the size of the value blob, and the size of the supplied buffer */ CFSTORE_TEST_UTEST_MESSAGE(cfstore_example2_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Read() returned value (%d) does not match the created length of the value blob(%d)\n", __func__, (int) cfsStatus, (int) PvStrLen(value) + 1); TEST_ASSERT_MESSAGE(cfsStatus == (int32_t) (PvStrLen(value) + 1), cfstore_example2_utest_msg_g); CFSTORE_TEST_UTEST_MESSAGE(cfstore_example2_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Read() returned len value (%d) does not match the created length of the value blob(%d)\n", __func__, (int) len, (int) PvStrLen(value) + 1); TEST_ASSERT_MESSAGE(len == PvStrLen(value) + 1, cfstore_example2_utest_msg_g); /* Note: * - original data = "Grumpy old man", which is 14+1 chars inc NULL * - New data = "Grumpy man" which is 10+1 chars inc NULL * - when the key "com.arm.mbed.spv.assets.asset2.payload"; was created, it was created with a value blob size of 14+1=15 chars. * - The new data is shorter that the old data so it will be accommodated in the value blob * - The size of the value blob will stay the same. */ // Update the value and value length /* note len set to sizeof(newDataToWrite) which includes the terminating null of the string */ len = sizeof(newDataToWrite); cfsStatus = drv->Write(hkey, newDataToWrite, &len); CFSTORE_TEST_UTEST_MESSAGE(cfstore_example2_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Write() returned cfsStatus value (%d) does not match the length of new data written(%d)\n", __func__, (int) cfsStatus, (int) sizeof(newDataToWrite)); TEST_ASSERT_MESSAGE(cfsStatus == (int32_t) sizeof(newDataToWrite), cfstore_example2_utest_msg_g); CFSTORE_TEST_UTEST_MESSAGE(cfstore_example2_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Write() returned len (%d) does not match the length of new data written(%d)\n", __func__, (int) len, (int) sizeof(newDataToWrite)); TEST_ASSERT_MESSAGE((int32_t) len == (int32_t) sizeof(newDataToWrite), cfstore_example2_utest_msg_g); drv->Close(hkey); // Check that the value was updated flags.write = false; cfsStatus = drv->Open(key, flags, updatedKeyH); TEST_ASSERT_EQUAL(ARM_DRIVER_OK, cfsStatus); len = CFSTORE_KEY_NAME_MAX_LENGTH; PvMemSet(readBuf, 0, len); cfsStatus = drv->Read(updatedKeyH, readBuf, &len); CFSTORE_TEST_UTEST_MESSAGE(cfstore_example2_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Read() returned value (%d) does not match the created length of the value blob(%d)\n", __func__, (int) cfsStatus, (int) PvStrLen(value) + 1); TEST_ASSERT_MESSAGE(cfsStatus == (int32_t) (PvStrLen(value) + 1), cfstore_example2_utest_msg_g); CFSTORE_TEST_UTEST_MESSAGE(cfstore_example2_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Read() returned len value (%d) does not match the created length of the value blob(%d)\n", __func__, (int) len, (int) PvStrLen(value) + 1); TEST_ASSERT_MESSAGE(len == (PvStrLen(value) + 1), cfstore_example2_utest_msg_g); /* convert any terminating nulls to '=' */ while( (ptr = (char*) memchr(readBuf, 0, (PvStrLen(value) + 1))) != NULL) { *ptr = '='; } /* check the data is as expected */ CFSTORE_TEST_UTEST_MESSAGE(cfstore_example2_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Read() returned unexpected string (%s) where nulls have been converted to '=' chars\n", __func__, readBuf); TEST_ASSERT_MESSAGE(strncmp(readBuf, "Grumpy man=man=", (PvStrLen(value) + 1)) == 0, cfstore_example2_utest_msg_g); /* revert to CFSTORE_LOG if more trace required */ CFSTORE_DBGLOG("Success: New value of KV (%s) value blob (with nulls converted to '=') = (%s)\n", key, readBuf); drv->Close(updatedKeyH); cfsStatus = drv->Uninitialize(); CFSTORE_TEST_UTEST_MESSAGE(cfstore_example2_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() failed (cfsStatus=%d)\n", __func__, (int) cfsStatus); TEST_ASSERT_MESSAGE(cfsStatus >= ARM_DRIVER_OK, cfstore_example2_utest_msg_g); return CaseNext; } /// @cond CFSTORE_DOXYGEN_DISABLE utest::v1::status_t greentea_setup(const size_t number_of_cases) { GREENTEA_SETUP(400, "default_auto"); return greentea_test_setup_handler(number_of_cases); } Case cases[] = { /* 1 2 3 4 5 6 7 */ /* 1234567890123456789012345678901234567890123456789012345678901234567890 */ Case("EXAMPLE2_test_00", cfstore_example2_test_00), Case("EXAMPLE2_test_01", cfstore_example2_test_01), }; /* Declare your test specification with a custom setup handler */ Specification specification(greentea_setup, cases); int main() { return !Harness::run(specification); } /// @endcond