text: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
   * Copyright by The HDF Group.                                               *
   * Copyright by the Board of Trustees of the University of Illinois.         *
   * 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://support.hdfgroup.org/ftp/HDF5/releases.  *
   * If you do not have access to either file, you may request a copy from     *
   * help@hdfgroup.org.                                                        *
   * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  
  /* Test user-created identifiers (hid_t's) and identifier types. */
  
  #include "testhdf5.h"
  
  /* Include H5Ipkg.h to calculate max number of groups */
  #define H5I_FRIEND        /*suppress error about including H5Ipkg      */
  #include "H5Ipkg.h"
  
  /* Test basic functionality of registering and deleting types and IDs */
  static int basic_id_test(void)
  {
      H5I_type_t myType = H5I_BADID;
      hid_t arrayID = H5I_INVALID_HID;
      void* testObj = NULL;
      void* testPtr = NULL;
      char nameString[10];
      hid_t testID;
      ssize_t testSize = -1;
      herr_t err;
      int num_ref;
      hsize_t num_members;
  
  
      /* Try to register an ID with ficticious types */
      H5E_BEGIN_TRY
          arrayID = H5Iregister((H5I_type_t) 420, testObj);
      H5E_END_TRY
  
      VERIFY(arrayID, H5I_INVALID_HID, "H5Iregister");
      if(arrayID != H5I_INVALID_HID)
          goto out;
  
      H5E_BEGIN_TRY
          arrayID = H5Iregister((H5I_type_t) -1, testObj);
      H5E_END_TRY
  
      VERIFY(arrayID, H5I_INVALID_HID, "H5Iregister");
      if(arrayID != H5I_INVALID_HID)
          goto out;
  
       /* Try to access IDs with ficticious types */
      H5E_BEGIN_TRY
          testPtr = H5Iobject_verify((hid_t)100, (H5I_type_t) 0);
      H5E_END_TRY
  
      CHECK_PTR_NULL(testPtr, "H5Iobject_verify");
      if(testPtr != NULL)
          goto out;
  
      H5E_BEGIN_TRY
          testPtr = H5Iobject_verify((hid_t)700, (H5I_type_t) 700);
      H5E_END_TRY
  
      CHECK_PTR_NULL(testPtr, "H5Iobject_verify");
      if(testPtr != NULL)
          goto out;
  
      /* Register a type */
      myType = H5Iregister_type((size_t)64, 0, (H5I_free_t) free );
  
      CHECK(myType, H5I_BADID, "H5Iregister_type");
      if(myType == H5I_BADID)
          goto out;
  
      /* Register an ID and retrieve the object it points to.
       * Once the ID has been registered, testObj will be freed when
       * its ID type is destroyed.
       */
      testObj = HDmalloc(7 * sizeof(int));
      arrayID = H5Iregister(myType, testObj);
  
      CHECK(arrayID, H5I_INVALID_HID, "H5Iregister");
      if(arrayID == H5I_INVALID_HID) {
          HDfree(testObj);
          goto out;
      }
  
      testPtr = (int *)H5Iobject_verify(arrayID, myType);
  
      CHECK_PTR_EQ(testPtr, testObj, "H5Iobject_verify");
      if(testPtr != testObj)
          goto out;
  
      /* Ensure that H5Iget_file_id and H5Iget_name() fail, since this
       * is an hid_t for the wrong kind of object
       */
      H5E_BEGIN_TRY
          testID = H5Iget_file_id(arrayID);
      H5E_END_TRY
  
      VERIFY(testID, H5I_INVALID_HID, "H5Iget_file_id");
      if(testID != H5I_INVALID_HID)
          goto out;
  
      H5E_BEGIN_TRY
          testSize = H5Iget_name(arrayID, nameString, (size_t)9);
      H5E_END_TRY
  
      VERIFY(testSize, -1, "H5Iget_name");
      if(testSize != -1)
          goto out;
  
      /* Make sure H5Iremove_verify catches objects of the wrong type */
      H5E_BEGIN_TRY
          testPtr = (int*) H5Iremove_verify(arrayID, (H5I_type_t) 0);
      H5E_END_TRY
  
      CHECK_PTR_NULL(testPtr, "H5Iremove_verify");
      if(testPtr != NULL)
          goto out;
  
      H5E_BEGIN_TRY
          testPtr = (int*) H5Iremove_verify(arrayID, (H5I_type_t) ((int) myType-1));
      H5E_END_TRY
  
      CHECK_PTR_NULL(testPtr, "H5Iremove_verify");
      if(testPtr != NULL)
          goto out;
  
      /* Remove an ID and make sure we can't access it */
      testPtr = (int*) H5Iremove_verify(arrayID, myType);
  
      CHECK_PTR(testPtr, "H5Iremove_verify");
      if(testPtr == NULL)
          goto out;
  
      H5E_BEGIN_TRY
          testPtr = (int*) H5Iobject_verify(arrayID, myType);
      H5E_END_TRY
  
      CHECK_PTR_NULL(testPtr, "H5Iobject_verify");
      if(testPtr != NULL)
          goto out;
  
      /* Delete the type and make sure we can't access objects within it */
      arrayID = H5Iregister(myType, testObj);
  
      err = H5Idestroy_type(myType);
      VERIFY(err, 0, "H5Idestroy_type");
      if( err != 0)
          goto out;
      VERIFY(H5Itype_exists(myType), 0, "H5Itype_exists");
      if(H5Itype_exists(myType) != 0)
          goto out;
  
      H5E_BEGIN_TRY
          VERIFY(H5Inmembers(myType, NULL), -1, "H5Inmembers");
          if(H5Inmembers(myType, NULL) != -1)
              goto out;
      H5E_END_TRY
  
      /* Register another type and another object in that type */
      myType = H5Iregister_type((size_t)64, 0, (H5I_free_t) free );
  
      CHECK(myType, H5I_BADID, "H5Iregister_type");
      if(myType == H5I_BADID)
          goto out;
  
      /* The memory that testObj pointed to should already have been
       * freed when the previous type was destroyed.  Allocate new
       * memory for it.
       */
      testObj = HDmalloc(7 * sizeof(int));
      arrayID = H5Iregister(myType, testObj);
  
      CHECK(arrayID, H5I_INVALID_HID, "H5Iregister");
      if(arrayID == H5I_INVALID_HID) {
          HDfree(testObj);
          goto out;
      }
  
      err = H5Inmembers(myType, &num_members);
      CHECK(err, -1, "H5Inmembers");
      if (err < 0)
          goto out;
      VERIFY(num_members, 1, "H5Inmembers");
      if(num_members != 1)
          goto out;
  
      /* Increment references to type and ensure that dec_type_ref
       * doesn't destroy the type
       */
      num_ref = H5Iinc_type_ref(myType);
      VERIFY(num_ref, 2, "H5Iinc_type_ref");
      if( num_ref != 2)
          goto out;
      num_ref = H5Idec_type_ref(myType);
      VERIFY(num_ref, 1, "H5Idec_type_ref");
      if(num_ref != 1)
          goto out;
      err = H5Inmembers(myType, &num_members);
      CHECK(err, -1, "H5Inmembers");
      if (err < 0)
          goto out;
      VERIFY(num_members, 1, "H5Inmembers");
      if(num_members != 1)
          goto out;
  
      /* This call to dec_type_ref should destroy the type */
      num_ref = H5Idec_type_ref(myType);
      VERIFY(num_ref, 0, "H5Idec_type_ref");
      if(num_ref != 0)
          goto out;
      VERIFY(H5Itype_exists(myType), 0, "H5Itype_exists");
      if (H5Itype_exists(myType) != 0)
          goto out;
  
      H5E_BEGIN_TRY
          err = H5Inmembers(myType, &num_members);
          if(err >= 0)
              goto out;
      H5E_END_TRY
  
      return 0;
  
  out:
      /* Clean up type if it has been allocated and free memory used
       * by testObj
       */
      if(myType >= 0)
          H5Idestroy_type(myType);
  
      return -1;
  }
  
  
      /* A dummy search function for the next test */
  static int test_search_func(void H5_ATTR_UNUSED * ptr1, void H5_ATTR_UNUSED * ptr2) { return 0; }
  
      /* Ensure that public functions cannot access "predefined" ID types */
  static int id_predefined_test(void )
  {
      void * testObj;
      hid_t testID;
      hid_t typeID = H5I_INVALID_HID;
      void * testPtr;
      herr_t testErr;
  
      testObj = HDmalloc(sizeof(int));
  
      /*
       * Attempt to perform public functions on various library types
       */
  
      H5E_BEGIN_TRY
          testID = H5Iregister(H5I_FILE, testObj);
      H5E_END_TRY
  
      VERIFY(testID, H5I_INVALID_HID, "H5Iregister");
      if(testID != H5I_INVALID_HID)
          goto out;
  
      H5E_BEGIN_TRY
          testPtr = H5Isearch(H5I_GENPROP_LST, (H5I_search_func_t) test_search_func, testObj);
      H5E_END_TRY
  
      CHECK_PTR_NULL(testPtr, "H5Isearch");
      if(testPtr != NULL)
          goto out;
  
      H5E_BEGIN_TRY
          testErr = H5Inmembers(H5I_ERROR_STACK, NULL);
      H5E_END_TRY
  
      VERIFY(testErr, -1, "H5Inmembers");
      if(testErr != -1)
          goto out;
  
      H5E_BEGIN_TRY
          testErr = H5Iclear_type(H5I_FILE, 0);
      H5E_END_TRY
  
      VERIFY((testErr >= 0), 0, "H5Iclear_type");
      if(testErr >= 0)
          goto out;
  
      H5E_BEGIN_TRY
          testErr = H5Idestroy_type(H5I_DATASET);
      H5E_END_TRY
  
      VERIFY((testErr >= 0), 0, "H5Idestroy_type");
      if(testErr >= 0)
          goto out;
  
      /* Create a datatype ID and try to perform illegal functions on it */
      typeID = H5Tcreate(H5T_OPAQUE, (size_t)42);
      CHECK(typeID, H5I_INVALID_HID, "H5Tcreate");
      if(typeID == H5I_INVALID_HID)
          goto out;
  
      H5E_BEGIN_TRY
          testPtr = H5Iremove_verify(typeID, H5I_DATATYPE);
      H5E_END_TRY
  
      CHECK_PTR_NULL(testPtr, "H5Iremove_verify");
      if(testPtr != NULL)
          goto out;
  
      H5E_BEGIN_TRY
          testPtr = H5Iobject_verify(typeID, H5I_DATATYPE);
      H5E_END_TRY
  
      CHECK_PTR_NULL(testPtr, "H5Iobject_verify");
      if(testPtr != NULL)
          goto out;
  
      H5Tclose(typeID);
  
      /* testObj was never registered as an atom, so it will not be
       * automatically freed. */
      HDfree(testObj);
      return 0;
  
  out:
      if(typeID != H5I_INVALID_HID)
          H5Tclose(typeID);
      if(testObj != NULL)
          HDfree(testObj);
  
      return -1;
  }
  
  
  /* Test the H5Iis_valid function */
  static int test_is_valid(void)
  {
      hid_t   dtype;      /* datatype id */
      int64_t nmembs1;    /* number of type memnbers */
      int64_t nmembs2;
      htri_t  tri_ret;    /* htri_t return value */
      herr_t  ret;        /* return value */
  
      /* Create a datatype id */
      dtype = H5Tcopy(H5T_NATIVE_INT);
      CHECK(dtype, FAIL, "H5Tcopy");
      if (dtype < 0)
          goto out;
  
      /* Check that the ID is valid */
      tri_ret = H5Iis_valid(dtype);
      VERIFY(tri_ret, TRUE, "H5Iis_valid");
      if (tri_ret != TRUE)
          goto out;
  
      /* Artificially manipulate the reference counts so app_count is 0, and dtype
       * appears to be an internal id.  This takes advantage of the fact that
       * H5Ipkg is included.
       */
      ret = H5I_inc_ref(dtype, FALSE);
      CHECK(ret, FAIL, "H5I_inc_ref");
      if (ret < 0)
          goto out;
      ret = H5I_dec_app_ref(dtype);
      CHECK(ret, FAIL, "H5I_dec_ref");
      if (ret < 0)
          goto out;
  
      /* Check that dtype is invalid */
      tri_ret = H5Iis_valid(dtype);
      VERIFY(tri_ret, FALSE, "H5Iis_valid");
      if (tri_ret != FALSE)
          goto out;
  
      /* Close dtype and verify that it has been closed */
      nmembs1 = H5I_nmembers(H5I_DATATYPE);
      CHECK(nmembs1, FAIL, "H5I_nmembers");
      if (nmembs1 < 0)
          goto out;
      ret = H5I_dec_ref(dtype);
      CHECK(ret, FAIL, "H5I_dec_ref");
      if (ret < 0)
          goto out;
      nmembs2 = H5I_nmembers(H5I_DATATYPE);
      VERIFY(nmembs2, nmembs1 - 1, "H5I_nmembers");
      if (nmembs2 != nmembs1 - 1)
          goto out;
  
      /* Check that dtype is invalid */
      tri_ret = H5Iis_valid(dtype);
      VERIFY(tri_ret, FALSE, "H5Iis_valid");
      if (tri_ret != FALSE)
          goto out;
  
      /* Check that an id of -1 is invalid */
      tri_ret = H5Iis_valid((hid_t)-1);
      VERIFY(tri_ret, FALSE, "H4Iis_valid");
      if (tri_ret != FALSE)
          goto out;
  
      return 0;
  
  out:
      /* Don't attempt to close dtype as we don't know the exact state of the
       * reference counts.  Every state in this function will be automatically
       * closed at library exit anyways, as internal count is never > 1.
       */
      return -1;
  }
  
  /* Test the H5Iget_type function */
  static int test_get_type(void)
  {
      hid_t   dtype;           /* datatype id */
      H5I_type_t  type_ret;    /* return value */
  
      /* Create a datatype id */
      dtype = H5Tcopy(H5T_NATIVE_INT);
      CHECK(dtype, FAIL, "H5Tcopy");
      if (dtype < 0)
          goto out;
  
      /* Check that the ID is correct */
      type_ret = H5Iget_type(dtype);
      VERIFY(type_ret, H5I_DATATYPE, "H5Iget_type");
      if (type_ret == H5I_BADID)
          goto out;
  
      /* Check that the ID is correct */
      type_ret = H5Iget_type((hid_t)H5T_STRING);
      VERIFY(type_ret, H5I_BADID, "H5Iget_type");
      if (type_ret != H5I_BADID)
          goto out;
  
      /* Check that the ID is correct */
      type_ret = H5Iget_type((hid_t)-1);
      VERIFY(type_ret, H5I_BADID, "H5Iget_type");
      if (type_ret != H5I_BADID)
          goto out;
  
      H5Tclose(dtype);
  
      return 0;
  
  out:
      if(dtype != H5I_INVALID_HID)
      H5Tclose(dtype);
  
      return -1;
  }
  
      /* Test boundary cases with lots of types */
  
  /* Type IDs range from H5I_NTYPES to H5I_MAX_NUM_TYPES.  The system will assign */
  /* IDs in sequential order until H5I_MAX_NUM_TYPES IDs have been given out, at which */
  /* point it will search for type IDs that were allocated but have since been */
  /* deleted. */
  /* This test will allocate IDs up to H5I_MAX_NUM_TYPES, ensure that IDs wrap around */
  /* to low values successfully, ensure that an error is thrown when all possible */
  /* type IDs are taken, then ensure that deleting types frees up their IDs. */
  /* Note that this test depends on the implementation of IDs, so may break */
  /*        if the implementation changes. */
  /* Also note that if someone else registered a user-defined type and forgot to */
  /* destroy it, this test will mysteriously fail (because it will expect there to */
  /* be one more "free" type ID than there is). */
  /* H5I_NTYPES is defined in h5public.h, H5I_MAX_NUM_TYPES is defined in h5pkg.h */
  static int test_id_type_list(void)
  {
      H5I_type_t startType;    /* The first type ID we were assigned in this test */
      H5I_type_t currentType;
      H5I_type_t testType;
      int i;    /* Just a counter variable */
  
      startType = H5Iregister_type((size_t)8, 0, (H5I_free_t) free );
      CHECK(startType, H5I_BADID, "H5Iregister_type");
      if(startType == H5I_BADID)
          goto out;
  
      /* Sanity check */
      if((int)startType >= H5I_MAX_NUM_TYPES || startType < H5I_NTYPES)
      {
          /* Error condition, throw an error */
          CHECK(1, 1, "H5Iregister_type");
          goto out;
      }
      /* Create types up to H5I_MAX_NUM_TYPES */
      for(i = startType + 1; i < H5I_MAX_NUM_TYPES; i++)
      {
          currentType = H5Iregister_type((size_t)8, 0, (H5I_free_t) free );
          CHECK(currentType, H5I_BADID, "H5Iregister_type");
          if(currentType == H5I_BADID)
              goto out;
      }
  
      /* Wrap around to low type ID numbers */
      for(i = H5I_NTYPES; i < startType; i++)
      {
          currentType = H5Iregister_type((size_t)8, 0, (H5I_free_t) free );
          CHECK(currentType, H5I_BADID, "H5Iregister_type");
          if(currentType == H5I_BADID)
              goto out;
      }
  
      /* There should be no room at the inn for a new ID type*/
      H5E_BEGIN_TRY
          testType = H5Iregister_type((size_t)8, 0, (H5I_free_t) free );
      H5E_END_TRY
  
      VERIFY(testType, H5I_BADID, "H5Iregister_type");
      if(testType != H5I_BADID)
          goto out;
  
      /* Now delete a type and try to insert again */
      H5Idestroy_type(H5I_NTYPES);
      testType = H5Iregister_type((size_t)8, 0, (H5I_free_t) free );
  
      VERIFY(testType, H5I_NTYPES, "H5Iregister_type");
      if(testType != H5I_NTYPES)
          goto out;
  
      /* Cleanup.  Destroy all types. */
      for(i = H5I_NTYPES; i < H5I_MAX_NUM_TYPES; i++)
          H5Idestroy_type((H5I_type_t) i);
  
      return 0;
  
  out:
      /* Cleanup.  For simplicity, just destroy all types and ignore errors. */
      H5E_BEGIN_TRY
          for(i = H5I_NTYPES; i < H5I_MAX_NUM_TYPES; i++)
              H5Idestroy_type((H5I_type_t) i);
      H5E_END_TRY
      return -1;
  }
  
      /* Test removing ids in callback for H5Iclear_type */
  
  /* There was a rare bug where, if an id free callback being called by
   * H5I_clear_type() removed another id in that type, a segfault could occur.
   * This test tests for that error (and freeing ids "out of order" within
   * H5Iclear_type() in general). */
  /* Macro definitions */
  #define TEST_RCT_MAX_NOBJS 25
  #define TEST_RCT_MIN_NOBJS 5
  #define TEST_RCT_NITER 50
  
  /* Structure to hold the list of objects */
  typedef struct {
      struct test_rct_obj_t *list; /* List of objects */
      long nobjs;                 /* Number of objects in list */
      long nobjs_rem;             /* Number of objects in list that have not been freed */
  } test_rct_list_t;
  
  /* Structure for an object */
  typedef struct test_rct_obj_t {
      hid_t id;                   /* ID for this object */
      int nfrees;                 /* Number of times this object has been freed */
      hbool_t freeing;            /* Whether we are currently freeing this object directly (through H5Idec_ref()) */
      test_rct_list_t *obj_list;  /* List of all objects */
  } test_rct_obj_t;
  
  /* Free callback */
  static herr_t test_rct_free(void *_obj) {
      test_rct_obj_t *obj = (test_rct_obj_t *)_obj;
      long rem_idx, i;
      herr_t  ret;        /* return value */
  
      /* Mark this object as freed */
      obj->nfrees++;
      obj->obj_list->nobjs_rem--;
  
      /* Check freeing and nobjs_rem */
      if(!obj->freeing && (obj->obj_list->nobjs_rem > 0)) {
          /* Remove a random object from the list */
          rem_idx = HDrandom() % obj->obj_list->nobjs_rem;
  
          /* Scan the list, finding the rem_idx'th object that has not been
           * freed */
          for(i = 0; i < obj->obj_list->nobjs; i++)
              if(obj->obj_list->list[i].nfrees == 0) {
                  if(rem_idx == 0)
                      break;
                  else
                      rem_idx--;
              } /* end if */
          if(i == obj->obj_list->nobjs) {
              ERROR("invalid obj_list");
              goto out;
          } /* end if */
          else {
              /* Remove the object.  Mark as "freeing" so its own callback does
               * not free another object. */
              obj->obj_list->list[i].freeing = TRUE;
              ret = H5Idec_ref(obj->obj_list->list[i].id);
              CHECK(ret, FAIL, "H5Idec_ref");
              if(ret == FAIL)
                  goto out;
              obj->obj_list->list[i].freeing = FALSE;
          } /* end else */
      } /* end if */
  
      /* Verify nobjs_rem is non-negative */
      if(obj->obj_list->nobjs_rem < 0) {
          ERROR("invalid nobjs_rem");
          goto out;
      } /* end if */
  
      return 0;
  
  out:
      return -1;
  } /* end test_rct_free() */
  
  /* Test function */
  static int test_remove_clear_type(void)
  {
      H5I_type_t obj_type;
      test_rct_list_t obj_list;
      test_rct_obj_t list[TEST_RCT_MAX_NOBJS];
      long i, j;
      long nobjs_found;
      hsize_t nmembers;
      herr_t  ret;        /* return value */
  
      /* Register type */
      obj_type = H5Iregister_type((size_t)8, 0, test_rct_free);
      CHECK(obj_type, H5I_BADID, "H5Iregister_type");
      if(obj_type == H5I_BADID)
          goto out;
  
      /* Init obj_list.list */
      obj_list.list = list;
  
      for(i = 0; i < TEST_RCT_NITER; i++) {
          /* Build object list */
          obj_list.nobjs = obj_list.nobjs_rem = TEST_RCT_MIN_NOBJS + (HDrandom() % (long)(TEST_RCT_MAX_NOBJS - TEST_RCT_MIN_NOBJS + 1));
          for(j = 0; j < obj_list.nobjs; j++) {
              list[j].nfrees = 0;
              list[j].freeing = FALSE;
              list[j].obj_list = &obj_list;
              list[j].id = H5Iregister(obj_type, &list[j]);
              CHECK(list[j].id, FAIL, "H5Iregister");
              if(list[j].id == FAIL)
                  goto out;
              if(HDrandom() % 2) {
                  ret = H5Iinc_ref(list[j].id);
                  CHECK(ret, FAIL, "H5Iinc_ref");
                  if(ret == FAIL)
                      goto out;
              } /* end if */
          } /* end for */
  
          /* Clear the type */
          ret = H5Iclear_type(obj_type, FALSE);
          CHECK(ret, FAIL, "H5Iclear_type");
          if(ret == FAIL)
              goto out;
  
          /* Verify list */
          nobjs_found = 0;
          for(j = 0; j < obj_list.nobjs; j++) {
              if(list[j].nfrees == 0)
                  nobjs_found++;
              else {
                  VERIFY(list[j].nfrees, (long)1, "list[j].nfrees");
                  if(list[j].nfrees != (long)1)
                      goto out;
              } /* end else */
              VERIFY(list[j].freeing, FALSE, "list[j].freeing");
              if(list[j].freeing != FALSE)
                  goto out;
          } /* end for */
  
          /* Verify number of objects */
          VERIFY(obj_list.nobjs_rem, nobjs_found, "obj_list.nobjs_rem");
          if(obj_list.nobjs_rem != nobjs_found)
              goto out;
          ret = H5Inmembers(obj_type, &nmembers);
          CHECK(ret, FAIL, "H5Inmembers");
          if(ret == FAIL)
              goto out;
          VERIFY(nmembers, (size_t)nobjs_found, "H5Inmembers");
          if(nmembers != (size_t)nobjs_found)
              goto out;
  
          /* Clear the type with force set to TRUE */
          ret = H5Iclear_type(obj_type, TRUE);
          CHECK(ret, FAIL, "H5Iclear_type");
          if(ret == FAIL)
              goto out;
  
          /* Verify list */
          for(j = 0; j < obj_list.nobjs; j++) {
              VERIFY(list[j].nfrees, (long)1, "list[j].nfrees");
              if(list[j].nfrees != (long)1)
                  goto out;
              VERIFY(list[j].freeing, FALSE, "list[j].freeing");
              if(list[j].freeing != FALSE)
                  goto out;
          } /* end for */
  
          /* Verify number of objects is 0 */
          VERIFY(obj_list.nobjs_rem, (long)0, "obj_list.nobjs_rem");
          if(obj_list.nobjs_rem != (long)0)
              goto out;
          ret = H5Inmembers(obj_type, &nmembers);
          CHECK(ret, FAIL, "H5Inmembers");
          if(ret == FAIL)
              goto out;
          VERIFY(nmembers, (size_t)0, "H5Inmembers");
          if(nmembers != (size_t)0)
              goto out;
      } /* end for */
  
      /* Destroy type */
      ret = H5Idestroy_type(obj_type);
      CHECK(ret, FAIL, "H5Idestroy_type");
      if(ret == FAIL)
          goto out;
  
      return 0;
  
  out:
      /* Cleanup.  For simplicity, just destroy the types and ignore errors. */
      H5E_BEGIN_TRY
          H5Idestroy_type(obj_type);
      H5E_END_TRY
      return -1;
  } /* end test_remove_clear_type() */
  
  void test_ids(void)
  {
      /* Set the random # seed */
      HDsrandom((unsigned)HDtime(NULL));
  
      if (basic_id_test() < 0) TestErrPrintf("Basic ID test failed\n");
      if (id_predefined_test() < 0) TestErrPrintf("Predefined ID type test failed\n");
      if (test_is_valid() < 0) TestErrPrintf("H5Iis_valid test failed\n");
      if (test_get_type() < 0) TestErrPrintf("H5Iget_type test failed\n");
      if (test_id_type_list() < 0) TestErrPrintf("ID type list test failed\n");
      if (test_remove_clear_type() < 0) TestErrPrintf("ID remove during H5Iclear_type test failed\n");
  
  }
  