1 /*
2 * Copyright (C) 2015, Northwestern University and Argonne National Laboratory
3 * See COPYRIGHT notice in top-level directory.
4 *
5 * $Id$
6 */
7
8 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
9 *
10 * This program tests whether NC_ERANGE error code can be reported correctly.
11 * Note in CDF-1 and CDF-2, a special case is made to NOT report NC_ERANGE
12 * when the variable is of NC_BYTE type and the calling APIs are of uchar. See
13 * http://www.unidata.ucar.edu/software/netcdf/docs/data_type.html#type_conversion
14 *
15 * In CDF-5, NC_ERANGE is checked for when the external data type mismatches the
16 * internal one.
17 *
18 * The test uses the following 2 case.
19 * 1. get a value of 255 from a NC_UBYTE variable defined in a netCDF file to a
20 * memory buffer of signed char through e.g. API ncmpi_get_var_schar_all
21 * 2. put a value of -1 of signed char from an in-memory buffer to a NC_UBYTE
22 * variable defined in a netCDF file
23 *
24 * The compile and run commands are given below.
25 *
26 * % mpicc -g -o test_erange test_erange.c -lpnetcdf
27 *
28 * % mpiexec -l -n 1 test_erange testfile.nc
29 *
30 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <libgen.h> /* basename() */
35 #include <pnetcdf.h>
36
37 #include <testutils.h>
38
39 #define ERR if (err!=NC_NOERR) {printf("Error at line %d: %s\n",__LINE__,ncmpi_strerror(err));nerrs++;}
40 #define EXPECT_ERR if (err != NC_ERANGE) {printf("Error at line %d: expecting NC_ERANGE, but got %d\n",__LINE__,err);nerrs++;}
41
42 static
test_cdf2(char * filename)43 int test_cdf2(char *filename)
44 {
45 int err, nerrs=0, ncid, vid, dimid;
46 unsigned char uc[1];
47 signed char sc[1];
48 int si[1];
49
50 err = ncmpi_create(MPI_COMM_WORLD, filename, NC_CLOBBER, MPI_INFO_NULL, &ncid); ERR
51
52 /* for CDF-1 and CDF-2, a special case is made: there is no NC_ERANGE
53 * error can occur converting between NC_BYTE and unsigned char.
54 * http://www.unidata.ucar.edu/software/netcdf/docs/data_type.html#type_conversion
55 * In brief, NC_BYTE is signed in all signed CDF-2 APIs, and unsigned in
56 * all unsigned APIs. In CDF-2, there is only one unsigned API, _uchar.
57 */
58 uc[0] = 255;
59 err = ncmpi_put_att_uchar(ncid, NC_GLOBAL, "att1", NC_BYTE, 1, uc); ERR
60 uc[0] = 0; /* initialize with a number that is not 0 */
61 err = ncmpi_get_att_uchar(ncid, NC_GLOBAL, "att1", uc); ERR
62 if (uc[0] != 255) {
63 printf("Error at line %d: unexpected read value %d (expecting 255)\n",__LINE__,(int)uc[0]);
64 nerrs++;
65 }
66 sc[0] = 3; /* initialize with a number that is not -1 or -0 */
67 /* No NC_ERANGE as the internal and external types are considered the same */
68 err = ncmpi_get_att_schar(ncid, NC_GLOBAL, "att1", sc); ERR
69 if ( sc[0] != -1 /* 2-complement bit representation */
70 && sc[0] != -0) { /* 1-complement bit representation */
71 printf("Error at line %d: unexpected read value %d (expecting 255)\n",__LINE__,(int)uc[0]);
72 nerrs++;
73 }
74
75 err = ncmpi_def_dim(ncid, "x", 1, &dimid); ERR
76 err = ncmpi_def_var(ncid, "var_byte", NC_BYTE, 1, &dimid, &vid); ERR
77 err = ncmpi_enddef(ncid); ERR
78
79 /* No NC_ERANGE should be returned for CDF-1 and 2 */
80 uc[0] = 255;
81 err = ncmpi_put_var_uchar_all(ncid, vid, uc); ERR
82 uc[0] = 3; /* initialize with a number that is not -1 or -0 */
83 err = ncmpi_get_var_uchar_all(ncid, vid, uc); ERR
84 if (uc[0] != 255) {
85 printf("Error at line %d: unexpected read value %d (expecting 255)\n",__LINE__,(int)uc[0]);
86 nerrs++;
87 }
88
89 /* No NC_ERANGE should be returned for CDF-1 and 2 */
90 sc[0] = -128;
91 err = ncmpi_put_var_schar_all(ncid, vid, sc); ERR
92 sc[0] = 0;
93 err = ncmpi_get_var_schar_all(ncid, vid, sc); ERR
94 if (sc[0] != -128) {
95 printf("Error at line %d: unexpected read value %d (expecting -128)\n",__LINE__,(int)sc[0]);
96 nerrs++;
97 }
98
99 /* expect NC_ERANGE */
100 si[0] = -129;
101 err = ncmpi_put_var_int_all(ncid, vid, si); EXPECT_ERR
102 if (si[0] != -129) { /* check if put buffer content is altered */
103 printf("Error at line %d: put buffer content altered %d (expecting -128)\n",__LINE__,si[0]);
104 nerrs++;
105 }
106
107 /* expect NC_ERANGE */
108 si[0] = 256;
109 err = ncmpi_put_var_int_all(ncid, vid, si); EXPECT_ERR
110 if (si[0] != 256) { /* check if put buffer content is altered */
111 printf("Error at line %d: put buffer content altered %d (expecting 256)\n",__LINE__,si[0]);
112 nerrs++;
113 }
114
115 /* expect no error */
116 si[0] = -128;
117 err = ncmpi_put_var_int_all(ncid, vid, si); ERR
118 si[0] = 0;
119 err = ncmpi_get_var_int_all(ncid, vid, si); ERR
120 if (si[0] != -128) {
121 printf("Error at line %d: unexpected read value %d (expecting -128)\n",__LINE__,si[0]);
122 nerrs++;
123 }
124
125 err = ncmpi_close(ncid); ERR
126
127 return nerrs;
128 }
129
130 static
test_cdf5(char * filename)131 int test_cdf5(char *filename)
132 {
133 int err, nerrs=0, ncid, uc_vid, sc_vid, dimid;
134 unsigned char uc[1];
135 signed char sc[1];
136
137 err = ncmpi_create(MPI_COMM_WORLD, filename, NC_CLOBBER|NC_64BIT_DATA, MPI_INFO_NULL, &ncid); ERR
138
139 /* CDF-5 considers NC_BYTE a signed 1-byte integer and NC_UBYTE an
140 * unsigned 1-byte integer. The special case in CDF-2 for skipping
141 * NC_ERANGE checking for converting between NC_BYTE and unsigned
142 * char is no longer held.
143 */
144 uc[0] = 255;
145 err = ncmpi_put_att_uchar(ncid, NC_GLOBAL, "att1", NC_UBYTE, 1, uc); ERR
146
147 /* in CDF-5, get 255 to a schar buffer should result in NC_ERANGE */
148 err = ncmpi_get_att_schar(ncid, NC_GLOBAL, "att1", sc); EXPECT_ERR
149
150 sc[0] = -1; /* a value should cause NC_ERANGE */
151 err = ncmpi_put_att_schar(ncid, NC_GLOBAL, "att2", NC_UBYTE, 1, sc); EXPECT_ERR
152
153 err = ncmpi_def_dim(ncid, "x", 1, &dimid); ERR
154 err = ncmpi_def_var(ncid, "var_ubyte", NC_UBYTE, 1, &dimid, &uc_vid); ERR
155 err = ncmpi_def_var(ncid, "var_byte", NC_BYTE, 1, &dimid, &sc_vid); ERR
156 err = ncmpi_enddef(ncid); ERR
157
158 uc[0] = 255;
159 err = ncmpi_put_var_uchar_all(ncid, uc_vid, uc); ERR
160
161 /* in CDF-5, get 255 to an schar should result in NC_ERANGE */
162 err = ncmpi_get_var_schar_all(ncid, uc_vid, sc); EXPECT_ERR
163
164 sc[0] = -1; /* in CDF-5, put -1 to an uchar should result in NC_ERANGE */
165 err = ncmpi_put_var_schar_all(ncid, uc_vid, sc); EXPECT_ERR
166
167 uc[0] = 255; /* in CDF-5, put 255 to a schar should result in NC_ERANGE */
168 err = ncmpi_put_var_uchar_all(ncid, sc_vid, uc); EXPECT_ERR
169
170 sc[0] = -1;
171 err = ncmpi_put_var_schar_all(ncid, sc_vid, sc); ERR
172 uc[0] = 0; /* in CDF-5, get -1 to an uchar should result in NC_ERANGE */
173 err = ncmpi_get_var_uchar_all(ncid, sc_vid, uc); EXPECT_ERR
174
175 err = ncmpi_close(ncid); ERR
176
177 return nerrs;
178 }
179
main(int argc,char * argv[])180 int main(int argc, char* argv[])
181 {
182 char filename[256];
183 int err, nerrs=0, rank;
184
185 MPI_Init(&argc, &argv);
186 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
187
188 if (argc > 2) {
189 if (!rank) printf("Usage: %s [filename]\n",argv[0]);
190 MPI_Finalize();
191 return 0;
192 }
193 if (argc == 2) snprintf(filename, 256, "%s", argv[1]);
194 else strcpy(filename, "testfile.nc");
195 MPI_Bcast(filename, 256, MPI_CHAR, 0, MPI_COMM_WORLD);
196
197 if (rank == 0) {
198 char *cmd_str = (char*)malloc(strlen(argv[0]) + 256);
199 sprintf(cmd_str, "*** TESTING C %s for checking for NC_ERANGE ", basename(argv[0]));
200 printf("%-66s ------ ", cmd_str); fflush(stdout);
201 free(cmd_str);
202 }
203
204 nerrs += test_cdf2(filename);
205 nerrs += test_cdf5(filename);
206
207 /* check if PnetCDF freed all internal malloc */
208 MPI_Offset malloc_size, sum_size;
209 err = ncmpi_inq_malloc_size(&malloc_size);
210 if (err == NC_NOERR) {
211 MPI_Reduce(&malloc_size, &sum_size, 1, MPI_OFFSET, MPI_SUM, 0, MPI_COMM_WORLD);
212 if (rank == 0 && sum_size > 0)
213 printf("heap memory allocated by PnetCDF internally has %lld bytes yet to be freed\n",
214 sum_size);
215 }
216
217 MPI_Allreduce(MPI_IN_PLACE, &nerrs, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
218 if (rank == 0) {
219 if (nerrs) printf(FAIL_STR,nerrs);
220 else printf(PASS_STR);
221 }
222
223 MPI_Finalize();
224
225 return 0;
226 }
227