MODULE ncdf_fail_tgv
  use pio_tutil
  implicit none

  ! tgv = test global vars
  character(len=PIO_TF_MAX_STR_LEN), parameter :: tgv_fname = "pio_ncdf_test_file.nc"
  integer :: tgv_iotype
END MODULE ncdf_fail_tgv

PIO_TF_AUTO_TEST_SUB_BEGIN test_clob_then_no_clob
  use ncdf_fail_tgv
  Implicit none
  type(file_desc_t) :: pio_file
  character(len=PIO_TF_MAX_STR_LEN), parameter :: clob_fname = "pio_clob_test_file.nc"
  character(len=PIO_TF_MAX_STR_LEN) :: errmsg
  integer :: ret

  ret = PIO_createfile(pio_tf_iosystem_, pio_file, tgv_iotype, clob_fname, PIO_CLOBBER)
  PIO_TF_CHECK_ERR(ret, "Failed to create:" // trim(clob_fname))

  call PIO_closefile(pio_file)

  ret = PIO_createfile(pio_tf_iosystem_, pio_file, tgv_iotype, clob_fname, PIO_NOCLOBBER)
  PIO_TF_PASSERT(ret /= PIO_NOERR, "Create file with clobber then no clobber did not fail as expected")

  ret = PIO_strerror(ret, errmsg)
  PIO_TF_CHECK_ERR(ret, "Failed to get error message (Trying to recreate file with noclobber):" // trim(clob_fname))

  PIO_TF_LOG(0,*) "Error message successfully retrieved (Trying to recreate file with noclobber), errmsg = ", trim(errmsg)

  ! No close since createfile should fail
  call PIO_deletefile(pio_tf_iosystem_, clob_fname)

PIO_TF_AUTO_TEST_SUB_END test_clob_then_no_clob

PIO_TF_AUTO_TEST_SUB_BEGIN test_redef_with_no_write
  use ncdf_fail_tgv
  Implicit none
  type(file_desc_t) :: pio_file
  integer :: ret

  ret = PIO_openfile(pio_tf_iosystem_, pio_file, tgv_iotype, tgv_fname, PIO_nowrite)
  PIO_TF_CHECK_ERR(ret, "Failed to open:" // trim(tgv_fname))

  ! A simple redef and then enddef
  ret = PIO_redef(pio_file)
  PIO_TF_PASSERT(ret /= PIO_NOERR, "Redef with nowrite did not fail as expected")

  ! No enddef because redef is expected to fail
  call PIO_closefile(pio_file)

PIO_TF_AUTO_TEST_SUB_END test_redef_with_no_write

PIO_TF_AUTO_TEST_SUB_BEGIN test_redef_twice
  use ncdf_fail_tgv
  Implicit none
  type(file_desc_t) :: pio_file
  integer :: i, ret
  ! iotypes = valid NC4 types
  integer, dimension(:), allocatable :: nc4_iotypes
  character(len=PIO_TF_MAX_STR_LEN), dimension(:), allocatable :: nc4_iotype_descs
  integer :: num_nc4_iotypes
  logical :: is_nc4_iotype

  is_nc4_iotype = .false.
  num_nc4_iotypes = 0
  call PIO_TF_Get_nc4_iotypes(nc4_iotypes, nc4_iotype_descs, num_nc4_iotypes)
  do i=1,num_nc4_iotypes
    if(tgv_iotype == nc4_iotypes(i)) then
      is_nc4_iotype = .true.
      exit
    end if
  end do

  ! NetCDF4 iotypes do not require an explicit enddef before redef or other calls
  ! The enddef is implicitly done for the NetCDF4 iotypes.
  if (.not. is_nc4_iotype) then
    ret = PIO_openfile(pio_tf_iosystem_, pio_file, tgv_iotype, tgv_fname, PIO_write)
    PIO_TF_CHECK_ERR(ret, "Failed to open:" // trim(tgv_fname))

    ! A simple redef and then enddef
    ret = PIO_redef(pio_file)
    PIO_TF_CHECK_ERR(ret, "Failed to enter redef mode" // trim(tgv_fname))

    ret = PIO_redef(pio_file)
    PIO_TF_PASSERT(ret /= PIO_NOERR, "Entering redef twice did not fail as expected")

    ret = PIO_enddef(pio_file)
    PIO_TF_CHECK_ERR(ret, "Failed to end redef mode" // trim(tgv_fname))

    call PIO_closefile(pio_file)
  end if

PIO_TF_AUTO_TEST_SUB_END test_redef_twice

PIO_TF_AUTO_TEST_SUB_BEGIN test_inq_missing
  use ncdf_fail_tgv
  Implicit none
  type(file_desc_t) :: pio_file
  character(len=PIO_TF_MAX_STR_LEN), parameter :: fname = "ncdf_fail_test_inq_missing.nc"
  character(len=PIO_TF_MAX_STR_LEN), parameter :: missing_data = "MISSING_VAL"
  character(len=PIO_TF_MAX_STR_LEN) :: tmp_str
  ! The file has no variables
  integer, parameter :: INVALID_ID = 1000
  integer :: var_id, dim_id, att_id, tmp_val
  integer(kind=PIO_OFFSET_KIND) :: tmp_val2
  integer :: ret

  ret = PIO_createfile(pio_tf_iosystem_, pio_file, tgv_iotype, fname, PIO_CLOBBER)
  PIO_TF_CHECK_ERR(ret, "Failed to create:" // trim(fname))

  ret = PIO_enddef(pio_file)
  PIO_TF_CHECK_ERR(ret, "Failed to end redef mode" // trim(fname))

  ret = PIO_inq_varid(pio_file, missing_data, var_id)
  PIO_TF_PASSERT(ret /= PIO_NOERR, "Querying missing var id did not fail as expected")

  var_id = INVALID_ID

  ret = PIO_inq_varname(pio_file, var_id, tmp_str)
  PIO_TF_PASSERT(ret /= PIO_NOERR, "Querying missing var name did not fail as expected")

  ret = PIO_inq_vartype(pio_file, var_id, tmp_val)
  PIO_TF_PASSERT(ret /= PIO_NOERR, "Querying missing var type did not fail as expected")

  ret = PIO_inq_varndims(pio_file, var_id, tmp_val)
  PIO_TF_PASSERT(ret /= PIO_NOERR, "Querying missing var ndims did not fail as expected")

  ret = PIO_inq_varnatts(pio_file, var_id, tmp_val)
  PIO_TF_PASSERT(ret /= PIO_NOERR, "Querying missing var natts did not fail as expected")

  ret = PIO_inq_dimid(pio_file, missing_data, dim_id)
  PIO_TF_PASSERT(ret /= PIO_NOERR, "Querying missing dim id did not fail as expected")

  dim_id = INVALID_ID

  ret = PIO_inq_dimname(pio_file, dim_id, tmp_str)
  PIO_TF_PASSERT(ret /= PIO_NOERR, "Querying missing dim name did not fail as expected")

  ret = PIO_inq_dimlen(pio_file, dim_id, tmp_val)
  PIO_TF_PASSERT(ret /= PIO_NOERR, "Querying missing dim len did not fail as expected")

  att_id = INVALID_ID

  ret = PIO_inq_attname(pio_file, var_id, att_id, tmp_str)
  PIO_TF_PASSERT(ret /= PIO_NOERR, "Querying missing att name did not fail as expected")

  ret = PIO_inq_attlen(pio_file, var_id, missing_data, tmp_val2)
  PIO_TF_PASSERT(ret /= PIO_NOERR, "Querying missing att len did not fail as expected")

  call PIO_closefile(pio_file)

  call PIO_deletefile(pio_tf_iosystem_, fname)
PIO_TF_AUTO_TEST_SUB_END test_inq_missing

PIO_TF_AUTO_TEST_SUB_BEGIN test_get_missing
  use ncdf_fail_tgv
  Implicit none
  type(file_desc_t) :: pio_file
  character(len=PIO_TF_MAX_STR_LEN), parameter :: fname = "ncdf_fail_test_get_missing.nc"
  character(len=PIO_TF_MAX_STR_LEN), parameter :: missing_data = "MISSING_VAL"
  character(len=PIO_TF_MAX_STR_LEN) :: tmp_str
  integer :: tmp_val(1)
  ! The file has no variables
  integer, parameter :: INVALID_ID = 1000
  integer :: var_id
  integer :: ret

  ret = PIO_createfile(pio_tf_iosystem_, pio_file, tgv_iotype, fname, PIO_CLOBBER)
  PIO_TF_CHECK_ERR(ret, "Failed to create:" // trim(fname))

  ret = PIO_enddef(pio_file)
  PIO_TF_CHECK_ERR(ret, "Failed to end redef mode" // trim(fname))

  ret = PIO_inq_varid(pio_file, missing_data, var_id)
  PIO_TF_PASSERT(ret /= PIO_NOERR, "Querying missing var id did not fail as expected")

  var_id = INVALID_ID

  ret = PIO_get_var(pio_file, var_id, tmp_val)
  PIO_TF_PASSERT(ret /= PIO_NOERR, "Getting missing var did not fail as expected")

  ret = PIO_get_att(pio_file, PIO_GLOBAL, missing_data, tmp_str)
  PIO_TF_PASSERT(ret /= PIO_NOERR, "Getting missing att did not fail as expected")

  call PIO_closefile(pio_file)

  call PIO_deletefile(pio_tf_iosystem_, fname)
PIO_TF_AUTO_TEST_SUB_END test_get_missing

PIO_TF_TEST_DRIVER_BEGIN
  use ncdf_fail_tgv
  Implicit none
  type(file_desc_t) :: pio_file
  integer :: ret, i
  ! iotypes = valid NC types
  integer, dimension(:), allocatable :: iotypes
  character(len=PIO_TF_MAX_STR_LEN), dimension(:), allocatable :: iotype_descs
  integer :: num_iotypes

  num_iotypes = 0
  call PIO_TF_Get_nc_iotypes(iotypes, iotype_descs, num_iotypes)
  do i=1,num_iotypes
    tgv_iotype = iotypes(i)
    ret = PIO_createfile(pio_tf_iosystem_, pio_file, tgv_iotype, tgv_fname)
    PIO_TF_CHECK_ERR(ret,&
      "Failed to create:"//trim(iotype_descs(i))//":"//trim(tgv_fname))

    call PIO_closefile(pio_file)

    ! Make sure that global variables are set correctly before running the tests
    PIO_TF_AUTO_TESTS_RUN(trim(iotype_descs(i)))

    call PIO_deletefile(pio_tf_iosystem_, tgv_fname)
  end do
  if(allocated(iotypes)) then
    deallocate(iotypes)
    deallocate(iotype_descs)
  end if

PIO_TF_TEST_DRIVER_END
