/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Copyright by The HDF Group.                                               *
 * All rights reserved.                                                      *
 *                                                                           *
 * This file is part of HDF5.  The full HDF5 copyright notice, including     *
 * terms governing use, modification, and redistribution, is contained in    *
 * the COPYING file, which can be found at the root of the source code       *
 * distribution tree, or in https://www.hdfgroup.org/licenses.               *
 * If you do not have access to either file, you may request a copy from     *
 * help@hdfgroup.org.                                                        *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/*
 * Purpose: unit-test functionality of the routines in `tools/lib/h5tools_utils`
 *
 * Jacob Smith 2017-11-10
 */

#include "h5tools.h"
#include "h5tools_utils.h"
#include "h5test.h"

/* Selector for which test cases to run */
typedef enum vfd_tests_e { VFD_TESTS_COMMON, VFD_TESTS_ROS3, VFD_TESTS_HDFS } vfd_tests_e;

/* Whether we pass in H5I_INVALID_HID, H5P_DEFAULT, or a created fapl */
typedef enum fapl_choice_e { FAPL_CHOICE_INVALID, FAPL_CHOICE_DEFAULT, FAPL_CHOICE_CREATE } fapl_choice_e;

/* Test case data */
typedef struct fapl_testcase_t {
    const char    error_message[88];
    herr_t        expected_result;
    fapl_choice_e fapl_choice;
    const char    vfd_name[12];
    void         *fa;
} fapl_testcase_t;

/* Generic "incorrect" VFD struct */
typedef struct other_fa_t {
    int a;
    int b;
    int c;
} other_fa_t;

other_fa_t wrong_fa_g = {0x432, 0xf82, 0x9093};

/******************************/
/* Common test configurations */
/******************************/

fapl_testcase_t common_cases_g[] = {
    {
        "(common) H5I_INVALID_HID + NULL VFD struct (UNEXPECTED SUCCESS)",
        FAIL,
        FAPL_CHOICE_INVALID,
        "",
        NULL,
    },
    {
        "(common) H5I_INVALID_HID + inappropriate VFD struct (UNEXPECTED SUCCESS)",
        FAIL,
        FAPL_CHOICE_INVALID,
        "",
        &wrong_fa_g,
    },
    {
        "(common) H5P_DEFAULT + NULL VFD struct (FAILED)",
        SUCCEED,
        FAPL_CHOICE_DEFAULT,
        "",
        NULL,
    },
    {
        "(common) H5P_DEFAULT + ignored VFD struct (FAILED)",
        SUCCEED,
        FAPL_CHOICE_DEFAULT,
        "",
        &wrong_fa_g,
    },
    {
        "(common) H5Pcreate() + NULL VFD struct (FAILED)",
        SUCCEED,
        FAPL_CHOICE_CREATE,
        "",
        NULL,
    },
    {
        "(common) H5Pcreate() + ignored VFD struct (FAILED)",
        SUCCEED,
        FAPL_CHOICE_CREATE,
        "",
        &wrong_fa_g,
    },
    {
        "(common) H5P_DEFAULT + non-VFD name + NULL VFD struct (UNEXPECTED SUCCESS)",
        FAIL,
        FAPL_CHOICE_DEFAULT,
        "unknown",
        NULL,
    }};

#ifdef H5_HAVE_ROS3_VFD

/****************************/
/* ROS3 test configurations */
/****************************/

H5FD_ros3_fapl_t ros3_anon_fa_g = {1, FALSE, "", "", ""};

fapl_testcase_t ros3_cases_g[] = {{
                                      "(ROS3) H5I_INVALID_HID + NULL VFD struct (UNEXPECTED SUCCESS)",
                                      FAIL,
                                      FAPL_CHOICE_INVALID,
                                      "ros3",
                                      NULL,
                                  },
                                  {
                                      "(ROS3) H5I_INVALID_HID + valid VFD struct (UNEXPECTED SUCCESS)",
                                      FAIL,
                                      FAPL_CHOICE_INVALID,
                                      "ros3",
                                      &ros3_anon_fa_g,
                                  },
                                  {
                                      "(ROS3) H5Pcreate() + NULL VFD struct (UNEXPECTED SUCCESS)",
                                      FAIL,
                                      FAPL_CHOICE_CREATE,
                                      "ros3",
                                      NULL,
                                  },
                                  {
                                      "(ROS3) H5Pcreate() + valid VFD struct (FAILED)",
                                      SUCCEED,
                                      FAPL_CHOICE_CREATE,
                                      "ros3",
                                      &ros3_anon_fa_g,
                                  },
                                  {
                                      "(ROS3) H5P_DEFAULT + valid VFD struct (FAILED)",
                                      SUCCEED,
                                      FAPL_CHOICE_DEFAULT,
                                      "ros3",
                                      &ros3_anon_fa_g,
                                  }};
