1 /*********************************************************************
2  *   Copyright 2018, UCAR/Unidata
3  *   See netcdf/COPYRIGHT file for copying and redistribution conditions.
4  *   $Header: /upc/share/CVS/netcdf-3/nctest/cdftests.c,v 1.23 2009/02/14 14:11:28 ed Exp $
5  *********************************************************************/
6 
7 #include <config.h>
8 #include <stdio.h>
9 #include <string.h>
10 #include <stdlib.h>		/* for free() */
11 #include "netcdf.h"
12 #include "emalloc.h"
13 #include "testcdf.h"		/* defines in-memory test netcdf structure */
14 #include "add.h"		/* functions to update in-memory netcdf */
15 #include "error.h"
16 #include "tests.h"
17 
18 #define LEN_OF(array) ((sizeof array) / (sizeof array[0]))
19 
20 
21 /*
22  * Test nccreate
23  *    create a netcdf with no data, close it, test that it can be opened
24  *    try again with NC_CLOBBER mode, check that no errors occurred
25  *    try again with NC_NOCLOBBER mode, check error return
26  * On exit, netcdf files are closed.
27  * Uses: nccreate, ncendef, ncclose, ncopen.
28  */
29 int
test_nccreate(path)30 test_nccreate(path)
31      const char *path;		/* name of netCDF file to create */
32 {
33     int nerrs = 0;
34     static char pname[] = "test_nccreate";
35     int ncid;
36 
37     (void) fprintf(stderr, "*** Testing %s ...\t", &pname[5]);
38 
39     if ((ncid = nccreate(path, NC_CLOBBER)) == -1) {
40 	error("%s: nccreate failed to NC_CLOBBER", pname);
41 	return 1;
42     }
43     /* in define mode already, so ncredef should fail  */
44     if (ncredef(ncid) != -1) {
45 	error("%s: ncredef should fail after nccreate", pname);
46 	nerrs++;
47     }
48     /* created OK */
49     if (ncendef (ncid) == -1) {
50 	error("%s: ncendef failed", pname);
51 	nerrs++;
52     }
53     if (ncclose (ncid) == -1) {
54 	error("%s: ncclose failed", pname);
55 	nerrs++;
56     }
57     if ((ncid = ncopen(path, NC_NOWRITE)) == -1) {
58 	error("%s: ncopen of newly created netcdf failed", pname);
59 	return ++nerrs;
60     }
61     /* opened OK */
62     if (ncclose (ncid) == -1) {
63 	error("%s: second ncclose failed", pname);
64 	nerrs++;
65     }
66     /* this call should fail, since we're using NC_NOCLOBBER mode */
67     if (nccreate(path, NC_NOCLOBBER) != -1) {
68 	error("%s: nccreate failed to honor NC_NOCLOBBER mode", pname);
69 	nerrs++;
70     }
71 
72     /* Initialize in-memory netcdf to empty */
73     add_reset(&test);
74     if (nerrs > 0)
75       (void) fprintf(stderr,"FAILED! ***\n");
76     else
77       (void) fprintf(stderr,"ok ***\n");
78 
79     return nerrs;
80 }
81 
82 
83 /*
84  * Test ncopen
85  *    try to open a non-existent netCDF, check error return
86  *    open a file that is not a netCDF file, check error return
87  *    open a netCDF with NC_WRITE mode, write something, close it
88  *    open a netCDF with NC_NOWRITE mode, write something and check error
89  *    try to open a netcdf twice, check whether returned netcdf ids different
90  * On exit, netcdf files are closed.
91  * Uses: ncopen, ncredef, ncattput, ncendef, ncclose.
92  */
93 #define DATA_LEN 32
94 #define TEMP_FILE_NAME "temp.tmp"
95 int
test_ncopen(path)96 test_ncopen(path)
97      const char *path;		/* name of writable netcdf file to open */
98 {
99     int nerrs = 0;
100     static char pname[] = "test_ncopen";
101     int ncid0, ncid1;
102     static char title_val[] = "test netcdf";
103     static char xpath[] = "tooth-fairy.nc"; /* must not exist */
104     static struct cdfatt title = /* attribute */
105       {NC_GLOBAL, "title", NC_CHAR, LEN_OF (title_val), (void *) title_val};
106     FILE *temp;
107     char dummy_data[DATA_LEN];
108     int i;
109 
110     /* Initialize to keep valgrind happy. */
111     for (i = 0; i < DATA_LEN; i++)
112        dummy_data[i] = 0;
113 
114     (void) fprintf(stderr, "*** Testing %s ...\t\t", &pname[5]);
115 
116     /* Open a nonexistent file */
117     if(ncopen(xpath, NC_NOWRITE) != -1) {
118 	error("%s: ncopen should fail opening nonexistent file",
119 	      pname);
120 	return ++nerrs;
121     }
122     if (ncerr != NC_SYSERR) {
123 	error("%s: ncopen of nonexistent file should set ncerr to %d",
124 	      pname, NC_SYSERR);
125     }
126     /*
127      * Open a non-netCDF file.  Don't use "Makefile.in" because that
128      * name is munged to something else by PC/NFS and, consequently,
129      * won't exist in a cross-mounted directory. Also don't use a
130      * source file, because that will break building in another
131      * directory, and consequently, make dist. An object file is not
132      * safe, because sometimes it's a .o and sometimes a .obj. So just
133      * create a file!
134      */
135     if (!(temp = fopen(TEMP_FILE_NAME, "w+")))
136     {
137        error("could not create temp file");
138        return ++nerrs;
139     }
140     if (fwrite(dummy_data, 1, DATA_LEN, temp) != DATA_LEN)
141     {
142        error("could not write to temp file");
143        return ++nerrs;
144     }
145     if (fclose(temp))
146     {
147        error("could not close temp file");
148        return ++nerrs;
149     }
150 
151     if(ncopen(TEMP_FILE_NAME, NC_NOWRITE) != -1) {
152 	error("%s: ncopen should fail opening non-netCDF file",
153 	      pname);
154 	return ++nerrs;
155     }
156     if(ncerr != NC_ENOTNC) {
157 	error("%s: ncopen of non-netCDF file should set ncerr to %d",
158 	      pname, NC_ENOTNC);
159 	return ++nerrs;
160     }
161 
162 
163     if ((ncid0 = ncopen(path, NC_WRITE)) == -1) {
164 	error("%s: ncopen failed with NC_WRITE mode", pname);
165 	return ++nerrs;
166     }
167 
168     /* opened */
169     if (ncredef(ncid0) == -1) {
170 	error("%s: cdredef failed", pname);
171 	ncclose(ncid0); return ++nerrs;
172     }
173     /* in define mode */
174     if (ncattput(ncid0, NC_GLOBAL, "title", NC_CHAR, title.len, title.val)
175 	== -1) {
176 	error("%s: ncattput failed", pname);
177 	ncclose(ncid0); return ++nerrs;
178     }
179     add_att(&test, NC_GLOBAL, &title); /* keep in-memory netcdf updated */
180     if (ncendef (ncid0) == -1) {
181 	error("%s: ncendef failed after ncattput", pname);
182 	ncclose(ncid0); return ++nerrs;
183     }
184     if (ncclose (ncid0) == -1) {
185 	error("%s: ncclose failed in NC_WRITE mode", pname);
186 	return ++nerrs;
187     }
188 
189     if ((ncid0 = ncopen(path, NC_WRITE)) == -1) {
190 	error("%s: ncopen failed with NC_NOWRITE mode", pname);
191 	return ++nerrs;
192     }
193     if ((ncid1 = ncopen(path, NC_NOWRITE)) == -1) {
194 #ifndef vms
195 	error("%s: second ncopen failed", pname);
196 	nerrs++;
197 #else
198 	fprintf(stderr,"Doesn't support shared access on vms\n") ;
199 #endif
200     }
201     else
202     {
203        /* this should fail, since in NC_NOWRITE mode */
204        if (ncredef(ncid1) != -1) {
205 	  error("%s: cdredef should fail after NC_NOWRITE open", pname);
206 	  ncclose(ncid1); return ++nerrs;
207        }
208        /* second open OK */
209        if (ncid0 == ncid1) {
210 	  error("%s: ncopen should return new ncid on second open",
211 		pname);
212 	  nerrs++;
213        }
214        if (ncclose (ncid1) == -1) {
215 	  error("%s: ncclose failed to close after second open", pname);
216 	  nerrs++;
217        }
218     }
219     if (ncclose (ncid0) == -1) {
220 	error("%s: ncclose failed in NC_NOWRITE mode", pname);
221 	nerrs++;
222     }
223     if (nerrs > 0)
224       (void) fprintf(stderr,"FAILED! ***\n");
225     else
226       (void) fprintf(stderr,"ok ***\n");
227 
228     return nerrs;
229 }
230 
231 
232 /*
233  * Test ncredef
234  *    open a netCDF, enter define mode, add dimension, variable, attribute
235  *    try ncredef from within define mode, check error
236  *    leave define mode and close, releasing netcdf handle
237  *    try ncredef with old handle, check error
238  * On exit netcdf files are closed.
239  * Uses: ncopen, ncredef, ncdimdef, ncvardef, ncattput, ncclose
240  */
241 int
test_ncredef(path)242 test_ncredef(path)
243      const char *path;		/* name of writable netcdf file to open */
244 {
245     int nerrs = 0;
246     static char pname[] = "test_ncredef";
247     int ncid;			/* netcdf id */
248     int ii_dim;			/* dimension id */
249     static struct cdfdim ii =	/* dimension */
250       {"ii", 4};
251     int aa_id;			/* variable id */
252     static struct cdfvar aa =	/* variable */
253       {"aa", NC_LONG, 1, ___, 0};
254     static char units_val[] = "furlongs";
255     static struct cdfatt aa_units = /* attribute */
256       {___, "units", NC_CHAR, LEN_OF(units_val), (void *)units_val};
257 
258     (void) fprintf(stderr, "*** Testing %s ...\t\t", &pname[5]);
259 
260     if ((ncid = ncopen(path, NC_WRITE)) == -1) {
261 	error("%s: ncopen failed", pname);
262 	return ++nerrs;
263     }
264     /* opened OK, enter define mode */
265     if (ncredef(ncid) == -1) {
266 	error("%s: cdredef failed", pname);
267 	ncclose(ncid); return ++nerrs;
268     }
269     /* in define mode OK, add a dimension */
270     if ((ii_dim = ncdimdef(ncid, ii.name, ii.size)) == -1) {
271 	error("%s: ncdimdef failed", pname);
272 	ncclose(ncid); return ++nerrs;
273     }
274     add_dim(&test, &ii);	/* keep in-memory netcdf in sync */
275 
276     /* dimension added OK, add a variable */
277     aa.dims = (int *)emalloc(sizeof(int) * aa.ndims);
278     aa.dims[0] = ii_dim;
279     if ((aa_id = ncvardef(ncid, aa.name, aa.type,
280 			   aa.ndims, aa.dims)) == -1) {
281 	error("%s: ncvardef failed", pname);
282 	ncclose(ncid); return ++nerrs;
283     }
284     add_var(&test, &aa);	/* keep in-memory netcdf in sync */
285 
286     /* variable added OK, add a variable attribute */
287     aa_units.var = aa_id;
288     if (ncattput(ncid, aa_units.var, aa_units.name,
289 		  aa_units.type, aa_units.len, (void *) aa_units.val) == -1) {
290 	error("%s: ncattput failed", pname);
291 	ncclose(ncid); return ++nerrs;
292     }
293     add_att(&test, aa_id, &aa_units); /* keep in-memory netcdf in sync */
294 
295     if (ncredef(ncid) != -1) {
296 	error("%s: cdredef in define mode should have failed", pname);
297 	ncclose(ncid); return ++nerrs;
298     }
299     if (ncendef (ncid) == -1) {
300 	error("%s: ncendef failed", pname);
301 	ncclose(ncid); return ++nerrs;
302     }
303     if (ncclose (ncid) == -1) {
304 	error("%s: ncclose failed", pname);
305 	return ++nerrs;
306     }
307     if (ncredef(ncid) != -1) {
308 	error("%s: ncredef failed to report bad netcdf handle", pname);
309 	nerrs++;
310     }
311     free (aa.dims);
312     if (nerrs > 0)
313       (void) fprintf(stderr,"FAILED! ***\n");
314     else
315       (void) fprintf(stderr,"ok ***\n");
316 
317     return nerrs;
318 }
319 
320 
321 /*
322  * Test ncendef
323  *    check return from proper cdfendif after define mode
324  *    try ncendef when in data mode, check error
325  *    try ncendef with bad handle, check error
326  *  On exit netcdf files are closed.
327  * Uses: ncopen, ncredef, ncdimdef, ncvardef, ncattput, ncendef, ncclose
328  */
329 int
test_ncendef(path)330 test_ncendef(path)
331      const char *path;		/* name of writable netcdf file to open */
332 {
333     int nerrs = 0;
334     static char pname[] = "test_ncendef";
335     int ncid;			/* netcdf id */
336     int jj_dim, kk_dim;		/* dimension ids */
337     int bb_id;			/* variable id */
338     static struct cdfdim kk =	/* dimension */
339       {"kk", 3};
340     static struct cdfdim jj =	/* dimension */
341       {"jj", 3};
342     static struct cdfvar bb =	/* variable */
343       {"bb", NC_LONG, 2, ___, 0};
344     static float bb_rangev[2] = {0., 100.}; /* attribute vector */
345     static struct cdfatt bb_range = /* attribute */
346       {___, "valid_range", NC_FLOAT, LEN_OF(bb_rangev), (void *)bb_rangev};
347 
348     (void) fprintf(stderr, "*** Testing %s ...\t\t", &pname[5]);
349 
350     if ((ncid = ncopen(path, NC_WRITE)) == -1) {
351 	error("%s: ncopen failed", pname);
352 	return ++nerrs;
353     }
354     /* opened */
355     if (ncredef(ncid) == -1) {
356 	error("%s: ncredef failed", pname);
357 	ncclose(ncid); return ++nerrs;
358     }
359     /* in define mode, add dimensions */
360     if ((jj_dim = ncdimdef(ncid, jj.name, jj.size)) == -1 ||
361 	(kk_dim = ncdimdef(ncid, kk.name, kk.size)) == -1) {
362 	error("%s: ncdimdef failed", pname);
363 	ncclose(ncid); return ++nerrs;
364     }
365     add_dim(&test, &jj);	/* keep in-memory netcdf in sync */
366     add_dim(&test, &kk);	/* keep in-memory netcdf in sync */
367 
368     /* dimensions added OK, add a variable */
369     bb.dims = (int *) emalloc(sizeof(int) * bb.ndims);
370     bb.dims[0] = kk_dim;
371     bb.dims[1] = jj_dim;
372     if ((bb_id = ncvardef(ncid, bb.name, bb.type,
373 			   bb.ndims, bb.dims)) == -1) {
374 	error("%s: ncvardef failed", pname);
375 	ncclose(ncid); return ++nerrs;
376     }
377     add_var(&test, &bb);	/* keep in-memory netcdf in sync */
378 
379     /* variable added OK, add a variable attribute */
380     if (ncattput(ncid, bb_id, bb_range.name, bb_range.type, bb_range.len,
381 		  (void *) bb_range.val) == -1) {
382 	error("%s: ncattput failed", pname);
383 	ncclose(ncid); return ++nerrs;
384     }
385     add_att(&test, bb_id, &bb_range); /* keep in-memory netcdf in sync */
386 
387     if (ncendef (ncid) == -1) {
388 	error("%s: ncendef failed", pname);
389 	ncclose(ncid); return ++nerrs;
390     }
391     /* in data mode */
392     if (ncendef (ncid) != -1) { /* should fail in data mode */
393 	error("%s: ncendef in data mode should have failed", pname);
394 	ncclose(ncid); return ++nerrs;
395     }
396     if (ncclose (ncid) == -1) {
397 	error("%s: ncclose failed", pname);
398 	return ++nerrs;
399     }
400     /* should fail on a bad handle */
401     if (ncendef (ncid) != -1) {
402 	error("ncendef failed to report bad netcdf handle");
403 	nerrs++;
404     }
405     if (nerrs > 0)
406       (void) fprintf(stderr,"FAILED! ***\n");
407     else
408       (void) fprintf(stderr,"ok ***\n");
409 
410     free(bb.dims);
411 
412     return nerrs;
413 }
414 
415 
416 /*
417  * Test ncclose
418  *    try on open netCDF
419  *    try in define mode and data mode
420  *    try with bad handle, check error
421  *  On exit netcdf files are closed.
422  */
423 int
test_ncclose(path)424 test_ncclose(path)
425      const char *path;		/* name of writable netcdf file to open */
426 {
427     int nerrs = 0;
428     static char pname[] = "test_ncclose";
429     int ncid;			/* netcdf id */
430 
431     (void) fprintf(stderr, "*** Testing %s ...\t\t", &pname[5]);
432 
433     if ((ncid = ncopen(path, NC_WRITE)) == -1) {
434 	error("%s: ncopen failed", pname);
435 	return ++nerrs;
436     }
437     /* opened */
438     if (ncredef(ncid) == -1) {
439 	error("%s: ncredef failed", pname);
440 	ncclose(ncid); return ++nerrs;
441     }
442     /* in define mode */
443     if (ncclose (ncid) == -1) {
444 	error("%s: ncclose in define mode failed", pname);
445 	nerrs++;
446     }
447 
448     if ((ncid = ncopen(path, NC_WRITE)) == -1) {
449 	error("%s: ncopen failed", pname);
450 	return ++nerrs;
451     }
452     /* in data mode */
453     if (ncclose (ncid) == -1) {
454 	error("%s: ncclose failed", pname);
455 	nerrs++;
456     }
457     if (ncclose (ncid) != -1) { /* should fail, since ncid is a bad handle */
458 	error("%s: ncclose failed to report bad netcdf handle", pname);
459 	nerrs++;
460     }
461     if (nerrs > 0)
462       (void) fprintf(stderr,"FAILED! ***\n");
463     else
464       (void) fprintf(stderr,"ok ***\n");
465 
466     return nerrs;
467 }
468 
469 
470 /*
471  * Test ncinquire
472  *    try in data mode, check returned values
473  *    try in define mode, after adding an unlimited dimension, variable
474  *    try with bad handle, check error
475  *  On exit netcdf files are closed.
476  */
477 int
test_ncinquire(path)478 test_ncinquire(path)
479      const char *path;		/* name of writable netcdf file to open */
480 {
481     int nerrs = 0;
482     static char pname[] = "test_ncinquire";
483     int ncid;			/* netcdf id */
484     int ndims;			/* number of dimensions */
485     int nvars;			/* number of variables */
486     int ngatts;			/* number of global attributes */
487     int xdimid;			/* id of unlimited dimension */
488     int rec_dim;		/* dimension id */
489     static struct cdfdim rec =	/* dimension */
490       {"rec", NC_UNLIMITED};
491     static struct cdfdim dims[] = { /* dimensions */
492 	{"i1", 5},{"i2", 3},{"i3", 7}
493     };
494     int id, nd = LEN_OF(dims);	/* number of dimensions */
495     int dimids[LEN_OF(dims)];
496     int cc_id;			/* variable id */
497     static struct cdfvar cc[] =	{ /* record variables of various sizes */
498 	{"cc", NC_LONG, 1, ___, 0},
499 	{"cd", NC_SHORT, 2, ___, 0},
500 	{"ce", NC_FLOAT, 3, ___, 0}
501     };
502     int iv;
503     int nv = LEN_OF(cc);	/* number of record variables */
504     static char units_val[] = "moles";
505     static struct cdfatt cc_units = /* attribute */
506       {___, "units", NC_CHAR, LEN_OF(units_val), (void *)units_val};
507 
508     (void) fprintf(stderr, "*** Testing %s ...\t", &pname[5]);
509 
510     if ((ncid = ncopen(path, NC_WRITE)) == -1) {
511 	error("%s: ncopen failed", pname);
512 	return ++nerrs;
513     }
514     /* opened, in data mode */
515     if (ncinquire(ncid, &ndims, &nvars, &ngatts, &xdimid) == -1) {
516 	error("%s: ncinquire in data mode failed", pname);
517 	ncclose(ncid); return ++nerrs;
518     }
519     /* compare returned with expected values */
520     if (ndims != test.ndims) {
521 	error("%s: ndims returned as %d, expected %d",
522 	    pname, ndims, test.ndims);
523 	nerrs++;
524     }
525     if (nvars != test.nvars) {
526 	error("%s: nvars returned as %d, expected %d",
527 	    pname, nvars, test.nvars);
528 	nerrs++;
529     }
530     if (ngatts != test.ngatts) {
531 	error("%s: ngatts returned as %d, expected %d",
532 	    pname, ngatts, test.ngatts);
533 	nerrs++;
534     }
535     if (xdimid != test.xdimid) {
536 	error("%s: xdimid returned as %d, expected %d",
537 	    pname, xdimid, test.xdimid);
538 	nerrs++;
539     }
540 
541     if (ncredef(ncid) == -1) {
542 	error("%s: ncredef failed", pname);
543 	ncclose(ncid); return ++nerrs;
544     }
545     /* add dimensions */
546     for (id = 0; id < nd; id++) {
547 	if ((dimids[id] = ncdimdef(ncid, dims[id].name, dims[id].size))
548 	    == -1) {
549 	    error("%s: ncdimdef failed on normal dimension", pname);
550 	    ncclose(ncid); return ++nerrs;
551 	}
552 	add_dim(&test, &dims[id]);
553     }
554 
555     /* add an unlimited dimension */
556     if ((rec_dim = ncdimdef(ncid, rec.name, rec.size)) == -1) {
557 	error("%s: ncdimdef failed on NC_UNLIMITED dimension", pname);
558 	ncclose(ncid); return ++nerrs;
559     }
560     add_dim(&test, &rec);
561 
562     /* add some record variables */
563     for (iv = 0; iv < nv; iv++) {
564 	cc[iv].dims = (int *) emalloc(sizeof(int) * cc[iv].ndims);
565 	cc[iv].dims[0] = rec_dim; /* first dimension unlimited */
566 	for (id = 1; id < cc[iv].ndims; id++)
567 	  cc[iv].dims[id] = dimids[id];
568 	if ((cc_id = ncvardef(ncid, cc[iv].name, cc[iv].type,
569 			       cc[iv].ndims, cc[iv].dims)) == -1) {
570 	    error("%s: ncvardef failed", pname);
571 	    ncclose(ncid); return ++nerrs;
572 	}
573 	add_var(&test, &cc[iv]);
574 
575 	/* add a variable attribute */
576 	if (ncattput(ncid, cc_id, cc_units.name, cc_units.type,
577 		      cc_units.len, (void *) cc_units.val) == -1) {
578 	    error("%s: ncattput failed", pname);
579 	    ncclose(ncid); return ++nerrs;
580 	}
581 	add_att(&test, cc_id, &cc_units);
582 	free(cc[iv].dims);
583     }
584     /* try calling from define mode, compare returned values to expected */
585     if (ncinquire(ncid, &ndims, &nvars, &ngatts, &xdimid) == -1) {
586 	error("%s: ncinquire in define mode failed", pname);
587 	ncclose(ncid); return ++nerrs;
588     }
589     /* compare returned with expected values */
590     if (ndims != test.ndims) {
591 	error("%s: ndims returned as %d, expected %d",
592 	    pname, ndims, test.ndims);
593 	nerrs++;
594     }
595     if (nvars != test.nvars) {
596 	error("%s: nvars returned as %d, expected %d",
597 	    pname, nvars, test.nvars);
598 	nerrs++;
599     }
600     if (ngatts != test.ngatts) {
601 	error("%s: ngatts returned as %d, expected %d",
602 	    pname, ngatts, test.ngatts);
603 	nerrs++;
604     }
605     if (xdimid != test.xdimid) {
606 	error("%s: xdimid returned as %d, expected %d",
607 	    pname, xdimid, test.xdimid);
608 	nerrs++;
609     }
610 
611     if (ncendef (ncid) == -1) {
612 	error("%s: ncendef failed", pname);
613 	ncclose(ncid); return ++nerrs;
614     }
615 
616     if (ncclose (ncid) == -1) {
617 	error("%s: ncclose failed", pname);
618 	return ++nerrs;
619     }
620     /* should fail, since bad handle */
621     if (ncinquire (ncid, &ndims, &nvars, &ngatts, &xdimid) != -1) {
622 	error("%s: ncinquire failed to report bad netcdf handle", pname);
623 	nerrs++;
624     }
625     if (nerrs > 0)
626       (void) fprintf(stderr,"FAILED! ***\n");
627     else
628       (void) fprintf(stderr,"ok ***\n");
629 
630     return nerrs;
631 }
632 
633 
634 /*
635  * Test ncsync
636  *    try in define mode, check error
637  *    try writing with one handle, reading with another on same netCDF
638  *    try with bad handle, check error
639  *  On exit netcdf files are closed.
640  */
641 int
test_ncsync(path)642 test_ncsync(path)
643      const char *path;		/* name of writable netcdf file to open */
644 {
645     int nerrs = 0;
646     static char pname[] = "test_ncsync";
647     int ncid0, ncid1;		/* netcdf ids */
648     int ll_dim;			/* dimension id */
649     static struct cdfdim ll =	/* dimension */
650       {"ll", 3};
651     int dd_id;			/* variable id */
652     static struct cdfvar dd =	/* variable */
653       {"dd", NC_SHORT, 1, ___, 0};
654     static short dd_fill_valv[] = {-999};
655     static struct cdfatt dd_fill_val = /* attribute */
656       {___, "fill_value", NC_SHORT, LEN_OF(dd_fill_valv), (void *) dd_fill_valv};
657 
658     (void) fprintf(stderr, "*** Testing %s ...\t\t", &pname[5]);
659 
660     if ((ncid0 = ncopen(path, NC_WRITE)) == -1) {
661 	error("%s: ncopen in NC_WRITE mode failed", pname);
662 	return ++nerrs;
663     }
664 
665     /* opened */
666     if (ncredef(ncid0) == -1) {
667 	error("%s: ncredef failed", pname);
668 	ncclose(ncid0); return ++nerrs;
669     }
670     /* in define mode, add a dimension, variable, and attribute */
671     if ((ll_dim = ncdimdef(ncid0, ll.name, ll.size)) == -1) {
672 	error("%s: ncdimdef failed", pname);
673 	ncclose(ncid0);
674 	return ++nerrs;
675     }
676     add_dim(&test, &ll);
677 
678     dd.dims = (int *) emalloc(sizeof(int) * dd.ndims);
679     dd.dims[0] = ll_dim;
680     if ((dd_id=ncvardef(ncid0, dd.name, dd.type, dd.ndims, dd.dims)) == -1) {
681 	error("%s: ncvardef failed", pname);
682 	ncclose(ncid0);
683 	return ++nerrs;
684     }
685     add_var(&test, &dd);
686 
687     if (ncattput(ncid0, dd_id, dd_fill_val.name, dd_fill_val.type,
688 		  dd_fill_val.len, (void *) dd_fill_val.val) == -1) {
689 	error("%s: ncattput failed", pname);
690 	ncclose(ncid0);
691 	return ++nerrs;
692     }
693     add_att(&test, dd_id, &dd_fill_val);
694 
695     if (ncsync (ncid0) != -1) {
696 	error("%s: ncsync in define mode should fail", pname);
697 	nerrs++;
698     }
699 
700     if (ncendef (ncid0) == -1) {
701 	error("%s: ncendef failed", pname);
702 	ncclose(ncid0); return ++nerrs;
703     }
704     /* in data mode */
705     if (ncsync (ncid0) == -1) {
706 	error("%s: ncsync in data mode failed", pname);
707 	nerrs++;
708     }
709 
710     /* put some data into a variable */
711     {
712 	static long dd_start[] = {0};
713 	static long dd_edges[] = {2};
714 	static short dd_vals[] = {1, 2};
715 	short got_vals[2];
716 
717 	if (ncvarput(ncid0,dd_id,dd_start,dd_edges,(void *)dd_vals) == -1) {
718 	    error("%s: ncvarput failed", pname);
719 	    ncclose(ncid0);
720 	    return ++nerrs;
721 	}
722 	add_data(&test,dd_id,dd_start,dd_edges); /* keep test in sync */
723 	if (ncsync (ncid0) == -1) {
724 	    error("%s: ncsync after putting data failed", pname);
725 	    nerrs++;
726 	}
727 	if ((ncid1 = ncopen(path, NC_NOWRITE)) == -1) {
728 #ifndef vms
729 	    error("%s: second ncopen failed", pname);
730 	    nerrs++;
731 #else
732 	    fprintf(stderr,"Doesn't support shared access on vms\n") ;
733 #endif
734 	} else {
735 		if (ncid0 == ncid1) {
736 		    error("%s: second ncopen should return distinct handle",
737 			  pname);
738 		    nerrs++;
739 		}	/* read data just put after a sync, should succeed */
740 		if (ncvarget(ncid1,dd_id,dd_start,dd_edges,(void *)got_vals)
741 		    == -1) {
742 		    error("%s: ncvarget failed", pname);
743 		    nerrs++;
744 		}
745 		if (dd_vals[0] != got_vals[0] || dd_vals[1] != got_vals[1]) {
746 		    error("%s: ncvarget succeeded but data values wrong",
747 			  pname);
748 		}
749    		if (ncclose (ncid1) == -1) {
750 		    error("%s: ncclose failed", pname);
751 		    nerrs++;
752 		}
753 	}
754     }
755     if (ncclose (ncid0) == -1) {
756 	error("%s: ncclose failed", pname);
757 	nerrs++;
758     }
759     if (ncsync (ncid0) != -1) { /* should fail, since ncid0 is bad handle */
760 	error("%s: ncsync failed to report bad netcdf handle", pname);
761 	nerrs++;
762     }
763     if (nerrs > 0)
764       (void) fprintf(stderr,"FAILED! ***\n");
765     else
766       (void) fprintf(stderr,"ok ***\n");
767 
768     /* Free resources. */
769     free(dd.dims);
770 
771     return nerrs;
772 }
773 
774 
775 /*
776  * Test ncabort
777  *    try in define mode, check that file was deleted
778  *    try after writing variable
779  *    try with bad handle, check error
780  *  On exit netcdf files are closed.
781  */
782 int
test_ncabort(path)783 test_ncabort(path)
784      const char *path;		/* name of writable netcdf file to open */
785 {
786     int nerrs = 0;
787     static char pname[] = "test_ncabort";
788     static char fpath[] = "ufo.nc";
789     static short attv[] = {3};
790     static struct cdfatt att = /* attribute */
791       {___, "temp", NC_SHORT, LEN_OF(attv), (void *) attv};
792     int ncid;			/* netcdf id */
793 
794     (void) fprintf(stderr, "*** Testing %s ...\t\t", &pname[5]);
795 
796     if ((ncid = ncopen(path, NC_WRITE)) == -1) {
797 	error("%s: ncopen failed", pname);
798 	return ++nerrs;
799     }
800     /* opened */
801     if (ncredef(ncid) == -1) {
802 	error("%s: ncredef failed", pname);
803 	ncclose(ncid); return ++nerrs;
804     }
805     /* in define mode, add a new global attribute */
806     if (ncattput(ncid, NC_GLOBAL, att.name, att.type, att.len, att.val) == -1) {
807 	error("%s: ncattput failed", pname);
808 	ncclose(ncid); return ++nerrs;
809     }
810 
811     /* abort in define mode, should restore to state before define mode */
812     if (ncabort(ncid) == -1) {
813 	error("%s: ncabort in define mode failed", pname);
814 	ncclose(ncid); return ++nerrs;
815     }
816     if ((ncid = ncopen(path, NC_WRITE)) == -1) {
817 	error("%s: ncopen after ncabort failed", pname);
818 	return ++nerrs;
819     }
820     /* check that new global attribute was not added */
821     if (ncattinq(ncid, NC_GLOBAL, att.name, &att.type, &att.len) != -1) {
822 	error("%s: ncabort should have restored state before ncredef", pname);
823 	ncclose(ncid); return ++nerrs;
824     }
825     /* in data mode not being created, should just close */
826     if (ncabort(ncid) == -1) {
827 	error("%s: ncabort in define mode failed", pname);
828 	return ++nerrs;
829     }
830     if ((ncid = nccreate(fpath, NC_CLOBBER)) == -1) {
831 	error("%s: nccreate failed to NC_CLOBBER", pname);
832 	return ++nerrs;
833     }
834     /* in define mode being created, should delete */
835     if (ncabort(ncid) == -1) {
836 	error("%s: ncabort after nccreate failed", pname);
837 	return ++nerrs;
838     }
839     /* check with ncopen that file doesn't exist */
840     if (ncopen(fpath, NC_NOWRITE) != -1) {
841 	error("%s: ncabort deleted file, but ncopen found it", pname);
842 	return ++nerrs;
843     }
844     if (ncabort(ncid) != -1) {	/* should fail, ncid is bad handle */
845 	error("%s: ncclose failed to report bad netcdf handle", pname);
846 	nerrs++;
847     }
848     if (nerrs > 0)
849       (void) fprintf(stderr,"FAILED! ***\n");
850     else
851       (void) fprintf(stderr,"ok ***\n");
852 
853     return nerrs;
854 }
855