From 80268ae6521d2498727f0452adf9a9dd763a5a3a Mon Sep 17 00:00:00 2001 From: Matthew Larson Date: Mon, 6 Nov 2023 12:41:12 -0600 Subject: [PATCH] Implement H5Arename(_by_name) with info loss --- src/rest_vol_attr.c | 228 +++++++++++++++++++++++++++++++- test/test_rest_vol.c | 305 ++++++++++++++++++++++++++++++++++++------- 2 files changed, 477 insertions(+), 56 deletions(-) diff --git a/src/rest_vol_attr.c b/src/rest_vol_attr.c index 902f958b..6e77a28c 100644 --- a/src/rest_vol_attr.c +++ b/src/rest_vol_attr.c @@ -997,6 +997,7 @@ RV_attr_write(void *attr, hid_t dtype_id, const void *buf, hid_t dxpl_id, void * curl_off_t write_len; hssize_t file_select_npoints; htri_t is_variable_str; + hbool_t is_transfer_binary; size_t dtype_size; size_t write_body_len = 0; size_t host_header_len = 0; @@ -1058,7 +1059,10 @@ RV_attr_write(void *attr, hid_t dtype_id, const void *buf, hid_t dxpl_id, void * curl_headers = curl_slist_append(curl_headers, "Expect:"); /* Instruct cURL on which type of transfer to perform, binary or JSON */ - curl_headers = curl_slist_append(curl_headers, "Content-Type: application/octet-stream"); + is_transfer_binary = (H5T_VLEN != dtype_class) && !is_variable_str; + curl_headers = + curl_slist_append(curl_headers, is_transfer_binary ? "Content-Type: application/octet-stream" + : "Content-Type: application/json"); /* URL-encode the attribute name to ensure that the resulting URL for the write * operation contains no illegal characters @@ -1162,6 +1166,9 @@ RV_attr_write(void *attr, hid_t dtype_id, const void *buf, hid_t dxpl_id, void * printf(" \\**********************************/\n\n"); #endif + /* Clear response buffer */ + memset(response_buffer.buffer, 0, response_buffer.buffer_size); + CURL_PERFORM(curl, H5E_ATTR, H5E_WRITEERROR, FAIL); done: @@ -1799,13 +1806,23 @@ RV_attr_specific(void *obj, const H5VL_loc_params_t *loc_params, H5VL_attr_speci { RV_object_t *loc_obj = (RV_object_t *)obj; RV_object_t *attr_iter_obj_typed = NULL; + RV_object_t *attr = NULL; + RV_object_t *renamed_attr = NULL; + RV_object_t *attr_parent = NULL; H5I_type_t parent_obj_type = H5I_UNINIT; size_t host_header_len = 0; + size_t elem_size = 0; H5VL_attr_get_args_t attr_get_args; + H5VL_loc_params_t attr_open_loc_params; + hssize_t num_elems = 0; size_t attr_name_to_delete_len = 0; hid_t attr_iter_object_id = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + hid_t type_id = H5I_INVALID_HID; + void *buf = NULL; void *attr_iter_object = NULL; - char *host_header = NULL; + char parent_URI[URI_MAX_LENGTH]; + char *host_header = NULL; char *obj_URI; char temp_URI[URI_MAX_LENGTH]; char request_url[URL_MAX_LENGTH]; @@ -2660,13 +2677,179 @@ RV_attr_specific(void *obj, const H5VL_loc_params_t *loc_params, H5VL_attr_speci } /* H5VL_ATTR_ITER */ /* H5Arename (_by_name) */ - case H5VL_ATTR_RENAME: - FUNC_GOTO_ERROR(H5E_ATTR, H5E_UNSUPPORTED, FAIL, - "H5Arename and H5Arename_by_name are unsupported"); - break; + case H5VL_ATTR_RENAME: { + /* Open original attribute */ + + switch (loc_params->type) { + /* H5rename */ + case H5VL_OBJECT_BY_SELF: { + parent_obj_type = loc_obj->obj_type; + break; + } + /* H5Arename_by_name */ + case H5VL_OBJECT_BY_NAME: { + if (loc_params->loc_data.loc_by_name.lapl_id == H5I_INVALID_HID) + FUNC_GOTO_ERROR(H5E_ATTR, H5E_BADVALUE, FAIL, "invalid LAPL"); + + if (RV_find_object_by_path(loc_obj, loc_params->loc_data.loc_by_name.name, + &parent_obj_type, RV_copy_object_URI_callback, NULL, + parent_URI) < 0) + FUNC_GOTO_ERROR(H5E_ATTR, H5E_PATH, FAIL, + "can't find object attribute is attached to"); + + /* Open parent object of attribute */ + switch (parent_obj_type) { + case H5I_FILE: + case H5I_GROUP: + if ((attr_parent = (RV_object_t *)RV_group_open( + obj, loc_params, loc_params->loc_data.loc_by_name.name, H5P_DEFAULT, + H5P_DEFAULT, NULL)) == NULL) + FUNC_GOTO_ERROR(H5E_SYM, H5E_CANTOPENOBJ, FAIL, "can't open parent group"); + break; + + case H5I_DATASET: + if ((attr_parent = (RV_object_t *)RV_dataset_open( + obj, loc_params, loc_params->loc_data.loc_by_name.name, H5P_DEFAULT, + H5P_DEFAULT, NULL)) == NULL) + FUNC_GOTO_ERROR(H5E_DATASET, H5E_CANTOPENOBJ, FAIL, + "can't open parent group"); + break; + + case H5I_DATATYPE: + if ((attr_parent = (RV_object_t *)RV_datatype_open( + obj, loc_params, loc_params->loc_data.loc_by_name.name, H5P_DEFAULT, + H5P_DEFAULT, NULL)) == NULL) + FUNC_GOTO_ERROR(H5E_DATATYPE, H5E_CANTOPENOBJ, FAIL, + "can't open parent group"); + break; + + default: + FUNC_GOTO_ERROR(H5E_ATTR, H5E_BADVALUE, FAIL, + "attribute's parent object is not group, dataset, or datatype"); + break; + } + + break; + } + + case H5VL_OBJECT_BY_TOKEN: + case H5VL_OBJECT_BY_IDX: + default: { + FUNC_GOTO_ERROR(H5E_ATTR, H5E_BADVALUE, FAIL, "invalid loc_params type"); + } break; + } + + /* Open original attribute */ + attr_open_loc_params.type = H5VL_OBJECT_BY_SELF; + attr_open_loc_params.obj_type = + (loc_params->type == H5VL_OBJECT_BY_SELF) ? loc_obj->obj_type : parent_obj_type; + + if ((attr = (RV_object_t *)RV_attr_open((attr_parent != NULL) ? (void *)attr_parent : obj, + (const H5VL_loc_params_t *)&attr_open_loc_params, + args->args.rename.old_name, H5P_DEFAULT, H5P_DEFAULT, + NULL)) == NULL) + FUNC_GOTO_ERROR(H5E_ATTR, H5E_CANTOPENOBJ, FAIL, "can't open attribute"); + + /* Create copy of attribute with same name */ + if ((renamed_attr = RV_attr_create( + (loc_params->type == H5VL_OBJECT_BY_SELF) ? obj : (void *)attr_parent, + (const H5VL_loc_params_t *)&attr_open_loc_params, args->args.rename.new_name, + attr->u.attribute.dtype_id, attr->u.attribute.space_id, attr->u.attribute.acpl_id, + attr->u.attribute.aapl_id, H5P_DEFAULT, NULL)) == NULL) + FUNC_GOTO_ERROR(H5E_ATTR, H5E_CANTCREATE, FAIL, "can't create renamed attribute"); + + /* Write original data to copy of attribute */ + + /* TODO - For now, avoid copying previous data of the attribute. + * Doing so runs into issues with reading from 'blank' attributes in HSDS, + * and trying to read/write to unsupported datatypes (references, vlen strings, arrays) */ + + /* + if ((num_elems = H5Sget_simple_extent_npoints(attr->u.attribute.space_id)) < 0) + FUNC_GOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, + "can't get number of elements in dataspace"); + + if ((elem_size = H5Tget_size(attr->u.attribute.dtype_id)) == 0) + FUNC_GOTO_ERROR(H5E_DATATYPE, H5E_CANTGET, FAIL, "can't get size of datatype"); + + /* Allocate buffer for attr read */ + /* + if ((buf = RV_calloc((size_t)num_elems * elem_size)) == NULL) + FUNC_GOTO_ERROR(H5E_ATTR, H5E_CANTALLOC, FAIL, "can't allocate space for attribute read"); + + if (RV_attr_read((void *)attr, attr->u.attribute.dtype_id, buf, H5P_DEFAULT, NULL) < 0) + FUNC_GOTO_ERROR(H5E_ATTR, H5E_READERROR, FAIL, "can't read attribute"); + + if (RV_attr_write((void *)renamed_attr, attr->u.attribute.dtype_id, (const void *)buf, + H5P_DEFAULT, NULL) < 0) FUNC_GOTO_ERROR(H5E_ATTR, H5E_WRITEERROR, FAIL, "can't write to + attribute"); + */ + + /* Close original attribute */ + if (RV_attr_close((void *)attr, H5P_DEFAULT, NULL) < 0) + FUNC_GOTO_ERROR(H5E_ATTR, H5E_CANTCLOSEOBJ, FAIL, "can't close attribute"); + + attr = NULL; + + /* Delete original attribute */ + + /* Setup the host header */ + host_header_len = strlen(loc_obj->domain->u.file.filepath_name) + strlen(host_string) + 1; + if (NULL == (host_header = (char *)RV_malloc(host_header_len))) + FUNC_GOTO_ERROR(H5E_ATTR, H5E_CANTALLOC, FAIL, + "can't allocate space for request Host header"); + + strcpy(host_header, host_string); + + curl_headers = + curl_slist_append(curl_headers, strncat(host_header, loc_obj->domain->u.file.filepath_name, + host_header_len - strlen(host_string) - 1)); + + /* Disable use of Expect: 100 Continue HTTP response */ + curl_headers = curl_slist_append(curl_headers, "Expect:"); + + /* Set request url */ + if (CURLE_OK != curl_easy_setopt(curl, CURLOPT_HTTPHEADER, curl_headers)) + FUNC_GOTO_ERROR(H5E_ATTR, H5E_CANTSET, FAIL, "can't set cURL HTTP headers: %s", curl_err_buf); + + if (RV_set_object_type_header(parent_obj_type, &parent_obj_type_header) < 0) + FUNC_GOTO_ERROR(H5E_ATTR, H5E_BADVALUE, FAIL, + "parent object not a group, datatype or dataset"); + + /* URL-encode the attribute name so that the resulting URL + * doesn't contain any illegal characters */ + if (NULL == (url_encoded_attr_name = curl_easy_escape(curl, args->args.rename.old_name, 0))) + FUNC_GOTO_ERROR(H5E_ATTR, H5E_CANTENCODE, FAIL, "can't URL-encode attribute name"); + + if ((url_len = snprintf(request_url, URL_MAX_LENGTH, "%s/%s/%s/attributes/%s", base_URL, + parent_obj_type_header, + (loc_params->type == H5VL_OBJECT_BY_SELF) ? loc_obj->URI : parent_URI, + url_encoded_attr_name)) < 0) + FUNC_GOTO_ERROR(H5E_ATTR, H5E_SYSERRSTR, FAIL, "snprintf error"); + + if (CURLE_OK != curl_easy_setopt(curl, CURLOPT_URL, request_url)) + FUNC_GOTO_ERROR(H5E_ATTR, H5E_CANTSET, FAIL, "can't set cURL request URL: %s", curl_err_buf); + + if (CURLE_OK != curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE")) + FUNC_GOTO_ERROR(H5E_ATTR, H5E_CANTSET, FAIL, + "can't set up cURL to make HTTP DELETE request: %s", curl_err_buf); + +#ifdef RV_CONNECTOR_DEBUG + printf("-> Deleting attribute at URL: %s\n\n", request_url); + + printf(" /*************************************\\\n"); + printf("-> | Making DELETE request to the server |\n"); + printf(" \\*************************************/\n\n"); +#endif + + CURL_PERFORM(curl, H5E_ATTR, H5E_CANTDELETE, FAIL); + + break; + } default: FUNC_GOTO_ERROR(H5E_ATTR, H5E_BADVALUE, FAIL, "unknown attribute operation"); + } /* end switch */ done: @@ -2698,6 +2881,36 @@ RV_attr_specific(void *obj, const H5VL_loc_params_t *loc_params, H5VL_attr_speci FUNC_DONE_ERROR(H5E_ATTR, H5E_CANTCLOSEOBJ, FAIL, "invalid attribute parent object type"); } /* end if */ + if (attr) + if (RV_attr_close(attr, H5P_DEFAULT, NULL) < 0) + FUNC_DONE_ERROR(H5E_ATTR, H5E_CANTCLOSEOBJ, FAIL, "can't close attribute"); + + if (renamed_attr) + if (RV_attr_close(renamed_attr, H5P_DEFAULT, NULL) < 0) + FUNC_DONE_ERROR(H5E_ATTR, H5E_CANTCLOSEOBJ, FAIL, "can't close attribute"); + + if (attr_parent) + switch (parent_obj_type) { + case H5I_FILE: + case H5I_GROUP: + if (RV_group_close((void *)attr_parent, H5P_DEFAULT, NULL) < 0) + FUNC_GOTO_ERROR(H5E_SYM, H5E_CANTCLOSEOBJ, FAIL, "can't close parent group"); + break; + + case H5I_DATASET: + if (RV_dataset_close((void *)attr_parent, H5P_DEFAULT, NULL) < 0) + FUNC_GOTO_ERROR(H5E_DATASET, H5E_CANTCLOSEOBJ, FAIL, "can't close parent dataset"); + break; + + case H5I_DATATYPE: + if (RV_datatype_close((void *)attr_parent, H5P_DEFAULT, NULL) < 0) + FUNC_GOTO_ERROR(H5E_DATATYPE, H5E_CANTCLOSEOBJ, FAIL, "can't close parent datatype"); + + default: + FUNC_GOTO_ERROR(H5E_ATTR, H5E_BADVALUE, FAIL, + "attribute's parent object is not group, dataset, or datatype"); + break; + } /* In case a custom DELETE request was made, reset the request to NULL * to prevent any possible future issues with requests */ @@ -2712,6 +2925,9 @@ RV_attr_specific(void *obj, const H5VL_loc_params_t *loc_params, H5VL_attr_speci curl_headers = NULL; } /* end if */ + if (buf) + RV_free(buf); + PRINT_ERROR_STACK; return ret_value; diff --git a/test/test_rest_vol.c b/test/test_rest_vol.c index a0dfb7aa..53a35ba9 100644 --- a/test/test_rest_vol.c +++ b/test/test_rest_vol.c @@ -172,10 +172,12 @@ char filename[FILENAME_MAX_LENGTH]; #define ATTRIBUTE_READ_TEST_SPACE_RANK 2 #define ATTRIBUTE_READ_TEST_ATTR_NAME "read_test_attr" -#define ATTRIBUTE_RENAME_TEST_SPACE_RANK 2 -#define ATTRIBUTE_RENAME_TEST_ATTR_NAME "rename_test_attr" -#define ATTRIBUTE_RENAME_TEST_NEW_NAME "renamed_attr" - +#define ATTRIBUTE_RENAME_TEST_SPACE_RANK 1 +#define ATTRIBUTE_RENAME_TEST_GROUP_NAME "attr_rename_test" +#define ATTRIBUTE_RENAME_TEST_ATTR_NAME "rename_test_attr" +#define ATTRIBUTE_RENAME_TEST_ATTR_NAME2 "rename_test_attr2" +#define ATTRIBUTE_RENAME_TEST_NEW_NAME "renamed_attr" +#define ATTRIBUTE_RENAME_TEST_NEW_NAME2 "renamed_attr2" #define ATTRIBUTE_GET_NUM_ATTRS_TEST_ATTRIBUTE_NAME "get_num_attrs_test_attribute" #define ATTRIBUTE_GET_NUM_ATTRS_TEST_SPACE_RANK 2 @@ -601,6 +603,70 @@ char filename[FILENAME_MAX_LENGTH]; #define COMPOUND_WITH_SYMBOLS_IN_MEMBER_NAMES_TEST_DSET_RANK 2 #define COMPOUND_WITH_SYMBOLS_IN_MEMBER_NAMES_TEST_DSET_NAME "dset" +/* + * The maximum dimensionality and dimension size of a dataspace + * generated for an attribute or compact dataset. + */ +#define COMPACT_SPACE_MAX_DIM_SIZE 4 +#define COMPACT_SPACE_MAX_DIMS 3 + +/* + * Macros used for multipart tests + */ +#define TESTING_MULTIPART(WHAT) \ + { \ + printf("Testing %-62s", WHAT); \ + puts(""); \ + fflush(stdout); \ + } + +/* + * Begin and end an entire section of multipart tests. By placing all the + * parts of a test between these macros, skipping to the 'error' cleanup + * section of a test is deferred until all parts have finished. + */ +#define BEGIN_MULTIPART \ + { \ + int nerrors = 0; + +#define END_MULTIPART \ + if (nerrors > 0) \ + goto error; \ + } + +/* + * Begin, end and handle errors within a single part of a multipart test. + * The PART_END macro creates a goto label based on the given "part name". + * When a failure occurs in the current part, the PART_ERROR macro uses + * this label to skip to the next part of the multipart test. The PART_ERROR + * macro also increments the error count so that the END_MULTIPART macro + * knows to skip to the test's 'error' label once all test parts have finished. + */ +#define PART_BEGIN(part_name) { +#define PART_END(part_name) \ + } \ + part_##part_name##_end: +#define PART_ERROR(part_name) \ + { \ + nerrors++; \ + goto part_##part_name##_end; \ + } +#define PART_EMPTY(part_name) \ + { \ + goto part_##part_name##_end; \ + } +#define PART_TEST_ERROR(part_name) \ + { \ + H5_FAILED(); \ + AT(); \ + nerrors++; \ + goto part_##part_name##_end; \ + } +#define TESTING_2(WHAT) \ + { \ + printf(" Testing %-60s", WHAT); \ + fflush(stdout); \ + } /* Connector initialization/termination test */ static int test_setup_connector(void); @@ -754,6 +820,8 @@ static herr_t object_visit_callback(hid_t o_id, const char *name, const H5O_info void *op_data); static hid_t generate_random_datatype(H5T_class_t parent_class); +static hid_t generate_random_dataspace(int rank, const hsize_t *max_dims, hsize_t *dims_out, + hbool_t is_compact); static int (*setup_tests[])(void) = {test_setup_connector, NULL}; @@ -4368,16 +4436,18 @@ test_read_attribute(void) static int test_rename_attribute(void) { - hsize_t attr_dims[ATTRIBUTE_RENAME_TEST_SPACE_RANK]; - size_t i; - htri_t attr_exists; - hid_t file_id = -1, fapl_id = -1; - hid_t container_group = -1; - hid_t attr_id = -1; - hid_t attr_dtype = -1; - hid_t attr_space_id = -1; + htri_t attr_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t fapl_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID, attr_id2 = H5I_INVALID_HID; + hid_t attr_dtype = H5I_INVALID_HID; + hid_t attr_space_id = H5I_INVALID_HID; - TESTING("rename an attribute") + TESTING_MULTIPART("attribute renaming"); + + TESTING_2("test setup"); if (H5rest_init() < 0) TEST_ERROR @@ -4389,34 +4459,45 @@ test_rename_attribute(void) if ((file_id = H5Fopen(filename, H5F_ACC_RDWR, fapl_id)) < 0) { H5_FAILED(); - printf(" couldn't open file\n"); + printf(" couldn't open file '%s'\n", filename); goto error; } if ((container_group = H5Gopen2(file_id, ATTRIBUTE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { H5_FAILED(); - printf(" couldn't open container group\n"); + printf(" couldn't open container group '%s'\n", ATTRIBUTE_TEST_GROUP_NAME); goto error; } - for (i = 0; i < ATTRIBUTE_RENAME_TEST_SPACE_RANK; i++) - attr_dims[i] = (hsize_t)(rand() % MAX_DIM_SIZE + 1); + if ((group_id = H5Gcreate2(container_group, ATTRIBUTE_RENAME_TEST_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + printf(" couldn't create container group '%s'\n", ATTRIBUTE_RENAME_TEST_GROUP_NAME); + goto error; + } - if ((attr_space_id = H5Screate_simple(ATTRIBUTE_RENAME_TEST_SPACE_RANK, attr_dims, NULL)) < 0) - TEST_ERROR + if ((attr_space_id = generate_random_dataspace(ATTRIBUTE_RENAME_TEST_SPACE_RANK, NULL, NULL, TRUE)) < 0) + TEST_ERROR; if ((attr_dtype = generate_random_datatype(H5T_NO_CLASS)) < 0) - TEST_ERROR + TEST_ERROR; - if ((attr_id = H5Acreate2(container_group, ATTRIBUTE_RENAME_TEST_ATTR_NAME, attr_dtype, attr_space_id, + if ((attr_id = H5Acreate2(group_id, ATTRIBUTE_RENAME_TEST_ATTR_NAME, attr_dtype, attr_space_id, H5P_DEFAULT, H5P_DEFAULT)) < 0) { H5_FAILED(); printf(" couldn't create attribute\n"); goto error; } - /* Verify the attribute has been created */ - if ((attr_exists = H5Aexists(container_group, ATTRIBUTE_RENAME_TEST_ATTR_NAME)) < 0) { + if ((attr_id2 = H5Acreate2(group_id, ATTRIBUTE_RENAME_TEST_ATTR_NAME2, attr_dtype, attr_space_id, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + printf(" couldn't create attribute\n"); + goto error; + } + + /* Verify the attributes have been created */ + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_RENAME_TEST_ATTR_NAME)) < 0) { H5_FAILED(); printf(" couldn't determine if attribute exists\n"); goto error; @@ -4428,46 +4509,126 @@ test_rename_attribute(void) goto error; } - H5E_BEGIN_TRY + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_RENAME_TEST_ATTR_NAME2)) < 0) { + H5_FAILED(); + printf(" couldn't determine if attribute exists\n"); + goto error; + } + + if (!attr_exists) { + H5_FAILED(); + printf(" attribute did not exist\n"); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART { -#ifdef RV_CONNECTOR_DEBUG - puts("Attempting to rename the attribute with H5Arename\n"); -#endif + PART_BEGIN(H5Arename) + { + TESTING_2("H5Arename"); - if (H5Arename(container_group, ATTRIBUTE_RENAME_TEST_ATTR_NAME, ATTRIBUTE_RENAME_TEST_NEW_NAME) >= - 0) { - H5_FAILED(); - printf(" unsupported API succeeded!\n"); - goto error; + if (H5Arename(group_id, ATTRIBUTE_RENAME_TEST_ATTR_NAME, ATTRIBUTE_RENAME_TEST_NEW_NAME) < 0) { + H5_FAILED(); + printf(" couldn't rename attribute '%s' to '%s' using H5Arename\n", + ATTRIBUTE_RENAME_TEST_ATTR_NAME, ATTRIBUTE_RENAME_TEST_NEW_NAME); + PART_ERROR(H5Arename); + } + + /* Verify the attribute has been renamed */ + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_RENAME_TEST_ATTR_NAME)) < 0) { + H5_FAILED(); + printf(" couldn't determine if attribute exists\n"); + PART_ERROR(H5Arename); + } + + if (attr_exists) { + H5_FAILED(); + printf(" attribute did not get renamed!\n"); + PART_ERROR(H5Arename); + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_RENAME_TEST_NEW_NAME)) < 0) { + H5_FAILED(); + printf(" couldn't determine if attribute exists\n"); + PART_ERROR(H5Arename); + } + + if (!attr_exists) { + H5_FAILED(); + printf(" attribute did not get renamed!\n"); + PART_ERROR(H5Arename); + } + + PASSED(); } + PART_END(H5Arename); -#ifdef RV_CONNECTOR_DEBUG - puts("Attempting to rename the attribute with H5Arename_by_name\n"); -#endif + PART_BEGIN(H5Arename_by_name) + { + TESTING_2("H5Arename_by_name"); - if (H5Arename_by_name(file_id, "/" ATTRIBUTE_TEST_GROUP_NAME, ATTRIBUTE_RENAME_TEST_ATTR_NAME, - ATTRIBUTE_RENAME_TEST_NEW_NAME, H5P_DEFAULT) >= 0) { - H5_FAILED(); - printf(" unsupported API succeeded!\n"); - goto error; + if (H5Arename_by_name(container_group, ATTRIBUTE_RENAME_TEST_GROUP_NAME, + ATTRIBUTE_RENAME_TEST_ATTR_NAME2, ATTRIBUTE_RENAME_TEST_NEW_NAME2, + H5P_DEFAULT) < 0) { + H5_FAILED(); + printf(" couldn't rename attribute '%s' to '%s' using H5Arename_by_name\n", + ATTRIBUTE_RENAME_TEST_ATTR_NAME2, ATTRIBUTE_RENAME_TEST_NEW_NAME2); + PART_ERROR(H5Arename_by_name); + } + + /* Verify the attribute has been renamed */ + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_RENAME_TEST_ATTR_NAME2)) < 0) { + H5_FAILED(); + printf(" couldn't determine if attribute exists\n"); + PART_ERROR(H5Arename_by_name); + } + + if (attr_exists) { + H5_FAILED(); + printf(" attribute did not get renamed!\n"); + PART_ERROR(H5Arename_by_name); + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_RENAME_TEST_NEW_NAME2)) < 0) { + H5_FAILED(); + printf(" couldn't determine if attribute exists\n"); + PART_ERROR(H5Arename_by_name); + } + + if (!attr_exists) { + H5_FAILED(); + printf(" attribute did not get renamed!\n"); + PART_ERROR(H5Arename_by_name); + } + + PASSED(); } + PART_END(H5Arename_by_name); } - H5E_END_TRY; + END_MULTIPART; + + TESTING_2("test cleanup"); if (H5Sclose(attr_space_id) < 0) - TEST_ERROR + TEST_ERROR; if (H5Tclose(attr_dtype) < 0) - TEST_ERROR + TEST_ERROR; if (H5Aclose(attr_id) < 0) - TEST_ERROR + TEST_ERROR; + if (H5Aclose(attr_id2) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; if (H5Gclose(container_group) < 0) - TEST_ERROR - if (H5Pclose(fapl_id) < 0) - TEST_ERROR + TEST_ERROR; if (H5Fclose(file_id) < 0) - TEST_ERROR + TEST_ERROR; + if (H5Pclose(fapl_id) < 0) + TEST_ERROR; if (H5rest_term() < 0) - TEST_ERROR + TEST_ERROR; PASSED(); @@ -4479,9 +4640,11 @@ test_rename_attribute(void) H5Sclose(attr_space_id); H5Tclose(attr_dtype); H5Aclose(attr_id); + H5Aclose(attr_id2); + H5Gclose(group_id); H5Gclose(container_group); - H5Pclose(fapl_id); H5Fclose(file_id); + H5Pclose(fapl_id); H5rest_term(); } H5E_END_TRY; @@ -18487,6 +18650,48 @@ generate_random_datatype(H5T_class_t parent_class) return datatype; } +/* + * Helper function to generate a random HDF5 dataspace in order to thoroughly + * test support for dataspaces. + */ +static hid_t +generate_random_dataspace(int rank, const hsize_t *max_dims, hsize_t *dims_out, hbool_t is_compact) +{ + hsize_t dataspace_dims[H5S_MAX_RANK]; + size_t i; + hid_t dataspace_id = H5I_INVALID_HID; + + if (rank < 0) + TEST_ERROR; + if (is_compact && (rank > COMPACT_SPACE_MAX_DIMS)) { + printf(" current rank of compact dataspace (%lld) exceeds maximum dimensionality (%lld)\n", + (long long)rank, (long long)COMPACT_SPACE_MAX_DIMS); + TEST_ERROR; + } + + /* + * XXX: if max_dims is specified, make sure that the dimensions generated + * are not larger than this. + */ + for (i = 0; i < (size_t)rank; i++) { + if (is_compact) + dataspace_dims[i] = (hsize_t)(rand() % COMPACT_SPACE_MAX_DIM_SIZE + 1); + else + dataspace_dims[i] = (hsize_t)(rand() % MAX_DIM_SIZE + 1); + + if (dims_out) + dims_out[i] = dataspace_dims[i]; + } + + if ((dataspace_id = H5Screate_simple(rank, dataspace_dims, max_dims)) < 0) + TEST_ERROR; + + return dataspace_id; + +error: + return H5I_INVALID_HID; +} + int main(int argc, char **argv) {