#endif /* H5_HAVE_ROS3_VFD */

#ifdef H5_HAVE_LIBHDFS

/****************************/
/* HDFS test configurations */
/****************************/

H5FD_hdfs_fapl_t hdfs_fa_g = {
    1,    /* fapl version          */
    "",   /* namenode name         */
    0,    /* namenode port         */
    "",   /* kerberos ticket cache */
    "",   /* user name             */
    2048, /* stream buffer size    */
};

fapl_testcase_t hdfs_cases_g[] = {{
                                      "(HDFS) H5I_INVALID_HID + NULL VFD struct (UNEXPECTED SUCCESS)",
                                      FAIL,
                                      FAPL_CHOICE_INVALID,
                                      "hdfs",
                                      NULL,
                                  },
                                  {
                                      "(HDFS) H5I_INVALID_HID + valid VFD struct (UNEXPECTED SUCCESS)",
                                      FAIL,
                                      FAPL_CHOICE_INVALID,
                                      "hdfs",
                                      &hdfs_fa_g,
                                  },
                                  {
                                      "(HDFS) H5Pcreate() + NULL VFD struct (UNEXPECTED SUCCESS)",
                                      FAIL,
                                      FAPL_CHOICE_CREATE,
                                      "hdfs",
                                      NULL,
                                  },
                                  {
                                      "(HDFS) H5Pcreate() + valid VFD struct (FAILED)",
                                      SUCCEED,
                                      FAPL_CHOICE_CREATE,
                                      "hdfs",
                                      &hdfs_fa_g,
                                  },
                                  {
                                      "(HDFS) H5P_DEFAULT + valid VFD struct (FAILED)",
                                      SUCCEED,
                                      FAPL_CHOICE_DEFAULT,
                                      "hdfs",
                                      &hdfs_fa_g,
                                  }};
#endif /* H5_HAVE_LIBHDFS */

typedef struct tuple_testcase_t {
    const char *test_msg;        /* info about test case */
    const char *in_str;          /* input string */
    int         sep;             /* separator "character" */
    herr_t      expected_result; /* expected SUCCEED / FAIL */
    unsigned    exp_nelems;      /* expected number of elements */
                                 /* (no more than 7!)           */
    const char *exp_elems[7];    /* list of elements (no more than 7!) */
} tuple_testcase_t;

tuple_testcase_t tuple_cases_g[] = {
    {
        "bad start",
        "words(before)",
        ';',
        FAIL,
        0,
        {NULL},
    },
    {
        "tuple not closed",
        "(not ok",
        ',',
        FAIL,
        0,
        {NULL},
    },
    {
        "empty tuple",
        "()",
        '-',
        SUCCEED,
        1,
        {""},
    },
    {
        "no separator",
        "(stuff keeps on going)",
        ',',
        SUCCEED,
        1,
        {"stuff keeps on going"},
    },
    {
        "4-ple, escaped separator",
        "(elem0,elem1,el\\,em2,elem3)", /* "el\,em" */
        ',',
        SUCCEED,
        4,
        {"elem0", "elem1", "el,em2", "elem3"},
    },
    {
        "5-ple, escaped escaped separator",
        "(elem0,elem1,el\\\\,em2,elem3)",
        ',',
        SUCCEED,
        5,
        {"elem0", "elem1", "el\\", "em2", "elem3"},
    },
    {
        "escaped non-comma separator",
        "(5-2-7-2\\-6-2)",
        '-',
        SUCCEED,
        5,
        {"5", "2", "7", "2-6", "2"},
    },
    {
        "embedded close-paren",
        "(be;fo)re)",
        ';',
        SUCCEED,
        2,
        {"be", "fo)re"},
    },
    {
        "embedded non-escaping backslash",
        "(be;fo\\re)",
        ';',
        SUCCEED,
        2,
        {"be", "fo\\re"},
    },
    {
        "double close-paren at end",
        "(be;fore))",
        ';',
        SUCCEED,
        2,
        {"be", "fore)"},
    },
    {
        "empty elements",
        "(;a1;;a4;)",
        ';',
        SUCCEED,
        5,
        {"", "a1", "", "a4", ""},
    },
    {
        "nested tuples with different separators",
        "((4,e,a);(6,2,a))",
        ';',
        SUCCEED,
        2,
        {"(4,e,a)", "(6,2,a)"},
    },
    {
        "nested tuples with same separators",
        "((4,e,a),(6,2,a))",
        ',',
        SUCCEED,
        6,
        {"(4", "e", "a)", "(6", "2", "a)"},
    },
    {
        "real-world use case",
        "(us-east-2,AKIAIMC3D3XLYXLN5COA,ugs5aVVnLFCErO/8uW14iWE3K5AgXMpsMlWneO/+)",
        ',',
        SUCCEED,
        3,
        {"us-east-2", "AKIAIMC3D3XLYXLN5COA", "ugs5aVVnLFCErO/8uW14iWE3K5AgXMpsMlWneO/+"},
    }};

