Mbed Cloud example program for workshop in W27 2018.

Dependencies:   MMA7660 LM75B

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