1 /* This is part of the netCDF package.
2    Copyright 2005 University Corporation for Atmospheric Research/Unidata
3    See COPYRIGHT file for conditions of use.
4 
5    Test data conversions and fill value handling.
6 
7    $Id: tst_converts.c,v 1.16 2008/10/20 01:48:09 ed Exp $
8 */
9 
10 #include <nc_tests.h>
11 #include "err_macros.h"
12 #include "netcdf.h"
13 
14 #define FILE_NAME "tst_converts.nc"
15 #define ATT1_NAME "att1"
16 #define ATT2_NAME "att2"
17 #define DIM1_NAME "dim1"
18 #define DIM1_LEN 3
19 #define DIM2_NAME "dim2"
20 #define DIM2_LEN 15
21 #define VAR1_NAME "var1"
22 #define VAR2_NAME "var2"
23 
24 /* This is handy for print statements. */
25 static char *format_name[MAX_NUM_FORMATS] = {"classic", "64-bit offset", "netCDF-4",
26                                              "netCDF-4 classic model", "CDF5"};
27 
28 int check_file(int format, unsigned char *uchar_out);
29 int create_file(int format, unsigned char *uchar_out);
30 
31 /* Determine how many formats are available, and what they are. */
32 void
determine_test_formats(int * num_formats,int * format)33 determine_test_formats(int *num_formats, int *format)
34 {
35    int ind = 0;
36    int num;
37 
38    /* Check inputs. */
39    assert(num_formats && format);
40 
41    /* We always have classic and 64-bit offset */
42    num = 2;
43    format[ind++] = NC_FORMAT_CLASSIC;
44    format[ind++] = NC_FORMAT_64BIT_OFFSET;
45 
46    /* Do we have netCDF-4 and netCDF-4 classic? */
47 #ifdef USE_NETCDF4
48    num += 2;
49    format[ind++] = NC_FORMAT_NETCDF4_CLASSIC;
50    format[ind++] = NC_FORMAT_NETCDF4;
51 #endif /* USE_NETCDF4 */
52 
53    /* Do we have CDF5? */
54 #ifdef ENABLE_CDF5
55    num++;
56    format[ind++] = NC_FORMAT_CDF5;
57 #endif /* ENABLE_CDF5 */
58 
59    *num_formats = num;
60 }
61 
62 int
main(int argc,char ** argv)63 main(int argc, char **argv)
64 {
65    unsigned char uchar_out[DIM1_LEN] = {0, 128, 255};
66    int format[MAX_NUM_FORMATS];
67    int num_formats;
68    int f = 0;
69 
70    printf("\n*** Testing netcdf data conversion.\n");
71    determine_test_formats(&num_formats, format);
72 
73    for (f = 0; f < num_formats; f++)
74    {
75       printf("*** Testing conversion in netCDF %s files... ", format_name[f]);
76       create_file(format[f], uchar_out);
77       check_file(format[f], uchar_out);
78       SUMMARIZE_ERR;
79    }
80 
81    FINAL_RESULTS;
82 }
83 
84 /* Create a test file with one var of type NC_BYTE. */
85 int
create_file(int format,unsigned char * uchar_out)86 create_file(int format, unsigned char *uchar_out)
87 {
88    int ncid, varid, cflags=0, dimids[1];
89    int retval;
90 
91    if (format == NC_FORMAT_64BIT_OFFSET)
92       cflags |= NC_64BIT_OFFSET;
93    else if (format == NC_FORMAT_CDF5)
94       cflags |= NC_CDF5;
95    else if (format == NC_FORMAT_NETCDF4_CLASSIC)
96    {
97       cflags |= (NC_NETCDF4|NC_CLASSIC_MODEL);
98    }
99    else if (format == NC_FORMAT_NETCDF4)
100       cflags |= NC_NETCDF4;
101 
102    if (nc_create(FILE_NAME, cflags, &ncid)) ERR;
103    if (nc_def_dim(ncid, DIM1_NAME, DIM1_LEN, &dimids[0])) ERR;
104    if (nc_def_var(ncid, VAR1_NAME, NC_BYTE, 1, dimids, &varid)) ERR;
105    if (nc_enddef(ncid)) ERR;
106    retval = nc_put_var_uchar(ncid, varid, uchar_out);
107    if (format == NC_FORMAT_NETCDF4 || format == NC_FORMAT_64BIT_DATA)
108    {
109       if (retval != NC_ERANGE) ERR;
110    }
111    else if (retval != NC_NOERR) ERR;
112 
113    if (nc_close(ncid)) ERR;
114    return NC_NOERR;
115 }
116 
117 int
check_file(int format,unsigned char * uchar_out)118 check_file(int format, unsigned char *uchar_out)
119 {
120    int ncid;
121    int ndims, natts;
122    int dimids_var[1], var_type;
123    char var_name[NC_MAX_NAME+1];
124    unsigned char uchar_in[DIM1_LEN];
125    signed char char_in[DIM1_LEN];
126    unsigned short ushort_in[DIM1_LEN];
127    short short_in[DIM1_LEN];
128    unsigned int uint_in[DIM1_LEN];
129    int int_in[DIM1_LEN];
130    long long int64_in[DIM1_LEN];
131    unsigned long long uint64_in[DIM1_LEN];
132    int i, res;
133 
134    /* Read it back in, and check conversions. */
135    if (nc_open(FILE_NAME, NC_NOWRITE, &ncid)) ERR;
136    if (nc_inq_var(ncid, 0, var_name, &var_type, &ndims, dimids_var, &natts)) ERR;
137    if (strcmp(var_name, VAR1_NAME) || natts !=0 || ndims != 1 ||
138        dimids_var[0] != 0 || var_type != NC_BYTE) ERR;
139 
140    /* This is actually an NC_BYTE, with some negatives, so this should
141     * generate a range error for netcdf-4, but not for netcdf-3,
142     * because range errors are not generated for byte type
143     * conversions. */
144    res = nc_get_var_uchar(ncid, 0, uchar_in);
145    if (format == NC_FORMAT_NETCDF4 || format == NC_FORMAT_64BIT_DATA)
146    {
147       if (res != NC_ERANGE) ERR;
148    }
149    else if (res) ERR;
150 
151    for (i=0; i<DIM1_LEN; i++)
152 #ifdef ERANGE_FILL
153       if (uchar_in[i] != uchar_out[i] && uchar_in[i] != NC_FILL_UBYTE) ERR;
154 #else
155       if (uchar_in[i] != uchar_out[i]) ERR;
156 #endif
157 
158    if (nc_get_var_schar(ncid, 0, char_in)) ERR;
159    for (i=0; i<DIM1_LEN; i++)
160 #ifdef ERANGE_FILL
161       if (char_in[i] != (signed char)uchar_out[i] && char_in[i] != NC_FILL_BYTE) ERR;
162 #else
163       if (char_in[i] != (signed char)uchar_out[i]) ERR;
164 #endif
165 
166    if (nc_get_var_short(ncid, 0, short_in)) ERR;
167    for (i=0; i<DIM1_LEN; i++)
168 #ifdef ERANGE_FILL
169       if (short_in[i] != (signed char)uchar_out[i] && short_in[i] != NC_FILL_BYTE) ERR;
170 #else
171       if (short_in[i] != (signed char)uchar_out[i]) ERR;
172 #endif
173 
174    if (nc_get_var_int(ncid, 0, int_in)) ERR;
175    for (i=0; i<DIM1_LEN; i++)
176 #ifdef ERANGE_FILL
177       if (int_in[i] != (signed char)uchar_out[i] && int_in[i] != NC_FILL_BYTE) ERR;
178 #else
179       if (int_in[i] != (signed char)uchar_out[i]) ERR;
180 #endif
181 
182    if (format == NC_FORMAT_NETCDF4 || format == NC_FORMAT_NETCDF4_CLASSIC)
183    {
184       /* Since we wrote them as NC_BYTE, some of these are negative
185        * values, and will return a range error when reading into
186        * unsigned type. To compare values, first cast uchar_out to
187        * signed int, then cast again to the type we are reading it
188        * as. */
189       if (nc_get_var_ushort(ncid, 0, ushort_in) != NC_ERANGE) ERR;
190       for (i=0; i<DIM1_LEN; i++)
191 	 if (ushort_in[i] != (unsigned short)(signed char)uchar_out[i]) ERR;
192 
193       if (nc_get_var_uint(ncid, 0, uint_in) != NC_ERANGE) ERR;
194       for (i=0; i<DIM1_LEN; i++)
195 	 if (uint_in[i] != (unsigned int)(signed char)uchar_out[i]) ERR;
196 
197       if (nc_get_var_ulonglong(ncid, 0, uint64_in) != NC_ERANGE) ERR;
198       for (i=0; i<DIM1_LEN; i++)
199 	 if (uint64_in[i] != (unsigned long long)(signed char)uchar_out[i]) ERR;
200 
201       if (nc_get_var_longlong(ncid, 0, int64_in)) ERR;
202       for (i=0; i<DIM1_LEN; i++)
203 	 if (int64_in[i] != (signed char)uchar_out[i]) ERR;
204 
205    }
206 
207    if (nc_close(ncid)) ERR;
208    return 0;
209 }
210