/*----------------------------------------------------------------------------
 *
 * Function:    test_parse_tuple()
 *
 * Purpose:     Provide unit tests and specification for the `parse_tuple()`
 *              function.
 *
 * Return:      SUCCEED/FAIL
 *
 * Programmer:  Jacob Smith
 *              2017-11-11
 *
 *----------------------------------------------------------------------------
 */
static herr_t
test_parse_tuple(void)
{
    tuple_testcase_t tc;
    unsigned         n_tests = 14;
    unsigned         u       = 0;
    unsigned         count   = 0;
    unsigned         elem_u  = 0;
    char           **parsed  = NULL;
    char            *cpy     = NULL;
    herr_t           ret;

    TESTING("arbitrary-count tuple parsing");

    for (u = 0; u < n_tests; u++) {

        tc = tuple_cases_g[u];

        ret = parse_tuple(tc.in_str, tc.sep, &cpy, &count, &parsed);

        if (tc.expected_result != ret)
            FAIL_PUTS_ERROR("unexpected result from parse_tuple()")
        if (tc.exp_nelems != count)
            FAIL_PUTS_ERROR("incorrect number of elements returned from parse_tupble()")

        if (ret == SUCCEED) {
            /* Successful return case checks */
            if (NULL == parsed)
                FAIL_PUTS_ERROR("parsed pointer should not be NULL on success");
            for (elem_u = 0; elem_u < count; elem_u++) {
                if (HDstrcmp(tc.exp_elems[elem_u], parsed[elem_u]))
                    FAIL_PUTS_ERROR("Bad elements detected")
            }
        }
        else {
            /* Failed return case checks */
            if (parsed != NULL)
                FAIL_PUTS_ERROR("should not have returned elements on failure")
        }

        HDfree(cpy);
        HDfree(parsed);

    } /* for each testcase */

    PASSED();
    return SUCCEED;

error:
    HDfree(parsed);
    HDfree(cpy);

    return FAIL;

} /* test_parse_tuple */

/*----------------------------------------------------------------------------
 *
 * Function:    test_populate_ros3_fa()
 *
 * Purpose:     Verify behavior of `populate_ros3_fa()`
 *
 * Return:      SUCCEED/FAIL
 *
 * Programmer:  Jacob Smith
 *              2017-11-13
 *
 *----------------------------------------------------------------------------
 */
