1 /* This is part of the netCDF package. Copyright 2005-2018 University
2    Corporation for Atmospheric Research/Unidata. See COPYRIGHT file
3    for conditions of use.
4 
5    Test handling of formats.
6 
7    Ed Hartnett, 11/22/17
8 */
9 
10 #include "config.h"
11 #include <nc_tests.h>
12 #include "err_macros.h"
13 
14 #define FILE_NAME_BASE "tst_formats"
15 #define HDF4_FILE "ref_contiguous.hdf4"
16 #define NDIM1 1
17 #define DIM_LEN 10
18 #define VAR_NAME "Copernicus_var"
19 #define DIM_NAME "Copernicus_dim"
20 #define NUM_FILL_WRITE_TESTS 2
21 #define NUM_FILL_WRITE_METHOD_TESTS 2
22 
23 /* Determine how many formats are available, and what they are. */
24 void
determine_test_formats(int * num_formats,int * format)25 determine_test_formats(int *num_formats, int *format)
26 {
27    int ind = 0;
28    int num;
29 
30    /* Check inputs. */
31    assert(num_formats && format);
32 
33    /* We always have classic and 64-bit offset */
34    num = 2;
35    format[ind++] = NC_FORMAT_CLASSIC;
36    format[ind++] = NC_FORMAT_64BIT_OFFSET;
37 
38    /* Do we have netCDF-4 and netCDF-4 classic? */
39 #ifdef USE_HDF5
40    num += 2;
41    format[ind++] = NC_FORMAT_NETCDF4;
42    format[ind++] = NC_FORMAT_NETCDF4_CLASSIC;
43 #endif /* USE_HDF5 */
44 
45    /* Do we have CDF5? */
46 #ifdef ENABLE_CDF5
47    num++;
48    format[ind++] = NC_FORMAT_CDF5;
49 #endif /* ENABLE_CDF5 */
50 
51    *num_formats = num;
52 }
53 
54 /* Function to test nc_inq_format(). */
55 int
check_inq_format(int ncid,int expected_format,int expected_extended_format,int expected_mode)56 check_inq_format(int ncid, int expected_format, int expected_extended_format, int expected_mode)
57 {
58    int format;
59    int extended_format;
60    int mode;
61 
62    if (nc_inq_format(ncid + 66000, NULL) != NC_EBADID) ERR;
63    if (nc_inq_format(ncid, NULL)) ERR;
64    if (nc_inq_format(ncid, &format)) ERR;
65    if (format != expected_format) {
66       printf("format %d expected_format %d\n", format, expected_format);
67       ERR;
68    }
69    if (nc_inq_format_extended(ncid + 66000, &extended_format, &mode) != NC_EBADID) ERR;
70    {
71       int mode;
72       if (nc_inq_format_extended(ncid, NULL, &mode)) ERR;
73       if (mode != expected_mode) {
74          printf("expected_mode %x mode %x\n", expected_mode, mode);
75          /*ERR;*/
76       }
77    }
78    {
79       int extended_format;
80       if (nc_inq_format_extended(ncid, &extended_format, NULL)) ERR;
81       if (extended_format != expected_extended_format) ERR;
82    }
83 
84    if (nc_inq_format_extended(ncid, &extended_format, &mode)) ERR;
85    if (mode != expected_mode) ERR;
86    if (extended_format != expected_extended_format) ERR;
87 
88    /* Nothing to do with inq_format, but let's check the base_pe
89     * functions. */
90    if (nc_set_base_pe(ncid, 0)) ERR;
91    if (nc_inq_base_pe(ncid, NULL)) ERR;
92 
93    return 0;
94 }
95 
96 int
main(int argc,char ** argv)97 main(int argc, char **argv)
98 {
99    printf("\n*** Testing netcdf format functions.\n");
100    {
101       int ncid;
102       int f, d, a;
103       int format[MAX_NUM_FORMATS];
104       int num_formats;
105       int ret;
106 
107       /* How many formats to be tested? */
108       determine_test_formats(&num_formats, format);
109 
110       for (f = 0; f < num_formats; f++)
111       {
112          printf("*** testing nc_inq_format() and nc_inq_format_extended() with format %d...", format[f]);
113          {
114             char file_name[NC_MAX_NAME + 1];
115             int expected_mode;
116             int expected_extended_format;
117 
118             sprintf(file_name, "%s_%d.nc", FILE_NAME_BASE, format[f]);
119 
120             /* Set up test. */
121             switch (format[f]) {
122             case NC_FORMAT_CLASSIC:
123                expected_extended_format = NC_FORMATX_NC3;
124                expected_mode = 0;
125                break;
126             case NC_FORMAT_64BIT_OFFSET:
127                expected_extended_format = NC_FORMATX_NC3;
128                expected_mode = NC_64BIT_OFFSET;
129                break;
130             case NC_FORMAT_CDF5:
131                expected_extended_format = NC_FORMATX_NC3;
132                expected_mode = NC_CDF5;
133                break;
134             case NC_FORMAT_NETCDF4:
135                expected_extended_format = NC_FORMATX_NC4;
136                expected_mode = NC_NETCDF4;
137                break;
138             case NC_FORMAT_NETCDF4_CLASSIC:
139                expected_extended_format = NC_FORMATX_NC4;
140                expected_mode = NC_NETCDF4|NC_CLASSIC_MODEL;
141                break;
142             }
143             if (nc_set_default_format(format[f], NULL)) ERR;
144 
145             /* Create a file. */
146             if (nc_create(file_name, 0, &ncid)) ERR;
147             if (check_inq_format(ncid, format[f], expected_extended_format, expected_mode)) ERR;
148             if (nc_close(ncid)) ERR;
149 
150             /* Re-open the file and check it again. */
151             if (nc_open(file_name, 0, &ncid)) ERR;
152             /* Classic flag is not set on mode in nc_open(). Not sure if
153              * this is a bug or not. */
154             if (format[f] == NC_FORMAT_NETCDF4_CLASSIC)
155                expected_mode = NC_NETCDF4;
156             if (check_inq_format(ncid, format[f], expected_extended_format, expected_mode)) ERR;
157             if (nc_close(ncid)) ERR;
158          }
159          SUMMARIZE_ERR;
160          /* Test without and with actual data write. */
161          for (d = 0; d < NUM_FILL_WRITE_TESTS; d++)
162          {
163             /* Test setting _FillValue directly or calling nc_def_var_fill(). */
164             for (a = 0; a < NUM_FILL_WRITE_METHOD_TESTS; a++)
165             {
166                printf("*** testing late fill handling with format %d writing %d "
167                       "using def_var_fill %d...", format[f], d, a);
168                char file_name[NC_MAX_NAME + 1];
169                int dimid, varid;
170                size_t index = {DIM_LEN - 1};
171                int data = TEST_VAL_42;
172                int data_in;
173                int fill_value = TEST_VAL_42 * 2;
174 
175                /* Try to set fill mode after data have been written. */
176                sprintf(file_name, "%s_%d_%d_%d_elatefill.nc", FILE_NAME_BASE, format[f], d, a);
177                if (nc_set_default_format(format[f], NULL)) ERR;
178                if (nc_create(file_name, 0, &ncid)) ERR;
179                if (nc_def_dim(ncid, DIM_NAME, DIM_LEN, &dimid)) ERR;
180                if (nc_def_var(ncid, VAR_NAME, NC_INT, NDIM1, &dimid, &varid)) ERR;
181                if (nc_enddef(ncid)) ERR;
182                /* For netCDF-4, we don't actually have to write data to
183                 * prevent future setting of the fill value. Once the user
184                 * leaves calls enddef after defining a var, fill values
185                 * can no longer be set. */
186                if (d)
187                   if (nc_put_var1_int(ncid, varid, &index, &data)) ERR;
188                if (nc_redef(ncid)) ERR;
189                if (a)
190                {
191                   ret = nc_def_var_fill(ncid, varid, NC_FILL, &fill_value);
192                }
193                else
194                {
195                   ret = nc_put_att_int(ncid, varid, "_FillValue", NC_INT, 1,
196                                        &fill_value);
197                }
198 
199                /* Setting the fill value after data are written is
200                 * allowed in classic formats, but not netcdf-4. */
201                if (format[f] == NC_FORMAT_CLASSIC || format[f] == NC_FORMAT_64BIT_OFFSET ||
202                    format[f] == NC_FORMAT_CDF5)
203                {
204                   if (ret) ERR;
205                }
206                else
207                {
208                   if (ret != (a ? NC_ELATEDEF: NC_ELATEFILL)) ERR;
209                }
210                if (nc_enddef(ncid)) ERR;
211                if (nc_close(ncid)) ERR;
212 
213                /* Open the file and check data. */
214                if (nc_open(file_name, NC_NOWRITE, &ncid)) ERR;
215                if (nc_get_var1_int(ncid, varid, &index, &data_in)) ERR;
216                if (data_in != (d ? data : NC_FILL_INT)) ERR;
217                if (nc_close(ncid)) ERR;
218                SUMMARIZE_ERR;
219             } /* next fill value method test */
220          } /* next fill val write test */
221 
222 #define NDIM2 2
223 #define DIM1_NAME "dim1"
224 #define DIM2_NAME "dim2"
225 #define NTYPE 6
226 #define DATA_LEN 4
227 
228          printf("*** testing handling of null strides with format %d... ",
229                 format[f]);
230          {
231             char file_name[NC_MAX_NAME + 1];
232             char var_name[NC_MAX_NAME + 1];
233             int dimid[NDIM2];
234             int xtype[NTYPE] = {NC_BYTE, NC_CHAR, NC_SHORT, NC_INT, NC_FLOAT, NC_DOUBLE};
235             int type_size[NTYPE] = {1, 1, 2, 4, 4, 8};
236             int varid[NTYPE];
237             size_t start[NDIM2] = {0, 0};
238             size_t count[NDIM2] = {2, 2};
239             signed char data_byte[DATA_LEN] = {1, 2, 3, 4};
240             unsigned char data_char[DATA_LEN] = {1, 2, 3, 4};
241             short data_short[DATA_LEN] = {1, 2, 3, 4};
242             int data_int[DATA_LEN] = {1, 2, 3, 4};
243             float data_float[DATA_LEN] = {1, 2, 3, 4};
244             double data_double[DATA_LEN] = {1, 2, 3, 4};
245             void *data_ptr[NTYPE] = {data_byte, data_char, data_short, data_int, data_float, data_double};
246             int t;
247 
248             /* Create the test file. */
249             sprintf(file_name, "%s_%d_null_strides.nc", FILE_NAME_BASE, format[f]);
250             if (nc_set_default_format(format[f], NULL)) ERR;
251             if (nc_create(file_name, 0, &ncid)) ERR;
252             if (nc_def_dim(ncid, DIM1_NAME, DIM_LEN, &dimid[0])) ERR;
253             if (nc_def_dim(ncid, DIM2_NAME, DIM_LEN, &dimid[1])) ERR;
254             for (t = 0; t < NTYPE; t++)
255             {
256                sprintf(var_name, "var_%d", xtype[t]);
257                if (nc_def_var(ncid, var_name, xtype[t], NDIM2, dimid, &varid[t])) ERR;
258             }
259             if (nc_enddef(ncid)) ERR;
260 
261             /* Write some data. */
262             for (t = 0; t < NTYPE; t++)
263             {
264                if (nc_put_vars(ncid, varid[t], start, count, NULL, data_ptr[t])) ERR;
265             }
266             if (nc_close(ncid)) ERR;
267 
268             /* Open the file and check data. */
269             {
270                int ndims, nvars, ngatts, unlimdimid;
271 
272                if (nc_open(file_name, NC_NOWRITE, &ncid)) ERR;
273                if (nc_inq(ncid, &ndims, &nvars, &ngatts, &unlimdimid)) ERR;
274                if (ndims != 2 || nvars != NTYPE || ngatts != 0 || unlimdimid != -1) ERR;
275                for (t = 0; t < NTYPE; t++)
276                {
277                   nc_type my_type;
278                   int var_ndims, natts;
279                   int var_dimid[NDIM2];
280                   void *data_in;
281 
282                   if (nc_inq_var(ncid, varid[t], NULL, &my_type, &var_ndims, var_dimid, &natts)) ERR;
283                   if (my_type != xtype[t] || var_ndims != 2 || var_dimid[0] != dimid[0] ||
284                       var_dimid[1] != dimid[1] || natts != 0) ERR;
285                   if (!(data_in = malloc(DATA_LEN * type_size[t]))) ERR;
286                   if (nc_get_vars(ncid, varid[t], start, count, NULL, data_in)) ERR;
287                   if (memcmp(data_in, data_ptr[t], DATA_LEN * type_size[t])) ERR;
288                   free(data_in);
289 
290                }
291                if (nc_close(ncid)) ERR;
292             }
293 
294          }
295          SUMMARIZE_ERR;
296          printf("*** testing bad name for nc_open/nc_create with format %d... ", format[f]);
297          {
298              int ncid;
299              if (nc_set_default_format(format[f], NULL)) ERR;
300              if (nc_create(NULL, 0, &ncid) != NC_EINVAL) ERR;
301              if (nc_open(NULL, NC_NOWRITE, &ncid) != NC_EINVAL) ERR;
302              if (nc_delete(NULL) != NC_EINVAL) ERR;
303          }
304          SUMMARIZE_ERR;
305       } /* next format */
306    }
307    FINAL_RESULTS;
308 }
309