1 /*********************************************************************
2  *   Copyright 1993, UCAR/Unidata
3  *   See netcdf/COPYRIGHT file for copying and redistribution conditions.
4  *   $Id$
5  *********************************************************************/
6 
7 #include <stdio.h>
8 #include <string.h>
9 #include <math.h>
10 
11 #include "h4config.h"
12 #ifdef H4_HAVE_NETCDF
13 #include "netcdf.h"
14 #else
15 #include "hdf4_netcdf.h"
16 #endif
17 
18 #include "testcdf.h"		/* defines in-memory test cdf structure */
19 #include "add.h"		/* functions to update in-memory netcdf */
20 #include "error.h"
21 #include "tests.h"
22 #include "alloc.h"
23 #include "emalloc.h"
24 #ifdef HDF
25 #include "hdf.h"
26 #endif
27 
28 #define LEN_OF(array) ((sizeof array) / (sizeof array[0]))
29 #ifdef HDF
30 #define  EPS64          ((float64)1.0E-14)
31 #define  EPS32          ((float32)1.0E-7)
32 #endif
33 
34 /*
35  * Test ncvardef
36  *    check that proper define worked with ncvarinq
37  *    check that returned id is one more than previous id
38  *    try redefining an existing variable, check error
39  *    try adding scalar variable (no dimensions)
40  *    try with bad datatype, check error
41  *    try with bad number of dimensions, check error
42  *    try with bad dimension ids, check error
43  *    try in data mode, check error
44  */
45 void
test_ncvardef(path)46 test_ncvardef(path)
47      char *path;		/* name of writable netcdf file to open */
48 {
49     int nerrs = 0;
50     int cdfid;			/* netcdf id */
51     static char pname[] = "test_ncvardef";
52     int id, iv;
53     static struct cdfvar va[] = { /* variables of all shapes and sizes */
54 	{"bytev", NC_BYTE, 6, ___, 0},
55 	{"charv", NC_CHAR, 5, ___, 0},
56 	{"shortv", NC_SHORT, 4, ___, 0},
57 	{"longv", NC_LONG, 3, ___, 0},
58 	{"floatv", NC_FLOAT, 2, ___, 0},
59 	{"doublev", NC_DOUBLE, 1, ___, 0},
60 	{"scalarv", NC_DOUBLE, 0, ___, 0}
61     };
62     int nv = LEN_OF(va);	/* number of variables to define */
63     int va_id[LEN_OF(va)];	/* variable ids */
64     static struct cdfvar tmp =	/* variable for testing bad types, etc. */
65 	{"tmpv", NC_DOUBLE, 1, ___, 0};
66     /* if d5 >= 91 in following, problem on machines with 16-bit ints ??? */
67     static struct cdfdim di[] = { /* a bunch of dimensions */
68 	{"d0", 2}, {"d1",3}, {"d2",5}, {"d3", 6}, {"d4", 4}, {"d5", 31}};
69     int nd = LEN_OF(di);	/* number of dimensions */
70     int di_id[LEN_OF(di)];	/* dimension ids */
71 
72     (void) fprintf(stderr, "*** Testing %s ...\t", &pname[5]);
73 
74     if ((cdfid = ncopen(path, NC_WRITE)) == -1) {
75 	error("%s: ncopen failed", pname);
76 	return;
77     }
78     /* opened, defining a variable should fail in data mode */
79     if (ncvardef(cdfid, va[0].name, va[0].type, va[0].ndims, va[0].dims)
80 	!= -1) {
81 	error("%s: ncvardef should have failed in data mode", pname);
82 	ncclose(cdfid); return;
83     }
84     /* enter define mode */
85     if (ncredef(cdfid) == -1) {
86 	error("%s: cdredef failed", pname);
87 	ncclose(cdfid); return;
88     }
89 
90     /* Add nd more dimensions */
91     for (id = 0; id < nd; id++) {
92 	if ((di_id[id] = ncdimdef(cdfid, di[id].name, di[id].size)) == -1) {
93 	    error("%s: ncdimdef failed for %s, size %d",
94 		  pname, di[id].name, di[id].size);
95 	    ncclose(cdfid); return;
96 	}
97 	add_dim(&test, &di[id]);	/* keep in-memory netcdf in sync */
98     }
99 
100     tmp.dims = (int *) emalloc(sizeof(int) * H4_MAX_VAR_DIMS);
101     tmp.name = (char *) emalloc(H4_MAX_NC_NAME);
102 
103     /* in define mode, add variables of each type with various shapes */
104     for (iv = 0; iv < nv; iv++) {
105 	/* set shape to use subset of dimensions previously defined */
106 	va[iv].dims = (int *) emalloc(sizeof(int) * va[iv].ndims);
107 	for (id = 0; id < va[iv].ndims; id++)
108 	  va[iv].dims[id] = di_id[id];
109 	if ((va_id[iv] = ncvardef(cdfid, va[iv].name, va[iv].type,
110 				  va[iv].ndims, va[iv].dims)) == -1) {
111 	    error("%s: ncvardef failed", pname);
112 	    errvar(&test,&va[iv]); /* prints details about variable */
113 	    ncclose(cdfid); return;
114 	}
115 	add_var(&test, &va[iv]); /* keep in-memory netcdf in sync */
116 	/* check that var id returned is one more than previous var id */
117 	if (va_id[iv] != test.nvars - 1) {
118 	    error("%s: ncvardef returned %d for var id, expected %d",
119 		  pname, va_id[iv], test.nvars-1);
120 	    ncclose(cdfid); return;
121 	}
122 	/* use ncvarinq to get values just set and compare values */
123 	if (ncvarinq(cdfid, va_id[iv], tmp.name, &tmp.type,
124 		      &tmp.ndims, tmp.dims, &tmp.natts) == -1) {
125 	    error("%s: ncvarinq failed", pname);
126 	    errvar(&test,&va[iv]); /* prints details about variable */
127 	    ncclose(cdfid); return;
128 	}
129 	if (strcmp(tmp.name, va[iv].name) != 0 ||
130 	    tmp.type != va[iv].type ||
131 	    tmp.ndims != va[iv].ndims ||
132 	    tmp.natts != va[iv].natts) {
133 	    error("%s: ncvardef and ncvarinq don't agree for %s",
134 		  pname, va[iv].name);
135 	    nerrs++;
136 	    errvar(&test,&va[iv]);
137 	    errvar(&test,&tmp);
138 	}
139 	for (id = 0; id < va[iv].ndims; id++) {
140 	    if (tmp.dims[id] != va[iv].dims[id]) {
141 	    error("%s: ncvardef and ncvarinq don't agree on shape of %s",
142 		  pname, va[iv].name);
143 	    nerrs++;
144 	    errvar(&test,&va[iv]);
145 	    errvar(&test,&tmp);
146 	    }
147 	}
148     }
149     /* try adding same variable again, this should fail */
150     if (ncvardef(cdfid, va[0].name, va[0].type,
151 		  va[0].ndims, va[0].dims) != -1) {
152 	error("%s: ncvardef should not allow redefinition", pname);
153 	ncclose(cdfid); return;
154     }
155     /* try bad type, should fail */
156     if (ncvardef(cdfid, "badtype", BAD_TYPE, va[0].ndims, va[0].dims) != -1) {
157 	error("%s: ncvardef should have failed on bad type", pname);
158 	ncclose(cdfid); return;
159     }
160     /* try bad ndims, should fail */
161     if (ncvardef(cdfid, "badndims", va[0].type, -1, va[0].dims) != -1) {
162 	error("%s: ncvardef should have failed on bad ndims", pname);
163 	ncclose(cdfid); return;
164     }
165     /* try bad ids in dims vector, should fail */
166     id = va[0].dims[0];
167     va[0].dims[va[0].ndims-1] = -1;
168     if (ncvardef(cdfid, "baddims", va[0].type, va[0].ndims, va[0].dims)
169 	!= -1) {
170 	error("%s: ncvardef should have failed on negative dim id in dims",
171 	      pname);
172 	ncclose(cdfid); return;
173     }
174     if (ncendef (cdfid) == -1) {
175 	error("%s: ncendef failed", pname);
176 	ncclose(cdfid); return;
177     }
178 
179     /* try reading a value of each type, should get appropriate fill value */
180     for (iv = 0; iv < nv; iv++) {
181 	static long where[] = {0,0,0,0,0,0};
182 
183 	switch(va[iv].type) {
184 	  case NC_BYTE:
185 	    {
186 		char val, fillval = FILL_BYTE;
187 		if (ncvarget1(cdfid, va_id[iv], where, (void *) &val) != -1) {
188 		    if (val != fillval) {
189 			error("%s: unwritten byte not FILL_BYTE", pname);
190 			nerrs++;
191 		    }
192 		} else {
193 		    error("%s: ncvarget1 failure for byte", pname);
194 		    nerrs++;
195 		}
196 	    }
197 	    break;
198 	  case NC_CHAR:
199 	    {
200 		char val, fillval = FILL_CHAR;
201 		if (ncvarget1(cdfid, va_id[iv], where, (void *) &val) != -1) {
202 		    if (val != fillval) {
203 			error("%s: unwritten char not FILL_CHAR", pname);
204 			nerrs++;
205 		    }
206 		} else {
207 		    error("%s: ncvarget1 failure for char", pname);
208 		    nerrs++;
209 		}
210 	    }
211 	    break;
212 	  case NC_SHORT:
213 	    {
214 		short val, fillval = FILL_SHORT;
215 		if (ncvarget1(cdfid, va_id[iv], where, (void *) &val) != -1) {
216 		    if (val != fillval) {
217 			error("%s: unwritten short not FILL_SHORT", pname);
218 			nerrs++;
219 		    }
220 		} else {
221 		    error("%s: ncvarget1 failure for short", pname);
222 		    nerrs++;
223 		}
224 	    }
225 	    break;
226 	  case NC_LONG:
227 	    {
228 		nclong val, fillval;
229                 val = 0;
230                 fillval = 0;
231                 fillval = FILL_LONG;
232 		if (ncvarget1(cdfid, va_id[iv], where, (void *) &val) != -1) {
233 		    if ((nclong) val != (nclong) fillval) {
234                         nclong a, b;
235 
236 printf("\n\n Was expecting %d instead got a %d\n", (int)fillval, (int)val);
237                         a = (nclong) val;
238                         b = (nclong) fillval;
239 printf("\n\n After cast %d %d\n", (int)a, (int)b);
240 
241 			error("%s: unwritten long not FILL_LONG", pname);
242 			nerrs++;
243 		    }
244 		} else {
245 		    error("%s: ncvarget1 failure for long", pname);
246 		    nerrs++;
247 		}
248 	    }
249 	    break;
250 	  case NC_FLOAT:
251 	    {
252 		float val, fillval = FILL_FLOAT;
253 		if (ncvarget1(cdfid, va_id[iv], where, (void *) &val) != -1) {
254 #ifdef HDF
255             if (fabs((double)(val - fillval)) > fabs((double)(fillval*EPS32)))
256 #else /*!HDF */
257 		    if (val != fillval)
258 #endif
259             {
260                 error("%s: unwritten float not FILL_FLOAT", pname);
261                 nerrs++;
262                 }
263         } else {
264             error("%s: ncvarget1 failure for float", pname);
265             nerrs++;
266         }
267 	    }
268 	    break;
269 	  case NC_DOUBLE:
270 	    {
271 		double val, fillval = FILL_DOUBLE;
272 		if (ncvarget1(cdfid, va_id[iv], where, (void *) &val) != -1) {
273 #ifdef HDF
274            if (fabs((double)(val - fillval)) > fabs((double)(fillval*EPS64)))
275 #else  /* !HDF */
276 		    if (val != fillval)
277 #endif /* !HDF */
278             {
279             error("%s: unwritten double not FILL_DOUBLE", pname);
280             nerrs++;
281             }
282         } else {
283             error("%s: ncvarget1 failure for double", pname);
284             nerrs++;
285         }
286 	    }
287 	    break;
288         default:
289             break;
290 	}
291     }
292 
293     if (ncclose (cdfid) == -1) {
294 	error("%s: ncclose failed", pname);
295 	return;
296     }
297     Free ((char *) tmp.dims);
298     Free (tmp.name);
299     for (iv = 0; iv < nv; iv++)
300       if (va[iv].dims)
301 	Free((char *) va[iv].dims);
302     if (nerrs > 0)
303       (void) fprintf(stderr,"FAILED! ***\n");
304     else
305       (void) fprintf(stderr,"ok ***\n");
306 }
307