#ifdef H5_HAVE_ROS3_VFD
static herr_t
test_populate_ros3_fa(void)
{
    int bad_version = 0xf87a; /* arbitrarily wrong version number */

    TESTING("ros3 fapl population");

    HDassert(bad_version != H5FD_CURR_ROS3_FAPL_T_VERSION);

    /* NULL fapl config pointer fails */
    {
        const char *values[] = {"x", "y", "z"};

        /* Should FAIL */
        if (SUCCEED == h5tools_populate_ros3_fapl(NULL, values))
            TEST_ERROR
    }

    /* NULL values pointer yields default fapl */
    {
        H5FD_ros3_fapl_t fa = {bad_version, TRUE, "u", "v", "w"};

        /* Should PASS */
        if (FAIL == h5tools_populate_ros3_fapl(&fa, NULL))
            TEST_ERROR

        if (fa.version != H5FD_CURR_ROS3_FAPL_T_VERSION)
            TEST_ERROR
        if (fa.authenticate != FALSE)
            TEST_ERROR
        if (HDstrcmp("", fa.aws_region))
            TEST_ERROR
        if (HDstrcmp("", fa.secret_id))
            TEST_ERROR
        if (HDstrcmp("", fa.secret_key))
            TEST_ERROR
    }

    /* all-empty values yields default fapl */
    {
        H5FD_ros3_fapl_t fa       = {bad_version, TRUE, "u", "v", "w"};
        const char      *values[] = {"", "", ""};

        /* Should PASS */
        if (FAIL == h5tools_populate_ros3_fapl(&fa, values))
            TEST_ERROR

        if (fa.version != H5FD_CURR_ROS3_FAPL_T_VERSION)
            TEST_ERROR
        if (fa.authenticate != FALSE)
            TEST_ERROR
        if (HDstrcmp("", fa.aws_region))
            TEST_ERROR
        if (HDstrcmp("", fa.secret_id))
            TEST_ERROR
        if (HDstrcmp("", fa.secret_key))
            TEST_ERROR
    }

    /* successfully set fapl with values
     * excess value is ignored
     */
    {
        H5FD_ros3_fapl_t fa       = {bad_version, FALSE, "a", "b", "c"};
        const char      *values[] = {"x", "y", "z", "a"};

        /* Should PASS */
        if (FAIL == h5tools_populate_ros3_fapl(&fa, values))
            TEST_ERROR

        if (fa.version != H5FD_CURR_ROS3_FAPL_T_VERSION)
            TEST_ERROR
        if (fa.authenticate != TRUE)
            TEST_ERROR
        if (HDstrcmp("x", fa.aws_region))
            TEST_ERROR
        if (HDstrcmp("y", fa.secret_id))
            TEST_ERROR
        if (HDstrcmp("z", fa.secret_key))
            TEST_ERROR
    }

    /* NULL region
     * yields default fapl
     */
    {
        H5FD_ros3_fapl_t fa       = {bad_version, FALSE, "a", "b", "c"};
        const char      *values[] = {NULL, "y", "z", NULL};

        /* Should FAIL */
        if (SUCCEED == h5tools_populate_ros3_fapl(&fa, values))
            TEST_ERROR

        if (fa.version != H5FD_CURR_ROS3_FAPL_T_VERSION)
            TEST_ERROR
        if (fa.authenticate != FALSE)
            TEST_ERROR
        if (HDstrcmp("", fa.aws_region))
            TEST_ERROR
        if (HDstrcmp("", fa.secret_id))
            TEST_ERROR
        if (HDstrcmp("", fa.secret_key))
            TEST_ERROR
    }

    /* empty region
     * yields default fapl
     */
    {
        H5FD_ros3_fapl_t fa       = {bad_version, FALSE, "a", "b", "c"};
        const char      *values[] = {"", "y", "z", NULL};

        /* Should FAIL */
        if (SUCCEED == h5tools_populate_ros3_fapl(&fa, values))
            TEST_ERROR

        if (fa.version != H5FD_CURR_ROS3_FAPL_T_VERSION)
            TEST_ERROR
        if (fa.authenticate != FALSE)
            TEST_ERROR
        if (HDstrcmp("", fa.aws_region))
            TEST_ERROR
        if (HDstrcmp("", fa.secret_id))
            TEST_ERROR
        if (HDstrcmp("", fa.secret_key))
            TEST_ERROR
    }

    /* region overflow
     * yields default fapl
     */
    {
        H5FD_ros3_fapl_t fa       = {bad_version, FALSE, "a", "b", "c"};
        const char      *values[] = {"somewhere over the rainbow not too high "
                                     "there is another rainbow bounding some darkened sky",
                                "y", "z"};

        HDassert(HDstrlen(values[0]) > H5FD_ROS3_MAX_REGION_LEN);

        /* Should FAIL */
        if (SUCCEED == h5tools_populate_ros3_fapl(&fa, values))
            TEST_ERROR

        if (fa.version != H5FD_CURR_ROS3_FAPL_T_VERSION)
            TEST_ERROR
        if (fa.authenticate != FALSE)
            TEST_ERROR
        if (HDstrcmp("", fa.aws_region))
            TEST_ERROR
        if (HDstrcmp("", fa.secret_id))
            TEST_ERROR
        if (HDstrcmp("", fa.secret_key))
            TEST_ERROR
    }

    /* NULL id
     * yields default fapl
     */
    {
        H5FD_ros3_fapl_t fa       = {bad_version, FALSE, "a", "b", "c"};
        const char      *values[] = {"x", NULL, "z", NULL};

        /* Should FAIL */
        if (SUCCEED == h5tools_populate_ros3_fapl(&fa, values))
            TEST_ERROR

        if (fa.version != H5FD_CURR_ROS3_FAPL_T_VERSION)
            TEST_ERROR
        if (fa.authenticate != FALSE)
            TEST_ERROR
        if (HDstrcmp("", fa.aws_region))
            TEST_ERROR
        if (HDstrcmp("", fa.secret_id))
            TEST_ERROR
        if (HDstrcmp("", fa.secret_key))
            TEST_ERROR
    }

    /* empty id (non-empty region, key)
     * yields default fapl
     */
    {
        H5FD_ros3_fapl_t fa       = {bad_version, FALSE, "a", "b", "c"};
        const char      *values[] = {"x", "", "z", NULL};

        /* Should FAIL */
        if (SUCCEED == h5tools_populate_ros3_fapl(&fa, values))
            TEST_ERROR

        if (fa.version != H5FD_CURR_ROS3_FAPL_T_VERSION)
            TEST_ERROR
        if (fa.authenticate != FALSE)
            TEST_ERROR
        if (HDstrcmp("", fa.aws_region))
            TEST_ERROR
        if (HDstrcmp("", fa.secret_id))
            TEST_ERROR
        if (HDstrcmp("", fa.secret_key))
            TEST_ERROR
    }

    /* id overflow
     * partial set: region
     */
    {
        H5FD_ros3_fapl_t fa       = {bad_version, FALSE, "a", "b", "c"};
        const char      *values[] = {"x",
                                "Why is it necessary to solve the problem? "
                                     "What benefits will you receive by solving the problem? "
                                     "What is the unknown? "
                                     "What is it you don't yet understand? "
                                     "What is the information you have? "
                                     "What isn't the problem? "
                                     "Is the information insufficient, redundant, or contradictory? "
                                     "Should you draw a diagram or figure of the problem? "
                                     "What are the boundaries of the problem? "
                                     "Can you separate the various parts of the problem?",
                                "z"};

        HDassert(HDstrlen(values[1]) > H5FD_ROS3_MAX_SECRET_ID_LEN);

        /* Should FAIL */
        if (SUCCEED == h5tools_populate_ros3_fapl(&fa, values))
            TEST_ERROR

        if (fa.version != H5FD_CURR_ROS3_FAPL_T_VERSION)
            TEST_ERROR
        if (fa.authenticate != FALSE)
            TEST_ERROR
        if (HDstrcmp("x", fa.aws_region))
            TEST_ERROR
        if (HDstrcmp("", fa.secret_id))
            TEST_ERROR
        if (HDstrcmp("", fa.secret_key))
            TEST_ERROR
    }

    /* NULL key
     * yields default fapl
     */
    {
        H5FD_ros3_fapl_t fa       = {bad_version, FALSE, "a", "b", "c"};
        const char      *values[] = {"x", "y", NULL, NULL};

        /* Should FAIL */
        if (SUCCEED == h5tools_populate_ros3_fapl(&fa, values))
            TEST_ERROR

        if (fa.version != H5FD_CURR_ROS3_FAPL_T_VERSION)
            TEST_ERROR
        if (fa.authenticate != FALSE)
            TEST_ERROR
        if (HDstrcmp("", fa.aws_region))
            TEST_ERROR
        if (HDstrcmp("", fa.secret_id))
            TEST_ERROR
        if (HDstrcmp("", fa.secret_key))
            TEST_ERROR
    }

    /* empty key (non-empty region, id)
     * yields authenticating fapl
     */
    {
        H5FD_ros3_fapl_t fa       = {bad_version, FALSE, "a", "b", "c"};
        const char      *values[] = {"x", "y", "", NULL};

        /* Should PASS */
        if (FAIL == h5tools_populate_ros3_fapl(&fa, values))
            TEST_ERROR

        if (fa.version != H5FD_CURR_ROS3_FAPL_T_VERSION)
            TEST_ERROR
        if (fa.authenticate != TRUE)
            TEST_ERROR
        if (HDstrcmp("x", fa.aws_region))
            TEST_ERROR
        if (HDstrcmp("y", fa.secret_id))
            TEST_ERROR
        if (HDstrcmp("", fa.secret_key))
            TEST_ERROR
    }

    /* empty key, region (non-empty id)
     * yields default fapl
     */
    {
        H5FD_ros3_fapl_t fa       = {bad_version, FALSE, "a", "b", "c"};
        const char      *values[] = {"", "y", "", NULL};

        /* Should FAIL */
        if (SUCCEED == h5tools_populate_ros3_fapl(&fa, values))
            TEST_ERROR

        if (fa.version != H5FD_CURR_ROS3_FAPL_T_VERSION)
            TEST_ERROR
        if (fa.authenticate != FALSE)
            TEST_ERROR
        if (HDstrcmp("", fa.aws_region))
            TEST_ERROR
        if (HDstrcmp("", fa.secret_id))
            TEST_ERROR
        if (HDstrcmp("", fa.secret_key))
            TEST_ERROR
    }

    /* empty key, id (non-empty region)
     * yields default fapl
     */
    {
        H5FD_ros3_fapl_t fa       = {bad_version, FALSE, "a", "b", "c"};
        const char      *values[] = {"x", "", "", NULL};

        /* Should FAIL */
        if (SUCCEED == h5tools_populate_ros3_fapl(&fa, values))
            TEST_ERROR

        if (fa.version != H5FD_CURR_ROS3_FAPL_T_VERSION)
            TEST_ERROR
        if (fa.authenticate != FALSE)
            TEST_ERROR
        if (HDstrcmp("", fa.aws_region))
            TEST_ERROR
        if (HDstrcmp("", fa.secret_id))
            TEST_ERROR
        if (HDstrcmp("", fa.secret_key))
            TEST_ERROR
    }

    /* key overflow
     * partial set: region, id
     */
    {
        H5FD_ros3_fapl_t fa       = {bad_version, FALSE, "a", "b", "c"};
        const char      *values[] = {"x", "y",
                                "Why is it necessary to solve the problem? "
                                     "What benefits will you receive by solving the problem? "
                                     "What is the unknown? "
                                     "What is it you don't yet understand? "
                                     "What is the information you have? "
                                     "What isn't the problem? "
                                     "Is the information insufficient, redundant, or contradictory? "
                                     "Should you draw a diagram or figure of the problem? "
                                     "What are the boundaries of the problem? "
                                     "Can you separate the various parts of the problem?"};

        HDassert(HDstrlen(values[2]) > H5FD_ROS3_MAX_SECRET_KEY_LEN);

        /* Should FAIL */
        if (SUCCEED == h5tools_populate_ros3_fapl(&fa, values))
            TEST_ERROR

        if (fa.version != H5FD_CURR_ROS3_FAPL_T_VERSION)
            TEST_ERROR
        if (fa.authenticate != FALSE)
            TEST_ERROR
        if (HDstrcmp("x", fa.aws_region))
            TEST_ERROR
        if (HDstrcmp("y", fa.secret_id))
            TEST_ERROR
        if (HDstrcmp("", fa.secret_key))
            TEST_ERROR
    }

    /* use case
     */
    {
        H5FD_ros3_fapl_t fa       = {0, 0, "", "", ""};
        const char      *values[] = {"us-east-2", "AKIAIMC3D3XLYXLN5COA",
                                "ugs5aVVnLFCErO/8uW14iWE3K5AgXMpsMlWneO/+"};

        /* Should PASS */
        if (FAIL == h5tools_populate_ros3_fapl(&fa, values))
            TEST_ERROR

        if (fa.version != 1)
            TEST_ERROR
        if (fa.authenticate != TRUE)
            TEST_ERROR
    }

    PASSED();
    return SUCCEED;

error:

    return FAIL;

} /* test_populate_ros3_fa */
#endif /* H5_HAVE_ROS3_VFD */

