Fork of my original MQTTGateway

Dependencies:   mbed-http

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