1 /*********************************************************************
2 * Copyright 2018, University Corporation for Atmospheric Research
3 * See netcdf/COPYRIGHT file for copying and redistribution conditions.
4 * $Header: /upc/share/CVS/netcdf-3/nctest/rec.c,v 1.11 2006/10/31 16:21:58 ed Exp $
5 *********************************************************************/
6
7 #include <config.h>
8 #include <stdio.h>
9 #include <stdlib.h> /* for free() */
10 #include "netcdf.h"
11 #include "testcdf.h" /* defines in-memory test cdf structure */
12 #include "emalloc.h"
13 #include "val.h"
14 #include "error.h"
15 #include "tests.h"
16
17 /*
18 * Returns number of record variables in an open netCDF file, and an array of
19 * the record variable ids, if the array parameter is non-null. Returns -1 on
20 * error.
21 */
22 static int
numrecvars(ncid,recvarids)23 numrecvars(ncid, recvarids)
24 int ncid;
25 int *recvarids;
26 {
27 int ndims, iv, nvars;
28 int nrecvars;
29 int recdimid;
30 int dimids[MAX_NC_DIMS];
31
32 if (ncinquire(ncid, 0, &nvars, 0, &recdimid) == -1)
33 return -1;
34 if (recdimid == -1)
35 return 0;
36 nrecvars = 0;
37 for (iv = 0; iv < nvars; iv++) {
38 if (ncvarinq(ncid, iv, 0, 0, &ndims, dimids, 0) == -1)
39 return -1;
40 if (ndims > 0 && dimids[0] == recdimid) {
41 if (recvarids)
42 recvarids[nrecvars] = iv;
43 nrecvars++;
44 }
45 }
46 return nrecvars;
47 }
48
49
50 /*
51 * Returns record size (in bytes) of the record variable with a specified
52 * variable id. Returns 0 if not a record variable. Returns -1 on error.
53 */
54 static long
ncrecsize(ncid,vid)55 ncrecsize(ncid,vid)
56 int ncid;
57 int vid;
58 {
59 int recdimid;
60 nc_type type;
61 int ndims;
62 int dimids[MAX_NC_DIMS];
63 int id;
64 long size;
65
66 if (ncinquire(ncid, 0, 0, 0, &recdimid) == -1)
67 return -1;
68 if (ncvarinq(ncid, vid, 0, &type, &ndims, dimids, 0) == -1)
69 return -1;
70 if (ndims == 0 || dimids[0] != recdimid)
71 return 0;
72 size = nctypelen(type);
73 for (id = 1; id < ndims; id++) {
74 long len;
75 (void) ncdiminq(ncid, dimids[id], 0, &len);
76 size *= len;
77 }
78 return size;
79 }
80
81
82 /*
83 * Retrieves the number of record variables, the record variable ids, and the
84 * record size of each record variable. If any pointer to info to be returned
85 * is null, the associated information is not returned. Returns -1 on error.
86 * This is the same as the ncrecinq() in the library, except that can handle
87 * errors better.
88 */
89 static int
recinq(ncid,nrecvars,recvarids,recsizes)90 recinq(ncid, nrecvars, recvarids, recsizes)
91 int ncid;
92 int *nrecvars;
93 int *recvarids;
94 long *recsizes;
95 {
96 int iv;
97 int rvarids[MAX_NC_VARS];
98 int nrvars = numrecvars(ncid, rvarids);
99
100 if (nrvars == -1)
101 return -1;
102
103 if (nrecvars)
104 *nrecvars = nrvars;
105 if (recvarids)
106 for (iv = 0; iv < nrvars; iv++)
107 recvarids[iv] = rvarids[iv];
108 if (recsizes)
109 for (iv = 0; iv < nrvars; iv++)
110 recsizes[iv] = ncrecsize(ncid, rvarids[iv]);
111 return 0;
112 }
113
114
115 /*
116 * Test ncrecinq
117 * try in both data and define modes
118 * check returned values against independently computed values
119 * try with bad netCDF handle, check error
120 */
121 int
test_ncrecinq(path)122 test_ncrecinq(path)
123 const char *path; /* name of netcdf file to open */
124 {
125 int nerrs = 0;
126 static char pname[] = "test_ncrecinq";
127 int ncid;
128 int nrvars; /* number of record variables */
129 int rvarids[MAX_NC_VARS]; /* id of each record variable */
130 long rvarsizes[MAX_NC_VARS]; /* record size of each record variable */
131 int tnrvars; /* true number of record variables */
132 int trvarids[MAX_NC_VARS]; /* true id of each record variable */
133 long trvarsizes[MAX_NC_VARS]; /* true rec size of each record variable */
134 int iv;
135
136 (void) fprintf(stderr, "*** Testing %s ...\t", &pname[5]);
137
138 if ((ncid = ncopen(path, NC_WRITE)) == -1) {
139 error("%s: ncopen failed", pname);
140 return ++nerrs;
141 }
142
143 /* First compute independently what ncrecinq should return */
144 if (recinq(ncid, &tnrvars, trvarids, trvarsizes) == -1) {
145 error("%s: recinq failed", pname);
146 ncclose(ncid);
147 return ++nerrs;
148 }
149
150 /* check that ncrecinq() returns correct information in data mode */
151 if (ncrecinq(ncid, &nrvars, rvarids, rvarsizes) == -1) {
152 error("%s: ncrecinq failed", pname);
153 ncclose(ncid);
154 return ++nerrs;
155 }
156
157 if (nrvars != tnrvars) {
158 error("ncrecinq returned wrong number of rec vars, %d != %d",
159 nrvars, tnrvars);
160 nerrs++;
161 }
162
163 for (iv = 0; iv < nrvars; iv++) {
164 if (rvarids[iv] != trvarids[iv]) {
165 error("ncrecinq returned wrong record id for var %d",
166 trvarids[iv]);
167 nerrs++;
168 }
169 if (rvarsizes[iv] != trvarsizes[iv]) {
170 error("ncrecinq returned wrong record size for var %d",
171 trvarids[iv]);
172 nerrs++;
173 }
174 }
175
176 if (ncredef(ncid) == -1) {
177 error("%s: ncredef failed", pname);
178 ncclose(ncid);
179 return ++nerrs;
180 }
181 /* check that ncrecinq() returns correct information in define mode too */
182 if (ncrecinq(ncid, &nrvars, rvarids, rvarsizes) == -1) {
183 error("%s: ncrecinq failed in define mode", pname);
184 ncclose(ncid);
185 return ++nerrs;
186 }
187 if (nrvars != tnrvars) {
188 error("define mode, ncrecinq returned wrong num of rec vars, %d != %d",
189 nrvars, tnrvars);
190 nerrs++;
191 }
192 for (iv = 0; iv < nrvars; iv++) {
193 if (rvarids[iv] != trvarids[iv]) {
194 error("define mode, ncrecinq returned wrong record id for var %d",
195 trvarids[iv]);
196 nerrs++;
197 }
198 if (rvarsizes[iv] != trvarsizes[iv]) {
199 error("define mode, ncrecinq returned wrong rec size for var %d",
200 trvarids[iv]);
201 nerrs++;
202 }
203 }
204
205 if (ncclose (ncid) == -1) {
206 error("%s: ncclose failed", pname);
207 return ++nerrs;
208 }
209
210 if (ncrecinq(ncid, &nrvars, rvarids, rvarsizes) != -1) {
211 error("%s: ncrecinq failed to report bad handle", pname);
212 nerrs++;
213 }
214
215 if (nerrs > 0)
216 (void) fprintf(stderr,"FAILED! ***\n");
217 else
218 (void) fprintf(stderr,"ok ***\n");
219 return nerrs;
220 }
221
222
223 /*
224 * Retrieves the dimension sizes of a variable with a specified variable id in
225 * an open netCDF file. Returns -1 on error.
226 */
227 static int
dimsizes(ncid,varid,sizes)228 dimsizes(ncid, varid, sizes)
229 int ncid;
230 int varid;
231 long *sizes;
232 {
233 int ndims;
234 int id;
235 int dimids[MAX_NC_DIMS];
236
237 if (ncvarinq(ncid, varid, 0, 0, &ndims, dimids, 0) == -1)
238 return -1;
239 if (ndims == 0 || sizes == 0)
240 return 0;
241 for (id = 0; id < ndims; id++)
242 (void) ncdiminq(ncid, dimids[id], 0, &sizes[id]);
243 return 0;
244 }
245
246
247 /*
248 * Write one record's worth of data, except don't write to variables for which
249 * the address of the data to be written is NULL. Return -1 on error. This is
250 * the same as the ncrecput() in the library, except that can handle errors
251 * better.
252 */
253 static int
recput(ncid,recnum,datap)254 recput(ncid, recnum, datap)
255 int ncid;
256 long recnum;
257 void **datap;
258 {
259 int iv;
260 int rvids[MAX_NC_VARS];
261 int nrvars = numrecvars(ncid, rvids);
262 long start[MAX_NC_DIMS];
263 long edges[MAX_NC_DIMS];
264
265 if (nrvars == -1)
266 return -1;
267
268 start[0] = recnum;
269 for (iv = 1; iv < nrvars; iv++)
270 start[iv] = 0;
271
272 for (iv = 0; iv < nrvars; iv++) {
273 if (datap[iv] != 0) {
274 (void) dimsizes(ncid, rvids[iv], edges);
275 edges[0] = 1; /* only 1 record's worth */
276 if (ncvarput(ncid, rvids[iv], start, edges, datap[iv]) == -1)
277 return -1;
278 }
279 }
280 return 0;
281 }
282
283
284 /*
285 * Read one record's worth of data, except don't read from variables for which
286 * the address of the data to be read is null. Return -1 on error. This is
287 * the same as the ncrecget() in the library, except that can handle errors
288 * better.
289 */
290 static int
recget(ncid,recnum,datap)291 recget(ncid, recnum, datap)
292 int ncid;
293 long recnum;
294 void **datap;
295 {
296 int iv;
297 int rvids[MAX_NC_VARS];
298 int nrvars = numrecvars(ncid, rvids);
299 long start[MAX_NC_DIMS];
300 long edges[MAX_NC_DIMS];
301
302 if (nrvars == -1)
303 return -1;
304
305 start[0] = recnum;
306 for (iv = 1; iv < nrvars; iv++)
307 start[iv] = 0;
308
309 for (iv = 0; iv < nrvars; iv++) {
310 if (datap[iv] != 0) {
311 (void) dimsizes(ncid, rvids[iv], edges);
312 edges[0] = 1; /* only 1 record's worth */
313 if (ncvarget(ncid, rvids[iv], start, edges, datap[iv]) == -1)
314 return -1;
315 }
316 }
317 return 0;
318 }
319
320
321 /*
322 * Test ncrecput
323 * check that proper call works putting all recoerd variables
324 * try putting only a proper subset of variables
325 * try putting the empty subset of variables
326 * try in define mode, check error
327 * try with bad netCDF handle, check error
328 */
329 int
test_ncrecput(path)330 test_ncrecput(path)
331 const char *path; /* name of writable netcdf file to open */
332 {
333 int nerrs = 0;
334 static char pname[] = "test_ncrecput";
335 int nrvars; /* number of record variables */
336 int rvarids[MAX_NC_VARS]; /* id of each record variable */
337 long rvarsizes[MAX_NC_VARS]; /* record size of each record variable */
338 int ncid; /* netcdf id */
339 void *datap[MAX_NC_VARS]; /* array of address pointers for rec vars */
340 void *datar[MAX_NC_VARS]; /* pointers for comparison data */
341 long recnum = 1; /* we'll write the second record */
342 int iv;
343 long recsize[MAX_NC_VARS]; /* record size in data elements */
344 nc_type vartype[MAX_NC_VARS];
345 void *zeros[MAX_NC_VARS];
346
347 (void) fprintf(stderr, "*** Testing %s ...\t", &pname[5]);
348
349 if ((ncid = ncopen(path, NC_WRITE)) == -1) {
350 error("%s: ncopen failed", pname);
351 return ++nerrs;
352 }
353
354 if (ncrecinq(ncid, &nrvars, rvarids, rvarsizes) == -1) {
355 error("%s: ncrecinq failed", pname);
356 ncclose(ncid);
357 return ++nerrs;
358 }
359
360 /* get a block of data of the right type for each record variable */
361 for (iv = 0; iv < nrvars; iv++) {
362 datap[iv] = emalloc(rvarsizes[iv]);
363 datar[iv] = emalloc(rvarsizes[iv]); /* for comparison values */
364 if (ncvarinq(ncid, rvarids[iv], 0, &vartype[iv], 0, 0, 0) == -1) {
365 error("%s: ncvarinq failed", pname);
366 ncclose(ncid);
367 return ++nerrs;
368 }
369 recsize[iv] = rvarsizes[iv]/nctypelen(vartype[iv]);
370 /* Fill data blocks with 0,1,2,3,... */
371 val_fill(vartype[iv], recsize[iv], datap[iv]);
372 /* Zero out comparison data */
373 val_fill_zero(vartype[iv], recsize[iv], datar[iv]);
374 }
375
376 /* Zero data in recnum record, before trying to put non-zero data */
377 if (recput(ncid, recnum, datar) == -1) {
378 error("%s: recput failed", pname);
379 ncclose(ncid);
380 return ++nerrs;
381 }
382
383 /* opened in data mode, try putting a complete record */
384 if (ncrecput(ncid, recnum, datap) == -1) {
385 error("%s: ncrecput failed on complete record", pname);
386 nerrs++;
387 }
388
389 /* Check that right values were put */
390 if (recget(ncid, recnum, datar) == -1) {
391 error("%s: recget failed", pname);
392 nerrs++;
393 }
394 for (iv = 0; iv < nrvars; iv++) {
395 if (val_cmp(vartype[iv], recsize[iv], datap[iv], datar[iv]) != 0) {
396 error("%s: bad values written by recput", pname);
397 nerrs++;
398 }
399 val_fill_zero(vartype[iv], recsize[iv], datap[iv]);
400 val_fill_zero(vartype[iv], recsize[iv], datar[iv]);
401 zeros[iv] = 0;
402 }
403
404 if (nrvars > 0) {
405 void *datap0 = datap[0];
406
407 /* put a partial record, everything but first record variable */
408 datap[0] = 0;
409 val_fill(vartype[0], recsize[0], datar[0]);
410 if (ncrecput(ncid, recnum, datap) == -1) {
411 error("%s: ncrecput failed on partial record", pname);
412 nerrs++;
413 }
414
415 /* Check right values were put, first record variable undisturbed */
416 datap[0] = datap0;
417 if (recget(ncid, recnum, datap) == -1) {
418 error("%s: recget failed after partial record put", pname);
419 nerrs++;
420 }
421 for (iv = 0; iv < nrvars; iv++) {
422 if (val_cmp(vartype[iv], recsize[iv], datap[iv], datar[iv]) != 0) {
423 error("%s: bad values written by partial recput", pname);
424 nerrs++;
425 }
426 }
427 }
428
429 /* Put an empty record, check that values remain undisturbed */
430 if (ncrecput(ncid, recnum, zeros) == -1) {
431 error("%s: ncrecput failed on empty record", pname);
432 nerrs++;
433 }
434 if (recget(ncid, recnum, datap) == -1) {
435 error("%s: recget failed after empty record put", pname);
436 nerrs++;
437 }
438 for (iv = 0; iv < nrvars; iv++) {
439 if (val_cmp(vartype[iv], recsize[iv], datap[iv], datar[iv]) != 0) {
440 error("%s: bad values written by empty recput", pname);
441 nerrs++;
442 }
443 }
444
445 /* try in define mode, check error */
446 if (ncredef(ncid) == -1) {
447 error("%s: ncredef failed", pname);
448 ncclose(ncid);
449 return ++nerrs;
450 }
451
452 if (ncrecput(ncid, recnum, datap) != -1) {
453 error("%s: ncrecput should fail in define mode", pname);
454 nerrs++;
455 }
456
457 /* try with bad netCDF handle, check error */
458 if (ncclose (ncid) == -1) {
459 error("%s: ncclose failed", pname);
460 return ++nerrs;
461 }
462 if (ncrecput(ncid, recnum, datap) != -1) {
463 error("%s: ncrecput failed to report bad handle", pname);
464 nerrs++;
465 }
466 for (iv = 0; iv < nrvars; iv++) {
467 free(datap[iv]);
468 free(datar[iv]);
469 }
470
471 if (nerrs > 0)
472 (void) fprintf(stderr,"FAILED! ***\n");
473 else
474 (void) fprintf(stderr,"ok ***\n");
475
476 return nerrs;
477 }
478
479
480 /*
481 * Test ncrecget
482 * check that proper call works getting all record variables
483 * try getting only a proper subset of variables
484 * try getting the empty subset of variables
485 * try with bad netCDF handle, check error
486 */
487 int
test_ncrecget(path)488 test_ncrecget(path)
489 const char *path; /* name of netcdf file to open */
490 {
491 int nerrs = 0;
492 static char pname[] = "test_ncrecget";
493 int nrvars; /* number of record variables */
494 int rvarids[MAX_NC_VARS]; /* id of each record variable */
495 long rvarsizes[MAX_NC_VARS]; /* record size of each record variable */
496 int ncid; /* netcdf id */
497 void *datap[MAX_NC_VARS]; /* array of address pointers for rec vars */
498 void *datar[MAX_NC_VARS]; /* pointers for comparison data */
499 long recnum = 1; /* we'll write the second record */
500 int iv;
501 long recsize[MAX_NC_VARS]; /* record size in data elements */
502 nc_type vartype[MAX_NC_VARS];
503 void *zeros[MAX_NC_VARS];
504
505 (void) fprintf(stderr, "*** Testing %s ...\t", &pname[5]);
506
507 if ((ncid = ncopen(path, NC_WRITE)) == -1) {
508 error("%s: ncopen failed", pname);
509 return ++nerrs;
510 }
511
512 if (ncrecinq(ncid, &nrvars, rvarids, rvarsizes) == -1) {
513 error("%s: ncrecinq failed", pname);
514 ncclose(ncid);
515 return ++nerrs;
516 }
517
518 /* get a block of data of the right type for each record variable */
519 for (iv = 0; iv < nrvars; iv++) {
520 datap[iv] = emalloc(rvarsizes[iv]);
521 datar[iv] = emalloc(rvarsizes[iv]); /* for comparison values */
522 if (ncvarinq(ncid, rvarids[iv], 0, &vartype[iv], 0, 0, 0) == -1) {
523 error("%s: ncvarinq failed", pname);
524 ncclose(ncid);
525 return ++nerrs;
526 }
527 recsize[iv] = rvarsizes[iv]/nctypelen(vartype[iv]);
528 /* Fill data blocks with 0,1,2,3,... */
529 val_fill(vartype[iv], recsize[iv], datap[iv]);
530 /* Zero out comparison data */
531 val_fill_zero(vartype[iv], recsize[iv], datar[iv]);
532 }
533
534 if (recput(ncid, recnum, datap) == -1) {
535 error("%s: recput failed", pname);
536 ncclose(ncid);
537 return ++nerrs;
538 }
539
540 /* opened in data mode, try getting a complete record */
541 if (recget(ncid, recnum, datap) == -1) {
542 error("%s: recget failed on complete record", pname);
543 nerrs++;
544 }
545 if (ncrecget(ncid, recnum, datar) == -1) {
546 error("%s: ncrecget failed on complete record", pname);
547 nerrs++;
548 }
549
550 for (iv = 0; iv < nrvars; iv++) {
551 if (val_cmp(vartype[iv], recsize[iv], datap[iv], datar[iv]) != 0) {
552 error("%s: bad values written by recget", pname);
553 nerrs++;
554 }
555 val_fill_zero(vartype[iv], recsize[iv], datap[iv]);
556 val_fill_zero(vartype[iv], recsize[iv], datar[iv]);
557 zeros[iv] = 0;
558 }
559
560 if (nrvars > 0) {
561 void *datap0 = datap[0];
562 void *datar0 = datar[0];
563
564 /* get a partial record, everything but first record variable */
565 datap[0] = 0;
566 if (ncrecget(ncid, recnum, datap) == -1) {
567 error("%s: ncrecget failed on partial record", pname);
568 nerrs++;
569 }
570 datar[0] = 0;
571 if (recget(ncid, recnum, datar) == -1) {
572 error("%s: recget failed on partial record", pname);
573 nerrs++;
574 }
575 /* Check right values were got, first record variable undisturbed */
576 datap[0] = datap0;
577 datar[0] = datar0;
578 for (iv = 0; iv < nrvars; iv++) {
579 if (val_cmp(vartype[iv], recsize[iv], datap[iv], datar[iv]) != 0) {
580 error("%s: bad values read by partial recget", pname);
581 nerrs++;
582 }
583 }
584 }
585
586 /* Get an empty record */
587 if (ncrecget(ncid, recnum, zeros) == -1) {
588 error("%s: ncrecget failed on empty record", pname);
589 nerrs++;
590 }
591
592 /* try with bad netCDF handle, check error */
593 if (ncclose (ncid) == -1) {
594 error("%s: ncclose failed", pname);
595 return ++nerrs;
596 }
597 if (ncrecget(ncid, recnum, datap) != -1) {
598 error("%s: ncrecget failed to report bad handle", pname);
599 nerrs++;
600 }
601 for (iv = 0; iv < nrvars; iv++) {
602 free(datap[iv]);
603 free(datar[iv]);
604 }
605
606 if (nerrs > 0)
607 (void) fprintf(stderr,"FAILED! ***\n");
608 else
609 (void) fprintf(stderr,"ok ***\n");
610
611 return nerrs;
612 }
613
614