/*----------------------------------------------------------------------------
 *
 * Function:    test_set_configured_fapl()
 *
 * Purpose:     Verify `h5tools_get_fapl()` with ROS3 and HDFS VFDs
 *
 * Return:      SUCCEED/FAIL
 *
 * Programmer:  Jacob Smith
 *              2018-07-12
 *
 *----------------------------------------------------------------------------
 */
static herr_t
test_set_configured_fapl(vfd_tests_e test_type, fapl_testcase_t cases[], unsigned n_cases)
{
    hid_t    in_fapl_id  = H5I_INVALID_HID;
    hid_t    out_fapl_id = H5I_INVALID_HID;
    unsigned u;

    if (VFD_TESTS_COMMON == test_type)
        TESTING("set fapl vfd (common)")
    else if (VFD_TESTS_ROS3 == test_type)
        TESTING("set fapl vfd (ros3)")
    else if (VFD_TESTS_HDFS == test_type)
        TESTING("set fapl vfd (hdfs)")

    /* Loop over all test cases */
    for (u = 0; u < n_cases; u++) {
        h5tools_vfd_info_t vfd_info;
        fapl_testcase_t    tc = cases[u];

        /* Setup */
        if (tc.fapl_choice == FAPL_CHOICE_DEFAULT) {
            in_fapl_id = H5P_DEFAULT;
        }
        else if (tc.fapl_choice == FAPL_CHOICE_CREATE) {
            if (H5I_INVALID_HID == (in_fapl_id = H5Pcreate(H5P_FILE_ACCESS)))
                TEST_ERROR
        }
        else
            in_fapl_id = H5I_INVALID_HID;

        /* Test */
        if (!HDstrcmp("", tc.vfd_name))
            out_fapl_id = h5tools_get_fapl(in_fapl_id, NULL);
        else {
            vfd_info.info = tc.fa;
            vfd_info.name = tc.vfd_name;
            out_fapl_id   = h5tools_get_fapl(in_fapl_id, &vfd_info);
        }

        /* Check */
        if ((tc.expected_result == FAIL && H5I_INVALID_HID != out_fapl_id) ||
            (tc.expected_result == SUCCEED && H5I_INVALID_HID == out_fapl_id))
            FAIL_PUTS_ERROR(tc.error_message)

        /* Close */
        if (tc.fapl_choice == FAPL_CHOICE_CREATE && H5Pclose(in_fapl_id) < 0)
            TEST_ERROR
        if (out_fapl_id != H5I_INVALID_HID && H5Pclose(out_fapl_id) < 0)
            TEST_ERROR
    }

    PASSED();
    return SUCCEED;

error:
    H5E_BEGIN_TRY
    {
        H5Pclose(in_fapl_id);
        H5Pclose(out_fapl_id);
    }
    H5E_END_TRY;

    return FAIL;
} /* test_set_configured_fapl */

