1 /*********************************************************************
2  *   Copyright 2018, UCAR/Unidata
3  *   See netcdf/COPYRIGHT file for copying and redistribution conditions.
4  *   $Header: /upc/share/CVS/netcdf-3/nctest/dimtests.c,v 1.14 2006/10/31 16:21:54 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 cdf structure */
14 #include "add.h"		/* functions to update in-memory netcdf */
15 #include "error.h"
16 #include "tests.h"
17 
18 /*
19  * Test ncdimdef
20  *    try in data mode, check error
21  *    check that returned id is one more than previous id
22  *    try adding same dimension twice, check error
23  *    try with illegal sizes, check error
24  *    make sure unlimited size works, shows up in ncinquire(...,*xtendim)
25  *    try to define a second unlimited dimension, check error
26  */
27 int
test_ncdimdef(path)28 test_ncdimdef(path)
29      const char *path;		/* name of writable netcdf to open */
30 {
31     int nerrs = 0;
32     static char pname[] = "test_ncdimdef";
33     int cdfid;			/* netcdf id */
34     static struct cdfdim mm =	/* dimension */
35       {"mm", 1};		/* 1 should be a valid dimension size */
36     static struct cdfdim nn =	/* dimension */
37       {"bogus", ___};		/* used for testing invalid dimension sizes */
38     static struct cdfdim rec =	/* dimension */
39       {"rec", NC_UNLIMITED};
40     int ndims;			/* number of dimensions */
41     int nvars;			/* number of variables */
42     int natts;			/* number of attributes */
43     int xdimid;			/* id of unlimited dimension, or -1 if none */
44     int dimid;			/* dimension id */
45 
46     (void) fprintf(stderr, "*** Testing %s ...\t", &pname[5]);
47 
48     if ((cdfid = ncopen(path, NC_WRITE)) == -1) {
49 	error("%s: ncopen failed", pname);
50 	return ++nerrs;
51     }
52     /* opened, defining a dimension should fail in data mode */
53     if (ncdimdef(cdfid, mm.name, mm.size) != -1) {
54 	error("%s: ncdimdef should have failed in data mode", pname);
55 	ncclose(cdfid); return ++nerrs;
56     }
57     /* enter define mode */
58     if (ncredef(cdfid) == -1) {
59 	error("%s: cdredef failed", pname);
60 	ncclose(cdfid); return ++nerrs;
61     }
62     /* in define mode OK, add a dimension */
63     if ((dimid = ncdimdef(cdfid, mm.name, mm.size)) == -1) {
64 	error("%s: ncdimdef failed", pname);
65 	ncclose(cdfid); return ++nerrs;
66     }
67     add_dim(&test, &mm);	/* keep in-memory netcdf in sync */
68     /* check that dim id returned is one more than previous dim id */
69     if (dimid != test.ndims - 1) {
70 	error("%s: ncdimdef returned %d for dim id, expected %d",
71 	      pname, dimid, test.ndims-1);
72 	ncclose(cdfid); return ++nerrs;
73     }
74 
75     /* try adding same dimension again, this should fail */
76     if (ncdimdef(cdfid, mm.name, mm.size) != -1) {
77 	error("%s: ncdimdef should not have allowed redefinition", pname);
78 	ncclose(cdfid); return ++nerrs;
79     }
80     /* try adding dimension with negative size, this should fail */
81     if (ncdimdef(cdfid, nn.name, (long) -10) != -1) {
82 	error("%s: ncdimdef should not allow negative size dimension", pname);
83 	ncclose(cdfid); return ++nerrs;
84     }
85     /* if there is not already an unlimited size dimension, try adding one */
86     if (ncinquire(cdfid, &ndims, &nvars, &natts, &xdimid) == -1) {
87 	error("%s: ncinquire failed", pname);
88 	ncclose(cdfid); return ++nerrs;
89     }
90     if (xdimid == -1) {
91 	if (ncdimdef(cdfid, rec.name, rec.size) == -1) {
92 	    error("%s: ncdimdef failed on NC_UNLIMITED dimension", pname);
93 	    ncclose(cdfid); return ++nerrs;
94 	}
95 	add_dim(&test, &rec);
96     }
97     /* try adding another unlimited dimension, which should fail */
98     if (ncdimdef(cdfid, "rec2", rec.size) != -1) {
99 	error("%s: ncdimdef should not allow second NC_UNLIMITED dimension",
100 	      pname);
101 	ncclose(cdfid); return ++nerrs;
102     }
103     if (ncendef (cdfid) == -1) {
104 	error("%s: ncendef failed", pname);
105 	ncclose(cdfid); return ++nerrs;
106     }
107     if (ncclose (cdfid) == -1) {
108 	error("%s: ncclose failed", pname);
109 	return ++nerrs;
110     }
111     if (ncdimdef(cdfid, "rec2", rec.size) != -1) {
112 	error("%s: ncdimdef should fail on bad netCDF id", pname);
113 	nerrs++;
114     }
115     if (nerrs > 0)
116       (void) fprintf(stderr,"FAILED! ***\n");
117     else
118       (void) fprintf(stderr,"ok ***\n");
119 
120     return nerrs;
121 }
122 
123 
124 /*
125  * Test ncdimid
126  *    check return with defined dimension in both modes
127  *    try with undefined dimension, check error
128  *    check return with unlimited size dimension
129  *    try with bad handle, check error
130  */
131 int
test_ncdimid(path)132 test_ncdimid(path)
133      const char *path;		/* name of writable netcdf file to open */
134 {
135     int nerrs = 0;
136     static char pname[] = "test_ncdimid";
137     int cdfid;			/* netcdf id */
138     int nn_dim;			/* dimension id */
139     static struct cdfdim nn =	/* dimension */
140       {"nn", 1};		/* 1 should be a valid dimension size */
141 
142     (void) fprintf(stderr, "*** Testing %s ...\t\t", &pname[5]);
143 
144     if ((cdfid = ncopen(path, NC_WRITE)) == -1) {
145 	error("%s: ncopen failed", pname);
146 	return ++nerrs;
147     }
148     /* opened, enter define mode */
149     if (ncredef(cdfid) == -1) {
150 	error("%s: cdredef failed", pname);
151 	ncclose(cdfid); return ++nerrs;
152     }
153     /* in define mode OK, add a dimension */
154     if ((nn_dim = ncdimdef(cdfid, nn.name, nn.size)) == -1) {
155 	error("%s: ncdimdef failed", pname);
156 	ncclose(cdfid); return ++nerrs;
157     }
158     add_dim(&test, &nn);	/* keep in-memory netcdf in sync */
159     /* check id returned for name matches id returned from definition */
160     if (ncdimid(cdfid, nn.name) != nn_dim) {
161 	error("%s: ncdimid returned wrong value in define mode", pname);
162 	ncclose(cdfid); return ++nerrs;
163     }
164     if (ncendef (cdfid) == -1) {
165 	error("%s: ncendef failed", pname);
166 	ncclose(cdfid); return ++nerrs;
167     }
168     /* in data mode, check returned id for dimension just added */
169     if (ncdimid(cdfid, nn.name) != nn_dim) {
170 	error("%s: ncdimid returned wrong value in data mode", pname);
171 	ncclose(cdfid); return ++nerrs;
172     }
173     /* try with undefined dimension, should fail */
174     if (ncdimid(cdfid, "easter-bunny") != -1) {
175 	error("%s: ncdimid with bogus name should have failed ", pname);
176 	ncclose(cdfid); return ++nerrs;
177     }
178     /* try with unlimited dimension, assumed to be "rec" from earlier calls */
179     if (ncdimid(cdfid, "rec") != test.xdimid) {
180 	error("%s: ncdimid returned bad value for record dimension", pname);
181 	ncclose(cdfid); return ++nerrs;
182     }
183     if (ncclose (cdfid) == -1) {
184 	error("%s: ncclose failed", pname);
185 	return ++nerrs;
186     }
187     /* try on bad handle, should fail */
188     if (ncdimid(cdfid, nn.name) != -1) {
189 	error("%s: ncdimid failed to report bad netcdf handle", pname);
190 	nerrs++;
191     }
192     if (nerrs > 0)
193       (void) fprintf(stderr,"FAILED! ***\n");
194     else
195       (void) fprintf(stderr,"ok ***\n");
196 
197     return nerrs;
198 }
199 
200 
201 /*
202  * Test ncdiminq
203  *    try in both modes
204  *    check returned name and size against defined name and size
205  *    try with bad dimension handle, check error
206  *    try with bad netCDF handle, check error
207  */
208 int
test_ncdiminq(path)209 test_ncdiminq(path)
210      const char *path;		/* name of writable netcdf file to open */
211 {
212     int nerrs = 0;
213     static char pname[] = "test_ncdiminq";
214     int cdfid;			/* netcdf id */
215     int dimid;			/* dimension id */
216     struct cdfdim dim;		/* dimension */
217 
218     (void) fprintf(stderr, "*** Testing %s ...\t", &pname[5]);
219 
220     if ((cdfid = ncopen(path, NC_WRITE)) == -1) {
221 	error("%s: ncopen failed", pname);
222 	return ++nerrs;
223     }
224     /* opened, in data mode */
225     dim.name = (char *) emalloc(MAX_NC_NAME);
226     for (dimid = 0 ; dimid < test.ndims; dimid++) { /* loop on all dim ids */
227 	if (ncdiminq(cdfid, dimid, dim.name, &dim.size) == -1) {
228 	    error("%s: ncdiminq in data mode failed on dim id %d",
229 		  pname, dimid);
230 	    ncclose(cdfid); return ++nerrs;
231 	}
232 	/* compare returned with expected values */
233 	if (strcmp(dim.name, test.dims[dimid].name) != 0) {
234 	    error("%s: ncdiminq (data mode), name %s, expected %s for id = %d",
235 		pname, dim.name, test.dims[dimid].name, dimid);
236 	    nerrs++;
237 	}
238 	if (dim.size != test.dims[dimid].size) {
239 	    error("%s: ncdiminq (data mode), size %d, expected %d for id = %d",
240 		pname, dim.size, test.dims[dimid].size, dimid);
241 	    nerrs++;
242 	}
243     }
244     if (ncredef(cdfid) == -1) {
245 	error("%s: ncredef failed", pname);
246 	ncclose(cdfid); return ++nerrs;
247     }
248     /* in define mode, compare returned with expected values again */
249     for (dimid = 0 ; dimid < test.ndims; dimid++) { /* loop on all dim ids */
250 	if (ncdiminq(cdfid, dimid, dim.name, &dim.size) == -1) {
251 	    error("%s: ncdiminq in define mode failed on dim id %d",
252 		  pname, dimid);
253 	    ncclose(cdfid); return ++nerrs;
254 	}
255 	/* compare returned with expected values */
256 	if (strcmp(dim.name, test.dims[dimid].name) != 0) {
257 	    error("%s: ncdiminq (define), name %s, expected %s for id = %d",
258 		pname, dim.name, test.dims[dimid].name, dimid);
259 	    nerrs++;
260 	}
261 	if (dim.size != test.dims[dimid].size) {
262 	    error("%s: ncdiminq (define), size %d, expected %d for id = %d",
263 		pname, dim.size, test.dims[dimid].size, dimid);
264 	    nerrs++;
265 	}
266     }
267     /* try with bad dimension handles, check for failure */
268     if (ncdiminq(cdfid, -1, dim.name, &dim.size) != -1 ||
269 	ncdiminq(cdfid, test.ndims, dim.name, &dim.size) != -1) {
270 	error("%s: ncdiminq should have failed on bad dimension ids",
271 	      pname, dimid);
272 	ncclose(cdfid); return ++nerrs;
273     }
274     if (ncendef (cdfid) == -1) {
275 	error("%s: ncendef failed", pname);
276 	ncclose(cdfid); return ++nerrs;
277     }
278     if (ncclose (cdfid) == -1) {
279 	error("%s: ncclose failed", pname);
280 	return ++nerrs;
281     }
282     /* should fail, since bad handle */
283     if (test.ndims >= 1) {	/* if any dimensions have been defined */
284 	if (ncdiminq (cdfid, 0, dim.name, &dim.size) != -1) {
285 	    error("%s: ncdiminq failed to report bad netcdf handle ", pname);
286 	    nerrs++;
287 	}
288     }
289     free(dim.name);
290     if (nerrs > 0)
291       (void) fprintf(stderr,"FAILED! ***\n");
292     else
293       (void) fprintf(stderr,"ok ***\n");
294 
295     return nerrs;
296 }
297 
298 /*
299  * Test ncdimrename
300  *    check that proper rename worked with ncdiminq
301  *    try renaming to existing dimension name, check error
302  *    try with bad dimension handle, check error
303  *    try with bad netCDF handle, check error
304  */
305 int
test_ncdimrename(path)306 test_ncdimrename(path)
307      const char *path;		/* name of writable netcdf file to open */
308 {
309     int nerrs = 0;
310     static char pname[] = "test_ncdimrename";
311     int cdfid;			/* netcdf id */
312     int pp_dim;			/* dimension id */
313     static struct cdfdim pp =	/* dimension */
314       {"pp", 7};
315     static char newname[MAX_NC_NAME] = /* dimension name */
316       "new_name";
317     struct cdfdim dim;		/* dimension */
318     static struct cdfdim qq =	/* dimension */
319       {"qq", 10};
320 
321     (void) fprintf(stderr, "*** Testing %s ...\t", &pname[5]);
322 
323     if ((cdfid = ncopen(path, NC_WRITE)) == -1) {
324 	error("%s: ncopen failed", pname);
325 	return ++nerrs;
326     }
327     /* opened */
328     if (ncredef(cdfid) == -1) {
329 	error("%s: ncredef failed", pname);
330 	ncclose(cdfid); return ++nerrs;
331     }
332     /* in define mode, add two dimensions */
333     if ((pp_dim = ncdimdef(cdfid, pp.name, pp.size)) == -1) {
334 	error("%s: ncdimdef failed", pname);
335 	ncclose(cdfid); return ++nerrs;
336     }
337     add_dim(&test, &pp);	/* keep in-memory netcdf in sync */
338     if (ncdimdef(cdfid, qq.name, qq.size) == -1) {
339 	error("%s: ncdimdef failed", pname);
340 	ncclose(cdfid); return ++nerrs;
341     }
342     add_dim(&test, &qq);	/* keep in-memory netcdf in sync */
343     /* rename first dimension */
344     if (ncdimrename(cdfid, pp_dim, newname) == -1) {
345 	error("%s: ncdimrename failed", pname);
346 	ncclose(cdfid); return ++nerrs;
347     }
348     /* check new name with ncdiminq */
349     dim.name = (char *) emalloc(MAX_NC_NAME);
350     if (ncdiminq(cdfid, pp_dim, dim.name, &dim.size) == -1) {
351 	error("%s: ncdiminq failed", pname);
352 	ncclose(cdfid); return ++nerrs;
353     }
354     if (strcmp(dim.name,pp.name) == 0) {
355 	error("%s: ncdimrename failed to change name", pname);
356 	ncclose(cdfid); return ++nerrs;
357     }
358     if (strcmp(dim.name,newname) != 0) {
359 	error("%s: ncdimrename changed name to %s instead of %s",
360 	      pname, dim.name, newname);
361 	ncclose(cdfid); return ++nerrs;
362     }
363     test.dims[pp_dim].name = (char *) erealloc((void *)test.dims[pp_dim].name,
364 					      strlen(newname)+1);
365     (void) strcpy(test.dims[pp_dim].name, newname); /* keep test consistent */
366     /* try to rename first dimension same as second, should fail */
367     if (ncdimrename(cdfid, pp_dim, qq.name) != -1) {
368 	error("%s: ncdimrename should have failed with used name", pname);
369 	ncclose(cdfid); return ++nerrs;
370     }
371     /* try with bad dimension handles, check for failure */
372     if (ncdimrename(cdfid, -1, dim.name) != -1 ||
373 	ncdimrename(cdfid, test.ndims, dim.name) != -1) {
374 	error("%s: ncdimrename should have failed on bad dimension ids",
375 	      pname);
376 	ncclose(cdfid); return ++nerrs;
377     }
378     if (ncendef (cdfid) == -1) {
379 	error("%s: ncendef failed", pname);
380 	ncclose(cdfid); return ++nerrs;
381     }
382 
383     /* in data mode, rename to shorter name */
384     if (ncdimrename(cdfid, pp_dim, "p") == -1) {
385 	error("%s: ncdimrename to shorter name failed in data mode", pname);
386 	ncclose(cdfid); return ++nerrs;
387     }
388     test.dims[pp_dim].name = (char *) erealloc((void *)test.dims[pp_dim].name,
389 					      strlen("p")+1);
390     (void) strcpy(test.dims[pp_dim].name, "p"); /* keep test consistent */
391     /* Check with ncdimid */
392     if (pp_dim != ncdimid(cdfid, "p")) {
393 	error("%s: lookup by name in data mode failed after ncdimrename",
394 	      pname);
395 	return ++nerrs;
396     }
397     /* in data mode, restore old name */
398     if (ncdimrename(cdfid, pp_dim, pp.name) == -1) {
399 	error("%s: ncdimrename failed in data mode", pname);
400 	ncclose(cdfid); return ++nerrs;
401     }
402     test.dims[pp_dim].name = (char *) erealloc((void *)test.dims[pp_dim].name,
403 					      strlen(pp.name)+1);
404     (void) strcpy(test.dims[pp_dim].name, pp.name); /* keep test consistent */
405     if (ncclose (cdfid) == -1) {
406 	error("%s: ncclose failed", pname);
407 	return ++nerrs;
408     }
409     /* should fail, since bad handle */
410     if (ncdimrename (cdfid, 0, dim.name) != -1) {
411 	error("%s: ncdimrename failed to report bad netcdf handle ", pname);
412 	nerrs++;
413     }
414     free (dim.name);
415     if (nerrs > 0)
416       (void) fprintf(stderr,"FAILED! ***\n");
417     else
418       (void) fprintf(stderr,"ok ***\n");
419 
420     return nerrs;
421 }
422