PageRenderTime 168ms CodeModel.GetById 38ms app.highlight 120ms RepoModel.GetById 1ms app.codeStats 1ms

/utilities/netcdf/src/nctest/atttests.c

https://bitbucket.org/seanmauch/stlib
C | 1371 lines | 1137 code | 45 blank | 189 comment | 410 complexity | 1c244674ee86f434abfcea657e8f91b7 MD5 | raw file
   1/*********************************************************************
   2 *   Copyright 1993, UCAR/Unidata
   3 *   See netcdf/COPYRIGHT file for copying and redistribution conditions.
   4 *   $Header$
   5 *********************************************************************/
   6
   7#ifdef _MPW
   8#define		__SEG__  toobig    /* under MPW on MacOS, makes it fit */
   9#endif
  10
  11#include <stdio.h>
  12#include <string.h>
  13#include <stdlib.h>		/* for free() */
  14#include "netcdf.h"
  15#include "testcdf.h"		/* defines in-memory test cdf structure */
  16#include "add.h"		/* functions to update in-memory netcdf */
  17#include "error.h"
  18#include "emalloc.h"
  19#include "tests.h"
  20#include "val.h"
  21
  22#define LEN_OF(array) ((sizeof array) / (sizeof array[0]))
  23
  24
  25/*
  26 * Test ncattput
  27 *    check that new attribute put works in define mode
  28 *    check that NC_GLOBAL variable id works
  29 *    check that changing type of existing attribute works in define mode
  30 *    check that increasing length of attribute works in define mode
  31 *    check that changing value of existing attribute works in define mode
  32 *    try with bad datatype, should fail
  33 *    try with negative length, should fail
  34 *    try increasing length of attribute in data mode, should fail
  35 *    try putting new attribute in data mode, should fail
  36 *    check that changing type of existing attribute works in data mode
  37 *    check that decreasing length of attribute works in data mode
  38 *    check that changing value of existing attribute works in data mode
  39 *    try with bad variable handle, should fail
  40 *    try with bad netCDF handle, check error
  41 */
  42void
  43test_ncattput(path)
  44     const char *path;		/* name of writable netcdf file to open */
  45{
  46    int nerrs = 0;
  47    static char pname[] = "test_ncattput";
  48    int cdfid;			/* netcdf id */
  49    int ndims;			/* number of dimensions */
  50    int nvars;			/* number of variables */
  51    int ngatts_prev, ngatts;	/* number of global attributes */
  52    int xdimid;			/* id of unlimited dimension */
  53    int ia, id;
  54    static char byte_vals[] = {'a', 'b'};
  55    static char char_vals[] = "chars";
  56    static short short_vals[] = {-999, 0, 999};
  57    static nclong long_vals[] = {10, 20};
  58    static float float_vals[] = {1.5, 2.5, 3.5 };
  59    static double double_vals[] = {4.5, 5.5, 6.5, 7.5};
  60    /* 
  61     * test attributes; it is important for this test that the size 
  62     * required for the attribute values increases monotonically.
  63     */
  64    static struct cdfatt atts[] = {
  65	{___, "att0", NC_BYTE, LEN_OF(byte_vals), (void *) byte_vals},
  66	{___, "att1", NC_CHAR, LEN_OF(char_vals), (void *) char_vals},
  67	{___, "att2", NC_SHORT, LEN_OF(short_vals), (void *) short_vals},
  68	{___, "att3", NC_LONG, LEN_OF(long_vals), (void *) long_vals},
  69	{___, "att4", NC_FLOAT, LEN_OF(float_vals), (void *) float_vals},
  70	{___, "att5", NC_DOUBLE, LEN_OF(double_vals), (void *) double_vals}
  71    };
  72    int na = LEN_OF(atts);	/* number of test attributes */
  73    int ww_id;			/* variable id */
  74    static struct cdfvar ww =	/* new variable */
  75      {"ww", NC_LONG, 1, ___, 0};
  76    static struct cdfatt tmp;	/* attribute */
  77
  78    (void) fprintf(stderr, "*** Testing %s ...\t", &pname[5]);
  79
  80    if ((cdfid = ncopen(path, NC_WRITE)) == -1) {
  81	error("%s: ncopen failed", pname);
  82	return;
  83    }
  84    /* enter define mode */
  85    if (ncredef(cdfid) == -1) {
  86	error("%s: cdredef failed", pname);
  87	ncclose(cdfid); return;
  88    }
  89    /* get count of global attributes */
  90    if (ncinquire(cdfid, &ndims, &nvars, &ngatts, &xdimid) == -1) {
  91	error("%s: ncinquire failed", pname);
  92	ncclose(cdfid); return;
  93    }
  94    ngatts_prev = ngatts;
  95    /* in define mode, add global attributes of every type */
  96    for (ia = 0; ia < na; ia++) {
  97	if (ncattput(cdfid, NC_GLOBAL, atts[ia].name, atts[ia].type,
  98		      atts[ia].len, atts[ia].val) == -1) {
  99	    error("%s: ncattput of NC_GLOBAL attribute failed", pname);
 100	    ncclose(cdfid); return;
 101	}
 102	add_att(&test, NC_GLOBAL, &atts[ia]); /* keep in-memory netcdf updated */
 103    }
 104    /* make sure count of global attributes has been updated */
 105    if (ncinquire(cdfid, &ndims, &nvars, &ngatts, &xdimid) == -1) {
 106	error("%s: ncinquire failed", pname);
 107	ncclose(cdfid); return;
 108    }
 109    if (ngatts != ngatts_prev + na) {
 110	error("%s: number of global = %d, expected %d",
 111	      pname, ngatts, ngatts_prev + na);
 112	nerrs++;
 113    }
 114    /* check with ncattinq and ncattget that NC_GLOBAL attributes put OK */
 115    for (ia = 0; ia < na; ia++) {
 116	if (ncattinq(cdfid, NC_GLOBAL, atts[ia].name,
 117		      &tmp.type, &tmp.len) == -1) {
 118	    error("%s: ncattinq of global attribute failed", pname);
 119	    ncclose(cdfid); return;
 120	}
 121	if (atts[ia].type != tmp.type || atts[ia].len != tmp.len) {
 122	    error("%s: NC_GLOBAL ncattinq got unexpected type or len",
 123		  pname);
 124	    ncclose(cdfid); return;
 125	}
 126	/* allocate space to hold the attribute value to be retrieved */
 127	tmp.val = emalloc(atts[ia].len * nctypelen(atts[ia].type));
 128	if (ncattget(cdfid, NC_GLOBAL, atts[ia].name, tmp.val) == -1) {
 129	    error("%s: ncattget of variable attribute failed", pname);
 130	    ncclose(cdfid); return;
 131	}
 132	if (val_cmp(tmp.type, tmp.len, tmp.val, atts[ia].val) != 0) {
 133	    error("%s: ncattget got bad values after put of NC_GLOBAL attrs",
 134		  pname);
 135	    nerrs++;
 136	}
 137	free (tmp.val);
 138    }
 139    /* add a variable, then variable attributes of every type */
 140    ww.dims = (int *) emalloc(sizeof(int) * ww.ndims);
 141    for (id = 0; id < ww.ndims; id++)
 142      ww.dims[id] = id;
 143    if ((ww_id = ncvardef(cdfid,
 144			   ww.name, ww.type, ww.ndims, ww.dims)) == -1) {
 145	error("%s: ncvardef failed", pname);
 146	ncclose(cdfid); return;
 147    }
 148    add_var(&test, &ww);	/* keep in-memory netcdf in sync */
 149    for (ia = 0; ia < na; ia++) {
 150	if (ncattput(cdfid, ww_id,
 151		      atts[ia].name, atts[ia].type, atts[ia].len, atts[ia].val)
 152	    == -1) {
 153	    error("%s: ncattput of variable attribute failed", pname);
 154	    ncclose(cdfid); return;
 155	}
 156	add_att(&test, ww_id, &atts[ia]); /* keep in-memory netcdf updated */
 157    }
 158    /* check with ncattinq and ncattget that variable attributes put OK */
 159    for (ia = 0; ia < na; ia++) {
 160	if (ncattinq(cdfid, ww_id, atts[ia].name,
 161		      &tmp.type, &tmp.len) == -1) {
 162	    error("%s: ncattinq of variable attribute failed", pname);
 163	    ncclose(cdfid); return;
 164	}
 165	if (atts[ia].type != tmp.type || atts[ia].len != tmp.len) {
 166	    error("%s: ncattinq for new attribute got bad type or len",
 167		  pname);
 168	    ncclose(cdfid); return;
 169	}
 170	/* allocate space to hold the attribute value to be retrieved */
 171	tmp.val = emalloc(atts[ia].len * nctypelen(atts[ia].type));
 172	if (ncattget(cdfid, ww_id, atts[ia].name, tmp.val) == -1) {
 173	    error("%s: ncattget of variable attribute failed", pname);
 174	    ncclose(cdfid); return;
 175	}
 176	if (val_cmp(tmp.type, tmp.len, tmp.val, atts[ia].val) != 0) {
 177	    error("%s: ncattget got bad values after put of variable attrs",
 178		  pname);
 179	    nerrs++;
 180	}
 181	free (tmp.val);
 182    }
 183    /*
 184     * check that changing type of existing attribute, increasing 
 185     * length of attribute, and changing value of existing attribute 
 186     * work OK in define mode.
 187     */
 188    tmp.name = (char *) emalloc(MAX_NC_NAME);
 189    for (ia = 1; ia < na; ia++) {
 190	if (ncattput(cdfid, ww_id, atts[ia-1].name, atts[ia].type,
 191		      atts[ia].len, atts[ia].val) == -1) {
 192	    error("%s: ncattput of larger attribute failed", pname);
 193	    ncclose(cdfid); return;
 194	}
 195	tmp.var = atts[ia].var;
 196	(void) strcpy (tmp.name, atts[ia-1].name);
 197	tmp.type = atts[ia].type;
 198	tmp.len = atts[ia].len;
 199	tmp.val = atts[ia].val;
 200	add_att(&test, ww_id, &tmp); /* keep in-memory netcdf updated */
 201    }
 202    /* check with ncattinq and ncattget that variable attributes put OK */
 203    for (ia = 1; ia < na; ia++) {
 204	if (ncattinq(cdfid, ww_id, atts[ia-1].name,
 205		      &tmp.type, &tmp.len) == -1) {
 206	    error("%s: ncattinq of larger attribute failed", pname);
 207	    ncclose(cdfid); return;
 208	}
 209	if (atts[ia].type != tmp.type || atts[ia].len != tmp.len) {
 210	    error("%s: ncattinq for larger attribute got bad type or len",
 211		  pname);
 212	    ncclose(cdfid); return;
 213	}
 214	/* allocate space to hold the attribute value to be retrieved */
 215	tmp.val = emalloc(atts[ia].len * nctypelen(atts[ia].type));
 216	if (ncattget(cdfid, ww_id, atts[ia-1].name, tmp.val) == -1) {
 217	    error("%s: ncattget of variable attribute failed", pname);
 218	    ncclose(cdfid); return;
 219	}
 220	if (val_cmp(tmp.type, tmp.len, tmp.val, atts[ia].val) != 0) {
 221	    error("%s: ncattget got bad values after put of larger attrs",
 222		  pname);
 223	    nerrs++;
 224	}
 225	free (tmp.val);
 226    }
 227    /* try with bad datatype, should fail */
 228    if (ncattput(cdfid, ww_id, "bogus_att1", BAD_TYPE,
 229		  atts[0].len, atts[0].val) != -1) {
 230	error("%s: ncattput should fail with bad type", pname);
 231	nerrs++;
 232    }
 233    /* try with negative length, should fail */
 234    if (ncattput(cdfid, ww_id, "bogus_att2", atts[0].type,
 235		  -1, atts[0].val) != -1) {
 236	error("%s: ncattput should fail with bad length", pname);
 237	nerrs++;
 238    }
 239    if (ncendef (cdfid) == -1) {
 240	error("%s: ncendef failed", pname);
 241	ncclose(cdfid); return;
 242    }
 243    /* in data mode try increasing length of attribute, should fail */
 244    if (ncattput(cdfid, ww_id, atts[0].name, atts[0].type,
 245		  atts[0].len + 10, atts[0].val) != -1) {
 246	error("%s: ncattput should fail with increased length in data mode",
 247	      pname);
 248	nerrs++;
 249	/* reset to correct length for later tests */
 250	if (ncattput(cdfid, ww_id, atts[0].name, atts[0].type,
 251		      atts[0].len, atts[0].val) != -1) {
 252	    error("%s: ncattput failed to reset length in data mode", pname);
 253	    nerrs++;
 254	}
 255    }
 256    /* try creating new attribute in data mode, should fail */
 257    if (ncattput(cdfid, ww_id, "new_name", atts[0].type,
 258		  atts[0].len, atts[0].val) != -1) {
 259	error("%s: ncattput of new attribute in data mode should fail",
 260	      pname);
 261	ncclose(cdfid); return;
 262    }
 263    /* 
 264     * check that changing type of existing attribute, decreasing 
 265     * length of attribute, and changing value of existing attribute 
 266     * work OK in data mode
 267     */
 268    for (ia = 0; ia < na - 1; ia++) {
 269	if (ncattput(cdfid, ww_id, atts[ia+1].name, atts[ia].type,
 270		      atts[ia].len, atts[ia].val) == -1) {
 271	    error("%s: ncattput of smaller attribute failed in data mode",
 272		  pname);
 273	    ncclose(cdfid); return;
 274	}
 275	tmp.var = atts[ia].var;
 276	(void) strcpy (tmp.name, atts[ia+1].name);
 277	tmp.type = atts[ia].type;
 278	tmp.len = atts[ia].len;
 279	tmp.val = atts[ia].val;
 280	add_att(&test, ww_id, &tmp); /* keep in-memory netcdf updated */
 281    }
 282    /* check with ncattinq and ncattget that variable attributes put OK */
 283    for (ia = 0; ia < na - 1; ia++) {
 284	if (ncattinq(cdfid, ww_id, atts[ia+1].name, &tmp.type, &tmp.len)
 285	    == -1) {
 286	    error("%s: ncattinq of variable attribute failed in data mode",
 287		  pname);
 288	    ncclose(cdfid); return;
 289	}
 290	if (atts[ia].type != tmp.type || atts[ia].len != tmp.len) {
 291	    error("%s: VARIABLE ncattinq got bad type or len in data mode",
 292		  pname);
 293	    ncclose(cdfid); return;
 294	}
 295	/* allocate space to hold the attribute value to be retrieved */
 296	tmp.val = emalloc(atts[ia].len * nctypelen(atts[ia].type));
 297	if (ncattget(cdfid, ww_id, atts[ia+1].name, tmp.val) == -1) {
 298	    error("%s: ncattget of variable attribute failed in data mode",
 299		  pname);
 300	    ncclose(cdfid); return;
 301	}
 302	if (val_cmp(tmp.type, tmp.len, tmp.val, atts[ia].val) != 0) {
 303	    error("%s: ncattget got bad values in data mode", pname);
 304	    nerrs++;
 305	}
 306	free (tmp.val);
 307    }
 308    /* try with bad variable handle, should fail */
 309    if (ncattput(cdfid, test.nvars, atts[0].name, atts[0].type, atts[0].len,
 310		  atts[0].val) != -1) {
 311	error("%s: ncattput should fail with bad variable handle", pname);
 312	ncclose(cdfid); return;
 313    }
 314    if (ncclose (cdfid) == -1) {
 315	error("%s: ncclose failed", pname);
 316	return;
 317    }
 318    /* try with bad netcdf handle, should fail */
 319    if (ncattput(cdfid, ww_id, atts[0].name, atts[0].type, atts[0].len,
 320		  atts[0].val) != -1) {
 321	error("%s: ncattput should fail with bad netcdf handle", pname);
 322	ncclose(cdfid); return;
 323    }
 324    free(tmp.name);
 325    if (nerrs > 0)
 326      (void) fprintf(stderr,"FAILED! ***\n");
 327    else
 328      (void) fprintf(stderr,"ok ***\n");
 329}
 330
 331
 332/*
 333 * Test ncattinq
 334 *    check returned values of properly created attributes
 335 *    try with nonexisting attribute, check error
 336 *    try with bad variable handle, check error
 337 *    try with bad netCDF handle, check error
 338 */
 339void
 340test_ncattinq(path)
 341     const char *path;		/* name of writable netcdf file to open */
 342{
 343    int nerrs = 0;
 344    static char pname[] = "test_ncattinq";
 345    int cdfid;			/* netcdf id */
 346    int ia, id;			/* attribute number */
 347    nc_type type;
 348    int len;
 349    int vv_id;			/* variable id */
 350    static struct cdfvar vv =	/* new variable */
 351      {"vv", NC_SHORT, 2, ___, 0};
 352
 353    (void) fprintf(stderr, "*** Testing %s ...\t", &pname[5]);
 354
 355    if ((cdfid = ncopen(path, NC_WRITE)) == -1) {
 356	error("%s: ncopen failed", pname);
 357	return;
 358    }
 359    /* in data mode, check all attributes against test netcdf */
 360    for (ia = 0; ia < test.natts; ia++) {
 361	if (ncattinq(cdfid, test.atts[ia].var, test.atts[ia].name,
 362		      &type, &len) == -1) {
 363	    error("%s: ncattinq failed", pname);
 364	    ncclose(cdfid);
 365	    return;
 366	}
 367	if (type != test.atts[ia].type) {
 368	    error("%s: ncattinq returned wrong type", pname);
 369	    ncclose(cdfid);
 370	    return;
 371	}
 372	if (len != test.atts[ia].len) {
 373	    error("%s: ncattinq returned wrong len", pname);
 374	    ncclose(cdfid);
 375	    return;
 376	}
 377    }
 378
 379    /* enter define mode */
 380    if (ncredef(cdfid) == -1) {
 381	error("%s: cdredef failed", pname);
 382	ncclose(cdfid); return;
 383    }
 384    /* in define mode, add a variable */
 385    vv.dims = (int *) emalloc(sizeof(int) * vv.ndims);
 386    for (id = 0; id < vv.ndims; id++)
 387      vv.dims[id] = id;		/* assumes vv.ndims <= test.ndims */
 388    if ((vv_id = ncvardef(cdfid, vv.name, vv.type, vv.ndims, vv.dims))
 389	== -1) {
 390	error("%s: ncvardef failed", pname);
 391	ncclose(cdfid); return;
 392    }
 393    add_var(&test, &vv);	/* keep in-memory netcdf in sync */
 394
 395    /* try with nonexisting attribute, should fail */
 396    if (ncattinq(cdfid, vv_id, "nonesuch", &type, &len) != -1) {
 397	error("%s: ncattinq should fail with nonexisting attribute", pname);
 398	ncclose(cdfid); return;
 399    }
 400    /* try with bad variable handle, should fail */
 401    if (ncattinq(cdfid, test.nvars, test.atts[0].name, &type, &len) != -1) {
 402	error("%s: ncattinq should fail with bad variable id", pname);
 403	ncclose(cdfid); return;
 404    }
 405    /* in define mode check all attributes against test netcdf */
 406    for (ia = 0; ia < test.natts; ia++) {
 407	if (ncattinq(cdfid, test.atts[ia].var, test.atts[ia].name,
 408		      &type, &len) == -1) {
 409	    error("%s: ncattinq in define mode failed", pname);
 410	    ncclose(cdfid);
 411	    return;
 412	}
 413	if (type != test.atts[ia].type) {
 414	    error("%s: ncattinq in define mode returned wrong type", pname);
 415	    ncclose(cdfid);
 416	    return;
 417	}
 418	if (len != test.atts[ia].len) {
 419	    error("%s: ncattinq in define mode returned wrong len", pname);
 420	    ncclose(cdfid);
 421	    return;
 422	}
 423    }
 424    if (ncendef (cdfid) == -1) {
 425	error("%s: ncendef failed", pname);
 426	ncclose(cdfid); return;
 427    }
 428    if (ncclose (cdfid) == -1) {
 429	error("%s: ncclose failed", pname);
 430	return;
 431    }
 432    if (ncattinq(cdfid, NC_GLOBAL, test.atts[0].name, &type, &len) != -1) {
 433	error("%s: ncattinq should fail with bad cdfid", pname);
 434	nerrs++;
 435    }
 436    if (nerrs > 0)
 437      (void) fprintf(stderr,"FAILED! ***\n");
 438    else
 439      (void) fprintf(stderr,"ok ***\n");
 440}
 441
 442
 443/*
 444 * Test ncattget
 445 *    check that NC_GLOBAL variable id works
 446 *    check in both modes
 447 *    check that proper call worked after ncattput
 448 *    try with bad variable handle, check error
 449 *    try with nonexisting attribute, check error
 450 *    try with bad netCDF handle, check error
 451 */
 452void
 453test_ncattget(path)
 454     const char *path;		/* name of writable netcdf file to open */
 455{
 456    int nerrs = 0;
 457    int cdfid;			/* netcdf id */
 458    int ia, id;
 459    static struct cdfatt tmp;	/* attribute */
 460    int uu_id;			/* variable id */
 461    static struct cdfvar uu =	/* variable */
 462      {"uu", NC_LONG, 2, ___, 0};
 463    static nclong uumax = 1000;	/* attribute value */
 464    static struct cdfatt vmax = /* attribute */
 465	{___, "valid_max", NC_LONG, 1, (void *) &uumax};
 466
 467    static char pname[] = "test_ncattget";
 468
 469    (void) fprintf(stderr, "*** Testing %s ...\t", &pname[5]);
 470
 471    if ((cdfid = ncopen(path, NC_WRITE)) == -1) {
 472	error("%s: ncopen failed", pname);
 473	return;
 474    }
 475    /* enter define mode */
 476    if (ncredef(cdfid) == -1) {
 477	error("%s: cdredef failed", pname);
 478	ncclose(cdfid); return;
 479    }
 480    /* add a variable */
 481    uu.dims = (int *) emalloc(sizeof(int) * uu.ndims);
 482    for (id = 0; id < uu.ndims; id++)
 483      uu.dims[id] = id;
 484    if ((uu_id = ncvardef(cdfid,
 485			   uu.name, uu.type, uu.ndims, uu.dims)) == -1) {
 486	error("%s: ncvardef failed", pname);
 487	ncclose(cdfid); return;
 488    }
 489    add_var(&test, &uu);	/* keep in-memory netcdf in sync */
 490
 491    /* add an attribute */
 492    if (ncattput(cdfid, uu_id,
 493		  vmax.name, vmax.type, vmax.len, vmax.val)
 494	== -1) {
 495	error("%s: ncattput of variable attribute failed", pname);
 496	ncclose(cdfid); return;
 497    }
 498    add_att(&test, uu_id, &vmax); /* keep in-memory netcdf updated */
 499
 500    /* in define mode, check all attributes values against test netcdf */
 501    for (ia = 0; ia < test.natts; ia++) {
 502	if (ncattinq(cdfid, test.atts[ia].var, test.atts[ia].name,
 503		      &tmp.type, &tmp.len) == -1) {
 504	    error("%s: ncattinq in define mode failed", pname);
 505	    ncclose(cdfid); return;
 506	}
 507	if (tmp.type != test.atts[ia].type) {
 508	    error("%s: ncattinq in define mode returned wrong type", pname);
 509	    ncclose(cdfid);
 510	    return;
 511	}
 512	if (tmp.len != test.atts[ia].len) {
 513	    error("%s: ncattinq in define mode returned wrong len", pname);
 514	    ncclose(cdfid); return;
 515	}
 516	/* allocate space to hold the attribute value to be retrieved */
 517	tmp.val = emalloc(tmp.len * nctypelen(tmp.type));
 518	if (ncattget(cdfid, test.atts[ia].var, test.atts[ia].name, tmp.val)
 519	    == -1) {
 520	    error("%s: ncattget of variable attribute failed in define mode",
 521		  pname);
 522	    ncclose(cdfid); return;
 523	}
 524	if (val_cmp(tmp.type, tmp.len, tmp.val, test.atts[ia].val) != 0) {
 525	    error("%s: ncattget got bad values in define mode", pname);
 526	    error("   cdfid=%d, varname=%s, attname=%s, type=%d, len=%d",
 527		  cdfid, test.vars[test.atts[ia].var].name,
 528		  test.atts[ia].name, test.atts[ia].type, test.atts[ia].len);
 529	    (void)fprintf(stderr,"should have got:");
 530	    val_out(test.atts[ia].type, test.atts[ia].len,
 531			   test.atts[ia].val);
 532	    (void)fprintf(stderr,"    instead got:");
 533	    val_out(tmp.type, tmp.len, tmp.val);
 534	    nerrs++;
 535	}
 536	free (tmp.val);
 537    }
 538    if (ncendef (cdfid) == -1) {
 539	error("%s: ncendef failed", pname);
 540	ncclose(cdfid); return;
 541    }
 542
 543    /* in data mode, check all attributes values against test netcdf */
 544    for (ia = 0; ia < test.natts; ia++) {
 545	if (ncattinq(cdfid, test.atts[ia].var, test.atts[ia].name,
 546		      &tmp.type, &tmp.len) == -1) {
 547	    error("%s: ncattinq failed", pname);
 548	    ncclose(cdfid);
 549	    return;
 550	}
 551	if (tmp.type != test.atts[ia].type) {
 552	    error("%s: ncattinq returned wrong type", pname);
 553	    ncclose(cdfid);
 554	    return;
 555	}
 556	if (tmp.len != test.atts[ia].len) {
 557	    error("%s: ncattinq returned wrong len", pname);
 558	    ncclose(cdfid);
 559	    return;
 560	}
 561	/* allocate space to hold the attribute value to be retrieved */
 562	tmp.val = emalloc(tmp.len * nctypelen(tmp.type));
 563	if (ncattget(cdfid, test.atts[ia].var, test.atts[ia].name, tmp.val)
 564	    == -1) {
 565	    error("%s: ncattget of variable attribute failed in data mode",
 566		  pname);
 567	    ncclose(cdfid); return;
 568	}
 569	if (val_cmp(tmp.type, tmp.len, tmp.val, test.atts[ia].val) != 0) {
 570	    error("%s: ncattget got bad values in data mode", pname);
 571	    error("   cdfid=%d, varname=%s, attname=%s, type=%d, len=%d",
 572		  cdfid, test.vars[test.atts[ia].var].name,
 573		  test.atts[ia].name, test.atts[ia].type, test.atts[ia].len);
 574	    (void)fprintf(stderr,"should have got:");
 575	    val_out(test.atts[ia].type, test.atts[ia].len,
 576			   test.atts[ia].val);
 577	    (void)fprintf(stderr,"    instead got:");
 578	    val_out(tmp.type, tmp.len, tmp.val);
 579	    nerrs++;
 580	}
 581	free (tmp.val);
 582    }
 583    /* try with bad variable handle, should fail */
 584    if (ncattget(cdfid, test.nvars, vmax.name, vmax.val) != -1) {
 585	error("%s: ncattget should fail with bad variable handle", pname);
 586	ncclose(cdfid); return;
 587    }
 588    /* try getting non-existent attribute, should fail */
 589    if (ncattget(cdfid, uu_id, "nonesuch", vmax.val) != -1) {
 590	error("%s: ncattget should fail with nonexistant attribute", pname);
 591	ncclose(cdfid); return;
 592    }
 593    if (ncclose (cdfid) == -1) {
 594	error("%s: ncclose failed", pname);
 595	return;
 596    }
 597    /* try with bad netcdf handle, should fail */
 598    if (ncattget(cdfid, uu_id, vmax.name, vmax.val) != -1) {
 599	error("%s: ncattput should fail with bad netcdf handle", pname);
 600	ncclose(cdfid); return;
 601    }
 602    if (nerrs > 0)
 603      (void) fprintf(stderr,"FAILED! ***\n");
 604    else
 605      (void) fprintf(stderr,"ok ***\n");
 606}
 607
 608
 609/*
 610 * Test ncattcopy
 611 *    check that NC_GLOBAL variable for source or target works
 612 *    check that new attribute put works with target in define mode
 613 *    check that old attribute put works with target in data mode
 614 *    check that changing type and length of an attribute work OK
 615 *    try with same cdfid for source and target, different variables
 616 *    try with same cdfid for source and target, same variable
 617 *    try with nonexisting attribute, check error
 618 *    try with bad source or target netCDF handles, check error
 619 *    try with bad source or target variable handle, check error
 620 */
 621void
 622test_ncattcopy(path1, path2)
 623     const char *path1;		/* name of input netcdf file to open */
 624     const char *path2;		/* name of output netcdf file to create */
 625{
 626    int nerrs = 0;
 627    static char pname[] = "test_ncattcopy";
 628    int cdfid, cdfid2;		/* netcdf id */
 629    int id;			/* dimension id */
 630    int tt_id;			/* variable id */
 631    static struct cdfvar tt =	/* new variable for source netcdf */
 632      {"tt", NC_LONG, 1, ___, 0};
 633    int tu_id, tu2_id;		/* variable ids */
 634    static struct cdfvar tu =	/* new variable for target netcdf */
 635      {"tu", NC_DOUBLE, 2, ___, 0};
 636    static double double_vals[] = {-1., -2.};
 637    static float float_vals[] = {-1., -2.};
 638    static struct cdfatt att = 	/* attribute */
 639 	{___, "att", NC_DOUBLE, LEN_OF(double_vals), (void *) double_vals};
 640    static struct cdfatt att2 =	/* attribute */
 641 	{___, "att", NC_FLOAT, LEN_OF(float_vals), (void *) float_vals};
 642    static struct cdfatt tmp; 	/* attribute */
 643
 644    (void) fprintf(stderr, "*** Testing %s ...\t", &pname[5]);
 645
 646    if ((cdfid = ncopen(path1, NC_WRITE)) == -1) {
 647	error("%s: ncopen failed", pname);
 648	return;
 649    }
 650    /* opened OK, enter define mode */
 651    if (ncredef(cdfid) == -1) {
 652	error("%s: ncredef failed on source", pname);
 653	ncclose(cdfid); return;
 654    }
 655    /* in define mode, add a global attribute, a variable and an attribute */
 656    if (ncattput(cdfid, NC_GLOBAL, att.name, att.type, att.len, att.val) == -1) {
 657	error("%s: ncattput failed", pname);
 658	ncclose(cdfid); return;
 659    }
 660    add_att(&test, NC_GLOBAL, &att); /* keep in-memory netcdf consistent */
 661    tt.dims = (int *) emalloc(sizeof(int) * tt.ndims);
 662    for (id=0; id < tt.ndims; id++)
 663      tt.dims[0] = id;
 664    if ((tt_id=ncvardef(cdfid, tt.name, tt.type, tt.ndims, tt.dims)) == -1) {
 665	error("%s: ncvardef failed", pname);
 666	ncclose(cdfid); return;
 667    }
 668    add_var(&test, &tt);	/* keep in-memory netcdf consistent */
 669    if (ncattput(cdfid, tt_id, att.name, att.type, att.len, att.val) == -1) {
 670	error("%s: ncattput failed", pname);
 671	ncclose(cdfid); return;
 672    }
 673    add_att(&test, tt_id, &att); /* keep in-memory netcdf consistent */
 674
 675    tu.dims = (int *) emalloc(sizeof(int) * tu.ndims);
 676    for (id = 0; id < tu.ndims; id++)
 677	tu.dims[id] = id;
 678    if ((tu_id=ncvardef(cdfid, tu.name, tu.type, tu.ndims, tu.dims)) == -1) {
 679	error("%s: ncvardef failed", pname);
 680	ncclose(cdfid); return;
 681    }
 682    add_var(&test, &tu);	/* keep in-memory netcdf consistent */
 683    if (ncattput(cdfid, tu_id, att.name, att.type, att.len, att.val) == -1) {
 684	error("%s: ncattput failed", pname);
 685	ncclose(cdfid); return;
 686    }
 687    add_att(&test, tu_id, &att); /* keep in-memory netcdf consistent */
 688    if (ncendef (cdfid) == -1) {
 689	error("%s: ncendef failed", pname);
 690	ncclose(cdfid); return;
 691    }
 692    /* first (source) netcdf is in data mode */
 693    /* create second netCDF to copy attributes to */
 694    if ((cdfid2 = nccreate(path2, NC_CLOBBER)) == -1) {
 695	error("%s: nccreate failed", pname);
 696	return;
 697    }
 698    /* create dimensions and variable in second netcdf */
 699    for (id = 0; id < tu.ndims; id++)	{ /* copy dimensions from source */
 700	if ((tu.dims[id] =ncdimdef(cdfid2, test.dims[id].name,
 701				    test.dims[id].size)) == -1) {
 702	    error("%s: ncdimdef failed", pname);
 703	    ncclose(cdfid); ncclose(cdfid2); return;
 704	}
 705    }
 706    if ((tu2_id=ncvardef(cdfid2, tu.name, tu.type, tu.ndims, tu.dims)) == -1) {
 707	error("%s: ncvardef failed", pname);
 708	ncclose(cdfid); ncclose(cdfid2); return;
 709    }
 710    /* try copying NC_GLOBAL attribute from source to target */
 711    if (ncattcopy(cdfid, NC_GLOBAL, att.name, cdfid2, NC_GLOBAL) == -1) {
 712	error("%s: ncattcopy on NC_GLOBAL attribute '%s' failed",
 713	      pname, att.name);
 714	ncclose(cdfid); ncclose(cdfid2); return;
 715    }
 716    /* check that copy worked with ncattinq and ncattget */
 717    if (ncattinq(cdfid2, NC_GLOBAL, att.name, &tmp.type, &tmp.len) == -1) {
 718	error("%s: ncattinq of NC_GLOBAL attribute failed", pname);
 719	ncclose(cdfid); ncclose(cdfid2); return;
 720    }
 721    if (att.type != tmp.type || att.len != tmp.len) {
 722	error("%s: NC_GLOBAL ncattinq got unexpected type or len", pname);
 723	ncclose(cdfid); ncclose(cdfid2); return;
 724    }
 725    /* allocate space to hold the attribute value to be retrieved */
 726    tmp.val = emalloc(att.len * nctypelen(att.type));
 727    if (ncattget(cdfid2, NC_GLOBAL, att.name, tmp.val) == -1) {
 728	error("%s: ncattget of variable attribute failed", pname);
 729	ncclose(cdfid); ncclose(cdfid2); return;
 730    }
 731    if (val_cmp(tmp.type, tmp.len, tmp.val, att.val) != 0) {
 732	error("%s: ncattget got bad values after put of NC_GLOBAL attrs",
 733	      pname);
 734	nerrs++;
 735    }
 736    free (tmp.val);
 737    /* try copying variable attribute from source to target */
 738    if (ncattcopy(cdfid, tt_id, att.name, cdfid2, tu2_id) == -1) {
 739	error("%s: ncattcopy failed", pname);
 740	ncclose(cdfid); ncclose(cdfid2); return;
 741    }
 742    /* check that copy worked with ncattinq and ncattget */
 743    if (ncattinq(cdfid2, tu2_id, att.name, &tmp.type, &tmp.len) == -1) {
 744	error("%s: ncattinq of variable attribute failed", pname);
 745	ncclose(cdfid); ncclose(cdfid2); return;
 746    }
 747    if (att.type != tmp.type || att.len != tmp.len) {
 748	error("%s: variable ncattinq got unexpected type or len", pname);
 749	ncclose(cdfid); ncclose(cdfid2); return;
 750    }
 751    /* allocate space to hold the attribute value to be retrieved */
 752    tmp.val = emalloc(att.len * nctypelen(att.type));
 753    if (ncattget(cdfid2, tu2_id, att.name, tmp.val) == -1) {
 754	error("%s: ncattget of variable attribute failed", pname);
 755	ncclose(cdfid); ncclose(cdfid2); return;
 756    }
 757    if (val_cmp(tmp.type, tmp.len, tmp.val, att.val) != 0) {
 758	error("%s: ncattget got bad values after copy of variable attrs",
 759	      pname);
 760	nerrs++;
 761    }
 762    free (tmp.val);
 763
 764    /* 
 765     * check that old attribute put works with target in data mode, 
 766     * also checks that changing type and length of an attribute works OK
 767     */
 768    if (ncendef (cdfid2) == -1) {
 769	error("%s: ncendef failed", pname);
 770	ncclose(cdfid); ncclose(cdfid2); return;
 771    }
 772    /* change attribute to shorter attribute */
 773    if (ncattput(cdfid, NC_GLOBAL, att2.name, att2.type, att2.len, att2.val)
 774	== -1) {
 775	error("%s: ncattput of shorter NC_GLOBAL attribute failed", pname);
 776	ncclose(cdfid); ncclose(cdfid2); return;
 777    }
 778    add_att(&test, NC_GLOBAL, &att2); /* keep in-memory netcdf consistent */
 779    /* copy shorter attribute on existing attribute */
 780    if (ncattcopy(cdfid, NC_GLOBAL, att2.name, cdfid2, tu2_id) == -1) {
 781	error("%s: ncattcopy of shorter attribute on old attribute failed",
 782	      pname);
 783	ncclose(cdfid); ncclose(cdfid2); return;
 784    }
 785    /* check that copy worked with ncattinq and ncattget */
 786    if (ncattinq(cdfid2, tu2_id, att2.name, &tmp.type, &tmp.len) == -1) {
 787	error("%s: ncattinq of variable attribute failed", pname);
 788	ncclose(cdfid); ncclose(cdfid2); return;
 789    }
 790    if (att2.type != tmp.type || att2.len != tmp.len) {
 791	error("%s: variable ncattinq got unexpected type or len", pname);
 792	ncclose(cdfid); ncclose(cdfid2); return;
 793    }
 794    /* allocate space to hold the attribute value to be retrieved */
 795    tmp.val = emalloc(att2.len * nctypelen(att2.type));
 796    if (ncattget(cdfid2, tu2_id, att2.name, tmp.val) == -1) {
 797	error("%s: ncattget of variable attribute failed", pname);
 798	ncclose(cdfid); ncclose(cdfid2); return;
 799    }
 800    if (val_cmp(tmp.type, tmp.len, tmp.val, att2.val) != 0) {
 801	error("%s: ncattget got bad values after copy of variable attrs",
 802	      pname);
 803	nerrs++;
 804    }
 805    free (tmp.val);
 806
 807    /* try copying with same source and target netcdf, different variables */
 808    /* copy shorter attribute on existing attribute */
 809    if (ncattcopy(cdfid, NC_GLOBAL, att2.name, cdfid, tu_id) == -1) {
 810	error("%s: ncattcopy of shorter NC_GLOBAL attribute failed", pname);
 811	ncclose(cdfid); ncclose(cdfid2); return;
 812    }
 813    add_att(&test, tu_id, &att2); /* keep in-memory netcdf consistent */
 814    /* check that copy worked with ncattinq and ncattget */
 815    if (ncattinq(cdfid, tu_id, att2.name, &tmp.type, &tmp.len) == -1) {
 816	error("%s: ncattinq of variable attribute failed", pname);
 817	ncclose(cdfid); ncclose(cdfid2); return;
 818    }
 819    if (att2.type != tmp.type || att2.len != tmp.len) {
 820	error("%s: variable ncattinq got unexpected type or len", pname);
 821	ncclose(cdfid); ncclose(cdfid2); return;
 822    }
 823    /* allocate space to hold the attribute value to be retrieved */
 824    tmp.val = emalloc(att2.len * nctypelen(att2.type));
 825    if (ncattget(cdfid, tu_id, att2.name, tmp.val) == -1) {
 826	error("%s: ncattget of variable attribute failed", pname);
 827	ncclose(cdfid); ncclose(cdfid2); return;
 828    }
 829    if (val_cmp(tmp.type, tmp.len, tmp.val, att2.val) != 0) {
 830	error("%s: ncattget got bad values after copy of variable attrs",
 831	      pname);
 832	nerrs++;
 833    }
 834    free (tmp.val);
 835
 836    /* try with same cdfid for source and target, same variable */
 837    if (ncattcopy(cdfid, tu_id, att.name, cdfid, tu_id) == -1) {
 838	error("%s: ncattcopy failed with identical source and target",
 839	      pname);
 840	ncclose(cdfid); ncclose(cdfid2); return;
 841    }
 842    /* try with nonexisting attribute, check error */
 843    if (ncattcopy(cdfid, tt_id, "nonesuch", cdfid, tu_id) != -1) {
 844	error("%s: ncattcopy should fail with bad attribute name",
 845	      pname);
 846	ncclose(cdfid); ncclose(cdfid2); return;
 847    }
 848    /* try with bad source or target variable handle, check error */
 849    if (ncattcopy(cdfid, test.nvars, att.name, cdfid, tu_id) != -1) {
 850	error("%s: ncattcopy should fail with bad source variable id",
 851	      pname);
 852	ncclose(cdfid); ncclose(cdfid2); return;
 853    }
 854    if (ncattcopy(cdfid, tt_id, att.name, cdfid, 2) != -1) {
 855	error("%s: ncattcopy should fail with bad target variable id",
 856	      pname);
 857	ncclose(cdfid); ncclose(cdfid2); return;
 858    }
 859    if (ncclose (cdfid2) == -1) {
 860	error("%s: ncclose failed", pname);
 861	ncclose(cdfid); return;
 862    }
 863    /* try with bad source or target netCDF handles, check error */
 864    if (ncattcopy(cdfid, tt_id, att.name, cdfid2, tu_id) != -1) {
 865	error("%s: ncattcopy should fail with bad target netcdf id",
 866	      pname);
 867	ncclose(cdfid); return;
 868    }
 869    if (ncclose (cdfid) == -1) {
 870	error("%s: ncclose failed", pname);
 871	return;
 872    }
 873    if (ncattcopy(cdfid, tt_id, att.name, cdfid2, tu_id) != -1) {
 874	error("%s: ncattcopy should fail with bad netcdf id", pname);
 875	nerrs++;
 876    }
 877    if (nerrs > 0)
 878      (void) fprintf(stderr,"FAILED! ***\n");
 879    else
 880      (void) fprintf(stderr,"ok ***\n");
 881}
 882
 883
 884/*
 885 * Test ncattname
 886 *    check that NC_GLOBAL variable id works
 887 *    check in both modes
 888 *    check that proper call worked after ncattput
 889 *    try with bad netCDF handle, check error
 890 *    try with bad variable handle, check error
 891 *    try with bad attribute number, check error
 892 */
 893void
 894test_ncattname(path)
 895     const char *path;		/* name of writable netcdf file to open */
 896{
 897    int nerrs = 0;
 898    static char pname[] = "test_ncattname";
 899    int cdfid;			/* netcdf id */
 900    struct cdfatt tmp;		/* attributes */
 901    int ia, ib;			/* attribute numbers */
 902    int iv;			/* variable id */
 903    static short short_vals[] = {3, 4, 5};
 904    static struct cdfatt att = 	/* attribute */
 905 	{___, ___, NC_SHORT, LEN_OF(short_vals), (void *) short_vals};
 906
 907    (void) fprintf(stderr, "*** Testing %s ...\t", &pname[5]);
 908
 909    if ((cdfid = ncopen(path, NC_WRITE)) == -1) {
 910	error("%s: ncopen failed", pname);
 911	return;
 912    }
 913    /* opened OK, enter define mode */
 914    if (ncredef(cdfid) == -1) {
 915	error("%s: ncredef failed", pname);
 916	ncclose(cdfid); return;
 917    }
 918    /* for each NC_GLOBAL attribute, get name and compare with expected name */
 919    att.name = (char *) emalloc(MAX_NC_NAME);
 920    ib = 0;
 921    for (ia = 0; ia < test.ngatts; ia++) {
 922	if (ncattname(cdfid, NC_GLOBAL, ia, att.name) == -1) {
 923	    error("%s: ncattname failed on global attribute", pname);
 924	    ncclose(cdfid); return;
 925	}
 926	/* find number of next global attribute */
 927	while (ib < test.natts && test.atts[ib].var != NC_GLOBAL)
 928	  ib++;
 929	if (ib >= test.natts) {
 930	    error("%s: test problem, expected global attribute not found",
 931		  pname);
 932	    ncclose(cdfid); return;
 933	}
 934	if (strcmp(att.name, test.atts[ib].name) != 0) {
 935	    error("%s: NC_GLOBAL attribute name `%s' instead of expected `%s'",
 936		  pname, att.name, test.atts[ib].name);
 937	    nerrs++;
 938	}
 939	ib++;
 940    }
 941    /* for each variable attribute, get name and compare with expected name */
 942    for (iv = 0; iv < test.nvars; iv++) {
 943	ib = 0;
 944	for (ia = 0; ia < test.vars[iv].natts; ia++) {
 945	    if (ncattname(cdfid, iv, ia, att.name) == -1) {
 946		error("%s: ncattname failed on variable attribute", pname);
 947		ncclose(cdfid); return;
 948	    }
 949	    /* find number of next attribute */
 950	    while (ib < test.natts && test.atts[ib].var != iv)
 951	      ib++;
 952	    if (ib >= test.natts) {
 953		error("%s: problem  in test, expected attribute not found",
 954		      pname);
 955		ncclose(cdfid); return;
 956	    }
 957	    if (strcmp(att.name, test.atts[ib].name) != 0) {
 958		error("%s: variable '%s' name `%s' instead of expected `%s'",
 959		      pname, test.vars[iv].name, att.name, test.atts[ib].name);
 960		nerrs++;
 961	    }
 962	    ib++;
 963	}
 964    }
 965    /* in define mode, add a global attribute */
 966    (void) strcpy(att.name,"attx");
 967    if (ncattput(cdfid, NC_GLOBAL, att.name, att.type, att.len, att.val)
 968	== -1) {
 969	error("%s: ncattput failed", pname);
 970	ncclose(cdfid); return;
 971    }
 972    add_att(&test, NC_GLOBAL, &att); /* keep in-memory netcdf consistent */
 973    /* test that ncattname works immediately after ncattput */
 974    tmp.name = (char *) emalloc(MAX_NC_NAME);
 975    if (ncattname(cdfid, NC_GLOBAL, test.ngatts-1, tmp.name) == -1) {
 976	error("%s: ncattname failed on variable attribute", pname);
 977	ncclose(cdfid); return;
 978    }
 979    if (strcmp(att.name, tmp.name) != 0) {
 980	error("%s: immediate NC_GLOBAL name `%s' instead of expected `%s'",
 981	      pname, tmp.name, att.name);
 982	nerrs++;
 983    }
 984    if (ncendef (cdfid) == -1) {
 985	error("%s: ncendef failed", pname);
 986	ncclose(cdfid); return;
 987    }
 988    /* in data mode */
 989    /* for each NC_GLOBAL attribute, get name and compare with expected name */
 990    ib = 0;
 991    for (ia = 0; ia < test.ngatts; ia++) {
 992	if (ncattname(cdfid, NC_GLOBAL, ia, att.name) == -1) {
 993	    error("%s: ncattname failed on global attribute", pname);
 994	    ncclose(cdfid); return;
 995	}
 996	/* find number of next global attribute */
 997	while (ib < test.natts && test.atts[ib].var != NC_GLOBAL)
 998	  ib++;
 999	if (ib >= test.natts) {
1000	    error("%s: test problem, expected global attribute not found",
1001		  pname);
1002	    ncclose(cdfid); return;
1003	}
1004	if (strcmp(att.name, test.atts[ib].name) != 0) {
1005	    error("%s: NC_GLOBAL attribute name `%s' instead of expected `%s'",
1006		  pname, att.name, test.atts[ib].name);
1007	    nerrs++;
1008	}
1009	ib++;
1010    }
1011    /* for each variable attribute, get name and compare with expected name */
1012    for (iv = 0; iv < test.nvars; iv++) {
1013	ib = 0;
1014	for (ia = 0; ia < test.vars[iv].natts; ia++) {
1015	    if (ncattname(cdfid, iv, ia, att.name) == -1) {
1016		error("%s: ncattname failed on variable attribute", pname);
1017		ncclose(cdfid); return;
1018	    }
1019	    /* find number of next attribute */
1020	    while (ib < test.natts && test.atts[ib].var != iv)
1021	      ib++;
1022	    if (ib >= test.natts) {
1023		error("%s: problem  in test, expected attribute not found",
1024		      pname);
1025		ncclose(cdfid); return;
1026	    }
1027	    if (strcmp(att.name, test.atts[ib].name) != 0) {
1028		error("%s: variable '%s' name `%s' instead of expected `%s'",
1029		      pname, test.vars[iv].name, att.name, test.atts[ib].name);
1030		nerrs++;
1031	    }
1032	    ib++;
1033	}
1034    }
1035    /* try with bad variable handle, check error */
1036    if (ncattname(cdfid, test.nvars, 0, att.name) != -1) {
1037	error("%s: ncattname should fail with bad variable handle", pname);
1038	ncclose(cdfid); return;
1039    }
1040    /* try with bad attribute number, check error */
1041    if (ncattname(cdfid, NC_GLOBAL, -1, att.name) != -1) {
1042	error("%s: ncattname should fail with negative number", pname);
1043	ncclose(cdfid); return;
1044    }
1045    if (ncattname(cdfid, NC_GLOBAL, test.ngatts, att.name) != -1) {
1046	error("%s: ncattname should fail with too-high number", pname);
1047	ncclose(cdfid); return;
1048    }
1049    if (ncclose (cdfid) == -1) {
1050	error("%s: ncclose failed", pname);
1051	nerrs++;
1052	return;
1053    }
1054    /* try with bad netCDF handle, check error */
1055    if (ncattname(cdfid, NC_GLOBAL, 0, att.name) != -1) {
1056	error("%s: ncattname shoul fail with bad cdfid", pname);
1057	nerrs++;
1058    }
1059    free (tmp.name);
1060    free (att.name);
1061    if (nerrs > 0)
1062      (void) fprintf(stderr,"FAILED! ***\n");
1063    else
1064      (void) fprintf(stderr,"ok ***\n");
1065}
1066
1067
1068/*
1069 * Test ncattrename
1070 *    check that proper rename worked with ncattinq, ncattget
1071 *    try renaming to existing attribute name, check error
1072 *    try with nonexisting attribute, check error
1073 *    try with bad variable handle, check error
1074 *    try in data mode, check error
1075 *    try with bad netCDF handle, check error
1076 */
1077void
1078test_ncattrename(path)
1079     const char *path;		/* name of writable netcdf file to open */
1080{
1081    int nerrs = 0;
1082    static char pname[] = "test_ncattrename";
1083    int cdfid;			/* netcdf id */
1084    static char newname[] = "shorter";
1085    static char longername[] = "longer_name";
1086    struct cdfatt tmp;		/* attributes */
1087    static short short_vals[] = {3, 4, 5};
1088    static struct cdfatt atty =	/* attribute */
1089 	{___, "long_name", NC_SHORT, LEN_OF(short_vals), (void *) short_vals};
1090    static struct cdfatt attz =	/* attribute */
1091 	{___, "arggh", NC_SHORT, LEN_OF(short_vals), (void *) short_vals};
1092    int ynum;			/* attribute number */
1093
1094    (void) fprintf(stderr, "*** Testing %s ...\t", &pname[5]);
1095
1096    if ((cdfid = ncopen(path, NC_WRITE)) == -1) {
1097	error("%s: ncopen failed", pname);
1098	return;
1099    }
1100    /* opened OK, enter define mode */
1101    if (ncredef(cdfid) == -1) {
1102	error("%s: cdredef failed", pname);
1103	ncclose(cdfid); return;
1104    }
1105    /* in define mode, add two attributes */
1106    if (ncattput(cdfid, NC_GLOBAL, atty.name, atty.type, atty.len,
1107		  atty.val) == -1) {
1108	error("%s: ncattput failed", pname);
1109	ncclose(cdfid); return;
1110    }
1111    add_att(&test, NC_GLOBAL, &atty); /* keep in-memory netcdf in sync */
1112    ynum = test.natts-1;	/* number of attribute just put */
1113    if (ncattput(cdfid, NC_GLOBAL, attz.name, attz.type, attz.len,
1114		  attz.val) == -1) {
1115	error("%s: ncattput failed", pname);
1116	ncclose(cdfid); return;
1117    }
1118    add_att(&test, NC_GLOBAL, &attz); /* keep in-memory netcdf in sync */
1119
1120    /* rename first attribute to shorter name */
1121    if (ncattrename(cdfid, NC_GLOBAL, atty.name, newname) == -1) {
1122	error("%s: ncattrename failed", pname);
1123	ncclose(cdfid); return;
1124    }
1125    (void) strcpy(test.atts[ynum].name, newname); /* keep test consistent */
1126    /* check new name with ncattinq */
1127    if (ncattinq(cdfid, NC_GLOBAL, newname, &tmp.type, &tmp.len) == -1) {
1128	error("%s: ncattinq of renamed attribute failed", pname);
1129	ncclose(cdfid); return;
1130    }
1131    if (atty.type != tmp.type || atty.len != tmp.len) {
1132	error("%s: NC_GLOBAL ncattinq got unexpected type or len", pname);
1133	ncclose(cdfid); return;
1134    }
1135    /* allocate space to hold the attribute value to be retrieved */
1136    tmp.val = emalloc(atty.len * nctypelen(atty.type));
1137    if (ncattget(cdfid, NC_GLOBAL, newname, tmp.val) == -1) {
1138	error("%s: ncattget of variable attribute failed", pname);
1139	ncclose(cdfid); return;
1140    }
1141    if (val_cmp(tmp.type, tmp.len, tmp.val, atty.val) != 0) {
1142	error("%s: ncattget got bad values after rename attrs", pname);
1143	nerrs++;
1144    }
1145    if (ncattinq(cdfid, NC_GLOBAL, atty.name, &tmp.type, &tmp.len) != -1) {
1146	error("%s: ncattrename left attribute with old name", pname);
1147	ncclose(cdfid); return;
1148    }
1149    /* try to rename second attribute same as first, should fail */
1150    if (ncattrename(cdfid, NC_GLOBAL, attz.name, newname) != -1) {
1151	error("%s: ncattrename should have failed with used name", pname);
1152	ncclose(cdfid); return;
1153    }
1154    /* try to rename second attribute with a longer name */
1155    if (ncattrename(cdfid, NC_GLOBAL, attz.name, longername) == -1) {
1156	error("%s: ncattrename failed with longer name", pname);
1157	ncclose(cdfid); return;
1158    }
1159    /* try with bad variable handle, check for failure */
1160    if (ncattrename(cdfid, test.nvars, newname, atty.name) != -1) {
1161	error("%s: ncattrename should have failed on bad variable id", pname);
1162	ncclose(cdfid); return;
1163    }
1164    /* try with bad attribute name, check for failure */
1165    if (ncattrename(cdfid, NC_GLOBAL, "nonesuch", newname) != -1) {
1166	error("%s: ncattrename should have failed on bad attribute name",
1167	      pname);
1168	ncclose(cdfid); return;
1169    }
1170    if (ncendef (cdfid) == -1) {
1171	error("%s: ncendef failed", pname);
1172	ncclose(cdfid); return;
1173    }
1174    /* in data mode change name to even shorter and check value */
1175    if (ncattrename(cdfid, NC_GLOBAL, newname, "short") == -1) {
1176	error("%s: ncattrename to shorter name failed in data mode", pname);
1177	ncclose(cdfid); return;
1178    }
1179    if (ncattrename(cdfid, NC_GLOBAL, "short", "plugh") == -1) {
1180	error("%s: ncattrename to same length failed in data mode", pname);
1181	ncclose(cdfid); return;
1182    }
1183    if (ncattget(cdfid, NC_GLOBAL, "plugh", tmp.val) == -1) {
1184	error("%s: ncgetatt of renamed attribute failed in data mode", pname);
1185	ncclose(cdfid); return;
1186    }
1187    if (val_cmp(tmp.type, tmp.len, tmp.val, atty.val) != 0) {
1188	error("%s: ncattget got bad values after data mode rename", pname);
1189	nerrs++;
1190    }
1191    free (tmp.val);
1192    if (ncclose (cdfid) == -1) {
1193	error("%s: ncclose failed", pname);
1194	return;
1195    }
1196    /* should fail, since bad handle */
1197    if (ncattrename(cdfid, NC_GLOBAL, newname, atty.name) != -1) {
1198	error("%s: ncattrename should fail with bad cdfid", pname);
1199	ncclose(cdfid); return;
1200    }
1201    if (nerrs > 0)
1202      (void) fprintf(stderr,"FAILED! ***\n");
1203    else
1204      (void) fprintf(stderr,"ok ***\n");
1205}
1206
1207
1208/*
1209 * Test ncattdel
1210 *    check that proper delete worked	
1211 *    try with bad netCDF handle, check error
1212 *    try with bad variable handle, check error
1213 *    try with nonexisting attribute, check error
1214 *    try in data mode, check error
1215 */
1216void
1217test_ncattdel(path)
1218     const char *path;		/* name of writable netcdf file to open */
1219{
1220    int nerrs = 0;
1221    static char pname[] = "test_ncattdel";
1222    int cdfid;			/* netcdf id */
1223    static short short_vals[] = {-1, -2, -3 };
1224    static struct cdfatt yaa =	/* attribute */
1225 	{___, "yet_another_attribute", NC_SHORT, LEN_OF(short_vals),
1226	   (void *) short_vals};
1227    int id;			/* dimension id */
1228    int yav_id;			/* variable id */
1229    static struct cdfvar yav =	/* new variable for target netcdf */
1230      {"yet_another_variable", NC_DOUBLE, 2, ___, 0};
1231    struct cdfvar vtmp;		/* variable */
1232    struct cdfatt atmp;		/* attribute */
1233    int ndims;			/* number of dimensions */
1234    int nvars;			/* number of variables */
1235    int ngatts1, ngatts2;	/* number of global attributes */
1236    int natts;			/* number of variable attributes */
1237    int xdimid;			/* id of unlimited dimension */
1238
1239    (void) fprintf(stderr, "*** Testing %s ...\t", &pname[5]);
1240
1241    if ((cdfid = ncopen(path, NC_WRITE)) == -1) {
1242	error("%s: ncopen failed", pname);
1243	return;
1244    }
1245    /* opened OK, enter define mode */
1246    if (ncredef(cdfid) == -1) {
1247	error("%s: cdredef failed", pname);
1248	ncclose(cdfid); return;
1249    }
1250    /* in define mode, add global attribute, variable, variable attribute */
1251    if (ncattput(cdfid, NC_GLOBAL, yaa.name, yaa.type, yaa.len, yaa.val) == -1) {
1252	error("%s: ncattput failed", pname);
1253	ncclose(cdfid); return;
1254    }
1255    add_att(&test, NC_GLOBAL, &yaa); /* keep in-memory netcdf in sync */
1256    yav.dims = (int *) emalloc(sizeof(int) * yav.ndims);
1257    for (id = 0; id < yav.ndims; id++)
1258	yav.dims[id] = id;
1259    if ((yav_id=ncvardef(cdfid, yav.name, yav.type, yav.ndims, yav.dims))
1260	== -1) {
1261	error("%s: ncvardef failed", pname);
1262	ncclose(cdfid); return;
1263    }
1264    add_var(&test, &yav);	/* keep in-memory netcdf consistent */
1265    if (ncattput(cdfid, yav_id, yaa.name, yaa.type, yaa.len, yaa.val) == -1) {
1266	error("%s: ncattput failed", pname);
1267	ncclose(cdfid); return;
1268    }
1269    add_att(&test, yav_id, &yaa); /* keep in-memory netcdf consistent */
1270
1271    /* get number of global attributes, number of attributes for variable */
1272    if (ncinquire(cdfid, &ndims, &nvars, &ngatts1, &xdimid) == -1) {
1273	error("%s: ncinquire in data mode failed", pname);
1274	ncclose(cdfid); return;
1275    }
1276    vtmp.dims = (int *) emalloc(sizeof(int) * MAX_VAR_DIMS);
1277    vtmp.name = (char *) emalloc(MAX_NC_NAME);
1278    if (ncvarinq(cdfid, yav_id, vtmp.name, &vtmp.type, &vtmp.ndims, vtmp.dims,
1279		  &natts) == -1) {
1280	error("%s: ncvarinq failed", pname);
1281	ncclose(cdfid); return;
1282    }    
1283
1284    /* delete global attribute and check that it's gone */
1285    if (ncattdel(cdfid, NC_GLOBAL, yaa.name) == -1) {
1286	error("%s: ncattdel failed", pname);
1287	ncclose(cdfid); return;
1288    }
1289    del_att(&test, NC_GLOBAL, &yaa); /* keep in-memory netcdf consistent */
1290    if (ncinquire(cdfid, &ndims, &nvars, &ngatts2, &xdimid) == -1) {
1291	error("%s: ncinquire failed", pname);
1292	ncclose(cdfid); return;
1293    }
1294    if (ngatts2 != ngatts1 - 1) {
1295	error("%s: NC_GLOBAL attribute deleted, but ngatts did not decrement",
1296	      pname);
1297	ncclose(cdfid); return;
1298    }
1299    if (ncattinq(cdfid, NC_GLOBAL, yaa.name, &atmp.type, &atmp.len) != -1) {
1300	error("%s: ncattinq on deleted NC_GLOBAL attribute should fail", pname);
1301	ncclose(cdfid); return;
1302    }
1303
1304    /* delete variable attribute and check that it's gone */
1305    if (ncattdel(cdfid, yav_id, yaa.name) == -1) {
1306	error("%s: ncattdel failed", pname);
1307	ncclose(cdfid); return;
1308    }
1309    del_att(&test, yav_id, &yaa); /* keep in-memory netcdf consistent */
1310    if (ncvarinq(cdfid, yav_id, vtmp.name, &vtmp.type, &vtmp.ndims,
1311		  vtmp.dims, &vtmp.natts) == -1) {
1312	error("%s: ncvarinq failed", pname);
1313	ncclose(cdfid); return;
1314    }
1315    if (vtmp.natts != natts - 1) {
1316	error("%s: NC_GLOBAL attribute deleted, but ngatts did not decrement",
1317	      pname);
1318	ncclose(cdfid); return;
1319    }
1320    if (ncattinq(cdfid, yav_id, yaa.name, &atmp.type, &atmp.len) != -1) {
1321	error("%s: ncattinq on deleted variable attribute should fail",
1322	      pname);
1323	ncclose(cdfid); return;
1324    }
1325    /* re-add global attribute, variable, variable attribute */
1326    if (ncattput(cdfid, NC_GLOBAL, yaa.name, yaa.type, yaa.len, yaa.val) == -1) {
1327	error("%s: ncattput failed", pname);
1328	ncclose(cdfid); return;
1329    }
1330    add_att(&test, NC_GLOBAL, &yaa); /* keep in-memory netcdf in sync */
1331    if (ncattput(cdfid, yav_id, yaa.name, yaa.type, yaa.len, yaa.val) == -1) {
1332	error("%s: ncattput failed", pname);
1333	ncclose(cdfid); return;
1334    }
1335    add_att(&test, yav_id, &yaa); /* keep in-memory netcdf consistent */
1336    /* try on nonexistent attribute, should fail */
1337    if (ncattdel(cdfid, yav_id, "nonesuch") != -1) {
1338	error("%s: ncattdel should fail on bogus attribute", pname);
1339	ncclose(cdfid); return;
1340    }
1341    /* try on bad variable id, should fail */
1342    if (ncattdel(cdfid, test.nvars, yaa.name) != -1) {
1343	error("%s: ncattdel should fail on bad variable id", pname);
1344	ncclose(cdfid); return;
1345    }
1346    if (ncendef (cdfid) == -1) {
1347	error("%s: ncendef failed", pname);
1348	ncclose(cdfid); return;
1349    }
1350    /* in data mode, should fail */
1351    if (ncattdel(cdfid, NC_GLOBAL, yaa.name) != -1) {
1352	error("%s: ncattdel in data mode should fail", pname);
1353	ncclose(cdfid); return;
1354    }
1355    if (ncclose (cdfid) == -1) {
1356	error("%s: ncclose failed", pname);
1357	return;
1358    }
1359    /* try on bad netcdf handle, should fail */
1360    if (ncattdel(cdfid, yav_id, yaa.name) != -1) {
1361	error("%s: ncattdel should fail on bad netcdf id", pname);
1362	nerrs++;
1363    }
1364    free(vtmp.dims);
1365    free(vtmp.name);
1366    free(yav.dims);
1367    if (nerrs > 0)
1368      (void) fprintf(stderr,"FAILED! ***\n");
1369    else
1370      (void) fprintf(stderr,"ok ***\n");
1371}