/*----------------------------------------------------------------------------
 *
 * Function:    main()
 *
 * Purpose:     Run all test functions
 *
 * Return:      EXIT_FAILURE/EXIT_SUCCESS
 *
 * Programmer:  Jacob Smith
 *              2017-11-10
 *
 *----------------------------------------------------------------------------
 */
int
main(void)
{
    int nerrors = 0;

    h5_reset();

    HDprintf("Testing tools VFD functionality.\n");

    nerrors += test_parse_tuple() < 0 ? 1 : 0;
    nerrors += test_set_configured_fapl(VFD_TESTS_COMMON, common_cases_g, 7) < 0 ? 1 : 0;
#ifdef H5_HAVE_ROS3_VFD
    nerrors += test_populate_ros3_fa() < 0 ? 1 : 0;
    nerrors += test_set_configured_fapl(VFD_TESTS_ROS3, ros3_cases_g, 5) < 0 ? 1 : 0;
#endif
#ifdef H5_HAVE_LIBHDFS
    nerrors += test_set_configured_fapl(VFD_TESTS_HDFS, hdfs_cases_g, 5) < 0 ? 1 : 0;
#endif

    if (nerrors) {
        HDprintf("***** %d tools VFD TEST%s FAILED! *****\n", nerrors, nerrors > 1 ? "S" : "");
        return EXIT_FAILURE;
    }

    HDprintf("All tools VFD tests passed.\n");

    return EXIT_SUCCESS;

} /* end main() */
