Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers fopen.cpp Source File

fopen.cpp

Go to the documentation of this file.
00001 /*
00002  * mbed Microcontroller Library
00003  * Copyright (c) 2006-2016 ARM Limited
00004  *
00005  * Licensed under the Apache License, Version 2.0 (the "License");
00006  * you may not use this file except in compliance with the License.
00007  * You may obtain a copy of the License at
00008  *
00009  *     http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 
00018 /** @file fopen.cpp Test cases to POSIX file fopen() interface.
00019  *
00020  * Please consult the documentation under the test-case functions for
00021  * a description of the individual test case.
00022  */
00023 
00024 #include "mbed.h"
00025 #include "mbed_config.h"
00026 #include "SDBlockDevice.h"
00027 #include "FATFileSystem.h"
00028 #include "fsfat_debug.h"
00029 #include "fsfat_test.h"
00030 #include "utest/utest.h"
00031 #include "unity/unity.h"
00032 #include "greentea-client/test_env.h"
00033 
00034 #include <stdio.h>
00035 #include <string.h>
00036 #include <stdlib.h>     /*rand()*/
00037 #include <inttypes.h>
00038 #include <errno.h>
00039 /* mbed_retarget.h is included after errno.h so symbols are mapped to
00040  * consistent values for all toolchains */
00041 #include "platform/mbed_retarget.h"
00042 
00043 using namespace utest::v1;
00044 
00045 /// @cond FSFAT_DOXYGEN_DISABLE
00046 #ifdef FSFAT_DEBUG
00047 #define FSFAT_FOPEN_GREENTEA_TIMEOUT_S     3000
00048 #else
00049 #define FSFAT_FOPEN_GREENTEA_TIMEOUT_S     1000
00050 #endif
00051 /// @endcond
00052 
00053 
00054 /* DEVICE_SPI
00055  *  This symbol is defined in targets.json if the target has a SPI interface, which is required for SDCard support.
00056  *
00057  * MBED_CONF_APP_FSFAT_SDCARD_INSTALLED
00058  *  For testing purposes, an SDCard must be installed on the target for the test cases in this file to succeed.
00059  *  If the target has an SD card installed then the MBED_CONF_APP_FSFAT_SDCARD_INSTALLED will be generated
00060  *  from the mbed_app.json, which includes the line
00061  *    {
00062  *    "config": {
00063  *        "UART_RX": "D0",
00064  *        <<< lines removed >>>
00065  *        "DEVICE_SPI": 1,
00066  *        "FSFAT_SDCARD_INSTALLED": 1
00067  *      },
00068  *      <<< lines removed >>>
00069  */
00070 
00071 #if !(DEVICE_SPI && ( defined(MBED_CONF_APP_FSFAT_SDCARD_INSTALLED) || (MBED_CONF_SD_FSFAT_SDCARD_INSTALLED)))
00072 #error [NOT_SUPPORTED] DEVICE_SPI need to be enabled for this test. SDcard need to be installed for this test.
00073 #else
00074 static char fsfat_fopen_utest_msg_g[FSFAT_UTEST_MSG_BUF_SIZE];
00075 #define FSFAT_FOPEN_TEST_MOUNT_PT_NAME      "sd"
00076 #define FSFAT_FOPEN_TEST_MOUNT_PT_PATH      "/" FSFAT_FOPEN_TEST_MOUNT_PT_NAME
00077 #define FSFAT_FOPEN_TEST_WORK_BUF_SIZE_1    64
00078 #define FSFAT_FOPEN_TEST_FILEPATH_MAX_DEPTH 20
00079 static const char *sd_badfile_path = "/sd/badfile.txt";
00080 static const char *sd_testfile_path = "/sd/test.txt";
00081 
00082 SDBlockDevice sd(MBED_CONF_SD_SPI_MOSI, MBED_CONF_SD_SPI_MISO, MBED_CONF_SD_SPI_CLK, MBED_CONF_SD_SPI_CS);
00083 FATFileSystem fs("sd", &sd);
00084 
00085 #define FSFAT_FOPEN_TEST_00      fsfat_fopen_test_00
00086 #define FSFAT_FOPEN_TEST_01      fsfat_fopen_test_01
00087 #define FSFAT_FOPEN_TEST_02      fsfat_fopen_test_02
00088 #define FSFAT_FOPEN_TEST_03      fsfat_fopen_test_03
00089 #define FSFAT_FOPEN_TEST_04      fsfat_fopen_test_04
00090 #define FSFAT_FOPEN_TEST_05      fsfat_fopen_test_05
00091 #define FSFAT_FOPEN_TEST_06      fsfat_fopen_test_06
00092 #define FSFAT_FOPEN_TEST_07      fsfat_fopen_test_07
00093 #define FSFAT_FOPEN_TEST_08      fsfat_fopen_test_08
00094 #define FSFAT_FOPEN_TEST_09      fsfat_fopen_test_09
00095 #define FSFAT_FOPEN_TEST_10      fsfat_fopen_test_10
00096 #define FSFAT_FOPEN_TEST_11      fsfat_fopen_test_11
00097 #define FSFAT_FOPEN_TEST_12      fsfat_fopen_test_12
00098 #define FSFAT_FOPEN_TEST_13      fsfat_fopen_test_13
00099 #define FSFAT_FOPEN_TEST_14      fsfat_fopen_test_14
00100 #define FSFAT_FOPEN_TEST_15      fsfat_fopen_test_15
00101 #define FSFAT_FOPEN_TEST_16      fsfat_fopen_test_16
00102 #define FSFAT_FOPEN_TEST_17      fsfat_fopen_test_17
00103 #define FSFAT_FOPEN_TEST_18      fsfat_fopen_test_18
00104 #define FSFAT_FOPEN_TEST_19      fsfat_fopen_test_19
00105 #define FSFAT_FOPEN_TEST_20      fsfat_fopen_test_20
00106 #define FSFAT_FOPEN_TEST_21      fsfat_fopen_test_21
00107 #define FSFAT_FOPEN_TEST_22      fsfat_fopen_test_22
00108 #define FSFAT_FOPEN_TEST_23      fsfat_fopen_test_23
00109 #define FSFAT_FOPEN_TEST_24      fsfat_fopen_test_24
00110 #define FSFAT_FOPEN_TEST_25      fsfat_fopen_test_25
00111 #define FSFAT_FOPEN_TEST_26      fsfat_fopen_test_26
00112 #define FSFAT_FOPEN_TEST_27      fsfat_fopen_test_27
00113 #define FSFAT_FOPEN_TEST_28      fsfat_fopen_test_28
00114 #define FSFAT_FOPEN_TEST_29      fsfat_fopen_test_29
00115 #define FSFAT_FOPEN_TEST_30      fsfat_fopen_test_30
00116 
00117 
00118 /* support functions */
00119 
00120 /*
00121  * open tests that focus on testing fopen()
00122  * fsfat_handle_t fopen(const char* filename, char* data, size_t* len, fsfat_key_desc_t* kdesc)
00123  */
00124 
00125 /* file data for test_01 */
00126 static fsfat_kv_data_t fsfat_fopen_test_01_kv_data[] = {
00127     { "/sd/fopentst/hello/world/animal/wobbly/dog/foot/frontlft.txt", "missing"},
00128     { NULL, NULL},
00129 };
00130 
00131 
00132 /** @brief
00133  * Split a file path into its component parts, setting '/' characters to '\0', and returning
00134  * pointers to the file path components in the parts array. For example, if
00135  * filepath = "/sd/fopentst/hello/world/animal/wobbly/dog/foot/frontlft.txt" then
00136  *  *parts[0] = "sd"
00137  *  *parts[1] = "fopentst"
00138  *  *parts[2] = "hello"
00139  *  *parts[3] = "world"
00140  *  *parts[4] = "animal"
00141  *  *parts[5] = "wobbly"
00142  *  *parts[6] = "dog"
00143  *  *parts[7] = "foot"
00144  *  *parts[8] = "frontlft.txt"
00145  *   parts[9] = NULL
00146  *
00147  * ARGUMENTS
00148  *  @param  filepath     IN file path string to split into component parts. Expected to start with '/'
00149  *  @param  parts        IN OUT array to hold pointers to parts
00150  *  @param  num          IN number of components available in parts
00151  *
00152  * @return  On success, this returns the number of components in the filepath Returns number of compoee
00153  */
00154 static int32_t fsfat_filepath_split(char *filepath, char *parts[], uint32_t num)
00155 {
00156     uint32_t i = 0;
00157     int32_t ret = -1;
00158     char *z = filepath;
00159 
00160     while (i < num && *z != '\0') {
00161         if (*z == '/') {
00162             *z = '\0';
00163             parts[i] = ++z;
00164             i++;
00165         } else {
00166             z++;
00167         }
00168     }
00169     if (*z == '\0' && i > 0) {
00170         ret = (int32_t) i;
00171     }
00172     return ret;
00173 }
00174 
00175 
00176 /** @brief
00177  * remove all directories and file in the given filepath
00178  *
00179  * ARGUMENTS
00180  *  @param  filepath     IN file path string to split into component parts. Expected to start with '/'
00181  *
00182  * @return  On success, this returns 0, otherwise < 0 is returned;
00183  */
00184 int32_t fsfat_filepath_remove_all(char *filepath)
00185 {
00186     int32_t ret = -1;
00187     int32_t len = 0;
00188     char *fpathbuf = NULL;
00189     char *pos = NULL;
00190 
00191     FSFAT_FENTRYLOG("%s:entered\n", __func__);
00192     len = strlen(filepath);
00193     fpathbuf = (char *) malloc(len + 1);
00194     if (fpathbuf == NULL) {
00195         FSFAT_DBGLOG("%s: failed to duplicate string (out of memory)\n", __func__);
00196         return ret;
00197     }
00198     memset(fpathbuf, 0, len + 1);
00199     memcpy(fpathbuf, filepath, len);
00200 
00201     /* delete the leaf node first, and then successively parent directories. */
00202     pos = fpathbuf + strlen(fpathbuf);
00203     while (pos != fpathbuf) {
00204         /* If the remaining file path is the mount point path then finish as the mount point cannot be removed */
00205         if (strlen(fpathbuf) == strlen(FSFAT_FOPEN_TEST_MOUNT_PT_PATH)) {
00206             if (strncmp(fpathbuf, FSFAT_FOPEN_TEST_MOUNT_PT_PATH, strlen(fpathbuf)) == 0) {
00207                 break;
00208             }
00209         }
00210         ret = remove(fpathbuf);
00211         pos = strrchr(fpathbuf, '/');
00212         *pos = '\0';
00213     }
00214     if (fpathbuf) {
00215         free(fpathbuf);
00216     }
00217     return ret;
00218 }
00219 
00220 
00221 /** @brief
00222  * make all directories in the given filepath. Do not create the file if present at end of filepath
00223  *
00224  * ARGUMENTS
00225  *  @param  filepath     IN file path containing directories and file
00226  *  @param  do_asserts   IN set to true if function should assert on errors
00227  *
00228  * @return  On success, this returns 0, otherwise < 0 is returned;
00229  */
00230 static int32_t fsfat_filepath_make_dirs(char *filepath, bool do_asserts)
00231 {
00232     int32_t i = 0;
00233     int32_t num_parts = 0;
00234     int32_t len = 0;
00235     int32_t ret = -1;
00236     char *fpathbuf = NULL;
00237     char *buf = NULL;
00238     int pos = 0;
00239     char *parts[FSFAT_FOPEN_TEST_FILEPATH_MAX_DEPTH];
00240 
00241     FSFAT_DBGLOG("%s:entered\n", __func__);
00242     /* find the dirs to create*/
00243     memset(parts, 0, sizeof(parts));
00244     len = strlen(filepath);
00245     fpathbuf = (char *) malloc(len + 1);
00246     if (fpathbuf == NULL) {
00247         FSFAT_DBGLOG("%s: failed to duplicate string (out of memory)\n", __func__);
00248         return ret;
00249     }
00250     memset(fpathbuf, 0, len + 1);
00251     memcpy(fpathbuf, filepath, len);
00252     num_parts = fsfat_filepath_split(fpathbuf, parts, FSFAT_FOPEN_TEST_FILEPATH_MAX_DEPTH);
00253     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
00254                              "%s:Error: failed to split filepath (filename=\"%s\", num_parts=%d)\n", __func__, filepath, (int) num_parts);
00255     TEST_ASSERT_MESSAGE(num_parts > 0, fsfat_fopen_utest_msg_g);
00256 
00257     /* Now create the directories on the directory path.
00258      * Skip creating dir for "/sd" which must be present */
00259     buf = (char *) malloc(strlen(filepath) + 1);
00260     memset(buf, 0, strlen(filepath) + 1);
00261     pos = sprintf(buf, "/%s", parts[0]);
00262     for (i = 1; i < num_parts - 1; i++) {
00263         pos += sprintf(buf + pos, "/%s", parts[i]);
00264         FSFAT_DBGLOG("mkdir(%s)\n", buf);
00265         ret = mkdir(buf, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
00266         if (do_asserts == true) {
00267             FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
00268                                      "%s:Error: failed to create directory (filepath2=\"%s\", ret=%d, errno=%d)\n", __func__, buf, (int) ret, errno);
00269             TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
00270         }
00271     }
00272 
00273     if (buf) {
00274         free(buf);
00275     }
00276     if (fpathbuf) {
00277         free(fpathbuf);
00278     }
00279     return ret;
00280 }
00281 
00282 /** @brief
00283  * First and last test must format the SD card to FAT FS format:
00284  * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
00285  */
00286 control_t fsfat_fopen_test_00(const size_t call_count)
00287 {
00288     FSFAT_FENTRYLOG("%s:entered\n", __func__);
00289     (void) call_count;
00290     int32_t ret = -1;
00291 
00292     fs.unmount();
00293     ret = fs.format(&sd);
00294     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
00295                              "%s:Error: failed to format sdcard (ret=%d)\n", __func__, (int) ret);
00296     TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
00297     fs.mount(&sd);
00298 
00299     return CaseNext;
00300 }
00301 
00302 
00303 /* FIX ME: errno not set correctly when error occurs. This indicates a problem with the implementation. */
00304 
00305 /** @brief
00306  * Basic fopen test which does the following:
00307  * - creates file and writes some data to the value blob.
00308  * - closes the newly created file.
00309  * - opens the file (r-only)
00310  * - reads the file data and checks its the same as the previously created data.
00311  * - closes the opened file
00312  *
00313  * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
00314  */
00315 static control_t fsfat_fopen_test_01(const size_t call_count)
00316 {
00317     char *read_buf;
00318     int32_t ret = 0;
00319     size_t len = 0;
00320     fsfat_kv_data_t *node;
00321     FILE *fp = NULL;
00322 
00323     FSFAT_DBGLOG("%s:entered\n", __func__);
00324     (void) call_count;
00325     node = fsfat_fopen_test_01_kv_data;
00326 
00327     /* remove file and directory from a previous failed test run, if present */
00328     fsfat_filepath_remove_all((char *) node->filename);
00329 
00330     /* create dirs */
00331     ret = fsfat_filepath_make_dirs((char *) node->filename, true);
00332     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
00333                              "%s:Error: failed to create dirs for filename (filename=\"%s\")(ret=%d)\n", __func__, node->filename, (int) ret);
00334     TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
00335 
00336     FSFAT_DBGLOG("%s:About to create new file (filename=\"%s\", data=\"%s\")\n", __func__, node->filename, node->value);
00337     fp = fopen(node->filename, "w+");
00338     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
00339                              "%s:Error: failed to create file (filename=\"%s\", data=\"%s\")(ret=%d, errno=%d)\n", __func__, node->filename,
00340                              node->value, (int) ret, errno);
00341     TEST_ASSERT_MESSAGE(fp != NULL, fsfat_fopen_utest_msg_g);
00342 
00343     FSFAT_DBGLOG("%s:length of file=%d (filename=\"%s\", data=\"%s\")\n", __func__, (int) len, node->filename, node->value);
00344     len = strlen(node->value);
00345     ret = fwrite((const void *) node->value, len, 1, fp);
00346     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
00347                              "%s:Error: failed to write file (filename=\"%s\", data=\"%s\")(ret=%d)\n", __func__, node->filename, node->value,
00348                              (int) ret);
00349     TEST_ASSERT_MESSAGE(ret == 1, fsfat_fopen_utest_msg_g);
00350 
00351     FSFAT_DBGLOG("Created file successfully (filename=\"%s\", data=\"%s\")\n", node->filename, node->value);
00352     ret = fclose(fp);
00353     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
00354                              "%s:Error: failed to close file (ret=%d, errno=%d)\n", __func__, (int) ret, errno);
00355     TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
00356 
00357     /* now open the newly created key */
00358     fp = NULL;
00359     fp = fopen(node->filename, "r");
00360     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
00361                              "%s:Error: failed to open file for reading (filename=\"%s\", data=\"%s\")(ret=%d)\n", __func__, node->filename,
00362                              node->value, (int) ret);
00363     TEST_ASSERT_MESSAGE(fp != NULL, fsfat_fopen_utest_msg_g);
00364 
00365     len = strlen(node->value) + 1;
00366     read_buf = (char *) malloc(len);
00367     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
00368                              "%s:Error: failed to allocated read buffer \n", __func__);
00369     TEST_ASSERT_MESSAGE(read_buf != NULL, fsfat_fopen_utest_msg_g);
00370 
00371     FSFAT_DBGLOG("Opened file successfully (filename=\"%s\", data=\"%s\")\n", node->filename, node->value);
00372     memset(read_buf, 0, len);
00373     ret = fread((void *) read_buf, len, 1, fp);
00374     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
00375                              "%s:Error: failed to read file (filename=\"%s\", data=\"%s\", read_buf=\"%s\", ret=%d)\n", __func__, node->filename,
00376                              node->value, read_buf, (int) ret);
00377     /* FIX ME: fread should return the number of items read, not 0 when an item is read successfully.
00378      * This indicates a problem with the implementation, as the correct data is read. The correct assert should be:
00379      *   TEST_ASSERT_MESSAGE(ret == 1, fsfat_fopen_utest_msg_g);
00380      * The following assert is curerntly used until the implementation is fixed
00381      */
00382     TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
00383 
00384     /* check read data is as expected */
00385     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
00386                              "%s:Error: read value data (%s) != expected value data (filename=\"%s\", data=\"%s\", read_buf=\"%s\", ret=%d)\n",
00387                              __func__, read_buf, node->filename, node->value, read_buf, (int) ret);
00388     TEST_ASSERT_MESSAGE(strncmp(read_buf, node->value, strlen(node->value)) == 0, fsfat_fopen_utest_msg_g);
00389 
00390     if (read_buf) {
00391         free(read_buf);
00392     }
00393     ret = fclose(fp);
00394     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
00395                              "%s:Error: fclose() call failed (ret=%d, errno=%d).\n", __func__, (int) ret, errno);
00396     TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
00397     return CaseNext;
00398 }
00399 
00400 static fsfat_kv_data_t fsfat_fopen_test_02_data[] = {
00401     FSFAT_INIT_1_TABLE_MID_NODE,
00402     { NULL, NULL},
00403 };
00404 
00405 /**
00406  * @brief   test to fopen() a pre-existing key and try to write it, which should fail
00407  *          as by default pre-existing keys are opened read-only
00408  *
00409  * Basic open test which does the following:
00410  * - creates file with default rw perms and writes some data to the value blob.
00411  * - closes the newly created file.
00412  * - opens the file with the default permissions (read-only)
00413  * - tries to write the file data which should fail because file was not opened with write flag set.
00414  * - closes the opened key
00415  *
00416  * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
00417  */
00418 control_t fsfat_fopen_test_02(const size_t call_count)
00419 {
00420     int32_t ret = -1;
00421     size_t len = 0;
00422     FILE *fp = NULL;
00423 
00424     FSFAT_FENTRYLOG("%s:entered\n", __func__);
00425     (void) call_count;
00426     len = strlen(fsfat_fopen_test_02_data[0].value);
00427     ret = fsfat_test_create(fsfat_fopen_test_02_data[0].filename, (char *) fsfat_fopen_test_02_data[0].value, len);
00428     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
00429                              "%s:Error: failed to create file (ret=%d).\n", __func__, (int) ret);
00430     TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g);
00431 
00432     /* by default, owner of key opens with read-only permissions*/
00433     fp = fopen(fsfat_fopen_test_02_data[0].filename, "r");
00434     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
00435                              "%s:Error: failed to open file (filename=\"%s\", ret=%d)\n", __func__, fsfat_fopen_test_02_data[0].filename, (int) ret);
00436     TEST_ASSERT_MESSAGE(fp != NULL, fsfat_fopen_utest_msg_g);
00437 
00438     len = strlen(fsfat_fopen_test_02_data[0].value);
00439     ret = fwrite((const void *) fsfat_fopen_test_02_data[0].value, len, 1, fp);
00440     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
00441                              "%s:Error: call to fwrite() succeeded when should have failed for read-only file (filename=\"%s\")(ret=%d).\n",
00442                              __func__, fsfat_fopen_test_02_data[0].filename, (int) ret);
00443     TEST_ASSERT_MESSAGE(ret <= 0, fsfat_fopen_utest_msg_g);
00444 
00445     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: fclose() call failed.\n",
00446                              __func__);
00447     TEST_ASSERT_MESSAGE(fclose(fp) == 0, fsfat_fopen_utest_msg_g);
00448 
00449     return CaseNext;
00450 }
00451 
00452 
00453 /**
00454  * @brief   test to fopen() a pre-existing file and try to write it, which should succeed
00455  *          because the key was opened read-write permissions explicitly
00456  *
00457  * Basic open test which does the following:
00458  * - creates file with default rw perms and writes some data to the value blob.
00459  * - closes the newly created file.
00460  * - opens the file with the rw permissions (non default)
00461  * - tries to write the file data which should succeeds because file was opened with write flag set.
00462  * - closes the opened key
00463  *
00464  * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
00465  */
00466 control_t fsfat_fopen_test_03(const size_t call_count)
00467 {
00468     int32_t ret = -1;
00469     size_t len = 0;
00470     FILE *fp = NULL;
00471 
00472     FSFAT_FENTRYLOG("%s:entered\n", __func__);
00473     (void) call_count;
00474     len = strlen(fsfat_fopen_test_02_data[0].value);
00475     ret = fsfat_test_create(fsfat_fopen_test_02_data[0].filename, (char *) fsfat_fopen_test_02_data[0].value, len);
00476     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
00477                              "%s:Error: failed to create file in store (ret=%d).\n", __func__, (int) ret);
00478     TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g);
00479 
00480     /* opens with read-write permissions*/
00481     fp = fopen(fsfat_fopen_test_02_data[0].filename, "w+");
00482     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
00483                              "%s:Error: failed to open file (filename=\"%s\")(ret=%d)\n", __func__, fsfat_fopen_test_02_data[0].filename, (int) ret);
00484     TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g);
00485 
00486     len = strlen(fsfat_fopen_test_02_data[0].value);
00487     ret = fwrite((const void *) fsfat_fopen_test_02_data[0].value, len, 1, fp);
00488     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
00489                              "%s:Error: call to fwrite() failed when should have succeeded (filename=\"%s\", ret=%d).\n", __func__,
00490                              fsfat_fopen_test_02_data[0].filename, (int) ret);
00491     TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g);
00492 
00493     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: fclose() call failed.\n",
00494                              __func__);
00495     TEST_ASSERT_MESSAGE(fclose(fp) >= 0, fsfat_fopen_utest_msg_g);
00496 
00497     /* clean-up */
00498     ret = remove(fsfat_fopen_test_02_data[0].filename);
00499     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
00500                              "%s:Error: unable to delete file (filename=%s, ret=%d) .\n", __func__, fsfat_fopen_test_02_data[0].filename, (int) ret);
00501     TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g);
00502 
00503     return CaseNext;
00504 }
00505 
00506 
00507 /** @brief  test to call fopen() with a filename string that exceeds the maximum length
00508  * - chanFS supports the exFAT format which should support 255 char filenames
00509  * - check that filenames of this length can be created
00510  *
00511  * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
00512  */
00513 control_t fsfat_fopen_test_04(const size_t call_count)
00514 {
00515     char filename_good[FSFAT_FILENAME_MAX_LENGTH + 1];
00516     char filename_bad[FSFAT_FILENAME_MAX_LENGTH + 2];
00517     int32_t ret = -1;
00518     size_t len = 0;
00519 
00520     FSFAT_FENTRYLOG("%s:entered\n", __func__);
00521     (void) call_count;
00522 
00523     memset(filename_good, 0, FSFAT_FILENAME_MAX_LENGTH + 1);
00524     memset(filename_bad, 0, FSFAT_FILENAME_MAX_LENGTH + 2);
00525     ret = fsfat_test_filename_gen(filename_good, FSFAT_FILENAME_MAX_LENGTH);
00526     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
00527                              "%s:Error: unable to generate filename_good.\n", __func__);
00528     TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g);
00529 
00530     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
00531                              "%s:Error: filename_good is not the correct length (filename_good=%s, len=%d, expected=%d).\n", __func__, filename_good,
00532                              (int) strlen(filename_good), (int) FSFAT_FILENAME_MAX_LENGTH);
00533     TEST_ASSERT_MESSAGE(strlen(filename_good) == FSFAT_FILENAME_MAX_LENGTH, fsfat_fopen_utest_msg_g);
00534 
00535     ret = fsfat_test_filename_gen(filename_bad, FSFAT_FILENAME_MAX_LENGTH + 1);
00536     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
00537                              "%s:Error: unable to generate filename_bad.\n", __func__);
00538     TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g);
00539     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
00540                              "%s:Error: filename_bad is not the correct length (len=%d, expected=%d).\n", __func__, (int) strlen(filename_bad),
00541                              (int) FSFAT_FILENAME_MAX_LENGTH + 1);
00542     TEST_ASSERT_MESSAGE(strlen(filename_bad) == FSFAT_FILENAME_MAX_LENGTH + 1, fsfat_fopen_utest_msg_g);
00543 
00544     len = strlen(filename_good);
00545     ret = fsfat_test_create(filename_good, filename_good, len);
00546     /* FIXME:
00547      * The current implementation can create file with a filename with 9 chars (more than the 8 restriction of FAT32 Short File Names).
00548      * However, the exFAT 255 char filesnames is not supported and hence the following is commented out. Find out what is
00549      * the supported max filename length and change this testcase according.
00550      *
00551      *  FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create file (filename=%s, ret=%d).\n", __func__, filename_good, (int) ret);
00552      *  TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g);
00553      */
00554 
00555     len = strlen(filename_bad);
00556     ret = fsfat_test_create(filename_bad, filename_bad, len);
00557     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
00558                              "%s:Error: created file in store for filename_bad when should have failed (filename=%s, ret=%d).\n", __func__,
00559                              filename_bad, (int) ret);
00560     TEST_ASSERT_MESSAGE(ret < 0, fsfat_fopen_utest_msg_g);
00561     return CaseNext;
00562 }
00563 
00564 
00565 /// @cond FSFAT_DOXYGEN_DISABLE
00566 typedef struct fsfat_fopen_kv_name_ascii_node {
00567     uint32_t code;
00568     uint32_t f_allowed : 1;
00569 } fsfat_fopen_kv_name_ascii_node;
00570 /// @endcond
00571 
00572 static const uint32_t fsfat_fopen_kv_name_ascii_table_code_sentinel_g = 256;
00573 
00574 /*@brief    table recording ascii character codes permitted in kv names */
00575 static fsfat_fopen_kv_name_ascii_node fsfat_fopen_kv_name_ascii_table[] = {
00576     {0, true},          /* code 0-33 allowed*/
00577     {34, false},        /* '"' not allowed */
00578     {35, true},         /* allowed */
00579     {42, false},        /* '*' not allowed */
00580     {43, true},         /* allowed */
00581     {47, false},        /* '/' not allowed */
00582     {48, true},         /* allowed */
00583     {58, false},        /* ':' not allowed */
00584     {59, true},         /* allowed */
00585     {60, false},        /* '<' not allowed */
00586     {61, true},         /* allowed */
00587     {62, false},        /* '?', '>' not allowed */
00588     {64, true},         /* allowed */
00589     {92, false},        /* '\' not allowed */
00590     {93, true},         /* allowed */
00591     {124, false},        /* '!' not allowed */
00592     {125, true},         /* allowed */
00593     {127, false},        /* DEL not allowed */
00594     {128, true},         /* allowed */
00595     {fsfat_fopen_kv_name_ascii_table_code_sentinel_g, false},       /* sentinel */
00596 };
00597 
00598 
00599 /// @cond FSFAT_DOXYGEN_DISABLE
00600 enum fsfat_fopen_kv_name_pos {
00601     fsfat_fopen_kv_name_pos_start = 0x0,
00602     fsfat_fopen_kv_name_pos_mid,
00603     fsfat_fopen_kv_name_pos_end,
00604     fsfat_fopen_kv_name_pos_max
00605 };
00606 /// @endcond
00607 
00608 /** @brief  test to call fopen() with filename that in includes illegal characters
00609  *          - the character(s) can be at the beginning of the filename
00610  *          - the character(s) can be at the end of the filename
00611  *          - the character(s) can be somewhere within the filename string
00612  *          - a max-length string of random characters (legal and illegal)
00613  *          - a max-length string of random illegal characters only
00614  *
00615  * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
00616  */
00617 control_t fsfat_fopen_test_05(const size_t call_count)
00618 {
00619     bool f_allowed = false;
00620     const char *mnt_pt = FSFAT_FOPEN_TEST_MOUNT_PT_PATH;
00621     const char *basename = "goodfile";
00622     const char *extname = "txt";
00623     const size_t basename_len = strlen(basename);
00624     const size_t filename_len = strlen(mnt_pt) + strlen(basename) + strlen(extname) +
00625                                 2; /* extra 2 chars for '/' and '.' in "/sd/goodfile.txt" */
00626     char filename[FSFAT_BUF_MAX_LENGTH];
00627     size_t len = 0;
00628     uint32_t j = 0;
00629     int32_t ret = 0;
00630     fsfat_fopen_kv_name_ascii_node *node = NULL;
00631     uint32_t pos;
00632 
00633     FSFAT_FENTRYLOG("%s:entered\n", __func__);
00634     (void) call_count;
00635 
00636 #ifdef FSFAT_DEBUG
00637     /* symbol only used why debug is enabled */
00638     const char *pos_str = NULL;
00639 #endif
00640 
00641     /* create bad keyname strings with invalid character code at start of keyname */
00642     node = fsfat_fopen_kv_name_ascii_table;
00643     memset(filename, 0, FSFAT_BUF_MAX_LENGTH);
00644     while (node->code !=  fsfat_fopen_kv_name_ascii_table_code_sentinel_g) {
00645         /* loop over range */
00646         for (j = node->code; j < (node + 1)->code; j++) {
00647             if ((j >= 48 && j <= 57) || (j >= 65 && j <= 90) || (j >= 97 && j <= 122)) {
00648                 FSFAT_DBGLOG("%s: skipping alpha-numeric ascii character code %d (%c).\n", __func__, (int) j, (char) j);
00649                 continue;
00650             }
00651 
00652             /* set the start, mid, last character of the name to the test char code */
00653             for (pos = (uint32_t) fsfat_fopen_kv_name_pos_start; pos < (uint32_t) fsfat_fopen_kv_name_pos_max; pos++) {
00654                 len = snprintf(filename, filename_len + 1, "%s/%s.%s", mnt_pt, basename, extname);
00655                 /* overwrite a char at the pos start, mid, end of the filename with an ascii char code (both illegal and legal)*/
00656                 switch (pos) {
00657                     case fsfat_fopen_kv_name_pos_start:
00658                         filename[5] = (char) j; /* 5 so at to write the second basename char (bad chars as first char not accepted)*/
00659                         break;
00660                     case fsfat_fopen_kv_name_pos_mid:
00661                         /* create bad keyname strings with invalid character code in the middle of keyname */
00662                         filename[5 + basename_len / 2] = (char) j;
00663                         break;
00664                     case fsfat_fopen_kv_name_pos_end:
00665                         /* create bad keyname strings with invalid character code at end of keyname */
00666                         filename[5 + basename_len - 1] = (char) j;
00667                         break;
00668                     default:
00669                         FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
00670                                                  "%s:Error: unexpected value of pos (pos=%d).\n", __func__, (int) pos);
00671                         TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g);
00672                         break;
00673                 }
00674 
00675 #ifdef FSFAT_DEBUG
00676                 /* processing only required when debug trace enabled */
00677                 switch (pos) {
00678                     case fsfat_fopen_kv_name_pos_start:
00679                         pos_str = "start";
00680                         break;
00681                     case fsfat_fopen_kv_name_pos_mid:
00682                         pos_str = "middle";
00683                         break;
00684                     case fsfat_fopen_kv_name_pos_end:
00685                         pos_str = "end";
00686                         break;
00687                     default:
00688                         break;
00689                 }
00690 #endif
00691                 ret = fsfat_test_create(filename, (const char *) filename, len);
00692 
00693                 /* special cases */
00694                 switch (j) {
00695                     //case 0 :
00696                     //case 46 :
00697                     //    switch(pos)
00698                     //    {
00699                     //    /* for code = 0 (null terminator). permitted at mid and end of string */
00700                     //    /* for code = 46 ('.'). permitted at mid and end of string but not at start */
00701                     //    case fsfat_fopen_kv_name_pos_start:
00702                     //        f_allowed = false;
00703                     //        break;
00704                     //    case fsfat_fopen_kv_name_pos_mid:
00705                     //    case fsfat_fopen_kv_name_pos_end:
00706                     //    default:
00707                     //        f_allowed = true;
00708                     //        break;
00709                     //    }
00710                     //    break;
00711                     default:
00712                         f_allowed = node->f_allowed;
00713                         break;
00714                 }
00715                 if (f_allowed == true) {
00716                     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
00717                                              "%s:Error: failed to create file in store when filename contains valid characters (code=%d, ret=%d).\n", __func__,
00718                                              (int) j, (int) ret);
00719                     TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g);
00720                     /* revert FSFAT_LOG for more trace */
00721                     FSFAT_DBGLOG("Successfully created a file with valid keyname containing ascii character code %d (%c) at the %s of the keyname.\n",
00722                                  (int) j, (int) j, pos_str);
00723                     FSFAT_LOG("%c", '.');
00724 
00725                     ret = fsfat_test_delete(filename);
00726                     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
00727                                              "%s:Error: failed to delete file previously created (code=%d, ret=%d).\n", __func__, (int) j, (int) ret);
00728                     TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g);
00729                 } else {
00730                     /*node->f_allowed == false => not allowed to create kv name with ascii code */
00731                     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
00732                                              "%s:Error: created file in store when filename contains an invalid character (code=%d, ret=%d).\n", __func__, (int) j,
00733                                              (int) ret);
00734                     TEST_ASSERT_MESSAGE(ret < 0, fsfat_fopen_utest_msg_g);
00735                     /* revert FSFAT_LOG for more trace */
00736                     FSFAT_DBGLOG("Successfully failed to create a file with an invalid keyname containing ascii character code %d at the %s of the keyname.\n",
00737                                  (int) j, pos_str);
00738                     FSFAT_LOG("%c", '.');
00739                 }
00740             }
00741         }
00742         node++;
00743     }
00744 
00745     FSFAT_LOG("%c", '\n');
00746     return CaseNext;
00747 }
00748 
00749 
00750 static const char fsfat_fopen_ascii_illegal_buf_g[] = "\"�'*+,./:;<=>?[\\]|";
00751 
00752 /** @brief  test to call fopen() with filename that in includes
00753  *          illegal characters
00754  *          - a max-length string of random illegal characters only
00755  *
00756  * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
00757  */
00758 control_t fsfat_fopen_test_06(const size_t call_count)
00759 {
00760     const char *mnt_pt = FSFAT_FOPEN_TEST_MOUNT_PT_PATH;
00761     const char *extname = "txt";
00762     const size_t filename_len = strlen(mnt_pt) + FSFAT_MAX_FILE_BASENAME + strlen(extname) +
00763                                 2; /* extra 2 chars for '/' and '.' in "/sd/goodfile.txt" */
00764     char filename[FSFAT_BUF_MAX_LENGTH];
00765     int32_t i = 0;
00766     int32_t j = 0;
00767     uint32_t pos = 0;
00768     uint32_t len = 0;
00769     int32_t ret = -1;
00770     size_t buf_data_max = 0;
00771 
00772     FSFAT_FENTRYLOG("%s:entered\n", __func__);
00773     (void) call_count;
00774 
00775     memset(filename, 0, FSFAT_BUF_MAX_LENGTH);
00776     /* create bad keyname strings with invalid character code at start of keyname */
00777     buf_data_max = strlen(fsfat_fopen_ascii_illegal_buf_g);
00778 
00779     /* generate a number of illegal filenames */
00780     for (j = 0; i < FSFAT_MAX_FILE_BASENAME; j++) {
00781         /* generate a kv name of illegal chars*/
00782         len = snprintf(filename, filename_len + 1, "%s/", mnt_pt);
00783         for (i = 0; i < FSFAT_MAX_FILE_BASENAME; i++) {
00784             pos = rand() % (buf_data_max + 1);
00785             len += snprintf(filename + len, filename_len + 1, "%c", fsfat_fopen_ascii_illegal_buf_g[pos]);
00786 
00787         }
00788         len += snprintf(filename + len, filename_len + 1, ".%s", extname);
00789         ret = fsfat_test_create(filename, filename, len);
00790         FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
00791                                  "%s:Error: created file when filename contains invalid characters (filename=%s, ret=%d).\n", __func__, filename,
00792                                  (int) ret);
00793         TEST_ASSERT_MESSAGE(ret < 0, fsfat_fopen_utest_msg_g);
00794     }
00795     return CaseNext;
00796 }
00797 
00798 
00799 /** @brief  test for errno reporting on a failed fopen()call
00800  *
00801  *  This test does the following:
00802  *  - tries to open a file that does not exist for reading, and checks that a NULL pointer is returned.
00803  *  - checks that errno is not 0 as there is an error.
00804  *  - checks that ferror() returns 1 indicating an error exists.
00805  *
00806  * Note: see NOTE_1 below.
00807  *
00808  * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
00809  */
00810 control_t fsfat_fopen_test_07(const size_t call_count)
00811 {
00812     FILE *f = NULL;
00813     int ret = -1;
00814     int errno_val = 0;
00815     const char *filename = sd_badfile_path;
00816 
00817     FSFAT_FENTRYLOG("%s:entered\n", __func__);
00818     (void) call_count;
00819 
00820     errno = 0;
00821     /* this is expect to fail as the file doesnt exist */
00822     f = fopen(filename, "r");
00823 
00824     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
00825                              "%s:Error: opened non-existent file for reading (filename=%s, f=%p).\n", __func__, filename, f);
00826     TEST_ASSERT_MESSAGE(f == NULL, fsfat_fopen_utest_msg_g);
00827 
00828     /* check errno is set correctly */
00829 #if ! defined(__ARMCC_VERSION) && defined(__GNUC__)
00830     /* Store errno so the current value set  is not changed by new function call */
00831     errno_val = errno;
00832     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
00833                              "%s:Error: errno has unexpected value (errno != 0 expected) (filename=%s, errno=%d).\n", __func__, filename, errno);
00834     TEST_ASSERT_MESSAGE(errno_val != 0, fsfat_fopen_utest_msg_g);
00835 #endif  /* ! defined(__ARMCC_VERSION) && defined(__GNUC__) */
00836     return CaseNext;
00837 }
00838 
00839 
00840 /** @brief  test for operation of clearerr() and ferror()
00841  *
00842  *  The test does the following:
00843  *  - opens and then closes a file, but keeps a copy of the FILE pointer fp.
00844  *  - set errno to 0.
00845  *  - write to the close file with fwrite(fp) which should return 0 (no writes) and set the errno.
00846  *  - check the error condition is set with ferror().
00847  *  - clear the error with clearerr().
00848  *  - check the error condition is reset with ferror().
00849  *
00850  * NOTE_1: GCC/ARMCC support for setting errno
00851  *  - Documentation (e.g. fwrite() man page) does not explicity say fwrite() sets errno
00852  *    (e.g. for an fwrite() on a read-only file).
00853  *  - GCC libc fwrite() appears to set errno as expected.
00854  *  - ARMCC & IAR libc fwrite() appears not to set errno.
00855  *
00856  * The following ARMCC documents are silent on whether fwrite() sets errno:
00857  * - "ARM C and C++ Libraries and Floating-Point Support".
00858  * - "RL-ARM User Guide fwrite() section".
00859  *
00860  * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
00861  */
00862 control_t fsfat_fopen_test_08(const size_t call_count)
00863 {
00864     FILE *fp = NULL;
00865     int ret = -1;
00866     int ret_ferror = -1;
00867     const char *filename = sd_testfile_path;
00868 
00869     FSFAT_FENTRYLOG("%s:entered\n", __func__);
00870     (void) call_count;
00871 
00872     errno = 0;
00873     fp = fopen(filename, "w+");
00874     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
00875                              "%s:Error: failed to open file (filename=%s, f=%p).\n", __func__, filename, fp);
00876     TEST_ASSERT_MESSAGE(fp != NULL, fsfat_fopen_utest_msg_g);
00877 
00878     /* close the fp but then try to read or write it */
00879     ret = fclose(fp);
00880     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
00881                              "%s:Error: failed to close file (ret=%d, errno=%d)\n", __func__, (int) ret, errno);
00882     TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
00883 
00884     /* open file  */
00885     errno = 0;
00886     fp = fopen(filename, "r");
00887     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
00888                              "%s:Error: failed to open file for reading (filename=\"%s\", ret=%d)\n", __func__, filename, (int) ret);
00889     TEST_ASSERT_MESSAGE(fp != NULL, fsfat_fopen_utest_msg_g);
00890 
00891     /* Perform fwrite() operation that will fail. */
00892     errno = 0;
00893     ret = fwrite("42!", 4, 1, fp);
00894 
00895     ret_ferror = ferror(fp);
00896     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
00897                              "%s:Error: ferror() failed to report error (filename=%s, ret_ferror=%d).\n", __func__, filename, (int) ret_ferror);
00898     TEST_ASSERT_MESSAGE(ret_ferror != 0, fsfat_fopen_utest_msg_g);
00899 
00900     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
00901                              "%s:Error: fwrite successfully wrote to read-only file (filename=%s, ret=%d).\n", __func__, filename, (int) ret);
00902     /* the fwrite() should fail and return 0. */
00903     TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
00904 
00905 #if ! defined(__ARMCC_VERSION) && defined(__GNUC__)
00906     /* check that errno is set. ARMCC appears not to set errno for fwrite() failure. */
00907     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
00908                              "%s:Error: unexpected zero value for errno (filename=%s, ret=%d, errno=%d).\n", __func__, filename, (int) ret, errno);
00909     TEST_ASSERT_MESSAGE(errno != 0, fsfat_fopen_utest_msg_g);
00910 
00911     /* check that errno is set to the expected value (this may change differ for different libc's) */
00912     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
00913                              "%s:Error: errno != EBADF (filename=%s, ret=%d, errno=%d).\n", __func__, filename, (int) ret, errno);
00914     TEST_ASSERT_MESSAGE(errno == EBADF, fsfat_fopen_utest_msg_g);
00915 #endif  /* ! defined(__ARMCC_VERSION) && defined(__GNUC__) */
00916 
00917     /* check clearerr() return clears the error */
00918     clearerr(fp);
00919     ret = ferror(fp);
00920     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
00921                              "%s:Error: ferror() did not return zero value when error has been cleared (filename=%s, ret=%d).\n", __func__, filename,
00922                              (int) ret);
00923     TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
00924 
00925     fclose(fp);
00926     return CaseNext;
00927 }
00928 
00929 
00930 /** @brief  test for operation of ftell()
00931  *
00932  * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
00933  */
00934 control_t fsfat_fopen_test_09(const size_t call_count)
00935 {
00936     FILE *fp = NULL;
00937     int ret = -1;
00938     int32_t len = 0;
00939 
00940     FSFAT_FENTRYLOG("%s:entered\n", __func__);
00941     (void) call_count;
00942 
00943     /* create a file of a certain length */
00944     len = strlen(fsfat_fopen_test_02_data[0].value);
00945     ret = fsfat_test_create(fsfat_fopen_test_02_data[0].filename, (char *) fsfat_fopen_test_02_data[0].value, len);
00946 
00947     errno = 0;
00948     /* Open the file for reading so the file is not truncated to 0 length. */
00949     fp = fopen(fsfat_fopen_test_02_data[0].filename, "r");
00950     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
00951                              "%s:Error: failed to open file (filename=%s, fp=%p, errno=%d).\n", __func__, fsfat_fopen_test_02_data[0].filename, fp,
00952                              errno);
00953     TEST_ASSERT_MESSAGE(fp != NULL, fsfat_fopen_utest_msg_g);
00954 
00955     errno = 0;
00956     ret = fseek(fp, 0, SEEK_END);
00957     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
00958                              "%s:Error: fseek() failed to SEEK_END (filename=%s, ret=%d, errno=%d).\n", __func__,
00959                              fsfat_fopen_test_02_data[0].filename, (int) ret, errno);
00960     TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
00961 
00962     errno = 0;
00963     ret = ftell(fp);
00964     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
00965                              "%s:Error: ftell() failed to report correct offset value (filename=%s, ret=%d, errno=%d).\n", __func__,
00966                              fsfat_fopen_test_02_data[0].filename, (int) ret, errno);
00967     TEST_ASSERT_MESSAGE(ret == len, fsfat_fopen_utest_msg_g);
00968 
00969     errno = 0;
00970     ret = fclose(fp);
00971     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
00972                              "%s:Error: failed to close file (ret=%d, errno=%d)\n", __func__, (int) ret, errno);
00973     TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
00974 
00975     return CaseNext;
00976 }
00977 
00978 
00979 /* file data for test_10 */
00980 static fsfat_kv_data_t fsfat_fopen_test_10_kv_data[] = {
00981     { "/sd/test_10/testfile.txt", "test_data"},
00982     { NULL, NULL},
00983 };
00984 
00985 /** @brief  test for operation of remove()
00986  *
00987  * Performs the following tests:
00988  *  1. test remove() on a file that exists. This should succeed.
00989  *  2. test remove() on a dir that exists. This should succeed.
00990  *  3. test remove() on a file that doesnt exist. This should fail. check errno set.
00991  *  4. test remove() on a dir that doesnt exist. This should fail. check errno set.
00992  *
00993  * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
00994  */
00995 control_t fsfat_fopen_test_10(const size_t call_count)
00996 {
00997     char buf[FSFAT_FOPEN_TEST_WORK_BUF_SIZE_1];
00998     char *pos = NULL;
00999     int32_t ret = -1;
01000     size_t len = 0;
01001     fsfat_kv_data_t *node = fsfat_fopen_test_10_kv_data;
01002 
01003     FSFAT_FENTRYLOG("%s:entered\n", __func__);
01004     (void) call_count;
01005 
01006     TEST_ASSERT(strlen(node->filename) < FSFAT_FOPEN_TEST_WORK_BUF_SIZE_1);
01007 
01008     /* start from a known state i.e. directory to be created in not present */
01009     fsfat_filepath_remove_all((char *) node->filename);
01010 
01011     /* (1) */
01012     errno = 0;
01013     ret = fsfat_filepath_make_dirs((char *) node->filename, false);
01014     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
01015                              "%s:Error: failed to create dir (dirname=%s, ret=%d, errno=%d)\n", __func__, node->filename, (int) ret, errno);
01016     TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
01017 
01018     len = strlen(node->value);
01019     ret = fsfat_test_create(node->filename, (char *) node->value, len);
01020     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
01021                              "%s:Error: failed to create file (ret=%d).\n", __func__, (int) ret);
01022     TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g);
01023 
01024     ret = remove(node->filename);
01025     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
01026                              "%s:Error: delete file operation failed (filename=%s, ret=%d) .\n", __func__, node->filename, (int) ret);
01027     TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
01028 
01029     /* (3) */
01030     ret = remove(node->filename);
01031     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
01032                              "%s:Error: deleted a file that doesn't exist (filename=%s, ret=%d, errno=%d) .\n", __func__, node->filename, (int) ret,
01033                              errno);
01034     TEST_ASSERT_MESSAGE(ret != 0, fsfat_fopen_utest_msg_g);
01035 
01036     /* (2) */
01037     memset(buf, 0, FSFAT_FOPEN_TEST_WORK_BUF_SIZE_1);
01038     memcpy(buf, node->filename, strlen(node->filename));
01039     pos = strrchr(buf, '/');
01040     *pos = '\0';
01041     ret = remove(buf);
01042     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
01043                              "%s:Error: delete directory operation failed (directory name=%s, ret=%d, errno=%d).\n", __func__, buf, (int) ret,
01044                              errno);
01045     TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
01046 
01047     /* (4) */
01048     ret = remove(buf);
01049     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
01050                              "%s:Error: deleted a directory that doesn't exist (directory name=%s, ret=%d, errno=%d).\n", __func__, buf, (int) ret,
01051                              errno);
01052     TEST_ASSERT_MESSAGE(ret != 0, fsfat_fopen_utest_msg_g);
01053 
01054     return CaseNext;
01055 }
01056 
01057 
01058 /* file data for test_11 */
01059 static fsfat_kv_data_t fsfat_fopen_test_11_kv_data[] = {
01060     { "/sd/test_11/step0.txt", "test_data"},
01061     { "/sd/test_11/step1.txt", "test_data"},
01062     { "/sd/test_11/subdir/step3.txt", "test_data"},
01063     { NULL, NULL},
01064 };
01065 
01066 /** @brief  test for operation of rename()
01067  *
01068  * This test does the following:
01069  *  1) test rename() on a file that exists to a new filename within the same directory.
01070  *  2) test rename() on a file that exists to a new filename within a different directory.
01071  *
01072  * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
01073  */
01074 control_t fsfat_fopen_test_11(const size_t call_count)
01075 {
01076     int32_t ret = -1;
01077     size_t len = 0;
01078     fsfat_kv_data_t *node = fsfat_fopen_test_11_kv_data;
01079 
01080     FSFAT_FENTRYLOG("%s:entered\n", __func__);
01081     (void) call_count;
01082 
01083     TEST_ASSERT(strlen(node->filename) < FSFAT_FOPEN_TEST_WORK_BUF_SIZE_1);
01084 
01085     /* start from a known state i.e. directory to be created in not present, files not present */
01086     while (node->filename != NULL) {
01087         fsfat_filepath_remove_all((char *) node->filename);
01088         node++;
01089     }
01090 
01091     /* create file and directories ready for rename() tests */
01092     errno = 0;
01093     node = fsfat_fopen_test_11_kv_data;
01094     ret = fsfat_filepath_make_dirs((char *) node->filename, false);
01095     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
01096                              "%s:Error: failed to create dir (dirname=%s, ret=%d, errno=%d)\n", __func__, node->filename, (int) ret, errno);
01097     TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
01098 
01099     len = strlen(node->value);
01100     ret = fsfat_test_create(node->filename, (char *) node->value, len);
01101     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
01102                              "%s:Error: failed to create file (ret=%d).\n", __func__, (int) ret);
01103     TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g);
01104 
01105     errno = 0;
01106     node = &fsfat_fopen_test_11_kv_data[2];
01107     ret = fsfat_filepath_make_dirs((char *) node->filename, false);
01108     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
01109                              "%s:Error: failed to create dir (dirname=%s, ret=%d, errno=%d)\n", __func__, node->filename, (int) ret, errno);
01110     TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
01111 
01112     /* (1) */
01113     ret = rename(fsfat_fopen_test_11_kv_data[0].filename, fsfat_fopen_test_11_kv_data[1].filename);
01114     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
01115                              "%s:Error: unable to rename file from (%s) to (%s) (ret=%d, errno=%d).\n", __func__,
01116                              fsfat_fopen_test_11_kv_data[0].filename, fsfat_fopen_test_11_kv_data[1].filename, (int) ret, errno);
01117     TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
01118 
01119     /* (2) */
01120     ret = rename(fsfat_fopen_test_11_kv_data[1].filename, fsfat_fopen_test_11_kv_data[2].filename);
01121     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
01122                              "%s:Error: unable to rename file from (%s) to (%s) (ret=%d, errno=%d).\n", __func__,
01123                              fsfat_fopen_test_11_kv_data[1].filename, fsfat_fopen_test_11_kv_data[2].filename, (int) ret, errno);
01124     TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
01125 
01126     return CaseNext;
01127 }
01128 
01129 
01130 /* file data for test_12 */
01131 static fsfat_kv_data_t fsfat_fopen_test_12_kv_data[] = {
01132     { "/sd/test_12/subdir/testfil1.txt", "testfil1.txt"},
01133     { "/sd/test_12/testfil2.txt", "testfil2.txt"},
01134     { "/sd/test_12/testfil3.txt", "testfil3.txt"},
01135     { "/sd/test_12/testfil4.txt", "testfil4.txt"},
01136     { "/sd/test_12/testfil5.txt", "testfil5.txt"},
01137     { NULL, NULL},
01138 };
01139 
01140 /** @brief  test for operation of readdir().
01141  *
01142  * Note, rewinddir(), telldir() and seekdir() dont appear to work reliably.
01143  * opendir() not available on ARM/IAR toolchains.
01144  *
01145  * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
01146  */
01147 control_t fsfat_fopen_test_12(const size_t call_count)
01148 {
01149     char buf[FSFAT_FOPEN_TEST_WORK_BUF_SIZE_1];
01150     char *pos = NULL;
01151     int32_t count = 0;
01152     int32_t ret = -1;
01153     size_t len = 0;
01154     DIR *dir;
01155     struct dirent *dp;
01156     fsfat_kv_data_t *node = fsfat_fopen_test_12_kv_data;
01157 
01158     FSFAT_FENTRYLOG("%s:entered\n", __func__);
01159     (void) call_count;
01160 
01161 #if ! defined(__ARMCC_VERSION) && defined(__GNUC__)
01162 
01163     /* start from a known state i.e. directory to be created in not present */
01164     while (node->filename != NULL) {
01165         fsfat_filepath_remove_all((char *) node->filename);
01166         node++;
01167     }
01168 
01169     /* create a file */
01170     node = fsfat_fopen_test_12_kv_data;
01171     errno = 0;
01172     ret = fsfat_filepath_make_dirs((char *) node->filename, false);
01173     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
01174                              "%s:Error: failed to create dir (dirname=%s, ret=%d, errno=%d)\n", __func__, node->filename, (int) ret, errno);
01175     TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
01176 
01177     node = fsfat_fopen_test_12_kv_data;
01178     while (node->filename != NULL) {
01179         len = strlen(node->value);
01180         ret = fsfat_test_create(node->filename, (char *) node->value, len);
01181         FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
01182                                  "%s:Error: failed to create file (ret=%d).\n", __func__, (int) ret);
01183         TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g);
01184         node++;
01185     }
01186 
01187     node = fsfat_fopen_test_12_kv_data;
01188     memset(buf, 0, FSFAT_FOPEN_TEST_WORK_BUF_SIZE_1);
01189     memcpy(buf, node->filename, strlen(node->filename));
01190     pos = strrchr(buf, '/');
01191     *pos = '\0';
01192     dir = opendir(buf);
01193 
01194     while ((dp = readdir(dir)) != NULL) {
01195         FSFAT_DBGLOG("%s: filename: \"%s\"\n", __func__, dp->d_name);
01196         TEST_ASSERT_MESSAGE(dp != 0, "Error: readdir() failed\n");
01197         FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
01198                                  "%s:Error: unexpected object name (name=%s, expected=%s).\n", __func__, dp->d_name,
01199                                  fsfat_fopen_test_12_kv_data[count].value);
01200         TEST_ASSERT_MESSAGE(strncmp(dp->d_name, fsfat_fopen_test_12_kv_data[count].value,
01201                                     strlen(fsfat_fopen_test_12_kv_data[count].value)) == 0, fsfat_fopen_utest_msg_g);
01202         count++;
01203     }
01204     closedir(dir);
01205 
01206     /* cleanup */
01207     node = fsfat_fopen_test_12_kv_data;
01208     while (node->filename != NULL) {
01209         fsfat_filepath_remove_all((char *) node->filename);
01210         node++;
01211     }
01212 #endif  /* ! defined(__ARMCC_VERSION) && defined(__GNUC__) */
01213     return CaseNext;
01214 }
01215 
01216 
01217 /* file data for test_13 */
01218 static fsfat_kv_data_t fsfat_fopen_test_13_kv_data[] = {
01219     /* a file is included in the filepath even though its not created by the test,
01220      * as the fsfat_filepath_make_dirs() works with it present. */
01221     { "/sd/test_13/dummy.txt", "testdir"},
01222     { NULL, NULL},
01223 };
01224 /** @brief  test for operation of mkdir()/remove()
01225  *
01226  * This test checks that:
01227  * - The mkdir() function successfully creates a directory that is not already present.
01228  * - The mkdir() function returns EEXIST when trying to create a directory thats already present.
01229  * - The remove() function successfully removes a directory that is present.
01230  *
01231  * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
01232  */
01233 control_t fsfat_fopen_test_13(const size_t call_count)
01234 {
01235     int32_t ret = 0;
01236 
01237     FSFAT_DBGLOG("%s:entered\n", __func__);
01238     (void) call_count;
01239 
01240     /* start from a known state i.e. directory to be created in not present */
01241     fsfat_filepath_remove_all((char *) fsfat_fopen_test_13_kv_data[0].filename);
01242 
01243     errno = 0;
01244     ret = fsfat_filepath_make_dirs((char *) fsfat_fopen_test_13_kv_data[0].filename, false);
01245     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
01246                              "%s:Error: failed to create dir (dirname=%s, ret=%d, errno=%d)\n", __func__, fsfat_fopen_test_13_kv_data[0].filename,
01247                              (int) ret, errno);
01248     TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
01249 
01250     /* check that get a suitable error when try to create it again.*/
01251     errno = 0;
01252     ret = fsfat_filepath_make_dirs((char *) fsfat_fopen_test_13_kv_data[0].filename, false);
01253     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
01254                              "%s:Error: permitted to create directory when already exists (dirname=%s, ret=%d, errno=%d)\n", __func__,
01255                              fsfat_fopen_test_13_kv_data[0].filename, (int) ret, errno);
01256     TEST_ASSERT_MESSAGE(ret != 0, fsfat_fopen_utest_msg_g);
01257 
01258     /* check errno is as expected */
01259     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
01260                              "%s:Error: errno != EEXIST (dirname=%s, ret=%d, errno=%d)\n", __func__, fsfat_fopen_test_13_kv_data[0].filename,
01261                              (int) ret, errno);
01262     TEST_ASSERT_MESSAGE(errno == EEXIST, fsfat_fopen_utest_msg_g);
01263 
01264     ret = fsfat_filepath_remove_all((char *) fsfat_fopen_test_13_kv_data[0].filename);
01265     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
01266                              "%s:Error: failed to remove directory (dirname=%s, ret=%d, errno=%d)\n", __func__,
01267                              fsfat_fopen_test_13_kv_data[0].filename, (int) ret, errno);
01268     TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
01269 
01270     return CaseNext;
01271 }
01272 
01273 /* file data for test_14 */
01274 static fsfat_kv_data_t fsfat_fopen_test_14_kv_data[] = {
01275     /* a file is included in the filepath even though its not created by the test,
01276      * as the fsfat_filepath_make_dirs() works with it present. */
01277     { "/sd/test_14/testfile.txt", "testdata"},
01278     { NULL, NULL},
01279 };
01280 
01281 /** @brief  test for operation of stat()
01282  *
01283  * stat() is currently no supported by ARMCC and IAR toolchains libc.
01284  *
01285  * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
01286  */
01287 control_t fsfat_fopen_test_14(const size_t call_count)
01288 {
01289 #if ! defined(__ARMCC_VERSION) && defined(__GNUC__)
01290 
01291     char buf[FSFAT_FOPEN_TEST_WORK_BUF_SIZE_1];
01292     char *pos = NULL;
01293     int32_t ret = -1;
01294     size_t len = 0;
01295     struct stat file_stat;
01296     fsfat_kv_data_t *node = fsfat_fopen_test_14_kv_data;
01297 
01298     FSFAT_FENTRYLOG("%s:entered\n", __func__);
01299     (void) call_count;
01300 
01301     TEST_ASSERT(strlen(node->filename) < FSFAT_FOPEN_TEST_WORK_BUF_SIZE_1);
01302 
01303     /* start from a known state i.e. directory to be created in not present */
01304     fsfat_filepath_remove_all((char *) node->filename);
01305 
01306     /* Create file in a directory. */
01307     errno = 0;
01308     ret = fsfat_filepath_make_dirs((char *) node->filename, false);
01309     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
01310                              "%s:Error: failed to create dir (dirname=%s, ret=%d, errno=%d)\n", __func__, node->filename, (int) ret, errno);
01311     TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
01312 
01313     len = strlen(node->value);
01314     ret = fsfat_test_create(node->filename, (char *) node->value, len);
01315     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
01316                              "%s:Error: failed to create file (ret=%d).\n", __func__, (int) ret);
01317     TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g);
01318 
01319     /* Test stat() on the file returns the correct attribute set */
01320     memset(&file_stat, 0, sizeof(file_stat));
01321     ret = stat(node->filename, &file_stat);
01322     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
01323                              "%s:Error: stat() operation on file failed (filename=%s, ret=%d, errno=%d).\n", __func__, node->filename, (int) ret,
01324                              errno);
01325     TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
01326 
01327     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
01328                              "%s:Error: expected st_mode S_IFREG flag not set (filename=%s).\n", __func__, node->filename);
01329     TEST_ASSERT_MESSAGE((file_stat.st_mode & S_IFREG) == S_IFREG, fsfat_fopen_utest_msg_g);
01330 
01331     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
01332                              "%s:Error: unexpected st_mode S_IFDIR flag set (filename=%s).\n", __func__, node->filename);
01333     TEST_ASSERT_MESSAGE((file_stat.st_mode & S_IFDIR) != S_IFDIR, fsfat_fopen_utest_msg_g);
01334 
01335     /* Test stat() on the directory returns the correct attribute set */
01336     memset(&file_stat, 0, sizeof(file_stat));
01337     memset(buf, 0, FSFAT_FOPEN_TEST_WORK_BUF_SIZE_1);
01338     memcpy(buf, node->filename, strlen(node->filename));
01339     pos = strrchr(buf, '/');
01340     *pos = '\0';
01341     ret = stat(buf, &file_stat);
01342     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
01343                              "%s:Error: stat() operation on directory failed (directory name=%s, ret=%d, errno=%d).\n", __func__, buf, (int) ret,
01344                              errno);
01345     TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
01346 
01347     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
01348                              "%s:Error: unexpected st_mode S_IFREG flag set (directory name=%s).\n", __func__, buf);
01349     TEST_ASSERT_MESSAGE((file_stat.st_mode & S_IFREG) != S_IFREG, fsfat_fopen_utest_msg_g);
01350 
01351     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
01352                              "%s:Error: expected st_mode S_IFDIR flag not set (directory name=%s).\n", __func__, buf);
01353     TEST_ASSERT_MESSAGE((file_stat.st_mode & S_IFDIR) == S_IFDIR, fsfat_fopen_utest_msg_g);
01354 
01355     /* clean up after successful test */
01356     fsfat_filepath_remove_all((char *) node->filename);
01357 
01358 #endif /* ! defined(__ARMCC_VERSION) && defined(__GNUC__) */
01359     return CaseNext;
01360 }
01361 
01362 /** @brief  test for operation of SDFileSystem::format()
01363  *
01364  * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
01365  */
01366 control_t fsfat_fopen_test_15(const size_t call_count)
01367 {
01368 
01369     FSFAT_FENTRYLOG("%s:entered\n", __func__);
01370     (void) call_count;
01371     int32_t ret = -1;
01372 
01373     /* the allocation_unit of 0 means chanFS will use the default for the card (varies according to capacity). */
01374     fs.unmount();
01375     ret = fs.format(&sd);
01376     FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
01377                              "%s:Error: failed to format sdcard (ret=%d)\n", __func__, (int) ret);
01378     TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
01379     fs.mount(&sd);
01380     return CaseNext;
01381 }
01382 
01383 
01384 /* @brief   test utility function to create a file of a given size.
01385  *
01386  * A reference data table is used of so that the data file can be later be
01387  * checked with fsfat_test_check_data_file().
01388  *
01389  * @param   filename    name of the file including path
01390  * @param   data        data to store in file
01391  * @param   len         number of bytes of data present in the data buffer.
01392  */
01393 int32_t fsfat_test_create_data_file(const char *filename, size_t len)
01394 {
01395     int32_t ret = -1;
01396     FILE *fp = NULL;
01397     size_t write_len = 0;
01398     size_t written_len = 0;
01399     int32_t exp = 0;
01400     const int32_t exp_max = 8;      /* so as not to exceed FSFAT_TEST_BYTE_DATA_TABLE_SIZE/2 */
01401 
01402     FSFAT_FENTRYLOG("%s:entered (filename=%s, len=%d).\n", __func__, filename, (int) len);
01403     TEST_ASSERT(len % FSFAT_TEST_BYTE_DATA_TABLE_SIZE == 0);
01404     fp = fopen(filename, "a");
01405     if (fp == NULL) {
01406         return ret;
01407     }
01408 
01409     while (written_len < len) {
01410         /* write fsfat_test_byte_data_table or part thereof, in 9 writes of sizes
01411          * 1, 2, 4, 8, 16, 32, 64, 128, 1, totalling 256 bytes len permitting. */
01412         for (exp = 0; (exp <= exp_max) && (written_len < len); exp++) {
01413             write_len = 0x1 << (exp % exp_max);
01414             write_len = len - written_len  > write_len ? write_len : len - written_len;
01415             ret = fwrite((const void *) &fsfat_test_byte_data_table[written_len % FSFAT_TEST_BYTE_DATA_TABLE_SIZE], write_len, 1,
01416                          fp);
01417             written_len += write_len;
01418             if (ret != 1) {
01419                 FSFAT_DBGLOG("%s:Error: fwrite() failed (ret=%d)\n", __func__, (int) ret);
01420                 ret = -1;
01421                 goto out0;
01422             }
01423         }
01424     }
01425     if (written_len == len) {
01426         ret = 0;
01427     } else {
01428         ret = -1;
01429     }
01430 out0:
01431     fclose(fp);
01432     return ret;
01433 }
01434 
01435 
01436 /* @brief   test utility function to check the data in the specified file is correct.
01437  *
01438  * The data read from the file is check that it agrees with the data written by
01439  * fsfat_test_create_data_file().
01440  *
01441  * @param   filename    name of the file including path
01442  * @param   data        data to store in file
01443  * @param   len         number of bytes of data present in the data buffer.
01444  */
01445 int32_t fsfat_test_check_data_file(const char *filename, size_t len)
01446 {
01447     int32_t ret = -1;
01448     FILE *fp = NULL;
01449     size_t read_len = 0;
01450     uint8_t buf[FSFAT_TEST_BYTE_DATA_TABLE_SIZE];
01451 
01452     FSFAT_FENTRYLOG("%s:entered (filename=%s, len=%d).\n", __func__, filename, (int) len);
01453     TEST_ASSERT(len % FSFAT_TEST_BYTE_DATA_TABLE_SIZE == 0);
01454     fp = fopen(filename, "r");
01455     if (fp == NULL) {
01456         return ret;
01457     }
01458 
01459     while (read_len < len) {
01460         ret = fread((void *) buf, FSFAT_TEST_BYTE_DATA_TABLE_SIZE, 1, fp);
01461         read_len += FSFAT_TEST_BYTE_DATA_TABLE_SIZE;
01462         if (ret == 0) {
01463             /* end of read*/
01464             FSFAT_DBGLOG("%s:unable to read data\n", __func__);
01465             break;
01466         }
01467         if (memcmp(buf, fsfat_test_byte_data_table, FSFAT_TEST_BYTE_DATA_TABLE_SIZE) != 0) {
01468             FSFAT_DBGLOG("%s:Error: read data not as expected (0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x\n",
01469                          __func__,
01470                          buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], buf[12], buf[13],
01471                          buf[14], buf[15]);
01472             ret = -1;
01473             goto out0;
01474         }
01475     }
01476     if (read_len == len) {
01477         ret = 0;
01478     }
01479 out0:
01480     fclose(fp);
01481     return ret;
01482 }
01483 
01484 /* file data for test_16 */
01485 static fsfat_kv_data_t fsfat_fopen_test_16_kv_data[] = {
01486     { "/sd/tst16_0/testfil0.txt", "dummy_data"},
01487     { "/sd/tst16_1/subdir0/testfil0.txt", "dummy_data"},
01488     { "/sd/tst16_2/subdir0/subdir1/testfil0.txt", "dummy_data"},
01489     { "/sd/tst16_3/subdir0/subdir1/subdir2/subdir3/testfil0.txt", "dummy_data"},
01490     { "/sd/tst16_4/subdir0/subdir1/subdir2/subdir3/subdir4/testfil0.txt", "dummy_data"},
01491     { "/sd/tst16_5/subdir0/subdir1/subdir2/subdir3/subdir4/subdir5/testfil0.txt", "dummy_data"},
01492     { "/sd/tst16_6/subdir0/subdir1/subdir2/subdir3/subdir4/subdir5/subdir6/testfil0.txt", "dummy_data"},
01493     { "/sd/tst16_7/subdir0/subdir1/subdir2/subdir3/subdir4/subdir5/subdir6/subdir7/testfil0.txt", "dummy_data"},
01494     { "/sd/tst16_8/subdir0/subdir1/subdir2/subdir3/subdir4/subdir5/subdir6/subdir7/subdir8/testfil0.txt", "dummy_data"},
01495     { "/sd/tst16_9/subdir0/subdir1/subdir2/subdir3/subdir4/subdir5/subdir6/subdir7/subdir8/subdir9/testfil0.txt", "dummy_data"},
01496     { NULL, NULL},
01497 };
01498 
01499 
01500 /** @brief  stress test to write data to fs
01501  *
01502  * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors.
01503  */
01504 control_t fsfat_fopen_test_16(const size_t call_count)
01505 {
01506     int32_t ret = 0;
01507     fsfat_kv_data_t *node = fsfat_fopen_test_16_kv_data;
01508     const int32_t num_blocks = 100; /* each file ~25kB */
01509 
01510     FSFAT_DBGLOG("%s:entered\n", __func__);
01511     (void) call_count;
01512 
01513     /* remove file and directory from a previous failed test run, if present */
01514     while (node->filename != NULL) {
01515         fsfat_filepath_remove_all((char *) node->filename);
01516         node++;
01517     }
01518 
01519     /* create dirs */
01520     node = fsfat_fopen_test_16_kv_data;
01521     while (node->filename != NULL) {
01522         ret = fsfat_filepath_make_dirs((char *) node->filename, true);
01523         FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
01524                                  "%s:Error: failed to create dirs for filename (filename=\"%s\")(ret=%d)\n", __func__, node->filename, (int) ret);
01525         TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
01526         node++;
01527     }
01528 
01529     /* create the data files */
01530     node = fsfat_fopen_test_16_kv_data;
01531     while (node->filename != NULL) {
01532         ret = fsfat_test_create_data_file(node->filename, num_blocks * FSFAT_TEST_BYTE_DATA_TABLE_SIZE);
01533         FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
01534                                  "%s:Error: failed to create data file (filename=\"%s\")(ret=%d)\n", __func__, node->filename, (int) ret);
01535         TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
01536         node++;
01537     }
01538 
01539     /* read the data back and check its as expected */
01540     node = fsfat_fopen_test_16_kv_data;
01541     while (node->filename != NULL) {
01542         ret = fsfat_test_check_data_file(node->filename, num_blocks * FSFAT_TEST_BYTE_DATA_TABLE_SIZE);
01543         FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE,
01544                                  "%s:Error: failed to check data file (filename=\"%s\")(ret=%d)\n", __func__, node->filename, (int) ret);
01545         TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g);
01546         node++;
01547     }
01548 
01549     /* clean up */
01550     node = fsfat_fopen_test_16_kv_data;
01551     while (node->filename != NULL) {
01552         fsfat_filepath_remove_all((char *) node->filename);
01553         node++;
01554     }
01555     return CaseNext;
01556 }
01557 
01558 /// @cond FSFAT_DOXYGEN_DISABLE
01559 utest::v1::status_t greentea_setup(const size_t number_of_cases)
01560 {
01561     GREENTEA_SETUP(FSFAT_FOPEN_GREENTEA_TIMEOUT_S, "default_auto");
01562     return greentea_test_setup_handler(number_of_cases);
01563 }
01564 
01565 Case cases[] = {
01566     /*          1         2         3         4         5         6        7  */
01567     /* 1234567890123456789012345678901234567890123456789012345678901234567890 */
01568     Case("FSFAT_FOPEN_TEST_00: format sd card to FAT FS.", FSFAT_FOPEN_TEST_00),
01569     Case("FSFAT_FOPEN_TEST_01: fopen()/fwrite()/fclose() directories/file in multi-dir filepath.", FSFAT_FOPEN_TEST_01),
01570     Case("FSFAT_FOPEN_TEST_02: fopen(r) pre-existing file try to write it.", FSFAT_FOPEN_TEST_02),
01571     Case("FSFAT_FOPEN_TEST_03: fopen(w+) pre-existing file try to write it.", FSFAT_FOPEN_TEST_03),
01572     Case("FSFAT_FOPEN_TEST_04: fopen() with a filename exceeding the maximum length.", FSFAT_FOPEN_TEST_04),
01573 #ifdef FOPEN_EXTENDED_TESTING
01574     Case("FSFAT_FOPEN_TEST_05: fopen() with bad filenames (extended).", FSFAT_FOPEN_TEST_05),
01575 #endif
01576     Case("FSFAT_FOPEN_TEST_06: fopen() with bad filenames (minimal).", FSFAT_FOPEN_TEST_06),
01577     Case("FSFAT_FOPEN_TEST_07: fopen()/errno handling.", FSFAT_FOPEN_TEST_07),
01578     Case("FSFAT_FOPEN_TEST_08: ferror()/clearerr()/errno handling.", FSFAT_FOPEN_TEST_08),
01579     Case("FSFAT_FOPEN_TEST_09: ftell() handling.", FSFAT_FOPEN_TEST_09),
01580     Case("FSFAT_FOPEN_TEST_10: remove() test.", FSFAT_FOPEN_TEST_10),
01581     Case("FSFAT_FOPEN_TEST_11: rename().", FSFAT_FOPEN_TEST_11),
01582     Case("FSFAT_FOPEN_TEST_12: opendir(), readdir(), closedir() test.", FSFAT_FOPEN_TEST_12),
01583     Case("FSFAT_FOPEN_TEST_13: mkdir() test.", FSFAT_FOPEN_TEST_13),
01584     Case("FSFAT_FOPEN_TEST_14: stat() test.", FSFAT_FOPEN_TEST_14),
01585     Case("FSFAT_FOPEN_TEST_15: format() test.", FSFAT_FOPEN_TEST_15),
01586     Case("FSFAT_FOPEN_TEST_16: write/check n x 25kB data files.", FSFAT_FOPEN_TEST_16),
01587 };
01588 
01589 
01590 /* Declare your test specification with a custom setup handler */
01591 Specification specification(greentea_setup, cases);
01592 
01593 int main()
01594 {
01595     return !Harness::run(specification);
01596 }
01597 /// @endcond
01598 #endif // !(DEVICE_SPI && ( defined(MBED_CONF_APP_FSFAT_SDCARD_INSTALLED) || (MBED_CONF_SD_FSFAT_SDCARD_INSTALLED)))