netcdf-c/nc_test/tst_inmemory.c

689 lines
21 KiB
C
Raw Normal View History

/** \file \internal
Basic NC_INMEMORY API tests both for netcdf-3 and netcdf-4
2018-12-07 05:56:42 +08:00
Copyright 2018, UCAR/Unidata. See COPYRIGHT file for copying and
redistribution conditions.
*/
#undef DDBG
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "netcdf.h"
#include "netcdf_mem.h"
#include "ncbytes.h"
Support MSYS2/Mingw platform re: The current netcdf-c release has some problems with the mingw platform on windows. Mostly they are path issues. Changes to support mingw+msys2: ------------------------------- * Enable option of looking into the windows registry to find the mingw root path. In aid of proper path handling. * Add mingw+msys as a specific platform in configure.ac and move testing of the platform to the front so it is available early. * Handle mingw X libncpoco (dynamic loader) properly even though mingw does not yet support it. * Handle mingw X plugins properly even though mingw does not yet support it. * Alias pwd='pwd -W' to better handle paths in shell scripts. * Plus a number of other minor compile irritations. * Disallow the use of multiple nc_open's on the same file for windows (and mingw) because windows does not seem to handle these properly. Not sure why we did not catch this earlier. * Add mountpoint info to dpathmgr.c to help support mingw. * Cleanup dpathmgr conversions. Known problems: --------------- * I have not been able to get shared libraries to work, so plugins/filters must be disabled. * There is some kind of problem with libcurl that I have not solved, so all uses of libcurl (currently DAP+Byterange) must be disabled. Misc. other fixes: ------------------ * Cleanup the relationship between ENABLE_PLUGINS and various other flags in CMakeLists.txt and configure.ac. * Re-arrange the TESTDIRS order in Makefile.am. * Add pseudo-breakpoint to nclog.[ch] for debugging. * Improve the documentation of the path manager code in ncpathmgr.h * Add better support for relative paths in dpathmgr.c * Default the mode args to NCfopen to include "b" (binary) for windows. * Add optional debugging output in various places. * Make sure that everything builds with plugins disabled. * Fix numerous (s)printf inconsistencies betweenb the format spec and the arguments.
2021-12-24 13:18:56 +08:00
#include "ncpathmgr.h"
#include "nc_tests.h"
#include "err_macros.h"
#ifdef USE_HDF5
2018-05-09 03:57:03 +08:00
#include <hdf5.h>
extern int H5Eprint11(FILE * stream);
#endif
#define FLAGS4 (NC_INMEMORY|NC_NETCDF4|NC_CLOBBER)
#define FLAGS3 (NC_INMEMORY|NCCLOBBER)
#define NC_NETCDF3 0
#define MODIFIED 1
#define EXTRA 1
#define LARGE_SPACE (1<<18)
#define FILE3 "tst_inmemory3.nc"
#define FILE4 "tst_inmemory4.nc"
#define CREATE3 "tst_inmemory3_create.nc"
#define CREATE4 "tst_inmemory4_create.nc"
#define XFAIL "tst_xfail.nc"
#define MISC "tst_misc.nc"
#define CREATEFILE3 "tst_memcreate3.nc"
#define CREATEFILE4 "tst_memcreate4.nc"
/* Make no dimension larger than this */
#define MAXDIMLEN (1024*12)
#define MAXDIMS 3 /* for defining arrays; includes all dimensions */
#define MAXVARS 4 /* for defining arrays; includes all variables */
#define NDIMS0 2 /* # dimensions in define_metadata: 1 unlimited + 1 fixed */
#define DIM0_NAME "fun" /* unlimited */
#define DIM0_LEN 2
#define DIM1_NAME "money"
#define DIM1_LEN 400
#define ATT0_NAME "home"
#define ATT0_TEXT "earthship"
#define NVARS0 3 /* # variables in define_metadata */
#define VAR0_NAME "nightlife"
#define VAR1_NAME "taxi_distance"
#define VAR2_NAME "time"
/* Variable added by modify_file */
#define VAR3_NAME "miles"
/* Added variable info for modify_file_extra */
#define DIMX_NAME "bigmoney"
#define DIMX_LEN 8000
#define VARX_NAME "expenses"
#define FLOATVAL ((float)42.22)
/*
CDL for created file:
netcdf tst_inmemory3 {
dimensions:
fun = UNLIMITED ; // (2 currently)
money = 8 ;
variables:
int nightlife(fun, money) ;
float time ;
short taxi_distance(money) ;
// global attributes:
:home = "earthship" ;
data:
nightlife =
0, 100, 200, 300, 400, 500, 600, 700,
800, 900, 1000, 1100, 1200, 1300, 1400, 1500 ;
time = 42.22 ;
taxi_distance = 0, 1, 2, 3, 4, 5, 6, 7 ;
}
*/
#ifdef DDBG
#undef ERR
static void
fail(int line) {
fflush(stdout);
fprintf(stderr,"\nline=%d\n",line);
fflush(stderr);
exit(1);
}
#define ERR fail(__LINE__)
#endif
static int
fail(int stat, const char* file, int line, int xfail)
{
fflush(stdout);
fprintf(stderr,"***%sFail: line: %d; status=%d %s\n",
(xfail?"X":""),line,stat,nc_strerror(stat));
err++;
fflush(stderr);
return stat;
}
static int
xxfail(int stat, const char* file, int line, int xfail)
{
fflush(stdout);
if(stat == NC_NOERR)
return fail(NC_EINVAL,file,line,xfail);
fprintf(stderr,"\t***XFail Pass: status=%d %s\n", stat,nc_strerror(stat));
stat = NC_NOERR; /* because xfail */
fflush(stderr);
return stat;
}
static int
check(int stat, const char* file, int line, int xfail)
{
if(!xfail && stat != NC_NOERR)
return fail(stat,file,line,xfail);
if(xfail)
return xxfail(stat,file,line,xfail);
return stat;
}
#define CHECK(expr) {stat = check((expr),__FILE__,__LINE__,0); if(stat) return stat;}
#define XCHECK(expr) {stat = check((expr),__FILE__,__LINE__,1); if(stat) return stat;}
#define REPORT(xfail,expr) {if((xfail)) {XCHECK((expr));} else {CHECK((expr));}}
/**************************************************/
static void
removefile(const char* path)
{
unlink(path);
}
static int
readfile(const char* path, NC_memio* memio)
{
int status = NC_NOERR;
Improve UTF8 Support On Windows re: Issue https://github.com/Unidata/netcdf-c/issues/2190 The primary purpose of this PR is to improve the utf8 support for windows. This is persuant to a change in Windows that supports utf8 natively (almost). The almost means that it is still utf16 internally and the set of characters representable by utf8 is larger than those representable by utf16. This leaves open the question in the Issue about handling the Windows 1252 character set. This required the following changes: 1. Test the Windows build and major version in order to see if native utf8 is supported. 2. If native utf8 is supported, Modify dpathmgr.c to call the 8-bit version of the windows fopen() and open() functions. 3. In support of this, programs that use XGetOpt (Windows versions) need to get the command line as utf8 and then parse to arc+argv as utf8. This requires using a homegrown command line parser named XCommandLineToArgvA. 4. Add a utility program called "acpget" that prints out the current Windows code page and locale. Additionally, some technical debt was cleaned up as follows: 1. Unify all the places which attempt to read all or a part of a file into the dutil.c#NC_readfile code. 2. Similary unify all the code that creates temp files into dutil.c#NC_mktmp code. 3. Convert almost all remaining calls to fopen() and open() to NCfopen() and NCopen3(). This is to ensure that path management is used consistently. This touches a number of files. 4. extern->EXTERNL as needed to get it to work under Windows.
2022-02-09 11:53:30 +08:00
NCbytes* buf = ncbytesnew();
if((status = NC_readfile(path,buf))) goto done;
if(memio) {
Improve UTF8 Support On Windows re: Issue https://github.com/Unidata/netcdf-c/issues/2190 The primary purpose of this PR is to improve the utf8 support for windows. This is persuant to a change in Windows that supports utf8 natively (almost). The almost means that it is still utf16 internally and the set of characters representable by utf8 is larger than those representable by utf16. This leaves open the question in the Issue about handling the Windows 1252 character set. This required the following changes: 1. Test the Windows build and major version in order to see if native utf8 is supported. 2. If native utf8 is supported, Modify dpathmgr.c to call the 8-bit version of the windows fopen() and open() functions. 3. In support of this, programs that use XGetOpt (Windows versions) need to get the command line as utf8 and then parse to arc+argv as utf8. This requires using a homegrown command line parser named XCommandLineToArgvA. 4. Add a utility program called "acpget" that prints out the current Windows code page and locale. Additionally, some technical debt was cleaned up as follows: 1. Unify all the places which attempt to read all or a part of a file into the dutil.c#NC_readfile code. 2. Similary unify all the code that creates temp files into dutil.c#NC_mktmp code. 3. Convert almost all remaining calls to fopen() and open() to NCfopen() and NCopen3(). This is to ensure that path management is used consistently. This touches a number of files. 4. extern->EXTERNL as needed to get it to work under Windows.
2022-02-09 11:53:30 +08:00
memio->size = (size_t)ncbyteslength(buf);
memio->memory = ncbytesextract(buf);
}
done:
Improve UTF8 Support On Windows re: Issue https://github.com/Unidata/netcdf-c/issues/2190 The primary purpose of this PR is to improve the utf8 support for windows. This is persuant to a change in Windows that supports utf8 natively (almost). The almost means that it is still utf16 internally and the set of characters representable by utf8 is larger than those representable by utf16. This leaves open the question in the Issue about handling the Windows 1252 character set. This required the following changes: 1. Test the Windows build and major version in order to see if native utf8 is supported. 2. If native utf8 is supported, Modify dpathmgr.c to call the 8-bit version of the windows fopen() and open() functions. 3. In support of this, programs that use XGetOpt (Windows versions) need to get the command line as utf8 and then parse to arc+argv as utf8. This requires using a homegrown command line parser named XCommandLineToArgvA. 4. Add a utility program called "acpget" that prints out the current Windows code page and locale. Additionally, some technical debt was cleaned up as follows: 1. Unify all the places which attempt to read all or a part of a file into the dutil.c#NC_readfile code. 2. Similary unify all the code that creates temp files into dutil.c#NC_mktmp code. 3. Convert almost all remaining calls to fopen() and open() to NCfopen() and NCopen3(). This is to ensure that path management is used consistently. This touches a number of files. 4. extern->EXTERNL as needed to get it to work under Windows.
2022-02-09 11:53:30 +08:00
ncbytesfree(buf);
return status;
}
static int
writefile(const char* path, NC_memio* memio)
{
int status = NC_NOERR;
Improve UTF8 Support On Windows re: Issue https://github.com/Unidata/netcdf-c/issues/2190 The primary purpose of this PR is to improve the utf8 support for windows. This is persuant to a change in Windows that supports utf8 natively (almost). The almost means that it is still utf16 internally and the set of characters representable by utf8 is larger than those representable by utf16. This leaves open the question in the Issue about handling the Windows 1252 character set. This required the following changes: 1. Test the Windows build and major version in order to see if native utf8 is supported. 2. If native utf8 is supported, Modify dpathmgr.c to call the 8-bit version of the windows fopen() and open() functions. 3. In support of this, programs that use XGetOpt (Windows versions) need to get the command line as utf8 and then parse to arc+argv as utf8. This requires using a homegrown command line parser named XCommandLineToArgvA. 4. Add a utility program called "acpget" that prints out the current Windows code page and locale. Additionally, some technical debt was cleaned up as follows: 1. Unify all the places which attempt to read all or a part of a file into the dutil.c#NC_readfile code. 2. Similary unify all the code that creates temp files into dutil.c#NC_mktmp code. 3. Convert almost all remaining calls to fopen() and open() to NCfopen() and NCopen3(). This is to ensure that path management is used consistently. This touches a number of files. 4. extern->EXTERNL as needed to get it to work under Windows.
2022-02-09 11:53:30 +08:00
if((status = NC_writefile(path,memio->size,memio->memory))) goto done;
done:
return status;
}
/* Duplicate an NC_memio instance; needed to avoid
attempting to use memory that might have been realloc'd
Allow the new memory to be larger than the src memory
*/
int
duplicatememory(NC_memio* src, NC_memio* target, size_t alloc, void** original)
{
if(src == NULL || target == NULL || src->size == 0 || src->memory == NULL)
return NC_EINVAL;
*target = *src;
if(alloc == 0) alloc = src->size;
target->memory = malloc(alloc);
if(target->memory == NULL)
return NC_ENOMEM;
if(original) *original = target->memory;
memcpy(target->memory,src->memory,src->size);
target->size = alloc;
return NC_NOERR;
}
/*
Given an ncid of a created file, fill in the meta-data
and data as described by the above CDL. Do not close
the file.
*/
static int
define_metadata(int ncid)
{
int stat = NC_NOERR;
int dimid[MAXDIMS], varid0, varid1, varid2;
size_t start[1] = {0};
size_t count[1] = {DIM1_LEN};
int dimprod = (DIM0_LEN*DIM1_LEN);
int i;
float float_data;
int nightdata[DIM0_LEN*DIM1_LEN] ;
short taxi_distance[DIM1_LEN] ;
/* Create data to write */
float_data = FLOATVAL;
2024-03-12 01:48:42 +08:00
for (short i = 0; i < DIM1_LEN; i++)
taxi_distance[i] = i;
for (i = 0; i < dimprod; i++)
nightdata[i] = (100*i);
CHECK(nc_put_att_text(ncid, NC_GLOBAL, ATT0_NAME,
sizeof(ATT0_TEXT), ATT0_TEXT));
CHECK(nc_def_dim(ncid, DIM0_NAME, NC_UNLIMITED, &dimid[0]));
CHECK(nc_def_dim(ncid, DIM1_NAME, DIM1_LEN, &dimid[1]));
CHECK(nc_def_var(ncid, VAR0_NAME, NC_INT, 2, dimid, &varid0));
CHECK(nc_def_var(ncid, VAR1_NAME, NC_SHORT, 1, &dimid[1], &varid1));
CHECK(nc_def_var(ncid, VAR2_NAME, NC_FLOAT, 0, NULL, &varid2));
CHECK(nc_enddef(ncid));
CHECK(nc_put_vara_short(ncid, varid1, start, count, taxi_distance));
CHECK(nc_put_var_float(ncid, varid2, &float_data));
{
size_t start[2] = {0,0};
size_t count[2] = {2,DIM1_LEN};
CHECK(nc_put_vara_int(ncid, varid0, start, count, nightdata));
}
return stat;
}
/*
Create our reference file as a real on-disk file
and read it back into memory
*/
static int
create_reference_file(const char* filename, int mode, NC_memio* filedata)
{
int stat = NC_NOERR;
int ncid;
CHECK(nc_create(filename, mode|NC_CLOBBER, &ncid)); /* overwrite */
CHECK(define_metadata(ncid));
CHECK(nc_close(ncid));
/* Read back the contents of the file into memory */
if(filedata != NULL) {
memset(filedata,0,sizeof(NC_memio));
CHECK(readfile(filename,filedata));
}
return stat;
}
static int
modify_file(int ncid)
{
int stat = NC_NOERR;
size_t i;
int varid3;
int dimid[1];
size_t len;
int data[MAXDIMLEN];
/* Get id of the unlimited dimension */
if((stat=nc_inq_dimid(ncid, DIM0_NAME, dimid))) goto done;
/* get current dim length */
if((stat=nc_inq_dimlen(ncid, dimid[0], &len))) goto done;
/* open file for new meta-data */
if((stat=nc_redef(ncid))) goto done;
/* Define a new variable */
if((stat=nc_def_var(ncid, VAR3_NAME, NC_INT, 1, dimid, &varid3))) goto done;
/* close metadata */
if((stat=nc_enddef(ncid))) goto done;
/* Write data to new variable */
for(i=0;i<len;i++)
2024-03-12 01:48:42 +08:00
data[i] = (int)i;
if((stat=nc_put_var_int(ncid,varid3,data))) goto done;
done:
return stat;
}
/* Use this to force significant file size increase */
static int
modify_file_extra(int ncid)
{
int stat = NC_NOERR;
size_t i;
int varidx;
int dimid[1];
int data[MAXDIMLEN];
/* open file for new meta-data */
if((stat=nc_redef(ncid))) goto done;
/* Define a new dimension */
CHECK(nc_def_dim(ncid, DIMX_NAME, DIMX_LEN, &dimid[0]));
/* Define a new variable using new dimension */
if((stat=nc_def_var(ncid, VARX_NAME, NC_INT, 1, dimid, &varidx))) goto done;
/* close metadata */
if((stat=nc_enddef(ncid))) goto done;
/* Write data to new variable */
for(i=0;i<DIMX_LEN;i++)
2024-03-12 01:48:42 +08:00
data[i] = (int)i;
if((stat=nc_put_var_int(ncid,varidx,data))) goto done;
done:
return stat;
}
/* Verify the content of a file */
static int
verify_file(int ncid, int modified, int extra)
{
int stat = NC_NOERR;
int i;
int dimid_in[MAXDIMS];
int dimid[MAXDIMS];
int ndims_in, nvars_in, natts_in, unlimdimid_in;
char name_in[NC_MAX_NAME + 1], att0_in[NC_MAX_NAME + 1];
nc_type type_in;
size_t len_in;
int varid[5];
int nightdata_in[DIM0_LEN*DIM1_LEN] ;
float float_data_in;
int milesdata_in[MAXDIMLEN];
int expenses_in[MAXDIMLEN];
short taxi_distance_in[MAXDIMLEN];
int dimprod = DIM0_LEN * DIM1_LEN;
#ifdef USE_HDF5
int tmp;
#endif
CHECK(nc_inq(ncid, &ndims_in, &nvars_in, &natts_in, &unlimdimid_in));
if (ndims_in != (NDIMS0+extra) || nvars_in != (NVARS0+modified+extra) || natts_in != 1 || unlimdimid_in != 0)
CHECK(NC_EINVAL);
/* Get all the dimids */
#ifdef USE_HDF5
tmp = 0;
CHECK((nc_inq_dimids(ncid,&tmp,dimid,1)));
if(tmp != NDIMS0+extra) CHECK(NC_EINVAL);
/* Get all the varids */
tmp = 0;
CHECK((nc_inq_varids(ncid,&tmp,varid)));
if(tmp != (NVARS0+modified+extra)) CHECK(NC_EINVAL);
#else
{ /* Simulate nc_inq_varids and nc_inq_dimids */
int j;
int dimcnt = 0;
int varcnt = 0;
CHECK(nc_inq(ncid, &dimcnt, &varcnt, NULL, NULL));
for(j=0;j<dimcnt;j++) dimid[j] = j;
for(j=0;j<varcnt;j++) varid[j] = j;
}
#endif
CHECK(nc_get_att_text(ncid, NC_GLOBAL, ATT0_NAME, att0_in));
att0_in[sizeof(ATT0_TEXT)] = '\0';
if (strcmp(att0_in, ATT0_TEXT) != 0) CHECK(NC_EINVAL);
/* CHECK dimensions. */
CHECK(nc_inq_dim(ncid, dimid[0], name_in, &len_in));
if (strcmp(name_in, DIM0_NAME) != 0) CHECK(NC_EINVAL);
CHECK(nc_inq_dim(ncid, dimid[1], name_in, &len_in));
if (strcmp(name_in, DIM1_NAME) != 0 || len_in != DIM1_LEN) CHECK(NC_EINVAL);
if(extra) {
CHECK(nc_inq_dim(ncid, dimid[2], name_in, &len_in));
if (strcmp(name_in, DIMX_NAME) != 0 || len_in != DIMX_LEN) CHECK(NC_EINVAL);
}
/* CHECK variables. */
CHECK(nc_inq_var(ncid, varid[0], name_in, &type_in, &ndims_in, dimid_in, &natts_in));
if (strcmp(name_in, VAR0_NAME) != 0 || type_in != NC_INT || ndims_in != NDIMS0 ||
dimid_in[0] != 0 || dimid_in[1] != 1 || natts_in != 0) CHECK(NC_EINVAL);
CHECK(nc_inq_var(ncid, varid[1], name_in, &type_in, &ndims_in, dimid_in, &natts_in));
if (strcmp(name_in, VAR1_NAME) != 0 || type_in != NC_SHORT || ndims_in != 1 || dimid_in[0] != 1 || natts_in != 0)
CHECK(NC_EINVAL);
CHECK(nc_inq_var(ncid, varid[2], name_in, &type_in, &ndims_in, dimid_in, &natts_in));
if (strcmp(name_in, VAR2_NAME) != 0 || type_in != NC_FLOAT || ndims_in != 0 || natts_in != 0)
CHECK(NC_EINVAL);
CHECK(nc_get_var_int(ncid, varid[0], nightdata_in));
for(i=0;i<dimprod;i++) {
if(nightdata_in[i] != (100*i)) CHECK(NC_EINVAL);
}
CHECK(nc_get_var_short(ncid, varid[1], taxi_distance_in));
for(i=0;i<DIM1_LEN;i++) {
if(taxi_distance_in[i] != (i)) CHECK(NC_EINVAL);
}
CHECK(nc_get_var_float(ncid, varid[2], &float_data_in));
if (float_data_in != FLOATVAL) CHECK(NC_EINVAL);
if(modified) {
size_t unlimlen;
CHECK(nc_inq_var(ncid, varid[3], name_in, &type_in, &ndims_in, dimid_in, &natts_in));
if (strcmp(name_in, VAR3_NAME) != 0 || type_in != NC_INT || ndims_in != 1 ||
dimid_in[0] != 0 || natts_in != 0) CHECK(NC_EINVAL);
CHECK(nc_inq_dimlen(ncid, dimid_in[0], &unlimlen));
CHECK(nc_get_var_int(ncid, varid[3], milesdata_in));
for(i=0;i<unlimlen;i++) {
if(milesdata_in[i] != i) CHECK(NC_EINVAL);
}
}
if(extra) {
size_t xlen;
CHECK(nc_inq_var(ncid, varid[4], name_in, &type_in, &ndims_in, dimid_in, &natts_in));
if (strcmp(name_in, VARX_NAME) != 0 || type_in != NC_INT || ndims_in != 1 ||
dimid_in[0] != dimid[2] || natts_in != 0) CHECK(NC_EINVAL);
CHECK(nc_inq_dimlen(ncid, dimid_in[0], &xlen));
CHECK(nc_get_var_int(ncid, varid[4], expenses_in));
for(i=0;i<xlen;i++) {
if(expenses_in[i] != i) CHECK(NC_EINVAL);
}
}
return stat;
}
void
memiofree(NC_memio* memio, void** original)
{
if(memio != NULL) {
if(memio->memory != NULL)
free(memio->memory);
memio->memory = NULL;
}
if(original) *original = NULL;
}
static int
test_open(const char* path, NC_memio* filedata, int mode)
{
int stat = NC_NOERR;
NC_memio duplicate;
void* original = NULL;
NC_memio finaldata;
int ncid;
int xmode = mode; /* modified mode */
finaldata.memory = NULL;
finaldata.size = 0;
finaldata.flags = 0;
fprintf(stderr,"\n\t***Test open 1: nc_open_mem(): read-only\n");
CHECK(duplicatememory(filedata,&duplicate,0,&original));
CHECK(nc_open_mem(path, xmode, duplicate.size, duplicate.memory, &ncid));
CHECK(verify_file(ncid,!MODIFIED,!EXTRA));
CHECK(nc_close(ncid));
memiofree(&duplicate,&original);
fprintf(stderr,"\n\t***Test open 2: nc_open_memio(): read-only\n");
CHECK(duplicatememory(filedata,&duplicate,0,&original));
duplicate.flags = NC_MEMIO_LOCKED;
CHECK(nc_open_memio(path, xmode, &duplicate, &ncid))
CHECK(verify_file(ncid,!MODIFIED,!EXTRA));
CHECK(nc_close_memio(ncid,&finaldata));
/* Published returned finaldata */
fprintf(stderr,"\tfinaldata: size=%lld memory=%p original=%p\n",(unsigned long long)finaldata.size,finaldata.memory,original);
/* Verify that finaldata is same */
if(finaldata.size != duplicate.size) CHECK(NC_EINVAL);
if(finaldata.memory != duplicate.memory) CHECK(NC_EINVAL);
memiofree(&finaldata,&original);
fprintf(stderr,"\n\t***Test open 3: nc_open_memio(): read-write, copy, no size increase\n");
fprintf(stderr,"\t*** Not testable\n");
#if 0
{
fprintf(stderr,"\n\t***Test open 3: nc_open_memio(): read-write, copy, no size increase\n");
xmode |= NC_WRITE; /* allow file to be modified */
CHECK(duplicatememory(filedata,&duplicate,0,&original));
CHECK(nc_open_memio(path, xmode, &duplicate, &ncid))
/* modify file */
CHECK(modify_file(ncid));
CHECK(verify_file(ncid,MODIFIED,!EXTRA));
CHECK(nc_close_memio(ncid,&finaldata));
/* Published returned finaldata */
fprintf(stderr,"\tfinaldata: size=%lld memory=%p original=%p\n",(unsigned long long)finaldata.size,finaldata.memory,original);
/* Verify that finaldata is same */
if(finaldata.size < filedata->size) CHECK(NC_EINVAL);
/* As a safeguard, the memory in duplicate should have been set to NULL*/
memiofree(&finaldata,&original);
}
#endif
fprintf(stderr,"\n\t***Test open 4: nc_open_memio(): read-write, copy, size increase\n");
xmode |= NC_WRITE; /* allow file to be modified */
CHECK(duplicatememory(filedata,&duplicate,0,&original));
CHECK(nc_open_memio(path, xmode, &duplicate, &ncid))
/* modify file */
CHECK(modify_file(ncid));
CHECK(modify_file_extra(ncid));
CHECK(verify_file(ncid,MODIFIED,EXTRA));
CHECK(nc_close_memio(ncid,&finaldata));
/* Published returned finaldata */
fprintf(stderr,"\tfinaldata: size=%lld memory=%p original=%p\n",(unsigned long long)finaldata.size,finaldata.memory,original);
/* Verify that finaldata is same */
if(finaldata.size < filedata->size) CHECK(NC_EINVAL);
/* As a safeguard, the memory in duplicate should have been set to NULL*/
memiofree(&finaldata,&original);
fprintf(stderr,"\n\t***Test open 5: nc_open_memio(): read-write, locked, extra space\n");
/* Store the filedata in a memory chunk that leaves room for modification */
CHECK(duplicatememory(filedata,&duplicate,LARGE_SPACE,&original));
/* Lock the duplicate memory */
duplicate.flags |= NC_MEMIO_LOCKED;
xmode |= NC_WRITE; /* allow file to be modified */
CHECK(nc_open_memio(path, xmode, &duplicate, &ncid))
/* modify file */
CHECK(modify_file(ncid));
CHECK(verify_file(ncid,MODIFIED,!EXTRA));
CHECK(nc_close_memio(ncid,&finaldata));
/* Published returned finaldata */
fprintf(stderr,"\tfinaldata: size=%lld memory=%p original=%p\n",(unsigned long long)finaldata.size,finaldata.memory,original);
/* Check returned finaldata:
should have same memory but
actual used final size should not exceed the original */
if(finaldata.size > duplicate.size) CHECK(NC_EINVAL);
if(finaldata.memory != duplicate.memory) CHECK(NC_EINVAL);
memiofree(&finaldata,&original);
return stat;
}
static int
test_create(const char* path, int mode)
{
int stat = NC_NOERR;
NC_memio finaldata;
int ncid;
int xmode = mode;
finaldata.memory = NULL;
finaldata.size = 0;
finaldata.flags = 0;
fprintf(stderr,"\n\t***Test create 1: nc_create_memio(): no initialsize\n");
CHECK(nc_create_mem(path, xmode, 0, &ncid))
/* create file metadata */
CHECK(define_metadata(ncid));
CHECK(verify_file(ncid,!MODIFIED,!EXTRA));
CHECK(nc_close_memio(ncid,&finaldata));
/* Published returned finaldata */
fprintf(stderr,"\tfinaldata: size=%lld memory=%p\n",(unsigned long long)finaldata.size,finaldata.memory);
free(finaldata.memory);
fprintf(stderr,"\n\t***Test create 2: nc_create_memio(): initialsize; save file\n");
CHECK(nc_create_mem(path, xmode, LARGE_SPACE, &ncid))
/* create file metadata */
CHECK(define_metadata(ncid));
CHECK(verify_file(ncid,!MODIFIED,!EXTRA));
CHECK(nc_close_memio(ncid,&finaldata));
/* Published returned finaldata */
fprintf(stderr,"\tfinaldata: size=%lld memory=%p\n",(unsigned long long)finaldata.size,finaldata.memory);
/* Write out the final data as a .nc file */
CHECK(writefile(path,&finaldata));
if(finaldata.memory != NULL)
free(finaldata.memory);
finaldata.memory = NULL;
return stat;
}
static int
test_misc(const char* path, int mode, NC_memio* filedata)
{
int stat = NC_NOERR;
int ncid;
int xmode = mode;
NC_memio duplicate;
void* original = NULL;
fprintf(stderr,"\n\t***Test misc 1: use nc_close on created inmemory file\n");
CHECK(nc_create_mem(MISC, xmode, 0, &ncid))
CHECK(nc_close(ncid));
fprintf(stderr,"\t***Pass\n");
removefile(MISC);
fprintf(stderr,"\n\t***Test misc 2: use nc_close on opened inmemory file\n");
CHECK(duplicatememory(filedata,&duplicate,0,&original));
CHECK(nc_open_memio(path, xmode, &duplicate, &ncid))
CHECK(verify_file(ncid,!MODIFIED,!EXTRA));
CHECK(nc_close(ncid));
fprintf(stderr,"\t***Pass\n");
/* Do not free: nc_close will have done it memiofree(&duplicate,&original); */
removefile(MISC);
return stat;
}
/* Test various edge conditions to ensure they fail correctly */
static int
test_xfail(const char* path, int mode, NC_memio* filedata)
{
int stat = NC_NOERR;
NC_memio duplicate = {0,NULL,0};
int ncid;
int xmode = mode; /* modified mode */
void* original = NULL;
fprintf(stderr,"\n\t***Test xfail 1: nc_open_mem(): write to read-only\n");
CHECK(duplicatememory(filedata,&duplicate,0,&original));
CHECK(nc_open_mem(XFAIL, xmode, duplicate.size, duplicate.memory, &ncid));
XCHECK(nc_redef(ncid));
CHECK(nc_abort(ncid));
memiofree(&duplicate,&original);
fprintf(stderr,"\n\t***Test xfail 2: nc_open_memio(): modify without overallocating\n");
if((mode & NC_NETCDF4)) {
fprintf(stderr,"\t*** Suppressed because of HDF5 library bug\n");
} else {
/* With HDF5 1.8.20, and possibly other versions,
this tests causes a seg fault in the HDF5 Library.
So until it is fixed, just leave well enough alone */
NC_memio finaldata;
memset(&finaldata,0,sizeof(finaldata));
CHECK(duplicatememory(filedata,&duplicate,0,&original));
duplicate.flags = NC_MEMIO_LOCKED;
xmode |= NC_WRITE;
CHECK(nc_open_memio(XFAIL, xmode, &duplicate, &ncid))
XCHECK(modify_file(ncid));
CHECK(nc_abort(ncid));
memiofree(&finaldata,&original);
memiofree(&duplicate,&original);
}
return stat;
}
int
main(int argc, char **argv)
{
int stat = NC_NOERR;
NC_memio filedata3;
void* original = NULL;
#ifdef USE_HDF5
NC_memio filedata4;
#endif
fprintf(stderr,"\n*** Testing the inmemory API: netcdf-3.\n");
CHECK(create_reference_file(FILE3,NC_NETCDF3,&filedata3)); /* netcdf-3 */
CHECK(test_open(FILE3,&filedata3,NC_NETCDF3));
CHECK(test_create(CREATE3,NC_NETCDF3));
CHECK(test_misc(FILE3, NC_NETCDF3, &filedata3));
CHECK(test_xfail(FILE3, NC_NETCDF3, &filedata3));
memiofree(&filedata3,&original);
#ifdef USE_HDF5
fprintf(stderr,"\n*** Testing the inmemory API: netcdf-4.\n");
CHECK(create_reference_file(FILE4,NC_NETCDF4,&filedata4));
CHECK(test_open(FILE4,&filedata4,NC_NETCDF4));
CHECK(test_create(CREATE4,NC_NETCDF4));
CHECK(test_misc(FILE4,NC_NETCDF4, &filedata4));
CHECK(test_xfail(FILE4, NC_NETCDF4, &filedata4));
memiofree(&filedata4,&original);
#endif
SUMMARIZE_ERR;
FINAL_RESULTS;
return 0;
}